initial commit for open source NoC IP

This commit is contained in:
Zexin Fu
2023-11-26 14:59:34 +01:00
commit 6ba3d27334
122 changed files with 14907 additions and 0 deletions

View File

@@ -0,0 +1,58 @@
Name: Queue
Dependency:
- ../StdDFF/StdDFF.yaml
- ../Basic/Basic.yaml
Module:
- name: QueueManager
description: Queue Ptr Manager
language: SystemVerilog
rtl:
- hw/QueueManager.v
dependency:
- CountOne
- StdDFF
- name: StaticPrioritySelector
description: Static Priority Selector
language: SystemVerilog
rtl:
- hw/StaticPrioritySelector.v
sim:
- dv/StaticPrioritySelector_tb.v
- name: AgeMatrixSelector
description: Age Matrix selector to select in age order
language: SystemVerilog
rtl:
- hw/AgeMatrixSelector.v
# sim:
# - dv/AgeMatrixSelector_tb.v
dependency:
- MuxOH
- name: MultiPortStreamFIFO
description: MultiPortStream FIFO
language: SystemVerilog
rtl:
- hw/FIFO/MultiPortStreamFIFO.v
sim:
- dv/FIFO/MultiPortStreamFIFO_tb.v
dependency:
- QueueManager
- name: FIAOWithQueueManager
description: FIAOWithQueueManager
language: SystemVerilog
rtl:
- hw/FIAO/FIAOWithQueueManager.v
dependency:
- QueueManager
# - name: FIAOWithAgeMatrix
# description: FIAOWithAgeMatrix
# language: SystemVerilog
# rtl:
# - hw/FIAO/FIAOWithAgeMatrix.v
# dependency:
# - OH2UInt
# - AgeMatrixSelector

View File

@@ -0,0 +1,168 @@
// module AgeMatrixSelector_tb;
// // Parameters
// localparam int unsigned EntryCount = 4;
// localparam int unsigned EnqWidth = 2;
// localparam int unsigned SelWidth = 2;
// // Ports
// reg [EnqWidth-1:0] enq_fire_i;
// reg [EntryCount-1:0] enq_mask_i[EnqWidth];
// reg [EntryCount-1:0] sel_mask_i;
// wire [EntryCount-1:0] result_mask_o[SelWidth];
// reg [EntryCount-1:0] entry_vld_i;
// reg clk = 0;
// reg rstn = 0;
// bit [EntryCount-1:0][EntryCount-1:0] golden_age_matrix_d, golden_age_matrix_q;
// bit [EntryCount-1:0][EntryCount-1:0] golden_masked_age_matrix[SelWidth];
// bit [EntryCount-1:0] golden_selected_mask[SelWidth];
// bit [EntryCount-1:0] golden_sel_result[SelWidth];
// always @(posedge clk) begin
// if (~rstn) begin
// golden_age_matrix_q <= 0;
// end else begin
// for (int row = 0; row < EntryCount; row++) begin
// for (int col = 0; col < EntryCount; col++) begin
// if (row != col) begin
// golden_age_matrix_q[row][col] <= golden_age_matrix_d[row][col];
// end
// end
// end
// end
// end
// always @(*) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_age_matrix_q[row][row] <= entry_vld_i[row];
// end
// end
// always @(*) begin
// golden_age_matrix_d = golden_age_matrix_q;
// for (int i = 0; i < EnqWidth; i++) begin
// if (enq_fire_i[i]) begin
// for (int row = 0; row < EntryCount; row++) begin
// if (enq_mask_i[i][row]) begin
// for (int col = 0; col < EntryCount; col++) begin
// golden_age_matrix_d[row][col] = ~golden_age_matrix_d[col][col];
// end
// end
// end
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < EntryCount; i++) begin
// if (i == 0) begin
// golden_selected_mask[i] = 0;
// end else begin
// golden_selected_mask[i] = golden_selected_mask[i-1] | golden_sel_result[i-1];
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < SelWidth; i++) begin
// golden_masked_age_matrix[i] = golden_age_matrix_q;
// for (int col = 0; col < EntryCount; col++) begin
// if (golden_selected_mask[i][col] | ~sel_mask_i[col]) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_masked_age_matrix[i][row][col] = col != row;
// end
// end
// end
// end
// end
// always @(*) begin
// for (int i = 0; i < SelWidth; i++) begin
// for (int row = 0; row < EntryCount; row++) begin
// golden_sel_result[i][row] = &golden_masked_age_matrix[i][row];
// end
// end
// end
// default disable iff (~rstn);
// int iter = 10000;
// int random_ptr;
// CHECK_EQULATION :
// assert property (@(negedge clk) golden_age_matrix_q == AgeMatrixSelector_dut.age_matrix_q)
// else begin
// $fatal("\n Error : Age matrix is not equal to golden one \n");
// end
// initial begin
// #100 rstn = 1'b1;
// entry_vld_i = 0;
// enq_fire_i = 0;
// sel_mask_i = 0;
// repeat (iter) begin
// @(posedge clk);
// entry_vld_i = entry_vld_i & ~(entry_vld_i & $urandom_range(0, (1 << EntryCount) - 1));
// for (int i = 0; i < EnqWidth; i++) begin
// if (enq_fire_i[i]) begin
// entry_vld_i = entry_vld_i | enq_mask_i[i];
// end
// end
// sel_mask_i = $urandom_range(0, (1 << EntryCount) - 1) & entry_vld_i;
// @(negedge clk);
// for (int i = 0; i < EnqWidth; i++) begin
// enq_fire_i[i] = 0;
// enq_mask_i[i] = 0;
// random_ptr = $urandom_range(0, EntryCount - 1);
// if (~entry_vld_i[random_ptr]) begin
// enq_fire_i[i] = 1;
// enq_mask_i[i][random_ptr] = 1;
// end
// for(int j = 0 ; j < i; j++) begin
// if(enq_fire_i[j] && (enq_mask_i[j] == enq_mask_i[i])) begin
// enq_fire_i[i] = 0;
// end
// end
// end
// for (int i = 0; i < SelWidth; i++) begin
// assert (result_mask_o[i] == golden_sel_result[i])
// else begin
// $fatal("\n Error : Selection is not equal, golden[%b] our[%b] \n", golden_sel_result[i],
// result_mask_o[i]);
// end
// end
// end
// $info("\n PASS after %d iter \n",iter);
// $finish();
// end
// AgeMatrixSelector #(
// .EntryCount(EntryCount),
// .EnqWidth (EnqWidth),
// .SelWidth (SelWidth)
// ) AgeMatrixSelector_dut (
// .enq_fire_i(enq_fire_i),
// .enq_mask_i(enq_mask_i),
// .sel_mask_i(sel_mask_i),
// .result_mask_o(result_mask_o),
// .entry_vld_i(entry_vld_i),
// .clk(clk),
// .rstn(rstn)
// );
// `ifdef DUMPON
// initial begin : GEN_WAVEFORM
// $fsdbDumpfile("AgeMatrixSelector_tb.fsdb");
// $fsdbDumpvars(0, AgeMatrixSelector_tb);
// $fsdbDumpvars("+mda");
// $fsdbDumpvars("+all");
// $fsdbDumpon();
// end
// `endif
// always #20 clk = !clk;
// endmodule

