When I simulate the following module with NC I get the expected result, 
when I simulate with Icarus 0.8.1 the simulator goes into an infinite 
zero-time loop.
What I expect to see is that after the initial block puts four entries 
into fifo, the always @(fill) block reads them out one at a time until 
fifo is empty. At this point there is nothing else to do so the 
simulation ends.
// -------------------- Module begin
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;
   end
   // Compute FIFO fill level
   always @(pi or ci) begin
      fill = (pi - ci);
   end
   // Drain FIFO whenever not empty
   always @(fill) begin
      while (fill > 0) begin
     read_word(my_word);
     $display("%m : got word 0x%h",my_word);
      end
   end
   task read_word;
      output [31:0] word;
      begin
     word = fifo[ci[15:0]];
     ci <= ci + 1;
     @(ci);
      end
   endtask // read_word
endmodule
// -------------------- Module end
NC-verilog log file:
ncsim> run
junk : got word 0x00000001
junk : got word 0x00000002
junk : got word 0x00000003
junk : got word 0x00000004
ncsim: *W,RNQUIE: Simulation is complete.
Icarus log file:
junk : got word 0x00000001
junk : got word 0x00000002
junk : got word 0x00000003
junk : got word 0x00000004
junk : got word 0x00000005
junk : got word 0x00000006
junk : got word 0x00000007
junk : got word 0x00000008
junk : got word 0x00000001
junk : got word 0x00000002
junk : got word 0x00000003
junk : got word 0x00000004
etc. etc. forever
Who's right? It kind of looks like the read_word() task fails to wait 
for @(ci) before leaving???
     Mark