+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+--------------------------------------------------------------------------------
+-- This entity is a generator of PWM signal.
+--
+-- PWM bit width is configurable by PWM_WIDTH generic parameter.
+--
+-- In practice, to generate PWM signal component must be fed by a counter vector
+-- (pwm_cnt input) of appropriate width and also period! (One counter can be
+-- used by several PWM generators and generated signals are then synchronized.)
+--
+-- The period of the input counter vector should be by 1 smaller than the count
+-- of all possible PWM values, i.e. counter vector should never reaches the
+-- maximum possible PWM value, and counting should start from 0. E.g. when full
+-- range of PWM values is used, binary counter should be reset just one step
+-- before it overflows. In such a case, when PWM value is maximal, output keeps
+-- log. 1.
+--
+-- PWM value is buffered and any change is propageted to the output by the next
+-- pwm period - 'pwm_cyc' must by feed.
+--------------------------------------------------------------------------------
+
+entity pwm is
+ generic (
+ PWM_WIDTH : integer);
+ port (
+ clk : in std_logic;
+ reset : in std_logic;
+ din : in std_logic_vector (PWM_WIDTH-1 downto 0);
+ we : in std_logic;
+ -- PWM interface
+ pwm_cnt : in std_logic_vector (PWM_WIDTH-1 downto 0);
+ pwm_cyc : in std_logic; -- Indicate new pwm period
+ pwm : out std_logic);
+end pwm;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of pwm is
+
+ -- Register accessible from bus
+ signal reg : std_logic_vector (PWM_WIDTH-1 downto 0);
+ -- Compare value during pwm cycle, loaded from 'reg' when new period begins.
+ signal cmp : std_logic_vector (PWM_WIDTH-1 downto 0);
+
+--------------------------------------------------------------------------------
+
+begin
+
+ -- Peripheral register
+ PWM_REGISTER : process (clk, reset)
+ begin
+ if reset = '1' then
+ reg <= (others => '0');
+
+ elsif rising_edge(clk) then
+ if we = '1' then
+ reg <= din;
+ end if;
+ end if;
+ end process;
+
+
+ -- Generation of PWM signal
+ -- When 'pwm_cyc' is high then new 'cmp' is loaded and 'counter' is reset
+ -- with next clk edge. Pwm output is delayed by one clock.
+ PWM_GEN : process (clk, reset)
+ begin
+ if reset = '1' then
+ pwm <= '0';
+
+ elsif rising_edge(clk) then
+ if pwm_cyc = '1' then
+ cmp <= reg;
+ end if;
+
+ if pwm_cnt < cmp then
+ pwm <= '1';
+ else
+ pwm <= '0';
+ end if;
+ end if;
+ end process;
+
+end behavioral;
+