Compare commits

...

10 Commits

Author SHA1 Message Date
31ce816816 Updates project configuration for PipelineFilter module 2025-04-16 17:27:48 +00:00
6c6c285e79 Optimizes pipeline and clock configuration
Refactors pipeline architecture by separating input and output stages.
Introduces additional controllers and registers for better modularity.
Aligns signal and attribute formatting for improved readability.
2025-04-16 17:27:18 +00:00
d320c31aea Adds testbench for PipelineFilter entity
Introduces a comprehensive VHDL testbench for the PipelineFilter entity, covering various mask modes ("none", "or", "and", "xor", "equal", "not_equal").
Includes signal setup, instance mapping, and test cases to validate filtering behavior for each mode.

Ensures correct functionality and highlights potential errors during simulation.
2025-04-16 17:26:29 +00:00
75ac016c9a Refines testbench logic and parameter configurations
Updates random seed values and adjusts pipeline configuration constants for improved testing flexibility. Refactors write and read processes for clarity, adding additional checks and error handling. Introduces `stop` function to terminate simulation on critical errors.

Enhances test coverage and simulation reliability.
2025-04-16 17:26:14 +00:00
9a7bffadec Adds configurable PipelineFilter with AXI-like handshake
Implements a generic VHDL entity for data filtering based on a bitmask and comparison modes.
Supports configurable filtering modes such as 'none', 'or', 'and', 'xor', 'equal', and 'not_equal'.
Integrates AXI-like valid/ready handshake for synchronous data transfer.

Ensures proper handling of unrecognized modes and validates mask size at runtime.
2025-04-16 17:25:35 +00:00
87b9bf20bf Adds configurable pipeline stage module
Introduces a VHDL entity for a configurable pipeline stage with generic parameters for data widths, reset behavior, and register balancing. Implements AXI-like handshake interfaces for input and output data management. Includes support for up to four data channels with optional pipeline registers.

Facilitates modular and reusable design for pipeline processing.
2025-04-16 17:25:17 +00:00
aae0a66fec Refactors pipeline controllers and registers for flexibility
Introduces conditional logic to handle cases with zero pipeline stages, improving adaptability.
Adds default values for generics and ports to enhance usability and reduce configuration errors.
Cleans up formatting for better readability and maintainability.

Relates to improved design modularity.
2025-04-16 17:24:51 +00:00
59e8302a48 Fix single-stage pipeline validity update issue
Enhanced the PipelineController's validity logic to handle single-stage configurations properly. This update ensures that the validity bit is correctly updated for systems that operate with only one pipeline stage, addressing a potential logic flaw in previous versions. Additionally, clarified documentation for random number generation in pipeline testbench.
2024-04-13 15:18:52 +02:00
f0c7144550 Fix the links in the readme file 2024-03-24 20:12:43 +01:00
5c9fad9cdc Add the documentation to the readme file. 2024-03-24 20:11:29 +01:00
11 changed files with 1264 additions and 181 deletions

4
.gitignore vendored
View File

@@ -1 +1,3 @@
build/working
build/working
.locale/
vhdl_ls.toml

196
README.md
View File

@@ -1 +1,195 @@
See at docs subdirectory for the documentation..
# Entity: PipelineController
- **File**: PipelineController.vhd
## Diagram
![Diagram](docs/PipelineController.svg "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
![Diagram](docs/PipelineRegister.svg "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**

View File

@@ -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 =
## ## ## ## ## ## ## ##
# ---------------------

View File

@@ -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
View 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;

View File

@@ -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
View 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;

View File

@@ -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 %;

View File

@@ -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
View 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;

View File

@@ -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;