[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

Re: gEDA-user: Icarus/NC mismatch -- who's right?



Ah yes... some instrumentation (below) demonstrated it. Thanks!

module junk;

   reg [3:0] pi, ci, fill;
   reg [31:0] my_word;
   reg [31:0] fifo [0:7];

   initial begin
      // Put some data in a fifo.
      fifo[0] = 1;
      fifo[1] = 2;
      fifo[2] = 3;
      fifo[3] = 4;
      fifo[4] = 5;
      fifo[5] = 6;
      fifo[6] = 7;
      fifo[7] = 8;

      // Initialize Producer Index and Consumer Index
      pi <= 4;
      ci <= 0;
      $display("%m : initial done.");
   end

   // Compute FIFO fill level
   always @(pi or ci) begin
      $display("%m : level evaluation.");
      fill = (pi - ci);
      $display("%m : fill updated to %0d",fill);
   end

   // Drain FIFO whenever not empty
   always @(fill) begin
      $display("%m : drain evaluation.");
      while (fill > 0) begin
	 $display("%m : fill seen as %0d",fill);
	
	 read_word(my_word);
	 $display("%m : got word 0x%h\n",my_word);
      end
   end

   task read_word;

      output [31:0] word;

      begin
	 $display("%m : entering task.");
	
	 word = fifo[ci[2:0]];
	 ci <= ci + 1;
	 @(ci);
	 $display("%m : leaving task.");
	
      end
   endtask // read_word

endmodule

Gave me this:

junk : initial done.
junk : level evaluation.
junk : fill updated to 4
junk : drain evaluation.
junk : fill seen as 4
junk.read_word : entering task.
junk.read_word : leaving task.
junk : got word 0x00000001

junk : fill seen as 4
junk.read_word : entering task.
junk : level evaluation.
junk : fill updated to 3
junk.read_word : leaving task.
junk : got word 0x00000002

junk : fill seen as 3
junk.read_word : entering task.
junk : level evaluation.
junk : fill updated to 2
junk.read_word : leaving task.
junk : got word 0x00000003

junk : fill seen as 2
junk.read_word : entering task.
junk : level evaluation.
junk : fill updated to 1
junk.read_word : leaving task.
junk : got word 0x00000004

junk : fill seen as 1
junk.read_word : entering task.
junk : level evaluation.
junk : fill updated to 0
junk.read_word : leaving task.
junk : got word 0x00000005

junk : level evaluation.
junk : fill updated to 15
junk : drain evaluation.
junk : fill seen as 15
junk.read_word : entering task.
junk.read_word : leaving task.
junk : got word 0x00000006

junk : fill seen as 15
junk.read_word : entering task.
junk : level evaluation.
junk : fill updated to 14
junk.read_word : leaving task.


Evan Lavelle wrote:
Mark Schellhorn wrote:

Who's right? It kind of looks like the read_word() task fails to wait for @(ci) before leaving???


They're both right - you've got a race between your fill calculation and the inner read/display loop. for your code to work, the '@(ci)' timing control must lead immediately to a new fill level calculation, but there's no guarantee of this in Verilog. For Icarus, when the first @(ci) is hit, the drain process is rescheduled; for subsequent @(ci)'s, the fill level process is scheduled. This means that you go around the inner loop 5 times in Icarus (but presumably 4 times in NC-Verilog). After 5 iterations the FIFO has underflowed, so you carry on for ever (since regs are unsigned).

Evan