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

143
rtl/util/age_order_selector.sv Executable file
View File

@@ -0,0 +1,143 @@
`ifndef __AGE_ORDER_SELECTOR_SV__
`define __AGE_ORDER_SELECTOR_SV__
/*
* Age Matrix
* | Dependency bit |
* |E| | 0 | 1 | 2 | 3 |
* |N| 0 | 1 | 1 | 1 | 1 |
* |T| 1 | 0 | 1 | 1 | 1 |
* |R| 2 | 0 | 0 | 1 | 1 |
* |Y| 3 | 0 | 0 | 0 | 1 |
*
* age_matrix_r[i][i] : valid signal for entry(i)
* age_matrix_r[i][j] : if entry(j) deponds on entry(i)
*
* */
module age_order_selector #(
parameter int unsigned ENTRY_COUNT = 4,
parameter int unsigned ENQ_WIDTH = 1,
parameter int unsigned DEQ_WIDTH = 1,
parameter int unsigned SEL_WIDTH = 1,
localparam int unsigned ENTRY_TAG = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ENQ_WIDTH-1:0] enq_vld_i,
input logic [ENQ_WIDTH-1:0][ENTRY_TAG-1:0] enq_tag_i,
// Dequeue
input logic [DEQ_WIDTH-1:0] deq_vld_i,
input logic [DEQ_WIDTH-1:0][ENTRY_TAG-1:0] deq_tag_i,
// Status
output logic [ENTRY_COUNT-1:0] vld_mask_o,
// Select Oldest
input logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_mask_i,
output logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask_o,
// Flush
input logic flush_i,
input clk,
input rst
);
logic [ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] age_matrix_r, age_matrix_n;
logic [ENTRY_COUNT-1:0] vld_mask;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] sel_age_matrix;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask;
logic clk_en;
assign clk_en = (|enq_vld_i) | (|deq_vld_i) | flush_i;
always_comb begin : get_vld_mask
for (int row = 0; row < ENTRY_COUNT; row++) begin
vld_mask[row] = age_matrix_r[row][row];
end
end
// Sel Oldest Logic
always_comb begin : gen_sel_matrix
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (row == col) begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col];
end else begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col] ? age_matrix_r[row][col] :
1'b1;
end
end
end
end
end
always_comb begin : gen_sel_oldest_mask
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
sel_oldest_mask[i][row] = &sel_age_matrix[i][row];
end
end
end
// Update Logic
always_comb begin : update_logic
age_matrix_n = age_matrix_r;
for (int i = 0; i < ENQ_WIDTH; i++) begin
if (enq_vld_i[i]) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[enq_tag_i[i]][col] = ~age_matrix_r[col][col]; // Set Dependency
for(int j = 0; j < i; j++) begin
if(enq_vld_i[j]) begin
age_matrix_n[enq_tag_i[i]][enq_tag_i[j]] = 1'b0;
end
end
end
end
end
for (int i = 0; i < DEQ_WIDTH; i++) begin
if (deq_vld_i[i]) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
age_matrix_n[row][deq_tag_i[i]] = deq_tag_i[i] !=
row[ENTRY_TAG-1:0]; // Clear Dependency
end
end
end
if (flush_i) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[row][col] = 1'b0;
end
end
end
end
always_ff @(posedge clk) begin : age_matrix_dff
if (rst) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_r[row][col] <= 1'b0;
end
end
end else begin
if (clk_en) begin
age_matrix_r <= age_matrix_n;
end
end
end
// Output
assign vld_mask_o = vld_mask;
assign sel_oldest_mask_o = sel_oldest_mask;
endmodule : age_order_selector
`endif

View File

@@ -0,0 +1,203 @@
`ifndef __AGE_ORDER_SELECTOR_WITH_HEAD_SV__
`define __AGE_ORDER_SELECTOR_WITH_HEAD_SV__
/*
* Age Matrix
* | Dependency bit |
* |E| | 0 | 1 | 2 | 3 |
* |N| 0 | 1 | 1 | 1 | 1 |
* |T| 1 | 0 | 1 | 1 | 1 |
* |R| 2 | 0 | 0 | 1 | 1 |
* |Y| 3 | 0 | 0 | 0 | 1 |
*
* age_matrix_r[i][i] : valid signal for entry(i)
* age_matrix_r[i][j] : if entry(j) deponds on entry(i)
*
* */
module age_order_selector_with_head #(
parameter int unsigned ENTRY_COUNT = 4,
parameter int unsigned ENQ_WIDTH = 1,
parameter int unsigned DEQ_WIDTH = 1,
parameter int unsigned SEL_WIDTH = 1,
parameter int unsigned HEAD_PTR_COUNT = 1,
localparam int unsigned ENTRY_TAG = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ENQ_WIDTH-1:0] enq_vld_i,
input logic [ENQ_WIDTH-1:0][ENTRY_TAG-1:0] enq_tag_i,
// Dequeue
input logic [DEQ_WIDTH-1:0] deq_vld_i,
input logic [DEQ_WIDTH-1:0][ENTRY_TAG-1:0] deq_tag_i,
// Status
output logic [ENTRY_COUNT-1:0] vld_mask_o,
output logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] oldest_mask_o,
// Select Oldest
input logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_mask_i,
output logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask_o,
// Flush
input logic flush_i,
input clk,
input rst
);
logic [ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] age_matrix_r, age_matrix_n;
logic [ENTRY_COUNT-1:0] vld_mask;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] sel_age_matrix;
logic [SEL_WIDTH-1:0][ENTRY_COUNT-1:0] sel_oldest_mask;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] oldest_mask_r, oldest_mask_n;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0] masked_vld_mask;
logic [HEAD_PTR_COUNT-1:0][ENTRY_COUNT-1:0][ENTRY_COUNT-1:0] head_masked_age_matrix;
logic clk_en;
assign clk_en = (|enq_vld_i) | (|deq_vld_i) | flush_i;
always_comb begin : get_vld_mask
for (int row = 0; row < ENTRY_COUNT; row++) begin
vld_mask[row] = age_matrix_r[row][row];
end
end
// Sel Oldest Logic
always_comb begin : gen_sel_matrix
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (row == col) begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col];
end else begin
sel_age_matrix[i][row][col] = sel_mask_i[i][col] ? age_matrix_r[row][col] :
1'b1;
end
end
end
end
end
always_comb begin : gen_sel_oldest_mask
for (int i = 0; i < SEL_WIDTH; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
sel_oldest_mask[i][row] = &sel_age_matrix[i][row];
end
end
end
// Update Logic
always_comb begin : update_logic
age_matrix_n = age_matrix_r;
for(int i = 0; i < ENQ_WIDTH; i++) begin
if (enq_vld_i[i]) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[enq_tag_i[i]][col] = ~age_matrix_r[col][col]; // Set Dependency
for(int j = 0; j < i; j++) begin
if(enq_vld_i[j]) begin
age_matrix_n[enq_tag_i[i]][enq_tag_i[j]] = 1'b0;
end
end
end
end
end
for(int i = 0 ; i < DEQ_WIDTH; i++) begin
if (deq_vld_i[i]) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
age_matrix_n[row][deq_tag_i[i]] = deq_tag_i[i] != row[ENTRY_TAG-1:0]; // Clear Dependency
end
end
end
if (flush_i) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_n[row][col] = 1'b0;
end
end
end
end
always_ff @(posedge clk) begin : age_matrix_dff
if (rst) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
age_matrix_r[row][col] <= 1'b0;
end
end
end else begin
if (clk_en) begin
age_matrix_r <= age_matrix_n;
end
end
end
// n-head Logic
always_comb begin : gen_masked_vld_mask
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
if (i == 0) begin
masked_vld_mask[i] = vld_mask;
end else begin
masked_vld_mask[i] = masked_vld_mask[i-1] & ~oldest_mask_n[i-1];
end
end
end
always_comb begin : gen_head_masked_matrix
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
for (int col = 0; col < ENTRY_COUNT; col++) begin
if (i == 0) begin
head_masked_age_matrix[i][row][col] = age_matrix_n[row][col];
end else begin
if (col == row) begin
head_masked_age_matrix[i][row][col] = masked_vld_mask[i][col];
end else begin
head_masked_age_matrix[i][row][col] = masked_vld_mask[i][col] ?
head_masked_age_matrix[i-1][row][col] : 1'b1;
end
end
end
end
end
end
always_comb begin : gen_n_head_mask
for (int i = 0; i < HEAD_PTR_COUNT; i++) begin
for (int row = 0; row < ENTRY_COUNT; row++) begin
oldest_mask_n[i][row] = &head_masked_age_matrix[i][row];
end
if (flush_i) begin
oldest_mask_n = {HEAD_PTR_COUNT * ENTRY_COUNT{1'b0}};
end
end
end
always_ff @(posedge clk) begin : oldest_mask_dff
if (rst) begin
oldest_mask_r <= {HEAD_PTR_COUNT * ENTRY_COUNT{1'b0}};
end else begin
if (clk_en) begin
oldest_mask_r <= oldest_mask_n;
end
end
end
// Output
assign oldest_mask_o = oldest_mask_r;
assign vld_mask_o = vld_mask;
assign sel_oldest_mask_o = sel_oldest_mask;
endmodule : age_order_selector_with_head
`endif

3
rtl/util/commoncell/.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "tools/pico"]
path = tools/pico
url = git@gitlab.com:series-han/development/pico.git

View File

@@ -0,0 +1,5 @@
Name: CommonCell
Dependency:
- src/StdDFF/StdDFF.yaml
- src/Basic/Basic.yaml
- src/Queue/Queue.yaml

View File

