#This notebook also uses the `(some) LaTeX environments for Jupyter`
#https://github.com/ProfFan/latex_envs wich is part of the
#jupyter_contrib_nbextensions package

from myhdl import *
from myhdlpeek import Peeker
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
%matplotlib inline

from sympy import *
init_printing()

import itertools

#EE drawing tools in python from https://cdelker.bitbucket.io/SchemDraw/
import SchemDraw as schem
import SchemDraw.elements as e
import SchemDraw.logic as l

#https://github.com/jrjohansson/version_information
%load_ext version_information
%version_information myhdl, myhdlpeek, numpy, pandas, matplotlib, sympy, itertools, SchemDraw

#helper  functions to read in the .v and .vhd generated files into python
def VerilogTextReader(loc, printresult=True):
    with open(f'{loc}.v', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***Verilog modual from {loc}.v***\n\n', VerilogText)
    return VerilogText

def VHDLTextReader(loc, printresult=True):
    with open(f'{loc}.vhd', 'r') as vText:
        VerilogText=vText.read()
    if printresult:
        print(f'***VHDL modual from {loc}.vhd***\n\n', VerilogText)
    return VerilogText

def ConstraintXDCTextReader(loc, printresult=True):
    with open(f'{loc}.xdc', 'r') as xdcText:
        ConstraintText=xdcText.read()
    if printresult:
        print(f'***Constraint file from {loc}.xdc***\n\n', ConstraintText)
    return ConstraintText

def TruthTabelGenrator(BoolSymFunc):
    """
    Function to generate a truth table from a sympy boolian expression
    BoolSymFunc: sympy boolian expression
    return TT: a Truth table stored in a pandas dataframe
    """
    colsL=sorted([i for i in list(BoolSymFunc.rhs.atoms())], key=lambda x:x.sort_key())
    colsR=sorted([i for i in list(BoolSymFunc.lhs.atoms())], key=lambda x:x.sort_key())
    bitwidth=len(colsL)
    cols=colsL+colsR; cols
    
    TT=pd.DataFrame(columns=cols, index=range(2**bitwidth))
    
    for i in range(2**bitwidth):
        inputs=[int(j) for j in list(np.binary_repr(i, bitwidth))]
        outputs=BoolSymFunc.rhs.subs({j:v for j, v in zip(colsL, inputs)})
        inputs.append(int(bool(outputs)))
        TT.iloc[i]=inputs
    
    return TT
    
    
    

"""
Explanation: \title{myHDL Combinational Logic Elements: Demultiplexers (DEMUXs))}
\author{Steven K Armour}
\maketitle
<h1>Table of Contents<span class="tocSkip"></span></h1>
<div class="toc" style="margin-top: 1em;"><ul class="toc-item"><li><span><a href="#Refrances" data-toc-modified-id="Refrances-1"><span class="toc-item-num">1&nbsp;&nbsp;</span>Refrances</a></span></li><li><span><a href="#Libraries-and-Helper-functions" data-toc-modified-id="Libraries-and-Helper-functions-2"><span class="toc-item-num">2&nbsp;&nbsp;</span>Libraries and Helper functions</a></span></li><li><span><a href="#Demultiplexers" data-toc-modified-id="Demultiplexers-3"><span class="toc-item-num">3&nbsp;&nbsp;</span>Demultiplexers</a></span></li><li><span><a href="#1-Channel-Input:-2-Channel-Output-demultiplexer-in-Gate-Level-Logic" data-toc-modified-id="1-Channel-Input:-2-Channel-Output-demultiplexer-in-Gate-Level-Logic-4"><span class="toc-item-num">4&nbsp;&nbsp;</span>1 Channel Input: 2 Channel Output demultiplexer in Gate Level Logic</a></span><ul class="toc-item"><li><span><a href="#Sympy-Expression" data-toc-modified-id="Sympy-Expression-4.1"><span class="toc-item-num">4.1&nbsp;&nbsp;</span>Sympy Expression</a></span></li><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-4.2"><span class="toc-item-num">4.2&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-4.3"><span class="toc-item-num">4.3&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-4.4"><span class="toc-item-num">4.4&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbech" data-toc-modified-id="myHDL-to-Verilog-Testbech-4.5"><span class="toc-item-num">4.5&nbsp;&nbsp;</span>myHDL to Verilog Testbech</a></span></li><li><span><a href="#PYNQ-Z1-Deployment" data-toc-modified-id="PYNQ-Z1-Deployment-4.6"><span class="toc-item-num">4.6&nbsp;&nbsp;</span>PYNQ-Z1 Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-4.6.1"><span class="toc-item-num">4.6.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraints" data-toc-modified-id="Board-Constraints-4.6.2"><span class="toc-item-num">4.6.2&nbsp;&nbsp;</span>Board Constraints</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-4.6.3"><span class="toc-item-num">4.6.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li><li><span><a href="#1-Channel-Input:4-Channel-Output-demultiplexer-in-Gate-Level-Logic" data-toc-modified-id="1-Channel-Input:4-Channel-Output-demultiplexer-in-Gate-Level-Logic-5"><span class="toc-item-num">5&nbsp;&nbsp;</span>1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic</a></span><ul class="toc-item"><li><span><a href="#Sympy-Expression" data-toc-modified-id="Sympy-Expression-5.1"><span class="toc-item-num">5.1&nbsp;&nbsp;</span>Sympy Expression</a></span></li><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-5.2"><span class="toc-item-num">5.2&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-5.3"><span class="toc-item-num">5.3&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-5.4"><span class="toc-item-num">5.4&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbench" data-toc-modified-id="myHDL-to-Verilog-Testbench-5.5"><span class="toc-item-num">5.5&nbsp;&nbsp;</span>myHDL to Verilog Testbench</a></span></li><li><span><a href="#PYNQ-Z1-Deployment" data-toc-modified-id="PYNQ-Z1-Deployment-5.6"><span class="toc-item-num">5.6&nbsp;&nbsp;</span>PYNQ-Z1 Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-5.6.1"><span class="toc-item-num">5.6.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraints" data-toc-modified-id="Board-Constraints-5.6.2"><span class="toc-item-num">5.6.2&nbsp;&nbsp;</span>Board Constraints</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-5.6.3"><span class="toc-item-num">5.6.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li><li><span><a href="#1-Channel-Input:4-Channel-Output-demultiplexer-via-DEMUX-Stacking" data-toc-modified-id="1-Channel-Input:4-Channel-Output-demultiplexer-via-DEMUX-Stacking-6"><span class="toc-item-num">6&nbsp;&nbsp;</span>1 Channel Input:4 Channel Output demultiplexer via DEMUX Stacking</a></span><ul class="toc-item"><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-6.1"><span class="toc-item-num">6.1&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-6.2"><span class="toc-item-num">6.2&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-6.3"><span class="toc-item-num">6.3&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbench" data-toc-modified-id="myHDL-to-Verilog-Testbench-6.4"><span class="toc-item-num">6.4&nbsp;&nbsp;</span>myHDL to Verilog Testbench</a></span></li><li><span><a href="#PYNQ-Z1-Deployment" data-toc-modified-id="PYNQ-Z1-Deployment-6.5"><span class="toc-item-num">6.5&nbsp;&nbsp;</span>PYNQ-Z1 Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-6.5.1"><span class="toc-item-num">6.5.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraint" data-toc-modified-id="Board-Constraint-6.5.2"><span class="toc-item-num">6.5.2&nbsp;&nbsp;</span>Board Constraint</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-6.5.3"><span class="toc-item-num">6.5.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li><li><span><a href="#1:2-DEMUX-via-Behavioral-IF" data-toc-modified-id="1:2-DEMUX-via-Behavioral-IF-7"><span class="toc-item-num">7&nbsp;&nbsp;</span>1:2 DEMUX via Behavioral IF</a></span><ul class="toc-item"><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-7.1"><span class="toc-item-num">7.1&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-7.2"><span class="toc-item-num">7.2&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-7.3"><span class="toc-item-num">7.3&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbench" data-toc-modified-id="myHDL-to-Verilog-Testbench-7.4"><span class="toc-item-num">7.4&nbsp;&nbsp;</span>myHDL to Verilog Testbench</a></span></li><li><span><a href="#PYNQ-Z1-Deployment" data-toc-modified-id="PYNQ-Z1-Deployment-7.5"><span class="toc-item-num">7.5&nbsp;&nbsp;</span>PYNQ-Z1 Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-7.5.1"><span class="toc-item-num">7.5.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraint" data-toc-modified-id="Board-Constraint-7.5.2"><span class="toc-item-num">7.5.2&nbsp;&nbsp;</span>Board Constraint</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-7.5.3"><span class="toc-item-num">7.5.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li><li><span><a href="#1:4-DEMUX-via-Behavioral-if-elif-else" data-toc-modified-id="1:4-DEMUX-via-Behavioral-if-elif-else-8"><span class="toc-item-num">8&nbsp;&nbsp;</span>1:4 DEMUX via Behavioral if-elif-else</a></span><ul class="toc-item"><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-8.1"><span class="toc-item-num">8.1&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-8.2"><span class="toc-item-num">8.2&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-8.3"><span class="toc-item-num">8.3&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbench" data-toc-modified-id="myHDL-to-Verilog-Testbench-8.4"><span class="toc-item-num">8.4&nbsp;&nbsp;</span>myHDL to Verilog Testbench</a></span></li><li><span><a href="#PYNQ-Z1-Deployment" data-toc-modified-id="PYNQ-Z1-Deployment-8.5"><span class="toc-item-num">8.5&nbsp;&nbsp;</span>PYNQ-Z1 Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-8.5.1"><span class="toc-item-num">8.5.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraint" data-toc-modified-id="Board-Constraint-8.5.2"><span class="toc-item-num">8.5.2&nbsp;&nbsp;</span>Board Constraint</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-8.5.3"><span class="toc-item-num">8.5.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li><li><span><a href="#Demultiplexer-1:4-Behavioral-via-Bitvectors" data-toc-modified-id="Demultiplexer-1:4-Behavioral-via-Bitvectors-9"><span class="toc-item-num">9&nbsp;&nbsp;</span>Demultiplexer 1:4 Behavioral via Bitvectors</a></span><ul class="toc-item"><li><span><a href="#myHDL-Module" data-toc-modified-id="myHDL-Module-9.1"><span class="toc-item-num">9.1&nbsp;&nbsp;</span>myHDL Module</a></span></li><li><span><a href="#myHDL-Testing" data-toc-modified-id="myHDL-Testing-9.2"><span class="toc-item-num">9.2&nbsp;&nbsp;</span>myHDL Testing</a></span></li><li><span><a href="#Verilog-Conversion" data-toc-modified-id="Verilog-Conversion-9.3"><span class="toc-item-num">9.3&nbsp;&nbsp;</span>Verilog Conversion</a></span></li><li><span><a href="#myHDL-to-Verilog-Testbench" data-toc-modified-id="myHDL-to-Verilog-Testbench-9.4"><span class="toc-item-num">9.4&nbsp;&nbsp;</span>myHDL to Verilog Testbench</a></span></li><li><span><a href="#PYNQ-Z1-Board-Deployment" data-toc-modified-id="PYNQ-Z1-Board-Deployment-9.5"><span class="toc-item-num">9.5&nbsp;&nbsp;</span>PYNQ-Z1 Board Deployment</a></span><ul class="toc-item"><li><span><a href="#Board-Circuit" data-toc-modified-id="Board-Circuit-9.5.1"><span class="toc-item-num">9.5.1&nbsp;&nbsp;</span>Board Circuit</a></span></li><li><span><a href="#Board-Constraints" data-toc-modified-id="Board-Constraints-9.5.2"><span class="toc-item-num">9.5.2&nbsp;&nbsp;</span>Board Constraints</a></span></li><li><span><a href="#Video-of-Deployment" data-toc-modified-id="Video-of-Deployment-9.5.3"><span class="toc-item-num">9.5.3&nbsp;&nbsp;</span>Video of Deployment</a></span></li></ul></li></ul></li></ul></div>

Refrances
Libraries and Helper functions
End of explanation
"""


x, s, y0, y1=symbols('x, s, y_0, y_1')
y12_0Eq=Eq(y0, ~s&x)
y12_1Eq=Eq(y1, s&x)
y12_0Eq, y12_1Eq

T0=TruthTabelGenrator(y12_0Eq)
T1=TruthTabelGenrator(y12_1Eq)
T10=pd.merge(T1, T0, how='left')
T10

y12_0EqN=lambdify([s, x], y12_0Eq.rhs, dummify=False)
y12_1EqN=lambdify([s, x], y12_1Eq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
print(SystmaticVals)
print(y12_0EqN(SystmaticVals[:, 0], SystmaticVals[:, 1]).astype(int))
print(y12_1EqN(SystmaticVals[:, 0], SystmaticVals[:, 1]).astype(int))

"""
Explanation: Demultiplexers
\begin{definition}\label{def:MUX}
A Demultiplexer, typically referred to as a DEMUX, is a Digital(or analog) switching unit that takes one input channel to be streamed to a single output channel from many via a control input. For single input DEMUXs with $2^n$ outputs, there are then $n$ input selection signals that make up the control word to select the output channel for the input.
Thus a DEMUX is the conjugate digital element to the MUX such that a MUX is an $N:1$ mapping device and a DEMUX is a $1:N$ mapping device.
From a behavioral standpoint DEMUXs are implemented with the same if-elif-else (case) control statements as a MUX but for each case, all outputs must be specified. 
Furthermore, DEMUXs are often implemented via stacked MUXs since there governing equation is the Product SET (Cartesian product) all internal products of a MUXs SOP equation 
\end{definition}
1 Channel Input: 2 Channel Output demultiplexer in Gate Level Logic
\begin{figure}
\centerline{\includegraphics{DEMUX12Gate.png}}
\caption{\label{fig:D12G} 1:2 DEMUX Symbol and Gate internals}
\end{figure}
Sympy Expression
End of explanation
"""


@block
def DEMUX1_2_Combo(x, s, y0, y1):
    """
    1:2 DEMUX written in full combo
    Inputs:
        x(bool): input feed
        s(bool): channel select
    Outputs:
        y0(bool): ouput channel 0
        y1(bool): ouput channel 1
    """
    
    @always_comb
    def logic():
        y0.next= not s and x
        y1.next= s and x
    
    return instances()

"""
Explanation: myHDL Module
End of explanation
"""


TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))

xTVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(15)
xTVs=np.append(xTVs, np.random.randint(0,2, TestLen)).astype(int)

sTVs=np.array([i[0] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(16)
sTVs=np.append(sTVs, np.random.randint(0,2, TestLen)).astype(int)

TestLen=len(xTVs)
SystmaticVals, sTVs, xTVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
s=Signal(bool(0)); Peeker(s, 's')
y0=Signal(bool(0)); Peeker(y0, 'y0')
y1=Signal(bool(0)); Peeker(y1, 'y1')

DUT=DEMUX1_2_Combo(x, s, y0, y1)

def DEMUX1_2_Combo_TB():
    """
    myHDL only testbench for module `DEMUX1_2_Combo`
    """
    
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTVs[i])
            s.next=int(sTVs[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, DEMUX1_2_Combo_TB(), *Peeker.instances()).run()    

Peeker.to_wavedrom('x', 's', 'y0','y1')

DEMUX1_2_ComboData=Peeker.to_dataframe()
DEMUX1_2_ComboData=DEMUX1_2_ComboData[['x', 's', 'y0','y1']]
DEMUX1_2_ComboData

DEMUX1_2_ComboData['y0Ref']=DEMUX1_2_ComboData.apply(lambda row:y12_0EqN(row['s'], row['x']), axis=1).astype(int)
DEMUX1_2_ComboData['y1Ref']=DEMUX1_2_ComboData.apply(lambda row:y12_1EqN(row['s'], row['x']), axis=1).astype(int)
DEMUX1_2_ComboData

Test0=(DEMUX1_2_ComboData['y0']==DEMUX1_2_ComboData['y0Ref']).all()
Test1=(DEMUX1_2_ComboData['y1']==DEMUX1_2_ComboData['y1Ref']).all()
Test=Test0&Test1
print(f'Module `DEMUX1_2_Combo` works as exspected: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_2_Combo');

"""
Explanation: Verilog Conversion
End of explanation
"""


#create BitVectors 
xTVs=intbv(int(''.join(xTVs.astype(str)), 2))[TestLen:]
sTVs=intbv(int(''.join(sTVs.astype(str)), 2))[TestLen:]

xTVs, bin(xTVs), sTVs, bin(sTVs)

@block
def DEMUX1_2_Combo_TBV():
    """
    myHDL -> testbench for module `DEMUX1_2_Combo`
    """

    x=Signal(bool(0))
    s=Signal(bool(0))
    y0=Signal(bool(0))
    y1=Signal(bool(0))
    
    @always_comb
    def print_data():
        print(x, s, y0, y1)
    
    #Test Signal Bit Vectors

    xTV=Signal(xTVs)
    sTV=Signal(sTVs)

    DUT=DEMUX1_2_Combo(x, s, y0, y1)

   
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTV[i])
            s.next=int(sTV[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

TB=DEMUX1_2_Combo_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('DEMUX1_2_Combo_TBV');         

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_Combo_RTL.png}}
\caption{\label{fig:D12CRTL} DEMUX1_2_Combo RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_Combo_SYN.png}}
\caption{\label{fig:D12CSYN} DEMUX1_2_Combo Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_Combo_IMP.png}}
\caption{\label{fig:D12CIMP} DEMUX1_2_Combo Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbech
End of explanation
"""


ConstraintXDCTextReader('DEMUX1_2');

"""
Explanation: PYNQ-Z1 Deployment
Board Circuit
\begin{figure}
\centerline{\includegraphics[width=5cm]{DEMUX12PYNQZ1Circ.png}}
\caption{\label{fig:D12Circ} 1:2 DEMUX PYNQ-Z1 (Non SoC) conceptualized circuit}
\end{figure}
Board Constraints
End of explanation
"""


x, s0, s1, y0, y1, y2, y3=symbols('x, s0, s1, y0, y1, y2, y3')
y14_0Eq=Eq(y0, ~s0&~s1&x)
y14_1Eq=Eq(y1, s0&~s1&x)
y14_2Eq=Eq(y2, ~s0&s1&x)
y14_3Eq=Eq(y3, s0&s1&x)
y14_0Eq, y14_1Eq, y14_2Eq, y14_3Eq

T0=TruthTabelGenrator(y14_0Eq)
T1=TruthTabelGenrator(y14_1Eq)
T2=TruthTabelGenrator(y14_2Eq)
T3=TruthTabelGenrator(y14_3Eq)
T10=pd.merge(T1, T0, how='left')
T20=pd.merge(T2, T10, how='left')
T30=pd.merge(T3, T20, how='left')
T30

y14_0EqN=lambdify([x, s0, s1], y14_0Eq.rhs, dummify=False)
y14_1EqN=lambdify([x, s0, s1], y14_1Eq.rhs, dummify=False)
y14_2EqN=lambdify([x, s0, s1], y14_2Eq.rhs, dummify=False)
y14_3EqN=lambdify([x, s0, s1], y14_3Eq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=3)))
print(SystmaticVals)
print(y14_0EqN(SystmaticVals[:, 2], SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int))
print(y14_1EqN(SystmaticVals[:, 2], SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int))
print(y14_2EqN(SystmaticVals[:, 2], SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int))
print(y14_3EqN(SystmaticVals[:, 2], SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int))

"""
Explanation: Video of Deployment
DEMUX1_2_Combo on PYNQ-Z1 (YouTube)
1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic
Sympy Expression
End of explanation
"""


@block
def DEMUX1_4_Combo(x, s0, s1, y0, y1, y2, y3):
    """
    1:4 DEMUX written in full combo

    Inputs:
        x(bool): input feed
        s0(bool): channel select 0
        s1(bool): channel select 1

    Outputs:
        y0(bool): ouput channel 0
        y1(bool): ouput channel 1
        y2(bool): ouput channel 2
        y3(bool): ouput channel 3
    """
    
    @always_comb
    def logic():
        y0.next= (not s0) and (not s1) and x
        y1.next= s0 and (not s1) and x
        y2.next= (not s0) and s1 and x
        y3.next= s0 and s1 and x

    return instances()

"""
Explanation: myHDL Module
End of explanation
"""


TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=3))

xTVs=np.array([i[2] for i in SystmaticVals]).astype(int)
np.random.seed(15)
xTVs=np.append(xTVs, np.random.randint(0,2, TestLen)).astype(int)

s0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(16)
s0TVs=np.append(s0TVs, np.random.randint(0,2, TestLen)).astype(int)

s1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(17)
s1TVs=np.append(s1TVs, np.random.randint(0,2, TestLen)).astype(int)

TestLen=len(xTVs)
SystmaticVals, xTVs, s0TVs, s1TVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
s0=Signal(bool(0)); Peeker(s0, 's0')
s1=Signal(bool(0)); Peeker(s1, 's1')
y0=Signal(bool(0)); Peeker(y0, 'y0')
y1=Signal(bool(0)); Peeker(y1, 'y1')
y2=Signal(bool(0)); Peeker(y2, 'y2')
y3=Signal(bool(0)); Peeker(y3, 'y3')


DUT=DEMUX1_4_Combo(x, s0, s1, y0, y1, y2, y3)

def DEMUX1_4_Combo_TB():
    """
    myHDL only testbench for module `DEMUX1_4_Combo`
    """
    
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTVs[i])
            s0.next=int(s0TVs[i])
            s1.next=int(s1TVs[i])


            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, DEMUX1_4_Combo_TB(), *Peeker.instances()).run()  

Peeker.to_wavedrom('x', 's1', 's0', 'y0', 'y1', 'y2', 'y3')

DEMUX1_4_ComboData=Peeker.to_dataframe()
DEMUX1_4_ComboData=DEMUX1_4_ComboData[['x', 's1', 's0', 'y0', 'y1', 'y2', 'y3']]
DEMUX1_4_ComboData

DEMUX1_4_ComboData['y0Ref']=DEMUX1_4_ComboData.apply(lambda row:y14_0EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_ComboData['y1Ref']=DEMUX1_4_ComboData.apply(lambda row:y14_1EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_ComboData['y2Ref']=DEMUX1_4_ComboData.apply(lambda row:y14_2EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_ComboData['y3Ref']=DEMUX1_4_ComboData.apply(lambda row:y14_3EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_ComboData

Test0=(DEMUX1_4_ComboData['y0']==DEMUX1_4_ComboData['y0Ref']).all()
Test1=(DEMUX1_4_ComboData['y1']==DEMUX1_4_ComboData['y1Ref']).all()
Test2=(DEMUX1_4_ComboData['y2']==DEMUX1_4_ComboData['y2Ref']).all()
Test3=(DEMUX1_4_ComboData['y3']==DEMUX1_4_ComboData['y3Ref']).all()
Test=Test0&Test1&Test2&Test3
print(f'Module `DEMUX1_4_Combo` works as exspected: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_4_Combo');

"""
Explanation: Verilog Conversion
End of explanation
"""


#create BitVectors 
xTVs=intbv(int(''.join(xTVs.astype(str)), 2))[TestLen:]
s0TVs=intbv(int(''.join(s0TVs.astype(str)), 2))[TestLen:]
s1TVs=intbv(int(''.join(s1TVs.astype(str)), 2))[TestLen:]


xTVs, bin(xTVs), s0TVs, bin(s0TVs), s1TVs, bin(s1TVs)

@block
def DEMUX1_4_Combo_TBV():
    """
    myHDL -> testbench for module `DEMUX1_4_Combo`
    """

    x=Signal(bool(0))
    s0=Signal(bool(0))
    s1=Signal(bool(0))
    y0=Signal(bool(0))
    y1=Signal(bool(0))
    y2=Signal(bool(0))
    y3=Signal(bool(0))
    
    @always_comb
    def print_data():
        print(x, s0, s1, y0, y1, y2, y3)
    
    #Test Signal Bit Vectors

    xTV=Signal(xTVs)
    s0TV=Signal(s0TVs)
    s1TV=Signal(s1TVs)

    DUT=DEMUX1_4_Combo(x, s0, s1, y0, y1, y2, y3)

   
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTV[i])
            s0.next=int(s0TV[i])
            s1.next=int(s1TV[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

TB=DEMUX1_4_Combo_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('DEMUX1_4_Combo_TBV');         

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_Combo_RTL.png}}
\caption{\label{fig:D14CRTL} DEMUX1_4_Combo RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_Combo_SYN.png}}
\caption{\label{fig:D14CSYN} DEMUX1_4_Combo Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_Combo_IMP.png}}
\caption{\label{fig:D14CIMP} DEMUX1_4_Combo Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbench
End of explanation
"""


ConstraintXDCTextReader('DEMUX1_4');

"""
Explanation: PYNQ-Z1 Deployment
Board Circuit
\begin{figure}
\centerline{\includegraphics[width=5cm]{DEMUX14PYNQZ1Circ.png}}
\caption{\label{fig:D14Circ} 1:4 DEMUX PYNQ-Z1 (Non SoC) conceptualized circuit}
\end{figure}
Board Constraints
End of explanation
"""


@block
def DEMUX1_4_DMS(x, s0, s1, y0, y1, y2, y3):
    """
    1:4 DEMUX via DEMUX Stacking
    Inputs:
        x(bool): input feed
        s0(bool): channel select 0
        s1(bool): channel select 1

    Outputs:
        y0(bool): ouput channel 0
        y1(bool): ouput channel 1
        y2(bool): ouput channel 2
        y3(bool): ouput channel 3
    """
    
    s0_y0y1_WIRE=Signal(bool(0))
    s0_y2y3_WIRE=Signal(bool(0))
    x_s1_DEMUX=DEMUX1_2_Combo(x, s1, s0_y0y1_WIRE, s0_y2y3_WIRE)
    
    s1_y0y1_DEMUX=DEMUX1_2_Combo(s0_y0y1_WIRE, s0, y0, y1)
    s1_y2y3_DEMUX=DEMUX1_2_Combo(s0_y2y3_WIRE, s0, y2, y3)

    return instances()

"""
Explanation: Video of Deployment
DEMUX1_4_Combo on PYNQ-Z1 (YouTube)
1 Channel Input:4 Channel Output demultiplexer via DEMUX Stacking
myHDL Module
End of explanation
"""


TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=3))

