Thread: [myhdl-list] please help with best way how to construct unittest testbench
Brought to you by:
jandecaluwe
From: David B. <da...@be...> - 2016-01-29 15:09:48
|
Dear all, my question is simple: when using unittest/testcase, one can write more testbenches. I have wrote one, like the one below. As you can see, the 'testbench' is quite long, as one has to initialize all the signals, instantiate the DUT, provide reset and clock, and it does nothing (yet). I want to add a second test-bench, but I'd like to re-use the fraction of instantiation and initialization of the DUT. This is quite a work (not for this design, but for more complex designs). So far I have seen only testbenches, which were implementing each test case as a separate test function, which contained each time copy of signal assignments and instantiation of DUT. Is there any way, how to write a second test bench, and re-use the instances and signal assignments aready done? In fact, it would be great if I could just instantiate it once, assign signals, and then in the test functions just by driving the signals and compare with expected *without re-starting the simulation*. Any hint appreciated. thaaanks .d. -------------------------------------------------------------------------------- from unittest import TestCase class testFIFO(TestCase): def __init__(self): self.FIFO_DEPTH = 4 self.width = 8 def testbench(self): # prepare instance of the item print "Testbench" rc = RC() DxD, QxD = [Signal(intbv(0)[self.width:]) for x in xrange(2)] DxE, QValidxS = [Signal(bool(0)) for x in xrange(2)] # test instance dut=fifo(rc, DxD, DxE, QxD, QValidxS, self.FIFO_DEPTH) # clock generation @always(delay(10)) def clockGen(): rc.ClkxC.next = not rc.ClkxC @instance def reset(): rc.ResetxRN.next = 0 yield(delay(147)) rc.ResetxRN.next = 1 # stimulus @instance def stimulus(): rc.ClkxC.next = 0 DxD.next = 0 # yield (rc.ResetxRN.posedge) # yield (rc.ClkxC.posedge) yield join(rc.ClkxC.posedge, rc.ResetxRN.posedge) # unit self.assertEqual(QValidxS, 0) # reset stage finished for i in xrange(10): DxD.next = i yield (rc.ClkxC.posedge) DxD.next = 0 yield(delay(200)) raise StopSimulation() return dut, stimulus, clockGen, reset, def testOutputFlow(self): tb = traceSignals(self.testbench) sim = Simulation(tb) sim.run() -------------------------------------------------------------------------------- |
From: Marcel H. <1he...@in...> - 2016-01-29 15:31:29
Attachments:
signature.asc
|
On 29.01.2016 16:05, David Belohrad wrote: > Dear all, > > my question is simple: when using unittest/testcase, one can write more testbenches. I have wrote one, like the one below. As you can see, the 'testbench' is quite long, as one has to initialize all the signals, instantiate the DUT, provide reset and clock, and it does nothing (yet). > > I want to add a second test-bench, but I'd like to re-use the fraction of instantiation and initialization of the DUT. This is quite a work (not for this design, but for more complex designs). So far I have seen only testbenches, which were implementing each test case as a separate test function, which contained each time copy of signal assignments and instantiation of DUT. Is there any way, how to write a second test bench, and re-use the instances and signal assignments aready done? In fact, it would be great if I could just instantiate it once, assign signals, and then in the test functions just by driving the signals and compare with expected *without re-starting the simulation*. > > Any hint appreciated. I had the same issue this week and decided to make up my mind and try some things out. I decided to use decoraters to wrap the tests to instantiate the clock etc. https://gist.github.com/punkkeks/9594800803bff9c57853 You have to use the _@myhdltest_ decoratetor to use this. In the setup method you have to instantiate all your signals (for an example, just see the gist). To trace a testcase you can use one of the three methods: 1. @trace decorator 2. self.trace = True in the setUp method 3. --trace as commandline argument If you have any improvements, let me know ;) Regards Marcel |
From: Christopher F. <chr...@gm...> - 2016-01-29 16:26:47
|
On 1/29/16 9:05 AM, David Belohrad wrote: > Dear all, > > my question is simple: when using unittest/testcase, one can write > more testbenches. I have wrote one, like the one below. As you can > see, the 'testbench' is quite long, as one has to initialize all the > signals, instantiate the DUT, provide reset and clock, and it does > nothing (yet). > > I want to add a second test-bench, but I'd like to re-use the > fraction of instantiation and initialization of the DUT. This is where things get fun :) Yes, use the power of Python to create reusable things, the following are some reusability items I have used in the past: 1) This is the testbench template I use (I am sure it can be improved upon): https://gist.github.com/cfelton/17bfc798550aa9ed8e04 2) Clock object with gen method clock = Clock(frequency=125e6) tbclk = clock.gen() https://github.com/cfelton/rhea/blob/master/rhea/system/clock.py 3) Reset object with `pulse` method reset = Reset(0, active=0, async=True) ... @instance def tbstim(): yield reset.pulse(10) 4) Interfaces with transactor methods! This simplifies a lot. class SomeInterface(): ... bus = SomeInterface() tbdut = my_dut(clock, reset, bus) @instance def tbstim(): yield bus.write() yield bus.read() # ... 5) portmap dicts, I create a dict with all the signals in the module port arguments, the portmap can be reused. Often I connect a portmap to a top-level (since top-level ports a tied to the physical hardware and fixed) def my_top_level_module(clock, reset, sdi, sdo): ... my_top_level_module.portmap = { clock: Clock(), reset: Reset(), sdi: Signal(bool(0)) sdo: Signal(bool(0)) } Use functions to wrap common tasks, use generators to wrap common simulation sequences, etc. # another reset resuse def doreset(reset): reset.next = reset.active yield delay(30) reset.next = not reset.active @instance def tbstim(): # reuse in various stimulus yield doreset(reset) As others have pointed out, use the various features of Python to make reusable objects. Keerthan has some utilities to simplify some of these task as well (setting up cosim, testbench generators, etc.) https://github.com/jck/uhdl You don't need to limit yourself to the above examples, there is a lot you can do with Python and reusability. Regards, Chris |
From: David B. <da...@be...> - 2016-01-29 17:34:56
|
Dear both, thanks for the quick answer. It seems to be exactly what i've been looking for. And it seems to be insanely powerful. I just have to digest it a bit, because my python level is not up to date :) .d. Christopher Felton <chr...@gm...> writes: > On 1/29/16 9:05 AM, David Belohrad wrote: >> Dear all, >> >> my question is simple: when using unittest/testcase, one can write >> more testbenches. I have wrote one, like the one below. As you can >> see, the 'testbench' is quite long, as one has to initialize all the >> signals, instantiate the DUT, provide reset and clock, and it does >> nothing (yet). >> >> I want to add a second test-bench, but I'd like to re-use the >> fraction of instantiation and initialization of the DUT. > > > This is where things get fun :) Yes, use the power of > Python to create reusable things, the following are some > reusability items I have used in the past: > > 1) This is the testbench template I use (I am sure it > can be improved upon): > https://gist.github.com/cfelton/17bfc798550aa9ed8e04 > > 2) Clock object with gen method > > clock = Clock(frequency=125e6) > tbclk = clock.gen() > > https://github.com/cfelton/rhea/blob/master/rhea/system/clock.py > > 3) Reset object with `pulse` method > > reset = Reset(0, active=0, async=True) > ... > @instance > def tbstim(): > yield reset.pulse(10) > > 4) Interfaces with transactor methods! This simplifies > a lot. > > class SomeInterface(): > ... > > bus = SomeInterface() > > tbdut = my_dut(clock, reset, bus) > > @instance > def tbstim(): > yield bus.write() > yield bus.read() > # ... > > 5) portmap dicts, I create a dict with all the signals > in the module port arguments, the portmap can be reused. > Often I connect a portmap to a top-level (since top-level > ports a tied to the physical hardware and fixed) > > def my_top_level_module(clock, reset, sdi, sdo): > ... > my_top_level_module.portmap = { > clock: Clock(), > reset: Reset(), > sdi: Signal(bool(0)) > sdo: Signal(bool(0)) > } > > > Use functions to wrap common tasks, use generators to > wrap common simulation sequences, etc. > > # another reset resuse > def doreset(reset): > reset.next = reset.active > yield delay(30) > reset.next = not reset.active > > @instance > def tbstim(): > # reuse in various stimulus > yield doreset(reset) > > > As others have pointed out, use the various features > of Python to make reusable objects. > > Keerthan has some utilities to simplify some of these > task as well (setting up cosim, testbench generators, etc.) > https://github.com/jck/uhdl > > You don't need to limit yourself to the above examples, > there is a lot you can do with Python and reusability. > > Regards, > Chris > > > > ------------------------------------------------------------------------------ > Site24x7 APM Insight: Get Deep Visibility into Application Performance > APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month > Monitor end-to-end web transactions and take corrective actions now > Troubleshoot faster and improve end-user experience. Signup Now! > http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140 > _______________________________________________ > myhdl-list mailing list > myh...@li... > https://lists.sourceforge.net/lists/listinfo/myhdl-list |
From: Uri N. <ur...@gm...> - 2016-01-30 21:49:22
|
Hi David, A technique I find very useful is unittest's test discovery protocol that simplifies collecting tests. You can see a working sample here: https://github.com/unixie/myhdl_arch I also like a CLI per test suite to enable debug of specific cases. Cheers, Uri On 29 January 2016 at 19:31, David Belohrad <da...@be...> wrote: > Dear both, > > thanks for the quick answer. It seems to be exactly what i've been looking > for. And it seems to be insanely powerful. I just have to digest it a bit, > because my python level is not up to date :) > > .d. > > > > Christopher Felton <chr...@gm...> writes: > > > On 1/29/16 9:05 AM, David Belohrad wrote: > >> Dear all, > >> > >> my question is simple: when using unittest/testcase, one can write > >> more testbenches. I have wrote one, like the one below. As you can > >> see, the 'testbench' is quite long, as one has to initialize all the > >> signals, instantiate the DUT, provide reset and clock, and it does > >> nothing (yet). > >> > >> I want to add a second test-bench, but I'd like to re-use the > >> fraction of instantiation and initialization of the DUT. > > > > > > This is where things get fun :) Yes, use the power of > > Python to create reusable things, the following are some > > reusability items I have used in the past: > > > > 1) This is the testbench template I use (I am sure it > > can be improved upon): > > https://gist.github.com/cfelton/17bfc798550aa9ed8e04 > > > > 2) Clock object with gen method > > > > clock = Clock(frequency=125e6) > > tbclk = clock.gen() > > > > https://github.com/cfelton/rhea/blob/master/rhea/system/clock.py > > > > 3) Reset object with `pulse` method > > > > reset = Reset(0, active=0, async=True) > > ... > > @instance > > def tbstim(): > > yield reset.pulse(10) > > > > 4) Interfaces with transactor methods! This simplifies > > a lot. > > > > class SomeInterface(): > > ... > > > > bus = SomeInterface() > > > > tbdut = my_dut(clock, reset, bus) > > > > @instance > > def tbstim(): > > yield bus.write() > > yield bus.read() > > # ... > > > > 5) portmap dicts, I create a dict with all the signals > > in the module port arguments, the portmap can be reused. > > Often I connect a portmap to a top-level (since top-level > > ports a tied to the physical hardware and fixed) > > > > def my_top_level_module(clock, reset, sdi, sdo): > > ... > > my_top_level_module.portmap = { > > clock: Clock(), > > reset: Reset(), > > sdi: Signal(bool(0)) > > sdo: Signal(bool(0)) > > } > > > > > > Use functions to wrap common tasks, use generators to > > wrap common simulation sequences, etc. > > > > # another reset resuse > > def doreset(reset): > > reset.next = reset.active > > yield delay(30) > > reset.next = not reset.active > > > > @instance > > def tbstim(): > > # reuse in various stimulus > > yield doreset(reset) > > > > > > As others have pointed out, use the various features > > of Python to make reusable objects. > > > > Keerthan has some utilities to simplify some of these > > task as well (setting up cosim, testbench generators, etc.) > > https://github.com/jck/uhdl > > > > You don't need to limit yourself to the above examples, > > there is a lot you can do with Python and reusability. > > > > Regards, > > Chris > > > > > > > > > ------------------------------------------------------------------------------ > > Site24x7 APM Insight: Get Deep Visibility into Application Performance > > APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month > > Monitor end-to-end web transactions and take corrective actions now > > Troubleshoot faster and improve end-user experience. Signup Now! > > http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140 > > _______________________________________________ > > myhdl-list mailing list > > myh...@li... > > https://lists.sourceforge.net/lists/listinfo/myhdl-list > > > ------------------------------------------------------------------------------ > Site24x7 APM Insight: Get Deep Visibility into Application Performance > APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month > Monitor end-to-end web transactions and take corrective actions now > Troubleshoot faster and improve end-user experience. Signup Now! > http://pubads.g.doubleclick.net/gampad/clk?id=267308311&iu=/4140 > _______________________________________________ > myhdl-list mailing list > myh...@li... > https://lists.sourceforge.net/lists/listinfo/myhdl-list > |