3
\$\begingroup\$

Code for a counters Verilog file: (Go to: THE LINE OF ISSUE)

module atomic_counters  (
input  wire            clk,
input  wire            reset,
input  wire            trig_i,
input  wire            req_i,
input  wire            atomic_i,
output wire            ack_o,
output wire[31:0]      count_o
);

wire [63:0] count;

// --------------------------------------------------------
// DO NOT CHANGE ANYTHING HERE
// --------------------------------------------------------
reg  [63:0] count_q;

always @(posedge clk or posedge reset)
if (reset)
    count_q[63:0] <= 64'h0;
else
    count_q[63:0] <= count;
// --------------------------------------------------------

// Write your logic here
reg  [63:0] counter;
reg  [31:0] counter_32_upp;
reg  [31:0] counter_32_low;
reg  state;
reg  ack;
reg  ack1;
reg  reset_ff;
reg  reset_ff1;
reg  low_or_high;

localparam FIRST  = 1'd0;
localparam SECOND = 1'd1; 

assign ack_o   = ack;
assign count_o = counter[31:0];


always @(posedge clk or posedge reset) begin 
    if (reset) begin 
        ack            <= 0;
        ack1           <= 0;
    end else begin
        ack <= req_i;           // THE LINE OF ISSUE
        ack1 <= ack;
    end
end 

endmodule

Code for the testbench:

module counters_tb_verilog();
`define TC1

reg  clk;
reg  reset;
reg  trig_i;
reg  req_i;
reg  atomic_i;
reg  tc1_or_tc2;
wire ack_o;
wire [31:0] count_o;

atomic_counters ac  (
.clk        (    clk            ),
.reset      (    reset          ),
.trig_i     (    trig_i         ),
.req_i      (    req_i          ),  
.atomic_i   (    atomic_i       ),      
.ack_o      (    ack_o          ),
.count_o    (    count_o        )
);

always #5 clk <= ~clk;

// Commeting due to sim error
/*
`ifdef TC1
    assign ac.count = 32'h0;
`elsif TC2
    assign ac.count = 32'hfff_ffff5;
`endif
*/

assign ac.count = (tc1_or_tc2) ? 32'hfff_ffff5 : 32'h0;

task test_case_1();
    begin 
        #15;
        trig_i <= 1;
        #100;
        trig_i <= 0;
        
        #50;
        req_i    = 1;
        atomic_i <= 1;
        
        #10;
        req_i    = 0;
        atomic_i <= 0;
        
        #10;
        trig_i   <= 1;
        
        #80;
        req_i    = 1;
        #10;
        atomic_i <= 1;
        #10;
        atomic_i <= 0;
        #10;
        req_i    = 0;
        
        #50;
        $stop;
    end
endtask

initial begin
    clk      <= 1;
    reset    <= 1;
    trig_i   <= 0;
    req_i    <= 0;
    atomic_i <= 0;
    tc1_or_tc2 <= 0;
    
    #15;
    reset    <= 0;
    
    tc1_or_tc2 <= 0;
    test_case_1();
end

endmodule

Waveform of the simulation:

If we focus on the "line of the issue":

ack <= req_i;

Ideally, ack should take the value of req_i at the occurrence of next timing event (in this case, the next posedge of clk, but I see that ack is readily getting the value of req_i without any delay. If you see ack1, it gets the value of ack as expected (after a clock cycle delay), but this should also have been the case for ack, right?

Is this because the req_i is assigned its values from a Verilog task? Is there any missing piece in the Verilog event scheduler/stratified event queue, which I'm not aware of?

sim_wave

\$\endgroup\$
0

2 Answers 2

4
\$\begingroup\$

If you want the design input signals to be synchronous to the clock, you need to drive them from the testbench in a similar manner as to how you drive them in the design, namely:

  1. Using nonblocking assignments (<=)
  2. @(posedge clk) instead of # delays
    task test_case_1();
        begin 
            #15;
            trig_i <= 1;
            #100;
            trig_i <= 0;
            
            repeat (5) @(posedge clk);
            req_i    <= 1;
            atomic_i <= 1;
            
            repeat (1) @(posedge clk);
            req_i    <= 0;
            atomic_i <= 0;

Driving signals from the task is fine.

waves

\$\endgroup\$
2
  • \$\begingroup\$ Somehow, I mistakenly put the BAs for req_i signal, corrected that. The usage of posedge clk is an intuitive way of deciding the order of precedence in assignments of clock and data signals, it makes sure that unless posedge occurs, assignment is not going to take place in the tb. Thanks for the answer. \$\endgroup\$
    – lousycoder
    Feb 18 at 11:13
  • 1
    \$\begingroup\$ @lousycoder: You're welcome. \$\endgroup\$
    – toolic
    Feb 18 at 11:46
4
\$\begingroup\$

A couple of issues.

Use only blocking assignments in making assignments to your clock; do not use nonblocking.

Waveforms do not always give you a good pitcure of exactly when assignments are made in each region of the Verilog event scheduler. It's hard to see if values are coming in before or after the clock edge. In your case req_i is being set before the posedge clk (because you used an NBA to assign the clk) and you are seeing the updated value of ack after the clock edge.

It is a better practice to offset your stimulus by a few ns or use the negedge of the clock. Or make sure both TB and DUT use the same clock, use NBA assignments to ALL sequential signals.

\$\endgroup\$
4
  • \$\begingroup\$ Thanks for answering. Yes, I need to keep it in mind to better use BA for clocking signals. The beauty of both the answers is that they give mutually exclusive solution to the problem, while they both converge very well. \$\endgroup\$
    – lousycoder
    Feb 18 at 11:17
  • \$\begingroup\$ Is it possible to accept more than one answers on EESE? \$\endgroup\$
    – lousycoder
    Feb 18 at 11:19
  • 1
    \$\begingroup\$ The two answers are not exclusive. But mine highlights the problems with visualizing NBAs in waveforms and using an offset that helps visualize the timing better. \$\endgroup\$
    – dave_59
    Feb 18 at 17:36
  • \$\begingroup\$ @lousycoder: You can only accept one answer on SE sites. See also the FAQ \$\endgroup\$
    – toolic
    Feb 19 at 12:05

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.