xTVs=np.array([i[2] for i in SystmaticVals]).astype(int)
np.random.seed(15)
xTVs=np.append(xTVs, np.random.randint(0,2, TestLen)).astype(int)

s0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(16)
s0TVs=np.append(s0TVs, np.random.randint(0,2, TestLen)).astype(int)

s1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(17)
s1TVs=np.append(s1TVs, np.random.randint(0,2, TestLen)).astype(int)

TestLen=len(xTVs)
SystmaticVals, xTVs, s0TVs, s1TVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
s0=Signal(bool(0)); Peeker(s0, 's0')
s1=Signal(bool(0)); Peeker(s1, 's1')
y0=Signal(bool(0)); Peeker(y0, 'y0')
y1=Signal(bool(0)); Peeker(y1, 'y1')
y2=Signal(bool(0)); Peeker(y2, 'y2')
y3=Signal(bool(0)); Peeker(y3, 'y3')


DUT=DEMUX1_4_DMS(x, s0, s1, y0, y1, y2, y3)

def DEMUX1_4_DMS_TB():
    """
    myHDL only testbench for module `DEMUX1_4_DMS`
    """
    
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTVs[i])
            s0.next=int(s0TVs[i])
            s1.next=int(s1TVs[i])


            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, DEMUX1_4_DMS_TB(), *Peeker.instances()).run()  

