From d9cde63bbc34ec52a1b34d51a72bba230d25b693 Mon Sep 17 00:00:00 2001 From: Paul Mackerras Date: Thu, 5 Dec 2019 12:41:23 +1100 Subject: [PATCH] divide: Move data formatting out of decode2 This moves the data formatting (sign extension of 32-bit operands, and shifting of the dividend for 32-bit extended divide operations) out of decode2 into the first cycle of the divider pipe. This will help make it possible to do forwarding of results from the execute pipe at the front of execute1. Signed-off-by: Paul Mackerras --- decode2.vhdl | 26 +++----------------------- divider.vhdl | 31 ++++++++++++++++++++++++++----- divider_tb.vhdl | 14 +++++++------- 3 files changed, 36 insertions(+), 35 deletions(-) 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);