# simulation issue : data get early 1T ###### tags: `verilog` ## issue desciption - this issue is cause by simulation behavior. - the coreclk is come from ioclk and the clock ratio is 1:4 ## root cause the ioclk is early then coreclk. simulation 將ioclk和coreclk分為兩個不同的時間點,依時間順序做計算 Step1. simulation 計算rx_sync_fifo的結果 @ posedge of ioclk rx_sync_fifo <= rx_shift_reg; Step2. simulation 使用 rx_sync_fifo result in step 1. and update to rxdata @ posedge of coreclk rxdata <= rx_sync_fifo; ![](https://hackmd.io/_uploads/r1sJALguh.png) ## code with issue ``` //write by ioclk in negedge and read by coreclk in posedge then simulation result is ok. reg [CLK_RATIO-1:0] rx_sync_fifo; reg rx_sync_fifo_valid; // always @(negedge ioclk or posedge rst) begin //use negedge, simulation result is ok. always @(posedge ioclk or posedge rst) begin //use posedge, the simulation result is early 1T in rxdata if (rst ) begin rx_sync_fifo <= 0; rx_sync_fifo_valid <= 0; end else begin if (rx_start && rx_shift_reg_valid) begin rx_sync_fifo <= rx_shift_reg; rx_sync_fifo_valid <= 1; end else begin rx_sync_fifo <= rx_sync_fifo; rx_sync_fifo_valid <= rx_sync_fifo_valid; end end end reg [CLK_RATIO-1:0] rxdata; reg rxdata_valid; assign rxdata_out = rxdata; assign rxdata_out_valid = rxdata_valid; always @(posedge coreclk or posedge rst) begin if (rst ) begin rxdata <= 0; rxdata_valid <= 0; end else begin rxdata <= rx_sync_fifo; rxdata_valid <= rx_sync_fifo_valid; end end ``` ## fail case : write by ioclk in posedge and read by coreclk in posedge in simulation rx_sync_fifo 值改變後,馬上被 rxdata sample 到,但是這個 code 去做 synthesis 應該是正常的,也就是說出現了 simulation and synthesis result mismatch. ![](https://hackmd.io/_uploads/r1sJALguh.png) ## pass case : write by ioclk in negedge and read by coreclk in posedge rx_sync_fifo 改變的時間提早半個 ioclck ![](https://hackmd.io/_uploads/rk2HTUe_2.png) ## solution 1 (不建議): - this solution imapct timing in rx_shift_reg, 1/2 T margin - write by ioclk posedge - read by ioclk negedge reference the code : write by ioclk in negedge and read by coreclk in posedge then simulation result is ok. ``` reg clk_div4; assign out = clk_div4; reg clk_div2; //for use non-block assigmnet always @(posedge in or negedge resetb) if ( !resetb ) clk_div2 <= 0; else clk_div2 <= ~clk_div2; always @(posedge clk_div2 or negedge resetb) if ( !resetb ) clk_div4 <= 0; else clk_div4 <= ~clk_div4; ``` ``` always @(negedge ioclk or posedge rst) begin //use negedge, simulation result is ok. //always @(posedge ioclk or posedge rst) begin //use posedge, the simulation result is early 1T in rxdata if (rst ) begin rx_sync_fifo <= 0; rx_sync_fifo_valid <= 0; end else begin if (rx_start && rx_shift_reg_valid) begin rx_sync_fifo <= rx_shift_reg; rx_sync_fifo_valid <= 1; end else begin rx_sync_fifo <= rx_sync_fifo; rx_sync_fifo_valid <= rx_sync_fifo_valid; end end end ``` ## solution 2 (better solution): reference [Gotcha 29: Sequential logic that requires blocking assignments](https://hackmd.io/@TonyHo/rJwPNuIu3) ![](https://hackmd.io/_uploads/S14MGQdOh.png) ``` //for use block assigmnet to avoid race condition in simulation always @(posedge in or negedge resetb) if ( !resetb ) clk_div2 = 0; else clk_div2 = ~clk_div2; always @(posedge clk_div2 or negedge resetb) if ( !resetb ) clk_div4 = 0; else clk_div4 = ~clk_div4; ``` ``` always @(posedge ioclk or posedge rst) begin if (rst ) begin rx_sync_fifo <= 0; rx_sync_fifo_valid <= 0; end else begin if (rx_start && rx_shift_reg_valid) begin rx_sync_fifo <= rx_shift_reg; rx_sync_fifo_valid <= 1; end else begin rx_sync_fifo <= rx_sync_fifo; rx_sync_fifo_valid <= rx_sync_fifo_valid; end end end ```