Peeker.to_wavedrom('x', 's1', 's0', 'y0', 'y1', 'y2', 'y3')

DEMUX1_4_DMSData=Peeker.to_dataframe()
DEMUX1_4_DMSData=DEMUX1_4_DMSData[['x', 's1', 's0', 'y0', 'y1', 'y2', 'y3']]
DEMUX1_4_DMSData

Test=DEMUX1_4_DMSData==DEMUX1_4_ComboData[['x', 's1', 's0', 'y0', 'y1', 'y2', 'y3']]
Test=Test.all().all()
print(f'DEMUX1_4_DMS equivlinet to DEMUX1_4_Combo: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_4_DMS');

"""
Explanation: Verilog Conversion
End of explanation
"""


#create BitVectors 
xTVs=intbv(int(''.join(xTVs.astype(str)), 2))[TestLen:]
s0TVs=intbv(int(''.join(s0TVs.astype(str)), 2))[TestLen:]
s1TVs=intbv(int(''.join(s1TVs.astype(str)), 2))[TestLen:]


xTVs, bin(xTVs), s0TVs, bin(s0TVs), s1TVs, bin(s1TVs)

@block
def DEMUX1_4_DMS_TBV():
    """
    myHDL -> testbench for module `DEMUX1_4_DMS`
    """

    x=Signal(bool(0))
    s0=Signal(bool(0))
    s1=Signal(bool(0))
    y0=Signal(bool(0))
    y1=Signal(bool(0))
    y2=Signal(bool(0))
    y3=Signal(bool(0))
    
    @always_comb
    def print_data():
        print(x, s0, s1, y0, y1, y2, y3)
    
    #Test Signal Bit Vectors

    xTV=Signal(xTVs)
    s0TV=Signal(s0TVs)
    s1TV=Signal(s1TVs)

    DUT=DEMUX1_4_DMS(x, s0, s1, y0, y1, y2, y3)

   
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTV[i])
            s0.next=int(s0TV[i])
            s1.next=int(s1TV[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

TB=DEMUX1_4_DMS_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('DEMUX1_4_DMS_TBV');         

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_DMS_RTL.png}}
\caption{\label{fig:D14DMSRTL} DEMUX1_4_DMS RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_DMS_SYN.png}}
\caption{\label{fig:D14DMSSYN} DEMUX1_4_DMS Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_DMS_IMP.png}}
\caption{\label{fig:D14DMSIMP} DEMUX1_4_DMS Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbench
End of explanation
"""


@block
def DEMUX1_2_B(x, s, y0, y1):
    """
    1:2 DMUX in behavioral
    Inputs:
        x(bool): input feed
        s(bool): channel select
    Outputs:
        y0(bool): ouput channel 0
        y1(bool): ouput channel 1
    """
    
    @always_comb
    def logic():
        if s==0:
            #take note that since we have 
            #two ouputs there next state values
            #must both be set, else the last
            #value will presist till it changes
            y0.next=x
            y1.next=0
        else:
            y0.next=0
            y1.next=x
    
    return instances()

"""
Explanation: PYNQ-Z1 Deployment
Board Circuit
See Board Circuit for "1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic"
Board Constraint
uses same 'DEMUX1_4.xdc' as "# 1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic"
Video of Deployment
DEMUX1_4_DMS on PYNQ-Z1 (YouTube)
1:2 DEMUX via Behavioral IF
myHDL Module
End of explanation
"""


TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))

xTVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(15)
xTVs=np.append(xTVs, np.random.randint(0,2, TestLen)).astype(int)

sTVs=np.array([i[0] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(16)
sTVs=np.append(sTVs, np.random.randint(0,2, TestLen)).astype(int)

TestLen=len(xTVs)
SystmaticVals, sTVs, xTVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
s=Signal(bool(0)); Peeker(s, 's')
y0=Signal(bool(0)); Peeker(y0, 'y0')
y1=Signal(bool(0)); Peeker(y1, 'y1')

DUT=DEMUX1_2_B(x, s, y0, y1)

def DEMUX1_2_B_TB():
    """
    myHDL only testbench for module `DEMUX1_2_B`
    """
    
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTVs[i])
            s.next=int(sTVs[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, DEMUX1_2_B_TB(), *Peeker.instances()).run()    

Peeker.to_wavedrom('x', 's', 'y0','y1')

DEMUX1_2_BData=Peeker.to_dataframe()
DEMUX1_2_BData=DEMUX1_2_BData[['x', 's', 'y0','y1']]
DEMUX1_2_BData

Test=DEMUX1_2_BData==DEMUX1_2_ComboData[['x', 's', 'y0','y1']]
Test=Test.all().all()
print(f'DEMUX1_2_BD is equivlent to DEMUX1_2_Combo: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_2_B');

"""
Explanation: Verilog Conversion
End of explanation
"""


#create BitVectors 
xTVs=intbv(int(''.join(xTVs.astype(str)), 2))[TestLen:]
sTVs=intbv(int(''.join(sTVs.astype(str)), 2))[TestLen:]

xTVs, bin(xTVs), sTVs, bin(sTVs)

@block
def DEMUX1_2_B_TBV():
    """
    myHDL -> testbench for module `DEMUX1_2_B`
    """

    x=Signal(bool(0))
    s=Signal(bool(0))
    y0=Signal(bool(0))
    y1=Signal(bool(0))
    
    @always_comb
    def print_data():
        print(x, s, y0, y1)
    
    #Test Signal Bit Vectors

    xTV=Signal(xTVs)
    sTV=Signal(sTVs)

    DUT=DEMUX1_2_B(x, s, y0, y1)

   
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTV[i])
            s.next=int(sTV[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

TB=DEMUX1_2_B_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('DEMUX1_2_B_TBV');         

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_B_RTL.png}}
\caption{\label{fig:D12BRTL} DEMUX1_2_B RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_B_SYN.png}}
\caption{\label{fig:D12BSYN} DEMUX1_2_B Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_2_B_IMP.png}}
\caption{\label{fig:D12BIMP} DEMUX1_2_B Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbench
End of explanation
"""


@block
def DEMUX1_4_B(x, s0, s1, y0, y1, y2, y3):
    """
    1:4 DEMUX written via behaviorial

    Inputs:
        x(bool): input feed
        s0(bool): channel select 0
        s1(bool): channel select 1

    Outputs:
        y0(bool): ouput channel 0
        y1(bool): ouput channel 1
        y2(bool): ouput channel 2
        y3(bool): ouput channel 3
    """
    
    @always_comb
    def logic():
        if s0==0 and s1==0:
            y0.next=x; y1.next=0
            y2.next=0; y3.next=0
            
        elif s0==1 and s1==0:
            y0.next=0; y1.next=x
            y2.next=0; y3.next=0
        
        elif s0==0 and s1==1:
            y0.next=0; y1.next=0
            y2.next=x; y3.next=0
            
        else:
            y0.next=0; y1.next=0
            y2.next=0; y3.next=x
    
    return instances()

"""
Explanation: PYNQ-Z1 Deployment
Board Circuit
See Board Circuit for "1 Channel Input: 2 Channel Output demultiplexer in Gate Level Logic"
Board Constraint
uses same 'DEMUX1_2.xdc' as "1 Channel Input: 2 Channel Output demultiplexer in Gate Level Logic"
Video of Deployment
DEMUX1_2_B on PYNQ-Z1 (YouTube)
1:4 DEMUX via Behavioral if-elif-else
myHDL Module
End of explanation
"""


TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=3))

