--- /dev/null
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+--------------------------------------------------------------------------------
+
+entity pwm_min is
+ generic (
+ IRF_ADR_W : integer := 5;
+ PWM_W : integer := 10;
+ BASE : integer := 0;
+ PWMMIN_OFF : integer := 6;
+ P_BASE : integer := 16;
+ P_SIZE : integer := 4;
+ PWM_OFF : integer := 1);
+ port (
+ -- Primary Slave interface
+ ACK_O : out std_logic;
+ CLK_I : in std_logic;
+ RST_I : in std_logic;
+ STB_I : in std_logic;
+ -- Shared dual-port memory
+ IRF_ACK_I : in std_logic;
+ IRF_ADR_O : out std_logic_vector (IRF_ADR_W-1 downto 0);
+ IRF_DAT_I : in std_logic_vector (15 downto 0);
+ IRF_DAT_O : out std_logic_vector (15 downto 0);
+ IRF_STB_O : out std_logic;
+ IRF_WE_O : out std_logic);
+end pwm_min;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of pwm_min is
+
+ type state_t is (ready, phase1, phase2, phase3, done);
+ subtype irf_adr_t is std_logic_vector (IRF_ADR_W-1 downto 0);
+
+ constant PWMMIN : irf_adr_t := conv_std_logic_vector(BASE+PWMMIN_OFF, IRF_ADR_W);
+ constant PWM1 : irf_adr_t := conv_std_logic_vector(P_BASE+PWM_OFF+0*P_SIZE, IRF_ADR_W);
+ constant PWM2 : irf_adr_t := conv_std_logic_vector(P_BASE+PWM_OFF+1*P_SIZE, IRF_ADR_W);
+ constant PWM3 : irf_adr_t := conv_std_logic_vector(P_BASE+PWM_OFF+2*P_SIZE, IRF_ADR_W);
+
+ signal state : state_t := ready;
+
+ signal pwm_adr : std_logic_vector (IRF_ADR_W-1 downto 0);
+ --signal pwm_compare : std_logic_vector (PWM_W-1 downto 0);
+ signal pwm_compare : std_logic_vector (PWM_W-1 downto 0);
+ signal pwm_less : std_logic;
+ signal write_min : std_logic;
+
+ signal ack : std_logic := '0';
+ signal irf_stb : std_logic := '0';
+ signal irf_we : std_logic;
+
+--------------------------------------------------------------------------------
+
+begin
+
+ ACK_O <= ack and STB_I;
+
+ IRF_ADR_O <= PWMMIN when write_min = '1' else pwm_adr;
+ IRF_DAT_O <= IRF_DAT_I;
+ IRF_STB_O <= irf_stb and (not write_min or irf_we);
+ IRF_WE_O <= irf_we;
+
+ pwm_less <= '1' when IRF_DAT_I(pwm_compare'RANGE) < pwm_compare else '0';
+ irf_we <= '1' when (pwm_less = '1' or state = phase1) and write_min = '1' else '0';
+
+ process (CLK_I) is
+ begin
+ if rising_edge(CLK_I) then
+ if irf_we = '1' then
+ pwm_compare <= IRF_DAT_I(pwm_compare'RANGE);
+ end if;
+ end if;
+ end process;
+
+
+ FSM : process (CLK_I) is
+ begin
+ if rising_edge(CLK_I) then
+ if RST_I = '1' then
+ state <= ready;
+ ack <= '0';
+ irf_stb <= '0';
+
+ else
+ case state is
+ when ready =>
+ if STB_I = '1' then
+ state <= phase1;
+ pwm_adr <= PWM1;
+ irf_stb <= '1';
+ write_min <= '0';
+ end if;
+
+ when phase1 =>
+ write_min <= '1';
+ if write_min = '1' then
+ state <= phase2;
+ pwm_adr <= PWM2;
+ write_min <= '0';
+ end if;
+
+ when phase2 =>
+ write_min <= '1';
+ if write_min = '1' then
+ state <= phase3;
+ pwm_adr <= PWM3;
+ write_min <= '0';
+ end if;
+
+ when phase3 =>
+ write_min <= '1';
+ if write_min = '1' then
+ state <= done;
+ ack <= '1';
+ irf_stb <= '0';
+ write_min <= '0';
+ end if;
+
+ when done =>
+ if STB_I = '0' then
+ state <= ready;
+ ack <= '0';
+ end if;
+ end case;
+
+ end if;
+ end if;
+ end process;
+
+end behavioral;
# bottom to up order (e.g. the top entity is the last in this list). Otherwise
# it won't compile.
-VHDL_MAIN = tb_vector_scale
+VHDL_MAIN = tb_pwm_min
VHDL_ENTITIES = counter.o \
pwm.o \
wave_table.o \
pwm_dump.o \
irc_dump.o \
irc_base.o \
+ pwm_min.o \
mcc.o
--- /dev/null
+[timestart] 0
+[size] 1000 600
+[pos] -108 63
+*-34.055782 -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 -1
+@28
+clk_i
+stb_i
+ack_o
+@200
+-
+@22
+dbg_mem0x06[15:0]
+dbg_mem0x11[15:0]
+dbg_mem0x15[15:0]
+@23
+dbg_mem0x19[15:0]
+[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_min is
+end tb_pwm_min;
+
+--------------------------------------------------------------------------------
+
+architecture testbench of tb_pwm_min is
+
+ constant period : time := 1 us;
+ constant offset : time := 0 us;
+
+ constant IRF_ADR_W : integer := 5;
+
+
+ signal ACK_O : std_logic;
+ signal CLK_I : std_logic;
+ signal RST_I : std_logic;
+ signal STB_I : std_logic;
+
+ signal IRF_ACK_I : std_logic;
+ signal IRF_ADR_O : std_logic_vector (IRF_ADR_W-1 downto 0);
+ signal IRF_DAT_I : std_logic_vector (15 downto 0);
+ signal IRF_DAT_O : std_logic_vector (15 downto 0);
+ signal IRF_STB_O : std_logic;
+ signal IRF_WE_O : std_logic;
+
+ subtype word_t is std_logic_vector (15 downto 0);
+
+ signal dbg_ack : std_logic := '0';
+
+ signal dbg_mem0x06 : word_t := (others => '0');
+ signal dbg_mem0x11 : word_t := (others => '0');
+ signal dbg_mem0x15 : word_t := (others => '0');
+ signal dbg_mem0x19 : word_t := (others => '0');
+
+--------------------------------------------------------------------------------
+
+begin
+
+ uut : entity work.pwm_min
+ generic map (
+ IRF_ADR_W => IRF_ADR_W,
+ PWM_W => 10,
+ BASE => 0,
+ PWMMIN_OFF => 16#06#,
+ P_BASE => 16#10#,
+ P_SIZE => 4,
+ PWM_OFF => 1)
+ port map (
+ ACK_O => ACK_O,
+ CLK_I => CLK_I,
+ RST_I => RST_I,
+ STB_I => STB_I,
+ IRF_ACK_I => IRF_ACK_I,
+ IRF_ADR_O => IRF_ADR_O,
+ IRF_DAT_I => IRF_DAT_I,
+ IRF_DAT_O => IRF_DAT_O,
+ IRF_STB_O => IRF_STB_O,
+ IRF_WE_O => IRF_WE_O);
+
+
+ SYSCON_CLK : process is
+ begin
+ CLK_I <= '0';
+ wait for offset;
+ loop
+ CLK_I <= '1';
+ wait for period/2;
+ CLK_I <= '0';
+ wait for period/2;
+ end loop;
+ end process;
+
+ SYSCON_RST : process is
+ begin
+ RST_I <= '0';
+ wait for offset;
+ wait for 0.75*period;
+ RST_I <= '1';
+ wait for 2*period;
+ RST_I <= '0';
+ wait;
+ end process;
+
+
+ DBG_MEM : process (IRF_STB_O, CLK_I) is
+ begin
+ IRF_ACK_I <= IRF_STB_O and (IRF_WE_O or dbg_ack);
+
+ if rising_edge(CLK_I) then
+ dbg_ack <= IRF_STB_O;
+ end if;
+
+ if rising_edge(CLK_I) and IRF_STB_O = '1' then
+ if IRF_WE_O = '0' then
+ case conv_integer(IRF_ADR_O) is
+ when 16#11# => IRF_DAT_I <= dbg_mem0x11;
+ when 16#15# => IRF_DAT_I <= dbg_mem0x15;
+ when 16#19# => IRF_DAT_I <= dbg_mem0x19;
+ when others =>
+ IRF_DAT_I <= (others => 'X');
+ report "Reading from non-readable register" severity warning;
+ end case;
+ else
+ case conv_integer(IRF_ADR_O) is
+ when 16#06# => dbg_mem0x06 <= IRF_DAT_O;
+ when others =>
+ report "Writing to read-only registers" severity error;
+ end case;
+ end if;
+ end if;
+ end process;
+
+--------------------------------------------------------------------------------
+
+ UUT_FEED : process is
+ begin
+ STB_I <= '0';
+
+ wait for offset;
+ wait for 4*period;
+
+ for i in 0 to 0 loop
+ dbg_mem0x11 <= "0000000111111111";
+ dbg_mem0x15 <= "0000000000100000";
+ dbg_mem0x19 <= "0000000001000000";
+
+ wait for 0.75*period;
+ STB_I <= '1';
+ wait for 0.25*period;
+ wait until rising_edge(CLK_I) and ACK_O = '1';
+ wait for 0.25*period;
+ STB_I <= '0';
+ wait for 0.75*period;
+
+ wait for 4*period;
+ end loop;
+
+ wait;
+ end process;
+
+end testbench;
+