前言
在写完上一篇【芯片前端】仿真向/基于静态随机函数的单比特跨时钟同步器之后,我觉得有必要测试一下在多比特格雷码跨异步的场景下,所以我又做了一下格雷码跨异步的测试;
代码
当然,要先准备二进制转格雷码的代码:
module B2G_Conv #(parameter WD = 4)(
output [WD-1:0] gray,
input [WD-1:0] binary
);
assign gray = (binary >> 1) ^ binary;
endmodule
以及格雷码转二进制的代码:
module G2B_Conv #(parameter WD = 4)(
output reg [WD-1:0] binary,
input [WD-1:0] gray
);
integer k;
always @(gray)
begin
for (k = 0; k < WD; k = k + 1)
binary[k] = ^(gray >> k);
end
endmodule
这两个代码在很久以前的博客进阶之路——二进制与格雷码的相互转换模块设计有比较详细的说明了,因此直接考过来使用了;
然后是跨异步模块,将上篇博客的单比特同步器上层再疯转一下就可以了,大体就是把二进制转格雷码,然后格雷码跨异步,然后格雷码转二进制,代码中的o_cnt_org为观察信号,即完全不考虑亚稳态影响下的接收端行为;
module cnt_sync_bus#(parameter WD = 4) (
//output
output [WD -1:0] o_cnt,
//input
input i_clk,
input i_rst_n,
input [WD -1:0] i_cnt,
input o_clk,
input o_rst_n
);
wire [WD -1:0] i_cnt_gray, o_cnt_gray, o_cnt_gray_org, o_cnt_org;
B2G_Conv #(.WD(WD))
u_b2g(.binary(i_cnt), .gray(i_cnt_gray));
genvar i;
generate
for(i=0; i<WD; i=i+1)begin: GRAY_SYNC
sync_sim_unit u_sync(
.o_sync (o_cnt_gray[i]),
.o_sync_org (o_cnt_gray_org[i]),
.i_clk (i_clk),
.i_rst_n (i_rst_n),
.i_sync (i_cnt_gray[i]),
.o_clk (o_clk),
.o_rst_n (o_rst_n)
);
end
endgenerate
G2B_Conv #(.WD(WD))
u_g2b(.gray(o_cnt_gray), .binary(o_cnt));
G2B_Conv #(.WD(WD))
u_g2b_org(.gray(o_cnt_gray_org), .binary(o_cnt_org));
endmodule
OK,代码就写完了,然后测试一下;
测试
快时钟跨异步到慢时钟的场景:
从图里可以挺明显的看到,有些值由于没有被采样到,直接就没了,比如2(sync里我还打了一拍,因此看看i_cnt延一拍的情况);有些因为亚稳态被吃掉了,比如 8;
满时钟到快时钟的场景:
可以看到确实不会有漏采,但是可能会晚一拍达到正确值。