xTVs=np.array([i[2] for i in SystmaticVals]).astype(int)
np.random.seed(15)
xTVs=np.append(xTVs, np.random.randint(0,2, TestLen)).astype(int)

s0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(16)
s0TVs=np.append(s0TVs, np.random.randint(0,2, TestLen)).astype(int)

s1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
#the random genrator must have a differint seed beween each generation
#call in order to produce differint values for each call
np.random.seed(17)
s1TVs=np.append(s1TVs, np.random.randint(0,2, TestLen)).astype(int)

TestLen=len(xTVs)
SystmaticVals, xTVs, s0TVs, s1TVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
s0=Signal(bool(0)); Peeker(s0, 's0')
s1=Signal(bool(0)); Peeker(s1, 's1')
y0=Signal(bool(0)); Peeker(y0, 'y0')
y1=Signal(bool(0)); Peeker(y1, 'y1')
y2=Signal(bool(0)); Peeker(y2, 'y2')
y3=Signal(bool(0)); Peeker(y3, 'y3')


DUT=DEMUX1_4_B(x, s0, s1, y0, y1, y2, y3)

def DEMUX1_4_B_TB():
    """
    myHDL only testbench for module `DEMUX1_4_Combo`
    """
    
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTVs[i])
            s0.next=int(s0TVs[i])
            s1.next=int(s1TVs[i])


            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

