0

I'm trying to implement the nand2tetris project in verilog and am hitting a wall using icarus verilog. In the book they implement the DFF as so, q(t) = d(t-1). The output at the current time is the input at the previous posedge clk. Here is the DFF I realized.

module Dff (
    output reg q,
    input data, clk
);

    reg p;
    reg o;

    always @(posedge clk) begin
        o <= data;
        q <= p;
    end

    always @(negedge clk) begin
        p <= o;
    end

endmodule

This DFF seems to work just fine when I test it directly. But when I reused it to create a Bit (a memory cell), it gets crazy. Interestingly, the craziness is different using Icarus Verilog or EDAPlayground (which uses VCS).

module Mux (out, a, b, sel);
    input a, b;
    input sel;
    output reg out;

    assign out = ~sel ? a : b;
endmodule

module Bit (
    output out,
    input data, load, clk
);

    Mux m0(in, out, data, load);
    Dff d0(out, in, clk);
endmodule

Icarus Verilog output

 data | load | clk | out
------+------+-----+-----
    0 |    1 |   1 |   x
    0 |    1 |   0 |   x
    1 |    1 |   1 |   x
    1 |    1 |   0 |   x
    0 |    1 |   1 |   1
    0 |    1 |   0 |   1
    0 |    0 |   1 |   0
    0 |    0 |   0 |   0
    1 |    1 |   1 |   0
    1 |    1 |   0 |   0
    0 |    0 |   1 |   0   # !?!?!
    0 |    0 |   0 |   0   # it should be 1 here.

EDAPlayground output

 data | load | clk | out
------+------+-----+-----
    0 |    1 |   1 |   x
    0 |    1 |   0 |   x
    1 |    1 |   1 |   x
    1 |    1 |   0 |   x
    0 |    1 |   1 |   1
    0 |    1 |   0 |   1
    0 |    0 |   1 |   0
    0 |    0 |   0 |   0
    1 |    1 |   1 |   1  # !?!?!
    1 |    1 |   0 |   1  # it should be 0 here.
    0 |    0 |   1 |   1
    0 |    0 |   0 |   1

The code is testable on EDAPlayground.

Matthew Taylor
  • 13,365
  • 3
  • 17
  • 44
greut
  • 4,305
  • 1
  • 30
  • 49
  • I'd say your DFF is not working correctly, as it uses three D flip-flops when synthesised. – Qiu Aug 17 '15 at 15:16
  • 2
    I dont know if I can properly explain exactly what is happening in both cases but Ill boil it down here: because you are not using non-blocking assignment for your `initial` block (ie `load <= 0`, not `load = 0`, treat it like its coming out of another register somewhere), simulation order of the various blocks in your design (the `always` in the DFF, the `assign` in the Mux and the `always` clocking block and `initial` stimulus block) matters. Ie, when the updates from the `initial` block happen are not happening when you want them to due to the blocking assignment. – Unn Aug 17 '15 at 16:20
  • DFF is usually sensitive to one edge of the clock, either posedge or negedge. Why are you using both? – Ari Aug 17 '15 at 18:31
  • 1
    Your DFF almost looks like a latches. "q(t) = d(t-1)" is simply `always @(posedge clk) begin q <= data; end`. As Unn pointed out, your `data` and `load` stimuli should be non-blocking so it doesn't cause a race condition with the clock. Alternatively, add a little delay so the simultaneous. Point being the new values for the stimuli must be updated after the clock. – Greg Aug 17 '15 at 18:37
  • To summarize: my test cases are badly designed hence the code is crap and the behavior hardly predictable. Big TA! – greut Aug 17 '15 at 19:25

1 Answers1

1

Thanks to Uun and Greg, here is how I fixed the issue. The code is on EDA playground

A DFF can be simpler.

module Dff (
    output reg q,
    input data, clk
);
    always @(posedge clk) begin
        q <= data;
    end
endmodule

Then the tests are the culprits. Blocking assignments are causing confusion. A simple way to fix that is to change all the = by <= like that:

module Bit_tb;
    reg clk = 0;
    reg data = 0;
    reg load = 1;
    wire out;

    initial begin
        #2
        data <= 1;

        #2
        load <= 0;  // load = 0; /!\ would be blocking before
        data <= 0;  // data = 0; doing this line. /!\

        #2
        $finish;
    end
endmodule
toolic
  • 57,801
  • 17
  • 75
  • 117
greut
  • 4,305
  • 1
  • 30
  • 49