274 lines
9.0 KiB
Systemverilog
Executable File
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 |