sim=Simulation(DUT, DEMUX1_4_B_TB(), *Peeker.instances()).run()  

Peeker.to_wavedrom('x', 's1', 's0', 'y0', 'y1', 'y2', 'y3')

DEMUX1_4_BData=Peeker.to_dataframe()
DEMUX1_4_BData=DEMUX1_4_BData[['x', 's1', 's0', 'y0', 'y1', 'y2', 'y3']]
DEMUX1_4_BData

Test=DEMUX1_4_BData==DEMUX1_4_ComboData[['x', 's1', 's0', 'y0', 'y1', 'y2', 'y3']]
Test=Test.all().all()
print(f'DEMUX1_4_B equivlinet to DEMUX1_4_Combo: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_4_B');

"""
Explanation: Verilog Conversion
End of explanation
"""


#create BitVectors 
xTVs=intbv(int(''.join(xTVs.astype(str)), 2))[TestLen:]
s0TVs=intbv(int(''.join(s0TVs.astype(str)), 2))[TestLen:]
s1TVs=intbv(int(''.join(s1TVs.astype(str)), 2))[TestLen:]


xTVs, bin(xTVs), s0TVs, bin(s0TVs), s1TVs, bin(s1TVs)

@block
def DEMUX1_4_B_TBV():
    """
    myHDL -> testbench for module `DEMUX1_4_B`
    """

    x=Signal(bool(0))
    s0=Signal(bool(0))
    s1=Signal(bool(0))
    y0=Signal(bool(0))
    y1=Signal(bool(0))
    y2=Signal(bool(0))
    y3=Signal(bool(0))
    
    @always_comb
    def print_data():
        print(x, s0, s1, y0, y1, y2, y3)
    
    #Test Signal Bit Vectors

    xTV=Signal(xTVs)
    s0TV=Signal(s0TVs)
    s1TV=Signal(s1TVs)

    DUT=DEMUX1_4_B(x, s0, s1, y0, y1, y2, y3)

   
    @instance
    def stimules():
        for i in range(TestLen):
            x.next=int(xTV[i])
            s0.next=int(s0TV[i])
            s1.next=int(s1TV[i])

            yield delay(1)
        
        raise StopSimulation()
        
    return instances()

