]> rtime.felk.cvut.cz Git - fpga/pwm.git/commitdiff
Multiplier and vector scaling components added
authorVladimir Burian <buriavl2@fel.cvut.cz>
Thu, 14 Apr 2011 21:26:07 +0000 (23:26 +0200)
committerVladimir Burian <buriavl2@fel.cvut.cz>
Thu, 14 Apr 2011 21:45:16 +0000 (23:45 +0200)
These components are also integrated to the MCC entity so it's now possible
to close the chain (path from IRC to PWM) and changing action variable.

mcc.vhd
multiplier.vhd [new file with mode: 0644]
tb/Makefile
tb/tb_multiplier.sav [new file with mode: 0644]
tb/tb_multiplier.vhd [new file with mode: 0644]
tb/tb_vector_scale.sav [new file with mode: 0644]
tb/tb_vector_scale.vhd [new file with mode: 0644]
vector_scale.vhd [new file with mode: 0644]

diff --git a/mcc.vhd b/mcc.vhd
index 47b9879a6b5747fd9fd85c5178bf20babe424655..5513069a9c38935fad0e25290660065a00950097 100644 (file)
--- a/mcc.vhd
+++ b/mcc.vhd
@@ -52,6 +52,10 @@ architecture behavioral of mcc is
   signal MCC_MUX_CODE : std_logic_vector (MUX_W-1 downto 0);
   signal MCC_MUX_EN   : std_logic;
 
+  signal MUL_A    : std_logic_vector (15 downto 0);
+  signal MUL_B    : std_logic_vector (15 downto 0);
+  signal MUL_PROD : std_logic_vector (31 downto 0);
+  
   signal MASTER_IRF_ADR_O : std_logic_vector (IRF_ADR_W-1 downto 0);
   signal MASTER_IRF_DAT_O : std_logic_vector (15 downto 0);
   signal MASTER_IRF_STB_O : std_logic;
@@ -62,6 +66,14 @@ architecture behavioral of mcc is
   signal VECTOR_IRF_STB_O : std_logic;
   signal VECTOR_IRF_WE_O  : std_logic;
 
+  signal SCALE_IRF_ADR_O    : std_logic_vector (IRF_ADR_W-1 downto 0);
+  signal SCALE_IRF_DAT_O    : std_logic_vector (15 downto 0);
+  signal SCALE_IRF_STB_O    : std_logic;
+  signal SCALE_IRF_WE_O     : std_logic;
+  signal SCALE_SL_ACK_O     : std_logic;
+  signal SCALE_SL_IRF_ADR_O : std_logic_vector (IRF_ADR_W-1 downto 0);
+  signal SCALE_SL_STB_I     : std_logic;
+  
   signal PWM_IRF_ADR_O    : std_logic_vector (IRF_ADR_W-1 downto 0);
   signal PWM_IRF_DAT_O    : std_logic_vector (15 downto 0);
   signal PWM_IRF_STB_O    : std_logic;
@@ -101,6 +113,7 @@ begin
                IRC_IRF_ADR_O    when MCC_MUX_CODE = 0 else
                BASE_IRF_ADR_O   when MCC_MUX_CODE = 1 else
                VECTOR_IRF_ADR_O when MCC_MUX_CODE = 2 else
+               SCALE_IRF_ADR_O  when MCC_MUX_CODE = 3 else
                PWM_IRF_ADR_O    when MCC_MUX_CODE = 5 else
                (others => '-');
 
@@ -108,6 +121,7 @@ begin
                IRC_IRF_DAT_O    when MCC_MUX_CODE = 0 else
                BASE_IRF_DAT_O   when MCC_MUX_CODE = 1 else
                VECTOR_IRF_DAT_O when MCC_MUX_CODE = 2 else
+               SCALE_IRF_DAT_O  when MCC_MUX_CODE = 3 else
                PWM_IRF_DAT_O    when MCC_MUX_CODE = 5 else
                (others => '-');
 
@@ -115,6 +129,7 @@ begin
                IRC_IRF_STB_O    when MCC_MUX_CODE = 0 else
                BASE_IRF_STB_O   when MCC_MUX_CODE = 1 else
                VECTOR_IRF_STB_O when MCC_MUX_CODE = 2 else
