Add Gray counter implementation and testbench
Introduces a synchronous Gray counter with configurable width, reset, enable, and look-ahead functionality. Implements binary-to-Gray and Gray-to-binary conversion functions. Includes a testbench for simulation and validation of the counter's behavior.
This commit is contained in:
119
libs/GrayCounter.vhd
Normal file
119
libs/GrayCounter.vhd
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
----------------------------------------------------------------------------------
|
||||||
|
--@ - Name: **Gray Counter** <br>
|
||||||
|
--@ - Version: 0.0.2 <br>
|
||||||
|
--@ - Author: __Maximilian Passarello ([Blog](mpassarello.de))__ <br>
|
||||||
|
--@ - License: [MIT](LICENSE) <br>
|
||||||
|
--@ A synchronous Gray counter with reset and enable
|
||||||
|
--@ History:
|
||||||
|
-- - 0.0.2 (2024-03-27) Refactored code to use conventions
|
||||||
|
-- - 0.0.1 (2009-04-02) Initial version
|
||||||
|
----------------------------------------------------------------------------------
|
||||||
|
library IEEE;
|
||||||
|
use IEEE.STD_LOGIC_1164.all;
|
||||||
|
use IEEE.NUMERIC_STD.all;
|
||||||
|
|
||||||
|
entity GrayCounter is
|
||||||
|
generic (
|
||||||
|
--@ Width of the counter
|
||||||
|
G_Width : integer := 4;
|
||||||
|
--@ Initial value of the counter
|
||||||
|
G_InitialValue : integer := 0;
|
||||||
|
--@ Reset value of the counter
|
||||||
|
G_ResetValue : integer := 0;
|
||||||
|
--@ Counting direction: "UP" or "DOWN"
|
||||||
|
G_CountingDirection : string := "UP";
|
||||||
|
--@ Look ahead value
|
||||||
|
G_LookAhead : integer := 0
|
||||||
|
);
|
||||||
|
port (
|
||||||
|
--@ Clock input; rising edge
|
||||||
|
I_CLK : in std_logic := '0';
|
||||||
|
--@ Clock enable; active high
|
||||||
|
I_CE : in std_logic := '1';
|
||||||
|
--@ Reset input; active high; synchronous
|
||||||
|
I_RST : in std_logic := '0';
|
||||||
|
--@ Count enable; active high
|
||||||
|
I_CountEnable : in std_logic := '0';
|
||||||
|
--@ Gray counter value
|
||||||
|
O_Value : out std_logic_vector(G_Width - 1 downto 0) := (others => '-');
|
||||||
|
--@ Look ahead value
|
||||||
|
O_LAValue : out std_logic_vector(G_Width - 1 downto 0) := (others => '-')
|
||||||
|
);
|
||||||
|
end GrayCounter;
|
||||||
|
|
||||||
|
architecture Behavioral of GrayCounter is
|
||||||
|
-- Functions
|
||||||
|
--@ Convert Binary to Gray code
|
||||||
|
function BinaryToGray(I_BinaryValue : std_logic_vector)
|
||||||
|
return std_logic_vector is
|
||||||
|
constant K_Width : integer := I_BinaryValue'Length;
|
||||||
|
variable V_GrayValue : std_logic_vector(K_Width - 1 downto 0);
|
||||||
|
begin
|
||||||
|
V_GrayValue(K_Width - 1) := I_BinaryValue(K_Width - 1);
|
||||||
|
for i in 1 to K_Width - 1 loop
|
||||||
|
V_GrayValue((K_Width - 1) - i) := I_BinaryValue((K_Width - 1) - i) xor I_BinaryValue(((K_Width - 1) - i) + 1);
|
||||||
|
end loop;
|
||||||
|
return V_GrayValue(K_Width - 1 downto 0);
|
||||||
|
end function BinaryToGray;
|
||||||
|
|
||||||
|
--@ Convert Gray code to binary
|
||||||
|
function GrayToBinary(I_GrayValue : std_logic_vector)
|
||||||
|
return std_logic_vector is
|
||||||
|
constant K_Width : integer := I_GrayValue'Length;
|
||||||
|
variable V_BinaryValue : std_logic_vector(K_Width - 1 downto 0);
|
||||||
|
begin
|
||||||
|
V_BinaryValue(K_Width - 1) := I_GrayValue(K_Width - 1);
|
||||||
|
for i in 1 to K_Width - 1 loop
|
||||||
|
V_BinaryValue((K_Width - 1) - i) := V_BinaryValue(K_Width - i) xor I_GrayValue((K_Width - 1) - i);
|
||||||
|
end loop;
|
||||||
|
return V_BinaryValue(K_Width - 1 downto 0);
|
||||||
|
end function GrayToBinary;
|
||||||
|
|
||||||
|
function CountingStep(I_BinaryValue : std_logic_vector; I_Step : integer := 1)
|
||||||
|
return std_logic_vector is
|
||||||
|
begin
|
||||||
|
if G_CountingDirection = "DOWN" then
|
||||||
|
return std_logic_vector(unsigned(I_BinaryValue) - I_Step);
|
||||||
|
else
|
||||||
|
return std_logic_vector(unsigned(I_BinaryValue) + I_Step);
|
||||||
|
end if;
|
||||||
|
end function CountingStep;
|
||||||
|
|
||||||
|
-- Constants
|
||||||
|
constant K_InitialValue : std_logic_vector(G_Width - 1 downto 0) := std_logic_vector(to_unsigned(G_InitialValue, G_Width));
|
||||||
|
constant K_InitialLookAhead : std_logic_vector(G_Width - 1 downto 0) := std_logic_vector(to_unsigned(G_InitialValue + G_LookAhead, G_Width));
|
||||||
|
constant K_ResetValue : std_logic_vector(G_Width - 1 downto 0) := std_logic_vector(to_unsigned(G_ResetValue, G_Width));
|
||||||
|
constant K_ResetLookAhead : std_logic_vector(G_Width - 1 downto 0) := std_logic_vector(to_unsigned(G_ResetValue + G_LookAhead, G_Width));
|
||||||
|
|
||||||
|
signal R_CounterValue : std_logic_vector(G_Width - 1 downto 0) := K_InitialValue;
|
||||||
|
signal R_GrayValue : std_logic_vector(G_Width - 1 downto 0) := BinaryToGray(K_InitialValue);
|
||||||
|
signal R_LookAheadValue : std_logic_vector(G_Width - 1 downto 0) := BinaryToGray(K_InitialLookAhead);
|
||||||
|
begin
|
||||||
|
|
||||||
|
O_Value <= R_GrayValue;
|
||||||
|
O_LAValue <= R_LookAheadValue;
|
||||||
|
|
||||||
|
Counter : process (I_CLK)
|
||||||
|
variable V_Counter : std_logic_vector(G_Width - 1 downto 0);
|
||||||
|
variable V_LookAhead : std_logic_vector(G_Width - 1 downto 0);
|
||||||
|
begin
|
||||||
|
if rising_edge(I_CLK) then
|
||||||
|
if I_RST = '1' then
|
||||||
|
V_Counter := (others => '0');
|
||||||
|
R_GrayValue <= BinaryToGray(K_ResetValue);
|
||||||
|
R_LookAheadValue <= BinaryToGray(K_ResetLookAhead);
|
||||||
|
R_CounterValue <= K_ResetValue;
|
||||||
|
elsif I_CE = '1' then
|
||||||
|
if I_CountEnable = '1' then
|
||||||
|
V_Counter := CountingStep(R_CounterValue);
|
||||||
|
|
||||||
|
R_CounterValue <= V_Counter;
|
||||||
|
R_GrayValue <= BinaryToGray(V_Counter);
|
||||||
|
|
||||||
|
V_LookAhead := CountingStep(V_Counter, G_LookAhead);
|
||||||
|
R_LookAheadValue <= BinaryToGray(V_LookAhead);
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end if;
|
||||||
|
end process;
|
||||||
|
end Behavioral;
|
46
tests/GrayCounter_tb.vhd
Normal file
46
tests/GrayCounter_tb.vhd
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
|
||||||
|
library ieee;
|
||||||
|
use ieee.std_logic_1164.all;
|
||||||
|
use ieee.numeric_std.all;
|
||||||
|
|
||||||
|
entity GrayCounter_tb is
|
||||||
|
end;
|
||||||
|
|
||||||
|
architecture bench of GrayCounter_tb is
|
||||||
|
-- Clock period
|
||||||
|
constant clk_period : time := 10 ns;
|
||||||
|
-- Generics
|
||||||
|
constant G_Width : integer := 6;
|
||||||
|
constant G_InitialValue : integer := 0;
|
||||||
|
constant G_ResetValue : integer := 0;
|
||||||
|
constant G_CountingDirection : string := "UP";
|
||||||
|
constant G_LookAhead : integer := 1;
|
||||||
|
-- Ports
|
||||||
|
signal I_CLK : std_logic := '0';
|
||||||
|
signal I_CE : std_logic := '1';
|
||||||
|
signal I_RST : std_logic := '0';
|
||||||
|
signal I_CountEnable : std_logic := '1';
|
||||||
|
signal O_Value : std_logic_vector(G_Width - 1 downto 0);
|
||||||
|
signal O_LookAheadValue : std_logic_vector(G_Width - 1 downto 0);
|
||||||
|
begin
|
||||||
|
|
||||||
|
GrayCounter_inst : entity work.GrayCounter
|
||||||
|
generic map (
|
||||||
|
G_Width => G_Width,
|
||||||
|
G_InitialValue => G_InitialValue,
|
||||||
|
G_ResetValue => G_ResetValue,
|
||||||
|
G_CountingDirection => G_CountingDirection,
|
||||||
|
G_LookAhead => G_LookAhead
|
||||||
|
)
|
||||||
|
port map (
|
||||||
|
I_CLK => I_CLK,
|
||||||
|
I_CE => I_CE,
|
||||||
|
I_RST => I_RST,
|
||||||
|
I_CountEnable => I_CountEnable,
|
||||||
|
O_Value => O_Value,
|
||||||
|
O_LAValue => O_LookAheadValue
|
||||||
|
);
|
||||||
|
|
||||||
|
I_CLK <= not I_CLK after clk_period/2;
|
||||||
|
|
||||||
|
end;
|
Reference in New Issue
Block a user