FIFO的设计与仿真
本设计参照齐威王大哥的设计,采用模块化的设计方法,每个模块简单易懂,并进行了每个模块的仿真。最后进行顶层设计,编写了测试激励在modisim上仿真正确,
下面给出代码和测试激励,附上一篇比较好的英文文献。
1 module yibu_fifo(wclk,wreset,wdata,wena,rclk,rena,rdata,rreset,full,empty); 2 parameter DSIZE = 8, 3 ASIZE = 4; 4 input wclk,wreset,rclk,rreset; 5 input wena,rena; //写控制信号 读控制信号 6 input [DSIZE-1:0] wdata; //写数据 7 output[DSIZE-1:0] rdata; //读数据 8 output full,empty ;//写满 读空 9 wire [ASIZE:0] wzz, wzz_syn,rzz,rzz_syn; //特别注意 10 wire [ASIZE-1:0] raddr,waddr; //特别注意 11 fifomem U1(rdata, wdata, waddr, raddr, wena,full, wclk); 12 w_full U2(full, waddr, wzz, rzz_syn, wena, wclk, wreset); 13 r_empty U3(empty, raddr, rzz, wzz_syn, rena, rclk, rreset); 14 syn_w2r U4(wzz,rclk,rreset,wzz_syn); 15 syn_r2w U5(wclk,wreset,rzz,rzz_syn); 16 endmodule
module fifomem (rdata, wdata, waddr, raddr, wena,full, wclk); parameter DSIZE = 8, ASIZE = 4; input wclk; input [DSIZE-1:0] wdata; input wena,full; output [DSIZE-1:0] rdata; input [ASIZE-1:0] waddr; input [ASIZE-1:0] raddr; reg [DSIZE-1:0] mem[0:(1<<ASIZE)-1]; //register assign rdata=mem[raddr]; //read always @(posedge wclk) //write if (wena && !full) mem[waddr] <= wdata; endmodule
module r_empty(empty, raddr, rzz, wzz_syn, rena, rclk, rreset); parameter DSIZE = 8, ASIZE = 4; // input rclk, rreset,rena; input [ASIZE:0] wzz_syn; output [ASIZE:0] rzz; output [ASIZE-1:0] raddr; output empty; reg empty; reg [ASIZE:0] rzz; reg [ASIZE:0] rbin; wire [ASIZE:0] rgraynext,rbinnext; //-------------empty产生与raddr产生------------------- always @(posedge rclk or negedge rreset) // GRAYSTYLE2 pointer begin if (!rreset) {rbin, rzz} <= 0; else {rbin, rzz} <= {rbinnext, rgraynext}; end // Memory read-address pointer (okay to use binary to address memory) assign raddr = rbin[ASIZE-1:0]; assign rbinnext = rbin + (rena & ~empty); assign rgraynext = (rbinnext>>1) ^ rbinnext; // FIFO empty when the next rptr == synchronized wptr or on reset assign rempty_val = (rgraynext == wzz_syn); always @(posedge rclk or negedge rreset) begin if (!rreset) empty <= 1'b1; else empty <= rempty_val; end endmodule
module w_full(full, waddr, wzz, rzz_syn, wena, wclk, wreset); parameter DSIZE = 8, ASIZE = 4; input wclk,wreset; input wena; input [ASIZE:0] rzz_syn; output [ASIZE:0] wzz; output full; output [ASIZE-1:0] waddr; reg full; reg [ASIZE:0] wzz; reg [ASIZE:0] wbin; wire [ASIZE:0] wgraynext,wbinnext; //---------------full产生与waddr产生-------------------- always @(posedge wclk or negedge wreset) if (!wreset) {wbin, wzz} <= 0; else {wbin, wzz} <= {wbinnext, wgraynext}; // Memory write-address pointer (okay to use binary to address memory) assign waddr = wbin[ASIZE-1:0]; assign wbinnext = wbin + (wena & ~full); assign wgraynext = (wbinnext>>1) ^ wbinnext; //bin to g assign wfull_val = (wgraynext=={~rzz_syn[ASIZE:ASIZE-1], rzz_syn[ASIZE-2:0]}); // full always @(posedge wclk or negedge wreset) if (!wreset) full <= 1'b0; else full <= wfull_val; endmodule
module syn_r2w(wclk,wreset,rzz,rzz_syn); parameter DSIZE = 8, ASIZE = 4; input wclk,wreset; input [ASIZE:0] rzz; output [ASIZE:0] rzz_syn; reg [ASIZE:0] rzz_syn; reg [ASIZE:0] rzz_syn_1; //两级同步 always @(posedge wclk or negedge wreset) if(!wreset) {rzz_syn,rzz_syn_1} <= 0; else {rzz_syn,rzz_syn_1} <= {rzz_syn_1,rzz}; endmodule
module syn_w2r (wzz,rclk,rreset,wzz_syn); parameter DSIZE = 8, ASIZE = 4; input rclk,rreset; input [ASIZE:0] wzz; output [ASIZE:0] wzz_syn; reg [ASIZE:0] wzz_syn; reg [ASIZE:0] wzz_syn_1; //两级同步 always @(posedge rclk or negedge rreset) if (!rreset) {wzz_syn,wzz_syn_1} <= 0; else {wzz_syn,wzz_syn_1} <= {wzz_syn_1,wzz}; endmodule
module testbench; reg wclk,wreset; reg rclk,rreset; reg rena; reg wena; wire full; wire empty; reg [7:0] wdata; wire [7:0] rdata; reg [7:0] value; yibu_fifo FIFO(wclk,wreset,wdata,wena,rclk,rena,rdata,rreset,full,empty); // read task read_word; begin @(negedge rclk); rena = 1; @(posedge rclk) #5; rena = 0; end endtask //write task write_word; input [7:0] value; begin @(negedge wclk); wdata = value; wena = 1; @(posedge wclk); #5; wdata = 8'hzz; wena = 0; end endtask //write clock initial begin wclk = 0; forever begin #5 wclk = 1; #5 wclk = 0; end end //read clock initial begin rclk = 0; forever begin #10 rclk = 1; #10 rclk = 0; end end // process initial begin test1; end task test1; begin wdata = 8'hzz; wena = 0; rena = 0; wreset = 0; rreset= 0; #10 wreset = 1;rreset=1; #50; //写入10个数据 write_word (8'h01); write_word (8'h02); //正常 write_word (8'h03); write_word (8'h04); write_word (8'h05); write_word (8'h06); write_word (8'h07); write_word (8'h08); write_word (8'h09); write_word (8'h0A); repeat (10) begin read_word; // read 10 end write_word (8'h01); write_word (8'h02); write_word (8'h03); write_word (8'h04); write_word (8'h05); write_word (8'h06); write_word (8'h07); write_word (8'h08); write_word (8'h09); write_word (8'h0A); write_word (8'h0B); write_word (8'h0C); write_word (8'h0D); write_word (8'h0E); write_word (8'h0F); write_word (8'h10); write_word (8'h11); write_word (8'h12); write_word (8'h13); // 写满溢出 repeat (16) begin read_word; // 读空 end end endtask endmodule
2013-03-24