Verified with testbench.
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+--------------------------------------------------------------------------------
+-- General counter which counter width and maximum value can be set by generic
+-- attributes. When 'count' is equal to MAX value, 'event_ow' is high.
+--------------------------------------------------------------------------------
+
+entity counter is
+ generic (
+ WIDTH : integer;
+ MAX : integer);
+ port (
+ clk : in std_logic;
+ reset : in std_logic;
+ count : out std_logic_vector (WIDTH-1 downto 0);
+ event_ow : out std_logic);
+end counter;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of counter is
+
+ signal eq_max : std_logic; -- cnt is equal to MAX
+ signal cnt : std_logic_vector (WIDTH-1 downto 0);
+
+--------------------------------------------------------------------------------
+
+begin
+
+ assert MAX < 2**WIDTH
+ report "MAX is bigger then counter max. value."
+ severity error;
+
+
+ count <= cnt;
+ event_ow <= eq_max;
+
+
+ COUTER : process (clk, reset) is
+ begin
+ if reset = '1' then
+ cnt <= (others => '0');
+
+ elsif rising_edge(clk) then
+ if eq_max = '1' then
+ cnt <= (others => '0');
+ else
+ cnt <= cnt + 1;
+ end if;
+ end if;
+ end process;
+
+
+ CNT_EQ_MAX : process (cnt) is
+ begin
+ if cnt = CONV_STD_LOGIC_VECTOR(MAX, WIDTH) then
+ eq_max <= '1';
+ else
+ eq_max <= '0';
+ end if;
+ end process;
+
+end behavioral;
+
--- /dev/null
+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;
+
--- /dev/null
+VHDL_MAIN = tb_wave_table
+VHDL_ENTITIES = counter.o \
+ pwm.o
+
+STOP_TIME = 50us
+
+
+all: $(VHDL_MAIN)
+
+run: $(VHDL_MAIN)
+ ghdl -r $< --stop-time=$(STOP_TIME) --vcd=$<.vcd
+
+view: run
+ gtkwave $(VHDL_MAIN).vcd $(VHDL_MAIN).sav
+
+$(VHDL_MAIN): $(VHDL_MAIN).o $(VHDL_ENTITIES)
+ ghdl -e -fexplicit --ieee=synopsys $@
+
+%.o: %.vhd
+ ghdl -a -fexplicit --ieee=synopsys $<
+
+%.o: ../%.vhd
+ ghdl -a -fexplicit --ieee=synopsys $<
+
+clean:
+ rm -Rf *.o *.vcd $(VHDL_MAIN) results.txt work-obj93.cf
+
--- /dev/null
+[timestart] 0
+[size] 1280 746
+[pos] -1 -1
+*-33.403706 5839000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+@28
+clk
+pwm_out
+pwm_cyc
+pwm_cnt[1:0]
+din[1:0]
+@29
+we
+[pattern_trace] 1
+[pattern_trace] 0
--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+entity tb_pwm is
+end tb_pwm;
+
+--------------------------------------------------------------------------------
+
+architecture testbench of tb_pwm is
+
+ constant period : time := 250 ns;
+ constant offset : time := 0 us;
+
+
+ constant PWM_W : integer := 2;
+ constant CNT_MAX : integer := 2**PWM_W - 2;
+
+
+ signal clk : std_logic;
+ signal reset : std_logic;
+ signal din : std_logic_vector (PWM_W-1 downto 0);
+ signal we : std_logic;
+ signal pwm_cnt : std_logic_vector (PWM_W-1 downto 0);
+ signal pwm_cyc : std_logic;
+ signal pwm_out : std_logic;
+
+--------------------------------------------------------------------------------
+
+ component 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_cnt : in std_logic_vector (PWM_WIDTH-1 downto 0);
+ pwm_cyc : in std_logic;
+ pwm : out std_logic);
+ end component pwm;
+
+ component counter is
+ generic (
+ WIDTH : integer;
+ MAX : integer);
+ port (
+ clk : in std_logic;
+ reset : in std_logic;
+ count : out std_logic_vector (WIDTH-1 downto 0);
+ event_ow : out std_logic);
+ end component counter;
+
+--------------------------------------------------------------------------------
+
+begin
+
+ uut : pwm
+ generic map (
+ PWM_WIDTH => PWM_W)
+ port map (
+ clk => clk,
+ reset => reset,
+ din => din,
+ we => we,
+ pwm_cnt => pwm_cnt,
+ pwm_cyc => pwm_cyc,
+ pwm => pwm_out);
+
+ counter_1 : counter
+ generic map (
+ WIDTH => PWM_W,
+ MAX => CNT_MAX)
+ port map (
+ clk => clk,
+ reset => reset,
+ count => pwm_cnt,
+ event_ow => pwm_cyc);
+
+
+ CLK_PROC : process
+ begin
+ clk <= '0';
+ wait for offset;
+
+ loop
+ clk <= '1';
+ wait for period/2;
+ clk <= '0';
+ wait for period/2;
+ end loop;
+ end process;
+
+
+ RSET_PROC : process
+ begin
+ reset <= '0';
+ wait for 1.5 * period;
+ reset <= '1';
+ wait for 1 * period;
+ reset <= '0';
+ wait;
+ end process;
+
+
+ ADDR_PROC : process
+ begin
+ din <= (others => '0');
+ we <= '0';
+
+ wait for offset;
+ wait for 3 * period;
+
+ for i in 0 to 2*(2**PWM_W)-1 loop
+ din <= conv_std_logic_vector(i, PWM_W);
+ we <= '1';
+ wait for period;
+ we <= '0';
+ wait for 12*period;
+ end loop;
+
+ wait;
+ end process;
+
+end testbench;
+