initial commit for open source NoC IP
This commit is contained in:
143
rtl/util/age_order_selector.sv
Executable file
143
rtl/util/age_order_selector.sv
Executable 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
|
||||
203
rtl/util/age_order_selector_with_head.sv
Executable file
203
rtl/util/age_order_selector_with_head.sv
Executable 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
3
rtl/util/commoncell/.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "tools/pico"]
|
||||
path = tools/pico
|
||||
url = git@gitlab.com:series-han/development/pico.git
|
||||
5
rtl/util/commoncell/CommonCell.yaml
Normal file
5
rtl/util/commoncell/CommonCell.yaml
Normal file
@@ -0,0 +1,5 @@
|
||||
Name: CommonCell
|
||||
Dependency:
|
||||
- src/StdDFF/StdDFF.yaml
|
||||
- src/Basic/Basic.yaml
|
||||
- src/Queue/Queue.yaml
|
||||
92
rtl/util/commoncell/README.md
Normal file
92
rtl/util/commoncell/README.md
Normal 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
0
rtl/util/commoncell/doc/.gitignore
vendored
Normal file
11
rtl/util/commoncell/env/sourceme
vendored
Normal file
11
rtl/util/commoncell/env/sourceme
vendored
Normal 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
|
||||
67
rtl/util/commoncell/src/Basic/Basic.yaml
Normal file
67
rtl/util/commoncell/src/Basic/Basic.yaml
Normal 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
|
||||
|
||||
59
rtl/util/commoncell/src/Basic/dv/CountOne_tb.v
Normal file
59
rtl/util/commoncell/src/Basic/dv/CountOne_tb.v
Normal 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
|
||||
66
rtl/util/commoncell/src/Basic/dv/MuxOH_tb.v
Normal file
66
rtl/util/commoncell/src/Basic/dv/MuxOH_tb.v
Normal 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
|
||||
49
rtl/util/commoncell/src/Basic/dv/PLRU_tb.v
Normal file
49
rtl/util/commoncell/src/Basic/dv/PLRU_tb.v
Normal 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
|
||||
83
rtl/util/commoncell/src/Basic/dv/StreamFIFO_tb.v
Normal file
83
rtl/util/commoncell/src/Basic/dv/StreamFIFO_tb.v
Normal 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
|
||||
83
rtl/util/commoncell/src/Basic/dv/SyncFIFO_tb.v
Normal file
83
rtl/util/commoncell/src/Basic/dv/SyncFIFO_tb.v
Normal 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
|
||||
42
rtl/util/commoncell/src/Basic/hw/CountOne.v
Normal file
42
rtl/util/commoncell/src/Basic/hw/CountOne.v
Normal 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
|
||||
21
rtl/util/commoncell/src/Basic/hw/MuxOH.v
Normal file
21
rtl/util/commoncell/src/Basic/hw/MuxOH.v
Normal 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
|
||||
25
rtl/util/commoncell/src/Basic/hw/OH2UInt.v
Normal file
25
rtl/util/commoncell/src/Basic/hw/OH2UInt.v
Normal 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
|
||||
48
rtl/util/commoncell/src/Basic/hw/PLRU.v
Normal file
48
rtl/util/commoncell/src/Basic/hw/PLRU.v
Normal 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
|
||||
64
rtl/util/commoncell/src/Basic/hw/PLRUTree.v
Normal file
64
rtl/util/commoncell/src/Basic/hw/PLRUTree.v
Normal 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
|
||||
24
rtl/util/commoncell/src/Basic/hw/PriorityMux.v
Normal file
24
rtl/util/commoncell/src/Basic/hw/PriorityMux.v
Normal 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
|
||||
52
rtl/util/commoncell/src/Basic/hw/StreamFIFO.v
Normal file
52
rtl/util/commoncell/src/Basic/hw/StreamFIFO.v
Normal 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
|
||||
129
rtl/util/commoncell/src/Basic/hw/SyncFIFO.v
Normal file
129
rtl/util/commoncell/src/Basic/hw/SyncFIFO.v
Normal 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
|
||||
58
rtl/util/commoncell/src/Queue/Queue.yaml
Normal file
58
rtl/util/commoncell/src/Queue/Queue.yaml
Normal 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
|
||||
168
rtl/util/commoncell/src/Queue/dv/AgeMatrixSelector_tb.v
Normal file
168
rtl/util/commoncell/src/Queue/dv/AgeMatrixSelector_tb.v
Normal 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
|
||||
111
rtl/util/commoncell/src/Queue/dv/FIFO/MultiPortStreamFIFO_tb.v
Normal file
111
rtl/util/commoncell/src/Queue/dv/FIFO/MultiPortStreamFIFO_tb.v
Normal 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
|
||||
99
rtl/util/commoncell/src/Queue/dv/StaticPrioritySelector_tb.v
Normal file
99
rtl/util/commoncell/src/Queue/dv/StaticPrioritySelector_tb.v
Normal 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
|
||||
187
rtl/util/commoncell/src/Queue/hw/AgeMatrixSelector.v
Normal file
187
rtl/util/commoncell/src/Queue/hw/AgeMatrixSelector.v
Normal 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
|
||||
|
||||
|
||||
61
rtl/util/commoncell/src/Queue/hw/FIAO/FIAOWithAgeMatrix.v
Normal file
61
rtl/util/commoncell/src/Queue/hw/FIAO/FIAOWithAgeMatrix.v
Normal 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
|
||||
126
rtl/util/commoncell/src/Queue/hw/FIAO/FIAOWithQueueManager.v
Normal file
126
rtl/util/commoncell/src/Queue/hw/FIAO/FIAOWithQueueManager.v
Normal 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
|
||||
124
rtl/util/commoncell/src/Queue/hw/FIFO/MultiPortStreamFIFO.v
Normal file
124
rtl/util/commoncell/src/Queue/hw/FIFO/MultiPortStreamFIFO.v
Normal 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
|
||||
206
rtl/util/commoncell/src/Queue/hw/QueueManager.v
Normal file
206
rtl/util/commoncell/src/Queue/hw/QueueManager.v
Normal 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
|
||||
52
rtl/util/commoncell/src/Queue/hw/StaticPrioritySelector.v
Normal file
52
rtl/util/commoncell/src/Queue/hw/StaticPrioritySelector.v
Normal 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
|
||||
39
rtl/util/commoncell/src/StdDFF/StdDFF.yaml
Normal file
39
rtl/util/commoncell/src/StdDFF/StdDFF.yaml
Normal 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
|
||||
17
rtl/util/commoncell/src/StdDFF/dv/DFFUncertainChecker.v
Normal file
17
rtl/util/commoncell/src/StdDFF/dv/DFFUncertainChecker.v
Normal 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
|
||||
25
rtl/util/commoncell/src/StdDFF/hw/DFF.v
Normal file
25
rtl/util/commoncell/src/StdDFF/hw/DFF.v
Normal 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
|
||||
28
rtl/util/commoncell/src/StdDFF/hw/DFFE.v
Normal file
28
rtl/util/commoncell/src/StdDFF/hw/DFFE.v
Normal 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
|
||||
31
rtl/util/commoncell/src/StdDFF/hw/DFFR.v
Normal file
31
rtl/util/commoncell/src/StdDFF/hw/DFFR.v
Normal 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
|
||||
35
rtl/util/commoncell/src/StdDFF/hw/DFFRE.v
Normal file
35
rtl/util/commoncell/src/StdDFF/hw/DFFRE.v
Normal 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
|
||||
1
rtl/util/commoncell/tools/pico/.gitignore
vendored
Normal file
1
rtl/util/commoncell/tools/pico/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
__pycache__
|
||||
132
rtl/util/commoncell/tools/pico/PackageParser.py
Executable file
132
rtl/util/commoncell/tools/pico/PackageParser.py
Executable 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)
|
||||
2
rtl/util/commoncell/tools/pico/README.md
Normal file
2
rtl/util/commoncell/tools/pico/README.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# pico
|
||||
Pico is a hardware dependency manangement tool which integrate Edalize to support different cad flow
|
||||
8
rtl/util/commoncell/tools/pico/defaultToolOption.yaml
Normal file
8
rtl/util/commoncell/tools/pico/defaultToolOption.yaml
Normal 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 : []
|
||||
127
rtl/util/commoncell/tools/pico/pico
Executable file
127
rtl/util/commoncell/tools/pico/pico
Executable 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
148
rtl/util/freelist.sv
Executable 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
|
||||
67
rtl/util/inorder_router.sv
Normal file
67
rtl/util/inorder_router.sv
Normal 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
|
||||
15
rtl/util/left_circular_rotate.sv
Normal file
15
rtl/util/left_circular_rotate.sv
Normal 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
91
rtl/util/mp_fifo.sv
Executable 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
94
rtl/util/mp_fifo_ptr_output.sv
Executable 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
134
rtl/util/mp_freelist.sv
Executable 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
29
rtl/util/oh2idx.sv
Normal 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
50
rtl/util/one_counter.sv
Executable 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
|
||||
28
rtl/util/one_hot_priority_encoder.sv
Executable file
28
rtl/util/one_hot_priority_encoder.sv
Executable 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
128
rtl/util/one_hot_rr_arb.sv
Executable 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
37
rtl/util/onehot_mux.sv
Executable 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
121
rtl/util/plru.sv
Normal 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
43
rtl/util/priority_encoder.sv
Executable 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
82
rtl/util/pseudo_dual_ram.sv
Executable 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
61
rtl/util/pseudo_ram.sv
Executable 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
45
rtl/util/reg_dual_ram.sv
Executable 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
|
||||
62
rtl/util/select_two_from_n_valid.sv
Executable file
62
rtl/util/select_two_from_n_valid.sv
Executable 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
|
||||
106
rtl/util/sp_fifo_dat_vld_output.sv
Executable file
106
rtl/util/sp_fifo_dat_vld_output.sv
Executable 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
274
rtl/util/usage_manager.sv
Executable 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
|
||||
Reference in New Issue
Block a user