+               SCALE_IRF_STB_O  when MCC_MUX_CODE = 3 else
                PWM_IRF_STB_O    when MCC_MUX_CODE = 5 else
                '0';
 
@@ -122,6 +137,7 @@ begin
               IRC_IRF_WE_O    when MCC_MUX_CODE = 0 else
               BASE_IRF_WE_O   when MCC_MUX_CODE = 1 else
               VECTOR_IRF_WE_O when MCC_MUX_CODE = 2 else
+              SCALE_IRF_WE_O  when MCC_MUX_CODE = 3 else
               '0';
 
 
@@ -151,6 +167,12 @@ begin
       IRF_STB_O    => MASTER_IRF_STB_O,
       IRF_WE_O     => MASTER_IRF_WE_O);
 
+  multiplier_1 : entity work.multiplier
+    port map (
+      A    => MUL_A,
+      B    => MUL_B,
+      prod => MUL_PROD);
+
   irc_dump_1 : entity work.irc_dump
     generic map (
       IRF_ADR_W => IRF_ADR_W,
@@ -198,9 +220,9 @@ begin
       IRF_ADR_W => 5,
       A_BASE => 16#04#,
       P_BASE => 16#10#,
-      P1_OFF => 16#01#,
-      P2_OFF => 16#05#,
-      P3_OFF => 16#09#)
+      P1_OFF => 16#00#,
+      P2_OFF => 16#04#,
+      P3_OFF => 16#08#)
     port map (
       ACK_O     => MCC_ACK (2),
       CLK_I     => CLK_I,
@@ -217,6 +239,47 @@ begin
       LUT_DAT_I => LUT_DAT_I,
       LUT_STB_O => LUT_STB_O);
 
+  vector_scale_sequencer : entity work.sequencer
+    generic map (
+      IRF_ADR_W => IRF_ADR_W,
+      P_BASE    => P_BASE,
+      P_SIZE    => P_SIZE)
+    port map (
+      ACK_O        => MCC_ACK (3),
+      CLK_I        => CLK_I,
+      RST_I        => RST_I,
+      STB_I        => MCC_STB (3),
+      IRF_ADR_O    => SCALE_IRF_ADR_O,
+      SL_ACK_I     => SCALE_SL_ACK_O,
+      SL_IRF_ADR_I => SCALE_SL_IRF_ADR_O,
+      SL_STB_O     => SCALE_SL_STB_I,
+      SL_MUX_CODE  => open);
+  
+  vector_scale_1 : entity work.vector_scale
+    generic map (
+      IRF_ADR_W  => IRF_ADR_W,
+      BASE       => 0,
+      SCALE_OFF  => 5,
+      PHASE_BASE => P_BASE,
+      VECTOR_OFF => 0,
+      SCALED_OFF => 1,
+      VECTOR_W   => LUT_DAT_W)
+    port map (
+      ACK_O     => SCALE_SL_ACK_O,
+      CLK_I     => CLK_I,
+      RST_I     => RST_I,
+      STB_I     => SCALE_SL_STB_I,
+      MUL_A     => MUL_A,
+      MUL_B     => MUL_B,
+      MUL_PROD  => MUL_PROD,
+      IRF_ACK_I => IRF_ACK_I,
+      IRF_ADR_O => SCALE_SL_IRF_ADR_O,
+      IRF_DAT_I => IRF_DAT_I,
+      IRF_DAT_O => SCALE_IRF_DAT_O,
+      IRF_STB_O => SCALE_IRF_STB_O,
+      IRF_WE_O  => SCALE_IRF_WE_O);
+
+  
   pwm_dump_sequencer : entity work.sequencer
     generic map (
       IRF_ADR_W => IRF_ADR_W,
diff --git a/multiplier.vhd b/multiplier.vhd
new file mode 100644 (file)
index 0000000..0a7c186
--- /dev/null
@@ -0,0 +1,26 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_signed.all;
+
+--------------------------------------------------------------------------------
+
+entity multiplier is
+  port (
+    A       : in  std_logic_vector (15 downto 0);
+    B       : in  std_logic_vector (15 downto 0);
+    prod    : out std_logic_vector (31 downto 0));
+end multiplier;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of multiplier is
+
+--------------------------------------------------------------------------------
+
+begin
+
+  prod <= A * B;
+  
+end behavioral;
+
index bcd8fbd4404bc81f15d13c04fc394c05596e8e26..87c82e0ded249bd0951cddb1508131610836bc7a 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_mcc
+VHDL_MAIN     = tb_vector_scale
 VHDL_ENTITIES = counter.o \
                 pwm.o \
                 wave_table.o \
@@ -10,6 +10,8 @@ VHDL_ENTITIES = counter.o \
                 priority_encoder.o \
                 mcc_master.o \
                 sequencer.o \
+                multiplier.o \
+                vector_scale.o \
                 pwm_dump.o \
                 irc_dump.o \
                 irc_base.o \
diff --git a/tb/tb_multiplier.sav b/tb/tb_multiplier.sav
new file mode 100644 (file)
index 0000000..fbf9fe8
--- /dev/null
@@ -0,0 +1,20 @@
+[timestart] 5270000000
+[size] 1280 769
+[pos] -1 -1
+*-32.512638 -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
+@24
+test_vector_no[31:0]
+@200
+-
+@420
+a[15:0]
+b[15:0]
+prod[31:0]
+@200
+-
+@22
+a[15:0]
+b[15:0]
+prod[31:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/tb/tb_multiplier.vhd b/tb/tb_multiplier.vhd
new file mode 100644 (file)
index 0000000..5d5aae1
--- /dev/null
@@ -0,0 +1,107 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_signed.all;
+
+entity tb_multiplier is
+end tb_multiplier;
+
+--------------------------------------------------------------------------------
+
+architecture testbench of tb_multiplier is
+
+  constant period : time := 2 us;
+  constant offset : time := 0 us;
+
+
+  signal clk      : std_logic;
+  signal reset    : std_logic;
+
+  signal A     : std_logic_vector (15 downto 0);
+  signal B     : std_logic_vector (15 downto 0);
+  signal prod  : std_logic_vector (31 downto 0);
+
+  signal test_vector_no : integer := 0;
+  
+
+  type test_vector_t is record
+    A    : std_logic_vector (15 downto 0);
+    B    : std_logic_vector (15 downto 0);
+    prod : std_logic_vector (31 downto 0);
+  end record;
+
+  type test_vector_array is array (natural range<>) of test_vector_t;
+
+  constant test_vectors : test_vector_array := (
+    (X"0000", X"0000", X"00000000"),
+    (X"0000", X"FFFF", X"00000000"),
+    (X"0001", X"0001", X"00000001"),
+    (X"7FFF", X"7FFF", X"3FFF0001"),
+    (X"FFFF", X"0001", X"FFFFFFFF"),
+    (X"FFFF", X"FFFF", X"00000001"),
+    (X"8000", X"7FFF", X"C0008000"),
+    (X"8000", X"FFFF", X"00008000"),
+    (X"8001", X"8001", X"BFFEFFFF"),
+    (X"8000", X"8000", X"C0000000"));
+  
+--------------------------------------------------------------------------------
+  
+begin
+
+  uut : entity work.multiplier
+    port map (
+      A     => A,
+      B     => B,
+      prod  => prod);
+
+  
+  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;
+
+
+  TEST_VECTOR_PROC : process
+  begin
+    A <= (others => '0');
+    B <= (others => '0');
+    
+    wait for offset;
+    wait for 3 * period;
+    
+    for i in test_vectors'RANGE loop
+      test_vector_no <= i;
+      
+      A <= test_vectors(i).A;      
+      B <= test_vectors(i).B;
+      wait for period;
+
+      assert prod = test_vectors(i).prod
+        report "Invalid product - test vector no. " & integer'image(i)
+        severity warning;
+    end loop;
+
+    wait;
+  end process;
+  
+end testbench;
+
diff --git a/tb/tb_vector_scale.sav b/tb/tb_vector_scale.sav
new file mode 100644 (file)
index 0000000..40fe479
--- /dev/null
@@ -0,0 +1,41 @@
+[timestart] 0
+[size] 1280 769
+[pos] -1 -1
+*-31.470821 -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
+rst_i
+clk_i
+stb_i
+ack_o
+@200
+-
+@22
+dbg_mem0x05[15:0]
+dbg_mem0x10[15:0]
+dbg_mem0x11[15:0]
+@200
+-
+@22
+mul_a[15:0]
+mul_b[15:0]
+mul_prod[31:0]
+@200
+-
+@28
+irf_stb_o
+irf_we_o
+@c00023
+irf_adr_o[4:0]
+@28
+(0)irf_adr_o[4:0]
+(1)irf_adr_o[4:0]
+(2)irf_adr_o[4:0]
+(3)irf_adr_o[4:0]
+(4)irf_adr_o[4:0]
+@1401201
+-group_end
+@22
+uut.irf_dat_i[15:0]
+irf_dat_o[15:0]
+[pattern_trace] 1
+[pattern_trace] 0
diff --git a/tb/tb_vector_scale.vhd b/tb/tb_vector_scale.vhd
new file mode 100644 (file)
index 0000000..b9acebb
--- /dev/null
@@ -0,0 +1,162 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_unsigned.all;
+
+entity tb_vector_scale is
+end tb_vector_scale;
+
+--------------------------------------------------------------------------------
+
+architecture testbench of tb_vector_scale is
+
+  constant period : time := 500 ns;
+  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_CYC_O : std_logic;
+  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;
+
+  signal MUL_A    : std_logic_vector (15 downto 0);
+  signal MUL_B    : std_logic_vector (15 downto 0);
+  signal MUL_PROD : std_logic_vector (31 downto 0);
+
+
+  subtype word_t is std_logic_vector (15 downto 0);
+  
+  signal dbg_mem0x05 : word_t    := (others => '0');
+  signal dbg_mem0x10 : word_t    := (others => '0');
+  signal dbg_mem0x11 : word_t    := (others => '0');
+  signal dbg_ack     : std_logic := '0';
+
+--------------------------------------------------------------------------------
+  
+begin
+
+  uut : entity work.vector_scale
+    generic map (
+      IRF_ADR_W  => IRF_ADR_W,
+      BASE       => 0,
+      SCALE_OFF  => 5,
+      PHASE_BASE => 16,
+      VECTOR_OFF => 0,
+      SCALED_OFF => 1,
+      VECTOR_W   => 10)
+    port map (
+      ACK_O     => ACK_O,
+      CLK_I     => CLK_I,
+      RST_I     => RST_I,
+      STB_I     => STB_I,
+      MUL_A     => MUL_A,
+      MUL_B     => MUL_B,
+      MUL_PROD  => MUL_PROD,
+      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);
+
+  multiplier_1 : entity work.multiplier
+    port map (
+      A    => MUL_A,
+      B    => MUL_B,
+      prod => MUL_PROD);
+
+  
+  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#05# => IRF_DAT_I <= dbg_mem0x05;
+          when 16#10# => IRF_DAT_I <= dbg_mem0x10;
+          when 16#11# => IRF_DAT_I <= dbg_mem0x11;
+          when others =>
+            IRF_DAT_I <= (others => '0');
+            report "Reading from non-existing register" severity warning;
+        end case;
+      else
+        case conv_integer(IRF_ADR_O) is
+          --when 16#05# => dbg_mem0x05 <= IRF_DAT_O;
+          --when 16#10# => dbg_mem0x10 <= IRF_DAT_O;
+          when 16#11# => dbg_mem0x11 <= 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 10 loop
+      dbg_mem0x10 <= "0000000111111111";
+      
+      dbg_mem0x05 <= conv_std_logic_vector(i*(2**10), 16);
+
+      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;
+
diff --git a/vector_scale.vhd b/vector_scale.vhd
new file mode 100644 (file)
index 0000000..05fb769
--- /dev/null
@@ -0,0 +1,123 @@
+library ieee;
+use ieee.std_logic_1164.all;
+use ieee.std_logic_arith.all;
+use ieee.std_logic_signed.all;
+
+--------------------------------------------------------------------------------
+
+entity vector_scale is
+  generic (
+    IRF_ADR_W  : integer := 5;
+    BASE       : integer := 0;
+    SCALE_OFF  : integer := 5;
+    PHASE_BASE : integer := 16;
+    VECTOR_OFF : integer := 0;
+    SCALED_OFF : integer := 1;
+    VECTOR_W   : integer := 10);
+  port (
+    -- Primary slave intefrace
+    ACK_O     : out std_logic;
+    CLK_I     : in  std_logic;
+    RST_I     : in  std_logic;
+    STB_I     : in  std_logic;
+    -- Multiplier interface
+    MUL_A     : out std_logic_vector (15 downto 0);
+    MUL_B     : out std_logic_vector (15 downto 0);
+    MUL_PROD  : in  std_logic_vector (31 downto 0);
+    -- 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 entity vector_scale;
+
+--------------------------------------------------------------------------------
+
+architecture behavioral of vector_scale is
+
+  constant SCALE_SUBDIV : integer := 10;
+  
+  type state_t is (ready, load_scale, load_vector, save_scaled, done);
+  subtype irf_adr_t is std_logic_vector (IRF_ADR_W-1 downto 0);
+
+  constant SCALE_ADR  : irf_adr_t := conv_std_logic_vector(BASE + SCALE_OFF, IRF_ADR_W);
+  constant VECTOR_ADR : irf_adr_t := conv_std_logic_vector(PHASE_BASE + VECTOR_OFF, IRF_ADR_W);
+  constant SCALED_ADR : irf_adr_t := conv_std_logic_vector(PHASE_BASE + SCALED_OFF, IRF_ADR_W);
+  
+  signal state : state_t;
+
+  signal INNER_ACK : std_logic;
+
+
+  function twos_to_biased (twos : std_logic_vector) return std_logic_vector is
+    variable result : std_logic_vector (twos'RANGE);
+  begin
+    result := twos;
+    result(result'HIGH) := not twos(twos'HIGH);
+    return result;
+  end;
+
+  function biased_to_twos (biased : std_logic_vector) return std_logic_vector is
+    variable result : std_logic_vector (biased'range);
+  begin
+    result := biased;
+    result(result'HIGH) := not biased(biased'HIGH);
+    return result;
+  end;
+  
+--------------------------------------------------------------------------------
+
+begin
+
+  ACK_O <= STB_I and INNER_ACK;
+
+  IRF_DAT_O <= "000000" & twos_to_biased(conv_std_logic_vector(signed(MUL_PROD(15+SCALE_SUBDIV downto SCALE_SUBDIV)), 10));
+
+  
+  FSM : process (CLK_I, RST_I) is
+  begin
+    if RST_I = '1' then
+      state     <= ready;
+      INNER_ACK <= '0';
+      IRF_STB_O <= '0';
+      IRF_WE_O  <= '0';
+      
+    elsif rising_edge(CLK_I) then
+      case state is
+        when ready =>
+          if STB_I = '1' then
+            state     <= load_scale;
+            IRF_ADR_O <= SCALE_ADR;
+            IRF_STB_O <= '1';
+          end if;
+
+        when load_scale =>
+          state     <= load_vector;
+          IRF_ADR_O <= VECTOR_ADR;
+
+        when load_vector =>
+          state     <= save_scaled;
+          IRF_ADR_O <= SCALED_ADR;
+          MUL_A     <= IRF_DAT_I;
+          
+        when save_scaled =>
+          state     <= done;
+          INNER_ACK <= '1';
+          IRF_WE_O  <= '1';
+          MUL_B     <= conv_std_logic_vector(signed(biased_to_twos(IRF_DAT_I(VECTOR_W-1 downto 0))), 16);
+          
+        when done =>
+          IRF_STB_O <= '0';
+          IRF_WE_O  <= '0';
+          if STB_I = '0' then
+            state     <= ready;
+            INNER_ACK <= '0';
+          end if;
+      end case;
+    end if;
+  end process;
+  
+end architecture behavioral;
+