From abb4a9f10a9b7efe4d885992f88dba1e8b3aea16 Mon Sep 17 00:00:00 2001 From: Max P Date: Sun, 24 Mar 2024 19:47:01 +0100 Subject: [PATCH] Enhance Pipeline Controller and Register with AXI-Like Handshaking and Register Rebalancing - Introduce comprehensive documentation for Pipeline Controller and Register, detailing core functions, generics, ports, and processes. Focus on data flow control, validity control, adjustability, and register rebalancing mechanisms. - Implement AXI-Like handshaking in Pipeline Controller for improved input and output data handling, supporting active-high ready and valid signals for efficient data transfer. - Refine Pipeline Register with register rebalancing options (no, yes, forward, backward) to optimize combinatorial logic pipelining in synthesis, configurable via `G_RegisterBalancing` generic. - Update generics and ports descriptions to reflect the inclusion of I/O FFs in pipeline depth calculation and clarify the reset active level and handshaking protocol. - Extend VHDL source for both modules to embody described functionalities and adjustments, ensuring alignment with documentation enhancements. - Augment testbench `Pipeline_tb.vhd` with random intervals for write and read operations, emphasizing dynamic testing scenarios. --- docs/PipelineController.md | 83 ++++++++++++++++++---- docs/PipelineRegister.md | 49 +++++++++++-- src/PipelineController.vhd | 79 ++++++++++++++++++--- src/PipelineRegister.vhd | 57 +++++++++++++-- tests/Pipeline_tb.vhd | 140 +++++++++++++++++++++---------------- tests/Pipeline_tb.wcfg | 43 ++++++++++-- 6 files changed, 350 insertions(+), 101 deletions(-) diff --git a/docs/PipelineController.md b/docs/PipelineController.md index 1b91e1d..73ce3cb 100644 --- a/docs/PipelineController.md +++ b/docs/PipelineController.md @@ -4,23 +4,73 @@ ## Diagram ![Diagram](PipelineController.svg "Diagram") +## Description + +- Name: **Pipeline Controller** +- Version: 0.0.1 +- Author: _Maximilian Passarello ([Blog](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 | -| G_ResetActiveAt | std_logic | '1' | Reset active at: | +| 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.
**Note:** Connect to `I_Enable` of the registers to be controlled by this controller. | -| Input-AXI-Handshake | in | Virtual bus | Input AXI like Handshake | -| Output-AXI-Handshake | out | Virtual bus | Output AXI like Handshake | +| 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.
**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 @@ -45,9 +95,12 @@ | C_Ready | std_logic | Ready signal for the pipeline controller to indicate that the pipeline can accept data;
mapped to `O_Enable` and `O_Ready` ports. | ## Processes -- P_Flags: ( R_Valid, I_Ready ) +- P_ExternalFlags: ( R_Valid, C_Ready, I_CE ) - **Description** - Produce the `C_Ready` signal for the pipeline controller, controlling the data flow in the pipeline. + Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller.
- `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals.
- `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.
`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 pipeline stages. + Shift the pipeline stages with `R_Valid` signal as placeholder to control the validity of the data in the individual pipeline stages. diff --git a/docs/PipelineRegister.md b/docs/PipelineRegister.md index ab6f625..8fe020b 100644 --- a/docs/PipelineRegister.md +++ b/docs/PipelineRegister.md @@ -4,13 +4,47 @@ ## Diagram ![Diagram](PipelineRegister.svg "Diagram") +## Description + +- Name: **Pipeline Register** +- Version: 0.0.1 +- Author: _Maximilian Passarello ([Blog](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 | -| G_Width | integer | 32 | Data width | -| G_RegisterBalancing | string | "yes" | Register balancing attribute
- "no" : **Disable** register balancing,
- "yes": **Enable** register balancing in both directions,
- "forward": **Enable** and moves a set of FFs at the inputs of a LUT to a single FF at its output,
- "backward": **Enable** and moves a single FF at the output of a LUT to a set of FFs at its inputs. | +| 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
- `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. | ## Ports @@ -36,4 +70,7 @@ ## Processes - P_PipelineRegister: ( I_CLK ) - **Description** - Pipeline register I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1) -> O_Data + Pipeline register and connection of the data from the input port to the first stage of the pipeline register.
**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.
I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data** diff --git a/src/PipelineController.vhd b/src/PipelineController.vhd index f262543..6efc2d7 100644 --- a/src/PipelineController.vhd +++ b/src/PipelineController.vhd @@ -1,3 +1,53 @@ +---------------------------------------------------------------------------------- +--@ - Name: **Pipeline Controller** +--@ - Version: 0.0.1 +--@ - Author: _Maximilian Passarello ([Blog](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 +---------------------------------------------------------------------------------- + library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; @@ -5,9 +55,9 @@ use ieee.math_real.all; entity PipelineController is generic ( - --@ Number of pipeline stages + --@ Number of pipeline stages (FFs in the pipeline including I/O FFs) G_PipelineStages : integer := 3; - --@ Reset active at: + --@ Reset active at this level G_ResetActiveAt : std_logic := '1' ); port ( @@ -18,7 +68,7 @@ entity PipelineController is --@ Chip enable; Active high I_CE : in std_logic; --@ Pipeline enable; Active high when pipeline can accept data and `I_CE` is high.
- --@ **Note:** Connect to `I_Enable` of the registers to be controlled by this controller. + --@ **Note:** Connect `CE` of the registers to be controlled by this controller to `O_Enable`. O_Enable : out std_logic; --@ @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. @@ -43,14 +93,24 @@ architecture RTL of PipelineController is signal C_Ready : std_logic := '1'; begin - O_Valid <= R_Valid(R_Valid'high); + --@ Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller.
+ --@ - `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals.
+ --@ - `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); - O_Enable <= C_Ready and I_CE; - O_Ready <= C_Ready and I_CE; + O_Enable <= C_Ready and I_CE; + O_Ready <= C_Ready and I_CE; + end process; --@ Produce the `C_Ready` signal for the pipeline controller, - --@ controlling the data flow in the pipeline. - P_Flags : process (R_Valid, I_Ready) + --@ controlling the data flow in the pipeline.
+ --@ `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. @@ -67,7 +127,8 @@ begin end if; end process; - --@ Shift the pipeline stages with `R_Valid` signal as placeholder to control the pipeline stages. + --@ 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 diff --git a/src/PipelineRegister.vhd b/src/PipelineRegister.vhd index 49ad026..d2d5403 100644 --- a/src/PipelineRegister.vhd +++ b/src/PipelineRegister.vhd @@ -1,3 +1,36 @@ +---------------------------------------------------------------------------------- +--@ - Name: **Pipeline Register** +--@ - Version: 0.0.1 +--@ - Author: _Maximilian Passarello ([Blog](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 +---------------------------------------------------------------------------------- library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; @@ -5,15 +38,17 @@ use ieee.math_real.all; entity PipelineRegister is generic ( - --@ Number of pipeline stages + --@ Number of pipeline stages (Correspondent to the number of registers in the pipeline) G_PipelineStages : integer := 3; --@ Data width G_Width : integer := 32; --@ Register balancing attribute
- --@ - "no" : **Disable** register balancing,
- --@ - "yes": **Enable** register balancing in both directions,
- --@ - "forward": **Enable** and moves a set of FFs at the inputs of a LUT to a single FF at its output,
- --@ - "backward": **Enable** and moves a single FF at the output of a LUT to a set of FFs at its inputs. + --@ - `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 ( @@ -39,15 +74,18 @@ architecture RTL of PipelineRegister is attribute register_balancing of R_Data : signal is G_RegisterBalancing; begin - --@ Pipeline register I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1) -> O_Data + --@ Pipeline register and connection of the data from the input port to the first stage of the pipeline register.
+ --@ **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; @@ -55,6 +93,11 @@ begin end if; end process; - O_Data <= R_Data(G_PipelineStages - 1); + --@ Connect (combinatoric) data from the last stage of the pipeline register to the output port.
+ --@ 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 architecture RTL; \ No newline at end of file diff --git a/tests/Pipeline_tb.vhd b/tests/Pipeline_tb.vhd index 50f35ca..7587962 100644 --- a/tests/Pipeline_tb.vhd +++ b/tests/Pipeline_tb.vhd @@ -1,21 +1,29 @@ library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; +use ieee.math_real.all; 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; + 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; + -- Clock signal period constant period : time := 20 ns; -- Adjustable wait times - constant write_delay : natural := 0; -- Wait time between write operations in clock cycles - constant read_delay : natural := 0; -- Wait time between read operations in clock cycles - - -- Adjustable number of data values to be written - constant writes : natural := 100; + 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 -- Setting constants for the FIFO to be tested constant K_Width : integer := 32; -- Data width of the FIFO @@ -25,22 +33,18 @@ architecture behavior of Pipeline_tb is -- Testbench signals signal CLK : std_logic := '0'; signal RST : std_logic := '1'; + signal CE : std_logic := '1'; - signal I_WriteCE : std_logic := '0'; - 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 I_ReadCE : std_logic := '0'; - signal O_Data : std_logic_vector(K_Width - 1 downto 0); - signal O_Valid : std_logic; - signal I_Ready : std_logic := '0'; - - signal CE : std_logic := '1'; + 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; begin - CE <= I_WriteCE or I_ReadCE; uut0 : entity work.PipelineController generic map( @@ -72,61 +76,79 @@ begin ); -- Clock process - clocking : process + Clocking : process begin while true loop CLK <= '0'; - wait for period / 2; + wait for (period / 2); CLK <= '1'; - wait for period / 2; + wait for (period / 2); end loop; end process; - -- Write process adapted for the falling edge of the clock signal - write_process : process - begin - wait for 100 ns; -- Initial wait time for reset and FIFO initialization - RST <= '0'; - wait for period; -- Wait an additional clock cycle after reset - I_WriteCE <= '1'; - wait until falling_edge(CLK); - for i in 0 to writes loop -- Writing loop for data values - if O_Ready = '0' then - wait on O_Ready until O_Ready = '1'; - wait until falling_edge(CLK); - end if; + -- Clock enable process + -- This process is used to enable the clock signal for a certain amount of time + -- and only for the Pipeline Controller to check if the dataflow is working correctly. + -- ClockEnable : process + -- begin + -- while true loop + -- CE <= '1'; + -- wait for 1000 ns; + -- CE <= '0'; + -- wait for 500 ns; + -- end loop; + -- end process; - I_Data <= std_logic_vector(to_unsigned(i, K_Width)); -- Data to be written - I_Valid <= '1'; - wait until falling_edge(CLK); - I_Valid <= '0'; -- Reset 'valid' after writing - for j in 1 to write_delay loop - wait until falling_edge(CLK); -- Wait based on the set wait time - end loop; - end loop; - I_WriteCE <= '0'; -- Deactivate write signal after writing - wait; - end process; + -- 100 ns Reset + RST <= '1', '0' after 100 ns; - -- Read process adapted for the falling edge of the clock signal - read_process : process + -- Write process + Write : process (CLK) + variable delay : integer := 0; + variable i : integer := 1; begin - wait for 110 ns; -- Delay to start writing - I_ReadCE <= '1'; - while true loop - if O_Valid = '1' and I_Ready = '0' then - I_Ready <= '1'; -- Signal readiness to read - wait until falling_edge(CLK); - if read_delay /= 0 then - I_Ready <= '0'; -- Reset the signal after reading - end if; - for j in 1 to read_delay loop - wait until falling_edge(CLK); -- Wait based on the set wait time - end loop; + if rising_edge(CLK) then + if RST = '1' then + I_Valid <= '0'; + delay := write_delay; + i := 1; + I_Data <= (others => 'U'); else - wait until falling_edge(CLK); -- Synchronize with the clock when not ready to read + 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 loop; + end if; + end process; + + -- Read process + Read : process (CLK) + variable delay : integer := 0; + begin + if rising_edge(CLK) then + if RST = '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; end process; end architecture behavior; diff --git a/tests/Pipeline_tb.wcfg b/tests/Pipeline_tb.wcfg index 99c7119..327c10b 100644 --- a/tests/Pipeline_tb.wcfg +++ b/tests/Pipeline_tb.wcfg @@ -13,7 +13,7 @@ - + clk clk @@ -22,6 +22,10 @@ rst rst + + ce + ce + i_data[31:0] i_data[31:0] @@ -47,6 +51,8 @@ i_ready i_ready + true + #00ff00 Pipeline @@ -54,6 +60,10 @@ 128 128 255 230 230 230 + + pipelineenable + pipelineenable + Controller label @@ -69,10 +79,27 @@ o_ready o_ready - - r_valid[2:0] - r_valid[2:0] - BINARYRADIX + + r_valid[0:2] + label + + [0] + r_valid[0] + true + #ff00ff + + + [1] + r_valid[1] + true + #ff00ff + + + [2] + r_valid[2] + true + #ff00ff + o_valid @@ -113,16 +140,22 @@ [0] r_data[0] UNSIGNEDDECRADIX + true + #ff00ff [1] r_data[1] UNSIGNEDDECRADIX + true + #ff00ff [2] r_data[2] UNSIGNEDDECRADIX + true + #ff00ff