mirror of
https://github.com/antonblanchard/microwatt.git
synced 2026-01-11 23:43:15 +00:00
FPU: Move computation of main adder inputs out of the state machine
Signed-off-by: Paul Mackerras <paulus@ozlabs.org>
This commit is contained in:
parent
b4aae8511d
commit
b63773f6e9
@ -151,8 +151,8 @@ architecture behaviour of decode1 is
|
||||
INSN_fabs => (FPU, FPU, OP_FP_MOVE, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fadd => (FPU, FPU, OP_FP_ARITH, FRA, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fadds => (FPU, FPU, OP_FP_ARITH, FRA, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfid => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfids => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfid => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '1', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfids => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '1', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfidu => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fcfidus => (FPU, FPU, OP_FP_MISC, NONE, FRB, NONE, NONE, FRT, '0', '0', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '1', '0', RC, '0', '0', '0', NONE),
|
||||
INSN_fcmpo => (FPU, FPU, OP_FP_CMP, FRA, FRB, NONE, NONE, NONE, '0', '1', '0', '0', ZERO, '0', NONE, '0', '0', '0', '0', '0', '0', NONE, '0', '0', '0', NONE),
|
||||
|
||||
127
fpu.vhdl
127
fpu.vhdl
@ -194,16 +194,16 @@ architecture behaviour of fpu is
|
||||
|
||||
signal fp_result : std_ulogic_vector(63 downto 0);
|
||||
signal opsel_a : std_ulogic_vector(2 downto 0);
|
||||
signal opsel_b : std_ulogic;
|
||||
signal opsel_b : std_ulogic_vector(2 downto 0);
|
||||
signal opsel_c : std_ulogic_vector(2 downto 0);
|
||||
signal opsel_r : std_ulogic_vector(1 downto 0);
|
||||
signal opsel_s : std_ulogic_vector(1 downto 0);
|
||||
signal opsel_ainv : std_ulogic;
|
||||
signal opsel_aneg : std_ulogic;
|
||||
signal opsel_aabs : std_ulogic;
|
||||
signal opsel_mask : std_ulogic;
|
||||
signal opsel_binv : std_ulogic;
|
||||
signal in_a : std_ulogic_vector(63 downto 0);
|
||||
signal in_b : std_ulogic_vector(63 downto 0);
|
||||
signal result : std_ulogic_vector(63 downto 0);
|
||||
signal carry_in : std_ulogic;
|
||||
signal lost_bits : std_ulogic;
|
||||
signal r_hi_nz : std_ulogic;
|
||||
signal r_lo_nz : std_ulogic;
|
||||
@ -228,8 +228,20 @@ architecture behaviour of fpu is
|
||||
constant AIN_RND_RBIT : std_ulogic_vector(2 downto 0) := "110";
|
||||
constant AIN_RND : std_ulogic_vector(2 downto 0) := "111";
|
||||
|
||||
constant BIN_ZERO : std_ulogic := '0';
|
||||
constant BIN_R : std_ulogic := '1';
|
||||
constant BIN_ZERO : std_ulogic_vector(2 downto 0) := "000";
|
||||
constant BIN_R : std_ulogic_vector(2 downto 0) := "001";
|
||||
constant BIN_MINUSR : std_ulogic_vector(2 downto 0) := "100";
|
||||
constant BIN_ABSR : std_ulogic_vector(2 downto 0) := "101";
|
||||
constant BIN_ADDSUBR : std_ulogic_vector(2 downto 0) := "110";
|
||||
constant BIN_RSIGNR : std_ulogic_vector(2 downto 0) := "111";
|
||||
|
||||
constant CIN_ZERO : std_ulogic_vector(2 downto 0) := "000";
|
||||
constant CIN_SUBEXT : std_ulogic_vector(2 downto 0) := "001";
|
||||
constant CIN_ABSEXT : std_ulogic_vector(2 downto 0) := "010";
|
||||
constant CIN_INC : std_ulogic_vector(2 downto 0) := "011";
|
||||
constant CIN_ROUND : std_ulogic_vector(2 downto 0) := "100";
|
||||
constant CIN_RNDX : std_ulogic_vector(2 downto 0) := "101";
|
||||
constant CIN_RNDQ : std_ulogic_vector(2 downto 0) := "110";
|
||||
|
||||
constant RES_SUM : std_ulogic_vector(1 downto 0) := "00";
|
||||
constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01";
|
||||
@ -1035,6 +1047,9 @@ begin
|
||||
variable cr_result : std_ulogic_vector(3 downto 0);
|
||||
variable set_cr : std_ulogic;
|
||||
variable set_fpcc : std_ulogic;
|
||||
variable asign : std_ulogic;
|
||||
variable bneg : std_ulogic;
|
||||
variable ci : std_ulogic;
|
||||
begin
|
||||
v := r;
|
||||
v.complete := '0';
|
||||
@ -1297,13 +1312,13 @@ begin
|
||||
v.first := '0';
|
||||
v.doing_ftdiv := "00";
|
||||
opsel_a <= AIN_ZERO;
|
||||
opsel_ainv <= '0';
|
||||
opsel_aneg <= '0';
|
||||
opsel_aabs <= '0';
|
||||
opsel_mask <= '0';
|
||||
opsel_b <= BIN_R;
|
||||
opsel_binv <= '0';
|
||||
opsel_c <= CIN_ZERO;
|
||||
opsel_r <= RES_SUM;
|
||||
opsel_s <= S_ZERO;
|
||||
carry_in <= '0';
|
||||
misc_sel <= "000";
|
||||
fpscr_mask := (others => '1');
|
||||
cr_op := CROP_NONE;
|
||||
@ -1634,14 +1649,10 @@ begin
|
||||
|
||||
when DO_FCFID =>
|
||||
opsel_a <= AIN_B;
|
||||
opsel_aabs <= '1';
|
||||
opsel_b <= BIN_ZERO;
|
||||
set_r := '1';
|
||||
rcls_op <= RCLS_SEL;
|
||||
if r.insn(8) = '0' and r.b.negative = '1' then
|
||||
-- fcfid[s] with negative operand, set R = -B
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
end if;
|
||||
re_con2 <= RECON2_UNIT;
|
||||
re_set_result <= '1';
|
||||
if r.b.class = ZERO then
|
||||
@ -1833,9 +1844,8 @@ begin
|
||||
else
|
||||
opsel_a <= AIN_B;
|
||||
end if;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_binv <= r.is_subtract;
|
||||
carry_in <= r.is_subtract and not r.x;
|
||||
opsel_b <= BIN_ADDSUBR;
|
||||
opsel_c <= CIN_SUBEXT;
|
||||
set_r := '1';
|
||||
-- set shift to -1
|
||||
rs_con2 <= RSCON2_1;
|
||||
@ -1847,13 +1857,12 @@ begin
|
||||
-- r.shift = -1
|
||||
re_sel2 <= REXP2_NE;
|
||||
rcls_op <= RCLS_TZERO;
|
||||
opsel_a <= AIN_ZERO;
|
||||
opsel_b <= BIN_ABSR;
|
||||
if r.r(63) = '1' then
|
||||
-- result is opposite sign to expected
|
||||
rsgn_op := RSGN_INV;
|
||||
opsel_a <= AIN_ZERO;
|
||||
set_r := '1';
|
||||
opsel_binv <= '1';
|
||||
carry_in <= '1';
|
||||
v.state := FINISH;
|
||||
elsif r.r(UNIT_BIT + 1) = '1' then
|
||||
-- sum overflowed, shift right
|
||||
@ -1876,9 +1885,7 @@ begin
|
||||
|
||||
when CMP_1 =>
|
||||
opsel_a <= AIN_A;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_binv <= '1';
|
||||
carry_in <= '1';
|
||||
opsel_b <= BIN_MINUSR;
|
||||
set_r := '1';
|
||||
v.state := CMP_2;
|
||||
|
||||
@ -1963,10 +1970,10 @@ begin
|
||||
|
||||
when FMADD_5 =>
|
||||
-- negate R:S:X if negative
|
||||
opsel_b <= BIN_ABSR;
|
||||
opsel_c <= CIN_ABSEXT;
|
||||
if r.r(63) = '1' then
|
||||
rsgn_op := RSGN_INV;
|
||||
opsel_binv <= '1';
|
||||
carry_in <= not (s_nz or r.x);
|
||||
set_r := '1';
|
||||
opsel_s <= S_NEG;
|
||||
set_s := '1';
|
||||
@ -2260,7 +2267,7 @@ begin
|
||||
when SQRT_12 =>
|
||||
-- test if remainder is 0 or >= B = 2*R + 1
|
||||
set_r := '0';
|
||||
carry_in <= '1';
|
||||
opsel_c <= CIN_INC;
|
||||
if pcmpb_lt = '1' then
|
||||
-- square root is correct, set X if remainder non-zero
|
||||
v.x := r.p(UNIT_BIT + 2) or px_nz;
|
||||
@ -2309,8 +2316,8 @@ begin
|
||||
|
||||
when INT_FINAL =>
|
||||
-- Negate if necessary, and increment for rounding if needed
|
||||
opsel_binv <= r.result_sign;
|
||||
carry_in <= r.fpscr(FPSCR_FR) xor r.result_sign;
|
||||
opsel_b <= BIN_RSIGNR;
|
||||
opsel_c <= CIN_ROUND;
|
||||
set_r := '1';
|
||||
-- Check for possible overflows
|
||||
case r.insn(9 downto 8) is
|
||||
@ -2547,13 +2554,9 @@ begin
|
||||
|
||||
when DO_IDIVMOD =>
|
||||
opsel_a <= AIN_B;
|
||||
opsel_aabs <= '1';
|
||||
opsel_b <= BIN_ZERO;
|
||||
set_r := '1';
|
||||
-- take absolute value for signed division
|
||||
if r.is_signed = '1' and r.b.negative = '1' then
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
end if;
|
||||
-- normalize and round up B to 8.56 format, like fcfid[u]
|
||||
re_con2 <= RECON2_UNIT;
|
||||
re_set_result <= '1';
|
||||
@ -2583,19 +2586,16 @@ begin
|
||||
v.state := IDIV_NORMB3;
|
||||
when IDIV_NORMB3 =>
|
||||
-- add the X bit onto R to round up B
|
||||
carry_in <= r.x;
|
||||
opsel_c <= CIN_RNDX;
|
||||
set_r := '1';
|
||||
-- prepare to do count-leading-zeroes on A
|
||||
v.state := IDIV_CLZA;
|
||||
when IDIV_CLZA =>
|
||||
set_b := '1'; -- put R back into B
|
||||
opsel_a <= AIN_A;
|
||||
opsel_aabs <= '1';
|
||||
opsel_b <= BIN_ZERO;
|
||||
set_r := '1';
|
||||
if r.is_signed = '1' and r.a.negative = '1' then
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
end if;
|
||||
re_con2 <= RECON2_UNIT;
|
||||
re_set_result <= '1';
|
||||
v.state := IDIV_CLZA2;
|
||||
@ -2608,8 +2608,7 @@ begin
|
||||
-- (using the original value of B, which is now in C)
|
||||
opsel_a <= AIN_C;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
opsel_aneg <= '1';
|
||||
set_r := '1';
|
||||
v.state := IDIV_CLZA3;
|
||||
when IDIV_CLZA3 =>
|
||||
@ -2924,8 +2923,7 @@ begin
|
||||
-- shifted dividend is in R, subtract left-justified divisor
|
||||
opsel_a <= AIN_B;
|
||||
opsel_b <= BIN_R;
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
opsel_aneg <= '1';
|
||||
set_r := '1';
|
||||
-- and put 1<<63 into B as the divisor (S is still 0)
|
||||
shiftin0 := '1';
|
||||
@ -3028,8 +3026,7 @@ begin
|
||||
when IDIV_MODSUB =>
|
||||
-- Subtract divisor from remainder
|
||||
opsel_a <= AIN_C;
|
||||
opsel_ainv <= '1';
|
||||
carry_in <= '1';
|
||||
opsel_aneg <= '1';
|
||||
opsel_b <= BIN_R;
|
||||
set_r := '1';
|
||||
if r.result_sign = '0' then
|
||||
@ -3041,8 +3038,8 @@ begin
|
||||
-- result (so far) is in R
|
||||
-- set carry to increment quotient if needed
|
||||
-- and also negate R if the answer is negative
|
||||
opsel_binv <= r.result_sign;
|
||||
carry_in <= r.inc_quot xor r.result_sign;
|
||||
opsel_b <= BIN_RSIGNR;
|
||||
opsel_c <= CIN_RNDQ;
|
||||
set_r := '1';
|
||||
if r.divmod = '0' then
|
||||
opsel_a <= AIN_RND_B32;
|
||||
@ -3257,11 +3254,14 @@ begin
|
||||
if (or (mask and r.r)) = '1' and set_x = '1' then
|
||||
v.x := '1';
|
||||
end if;
|
||||
asign := '0';
|
||||
case opsel_a is
|
||||
when AIN_A =>
|
||||
in_a0 := r.a.mantissa;
|
||||
asign := r.a.negative;
|
||||
when AIN_B =>
|
||||
in_a0 := r.b.mantissa;
|
||||
asign := r.b.negative;
|
||||
when AIN_C =>
|
||||
in_a0 := r.c.mantissa;
|
||||
when AIN_PS8 => -- 8 LSBs of P sign-extended to 64
|
||||
@ -3275,18 +3275,45 @@ begin
|
||||
when others =>
|
||||
in_a0 := (others => '0');
|
||||
end case;
|
||||
if opsel_ainv = '1' then
|
||||
ci := '0';
|
||||
case opsel_c is
|
||||
when CIN_SUBEXT =>
|
||||
ci := r.is_subtract and r.x;
|
||||
when CIN_ABSEXT =>
|
||||
ci := r.r(63) and (s_nz or r.x);
|
||||
when CIN_INC =>
|
||||
ci := '1';
|
||||
when CIN_ROUND =>
|
||||
ci := r.fpscr(FPSCR_FR);
|
||||
when CIN_RNDX =>
|
||||
ci := r.x;
|
||||
when CIN_RNDQ =>
|
||||
ci := r.inc_quot;
|
||||
when others =>
|
||||
end case;
|
||||
if opsel_aneg = '1' or (opsel_aabs = '1' and r.is_signed = '1' and asign = '1') then
|
||||
in_a0 := not in_a0;
|
||||
ci := not ci;
|
||||
end if;
|
||||
in_a <= in_a0;
|
||||
in_b0 := r.r;
|
||||
bneg := '0';
|
||||
case opsel_b is
|
||||
when BIN_R =>
|
||||
in_b0 := r.r;
|
||||
when BIN_MINUSR =>
|
||||
bneg := '1';
|
||||
when BIN_ABSR =>
|
||||
bneg := r.r(63);
|
||||
when BIN_ADDSUBR =>
|
||||
bneg := r.is_subtract;
|
||||
when BIN_RSIGNR =>
|
||||
bneg := r.result_sign;
|
||||
when others =>
|
||||
in_b0 := (others => '0');
|
||||
end case;
|
||||
if opsel_binv = '1' then
|
||||
if bneg = '1' then
|
||||
in_b0 := not in_b0;
|
||||
ci := not ci;
|
||||
end if;
|
||||
in_b <= in_b0;
|
||||
if is_X(r.shift) then
|
||||
@ -3298,7 +3325,7 @@ begin
|
||||
else
|
||||
shift_res := (others => '0');
|
||||
end if;
|
||||
sum := std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);
|
||||
sum := std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + ci);
|
||||
if opsel_mask = '1' then
|
||||
sum(DP_LSB - 1 downto 0) := "0000";
|
||||
if r.single_prec = '1' then
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user