Compare commits

...

26 Commits

Author SHA1 Message Date
81524edd18 feat(vscode): add custom color theme settings 2025-07-18 19:19:57 +02:00
40df0e3e65 refactor(module): improve naming consistency in pipeline components 2025-07-18 19:19:23 +02:00
30d00812c1 chore(devcontainer): updates image and configuration
- Updates the devcontainer image to a newer version.
- Modifies the GPG agent path for consistency.
- Adds the WakaTime extension for tracking development time.
- Updates the postStartCommand to install hdlbuild from a
  private package repository.
2025-07-15 14:58:21 +00:00
a143e8a1aa refactor: Simplifies ready signal logic in buffer controller
- Removes redundant signal and assigns directly to output.
- Simplifies the state update logic for the ready signal.
2025-07-11 10:52:06 +00:00
506f2edabb fix: Corrects ready signal and data buffering logic
- Corrects the ready signal to properly reflect buffer status.
- Modifies data buffering logic to ensure proper data handling.
- Updates the ready signal to high when buffer is not full.
2025-07-11 10:17:37 +00:00
5e1a3c2161 refactor: adjusts pipeline parameters for performance
- Changes clock frequency to 280 MHz.
- Reduces pipeline module count to improve performance.
2025-07-11 10:15:49 +00:00
88753b62f4 feat: implements pipelined module chaining for performance
- Introduces a pipelined module and top-level wrapper for
  performance benchmarking.
- Chains multiple pipeline modules in series to increase throughput.
- Adds generics to control pipeline depth, data width, and
  register balancing.
- Includes optional CE/RST enables and pipeline buffer.
2025-07-11 10:05:02 +00:00
96833c0f77 test: Updates waveform configuration for testbench
- Corrects signal names in the waveform configuration file.
- Adds individual bit signals for output data.
2025-07-11 10:03:32 +00:00
caff24255d Refactor: Reduces maximum fanout for nets
- Reduces the maximum allowed fanout value to improve timing
  closure.
- This change aims to optimize resource utilization.
2025-07-11 10:03:18 +00:00
c51815cb51 Updates devcontainer.json to add volume mapping for GPG agent and formats the configuration for clarity 2025-04-27 19:01:34 +00:00
d847fe3dc8 Updates .gitignore to include build directories for improved project management 2025-04-27 19:01:24 +00:00
cb5259c284 Refactors project.yml to clarify dependencies and improve tool options formatting 2025-04-27 19:01:08 +00:00
c74b34f610 Adds devcontainer configuration and updates project structure to hdlbuild 2025-04-27 17:46:05 +00:00
454172e91c Standardizes formatting and adds output signal
Adjusts entity and architecture formatting for consistency, aligning spacing and indentation across declarations and constants.

Adds `O_MUX_Select` output signal to indicate routing decision, improving functionality and clarity of the module.
2025-04-24 18:29:53 +00:00
3a588948a6 Adds PipelineSwitch entity and testbench
Introduces the PipelineSwitch component with configurable routing behavior based on input comparison modes. Implements modes such as "none", "or", "and", "xor", "equal", and others. Adds a comprehensive testbench to validate functionality across all supported modes.
2025-04-19 20:39:29 +00:00
286ae5a12c Adds pipeline buffer and controller with testbench
Implements a pipeline buffer component supporting passthrough and register modes, controlled via a dedicated controller.
Adds AXI-like handshake signals for data flow management.
Includes a testbench to validate functionality with randomized delays.

Addresses robust data buffering and flow control.
2025-04-19 20:39:13 +00:00
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
24 changed files with 2779 additions and 314 deletions

View File

@@ -0,0 +1,31 @@
{
"name": "Xilinx ISE 14.7",
"image": "git.0xmax42.io/simdev/xilinx-ise:latest",
"runArgs": [
"--privileged",
"--cap-add=SYS_ADMIN",
"--shm-size=2g",
"-v",
"/run/user/1000/gnupg/S.gpg-agent:/home/xilinx/.gnupg/S.gpg-agent"
],
"customizations": {
"vscode": {
"extensions": [
"/home/xilinx/vsxirepo/vhdl-by-hgb.vsix",
"eamodio.gitlens",
"WakaTime.vscode-wakatime"
],
"settings": {
"terminal.integrated.defaultProfile.linux": "bash"
}
}
},
"remoteUser": "xilinx",
"workspaceMount": "source=${localWorkspaceFolder},target=/workspaces/${localWorkspaceFolderBasename},type=bind",
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}",
"features": {},
"forwardPorts": [
10000
],
"postStartCommand": "git config --global user.signingkey 87C8A5DD5C14DF55DBE1DB4199AC216D447E61C0 && git config --global gpg.format openpgp && git config --global commit.gpgsign true && git config --global tag.forceSignAnnotated true && pip install --upgrade --index-url https://git.0xmax42.io/api/packages/maxp/pypi/simple/ --extra-index-url https://pypi.org/simple/ hdlbuild"
}

7
.gitignore vendored
View File

@@ -1 +1,6 @@
build/working
.hdlbuild_deps/
.working/
reports/
output/
.locale/
vhdl_ls.toml

3
.gitmodules vendored
View File

@@ -1,3 +0,0 @@
[submodule "build"]
path = build
url = https://github.com/PxaMMaxP/Xilinx-ISE-Makefile.git

12
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,12 @@
{
"workbench.colorCustomizations": {
"activityBar.activeBackground": "#9ed8bc",
"activityBar.background": "#9ed8bc",
"activityBar.foreground": "#15202b",
"activityBar.inactiveForeground": "#15202b99",
"activityBarBadge.background": "#a177c8",
"activityBarBadge.foreground": "#15202b"
},
"peacock.color": "#7ac9a3",
"peacock.remoteColor": "#e67338"
}

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**

1
build

Submodule build deleted from a8ed470e7d

View File

View File

@@ -1,91 +0,0 @@
## Main settings.. ##
# Project name
# @remark The name of the project is used as default name for the top module and the ucf file
PROJECT = Pipeline
# Target device
# @example xc3s1200e-4-fg320 | xc5vlx50t-1-ff1136
TARGET_PART = xc3s1200e-4-fg320
# Path to the Xilinx ISE installation
XILINX = /opt/Xilinx/14.7/ISE_DS/ISE
# Optional the name of the top module (default is the project name)
TOPLEVEL = Pipeline_pb
# Optional the name of the ucf file (default is the project name)
CONSTRAINTS = src/Pipeline_pb.ucf
## ## ## ## ## ## ## ##
# ---------------------
## Source files settings.. ##
# The source files to be compiled
# @example `VSOURCE += src/main.v` (add a single Verilog file per line)
# @example `VHDSOURCE += src/main.vhd` (add a single VHDL file per line)
VHDSOURCE += src/Pipeline_pb.vhd
VHDSOURCE += src/PipelineController.vhd
VHDSOURCE += src/PipelineRegister.vhd
VHDTEST += tests/Pipeline_tb.vhd
## ## ## ## ## ## ## ##
# ---------------------
## ISE executable settings.. ##
# 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
# Options for the NGDBuild tool
# NGDBUILD_OPTS =
# Options for the MAP tool
# @example -mt 2 (multi-threading with 2 threads)
MAP_OPTS = -cm speed -ol high -detail -timing
# Options for the PAR tool
# @example -mt 2 (multi-threading with 2 threads)
PAR_OPTS = -ol high
# Options for the BitGen tool
# @example -g Compress (compress bitstream)
# @example -g StartupClk:Cclk (specify the startup clock to onboard clock)
# @example -g StartupClk:JtagClk (specify the startup clock to JTAG clock)
# BITGEN_OPTS =
# Options for the Trace tool
# TRACE_OPTS =
# Options for the Fuse tool
# FUSE_OPTS =
ISIM_CMD =
## ## ## ## ## ## ## ##
# ---------------------
## Programmer settings.. ##
# The programmer to use
# @example impact | digilent | xc3sprog
# @remark impact is the default Xilinx programmer and you must create a impact.cmd file in the root directory..
PROGRAMMER =
## Digilent JTAG cable settings
# @remark Use the `djtgcfg enum` command to list all available devices
# DJTG_DEVICE = DOnbUsb
# The index of the JTAG device for the `prog` target
# DJTG_INDEX = 0
# The index of the flash device for the `flash` target
# DJTG_FLASH_INDEX = 1
## ## ## ## ## ## ## ##
# ---------------------

