B-Lang-org/bsc

Bluesim VCD for mkLFIFO has wrong FULL_N value

Open

#519 opened on Dec 4, 2022

View on GitHub
 (4 comments) (0 reactions) (0 assignees)Haskell (1,108 stars) (178 forks)batch import
bluesimbuggood first issue

Description

As reported on the b-lang-discuss mailing list, for the BSV code below, the VCD file generated when simulating with Bluesim has a different value for the FULL_N port of the mkLFIFO module than the VCD from Verilog simulation.

At a clock edge, Bluesim steps through all the rules that are schedule to fire, executing them in order. Thus, Bluesim is able to see the state of the system at all the micro-steps that happen: a FIFO may start full (FULL_N is False), then a rule dequeues from the FIFO (FULL_N becomes True), and then another rule enqueues into the FIFO (FULL_N becomes False again). For someone debugging a design, it could be useful to see all of these values. However, we have chosen that Bluesim VCDs should match the VCDs generated from Verilog simulation. The Verilog is simulating closer to what happens in the hardware: after the clock edge, the signals settle down into one value, which is latched at the next edge. For typical submodules, the values represent the view of the state at the start of the clock cycle; however, for "loopy" modules (like mkLFIFO), the values are the ones seen at some later micro-step. Thus, in the Verilog simulation, FULL_N has the value after the first rule has executed (when FULL_N goes to True) and not the value at the start or end of the execution. Bluesim should generate a VCD file that matches this behavior of Verilog.

This bug is only in the dumping of the VCD; the behavior of the Bluesim simulation is correct. In Bluesim, there is a C++ class for modules, which has functions for executing rules and methods, and separately it has a function to dump the VCD -- a function which is called at the end of the execution of all rules at a clock edge. Here, it's just that dump function which is buggy. And this is because Bluesim shares one C++ class for all FIFO modules. When instantiated, the constructor has arguments that specify which of the many FIFOs that instance should be. One is for "loopy" behavior. In the VCD dump function, there are if-else statements to pick how to dump the VCD depending on the type of FIFO, but it is missing if-statements that check for loopy. We should fix that and also add a test case.

Here is the example that illustrates the difference:

import StmtFSM::*;
import FIFO::*;
(* synthesize *)
module mkTb (Empty);
   FIFO#(Maybe#(UInt#(8))) a1a2 <- mkLFIFO,
   a2a3 <- mkLFIFO;
   Reg#(UInt#(8)) x <- mkReg(23);
   
   // <A1>
   rule a1_stage;
      a1a2.enq(tagged Valid x);
      x <= x + 1;
   endrule
   
   // <A2>
   rule a2_stage;
      let a2 = a1a2.first; a1a2.deq;
      a2a3.enq(a2);
   endrule
 
   // <A3>
   rule a3_stage;
      let a3 = a2a3.first; a2a3.deq;
   endrule
   
   Stmt main = seq
      delay(10);
      $finish(0);
   endseq;
   mkAutoFSM(main);
 
endmodule: mkTb

Contributor guide