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:
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1 +1,3 @@
|
||||
build/working
|
||||
build/working
|
||||
.locale/
|
||||
vhdl_ls.toml
|
||||
|
@@ -48,7 +48,6 @@
|
||||
--@ - 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;
|
||||
@@ -57,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;
|
||||
@@ -91,59 +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
|
||||
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;
|
||||
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;
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user