\title{Logic Gate Primitives in myHDL} \author{Steven K Armour} \maketitle
In [1]:
#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
Out[1]:
In [2]:
#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
In [3]:
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
In [4]:
d = schem.Drawing(unit=.5)
d.add(e.VDD, label='High')
d.add(e.LINE, l=d.unit*2, d='down')
d.add(e.DOT_OPEN, botlabel='$1$')
d.draw()
In [5]:
Y=symbols('Y')
YEq=Eq(Y, 1); YEq
Out[5]:
In [6]:
#decorator to specify a myHDL module that can be converted
#to myHDL
@block
def WireHigh(Y):
"""
Wire to Constatnt High
Input:
None
Output:
Y(bool): output
"""
#create signal to High Source
HSource=Signal(bool(1))
#decorator for a compintorical senstvity
@always_comb
def logic():
#internal function to specfiy Out is set to High Source
Y.next=HSource
#return all internal functions
return instances()
In [7]:
#create output signal to bind to `WireHigh` Mod
Y=Signal(bool(0))
#Create instatnce of `WireHigh` and bind `Out` Signal to it
DUT=WireHigh(Y)
#Run convert on `DUT` instance of `WireHigh` to create Verilog/VHDL
DUT.convert()
#Read ouput `WireHigh.v` into notebook
VerilogTextReader('WireHigh');
In [8]:
d = schem.Drawing(unit=.5)
d.add(e.VDD, label='High')
d.add(e.LINE, l=d.unit*2, d='down')
d.add(e.DOT, rgtlabel='$1$')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.LED, rgtlabel='LD0', d='down')
#LED to ground
d.add(e.LINE, d='down', l=d.unit*1.5)
d.add(e.GND)
d.draw()
In [9]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_WireHigh');
LED 0 (the furthest Right one above the buttons) will light up green
In most modern digital circuits this Lowest reference voltage will be digital ground.
In [10]:
d = schem.Drawing(unit=.5)
d.add(e.DOT_OPEN, label='$0$')
d.add(e.LINE, l=d.unit*2, d='down')
d.add(e.GND)
d.draw()
In [11]:
Y=Symbol('Y')
YEq=Eq(Y, 0); YEq
Out[11]:
In [12]:
#decorator to specify a myHDL module that can be converted
#to myHDL
@block
def WireLow(Y):
"""
Wire to Constatnt Low
Input:
None
Output:
Y(bool): output
"""
#create signal to Low Source
LSource=Signal(bool(0))
#decorator for a compintorical senstvity
@always_comb
def logic():
#internal function to specfiy Out is set to Low Source
Y.next=LSource
#return all internal functions
return instances()
In [13]:
#create output signal to bind to `WireHigh` Mod
Y=Signal(bool(0))
#Create instatnce of `WireHigh` and bind `Out` Signal to it
DUT=WireLow(Y)
#Run convert on `DUT` instance of `WireHigh` to create Verilog/VHDL
DUT.convert()
#Read ouput `WireHigh.v` into notebook
VerilogTextReader('WireLow');
In [14]:
d = schem.Drawing(unit=.5)
LD0=d.add(e.LED, d='right', label='LD0')
d.add(e.LINE, l=d.unit*2, d='left', xy=LD0.start)
d.add(e.LINE, l=d.unit*2, d='down')
d.add(e.GND)
d.add(e.LINE, l=d.unit*2, d='right', xy=LD0.end)
d.add(e.LINE, l=d.unit*2, d='down')
d.add(e.GND)
d.draw()
In [15]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_WireLow');
Nothing will happen since the Low Signal on the PYNQ-Z1 is ground so LED 0 will remain off
From a Boolean algebra/software perspective this may be a do-nothing gate but from a hardware perspective, it is incredibly valuable as it isolates the incoming signal circuit from any inline feedback on the outgoing signal's circuit. And is also typically used in circuit design as a way of ensuring the output of a system will be at the right voltage levels of the technology so that the next set of gates will register the input to them correctly
In [16]:
d = schem.Drawing(unit=.5)
d.add(e.DOT_OPEN, l=d.unit*3, lftlabel='$X$')
d.add(l.BUF, label='$Buffer$')
d.add(e.DOT_OPEN, l=d.unit*2, rgtlabel='$Y$')
d.draw()
In [17]:
X, Y=symbols('X, Y')
YEq=Eq(Y, X); YEq
Out[17]:
In [18]:
TruthTabelGenrator(YEq)
Out[18]:
In [19]:
#convert the Sympy exspresion to a
#numpy exspresion via lambdify
YEqN=lambdify(X, YEq.rhs, dummify=False)
YEqN(np.array([0, 1]))
Out[19]:
In [20]:
@block
def BufferGate(X, Y):
"""
Buffer Gate demo module
Input:
X(bool): Input conection to wire between `X` and `Y`
Ouput:
Y(bool): Output connection to wire between 'X' and 'Y'
"""
@always_comb
def logic():
Y.next=X
return instances()
Every module (WireHigh
and WireLow
are just too primitive to test) should be tested with a Testbench in python. This test does not confirm that the module meets the requirements of synthesization in Verilog/VHDL but confirms that the behavior of the myHDL module under test (DUT) behavior wise conforms to the desired behavior.
Because of the data analysis ability of python to full analysis the test output in the same framework that the test, let alone module, was written in development time is decreased. This is one of the defining abilities of myHDL over other HDLs such as Verilog/VHDL
Synthesization in the world of HDL refers to the ability to turn HDL code into Hardware via an FPGA or a dedicated circuit (typically called an ASIC). It is for that reason that HDL codeing is not pure software nor pure hardware but rather a hybrid of the two. And why HDL coding has high constraints then all other coding seeing as the HDL must meet Behavior and Timing of software but must also meet the hardware synthesis requirements of Power, Physical Size, Implantability, and more
In [21]:
#generate random test values for BufferGate_TB
#stimules input In
TestLen=10
#for testing purpose the random genrator need to be seeded
#to create reproducable values
np.random.seed(12)
XTVs=np.random.randint(0,2, TestLen).astype(int)
XTVs
Out[21]:
In [22]:
#clear any previouse stored values in Peeker
Peeker.clear()
#Create the Signals to the BufferGate and
#add them to Peeker for display and anylis
X=Signal(bool(0)); Peeker(X, 'X')
Y=Signal(bool(0)); Peeker(Y, 'Y')
#create instance of `BufferGate` and bind signals
#to it as the "Device Under Testing"
DUT=BufferGate(X, Y)
#Create a Testbench for `BufferGate`
def BufferGate_TB():
"""
myHDL only testbench for module `BufferGate`
"""
#internal function that will apply
#stimules to DUT
@instance
def stimules():
for i in range(TestLen):
#asign next stimules value to X input of DUT
#for every 1 interval delay
X.next=int(XTVs[i])
yield delay(1)
#flag to end the simulation of the DUT after all
#stimules have been run
raise StopSimulation()
#return all internal stimules
return instances()
#bind the DUT, Testbench and Peeker to simulator and run it
sim=Simulation(DUT, BufferGate_TB(), *Peeker.instances()).run()
In [23]:
#View Waveform diagram from Simulation with
#wavefroms in the order of `X` then `Y`
Peeker.to_wavedrom('X', 'Y')
In [24]:
#Capture the Waveform as a Pandas Dataframe for
#detiled anylsis
WireData=Peeker.to_dataframe()
#order the cols in the dataframe `X` then `Y`
WireData=WireData[['X', 'Y']]
WireData
Out[24]:
In [25]:
#apply the lampdfid sympy expspresion for a buffer to the X input to
#get a refrance to compare the BufferGate modules
WireData['YRef']=WireData['X'].apply(YEqN)
WireData
Out[25]:
In [26]:
#Test wither the modules ouput matchs the sympy refrance
Test=(WireData['Y']==WireData['YRef']).all()
print(f'Module `BufferGate` works as exspected: {Test}')
In [27]:
DUT.convert()
VerilogTextReader('BufferGate');
In [28]:
#create BitVector for BufferGate_TBV
XTVs=intbv(int(''.join(XTVs.astype(str)), 2))[TestLen:]
XTVs, bin(XTVs)
Out[28]:
In [29]:
#Convertable testbenchs must be treated as a module
@block
def BufferGate_TBV():
"""
myHDL -> Verilog testbench for module `BufferGate`
"""
#create the signals to bind to the DUT
X=Signal(bool(0))
Y=Signal(bool(0))
#print out the waveform of `X` and `Y`
@always_comb
def print_data():
print(X, Y)
#create a register to hold the testdata vector
#Test Signal Bit Vector
XTV=Signal(XTVs)
#create an instance of the `BufferGate` and
#bind X and Y to it
DUT=BufferGate(X, Y)
#create the stimules action
@instance
def stimules():
for i in range(TestLen):
#asign X the next bit from XTV testvector reg
X.next=XTV[i]
#delay one of the smallest time intervals
yield delay(1)
#raise the stop simulation flag
raise StopSimulation()
#return all internals of the Testbench
return instances()
#create instance of the Testbench
TB=BufferGate_TBV()
#run the conversion to Verilog and insure that
#all Signal values are at there default value
TB.convert(hdl="Verilog", initial_values=True)
#read back the testbench into python
VerilogTextReader('BufferGate_TBV');
In [30]:
d=schem.Drawing(unit=.5)
#add switch
SW0=d.add(e.SWITCH_SPDT2, reverse=True, label='SW0')
#connect to buffer
d.add(e.LINE, d='right', xy=SW0.a, l=d.unit*2, label='X')
d.add(e.DOT)
B0=d.add(l.BUF, label='BUF')
#buffer to LED
d.add(e.DOT)
d.add(e.LINE, d='right', l=d.unit*2, label='Y')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.LED, rgtlabel='LD0', d='down')
#LED to ground
d.add(e.LINE, d='down', l=d.unit*1.5)
d.add(e.GND)
#swtich bottom to ground
d.add(e.LINE, d='down', xy=SW0.c, l=d.unit*4)
d.add(e.GND)
#switch top to rail
d.add(e.LINE, d='up', xy=SW0.b, l=d.unit*2.3)
d.add(e.VDD)
d.draw()
In [31]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_BufferGate');
BUFFER Gate myHDL PYNQ-Z1 (YouTube)
In [32]:
d = schem.Drawing(unit=.5)
d.add(e.DOT_OPEN, l=d.unit*3, lftlabel='$X$')
d.add(l.NOT, label='$NOT$')
d.add(e.LINE)
d.add(e.DOT_OPEN, rgtlabel='$Y$')
d.draw()
In [33]:
X, Y=symbols('X, Y')
YEq=Eq(Y, ~X); YEq
Out[33]:
In [34]:
TruthTabelGenrator(YEq)
Out[34]:
In [35]:
YEqN=lambdify(X, YEq.rhs, dummify=False)
YEqN(0), YEqN(1)
Out[35]:
In [36]:
@block
def NotGate(X, Y):
"""
NOT gate exsample module
Input:
X(bool): input
Output:
Y(bool): ouput
"""
@always_comb
def logic():
Y.next=not X
return instances()
In [37]:
#generate random test values for NotGate_TB
#stimules input In
TestLen=10
np.random.seed(14)
XTVs=np.random.randint(0,2, TestLen).astype(int)
XTVs
Out[37]:
In [38]:
Peeker.clear()
X=Signal(bool(0)); Peeker(X, 'X')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=NotGate(X, Y)
def NotGate_TB():
"""
myHDL only testbench for module `NotGate`
"""
@instance
def stimules():
for i in range(TestLen):
X.next=int(XTVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, NotGate_TB(), *Peeker.instances()).run()
In [39]:
Peeker.to_wavedrom()
In [40]:
NotData=Peeker.to_dataframe()
NotData
Out[40]:
In [41]:
NotData['YRef']=NotData['X'].apply(YEqN).astype(int)
NotData
Out[41]:
In [42]:
Test=(NotData['Y']==NotData['YRef']).all()
print(f'Module `NotGate` works as exspected: {Test}')
In [43]:
DUT.convert()
VerilogTextReader('NotGate');
In [44]:
#create BitVector for NotGate_TBV
XTVs=intbv(int(''.join(XTVs.astype(str)), 2))[TestLen:]
XTVs, bin(XTVs)
Out[44]:
In [45]:
@block
def NotGate_TBV():
"""
myHDL -> Verilog testbench for module `NotGate`
"""
X=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X, Y)
#Test Signal Bit Vector
XTV=Signal(XTVs)
DUT=NotGate(X, Y)
@instance
def stimules():
for i in range(TestLen):
X.next=XTV[i]
yield delay(1)
raise StopSimulation()
return instances()
TB=NotGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('NotGate_TBV');
In [46]:
d=schem.Drawing(unit=.5)
#add switch
SW0=d.add(e.SWITCH_SPDT2, reverse=True, label='SW0')
#connect to buffer
d.add(e.LINE, d='right', xy=SW0.a, l=d.unit*2, label='X')
d.add(e.DOT)
N0=d.add(l.NOT, label='NOT')
#buffer to LED
d.add(e.DOT)
d.add(e.LINE, d='right', l=d.unit*2, label='Y')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.LED, rgtlabel='LD0', d='down')
#LED to ground
d.add(e.LINE, d='down', l=d.unit*1.5)
d.add(e.GND)
#swtich bottom to ground
d.add(e.LINE, d='down', xy=SW0.c, l=d.unit*4)
d.add(e.GND)
#switch top to rail
d.add(e.LINE, d='up', xy=SW0.b, l=d.unit*2.3)
d.add(e.VDD)
d.draw()
In [47]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_NotGate');
NOT Gate myHDL PYNQ-Z1 (YouTube)
In [48]:
d = schem.Drawing(unit=.5)
G = d.add(l.AND2, label='$AND_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [49]:
X0, X1, Y=symbols('X_0, X_1, Y')
YEq=Eq(Y, X0&X1); YEq
Out[49]:
In [50]:
TruthTabelGenrator(YEq)
Out[50]:
In [51]:
YEqN=lambdify([X0, X1], YEq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[51]:
In [52]:
@block
def AndGate(X0, X1, Y):
"""
And Gate demo module
Input:
X0(bool): And gate input 0
X1(bool): And gate input 1
Output:
Y(bool): And gate ouput
"""
@always_comb
def logic():
#note here that `and` is used since this
#is a bit wise AND
Y.next=X0 and X1
#if `&` had been used the conversion
#would yield `&` the .all() AND
# when dealing with bus's and behavior mux's this
#distiction must be known
#see:
# https://stackoverflow.com/questions/17327680/what-is-the-difference-between-single-and-double-ampersand-binary-opera
return instances()
In [53]:
#generate systmatic and random test values for AndGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(15)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=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)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[53]:
In [54]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=AndGate(X0, X1, Y)
def AndGate_TB():
"""
myHDL only testbench for module `AndGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, AndGate_TB(), *Peeker.instances()).run()
In [55]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [56]:
AndData=Peeker.to_dataframe()
AndData=AndData[['X1', 'X0', 'Y']]
AndData
Out[56]:
In [57]:
AndData['YRef']=AndData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
AndData
Out[57]:
In [58]:
Test=(AndData['Y']==AndData['YRef']).all()
print(f'Module `AndGate` works as exspected: {Test}')
In [59]:
DUT.convert()
VerilogTextReader('AndGate');
In [60]:
#create BitVectora for AndGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[60]:
In [61]:
@block
def AndGate_TBV():
"""
myHDL -> Verilog testbench for module `AndGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=AndGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=AndGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('AndGate_TBV');
In [62]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.AND2,d='right', label='$AND_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [63]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_AndGate');
AND Gate myHDL PYNQ-Z1 (YouTube)
In [64]:
d = schem.Drawing(unit=.5)
G = d.add(l.AND2, label='$OR_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [65]:
X0, X1, Y=symbols('X_0, X_1, Y')
YEq=Eq(Y, X0|X1); YEq
Out[65]:
In [66]:
TruthTabelGenrator(YEq)
Out[66]:
In [67]:
YEqN=lambdify([X0, X1], YEq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[67]:
In [68]:
@block
def OrGate(X0, X1, Y):
"""
Or Gate demo module
Input:
X0(bool): Or gate input 0
X1(bool): Or gate input 1
Output:
Y(bool): Or gate ouput
"""
@always_comb
def logic():
#note here that `or` is used since this
#is a bit wise OR
Y.next=X0 or X1
#if `|` had been used the conversion
#would yield `||` the .all() OR
# when dealing with bus's and behavior mux's this
#distiction must be known
#see:
# https://stackoverflow.com/questions/17327680/what-is-the-difference-between-single-and-double-ampersand-binary-opera
return instances()
In [69]:
#generate systmatic and random test values for OrGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(17)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
np.random.seed(18)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[69]:
In [70]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=OrGate(X0, X1, Y)
def OrGate_TB():
"""
myHDL only testbench for module `OrGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, OrGate_TB(), *Peeker.instances()).run()
In [71]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [72]:
OrData=Peeker.to_dataframe()
OrData=OrData[['X1', 'X0', 'Y']]
OrData
Out[72]:
In [73]:
OrData['YRef']=OrData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
OrData
Out[73]:
In [74]:
Test=(OrData['Y']==OrData['YRef']).all()
print(f'Module `OrGate` works as exspected: {Test}')
In [75]:
DUT.convert()
VerilogTextReader('OrGate');
In [76]:
#create BitVectora for OrGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[76]:
In [77]:
@block
def OrGate_TBV():
"""
myHDL -> Verilog testbench for module `OrGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=OrGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=OrGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('OrGate_TBV');
In [78]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.OR2,d='right', label='$OR_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [79]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_OrGate');
OR Gate myHDL PYNQ-Z1 (YouTube)
In [80]:
d = schem.Drawing(unit=.5)
G = d.add(l.XOR2, label='$XOR_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [81]:
X0, X1, Y=symbols('X_0, X_1, Y')
YEq=Eq(Y, X0^X1); YEq
Out[81]:
In [82]:
TruthTabelGenrator(YEq)
Out[82]:
In [83]:
#lampdfy must have maping manuly set from `Xor` to `np.bitwise_xor`
YEqN=lambdify([X0, X1], YEq.rhs, {'Xor':np.bitwise_xor}, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[83]:
In [84]:
@block
def XorGate(X0, X1, Y):
"""
XOR Gate demo module
Input:
X0(bool): XOR gate input 0
X1(bool): XOR gate input 1
Output:
Y(bool): XOR gate ouput
"""
@always_comb
def logic():
Y.next=X0 ^ X1
return instances()
In [85]:
#generate systmatic and random test values for XorGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(19)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
np.random.seed(20)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[85]:
In [86]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=XorGate(X0, X1, Y)
def XorGate_TB():
"""
myHDL only testbench for module `XorGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, XorGate_TB(), *Peeker.instances()).run()
In [87]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [88]:
XorData=Peeker.to_dataframe()
XorData=XorData[['X1', 'X0', 'Y']]
XorData
Out[88]:
In [89]:
XorData['YRef']=XorData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
XorData
Out[89]:
In [90]:
Test=(XorData['Y']==XorData['YRef']).all()
print(f'Module `XorGate` works as exspected: {Test}')
In [91]:
DUT.convert()
VerilogTextReader('XorGate');
In [92]:
#create BitVectora for XorGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[92]:
In [93]:
@block
def XorGate_TBV():
"""
myHDL -> Verilog testbench for module `XorGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=XorGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=XorGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('XorGate_TBV');
In [94]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.XOR2,d='right', label='$XOR_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [95]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_XorGate');
XOR Gate myHDL PYNQ-Z1 (YouTube)
One peculiar aspect of the NAND Gate is that from a pure Boolean algebra position it is one of the two "Universal Gates". Which means that any other gate can be constructed from no more than NAND Gates. See https://en.wikipedia.org/wiki/NAND_logic#Making_other_gates_by_using_NAND_gates for more info. And while this somewhat holds True for ASIC circuits, this not entirely true in terms of FPGAs
In [96]:
d = schem.Drawing(unit=.5)
G = d.add(l.NAND2, label='$NAND_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [97]:
X0, X1, Y=symbols('X_0, X_1, Y')
YEq=Eq(Y, Nand(X0,X1)); YEq
Out[97]:
In [98]:
TruthTabelGenrator(YEq)
Out[98]:
In [99]:
YEqN=lambdify([X0, X1], YEq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[99]:
In [100]:
@block
def NAndGate(X0, X1, Y):
"""
NAND Gate demo module
Input:
X0(bool): NAnd gate input 0
X1(bool): NAnd gate input 1
Output:
Y(bool): NAnd gate ouput
"""
@always_comb
def logic():
#note here that `and` is used since this
#is a bit wise AND
Y.next=not(X0 and X1)
#if `&` had been used the conversion
#would yield `&` the .all() AND
# when dealing with bus's and behavior mux's this
#distiction must be known
#see:
# https://stackoverflow.com/questions/17327680/what-is-the-difference-between-single-and-double-ampersand-binary-opera
return instances()
In [101]:
#generate systmatic and random test values for AndGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(21)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
np.random.seed(23)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[101]:
In [102]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=NAndGate(X0, X1, Y)
def NAndGate_TB():
"""
myHDL only testbench for module `NAndGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, NAndGate_TB(), *Peeker.instances()).run()
In [103]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [104]:
NAndData=Peeker.to_dataframe()
NAndData=NAndData[['X1', 'X0', 'Y']]
NAndData
Out[104]:
In [105]:
NAndData['YRef']=NAndData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
NAndData
Out[105]:
In [106]:
Test=(NAndData['Y']==NAndData['YRef']).all()
print(f'Module `NAndGate` works as exspected: {Test}')
In [107]:
DUT.convert()
VerilogTextReader('NAndGate');
In [108]:
#create BitVectora for NAndGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[108]:
In [109]:
@block
def NAndGate_TBV():
"""
myHDL -> Verilog testbench for module `NAndGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=NAndGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=NAndGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('NAndGate_TBV');
In [110]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.NAND2,d='right', label='$NAND_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [111]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_NAndGate');
NAND Gate myHDL PYNQ-Z1 (YouTube)
One peculiar aspect of the NOR Gate is that from a pure Boolean algebra position it is one of the two "Universal Gates". Which means that any other gate can be constructed from no more than NOR Gates. See https://en.wikipedia.org/wiki/NOR_logic#Making_other_gates_by_using_NOR_gates for more info. And while this somewhat holds True for ASIC circuits, this not entirely true in terms of FPGAs
In [112]:
d = schem.Drawing(unit=.5)
G = d.add(l.NOR2, label='$NOR_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [113]:
X0, X1, Y=symbols('X_0, X_1, Y')
YEq=Eq(Y, Nor(X0,X1)); YEq
Out[113]:
In [114]:
TruthTabelGenrator(YEq)
Out[114]:
In [115]:
YEqN=lambdify([X0, X1], YEq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[115]:
In [116]:
@block
def NOrGate(X0, X1, Y):
"""
NOr Gate demo module
Input:
X0(bool): Or gate input 0
X1(bool): Or gate input 1
Output:
Y(bool): Or gate ouput
"""
@always_comb
def logic():
#note here that `or` is used since this
#is a bit wise OR
Y.next=not(X0 or X1)
#if `|` had been used the conversion
#would yield `||` the .all() OR
# when dealing with bus's and behavior mux's this
#distiction must be known
#see:
# https://stackoverflow.com/questions/17327680/what-is-the-difference-between-single-and-double-ampersand-binary-opera
return instances()
In [117]:
#generate systmatic and random test values for NOrGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(24)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
np.random.seed(25)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[117]:
In [118]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=NOrGate(X0, X1, Y)
def NOrGate_TB():
"""
myHDL only testbench for module `NOrGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, NOrGate_TB(), *Peeker.instances()).run()
In [119]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [120]:
NOrData=Peeker.to_dataframe()
NOrData=NOrData[['X1', 'X0', 'Y']]
NOrData
Out[120]:
In [121]:
NOrData['YRef']=NOrData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
NOrData
Out[121]:
In [122]:
Test=(NOrData['Y']==NOrData['YRef']).all()
print(f'Module `NOrGate` works as exspected: {Test}')
In [123]:
DUT.convert()
VerilogTextReader('NOrGate');
In [124]:
#create BitVectora for NOrGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[124]:
In [125]:
@block
def NOrGate_TBV():
"""
myHDL -> Verilog testbench for module `NOrGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=NOrGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=NOrGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('NOrGate_TBV');
In [126]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.NOR2,d='right', label='$NOR_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [127]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_NOrGate');
AND Gate myHDL PYNQ-Z1 (YouTube)
In [128]:
d = schem.Drawing(unit=.5)
G = d.add(l.XNOR2, label='$XNOR_2$')
d.add(e.DOT_OPEN, xy=G.out, rgtlabel='$Y$')
d.add(e.DOT_OPEN, xy=G.in1, lftlabel='$X_1$')
d.add(e.DOT_OPEN, xy=G.in2, lftlabel='$X_0$')
d.draw()
In [129]:
X0, X1, Y=symbols('X_0, X_1, Y')
#expanded exspresion of XNOR
YEq=Eq(Y, X0&X1|~X0&~X1); YEq
Out[129]:
In [130]:
TruthTabelGenrator(YEq)
Out[130]:
In [131]:
YEqN=lambdify([X0, X1], YEq.rhs, dummify=False)
SystmaticVals=np.array(list(itertools.product([0,1], repeat=2)))
SystmaticVals, YEqN(SystmaticVals[:, 1], SystmaticVals[:, 0]).astype(int)
Out[131]:
In [132]:
@block
def XNOrGate(X0, X1, Y):
"""
XNOR Gate demo module
Input:
X0(bool): XOR gate input 0
X1(bool): XOR gate input 1
Output:
Y(bool): XOR gate ouput
"""
@always_comb
def logic():
Y.next=not(X0 ^ X1)
return instances()
In [133]:
#generate systmatic and random test values for XNOrGate_TB
#stimules inputs X1 and X2
TestLen=10
SystmaticVals=list(itertools.product([0,1], repeat=2))
X0TVs=np.array([i[1] for i in SystmaticVals]).astype(int)
np.random.seed(26)
X0TVs=np.append(X0TVs, np.random.randint(0,2, TestLen)).astype(int)
X1TVs=np.array([i[0] for i in SystmaticVals]).astype(int)
np.random.seed(27)
X1TVs=np.append(X1TVs, np.random.randint(0,2, TestLen)).astype(int)
TestLen=len(X1TVs)
SystmaticVals, X1TVs, X0TVs, TestLen
Out[133]:
In [134]:
Peeker.clear()
X0=Signal(bool(0)); Peeker(X0, 'X0')
X1=Signal(bool(0)); Peeker(X1, 'X1')
Y=Signal(bool(0)); Peeker(Y, 'Y')
DUT=XNOrGate(X0, X1, Y)
def XNOrGate_TB():
"""
myHDL only testbench for module `NOrGate`
"""
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TVs[i])
X1.next=int(X1TVs[i])
yield delay(1)
raise StopSimulation()
return instances()
sim=Simulation(DUT, XNOrGate_TB(), *Peeker.instances()).run()
In [135]:
Peeker.to_wavedrom('X1', 'X0', 'Y')
In [136]:
XNOrData=Peeker.to_dataframe()
XNOrData=XNOrData[['X1', 'X0', 'Y']]
XNOrData
Out[136]:
In [137]:
XNOrData['YRef']=XNOrData.apply(lambda row:YEqN(row['X0'], row['X1']), axis=1).astype(int)
XNOrData
Out[137]:
In [138]:
Test=(XNOrData['Y']==XNOrData['YRef']).all()
print(f'Module `XNOrGate` works as exspected: {Test}')
In [139]:
DUT.convert()
VerilogTextReader('XNOrGate');
In [140]:
#create BitVectora for XNOrGate_TBV
X0TVs=intbv(int(''.join(X0TVs.astype(str)), 2))[TestLen:]
X1TVs=intbv(int(''.join(X1TVs.astype(str)), 2))[TestLen:]
X0TVs, bin(X0TVs), X1TVs, bin(X1TVs)
Out[140]:
In [141]:
@block
def XNOrGate_TBV():
"""
myHDL -> Verilog testbench for module `NOrGate`
"""
X0=Signal(bool(0))
X1=Signal(bool(0))
Y=Signal(bool(0))
@always_comb
def print_data():
print(X0, X1, Y)
#Test Signal Bit Vectors
X0TV=Signal(X0TVs)
X1TV=Signal(X1TVs)
DUT=XNOrGate(X0, X1, Y)
@instance
def stimules():
for i in range(TestLen):
X0.next=int(X0TV[i])
X1.next=int(X1TV[i])
yield delay(1)
raise StopSimulation()
return instances()
TB=XNOrGate_TBV()
TB.convert(hdl="Verilog", initial_values=True)
VerilogTextReader('XNOrGate_TBV');
In [142]:
d=schem.Drawing(unit=.5)
#add elements
G=d.add(l.XNOR2,d='right', label='$XNOR_2$')
#Gate to led to gnd
d.add(e.LINE, d='right', xy=G.out)
d.add(e.DOT, label='$Y$')
d.add(e.LINE, d='down', l=d.unit*2)
LD0=d.add(e.LED, d='down', label='LD0')
d.add(e.LINE, d='down', l=d.unit*2)
d.add(e.GND)
d.add(e.LINE, d='left', xy=G.in1, l=d.unit)
d.add(e.DOT, label='$X_0$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='up', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*2)
SW0=d.add(e.SWITCH_SPDT, lftlabel='SW0')
d.add(e.GND, xy=SW0.c)
d.add(e.VDD, xy=SW0.b)
d.add(e.LINE, d='left', xy=G.in2, l=d.unit)
d.add(e.DOT, botlabel='$X_1$')
d.add(e.LINE,d='left', l=d.unit)
d.add(e.LINE,d='down', l=d.unit*2)
d.add(e.LINE,d='left', l=d.unit*4)
SW1=d.add(e.SWITCH_SPDT, lftlabel='SW1')
d.add(e.GND, xy=SW1.c)
d.add(e.VDD, xy=SW1.b)
d.draw()
In [143]:
ConstraintXDCTextReader('PYNQ_Z1Constraints_XNOrGate');
AND Gate myHDL PYNQ-Z1 (YouTube)
In [ ]: