I have observed behavior with Icarus Verilog which may be a bug.
I have a simulation of a SoC with a small monitor program. The monitor program uses out-of-module references to report on state in the SoC.
I use a command file with Icarus Verilog to list all the files which make up the SoC and its monitor. Here is part of it:
../../rtl/verilog/orpsoc.v
../../bench/verilog/or1200_monitor.v
orpsoc.v is the top of the module tree for the SoC, or1200_monitor.v is the monitor program. Both of these are top level modules in the SoC.
Here is part of the code for the monitor:
`define OR1200_TOP orpsoc.i_orpsoc_fpga.or1200_top
...
always @(posedge `OR1200_TOP.or1200_cpu.or1200_ctrl.clk) begin
if (!`OR1200_TOP.or1200_cpu.or1200_ctrl.wb_freeze) begin
#2;
<print out diagnostics>
This all works fine with Icarus Verilog and I can get a nice VCD and view it with GTKWave.
However if I change the ordering in my command file, so that the monitor is instantiated BEFORE the SoC, it all stops working:
../../bench/verilog/or1200_monitor.v
../../rtl/verilog/orpsoc.v
Some diagnostic wave tracing shows that the monitor always block triggers once on the first leading edge of
`OR1200_TOP.or1200_cpu.or1200_ctrl.clk and then never again.
Cary R has not been able to reproduce this with a trivial example.
The attached large example demonstrates the problem. The monitor can be found in bench/verilog/or1200_monitor.v. The top of the SoC hierarchy is in rtl/verilog/orpsoc.v. The majority of the source code is unchanged from the standard OpenCores ORPSOC and is found in the orp_soc directory.
There are two versions of the Icarus Verilog command file in sim/iv-good.scr and sim/iv-bad.scr. They differ only in the ordering or orpsoc.v and or1200_monitor.v.
The examples can be run from the top directory using
make clean simulate-good
make clean simulate-bad
To generate a VCD dump (in sim/run/dump.vcd) use
make clean simulate-good VTRACE=-DORPSOC_DUMP
make clean simulate-bad VTRACE=-DORPSOC_DUMP
Good runs produce the following output:
$readmemh(../src/flash.in): Not enough words in the read file for requested range.
(orpsoc.i_orpsoc_fpga.uart_top) UART INFO: Data bus width is 32. Debug Interface present.
(orpsoc.i_orpsoc_fpga.uart_top) UART INFO: Doesn't have baudrate output
Execution starts, 1 runs through Dhrystone
Begin Time = 6
End Time = 239
OR1K at 10 MHz (+PROC_6)
Microseconds for one run through Dhrystone: 233us / 1 runs
Dhrystones per Second: 4291
1643.25 ns: l.nop report (deaddead)
1653.35 ns: l.nop exit (00000000)
real 18.73
user 18.49
sys 0.07
[jeremy@thomas icarus-verilog-bug]$ make clean simulate-bad
rm -f -rf sim/run/*
find . -name '*~' -exec rm -f {} \;
cd sim/run && time -p iverilog -c iv_processed.scr
real 1.83
user 1.53
sys 0.28
The or1200_monitor module is responsible for generating the output beginning "Execution starts..." earlier messages are $display in the main SoC.
The bad output stops after the UART INFO warnings, and must be interrupted with ctrl-C:
$readmemh(../src/flash.in): Not enough words in the read file for requested range.
(orpsoc.i_orpsoc_fpga.uart_top) UART INFO: Data bus width is 32. Debug Interface present.
(orpsoc.i_orpsoc_fpga.uart_top) UART INFO: Doesn't have baudrate output
^C** VVP Stop(0) **
** Current simulation time is 47027550 ticks.
> finish
** Continue **
real 368.11
user 365.19
sys 0.09
Hope this example allows the problem to be tracked down.
tar and bzip2 file of the system demonstrating the bug
I verified that this fails on my local workstation as well. It would have been nice if this could have been reduced in size, but it's better than nothing. My first thought is that this could be a race condition that when you change the order of the files things break. How hard would it be for you to verify that the core is functioning correctly independent of file order. The fact that it doesn't finish implies something more than just monitoring is going wrong in the simulation.
Hi Cary,
I'll try to construct a smaller example today. I think I can reduce it to just CPU + memory + monitor.
I should have explained more. The monitor is responsible for terminating the run, so if it fails to trigger its "always" block, the program will not terminate. My GTKwave analysis suggests the system is otherwise behaving correctly.
Here's a bit more about what is happening. The OpenRISC 1000 has a no-op instruction, l.nop, which can incorporate a 16-bit constant in its bottom 16-bits. It has no effect on the behavior of the NOP in the CPU, but test benches can use the 16-bits of information to monitor behavior. All OpenRISC 1000 instructions are 32 bits. l.nop is 32'h1500_iiii.
On each clock posedge, or1200_monitor looks at the "freeze" signal in the CPU control unit. If it is clear, it reads the value of the current instruction register. If it is l.nop with a constant in its lower 16-bits it performs a special action:
- l.nop 1 (32'h1500_0001): terminate ($finish)
- l.nop 2 (32'h1500_0002): print the value in R3
- l.nop 3 (32'h1500_0003): do a printf (broken)
- l.nop 4 (32'h1500_0004): print R3 as a char
The test program loaded from sim/src/flash.in has l.nop 3 instructions embedded to print out the text "Execution starts...". When the program is complete it uses l.nop 1 to terminate.
GTKwave shows the correct sequence of instructions are being executed (I can see them in the instruction register). However the monitor "always" block is not triggering after the first clock edge, so does not compare the instruction to l.nop, and hence does not print the characters or terminate using $finish.
HTH
Jeremy
Simplified demonstration of the problem
I have built a simplified example with just the monitor and OR1200 CPU (attached).
I can now identify the cause of the problem is a missing `timescale declaration in or1200_monitor.v. However I believe this could still be a bug (needs expert Verilog interpretation). There are now three ways to run the example:
make simulate-good
make simulate-bad
make simulate-bad IVFLAGS=-DNOBUG
The first case uses a command file in which orpsoc.v (which contains a `timescale directive) precedes or1200_monitor.v (which does not). The output is:
$readmemh(../src/flash.in): Not enough words in the read file for requested range.
Execution starts, 1 runs through Dhrystone
Begin Time = 6
End Time = 239
OR1K at 10 MHz (+PROC_6)
Microseconds for one run through Dhrystone: 233us / 1 runs
Dhrystones per Second: 4291
1641.45 ns: l.nop report (deaddead)
1651.55 ns: l.nop exit (00000000)
real 10.52
user 10.01
sys 0.08
The second case is indentical except that or1200_monitor.v precedes orpsoc.v. The simulation must be interrupted:
$readmemh(../src/flash.in): Not enough words in the read file for requested range.
^C** VVP Stop(0) **
** Current simulation time is 3407750 ticks.
> finish
** Continue **
real 17.63
user 14.67
sys 0.06
The third version also has or1200_monitor.v prededing orpsoc.v, but uses a `define to add the missing `timescale directive to or1200_monitor.v. Output is as for the first example.
In each case a VCD may be generated by adding -DORPSOC_DUMP to the IVFLAGS macro.
My understanding is that the `timescale directive (in each case 1ps/1ps by including bench/verilog/timescale.v) should only affect the source file in which it is used, so should not differ in its effect depending on the order of the source files.
Hope this is useful in getting to the bottom of the problem.
File Added: icarus-verilog-bug-simplified.tar.bz2
Evan Lavelle has clarified this for me. It is order specific. The following text appears in IEEE 1364-2001 (p359) and IEEE 1364-2005 (p358)
"The `timescale compiler directive specifies the unit of measurement for time and delay values and the degree of accuracy for delays in all modules that follow this directive until another `timescale compiler directive is read. If there is no `timescale specified or it has been reset by a `resetall directive, the time unit and precision are simulator specific. It shall be an error if some modules have a `timescale specified and others do not."
So it seems the only bug is that in my second example (make simulate-bad), Icarus Verilog should have warned that `timescale was not defined when other modules had defined it. Evan does not recall ANY simulator actually doing this, so maybe it could be a first for Icarus Verilog!
I've suggested downgrading the priority to 3.
Jeremy
I'm betting if we make this a fatal error people will complain. Kind of like implementing a more logical include search path ;-). I personally think the warning is the best we can hope for and that this should be closed. Thanks for spending the time to simplify the example. It's much more efficient for us if we can focus on solving a specific problem vs trying to find the problem and then fixing it. I'll leave this open to see if other have a different opinion, but it will likely be closed fairly soon.
Agreed fatal error would not be a good idea if it doesn't do that on other simulators. Only change to consider is turning the warning on by default - just based on my experience chasing down why my design didn't work.
If we do a waring that is always on it needs to be a subset of what timescale does. Specifically I think it should only warn when you have a netlist that has delays that use both the default timescale and a specified timescale. Inherited timescales work just fine when used correctly. This warning would have also prevented the initial confusion related to the NB delays do not work with 64 bit values. The user didn't really need 64 bit delays, but because of timescale differences a 64 bit delay was being created.
I'm switching this to a feature request. We would like a compilation warning when we find both default delays (no timescale) and delays related to a time scale.
I have submitted a patch that prints a warning when it finds both default and `timescale based delays in a design. It recommends using -Wtimescale to find modules with out a `timescale directive.