Last active
November 29, 2025 05:35
-
-
Save neilzheng/a985fb96bfed084e2ffff720fbb07f66 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module fifo #( | |
| parameter DATA_WIDTH = 8, | |
| parameter BUFFER_DEPTH = 4, // must greater than 4 | |
| parameter ADDR_WIDTH = $clog2(BUFFER_DEPTH) | |
| ) ( | |
| input logic clk, | |
| input logic rst_n, | |
| // Input side (write port) | |
| input logic i_valid, | |
| input logic [DATA_WIDTH-1:0] i_data, | |
| output logic i_ready, // Registered | |
| // Output side (read port) | |
| output logic o_valid, // Registered | |
| output logic [DATA_WIDTH-1:0] o_data, // Registered | |
| input logic o_ready | |
| ); | |
| localparam [ADDR_WIDTH-1:0] PTR_MAX = ADDR_WIDTH'(BUFFER_DEPTH - 1); | |
| // Internal buffer and pointers | |
| logic [DATA_WIDTH-1:0] buffer[BUFFER_DEPTH-1:0]; | |
| logic [ADDR_WIDTH:0] count_reg; | |
| logic [ADDR_WIDTH:0] next_count; | |
| logic [ADDR_WIDTH-1:0] read_ptr_reg; | |
| logic [ADDR_WIDTH-1:0] write_ptr_reg; | |
| logic [ADDR_WIDTH-1:0] next_read_ptr; | |
| logic [ADDR_WIDTH-1:0] next_write_ptr; | |
| // Transaction signals | |
| logic write_en; | |
| logic read_en; | |
| logic net_read_en; | |
| logic net_write_en; | |
| logic i_ready_reg; | |
| logic o_valid_reg; | |
| logic [DATA_WIDTH-1:0] o_data_reg; | |
| logic i_ready_next; | |
| logic o_valid_next; | |
| logic [DATA_WIDTH-1:0] o_data_next; | |
| //---------------------------------------------------------------- | |
| // Combinational Logic | |
| //---------------------------------------------------------------- | |
| assign write_en = i_valid && i_ready; | |
| assign read_en = o_ready && o_valid; | |
| assign net_write_en = write_en & ~read_en; | |
| assign net_read_en = read_en & ~write_en; | |
| // state management | |
| always @* begin | |
| next_count = count_reg; | |
| if (net_read_en) begin | |
| next_count = count_reg - 1; | |
| end | |
| if (net_write_en) begin | |
| next_count = count_reg + 1; | |
| end | |
| next_read_ptr = read_ptr_reg; | |
| next_write_ptr = write_ptr_reg; | |
| if (read_en) begin | |
| next_read_ptr = read_ptr_reg == PTR_MAX ? 0 : read_ptr_reg + 1; | |
| end | |
| if (write_en) begin | |
| next_write_ptr = write_ptr_reg == PTR_MAX ? 0 : write_ptr_reg + 1; | |
| end | |
| end | |
| // output generation | |
| always @* begin | |
| i_ready_next = i_ready_reg; | |
| o_valid_next = o_valid_reg; | |
| o_data_next = buffer[next_read_ptr]; | |
| if (next_count == 0) begin | |
| // empty | |
| o_valid_next = 0; | |
| o_data_next = 0; | |
| end else if (next_count == BUFFER_DEPTH) begin | |
| // full | |
| i_ready_next = 0; | |
| end else begin | |
| i_ready_next = 1; | |
| o_valid_next = 1; | |
| if (next_count == (ADDR_WIDTH+1)'(1) | |
| & count_reg != (ADDR_WIDTH+1)'(2)) begin | |
| // almost empty filled | |
| o_data_next = i_data; | |
| end | |
| end | |
| end | |
| //---------------------------------------------------------------- | |
| // Sequential Logic | |
| //---------------------------------------------------------------- | |
| always_ff @(posedge clk or negedge rst_n) begin | |
| if (!rst_n) begin | |
| count_reg = 0; | |
| read_ptr_reg = 0; | |
| write_ptr_reg = 0; | |
| i_ready_reg = 1; | |
| o_valid_reg = 0; | |
| o_data_reg = 0; | |
| end else begin | |
| count_reg <= next_count; | |
| read_ptr_reg <= next_read_ptr; | |
| write_ptr_reg <= next_write_ptr; | |
| i_ready_reg <= i_ready_next; | |
| o_valid_reg <= o_valid_next; | |
| o_data_reg <= o_data_next; | |
| if (write_en) begin | |
| buffer[write_ptr_reg] <= i_data; | |
| end | |
| end | |
| end | |
| assign i_ready = i_ready_reg; | |
| assign o_valid = o_valid_reg; | |
| assign o_data = o_data_reg; | |
| endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment