X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=src%2Falu.vhd;h=3a8f54c67ff4d20a9cdc55c74f32ca0da61b878a;hb=67bd159bb1c72ba8eaf46e072932a6f19c8347b6;hp=caff4958e91f011f31ee3def3a854fe3ad9f6db9;hpb=a7c7f6d9cce95dd1707828ca6ddc9f6a5ee9dadf;p=hwmod.git diff --git a/src/alu.vhd b/src/alu.vhd index caff495..3a8f54c 100644 --- a/src/alu.vhd +++ b/src/alu.vhd @@ -12,25 +12,33 @@ entity alu is op1 : in csigned; op2 : in csigned; op3 : out csigned; + opM : out csigned; do_calc : in std_logic; - calc_done : out std_logic - -- TODO: hier debug ports hinzufuegen ;) + calc_done : out std_logic; + calc_error : out std_logic ); end entity alu; architecture beh of alu is - type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDIV_DONE, SDONE); + type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDIV_DONE, + SDONE, SERROR); signal state_int, state_next : ALU_STATE; - signal done_intern, div_calc_done, div_go_calc : std_logic; - signal op3_int, op3_next : csigned := (others => '0'); + signal done_intern, error_intern : std_logic; + signal div_calc_done_int : std_logic; + signal div_calc_done2_int : std_logic; + signal div_go_calc_int : std_logic; + signal op3_int, op3_next, opM_int, opM_next : csigned; signal calc_done_int, calc_done_next : std_logic; + signal calc_error_int, calc_error_next : std_logic; -- signale fuer division - signal dividend_msb_int, dividend_msb_next, laengediv_int, laengediv_next : natural; + signal dividend_msb_int, dividend_msb_next, laengediv_int, laengediv_next : divinteger; signal quo_int, quo_next, aktdiv_int, aktdiv_int_next, op1_int, op1_next, op2_int, op2_next : csigned; signal sign_int, sign_next : std_logic; begin op3 <= op3_int; + opM <= opM_int; calc_done <= calc_done_int; + calc_error <= calc_error_int; -- sync process(sys_clk, sys_res_n) @@ -38,7 +46,9 @@ begin if sys_res_n = '0' then state_int <= SIDLE; op3_int <= (others => '0'); + opM_int <= (others => '0'); calc_done_int <= '0'; + calc_error_int <= '0'; --div dividend_msb_int <= 0; laengediv_int <= 0; @@ -50,7 +60,9 @@ begin elsif rising_edge(sys_clk) then state_int <= state_next; op3_int <= op3_next; + opM_int <= opM_next; calc_done_int <= calc_done_next; + calc_error_int <= calc_error_next; -- div dividend_msb_int <= dividend_msb_next; laengediv_int <= laengediv_next; @@ -63,7 +75,8 @@ begin end process; -- next state - process(state_int, opcode, done_intern, do_calc, div_calc_done, div_go_calc) + process(state_int, opcode, done_intern, error_intern, do_calc, + div_calc_done_int, div_calc_done2_int, div_go_calc_int) begin -- set a default value for next state state_next <= state_int; @@ -88,15 +101,24 @@ begin if done_intern = '1' then state_next <= SDONE; end if; + if error_intern = '1' then + state_next <= SERROR; + end if; when SDIV => - if div_go_calc = '1' then + if div_go_calc_int = '1' then state_next <= SDIV_CALC; end if; + if div_calc_done2_int = '1' then + state_next <= SDIV_DONE; + end if; + if error_intern = '1' then + state_next <= SERROR; + end if; when SDIV_CALC => - if div_calc_done = '1' then + if div_calc_done_int = '1' then state_next <= SDIV_DONE; end if; - when SDONE => + when SDONE | SERROR => if do_calc = '0' then state_next <= SIDLE; end if; @@ -104,54 +126,88 @@ begin end process; -- output - process(state_int, op1, op2, dividend_msb_int, laengediv_int, quo_int, aktdiv_int, sign_int, op1_int, op2_int, op3_int) - variable multmp : signed(((2*CBITS)-1) downto 0); + process(state_int, op1, op2, dividend_msb_int, laengediv_int, quo_int, + aktdiv_int, sign_int, op1_int, op2_int, op3_int, opM_int) + variable multmp, multmp2 : signed(((2*CBITS)-1) downto 0); + variable mulsign : std_logic; + variable tmp : csigned; -- vars fuer div - variable laengediv_var, dividend_msb_var : natural; + variable laengediv_var, dividend_msb_var, divtmp : divinteger; variable aktdiv_int_var, quo_var, op1_var, op2_var : csigned; begin calc_done_next <= '0'; - div_calc_done <= '0'; - div_go_calc <= '0'; + calc_error_next <= '0'; + div_calc_done_int <= '0'; + div_calc_done2_int <= '0'; + div_go_calc_int <= '0'; done_intern <= '0'; + error_intern <= '0'; -- default fuer div dividend_msb_next <= 0; laengediv_next <= 0; quo_next <= (others => '0'); - aktdiv_int_next <= (others => '0'); + aktdiv_int_next <= aktdiv_int; op1_next <= (others => '0'); op2_next <= (others => '0'); sign_next <= '0'; - op3_next <= (others => '0'); + op3_next <= op3_int; + opM_next <= opM_int; case state_int is when SIDLE => - null; + opM_next <= (others => '0'); + aktdiv_int_next <= (others => '0'); when SADD => - op3_next <= op1 + op2; - done_intern <= '1'; + tmp := op1 + op2; + op3_next <= tmp; + + -- over- bzw. underflow? + if (op1(CBITS-1) = op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then + error_intern <= '1'; + else + done_intern <= '1'; + end if; when SSUB => - op3_next <= op1 - op2; - done_intern <= '1'; + tmp := op1 - op2; + op3_next <= tmp; + + -- over- bzw. underflow? + if (op1(CBITS-1) /= op2(CBITS-1)) and (op1(CBITS-1) /= tmp(CBITS -1)) then + error_intern <= '1'; + else + done_intern <= '1'; + end if; when SMUL => + mulsign := op1(CBITS-1) xor op2(CBITS-1); multmp := op1 * op2; - op3_next(CBITS-1) <= multmp((2*CBITS)-1); op3_next((CBITS-2) downto 0) <= multmp((CBITS-2) downto 0); - done_intern <= '1'; + op3_next(CBITS-1) <= mulsign; + + if mulsign = '1' then + multmp2 := (not multmp) + 1; + else + multmp2 := multmp; + end if; + -- overflow? + if(multmp2((2*CBITS)-2 downto (CBITS-1)) > 0) then + error_intern <= '1'; + else + done_intern <= '1'; + end if; + when SDIV => -- division implementiert nach ~hwmod/doc/division.pdf - if op2 = to_signed(0,CBITS) then - -- TODO: err out signal - done_intern <= '1'; + if ((op1 = x"80000000" and op2 = to_signed(-1, CBITS)) or op2 = to_signed(0, CBITS)) then + error_intern <= '1'; else -- sign check op1_var := op1; op2_var := op2; if op1(CBITS-1) = '1' then - op1_var := not (op1_var + 1); + op1_var := (not op1_var) + 1; end if; if op2(CBITS-1) = '1' then - op2_var := not (op2_var + 1); + op2_var := (not op2_var) + 1; end if; dividend_msb_var := find_msb(op1_var)-1; @@ -159,18 +215,34 @@ begin aktdiv_int_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); + -- anmerkung: xst (xilinx) kann folgende zeile nicht uebersetzen + -- > if op1 = to_signed(-2147483648, CBITS) then + -- darum folgende schreibweise -> + if op1 = x"80000000" then + -- so ziemlich das boeseste was passieren kann + div_calc_done2_int <= '1'; + quo_next <= to_signed(-214748364,CBITS); + aktdiv_int_next <= to_signed(8,CBITS); + elsif (op1_var < op2_var) then + div_calc_done2_int <= '1'; + quo_next <= to_signed(0,CBITS); + aktdiv_int_next <= op1_var; + else + div_go_calc_int <= '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; end if; when SDIV_CALC => - if (dividend_msb_int - laengediv_int + 1) > 0 then + divtmp := dividend_msb_int - laengediv_int + 1; + + if divtmp > 0 then aktdiv_int_var := aktdiv_int sll 1; - aktdiv_int_var(0) := op1_int(dividend_msb_int - laengediv_int); + aktdiv_int_var(0) := op1_int(divtmp - 1); quo_var := quo_int sll 1; if aktdiv_int_var >= op2_int then @@ -191,14 +263,17 @@ begin else quo_next <= quo_int; end if; - div_calc_done <= '1'; + div_calc_done_int <= '1'; end if; when SDIV_DONE => op3_next <= quo_int; + opM_next <= aktdiv_int; done_intern <= '1'; - when SDONE => + when SDONE | SERROR => calc_done_next <= '1'; - op3_next <= op3_int; + if (state_int = SERROR) then + calc_error_next <= '1'; + end if; end case; end process; end architecture beh;