VL46. 同步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 |
描述 |
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 //深度对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 clk ,输出描述
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 //深度对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 /**********************************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] w_pointer,r_pointer; wire wenc,renc; assign wenc = winc& !wfull; assign renc = rinc& !rempty; always@(posedge clk or negedge rst_n) begin if(!rst_n) begin wfull <='b0; end else begin wfull <= w_pointer==r_pointer+'d16; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin rempty <='b0; end else begin rempty <= w_pointer==r_pointer; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin w_pointer <='b0; end else begin w_pointer <=(wenc)?w_pointer+1'b1:w_pointer; end end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin r_pointer <='b0; end else begin r_pointer <=(renc)?r_pointer+1'b1:r_pointer; end end dual_port_RAM #(.DEPTH(DEPTH),.WIDTH(WIDTH)) my_dual_port_RAM( .wclk(clk), .wenc(wenc), .waddr(w_pointer), .wdata(wdata), .rclk(clk), .renc(renc), .raddr(r_pointer), .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 /**********************************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 ); //---------------------------------------计数器实现------------------------------------- assign wenc = (winc & ~wfull); assign renc = (rinc & ~rempty); reg [$clog2(DEPTH):0] cnt; reg [$clog2(DEPTH)-1:0] waddr; reg [$clog2(DEPTH)-1:0] raddr; always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin cnt <= 0; end // else if(renc && wenc)begin //cnt <= cnt; //end else if(wenc)begin cnt <= cnt + 1; end else if(renc)begin cnt <= cnt - 1; end else begin cnt <= cnt; end end always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin waddr <= 0; end else if(wenc)begin waddr <= waddr + 1; end else begin waddr <= waddr; end end always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin raddr <= 0; end else if(renc)begin raddr <= raddr + 1; end else begin raddr <= raddr; end end always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin wfull <= 0; end else if(cnt == DEPTH)begin wfull <= 1; end else begin wfull <= 0; end end always@(posedge clk or negedge rst_n)begin if(rst_n == 1'b0)begin rempty <= 0; end else if(cnt == 0)begin rempty <= 1 ; end else begin rempty <= 0; end end dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH) ) dut_ram ( .wclk(clk), .wenc(wenc), .waddr(waddr), .wdata (wdata), .rclk(clk), .renc(renc), .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 //深度对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 /**********************************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 ); //waddr & raddr reg [$clog2(DEPTH)-1:0] waddr, raddr; always @ (posedge clk or negedge rst_n) begin if(~rst_n) waddr <= 0; else waddr <= (~wfull & winc) ? waddr + 1 : waddr; end always @ (posedge clk or negedge rst_n) begin if(~rst_n) raddr <= 0; else raddr <= (~rempty & rinc) ? raddr + 1 : raddr; end //wfull & rempty reg [$clog2(DEPTH):0] cnt; always @ (posedge clk or negedge rst_n) begin if(~rst_n) cnt <= 0; else begin if(winc & rinc & ~wfull & ~rempty) cnt <= cnt; else if(rinc & ~rempty) cnt <= cnt - 1; else if(winc & ~wfull) cnt <= cnt + 1; else cnt <= cnt; end end always @ (posedge clk or negedge rst_n) begin if(~rst_n) begin wfull = 0; rempty = 0; end else begin wfull = cnt == DEPTH; rempty = cnt == 0; end end //RAM dual_port_RAM #(.DEPTH(DEPTH), .WIDTH(WIDTH)) RAM0 ( .wclk(clk), .wenc(winc & ~wfull), .waddr(waddr), //深度对2取对数,得到地址的位宽。 .wdata(wdata), //数据写入 .rclk(clk), .renc(rinc & ~rempty), .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 /**********************************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 ); wire w_en,r_en; reg [4:0] r_addr,w_addr; assign w_en = winc & !wfull; assign r_en = rinc & !rempty; always@(posedge clk or negedge rst_n) begin if(!rst_n) r_addr <= 5'd0; else if(r_en) r_addr <= r_addr + 1'b1; end always@(posedge clk or negedge rst_n) begin if(!rst_n) w_addr <= 5'd0; else if(w_en) w_addr <= w_addr + 1'b1; end always@(posedge clk or negedge rst_n) begin if(!rst_n) begin wfull <= 1'd0; rempty <= 1'b0; end else begin wfull <= r_addr == {!w_addr[4],w_addr[3:0]}; rempty <= r_addr == w_addr; end end dual_port_RAM u_dual_port_RAM( .wclk (clk), .wenc (w_en), .waddr (w_addr[3:0]), .wdata (wdata), .rclk (clk), .renc (r_en), .raddr (r_addr[3: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 /**********************************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 ); localparam ADDR_WIDTH = $clog2(DEPTH); reg [WIDTH-1:0] mem [DEPTH-1:0]; reg [ADDR_WIDTH:0] raddr,waddr; always@(posedge clk or negedge rst_n)begin if(!rst_n) waddr <= 'b0; else if(winc & ~wfull) waddr <= waddr + 1'b1; else waddr <= waddr; end always@(posedge clk or negedge rst_n)begin if(!rst_n) raddr <= 'b0; else if(rinc & ~rempty) raddr <= raddr + 1'b1; else raddr <= raddr; end // assign wfull = ({~raddr[ADDR_WIDTH],raddr[ADDR_WIDTH-1:0]} == waddr)?1'b1:1'b0; // assign rempty = (raddr == waddr)?1'b1:1'b0; always@(posedge clk or negedge rst_n)begin if(!rst_n) wfull <= 1'b0; else if({~raddr[ADDR_WIDTH],raddr[ADDR_WIDTH-1:0]} == waddr) wfull <= 1'b1; else wfull <= 1'b0; end always@(posedge clk or negedge rst_n)begin if(!rst_n) rempty <= 1'b0; else if(raddr == waddr) rempty <= 1'b1; else rempty <= 1'b0; end always@(posedge clk)begin if(winc & ~wfull) mem[waddr[ADDR_WIDTH-1:0]] <= wdata; end reg [WIDTH-1:0] rdata_o; always@(posedge clk)begin if(rinc & ~rempty) rdata_o <= mem[raddr[ADDR_WIDTH-1:0]]; end assign rdata = rdata_o; endmodule