1
\$\begingroup\$

I am making a simple module that has a 8-bit counter that counts to a specific number that is written to an 8-bit register. It consists of said counter with asynchronous reset, a register with write-enable input which allows the value to be written and also a combining block that compares values from two other modules and gives a pulse. The pulse is also wired back to reset input of a counter.

The code of register (paral_reg8):

module paral_reg8(
  input [7:0] data_in,
  input clk,
  input WE,
  
  output [7:0] data_out
);
  reg [7:0] reg_data = 0;

  always @(posedge clk) begin
    if (WE) begin
      reg_data <= data_in;
    end
  end
  assign data_out = reg_data;
endmodule

Counter (synchro_clock8):

module synchro_clock8(
    input clk,
    input rst,
  
    output reg [7:0] data_out
);
  always @(posedge clk or posedge rst) begin
    if (rst) begin
        data_out <= 0;
    end
    else if (clk == 1) begin
        data_out <= data_out + 1;
    end
  end
endmodule

Comparison module (block):

module block(
  input [7:0] data_in,
  input WE,
  input rst,
  input clk,
  
  output pulse_out
);
  
  wire [7:0] clock_out, reg_out;
  wire clock_rst;
  synchro_clock8 clock(
    .clk(clk),
    .rst(clock_rst),
    .data_out(clock_out)
  );
  paral_reg8 register(
    .data_in(data_in),
    .clk(clk),
    .WE(WE),
    .data_out(reg_out)
  );
  
  assign clock_rst = pulse_out | rst;
  
  assign pulse_out = clock_out == reg_out;
endmodule

I have also made a testbench to test the behaviour of the modules (tb_block):

module tb_block();

reg WE, clk_rst;
reg clk;
reg [7:0] data_in;
wire pulse_out;

block blk(
    .WE(WE),
    .rst(clk_rst),
    .data_in(data_in),
    .clk(clk),
    .pulse_out(pulse_out)
);

always #2 clk = ~clk;
initial begin
    clk <= 0;
    data_in <= 8'd16;
    WE <= 1;
    clk_rst <= 1;
    #14.1 WE <= 0;
    #15.1 clk_rst <= 0;
    #1000
    $finish;
end

endmodule

The problem is when I run behavioral simulation, modules work correctly: Behavioral simulation waveform

However, after running synthesis and running post-synthesis functional simulation, the behavior changes and everything stalls (notice that pulse_out is always 1 as opposed to almost always being 0 before):

Post-synthesis simulation waveform

Also, the register inputs is converted to D, E (as I understand to input and reset) and Q (output) and Q never changes despite the constant value of 10 on D and going clock.

Edit: After implementing and testing solutions provided by toolic (i.e. using synchronized pulse_out and making asynchronous reset on the register and fixing code pattern), I came to conclusion that the problematic module is paral_reg8, which, even though is converted to trigger after synthesis, doesn't save the data_in value (D on second waveform) which results in Q to equal zero. It can be checked if you were to connect data_in directly to comparison: In block:

...
// with paral_register8 removed
always @(posedge clk_comp) begin
    pulse_out <= clock_out == data_in;
end 
...

Is the Verilog code incorrect, or I don't understand the meaning of post-synthesis simulation?

Additional info: I am using Vivado 2019.1, and the target device is Digilent Arty S7-50 (xc7s50csga324-1)

\$\endgroup\$
1
  • \$\begingroup\$ It looks like you edited an answer into your question, which will be confusing to future visitors reading your question. If so, you should post an Answer instead. \$\endgroup\$
    – toolic
    Commented Feb 16 at 13:54

1 Answer 1

2
\$\begingroup\$

I can reproduce your behavioral simulation results with other simulation software. This is based on the code that you provided.

The Verilog code looks fine for the most part, but there are a few things you could improve.

In the synchro_clock8 module, you should not use if (clk == 1) because it is not a common synthesis coding pattern. That may cause a problem when you are synthesizing the code for your FPGA. Carefully look through your synthesis log files for any error or warning messages. Here is a better way to write the code:

module synchro_clock8(
    input clk,
    input rst,
  
    output reg [7:0] data_out
);
  always @(posedge clk or posedge rst) begin
    if (rst) begin
        data_out <= 0;
    end
    else begin
        data_out <= data_out + 1;
    end
  end
endmodule

Another issue is that you are using an asynchronous reset which is the output of combinational logic: pulse_out. This could have glitches which could reset your logic when you don't want it to. It would be better to synchronize the signal to the clock before connecting it to the counter reset input. Since this will incur one clock cycle of latency, you need to understand if that is a problem.

Initializing a signal in the declaration works fine for behavioral simulation:

  reg [7:0] reg_data = 0;

Perhaps your synthesis tool chain supports this, but you should consider using the asynchronous reset signal to reset the reg_data in the always block.

When running post-synthesis simulations, there are other considerations. For example, some simulations can be run with annotated timing delays, while others can be run without delays. Look into your documentation to see what options are available to you.

\$\endgroup\$

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.