View File

@@ -0,0 +1,111 @@
module MultiPortStreamFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned DataWidth = 32;
localparam int unsigned EnqWidth = 2;
localparam int unsigned DeqWidth = 2;
localparam int unsigned TakenAll = 0;
// Ports
reg [EnqWidth-1:0] enq_vld_i;
reg [EnqWidth-1:0][DataWidth-1:0] enq_payload_i;
wire [EnqWidth-1:0] enq_rdy_o;
wire [DeqWidth-1:0] deq_vld_o;
wire [DeqWidth-1:0][DataWidth-1:0] deq_payload_o;
reg [DeqWidth-1:0] deq_rdy_i;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [DataWidth-1:0] golden_fifo[$];
bit [DataWidth-1:0] golden_fifo_front;
int usage = 0;
int iter = 1000000;
always @(posedge clk) begin
for (int i = 0; i < DeqWidth; i++) begin : test_deq
if (deq_vld_o[i] & deq_rdy_i[i]) begin
usage = usage - 1;
golden_fifo_front = golden_fifo.pop_front();
assert (deq_payload_o[i] == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", deq_payload_o[i],
golden_fifo_front);
end
end
end
for (int i = 0; i < EnqWidth; i++) begin : enq_test
if (enq_vld_i[i] & enq_rdy_o[i]) begin
usage = usage + 1;
golden_fifo.push_back(enq_payload_i[i]);
end
end
end
initial begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
deq_rdy_i = {DeqWidth{1'b0}};
enq_vld_i = {EnqWidth{1'b0}};
for (int i = 0; i < DeqWidth; i++) begin : gen_deq_rdy
if ($urandom_range(0, 1)) begin
deq_rdy_i[i] = 1'b1;
end else begin
break;
end
end
for (int i = 0; i < EnqWidth; i++) begin : gen_enq_vld
if ($urandom_range(0, 1)) begin
enq_vld_i[i] = 1'b1;
enq_payload_i[i] = $urandom();
end else begin
break;
end
end
CHECK_USAGE :
assert (usage == MultiPortStreamFIFO_dut.u_QueueManager.usage)
else begin
$fatal("\n Error : Usage is not equal, which should never happen! ours[%d] gloden[%d] \n",
MultiPortStreamFIFO_dut.u_QueueManager.usage, usage);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
MultiPortStreamFIFO #(
.Depth(Depth),
.DataWidth(DataWidth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.TakenAll(TakenAll)
) MultiPortStreamFIFO_dut (
.enq_vld_i(enq_vld_i),
.enq_payload_i(enq_payload_i),
.enq_rdy_o(enq_rdy_o),
.deq_vld_o(deq_vld_o),
.deq_payload_o(deq_payload_o),
.deq_rdy_i(deq_rdy_i),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("MultiPortStreamFIFO_tb.fsdb");
$fsdbDumpvars(0, MultiPortStreamFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,99 @@
module StaticPrioritySelector_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned EnqWidth = 2;
localparam int unsigned SelWidth = 2;
localparam int unsigned PtrWidth = $clog2(Depth);
// Ports
wire [EnqWidth-1:0][Depth-1:0] enq_mask_o;
reg [Depth-1:0] sel_mask_i;
wire [SelWidth-1:0][Depth-1:0] result_mask_o;
reg [Depth-1:0] entry_vld_i;
int iter = 100000;
bit [EnqWidth-1:0][Depth-1:0] golden_enq_mask;
bit [SelWidth-1:0][Depth-1:0] golden_result_mask;
int cnt;
initial begin
repeat (iter) begin
entry_vld_i = $urandom_range(0, ((1 << Depth) - 1));
sel_mask_i = $urandom_range(0, ((1 << Depth) - 1)) & entry_vld_i;
#100;
for (int i = 0; i < EnqWidth; i++) begin : init_golden_enq_mask
golden_enq_mask[i] = 0;
end
cnt = 0;
for (int i = 0; i < Depth; i++) begin : gen_golden_enq_mask
if (~entry_vld_i[i]) begin
golden_enq_mask[cnt][i] = 1'b1;
cnt = cnt + 1;
if (cnt == EnqWidth) begin
break;
end
end
end
for (int i = 0; i < SelWidth; i++) begin : init_golden_result_mask
golden_result_mask[i] = 0;
end
cnt = 0;
for (int i = 0; i < Depth; i++) begin : gen_golden_result_mask
if (sel_mask_i[i]) begin
golden_result_mask[cnt][i] = 1'b1;
cnt = cnt + 1;
if (cnt == SelWidth) begin
break;
end
end
end
CheckEnqEqual :
for (int i = 0; i < EnqWidth; i++) begin
assert (golden_enq_mask[i] == enq_mask_o[i])
else begin
$fatal("\n Masks are not equal, ours[%b] - golden[%b] \n", enq_mask_o[i],
golden_enq_mask[i]);
end
end
for (int i = 0; i < SelWidth; i++) begin
CheckSelEqual :
assert (golden_result_mask[i] == result_mask_o[i])
else begin
$fatal("\n Masks are not equal, ours[%b] - golden[%b] \n", result_mask_o[i],
golden_result_mask[i]);
end
end
end
#100;
$info("PASS\n");
$finish;
end
StaticPrioritySelector #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.SelWidth(SelWidth)
) StaticPrioritySelector_dut (
.enq_mask_o(enq_mask_o),
.sel_mask_i(sel_mask_i),
.result_mask_o(result_mask_o),
.entry_vld_i(entry_vld_i)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("StaticPrioritySelector_tb.fsdb");
$fsdbDumpvars(0, StaticPrioritySelector_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
endmodule

View File

@@ -0,0 +1,187 @@
module AgeMatrixSelector #(
parameter int unsigned EntryCount = 4,
parameter int unsigned EnqWidth = 2,
parameter int unsigned SelWidth = 2
) (
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0][EntryCount-1:0] enq_mask_i,
input wire deq_fire_i,
input wire [EntryCount-1:0] deq_mask_i,
input wire [EntryCount-1:0] sel_mask_i,
output wire [SelWidth-1:0][EntryCount-1:0] result_mask_o,
input wire [EntryCount-1:0] entry_vld_i,
input wire clk,
input wire rstn
);
wire [EntryCount-1:0] age_matrix_clk_en;
wire [EntryCount-1:0] enq_age_matrix_en;
wire [EntryCount-1:0] deq_age_matrix_en;
wire [EnqWidth-1:0][EntryCount-1:0] enq_dependency_vec;
wire [EntryCount-1:0][EnqWidth-1:0] enq_entry_sel_mask;
wire [EntryCount-1:0][EntryCount-1:0] enq_age_matrix;
wire [EntryCount-1:0][EntryCount-1:0] deq_age_matrix;
reg [EntryCount-1:0][EntryCount-1:0] age_matrix_d, age_matrix_q;
wire [SelWidth-1:0][EntryCount-1:0] selected_vec;
wire [SelWidth-1:0][EntryCount-1:0][EntryCount-1:0] masked_age_matrix;
// In age order select
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_selected_vec
if (i == 0) begin : gen_initial_one
assign selected_vec[i] = {EntryCount{1'b0}};
end else begin : gen_others
assign selected_vec[i] = selected_vec[i-1] | result_mask_o[i-1];
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_matrix
for (genvar col = 0; col < EntryCount; col++) begin : gen_col
for (genvar row = 0; row < EntryCount; row++) begin : gen_row
if (col == row) begin : gen_masked_vld
assign masked_age_matrix[i][row][col] = sel_mask_i[col] & ~selected_vec[i][col];
end else begin : gen_masked_dependency
assign masked_age_matrix[i][row][col] = (sel_mask_i[col] & ~selected_vec[i][col]) ?
age_matrix_q[row][col] : 1'b1;
end
end
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_multi_result
for (genvar row = 0; row < EntryCount; row++) begin : gen_one
assign result_mask_o[i][row] = &masked_age_matrix[i][row];
end
end
endgenerate
// Enq -> Set dependency bits
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_enq_entry_en
assign enq_age_matrix_en[i] = |enq_entry_sel_mask[i];
end
endgenerate
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_dependency_vec
if (i == 0) begin : gen_init_vec
assign enq_dependency_vec[i] = deq_fire_i ? (~entry_vld_i | deq_mask_i) : ~entry_vld_i;
end else begin : gen_vec_with_inter_check
assign enq_dependency_vec[i] = enq_fire_i[i-1] ?
(enq_dependency_vec[i-1] & ~enq_mask_i[i-1]) : enq_dependency_vec[i-1];
end
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_enq_entry_sel_mask
for (genvar j = 0; j < EnqWidth; j++) begin : gen_sel
assign enq_entry_sel_mask[i][j] = enq_fire_i[j] & enq_mask_i[j][i];
end
end
endgenerate
// Deq -> Clear dependency bits
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_deq_entry_clk_en
assign deq_age_matrix[i] = age_matrix_q[i] | deq_mask_i;
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_deq_entry_en
assign deq_age_matrix_en[i] = deq_fire_i & entry_vld_i[i];
end
endgenerate
assign age_matrix_clk_en = enq_age_matrix_en | deq_age_matrix_en;
// Age matrix update
always @(*) begin : age_matrix_vld_dff
for (int i = 0; i < EntryCount; i++) begin
age_matrix_q[i][i] = entry_vld_i[i];
end
end
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_age_matrix_update_logic
MuxOH #(
.InputWidth(2),
.DataWidth (EntryCount)
) u_age_matrix_update_MuxOH (
.sel_i ({enq_age_matrix_en[i], deq_age_matrix_en[i]}),
.data_i({enq_age_matrix[i], deq_age_matrix[i]}),
.data_o(age_matrix_d[i])
);
end
endgenerate
generate
for (genvar i = 0; i < EntryCount; i++) begin : gen_entry_update_dependency_vec
MuxOH #(
.InputWidth(EnqWidth),
.DataWidth (EntryCount)
) u_depend_vec_MuxOH (
.sel_i (enq_entry_sel_mask[i]),
.data_i(enq_dependency_vec),
.data_o(enq_age_matrix[i])
);
end
endgenerate
always @(posedge clk or negedge rstn) begin : age_matrix_dependency_dff
if (~rstn) begin
for (int row = 0; row < EntryCount; row++) begin
for (int col = 0; col < EntryCount; col++) begin
if (row != col) begin
age_matrix_q[row][col] <= 1'b0;
end
end
end
end else begin
for (int row = 0; row < EntryCount; row++) begin
if (age_matrix_clk_en[row]) begin
for (int col = 0; col < EntryCount; col++) begin
if (row != col) begin
age_matrix_q[row][col] <= age_matrix_d[row][col];
end
end
end
end
end
end
`ifndef SYNTHESIS
default disable iff (~rstn);
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_checker
ENQ_VLD_ENTRY :
assert property (@(posedge clk) enq_fire_i[i] |-> ((enq_mask_i[i] & entry_vld_i) == 0))
else begin
$fatal("\n Error : Enqueueing a valid entry! enq_mask[%b]\n", enq_mask_i[i]);
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_checker
SEL_INVLD_ENTRY :
assert property (@(negedge clk) |sel_mask_i |-> ((result_mask_o[i] & ~entry_vld_i) == 0))
else begin
$fatal("\n Error : Selecting a invalid entry! sel_mask[%b]\n",
(result_mask_o[i] & ~entry_vld_i));
end
RESULT_MASK_IS_ONEHOT :
assert property (@(negedge clk) |sel_mask_i |-> $onehot0(result_mask_o[i]))
else begin
$fatal("\n Error : Got multi-choice which should never happend! result_mask[%b]\n",
result_mask_o[i]);
end
end
endgenerate
`endif
endmodule

View File

@@ -0,0 +1,61 @@
// module FIAOWithAgeMatrix #(
// parameter int unsigned Depth = 8,
// parameter int unsigned EnqWidth = 2,
// parameter int unsigned SelWidth = 2,
// localparam int unsigned PtrWidth = $clog2(Depth)
// ) (
// // Enqueue Port
// input wire [EnqWidth-1:0] enq_fire_i,
// input wire [EnqWidth-1:0] enq_eval_i,
// output wire [Depth-1:0] enq_mask_o[EnqWidth],
// output wire [PtrWidth-1:0] enq_ptr_o[EnqWidth],
// // Select Port
// input wire [Depth-1:0] sel_mask_i,
// output wire [Depth-1:0] result_mask_o[SelWidth],
// // Status
// input wire [Depth-1:0] entry_vld_i,
// input wire clk,
// input wire rstn
// );
// wire [Depth-1:0] enq_rdy_mask[EnqWidth];
// generate
// for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_rdy_mask
// if (i == 0) begin : gen_initial_one
// assign enq_rdy_mask[i] = ~entry_vld_i;
// end else begin : gen_others
// assign enq_rdy_mask[i] = enq_eval_i[i-1] ?
// enq_rdy_mask[i-1] : (enq_rdy_mask[i-1] & ~enq_mask_o[i-1]);
// end
// end
// for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_mask
// assign enq_mask_o[i] = enq_rdy_mask[i] & ~(enq_rdy_mask[i] - 1'b1);
// OH2UInt #(
// .InputWidth(Depth)
// ) u_OH2UInt (
// .oh_i(enq_mask_o[i]),
// .result_o(enq_ptr_o[i])
// );
// end
// endgenerate
// AgeMatrixSelector #(
// .EntryCount(Depth),
// .EnqWidth (EnqWidth),
// .SelWidth (SelWidth)
// ) u_AgeMatrixSelector (
// .enq_fire_i(enq_fire_i),
// .enq_mask_i(enq_mask_o),
// .sel_mask_i(sel_mask_i),
// .result_mask_o(result_mask_o),
// .entry_vld_i(entry_vld_i),
// .clk(clk),
// .rstn(rstn)
// );
// endmodule

View File

@@ -0,0 +1,126 @@
module FIAOWithQueueManager #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter int unsigned SelWidth = 2,
localparam int unsigned PtrWidth = $clog2(Depth)
) (
// Enqueue Port
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0] enq_eval_i,
output wire [EnqWidth-1:0][Depth-1:0] enq_mask_o,
output wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr_o,
// Select Port
input wire [Depth-1:0] sel_mask_i,
output wire [SelWidth-1:0][Depth-1:0] result_mask_o,
// Status
input wire [Depth-1:0] entry_vld_i,
input wire clk,
input wire rstn
);
localparam int unsigned TagWidth = PtrWidth + 1;
wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr;
wire [EnqWidth-1:0] enq_flag;
wire [EnqWidth-1:0][TagWidth-1:0] enq_tag;
wire [DeqWidth-1:0] enq_eval;
wire [DeqWidth-1:0] enq_fire;
wire [DeqWidth-1:0][PtrWidth-1:0] deq_ptr;
wire [DeqWidth-1:0] deq_flag;
wire [DeqWidth-1:0][TagWidth-1:0] deq_tag;
wire [DeqWidth-1:0] deq_eval;
wire [DeqWidth-1:0] deq_fire;
wire first_enq_flag;
wire [PtrWidth-1:0] first_enq_ptr;
wire first_deq_flag;
wire [PtrWidth-1:0] first_deq_ptr;
wire flag_equal;
wire [Depth-1:0] head_inv_mask;
wire [Depth-1:0] tail_inv_mask;
wire [Depth-1:0] head_side_sel_mask[SelWidth-1:0];
wire [Depth-1:0] tail_side_sel_mask[SelWidth-1:0];
wire [Depth-1:0] head_side_sel_result[SelWidth-1:0];
wire [Depth-1:0] tail_side_sel_result[SelWidth-1:0];
wire [Depth-1:0] selected_mask[SelWidth-1:0];
// Enqueue Logic
assign enq_eval = enq_eval_i;
assign enq_fire = enq_fire_i;
assign enq_ptr_o = enq_ptr;
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_logic
assign enq_ptr[i] = enq_tag[i][PtrWidth-1:0];
assign enq_flag[i] = enq_tag[i][TagWidth-1];
assign enq_mask_o[i] = {{Depth - 1{1'b0}}, 1'b1} << enq_ptr[i];
end
endgenerate
// Select Logic
assign first_enq_flag = enq_flag[0];
assign first_enq_ptr = enq_ptr[0];
assign first_deq_flag = deq_flag[0];
assign first_deq_ptr = deq_ptr[0];
assign flag_equal = ~(first_enq_flag ^ first_deq_flag);
assign head_inv_mask = (({{PtrWidth - 1{1'b0}}, {1'b1}} << first_deq_ptr) - 1'b1);
assign tail_inv_mask = ~(({{PtrWidth - 1{1'b0}}, {1'b1}} << first_enq_ptr) - 1'b1);
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_selected_mask
if (i == 0) begin : gen_initial_one
assign selected_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign selected_mask[i] = selected_mask[i-1] | result_mask_o[i-1];
end
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_side_sel_mask
assign head_side_sel_mask[i] = sel_mask_i & ~selected_mask[i] & ~head_inv_mask;
assign tail_side_sel_mask[i] = sel_mask_i & ~selected_mask[i] & ~tail_inv_mask;
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_priority_select_result
assign head_side_sel_result[i] = head_side_sel_mask[i] & ~(head_side_sel_mask[i] - 1'b1);
assign tail_side_sel_result[i] = tail_side_sel_mask[i] & ~(tail_side_sel_mask[i] - 1'b1);
assign result_mask_o[i] = flag_equal ? head_side_sel_result[i] :
(|head_side_sel_result[i] ? head_side_sel_result[i] : tail_side_sel_result[i]);
end
endgenerate
// Dequeue Logic
generate
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_logic
assign deq_ptr[i] = deq_tag[i][PtrWidth-1:0];
assign deq_flag[i] = deq_tag[i][TagWidth-1];
assign deq_eval[i] = 1'b1;
assign deq_fire[i] = ~entry_vld_i[deq_tag[i]];
end
endgenerate
QueueManager #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.FlagEnable(1),
.EnqCollapse(1),
.DeqCollapse(0),
.InitFull(0)
) u_QueueManager (
.enq_fire_i(enq_fire),
.enq_eval_i(enq_eval),
.enq_tag_o(enq_tag),
.deq_fire_i(deq_fire),
.deq_eval_i(deq_eval),
.deq_tag_o(deq_tag),
.flush_i(1'b0),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,124 @@
module MultiPortStreamFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned DataWidth = 32,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter int unsigned TakenAll = 0
) (
input wire [EnqWidth-1:0] enq_vld_i,
input wire [EnqWidth-1:0][DataWidth-1:0] enq_payload_i,
output wire [EnqWidth-1:0] enq_rdy_o,
output wire [DeqWidth-1:0] deq_vld_o,
output wire [DeqWidth-1:0][DataWidth-1:0] deq_payload_o,
input wire [DeqWidth-1:0] deq_rdy_i,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned PtrWidth = $clog2(Depth);
reg [Depth-1:0] payload_clk_en;
reg [Depth-1:0] vld_dff_d, vld_dff_q;
reg [Depth-1:0][DataWidth-1:0] payload_dff_d, payload_dff_q;
wire [EnqWidth-1:0][PtrWidth-1:0] enq_ptr;
wire [DeqWidth-1:0][PtrWidth-1:0] deq_ptr;
wire [EnqWidth-1:0] enq_rdy;
wire [EnqWidth-1:0] enq_fire;
wire [DeqWidth-1:0] deq_fire;
assign enq_fire = enq_vld_i & enq_rdy_o;
assign deq_fire = deq_vld_o & deq_rdy_i;
always @(*) begin : vld_dff_update_logic
vld_dff_d = vld_dff_q;
for (int i = 0; i < EnqWidth; i++) begin
if (enq_fire[i]) begin
vld_dff_d[enq_ptr[i]] = 1'b1;
end
end
for (int i = 0; i < DeqWidth; i++) begin
if (deq_fire[i]) begin
vld_dff_d[deq_ptr[i]] = 1'b0;
end
end
if (flush_i) begin
vld_dff_d = {Depth{1'b0}};
end
end
always @(*) begin : payload_update_logic
for (int i = 0; i < Depth; i++) begin : payload_init
payload_clk_en[i] = 1'b0;
payload_dff_d[i] = payload_dff_q[i];
end
for (int i = 0; i < EnqWidth; i++) begin : enq_update
if (enq_fire[i] & ~flush_i) begin
payload_clk_en[enq_ptr[i]] = 1'b1;
payload_dff_d[enq_ptr[i]] = enq_payload_i[i];
end
end
end
generate
if (TakenAll) begin : gen_rdy_if_need_taken_all
assign enq_rdy_o = {EnqWidth{&enq_rdy}};
end else begin : gen_normal_rdy
assign enq_rdy_o = enq_rdy;
end
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_rdy_logic
assign enq_rdy[i] = ~vld_dff_q[enq_ptr[i]];
end
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_logic
assign deq_vld_o[i] = vld_dff_q[deq_ptr[i]];
assign deq_payload_o[i] = payload_dff_q[deq_ptr[i]];
end
endgenerate
DFFR #(
.Width(Depth)
) u_vld_dff (
.CLK(clk),
.RSTN(rstn),
.DRST({Depth{1'b0}}),
.D(vld_dff_d),
.Q(vld_dff_q)
);
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_dff
DFFE #(
.Width(DataWidth)
) u_payload_dff (
.CLK(clk),
.EN (payload_clk_en[i]),
.D (payload_dff_d[i]),
.Q (payload_dff_q[i])
);
end
endgenerate
QueueManager #(
.Depth(Depth),
.EnqWidth(EnqWidth),
.DeqWidth(DeqWidth),
.FlagEnable(0),
.EnqCollapse(1),
.DeqCollapse(0),
.InitFull(0)
) u_QueueManager (
.enq_fire_i(enq_fire),
.enq_eval_i(enq_vld_i),
.enq_tag_o(enq_ptr),
.deq_fire_i(deq_fire),
.deq_eval_i(deq_vld_o),
.deq_tag_o(deq_ptr),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,206 @@
module QueueManager #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned DeqWidth = 2,
parameter bit FlagEnable = 0,
parameter bit EnqCollapse = 0,
parameter bit DeqCollapse = 0,
parameter bit InitFull = 0,
localparam int unsigned PtrWidth = $clog2(Depth),
localparam int unsigned CntWidth = $clog2(Depth + 1),
localparam int unsigned TagWidth = PtrWidth + FlagEnable
) (
input wire [EnqWidth-1:0] enq_fire_i,
input wire [EnqWidth-1:0] enq_eval_i,
output wire [EnqWidth-1:0][TagWidth-1:0] enq_tag_o,
input wire [DeqWidth-1:0] deq_fire_i,
input wire [DeqWidth-1:0] deq_eval_i,
output wire [DeqWidth-1:0][TagWidth-1:0] deq_tag_o,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned EnqCountWidth = $clog2(EnqWidth + 1);
localparam int unsigned DeqCountWidth = $clog2(DeqWidth + 1);
function automatic [TagWidth-1:0] tagPlusOne;
input [TagWidth-1:0] originalTag;
begin
if (FlagEnable) begin
if (originalTag[PtrWidth-1:0] == Depth - 1) begin
tagPlusOne = {~originalTag[TagWidth-1], {PtrWidth{1'b0}}};
end else begin
tagPlusOne = originalTag + 1'b1;
end
end else begin
if (originalTag[PtrWidth-1:0] == Depth - 1) begin
tagPlusOne = {PtrWidth{1'b0}};
end else begin
tagPlusOne = originalTag + 1'b1;
end
end
end
endfunction
function automatic [TagWidth-1:0] tagPlus;
input [TagWidth-1:0] originalTag;
input [PtrWidth-1:0] delta;
reg [PtrWidth:0] sum;
reg [PtrWidth:0] reverse_sum;
begin
if (2 ** $clog2(Depth) == Depth) begin
tagPlus = originalTag + delta;
end else begin
sum = $unsigned({1'b0, originalTag[PtrWidth-1:0]}) + $unsigned({{1'b0}, delta});
reverse_sum = $signed(sum) - $unsigned(Depth);
if ($signed(reverse_sum) >= 0) begin
if (FlagEnable) begin
tagPlus = {~originalTag[TagWidth-1], reverse_sum[PtrWidth-1:0]};
end else begin
tagPlus = reverse_sum[PtrWidth-1:0];
end
end else begin
if (FlagEnable) begin
tagPlus = {originalTag[TagWidth-1], sum[PtrWidth-1:0]};
end else begin
tagPlus = sum[PtrWidth-1:0];
end
end
end
end
endfunction
wire enq_tag_clk_en;
wire [EnqWidth-1:0] enq_rdy_mask, enq_collapse_rdy_mask;
wire [EnqCountWidth-1:0] enq_cnt;
wire [PtrWidth-1:0] enq_delta;
reg [TagWidth-1:0] enq_tag_d, enq_tag_q;
wire deq_tag_clk_en;
wire [DeqCountWidth-1:0] deq_cnt;
wire [PtrWidth-1:0] deq_delta;
reg [TagWidth-1:0] deq_tag_d, deq_tag_q;
assign enq_tag_clk_en = (|enq_fire_i);
assign deq_tag_clk_en = (|deq_fire_i);
assign enq_delta = {{PtrWidth - EnqCountWidth{1'b0}}, enq_cnt};
assign deq_delta = {{PtrWidth - DeqCountWidth{1'b0}}, deq_cnt};
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_ptr
if (i == 0) begin : gen_first_enq_ptr
assign enq_tag_o[i] = enq_tag_q;
end else begin : gen_next_enq_ptr
assign enq_tag_o[i] = (EnqCollapse & ~enq_eval_i[i-1]) ? enq_tag_o[i-1] : tagPlusOne(
enq_tag_o[i-1]
);
end
end
for (genvar i = 0; i < DeqWidth; i++) begin : gen_deq_ptr
if (i == 0) begin : gen_first_deq_ptr
assign deq_tag_o[i] = deq_tag_q;
end else begin : gen_next_deq_ptr
assign deq_tag_o[i] = (DeqCollapse & ~deq_eval_i[i-1]) ? deq_tag_o[i-1] : tagPlusOne(
deq_tag_o[i-1]
);
end
end
endgenerate
always @(*) begin : enq_tag_update_logic
enq_tag_d = enq_tag_q;
if (enq_tag_clk_en) begin
enq_tag_d = tagPlus(enq_tag_q, enq_delta);
end
if (flush_i) begin
if (InitFull & FlagEnable) begin
enq_tag_d = {~deq_tag_q[TagWidth-1], deq_tag_q[PtrWidth-1:0]};
end else begin
enq_tag_d = deq_tag_q;
end
end
end
always @(*) begin : deq_tag_update_logic
deq_tag_d = deq_tag_q;
if (deq_tag_clk_en) begin
deq_tag_d = tagPlus(deq_tag_q, deq_delta);
end
if (flush_i) begin
deq_tag_d = deq_tag_q;
end
end
CountOne #(
.InputWidth(EnqWidth)
) u_enqCounter (
.bits_i(enq_fire_i),
.cnt_o (enq_cnt)
);
CountOne #(
.InputWidth(DeqWidth)
) u_deqCounter (
.bits_i(deq_fire_i),
.cnt_o (deq_cnt)
);
DFFRE #(
.Width(TagWidth)
) u_enq_tag_dff (
.CLK(clk),
.RSTN(rstn),
.EN(enq_tag_clk_en | flush_i),
.DRST({(InitFull & FlagEnable), {TagWidth - 1{1'b0}}}),
.D(enq_tag_d),
.Q(enq_tag_q)
);
DFFRE #(
.Width(TagWidth)
) u_deq_tag_dff (
.CLK(clk),
.RSTN(rstn),
.EN(deq_tag_clk_en | flush_i),
.DRST({TagWidth{1'b0}}),
.D(deq_tag_d),
.Q(deq_tag_q)
);
`ifndef SYNTHESIS
default disable iff (~rstn);
int unsigned usage = 0;
always @(posedge clk) begin : gen_usage
if (~rstn) begin
usage = 0;
end else begin
if (flush_i) begin
usage = 0;
end else if (enq_tag_clk_en & deq_tag_clk_en) begin
usage = usage + enq_cnt - deq_cnt;
end else if (enq_tag_clk_en) begin
usage = usage + enq_cnt;
end else if (deq_tag_clk_en) begin
usage = usage - deq_cnt;
end
end
end
CHECK_ENQ_WHEN_FULL :
assert property (@(posedge clk) enq_tag_clk_en |-> (Depth - usage >= enq_cnt))
else begin
$fatal("\n Error : Enqueue count[%d] > Availible count[%d]\n", enq_cnt, Depth - usage);
end
CHECK_DEQ_WHEN_EMPTY :
assert property (@(posedge clk) deq_tag_clk_en |-> (usage >= deq_cnt))
else begin
$fatal("\n Error : Dequeue count[%d] > Availible count[%d]\n", deq_cnt, usage);
end
`endif
endmodule

View File

@@ -0,0 +1,52 @@
module StaticPrioritySelector #(
parameter int unsigned Depth = 8,
parameter int unsigned EnqWidth = 2,
parameter int unsigned SelWidth = 2
) (
// Enqueue Port
output wire [EnqWidth-1:0][Depth-1:0] enq_mask_o,
// Select Port
input wire [Depth-1:0] sel_mask_i,
output wire [SelWidth-1:0][Depth-1:0] result_mask_o,
// Status
input wire [Depth-1:0] entry_vld_i
);
wire [EnqWidth-1:0][Depth-1:0] enq_allocated_mask;
wire [EnqWidth-1:0][Depth-1:0] masked_enq_rdy;
wire [SelWidth-1:0][Depth-1:0] selected_mask;
wire [SelWidth-1:0][Depth-1:0] masked_sel_mask;
generate
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_allocated_mask
if (i == 0) begin : gen_initial_one
assign enq_allocated_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign enq_allocated_mask[i] = enq_allocated_mask[i-1] | enq_mask_o[i-1];
end
assign masked_enq_rdy[i] = ~enq_allocated_mask[i] & ~entry_vld_i;
end
for (genvar i = 0; i < EnqWidth; i++) begin : gen_enq_mask
assign enq_mask_o[i] = masked_enq_rdy[i] & ~(masked_enq_rdy[i] - 1);
end
endgenerate
generate
for (genvar i = 0; i < SelWidth; i++) begin : gen_masked_sel_mask
if (i == 0) begin : gen_initial_one
assign selected_mask[i] = {Depth{1'b0}};
end else begin : gen_others
assign selected_mask[i] = selected_mask[i-1] | result_mask_o[i-1];
end
assign masked_sel_mask[i] = ~selected_mask[i] & sel_mask_i;
end
for (genvar i = 0; i < SelWidth; i++) begin : gen_sel_result
assign result_mask_o[i] = masked_sel_mask[i] & ~(masked_sel_mask[i] - 1);
end
endgenerate
endmodule