Thread: [myhdl-list] Problems inferring RAM when it is buried in system
Brought to you by:
jandecaluwe
From: George P. <ge...@ga...> - 2005-11-29 07:33:04
|
Hi Jan, Your trivial example of mapping a list of signals to a RAM memory successfully infers a Distributed RAM under myHDL 0.5a1 and Xilinx ISE 7.1.04i: def RAM(dout, din, addr, we, clk, depth=128): """ Ram model """ mem = [Signal(intbv(0)[8:]) for i in range(depth)] @always(clk.posedge) def write(): if we: mem[int(addr)].next = din @always_comb def read(): dout.next = mem[int(addr)] return write, read However, Xilinx ISE fails to infer a Distributed RAM if the ram logic is buried in the system (input/output ports not exposed at top level). In my system, I have a UART (in myHDL) that feeds a RAM bank, such that the RAM bank is not accessible directly from the outside world. I have boiled down the resulting Verilog code to just the code necessary to show the problem. Xilinx ISE infers a Distributed RAM successfully from the Verilog code I pasted below. However, merely commenting out the lines that bring data_out to the top level causes ISE to fail to infer a Distributed RAM. It wrongly creates 2048 flip-flops and prints a warning. Because my RAM bank needs to be hidden within the system, I can not have data_in or data_out listed as an input and output, respectively, at the module level. Besides the possibility of a myHDL problem, am I going about things wrong? All my work in myHDL so far has resulted in a single module( ); section in the verilog code. Do I need to somehow make multiple modules? module Synth_plus_UART_BUG ( sysclk, RxD, TxD, RxD_led, audio_out, debug_out, data_in, data_out, // commenting this out causes RAM inference to fail ); input sysclk; input RxD; output TxD; reg TxD; output RxD_led; reg RxD_led; output audio_out; reg audio_out; output [7:0] debug_out; reg [7:0] debug_out; input data_in; output data_out; // commenting this out causes RAM inference to fail reg [7:0] addr; reg we; wire [7:0] data_out; reg [7:0] _S65X81_0_rbank [0:32-1]; reg [7:0] _S65X81_0_S65X81_0_0_mem [0:256-1]; always @(posedge sysclk) begin: _Synth_plus_UART_BUG_S65X81_0_RAM_0_write if (we) begin _S65X81_0_S65X81_0_0_mem[addr] <= data_in; end end assign data_out = _S65X81_0_S65X81_0_0_mem[addr]; endmodule |
From: Jan D. <ja...@ja...> - 2005-11-29 13:48:08
|
George Pantazopoulos wrote: > However, Xilinx ISE fails to infer a Distributed RAM if the ram logic is > buried in the system (input/output ports not exposed at top level). That's quite surprizing, because I don't see the technical reason behind it, and it would also severely restrict the usefulness of the RAM inference feature. I assume other kinds of embedded structures are inferred properly (counters, shift registers ...) Now, I don't have Xilinx installed so I can't experiment myself. BTW, is this something that I could check with the free version? In that case, I'll install it here. Can other Xilinx users confirm this, perhaps with other (more recent?) ise versions, before we start looking for workarounds? Note that the small example you give doesn't prove your statement above: it merely shows that RAM inference fails when the output port is not connected at all. (In fact, I would have expected that the synthesis tool removes all logic in that case.) But I assume that the RAM output is properly connected in the embedded case, because otherwize the Verilog convertor would have turned it into an output. Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: George P. <ge...@ga...> - 2005-11-29 14:45:40
|
Hi Jan, I am using the free Xilinx ISE WebPACK(http://www.xilinx.com/ise/logic_design_prod/webpack.htm). The latest version is 7.1.04i (which is what I am using). I would recommend installing it, even if you don't use a Xilinx part at the moment. You can choose to only synthesize (right click the Synthesize-XST item in the list of processes and select Run) and see what is being inferred when you view the synthesis report in the Design Summary. You don't need to do any other steps of the FPGA implementation. You probably need my device stats. I am using the xc3s1000 device, speed grade -4, package type ft256. You can see the templates that ISE looks for when inferring components if you select the menu Edit->Language Templates. And yes, I was having the same problem with the shift register you showed me in a previous email. It would infer on a standalone example, but not if it was buried inside my system. The warning I get is: "INFO:Xst:738 - HDL ADVISOR - 2048 flip-flops were inferred for signal <_S65X81_0_S65X81_0_0_mem>. You may be trying to describe a RAM in a way that is incompatible with block and distributed RAM resources available on Xilinx devices, or with a specific template that is not supported. Please review the Xilinx resources documentation and the XST user manual for coding guidelines. Taking advantage of RAM resources will lead to improved device usage and reduced synthesis time." Even though my small example doesn't necessarily prove my statement, I have been watching the Synthesis Report when I synthesize my entire system, and no Distributed RAMs or shift registers are inferred. But they are inferred when I try synthesizing trivial examples. I'd like to provide you with a more complete example. Is there something specific you'd like to see? This is a crucial feature and I've come so far with myHDL already, thanks to your good work. I'd like to help you get it working. Thanks, George > George Pantazopoulos wrote: > >> However, Xilinx ISE fails to infer a Distributed RAM if the ram logic >> is buried in the system (input/output ports not exposed at top level). > > > That's quite surprizing, because I don't see the technical > reason behind it, and it would also severely restrict the usefulness > of the RAM inference feature. I assume other kinds of embedded > structures are inferred properly (counters, shift registers ...) > > Now, I don't have Xilinx installed so I can't experiment myself. BTW, is > this something that I could check with the free version? In that > case, I'll install it here. > > Can other Xilinx users confirm this, perhaps with other (more recent?) > ise versions, before we start looking for workarounds? > > Note that the small example you give doesn't prove your statement > above: it merely shows that RAM inference fails when the output > port is not connected at all. (In fact, I would have expected > that the synthesis tool removes all logic in that case.) > But I assume that the RAM output is properly connected in the > embedded case, because otherwize the Verilog convertor would > have turned it into an output. > > Jan > |
From: Tom D. <td...@di...> - 2005-11-29 15:01:48
|
George, Could you include the MyHDL code for the example that doesn't work? My experience with XST (ISE synthesis tool) is that it isn't very useful at this. I will try it on Mentor Precision which is very good at inferring all the structures available in your target FPGA family. You may need to use the new User Defined Verilog feature of MyHDL to include a hand coded Verilog module. Tom George Pantazopoulos wrote: > Hi Jan, > > Your trivial example of mapping a list of signals to a RAM memory > successfully infers a Distributed RAM under myHDL 0.5a1 and Xilinx ISE > 7.1.04i: > > def RAM(dout, din, addr, we, clk, depth=128): > """ Ram model """ > mem = [Signal(intbv(0)[8:]) for i in range(depth)] > > @always(clk.posedge) > def write(): > if we: > mem[int(addr)].next = din > @always_comb > def read(): > dout.next = mem[int(addr)] > return write, read > > > However, Xilinx ISE fails to infer a Distributed RAM if the ram logic > is buried in the system (input/output ports not exposed at top level). > > In my system, I have a UART (in myHDL) that feeds a RAM bank, such > that the RAM bank is not accessible directly from the outside world. > I have boiled down the resulting Verilog code to just the code > necessary to show the problem. > > Xilinx ISE infers a Distributed RAM successfully from the Verilog code > I pasted below. However, merely commenting out the lines that bring > data_out to the top level causes ISE to fail to infer a Distributed > RAM. It wrongly creates 2048 flip-flops and prints a warning. Because > my RAM bank needs to be hidden within the system, I can not have > data_in or data_out listed as an input and output, respectively, at > the module level. > > Besides the possibility of a myHDL problem, am I going about things > wrong? All my work in myHDL so far has resulted in a single module( ); > section in the verilog code. Do I need to somehow make multiple modules? > > module Synth_plus_UART_BUG ( > sysclk, > RxD, > TxD, > RxD_led, > audio_out, > debug_out, > data_in, > data_out, // commenting this out causes RAM inference to fail > ); > > input sysclk; > input RxD; > output TxD; > reg TxD; > output RxD_led; > reg RxD_led; > output audio_out; > reg audio_out; > output [7:0] debug_out; > reg [7:0] debug_out; > > input data_in; > output data_out; // commenting this out causes RAM inference to fail > > reg [7:0] addr; > > > reg we; > > wire [7:0] data_out; > > reg [7:0] _S65X81_0_rbank [0:32-1]; > reg [7:0] _S65X81_0_S65X81_0_0_mem [0:256-1]; > > always @(posedge sysclk) begin: _Synth_plus_UART_BUG_S65X81_0_RAM_0_write > if (we) begin > _S65X81_0_S65X81_0_0_mem[addr] <= data_in; > end > end > > > assign data_out = _S65X81_0_S65X81_0_0_mem[addr]; > > > endmodule > > > ------------------------------------------------------- > This SF.net email is sponsored by: Splunk Inc. Do you grep through log > files > for problems? Stop! Download the new AJAX search engine that makes > searching your log files as easy as surfing the web. DOWNLOAD SPLUNK! > http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click > _______________________________________________ > myhdl-list mailing list > myh...@li... > https://lists.sourceforge.net/lists/listinfo/myhdl-list > |
From: George P. <ge...@ga...> - 2005-11-30 02:43:37
|
Dear Jan and Tom, I have created a simplified, representative mock-up of my system. When this code is processed with myHDL (0.5dev1) and Xilinx ISE WebPACK 7.1.04i, no RAM's are inferred. However, using the same RAM function in a trivial standalone example results in inferred RAM. I also noticed a major discrepancy between the HDL Synthesis and the Final Report. Where did those 2048 flip-flops go? A similar discrepancy appears to be in the "real" system too. Xilinx ISE Synthesis report except is pasted below, followed by the myHDL code of the mock system. By the way, I'm fairly new to working with python, myHDL, and the FPGA design flow. So if I am doing something wrong, please let me know! Hope this helps, George Release 7.1.04i - xst H.42 ========================================================================= * HDL Synthesis * ========================================================================= Synthesizing Unit <ram_inference_test_embedded>. Related source file is "../../Synth_plus_UART_BUG.v". WARNING:Xst:646 - Signal <_ADAP_0_buf_in1> is assigned but never used. WARNING:Xst:646 - Signal <_ADAP_0_buf_in2> is assigned but never used. WARNING:Xst:646 - Signal <_U_0_bufin> is assigned but never used. WARNING:Xst:646 - Signal <_U_0_bufRxD> is assigned but never used. Register <adapter_to_synth_data> equivalent to <addr> has been removed Found 1-bit register for signal <audio_out>. Found 1-bit register for signal <TxD>. Found 8-bit adder for signal <$n0000> created at line 41. Found 8-bit adder for signal <$n0001> created at line 46. Found 8-bit adder for signal <$n0002> created at line 56. Found 8-bit register for signal <_ADAP_0_c1>. Found 8-bit register for signal <_SYNTH_0_c1>. Found 2048-bit register for signal <_SYNTH_0_SYNTH_0_0_mem>. Found 8-bit register for signal <_U_0_c1>. Found 8-bit register for signal <addr>. Found 1-bit register for signal <we>. INFO:Xst:738 - HDL ADVISOR - 2048 flip-flops were inferred for signal <_SYNTH_0_SYNTH_0_0_mem>. You may be trying to describe a RAM in a way that is incompatible with block and distributed RAM resources available on Xilinx devices, or with a specific template that is not supported. Please review the Xilinx resources documentation and the XST user manual for coding guidelines. Taking advantage of RAM resources will lead to improved device usage and reduced synthesis time. Summary: inferred 2083 D-type flip-flop(s). inferred 3 Adder/Subtractor(s). Unit <ram_inference_test_embedded> synthesized. ========================================================================= * Final Report * ========================================================================= Final Results RTL Top Level Output File Name : ram_inference_test_embedded.ngr Top Level Output File Name : ram_inference_test_embedded Output Format : NGC Optimization Goal : Speed Keep Hierarchy : NO Design Statistics # IOs : 4 Macro Statistics : # Registers : 4 # 1-bit register : 2 # 8-bit register : 2 # Adders/Subtractors : 2 # 8-bit adder : 2 Cell Usage : # BELS : 1 # VCC : 1 # FlipFlops/Latches : 4 # FD : 2 # FDR : 2 # Clock Buffers : 1 # BUFGP : 1 # IO Buffers : 2 # OBUF : 2 ========================================================================= /// Begin code //////////////////// # George Pantazopoulos # ram_inference_test_embedded.py from myhdl import * # Dummy system set up to show that RAM inference does not occur under # Xilinx ISE WebPACK 7.1.04i (Windows free version with # XST as the synthesis tool) # Tested with myHDL 0.5a1 # RAM construct copied verbatim from the example on the myHDL website. # In a trivial (standalone) case, a RAM was inferred from this code # using Xilinx XST but fails to do so when part of this system. # Instead, it instantiates 2048 flip-flops and prints a warning to that effect. # --------------------------- # Explanation of Mock system: # --------------------------- # PC serial port <-> UART <- bytestream -> Adapter <- SRAM-style ctrl -> Synth # A Uart turns a stream of bits into a stream of bytes. # This byte stream is parsed by the Adapter into address, data, and control # signals # These control signals communicate with the Synth module and manipulate # its internal RAM bank. # ----------------------------------------------------------------------------- # RAM construct copied verbatim from the example on the myHDL website. def RAM(dout, din, addr, we, clk, depth=128): """ Ram model """ mem = [Signal(intbv(0)[8:]) for i in range(depth)] @always(clk.posedge) def write(): if we: mem[int(addr)].next = din @always_comb def read(): dout.next = mem[int(addr)] return write, read # ----------------------------------------------------------------------------- def UART(clk, RxD, TxD, data_out, data_in): c1 = Signal(intbv(0)[8:]) bufRxD = Signal(bool(0)) bufin = Signal(intbv(0)[8:]) @always(clk.posedge) def UartProc(): c1.next = (c1 + 1) % 2**8 bufRxD.next = RxD TxD.next = c1[0] data_out.next = c1 bufin.next = data_in return instances() # ----------------------------------------------------------------------------- # Mock-up bytestream to RAM protocol adapter # # Converts the stream of data bytes from the UART # into a RAM write protocol. def AdapterU2R(clk, uart_data_in, uart_data_out, ram_data_in, ram_data_out, addr, we): c1 = Signal(intbv(0)[8:]) buf_in1 = Signal(intbv(0)[8:]) buf_in2 = Signal(intbv(0)[8:]) @always(clk.posedge) def dUtR(): c1.next = (c1 + 1) % 2**8 addr.next = c1 we.next = c1[0] buf_in1.next = uart_data_in uart_data_out.next = c1 buf_in2.next = ram_data_in ram_data_out.next = c1 return instances() # ----------------------------------------------------------------------------- # Mock up audio synthesizer. # Controlled by talking to its internal register bank as a RAM. # # Takes commands from a SRAM-like interface. # data_in and data_out are for doing writes/reads to its # internal register bank. def Synth(clk, we, addr, data_in, data_out, audio_out): c1 = Signal(intbv(0)[8:]) # The register bank RAM_0 = RAM(dout=data_out, din=data_in, addr=addr, we=we, clk=clk, depth=256) @always(clk.posedge) def SynthProcess(): c1.next = (c1 + 1) % 2**8 audio_out.next = c1[0] return instances() # ----------------------------------------------------------------------------- clk = Signal(bool(0)) RxD = Signal(bool(0)) TxD = Signal(bool(0)) audio_out = Signal(bool(0)) def Top(clk, RxD, TxD, audio_out): uart_to_adapter_data = Signal(intbv(0)[8:]) adapter_to_uart_data = Signal(intbv(0)[8:]) adapter_to_synth_data = Signal(intbv(0)[8:]) synth_to_adapter_data = Signal(intbv(0)[8:]) addr = Signal(intbv(0)[8:]) we = Signal(bool(0)) U_0 = UART(clk=clk, RxD=RxD, TxD=TxD, data_out=uart_to_adapter_data, data_in=adapter_to_uart_data) ADAP_0 = AdapterU2R(clk=clk, uart_data_in=uart_to_adapter_data, uart_data_out=adapter_to_uart_data, ram_data_in=synth_to_adapter_data, ram_data_out=adapter_to_synth_data, addr=addr, we=we) SYNTH_0 = Synth(clk=clk, we=we, addr=addr, data_in=adapter_to_synth_data, data_out=synth_to_adapter_data, audio_out=audio_out) return instances() toVerilog.name = "ram_inference_test_embedded" toVerilog(Top, clk, RxD, TxD, audio_out) ///// End code ///////// |
From: Jan D. <ja...@ja...> - 2005-11-30 13:37:57
|
George Pantazopoulos wrote: > Dear Jan and Tom, > > I have created a simplified, representative mock-up of my system. When > this code is processed with myHDL (0.5dev1) and Xilinx ISE WebPACK > 7.1.04i, no RAM's are inferred. However, using the same RAM function in > a trivial standalone example results in inferred RAM. > > I also noticed a major discrepancy between the HDL Synthesis and the > Final Report. Where did those 2048 flip-flops go? A similar discrepancy > appears to be in the "real" system too. George: I have been able to reproduce your issue. By now I'm pretty sure that the problem is not related to embedded code, but to the fact that the design is not clean. Note that several signals are driven but not used. I have tried the same with my Ram wrapper code: with the clean version, a ram gets inferred, but when I disconnect the output register from its surroundings, I get the same flip-flop inference and advisor message as you are getting. For MyHDL, I learn from this that it should issue similar warning messages as XST about driven but unused signals. I have added that to the development version. The overall message should be that you shouldn't draw too many conclusions from conversion/synthesis unless the design is clean. Clean meaning that it does something useful in simulation. Note that it is normal and useful for synthesis tools to remove "unnecessary" logic, such as anything that is not connected to its surroundings. Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: Tom D. <td...@di...> - 2005-11-30 14:40:22
|
Jan Decaluwe wrote: > > The overall message should be that you shouldn't draw too > many conclusions from conversion/synthesis unless the > design is clean. Clean meaning that it does something > useful in simulation. 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. > > Note that it is normal and useful for synthesis tools > to remove "unnecessary" logic, such as anything that > is not connected to its surroundings. XST is not that robust of a tool, but in general the cleaner the HDL, the less likely you get trouble with any synthesis tool. Potentially that is another benefit of MyHDL as the Verilog generated should be less diverse than you could create from scratch. For example RAMs inferred from a list should always produce Verilog that is the same structure, leaving less opportunity for a synthesis problem. Tom |
From: George P. <ge...@ga...> - 2005-11-30 19:39:29
|
Hi Tom, > 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. It seems that some unit tests I would want to do require a human in the loop. Examples would be verifying that sounds are being produced, or certain messages displayed on an LCD screen. How do these fit into this flow, if the flow is to be automated? Rather than unit tests, I've been doing test-benches and viewing the resulting waveforms with gtkwave. I'm running into the probem quite often that my system looks great in simulation, but does not work correctly (or at all sometimes) after being synthesized. I'd like to add unit tests to my flow, but I could really use some guidance and example code for this. What should I unit test? Should a unit test always be completely automated, etc? > 2. Apply unittest to toVerilog logic via cosimulation. Could you tell me about co-simulation? I've had a tough time browsing the web looking for non-expert information about it. How would I go about doing this with myHDL and other free/low-cost tools? > 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. Thanks, George Pantazopoulos http://www.gammaburst.net |
From: Tom D. <td...@di...> - 2005-11-30 20:42:18
|
George Pantazopoulos wrote: > It seems that some unit tests I would want to do require a human in the >loop. Examples would be verifying that sounds are being produced, or >certain messages displayed on an LCD screen. How do these fit into this >flow, if the flow is to be automated? > > I've learned everything I know about unittests from the MyHDL manual, check out the unittest section: http://www.jandecaluwe.com/Tools/MyHDL/manual/unittest.html You need to figure out a test strategy for your system. I would not make a single module that I didn't test before combining it with other modules though and unittests make a great way to thoroughly test a module. And provide a means to retest later when new features are added or modified. It is much easier to troubleshoot a problem in simulation than in hardware, so it well worth your while to create a simulation environment that more closely represents the real system. > Rather than unit tests, I've been doing test-benches and viewing the >resulting waveforms with gtkwave. I'm running into the probem quite >often that my system looks great in simulation, but does not work >correctly (or at all sometimes) after being synthesized. > > Waveform viewing is very tedious and is difficult to really verify operation. I only look at waveforms out of desperation to help diagnose a problem. > I'd like to add unit tests to my flow, but I could really use some >guidance and example code for this. What should I unit test? Should a >unit test always be completely automated, etc? > > Like I said before, I would unittest everything and automate it all. Since you are testing in python, it becomes fairly simple to automate. > Could you tell me about co-simulation? I've had a tough time browsing >the web looking for non-expert information about it. How would I go >about doing this with myHDL and other free/low-cost tools? > > Co-simulation here refers to a mixed MyHDL and HDL simulation environment. Again check the manual for a great source of information: http://www.jandecaluwe.com/Tools/MyHDL/manual/cosim.html Tom |
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 /////////////////////////////////////////////////////////// |
From: George P. <ge...@ga...> - 2005-12-16 14:32:11
|
I'm sorry that the spacing and structure of my code got mangled during the posting process. Would you prefer another way to present the code? (put it in the wiki, for example?) Thanks, George |
From: <dan...@we...> - 2005-12-16 15:01:25
|
George Pantazopoulos wrote: > 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 :) Let unittest do the job for you. What you can do is have different test cases that perform what your makefile is doing. A split might be here appropriate. So you have, I call it testbench code, that performs the test with your logic. In the first step this is the myhdl logic. This code will be the same whether you test myhdl for now or the verilog generated code later. Put this testbench code in a test case and run it. If that works, add a second unittest test case. This one will generate the verilog code and then run your testbench code again, this time with cosimulation. Here comes the beauty of myhdl, as you have one testbench that tests both myhdl and verilog code. To run the test, you just call your unittest file. If the project becomes more complex you can group them. At the end you only have one file that you call which will run all the tests. Have a look at the examples that come along with myhdl. I believe you just ran some to test you cosimulation. They show this grouping of test cases very nice. You can call them individual or all together, just depends on which file you start. Guenter |
From: George P. <ge...@ga...> - 2005-12-01 21:09:04
|
> George Pantazopoulos wrote: >> Dear Jan and Tom, >> >> I have created a simplified, representative mock-up of my system. When >> this code is processed with myHDL (0.5dev1) and Xilinx ISE WebPACK >> 7.1.04i, no RAM's are inferred. However, using the same RAM function i= n >> a trivial standalone example results in inferred RAM. >> > George: > > I have been able to reproduce your issue. > > By now I'm pretty sure that the problem is not related to embedded > code, but to the fact that the design is not clean. > Jan, you were right. I tweaked my ram_inference_test_embedded.py example to eliminate two signals that generated "assigned but never used" XST warnings, and magically, a block ram got synthesized! :) Now I have to do this with my real system, which will be more difficult. However, at this point I think I should rewrite it from scratch with unit testing and co-simulation in mind. Besides the online manual, do you know of any other complete examples or other resources to help get me started? Thanks, George |
From: Tom D. <td...@di...> - 2005-12-02 06:28:43
|
George Pantazopoulos wrote: >However, at this point I think I should rewrite it from scratch with unit >testing and co-simulation in mind. Besides the online manual, do you know >of any other complete examples or other resources to help get me started? > > > > Check this python information about unittest if you haven't seen it already. http://docs.python.org/lib/module-unittest.html Good luck. Tom |
From: Jan D. <ja...@ja...> - 2005-12-02 08:58:09
|
George Pantazopoulos wrote: > However, at this point I think I should rewrite it from scratch with unit > testing and co-simulation in mind. Besides the online manual, do you know > of any other complete examples or other resources to help get me started? I think you have all the references for MyHDL-related info. In your spare time background material on extreme programming (XP) techniques may be useful reading. Let me add some general remarks. Part of the vision behind MyHDL is the idea that hardware design can be viewed as a specialized software engineering discipline that can therefore benefit from popular software development techniques, such as unit testing. This is certainly not a mainstream viewpoint. Mainstream hardware verification nowadays goes in totally different directions, such as heavy use of embedded, complex assertions and constraint-driven random testing. So here again, we are in pioneering mode. I don't think anyone else is considering to use unit testing (in the XP way) for hardware design. I am very happy to hear that Tom seems completely sold on the idea. But there's a lot of room left for exploration. I can only hope that more people will pick it up - and also take the time to document their findings. Final practical remark: the standard unittest is nice, but py.test may be an easier way to write unit tests. Disclaimer: I haven't used it myself a lot, and you need to install a subversion client to get it. Greetings, Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |
From: Jan D. <ja...@ja...> - 2005-11-29 15:28:56
|
George Pantazopoulos wrote: > Hi Jan, > > Your trivial example of mapping a list of signals to a RAM memory > successfully infers a Distributed RAM under myHDL 0.5a1 and Xilinx ISE > 7.1.04i: > > def RAM(dout, din, addr, we, clk, depth=128): > """ Ram model """ > mem = [Signal(intbv(0)[8:]) for i in range(depth)] > > @always(clk.posedge) > def write(): > if we: > mem[int(addr)].next = din > @always_comb > def read(): > dout.next = mem[int(addr)] > return write, read > > > However, Xilinx ISE fails to infer a Distributed RAM if the ram logic is > buried in the system (input/output ports not exposed at top level). Hi: I have installed Xilinx Webpack for Linux and done some experiments. In contrast to what you see, I have been able to infer distributed RAM for embedded code. Details: I have used the MyHDL code above, as well as a wrapped version in which every RAM interface signal comes from/goes to a register (except the clock). So for the wrapped version, all RAM interface signals except for the clock are internal. For the default device choice, I noticed that only flip-flops were inferred. I assume that the simpler devices don't contain RAM. To be sure, I chose a Virtex 4 device for my experiments. Initially the RAM inference style was set to "auto". For the non-wrapped version, I get an info that it cannot use block RAM, but then it uses distributed RAM correctly (and automatically). For the wrapped version, it tries to use a block RAM, but then XST fails with an internal error. However, when I then set the RAM inference style to "distributed", a distributed RAM gets properly inferred. I think this shows that the issue you see is not necessarily related to the "embedded" nature of the code, but may well be related to other issues. Also, it seems there's nothing conceptually wrong with the approach, but we need good synthesis tools of course. Jan -- Jan Decaluwe - Resources bvba - http://www.jandecaluwe.com Losbergenlaan 16, B-3010 Leuven, Belgium From Python to silicon: http://myhdl.jandecaluwe.com |