VL68. 同步FIFO
描述
请设计带有空满信号的同步FIFO,FIFO的深度和宽度可配置。双口RAM的参考代码和接口信号已给出,请在答案中添加并例化此部分代码。
端口名 |
I/O |
描述 |
wclk |
input |
写数据时钟 |
wenc |
input |
写使能 |
waddr |
input |
写地址 |
wdata |
input |
输入数据 |
rclk |
input |
读数据时钟 |
renc |
input |
读使能 |
raddr |
input |
读地址 |
rdata |
output |
输出数据 |
端口名 |
I/O |
描述 |
clk |
input |
时钟 |
rst_n |
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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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
输入描述
输出描述
output reg 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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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 /**********************************SFIFO************************************/ module sfifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata , output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata ); parameter ADDR_WIDTH = $clog2(DEPTH); reg [ADDR_WIDTH:0] waddr; reg [ADDR_WIDTH:0] raddr; always @(posedge clk or negedge rst_n) begin if(~rst_n) begin waddr <= 'd0; end else if(!wfull && winc)begin waddr <= waddr + 1'd1; end end always @(posedge clk or negedge rst_n) begin if(~rst_n) begin raddr <= 'd0; end else if(!rempty && rinc)begin raddr <= raddr + 1'd1; end end wire [ADDR_WIDTH : 0] fifo_cnt; assign fifo_cnt = (waddr[ADDR_WIDTH] == raddr[ADDR_WIDTH]) ? (waddr[ADDR_WIDTH:0] - raddr[ADDR_WIDTH:0]) : (DEPTH + waddr[ADDR_WIDTH-1:0] - raddr[ADDR_WIDTH-1:0]); always @(posedge clk or negedge rst_n) begin if(~rst_n) begin wfull <= 'd0; rempty <= 'd0; end else if(fifo_cnt == 'd0)begin rempty <= 1'd1; end else if(fifo_cnt == DEPTH)begin wfull <= 1'd1; end else begin wfull <= 'd0; rempty <= 'd0; end end wire wen ; wire ren ; wire wren;//high write assign wen = winc & !wfull; assign ren = rinc & !rempty; dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH) )dual_port_RAM( .wclk (clk), .wenc (wen), .waddr(waddr[ADDR_WIDTH-1:0]), //深度对2取对数,得到地址的位宽。 .wdata(wdata), //数据写入 .rclk (clk), .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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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 /**********************************SFIFO************************************/ module sfifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata , output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata ); parameter ADDR_WIDTH = $clog2(DEPTH); reg [ADDR_WIDTH:0] waddr, raddr; wire [ADDR_WIDTH:0] waddr_next, raddr_next; assign waddr_next = (winc & (!wfull))?(waddr+'d1):waddr; assign raddr_next = (rinc & (!rempty))?(raddr+'d1):raddr; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin {waddr,raddr} <= 'd0; end else begin {waddr,raddr} <= {waddr_next,raddr_next}; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin {wfull,rempty} <= 'd0; end else begin {wfull,rempty} <= {(waddr=={~raddr[ADDR_WIDTH],raddr[ADDR_WIDTH-1:0]}),(waddr==raddr)}; end end dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) u_dual_port_RAM( .wclk(clk), .wenc(winc & (!wfull)), .waddr(waddr[ADDR_WIDTH-1:0]), .wdata(wdata), .rclk(clk), .renc(rinc & (!rempty)), .raddr(raddr[ADDR_WIDTH-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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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 /**********************************SFIFO************************************/ module sfifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata , output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata ); reg [$clog2(DEPTH)-1:0] waddr; reg [$clog2(DEPTH)-1:0] raddr; reg [$clog2(DEPTH):0] dat_cnt;//ram中的未被读走数据个数 wire ram_wr_en;//ram写信号 wire ram_rd_en;//ram读信号 assign ram_wr_en=winc&(!wfull);//不满的情况下,写ram才有效 assign ram_rd_en=rinc&(!rempty);//不空的情况,读ram才有效 //写地址控制 always@(posedge clk or negedge rst_n) if(!rst_n) begin waddr<='d0; end else if(ram_wr_en&&(waddr==DEPTH-1'b1)) begin waddr<='d0; end else if(ram_wr_en) begin waddr<=waddr+'d1; end //读地址控制 always@(posedge clk or negedge rst_n) if(!rst_n) begin raddr<='d0; end else if(ram_rd_en&&(raddr==DEPTH-1'b1)) begin raddr<='d0; end else if(ram_rd_en) begin raddr<=raddr+1'b1; end //用于统计ram中未被读走的数据个数 always@(posedge clk or negedge rst_n) if(!rst_n) begin dat_cnt<='d0; end else if(ram_wr_en&ram_rd_en) //读写使能同时拉高,数据个数不变 begin dat_cnt<=dat_cnt; end else if(ram_wr_en) begin dat_cnt<=dat_cnt+1'b1; end else if(ram_rd_en) begin dat_cnt<=dat_cnt-1'b1; end //*************************满标志位控制*************************// //组合逻辑实现,该方式也是正确的,并且数据写满的下一个周期就不能写入数据了 // always @* // if(dat_cnt==DEPTH) // begin // wfull<='d1; // end // else // begin // wfull<='d0; // end //时序逻辑实现,该方式下,要在数据写满的第二个周期才能停止写入数据,当连续写入的时候,有可能出现错误,也就是多覆盖了一个数据,并且写指针也多加了一次 always@(posedge clk or negedge rst_n) if(!rst_n) begin wfull<='d0; end else if(dat_cnt==DEPTH) begin wfull<='d1; end else begin wfull<='d0; end //*************************读标志位控制*************************// //组合逻辑实现,该方式也是正确的,并且数据读完的下一个周期就不能读出数据了 // always @* // if(dat_cnt=='d0) // begin // rempty<='d1; // end // else // begin // rempty<='d0; // end //时序逻辑实现,该方式下,要在数据读完的第二个周期才能停止读出数据,当连续读出的时候,有可能出现错误,也就是多读了一个数据,并且读指针也多加了一次 always@(posedge clk or negedge rst_n) if(!rst_n) begin rempty<='d0; end else if(dat_cnt=='d0) begin rempty<='d1; end else begin rempty<='d0; end dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) inst_dual_port_RAM( .wclk(clk) ,.wenc(ram_wr_en) ,.waddr(waddr) ,.wdata(wdata) ,.rclk(clk) ,.renc(ram_rd_en) ,.raddr(raddr) ,.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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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 /**********************************SFIFO************************************/ module sfifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata , output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata ); reg [$clog2(DEPTH) : 0] data_cnt; reg [$clog2(DEPTH) - 1 : 0] w_addr, r_addr; wire wenc, renc; assign wenc = winc == 1'b1 && wfull == 1'b0 ? 1'b1 : 1'b0; assign renc = rinc == 1'b1 && rempty == 1'b0 ? 1'b1 : 1'b0; dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) u_dual_port_RAM( .wclk(clk), .wenc(wenc), .waddr(w_addr), .wdata(wdata), .rclk(clk), .renc(renc), .raddr(r_addr), .rdata(rdata) ); always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) data_cnt <= 0; else if(winc == 1'b1 && wfull == 1'b0) data_cnt <= data_cnt + 1; else if(rinc == 1'b1 && rempty == 1'b0) data_cnt <= data_cnt - 1; else data_cnt <= data_cnt; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) w_addr <= 0; else if(winc == 1'b1 && wfull == 1'b0) w_addr <= w_addr + 1; else w_addr <= w_addr; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) r_addr <= 0; else if(rinc == 1'b1 && rempty == 1'b0) r_addr <= r_addr + 1; else r_addr <= r_addr; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) wfull <= 0; else if(data_cnt == DEPTH) wfull <= 1; else wfull <= 0; end always@(posedge clk or negedge rst_n) begin if(rst_n == 1'b0) rempty <= 0; else if(data_cnt == 0) rempty <= 1; else rempty <= 0; end 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 ,input [WIDTH-1:0] wdata ,input rclk ,input renc ,input [$clog2(DEPTH)-1:0] raddr ,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 /**********************************SFIFO************************************/ module sfifo#( parameter WIDTH = 8, parameter DEPTH = 16 )( input clk , input rst_n , input winc , input rinc , input [WIDTH-1:0] wdata , output reg wfull , output reg rempty , output wire [WIDTH-1:0] rdata ); parameter ADDR_WIDTH = $clog2(DEPTH); reg [ADDR_WIDTH-1:0] r_addr; reg [ADDR_WIDTH-1:0] w_addr; always @(posedge clk or negedge rst_n) begin if(!rst_n) r_addr <= {(ADDR_WIDTH){1'b0}}; else begin if(rinc & ~rempty) r_addr <= r_addr + 1'b1; end end always @(posedge clk or negedge rst_n) begin if(!rst_n) w_addr <= {(ADDR_WIDTH){1'b0}}; else begin if(winc & ~wfull) w_addr <= w_addr + 1'b1; end end reg [ADDR_WIDTH:0] addr_gap; always @(posedge clk or negedge rst_n) begin if(!rst_n) addr_gap <= {ADDR_WIDTH+1{1'b0}}; else begin if(rinc & ~rempty & ~winc || rinc & wfull) addr_gap <= addr_gap - 1'b1; else if(winc & ~wfull & ~rinc || winc & rempty) addr_gap <= addr_gap + 1'b1; end end wire wfull_inner; assign wfull_inner = addr_gap == DEPTH; always @(posedge clk or negedge rst_n) begin if(!rst_n) wfull <= 1'b0; else begin wfull <= wfull_inner; end end wire rempty_inner; assign rempty_inner = (addr_gap == {ADDR_WIDTH+1{1'b0}}); always @(posedge clk or negedge rst_n) begin if(!rst_n) rempty <= 1'b0; else begin rempty <= rempty_inner; end end dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) dual_port_RAM_u( .wclk(clk) ,.wenc(winc & ~wfull) ,.waddr(w_addr[ADDR_WIDTH-1:0]) ,.wdata(wdata) ,.rclk(clk) ,.renc(rinc & ~rempty) ,.raddr(r_addr[ADDR_WIDTH-1:0]) ,.rdata(rdata) ); endmodule