Compare commits
10 Commits
732d21618a
...
31ce816816
Author | SHA1 | Date | |
---|---|---|---|
31ce816816 | |||
6c6c285e79 | |||
d320c31aea | |||
75ac016c9a | |||
9a7bffadec | |||
87b9bf20bf | |||
aae0a66fec | |||
59e8302a48 | |||
f0c7144550 | |||
5c9fad9cdc |
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
build/working
|
||||
build/working
|
||||
.locale/
|
||||
vhdl_ls.toml
|
||||
|
196
README.md
196
README.md
@@ -1 +1,195 @@
|
||||
See at docs subdirectory for the documentation..
|
||||
# Entity: PipelineController
|
||||
|
||||
- **File**: PipelineController.vhd
|
||||
|
||||
## Diagram
|
||||
|
||||

|
||||
|
||||
## Description
|
||||
|
||||
- Name: **Pipeline Controller**
|
||||
- Version: 0.0.1
|
||||
- Author: _Maximilian Passarello ([Blog](http://mpassarello.de))_
|
||||
- License: [MIT](LICENSE)
|
||||
|
||||
The Pipeline Controller provides an easy way to construct a pipeline
|
||||
with AXI-Like handshaking at the input and output of the pipeline.
|
||||
|
||||
### Core functions
|
||||
|
||||
- **Data flow control**: Data flow control is implemented via handshaking at the input and output ports.
|
||||
- **Validity control**: The controller keeps the validity of the data in the individual pipeline stages under control.
|
||||
- **Adjustability**: The pipeline controller can be customized via the generics.
|
||||
|
||||
### Generics
|
||||
|
||||
Use the generic `G_PipelineStages` to set how deep the pipeline is.
|
||||
This depth contains all the registers associated with the pipeline.
|
||||
For example, for an _I_FF ⇨ Combinatorics ⇨ O_FF_ construction, the generic must be set to **2**.
|
||||
|
||||
The active level of the reset input can also be set.
|
||||
|
||||
### Clock Enable
|
||||
|
||||
The `I_CE` port is active high and, when deactivated,
|
||||
effectively switches on the acceptance or output of data via handshaking in addition to the pipeline.
|
||||
|
||||
### Reset
|
||||
|
||||
A reset is explicitly **not** necessary on the pipeline registers.
|
||||
The validity of the data is kept under control via the pipeline controller
|
||||
and only this requires a dedicated reset if necessary.
|
||||
|
||||
### Pipeline control
|
||||
|
||||
You must connect the `O_Enable` port to the CE input of the corresponding pipeline registers.
|
||||
This is used to activate or deactivate the pipeline in full or via CE deactivated state.
|
||||
|
||||
### AXI like Handshaking
|
||||
|
||||
- **Input**: The `O_Ready` (active high) port is used to signal to the data-supplying component that data should be accepted.
|
||||
If it switches on `I_Valid` (active high), this in turn signals that data is ready to be accepted at its output.
|
||||
If both ports are active at the same time, the transfer is executed.
|
||||
- **Output**: The process runs analogously at the pipeline output.
|
||||
|
||||
## History
|
||||
|
||||
- 0.0.1 (2024-03-24) Initial version
|
||||
|
||||
## Generics
|
||||
|
||||
| Generic name | Type | Value | Description |
|
||||
| ---------------- | --------- | ----- | ----------------------------------------------------------------- |
|
||||
| G_PipelineStages | integer | 3 | Number of pipeline stages (FFs in the pipeline including I/O FFs) |
|
||||
| G_ResetActiveAt | std_logic | '1' | Reset active at this level |
|
||||
|
||||
## Ports
|
||||
|
||||
| Port name | Direction | Type | Description |
|
||||
| -------------------- | --------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| I_CLK | in | std_logic | Clock signal; **Rising edge** triggered |
|
||||
| I_RST | in | std_logic | Reset signal; Active at `G_ResetActiveAt` |
|
||||
| I_CE | in | std_logic | Chip enable; Active high |
|
||||
| O_Enable | out | std_logic | Pipeline enable; Active high when pipeline can accept data and `I_CE` is high. <br> **Note:** Connect `CE` of the registers to be controlled by this controller to `O_Enable`. |
|
||||
| Input-AXI-Handshake | in | Virtual bus | Input AXI like Handshake |
|
||||
| Output-AXI-Handshake | out | Virtual bus | Output AXI like Handshake |
|
||||
|
||||
### Virtual Buses
|
||||
|
||||
#### Input-AXI-Handshake
|
||||
|
||||
| Port name | Direction | Type | Description |
|
||||
| --------- | --------- | --------- | ----------------------------------------------------------------------------------------- |
|
||||
| I_Valid | in | std_logic | Valid data flag; indicates that the data on `I_Data` of the connected registers is valid. |
|
||||
| O_Ready | out | std_logic | Ready flag; indicates that the connected registers is ready to accept data. |
|
||||
|
||||
#### Output-AXI-Handshake
|
||||
|
||||
| Port name | Direction | Type | Description |
|
||||
| --------- | --------- | --------- | ----------------------------------------------------------------------------------------- |
|
||||
| O_Valid | out | std_logic | Valid data flag; indicates that the data on `O_Data` of the connected registers is valid. |
|
||||
| I_Ready | in | std_logic | Ready flag; indicates that the external component is ready to accept data. |
|
||||
|
||||
## Signals
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------- | ----------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| R_Valid | std_logic_vector(G_PipelineStages - 1 downto 0) | Pipeline ready signal for each stage of the pipeline to indicate that the data in pipeline is valid |
|
||||
| C_Ready | std_logic | Ready signal for the pipeline controller to indicate that the pipeline can accept data; <br> mapped to `O_Enable` and `O_Ready` ports. |
|
||||
|
||||
## Processes
|
||||
|
||||
- P_ExternalFlags: ( R_Valid, C_Ready, I_CE )
|
||||
- **Description**
|
||||
Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller. <br> - `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals. <br> - `O_Valid` is the last bit of the `R_Valid` signal and represents the validity of the data in the last stage of the pipeline.
|
||||
- P_InternalFlags: ( R_Valid, I_Ready )
|
||||
- **Description**
|
||||
Produce the `C_Ready` signal for the pipeline controller, controlling the data flow in the pipeline. <br> `C_Ready` is asserted when the data is available in the last stage of the pipeline **and** the external component is ready to accept data **or** when no data is available in the last stage of the pipeline.
|
||||
- P_ValidPipeline: ( I_CLK )
|
||||
- **Description**
|
||||
Shift the pipeline stages with `R_Valid` signal as placeholder to control the validity of the data in the individual pipeline stages.
|
||||
|
||||
---
|
||||
|
||||
# Entity: PipelineRegister
|
||||
|
||||
- **File**: PipelineRegister.vhd
|
||||
|
||||
## Diagram
|
||||
|
||||

|
||||
|
||||
## Description
|
||||
|
||||
- Name: **Pipeline Register**
|
||||
- Version: 0.0.1
|
||||
- Author: _Maximilian Passarello ([Blog](http://mpassarello.de))_
|
||||
- License: [MIT](LICENSE)
|
||||
|
||||
The pipeline register provides a simple way to pipeline combinatorial logic using the **register rebalancing** of the synthesis.
|
||||
|
||||
### Core functions
|
||||
|
||||
- **Register rebalancing**: The generic `G_RegisterBalancing` can be used
|
||||
to precisely configure how register rebalancing works.
|
||||
- **Number of registers**: The pipeline register instantiates a number of FFs corresponding
|
||||
to the generic `G_PipelineStages`.
|
||||
- **Data width**: The data width of the registers
|
||||
and the input/output vectors (std_logic_vector) is configured via the generic `G_Width`.
|
||||
|
||||
### Register rebalancing
|
||||
|
||||
The generic `G_RegisterBalancing` can be used to set the **Register Rebalancing** of the Xilinx ISE.
|
||||
The possible variants are
|
||||
|
||||
- `no`: Deactivates the rebalancing register.
|
||||
- `yes`: Activates the rebalancing register in both directions (forwards and backwards).
|
||||
- `forward`: Activates the rebalancing register in the forward direction.
|
||||
This causes the synthesis to shift and reduce a **multiple** of FFs at the inputs of a LUT
|
||||
to a **single** FF forward at the output of a LUT.
|
||||
- `backward`: Activates the rebalancing register in the backward direction.
|
||||
This causes the synthesis to shift and duplicate a **single** FF at the output of a LUT
|
||||
backwards to a **multiple** of FFs at the input of a LUT.
|
||||
|
||||
## History
|
||||
|
||||
- 0.0.1 (2024-03-24) Initial version
|
||||
|
||||
## Generics
|
||||
|
||||
| Generic name | Type | Value | Description |
|
||||
| ------------------- | ------- | ----- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| G_PipelineStages | integer | 3 | Number of pipeline stages (Correspondent to the number of registers in the pipeline) |
|
||||
| G_Width | integer | 32 | Data width |
|
||||
| G_RegisterBalancing | string | "yes" | Register balancing attribute<br> - `no` : **Disable** register balancing, <br> - `yes`: **Enable** register balancing in both directions, <br> - `forward`: **Enable** register balancing and moves a set of FFs at the inputs of a LUT to a single FF at its output, <br> - `backward`: **Enable** register balancing and moves a single FF at the output of a LUT to a set of FFs at its inputs. |
|
||||
|
||||
## Ports
|
||||
|
||||
| Port name | Direction | Type | Description |
|
||||
| --------- | --------- | -------------------------------------- | ----------------------------------------- |
|
||||
| I_CLK | in | std_logic | Clock signal; **Rising edge** triggered |
|
||||
| I_Enable | in | std_logic | Enable input from **Pipeline Controller** |
|
||||
| I_Data | in | std_logic_vector(G_Width - 1 downto 0) | Data input |
|
||||
| O_Data | out | std_logic_vector(G_Width - 1 downto 0) | Data output |
|
||||
|
||||
## Signals
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ------ | --------------------------------------------------------------------------- |
|
||||
| R_Data | T_Data | Pipeline register data signal; `G_PipelineStages` stages of `G_Width` bits. |
|
||||
|
||||
## Types
|
||||
|
||||
| Name | Type | Description |
|
||||
| ------ | ---- | --------------------------------------------------------------------------------------- |
|
||||
| T_Data | | Pipeline register data type; organized as an array (Stages) of std_logic_vector (Data). |
|
||||
|
||||
## Processes
|
||||
|
||||
- P_PipelineRegister: ( I_CLK )
|
||||
- **Description**
|
||||
Pipeline register and connection of the data from the input port to the first stage of the pipeline register. <br> **I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1)** -> O_Data
|
||||
- P_ForwardData: ( R_Data )
|
||||
- **Description**
|
||||
Connect (combinatoric) data from the last stage of the pipeline register to the output port. <br> I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data**
|
||||
|
223
project.cfg
223
project.cfg
@@ -12,7 +12,7 @@ TARGET_PART = xc3s1200e-4-fg320
|
||||
XILINX = /opt/Xilinx/14.7/ISE_DS/ISE
|
||||
|
||||
# Optional the name of the top module (default is the project name)
|
||||
TOPLEVEL = Pipeline_pb
|
||||
TOPLEVEL = PipelineFilter
|
||||
|
||||
# Optional the name of the ucf file (default is the project name)
|
||||
CONSTRAINTS = src/Pipeline_pb.ucf
|
||||
@@ -28,8 +28,10 @@ CONSTRAINTS = src/Pipeline_pb.ucf
|
||||
VHDSOURCE += src/Pipeline_pb.vhd
|
||||
VHDSOURCE += src/PipelineController.vhd
|
||||
VHDSOURCE += src/PipelineRegister.vhd
|
||||
VHDSOURCE += src/PipelineFilter.vhd
|
||||
|
||||
VHDTEST += tests/Pipeline_tb.vhd
|
||||
# VHDTEST += tests/Pipeline_tb.vhd
|
||||
VHDTEST += tests/PipelineFilter_tb.vhd
|
||||
|
||||
## ## ## ## ## ## ## ##
|
||||
# ---------------------
|
||||
@@ -38,8 +40,221 @@ VHDTEST += tests/Pipeline_tb.vhd
|
||||
|
||||
# General command line options to be passed to all ISE executables (default is `-intstyle xflow`)
|
||||
# COMMON_OPTS =
|
||||
|
||||
# Options for the XST synthesizer
|
||||
XST_OPTS = -opt_mode speed -opt_level 2
|
||||
#### Synthese Options (XST) #####
|
||||
|
||||
# Optimization goal: prioritize speed or area.
|
||||
# Values: Speed | Area
|
||||
XST_OPTS += -opt_mode Speed
|
||||
|
||||
# Optimization level: more aggressive optimizations at level 2.
|
||||
# Values: 1 | 2
|
||||
XST_OPTS += -opt_level 2
|
||||
|
||||
# Use the new XST parser (recommended for modern designs).
|
||||
# Values: yes | no
|
||||
XST_OPTS += -use_new_parser yes
|
||||
|
||||
# Preserve design hierarchy or allow flattening for optimization.
|
||||
# Values: Yes | No | Soft
|
||||
XST_OPTS += -keep_hierarchy No
|
||||
|
||||
# Determines how hierarchy is preserved in the netlist.
|
||||
# Values: As_Optimized | Rebuilt
|
||||
XST_OPTS += -netlist_hierarchy As_Optimized
|
||||
|
||||
# Global optimization strategy for nets.
|
||||
# Values: AllClockNets | Offset_In_Before | Offset_Out_After | Inpad_To_Outpad | Max_Delay
|
||||
XST_OPTS += -glob_opt AllClockNets
|
||||
|
||||
## Misc ##
|
||||
|
||||
# Enable reading of IP cores.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -read_cores YES
|
||||
|
||||
# Do not write timing constraints into synthesis report.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -write_timing_constraints NO
|
||||
|
||||
# Analyze paths across different clock domains.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -cross_clock_analysis NO
|
||||
|
||||
# Character used to separate hierarchy levels in instance names.
|
||||
# Default: /
|
||||
XST_OPTS += -hierarchy_separator /
|
||||
|
||||
# Delimiters used for bus signals.
|
||||
# Values: <> | [] | () | {}
|
||||
XST_OPTS += -bus_delimiter <>
|
||||
|
||||
# Maintain original case of identifiers.
|
||||
# Values: Maintain | Upper | Lower
|
||||
XST_OPTS += -case Maintain
|
||||
|
||||
# Target maximum utilization ratio for slices.
|
||||
# Values: 1–100
|
||||
XST_OPTS += -slice_utilization_ratio 100
|
||||
|
||||
# Target maximum utilization ratio for BRAMs.
|
||||
# Values: 1–100
|
||||
XST_OPTS += -bram_utilization_ratio 100
|
||||
|
||||
# Use Verilog 2001 syntax features.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -verilog2001 YES
|
||||
|
||||
#### HDL Options ####
|
||||
|
||||
## FSM ##
|
||||
|
||||
# Extract FSMs (Finite State Machines) from HDL code.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -fsm_extract YES
|
||||
|
||||
# Encoding strategy for FSMs.
|
||||
# Values: Auto | Gray | One-Hot | Johnson | Compact | Sequential | Speed1 | User
|
||||
XST_OPTS += -fsm_encoding Auto
|
||||
|
||||
# Add safe logic for undefined FSM states.
|
||||
# Values: Yes | No
|
||||
XST_OPTS += -safe_implementation No
|
||||
|
||||
# Structure used to implement FSMs.
|
||||
# Values: LUT | BRAM
|
||||
XST_OPTS += -fsm_style LUT
|
||||
|
||||
## RAM/ROM ##
|
||||
|
||||
# Extract RAM inference from HDL.
|
||||
# Values: Yes | No
|
||||
XST_OPTS += -ram_extract Yes
|
||||
|
||||
# Style used to implement RAM.
|
||||
# Values: Auto | Block | Distributed
|
||||
XST_OPTS += -ram_style Auto
|
||||
|
||||
# Extract ROM inference from HDL.
|
||||
# Values: Yes | No
|
||||
XST_OPTS += -rom_extract Yes
|
||||
|
||||
# Style used for implementing ROM.
|
||||
# Values: Auto | Distributed | Block
|
||||
XST_OPTS += -rom_style Auto
|
||||
|
||||
# Enable or disable automatic BRAM packing.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -auto_bram_packing NO
|
||||
|
||||
## MUX/Decoder/Shift Register ##
|
||||
|
||||
# Extract multiplexers where possible.
|
||||
# Values: Yes | No | Force
|
||||
XST_OPTS += -mux_extract Yes
|
||||
|
||||
# Style used for implementing MUX logic.
|
||||
# Values: Auto | MUXCY | MUXF
|
||||
XST_OPTS += -mux_style Auto
|
||||
|
||||
# Extract decoder logic from behavioral code.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -decoder_extract YES
|
||||
|
||||
# Extract and optimize priority encoder structures.
|
||||
# Values: Yes | No | Force
|
||||
XST_OPTS += -priority_extract Yes
|
||||
|
||||
# Extract shift register logic.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -shreg_extract YES
|
||||
|
||||
# Extract simple shift operations into dedicated hardware.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -shift_extract YES
|
||||
|
||||
## Multiplier ##
|
||||
|
||||
# Style for implementing multipliers.
|
||||
# Values: Auto | LUT | Pipe_LUT | Pipe_Block | Block
|
||||
XST_OPTS += -mult_style Auto
|
||||
|
||||
## Misc ##
|
||||
|
||||
# Collapse XOR trees where beneficial.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -xor_collapse YES
|
||||
|
||||
# Share resources like adders or multipliers between logic blocks.
|
||||
# Values: YES | NO | Force
|
||||
XST_OPTS += -resource_sharing YES
|
||||
|
||||
# Convert asynchronous resets to synchronous where possible.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -async_to_sync NO
|
||||
|
||||
#### Xilinx Specific Options ####
|
||||
|
||||
## Optimization ##
|
||||
|
||||
# Enable removal of logically equivalent registers.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -equivalent_register_removal YES
|
||||
|
||||
# Duplicate registers to reduce fanout or improve timing.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -register_duplication YES
|
||||
|
||||
# Move registers across logic to balance timing.
|
||||
# Values: Yes | No
|
||||
XST_OPTS += -register_balancing No
|
||||
|
||||
# Use clock enable signals where possible.
|
||||
# Values: Auto | Yes | No
|
||||
XST_OPTS += -use_clock_enable Yes
|
||||
|
||||
# Use synchronous set (preset) signals when available.
|
||||
# Values: Auto | Yes | No
|
||||
XST_OPTS += -use_sync_set Yes
|
||||
|
||||
# Use synchronous reset signals where possible.
|
||||
# Values: Auto | Yes | No
|
||||
XST_OPTS += -use_sync_reset Yes
|
||||
|
||||
## I/O ##
|
||||
|
||||
# Insert IO buffers for top-level ports.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -iobuf YES
|
||||
|
||||
# Placement strategy for IOB registers (Auto = let tools decide).
|
||||
# Values: Auto | YES | NO
|
||||
XST_OPTS += -iob Auto
|
||||
|
||||
## Misc ##
|
||||
|
||||
# Maximum allowed fanout for a net.
|
||||
# Values: integer (e.g., 500)
|
||||
XST_OPTS += -max_fanout 500
|
||||
|
||||
# Maximum number of BUFGs (global buffers) to use.
|
||||
# Values: 0–32 (device-dependent)
|
||||
XST_OPTS += -bufg 24
|
||||
|
||||
# Enable logic packing into slices.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -slice_packing YES
|
||||
|
||||
# Try to reduce the number of primitive instances used.
|
||||
# Values: YES | NO
|
||||
XST_OPTS += -optimize_primitives NO
|
||||
|
||||
# Margin in percent beyond the target slice utilization.
|
||||
# Values: 0–100
|
||||
XST_OPTS += -slice_utilization_ratio_maxmargin 5
|
||||
|
||||
|
||||
|
||||
# Options for the NGDBuild tool
|
||||
# NGDBUILD_OPTS =
|
||||
@@ -64,7 +279,7 @@ PAR_OPTS = -ol high
|
||||
# Options for the Fuse tool
|
||||
# FUSE_OPTS =
|
||||
|
||||
ISIM_CMD =
|
||||
# ISIM_CMD =
|
||||
|
||||
## ## ## ## ## ## ## ##
|
||||
# ---------------------
|
||||
|
@@ -1,6 +1,6 @@
|
||||
----------------------------------------------------------------------------------
|
||||
--@ - Name: **Pipeline Controller**
|
||||
--@ - Version: 0.0.1
|
||||
--@ - Version: 0.0.2
|
||||
--@ - Author: _Maximilian Passarello ([Blog](mpassarello.de))_
|
||||
--@ - License: [MIT](LICENSE)
|
||||
--@
|
||||
@@ -46,8 +46,8 @@
|
||||
--@
|
||||
--@ ## History
|
||||
--@ - 0.0.1 (2024-03-24) Initial version
|
||||
--@ - 0.0.2 (2024-04-13) Enhanced the validity update logic to correctly handle configurations with a single pipeline stage
|
||||
----------------------------------------------------------------------------------
|
||||
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
@@ -56,31 +56,34 @@ use ieee.math_real.all;
|
||||
entity PipelineController is
|
||||
generic (
|
||||
--@ Number of pipeline stages (FFs in the pipeline including I/O FFs)
|
||||
G_PipelineStages : integer := 3;
|
||||
G_PipelineStages : integer := 3;
|
||||
--@ Reset active at this level
|
||||
G_ResetActiveAt : std_logic := '1'
|
||||
G_ResetActiveAt : std_logic := '1'
|
||||
);
|
||||
port (
|
||||
--@ Clock signal; **Rising edge** triggered
|
||||
I_CLK : in std_logic;
|
||||
I_CLK : in std_logic := '0';
|
||||
--@ Reset signal; Active at `G_ResetActiveAt`
|
||||
I_RST : in std_logic;
|
||||
I_RST : in std_logic := '0';
|
||||
--@ Chip enable; Active high
|
||||
I_CE : in std_logic;
|
||||
I_CE : in std_logic := '1';
|
||||
|
||||
--@ Pipeline enable; Active high when pipeline can accept data and `I_CE` is high. <br>
|
||||
--@ **Note:** Connect `CE` of the registers to be controlled by this controller to `O_Enable`.
|
||||
O_Enable : out std_logic;
|
||||
O_Enable : out std_logic := '0';
|
||||
|
||||
--@ @virtualbus Input-AXI-Handshake @dir in Input AXI like Handshake
|
||||
--@ Valid data flag; indicates that the data on `I_Data` of the connected registers is valid.
|
||||
I_Valid : in std_logic;
|
||||
I_Valid : in std_logic := '0';
|
||||
--@ Ready flag; indicates that the connected registers is ready to accept data.
|
||||
O_Ready : out std_logic;
|
||||
O_Ready : out std_logic := '0';
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus Output-AXI-Handshake @dir out Output AXI like Handshake
|
||||
--@ Valid data flag; indicates that the data on `O_Data` of the connected registers is valid.
|
||||
O_Valid : out std_logic;
|
||||
O_Valid : out std_logic := '0';
|
||||
--@ Ready flag; indicates that the external component is ready to accept data.
|
||||
I_Ready : in std_logic
|
||||
I_Ready : in std_logic := '0'
|
||||
--@ @end
|
||||
);
|
||||
end entity PipelineController;
|
||||
@@ -90,55 +93,75 @@ architecture RTL of PipelineController is
|
||||
signal R_Valid : std_logic_vector(G_PipelineStages - 1 downto 0) := (others => '0');
|
||||
--@ Ready signal for the pipeline controller to indicate that the pipeline can accept data; <br>
|
||||
--@ mapped to `O_Enable` and `O_Ready` ports.
|
||||
signal C_Ready : std_logic := '1';
|
||||
signal C_Ready : std_logic := '1';
|
||||
begin
|
||||
|
||||
--@ Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller. <br>
|
||||
--@ - `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals. <br>
|
||||
--@ - `O_Valid` is the last bit of the `R_Valid` signal
|
||||
--@ and represents the validity of the data in the last stage of the pipeline.
|
||||
P_ExternalFlags : process (R_Valid, C_Ready, I_CE)
|
||||
begin
|
||||
O_Valid <= R_Valid(R_Valid'high);
|
||||
GEN_ForwardExternalFlags : if G_PipelineStages = 0 generate
|
||||
--@ If no pipeline stages are defined, the flags are directly connected to the input and output ports.
|
||||
P_ExternalFlags : process (I_CE, I_Valid, I_Ready)
|
||||
begin
|
||||
O_Valid <= I_Valid;
|
||||
O_Enable <= I_Ready and I_CE;
|
||||
O_Ready <= I_Ready and I_CE;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
O_Enable <= C_Ready and I_CE;
|
||||
O_Ready <= C_Ready and I_CE;
|
||||
end process;
|
||||
GEN_ExternalFlags : if G_PipelineStages > 0 generate
|
||||
--@ Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller. <br>
|
||||
--@ - `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals. <br>
|
||||
--@ - `O_Valid` is the last bit of the `R_Valid` signal
|
||||
--@ and represents the validity of the data in the last stage of the pipeline.
|
||||
P_ExternalFlags : process (R_Valid, C_Ready, I_CE)
|
||||
begin
|
||||
O_Valid <= R_Valid(R_Valid'high);
|
||||
|
||||
--@ Produce the `C_Ready` signal for the pipeline controller,
|
||||
--@ controlling the data flow in the pipeline. <br>
|
||||
--@ `C_Ready` is asserted when the data is available in the last stage of the pipeline
|
||||
--@ **and** the external component is ready to accept data
|
||||
--@ **or** when no data is available in the last stage of the pipeline.
|
||||
P_InternalFlags : process (R_Valid, I_Ready)
|
||||
begin
|
||||
if R_Valid(R_Valid'high) = '1' then
|
||||
-- Data is available in the last stage of the pipeline.
|
||||
if I_Ready = '1' then
|
||||
-- O_Data is accepted from the external component.
|
||||
C_Ready <= '1';
|
||||
O_Enable <= C_Ready and I_CE;
|
||||
O_Ready <= C_Ready and I_CE;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
GEN_InternalFlags : if G_PipelineStages > 0 generate
|
||||
--@ Produce the `C_Ready` signal for the pipeline controller,
|
||||
--@ controlling the data flow in the pipeline. <br>
|
||||
--@ `C_Ready` is asserted when the data is available in the last stage of the pipeline
|
||||
--@ **and** the external component is ready to accept data
|
||||
--@ **or** when no data is available in the last stage of the pipeline.
|
||||
P_InternalFlags : process (R_Valid, I_Ready)
|
||||
begin
|
||||
if R_Valid(R_Valid'high) = '1' then
|
||||
-- Data is available in the last stage of the pipeline.
|
||||
if I_Ready = '1' then
|
||||
-- O_Data is accepted from the external component.
|
||||
C_Ready <= '1';
|
||||
else
|
||||
-- O_Data is not accepted from the external component.
|
||||
C_Ready <= '0';
|
||||
end if;
|
||||
else
|
||||
-- O_Data is not accepted from the external component.
|
||||
C_Ready <= '0';
|
||||
-- No data available in the last stage of the pipeline.
|
||||
C_Ready <= '1';
|
||||
end if;
|
||||
else
|
||||
-- No data available in the last stage of the pipeline.
|
||||
C_Ready <= '1';
|
||||
end if;
|
||||
end process;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
--@ Shift the pipeline stages with `R_Valid` signal as placeholder to control
|
||||
--@ the validity of the data in the individual pipeline stages.
|
||||
P_ValidPipeline : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_RST = G_ResetActiveAt then
|
||||
R_Valid <= (others => '0');
|
||||
elsif I_CE = '1' then
|
||||
if C_Ready = '1' then
|
||||
R_Valid <= R_Valid(R_Valid'high - 1 downto R_Valid'low) & I_Valid;
|
||||
GEN_ValidPipe : if G_PipelineStages > 0 generate
|
||||
--@ Shift the pipeline stages with `R_Valid` signal as placeholder to control
|
||||
--@ the validity of the data in the individual pipeline stages.
|
||||
P_ValidPipeline : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_RST = G_ResetActiveAt then
|
||||
R_Valid <= (others => '0');
|
||||
elsif I_CE = '1' then
|
||||
if C_Ready = '1' then
|
||||
if G_PipelineStages = 1 then
|
||||
R_Valid(0) <= I_Valid;
|
||||
else
|
||||
R_Valid <= R_Valid(R_Valid'high - 1 downto R_Valid'low) & I_Valid;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end architecture RTL;
|
||||
end process;
|
||||
end generate;
|
||||
end architecture RTL;
|
||||
|
140
src/PipelineFilter.vhd
Normal file
140
src/PipelineFilter.vhd
Normal file
@@ -0,0 +1,140 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity PipelineFilter is
|
||||
generic (
|
||||
--@ Width of the comparison input and mask.
|
||||
G_MaskWidth : integer := 4;
|
||||
|
||||
--@ Bit mask to be compared against `I_Match` input.
|
||||
G_Mask : std_logic_vector := "1010";
|
||||
|
||||
--@ Comparison mode that defines the filter behavior.
|
||||
--@ Available modes:
|
||||
--@ - `"none"`: Disables filtering; always passes data.
|
||||
--@ - `"or"`: Filters if **any** bit in `I_Match` matches a bit set in `G_Mask`.
|
||||
--@ - `"and"`: Filters if **all** bits set in `G_Mask` are also set in `I_Match`.
|
||||
--@ - `"xor"`: Filters if **any** bit differs between `I_Match` and `G_Mask`.
|
||||
--@ - `"equal"`: Filters if `I_Match` is **bitwise equal** to `G_Mask`.
|
||||
--@ - `"not_equal"`: Filters if `I_Match` is **not equal** to `G_Mask`.
|
||||
G_MaskMode : string := "equal"
|
||||
);
|
||||
port (
|
||||
I_Match : in std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
|
||||
--@ @virtualbus AXI-Flags-In @dir In Input interface for AXI-like handshake
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
I_Valid : in std_logic := '0';
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
O_Ready : out std_logic := '0';
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus AXI-Flags-Out @dir Out Output interface for AXI-like handshake
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
O_Valid : out std_logic := '0';
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
I_Ready : in std_logic := '0'
|
||||
--@ @end
|
||||
);
|
||||
end entity PipelineFilter;
|
||||
|
||||
architecture RTL of PipelineFilter is
|
||||
function strings_equal(A, B : string) return boolean is
|
||||
begin
|
||||
if A'length /= B'length then
|
||||
return false;
|
||||
end if;
|
||||
|
||||
for i in A'range loop
|
||||
if A(i) /= B(i) then
|
||||
return false;
|
||||
end if;
|
||||
end loop;
|
||||
|
||||
return true;
|
||||
end function;
|
||||
|
||||
constant K_Mode_None : string := "none";
|
||||
constant K_Mode_OR : string := "or";
|
||||
constant K_Mode_XOR : string := "xor";
|
||||
constant K_Mode_AND : string := "and";
|
||||
constant K_Mode_Equal : string := "equal";
|
||||
constant K_Mode_NotEqual : string := "not_equal";
|
||||
|
||||
signal C_ShouldFiltered : std_logic := '0';
|
||||
begin
|
||||
assert G_Mask'length = G_MaskWidth
|
||||
report "G_Mask length does not match G_MaskWidth" severity failure;
|
||||
|
||||
process (I_Match)
|
||||
begin
|
||||
if strings_equal(G_MaskMode, K_Mode_None) then
|
||||
--@ No filtering: Always pass the data through.
|
||||
C_ShouldFiltered <= '0';
|
||||
|
||||
elsif strings_equal(G_MaskMode, K_Mode_OR) then
|
||||
--@ Filter if **any** bit in I_Match matches a bit set in G_Mask.
|
||||
--@ Equivalent to: (I_Match AND G_Mask) /= 0
|
||||
if (I_Match and G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then
|
||||
C_ShouldFiltered <= '1';
|
||||
else
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
|
||||
elsif strings_equal(G_MaskMode, K_Mode_XOR) then
|
||||
--@ Filter if **any** bit differs between I_Match and G_Mask.
|
||||
--@ This checks if the vectors are **not bitwise equal**.
|
||||
if (I_Match xor G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then
|
||||
C_ShouldFiltered <= '1';
|
||||
else
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
|
||||
elsif strings_equal(G_MaskMode, K_Mode_AND) then
|
||||
--@ Filter if **all bits** set in G_Mask are also set in I_Match.
|
||||
--@ In other words, I_Match must contain the full mask.
|
||||
if (I_Match and G_Mask) = G_Mask then
|
||||
C_ShouldFiltered <= '1';
|
||||
else
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
|
||||
elsif strings_equal(G_MaskMode, K_Mode_Equal) then
|
||||
--@ Filter if I_Match is **exactly equal** to G_Mask.
|
||||
if I_Match = G_Mask then
|
||||
C_ShouldFiltered <= '1';
|
||||
else
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
|
||||
elsif strings_equal(G_MaskMode, K_Mode_NotEqual) then
|
||||
--@ Filter if I_Match is **not equal** to G_Mask.
|
||||
if I_Match /= G_Mask then
|
||||
C_ShouldFiltered <= '1';
|
||||
else
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
|
||||
else
|
||||
--@ Unknown mode: fallback to no filtering.
|
||||
C_ShouldFiltered <= '0';
|
||||
end if;
|
||||
end process;
|
||||
|
||||
process (I_Valid, I_Ready, C_ShouldFiltered)
|
||||
begin
|
||||
if C_ShouldFiltered = '1' then
|
||||
--@ Data is filtered: do not pass it through.
|
||||
O_Valid <= '0';
|
||||
--@ Assert O_Ready to indicate that the input is ready to accept data.
|
||||
O_Ready <= '1';
|
||||
else
|
||||
--@ Data is not filtered: pass it through.
|
||||
O_Valid <= I_Valid;
|
||||
O_Ready <= I_Ready;
|
||||
end if;
|
||||
end process;
|
||||
|
||||
end architecture;
|
@@ -39,9 +39,9 @@ use ieee.math_real.all;
|
||||
entity PipelineRegister is
|
||||
generic (
|
||||
--@ Number of pipeline stages (Correspondent to the number of registers in the pipeline)
|
||||
G_PipelineStages : integer := 3;
|
||||
G_PipelineStages : integer := 3;
|
||||
--@ Data width
|
||||
G_Width : integer := 32;
|
||||
G_Width : integer := 32;
|
||||
--@ Register balancing attribute<br>
|
||||
--@ - `no` : **Disable** register balancing, <br>
|
||||
--@ - `yes`: **Enable** register balancing in both directions, <br>
|
||||
@@ -49,17 +49,17 @@ entity PipelineRegister is
|
||||
--@ and moves a set of FFs at the inputs of a LUT to a single FF at its output, <br>
|
||||
--@ - `backward`: **Enable** register balancing
|
||||
--@ and moves a single FF at the output of a LUT to a set of FFs at its inputs.
|
||||
G_RegisterBalancing : string := "yes"
|
||||
G_RegisterBalancing : string := "yes"
|
||||
);
|
||||
port (
|
||||
--@ Clock signal; **Rising edge** triggered
|
||||
I_CLK : in std_logic;
|
||||
--@ Clock; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic := '0';
|
||||
--@ Enable input from **Pipeline Controller**
|
||||
I_Enable : in std_logic;
|
||||
I_Enable : in std_logic := '0';
|
||||
--@ Data input
|
||||
I_Data : in std_logic_vector(G_Width - 1 downto 0);
|
||||
I_Data : in std_logic_vector(G_Width - 1 downto 0) := (others => '0');
|
||||
--@ Data output
|
||||
O_Data : out std_logic_vector(G_Width - 1 downto 0) := (others => '0')
|
||||
O_Data : out std_logic_vector(G_Width - 1 downto 0) := (others => '0')
|
||||
);
|
||||
end entity PipelineRegister;
|
||||
|
||||
@@ -69,35 +69,50 @@ architecture RTL of PipelineRegister is
|
||||
--@ Pipeline register data type; organized as an array (Stages) of std_logic_vector (Data).
|
||||
type T_Data is array(0 to G_PipelineStages - 1) of std_logic_vector(G_Width - 1 downto 0);
|
||||
--@ Pipeline register data signal; `G_PipelineStages` stages of `G_Width` bits.
|
||||
signal R_Data : T_Data := (others => (others => '0'));
|
||||
signal R_Data : T_Data := (others => (others => '0'));
|
||||
--@ Pipeline register balancing attribute from generic
|
||||
attribute register_balancing of R_Data : signal is G_RegisterBalancing;
|
||||
begin
|
||||
|
||||
--@ Pipeline register and connection of the data from the input port to the first stage of the pipeline register. <br>
|
||||
--@ **I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1)** -> O_Data
|
||||
P_PipelineRegister : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_Enable = '1' then
|
||||
for i in 0 to G_PipelineStages - 1 loop
|
||||
if i = 0 then
|
||||
--@ Input data from the input port to the first stage of the pipeline register
|
||||
R_Data(i) <= I_Data;
|
||||
else
|
||||
--@ Data from the previous stage of the pipeline register to the current stage
|
||||
R_Data(i) <= R_Data(i - 1);
|
||||
end if;
|
||||
end loop;
|
||||
--@ Generate the pipeline registers if `G_PipelineStages` is greater than 0.
|
||||
GEN_PipelineRegister : if G_PipelineStages > 0 generate
|
||||
--@ Pipeline register and connection of the data from the input port to the first stage of the pipeline register. <br>
|
||||
--@ **I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1)** -> O_Data
|
||||
P_PipelineRegister : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
if I_Enable = '1' then
|
||||
for i in 0 to G_PipelineStages - 1 loop
|
||||
if i = 0 then
|
||||
--@ Input data from the input port to the first stage of the pipeline register
|
||||
R_Data(i) <= I_Data;
|
||||
else
|
||||
--@ Data from the previous stage of the pipeline register to the current stage
|
||||
R_Data(i) <= R_Data(i - 1);
|
||||
end if;
|
||||
end loop;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
end process;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
--@ Connect (combinatoric) data from the last stage of the pipeline register to the output port. <br>
|
||||
--@ I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data**
|
||||
P_ForwardData : process (R_Data)
|
||||
begin
|
||||
O_Data <= R_Data(G_PipelineStages - 1);
|
||||
end process;
|
||||
--@ Generate the connection last register to the output port if `G_PipelineStages` is greater than 0.
|
||||
GEN_ForwardRegister : if G_PipelineStages > 0 generate
|
||||
--@ Connect (combinatoric) data from the last stage of the pipeline register to the output port. <br>
|
||||
--@ I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data**
|
||||
P_ForwardData : process (R_Data)
|
||||
begin
|
||||
O_Data <= R_Data(G_PipelineStages - 1);
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
end architecture RTL;
|
||||
--@ Generate the connection of the input port to the output port if `G_PipelineStages` is 0.
|
||||
GEN_ForwardData : if G_PipelineStages = 0 generate
|
||||
--@ If `G_PipelineStages` is 0, the data from the input port is directly connected to the output port.
|
||||
P_ForwardData : process (I_Data)
|
||||
begin
|
||||
O_Data <= I_Data;
|
||||
end process;
|
||||
end generate;
|
||||
|
||||
end architecture RTL;
|
||||
|
161
src/PipelineStage.vhd
Normal file
161
src/PipelineStage.vhd
Normal file
@@ -0,0 +1,161 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity PipelineStage is
|
||||
generic (
|
||||
--@ Number of pipeline stages (FFs in the pipeline including I/O FFs)
|
||||
G_PipelineStages : integer := 3;
|
||||
--@ Data width
|
||||
G_D0_Width : integer := 1;
|
||||
--@ Data width
|
||||
G_D1_Width : integer := 0;
|
||||
--@ Data width
|
||||
G_D2_Width : integer := 0;
|
||||
--@ Data width
|
||||
G_D3_Width : integer := 0;
|
||||
--@ Reset active at this level
|
||||
G_ResetActiveAt : std_logic := '1';
|
||||
--@ Register balancing attribute
|
||||
--@ - `no` : **Disable** register balancing,
|
||||
--@ - `yes`: **Enable** register balancing in both directions,
|
||||
--@ - `forward`: **Enable** register balancing
|
||||
--@ and moves a set of FFs at the inputs of a LUT to a single FF at its output,
|
||||
--@ - `backward`: **Enable** register balancing
|
||||
--@ and moves a single FF at the output of a LUT to a set of FFs at its inputs.
|
||||
G_RegisterBalancing : string := "yes"
|
||||
);
|
||||
port (
|
||||
--@ Clock; (**Rising edge** triggered)
|
||||
I_CLK : in std_logic := '0';
|
||||
--@ Clock Enable; (**Synchronous**, **Active high**)
|
||||
I_CE : in std_logic := '1';
|
||||
--@ Reset; (**Synchronous**, **Active high**)
|
||||
I_RST : in std_logic := '0';
|
||||
|
||||
--@ Pipeline enable for additional stages; (**Synchronous**, **Active high**)
|
||||
O_PipelineEnable : out std_logic := '0';
|
||||
|
||||
--@ @virtualbus AXI-Data-In @dir In Input interface with AXI-like handshake
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
I_Valid : in std_logic := '0';
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
O_Ready : out std_logic := '0';
|
||||
--@ Data input 0
|
||||
I_Data_0 : in std_logic_vector(G_D0_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data input 1
|
||||
I_Data_1 : in std_logic_vector(G_D1_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data input 2
|
||||
I_Data_2 : in std_logic_vector(G_D2_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data input 3
|
||||
I_Data_3 : in std_logic_vector(G_D3_Width - 1 downto 0) := (others => '-');
|
||||
--@ @end
|
||||
|
||||
--@ @virtualbus AXI-Data-Out @dir Out Output interface with AXI-like handshake
|
||||
--@ AXI like valid; (**Synchronous**, **Active high**)
|
||||
O_Valid : out std_logic := '0';
|
||||
--@ AXI like ready; (**Synchronous**, **Active high**)
|
||||
I_Ready : in std_logic := '0';
|
||||
--@ Data output 0
|
||||
O_Data_0 : out std_logic_vector(G_D0_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data output 1
|
||||
O_Data_1 : out std_logic_vector(G_D1_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data output 2
|
||||
O_Data_2 : out std_logic_vector(G_D2_Width - 1 downto 0) := (others => '-');
|
||||
--@ Data output 3
|
||||
O_Data_3 : out std_logic_vector(G_D3_Width - 1 downto 0) := (others => '-')
|
||||
--@ @end
|
||||
);
|
||||
end entity PipelineStage;
|
||||
|
||||
architecture Rtl of PipelineStage is
|
||||
signal S_PipelineEnable : std_logic := '0';
|
||||
begin
|
||||
--@ Forwarding the pipeline enable signal to the output port.
|
||||
--@ This signal is used to control the pipeline enable signal
|
||||
--@ of additional external stages.
|
||||
O_PipelineEnable <= S_PipelineEnable;
|
||||
|
||||
--@ Pipeline controller
|
||||
I_PipelineCtrl : entity work.PipelineController
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_ResetActiveAt => G_ResetActiveAt
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_CE => I_CE,
|
||||
I_RST => I_RST,
|
||||
O_Enable => S_PipelineEnable,
|
||||
I_Valid => I_Valid,
|
||||
O_Ready => O_Ready,
|
||||
O_Valid => O_Valid,
|
||||
I_Ready => I_Ready
|
||||
);
|
||||
|
||||
GEN_PipelineRegister_D0 : if G_D0_Width > 0 generate
|
||||
--@ Pipeline register Data 0
|
||||
I_PielineRegister_D0 : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_D0_Width,
|
||||
G_RegisterBalancing => G_RegisterBalancing
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_PipelineEnable,
|
||||
I_Data => I_Data_0,
|
||||
O_Data => O_Data_0
|
||||
);
|
||||
end generate;
|
||||
|
||||
GEN_PipelineRegister_D1 : if G_D1_Width > 0 generate
|
||||
--@ Pipeline register Data 1
|
||||
I_PielineRegister_D1 : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_D1_Width,
|
||||
G_RegisterBalancing => G_RegisterBalancing
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_PipelineEnable,
|
||||
I_Data => I_Data_1,
|
||||
O_Data => O_Data_1
|
||||
);
|
||||
end generate;
|
||||
|
||||
GEN_PipelineRegister_D2 : if G_D2_Width > 0 generate
|
||||
--@ Pipeline register Data 2
|
||||
I_PielineRegister_D2 : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_D2_Width,
|
||||
G_RegisterBalancing => G_RegisterBalancing
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_PipelineEnable,
|
||||
I_Data => I_Data_2,
|
||||
O_Data => O_Data_2
|
||||
);
|
||||
end generate;
|
||||
|
||||
GEN_PipelineRegister_D3 : if G_D3_Width > 0 generate
|
||||
--@ Pipeline register Data 3
|
||||
I_PielineRegister_D3 : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_D3_Width,
|
||||
G_RegisterBalancing => G_RegisterBalancing
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => S_PipelineEnable,
|
||||
I_Data => I_Data_3,
|
||||
O_Data => O_Data_3
|
||||
);
|
||||
end generate;
|
||||
|
||||
end architecture;
|
@@ -1,3 +1,4 @@
|
||||
#NET I_CLK LOC = AG18;
|
||||
NET I_CLK LOC = B8;
|
||||
NET I_CLK TNM_NET = CLOCK;
|
||||
TIMESPEC TS_CLOCK = PERIOD CLOCK 240 MHz HIGH 50 %;
|
||||
TIMESPEC TS_CLOCK = PERIOD CLOCK 250 MHz HIGH 50 %;
|
@@ -12,67 +12,72 @@ use ieee.math_real.all;
|
||||
entity Pipeline_pb is
|
||||
generic (
|
||||
--@ Number of pipeline stages
|
||||
G_PipelineStages : integer := 3;
|
||||
G_PipelineStages : integer := 10;
|
||||
--@ Data width
|
||||
G_Width : integer := 32;
|
||||
G_Width : integer := 32;
|
||||
--@ Register balancing attribute<br>
|
||||
--@ - "no" : No register balancing <br>
|
||||
--@ - "yes": Register balancing in both directions <br>
|
||||
--@ - "forward": Moves a set of FFs at the inputs of a LUT to a single FF at its output. <br>
|
||||
--@ - "backward": Moves a single FF at the output of a LUT to a set of FFs at its inputs.
|
||||
G_RegisterBalancing : string := "yes"
|
||||
G_RegisterBalancing : string := "yes"
|
||||
);
|
||||
port (
|
||||
I_CLK : in std_logic;
|
||||
I_RST : in std_logic;
|
||||
I_CE : in std_logic;
|
||||
I_Data : in std_logic_vector(G_Width - 1 downto 0);
|
||||
I_Valid : in std_logic;
|
||||
I_CLK : in std_logic;
|
||||
I_RST : in std_logic;
|
||||
I_CE : in std_logic;
|
||||
I_Data : in std_logic_vector(G_Width - 1 downto 0);
|
||||
I_Valid : in std_logic;
|
||||
O_Ready : out std_logic;
|
||||
O_Data : out std_logic_vector(G_Width - 1 downto 0);
|
||||
O_Valid : out std_logic;
|
||||
I_Ready : in std_logic
|
||||
I_Ready : in std_logic
|
||||
);
|
||||
end entity Pipeline_pb;
|
||||
|
||||
architecture RTL of Pipeline_pb is
|
||||
-- Keep attribute: Prevents the synthesis tool from removing the entity if is "true".
|
||||
attribute keep : string;
|
||||
attribute keep : string;
|
||||
-- IOB attribute: Attaches the FF to the IOB if is "true".
|
||||
attribute IOB : string;
|
||||
attribute IOB : string;
|
||||
|
||||
-- General Interace
|
||||
signal R_RST : std_logic;
|
||||
signal R_CE : std_logic;
|
||||
signal R_RST : std_logic;
|
||||
signal R_CE : std_logic;
|
||||
-- Attribute
|
||||
attribute keep of R_RST, R_CE : signal is "true";
|
||||
attribute IOB of R_RST, R_CE : signal is "false";
|
||||
attribute keep of R_RST, R_CE : signal is "true";
|
||||
attribute IOB of R_RST, R_CE : signal is "false";
|
||||
|
||||
-- Input Interface
|
||||
signal R_DataIn : std_logic_vector(G_Width - 1 downto 0);
|
||||
signal R_ValidIn : std_logic;
|
||||
signal R_ReadyOut : std_logic;
|
||||
signal R_DataIn : std_logic_vector(G_Width - 1 downto 0);
|
||||
signal R_ValidIn : std_logic;
|
||||
signal R_ReadyOut : std_logic;
|
||||
-- Attribute
|
||||
attribute keep of R_DataIn, R_ValidIn, R_ReadyOut : signal is "true";
|
||||
attribute IOB of R_DataIn, R_ValidIn, R_ReadyOut : signal is "false";
|
||||
attribute keep of R_DataIn, R_ValidIn, R_ReadyOut : signal is "true";
|
||||
attribute IOB of R_DataIn, R_ValidIn, R_ReadyOut : signal is "false";
|
||||
|
||||
-- Output Interface
|
||||
signal R_DataOut : std_logic_vector(G_Width - 1 downto 0);
|
||||
signal R_ValidOut : std_logic;
|
||||
signal R_ReadyIn : std_logic;
|
||||
signal R_DataOut : std_logic_vector(G_Width - 1 downto 0);
|
||||
signal R_ValidOut : std_logic;
|
||||
signal R_ReadyIn : std_logic;
|
||||
-- Attribute
|
||||
attribute keep of R_DataOut, R_ValidOut, R_ReadyIn : signal is "true";
|
||||
attribute IOB of R_DataOut, R_ValidOut, R_ReadyIn : signal is "false";
|
||||
|
||||
signal C_PipelineEnable : std_logic;
|
||||
signal C_Pipeline0Enable : std_logic;
|
||||
signal C_Pipeline1Enable : std_logic;
|
||||
|
||||
signal R_Valid : std_logic;
|
||||
signal R_Ready : std_logic;
|
||||
signal R_Data : std_logic_vector(G_Width - 1 downto 0);
|
||||
begin
|
||||
|
||||
BenchmarkEnvironmentFFs : process (I_CLK)
|
||||
begin
|
||||
if rising_edge(I_CLK) then
|
||||
-- General Interace
|
||||
R_RST <= I_RST;
|
||||
R_CE <= I_CE;
|
||||
R_RST <= I_RST;
|
||||
R_CE <= I_CE;
|
||||
|
||||
-- Input Interface
|
||||
R_DataIn <= I_Data;
|
||||
@@ -86,7 +91,7 @@ begin
|
||||
end if;
|
||||
end process;
|
||||
|
||||
PipelineController : entity work.PipelineController
|
||||
PipelineControllerIn : entity work.PipelineController
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_ResetActiveAt => '1'
|
||||
@@ -95,14 +100,14 @@ begin
|
||||
I_CLK => I_CLK,
|
||||
I_RST => R_RST,
|
||||
I_CE => R_CE,
|
||||
O_Enable => C_PipelineEnable,
|
||||
O_Enable => C_Pipeline0Enable,
|
||||
I_Valid => R_ValidIn,
|
||||
O_Ready => R_ReadyOut,
|
||||
O_Valid => R_ValidOut,
|
||||
I_Ready => R_ReadyIn
|
||||
O_Valid => R_Valid,
|
||||
I_Ready => R_Ready
|
||||
);
|
||||
|
||||
PipelineRegister : entity work.PipelineRegister
|
||||
PipelineRegisterIn : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_Width,
|
||||
@@ -110,9 +115,40 @@ begin
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => C_PipelineEnable,
|
||||
I_Enable => C_Pipeline0Enable,
|
||||
I_Data => R_DataIn,
|
||||
O_Data => R_Data
|
||||
);
|
||||
|
||||
---------
|
||||
|
||||
PipelineControllerOut : entity work.PipelineController
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_ResetActiveAt => '1'
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_RST => R_RST,
|
||||
I_CE => R_CE,
|
||||
O_Enable => C_Pipeline1Enable,
|
||||
I_Valid => R_Valid,
|
||||
O_Ready => R_Ready,
|
||||
O_Valid => R_ValidOut,
|
||||
I_Ready => R_ReadyIn
|
||||
);
|
||||
|
||||
PipelineRegisterOut : entity work.PipelineRegister
|
||||
generic map(
|
||||
G_PipelineStages => G_PipelineStages,
|
||||
G_Width => G_Width,
|
||||
G_RegisterBalancing => G_RegisterBalancing
|
||||
)
|
||||
port map(
|
||||
I_CLK => I_CLK,
|
||||
I_Enable => C_Pipeline1Enable,
|
||||
I_Data => R_Data,
|
||||
O_Data => R_DataOut
|
||||
);
|
||||
|
||||
end architecture RTL;
|
||||
end architecture RTL;
|
||||
|
272
tests/PipelineFilter_tb.vhd
Normal file
272
tests/PipelineFilter_tb.vhd
Normal file
@@ -0,0 +1,272 @@
|
||||
library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
|
||||
entity PipelineFilter_tb is
|
||||
end entity PipelineFilter_tb;
|
||||
|
||||
architecture RTL of PipelineFilter_tb is
|
||||
-- Konstanten
|
||||
constant G_MaskWidth : integer := 4;
|
||||
constant G_Mask : std_logic_vector(G_MaskWidth - 1 downto 0) := "1101";
|
||||
|
||||
-- Signale für Modus "none"
|
||||
signal I_Match_none : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_none : std_logic := '0';
|
||||
signal O_Ready_none : std_logic;
|
||||
signal O_Valid_none : std_logic;
|
||||
signal I_Ready_none : std_logic := '0';
|
||||
|
||||
-- Signale für Modus "or"
|
||||
signal I_Match_or : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_or : std_logic := '0';
|
||||
signal O_Ready_or : std_logic;
|
||||
signal O_Valid_or : std_logic;
|
||||
signal I_Ready_or : std_logic := '0';
|
||||
|
||||
-- Signale für Modus "and"
|
||||
signal I_Match_and : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_and : std_logic := '0';
|
||||
signal O_Ready_and : std_logic;
|
||||
signal O_Valid_and : std_logic;
|
||||
signal I_Ready_and : std_logic := '0';
|
||||
|
||||
-- Signale für Modus "xor"
|
||||
signal I_Match_xor : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_xor : std_logic := '0';
|
||||
signal O_Ready_xor : std_logic;
|
||||
signal O_Valid_xor : std_logic;
|
||||
signal I_Ready_xor : std_logic := '0';
|
||||
|
||||
-- Signale für Modus "equal"
|
||||
signal I_Match_equal : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_equal : std_logic := '0';
|
||||
signal O_Ready_equal : std_logic;
|
||||
signal O_Valid_equal : std_logic;
|
||||
signal I_Ready_equal : std_logic := '0';
|
||||
|
||||
-- Signale für Modus "not_equal"
|
||||
signal I_Match_neq : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
|
||||
signal I_Valid_neq : std_logic := '0';
|
||||
signal O_Ready_neq : std_logic;
|
||||
signal O_Valid_neq : std_logic;
|
||||
signal I_Ready_neq : std_logic := '0';
|
||||
|
||||
begin
|
||||
|
||||
-- Instanz für Modus "none"
|
||||
UUT_none : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "none"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_none,
|
||||
I_Valid => I_Valid_none,
|
||||
O_Ready => O_Ready_none,
|
||||
O_Valid => O_Valid_none,
|
||||
I_Ready => I_Ready_none
|
||||
);
|
||||
|
||||
-- Instanz für Modus "or"
|
||||
UUT_or : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "or"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_or,
|
||||
I_Valid => I_Valid_or,
|
||||
O_Ready => O_Ready_or,
|
||||
O_Valid => O_Valid_or,
|
||||
I_Ready => I_Ready_or
|
||||
);
|
||||
|
||||
-- Instanz für Modus "and"
|
||||
UUT_and : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "and"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_and,
|
||||
I_Valid => I_Valid_and,
|
||||
O_Ready => O_Ready_and,
|
||||
O_Valid => O_Valid_and,
|
||||
I_Ready => I_Ready_and
|
||||
);
|
||||
|
||||
-- Instanz für Modus "xor"
|
||||
UUT_xor : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "xor"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_xor,
|
||||
I_Valid => I_Valid_xor,
|
||||
O_Ready => O_Ready_xor,
|
||||
O_Valid => O_Valid_xor,
|
||||
I_Ready => I_Ready_xor
|
||||
);
|
||||
|
||||
-- Instanz für Modus "equal"
|
||||
UUT_equal : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "equal"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_equal,
|
||||
I_Valid => I_Valid_equal,
|
||||
O_Ready => O_Ready_equal,
|
||||
O_Valid => O_Valid_equal,
|
||||
I_Ready => I_Ready_equal
|
||||
);
|
||||
|
||||
-- Instanz für Modus "not_equal"
|
||||
UUT_neq : entity work.PipelineFilter
|
||||
generic map(
|
||||
G_MaskWidth => G_MaskWidth,
|
||||
G_Mask => G_Mask,
|
||||
G_MaskMode => "not_equal"
|
||||
)
|
||||
port map(
|
||||
I_Match => I_Match_neq,
|
||||
I_Valid => I_Valid_neq,
|
||||
O_Ready => O_Ready_neq,
|
||||
O_Valid => O_Valid_neq,
|
||||
I_Ready => I_Ready_neq
|
||||
);
|
||||
|
||||
stimulus : process
|
||||
begin
|
||||
wait for 10 ns;
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "none" (es darf nie gefiltert werden)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: none";
|
||||
I_Ready_none <= '1';
|
||||
I_Match_none <= "1101"; -- Irgendein Wert
|
||||
I_Valid_none <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_none = '1'
|
||||
report "Fehler: Modus 'none' hat Paket gefiltert" severity error;
|
||||
I_Valid_none <= '0';
|
||||
I_Ready_none <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "or" (filtert, wenn irgendein gesetztes Bit aus Maske auch in Match ist)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: or";
|
||||
I_Ready_or <= '1';
|
||||
I_Match_or <= "0000"; -- sollte durchgelassen werden
|
||||
I_Valid_or <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_or = '1'
|
||||
report "Fehler: Paket mit 0000 wurde faelschlich gefiltert (or)" severity error;
|
||||
|
||||
I_Match_or <= "0100"; -- sollte gefiltert werden
|
||||
wait for 10 ns;
|
||||
assert O_Valid_or = '0'
|
||||
report "Fehler: Paket mit 0100 wurde nicht gefiltert (or)" severity error;
|
||||
|
||||
I_Valid_or <= '0';
|
||||
I_Ready_or <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "and" (filtert, wenn alle gesetzten Maskenbits auch in Match sind)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: and";
|
||||
I_Ready_and <= '1';
|
||||
I_Match_and <= "1101"; -- erfüllt Maske → filtern
|
||||
I_Valid_and <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_and = '0'
|
||||
report "Fehler: Paket mit 1101 wurde nicht gefiltert (and)" severity error;
|
||||
|
||||
I_Match_and <= "1001"; -- fehlt Bit 2 → durchlassen
|
||||
wait for 10 ns;
|
||||
assert O_Valid_and = '1'
|
||||
report "Fehler: Paket mit 1001 wurde faelschlich gefiltert (and)" severity error;
|
||||
|
||||
I_Valid_and <= '0';
|
||||
I_Ready_and <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "xor" (filtert, wenn sich mindestens 1 Bit unterscheidet)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: xor";
|
||||
I_Ready_xor <= '1';
|
||||
I_Match_xor <= "1101"; -- identisch → durchlassen
|
||||
I_Valid_xor <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_xor = '1'
|
||||
report "Fehler: Paket mit 1101 wurde faelschlich gefiltert (xor)" severity error;
|
||||
|
||||
I_Match_xor <= "1111"; -- Unterschied → filtern
|
||||
wait for 10 ns;
|
||||
assert O_Valid_xor = '0'
|
||||
report "Fehler: Paket mit 1111 wurde nicht gefiltert (xor)" severity error;
|
||||
|
||||
I_Valid_xor <= '0';
|
||||
I_Ready_xor <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "equal" (filtert, wenn genau gleich)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: equal";
|
||||
I_Ready_equal <= '1';
|
||||
I_Match_equal <= "1101"; -- genau gleich → filtern
|
||||
I_Valid_equal <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_equal = '0'
|
||||
report "Fehler: Paket mit 1101 wurde nicht gefiltert (equal)" severity error;
|
||||
|
||||
I_Match_equal <= "1111"; -- ungleich → durchlassen
|
||||
wait for 10 ns;
|
||||
assert O_Valid_equal = '1'
|
||||
report "Fehler: Paket mit 1111 wurde faelschlich gefiltert (equal)" severity error;
|
||||
|
||||
I_Valid_equal <= '0';
|
||||
I_Ready_equal <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Test: Modus "not_equal" (filtert, wenn ungleich)
|
||||
----------------------------------------------------------------
|
||||
report "Testmodus: not_equal";
|
||||
I_Ready_neq <= '1';
|
||||
I_Match_neq <= "1101"; -- gleich → durchlassen
|
||||
I_Valid_neq <= '1';
|
||||
wait for 10 ns;
|
||||
assert O_Valid_neq = '1'
|
||||
report "Fehler: Paket mit 1101 wurde faelschlich gefiltert (not_equal)" severity error;
|
||||
|
||||
I_Match_neq <= "1111"; -- ungleich → filtern
|
||||
wait for 10 ns;
|
||||
assert O_Valid_neq = '0'
|
||||
report "Fehler: Paket mit 1111 wurde nicht gefiltert (not_equal)" severity error;
|
||||
|
||||
I_Valid_neq <= '0';
|
||||
I_Ready_neq <= '0';
|
||||
wait for 10 ns;
|
||||
|
||||
----------------------------------------------------------------
|
||||
-- Abschluss
|
||||
----------------------------------------------------------------
|
||||
report "Alle Tests abgeschlossen." severity note;
|
||||
wait;
|
||||
end process;
|
||||
|
||||
end architecture RTL;
|
@@ -2,14 +2,21 @@ library ieee;
|
||||
use ieee.std_logic_1164.all;
|
||||
use ieee.numeric_std.all;
|
||||
use ieee.math_real.all;
|
||||
use std.env.stop;
|
||||
|
||||
entity Pipeline_tb is
|
||||
-- The testbench does not require any ports
|
||||
end entity Pipeline_tb;
|
||||
|
||||
architecture behavior of Pipeline_tb is
|
||||
shared variable seed1 : integer := 483;
|
||||
shared variable seed2 : integer := 847;
|
||||
-- Random number generator
|
||||
--@ Select a random number for `seed1` to generate random numbers
|
||||
shared variable seed1 : integer := 467;
|
||||
--@ Select a random number for `seed2` to generate random numbers
|
||||
shared variable seed2 : integer := 623;
|
||||
--@ Generate a random number between `min_val` and `max_val`
|
||||
--@ You must provide the `shared variable seed1` and `shared variable seed2` to generate random numbers.
|
||||
--@ You need `use ieee.math_real.all;` to use this function.
|
||||
impure function rand_int(min_val, max_val : integer) return integer is
|
||||
variable r : real;
|
||||
begin
|
||||
@@ -19,31 +26,31 @@ architecture behavior of Pipeline_tb is
|
||||
end function;
|
||||
|
||||
-- Clock signal period
|
||||
constant period : time := 20 ns;
|
||||
constant period : time := 20 ns;
|
||||
|
||||
-- Adjustable wait times
|
||||
constant write_delay : natural := 10; -- Maximal wait time between write operations in clock cycles
|
||||
constant read_delay : natural := 10; -- Maximal wait time between read operations in clock cycles
|
||||
constant write_delay : natural := 40; -- Maximal wait time between write operations in clock cycles
|
||||
constant read_delay : natural := 60; -- Maximal wait time between read operations in clock cycles
|
||||
|
||||
-- Setting constants for the FIFO to be tested
|
||||
constant K_Width : integer := 32; -- Data width of the FIFO
|
||||
constant K_PipelineStages : integer := 3; -- Number of pipeline stages
|
||||
constant K_RegisterBalancing : string := "yes"; -- Register balancing attribute
|
||||
constant K_Width : integer := 32; -- Data width of the FIFO
|
||||
constant K_PipelineStages : integer := 5; -- Number of pipeline stages
|
||||
constant K_RegisterBalancing : string := "yes"; -- Register balancing attribute
|
||||
|
||||
-- Testbench signals
|
||||
signal CLK : std_logic := '0';
|
||||
signal RST : std_logic := '1';
|
||||
signal CE : std_logic := '1';
|
||||
signal CLK : std_logic := '0';
|
||||
signal RST : std_logic := '1';
|
||||
signal CE : std_logic := '1';
|
||||
|
||||
signal I_Data : std_logic_vector(K_Width - 1 downto 0) := (others => 'U');
|
||||
signal I_Valid : std_logic := '0';
|
||||
signal O_Ready : std_logic;
|
||||
signal I_Data : std_logic_vector(K_Width - 1 downto 0) := (others => 'U');
|
||||
signal I_Valid : std_logic := '0';
|
||||
signal O_Ready : std_logic;
|
||||
|
||||
signal O_Data : std_logic_vector(K_Width - 1 downto 0) := (others => 'U');
|
||||
signal O_Valid : std_logic;
|
||||
signal I_Ready : std_logic := '0';
|
||||
signal O_Data : std_logic_vector(K_Width - 1 downto 0) := (others => 'U');
|
||||
signal O_Valid : std_logic;
|
||||
signal I_Ready : std_logic := '0';
|
||||
|
||||
signal PipelineEnable : std_logic;
|
||||
signal PipelineEnable : std_logic;
|
||||
begin
|
||||
|
||||
uut0 : entity work.PipelineController
|
||||
@@ -103,52 +110,69 @@ begin
|
||||
RST <= '1', '0' after 100 ns;
|
||||
|
||||
-- Write process
|
||||
Write : process (CLK)
|
||||
Write : process
|
||||
variable delay : integer := 0;
|
||||
variable i : integer := 1;
|
||||
begin
|
||||
if rising_edge(CLK) then
|
||||
if RST = '1' then
|
||||
I_Valid <= '0';
|
||||
I_Data <= (others => 'U');
|
||||
wait until RST = '0'; -- auf Reset-Ende warten
|
||||
|
||||
while true loop
|
||||
wait until rising_edge(CLK);
|
||||
|
||||
if O_Ready = '1' and delay = 0 then
|
||||
I_Data <= std_logic_vector(to_unsigned(i, K_Width));
|
||||
I_Valid <= '1';
|
||||
report "Sende Paket #" & integer'image(i) severity note;
|
||||
i := i + 1;
|
||||
delay := rand_int(1, write_delay);
|
||||
elsif O_Ready = '1' and I_Valid = '1' then
|
||||
I_Valid <= '0';
|
||||
delay := write_delay;
|
||||
i := 1;
|
||||
I_Data <= (others => 'U');
|
||||
else
|
||||
if O_Ready = '1' and delay = 0 then
|
||||
I_Data <= std_logic_vector(to_unsigned(i, K_Width)); -- Data to be written
|
||||
I_Valid <= '1';
|
||||
i := i + 1;
|
||||
delay := rand_int(1, write_delay);
|
||||
elsif O_Ready = '1' and I_Valid = '1' then
|
||||
I_Valid <= '0';
|
||||
end if;
|
||||
if delay /= 0 then
|
||||
delay := delay - 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if delay /= 0 then
|
||||
delay := delay - 1;
|
||||
end if;
|
||||
end loop;
|
||||
end process;
|
||||
|
||||
-- Read process
|
||||
Read : process (CLK)
|
||||
variable delay : integer := 0;
|
||||
Read : process
|
||||
variable delay : integer := 0;
|
||||
variable expected : integer := 1;
|
||||
variable received : integer;
|
||||
begin
|
||||
if rising_edge(CLK) then
|
||||
if RST = '1' then
|
||||
I_Ready <= '0';
|
||||
wait until RST = '0'; -- auf Reset-Ende warten
|
||||
|
||||
while true loop
|
||||
wait until rising_edge(CLK);
|
||||
wait for 1 ns;
|
||||
|
||||
if O_Valid = '1' and delay = 0 then
|
||||
I_Ready <= '1';
|
||||
|
||||
received := to_integer(unsigned(O_Data));
|
||||
if received = expected then
|
||||
report "Empfange Paket #" & integer'image(expected) severity note;
|
||||
else
|
||||
report "Fehler bei Paket #" & integer'image(expected) &
|
||||
": erwartet " & integer'image(expected) &
|
||||
", empfangen " & integer'image(received) severity error;
|
||||
stop(0);
|
||||
end if;
|
||||
|
||||
expected := expected + 1;
|
||||
delay := rand_int(1, read_delay);
|
||||
elsif O_Valid = '1' and I_Ready = '1' then
|
||||
I_Ready <= '0';
|
||||
delay := read_delay;
|
||||
else
|
||||
if O_Valid = '1' and delay = 0 then
|
||||
I_Ready <= '1'; -- Signal readiness to read
|
||||
delay := rand_int(1, read_delay);
|
||||
elsif O_Valid = '1' and I_Ready = '1' then
|
||||
I_Ready <= '0';
|
||||
end if;
|
||||
if delay /= 0 then
|
||||
delay := delay - 1;
|
||||
end if;
|
||||
end if;
|
||||
end if;
|
||||
|
||||
if delay /= 0 then
|
||||
delay := delay - 1;
|
||||
end if;
|
||||
end loop;
|
||||
end process;
|
||||
|
||||
end architecture behavior;
|
||||
|
Reference in New Issue
Block a user