-- Planet Earth Research Lab (PERL) -- Clemson University -- Copyright (c) 1997 All Rights Reserved. -- This part is a generic integer multiplier which -- uses bit serial multiplication. -- WIDTH_IN_1 and _2 are the number of bits of the input data -- and WIDTH_OUT determines the number of bits of output. The -- functions max and some_bits are used by the generic -- portions of the program to allow for different combinations -- of WIDTH_OUT and WIDTH_IN/ Library IEEE; use IEEE.STD_LOGIC_1164.all; use IEEE.STD_LOGIC_SIGNED.all; use IEEE.STD_LOGIC_ARITH.CONV_STD_LOGIC_VECTOR; use IEEE.STD_LOGIC_ARITH.CONV_SIGNED; use IEEE.STD_LOGIC_ARITH.SIGNED; use IEEE.STD_LOGIC_MISC.NOR_REDUCE; entity umult_shift is generic( WIDTH_IN_1 : INTEGER := 32; WIDTH_IN_2 : INTEGER := 32; WIDTH_OUT : INTEGER := 32; LOG2ITER : INTEGER := 6); -- Log 2 of WIDTH_IN_1 port( clk : in std_logic; rst : in std_logic; ffin1 : in std_logic; -- input reg. full flag ffin2 : in std_logic; -- input reg. full flag ffout : in std_logic; -- output reg. full flag data_in_1 : in STD_LOGIC_VECTOR(WIDTH_IN_1 - 1 downto 0); data_in_2 : in STD_LOGIC_VECTOR(WIDTH_IN_2 - 1 downto 0); write : out std_logic; -- write signal to output reg. read : out std_logic; -- read signal to input reg. data_out : out std_logic_vector(WIDTH_OUT - 1 downto 0)); end umult_shift; architecture behavioral of umult_shift is function max(L, R: INTEGER) return INTEGER is begin if L > R then return L; else return R; end if; end; function some_bits(K,L: STD_LOGIC_VECTOR; R: INTEGER) return STD_LOGIC_VECTOR is begin if R = 0 then return K; else return K & L(R downto 1); end if; end; -- State definitions constant WAIT_FOR_GO : std_logic_vector(4 downto 0) := "00001"; constant LATCH : std_logic_vector(4 downto 0) := "00010"; constant ADD : std_logic_vector(4 downto 0) := "00100"; constant HOLD : std_logic_vector(4 downto 0) := "01000"; constant DONE_STATE : std_logic_vector(4 downto 0) := "10000"; signal STATE : std_logic_vector(4 downto 0); signal NEXT_STATE : std_logic_vector(4 downto 0); constant DONT_CARE5 : std_logic_vector(4 downto 0) := "XXXXX"; -- Constants used for future case statement constant ADD1 : std_logic := '1'; constant ADD2 : std_logic := '0'; -- Internal data signals signal sum : std_logic_vector (max(WIDTH_IN_2, WIDTH_OUT) + 1 downto 0); signal add_out : std_logic_vector(WIDTH_IN_2 downto 0); signal in_store1 : std_logic_vector(WIDTH_IN_1 - 1 downto 0); signal in_store2 : std_logic_vector(WIDTH_IN_2 - 1 downto 0); -- Internal control flags signal muxselect : std_logic; signal add_en : std_logic; signal in_load_en : std_logic; signal internal_wr : std_logic; signal dec_count : std_logic; -- Holds running total of addition steps in the multiplication signal count : STD_LOGIC_VECTOR(LOG2ITER - 1 downto 0); -- Constants used to allow for various combinations of WIDTH_OUT -- and WIDTH_IN. constant EXTRA : INTEGER := max(0, (WIDTH_OUT - WIDTH_IN_2)); constant EXTRA1 : INTEGER := max(0, (WIDTH_IN_2 - WIDTH_OUT)); begin -- Continuous assignment signals write <= STATE(4); read <= STATE(1); data_out <= sum(max(WIDTH_IN_2, WIDTH_OUT) - 1 downto EXTRA1); -- assignment of internal control signals muxselect <= in_store1(0); in_load_en <= STATE(1); add_en <= STATE(2); internal_wr <= STATE(4); dec_count <= add_en; -- Finite State Machine process(STATE, ffin1, ffin2, in_store1, ffout, count) begin case STATE is -- wait for both data inputs to become available when WAIT_FOR_GO => if ffin1 = '1' and ffin2 = '1' then NEXT_STATE <= LATCH; else NEXT_STATE <= WAIT_FOR_GO; end if; -- latch data_in_1 and _2 into in_store1 and 2 registers when LATCH => NEXT_STATE <= ADD; -- performs multiplication when ADD => if (NOR_REDUCE(count) = '0') then NEXT_STATE <= ADD; elsif ffout = '0' then NEXT_STATE <= DONE_STATE; else NEXT_STATE <= HOLD; end if; -- if following register is full, wait here until empty when HOLD => if ffout='0' then NEXT_STATE <= DONE_STATE; else NEXT_STATE <= HOLD; end if; -- write the result to following register when DONE_STATE => if ffin1 = '1' and ffin2 = '1' then NEXT_STATE <= LATCH; else NEXT_STATE <= WAIT_FOR_GO; end if; when others => NEXT_STATE <= DONT_CARE5; end case; end process; -- This process controls the latching of the inputs and the -- right shifting of in_store1 after each add cycle during -- the multiplication. in_store1 must be shifted in order -- to determine whether to add or not in the multiplication -- steps process(clk, rst) begin if rst = '1' then in_store1 <= CONV_STD_LOGIC_VECTOR(0, WIDTH_IN_1); elsif clk'event and clk='1' then if in_load_en = '1' then in_store1 <= data_in_1; else in_store1 <= '0' & in_store1(WIDTH_IN_1 - 1 downto 1); end if; end if; end process; -- latches data_in_2 into the in_store2 process(clk, rst) begin if rst = '1' then in_store2 <= CONV_STD_LOGIC_VECTOR(0, WIDTH_IN_2); elsif clk'event and clk='1' then if in_load_en = '1' then in_store2 <= data_in_2; end if; end if; end process; process(clk, rst) begin if rst = '1' then STATE <= WAIT_FOR_GO; elsif clk'event and clk='1' then STATE <= NEXT_STATE; end if; end process; -- determines whether to add or not in the multiplication steps -- (based on the low order bit of in_store1) and performs the -- addition. process(muxselect, in_store2, sum) begin CASE muxselect is when ADD1 => add_out <= sum(max(WIDTH_OUT, WIDTH_IN_2) + 1 downto EXTRA + 1) + ('0' & in_store2); when ADD2 => add_out <= sum(max(WIDTH_OUT, WIDTH_IN_2) + 1 downto EXTRA + 1); when others => add_out <= sum(max(WIDTH_OUT, WIDTH_IN_2) + 1 downto EXTRA + 1); end case; end process; -- latches the running sum after each addition step. process(clk, rst) begin if rst = '1' then sum <= CONV_STD_LOGIC_VECTOR(0, max(WIDTH_IN_2, WIDTH_OUT) + 2); elsif ( clk'event and clk = '1' ) then if ( add_en = '1' ) then sum <= '0' & some_bits(add_out(WIDTH_IN_2 downto 0), sum, EXTRA); -- Re-initialize the internal register elsif ( internal_wr = '1' ) then sum <= CONV_STD_LOGIC_VECTOR(0, max(WIDTH_IN_2, WIDTH_OUT) + 2); end if; end if; end process; -- keeps track of number of addition steps performed and resets -- the counter for each new multiplication. process(clk, rst) begin if rst = '1' then count <= CONV_STD_LOGIC_VECTOR(WIDTH_IN_1, LOG2ITER+1)(LOG2ITER-1 downto 0); -- coded to NUM_TERMS elsif (clk'event and clk = '1') then if (dec_count = '1') then if (NOR_REDUCE(count) = '1') then count <= CONV_STD_LOGIC_VECTOR(WIDTH_IN_1, LOG2ITER+1)(LOG2ITER-1 downto 0); -- coded to NUM_TERMS else count <= count - 1; -- low order zero first compare end if; end if; end if; end process; end behavioral;