]> rtime.felk.cvut.cz Git - fpga/pwm.git/commitdiff
Added pwm_min component.
authorVladimir Burian <buriavl2@fel.cvut.cz>
Wed, 18 May 2011 22:00:07 +0000 (00:00 +0200)
committerVladimir Burian <buriavl2@fel.cvut.cz>
Wed, 18 May 2011 22:00:07 +0000 (00:00 +0200)
This component computes minimal value pro all pwm values. Is useful when
implementing modified sin wave switching.

pwm_min.vhd [new file with mode: 0644]
tb/Makefile
tb/tb_pwm_min.sav [new file with mode: 0644]
tb/tb_pwm_min.vhd [new file with mode: 0644]

diff --git a/pwm_min.vhd b/pwm_min.vhd
new file mode 100644 (file)
index 0000000..df0b248
--- /dev/null
@@ -0,0 +1,134 @@
+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;
index 87c82e0ded249bd0951cddb1508131610836bc7a..99cabe9bae82022c961696e12b73b15c4e356dcf 100644 (file)
@@ -2,7 +2,7 @@
 # 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 \
@@ -15,6 +15,7 @@ VHDL_ENTITIES = counter.o \
                 pwm_dump.o \
                 irc_dump.o \
                 irc_base.o \
+                pwm_min.o \
                 mcc.o
 
 
diff --git a/tb/tb_pwm_min.sav b/tb/tb_pwm_min.sav
new file mode 100644 (file)
index 0000000..9166f57
--- /dev/null
@@ -0,0 +1,18 @@
+[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
diff --git a/tb/tb_pwm_min.vhd b/tb/tb_pwm_min.vhd
new file mode 100644 (file)
index 0000000..33a0619
--- /dev/null
@@ -0,0 +1,147 @@
+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;
+