承接上一篇,FIFO的基础理论,理论基础参考《VerilogHDL高级数字设计》,Clifford的论文Simulation and Synthesis Techniques for Asynchronous FIFO Design以及张波的硕士论文:基于SOC异步FIFO的设计与形式验证。
代码为自己独立完成。
顶层代码:
module (
clk_w,rst_w,b_w,full_w,
clk_r,rst_r,b_r,empty_r,
data_in,data_out,rst_n
);
parameter WIDTH_A=8;
parameter WIDTH_D=16;
parameter DEPTH=256;
input clk_w,rst_w,b_w;
input clk_r,rst_r,b_r;
input [WIDTH_D-1:0] data_in;
input rst_n;
output empty_r;
output full_w;
output [WIDTH_D-1:0]data_out;
//write wire
wire [WIDTH_A:0] addr_w,addr_w_g;
wire [WIDTH_A:0] syn_data_w,addr_w_syn;
//read
wire [WIDTH_A:0] addr_r,addr_r_g,syn_data_r,addr_r_syn;
//RAM
wire en_r,en_w;
write_controll #(
.WIDTH_A(WIDTH_A)
)write_control( .clk_w(clk_w),
.rst_w(rst_w),
.b_w(b_w),
.addr_r_syn(addr_r_syn),
.addr_w(addr_w),
.full_w(full_w));
b2g #(
.WIDTH_A(WIDTH_A)
)bin_gray_w(.bin(addr_w),
.gray(addr_w_g));
generate
genvar i;
for (i=0;i<=WIDTH_A;i=i+1) begin:
fast_syn_slow write_syn_read(
.vcc(1'b1),
.data_in(addr_w_g[i]),
.clk_s(clk_r),
.rst_s(rst_r),
.syn_data(syn_data_w[i]));
end
endgenerate
g2b #(
.WIDTH_A(WIDTH_A)
)gray_bin(
.bin(addr_w_syn)
.gray(syn_data_w)
);
read_controll #(
.WIDTH_A(WIDTH_A)
)read_control(.clk_r(clk_r),
.rst_r(rst_r),
.addr_w_syn(addr_w_syn),
.b_r(b_r),
.empty_r(empty_r),
.addr_r(addr_r));
b2g #(
.WIDTH_A(WIDTH_A)
)bin_gray_r( .bin(addr_r),
.gray(addr_r_g));
slow_syn_fast #(
.WIDTH_A(WIDTH_A)
)read_syn_write(
.clk_f(clk_w),
.rst_f(rst_w),
.data_in(addr_r_g),
.syn_data(syn_data_r));
g2b #(
.WIDTH_A(WIDTH_A)
)gray_bin(
.bin(addr_r_syn)
.gray(syn_data_r)
);
assign en_r=(!empty_r)&b_r;
assign en_w=(!full_w)&b_w;
RAM #(
.DEPTH(DEPTH),
.WIDTH_A(WIDTH_A),
.WIDTH_D(WIDTH_D)
)data_path(
.clk_r(clk_r),.en_r(en_r),.addr_r(addr_r),
.clk_w(clk_w),.en_w(en_w),.addr_w(addr_w),
.data_in(data_in),.data_out(data_out),
.rst_n(rst_n));
endmodule
写控制模块
module write_controll(
clk_w,
rst_w,
b_w,//begin write to stack
addr_r_syn,//read address
full_w,
addr_w
);
parameter WIDTH_A=8;
input clk_w,rst_w,b_w;
input [WIDTH_A:0]addr_r_syn;
output [WIDTH_A:0]addr_w;
output full_w;
always@(posedge clk_w)
if (!rst_w)
addr_w<='h00;
else if (b_w&&(!w_full))
addr_w<=addr_w+1'b1;
assign w_full=({~addr_w[WIDTH_A],addr_w[WIDTH_A-1:0]}==addr_r_syn)?1'b1:1'b0;
endmodule
读控制模块
module read_controll(
clk_r,
rst_r,
b_r,//begin read from stack
addr_w_syn,//write address
empty_r,
addr_r);
parameter WIDTH_A=8;
output empty_r ;
output [WIDTH_A:0] addr_r;
input clk_r,rst_r,b_r;
input [WIDTH_A:0]addr_w;
reg [WIDTH_A:0] addr_r;
always@(posedge clk_r)
if (! rst_r)
addr_r<='h00;
else if
addr_r<=addr_r+1'b1;
assign empty_r=(addr_r==addr_w_syn)?1'b1:1'b0;
endmodule
二进制码转格雷码
module b2g (bin,gray);
parameter WIDTH_A=8
output [WIDTH_A:0] gray;
input [WIDTH_A:0] bin;
wire h_b; //high
reg [WIDTH_A-1:0]gray_l;
assign h_b=bin[WIDTH_A];
integer i;
always@(*)
for (i=0;i<WIDTH_A;i=i+1) begin
gray_l[i] = bin[i]^bin[i+1];
end
assign gray={h_b,gray_l};
endmodule
格雷码转二进制码
module g2b(
bin,
gray
);
parameter WIDTH_A=8;
input [WIDTH_A:0] gray;
output [WIDTH_A:0] bin;
reg bin_reg;
integer i;
always @(*)
begin
bin_reg=gray;
for (i=WIDTH_A-1;i>0;i=i-1) begin
bin_reg[i]=bin_reg[i+1]^gray[i];
end
end
assign bin=bin_reg;
endmodule
同步器 慢时钟域到快时钟域
module slow_syn_fast(
clk_f,
rst_f,
data_in,
syn_data
);
parameter WIDTH_A=8;
input clk_f,rst_f;
input [WIDTH_A:0]data_in;
output [WIDTH_A:0]data_out;
reg [WIDTH_A:0] syn_reg_1,syn_reg_2;
always@(posedge clk_f)
if (!rst_f) begin
syn_reg_1<='h00;
syn_reg_2<='h00;
end
else begin
syn_reg_1<=data_in;
syn_reg_2<=syn_reg_1;
end
assign syn_data=syn_reg_2;
endmodule
同步器 快时钟域到慢时钟域
module slow_syn_fast(
vcc,
data_in,
clk_s,
rst_s,
syn_data);
input vcc,clk_s,rst_s;
input data_in;
output syn_data;
reg syn_reg_1,syn_reg_2,syn_reg_3;
wire rst_1,rst_2,rst_3;
assign rst_1=((~data_in)&syn_reg_3)|rst_s;
assign rst_2=((~data_in)&syn_reg_3)|rst_s;
assign rst_3=rst_s;
always@(posedge data_in)
if (!rst_1)
syn_reg_1<=1'b0;
else
syn_reg_1<=vcc;
always@(posedge clk_s)
if (!rst_2)
syn_reg_2<=1'b0;
else
syn_reg_2<=syn_reg_1;
always@(posedge clk_s)
if (!rst_3)
syn_reg_3<=1'b0;
else
syn_reg_3<=syn_reg_2;
assign syn_data=syn_reg_3;
endmodule
RAM
module RAM (
clk_r,en_r,addr_r,
clk_w,en_w,addr_w,
data_in,data_out,
rst_n);
parameter DEPTH = 256;
parameter WIDTH_A = 8;
parameter WIDTH_D = 16;
input clk_r,rst_r,en_r;
input clk_w,rst_w,en_w;
input [WIDTH_A:0]addr_r,addr_w;
input [WIDTH_D-1:0]data_in;
output [WIDTH_D-1:0]data_out;
reg [WIDTH_D-1:0]data_out;
reg [WIDTH_D-1:0] mem[0:DEPTH-1];
integer i;
always@(posedge clk_w)
if (!rst_n) begin
for (i=0;i<DEPTH;i=i+1)
mem[i]<='h0000;
end
else if (en_w)
mem[addr_r]<=data_out;
always@(posedge clk_r)
if (!rst_n)
data_out<='h0000;
else if (en_r)
data_out<=mem[addr_r];
endmodule