@@ -0,0 +1,92 @@
# CommonCell
Common logic cell for RTL encoding.
## Getting started
To make it easy for you to get started with GitLab, here's a list of recommended next steps.
Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
## Add your files
- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
```
cd existing_repo
git remote add origin https://gitlab.com/series-han/hardware/commoncell.git
git branch -M main
git push -uf origin main
```
## Integrate with your tools
- [ ] [Set up project integrations](https://gitlab.com/series-han/hardware/commoncell/-/settings/integrations)
## Collaborate with your team
- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
- [ ] [Automatically merge when pipeline succeeds](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
## Test and Deploy
Use the built-in continuous integration in GitLab.
- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing(SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
***
# Editing this README
When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thank you to [makeareadme.com](https://www.makeareadme.com/) for this template.
## Suggestions for a good README
Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
## Name
Choose a self-explaining name for your project.
## Description
Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
## Badges
On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
## Visuals
Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
## Installation
Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
## Usage
Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
## Support
Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
## Roadmap
If you have ideas for releases in the future, it is a good idea to list them in the README.
## Contributing
State if you are open to contributions and what your requirements are for accepting them.
For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
## Authors and acknowledgment
Show your appreciation to those who have contributed to the project.
## License
For open source projects, say how it is licensed.
## Project status
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

0
rtl/util/commoncell/doc/.gitignore vendored Normal file
View File

11
rtl/util/commoncell/env/sourceme vendored Normal file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
CURDIR=$(cd $(dirname ${BASH_SOURCE[0]}); pwd )
PROJ_ROOT=$CURDIR/../
PICO_PATH=$PROJ_ROOT/tools/pico/
export PROJ_ROOT
export PATH=$PICO_PATH:$PATH

View File

@@ -0,0 +1,67 @@
Name: Basic
Dependency:
- ../StdDFF/StdDFF.yaml
Module:
- name: CountOne
description: CountOne
language: SystemVerilog
rtl:
- hw/CountOne.v
sim:
- dv/CountOne_tb.v
- name: MuxOH
description: One-hot Mux
language: SystemVerilog
rtl:
- hw/MuxOH.v
sim:
- dv/MuxOH_tb.v
- name: OH2UInt
description: One-hot to UInt
language: SystemVerilog
rtl:
- hw/OH2UInt.v
dependency:
- CountOne
- name: PriorityMux
description: Priority Mux
language: SystemVerilog
rtl:
- hw/PriorityMux.v
dependency:
- MuxOH
- name: SyncFIFO
description: Sync FIFO
language: SystemVerilog
rtl:
- hw/SyncFIFO.v
sim:
- dv/SyncFIFO_tb.v
dependency:
- StdDFF
- name: StreamFIFO
description: StreamFIFO
language: SystemVerilog
rtl:
- hw/StreamFIFO.v
sim:
- dv/StreamFIFO_tb.v
dependency:
- SyncFIFO
- name: PLRU
description: PLRU
language: SystemVerilog
rtl:
- hw/PLRUTree.v
- hw/PLRU.v
sim:
- dv/PLRU_tb.v
dependency:
- StdDFF

View File

@@ -0,0 +1,59 @@
module CountOne_tb;
// Parameters
localparam int unsigned InputWidth = 8;
localparam int unsigned CountWidth = $clog2(InputWidth + 1);
// Ports
reg [InputWidth-1:0] bits_i;
wire [CountWidth-1:0] cnt_o;
CountOne #(
.InputWidth(InputWidth)
) u_CountOne (
.bits_i(bits_i),
.cnt_o (cnt_o)
);
function automatic [CountWidth-1:0] GlodenModel;
input bit [InputWidth-1:0] in;
bit [CountWidth-1:0] sum;
begin
sum = 0;
for (int i = 0; i < InputWidth; i++) begin
sum = sum + in[i];
end
GlodenModel = sum;
end
endfunction
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("CountOne_tb.fsdb");
$fsdbDumpvars(0, CountOne_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
initial begin : RANDOM_TEST
begin
repeat (10000) begin : GEN_CASE
bits_i = $urandom_range(0, InputWidth - 1);
#100;
NOT_EQUAL :
assert (cnt_o == GlodenModel(bits_i))
else begin
$error("Input[%b], Output[%d], Gloden[%d]\n", bits_i, cnt_o, GlodenModel(bits_i));
break;
end
end
#100;
$fatal("PASS\n");
$finish;
end
end
endmodule

View File

@@ -0,0 +1,66 @@
module MuxOH_tb;
// Parameters
localparam int unsigned InputWidth = 8;
localparam int unsigned DataWidth = 8;
// Ports
reg [InputWidth-1:0] sel_i;
reg [InputWidth-1:0][DataWidth-1:0] data_i;
wire [DataWidth-1:0] data_o;
MuxOH #(
.InputWidth(InputWidth),
.DataWidth (DataWidth)
) u_MuxOH (
.sel_i (sel_i),
.data_i(data_i),
.data_o(data_o)
);
function automatic [DataWidth-1:0] GlodenModel;
input bit [InputWidth-1:0] sel;
input bit [InputWidth-1:0][DataWidth-1:0] data;
bit [DataWidth-1:0] result;
begin
for (int i = 0; i < InputWidth; i++) begin
if (sel[i]) begin
result = data[i];
end
end
GlodenModel = result;
end
endfunction
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("MuxOH_tb.fsdb");
$fsdbDumpvars(0, MuxOH_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
initial begin
repeat (10000) begin : GEN_CASE
sel_i = 1 << $urandom_range(0, InputWidth - 1);
for (int i = 0; i < InputWidth; i++) begin
data_i[i] = $urandom();
end
#100;
NOT_EQUAL :
assert (data_o == GlodenModel(sel_i, data_i))
else begin
$fatal("Input[%b], Output[%d], Gloden[%d]\n", sel_i, data_o, GlodenModel(sel_i, data_i));
break;
end
end
#100;
$info("PASS\n");
$finish;
end
endmodule

View File

@@ -0,0 +1,49 @@
module PLRU_tb;
// Parameters
localparam ENTRY_COUNT = 4;
// Ports
reg [ENTRY_COUNT-1:0] access_mask_i;
wire [ENTRY_COUNT-1:0] least_used_mask_o;
reg clk = 0;
reg rstn = 0;
PLRU #(
.ENTRY_COUNT(ENTRY_COUNT)
) PLRU_dut (
.access_mask_i(access_mask_i),
.least_used_mask_o(least_used_mask_o),
.clk(clk),
.rstn(rstn)
);
initial begin
begin
#10 rstn = 1'b1;
repeat (10000) begin
@(negedge clk);
if (|access_mask_i) begin
$info("\n Access Entry[%d], PLRU Change to [%d]\n", $countones(access_mask_i-1), $countones(
least_used_mask_o - 1));
end
access_mask_i = 1 << $urandom_range(0, ENTRY_COUNT - 1);
@(posedge clk);
end
$finish;
end
end
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("PLRU_tb.fsdb");
$fsdbDumpvars(0, PLRU_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,83 @@
module StreamFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned WordWidth = 64;
// Ports
reg enq_vld_i = 0;
reg [WordWidth-1:0] enq_payload_i;
wire enq_rdy_o;
wire deq_vld_o;
wire [WordWidth-1:0] deq_payload_o;
reg deq_rdy_i = 0;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [WordWidth-1:0] golden_fifo[$];
bit [WordWidth-1:0] random_payload;
bit [WordWidth-1:0] golden_fifo_front;
int iter = 1000000;
initial begin
begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
enq_vld_i = 1'b0;
deq_rdy_i = 1'b0;
if ($urandom_range(0, 1) && deq_vld_o) begin : test_deq
deq_rdy_i = 1'b1;
golden_fifo_front = golden_fifo.pop_front();
CHECK_EQUALATION :
assert (deq_payload_o == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", deq_payload_o,
golden_fifo_front);
end
;
end
if ($urandom_range(0, 1) && enq_rdy_o) begin : test_push
random_payload = $urandom();
enq_vld_i = 1'b1;
enq_payload_i = random_payload;
golden_fifo.push_back(random_payload);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
end
StreamFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) StreamFIFO_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("StreamFIFO_tb.fsdb");
$fsdbDumpvars(0, StreamFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,83 @@
module SyncFIFO_tb;
// Parameters
localparam int unsigned Depth = 8;
localparam int unsigned WordWidth = 32;
// Ports
reg push_i = 0;
reg [WordWidth-1:0] push_payload_i;
reg pop_i = 0;
wire [WordWidth-1:0] pop_payload_o;
wire full_o;
wire empty_o;
reg flush_i = 0;
reg clk = 0;
reg rstn = 0;
bit [WordWidth-1:0] golden_fifo[$];
bit [WordWidth-1:0] random_payload;
bit [WordWidth-1:0] golden_fifo_front;
int iter = 1000000;
initial begin
begin
#10 rstn = 1'b1;
repeat (iter) begin : random_test
@(negedge clk);
pop_i = 1'b0;
push_i = 1'b0;
if ($urandom_range(0, 1) && ~empty_o) begin : test_pop
pop_i = 1'b1;
golden_fifo_front = golden_fifo.pop_front();
CHECK_EQUALATION :
assert (pop_payload_o == golden_fifo_front)
else begin
$fatal("\n Error: Fail when check equalation, ours[%x] -- gloden[%x]", pop_payload_o,
golden_fifo_front);
end
;
end
if ($urandom_range(0, 1) && ~full_o) begin : test_push
random_payload = $urandom();
push_i = 1'b1;
push_payload_i = random_payload;
golden_fifo.push_back(random_payload);
end
end
$info("\n PASS after %d iter \n", iter);
$finish;
end
end
SyncFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) SyncFIFO_dut (
.push_i(push_i),
.push_payload_i(push_payload_i),
.pop_i(pop_i),
.pop_payload_o(pop_payload_o),
.full_o(full_o),
.empty_o(empty_o),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
`ifdef DUMPON
initial begin : GEN_WAVEFORM
$fsdbDumpfile("SyncFIFO_tb.fsdb");
$fsdbDumpvars(0, SyncFIFO_tb);
$fsdbDumpvars("+mda");
$fsdbDumpvars("+all");
$fsdbDumpon();
end
`endif
always #20 clk = !clk;
endmodule

View File

@@ -0,0 +1,42 @@
module CountOne #(
parameter int unsigned InputWidth = 8,
localparam int unsigned CountWidth = $clog2(InputWidth + 1)
) (
input wire [InputWidth-1:0] bits_i,
output wire [CountWidth-1:0] cnt_o
);
localparam int unsigned PaddedWidth = 1 << $clog2(InputWidth);
localparam int unsigned ChildCountWidth = PaddedWidth == 1 ? 1 : $clog2(PaddedWidth);
wire [ChildCountWidth-1:0] leftChildCount, rightChildCount;
generate
if (InputWidth == 1) begin : gen_single_node
assign leftChildCount = 1'b0;
assign rightChildCount = bits_i;
end else if (InputWidth == 2) begin : gen_leaf_node
assign leftChildCount = bits_i[0];
assign rightChildCount = bits_i[1];
end else begin : gen_non_leaf_node
wire [PaddedWidth-1:0] paddedBits;
// Zero pad the input bits to next power of two
assign paddedBits = {{PaddedWidth - InputWidth{1'b0}}, bits_i};
CountOne #(
.InputWidth(PaddedWidth / 2)
) u_leftChild (
.bits_i(paddedBits[PaddedWidth-1:PaddedWidth/2]),
.cnt_o (leftChildCount)
);
CountOne #(
.InputWidth(PaddedWidth / 2)
) u_rightChild (
.bits_i(paddedBits[PaddedWidth/2-1:0]),
.cnt_o (rightChildCount)
);
end
endgenerate
assign cnt_o = leftChildCount + rightChildCount;
endmodule

View File

@@ -0,0 +1,21 @@
module MuxOH #(
parameter int unsigned InputWidth = 8,
parameter int unsigned DataWidth = 8
) (
input wire [InputWidth-1:0] sel_i,
input wire [InputWidth-1:0][DataWidth-1:0] data_i,
output wire [DataWidth-1:0] data_o
);
wire [DataWidth-1:0][InputWidth-1:0] dataT;
generate
for (genvar i = 0; i < DataWidth; i++) begin : gen_row
for (genvar j = 0; j < InputWidth; j++) begin : gen_col
assign dataT[i][j] = data_i[j][i];
end
assign data_o[i] = |(dataT[i] & sel_i);
end
endgenerate
endmodule

View File

@@ -0,0 +1,25 @@
module OH2UInt #(
parameter int unsigned InputWidth = 8,
localparam int unsigned OutputWidth = InputWidth > 1 ? $clog2(InputWidth) : 1
) (
input wire [ InputWidth-1:0] oh_i,
output wire [OutputWidth-1:0] result_o
);
localparam int unsigned CountWidth = $clog2(InputWidth + 1);
wire [InputWidth-1:0] maskLow;
wire [CountWidth-1:0] count;
assign maskLow = oh_i - 1'b1;
assign result_o = count[OutputWidth-1:0];
CountOne #(
.InputWidth(InputWidth)
) CountOne_dut (
.bits_i(maskLow),
.cnt_o (count)
);
endmodule

View File

@@ -0,0 +1,48 @@
module PLRU #(
parameter ENTRY_COUNT = 4
) (
input [ENTRY_COUNT-1:0] access_mask_i,
output [ENTRY_COUNT-1:0] least_used_mask_o,
input clk,
input rstn
);
localparam PLRUTreeLvl = $clog2(ENTRY_COUNT);
localparam NodeCount = ENTRY_COUNT - 1;
generate
if (ENTRY_COUNT == 1) begin : gen_one_entry_case
assign least_used_mask_o = 1'b1;
end else begin : gen_normal_case
wire plru_nodes_clk_en;
wire [NodeCount-1:0] plru_nodes_d;
reg [NodeCount-1:0] plru_nodes_q;
assign plru_nodes_clk_en = |access_mask_i;
DFFRE #(
.Width(NodeCount)
) u_plru_nodes_DFFRE (
.CLK(clk),
.RSTN(rstn),
.DRST({NodeCount{1'b0}}),
.EN(plru_nodes_clk_en),
.D(plru_nodes_d),
.Q(plru_nodes_q)
);
PLRUTree #(
.TREE_LVL_COUNT(PLRUTreeLvl)
) u_PLRUTree (
.access_mask_i(access_mask_i),
.plru_old_node_i(plru_nodes_q),
.plru_new_node_o(plru_nodes_d),
.node_en_i(1'b1),
.least_used_mask_o(least_used_mask_o),
.clk(clk),
.rstn(rstn)
);
end
endgenerate
endmodule

View File

@@ -0,0 +1,64 @@
module PLRUTree #(
parameter TREE_LVL_COUNT = 3,
localparam ENTRY_COUNT = (1 << TREE_LVL_COUNT),
localparam NODE_COUNT = ENTRY_COUNT - 1
) (
input [ENTRY_COUNT-1:0] access_mask_i,
input [NODE_COUNT-1:0] plru_old_node_i,
output [NODE_COUNT-1:0] plru_new_node_o,
input node_en_i,
output [ENTRY_COUNT-1:0] least_used_mask_o,
input clk,
input rstn
);
wire node_toggle_en;
wire node;
wire left_child_node_en;
wire right_child_node_en;
wire access_left;
wire access_right;
assign node = plru_old_node_i[0];
assign node_toggle_en = (~node & access_left) | (node & access_right);
assign plru_new_node_o[0] = node_toggle_en ? ~node : node;
assign access_left = |access_mask_i[ENTRY_COUNT/2-1:0];
assign access_right = |access_mask_i[ENTRY_COUNT-1:ENTRY_COUNT/2];
assign left_child_node_en = node_en_i & ~node;
assign right_child_node_en = node_en_i & node;
generate
if (TREE_LVL_COUNT > 1) begin : gen_child_tree
PLRUTree #(
.TREE_LVL_COUNT(TREE_LVL_COUNT - 1)
) u_left_child_PLRUTree (
.access_mask_i(access_mask_i[ENTRY_COUNT/2-1:0]),
.plru_old_node_i(plru_old_node_i[(NODE_COUNT-1)/2:1]),
.plru_new_node_o(plru_new_node_o[(NODE_COUNT-1)/2:1]),
.node_en_i(left_child_node_en),
.least_used_mask_o(least_used_mask_o[ENTRY_COUNT/2-1:0]),
.clk(clk),
.rstn(rstn)
);
PLRUTree #(
.TREE_LVL_COUNT(TREE_LVL_COUNT - 1)
) u_right_child_PLRUTree (
.access_mask_i(access_mask_i[ENTRY_COUNT-1:ENTRY_COUNT/2]),
.plru_old_node_i(plru_old_node_i[NODE_COUNT-1:(NODE_COUNT+1)/2]),
.plru_new_node_o(plru_new_node_o[NODE_COUNT-1:(NODE_COUNT+1)/2]),
.node_en_i(right_child_node_en),
.least_used_mask_o(least_used_mask_o[ENTRY_COUNT-1:ENTRY_COUNT/2]),
.clk(clk),
.rstn(rstn)
);
end else begin : gen_leaf
assign least_used_mask_o[0] = left_child_node_en;
assign least_used_mask_o[1] = right_child_node_en;
end
endgenerate
endmodule

