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.
This commit is contained in:
2025-04-16 17:24:51 +00:00
parent 59e8302a48
commit aae0a66fec
3 changed files with 126 additions and 91 deletions

4
.gitignore vendored
View File

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

View File

@@ -48,7 +48,6 @@
--@ - 0.0.1 (2024-03-24) Initial version --@ - 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 --@ - 0.0.2 (2024-04-13) Enhanced the validity update logic to correctly handle configurations with a single pipeline stage
---------------------------------------------------------------------------------- ----------------------------------------------------------------------------------
library ieee; library ieee;
use ieee.std_logic_1164.all; use ieee.std_logic_1164.all;
use ieee.numeric_std.all; use ieee.numeric_std.all;
@@ -57,31 +56,34 @@ use ieee.math_real.all;
entity PipelineController is entity PipelineController is
generic ( generic (
--@ Number of pipeline stages (FFs in the pipeline including I/O FFs) --@ 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 --@ Reset active at this level
G_ResetActiveAt : std_logic := '1' G_ResetActiveAt : std_logic := '1'
); );
port ( port (
--@ Clock signal; **Rising edge** triggered --@ Clock signal; **Rising edge** triggered
I_CLK : in std_logic; I_CLK : in std_logic := '0';
--@ Reset signal; Active at `G_ResetActiveAt` --@ Reset signal; Active at `G_ResetActiveAt`
I_RST : in std_logic; I_RST : in std_logic := '0';
--@ Chip enable; Active high --@ 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> --@ 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`. --@ **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 --@ @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. --@ 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. --@ Ready flag; indicates that the connected registers is ready to accept data.
O_Ready : out std_logic; O_Ready : out std_logic := '0';
--@ @end --@ @end
--@ @virtualbus Output-AXI-Handshake @dir out Output AXI like Handshake --@ @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. --@ 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. --@ 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
); );
end entity PipelineController; end entity PipelineController;
@@ -91,59 +93,75 @@ architecture RTL of PipelineController is
signal R_Valid : std_logic_vector(G_PipelineStages - 1 downto 0) := (others => '0'); 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> --@ Ready signal for the pipeline controller to indicate that the pipeline can accept data; <br>
--@ mapped to `O_Enable` and `O_Ready` ports. --@ mapped to `O_Enable` and `O_Ready` ports.
signal C_Ready : std_logic := '1'; signal C_Ready : std_logic := '1';
begin begin
--@ Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller. <br> GEN_ForwardExternalFlags : if G_PipelineStages = 0 generate
--@ - `O_Enable`, and `O_Ready` are **and** combined from the `C_Ready` and `I_CE` signals. <br> --@ If no pipeline stages are defined, the flags are directly connected to the input and output ports.
--@ - `O_Valid` is the last bit of the `R_Valid` signal P_ExternalFlags : process (I_CE, I_Valid, I_Ready)
--@ and represents the validity of the data in the last stage of the pipeline. begin
P_ExternalFlags : process (R_Valid, C_Ready, I_CE) O_Valid <= I_Valid;
begin O_Enable <= I_Ready and I_CE;
O_Valid <= R_Valid(R_Valid'high); O_Ready <= I_Ready and I_CE;
end process;
end generate;
O_Enable <= C_Ready and I_CE; GEN_ExternalFlags : if G_PipelineStages > 0 generate
O_Ready <= C_Ready and I_CE; --@ Produce the `O_Valid`, `O_Enable`, and `O_Ready` signals for the pipeline controller. <br>
end process; --@ - `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, O_Enable <= C_Ready and I_CE;
--@ controlling the data flow in the pipeline. <br> O_Ready <= C_Ready and I_CE;
--@ `C_Ready` is asserted when the data is available in the last stage of the pipeline end process;
--@ **and** the external component is ready to accept data end generate;
--@ **or** when no data is available in the last stage of the pipeline.
P_InternalFlags : process (R_Valid, I_Ready) GEN_InternalFlags : if G_PipelineStages > 0 generate
begin --@ Produce the `C_Ready` signal for the pipeline controller,
if R_Valid(R_Valid'high) = '1' then --@ controlling the data flow in the pipeline. <br>
-- Data is available in the last stage of the pipeline. --@ `C_Ready` is asserted when the data is available in the last stage of the pipeline
if I_Ready = '1' then --@ **and** the external component is ready to accept data
-- O_Data is accepted from the external component. --@ **or** when no data is available in the last stage of the pipeline.
C_Ready <= '1'; 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 else
-- O_Data is not accepted from the external component. -- No data available in the last stage of the pipeline.
C_Ready <= '0'; C_Ready <= '1';
end if; end if;
else end process;
-- No data available in the last stage of the pipeline. end generate;
C_Ready <= '1';
end if;
end process;
--@ Shift the pipeline stages with `R_Valid` signal as placeholder to control GEN_ValidPipe : if G_PipelineStages > 0 generate
--@ the validity of the data in the individual pipeline stages. --@ Shift the pipeline stages with `R_Valid` signal as placeholder to control
P_ValidPipeline : process (I_CLK) --@ the validity of the data in the individual pipeline stages.
begin P_ValidPipeline : process (I_CLK)
if rising_edge(I_CLK) then begin
if I_RST = G_ResetActiveAt then if rising_edge(I_CLK) then
R_Valid <= (others => '0'); if I_RST = G_ResetActiveAt then
elsif I_CE = '1' then R_Valid <= (others => '0');
if C_Ready = '1' then elsif I_CE = '1' then
if G_PipelineStages = 1 then if C_Ready = '1' then
R_Valid(0) <= I_Valid; if G_PipelineStages = 1 then
else R_Valid(0) <= I_Valid;
R_Valid <= R_Valid(R_Valid'high - 1 downto R_Valid'low) & 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 if; end if;
end if; end process;
end process; end generate;
end architecture RTL; end architecture RTL;

View File

@@ -39,9 +39,9 @@ use ieee.math_real.all;
entity PipelineRegister is entity PipelineRegister is
generic ( generic (
--@ Number of pipeline stages (Correspondent to the number of registers in the pipeline) --@ Number of pipeline stages (Correspondent to the number of registers in the pipeline)
G_PipelineStages : integer := 3; G_PipelineStages : integer := 3;
--@ Data width --@ Data width
G_Width : integer := 32; G_Width : integer := 32;
--@ Register balancing attribute<br> --@ Register balancing attribute<br>
--@ - `no` : **Disable** register balancing, <br> --@ - `no` : **Disable** register balancing, <br>
--@ - `yes`: **Enable** register balancing in both directions, <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> --@ and moves a set of FFs at the inputs of a LUT to a single FF at its output, <br>
--@ - `backward`: **Enable** register balancing --@ - `backward`: **Enable** register balancing
--@ and moves a single FF at the output of a LUT to a set of FFs at its inputs. --@ 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 ( port (
--@ Clock signal; **Rising edge** triggered --@ Clock; (**Rising edge** triggered)
I_CLK : in std_logic; I_CLK : in std_logic := '0';
--@ Enable input from **Pipeline Controller** --@ Enable input from **Pipeline Controller**
I_Enable : in std_logic; I_Enable : in std_logic := '0';
--@ Data input --@ 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 --@ 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; 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). --@ 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); 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. --@ 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 --@ Pipeline register balancing attribute from generic
attribute register_balancing of R_Data : signal is G_RegisterBalancing; attribute register_balancing of R_Data : signal is G_RegisterBalancing;
begin begin
--@ Pipeline register and connection of the data from the input port to the first stage of the pipeline register. <br> --@ Generate the pipeline registers if `G_PipelineStages` is greater than 0.
--@ **I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1)** -> O_Data GEN_PipelineRegister : if G_PipelineStages > 0 generate
P_PipelineRegister : process (I_CLK) --@ Pipeline register and connection of the data from the input port to the first stage of the pipeline register. <br>
begin --@ **I_Data -> R_Data(0) -> R_Data(1) -> ... -> R_Data(G_PipelineStages - 1)** -> O_Data
if rising_edge(I_CLK) then P_PipelineRegister : process (I_CLK)
if I_Enable = '1' then begin
for i in 0 to G_PipelineStages - 1 loop if rising_edge(I_CLK) then
if i = 0 then if I_Enable = '1' then
--@ Input data from the input port to the first stage of the pipeline register for i in 0 to G_PipelineStages - 1 loop
R_Data(i) <= I_Data; if i = 0 then
else --@ Input data from the input port to the first stage of the pipeline register
--@ Data from the previous stage of the pipeline register to the current stage R_Data(i) <= I_Data;
R_Data(i) <= R_Data(i - 1); else
end if; --@ Data from the previous stage of the pipeline register to the current stage
end loop; R_Data(i) <= R_Data(i - 1);
end if;
end loop;
end if;
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> --@ Generate the connection last register to the output port if `G_PipelineStages` is greater than 0.
--@ I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data** GEN_ForwardRegister : if G_PipelineStages > 0 generate
P_ForwardData : process (R_Data) --@ Connect (combinatoric) data from the last stage of the pipeline register to the output port. <br>
begin --@ I_Data -> R_Data(0) -> R_Data(1) -> ... -> **R_Data(G_PipelineStages - 1) -> O_Data**
O_Data <= R_Data(G_PipelineStages - 1); P_ForwardData : process (R_Data)
end process; 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;