TB=DEMUX1_4_B_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('DEMUX1_4_B_TBV');         

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_B_RTL.png}}
\caption{\label{fig:D14BRTL} DEMUX1_4_B RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_B_SYN.png}}
\caption{\label{fig:D14BSYN} DEMUX1_4_B Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_B_IMP.png}}
\caption{\label{fig:D14BIMP} DEMUX1_4_B Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbench
End of explanation
"""


@block
def DEMUX1_4_BV(x, S, Y):
    """
    1:4 DEMUX written via behaviorial with
    bit vectors

    Inputs:
        x(bool): input feed
        S(2bit vector): channel select bitvector;  
            min=0, max=3

    Outputs:
        Y(4bit vector): ouput channel bitvector;
            values min=0, max=15; allowed is: 0,1,2,4,8  
            in this application
        
    """
    
    @always_comb
    def logic():
        #here concat is used to build up the word
        #from the x input
        if S==0:
            Y.next=concat(intbv(0)[3:], x); '0001'
        elif S==1:
            Y.next=concat(intbv(0)[2:], x, intbv(0)[1:]); '0010'
        elif S==2:
            Y.next=concat(intbv(0)[1:], x, intbv(0)[2:]); '0100'
        else:
            Y.next=concat(x, intbv(0)[3:]); '1000'
    
    return instances()

"""
Explanation: PYNQ-Z1 Deployment
Board Circuit
See Board Circuit for "1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic"
Board Constraint
uses same 'DEMUX1_4.xdc' as "# 1 Channel Input:4 Channel Output demultiplexer in Gate Level Logic"
Video of Deployment
DEMUX1_4_B on PYNQ-Z1 (YouTube)
Demultiplexer 1:4 Behavioral via Bitvectors
myHDL Module
End of explanation
"""


xTVs=np.array([0,1])
xTVs=np.append(xTVs, np.random.randint(0,2,6)).astype(int)
TestLen=len(xTVs)

np.random.seed(12)
STVs=np.arange(0,4)
STVs=np.append(STVs, np.random.randint(0,4, 5))
TestLen, xTVs, STVs

Peeker.clear()
x=Signal(bool(0)); Peeker(x, 'x')
S=Signal(intbv(0)[2:]); Peeker(S, 'S')
Y=Signal(intbv(0)[4:]); Peeker(Y, 'Y')

DUT=DEMUX1_4_BV(x, S, Y)

def DEMUX1_4_BV_TB():
    
    @instance
    def stimules():
        for i in STVs:
            for j in xTVs:
                S.next=int(i)
                x.next=int(j)
                yield delay(1)
                
        raise StopSimulation()
    
    return instances()

sim=Simulation(DUT, DEMUX1_4_BV_TB(), *Peeker.instances()).run()

Peeker.to_wavedrom('x', 'S', 'Y', start_time=0, stop_time=2*TestLen+2)

DEMUX1_4_BVData=Peeker.to_dataframe()
DEMUX1_4_BVData=DEMUX1_4_BVData[['x', 'S', 'Y']]
DEMUX1_4_BVData

DEMUX1_4_BVData['y0']=None; DEMUX1_4_BVData['y1']=None; DEMUX1_4_BVData['y2']=None; DEMUX1_4_BVData['y3']=None
DEMUX1_4_BVData[['y3', 'y2', 'y1', 'y0']]=DEMUX1_4_BVData[['Y']].apply(lambda bv: [int(i) for i in bin(bv, 4)], axis=1, result_type='expand')

DEMUX1_4_BVData['s0']=None; DEMUX1_4_BVData['s1']=None
DEMUX1_4_BVData[['s1', 's0']]=DEMUX1_4_BVData[['S']].apply(lambda bv: [int(i) for i in bin(bv, 2)], axis=1, result_type='expand')

DEMUX1_4_BVData=DEMUX1_4_BVData[['x', 'S', 's0', 's1', 'Y', 'y3', 'y2', 'y1', 'y0']]
DEMUX1_4_BVData

DEMUX1_4_BVData['y0Ref']=DEMUX1_4_BVData.apply(lambda row:y14_0EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_BVData['y1Ref']=DEMUX1_4_BVData.apply(lambda row:y14_1EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_BVData['y2Ref']=DEMUX1_4_BVData.apply(lambda row:y14_2EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)
DEMUX1_4_BVData['y3Ref']=DEMUX1_4_BVData.apply(lambda row:y14_3EqN(row['x'], row['s0'], row['s1']), axis=1).astype(int)

DEMUX1_4_BVData

Test=DEMUX1_4_BVData[['y0', 'y1', 'y2', 'y3']].sort_index(inplace=True)==DEMUX1_4_BVData[['y0Ref', 'y1Ref', 'y2Ref', 'y3Ref']].sort_index(inplace=True)
print(f'Module `DEMUX1_4_BVData` works as exspected: {Test}')

"""
Explanation: myHDL Testing
End of explanation
"""


DUT.convert()
VerilogTextReader('DEMUX1_4_BV');

"""
Explanation: Verilog Conversion
End of explanation
"""


ConstraintXDCTextReader('DEMUX1_4_BV');

"""
Explanation: \begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_BV_RTL.png}}
\caption{\label{fig:D14BVRTL} DEMUX1_4_BV RTL schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_BV_SYN.png}}
\caption{\label{fig:D14BVSYN} DEMUX1_4_BV Synthesized Schematic; Xilinx Vivado 2017.4}
\end{figure}
\begin{figure}
\centerline{\includegraphics[width=10cm]{DEMUX1_4_BV_IMP.png}}
\caption{\label{fig:D14BVIMP} DEMUX1_4_BV Implementated Schematic; Xilinx Vivado 2017.4}
\end{figure}
myHDL to Verilog Testbench
(To Do!)
PYNQ-Z1 Board Deployment
Board Circuit
Board Constraints
End of explanation
"""


