Search code examples
verilog

Verilog posedge register manipulaton


I have stumbled upon an unusual behavior in verilog. I have this very simple module test

`timescale 1ns / 1ps

module test (
    input clk,
    input left,
    output right
);
    reg right_ = 0;
    assign right = right_;
    always @(posedge clk) begin
        right_ <= left;
    end
endmodule

All it does is transfer the input value to the output on the next posedge.

Now let us see the test bench I wrote and discus what it is actually doing!

In this testbench I have instantiated 2 modules test and connected them one after another. What seems weird to me is that the first module seems to immediately transfer the value on its left to the rights, however the next one patiently waits and does the following only after one clock cycle.

`include "test.v"

`timescale 1ns / 1ps

module test_tb;

// Inputs
reg clk = 1;
reg left = 0;

// Outputs
wire right;
wire out;

// Clock gen
always  begin
    #1;
    clk = ~clk;
end

// Instantiate modules
test t1
(
    .clk(clk),
    .left(left),
    .right(right)
);

test t2
(
    .clk(clk),
    .left(right),
    .right(out)
);


initial begin
    $dumpfile(`VCD_FILE);
    $dumpvars(0, test_tb);
    #10;
    left = 1;
    #11;
    $finish;
end


endmodule

Here is a screenshot from gtkWave to have a better picture: gtkWave

  • How can I make the first module wait too? And how is this even possible?

  • Do the same solutions apply in FPGA Hardware?

Thanks in advance!


Solution

  • Stimulus driven to a DUT (design under test) from a testbench should be modeled synchronously, using techniques similar to those used to model synchronous behavior in RTL.

    Use the Verilog @(posedge clk) statement and a non-blocking assignment operator <= to synchronize the stimulus to the DUT at the boundary.

    Like this.

    initial begin
        // #<some_delay you might want>
        @(posedge clk);
        left <= 1;
        #11;  // This number does not mater now its setting the test run time 
        $finish;
    end
    

    There are different ways to accomplish the same.

    Moving the stimulus away from the clock edge is the idea with this one. The away point does not have to be the opiate edge, even though it is in this case, because moving the minimum sim time (#1) moves to the other edge.

    initial begin
        #11; // changed from 10 to 11 to move off the active clk edge
        left = 1;
        #11;  // This number does not mater now its setting the test run time 
        $finish;
    end    
    

    A SystemVerilog interface with clocking block is yet another solution to synchronize testbench stimulus to the DUT. The interface\w clocking block pattern is specifically designed to address testbench synchronization with the DUT. This solution is often used with object oriented testbench's and forms the interface between the domains of objects and RTL modeling.

    Keep in mind these approaches are RTL behavioral simulations which model hardware flips flops according to the Verilog specification IEEE 1364 2005 Section 11 Scheduling Semantics (not setup and hold time).

    Hardware (FPGA, ASIC, TTL, CMOS, ...) flip flops (ff) operate within the limits of the physical technologies setup and hold times for the sampled data. In hardware, the ff output at the next clock edge will change to the data that was present on the ff d pin starting at Tsu before the same clock edge. To obtain synchronous behavior at the first ff in hardware, then apply input data such that the first ff's setup and hold times are met.

    Logic designers and verification specialists need to understand where module inputs originate and if they are synchronous to the clock of interest. If the inputs originate from other parts of the fpga on the same clock then the inputs are likely to be synchronous, or are easy to synchronize using another ff. If local inputs are coming from a pin/pad outside the FPGA, then find out from the hardware engineer about how they are timed. If the inputs are known to change asynchronously to the clock of interest, then clock domain crossing (CDC) techniques are needed to synchronize the inputs. CDC is a broad area with special cases depending on context.