268
project.yml Normal file
View File

@@ -0,0 +1,268 @@
name: Pipeline-AXI-Handshake
topmodule: Pipeline_pb
target_device: xc3s1200e-4-fg320
xilinx_path: /opt/Xilinx/14.7/ISE_DS/ISE
sources:
vhdl:
- path: src/*.vhd
library: work
constraints: src/Pipeline_pb.ucf
testbenches:
vhdl:
- path: tests/*.vhd
library: work
dependencies:
# - git: "https://git.0xmax42.io/maxp/Asynchronous-FIFO-AXI-Handshake.git"
# rev: "hdlbuild"
build:
build_dir: working
report_dir: reports
copy_target_dir: output
# Tool Optionen
tool_options:
common:
- "-intstyle"
- "xflow"
ngdbuild: []
map:
- "-detail"
- "-timing"
- "-ol"
- "high"
par: []
bitgen:
- "-g"
- "StartupClk:JtagClk"
trace:
- "-v"
- "3"
- "-n"
- "3"
fuse:
- "-incremental"
isim:
- "-gui"
xst:
# Optimization goal: prioritize speed or area.
# Values: Speed | Area
- "-opt_mode Speed"
# Optimization level: more aggressive optimizations at level 2.
# Values: 1 | 2
- "-opt_level 2"
# Use the new XST parser (recommended for modern designs).
# Values: yes | no
- "-use_new_parser yes"
# Preserve design hierarchy or allow flattening for optimization.
# Values: Yes | No | Soft
- "-keep_hierarchy No"
# Determines how hierarchy is preserved in the netlist.
# Values: As_Optimized | Rebuilt
- "-netlist_hierarchy As_Optimized"
# Global optimization strategy for nets.
# Values: AllClockNets | Offset_In_Before | Offset_Out_After | Inpad_To_Outpad | Max_Delay
- "-glob_opt AllClockNets"
## Misc ##
# Enable reading of IP cores.
# Values: YES | NO
- "-read_cores YES"
# Do not write timing constraints into synthesis report.
# Values: YES | NO
- "-write_timing_constraints NO"
# Analyze paths across different clock domains.
# Values: YES | NO
- "-cross_clock_analysis NO"
# Character used to separate hierarchy levels in instance names.
# Default: /
- "-hierarchy_separator /"
# Delimiters used for bus signals.
# Values: <> | [] | () | {}
- "-bus_delimiter <>"
# Maintain original case of identifiers.
# Values: Maintain | Upper | Lower
- "-case Maintain"
# Target maximum utilization ratio for slices.
# Values: 1–100
- "-slice_utilization_ratio 100"
# Target maximum utilization ratio for BRAMs.
# Values: 1–100
- "-bram_utilization_ratio 100"
# Use Verilog 2001 syntax features.
# Values: YES | NO
- "-verilog2001 YES"
#### HDL Options ####
## FSM ##
# Extract FSMs (Finite State Machines) from HDL code.
# Values: YES | NO
- "-fsm_extract YES"
# Encoding strategy for FSMs.
# Values: Auto | Gray | One-Hot | Johnson | Compact | Sequential | Speed1 | User
- "-fsm_encoding Auto"
# Add safe logic for undefined FSM states.
# Values: Yes | No
- "-safe_implementation No"
# Structure used to implement FSMs.
# Values: LUT | BRAM
- "-fsm_style LUT"
## RAM/ROM ##
# Extract RAM inference from HDL.
# Values: Yes | No
- "-ram_extract Yes"
# Style used to implement RAM.
# Values: Auto | Block | Distributed
- "-ram_style Auto"
# Extract ROM inference from HDL.
# Values: Yes | No
- "-rom_extract Yes"
# Style used for implementing ROM.
# Values: Auto | Distributed | Block
- "-rom_style Auto"
# Enable or disable automatic BRAM packing.
# Values: YES | NO
- "-auto_bram_packing NO"
## MUX/Decoder/Shift Register ##
# Extract multiplexers where possible.
# Values: Yes | No | Force
- "-mux_extract Yes"
# Style used for implementing MUX logic.
# Values: Auto | MUXCY | MUXF
- "-mux_style Auto"
# Extract decoder logic from behavioral code.
# Values: YES | NO
- "-decoder_extract YES"
# Extract and optimize priority encoder structures.
# Values: Yes | No | Force
- "-priority_extract Yes"
# Extract shift register logic.
# Values: YES | NO
- "-shreg_extract YES"
# Extract simple shift operations into dedicated hardware.
# Values: YES | NO
- "-shift_extract YES"
## Multiplier ##
# Style for implementing multipliers.
# Values: Auto | LUT | Pipe_LUT | Pipe_Block | Block
- "-mult_style Auto"
## Misc ##
# Collapse XOR trees where beneficial.
# Values: YES | NO
- "-xor_collapse YES"
# Share resources like adders or multipliers between logic blocks.
# Values: YES | NO | Force
- "-resource_sharing YES"
# Convert asynchronous resets to synchronous where possible.
# Values: YES | NO
- "-async_to_sync NO"
#### Xilinx Specific Options ####
## Optimization ##
# Enable removal of logically equivalent registers.
# Values: YES | NO
- "-equivalent_register_removal YES"
# Duplicate registers to reduce fanout or improve timing.
# Values: YES | NO
- "-register_duplication YES"
# Move registers across logic to balance timing.
# Values: Yes | No | Forward | Backward
- "-register_balancing No"
# Use clock enable signals where possible.
# Values: Auto | Yes | No
- "-use_clock_enable Yes"
# Use synchronous set (preset) signals when available.
# Values: Auto | Yes | No
- "-use_sync_set Yes"
# Use synchronous reset signals where possible.
# Values: Auto | Yes | No
- "-use_sync_reset Yes"
## I/O ##
# Insert IO buffers for top-level ports.
# Values: YES | NO
- "-iobuf YES"
# Placement strategy for IOB registers (Auto = let tools decide).
# Values: Auto | YES | NO
- "-iob Auto"
## Misc ##
# Maximum allowed fanout for a net.
# Values: integer (e.g., 500)
- "-max_fanout 50"
# Maximum number of BUFGs (global buffers) to use.
# Values: 0–32 (device-dependent)
- "-bufg 24"
# Enable logic packing into slices.
# Values: YES | NO
- "-slice_packing YES"
# Try to reduce the number of primitive instances used.
# Values: YES | NO
- "-optimize_primitives NO"
# Margin in percent beyond the target slice utilization.
# Values: 0–100
- "-slice_utilization_ratio_maxmargin 5"

52
src/PipelineBuffer.vhd Normal file
View File

@@ -0,0 +1,52 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity PipelineBuffer is
generic (
--@ Data width
G_Width : integer := 32
);
port (
--@ Clock signal; (**Rising edge** triggered)
I_CLK : in std_logic := '0';
--@ Enable input from **Pipeline Buffer Controller**
--@ [1]: If low, data is passed through, else data is registered
--@ [0]: Enable for register
I_Enable : in std_logic_vector(1 downto 0) := (others => '0');
--@ Data input
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')
);
end entity PipelineBuffer;
architecture RTL of PipelineBuffer is
signal C_MUX : std_logic := '0';
signal C_Enable : std_logic := '0';
signal R_Data : std_logic_vector(G_Width - 1 downto 0) := (others => '0');
begin
C_MUX <= I_Enable(1);
C_Enable <= I_Enable(0);
P_MUX : process (C_MUX, I_Data, R_Data)
begin
if C_MUX = '0' then -- Passthrough mode
O_Data <= I_Data;
else -- Register mode
O_Data <= R_Data;
end if;
end process;
P_Register : process (I_CLK)
begin
if rising_edge(I_CLK) then
if C_Enable = '1' then
R_Data <= I_Data;
end if;
end if;
end process;
end architecture;

View File

@@ -0,0 +1,74 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity PipelineBufferController is
generic (
--@ Reset active at this level
G_ResetActiveAt : std_logic := '1'
);
port (
--@ Clock signal; (**Rising edge** triggered)
I_CLK : in std_logic := '0';
--@ Reset; (**Synchronous**, **Active at `G_ResetActiveAt`**)
I_RST : in std_logic := '0';
--@ Chip enable; (**Synchronous**, **Active high**)
I_CE : in std_logic := '1';
--@ [1]: If low, data is passed through, else data is registered
--@ [0]: Enable for register
O_Enable : out std_logic_vector(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 PipelineBufferController;
architecture RTL of PipelineBufferController is
signal C_MUX : std_logic := '0';
signal C_Enable : std_logic := '0';
signal R_IsBuffered : std_logic := '0';
begin
--@ Set mux to buffered mode if data is available in the buffer.
C_MUX <= R_IsBuffered;
--@ Enable the buffer register if not buffered and chip enable is high.
C_Enable <= I_CE and not R_IsBuffered;
--@ Set the valid signal to high if data is available in the buffer or if data is valid.
O_Valid <= R_IsBuffered or I_Valid;
process (I_CLK)
begin
if rising_edge(I_CLK) then
if I_RST = G_ResetActiveAt then
R_IsBuffered <= '0';
O_Ready <= '1';
elsif I_CE = '1' then
if R_IsBuffered = '0' and I_Valid = '1' then
R_IsBuffered <= '1';
O_Ready <= '0';
elsif I_Ready = '1' and (R_IsBuffered or I_Valid) = '1' then
R_IsBuffered <= '0';
O_Ready <= '1';
end if;
end if;
end if;
end process;
O_Enable(1) <= C_MUX;
O_Enable(0) <= C_Enable;
end architecture;

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;

197
src/PipelineSwitch.vhd Normal file
View File

@@ -0,0 +1,197 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity PipelineSwitch is
generic (
--@ Width of the comparison input and mask.
--@ This defines the bit width of `I_Match` and `G_Mask`.
G_MaskWidth : integer := 4;
--@ Comparison mask or reference value used to control routing.
--@ Its width must match `G_MaskWidth`.
G_Mask : std_logic_vector := "1010";
--@ Comparison mode that determines to which output the data is routed.
--@ Available modes:
--@ - `"none"`: Always route to `Default`.
--@ - `"or"`: Route to `Selected` if **any** bit in `I_Match` matches a set bit in `G_Mask`.
--@ - `"and"`: Route to `Selected` if **all** bits set in `G_Mask` are also set in `I_Match`.
--@ - `"xor"`: Route to `Selected` if **any** bit differs between `I_Match` and `G_Mask`.
--@ - `"equal"`: Route to `Selected` if `I_Match` is **bitwise equal** to `G_Mask`.
--@ - `"not_equal"`: Route to `Selected` if `I_Match` is **not equal** to `G_Mask`.
--@ - `"gt"`: Route to `Selected` if `I_Match` **>** `G_Mask` (unsigned).
--@ - `"ge"`: Route to `Selected` if `I_Match` **≥** `G_Mask`.
--@ - `"lt"`: Route to `Selected` if `I_Match` **<** `G_Mask`.
--@ - `"le"`: Route to `Selected` if `I_Match` **≤** `G_Mask`.
G_MaskMode : string := "equal"
);
port (
--@ Input value to be compared against `G_Mask` to determine routing.
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
--@ If `1`, route to `Selected` output; if `0`, route to `Default` output.
O_MUX_Select : out std_logic := '0';
--@ @virtualbus AXI-Flags-Out @dir Out Output interface for unmatched routing
--@ Activated when the comparison **fails**.
--@ AXI-like valid; (**Synchronous**, **Active high**)
O_Default_Valid : out std_logic := '0';
--@ AXI-like ready; (**Synchronous**, **Active high**)
I_Default_Ready : in std_logic := '0';
--@ @end
--@ @virtualbus AXI-Flags-Out @dir Out Output interface for matched routing
--@ Activated when the comparison **succeeds**.
--@ AXI-like valid; (**Synchronous**, **Active high**)
O_Selected_Valid : out std_logic := '0';
--@ AXI-like ready; (**Synchronous**, **Active high**)
I_Selected_Ready : in std_logic := '0'
--@ @end
);
end entity PipelineSwitch;
architecture RTL of PipelineSwitch 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";
constant K_Mode_GT : string := "gt";
constant K_Mode_GE : string := "ge";
constant K_Mode_LT : string := "lt";
constant K_Mode_LE : string := "le";
signal C_ShouldRouteToSelected : 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 condition: Always route to Default
C_ShouldRouteToSelected <= '0';
elsif strings_equal(G_MaskMode, K_Mode_OR) then
--@ Route to Selected if any bit in I_Match is also set in G_Mask
if (I_Match and G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_XOR) then
--@ Route to Selected if any bit differs between I_Match and G_Mask
if (I_Match xor G_Mask) /= (G_MaskWidth - 1 downto 0 => '0') then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_AND) then
--@ Route to Selected if all bits set in G_Mask are also set in I_Match
if (I_Match and G_Mask) = G_Mask then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_Equal) then
--@ Route to Selected if I_Match is exactly equal to G_Mask
if I_Match = G_Mask then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_NotEqual) then
--@ Route to Selected if I_Match is not equal to G_Mask
if I_Match /= G_Mask then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_GT) then
--@ Route to Selected if I_Match > G_Mask (interpreted as unsigned)
if unsigned(I_Match) > unsigned(G_Mask) then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_GE) then
--@ Route to Selected if I_Match >= G_Mask (unsigned)
if unsigned(I_Match) >= unsigned(G_Mask) then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_LT) then
--@ Route to Selected if I_Match < G_Mask (unsigned)
if unsigned(I_Match) < unsigned(G_Mask) then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
elsif strings_equal(G_MaskMode, K_Mode_LE) then
--@ Route to Selected if I_Match <= G_Mask (unsigned)
if unsigned(I_Match) <= unsigned(G_Mask) then
C_ShouldRouteToSelected <= '1';
else
C_ShouldRouteToSelected <= '0';
end if;
else
--@ Unknown comparison mode: fallback to Default
C_ShouldRouteToSelected <= '0';
end if;
end process;
process (I_Valid, I_Default_Ready, I_Selected_Ready, C_ShouldRouteToSelected)
begin
if C_ShouldRouteToSelected = '1' then
-- Route to Selected
O_Selected_Valid <= I_Valid;
O_Default_Valid <= '0';
O_Ready <= I_Selected_Ready;
else
-- Route to Default
O_Selected_Valid <= '0';
O_Default_Valid <= I_Valid;
O_Ready <= I_Default_Ready;
end if;
end process;
O_MUX_Select <= C_ShouldRouteToSelected;
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 280 MHz HIGH 50 %;

View File

@@ -11,108 +11,153 @@ use ieee.math_real.all;
entity Pipeline_pb is
generic (
--@ Number of pipeline stages
G_PipelineStages : integer := 3;
--@ Number of pipeline stages inside each module
G_PipelineStages : integer := 2;
--@ Data width
G_Width : integer := 32;
G_Width : integer := 8;
--@ 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";
--@ Enable pipeline buffer
--@ - true : Use pipeline buffer
--@ - false : Direct connection (bypass)
G_EnablePipelineBuffer : boolean := true;
--@ How many Pipeline modules shall be chained?
G_PipelineModules : integer := 20;
--@ Enable chip enable signal
G_Enable_CE : boolean := false;
--@ Enable reset signal
G_Enable_RST : boolean := false
);
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 helpers
---------------------------------------------------------------------------
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;
-- Attribute
---------------------------------------------------------------------------
-- Bench‐wrapper FFs (synchronous IO)
---------------------------------------------------------------------------
signal R_RST : std_logic := '0';
signal R_CE : std_logic := '1';
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;
-- 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";
signal R_DataIn : std_logic_vector(G_Width-1 downto 0);
signal R_ValidIn : std_logic;
attribute keep of R_DataIn, R_ValidIn : signal is "true";
attribute IOB of R_DataIn, R_ValidIn : 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;
-- Attribute
signal R_DataOut : std_logic_vector(G_Width-1 downto 0);
signal R_ValidOut : std_logic;
signal R_ReadyIn : std_logic;
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;
begin
---------------------------------------------------------------------------
-- Chaining arrays (sentinel element @0 and @G_PipelineModules)
---------------------------------------------------------------------------
type T_DataArray is array(0 to G_PipelineModules) of std_logic_vector(G_Width-1 downto 0);
BenchmarkEnvironmentFFs : process (I_CLK)
signal S_Data : T_DataArray;
signal S_Valid : std_logic_vector(0 to G_PipelineModules);
signal S_Ready : std_logic_vector(0 to G_PipelineModules);
begin
GEN_Enable_CE : if G_Enable_CE = true generate
process(I_CLK)
begin
if rising_edge(I_CLK) then
R_CE <= I_CE;
end if;
end process;
end generate GEN_Enable_CE;
GEN_Enable_RST : if G_Enable_RST = true generate
process(I_CLK)
begin
if rising_edge(I_CLK) then
R_RST <= I_RST;
end if;
end process;
end generate GEN_Enable_RST;
-----------------------------------------------------------------------
-- Wrapper FFs: register all top‑level ports once for fair timing
-----------------------------------------------------------------------
BenchFF : process(I_CLK)
begin
if rising_edge(I_CLK) then
-- General Interace
R_RST <= I_RST;
R_CE <= I_CE;
-- Input Interface
R_DataIn <= I_Data;
R_ValidIn <= I_Valid;
O_Ready <= R_ReadyOut;
-- Output Interface
O_Data <= R_DataOut;
O_Valid <= R_ValidOut;
R_ReadyIn <= I_Ready;
--- Register inputs
R_DataIn <= I_Data;
R_ValidIn <= I_Valid;
O_Ready <= S_Ready(0);
--- Register outputs
R_DataOut <= S_Data (G_PipelineModules);
R_ValidOut <= S_Valid(G_PipelineModules);
R_ReadyIn <= I_Ready;
end if;
end process;
PipelineController : 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_PipelineEnable,
I_Valid => R_ValidIn,
O_Ready => R_ReadyOut,
O_Valid => R_ValidOut,
I_Ready => R_ReadyIn
);
O_Data <= R_DataOut;
O_Valid <= R_ValidOut;
PipelineRegister : 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_PipelineEnable,
I_Data => R_DataIn,
O_Data => R_DataOut
);
-----------------------------------------------------------------------
-- Bind sentinel 0 with registered inputs
-----------------------------------------------------------------------
S_Data (0) <= R_DataIn;
S_Valid(0) <= R_ValidIn;
end architecture RTL;
-----------------------------------------------------------------------
-- Bind last sentinel with registered outputs
-----------------------------------------------------------------------
S_Ready(G_PipelineModules) <= R_ReadyIn;
-----------------------------------------------------------------------
-- Generate N pipeline modules in series
-----------------------------------------------------------------------
gen_modules : for i in 0 to G_PipelineModules-1 generate
P_MOD : entity work.Pipeline_pb_Module
generic map(
G_PipelineStages => G_PipelineStages,
G_Width => G_Width,
G_RegisterBalancing => G_RegisterBalancing,
G_EnablePipelineBuffer => G_EnablePipelineBuffer
)
port map(
I_CLK => I_CLK,
I_RST => R_RST,
I_CE => R_CE,
-- Up‑stream side
I_Data => S_Data (i),
I_Valid => S_Valid(i),
O_Ready => S_Ready(i),
-- Down‑stream side
O_Data => S_Data (i+1),
O_Valid => S_Valid(i+1),
I_Ready => S_Ready(i+1)
);
end generate gen_modules;
end architecture RTL;

124
src/Pipeline_pb_Module.vhd Normal file
View File

@@ -0,0 +1,124 @@
--@ Performance Benchmarking Environment
--@ This file is a wrapper for the module which is to be tested
--@ and capsulates the module with flip-flops to create a synchronous
--@ interface for the module. This is necessary to test the synthesis
--@ results of the module.
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity Pipeline_pb_Module is
generic (
--@ Number of pipeline stages
G_PipelineStages : integer := 10;
--@ Data width
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 := "no";
--@ Enable pipeline buffer
--@ - true : Use pipeline buffer
--@ - false : Direct connection (bypass)
G_EnablePipelineBuffer : boolean := false
);
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;
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
);
end entity Pipeline_pb_Module;
architecture RTL of Pipeline_pb_Module is
signal C_PipelineEnable : std_logic;
signal C_PipelineBufferEnable : std_logic_vector(1 downto 0) := (others => '0');
signal R_Valid : std_logic;
signal R_Ready : std_logic;
signal R_Data : std_logic_vector(G_Width - 1 downto 0);
signal C_Data : std_logic_vector(G_Width - 1 downto 0);
begin
INST_PipelineControllerIn : entity work.PipelineController
generic map(
G_PipelineStages => G_PipelineStages,
G_ResetActiveAt => '1'
)
port map(
I_CLK => I_CLK,
I_RST => I_RST,
I_CE => I_CE,
O_Enable => C_PipelineEnable,
I_Valid => I_Valid,
O_Ready => O_Ready,
O_Valid => R_Valid,
I_Ready => R_Ready
);
INST_PipelineRegisterIn : 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_PipelineEnable,
I_Data => I_Data,
O_Data => R_Data
);
---------
C_Data <= std_logic_vector(unsigned(R_Data) + 3); -- Example operation, can be replaced with actual logic
---------
-- Pipeline Buffer Generation based on G_EnablePipelineBuffer
GEN_PipelineBuffer : if G_EnablePipelineBuffer generate
INST_PipelineBufferController : entity work.PipelineBufferController
generic map(
G_ResetActiveAt => '1'
)
port map(
I_CLK => I_CLK,
I_RST => I_RST,
I_CE => I_CE,
O_Enable => C_PipelineBufferEnable,
I_Valid => R_Valid,
O_Ready => R_Ready,
O_Valid => O_Valid,
I_Ready => I_Ready
);
INST_PipelineBuffer : entity work.PipelineBuffer
generic map(
G_Width => G_Width
)
port map(
I_CLK => I_CLK,
I_Enable => C_PipelineBufferEnable,
I_Data => C_Data,
O_Data => O_Data
);
end generate GEN_PipelineBuffer;
-- Direct connection when pipeline buffer is disabled
GEN_PassthroughWithoutBuffer : if not G_EnablePipelineBuffer generate
O_Valid <= R_Valid;
O_Data <= R_Data;
R_Ready <= I_Ready;
end generate GEN_PassthroughWithoutBuffer;
end architecture RTL;

169
tests/PipelineBuffer_tb.vhd Normal file
View File

@@ -0,0 +1,169 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
use std.env.stop;
entity PipelineBuffer_tb is
end entity PipelineBuffer_tb;
architecture RTL of PipelineBuffer_tb is
-- Clock signal period
constant K_Period : time := 20 ns;
-- Zufallsverzögerungen
constant K_WriteDelay : natural := 40;
constant K_ReadDelay : natural := 60;
-- Konstanten
constant G_ResetActiveAt : std_logic := '1';
constant G_Width : integer := 32;
-- Zufalls-Seed
shared variable seed1 : integer := 42;
shared variable seed2 : integer := 1337;
-- Randomfunktion
impure function rand_int(min_val, max_val : integer) return integer is
variable r : real;
begin
uniform(seed1, seed2, r);
return integer(round(r * real(max_val - min_val + 1) + real(min_val) - 0.5));
end function;
-- Signale
signal I_CLK : std_logic := '0';
signal I_RST : std_logic := '1';
signal I_CE : std_logic := '1';
signal O_Enable : std_logic_vector(1 downto 0) := (others => '0');
signal I_Valid : std_logic := '0';
signal O_Ready : std_logic := '0';
signal O_Valid : std_logic := '0';
signal I_Ready : std_logic := '0';
signal I_Data : std_logic_vector(G_Width - 1 downto 0) := (others => 'U');
signal O_Data : std_logic_vector(G_Width - 1 downto 0) := (others => 'U');
begin
-- Clock
Clocking : process
begin
while true loop
I_CLK <= '0';
wait for (K_Period / 2);
I_CLK <= '1';
wait for (K_Period / 2);
end loop;
end process;
-- Reset
I_RST <= G_ResetActiveAt, not G_ResetActiveAt after 100 ns;
-- DUT: Controller
i_PipelineBufferController : entity work.PipelineBufferController
generic map(
G_ResetActiveAt => G_ResetActiveAt
)
port map(
I_CLK => I_CLK,
I_RST => I_RST,
I_CE => I_CE,
O_Enable => O_Enable,
I_Valid => I_Valid,
O_Ready => O_Ready,
O_Valid => O_Valid,
I_Ready => I_Ready
);
-- DUT: Register
i_PipelineBuffer : entity work.PipelineBuffer
generic map(
G_Width => G_Width
)
port map(
I_CLK => I_CLK,
I_Enable => O_Enable,
I_Data => I_Data,
O_Data => O_Data
);
-- Write Stimulus
Stim_Write : process
variable delay : integer := 0;
variable i : integer := 1;
variable pending : boolean := false;
begin
I_Valid <= '0';
I_Data <= (others => 'U');
wait until I_RST = '0';
while true loop
wait until rising_edge(I_CLK);
-- Neues Paket vorbereiten
if not pending and delay = 0 then
I_Data <= std_logic_vector(to_unsigned(i, G_Width));
I_Valid <= '1';
pending := true;
report "Sende Paket #" & integer'image(i) severity note;
end if;
-- Handshake erfolgt
if O_Ready = '1' and I_Valid = '1' then
I_Valid <= '0';
i := i + 1;
delay := rand_int(1, K_WriteDelay);
pending := false;
end if;
-- Verzögerung herunterzählen
if delay > 0 and not pending then
delay := delay - 1;
end if;
end loop;
end process;
-- Read Stimulus (robust)
Stim_Read : process
variable delay : integer := 0;
variable expected : integer := 1;
variable received : integer;
variable consume_now : boolean := false;
begin
I_Ready <= '0';
wait until I_RST = '0';
while true loop
wait until rising_edge(I_CLK);
-- Wenn O_Valid vorhanden und kein Delay mehr: jetzt lesen
if O_Valid = '1' and delay = 0 and not consume_now then
I_Ready <= '1';
consume_now := true; -- Warte auf nächste Gültigkeit
end if;
-- Sobald Handshake erfolgt (O_Valid & I_Ready), auswerten
if O_Valid = '1' and I_Ready = '1' and consume_now then
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;
end if;
expected := expected + 1;
delay := rand_int(1, K_ReadDelay);
consume_now := false;
I_Ready <= '0';
end if;
-- Wartezeit herunterzählen
if delay > 0 and not consume_now then
delay := delay - 1;
end if;
end loop;
end process;
end architecture RTL;

View File

@@ -0,0 +1,237 @@
<?xml version="1.0" encoding="UTF-8"?>
<wave_config>
<wave_state>
</wave_state>
<db_ref_list>
<db_ref path="./isim.wdb" id="1" type="auto">
<top_modules>
<top_module name="env" />
<top_module name="glbl" />
<top_module name="math_real" />
<top_module name="numeric_std" />
<top_module name="pipelinebuffer_tb" />
<top_module name="std_logic_1164" />
</top_modules>
</db_ref>
</db_ref_list>
<WVObjectSize size="12" />
<wvobject fp_name="/pipelinebuffer_tb/i_clk" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">i_clk</obj_property>
<obj_property name="ObjectShortName">i_clk</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_rst" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">i_rst</obj_property>
<obj_property name="ObjectShortName">i_rst</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_ce" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">i_ce</obj_property>
<obj_property name="ObjectShortName">i_ce</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_enable" type="array" db_ref_id="1">
<obj_property name="ElementShortName">o_enable[1:0]</obj_property>
<obj_property name="ObjectShortName">o_enable[1:0]</obj_property>
<wvobject fp_name="/pipelinebuffer_tb/o_enable[1]" type="logic" db_ref_id="1">
<obj_property name="DisplayName">label</obj_property>
<obj_property name="ElementShortName">[1]</obj_property>
<obj_property name="ObjectShortName">o_enable[1]</obj_property>
<obj_property name="label">MUX</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_enable[0]" type="logic" db_ref_id="1">
<obj_property name="DisplayName">label</obj_property>
<obj_property name="ElementShortName">[0]</obj_property>
<obj_property name="ObjectShortName">o_enable[0]</obj_property>
<obj_property name="label">Enable</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_valid" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">i_valid</obj_property>
<obj_property name="ObjectShortName">i_valid</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_ready" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">o_ready</obj_property>
<obj_property name="ObjectShortName">o_ready</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_data" type="array" db_ref_id="1">
<obj_property name="ElementShortName">i_data[31:0]</obj_property>
<obj_property name="ObjectShortName">i_data[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
<wvobject fp_name="divider12" type="divider">
<obj_property name="label">Out</obj_property>
<obj_property name="DisplayName">label</obj_property>
<obj_property name="BkColor">128 128 255</obj_property>
<obj_property name="TextColor">230 230 230</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_valid" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">o_valid</obj_property>
<obj_property name="ObjectShortName">o_valid</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_ready" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">i_ready</obj_property>
<obj_property name="ObjectShortName">i_ready</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data" type="array" db_ref_id="1">
<obj_property name="ElementShortName">o_data[31:0]</obj_property>
<obj_property name="ObjectShortName">o_data[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
<wvobject fp_name="/pipelinebuffer_tb/o_data[31]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[31]</obj_property>
<obj_property name="ObjectShortName">o_data[31]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[30]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[30]</obj_property>
<obj_property name="ObjectShortName">o_data[30]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[29]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[29]</obj_property>
<obj_property name="ObjectShortName">o_data[29]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[28]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[28]</obj_property>
<obj_property name="ObjectShortName">o_data[28]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[27]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[27]</obj_property>
<obj_property name="ObjectShortName">o_data[27]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[26]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[26]</obj_property>
<obj_property name="ObjectShortName">o_data[26]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[25]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[25]</obj_property>
<obj_property name="ObjectShortName">o_data[25]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[24]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[24]</obj_property>
<obj_property name="ObjectShortName">o_data[24]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[23]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[23]</obj_property>
<obj_property name="ObjectShortName">o_data[23]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[22]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[22]</obj_property>
<obj_property name="ObjectShortName">o_data[22]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[21]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[21]</obj_property>
<obj_property name="ObjectShortName">o_data[21]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[20]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[20]</obj_property>
<obj_property name="ObjectShortName">o_data[20]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[19]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[19]</obj_property>
<obj_property name="ObjectShortName">o_data[19]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[18]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[18]</obj_property>
<obj_property name="ObjectShortName">o_data[18]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[17]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[17]</obj_property>
<obj_property name="ObjectShortName">o_data[17]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[16]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[16]</obj_property>
<obj_property name="ObjectShortName">o_data[16]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[15]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[15]</obj_property>
<obj_property name="ObjectShortName">o_data[15]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[14]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[14]</obj_property>
<obj_property name="ObjectShortName">o_data[14]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[13]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[13]</obj_property>
<obj_property name="ObjectShortName">o_data[13]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[12]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[12]</obj_property>
<obj_property name="ObjectShortName">o_data[12]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[11]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[11]</obj_property>
<obj_property name="ObjectShortName">o_data[11]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[10]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[10]</obj_property>
<obj_property name="ObjectShortName">o_data[10]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[9]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[9]</obj_property>
<obj_property name="ObjectShortName">o_data[9]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[8]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[8]</obj_property>
<obj_property name="ObjectShortName">o_data[8]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[7]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[7]</obj_property>
<obj_property name="ObjectShortName">o_data[7]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[6]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[6]</obj_property>
<obj_property name="ObjectShortName">o_data[6]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[5]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[5]</obj_property>
<obj_property name="ObjectShortName">o_data[5]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[4]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[4]</obj_property>
<obj_property name="ObjectShortName">o_data[4]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[3]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[3]</obj_property>
<obj_property name="ObjectShortName">o_data[3]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[2]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[2]</obj_property>
<obj_property name="ObjectShortName">o_data[2]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[1]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[1]</obj_property>
<obj_property name="ObjectShortName">o_data[1]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/o_data[0]" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">[0]</obj_property>
<obj_property name="ObjectShortName">o_data[0]</obj_property>
</wvobject>
</wvobject>
<wvobject fp_name="group15" type="group">
<obj_property name="label">Buffer</obj_property>
<obj_property name="DisplayName">label</obj_property>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/i_enable" type="array" db_ref_id="1">
<obj_property name="ElementShortName">i_enable[1:0]</obj_property>
<obj_property name="ObjectShortName">i_enable[1:0]</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/i_data" type="array" db_ref_id="1">
<obj_property name="ElementShortName">i_data[31:0]</obj_property>
<obj_property name="ObjectShortName">i_data[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/o_data" type="array" db_ref_id="1">
<obj_property name="ElementShortName">o_data[31:0]</obj_property>
<obj_property name="ObjectShortName">o_data[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/c_mux" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">c_mux</obj_property>
<obj_property name="ObjectShortName">c_mux</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/c_enable" type="logic" db_ref_id="1">
<obj_property name="ElementShortName">c_enable</obj_property>
<obj_property name="ObjectShortName">c_enable</obj_property>
</wvobject>
<wvobject fp_name="/pipelinebuffer_tb/i_PipelineBuffer/r_data" type="array" db_ref_id="1">
<obj_property name="ElementShortName">r_data[31:0]</obj_property>
<obj_property name="ObjectShortName">r_data[31:0]</obj_property>
<obj_property name="Radix">UNSIGNEDDECRADIX</obj_property>
</wvobject>
</wvobject>
</wave_config>

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;

516
tests/PipelineSwitch_tb.vhd Normal file
View File

@@ -0,0 +1,516 @@
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.math_real.all;
entity PipelineSwitch_tb is
end entity PipelineSwitch_tb;
architecture RTL of PipelineSwitch_tb is
constant G_MaskWidth : integer := 4;
constant G_Mask : std_logic_vector(G_MaskWidth - 1 downto 0) := "1101";
-- === Signals for mode "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_Default_Valid_none : std_logic;
signal I_Default_Ready_none : std_logic := '0';
signal O_Selected_Valid_none : std_logic;
signal I_Selected_Ready_none : std_logic := '0';
-- === Signals for mode "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_Default_Valid_or : std_logic;
signal I_Default_Ready_or : std_logic := '0';
signal O_Selected_Valid_or : std_logic;
signal I_Selected_Ready_or : std_logic := '0';
-- === Signals for mode "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_Default_Valid_and : std_logic;
signal I_Default_Ready_and : std_logic := '0';
signal O_Selected_Valid_and : std_logic;
signal I_Selected_Ready_and : std_logic := '0';
-- === Signals for mode "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_Default_Valid_xor : std_logic;
signal I_Default_Ready_xor : std_logic := '0';
signal O_Selected_Valid_xor : std_logic;
signal I_Selected_Ready_xor : std_logic := '0';
-- === Signals for mode "equal" ===
signal I_Match_eq : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
signal I_Valid_eq : std_logic := '0';
signal O_Ready_eq : std_logic;
signal O_Default_Valid_eq : std_logic;
signal I_Default_Ready_eq : std_logic := '0';
signal O_Selected_Valid_eq : std_logic;
signal I_Selected_Ready_eq : std_logic := '0';
-- === Signals for mode "not_eq" ===
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_Default_Valid_neq : std_logic;
signal I_Default_Ready_neq : std_logic := '0';
signal O_Selected_Valid_neq : std_logic;
signal I_Selected_Ready_neq : std_logic := '0';
-- === Signals for mode "gt" ===
signal I_Match_gt : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
signal I_Valid_gt : std_logic := '0';
signal O_Ready_gt : std_logic;
signal O_Default_Valid_gt : std_logic;
signal I_Default_Ready_gt : std_logic := '0';
signal O_Selected_Valid_gt : std_logic;
signal I_Selected_Ready_gt : std_logic := '0';
-- === Signals for mode "ge" ===
signal I_Match_ge : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
signal I_Valid_ge : std_logic := '0';
signal O_Ready_ge : std_logic;
signal O_Default_Valid_ge : std_logic;
signal I_Default_Ready_ge : std_logic := '0';
signal O_Selected_Valid_ge : std_logic;
signal I_Selected_Ready_ge : std_logic := '0';
-- === Signals for mode "lt" ===
signal I_Match_lt : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
signal I_Valid_lt : std_logic := '0';
signal O_Ready_lt : std_logic;
signal O_Default_Valid_lt : std_logic;
signal I_Default_Ready_lt : std_logic := '0';
signal O_Selected_Valid_lt : std_logic;
signal I_Selected_Ready_lt : std_logic := '0';
-- === Signals for mode "le" ===
signal I_Match_le : std_logic_vector(G_MaskWidth - 1 downto 0) := (others => '0');
signal I_Valid_le : std_logic := '0';
signal O_Ready_le : std_logic;
signal O_Default_Valid_le : std_logic;
signal I_Default_Ready_le : std_logic := '0';
signal O_Selected_Valid_le : std_logic;
signal I_Selected_Ready_le : std_logic := '0';
begin
-- === Instanz: "none" ===
UUT_none : entity work.PipelineSwitch
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_Default_Valid => O_Default_Valid_none,
I_Default_Ready => I_Default_Ready_none,
O_Selected_Valid => O_Selected_Valid_none,
I_Selected_Ready => I_Selected_Ready_none
);
-- === Instanz: "or" ===
UUT_or : entity work.PipelineSwitch
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_Default_Valid => O_Default_Valid_or,
I_Default_Ready => I_Default_Ready_or,
O_Selected_Valid => O_Selected_Valid_or,
I_Selected_Ready => I_Selected_Ready_or
);
-- === Instanz: "and" ===
UUT_and : entity work.PipelineSwitch
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_Default_Valid => O_Default_Valid_and,
I_Default_Ready => I_Default_Ready_and,
O_Selected_Valid => O_Selected_Valid_and,
I_Selected_Ready => I_Selected_Ready_and
);
-- === Instanz: "xor" ===
UUT_xor : entity work.PipelineSwitch
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_Default_Valid => O_Default_Valid_xor,
I_Default_Ready => I_Default_Ready_xor,
O_Selected_Valid => O_Selected_Valid_xor,
I_Selected_Ready => I_Selected_Ready_xor
);
-- === Instanz: "equal" ===
UUT_eq : entity work.PipelineSwitch
generic map(
G_MaskWidth => G_MaskWidth,
G_Mask => G_Mask,
G_MaskMode => "equal"
)
port map(
I_Match => I_Match_eq,
I_Valid => I_Valid_eq,
O_Ready => O_Ready_eq,
O_Default_Valid => O_Default_Valid_eq,
I_Default_Ready => I_Default_Ready_eq,
O_Selected_Valid => O_Selected_Valid_eq,
I_Selected_Ready => I_Selected_Ready_eq
);
-- === Instanz: "not_eq" ===
UUT_neq : entity work.PipelineSwitch
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_Default_Valid => O_Default_Valid_neq,
I_Default_Ready => I_Default_Ready_neq,
O_Selected_Valid => O_Selected_Valid_neq,
I_Selected_Ready => I_Selected_Ready_neq
);
-- === Instanz: "gt" ===
UUT_gt : entity work.PipelineSwitch
generic map(
G_MaskWidth => G_MaskWidth,
G_Mask => G_Mask,
G_MaskMode => "gt"
)
port map(
I_Match => I_Match_gt,
I_Valid => I_Valid_gt,
O_Ready => O_Ready_gt,
O_Default_Valid => O_Default_Valid_gt,
I_Default_Ready => I_Default_Ready_gt,
O_Selected_Valid => O_Selected_Valid_gt,
I_Selected_Ready => I_Selected_Ready_gt
);
-- === Instanz: "ge" ===
UUT_ge : entity work.PipelineSwitch
generic map(
G_MaskWidth => G_MaskWidth,
G_Mask => G_Mask,
G_MaskMode => "ge"
)
port map(
I_Match => I_Match_ge,
I_Valid => I_Valid_ge,
O_Ready => O_Ready_ge,
O_Default_Valid => O_Default_Valid_ge,
I_Default_Ready => I_Default_Ready_ge,
O_Selected_Valid => O_Selected_Valid_ge,
I_Selected_Ready => I_Selected_Ready_ge
);
-- === Instanz: "lt" ===
UUT_lt : entity work.PipelineSwitch
generic map(
G_MaskWidth => G_MaskWidth,
G_Mask => G_Mask,
G_MaskMode => "lt"
)
port map(
I_Match => I_Match_lt,
I_Valid => I_Valid_lt,
O_Ready => O_Ready_lt,
O_Default_Valid => O_Default_Valid_lt,
I_Default_Ready => I_Default_Ready_lt,
O_Selected_Valid => O_Selected_Valid_lt,
I_Selected_Ready => I_Selected_Ready_lt
);
-- === Instanz: "le" ===
UUT_le : entity work.PipelineSwitch
generic map(
G_MaskWidth => G_MaskWidth,
G_Mask => G_Mask,
G_MaskMode => "le"
)
port map(
I_Match => I_Match_le,
I_Valid => I_Valid_le,
O_Ready => O_Ready_le,
O_Default_Valid => O_Default_Valid_le,
I_Default_Ready => I_Default_Ready_le,
O_Selected_Valid => O_Selected_Valid_le,
I_Selected_Ready => I_Selected_Ready_le
);
stimulus : process
begin
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "none"
----------------------------------------------------------------
report "Testmodus: none";
I_Default_Ready_none <= '1';
I_Match_none <= "0000";
I_Valid_none <= '1';
wait for 10 ns;
assert O_Default_Valid_none = '1' and O_Selected_Valid_none = '0'
report "Fehler im Modus 'none'" severity error;
I_Valid_none <= '0';
I_Default_Ready_none <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "or"
----------------------------------------------------------------
report "Testmodus: or";
I_Selected_Ready_or <= '1';
I_Match_or <= "0100"; -- bit 2 matches mask
I_Valid_or <= '1';
wait for 10 ns;
assert O_Selected_Valid_or = '1' and O_Default_Valid_or = '0'
report "Fehler im Modus 'or' (Match-Fall)" severity error;
I_Selected_Ready_or <= '0';
I_Valid_or <= '0';
wait for 10 ns;
I_Default_Ready_or <= '1';
I_Match_or <= "0010"; -- no bit matches mask
I_Valid_or <= '1';
wait for 10 ns;
assert O_Default_Valid_or = '1' and O_Selected_Valid_or = '0'
report "Fehler im Modus 'or' (No-Match-Fall)" severity error;
I_Default_Ready_or <= '0';
I_Valid_or <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "and"
----------------------------------------------------------------
report "Testmodus: and";
I_Selected_Ready_and <= '1';
I_Match_and <= "1101";
I_Valid_and <= '1';
wait for 10 ns;
assert O_Selected_Valid_and = '1' and O_Default_Valid_and = '0'
report "Fehler im Modus 'and' (Match-Fall)" severity error;
I_Selected_Ready_and <= '0';
I_Valid_and <= '0';
wait for 10 ns;
I_Default_Ready_and <= '1';
I_Match_and <= "1001"; -- bit 2 missing
I_Valid_and <= '1';
wait for 10 ns;
assert O_Default_Valid_and = '1' and O_Selected_Valid_and = '0'
report "Fehler im Modus 'and' (No-Match-Fall)" severity error;
I_Default_Ready_and <= '0';
I_Valid_and <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "xor"
----------------------------------------------------------------
report "Testmodus: xor";
I_Selected_Ready_xor <= '1';
I_Match_xor <= "1001"; -- differs at bit 2
I_Valid_xor <= '1';
wait for 10 ns;
assert O_Selected_Valid_xor = '1' and O_Default_Valid_xor = '0'
report "Fehler im Modus 'xor' (Match-Fall)" severity error;
I_Selected_Ready_xor <= '0';
I_Valid_xor <= '0';
wait for 10 ns;
I_Default_Ready_xor <= '1';
I_Match_xor <= "1101";
I_Valid_xor <= '1';
wait for 10 ns;
assert O_Default_Valid_xor = '1' and O_Selected_Valid_xor = '0'
report "Fehler im Modus 'xor' (No-Match-Fall)" severity error;
I_Default_Ready_xor <= '0';
I_Valid_xor <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "equal"
----------------------------------------------------------------
report "Testmodus: equal";
I_Selected_Ready_eq <= '1';
I_Match_eq <= "1101";
I_Valid_eq <= '1';
wait for 10 ns;
assert O_Selected_Valid_eq = '1' and O_Default_Valid_eq = '0'
report "Fehler im Modus 'equal' (Match-Fall)" severity error;
I_Selected_Ready_eq <= '0';
I_Valid_eq <= '0';
wait for 10 ns;
I_Default_Ready_eq <= '1';
I_Match_eq <= "1111";
I_Valid_eq <= '1';
wait for 10 ns;
assert O_Default_Valid_eq = '1' and O_Selected_Valid_eq = '0'
report "Fehler im Modus 'equal' (No-Match-Fall)" severity error;
I_Default_Ready_eq <= '0';
I_Valid_eq <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "not_equal"
----------------------------------------------------------------
report "Testmodus: not_equal";
I_Selected_Ready_neq <= '1';
I_Match_neq <= "1111"; -- not equal
I_Valid_neq <= '1';
wait for 10 ns;
assert O_Selected_Valid_neq = '1' and O_Default_Valid_neq = '0'
report "Fehler im Modus 'not_equal' (Match-Fall)" severity error;
I_Selected_Ready_neq <= '0';
I_Valid_neq <= '0';
wait for 10 ns;
I_Default_Ready_neq <= '1';
I_Match_neq <= "1101";
I_Valid_neq <= '1';
wait for 10 ns;
assert O_Default_Valid_neq = '1' and O_Selected_Valid_neq = '0'
report "Fehler im Modus 'not_equal' (No-Match-Fall)" severity error;
I_Default_Ready_neq <= '0';
I_Valid_neq <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "gt"
----------------------------------------------------------------
report "Testmodus: gt";
I_Selected_Ready_gt <= '1';
I_Match_gt <= "1110"; -- > 1101
I_Valid_gt <= '1';
wait for 10 ns;
assert O_Selected_Valid_gt = '1' and O_Default_Valid_gt = '0'
report "Fehler im Modus 'gt' (Match-Fall)" severity error;
I_Selected_Ready_gt <= '0';
I_Valid_gt <= '0';
wait for 10 ns;
I_Default_Ready_gt <= '1';
I_Match_gt <= "1010"; -- < 1101
I_Valid_gt <= '1';
wait for 10 ns;
assert O_Default_Valid_gt = '1' and O_Selected_Valid_gt = '0'
report "Fehler im Modus 'gt' (No-Match-Fall)" severity error;
I_Default_Ready_gt <= '0';
I_Valid_gt <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "ge"
----------------------------------------------------------------
report "Testmodus: ge";
I_Selected_Ready_ge <= '1';
I_Match_ge <= "1101"; -- == 1101
I_Valid_ge <= '1';
wait for 10 ns;
assert O_Selected_Valid_ge = '1' and O_Default_Valid_ge = '0'
report "Fehler im Modus 'ge' (Match-Fall ==)" severity error;
I_Selected_Ready_ge <= '0';
I_Valid_ge <= '0';
wait for 10 ns;
I_Default_Ready_ge <= '1';
I_Match_ge <= "0101"; -- < 1101
I_Valid_ge <= '1';
wait for 10 ns;
assert O_Default_Valid_ge = '1' and O_Selected_Valid_ge = '0'
report "Fehler im Modus 'ge' (No-Match-Fall)" severity error;
I_Default_Ready_ge <= '0';
I_Valid_ge <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "lt"
----------------------------------------------------------------
report "Testmodus: lt";
I_Selected_Ready_lt <= '1';
I_Match_lt <= "0101"; -- < 1101
I_Valid_lt <= '1';
wait for 10 ns;
assert O_Selected_Valid_lt = '1' and O_Default_Valid_lt = '0'
report "Fehler im Modus 'lt' (Match-Fall)" severity error;
I_Selected_Ready_lt <= '0';
I_Valid_lt <= '0';
wait for 10 ns;
I_Default_Ready_lt <= '1';
I_Match_lt <= "1111"; -- > 1101
I_Valid_lt <= '1';
wait for 10 ns;
assert O_Default_Valid_lt = '1' and O_Selected_Valid_lt = '0'
report "Fehler im Modus 'lt' (No-Match-Fall)" severity error;
I_Default_Ready_lt <= '0';
I_Valid_lt <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Mode: "le"
----------------------------------------------------------------
report "Testmodus: le";
I_Selected_Ready_le <= '1';
I_Match_le <= "1101"; -- == 1101
I_Valid_le <= '1';
wait for 10 ns;
assert O_Selected_Valid_le = '1' and O_Default_Valid_le = '0'
report "Fehler im Modus 'le' (Match-Fall ==)" severity error;
I_Selected_Ready_le <= '0';
I_Valid_le <= '0';
wait for 10 ns;
I_Default_Ready_le <= '1';
I_Match_le <= "1111"; -- > 1101
I_Valid_le <= '1';
wait for 10 ns;
assert O_Default_Valid_le = '1' and O_Selected_Valid_le = '0'
report "Fehler im Modus 'le' (No-Match-Fall)" severity error;
I_Default_Ready_le <= '0';
I_Valid_le <= '0';
wait for 10 ns;
----------------------------------------------------------------
-- Done!
----------------------------------------------------------------
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;