From: Bernhard Urban Date: Mon, 24 May 2010 13:10:23 +0000 (+0200) Subject: alu: refactor von drei prozessmodell auf zwei prozessmodell X-Git-Tag: abgabe~54 X-Git-Url: http://wien.tomnetworks.com/gitweb/?p=hwmod.git;a=commitdiff_plain;h=add09426c37207967bc917a7ada78a05f7c47eb2 alu: refactor von drei prozessmodell auf zwei prozessmodell von 3030 auf 3029 logic elements :P --- diff --git a/src/alu.vhd b/src/alu.vhd index f3eb81c..b6211ba 100644 --- a/src/alu.vhd +++ b/src/alu.vhd @@ -22,8 +22,6 @@ end entity alu; architecture beh of alu is type ALU_STATE is (SIDLE, SADD, SSUB, SMUL, SDIV, SDIV_CALC, SDONE, SERROR); signal state_int, state_next : ALU_STATE; - signal done_intern, error_intern : 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; @@ -71,48 +69,58 @@ begin end if; end process; - -- next state - process(state_int, opcode, done_intern, error_intern, do_calc, div_go_calc_int) - 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 | SSUB | SMUL | SDIV | SDIV_CALC => - case state_int is - when SDIV => - if div_go_calc_int = '1' then - state_next <= SDIV_CALC; - end if; - when others => null; - end case; - if done_intern = '1' then - state_next <= SDONE; - end if; - if error_intern = '1' then - state_next <= SERROR; - end if; - when SDONE | SERROR => - if do_calc = '0' then - state_next <= SIDLE; + -- next state & out + process(opcode, do_calc, state_int, op1, op2, dividend_msb_int, + laengediv_int, quo_int, aktdiv_int, sign_int, op1_int, op2_int, + op3_int, opM_int) + -- http://www.velocityreviews.com/forums/showpost.php?p=137148&postcount=5 + function find_msb(a : std_logic_vector) return std_logic_vector is + function bits_to_fit(n : positive) return natural is + variable nn, bits : natural := 0; + begin + nn := n; + while nn > 0 loop + bits := bits + 1; + nn := nn/2; + end loop; + return bits; + end; + + function or_all(p : std_logic_vector) return std_logic is + variable r : std_logic; + begin + r := '0'; + for i in p'range loop + r := r or p(i); + end loop; + return r; + end; + + constant wN : positive := bits_to_fit(a'length - 1); + constant wP : positive := 2 ** wN; + variable pv : std_logic_vector(wP-1 downto 0); + variable n : std_logic_vector(wN downto 1); + begin + if a'length <= 2 then + n(n'right) := a(a'left); + else + pv(a'length-1 downto 0) := a; + if or_all(pv(wP-1 downto wP/2)) = '1' then + n := '1' & find_msb((pv(wP-1 downto wP/2))); + else + n := '0' & find_msb((pv(wP/2-1 downto 0))); end if; - end case; - end process; + end if; + return n; + end function find_msb; + -- -- alternativ: eleganter, braucht aber mehr logic cells + -- for i in (CBITS-1) downto 0 loop + -- exit when a(i) = '1'; + -- r := r+1; + -- end loop; + -- return (CBITS - r); - -- output - 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 multmp : signed(((2*CBITS)-1) downto 0); variable mulsign : std_logic; variable tmp : csigned; -- vars fuer div @@ -121,9 +129,6 @@ begin begin calc_done_next <= '0'; calc_error_next <= '0'; - div_go_calc_int <= '0'; - done_intern <= '0'; - error_intern <= '0'; -- default fuer div dividend_msb_next <= (others => '0'); laengediv_next <= (others => '0'); @@ -134,30 +139,40 @@ begin sign_next <= '0'; op3_next <= op3_int; opM_next <= opM_int; - + -- set a default value for next state + state_next <= state_int; + -- next state berechnen case state_int is when SIDLE => - opM_next <= (others => '0'); aktdiv_int_next <= (others => '0'); + -- opM_next <= (others => '0'); + + 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 => tmp := op1 + op2; op3_next <= tmp; + state_next <= SDONE; -- 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'; + state_next <= SERROR; end if; when SSUB => tmp := op1 - op2; op3_next <= tmp; + state_next <= SDONE; -- 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'; + state_next <= SERROR; end if; when SMUL => mulsign := op1(CBITS-1) xor op2(CBITS-1); @@ -166,21 +181,17 @@ begin op3_next(CBITS-1) <= mulsign; if mulsign = '1' then - multmp2 := (not multmp) + 1; - else - multmp2 := multmp; + multmp := (not multmp) + 1; end if; + state_next <= SDONE; -- overflow? - if(multmp2((2*CBITS)-2 downto (CBITS-1)) > 0) then - error_intern <= '1'; - else - done_intern <= '1'; + if(multmp((2*CBITS)-2 downto (CBITS-1)) > 0) then + state_next <= SERROR; end if; - when SDIV => -- division implementiert nach ~hwmod/doc/division.pdf if ((op1 = x"80000000" and op2 = to_signed(-1, CBITS)) or op2 = to_signed(0, CBITS)) then - error_intern <= '1'; + state_next <= SERROR; else -- sign check op1_var := op1; @@ -200,17 +211,16 @@ begin -- anmerkung: xst (xilinx) kann folgende zeile nicht uebersetzen -- > if op1 = to_signed(-2147483648, CBITS) then -- darum folgende schreibweise -> + state_next <= SDONE; if op1 = x"80000000" then -- so ziemlich das boeseste was passieren kann - done_intern <= '1'; op3_next <= to_signed(-214748364,CBITS); opM_next <= to_signed(8,CBITS); elsif (op1_var < op2_var) then - done_intern <= '1'; op3_next <= to_signed(0,CBITS); opM_next <= op1_var; else - div_go_calc_int <= '1'; + state_next <= SDIV_CALC; dividend_msb_next <= dividend_msb_var; laengediv_next <= laengediv_var; quo_next <= (others => '0'); @@ -246,14 +256,16 @@ begin op3_next <= quo_int; end if; opM_next <= aktdiv_int; - done_intern <= '1'; + state_next <= SDONE; end if; when SDONE | SERROR => calc_done_next <= '1'; - if (state_int = SERROR) then + if state_int = SERROR then calc_error_next <= '1'; end if; + if do_calc = '0' then + state_next <= SIDLE; + end if; end case; end process; end architecture beh; - diff --git a/src/beh_alu_tb.vhd b/src/beh_alu_tb.vhd index de347a1..15bb002 100644 --- a/src/beh_alu_tb.vhd +++ b/src/beh_alu_tb.vhd @@ -162,8 +162,8 @@ begin assert(false) report "testfall war ein error (passt)"; end if; else - assert ((op3 = to_signed(testmatrix(i).expected,CBITS)) and (opM = to_signed(testmatrix(i).om,CBITS))) - report "" & cinteger'image(testmatrix(i).o1) & + if not((op3 = to_signed(testmatrix(i).expected,CBITS)) and (opcode /= ALU_DIV or opM = to_signed(testmatrix(i).om,CBITS))) then + assert(false) report "" & cinteger'image(testmatrix(i).o1) & " " & integer'image(to_integer(signed(opcode))) & " " & cinteger'image(testmatrix(i).o2) & " /= " & integer'image(to_integer(op3)) & @@ -171,7 +171,6 @@ begin " -- erwartet: " & cinteger'image(testmatrix(i).expected) & " ( " & cinteger'image(testmatrix(i).om) & " ) "; - if not((op3 = to_signed(testmatrix(i).expected,CBITS)) and (opM = to_signed(testmatrix(i).om,CBITS))) then checkall := false; end if; end if; diff --git a/src/gen_pkg.vhd b/src/gen_pkg.vhd index 4dfbf6d..d97b943 100644 --- a/src/gen_pkg.vhd +++ b/src/gen_pkg.vhd @@ -27,7 +27,6 @@ package gen_pkg is subtype hstring is string(1 to 72); subtype hstr_int is integer range 0 to 72; - function find_msb(a : std_logic_vector) return std_logic_vector; procedure icwait(signal clk_i : IN std_logic; cycles: natural); -- http://www.marjorie.de/ps2/scancode-set2.htm @@ -67,53 +66,6 @@ package gen_pkg is end package gen_pkg; package body gen_pkg is - -- http://www.velocityreviews.com/forums/showpost.php?p=137148&postcount=5 - function find_msb(a : std_logic_vector) return std_logic_vector is - function bits_to_fit(n : positive) return natural is - variable nn, bits : natural := 0; - begin - nn := n; - while nn > 0 loop - bits := bits + 1; - nn := nn/2; - end loop; - return bits; - end; - - function or_all(p : std_logic_vector) return std_logic is - variable r : std_logic; - begin - r := '0'; - for i in p'range loop - r := r or p(i); - end loop; - return r; - end; - - constant wN : positive := bits_to_fit(a'length - 1); - constant wP : positive := 2 ** wN; - variable pv : std_logic_vector(wP-1 downto 0); - variable n : std_logic_vector(wN downto 1); - begin - if a'length <= 2 then - n(n'right) := a(a'left); - else - pv(a'length-1 downto 0) := a; - if or_all(pv(wP-1 downto wP/2)) = '1' then - n := '1' & find_msb((pv(wP-1 downto wP/2))); - else - n := '0' & find_msb((pv(wP/2-1 downto 0))); - end if; - end if; - return n; - end function find_msb; - -- -- alternativ: eleganter, braucht aber mehr logic cells - -- for i in (CBITS-1) downto 0 loop - -- exit when a(i) = '1'; - -- r := r+1; - -- end loop; - -- return (CBITS - r); - procedure icwait(signal clk_i : IN std_logic; cycles: Natural) is begin for i in 1 to cycles loop @@ -121,4 +73,3 @@ package body gen_pkg is end loop; end; end package body gen_pkg; - diff --git a/src/post_alu_tb.vhd b/src/post_alu_tb.vhd index b6f9db1..cf1da2d 100644 --- a/src/post_alu_tb.vhd +++ b/src/post_alu_tb.vhd @@ -177,14 +177,12 @@ begin assert(false) report "testfall war ein error (passt)"; end if; else - assert op3 = std_logic_vector(to_signed(testmatrix(i).expected,CBITS)) - report "" & cinteger'image(testmatrix(i).o1) & + if not((op3 = std_logic_vector(to_signed(testmatrix(i).expected,CBITS))) and (opcode /= ALU_DIV or opM = std_logic_vector(to_signed(testmatrix(i).om,CBITS)))) then + assert(false) report "" & cinteger'image(testmatrix(i).o1) & " " & integer'image(to_integer(signed(opcode))) & " " & cinteger'image(testmatrix(i).o2) & "/= " & integer'image(to_integer(signed(op3))) & " -- erwartet: " & cinteger'image(testmatrix(i).expected); - - if not((op3 = std_logic_vector(to_signed(testmatrix(i).expected,CBITS))) and (opM = std_logic_vector(to_signed(testmatrix(i).om,CBITS)))) then checkall := false; end if; end if;