library ieee; use ieee.std_logic_1164.all; use ieee.numeric_std.all; use work.gen_pkg.all; entity alu is port ( sys_clk : in std_logic; sys_res_n : in std_logic; opcode : in alu_ops; op1 : in csigned; op2 : in csigned; op3 : out csigned; do_calc : in std_logic; calc_done : out std_logic -- TODO: hier debug ports hinzufuegen ;) ); end entity alu; architecture beh of alu is type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDIV_DONE, SDONE); signal state_int, state_next : ALU_STATE; signal done_intern, div_calc_done, div_go_calc : std_logic; signal op3_int, op3_next : csigned; signal calc_done_int, calc_done_next : std_logic; -- signale fuer division signal dividend_msb_int, dividend_msb_next, laengediv_int, laengediv_next : natural; signal quo_int, quo_next, aktdiv, aktdiv_next, op1_int, op1_next, op2_int, op2_next : csigned; signal sign_int, sign_next : std_logic; begin op3 <= op3_int; calc_done <= calc_done_int; -- sync process(sys_clk, sys_res_n) begin if sys_res_n = '0' then state_int <= SIDLE; op3_int <= (others => '0'); calc_done_int <= '0'; --div dividend_msb_int <= 0; laengediv_int <= 0; quo_int <= (others => '0'); aktdiv <= (others => '0'); op1_int <= (others => '0'); op2_int <= (others => '0'); sign_int <= '0'; elsif rising_edge(sys_clk) then state_int <= state_next; op3_int <= op3_next; calc_done_int <= calc_done_next; -- div dividend_msb_int <= dividend_msb_next; laengediv_int <= laengediv_next; quo_int <= quo_next; aktdiv <= aktdiv_next; op1_int <= op1_next; op2_int <= op2_next; sign_int <= sign_next; end if; end process; -- next state process(state_int, opcode, done_intern, do_calc, div_calc_done, div_go_calc) begin -- set a default value for next state state_next <= state_int; -- next state berechnen case state_int is when SIDLE => if do_calc = '1' then case opcode is when ALU_ADD => state_next <= SADD; when ALU_SUB => state_next <= SSUB; when ALU_MUL => state_next <= SMUL; when ALU_DIV => state_next <= SDIV; when others => state_next <= SIDLE; end case; end if; when SADD => if done_intern = '1' then state_next <= SDONE; end if; when SSUB => if done_intern = '1' then state_next <= SDONE; end if; when SMUL => if done_intern = '1' then state_next <= SDONE; end if; when SDIV => if div_go_calc = '1' then state_next <= SDIV_CALC; end if; when SDIV_CALC => if div_calc_done = '1' then state_next <= SDIV_DONE; end if; when SDIV_DONE => if done_intern = '1' then state_next <= SDONE; end if; when SDONE => if do_calc = '0' then state_next <= SIDLE; end if; end case; end process; -- output process(state_int, op1, op2, dividend_msb_int, laengediv_int, quo_int, aktdiv, sign_int, op1_int, op2_int) variable tmperg : csigned; variable multmp : signed(((2*CBITS)-1) downto 0); -- vars fuer div variable laengediv_var, dividend_msb_var : natural; variable aktdiv_var, quo_var, op1_var, op2_var : csigned; begin op3_next <= (others => '0'); calc_done_next <= '0'; div_calc_done <= '0'; div_go_calc <= '0'; done_intern <= '0'; -- default fuer div dividend_msb_next <= 0; laengediv_next <= 0; quo_next <= (others => '0'); aktdiv_next <= (others => '0'); op1_next <= (others => '0'); op2_next <= (others => '0'); sign_next <= '0'; case state_int is when SIDLE => tmperg := (others => '0'); when SADD => tmperg := op1 + op2; done_intern <= '1'; when SSUB => tmperg := op1 - op2; done_intern <= '1'; when SMUL => multmp := op1 * op2; tmperg(CBITS-1) := multmp((2*CBITS)-1); tmperg((CBITS-2) downto 0) := multmp((CBITS-2) downto 0); done_intern <= '1'; when SDIV => -- division implementiert nach ~hwmod/doc/division.pdf tmperg := (others => '0'); if op2 = to_signed(0,CBITS) then -- TODO: err out signal done_intern <= '1'; else -- sign check op1_var := op1; op2_var := op2; if op1(CBITS-1) = '1' then op1_var := not (op1_var + 1); end if; if op2(CBITS-1) = '1' then op2_var := not (op2_var + 1); end if; dividend_msb_var := find_msb(op1_var)-1; laengediv_var := find_msb(op2_var)-1; aktdiv_next <= op1_var srl (dividend_msb_var - laengediv_var + 1); div_go_calc <= '1'; dividend_msb_next <= dividend_msb_var; laengediv_next <= laengediv_var; quo_next <= (others => '0'); op1_next <= op1_var; op2_next <= op2_var; sign_next <= op1(CBITS-1) xor op2(CBITS-1); end if; when SDIV_CALC => tmperg := (others => '0'); if (dividend_msb_int - laengediv_int + 1) > 0 then aktdiv_var := aktdiv sll 1; aktdiv_var(0) := op1_int(dividend_msb_int - laengediv_int); quo_var := quo_int sll 1; if aktdiv_var >= op2_int then quo_var(0) := '1'; aktdiv_var := aktdiv_var - op2_int; end if; quo_next <= quo_var; aktdiv_next <= aktdiv_var; dividend_msb_next <= dividend_msb_int; laengediv_next <= laengediv_int + 1; op1_next <= op1_int; op2_next <= op2_int; sign_next <= sign_int; else if sign_int = '1' then quo_next <= (not quo_int) + 1; else quo_next <= quo_int; end if; div_calc_done <= '1'; end if; when SDIV_DONE => tmperg := quo_int; done_intern <= '1'; when SDONE => done_intern <= '1'; calc_done_next <= '1'; op3_next <= tmperg; tmperg := (others => '0'); end case; end process; end architecture beh;