148 lines
4.1 KiB
Systemverilog
Executable File
148 lines
4.1 KiB
Systemverilog
Executable File
`ifndef __FREELIST_SV__
|
|
`define __FREELIST_SV__
|
|
|
|
module freelist
|
|
#(
|
|
parameter int unsigned ENTRY_COUNT = 4,
|
|
localparam int unsigned ENTRY_TAG_WIDTH = $clog2(ENTRY_COUNT),
|
|
localparam int unsigned IS_LOG2 = (2 ** ENTRY_TAG_WIDTH) == ENTRY_COUNT
|
|
)
|
|
(
|
|
// Enqueue
|
|
input logic enq_vld_i,
|
|
input logic[ENTRY_TAG_WIDTH-1:0] enq_tag_i,
|
|
// Dequeue
|
|
input logic deq_vld_i,
|
|
output logic[ENTRY_TAG_WIDTH-1:0] deq_tag_o,
|
|
output logic deq_rdy_o,
|
|
// Flush
|
|
input logic flush_i,
|
|
|
|
input clk,
|
|
input rst
|
|
);
|
|
|
|
logic [ENTRY_COUNT-1:0][ENTRY_TAG_WIDTH-1:0] ram_r,ram_n;
|
|
logic [ENTRY_COUNT-1:0] ram_clk_en;
|
|
|
|
logic [ENTRY_TAG_WIDTH-1:0] head_r,head_n;
|
|
logic head_flag_r,head_flag_n;
|
|
logic head_clk_en;
|
|
|
|
logic [ENTRY_TAG_WIDTH-1:0] tail_r,tail_n;
|
|
logic tail_flag_r,tail_flag_n;
|
|
logic tail_clk_en;
|
|
|
|
logic enq_fire;
|
|
logic deq_fire;
|
|
|
|
logic full,empty;
|
|
logic flag_equal,tag_equal;
|
|
|
|
assign enq_fire = enq_vld_i;
|
|
assign deq_fire = deq_rdy_o & deq_vld_i;
|
|
|
|
assign flag_equal = tail_flag_r == head_flag_r;
|
|
assign tag_equal = tail_r == head_r;
|
|
|
|
assign full = ~flag_equal & tag_equal;
|
|
assign empty = flag_equal & tag_equal;
|
|
|
|
// Output
|
|
assign deq_tag_o = ram_r[head_r];
|
|
|
|
always_comb begin : ram_update
|
|
ram_n = ram_r;
|
|
ram_n[tail_r] = enq_tag_i;
|
|
if(flush_i) begin
|
|
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
|
|
ram_n[i] = i[ENTRY_TAG_WIDTH-1:0];
|
|
end
|
|
end
|
|
end
|
|
|
|
always_comb begin : ram_clk_en_gen
|
|
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
|
|
ram_clk_en[i] = (enq_fire & (i == tail_r)) | flush_i;
|
|
end
|
|
end
|
|
|
|
|
|
always_comb begin : head_update
|
|
if(IS_LOG2) begin
|
|
{head_flag_n,head_n} = {head_flag_r,head_r} + 1'b1;
|
|
end else begin
|
|
if(head_r == ENTRY_COUNT-1) begin
|
|
head_n = {ENTRY_COUNT{1'b0}};
|
|
head_flag_n = ~head_flag_r;
|
|
end else begin
|
|
head_n = head_r + 1'b1;
|
|
head_flag_n = head_flag_r;
|
|
end
|
|
end
|
|
if(flush_i) begin
|
|
{head_flag_n,head_n} = {head_flag_r,head_r};
|
|
end
|
|
end
|
|
|
|
assign tail_clk_en = enq_fire | flush_i;
|
|
assign deq_rdy_o = ~empty;
|
|
|
|
always_comb begin : tail_update
|
|
if(IS_LOG2) begin
|
|
{tail_flag_n,tail_n} = {tail_flag_r,tail_r} + 1'b1;
|
|
end else begin
|
|
if(tail_r == ENTRY_COUNT-1) begin
|
|
tail_n = {ENTRY_TAG_WIDTH{1'b0}};
|
|
tail_flag_n = ~tail_flag_r;
|
|
end else begin
|
|
tail_n = tail_r + 1'b1;
|
|
tail_flag_n = tail_flag_r;
|
|
end
|
|
end
|
|
if(flush_i) begin
|
|
{tail_flag_n,tail_n} = {~head_flag_r,head_r};
|
|
end
|
|
end
|
|
|
|
assign head_clk_en = deq_fire | flush_i;
|
|
|
|
always_ff@(posedge clk) begin : head_dff
|
|
if(rst) begin
|
|
{head_flag_r,head_r} <= {(ENTRY_TAG_WIDTH+1){1'b0}};
|
|
end else begin
|
|
if(head_clk_en) begin
|
|
{head_flag_r,head_r} <= {head_flag_n,head_n};
|
|
end
|
|
end
|
|
end
|
|
|
|
always_ff@(posedge clk) begin : tail_dff
|
|
if(rst) begin
|
|
{tail_flag_r,tail_r} <= {1'b1,{(ENTRY_TAG_WIDTH){1'b0}}};
|
|
end else begin
|
|
if(tail_clk_en) begin
|
|
{tail_flag_r,tail_r} <= {tail_flag_n,tail_n};
|
|
end
|
|
end
|
|
end
|
|
|
|
always_ff@(posedge clk) begin : ram_dff
|
|
if(rst) begin
|
|
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
|
|
ram_r[i] <= i[ENTRY_TAG_WIDTH-1:0];
|
|
end
|
|
end else begin
|
|
for(int i = 0 ; i < ENTRY_COUNT; i++) begin
|
|
if(ram_clk_en[i]) begin
|
|
ram_r[i] <= ram_n[i];
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
|
|
endmodule : freelist
|
|
|
|
`endif |