[myhdl-list] my myHDL Unit test framework so far. please critique
Brought to you by:
jandecaluwe
|
From: George P. <ge...@ga...> - 2005-12-16 14:25:23
|
Tom Dillon wrote:
>
> It can't be stressed enough that the proper flow for logic design with
> MyHDL is the following:
>
> 1. MyHDL logic unittest, used here and in steps 2 and 4.
> 2. Apply unittest to toVerilog logic via cosimulation.
> 3. toVerilog logic synthesis with your favorite synthesis tool.
> 4. post synthesis unittest.
>
> If logic changes are required after step 4, all steps should be
> repeated. Note, these can all be automated from the MyHDL unittest.
>
How do you automate it so the same file performs steps 1 and 2 in the
same run? Currently I have a unit test file that takes command-line
arguments. If I run "python module_ut.py -v" it does a myHDL-only
unittest. If I add the -cosim option, as in "python module_ut.py -v
-cosim" then it does a unit test w/cosimulation. So I need two seperate
runs w/different arguments. I use a Makefile to have it automatically
run steps 1 and 2 in sequence (as well as step #3). I'm interested in
eliminating the need for a pesky Makefile :)
Also, please critique the way I'm approaching unit tests currently. I've
pasted all three of my test files below. I broke my unit test late last
night, trying to consolidate the dut and the signals as class objects
instead of per-test-case objects, and I decided to paste it as-is.
I am in the process of making the bp2ram_ut.py and bp2ram_cosium.py
generic so they can be used with any module. That means specifying the
component name once somewhere and using some kind of macro
substitution. However, I'm not sure how to do "macro substitution" with
python. I'd like to be able to do something like what's seen in Makefiles:
# generic_ut.py - not legal python - can something similar to this be done?
COMPONENT = bp2ram
from $(COMPONENT) import $(COMPONENT)
import $(COMPONENT)_cosim
$(COMPONENT) = $(COMPONENT)_cosim.$(COMPONENT)
I would really appreciate any feeback, since I am new to python (and
myHDL). Don't hold back :)
Thanks,
George
/// Makefile pasted below ////////
# George Pantazopoulos
# python/myHDL + co-simulation Makefile
# 15 Dec 2005
MODULE = bp2ram
all: ut ut_cosim synth
ut: $(MODULE).py $(MODULE)_ut.py
python $(MODULE)_ut.py -v
ut_cosim: $(MODULE).py $(MODULE)_ut.py $(MODULE)_cosim.py
python $(MODULE)_ut.py -v -cosim
synth: $(MODULE).py $(MODULE)_synthesis_test.py
python $(MODULE)_synthesis_test.py -v
clean:
rm -f *.v
//// End paste ////////////////////////////
//// Excerpt of bp2ram_ut.py pasted below ///
# George Pantazopoulos
import os
import sys
import unittest
from myhdl import Signal, intbv, Simulation, StopSimulation, delay
from bp2ram import bp2ram
import bp2ram_cosim as MODULE_cosim
#
-----------------------------------------------------------------------------
# Logic to select between running the unit test as myHDL-only or
# with co-simulation
# Options
# -------
# use cosimulation?
useCosim = False
# search the list of command-line arguments for -cosim option
for i in sys.argv:
if i == "-cosim":
useCosim = True
break
else:
useCosim = False
# -------
if useCosim == True:
print "Running unit test with co-simulation."
MODULE_cosim.makeHDLTestBench()
# Import the alternate (co-simulation) definition of bp2ram
# This overrides the "real" object
import bp2ram_cosim
bp2ram = bp2ram_cosim.bp2ram
else:
print "Running unit test as myHDL-only (no co-simulation)."
#
-----------------------------------------------------------------------------
# Unit test code
# --------------
# Broken due to late night consolidation attempt :(
class TestBp2ram(unittest.TestCase):
def ClkGen(clk):
while 1:
clk.next = 0
yield delay(1)
clk.next = 1
yield delay(1)
clk = Signal(bool(0))
byteIn = Signal(intbv(0)[8:])
byteInRdy = Signal(bool(0))
dIn = Signal(intbv(0)[8:])
byteOut = Signal(intbv(0)[8:])
byteOutRdy = Signal(bool(0))
addrOut = Signal(intbv(0)[8:])
dOut = Signal(intbv(0)[8:])
we = Signal(bool(0))
state_out = Signal(intbv(0)[2:])
clkGen = ClkGen(clk=clk)
dut = bp2ram(clk=clk, byteIn=byteIn, byteInRdy=byteInRdy,
dIn=dIn, byteOut=byteOut, byteOutRdy=byteOutRdy,
addrOut=addrOut,
dOut=dOut, we=we, state_out=state_out)
def setUp(self):
# self.clk = Signal(bool(0))
# self.byteIn = Signal(intbv(0)[8:])
# self.byteInRdy = Signal(bool(0))
# self.dIn = Signal(intbv(0)[8:])
# self.byteOut = Signal(intbv(0)[8:])
# self.byteOutRdy = Signal(bool(0))
# self.addrOut = Signal(intbv(0)[8:])
# self.dOut = Signal(intbv(0)[8:])
# self.we = Signal(bool(0))
# self.state_out = Signal(intbv(0)[2:])
self.clk.next = 0
self.byteIn.next = 0
self.byteInRdy.next = 0
self.dIn.next = 0
self.byteOut.next = 0
self.byteOutRdy.next = 0
self.addrOut.next = 0
self.dOut.next = 0
self.we.next = 0
self.state_out.next = 0
# self.dut = bp2ram(clk=self.clk, byteIn=self.byteIn,
byteInRdy=self.byteInRdy, dIn=self.dIn,
# byteOut=self.byteOut, byteOutRdy=self.byteOutRdy,
addrOut=self.addrOut,
# dOut=self.dOut, we=self.we, state_out=self.state_out)
def tearDown(self):
self.dut = None
self.clkGen = None
#
-----------------------------------------------------------------------------
def testCaseW1(self):
""" W1: Check that control byte (MSB=1) followed by address byte
sets addrOut """
yield delay(10)
def test(clk, byteIn, byteInRdy, addrOut):
inputBytes = [0xFF, 0x69, 0xA5]
# Input the first two bytes in the input stream
for i in range(2):
byteIn.next = inputBytes[i]
byteInRdy.next = 1
yield clk.posedge
byteInRdy.next = 0
yield clk.posedge
yield clk.posedge
# Check this assertion
self.assertEqual(addrOut, inputBytes[1])
yield delay(10)
# Stop the simulation
raise StopSimulation
check = test(self.clk, self.byteIn, self.byteInRdy, self.addrOut)
sim = Simulation(self.clkGen, self.dut, check)
sim.run(quiet=1)
#
-----------------------------------------------------------------------------
def testCaseW2(self):
""" W2: Check that the sequence of ctrlbyte (MSB=1), addrbyte,
databyte
sets dataOut when databyte is received """
yield delay(10)
def test(clk, byteIn, byteInRdy, dOut):
inputBytes = [0xFF, 0x69, 0xA5]
# Input all the sample bytes
for i in range(len(inputBytes)):
byteIn.next = inputBytes[i]
byteInRdy.next = 1
yield clk.posedge
byteInRdy.next = 0
yield clk.posedge
yield clk.posedge
# Check this assertion
self.assertEqual(dOut, inputBytes[2])
yield delay(10)
# Stop the simulation
raise StopSimulation
check = test(self.clk, self.byteIn, self.byteInRdy, self.dOut)
sim = Simulation(self.clkGen, self.dut, check)
sim.run(quiet=1)
#
-----------------------------------------------------------------------------
def testCaseW3(self):
yield delay(10)
""" W3: Check that we is strobed after data to write is received """
def test(clk, byteIn, byteInRdy, dOut):
inputBytes = [0xFF, 0x69, 0xA5]
# "we" should be low at this point.
self.assertEqual(we,False)
# Input all the sample bytes
for i in range(len(inputBytes)):
byteIn.next = inputBytes[i]
byteInRdy.next = 1
yield clk.posedge
byteInRdy.next = 0
yield clk.posedge
# "We" should be high on the next clock
# Check this assertion
self.assertEqual(we, True)
yield clk.posedge
# "we" should go low again next
actual = we
expected = False
self.assertEqual(actual, expected)
# Stop the simulation
raise StopSimulation
check = test(self.clk, self.byteIn, self.byteInRdy, self.dOut)
sim = Simulation(self.clkGen, self.dut, check)
sim.run(quiet=1)
#
-----------------------------------------------------------------------------
# def testCaseW4(self):
# """ W4: Check that two back-to-back writes happen properly """
#
# def test(clk, byteIn, byteInRdy, dOut, addrOut, we):
# yield delay(10)
# inputBytes = [0xFF, 0x69, 0xA5, 0x80, 0xF5, 0xAE]
#
# # "we" should be low at this point.
# self.assertEqual(we,False)
#
# # Input all the sample bytes
# for i in range(len(inputBytes)):
# byteIn.next = inputBytes[i]
# byteInRdy.next = 1
# yield clk.posedge
# byteInRdy.next = 0
# yield clk.posedge
#
# # "We" should be high on the next clock
#
# # Check this assertion
# self.assertEqual(we, True)
#
# # Check that dOut is the right value
# self.assertEqual(dOut, inputBytes[5])
#
# # Check that addrOut is correct
# self.assertEqual(addrOut, inputBytes[4])
#
# yield clk.posedge
#
# # "we" should go low again next
# actual = we
# expected = False
#
# self.assertEqual(actual, expected)
#
# # Stop the simulation
# raise StopSimulation
#
# check = test(self.clk, self.byteIn, self.byteInRdy, self.dOut,
self.addrOut, self.we)
#
# sim = Simulation(self.clkGen, self.dut, check)
# sim.run(quiet=1)
#
##
-----------------------------------------------------------------------------
#
# def testCaseR1(self):
# """ R1: Check that control byte (MSB=0) followed by address byte
# sets addrOut """
#
# def test(clk, byteIn, byteInRdy, addrOut):
# yield delay(10)
# inputBytes = [0x7F, 0x69]
# self.failUnless(inputBytes[0] < 0x80, 'ctrl byte MSB must =
0')
# # Input the first two bytes in the input stream
# for i in range(2):
# byteIn.next = inputBytes[i]
# byteInRdy.next = 1
# yield clk.posedge
# byteInRdy.next = 0
# yield clk.posedge
#
# yield clk.posedge
#
# # Check this assertion
# self.assertEqual(addrOut, inputBytes[1])
#
# # Stop the simulation
# raise StopSimulation
#
# check = test(self.clk, self.byteIn, self.byteInRdy, self.addrOut)
#
# sim = Simulation(self.clkGen, self.dut, check)
# sim.run(quiet=1)
#
##
-----------------------------------------------------------------------------
#
# def testCaseR2(self):
# """ R2: Read from RAM side and set byteOut """
#
# def test(clk, byteIn, byteInRdy, addrOut, byteOut, byteOutRdy,
dIn):
# yield delay(10)
#
# address = 0x01
#
# # Pretend that a RAM is already outputting data
# # at the target address
# dIn.next = 0x69
#
# # Read command
# inputBytes = [0x7F, address]
# self.failUnless(inputBytes[0] < 0x80, 'ctrl byte MSB must =
0')
# # Input the first two bytes in the input stream
# for i in range(2):
# yield clk.posedge
# byteIn.next = inputBytes[i]
# byteInRdy.next = 1
# yield clk.posedge
# byteInRdy.next = 0
#
# # byteOutRdy should be false here
# self.assertEqual(byteOutRdy, False)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, True)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, False)
#
# # Check this assertion
# self.assertEqual(addrOut, inputBytes[1])
#
# # RAM should be outputting data into our dIn, and that
# # data should be passed to the UART side, as byteOut
#
# print "dIn = 0x%x" % dIn
# self.assertEqual(byteOut, dIn)
#
# raise StopSimulation
#
# check = test(self.clk, self.byteIn, self.byteInRdy,
self.addrOut, self.byteOut, self.byteOutRdy, self.dIn)
#
# sim = Simulation(self.clkGen, self.dut, check)
# sim.run(quiet=1)
#
##
-----------------------------------------------------------------------------
#
# def testCaseR3(self):
# """ R3: Two back-to-back reads """
#
#
# def test(clk, byteIn, byteInRdy, addrOut, byteOut, byteOutRdy,
dIn):
# yield delay(10)
#
# address = 0x01
# # Pretend that a RAM is already outputting data
# # at the target address
# dIn.next = 0x69
#
# # Read command
# inputBytes = [0x7F, address]
# self.failUnless(inputBytes[0] < 0x80, 'ctrl byte MSB must =
0')
# # Input the first two bytes in the input stream
# for i in range(2):
# yield clk.posedge
# byteIn.next = inputBytes[i]
# byteInRdy.next = 1
# yield clk.posedge
# byteInRdy.next = 0
#
# # byteOutRdy should be false here
# self.assertEqual(byteOutRdy, False)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, True)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, False)
#
# # Check this assertion
# self.assertEqual(addrOut, inputBytes[1])
#
# # RAM should be outputting data into our dIn, and that
# # data should be passed to the UART side, as byteOut
#
# print "dIn = 0x%x" % dIn
# self.assertEqual(byteOut, dIn)
#
## --- Read #2 ----------------------------------------------------
#
# address = 0x02
# # Pretend that a RAM is already outputting data
# # at the target address
# dIn.next = 0x71
#
# # Read command
# inputBytes = [0x50, address]
# self.failUnless(inputBytes[0] < 0x80, 'ctrl byte MSB must =
0')
# # Input the first two bytes in the input stream
# for i in range(2):
# yield clk.posedge
# byteIn.next = inputBytes[i]
# byteInRdy.next = 1
# yield clk.posedge
# byteInRdy.next = 0
#
# # byteOutRdy should be false here
# self.assertEqual(byteOutRdy, False)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, True)
#
# yield clk.posedge
#
# self.assertEqual(byteOutRdy, False)
#
# # Check this assertion
# self.assertEqual(addrOut, inputBytes[1])
#
# # RAM should be outputting data into our dIn, and that
# # data should be passed to the UART side, as byteOut
#
# print "dIn = 0x%x" % dIn
# self.assertEqual(byteOut, dIn)
#
# raise StopSimulation
#
# check = test(self.clk, self.byteIn, self.byteInRdy,
self.addrOut, self.byteOut, self.byteOutRdy, self.dIn)
#
# sim = Simulation(self.clkGen, self.dut, check)
# sim.run(quiet=1)
#
# Don't do unittest.main() here,
# it interferes with our command-line argument passing. Do this instead:
suite = unittest.makeSuite(TestBp2ram)
unittest.TextTestRunner(verbosity=2).run(suite)
////// End paste //////////////////////////////////////////////////////
/// bp2ram_cosim.py pasted below ////
# George Pantazopoulos
# myHDL Co-simulation support
from myhdl import Cosimulation, Signal, intbv, toVerilog
import os
# For cosimulation, provide an alternate definition for device under test.
def bp2ram(clk, byteIn, byteInRdy, dIn, byteOut, byteOutRdy, addrOut,
dOut, we, state_out):
cmd = "iverilog -o bp2ram bp2ram.v tb_bp2ram.v"
os.system(cmd)
return Cosimulation("vvp -m ./myhdl.vpi bp2ram", clk=clk,
byteIn=byteIn,
byteInRdy=byteInRdy, dIn=dIn, byteOut=byteOut,
byteOutRdy=byteOutRdy, addrOut=addrOut,
dOut=dOut, we=we, state_out=state_out)
#
-----------------------------------------------------------------------------
def makeHDLTestBench():
from bp2ram import bp2ram
print "Generating Verilog testbench for co-simulation."
clk = Signal(bool(0))
byteIn = Signal(intbv(0)[8:])
byteInRdy = Signal(bool(0))
dIn = Signal(intbv(0)[8:])
byteOut = Signal(intbv(0)[8:])
byteOutRdy = Signal(bool(0))
addrOut = Signal(intbv(0)[8:])
dOut = Signal(intbv(0)[8:])
we = Signal(bool(0))
state_out = Signal(intbv(0)[2:])
toVerilog.name = "bp2ram"
toVerilog(bp2ram, clk=clk, byteIn=byteIn, byteInRdy=byteInRdy,
dIn=dIn, byteOut=byteOut, byteOutRdy=byteOutRdy,
addrOut=addrOut,
dOut=dOut, we=we, state_out=state_out)
print "Done generating Verilog testbench."
/// End Paste ///////////////////////////////////////////////////////////
|