diff --git a/decode2.vhdl b/decode2.vhdl index e441b02..62a6622 100644 --- a/decode2.vhdl +++ b/decode2.vhdl @@ -294,30 +294,10 @@ begin else signed_division := d_in.insn(10); end if; + v.d.is_extended := d_in.insn(8) and not d_in.insn(7); v.d.is_signed := signed_division; - if d_in.insn(2) = '0' then - -- 64-bit forms - if d_in.insn(8) = '1' and d_in.insn(7) = '0' then - v.d.is_extended := '1'; - end if; - v.d.dividend := decoded_reg_a.data; - v.d.divisor := decoded_reg_b.data; - else - -- 32-bit forms - if d_in.insn(8) = '1' and d_in.insn(7) = '0' then -- extended forms - v.d.dividend := decoded_reg_a.data(31 downto 0) & x"00000000"; - elsif signed_division = '1' and decoded_reg_a.data(31) = '1' then - -- sign extend to 64 bits - v.d.dividend := x"ffffffff" & decoded_reg_a.data(31 downto 0); - else - v.d.dividend := x"00000000" & decoded_reg_a.data(31 downto 0); - end if; - if signed_division = '1' and decoded_reg_b.data(31) = '1' then - v.d.divisor := x"ffffffff" & decoded_reg_b.data(31 downto 0); - else - v.d.divisor := x"00000000" & decoded_reg_b.data(31 downto 0); - end if; - end if; + v.d.dividend := decoded_reg_a.data; + v.d.divisor := decoded_reg_b.data; v.d.rc := decode_rc(d_in.decode.rc, d_in.insn); -- load/store unit diff --git a/divider.vhdl b/divider.vhdl index 20d4600..ce3aff9 100644 --- a/divider.vhdl +++ b/divider.vhdl @@ -48,17 +48,34 @@ begin running <= '0'; count <= "0000000"; elsif d_in.valid = '1' then - if d_in.is_extended = '1' and not (d_in.is_signed = '1' and d_in.dividend(63) = '1') then + if d_in.is_extended = '1' and d_in.is_32bit = '0' and + not (d_in.is_signed = '1' and d_in.dividend(63) = '1') then + -- 64-bit extended division dend <= '0' & d_in.dividend & x"0000000000000000"; - else + elsif d_in.is_32bit = '0' then + -- other 64-bit ops dend <= '0' & x"0000000000000000" & d_in.dividend; + elsif d_in.is_extended = '1' then + -- 32-bit extended ops + dend <= '0' & x"0000000000000000" & d_in.dividend(31 downto 0) & x"00000000"; + elsif d_in.is_signed = '1' and d_in.dividend(31) = '1' then + -- other 32-bit signed ops with negative dividend + dend <= '0' & x"0000000000000000ffffffff" & d_in.dividend(31 downto 0); + else + dend <= '0' & x"000000000000000000000000" & d_in.dividend(31 downto 0); end if; - div <= unsigned(d_in.divisor); + if d_in.is_32bit = '0' then + div <= unsigned(d_in.divisor); + elsif d_in.is_signed = '1' and d_in.divisor(31) = '1' then + div <= unsigned(x"ffffffff" & d_in.divisor(31 downto 0)); + else + div <= unsigned(x"00000000" & d_in.divisor(31 downto 0)); + end if; quot <= (others => '0'); write_reg <= d_in.write_reg; neg_result <= '0'; is_modulus <= d_in.is_modulus; - extended <= d_in.is_extended; + extended <= d_in.is_extended and not d_in.is_32bit; is_32bit <= d_in.is_32bit; is_signed <= d_in.is_signed; rc <= d_in.rc; @@ -66,7 +83,11 @@ begin running <= '1'; overflow <= '0'; ovf32 <= '0'; - signcheck <= d_in.is_signed and (d_in.dividend(63) or d_in.divisor(63)); + if d_in.is_32bit = '1' then + signcheck <= d_in.is_signed and (d_in.dividend(31) or d_in.divisor(31)); + else + signcheck <= d_in.is_signed and (d_in.dividend(63) or d_in.divisor(63)); + end if; elsif signcheck = '1' then signcheck <= '0'; neg_result <= dend(63) xor (div(63) and not is_modulus); diff --git a/divider_tb.vhdl b/divider_tb.vhdl index 5f809bb..b6fab92 100644 --- a/divider_tb.vhdl +++ b/divider_tb.vhdl @@ -319,13 +319,13 @@ begin divwe_loop : for vlength in 1 to 4 loop for dlength in 1 to vlength loop for i in 0 to 100 loop - ra := std_ulogic_vector(resize(signed(pseudorand(dlength * 8)), 32)) & x"00000000"; + ra := std_ulogic_vector(resize(signed(pseudorand(dlength * 8)), 64)); rb := std_ulogic_vector(resize(signed(pseudorand(vlength * 8)), 64)); d1.dividend <= ra; d1.divisor <= rb; d1.is_signed <= '1'; - d1.is_extended <= '0'; + d1.is_extended <= '1'; d1.is_32bit <= '1'; d1.valid <= '1'; @@ -342,7 +342,7 @@ begin behave_rt := (others => '0'); if rb /= x"0000000000000000" then - q64 := std_ulogic_vector(signed(ra) / signed(rb)); + q64 := std_ulogic_vector(signed(ra(31 downto 0) & x"00000000") / signed(rb)); if q64(63 downto 31) = x"00000000" & '0' or q64(63 downto 31) = x"ffffffff" & '1' then behave_rt := x"00000000" & q64(31 downto 0); @@ -359,13 +359,13 @@ begin divweu_loop : for vlength in 1 to 4 loop for dlength in 1 to vlength loop for i in 0 to 100 loop - ra := std_ulogic_vector(resize(unsigned(pseudorand(dlength * 8)), 32)) & x"00000000"; + ra := std_ulogic_vector(resize(unsigned(pseudorand(dlength * 8)), 64)); rb := std_ulogic_vector(resize(unsigned(pseudorand(vlength * 8)), 64)); d1.dividend <= ra; d1.divisor <= rb; d1.is_signed <= '0'; - d1.is_extended <= '0'; + d1.is_extended <= '1'; d1.is_32bit <= '1'; d1.valid <= '1'; @@ -381,8 +381,8 @@ begin assert d2.valid = '1'; behave_rt := (others => '0'); - if unsigned(rb(31 downto 0)) > unsigned(ra(63 downto 32)) then - behave_rt := std_ulogic_vector(unsigned(ra) / unsigned(rb)); + if unsigned(rb(31 downto 0)) > unsigned(ra(31 downto 0)) then + behave_rt := std_ulogic_vector(unsigned(ra(31 downto 0) & x"00000000") / unsigned(rb)); end if; assert behave_rt = d2.write_reg_data report "bad divweu expected " & to_hstring(behave_rt) & " got " & to_hstring(d2.write_reg_data) & " for ra = " & to_hstring(ra) & " rb = " & to_hstring(rb);