From 04741b79c09e92f4ed65047def66837b8f5b5d9e Mon Sep 17 00:00:00 2001 From: Vladimir Burian Date: Thu, 14 Apr 2011 23:26:07 +0200 Subject: [PATCH] Multiplier and vector scaling components added 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 | 69 +++++++++++++++++- multiplier.vhd | 26 +++++++ tb/Makefile | 4 +- tb/tb_multiplier.sav | 20 +++++ tb/tb_multiplier.vhd | 107 +++++++++++++++++++++++++++ tb/tb_vector_scale.sav | 41 +++++++++++ tb/tb_vector_scale.vhd | 162 +++++++++++++++++++++++++++++++++++++++++ vector_scale.vhd | 123 +++++++++++++++++++++++++++++++ 8 files changed, 548 insertions(+), 4 deletions(-) create mode 100644 multiplier.vhd create mode 100644 tb/tb_multiplier.sav create mode 100644 tb/tb_multiplier.vhd create mode 100644 tb/tb_vector_scale.sav create mode 100644 tb/tb_vector_scale.vhd create mode 100644 vector_scale.vhd diff --git a/mcc.vhd b/mcc.vhd index 47b9879..5513069 100644 --- 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 index 0000000..0a7c186 --- /dev/null +++ b/multiplier.vhd @@ -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; + diff --git a/tb/Makefile b/tb/Makefile index bcd8fbd..87c82e0 100644 --- a/tb/Makefile +++ b/tb/Makefile @@ -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 index 0000000..fbf9fe8 --- /dev/null +++ b/tb/tb_multiplier.sav @@ -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 index 0000000..5d5aae1 --- /dev/null +++ b/tb/tb_multiplier.vhd @@ -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 index 0000000..40fe479 --- /dev/null +++ b/tb/tb_vector_scale.sav @@ -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 index 0000000..b9acebb --- /dev/null +++ b/tb/tb_vector_scale.vhd @@ -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 index 0000000..05fb769 --- /dev/null +++ b/vector_scale.vhd @@ -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; + -- 2.39.2