Let's think about a common peripheral, the Pulse Width Modulation (PWM) Module. The concept is very simple and ilustrated in the next figure
There is a COUNTER register that start in zero. As a CLK edge arrives to circuit the COUNTER is updated one-by-one up to MAXIMUM value. The MAXIMUM value determines the PWM frequency (fPWM) as follows,
Where fCLK is the Clock Frequency.
In order to think the behavior of this element we have the following logic.
- Let's break up the counting and comparing logic for the hardware description language (HDL).
- For testing purposes consider the posibility of simulate before implement in the board. The simulation time is important because you can obtain limited resources in your computer.
- Consider a variable word length because we do not know about the CPU architecture in the future. By default, the PWM generator work with 15 bit resolution.
The first step is declare the entity. By default Width defines the word length in 15 bits. According to the time diagram there are two inputs plus CLK and one output. The MAX input define the max value of the counter and the CMP value allow the logic for the output of the PWM generation in Q.
entity WG_PH is Generic( Width : integer := 15); Port ( CLK : in std_logic; MAX : in std_logic_vector((Width - 1) downto 0); CMP : in std_logic_vector((Width - 1) downto 0); Q : out std_logic ); end WG_PH;
Remember the logic break up for the counting and comparing processes.
process(CLK) begin if rising_edge(CLK) then if counter >= to_integer(unsigned(MAX)) then counter <= 0; else counter <= counter + 1; end if; end if; end process;
The counter depends on the rising edges over the CLK signal, consequently, CLK is in the sensibility list. The counter restart its value to 0 when the MAX value is reached.
process(counter) begin if counter >= to_integer(unsigned(CMP)) then Q <= '0'; else Q <= '1'; end if; end process;
The counter value changes define the behavior of the PWM output. if the value is less than the CMP value the output is zero, and one otherwise
Finally, we can instantiate our circuit to simulate and observe if the behavior is the expected to the diagram and logic.
The two codes, Circuit and Simulation, are below. The Simulation instantiates a 4 bit width PWM generator, but for the HACK CPU will be wider
---------------------------------------------------------------------------------- -- Engineer: Miguel Angel Castillo Martinez -- -- Create Date: 22.01.2022 16:59:54 -- Design Name: Waveform Generator Peripheral -- Module Name: WG_PH - Behavior -- Revision: -- Revision 0.01 - File Created ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; use IEEE.numeric_std.ALL; entity WG_PH is Generic( Width : integer := 15); Port ( CLK : in std_logic; MAX : in std_logic_vector((Width - 1) downto 0); CMP : in std_logic_vector((Width - 1) downto 0); Q : out std_logic ); end WG_PH; architecture Behavior of WG_PH is signal counter : integer range 0 to (2**Width - 1) := 0; begin process(CLK) begin if rising_edge(CLK) then if counter >= to_integer(unsigned(MAX)) then counter <= 0; else counter <= counter + 1; end if; end if; end process; process(counter) begin if counter >= to_integer(unsigned(CMP)) then Q <= '0'; else Q <= '1'; end if; end process; end Behavior;
---------------------------------------------------------------------------------- -- Engineer: Miguel Angel Castillo Martinez -- -- Create Date: 22.01.2022 16:59:54 -- Design Name: Waveform Generator Peripheral -- Module Name: WG_PH - Behavior -- Revision: -- Revision 0.01 - File Created ---------------------------------------------------------------------------------- library IEEE; use IEEE.STD_LOGIC_1164.ALL; entity WG_Sim is end WG_Sim; architecture Behavioral of WG_Sim is constant width : integer := 4; signal clk : std_logic := '0'; signal max : std_logic_vector((width - 1) downto 0) := x"5"; signal cmp : std_logic_vector((width - 1) downto 0) := x"3"; signal q : std_logic; begin clk <= not clk after 40 ns; WG: entity work.WG_PH generic map( Width => width) port map( CLK => clk, MAX => max, CMP => cmp, Q => q); process is begin wait for 960 ns; max <= x"A"; wait for 1760 ns; cmp <= x"9"; wait for 1760 ns; end process; end Behavioral;