View File

@@ -0,0 +1,24 @@
module PriorityMux #(
parameter int unsigned InputWidth = 8,
parameter int unsigned DataWidth = 8
) (
input wire [InputWidth-1:0] sel_i,
input wire [InputWidth-1:0][DataWidth-1:0] data_i,
output wire [DataWidth-1:0] data_o
);
wire [InputWidth-1:0] sel_oh;
assign sel_oh = sel_i & (~(sel_i - 1));
MuxOH #(
.InputWidth(InputWidth),
.DataWidth (DataWidth)
) u_MuxOH (
.sel_i (sel_oh),
.data_i(data_i),
.data_o(data_o)
);
endmodule

View File

@@ -0,0 +1,52 @@
module StreamFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned WordWidth = 64
) (
input wire enq_vld_i,
input wire [WordWidth-1:0] enq_payload_i,
output wire enq_rdy_o,
output wire deq_vld_o,
output wire [WordWidth-1:0] deq_payload_o,
input wire deq_rdy_i,
input wire flush_i,
input wire clk,
input wire rstn
);
wire push;
wire [WordWidth-1:0] push_payload;
wire pop;
wire [WordWidth-1:0] pop_payload;
wire full;
wire empty;
wire enq_fire;
wire deq_fire;
assign enq_rdy_o = ~full;
assign enq_fire = enq_vld_i & enq_rdy_o;
assign push = enq_fire;
assign push_payload = enq_payload_i;
assign pop = deq_fire;
assign deq_vld_o = ~empty;
assign deq_fire = deq_vld_o & deq_rdy_i;
assign deq_payload_o = pop_payload;
SyncFIFO #(
.Depth(Depth),
.WordWidth(WordWidth)
) u_SyncFIFO (
.push_i(push),
.push_payload_i(push_payload),
.pop_i(pop),
.pop_payload_o(pop_payload),
.full_o(full),
.empty_o(empty),
.flush_i(flush_i),
.clk(clk),
.rstn(rstn)
);
endmodule

View File

