Files
OpenExSys_NoC/rtl/util/usage_manager.sv
2023-11-26 14:59:34 +01:00

274 lines
9.0 KiB
Systemverilog
Executable File

`ifndef __USAGE_MANAGER_SV__
`define __USAGE_MANAGER_SV__
module usage_manager #(
parameter int unsigned ENTRY_COUNT = 8,
parameter int unsigned ENQ_WIDTH = 2,
parameter int unsigned DEQ_WIDTH = 2,
parameter int unsigned FLAG_EN = 0,
parameter int unsigned INIT_IS_FULL = 0,
parameter int unsigned COMB_ENQ_EN = 0,
parameter int unsigned COMB_DEQ_EN = 0,
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(ENTRY_COUNT),
localparam int unsigned ENTRY_TAG_WIDTH = ENTRY_PTR_WIDTH + FLAG_EN,
localparam int unsigned USAGE_CNT_WIDTH = $clog2(ENTRY_COUNT + 1)
) (
// Enqueue
input logic [ENQ_WIDTH-1:0] enq_fire_i,
// Dequeue
input logic [DEQ_WIDTH-1:0] deq_fire_i,
// Status
output logic [DEQ_WIDTH-1:0][ENTRY_TAG_WIDTH-1:0] head_o,
output logic [ENQ_WIDTH-1:0][ENTRY_TAG_WIDTH-1:0] tail_o,
output logic [USAGE_CNT_WIDTH-1:0] avail_cnt_o,
input logic flush_i,
input clk,
input rst
);
// Local Param
localparam int unsigned ENQ_CNT_WIDTH = $clog2(ENQ_WIDTH + 1);
localparam int unsigned DEQ_CNT_WIDTH = $clog2(DEQ_WIDTH + 1);
localparam int unsigned IS_2N = (2 ** ENTRY_PTR_WIDTH == ENTRY_COUNT);
// Function
function automatic [ENTRY_TAG_WIDTH-1:0] head_ptr_plus;
input logic [ENTRY_TAG_WIDTH-1:0] head_ptr_i;
input logic [DEQ_CNT_WIDTH-1:0] plus_cnt_i;
logic flag;
logic [ENTRY_PTR_WIDTH-1:0] index;
logic [ENTRY_PTR_WIDTH:0] sum;
logic [ENTRY_PTR_WIDTH:0] reverse_sum;
begin
if (IS_2N) begin
head_ptr_plus = head_ptr_i + plus_cnt_i;
end else begin
index = head_ptr_i[ENTRY_PTR_WIDTH-1:0];
flag = head_ptr_i[ENTRY_TAG_WIDTH-1];
sum = index + plus_cnt_i;
reverse_sum = sum - ENTRY_COUNT;
if (FLAG_EN) begin
if (~reverse_sum[ENTRY_PTR_WIDTH]) begin
head_ptr_plus = {~flag, reverse_sum[ENTRY_PTR_WIDTH-1:0]};
end else begin
head_ptr_plus = {flag, sum[ENTRY_PTR_WIDTH-1:0]};
end
end else begin
if (~reverse_sum[ENTRY_PTR_WIDTH]) begin
head_ptr_plus = reverse_sum[ENTRY_PTR_WIDTH-1:0];
end else begin
head_ptr_plus = sum[ENTRY_PTR_WIDTH-1:0];
end
end
end
end
endfunction : head_ptr_plus
function automatic [ENTRY_TAG_WIDTH-1:0] ptr_plus_one;
input logic [ENTRY_TAG_WIDTH-1:0] ptr_i;
logic flag;
logic [ENTRY_PTR_WIDTH-1:0] index;
logic reverse_flag;
begin
if (IS_2N) begin
ptr_plus_one = ptr_i + 1'b1;
end else begin
index = ptr_i[ENTRY_PTR_WIDTH-1:0];
flag = ptr_i[ENTRY_TAG_WIDTH-1];
if (index == ENTRY_COUNT - 1) begin
index = {ENTRY_PTR_WIDTH{1'b0}};
reverse_flag = ~flag;
end else begin
index = ptr_i + 1'b1;
reverse_flag = flag;
end
if (FLAG_EN) begin
ptr_plus_one = {reverse_flag, index};
end else begin
ptr_plus_one = index;
end
end
end
endfunction : ptr_plus_one
function automatic [ENTRY_TAG_WIDTH-1:0] tail_ptr_plus;
input logic [ENTRY_TAG_WIDTH-1:0] tail_ptr_i;
input logic [ENQ_CNT_WIDTH-1:0] plus_cnt_i;
logic flag;
logic [ENTRY_PTR_WIDTH-1:0] index;
logic [ENTRY_PTR_WIDTH:0] sum;
logic [ENTRY_PTR_WIDTH:0] reverse_sum;
begin
if (IS_2N) begin
tail_ptr_plus = tail_ptr_i + plus_cnt_i;
end else begin
index = tail_ptr_i[ENTRY_PTR_WIDTH-1:0];
flag = tail_ptr_i[ENTRY_TAG_WIDTH-1];
sum = index + plus_cnt_i;
reverse_sum = sum - ENTRY_COUNT;
if (FLAG_EN) begin
if (~reverse_sum[ENTRY_PTR_WIDTH]) begin
tail_ptr_plus = {~flag, reverse_sum[ENTRY_PTR_WIDTH-1:0]};
end else begin
tail_ptr_plus = {flag, sum[ENTRY_PTR_WIDTH-1:0]};
end
end else begin
if (~reverse_sum[ENTRY_PTR_WIDTH]) begin
tail_ptr_plus = reverse_sum[ENTRY_PTR_WIDTH-1:0];
end else begin
tail_ptr_plus = sum[ENTRY_PTR_WIDTH-1:0];
end
end
end
end
endfunction : tail_ptr_plus
// Clock Gate
logic enq_clk_en, deq_clk_en;
logic [ENQ_CNT_WIDTH-1:0] enq_cnt;
logic [DEQ_CNT_WIDTH-1:0] deq_cnt;
logic [ENTRY_TAG_WIDTH-1:0] head_ptr_d, head_ptr_q;
logic [ENTRY_TAG_WIDTH-1:0] tail_ptr_d, tail_ptr_q;
logic [USAGE_CNT_WIDTH-1:0] avail_cnt_d, avail_cnt_q;
assign enq_clk_en = |enq_fire_i;
assign deq_clk_en = |deq_fire_i;
// Output
always_comb begin : gen_head
for (int i = 0; i < DEQ_WIDTH; i++) begin
if (i == 0) begin
head_o[i] = head_ptr_q;
end else begin
if(COMB_DEQ_EN) begin
head_o[i] = deq_fire_i[i-1] ? ptr_plus_one(head_o[i-1]) : head_o[i-1];
end else begin
head_o[i] = ptr_plus_one(head_o[i-1]);
end
end
end
end
always_comb begin : gen_tail
for (int i = 0; i < ENQ_WIDTH; i++) begin
if (i == 0) begin
tail_o[i] = tail_ptr_q;
end else begin
if(COMB_ENQ_EN) begin
tail_o[i] = enq_fire_i[i-1] ? ptr_plus_one(tail_o[i-1]) : tail_o[i-1];
end else begin
tail_o[i] = ptr_plus_one(tail_o[i-1]);
end
end
end
end
assign avail_cnt_o = avail_cnt_q;
always_comb begin : head_ptr_update
head_ptr_d = head_ptr_q;
if (deq_clk_en) begin
head_ptr_d = head_ptr_plus(head_ptr_q, deq_cnt);
end
if (flush_i) begin
head_ptr_d = head_ptr_q;
end
end
always_comb begin : tail_ptr_update
tail_ptr_d = tail_ptr_q;
if (enq_clk_en) begin
tail_ptr_d = tail_ptr_plus(tail_ptr_q, enq_cnt);
end
if (flush_i) begin
if((INIT_IS_FULL==1) && (FLAG_EN==1)) begin
tail_ptr_d = {~head_ptr_q[ENTRY_TAG_WIDTH-1], head_ptr_q[ENTRY_PTR_WIDTH-1:0]};
end else begin
tail_ptr_d = head_ptr_q;
end
end
end
always_comb begin : avail_cnt_update
avail_cnt_d = avail_cnt_q;
if (enq_clk_en) begin
avail_cnt_d = avail_cnt_q - enq_cnt;
end
if (deq_clk_en) begin
avail_cnt_d = avail_cnt_q + deq_cnt;
end
if (enq_clk_en & deq_clk_en) begin
avail_cnt_d = avail_cnt_q + deq_cnt - enq_cnt;
end
if (flush_i) begin
if (INIT_IS_FULL) begin
avail_cnt_d = {USAGE_CNT_WIDTH{1'b0}};
end else begin
avail_cnt_d = ENTRY_COUNT[USAGE_CNT_WIDTH-1:0];
end
end
end
always_ff @(posedge clk) begin : head_ptr_dff
if (rst) begin
head_ptr_q <= {ENTRY_TAG_WIDTH{1'b0}};
end else begin
if (deq_clk_en | flush_i) begin
head_ptr_q <= head_ptr_d;
end
end
end
always_ff @(posedge clk) begin : tail_ptr_dff
if (rst) begin
if (INIT_IS_FULL & FLAG_EN) begin
tail_ptr_q <= {1'b1, {ENTRY_PTR_WIDTH{1'b0}}};
end else begin
tail_ptr_q <= {ENTRY_TAG_WIDTH{1'b0}};
end
end else begin
if (enq_clk_en | flush_i) begin
tail_ptr_q <= tail_ptr_d;
end
end
end
always_ff @(posedge clk) begin : avail_cnt_dff
if (rst) begin
if (INIT_IS_FULL) begin
avail_cnt_q <= {USAGE_CNT_WIDTH{1'b0}};
end else begin
avail_cnt_q <= ENTRY_COUNT[USAGE_CNT_WIDTH-1:0];
end
end else begin
if (enq_clk_en | deq_clk_en | flush_i) begin
avail_cnt_q <= avail_cnt_d;
end
end
end
one_counter #(
.DATA_WIDTH(ENQ_WIDTH)
) u_enq_one_counter (
.data_i(enq_fire_i),
.cnt_o (enq_cnt)
);
one_counter #(
.DATA_WIDTH(DEQ_WIDTH)
) u_deq_one_counter (
.data_i(deq_fire_i),
.cnt_o (deq_cnt)
);
endmodule : usage_manager
`endif