From 05882ef8805341c413d6f4748766fc01bcd2b3f7 Mon Sep 17 00:00:00 2001 From: Bernhard Urban Date: Mon, 10 May 2010 23:00:42 +0200 Subject: [PATCH] alu: error flag setzen bei overflow/underflow bzw. bei division durch 0 --- quartus/project_web.tcl | 4 +- src/alu.vhd | 79 ++++++++++++++++++++++------ src/beh_alu_tb.do | 25 ++++++--- src/beh_alu_tb.vhd | 108 ++++++++++++++++++++++++++----------- src/gen_pkg.vhd | 4 +- src/parser.vhd | 2 +- src/post_alu_tb.vhd | 114 ++++++++++++++++++++++++++++------------ 7 files changed, 242 insertions(+), 94 deletions(-) diff --git a/quartus/project_web.tcl b/quartus/project_web.tcl index 5d297b1..1fef3ff 100755 --- a/quartus/project_web.tcl +++ b/quartus/project_web.tcl @@ -32,11 +32,11 @@ if {$make_assignments} { set_global_assignment -name RESERVE_ASDO_AFTER_CONFIGURATION "AS INPUT TRI-STATED" #set_global_assignment -name TOP_LEVEL_ENTITY calc - set_global_assignment -name TOP_LEVEL_ENTITY parser + set_global_assignment -name TOP_LEVEL_ENTITY alu set_global_assignment -name VHDL_FILE ../../src/gen_pkg.vhd #set_global_assignment -name VHDL_FILE ../../src/calc.vhd set_global_assignment -name VHDL_FILE ../../src/alu.vhd - set_global_assignment -name VHDL_FILE ../../src/parser.vhd + #set_global_assignment -name VHDL_FILE ../../src/parser.vhd set_location_assignment PIN_N3 -to sys_clk set_location_assignment PIN_AF17 -to sys_res_n diff --git a/src/alu.vhd b/src/alu.vhd index cdb9fdd..7a57b59 100644 --- a/src/alu.vhd +++ b/src/alu.vhd @@ -13,17 +13,19 @@ entity alu is op2 : in csigned; op3 : out csigned; do_calc : in std_logic; - calc_done : out std_logic - -- TODO: calc_error : out std_logic; + 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 done_intern, error_intern, div_calc_done, div_go_calc : std_logic; signal op3_int, op3_next : csigned := (others => '0'); 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 quo_int, quo_next, aktdiv_int, aktdiv_int_next, op1_int, op1_next, op2_int, op2_next : csigned; @@ -31,6 +33,7 @@ architecture beh of alu is begin op3 <= op3_int; calc_done <= calc_done_int; + calc_error <= calc_error_int; -- sync process(sys_clk, sys_res_n) @@ -39,6 +42,7 @@ begin state_int <= SIDLE; op3_int <= (others => '0'); calc_done_int <= '0'; + calc_error_int <= '0'; --div dividend_msb_int <= 0; laengediv_int <= 0; @@ -51,6 +55,7 @@ begin state_int <= state_next; op3_int <= op3_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 +68,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, div_go_calc) begin -- set a default value for next state state_next <= state_int; @@ -88,15 +94,21 @@ 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 state_next <= SDIV_CALC; end if; + if error_intern = '1' then + state_next <= SERROR; + end if; when SDIV_CALC => if div_calc_done = '1' then state_next <= SDIV_DONE; end if; - when SDONE => + when SDONE | SERROR => if do_calc = '0' then state_next <= SIDLE; end if; @@ -105,15 +117,19 @@ begin -- 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); + 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 aktdiv_int_var, quo_var, op1_var, op2_var : csigned; begin calc_done_next <= '0'; + calc_error_next <= '0'; div_calc_done <= '0'; div_go_calc <= '0'; done_intern <= '0'; + error_intern <= '0'; -- default fuer div dividend_msb_next <= 0; laengediv_next <= 0; @@ -128,21 +144,47 @@ begin when SIDLE => null; 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; @@ -196,8 +238,11 @@ begin when SDIV_DONE => op3_next <= quo_int; done_intern <= '1'; - when SDONE => + when SDONE | SERROR => calc_done_next <= '1'; + if (state_int = SERROR) then + calc_error_next <= '1'; + end if; op3_next <= op3_int; end case; end process; diff --git a/src/beh_alu_tb.do b/src/beh_alu_tb.do index 27a9363..3a14770 100644 --- a/src/beh_alu_tb.do +++ b/src/beh_alu_tb.do @@ -2,14 +2,23 @@ alias rr "restart -f" #signale hinzufuegen -add wave sys_clk -add wave sys_res_n -add wave -radix decimal op1 -add wave opcode -add wave -radix decimal op2 -add wave -radix decimal op3 -add wave do_calc -add wave calc_done +add wave inst/* + +delete wave /beh_alu_tb/inst/op1_int +delete wave /beh_alu_tb/inst/op1 +delete wave /beh_alu_tb/inst/op1_next +add wave -radix decimal inst/op1_int + +delete wave /beh_alu_tb/inst/op2_int +delete wave /beh_alu_tb/inst/op1 +delete wave /beh_alu_tb/inst/op2_next +add wave -radix decimal inst/op2_int + +delete wave /beh_alu_tb/inst/op3_int +delete wave /beh_alu_tb/inst/op1 +delete wave /beh_alu_tb/inst/op3_next +add wave -radix decimal inst/op3_int + #rauszoomen wave zoomout 500.0 diff --git a/src/beh_alu_tb.vhd b/src/beh_alu_tb.vhd index 0da87c2..8a3f5b3 100644 --- a/src/beh_alu_tb.vhd +++ b/src/beh_alu_tb.vhd @@ -7,7 +7,7 @@ entity beh_alu_tb is end entity beh_alu_tb; architecture sim of beh_alu_tb is - signal sys_clk, sys_res_n, do_calc, calc_done : std_logic; + signal sys_clk, sys_res_n, do_calc, calc_done, calc_error : std_logic; signal opcode : alu_ops; signal op1, op2, op3 : csigned; signal stop : boolean := false; @@ -22,7 +22,8 @@ begin op1 => op1, op2 => op2, op3 => op3, - opcode => opcode + opcode => opcode, + calc_error => calc_error ); process @@ -42,31 +43,61 @@ begin o : alu_ops; o2 : cinteger; expected : cinteger; + errcase : boolean; end record alu_testv; -- ggf. groesse des arrays erhoehen - type alu_testv_array is array (natural range 0 to 30) of alu_testv; + type alu_testv_array is array (natural range 0 to 44) of alu_testv; variable testmatrix : alu_testv_array := - ( 0 => (-5, ALU_DIV, 3, -1), - 1 => (7, ALU_ADD, 3, 10), - 2 => (7, ALU_SUB, 1, 6), - 3 => (7, ALU_DIV, 1, 7), - 4 => (7, ALU_DIV, 3, 2), - 5 => (7, ALU_ADD, 1, 8), - 6 => (7, ALU_MUL, 3, 21), - 7 => (-7, ALU_MUL, 3, -21), - 8 => (268435456, ALU_MUL, -2, -536870912), - 9 => (268435456, ALU_MUL, 2**5, 0), -- um fuenf nach links shiften - 10 => (268435456 + 5, ALU_MUL, 2**5, 160), -- = 5 * (2^5) - 11 => (100, ALU_DIV, 10, 10), - 12 => (100, ALU_DIV, 51, 1), - 13 => (100, ALU_DIV, 49, 2), - 14 => (153156, ALU_DIV, 3543, 43), - 15 => (-153156, ALU_DIV, 3543, -43), - 16 => (153156, ALU_DIV, -3543, -43), - 17 => (-153156, ALU_DIV, -3543, 43), - others => (0, ALU_ADD, 0, 0) + ( 0 => (-5, ALU_DIV, 3, -1, false), + 1 => (7, ALU_ADD, 3, 10, false), + 2 => (7, ALU_SUB, 1, 6, false), + 3 => (7, ALU_DIV, 1, 7, false), + 4 => (7, ALU_DIV, 3, 2, false), + 5 => (7, ALU_ADD, 1, 8, false), + 6 => (7, ALU_MUL, 3, 21, false), + 7 => (-7, ALU_MUL, 3, -21, false), + 8 => (268435456, ALU_MUL, -2, -536870912, false), + 9 => (268435456, ALU_MUL, 2**5, 0, false), -- um fuenf nach links shiften + 10 => (268435456 + 5, ALU_MUL, 2**5, 160, false), -- = 5 * (2^5) + 11 => (100, ALU_DIV, 10, 10, false), + 12 => (100, ALU_DIV, 51, 1, false), + 13 => (100, ALU_DIV, 49, 2, false), + 14 => (153156, ALU_DIV, 3543, 43, false), + 15 => (-153156, ALU_DIV, 3543, -43, false), + 16 => (153156, ALU_DIV, -3543, -43, false), + 17 => (-153156, ALU_DIV, -3543, 43, false), + -- add: sign and under-/overflow check + 18 => (2147483647, ALU_ADD, -1, 2147483646, false), + 19 => (2147483647, ALU_ADD, 1, 0, true), + 20 => (-2147483645, ALU_ADD, -100, 0, true), + 21 => (7, ALU_ADD, 1, 8, false), + 22 => (7, ALU_ADD, -1, 6, false), + 23 => (-7, ALU_ADD, 1, -6, false), + 24 => (-7, ALU_ADD, -1, -8, false), + -- sub: sign and under-/overflow check + 25 => (-7, ALU_SUB, 1, -8, false), + 26 => (-7, ALU_SUB, -1, -6, false), + 27 => (7, ALU_SUB, 1, 6, false), + 28 => (7, ALU_SUB, -1, 8, false), + 29 => (-2147483645, ALU_SUB, 1000, 0, true), + 30 => (2147483645, ALU_SUB, -1000, 0, true), + 31 => (-1000, ALU_SUB, 2147483645, 0, true), + 32 => (1000, ALU_SUB, -2147483645, 0, true), + -- mul: sign and under-/overflow check + 33 => (3, ALU_MUL, 2, 6, false), + 34 => (3, ALU_MUL, -2, -6, false), + 35 => (-3, ALU_MUL, 2, -6, false), + 36 => (-3, ALU_MUL, -2, 6, false), + 37 => (90000, ALU_MUL, 100000, 0, true), + 38 => (90000, ALU_MUL, -100000, 0, true), + 39 => (-90000, ALU_MUL, 100000, 0, true), + 40 => (-90000, ALU_MUL, -100000, 0, true), + -- mul: overflow check und division durch null + 41 => (-2147483648, ALU_DIV, -1, 0, true), + 42 => (-2147483648, ALU_DIV, 0, 0, true), + others => (0, ALU_ADD, 0, 0, false) ); variable checkall : boolean := true; begin @@ -93,15 +124,30 @@ begin wait on calc_done; icwait(sys_clk, 1); - assert op3 = to_signed(testmatrix(i).expected,CBITS) - report "" & cinteger'image(testmatrix(i).o1) & - " " & integer'image(to_integer(signed(opcode))) & - " " & cinteger'image(testmatrix(i).o2) & - "/= " & integer'image(to_integer(op3)) & - " -- erwartet: " & cinteger'image(testmatrix(i).expected); + if testmatrix(i).errcase then + if (calc_error = '0') then + assert(false) report "sollte ein error sein"; + assert op3 = to_signed(testmatrix(i).expected,CBITS) + report "" & cinteger'image(testmatrix(i).o1) & + " " & integer'image(to_integer(signed(opcode))) & + " " & cinteger'image(testmatrix(i).o2) & + "/= " & integer'image(to_integer(op3)) & + " -- erwartet: " & cinteger'image(testmatrix(i).expected); + checkall := false; + else + assert(false) report "testfall war ein error (passt)"; + end if; + else + assert op3 = to_signed(testmatrix(i).expected,CBITS) + report "" & cinteger'image(testmatrix(i).o1) & + " " & integer'image(to_integer(signed(opcode))) & + " " & cinteger'image(testmatrix(i).o2) & + "/= " & integer'image(to_integer(op3)) & + " -- erwartet: " & cinteger'image(testmatrix(i).expected); - if op3 /= to_signed(testmatrix(i).expected,CBITS) then - checkall := false; + if op3 /= to_signed(testmatrix(i).expected,CBITS) then + checkall := false; + end if; end if; icwait(sys_clk, 2); @@ -112,7 +158,7 @@ begin if checkall then report "alle testfaelle der ALU waren erfolgreich!"; else - report "nicht alle testfaelle der ALU waren erfolgreich!"; + report "einige testfaelle schlugen fehl"; end if; stop <= true; wait; diff --git a/src/gen_pkg.vhd b/src/gen_pkg.vhd index e5c692e..7f5e2dc 100644 --- a/src/gen_pkg.vhd +++ b/src/gen_pkg.vhd @@ -13,8 +13,8 @@ package gen_pkg is constant CBITS : integer := 32; subtype csigned is signed((CBITS-1) downto 0); - --TODO: bei CBITS-1 gibts einen overflow :/ - subtype cinteger is integer range -(2**(CBITS-2)) to ((2**(CBITS-2))-1); + -- integer ist 32bit (31bit + sign) + subtype cinteger is integer; subtype hspalte is std_logic_vector(6 downto 0); subtype hzeile is std_logic_vector(4 downto 0); diff --git a/src/parser.vhd b/src/parser.vhd index e9778da..a2a2caf 100644 --- a/src/parser.vhd +++ b/src/parser.vhd @@ -159,7 +159,7 @@ begin -- out process(state_int, p_read, p_write_int, z_int, rbyte_int, p_rget_int, strich_int, aktop_int, opp_int, opcode_int, op1_int, op2_int, op3, - do_calc_int) + do_calc_int, wtmp_int) function hbyte2csigned (x : hbyte) return csigned is variable y : csigned; begin diff --git a/src/post_alu_tb.vhd b/src/post_alu_tb.vhd index 5c05298..d113dca 100644 --- a/src/post_alu_tb.vhd +++ b/src/post_alu_tb.vhd @@ -18,13 +18,14 @@ architecture sim of post_alu_tb is op2 : in std_logic_vector(31 downto 0); op3 : out std_logic_vector(31 downto 0); do_calc : in std_logic; - calc_done : out std_logic + calc_done : out std_logic; + calc_error : out std_logic ); end component alu; - signal sys_clk, sys_res_n, do_calc, calc_done : std_logic; + signal sys_clk, sys_res_n, do_calc, calc_done, calc_error : std_logic; signal opcode : alu_ops; - signal op1, op2, op3 : std_logic_vector(31 downto 0); + signal op1, op2, op3 : std_logic_vector((CBITS-1) downto 0); signal stop : boolean := false; begin inst : alu @@ -37,7 +38,8 @@ begin op1 => op1, op2 => op2, op3 => op3, - opcode => opcode + opcode => opcode, + calc_error => calc_error ); process @@ -57,31 +59,61 @@ begin o : alu_ops; o2 : cinteger; expected : cinteger; + errcase : boolean; end record alu_testv; -- ggf. groesse des arrays erhoehen - type alu_testv_array is array (natural range 0 to 20) of alu_testv; + type alu_testv_array is array (natural range 0 to 44) of alu_testv; variable testmatrix : alu_testv_array := - ( 0 => (-5, ALU_DIV, 3, -1), - 1 => (7, ALU_ADD, 3, 10), - 2 => (7, ALU_SUB, 1, 6), - 3 => (7, ALU_DIV, 1, 7), - 4 => (7, ALU_DIV, 3, 2), - 5 => (7, ALU_ADD, 1, 8), - 6 => (7, ALU_MUL, 3, 21), - 7 => (-7, ALU_MUL, 3, -21), - 8 => (268435456, ALU_MUL, -2, -536870912), - 9 => (268435456, ALU_MUL, 2**5, 0), -- um fuenf nach links shiften - 10 => (268435456 + 5, ALU_MUL, 2**5, 160), -- = 5 * (2^5) - 11 => (100, ALU_DIV, 10, 10), - 12 => (100, ALU_DIV, 51, 1), - 13 => (100, ALU_DIV, 49, 2), - 14 => (153156, ALU_DIV, 3543, 43), - 15 => (-153156, ALU_DIV, 3543, -43), - 16 => (153156, ALU_DIV, -3543, -43), - 17 => (-153156, ALU_DIV, -3543, 43), - others => (0, ALU_ADD, 0, 0) + ( 0 => (-5, ALU_DIV, 3, -1, false), + 1 => (7, ALU_ADD, 3, 10, false), + 2 => (7, ALU_SUB, 1, 6, false), + 3 => (7, ALU_DIV, 1, 7, false), + 4 => (7, ALU_DIV, 3, 2, false), + 5 => (7, ALU_ADD, 1, 8, false), + 6 => (7, ALU_MUL, 3, 21, false), + 7 => (-7, ALU_MUL, 3, -21, false), + 8 => (268435456, ALU_MUL, -2, -536870912, false), + 9 => (268435456, ALU_MUL, 2**5, 0, false), -- um fuenf nach links shiften + 10 => (268435456 + 5, ALU_MUL, 2**5, 160, false), -- = 5 * (2^5) + 11 => (100, ALU_DIV, 10, 10, false), + 12 => (100, ALU_DIV, 51, 1, false), + 13 => (100, ALU_DIV, 49, 2, false), + 14 => (153156, ALU_DIV, 3543, 43, false), + 15 => (-153156, ALU_DIV, 3543, -43, false), + 16 => (153156, ALU_DIV, -3543, -43, false), + 17 => (-153156, ALU_DIV, -3543, 43, false), + -- add: sign and under-/overflow check + 18 => (2147483647, ALU_ADD, -1, 2147483646, false), + 19 => (2147483647, ALU_ADD, 1, 0, true), + 20 => (-2147483645, ALU_ADD, -100, 0, true), + 21 => (7, ALU_ADD, 1, 8, false), + 22 => (7, ALU_ADD, -1, 6, false), + 23 => (-7, ALU_ADD, 1, -6, false), + 24 => (-7, ALU_ADD, -1, -8, false), + -- sub: sign and under-/overflow check + 25 => (-7, ALU_SUB, 1, -8, false), + 26 => (-7, ALU_SUB, -1, -6, false), + 27 => (7, ALU_SUB, 1, 6, false), + 28 => (7, ALU_SUB, -1, 8, false), + 29 => (-2147483645, ALU_SUB, 1000, 0, true), + 30 => (2147483645, ALU_SUB, -1000, 0, true), + 31 => (-1000, ALU_SUB, 2147483645, 0, true), + 32 => (1000, ALU_SUB, -2147483645, 0, true), + -- mul: sign and under-/overflow check + 33 => (3, ALU_MUL, 2, 6, false), + 34 => (3, ALU_MUL, -2, -6, false), + 35 => (-3, ALU_MUL, 2, -6, false), + 36 => (-3, ALU_MUL, -2, 6, false), + 37 => (90000, ALU_MUL, 100000, 0, true), + 38 => (90000, ALU_MUL, -100000, 0, true), + 39 => (-90000, ALU_MUL, 100000, 0, true), + 40 => (-90000, ALU_MUL, -100000, 0, true), + -- mul: overflow check und division durch null + 41 => (-2147483648, ALU_DIV, -1, 0, true), + 42 => (-2147483648, ALU_DIV, 0, 0, true), + others => (0, ALU_ADD, 0, 0, false) ); variable checkall : boolean := true; begin @@ -108,14 +140,30 @@ begin wait on calc_done; icwait(sys_clk, 1); - assert op3 = std_logic_vector(to_signed(testmatrix(i).expected,CBITS)) - 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 op3 /= std_logic_vector(to_signed(testmatrix(i).expected,CBITS)) then - checkall := false; + if testmatrix(i).errcase then + if (calc_error = '0') then + assert(false) report "sollte ein error sein"; + assert op3 = std_logic_vector(to_signed(testmatrix(i).expected,CBITS)) + 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); + checkall := false; + else + 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) & + " " & integer'image(to_integer(signed(opcode))) & + " " & cinteger'image(testmatrix(i).o2) & + "/= " & integer'image(to_integer(signed(op3))) & + " -- erwartet: " & cinteger'image(testmatrix(i).expected); + + if op3 /= std_logic_vector(to_signed(testmatrix(i).expected,CBITS)) then + checkall := false; + end if; end if; icwait(sys_clk, 2); @@ -126,7 +174,7 @@ begin if checkall then report "alle testfaelle der ALU waren erfolgreich!"; else - report "nicht alle testfaelle der ALU waren erfolgreich!"; + report "einige testfaelle schlugen fehl"; end if; stop <= true; wait; -- 2.25.1