VL45. 异步FIFO
描述
请根据题目中给出的双口RAM代码和接口描述,实现异步FIFO,要求FIFO位宽和深度参数化可配置。
双口RAM端口说明:
端口名 |
I/O |
描述 |
wclk |
input |
写数据时钟 |
wenc |
input |
写使能 |
waddr |
input |
写地址 |
wdata |
input |
输入数据 |
rclk |
input |
读数据时钟 |
renc |
input |
读使能 |
raddr |
input |
读地址 |
rdata |
output |
输出数据 |
同步FIFO端口说明:
端口名 |
I/O |
描述 |
wclk |
input |
写时钟 |
rclk |
input |
读时钟 |
wrstn |
input |
写时钟域异步复位 |
rrstn |
input |
读时钟域异步复位 |
winc |
input |
写使能 |
rinc |
input |
读使能 |
wdata |
input |
写数据 |
wfull |
output |
写满信号 |
rempty |
output |
读空信号 |
rdata |
output |
读数据 |
module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule
输入描述
input wclk ,输出描述
output wire wfull ,Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata , output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata ); parameter ADDR_SIZE = $clog2(DEPTH);//深度对2取对数,得到写地址的位宽 //-----------------二进制读写地址生成-------------------------------------------------- reg[ADDR_SIZE:0] waddr_bin;//写地址 reg[ADDR_SIZE:0] raddr_bin;//读地址 always@(posedge wclk or negedge wrstn)begin if(!wrstn) begin waddr_bin <= 0 ; end else begin if(winc && (~wfull)) begin waddr_bin <= waddr_bin + 1 ;//每当写时钟沿到来,写使能有效且未写满时,写地址加一 end end end always@(posedge rclk or negedge rrstn)begin if(!rrstn) begin raddr_bin <= 0 ; end else begin if(rinc && (~rempty)) begin raddr_bin <= raddr_bin + 1 ;//每当读时钟沿到来,读使能有效且未读空时,读地址加一 end end end //-----------二进制读写地址转换为格雷码读写指针---------------------------------------- wire[ADDR_SIZE:0] waddr_gray;//格雷码写地址 wire[ADDR_SIZE:0] raddr_gray;//格雷码读地址 reg[ADDR_SIZE:0] wptr;//写指针 reg[ADDR_SIZE:0] rptr;//读指针 assign waddr_gray = waddr_bin ^ (waddr_bin >> 1 ) ; assign raddr_gray = raddr_bin ^ (raddr_bin >> 1 ) ; always@(posedge wclk or negedge wrstn)begin if(!wrstn) begin wptr <= 0 ; end else begin wptr <= waddr_gray; end end always@(posedge rclk or negedge rrstn)begin if(!rrstn) begin rptr <= 0 ; end else begin rptr <= raddr_gray; end end //------------格雷码读写指针打两拍同步-------------------------------------------------- reg[ADDR_SIZE:0] rptr_wclk_buffer; reg[ADDR_SIZE:0] rptr_wclk_syn; reg[ADDR_SIZE:0] wptr_rclk_buffer; reg[ADDR_SIZE:0] wptr_rclk_syn; always@(posedge wclk or negedge wrstn)begin if(!wrstn) begin rptr_wclk_buffer <= 0 ; rptr_wclk_syn <= 0 ; end else begin rptr_wclk_buffer <= rptr ; rptr_wclk_syn <= rptr_wclk_buffer; end end always@(posedge rclk or negedge rrstn)begin if(!rrstn) begin wptr_rclk_buffer <= 0 ; wptr_rclk_syn <= 0 ; end else begin wptr_rclk_buffer <= wptr ; wptr_rclk_syn <= wptr_rclk_buffer ; end end //------------空满判断----------------------------------------------------------------- assign rempty = (wptr_rclk_syn == rptr ) ;//当读写指针相等时,说明FIFO已读空 assign wfull = (wptr == {~ rptr_wclk_syn[ADDR_SIZE : ADDR_SIZE-1] , rptr_wclk_syn[ADDR_SIZE-2 : 0]}) ;//当读写指针最高两位相反,其余低位都相同时,说明FIFO已写满 //------双口RAM调用------------------------------ wire wen;//RAM写使能驱动 wire ren;//RAM读使能驱动 wire [ADDR_SIZE-1:0] waddr; wire [ADDR_SIZE-1:0] raddr; assign wen = winc & !wfull; assign ren = rinc & !rempty; assign waddr = waddr_bin[ADDR_SIZE-1:0]; assign raddr = raddr_bin[ADDR_SIZE-1:0]; dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH) ) dual_port_RAM( .wclk (wclk), .wenc (wen), .waddr(waddr), //深度对2取对数,得到地址的位宽。 .wdata(wdata), //数据写入 .rclk (rclk), .renc (ren), .raddr(raddr), //深度对2取对数,得到地址的位宽。 .rdata(rdata) //数据输出 ); endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata , output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata ); wire r_en,w_en; wire [4:0] w_addr,r_addr; wire [$clog2(DEPTH):0] waddr_gray,raddr_gray; reg [4:0] waddr,raddr; reg [$clog2(DEPTH):0] w_addr_gray,r_addr_gray; reg [$clog2(DEPTH):0] w_addr_gray_d1,r_addr_gray_d1,w_addr_gray_d2,r_addr_gray_d2; assign w_en = winc & ~wfull; assign r_en = rinc & !rempty; always@(posedge wclk or negedge wrstn) begin if(!wrstn) begin waddr <= 5'd0; w_addr_gray<= 5'd0; end else begin waddr <= w_addr; w_addr_gray<=waddr_gray; end end always@(posedge rclk or negedge rrstn) begin if(!rrstn) begin raddr <= 5'd0; r_addr_gray<= 5'd0; end else begin raddr <= r_addr; r_addr_gray<=raddr_gray; end end assign w_addr = waddr+w_en; assign r_addr = raddr+r_en; assign waddr_gray = waddr ^ (waddr >> 1); assign raddr_gray = raddr ^ (raddr >> 1); always@(posedge rclk or negedge rrstn) begin if(!rrstn) begin w_addr_gray_d1 <= 4'd0; w_addr_gray_d2 <= 4'd0; end else begin w_addr_gray_d1 <= w_addr_gray; w_addr_gray_d2 <= w_addr_gray_d1; end end always@(posedge wclk or negedge wrstn) begin if(!wrstn) begin r_addr_gray_d1 <= 4'd0; r_addr_gray_d2 <= 4'd0; end else begin r_addr_gray_d1 <= r_addr_gray; r_addr_gray_d2 <= r_addr_gray_d1; end end assign rempty = r_addr_gray == w_addr_gray_d2; assign wfull = w_addr_gray == {~r_addr_gray_d2[4:3],r_addr_gray_d2[2:0]}; dual_port_RAM u_dual_port_RAM( .wclk (wclk), .wenc (w_en), .waddr (waddr[$clog2(DEPTH)-1:0]), .wdata (wdata), .rclk (rclk), .renc (r_en), .raddr (raddr[$clog2(DEPTH)-1:0]), .rdata (rdata) ); endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata , output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata ); localparam ADDR_WIDTH = $clog2(DEPTH); // write reg [WIDTH-1:0] mem [DEPTH-1:0]; reg [ADDR_WIDTH:0] waddr; wire full; always@(posedge wclk or negedge wrstn)begin if(!wrstn) waddr <= 'b0; else if(winc & ~full) waddr <= waddr + 1'b1; else waddr <= waddr; end reg [ADDR_WIDTH:0] waddr_gray_r; wire [ADDR_WIDTH:0] waddr_gray; assign waddr_gray = waddr ^ (waddr>>1); always@(posedge wclk or negedge wrstn)begin if(!wrstn) waddr_gray_r <= 'b0; else waddr_gray_r <= waddr_gray; end reg [ADDR_WIDTH:0] raddr2w [1:0]; always@(posedge wclk or negedge wrstn)begin if(!wrstn) begin raddr2w[0] <= 'b0; raddr2w[1] <= 'b0; end else begin raddr2w[0] <= raddr_gray_r; raddr2w[1] <= raddr2w[0]; end end assign wfull = ({~raddr2w[1][ADDR_WIDTH:ADDR_WIDTH-1],raddr2w[1][ADDR_WIDTH-2:0]} == waddr_gray_r) ? 1'b1 : 1'b0; assign full = wfull; always@(posedge wclk)begin if(winc & ~full) mem[waddr[ADDR_WIDTH-1:0]] <= wdata; end //read reg [ADDR_WIDTH:0] raddr; wire empty; always@(posedge rclk or negedge rrstn)begin if(!rrstn) raddr <= 'b0; else if(rinc & ~empty) raddr <= raddr + 1'b1; else raddr <= raddr; end wire [ADDR_WIDTH:0] raddr_gray; reg [ADDR_WIDTH:0] raddr_gray_r; assign raddr_gray = raddr ^ (raddr>>1); always@(posedge rclk or negedge rrstn)begin if(!rrstn) raddr_gray_r <= 'b0; else raddr_gray_r <= raddr_gray; end reg [ADDR_WIDTH:0] waddr2r [1:0]; always@(posedge rclk or negedge rrstn)begin if(!rrstn) begin waddr2r[0] <= 'b0; waddr2r[1] <= 'b0; end else begin waddr2r[0] <= waddr_gray_r; waddr2r[1] <= waddr2r[0]; end end assign empty = (waddr2r[1] == raddr_gray_r) ? 1'b1 : 1'b0; assign rempty = empty; reg [WIDTH-1:0] rdata_o; always@(posedge rclk)begin if(rinc & ~empty) rdata_o <= mem[raddr[ADDR_WIDTH-1:0]]; end assign rdata = rdata_o; endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata , output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata ); parameter ADDR_WIDTH = $clog2(DEPTH); /**********************addr bin gen*************************/ reg [ADDR_WIDTH:0] waddr_bin; reg [ADDR_WIDTH:0] raddr_bin; always @(posedge wclk or negedge wrstn) begin if(~wrstn) begin waddr_bin <= 'd0; end else if(!wfull && winc)begin waddr_bin <= waddr_bin + 1'd1; end end always @(posedge rclk or negedge rrstn) begin if(~rrstn) begin raddr_bin <= 'd0; end else if(!rempty && rinc)begin raddr_bin <= raddr_bin + 1'd1; end end /**********************addr gray gen*************************/ wire [ADDR_WIDTH:0] waddr_gray; wire [ADDR_WIDTH:0] raddr_gray; reg [ADDR_WIDTH:0] wptr; reg [ADDR_WIDTH:0] rptr; assign waddr_gray = waddr_bin ^ (waddr_bin>>1); assign raddr_gray = raddr_bin ^ (raddr_bin>>1); always @(posedge wclk or negedge wrstn) begin if(~wrstn) begin wptr <= 'd0; end else begin wptr <= waddr_gray; end end always @(posedge rclk or negedge rrstn) begin if(~rrstn) begin rptr <= 'd0; end else begin rptr <= raddr_gray; end end /**********************syn addr gray*************************/ reg [ADDR_WIDTH:0] wptr_buff; reg [ADDR_WIDTH:0] wptr_syn; reg [ADDR_WIDTH:0] rptr_buff; reg [ADDR_WIDTH:0] rptr_syn; always @(posedge wclk or negedge wrstn) begin if(~wrstn) begin rptr_buff <= 'd0; rptr_syn <= 'd0; end else begin rptr_buff <= rptr; rptr_syn <= rptr_buff; end end always @(posedge rclk or negedge rrstn) begin if(~rrstn) begin wptr_buff <= 'd0; wptr_syn <= 'd0; end else begin wptr_buff <= wptr; wptr_syn <= wptr_buff; end end /**********************full empty gen*************************/ assign wfull = (wptr == {~rptr_syn[ADDR_WIDTH:ADDR_WIDTH-1],rptr_syn[ADDR_WIDTH-2:0]}); assign rempty = (rptr == wptr_syn); /**********************RAM*************************/ wire wen ; wire ren ; wire wren;//high write wire [ADDR_WIDTH-1:0] waddr; wire [ADDR_WIDTH-1:0] raddr; assign wen = winc & !wfull; assign ren = rinc & !rempty; assign waddr = waddr_bin[ADDR_WIDTH-1:0]; assign raddr = raddr_bin[ADDR_WIDTH-1:0]; dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH) )dual_port_RAM( .wclk (wclk), .wenc (wen), .waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。 .wdata(wdata), //数据写入 .rclk (rclk), .renc (ren), .raddr(raddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。 .rdata(rdata) //数据输出 ); endmodule
Verilog 解法, 执行用时: 0ms, 内存消耗: 0KB, 提交时间: 2022-08-06
`timescale 1ns/1ns /***************************************RAM*****************************************/ module dual_port_RAM #(parameter DEPTH = 16, parameter WIDTH = 8)( input wclk ,input wenc ,input [$clog2(DEPTH)-1:0] waddr //深度对2取对数,得到地址的位宽。 ,input [WIDTH-1:0] wdata //数据写入 ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr //深度对2取对数,得到地址的位宽。 ,output reg [WIDTH-1:0] rdata //数据输出 ); reg [WIDTH-1:0] RAM_MEM [0:DEPTH-1]; always @(posedge wclk) begin if(wenc) RAM_MEM[waddr] <= wdata; end always @(posedge rclk) begin if(renc) rdata <= RAM_MEM[raddr]; end endmodule /***************************************AFIFO*****************************************/ module asyn_fifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input wclk , input rclk , input wrstn , input rrstn , input winc , input rinc , input [WIDTH-1:0] wdata , output wire wfull , output wire rempty , output wire [WIDTH-1:0] rdata ); localparam ADDR_WIDTH = $clog2(DEPTH); reg [ADDR_WIDTH:0] waddr_bin; reg [ADDR_WIDTH:0] raddr_bin; //数据地址生成部分 always@(posedge wclk or negedge wrstn) begin if(!wrstn) waddr_bin <= 0; else if(!wfull && winc) waddr_bin <= waddr_bin+1; end always@(posedge rclk or negedge rrstn) begin if(!rrstn) raddr_bin <= 0; else if(!rempty && rinc) raddr_bin <= raddr_bin+1; end //二进制地址转格雷码 wire [ADDR_WIDTH:0] waddr_gray; wire [ADDR_WIDTH:0] raddr_gray; reg [ADDR_WIDTH:0] waddr_gray1; reg [ADDR_WIDTH:0] raddr_gray1; assign waddr_gray = waddr_bin^(waddr_bin>>1); assign raddr_gray = raddr_bin^(raddr_bin>>1); always@(posedge wclk or negedge wrstn) begin if(!wrstn) waddr_gray1 <= 0; else waddr_gray1 <= waddr_gray; end always@(posedge rclk or negedge rrstn) begin if(!rrstn) raddr_gray1 <= 0; else raddr_gray1 <= raddr_gray; end //异步跨时钟 reg [ADDR_WIDTH:0] waddr_gray2; reg [ADDR_WIDTH:0] raddr_gray2; reg [ADDR_WIDTH:0] waddr_gray3; reg [ADDR_WIDTH:0] raddr_gray3; always@(posedge wclk or negedge wrstn) begin if(!wrstn) begin raddr_gray2 <= 0; raddr_gray3 <= 0; end else begin raddr_gray2 <= raddr_gray1; raddr_gray3 <= raddr_gray2; end end always@(posedge rclk or negedge rrstn) begin if(!rrstn) begin waddr_gray2 <= 0; waddr_gray3 <= 0; end else begin waddr_gray2 <= waddr_gray1; waddr_gray3 <= waddr_gray2; end end //full与empty判断 assign wfull = (waddr_gray1 == {~raddr_gray3[ADDR_WIDTH:ADDR_WIDTH-1],raddr_gray3[ADDR_WIDTH-2:0]}); assign rempty = (raddr_gray1 == waddr_gray3); //RAM例化 wire [ADDR_WIDTH-1:0] waddr_r; wire [ADDR_WIDTH-1:0] raddr_r; wire wen; wire ren; assign wen = ~wfull & winc; assign ren = ~rempty & rinc; assign waddr_r = waddr_bin[ADDR_WIDTH-1:0]; assign raddr_r = raddr_bin[ADDR_WIDTH-1:0]; dual_port_RAM #( .DEPTH(DEPTH), .WIDTH(WIDTH) ) dual_port_RAM_U0 ( .wclk(wclk), .wenc(wen), .waddr(waddr_r), //深度对2取对数,得到地址的位宽。 .wdata(wdata), //数据写入 .rclk(rclk), .renc(ren), .raddr(raddr_r), //深度对2取对数,得到地址的位宽。 .rdata(rdata) //数据输出 ); endmodule