@@ -0,0 +1,129 @@
module SyncFIFO #(
parameter int unsigned Depth = 8,
parameter int unsigned WordWidth = 64
) (
input wire push_i,
input wire [WordWidth-1:0] push_payload_i,
input wire pop_i,
output wire [WordWidth-1:0] pop_payload_o,
output wire full_o,
output wire empty_o,
input wire flush_i,
input wire clk,
input wire rstn
);
localparam int unsigned PtrWidth = $clog2(Depth);
wire [Depth-1:0] payload_ram_clk_en;
wire [Depth-1:0][WordWidth-1:0] payload_ram_d, payload_ram_q;
wire head_clk_en;
reg head_flag_d, head_flag_q;
reg [PtrWidth-1:0] head_ptr_d, head_ptr_q;
wire tail_clk_en;
reg tail_flag_d, tail_flag_q;
reg [PtrWidth-1:0] tail_ptr_d, tail_ptr_q;
wire ptr_equal;
wire flag_equal;
assign head_clk_en = pop_i | flush_i;
assign tail_clk_en = push_i | flush_i;
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_update_logic
assign payload_ram_clk_en[i] = (push_i & ~flush_i) & (tail_ptr_q == i);
assign payload_ram_d[i] = payload_ram_clk_en[i] ? push_payload_i : payload_ram_q[i];
end
endgenerate
always @(*) begin : tail_update_logic
{tail_flag_d, tail_ptr_d} = {tail_flag_q, tail_ptr_q};
if (push_i) begin
if (tail_ptr_q == Depth - 1) begin
{tail_flag_d, tail_ptr_d} = {~tail_flag_q, {PtrWidth{1'b0}}};
end else begin
tail_ptr_d = tail_ptr_q + 1'b1;
end
end
if (flush_i) begin
{tail_flag_d, tail_ptr_d} = {PtrWidth + 1{1'b0}};
end
end
always @(*) begin : head_update_logic
{head_flag_d, head_ptr_d} = {head_flag_q, head_ptr_q};
if (pop_i) begin
if (head_ptr_q == Depth - 1) begin
{head_flag_d, head_ptr_d} = {~head_flag_q, {PtrWidth{1'b0}}};
end else begin
head_ptr_d = head_ptr_q + 1'b1;
end
end
if (flush_i) begin
{head_flag_d, head_ptr_d} = {PtrWidth + 1{1'b0}};
end
end
assign flag_equal = head_flag_q == tail_flag_q;
assign ptr_equal = head_ptr_q == tail_ptr_q;
assign full_o = (~flag_equal & ptr_equal & ~pop_i);
assign empty_o = flag_equal & ptr_equal;
assign pop_payload_o = payload_ram_q[head_ptr_q];
DFFRE #(
.Width(PtrWidth + 1)
) u_head_dff (
.CLK(clk),
.RSTN(rstn),
.EN(head_clk_en),
.DRST({PtrWidth + 1{1'b0}}),
.D({head_flag_d, head_ptr_d}),
.Q({head_flag_q, head_ptr_q})
);
DFFRE #(
.Width(PtrWidth + 1)
) u_tail_dff (
.CLK(clk),
.RSTN(rstn),
.EN(tail_clk_en),
.DRST({PtrWidth + 1{1'b0}}),
.D({tail_flag_d, tail_ptr_d}),
.Q({tail_flag_q, tail_ptr_q})
);
generate
for (genvar i = 0; i < Depth; i++) begin : gen_payload_dff
DFFE #(
.Width(WordWidth)
) u_payload_dff (
.CLK(clk),
.EN (payload_ram_clk_en[i]),
.D (payload_ram_d[i]),
.Q (payload_ram_q[i])
);
end
endgenerate
`ifndef SYNTHESIS
default disable iff (~rstn); CHECK_POP_WHEN_EMPTY :
assert property (@(posedge clk) pop_i |-> ~empty_o)
else begin
$error("Pop when empty\n");
end
CHECK_PUSH_WHEN_FULL :
assert property (@(posedge clk) push_i |-> ~full_o)
else begin
$error("Push when full\n");
end
`endif
endmodule

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

View File

@@ -0,0 +1,39 @@
Name : StdDFF
Module:
- name: DFFUncertainChecker
description: DFF uncertain checker
language: SystemVerilog
rtl:
- dv/DFFUncertainChecker.v
- name: DFF
description: Standard DFF
language: SystemVerilog
rtl:
- hw/DFF.v
dependency:
- DFFUncertainChecker
- name: DFFE
description: Standard DFF with EN port
language: SystemVerilog
rtl:
- hw/DFFE.v
dependency:
- DFFUncertainChecker
- name: DFFR
description: Standard DFF with RST port
language: SystemVerilog
rtl:
- hw/DFFR.v
dependency:
- DFFUncertainChecker
- name: DFFRE
description: Standard DFF with EN and RST port
language: SystemVerilog
rtl:
- hw/DFFRE.v
dependency:
- DFFUncertainChecker

View File

@@ -0,0 +1,17 @@
module DFFUncertainChecker #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire EN,
input reg [Width-1:0] Q
);
`ifndef SYNTHESIS
CHECK_UNCERTAIN :
assert property (@(posedge CLK) EN |=> (|Q !== 1'bx))
else begin
$fatal("\n Error : detected a X value which should never happen!\n");
end
`endif
endmodule

View File

@@ -0,0 +1,25 @@
module DFF #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK) begin : dff
Q <= D;
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (1'b1),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,28 @@
module DFFE #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire EN,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK) begin : dff
if (EN) begin
Q <= D;
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (EN),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,31 @@
module DFFR #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire RSTN,
input wire [Width-1:0] DRST,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK or negedge RSTN) begin : dff
if (~RSTN) begin
Q <= DRST;
end else begin
Q <= D;
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (1'b1),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1,35 @@
module DFFRE #(
parameter int unsigned Width = 8
) (
input wire CLK,
input wire RSTN,
input wire EN,
input wire [Width-1:0] DRST,
input wire [Width-1:0] D,
output reg [Width-1:0] Q
);
always @(posedge CLK or negedge RSTN) begin : dff
if (~RSTN) begin
Q <= DRST;
end else begin
if (EN) begin
Q <= D;
end
end
end
`ifndef SYNTHESIS
DFFUncertainChecker #(
.Width(Width)
) u_DFFUncertainChecker (
.CLK(CLK),
.EN (EN),
.Q (Q)
);
`endif
endmodule

View File

@@ -0,0 +1 @@
__pycache__

View File

@@ -0,0 +1,132 @@
#!/usr/bin/python3
from distutils.log import error, fatal
from pathlib import Path
from sys import argv
import yaml
class Module:
def __init__(self, root: Path, moduleMeta: dict) -> None:
self.rtlPathList = []
self.simPathList = []
self.dependModuleList = []
if moduleMeta.get("dependency"):
for m in moduleMeta["dependency"]:
self.dependModuleList.append(m)
if moduleMeta.get("rtl"):
for m in moduleMeta["rtl"]:
self.rtlPathList.append(Path(root) / m)
if moduleMeta.get("sim"):
for m in moduleMeta["sim"]:
self.simPathList.append(Path(root) / m)
try:
self.name = moduleMeta["name"]
self.description = moduleMeta["description"]
self.language = moduleMeta["language"]
except yaml.YAMLError as e:
error(e)
class PackageParser:
def __init__(self, manifestPath: str):
with open(manifestPath) as f:
self.packageLocation = Path(manifestPath)
ROOT = self.packageLocation.parent
manifest = yaml.load(f, yaml.CLoader)
self.dependPackageDict = {}
self.ModuleDict = {}
if manifest.get("Dependency"):
for packagePath in manifest["Dependency"]:
filePath = Path(ROOT / packagePath)
package = PackageParser(filePath)
if not self.dependPackageDict.get(package.Name):
self.dependPackageDict[package.Name] = package
for (key, value) in package.ModuleDict.items():
if not self.ModuleDict.get(key):
self.ModuleDict[key] = value
if manifest.get("Module"):
for module in manifest["Module"]:
self.addModule(ROOT, module)
try:
self.Name = manifest["Name"]
self.addModule(ROOT, self.packModule())
except yaml.YAMLError as e:
error(e)
def packModule(self):
packedModule = {}
packedModule['name'] = self.Name
packedModule['language'] = None
packedModule['description'] = "package {}".format(self.Name)
packedModule['dependency'] = []
for module in self.ModuleDict:
packedModule['dependency'].append(module)
return packedModule
def addModule(self, root: Path, moduleMeta: dict) -> None:
self.ModuleDict[moduleMeta["name"]] = Module(root, moduleMeta)
if moduleMeta.get("sim"):
self.ModuleDict[moduleMeta["name"]+'_tb'] = Module(root, moduleMeta)
def genModuleFileList(self, top: str, sim: bool):
if self.ModuleDict.get(top):
module = self.ModuleDict[top]
filelist = []
for dependModule in module.dependModuleList:
for file in self.genModuleFileList(dependModule, False):
if file not in filelist:
filelist.append(file)
for file in module.rtlPathList:
absPath = str(file.absolute())
if absPath not in filelist:
filelist.append((absPath,module.language))
if sim:
for file in module.simPathList:
absPath = str(file.absolute())
if absPath not in filelist:
filelist.append((absPath,module.language))
return filelist
else:
fatal("Module {} doesn't exist".format(top))
def genPackageFileList(self, sim: bool):
filelist = []
for module in self.ModuleDict:
for file in self.genModuleFileList(module, sim):
if file not in filelist :
filelist.append(file)
return filelist
def genVcsFileList(self, sim: bool):
filelist = self.genPackageFileList(sim)
vcsfilelist = []
for file in filelist:
vcsfilelist.append(file[0])
return vcsfilelist
def genEDAlizeFile(self,top: str, sim: bool):
edalizeFileList = []
filelist = self.genModuleFileList(top,sim)
for (filePath,language) in filelist:
if language == "SystemVerilog" :
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'systemVerilogSource'}
)
elif language == "Verilog" :
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'verilogSource'}
)
elif language == "Vhdl":
edalizeFileList.append(
{'name' : filePath, 'file_type' : 'vhdlSource'}
)
return edalizeFileList
if __name__ == "__main__":
t = PackageParser(argv[1])
for file in t.genVcsFileList(False):
print(file)

View File

@@ -0,0 +1,2 @@
# pico
Pico is a hardware dependency manangement tool which integrate Edalize to support different cad flow

View File

@@ -0,0 +1,8 @@
vcs :
vcs_options : [-full64,-sverilog,+v2k,-debug_access+all,-kdb]
run_options : []
spyglass:
methodology : GuideWare/latest/block/rtl_handoff
goals : [ 'lint/lint_rtl' ]
spyglass_parameters : []
rule_parameters : []

View File

@@ -0,0 +1,127 @@
#!/usr/bin/python3
import argparse
from distutils.log import fatal
from genericpath import getmtime
import os
from pathlib import Path
from sys import argv
import yaml
from time import ctime, gmtime, strftime, time
from edalize import *
import edalize
from PackageParser import PackageParser
SIM_TOOL = [
'vcs', 'verilator'
]
TOOLS = [tool for tool in edalize.walk_tool_packages()]
def getTime():
return strftime("%m%d_%H_%M", gmtime())
class PicoArgsParser:
def __init__(self, argv) -> None:
argParser = argparse.ArgumentParser(usage='Pico.py [manifest] -top [topmodule] -tool [vcs/verilator/veriblelint .etc] -configure -build -run',prefix_chars="-+")
argParser.add_argument('manifest', type=str, help="Project manifest")
argParser.add_argument(
'+args', nargs='?', action='append', help="Compile arguments")
argParser.add_argument(
'-tool', type=str, choices=TOOLS, required=True, help="EDA tool")
argParser.add_argument(
'-top', type=str, required=True, help="Top module")
argParser.add_argument('-trace', action='store_true',
default=False, help="Enable Waveform")
argParser.add_argument(
'+define', nargs='?', action='append', type=str, help="Verilog defination")
argParser.add_argument('-workdir', type=str, help="Work space")
argParser.add_argument('-build', action='store_true',
default=False, help="Build Project")
argParser.add_argument('-run', action='store_true',
default=False, help="Run Project")
argParser.add_argument('+runtime', action='append', help="runtime args")
argParser.add_argument('-cov','-coverage', dest='coverage', action='store_true',help='Enable coverage')
self.config = argParser.parse_args(argv)
self.tool = self.config.tool
self.toplevel = self.config.top
self.build = self.config.build
self.run = self.config.run
self.tool_options = self.buildToolOptions()
self.parameters = self.buildDefination()
self.file = self.buildFlist()
self.edam = {
'files': self.file,
'name': self.toplevel,
'parameters': self.parameters,
'tool_options': self.tool_options,
'toplevel': self.toplevel
}
self.workSpace = self.getWorkSpace()
def getWorkSpace(self):
if self.config.workdir:
work_root = self.config.workdir
else:
work_root = self.tool + '_' + self.toplevel + '_' + getTime()
return work_root
def buildFlist(self):
manifestParser = PackageParser(self.config.manifest)
simulationEnable = self.tool in SIM_TOOL
return manifestParser.genEDAlizeFile(self.toplevel, simulationEnable)
def buildToolOptions(self):
config = self.config
tool_options = yaml.load(
open(Path(__file__).parent / "defaultToolOption.yaml"), yaml.CLoader)
if config.args:
if config.tool == 'vcs':
tool_options['vcs']['vcs_options'] += config.args
if config.runtime:
if config.tool == 'vcs':
tool_options['vcs']['run_options'] += config.runtime
if config.coverage:
if config.tool == 'vcs':
tool_options['vcs']['vcs_options'] += ['-cm line+cond+tgl+fsm+branch+assert']
tool_options['vcs']['run_options'] += ['-cm line+cond+tgl+fsm+branch+assert']
return tool_options
def buildDefination(self):
parameters = {}
config = self.config
if config.trace:
parameters["DUMPON"] = {
'datatype': 'bool',
'default': 1,
'paramtype': 'vlogdefine'
}
if config.define:
for define in config.define:
for item in define.split(','):
parameters[item] = {
'datatype': 'bool',
'default': 1,
'paramtype': 'vlogdefine'
}
return parameters
if __name__ == "__main__":
config = PicoArgsParser(argv[1:])
work_root = config.workSpace
backend = get_edatool(config.tool)(edam=config.edam, work_root=work_root)
if not os.path.exists(work_root):
os.makedirs(work_root)
if config.build:
backend.configure()
backend.build()
if config.run:
backend.run()

148
rtl/util/freelist.sv Executable file
View File

@@ -0,0 +1,148 @@
`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

View File

@@ -0,0 +1,67 @@
`ifndef __INORDER_ROUTER_SV__
`define __INORDER_ROUTER_SV__
module inorder_router
#(
parameter int unsigned SRC_COUNT = 4,
parameter int unsigned DES_COUNT = 4
) (
input logic[SRC_COUNT-1:0] src_vld_i,
input logic[SRC_COUNT-1:0][DES_COUNT-1:0] src_des_en_i,
output logic[SRC_COUNT-1:0] success_o,
output logic[DES_COUNT-1:0][SRC_COUNT-1:0] src_des_sel_o
);
logic[SRC_COUNT-1:0] success;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_sel_mask;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_disable_mask;
logic[SRC_COUNT-1:0][DES_COUNT-1:0] des_rdy_mask;
generate
for(genvar src = 0 ; src < SRC_COUNT; src++) begin : gen_des_disable_mask
if(src == 0) begin
assign des_disable_mask[src] = {DES_COUNT{1'b0}};
end else begin
assign des_disable_mask[src] = des_disable_mask[src-1] | des_sel_mask[src-1];
end
end
endgenerate
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin : gen_des_rdy_mask
if(src == 0) begin
assign des_rdy_mask[src] = {DES_COUNT{src_vld_i[src]}} & src_des_en_i[src];
end else begin
assign des_rdy_mask[src] = {DES_COUNT{src_vld_i[src]}} & src_des_en_i[src] & ~des_disable_mask[src] & {DES_COUNT{success[src-1]}};
end
end
endgenerate
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin : gen_success_vec
assign success[src] = |des_sel_mask[src];
end
endgenerate
always_comb begin : output_logic
success_o = success;
for(int src = 0 ; src < SRC_COUNT; src++) begin
for(int des = 0 ; des < DES_COUNT; des++) begin
src_des_sel_o[des][src] = des_sel_mask[src][des];
end
end
end
generate
for(genvar src = 0 ; src < SRC_COUNT ; src++) begin
one_hot_priority_encoder
#(
.SEL_WIDTH(DES_COUNT)
) u_routing_encoder (
.sel_i(des_rdy_mask[src]),
.sel_o(des_sel_mask[src])
);
end
endgenerate
endmodule
`endif

View File

@@ -0,0 +1,15 @@
module left_circular_rotate #(
parameter N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1
) (
input logic [N_INPUT-1:0] ori_vector_i,
input logic [N_INPUT_WIDTH-1:0] req_left_rotate_num_i,
output logic [N_INPUT-1:0] roteted_vector_o
);
logic [N_INPUT*2-1:0] ori_vector_mid;
assign ori_vector_mid = {ori_vector_i, ori_vector_i} << req_left_rotate_num_i;
assign roteted_vector_o = ori_vector_mid[N_INPUT*2-1-:N_INPUT];
endmodule

91
rtl/util/mp_fifo.sv Executable file
View File

@@ -0,0 +1,91 @@
`ifndef __MP_FIFO_SV__
`define __MP_FIFO_SV__
module mp_fifo
#(
parameter type payload_t = logic[3:0],
parameter int unsigned ENQUEUE_WIDTH = 4,
parameter int unsigned DEQUEUE_WIDTH = 4,
parameter int unsigned DEPTH = 16,
parameter int unsigned MUST_TAKEN_ALL = 1
)
(
// Enqueue
input logic[ENQUEUE_WIDTH-1:0] enqueue_vld_i,
input payload_t[ENQUEUE_WIDTH-1:0] enqueue_payload_i,
output logic[ENQUEUE_WIDTH-1:0] enqueue_rdy_o,
// Dequeue
output logic[DEQUEUE_WIDTH-1:0] dequeue_vld_o,
output payload_t[DEQUEUE_WIDTH-1:0] dequeue_payload_o,
input logic[DEQUEUE_WIDTH-1:0] dequeue_rdy_i,
input logic flush_i,
input clk,
input rst
);
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(DEPTH);
localparam int unsigned ENTRY_CNT_WIDTH = $clog2(DEPTH+1);
logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr;
logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr;
logic[ENTRY_CNT_WIDTH-1:0] avail_cnt;
payload_t[DEPTH-1:0] payload_dff;
logic[ENQUEUE_WIDTH-1:0] enq_fire;
logic[DEQUEUE_WIDTH-1:0] deq_fire;
assign enq_fire = enqueue_vld_i & enqueue_rdy_o;
assign deq_fire = dequeue_vld_o & dequeue_rdy_i;
generate
for(genvar i = 0 ; i < DEQUEUE_WIDTH; i++) begin
assign dequeue_payload_o[i] = payload_dff[deq_ptr[i]];
assign dequeue_vld_o[i] = (DEPTH-avail_cnt) > i;
end
endgenerate
generate
if(MUST_TAKEN_ALL) begin
assign enqueue_rdy_o = {ENQUEUE_WIDTH{avail_cnt >= ENQUEUE_WIDTH}};
end else begin
for(genvar i = 0; i < ENQUEUE_WIDTH; i++) begin
assign enqueue_rdy_o[i] = avail_cnt > i;
end
end
endgenerate
always_ff@(posedge clk) begin : payload_dff_update
for(int i = 0; i < ENQUEUE_WIDTH; i++) begin
if(enq_fire[i]) begin
payload_dff[enq_ptr[i]] <= enqueue_payload_i[i];
end
end
end
usage_manager #(
.ENTRY_COUNT(DEPTH),
.ENQ_WIDTH(ENQUEUE_WIDTH),
.DEQ_WIDTH(DEQUEUE_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(0),
.COMB_DEQ_EN(0),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(enq_fire),
.deq_fire_i(deq_fire),
.head_o(deq_ptr),
.tail_o(enq_ptr),
.avail_cnt_o(avail_cnt),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_fifo
`endif

94
rtl/util/mp_fifo_ptr_output.sv Executable file
View File

@@ -0,0 +1,94 @@
module mp_fifo_ptr_output
#(
parameter type payload_t = logic[3:0],
parameter int unsigned ENQUEUE_WIDTH = 4,
parameter int unsigned DEQUEUE_WIDTH = 4,
parameter int unsigned DEPTH = 16,
parameter int unsigned MUST_TAKEN_ALL = 1,
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(DEPTH),
localparam int unsigned ENTRY_CNT_WIDTH = $clog2(DEPTH+1)
)
(
// Enqueue
input logic[ENQUEUE_WIDTH-1:0] enqueue_vld_i,
input payload_t[ENQUEUE_WIDTH-1:0] enqueue_payload_i,
output logic[ENQUEUE_WIDTH-1:0] enqueue_rdy_o,
// Dequeue
output logic[DEQUEUE_WIDTH-1:0] dequeue_vld_o,
output payload_t[DEQUEUE_WIDTH-1:0] dequeue_payload_o,
input logic[DEQUEUE_WIDTH-1:0] dequeue_rdy_i,
// ptr output
output logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr_o,
output logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr_o,
input logic flush_i,
input clk,
input rst
);
logic[ENQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr;
logic[DEQUEUE_WIDTH-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr;
logic[ENTRY_CNT_WIDTH-1:0] avail_cnt;
payload_t[DEPTH-1:0] payload_dff;
logic[ENQUEUE_WIDTH-1:0] enq_fire;
logic[DEQUEUE_WIDTH-1:0] deq_fire;
assign enq_ptr_o = enq_ptr;
assign deq_ptr_o = deq_ptr;
assign enq_fire = enqueue_vld_i & enqueue_rdy_o;
assign deq_fire = dequeue_vld_o & dequeue_rdy_i;
generate
for(genvar i = 0 ; i < DEQUEUE_WIDTH; i++) begin
assign dequeue_payload_o[i] = payload_dff[deq_ptr[i]];
assign dequeue_vld_o[i] = (DEPTH-avail_cnt) > i;
end
endgenerate
generate
if(MUST_TAKEN_ALL) begin
assign enqueue_rdy_o = {ENQUEUE_WIDTH{avail_cnt >= ENQUEUE_WIDTH}};
end else begin
for(genvar i = 0; i < ENQUEUE_WIDTH; i++) begin
assign enqueue_rdy_o[i] = avail_cnt > i;
end
end
endgenerate
always_ff@(posedge clk) begin : payload_dff_update
for(int i = 0; i < ENQUEUE_WIDTH; i++) begin
if(enq_fire[i]) begin
payload_dff[enq_ptr[i]] <= enqueue_payload_i[i];
end
end
end
usage_manager #(
.ENTRY_COUNT(DEPTH),
.ENQ_WIDTH(ENQUEUE_WIDTH),
.DEQ_WIDTH(DEQUEUE_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(0),
.COMB_DEQ_EN(0),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(enq_fire),
.deq_fire_i(deq_fire),
.head_o(deq_ptr),
.tail_o(enq_ptr),
.avail_cnt_o(avail_cnt),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_fifo_ptr_output

134
rtl/util/mp_freelist.sv Executable file
View File

@@ -0,0 +1,134 @@
`ifndef __MP_FREELIST_SV__
`define __MP_FREELIST_SV__
module mp_freelist #(
parameter int unsigned ENTRY_COUNT = 12,
parameter int unsigned ALLOC_WIDTH = 4,
parameter int unsigned DEALLOC_WIDTH = 4,
parameter bit MUST_TAKEN_ALL = 1,
localparam int unsigned TAG_WIDTH = $clog2(ENTRY_COUNT)
) (
// Enqueue
input logic [ALLOC_WIDTH-1:0] alloc_vld_i,
output logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] alloc_tag_o,
output logic [ALLOC_WIDTH-1:0] alloc_rdy_o,
// Dequeue
input logic [DEALLOC_WIDTH-1:0] dealloc_vld_i,
input logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] dealloc_tag_i,
input logic flush_i,
input clk,
input rst
);
localparam int unsigned AVAIL_CNT_WIDTH = $clog2(ENTRY_COUNT + 1);
// Clk gate
logic [ENTRY_COUNT-1:0] ram_clk_en;
// Status
logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] head;
logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] tail;
logic [AVAIL_CNT_WIDTH-1:0] usage;
logic [ENTRY_COUNT-1:0][TAG_WIDTH-1:0] ram_d, ram_q;
// Allocate
logic [ALLOC_WIDTH-1:0] alloc_fire;
logic [ALLOC_WIDTH-1:0][TAG_WIDTH-1:0] alloc_entry_ptr;
// Deallocate
logic [DEALLOC_WIDTH-1:0] dealloc_fire;
logic [DEALLOC_WIDTH-1:0][TAG_WIDTH-1:0] dealloc_entry_ptr;
always_comb begin : gen_alloc_rdy
if (MUST_TAKEN_ALL) begin
for (int i = 0; i < ALLOC_WIDTH; i++) begin
alloc_rdy_o[i] = (ENTRY_COUNT - usage) >= ALLOC_WIDTH;
end
end else begin
for (int i = 0; i < ALLOC_WIDTH; i++) begin
alloc_rdy_o[i] = (ENTRY_COUNT - usage) > i;
end
end
end
generate
for (genvar i = 0; i < ALLOC_WIDTH; i++) begin : gen_alloc_tag
assign alloc_tag_o[i] = ram_q[alloc_entry_ptr[i]];
end
endgenerate
assign alloc_fire = alloc_vld_i & alloc_rdy_o;
assign alloc_entry_ptr = head;
assign dealloc_fire = dealloc_vld_i;
assign dealloc_entry_ptr = tail;
always_comb begin : gen_ram_clk_en
ram_clk_en = {ENTRY_COUNT{flush_i}};
for (int i = 0; i < DEALLOC_WIDTH; i++) begin
if(dealloc_fire[i]) begin
ram_clk_en[dealloc_entry_ptr[i]] = 1'b1;
end
end
end
always_comb begin : ram_update
ram_d = ram_q;
for (int i = 0; i < DEALLOC_WIDTH; i++) begin
ram_d[dealloc_entry_ptr[i]] = dealloc_tag_i[i];
end
if (flush_i) begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
ram_d[i] = i[TAG_WIDTH-1:0];
end
end
end
always_ff @(posedge clk) begin : ram_dff
if (rst) begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
ram_q[i] <= i[TAG_WIDTH-1:0];
end
end else begin
for (int i = 0; i < ENTRY_COUNT; i++) begin
if (ram_clk_en[i]) begin
ram_q[i] <= ram_d[i];
end
end
end
end
usage_manager #(
.ENTRY_COUNT(ENTRY_COUNT),
.ENQ_WIDTH(DEALLOC_WIDTH),
.DEQ_WIDTH(ALLOC_WIDTH),
.FLAG_EN(0),
.INIT_IS_FULL(1),
.COMB_DEQ_EN(1),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(dealloc_fire),
.deq_fire_i(alloc_fire),
.head_o(head),
.tail_o(tail),
.avail_cnt_o(usage),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : mp_freelist
`endif

29
rtl/util/oh2idx.sv Normal file
View File

@@ -0,0 +1,29 @@
module oh2idx
#(
parameter int unsigned N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1
)
(
input [N_INPUT-1:0] oh_i,
output [N_INPUT_WIDTH-1:0] idx_o
);
genvar i, j;
logic [N_INPUT_WIDTH-1:0][N_INPUT-1:0] mask;
generate
for(i = 0; i < N_INPUT_WIDTH; i++) begin: gen_mask_i
for(j = 0; j < N_INPUT; j++) begin: gen_mask_j
assign mask[i][j] = (j/(2**i)) % 2;
end
end
endgenerate
generate
for(i = 0; i < N_INPUT_WIDTH; i++) begin: gen_idx_o
assign idx_o[i] = |(oh_i & mask[i]);
end
endgenerate
endmodule

50
rtl/util/one_counter.sv Executable file
View File

@@ -0,0 +1,50 @@
`ifndef __ONE_COUNTER_SV__
`define __ONE_COUNTER_SV__
module one_counter
#(
parameter int unsigned DATA_WIDTH = 8,
localparam int unsigned CNT_WIDTH = $clog2(DATA_WIDTH) + 1
)
(
input logic[DATA_WIDTH-1:0] data_i,
output logic[CNT_WIDTH-1:0] cnt_o
);
localparam int unsigned PADDED_DATA_WIDTH = 1 << $clog2(DATA_WIDTH);
logic [PADDED_DATA_WIDTH-1:0] padded_data;
always_comb begin
padded_data = {PADDED_DATA_WIDTH{1'b0}};
padded_data[DATA_WIDTH-1:0] = data_i;
end
if(DATA_WIDTH == 1) begin
assign cnt_o = data_i;
end else begin
logic [CNT_WIDTH-2:0] res_left,res_right;
assign cnt_o = res_left + res_right;
one_counter #(
.DATA_WIDTH(PADDED_DATA_WIDTH/2)
) one_counter_left_u (
.data_i(padded_data[PADDED_DATA_WIDTH-1:PADDED_DATA_WIDTH/2]),
.cnt_o(res_left)
);
one_counter #(
.DATA_WIDTH(PADDED_DATA_WIDTH/2)
) one_counter_right_u (
.data_i(padded_data[PADDED_DATA_WIDTH/2-1:0]),
.cnt_o(res_right)
);
end
endmodule : one_counter
`endif

View File

@@ -0,0 +1,28 @@
`ifndef __ONE_HOT_PRIORITY_ENCODER_SV__
`define __ONE_HOT_PRIORITY_ENCODER_SV__
module one_hot_priority_encoder
#(
parameter int unsigned SEL_WIDTH = 8
)
(
input logic[SEL_WIDTH-1:0] sel_i,
output logic[SEL_WIDTH-1:0] sel_o
);
localparam int unsigned SEL_ID_WIDHT = $clog2(SEL_WIDTH);
logic [SEL_WIDTH-1:0] sel_mask;
assign sel_mask = ((~sel_i + 1'b1) & sel_i);
assign sel_o = sel_mask;
endmodule : one_hot_priority_encoder
`endif

128
rtl/util/one_hot_rr_arb.sv Executable file
View File

@@ -0,0 +1,128 @@
module one_hot_rr_arb #(
parameter N_INPUT = 2,
localparam int unsigned N_INPUT_WIDTH = N_INPUT > 1 ? $clog2(N_INPUT) : 1,
localparam int unsigned IS_LOG2 = (2 ** N_INPUT_WIDTH) == N_INPUT,
parameter TIMEOUT_UPDATE_EN = 0,
parameter TIMEOUT_UPDATE_CYCLE = 10
) (
input logic [N_INPUT-1:0] req_i,
input logic update_i,
output logic [N_INPUT-1:0] grt_o,
output logic [N_INPUT_WIDTH-1:0] grt_idx_o,
input logic rstn, clk
);
logic [$clog2(TIMEOUT_UPDATE_CYCLE)-1:0] timeout_counter_q, timeout_counter_d;
logic timeout_counter_add, timeout_counter_clr;
logic timeout_counter_en;
logic timeout_en;
generate
if(N_INPUT == 1) begin: gen_one_hot_rr_arb_one_input
assign grt_o = req_i;
assign grt_idx_o = 0;
end else begin: gen_one_hot_rr_arb_common_input
logic req_vld;
logic [N_INPUT*2-1:0] reversed_dereordered_selected_req_pre_shift, reversed_dereordered_selected_req_shift;
logic [N_INPUT-1:0] reodered_req, reordered_selected_req;
logic [N_INPUT-1:0] dereordered_selected_req;
logic [N_INPUT-1:0] reversed_reordered_selected_req, reversed_dereordered_selected_req;
logic [N_INPUT_WIDTH-1:0] round_ptr_q, round_ptr_d;
logic [N_INPUT_WIDTH-1:0] round_ptr_q_comp;
logic [N_INPUT_WIDTH-1:0] oh_to_idx;
logic [N_INPUT_WIDTH-1:0] selected_req_idx;
assign req_vld = update_i | timeout_en;
always_ff @(posedge clk or negedge rstn) begin
if (~rstn) begin
round_ptr_q <= '0;
end else begin
if (req_vld) begin
round_ptr_q <= round_ptr_d;
end
end
end
assign round_ptr_q_comp = N_INPUT - round_ptr_q;
//7 6 5 4 3 2 1 0 // req_i
//2 1 0 7 6 5 4 3 // reodered_req
//7 6 5 4 3 2 1 0 // dereordered_selected_req
left_circular_rotate
#(
.N_INPUT(N_INPUT )
)
left_circular_rotate_reodered_req_u (
.ori_vector_i (req_i ),
.req_left_rotate_num_i (round_ptr_q ),
.roteted_vector_o ( reodered_req)
);
one_hot_priority_encoder
#(
.SEL_WIDTH (N_INPUT)
)
biased_one_hot_priority_encoder_u
(
.sel_i (reodered_req ),
.sel_o (reordered_selected_req )
);
left_circular_rotate
#(
.N_INPUT(N_INPUT )
)
left_circular_rotate_dereordered_selected_req_u (
.ori_vector_i (reordered_selected_req ),
.req_left_rotate_num_i (round_ptr_q_comp ),
.roteted_vector_o ( dereordered_selected_req)
);
oh2idx
#(
.N_INPUT(N_INPUT )
)
oh2idx_u (
.oh_i (dereordered_selected_req ),
.idx_o (oh_to_idx)
);
assign selected_req_idx = oh_to_idx[N_INPUT_WIDTH-1:0];
assign round_ptr_d = (selected_req_idx == '0) ? N_INPUT-1 :
(selected_req_idx == (N_INPUT-1)) ? '0 :
(N_INPUT-1) - selected_req_idx;
assign grt_o = dereordered_selected_req;
assign grt_idx_o = selected_req_idx;
// timeout update
if(TIMEOUT_UPDATE_EN) begin
assign timeout_counter_add = (|req_i) & ~req_vld;
assign timeout_counter_clr = req_vld;
assign timeout_counter_d = timeout_counter_clr ? '0 : timeout_counter_q + 1;
assign timeout_counter_en = timeout_counter_add | (timeout_counter_clr & (timeout_counter_q != '0));
always @(posedge clk or negedge rstn) begin
if (~rstn) begin
timeout_counter_q <= '0;
end else begin
if (timeout_counter_en) begin
timeout_counter_q <= timeout_counter_d;
end
end
end
assign timeout_en = (timeout_counter_q == TIMEOUT_UPDATE_CYCLE);
end else begin
assign timeout_en = '0;
end
end
endgenerate
endmodule

37
rtl/util/onehot_mux.sv Executable file
View File

@@ -0,0 +1,37 @@
`ifndef __ONEHOT_MUX_SV__
`define __ONEHOT_MUX_SV__
module onehot_mux
#(
parameter int unsigned SOURCE_COUNT = 2,
parameter int unsigned DATA_WIDTH = 1
)
(
input logic[SOURCE_COUNT-1:0] sel_i,
input logic[SOURCE_COUNT-1:0][DATA_WIDTH-1:0] data_i,
output logic[DATA_WIDTH-1:0] data_o
);
logic[DATA_WIDTH-1:0][SOURCE_COUNT-1:0] trans_data;
logic[DATA_WIDTH-1:0][SOURCE_COUNT-1:0] select_mat;
generate
for(genvar i = 0 ; i < DATA_WIDTH; i++) begin
for(genvar j = 0 ; j < SOURCE_COUNT; j++) begin
assign trans_data[i][j] = data_i[j][i];
end
end
endgenerate
generate
for(genvar i = 0; i < DATA_WIDTH; i++) begin
assign select_mat[i] = trans_data[i] & sel_i;
assign data_o[i] = |select_mat[i];
end
endgenerate
endmodule
`endif

121
rtl/util/plru.sv Normal file
View File

@@ -0,0 +1,121 @@
`ifndef __PLRU_SV__
`define __PLRU_SV__
module plru
#(
parameter int unsigned N_WAYS = 2,
parameter int unsigned N_SETS = 2
)
(
input logic touch_valid_i,
input logic [$clog2(N_SETS)-1:0] touch_addr_i,
input logic [$clog2(N_WAYS)-1:0] touch_way_i,
output logic [$clog2(N_WAYS)-1:0] alloc_way_o,
input logic clk,
input logic rst
);
logic [N_SETS-1:0][N_WAYS-2:0] plru_regs;
generate
if(N_WAYS == 2) begin
assign alloc_way_o = plru_regs[touch_addr_i][0];
end
else if (N_WAYS == 4) begin
assign alloc_way_o = plru_regs[touch_addr_i][0] ?
{plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2]} :
{plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1]};
end
else if (N_WAYS == 8) begin
always_comb begin
if (plru_regs[touch_addr_i][0]) begin
if (plru_regs[touch_addr_i][2]) begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2], plru_regs[touch_addr_i][6]};
end
else begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][2], plru_regs[touch_addr_i][5]};
end
end
else begin
if (plru_regs[touch_addr_i][1]) begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1], plru_regs[touch_addr_i][4]};
end
else begin
alloc_way_o = {plru_regs[touch_addr_i][0], plru_regs[touch_addr_i][1], plru_regs[touch_addr_i][3]};
end
end
end
end
endgenerate
generate
if(N_WAYS == 2) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i) begin
if (touch_way_i == alloc_way_o) begin
plru_regs[touch_addr_i] <= ~plru_regs[touch_addr_i];
end
end
end
end
else if (N_WAYS == 4) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i & (alloc_way_o == touch_way_i)) begin
if (plru_regs[touch_addr_i][0]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][1] <= ~plru_regs[touch_addr_i][1];
end
end
end
end
else if (N_WAYS == 8) begin
always_ff @(posedge clk) begin
if (rst) begin
plru_regs <= 0;
end
else if (touch_valid_i & (alloc_way_o == touch_way_i)) begin
if (plru_regs[touch_addr_i][0]) begin
if (plru_regs[touch_addr_i][2]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][6] <= ~plru_regs[touch_addr_i][6];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][5] <= ~plru_regs[touch_addr_i][5];
end
end
else begin
if (plru_regs[touch_addr_i][1]) begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][4] <= ~plru_regs[touch_addr_i][4];
end
else begin
plru_regs[touch_addr_i][0] <= ~plru_regs[touch_addr_i][0];
plru_regs[touch_addr_i][2] <= ~plru_regs[touch_addr_i][2];
plru_regs[touch_addr_i][3] <= ~plru_regs[touch_addr_i][3];
end
end
end
end
end
endgenerate
endmodule
`endif

43
rtl/util/priority_encoder.sv Executable file
View File

@@ -0,0 +1,43 @@
`ifndef __PRIORITY_ENCODER_SV__
`define __PRIORITY_ENCODER_SV__
module priority_encoder
#(
parameter int unsigned SEL_WIDTH = 8,
localparam int unsigned SEL_ID_WIDHT = SEL_WIDTH > 1 ? $clog2(SEL_WIDTH) : 1
)
(
input logic[SEL_WIDTH-1:0] sel_i,
output logic id_vld_o,
output logic[SEL_ID_WIDHT-1:0] id_o
);
if(SEL_WIDTH == 1) begin
assign id_vld_o = sel_i;
assign id_o = 1'b0;
end
else begin
logic [SEL_WIDTH-1:0] sel_mask;
logic [SEL_ID_WIDHT+1-1:0] sel_result;
assign sel_mask = ((~sel_i + 1'b1) & sel_i) - 1'b1;
one_counter #(
.DATA_WIDTH(SEL_WIDTH)
) one_counter_u (
.data_i(sel_mask),
.cnt_o(sel_result)
);
assign id_o = sel_result[SEL_ID_WIDHT-1:0];
assign id_vld_o = |sel_i;
end
endmodule : priority_encoder
`endif

82
rtl/util/pseudo_dual_ram.sv Executable file
View File

@@ -0,0 +1,82 @@
`ifndef __PSEUDO_DUAL_RAM_SV__
`define __PSEUDO_DUAL_RAM_SV__
module pseudo_dual_ram
#(
parameter int unsigned WIDTH = 8,
parameter int unsigned DEPTH = 8
)
(
input logic [$clog2(DEPTH)-1:0] ra,
input logic re,
output logic [WIDTH-1:0] rd,
input logic [$clog2(DEPTH)-1:0] wa,
input logic we,
input logic [WIDTH-1:0] wd,
input logic rst,
input logic clk
);
logic [DEPTH-1:0][WIDTH-1:0] ram;
logic [$clog2(DEPTH)-1:0] ra_ff;
logic re_ff;
logic [$clog2(DEPTH)-1:0] wa_ff;
logic we_ff;
logic [WIDTH-1:0] wd_ff;
//sync
always_ff@(posedge clk) begin
if (rst) begin
ra_ff <= 0;
re_ff <= 0;
end
else begin
ra_ff <= ra;
re_ff <= re;
end
end
always_ff@(posedge clk) begin
if (rst) begin
wa_ff <= 0;
we_ff <= 0;
wd_ff <= 0;
end
else begin
wa_ff <= wa;
we_ff <= we;
wd_ff <= wd;
end
end
// read
always_comb begin
rd = 0;
if (re_ff) begin
// write bypass read
if (we_ff && wa_ff == ra_ff) begin
rd = wd_ff;
end
else begin
rd = ram[ra_ff];
end
end
end
// write
always_ff@(posedge clk) begin
if (rst) begin
for (int i=0; i<DEPTH; i++) begin
ram[i] <= 0;
end
end
else if (we_ff) begin
ram[wa_ff] <= wd_ff;
end
end
endmodule
`endif

61
rtl/util/pseudo_ram.sv Executable file
View File

@@ -0,0 +1,61 @@
`ifndef __PSEUDO_RAM_SV__
`define __PSEUDO_RAM_SV__
module pseudo_ram
#(
parameter int unsigned WIDTH = 8,
parameter int unsigned DEPTH = 8
)
(
input logic we,
input logic [$clog2(DEPTH)-1:0] a,
input logic [WIDTH-1:0] d,
output logic [WIDTH-1:0] q,
input logic rst,
input logic clk
);
logic [DEPTH-1:0][WIDTH-1:0] ram;
logic [$clog2(DEPTH)-1:0] a_ff;
logic we_ff;
logic [WIDTH-1:0] d_ff;
//sync
always_ff@(posedge clk) begin
if (rst) begin
a_ff <= 0;
d_ff <= 0;
we_ff <= 0;
end
else begin
a_ff <= a;
d_ff <= d;
we_ff <= we;
end
end
// read
always_comb begin
q = 0;
if (!we_ff) begin
q = ram[a_ff];
end
end
// write
always_ff@(posedge clk) begin
if (rst) begin
for (int i=0; i<DEPTH; i++) begin
ram[i] <= 0;
end
end
else if (we_ff) begin
ram[a_ff] <= d_ff;
end
end
endmodule
`endif

45
rtl/util/reg_dual_ram.sv Executable file
View File

@@ -0,0 +1,45 @@
`ifndef __REG_DUAL_RAM_SV__
`define __REG_DUAL_RAM_SV__
module reg_dual_ram
#(
parameter int unsigned WIDTH = 8,
parameter int unsigned DEPTH = 8
)
(
input logic [$clog2(DEPTH)-1:0] ra,
input logic re,
output logic [WIDTH-1:0] rd,
input logic [$clog2(DEPTH)-1:0] wa,
input logic we,
input logic [WIDTH-1:0] wd,
input logic rst,
input logic clk
);
logic [DEPTH-1:0][WIDTH-1:0] ram;
// read
always_comb begin
rd = 0;
if (re) begin
rd = ram[ra];
end
end
// write
always_ff@(posedge clk) begin
if (rst) begin
for (int i=0; i<DEPTH; i++) begin
ram[i] <= 0;
end
end
else if (we) begin
ram[wa] <= wd;
end
end
endmodule
`endif

View File

@@ -0,0 +1,62 @@
`ifndef __SELECT_TWO_FROM_N_VALID_SV__
`define __SELECT_TWO_FROM_N_VALID_SV__
module select_two_from_n_valid
#(
parameter int unsigned SEL_WIDTH = 8,
localparam int unsigned SEL_ID_WIDHT = SEL_WIDTH > 1 ? $clog2(SEL_WIDTH) : 1
)
(
input logic[SEL_WIDTH-1:0] sel_i,
input logic first_id_needed_vld_i,
input logic second_id_needed_vld_i,
output logic first_id_vld_o,
output logic second_id_vld_o,
output logic[SEL_ID_WIDHT-1:0] first_id_o,
output logic[SEL_ID_WIDHT-1:0] second_id_o
);
genvar i;
logic[SEL_WIDTH-1:0] sel_rev;
logic first_id_vld_mid;
logic secondid_vld_mid;
logic[SEL_ID_WIDHT-1:0] first_id_mid;
logic[SEL_ID_WIDHT-1:0] second_id_mid, second_id_mid_comp;
generate
for(i = 0; i < SEL_WIDTH; i++) begin: sel_rev_gen
assign sel_rev[i] = sel_i[SEL_WIDTH-1-i];
end
endgenerate
priority_encoder
#(
.SEL_WIDTH (SEL_WIDTH)
)
first_vld_sel_u
(
.sel_i (sel_i ),
.id_vld_o (first_id_vld_mid ),
.id_o (first_id_mid )
);
priority_encoder
#(
.SEL_WIDTH (SEL_WIDTH)
)
second_vld_sel_u
(
.sel_i (sel_rev ),
.id_vld_o (secondid_vld_mid ),
.id_o (second_id_mid )
);
assign second_id_mid_comp = SEL_ID_WIDHT'(SEL_WIDTH-1-second_id_mid);
assign first_id_vld_o = first_id_vld_mid & first_id_needed_vld_i;
assign second_id_vld_o = secondid_vld_mid & (~(first_id_mid == second_id_mid_comp) | ~first_id_needed_vld_i) & second_id_needed_vld_i;
assign first_id_o = first_id_mid;
assign second_id_o = second_id_mid_comp;
endmodule
`endif

View File

@@ -0,0 +1,106 @@
module sp_fifo_dat_vld_output
#(
parameter type payload_t = logic[3:0],
// parameter int unsigned 1 = 4,
// parameter int unsigned 1 = 4,
parameter int unsigned DEPTH = 16,
parameter int unsigned MUST_TAKEN_ALL = 1
)
(
// Enqueue
input logic[1-1:0] enqueue_vld_i,
input payload_t[1-1:0] enqueue_payload_i,
output logic[1-1:0] enqueue_rdy_o,
// Dequeue
output logic[1-1:0] dequeue_vld_o,
output payload_t[1-1:0] dequeue_payload_o,
input logic[1-1:0] dequeue_rdy_i,
// output data and valid
output payload_t[DEPTH-1:0] payload_dff,
output logic [DEPTH-1:0] payload_vld_dff,
input logic flush_i,
input clk,
input rst
);
localparam int unsigned ENTRY_PTR_WIDTH = $clog2(DEPTH);
localparam int unsigned ENTRY_CNT_WIDTH = $clog2(DEPTH+1);
logic[1-1:0][ENTRY_PTR_WIDTH-1:0] enq_ptr;
logic[1-1:0][ENTRY_PTR_WIDTH-1:0] deq_ptr;
logic[ENTRY_CNT_WIDTH-1:0] avail_cnt;
// payload_t[DEPTH-1:0] payload_dff;
// logic [DEPTH-1:0] payload_vld_dff;
logic[1-1:0] enq_fire;
logic[1-1:0] deq_fire;
assign enq_fire = enqueue_vld_i & enqueue_rdy_o;
assign deq_fire = dequeue_vld_o & dequeue_rdy_i;
generate
for(genvar i = 0 ; i < 1; i++) begin
assign dequeue_payload_o[i] = payload_dff[deq_ptr[i]];
assign dequeue_vld_o[i] = (DEPTH-avail_cnt) > i;
end
endgenerate
generate
if(MUST_TAKEN_ALL) begin
assign enqueue_rdy_o = {1{avail_cnt >= 1}};
end else begin
for(genvar i = 0; i < 1; i++) begin
assign enqueue_rdy_o[i] = avail_cnt > i;
end
end
endgenerate
always_ff@(posedge clk) begin : payload_dff_update
for(int i = 0; i < 1; i++) begin
if(enq_fire[i]) begin
payload_dff[enq_ptr[i]] <= enqueue_payload_i[i];
end
end
end
always_ff@(posedge clk) begin : payload_vld_dff_update
if(rst) begin
payload_vld_dff <= '0;
end else begin
for(int i = 0; i < 1; i++) begin
if(enq_fire[i]) begin
payload_vld_dff[enq_ptr[i]] <= 1'b1;
end
if(deq_fire[i]) begin
payload_vld_dff[deq_ptr[i]] <= 1'b0;
end
end
end
end
usage_manager #(
.ENTRY_COUNT(DEPTH),
.ENQ_WIDTH(1),
.DEQ_WIDTH(1),
.FLAG_EN(0),
.INIT_IS_FULL(0),
.COMB_DEQ_EN(0),
.COMB_ENQ_EN(1)
) u_usage_manager (
.enq_fire_i(enq_fire),
.deq_fire_i(deq_fire),
.head_o(deq_ptr),
.tail_o(enq_ptr),
.avail_cnt_o(avail_cnt),
.flush_i(flush_i),
.clk(clk),
.rst(rst)
);
endmodule : sp_fifo_dat_vld_output

274
rtl/util/usage_manager.sv Executable file
View File

@@ -0,0 +1,274 @@
`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