デジタルIC設計研究ノート
クロスクロックドメイン同期の問題
2 多比特信号跨时钟域问题_异步FIFO
2非同期FIFO
- 回路図
非同期FIFOの設計は、主に5つの部分で構成されています。
- FIFOメモリ:データを保存するためのデュアルポートRAM
- sync_r2w:シンクロナイザー、読み取りデータポインターを書き込みクロックドメインに同期します
- sync_w2r:シンクロナイザー、書き込みデータポインターを読み取りクロックドメインに同期します
- wptr_full:書き込みポインタと完全な信号を処理するロジック
- rptr_empt:読み取りポインターと空の信号を処理するロジック
- Verilogコード
//----TOP module-------------------------------
module asyncfifo_r1#(
parameter ADDRSIZE = 4,
parameter DATASIZE = 8
)
(
//----write signal ----------------------------
input wclk,
input wrst,
input [DATASIZE-1:0] wdata,
input winc,
output wfull,
//----read signal ----------------------------
input rclk,
input rrst,
input rinc,
output empty,
output [DATASIZE-1:0] rdata
);
wire [ADDRSIZE-1:0] waddr;
wire [ADDRSIZE-1:0] raddr;
wire [ADDRSIZE:0] wptr, rptr, wq2_rptr, rq2_wptr;
FIFOMEM_R0 U1 (
.wclk (wclk),
.wdata(wdata),
.rdata(rdata),
.waddr (waddr),
.raddr(raddr),
.wclken(winc),
.wfull (wfull)
);
syn_r2w U2 (
.wclk(wclk),
.rst_n(wrst),
.wq2_rptr(wq2_rptr),
.rptr(rptr)
);
sync_w2r_r1 U3 (
.rclk(rclk),
.rst_n(rrst),
.rq2_wptr(rq2_wptr),
.wptr(wptr)
);
wptr_full_r1 U4(
.wclk(wclk),
.wrst_n(wrst),
.winc(winc),
.wq2_rptr(wq2_rptr),
.wfull(wfull),
.waddr(waddr),
.wptr(wptr)
);
rptr_empty U5(
.rclk(rclk),
.rst_n(rrst),
.rinc(rinc),
.rq2_wptr(rq2_wptr),
.rempty(empty),
.raddr(raddr),
.rptr(rptr)
);
endmodule
1.FIFOメモリ
- FPGAでは、ブロックRAMまたは分散RAMを使用できます。
- Verilogコード
module FIFOMEM_R0#(
parameter DATASIZE = 8, // memory data word width
parameter ADDRSIZE = 4 // memory address bits
)
(
input wclk,
input [DATASIZE-1:0] wdata,
input [ADDRSIZE-1:0] waddr,
input [ADDRSIZE-1:0] raddr,
input wclken,
input wfull,
output [DATASIZE-1:0] rdata
);
localparam DEPTH = 1<< ADDRSIZE;
reg [DATASIZE-1:0] mem [0:DEPTH-1];
//read----------------------------------
assign rdata = mem[raddr];
//write---------------------------------
always@(posedge wclk)begin
if(wclken && !wfull) //写有效且未写满
mem[waddr] <= wdata;
end
endmodule
- Modelsimシミュレーション
注:メモリアドレスはバイナリアドレスです。メモリアドレスがいっぱいか空かを判断するためのアドレスは、グレイコードアドレスです。
2. sync_r2w
- Verilogコード
module syn_r2w#(
parameter ADDRSIZE = 4
)
(
input wclk,
input rst_n,
input [ADDRSIZE:0] rptr,
output reg [ADDRSIZE:0] wq2_rptr
);
reg [ADDRSIZE:0] wq1_rptr;
always@(posedge wclk or negedge rst_n)begin
if(!rst_n)begin
wq1_rptr <= 0;
wq2_rptr <= 0;
end else begin
wq1_rptr <= rptr;
wq2_rptr <= wq1_rptr;
end
end
endmodule
- Modelsimシミュレーション
3. sync_w2r
- Verilogコード
module sync_w2r_r1#(
parameter ADDRSIZE = 4
)
(
input rclk,
input rst_n,
input [ADDRSIZE:0] wptr,
output reg [ADDRSIZE:0] rq2_wptr
);
reg [ADDRSIZE:0] rq1_wptr;
always@(posedge rclk or negedge rst_n)begin
if(!rst_n)begin
rq1_wptr <= 0;
rq2_wptr <= 0;
end else begin
rq1_wptr <= wptr;
rq2_wptr <= rq1_wptr;
end
end
endmodule
- Modelsimシミュレーション
4. wptr_full
-
完全な信号生成ロジックは、書き込みクロックドメインに配置されます。Nビットグレイコードの下位N-1ビットは対称であるため、読み取りポインタと書き込みポインタを比較する場合、次のように、N番目のビットが等しくなく下位のN-1ビットが等しいと判断するだけでは不十分です。バイナリコード、および偽の完全な信号が生成されます。正しいフル信号を生成するには、次の3つの条件を同時に判断する必要があります
。N-1番目のビットが等しくない
N-2番目のビットが等しくない
下位のN-3ビットがすべて等しく
、空信号も同様です。完全な信号のレジスタ出力の場合、ポインタの書き込みの場合、wptrの代わりにwgraynextを使用できます(wptrはwgraynextより1ビート遅い)。 -
Verilogコード
module wptr_full_r1#(
parameter ADDRSIZE = 4
)
(
input wclk,
input wrst_n,
input winc,
input [ADDRSIZE:0] wq2_rptr,
output reg wfull,
output [ADDRSIZE-1:0] waddr,
output reg [ADDRSIZE:0] wptr
);
wire wfull_val;
wire [ADDRSIZE:0] wbinnext;
wire [ADDRSIZE:0] wgraynext;
reg [ADDRSIZE:0] wbin;
//----write address---------------//
assign waddr = wbin[ADDRSIZE-1:0];
//----bin2gray--------------------//
assign wbinnext = wbin + (winc & ~wfull);
assign wgraynext = (wbinnext>>1)^ wbinnext;
//----gray pointer----------------//
always@(posedge wclk or negedge wrst_n)begin
if(!wrst_n)begin
wptr <= 0;
wbin <= 0;
end else
begin
wptr <= wgraynext;//gray
wbin <= wbinnext;
end
end
//----write full------------------//
assign wfull_val = ((wgraynext[ADDRSIZE] != wq2_rptr[ADDRSIZE]) &&
(wgraynext[ADDRSIZE-1] != wq2_rptr[ADDRSIZE-1]) &&
(wgraynext[ADDRSIZE-2:0] == wq2_rptr[ADDRSIZE-2:0]));
always@(posedge wclk or negedge wrst_n)begin
if(!wrst_n)
wfull <= 0;
else
wfull <= wfull_val;
end
endmodule
- Modelsimシミュレーション
5.rptr_empty - ヌル信号の生成ロジックは、読み取りクロックドメインに配置されます。読み取りポインターと書き込みポインターが等しいかどうかを直接比較するだけで十分です(読み取りポインターは書き込みポインターに追いつきます)。ここでの書き込みポインターは、読み取りクロックドメインに同期された書き込みポインターであることに注意してください。空の信号のレジスタ出力の場合、
比較時にrptrの代わりにrgraynextを使用してポインタを読み取ることができます(rptrはrgraynextより1ビート遅れています)。 - Verilogコード
module rptr_empty#(
parameter ADDRSIZE = 4
)
(
input rclk,
input rst_n,
input rinc,
input [ADDRSIZE:0] rq2_wptr,
output reg rempty,
output [ADDRSIZE-1:0] raddr,
output reg [ADDRSIZE:0] rptr //gray
);
reg [ADDRSIZE:0] rbin;
wire [ADDRSIZE:0] rgraynext;
wire [ADDRSIZE:0] rbinnext;
wire rempty_val;
//----gray pointer---------------------------------------//
always@(posedge rclk or negedge rst_n)begin
if(!rst_n)begin
rbin <= 0;
rptr <= 0;
end else
begin
rbin <= rbinnext;
rptr <= rgraynext;
end
end
//----memory address-------------------------------------//
assign raddr = rbin[ADDRSIZE-1:0];
//----bin2gray-------------------------------------------//
assign rbinnext = rbin + (rinc & ~rempty);
assign rgraynext = (rbinnext>>1)^rbinnext;
//----FIFO empty when rptr == ayncronized wptr-----------//
assign rempty_val = (rgraynext == rq2_wptr);
always@(posedge rclk or negedge rst_n)begin
if(!rst_n)begin
rempty <= 0;
end else
rempty <= rempty_val;
end
endmodule
- Modelsimシミュレーション
【注意】:個人学習メモ、間違いがありましたら、お気軽に教えてください、丁寧です~~~