|
|
@ -80,7 +80,7 @@ architecture behaviour of fpu is
|
|
|
|
IDIV_NORMB, IDIV_NORMB2, IDIV_NORMB3,
|
|
|
|
IDIV_NORMB, IDIV_NORMB2, IDIV_NORMB3,
|
|
|
|
IDIV_CLZA, IDIV_CLZA2, IDIV_CLZA3,
|
|
|
|
IDIV_CLZA, IDIV_CLZA2, IDIV_CLZA3,
|
|
|
|
IDIV_NR0, IDIV_NR1, IDIV_NR2, IDIV_USE0_5,
|
|
|
|
IDIV_NR0, IDIV_NR1, IDIV_NR2, IDIV_USE0_5,
|
|
|
|
IDIV_DODIV,
|
|
|
|
IDIV_DODIV, IDIV_SH32,
|
|
|
|
IDIV_DIV, IDIV_DIV2, IDIV_DIV3, IDIV_DIV4, IDIV_DIV5,
|
|
|
|
IDIV_DIV, IDIV_DIV2, IDIV_DIV3, IDIV_DIV4, IDIV_DIV5,
|
|
|
|
IDIV_DIV6, IDIV_DIV7, IDIV_DIV8, IDIV_DIV9,
|
|
|
|
IDIV_DIV6, IDIV_DIV7, IDIV_DIV8, IDIV_DIV9,
|
|
|
|
IDIV_EXT_TBH, IDIV_EXT_TBH2, IDIV_EXT_TBH3,
|
|
|
|
IDIV_EXT_TBH, IDIV_EXT_TBH2, IDIV_EXT_TBH3,
|
|
|
@ -445,17 +445,20 @@ architecture behaviour of fpu is
|
|
|
|
|
|
|
|
|
|
|
|
-- Split a DP floating-point number into components and work out its class.
|
|
|
|
-- Split a DP floating-point number into components and work out its class.
|
|
|
|
-- If is_int = 1, the input is considered an integer
|
|
|
|
-- If is_int = 1, the input is considered an integer
|
|
|
|
function decode_dp(fpr: std_ulogic_vector(63 downto 0); is_int: std_ulogic) return fpu_reg_type is
|
|
|
|
function decode_dp(fpr: std_ulogic_vector(63 downto 0); is_int: std_ulogic;
|
|
|
|
|
|
|
|
is_32bint: std_ulogic; is_signed: std_ulogic) return fpu_reg_type is
|
|
|
|
variable r : fpu_reg_type;
|
|
|
|
variable r : fpu_reg_type;
|
|
|
|
variable exp_nz : std_ulogic;
|
|
|
|
variable exp_nz : std_ulogic;
|
|
|
|
variable exp_ao : std_ulogic;
|
|
|
|
variable exp_ao : std_ulogic;
|
|
|
|
variable frac_nz : std_ulogic;
|
|
|
|
variable frac_nz : std_ulogic;
|
|
|
|
|
|
|
|
variable low_nz : std_ulogic;
|
|
|
|
variable cls : std_ulogic_vector(2 downto 0);
|
|
|
|
variable cls : std_ulogic_vector(2 downto 0);
|
|
|
|
begin
|
|
|
|
begin
|
|
|
|
r.negative := fpr(63);
|
|
|
|
r.negative := fpr(63);
|
|
|
|
exp_nz := or (fpr(62 downto 52));
|
|
|
|
exp_nz := or (fpr(62 downto 52));
|
|
|
|
exp_ao := and (fpr(62 downto 52));
|
|
|
|
exp_ao := and (fpr(62 downto 52));
|
|
|
|
frac_nz := or (fpr(51 downto 0));
|
|
|
|
frac_nz := or (fpr(51 downto 0));
|
|
|
|
|
|
|
|
low_nz := or (fpr(31 downto 0));
|
|
|
|
if is_int = '0' then
|
|
|
|
if is_int = '0' then
|
|
|
|
r.exponent := signed(resize(unsigned(fpr(62 downto 52)), EXP_BITS)) - to_signed(1023, EXP_BITS);
|
|
|
|
r.exponent := signed(resize(unsigned(fpr(62 downto 52)), EXP_BITS)) - to_signed(1023, EXP_BITS);
|
|
|
|
if exp_nz = '0' then
|
|
|
|
if exp_nz = '0' then
|
|
|
@ -472,6 +475,16 @@ architecture behaviour of fpu is
|
|
|
|
when "110" => r.class := INFINITY;
|
|
|
|
when "110" => r.class := INFINITY;
|
|
|
|
when others => r.class := NAN;
|
|
|
|
when others => r.class := NAN;
|
|
|
|
end case;
|
|
|
|
end case;
|
|
|
|
|
|
|
|
elsif is_32bint = '1' then
|
|
|
|
|
|
|
|
r.negative := fpr(31);
|
|
|
|
|
|
|
|
r.mantissa(31 downto 0) := fpr(31 downto 0);
|
|
|
|
|
|
|
|
r.mantissa(63 downto 32) := (others => (is_signed and fpr(31)));
|
|
|
|
|
|
|
|
r.exponent := (others => '0');
|
|
|
|
|
|
|
|
if low_nz = '1' then
|
|
|
|
|
|
|
|
r.class := FINITE;
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
r.class := ZERO;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
else
|
|
|
|
else
|
|
|
|
r.mantissa := fpr;
|
|
|
|
r.mantissa := fpr;
|
|
|
|
r.exponent := (others => '0');
|
|
|
|
r.exponent := (others => '0');
|
|
|
@ -659,6 +672,7 @@ begin
|
|
|
|
variable j, k : integer;
|
|
|
|
variable j, k : integer;
|
|
|
|
variable flm : std_ulogic_vector(7 downto 0);
|
|
|
|
variable flm : std_ulogic_vector(7 downto 0);
|
|
|
|
variable int_input : std_ulogic;
|
|
|
|
variable int_input : std_ulogic;
|
|
|
|
|
|
|
|
variable is_32bint : std_ulogic;
|
|
|
|
variable mask : std_ulogic_vector(63 downto 0);
|
|
|
|
variable mask : std_ulogic_vector(63 downto 0);
|
|
|
|
variable in_a0 : std_ulogic_vector(63 downto 0);
|
|
|
|
variable in_a0 : std_ulogic_vector(63 downto 0);
|
|
|
|
variable in_b0 : std_ulogic_vector(63 downto 0);
|
|
|
|
variable in_b0 : std_ulogic_vector(63 downto 0);
|
|
|
@ -710,6 +724,8 @@ begin
|
|
|
|
variable round_inc : std_ulogic_vector(63 downto 0);
|
|
|
|
variable round_inc : std_ulogic_vector(63 downto 0);
|
|
|
|
variable rbit_inc : std_ulogic;
|
|
|
|
variable rbit_inc : std_ulogic;
|
|
|
|
variable mult_mask : std_ulogic;
|
|
|
|
variable mult_mask : std_ulogic;
|
|
|
|
|
|
|
|
variable sign_bit : std_ulogic;
|
|
|
|
|
|
|
|
variable rnd_b32 : std_ulogic;
|
|
|
|
variable int_result : std_ulogic;
|
|
|
|
variable int_result : std_ulogic;
|
|
|
|
variable illegal : std_ulogic;
|
|
|
|
variable illegal : std_ulogic;
|
|
|
|
begin
|
|
|
|
begin
|
|
|
@ -717,6 +733,7 @@ begin
|
|
|
|
v.complete := '0';
|
|
|
|
v.complete := '0';
|
|
|
|
v.do_intr := '0';
|
|
|
|
v.do_intr := '0';
|
|
|
|
int_input := '0';
|
|
|
|
int_input := '0';
|
|
|
|
|
|
|
|
is_32bint := '0';
|
|
|
|
|
|
|
|
|
|
|
|
if r.complete = '1' or r.do_intr = '1' then
|
|
|
|
if r.complete = '1' or r.do_intr = '1' then
|
|
|
|
v.instr_done := '0';
|
|
|
|
v.instr_done := '0';
|
|
|
@ -735,13 +752,26 @@ begin
|
|
|
|
v.fe_mode := or (e_in.fe_mode);
|
|
|
|
v.fe_mode := or (e_in.fe_mode);
|
|
|
|
v.dest_fpr := e_in.frt;
|
|
|
|
v.dest_fpr := e_in.frt;
|
|
|
|
v.single_prec := e_in.single;
|
|
|
|
v.single_prec := e_in.single;
|
|
|
|
v.longmask := e_in.single;
|
|
|
|
v.is_signed := e_in.is_signed;
|
|
|
|
v.rc := e_in.rc;
|
|
|
|
v.rc := e_in.rc;
|
|
|
|
v.is_cmp := e_in.out_cr;
|
|
|
|
v.is_cmp := e_in.out_cr;
|
|
|
|
int_input := '0';
|
|
|
|
v.longmask := '0';
|
|
|
|
|
|
|
|
v.divext := '0';
|
|
|
|
|
|
|
|
v.divmod := '0';
|
|
|
|
|
|
|
|
if e_in.op = OP_FPOP or e_in.op = OP_FPOP_I then
|
|
|
|
|
|
|
|
v.longmask := e_in.single;
|
|
|
|
if e_in.op = OP_FPOP_I then
|
|
|
|
if e_in.op = OP_FPOP_I then
|
|
|
|
int_input := '1';
|
|
|
|
int_input := '1';
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
else -- OP_DIV, OP_DIVE, OP_MOD
|
|
|
|
|
|
|
|
int_input := '1';
|
|
|
|
|
|
|
|
is_32bint := e_in.single;
|
|
|
|
|
|
|
|
if e_in.op = OP_DIVE then
|
|
|
|
|
|
|
|
v.divext := '1';
|
|
|
|
|
|
|
|
elsif e_in.op = OP_MOD then
|
|
|
|
|
|
|
|
v.divmod := '1';
|
|
|
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
v.quieten_nan := '1';
|
|
|
|
v.quieten_nan := '1';
|
|
|
|
v.tiny := '0';
|
|
|
|
v.tiny := '0';
|
|
|
|
v.denorm := '0';
|
|
|
|
v.denorm := '0';
|
|
|
@ -751,15 +781,12 @@ begin
|
|
|
|
v.is_sqrt := '0';
|
|
|
|
v.is_sqrt := '0';
|
|
|
|
v.add_bsmall := '0';
|
|
|
|
v.add_bsmall := '0';
|
|
|
|
v.doing_ftdiv := "00";
|
|
|
|
v.doing_ftdiv := "00";
|
|
|
|
v.divext := e_in.insn(8) and not e_in.insn(7);
|
|
|
|
|
|
|
|
v.divmod := not e_in.insn(8);
|
|
|
|
|
|
|
|
v.is_signed := e_in.is_signed;
|
|
|
|
|
|
|
|
v.int_ovf := '0';
|
|
|
|
v.int_ovf := '0';
|
|
|
|
v.div_close := '0';
|
|
|
|
v.div_close := '0';
|
|
|
|
|
|
|
|
|
|
|
|
adec := decode_dp(e_in.fra, int_input);
|
|
|
|
adec := decode_dp(e_in.fra, int_input, is_32bint, e_in.is_signed);
|
|
|
|
bdec := decode_dp(e_in.frb, int_input);
|
|
|
|
bdec := decode_dp(e_in.frb, int_input, is_32bint, e_in.is_signed);
|
|
|
|
cdec := decode_dp(e_in.frc, int_input);
|
|
|
|
cdec := decode_dp(e_in.frc, int_input, '0', '0');
|
|
|
|
v.a := adec;
|
|
|
|
v.a := adec;
|
|
|
|
v.b := bdec;
|
|
|
|
v.b := bdec;
|
|
|
|
v.c := cdec;
|
|
|
|
v.c := cdec;
|
|
|
@ -870,6 +897,7 @@ begin
|
|
|
|
shiftin0 := '0';
|
|
|
|
shiftin0 := '0';
|
|
|
|
rbit_inc := '0';
|
|
|
|
rbit_inc := '0';
|
|
|
|
mult_mask := '0';
|
|
|
|
mult_mask := '0';
|
|
|
|
|
|
|
|
rnd_b32 := '0';
|
|
|
|
int_result := '0';
|
|
|
|
int_result := '0';
|
|
|
|
illegal := '0';
|
|
|
|
illegal := '0';
|
|
|
|
case r.state is
|
|
|
|
case r.state is
|
|
|
@ -918,7 +946,7 @@ begin
|
|
|
|
else
|
|
|
|
else
|
|
|
|
v.state := DO_FRI;
|
|
|
|
v.state := DO_FRI;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
when "01001" =>
|
|
|
|
when "01001" | "01011" =>
|
|
|
|
-- integer divides and mods, major opcode 31
|
|
|
|
-- integer divides and mods, major opcode 31
|
|
|
|
v.opsel_a := AIN_B;
|
|
|
|
v.opsel_a := AIN_B;
|
|
|
|
v.state := DO_IDIVMOD;
|
|
|
|
v.state := DO_IDIVMOD;
|
|
|
@ -2552,6 +2580,10 @@ begin
|
|
|
|
v.shift := to_signed(-UNIT_BIT, EXP_BITS);
|
|
|
|
v.shift := to_signed(-UNIT_BIT, EXP_BITS);
|
|
|
|
v.first := '1';
|
|
|
|
v.first := '1';
|
|
|
|
v.state := IDIV_DIV;
|
|
|
|
v.state := IDIV_DIV;
|
|
|
|
|
|
|
|
elsif r.single_prec = '1' then
|
|
|
|
|
|
|
|
-- divwe[u][o], shift A left 32 bits
|
|
|
|
|
|
|
|
v.shift := to_signed(32, EXP_BITS);
|
|
|
|
|
|
|
|
v.state := IDIV_SH32;
|
|
|
|
elsif r.div_close = '0' then
|
|
|
|
elsif r.div_close = '0' then
|
|
|
|
v.shift := to_signed(64 - UNIT_BIT, EXP_BITS);
|
|
|
|
v.shift := to_signed(64 - UNIT_BIT, EXP_BITS);
|
|
|
|
v.state := IDIV_EXTDIV;
|
|
|
|
v.state := IDIV_EXTDIV;
|
|
|
@ -2561,6 +2593,12 @@ begin
|
|
|
|
v.opsel_a := AIN_C;
|
|
|
|
v.opsel_a := AIN_C;
|
|
|
|
v.state := IDIV_EXT_TBH;
|
|
|
|
v.state := IDIV_EXT_TBH;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
|
|
|
|
when IDIV_SH32 =>
|
|
|
|
|
|
|
|
-- r.shift = 32, R contains the dividend
|
|
|
|
|
|
|
|
opsel_r <= RES_SHIFT;
|
|
|
|
|
|
|
|
v.shift := to_signed(-UNIT_BIT, EXP_BITS);
|
|
|
|
|
|
|
|
v.first := '1';
|
|
|
|
|
|
|
|
v.state := IDIV_DIV;
|
|
|
|
when IDIV_DIV =>
|
|
|
|
when IDIV_DIV =>
|
|
|
|
-- Dividing A by C, r.shift = -56; A is in R
|
|
|
|
-- Dividing A by C, r.shift = -56; A is in R
|
|
|
|
-- Put A into the bottom 64 bits of Ahi/A/Alo
|
|
|
|
-- Put A into the bottom 64 bits of Ahi/A/Alo
|
|
|
@ -2805,13 +2843,22 @@ begin
|
|
|
|
-- and also negate R if the answer is negative
|
|
|
|
-- and also negate R if the answer is negative
|
|
|
|
opsel_ainv <= r.result_sign;
|
|
|
|
opsel_ainv <= r.result_sign;
|
|
|
|
carry_in <= r.inc_quot xor r.result_sign;
|
|
|
|
carry_in <= r.inc_quot xor r.result_sign;
|
|
|
|
|
|
|
|
rnd_b32 := '1';
|
|
|
|
|
|
|
|
if r.divmod = '0' then
|
|
|
|
|
|
|
|
opsel_b <= BIN_RND;
|
|
|
|
|
|
|
|
end if;
|
|
|
|
if r.is_signed = '0' then
|
|
|
|
if r.is_signed = '0' then
|
|
|
|
v.state := IDIV_DONE;
|
|
|
|
v.state := IDIV_DONE;
|
|
|
|
else
|
|
|
|
else
|
|
|
|
v.state := IDIV_OVFCHK;
|
|
|
|
v.state := IDIV_OVFCHK;
|
|
|
|
end if;
|
|
|
|
end if;
|
|
|
|
when IDIV_OVFCHK =>
|
|
|
|
when IDIV_OVFCHK =>
|
|
|
|
v.int_ovf := r.r(63) xor r.result_sign;
|
|
|
|
if r.single_prec = '0' then
|
|
|
|
|
|
|
|
sign_bit := r.r(63);
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
sign_bit := r.r(31);
|
|
|
|
|
|
|
|
end if;
|
|
|
|
|
|
|
|
v.int_ovf := sign_bit xor r.result_sign;
|
|
|
|
if v.int_ovf = '1' then
|
|
|
|
if v.int_ovf = '1' then
|
|
|
|
v.state := IDIV_ZERO;
|
|
|
|
v.state := IDIV_ZERO;
|
|
|
|
else
|
|
|
|
else
|
|
|
@ -2953,7 +3000,9 @@ begin
|
|
|
|
when BIN_R =>
|
|
|
|
when BIN_R =>
|
|
|
|
in_b0 := r.r;
|
|
|
|
in_b0 := r.r;
|
|
|
|
when BIN_RND =>
|
|
|
|
when BIN_RND =>
|
|
|
|
if rbit_inc = '0' then
|
|
|
|
if rnd_b32 = '1' then
|
|
|
|
|
|
|
|
round_inc := (32 => r.result_sign and r.single_prec, others => '0');
|
|
|
|
|
|
|
|
elsif rbit_inc = '0' then
|
|
|
|
round_inc := (SP_LSB => r.single_prec, DP_LSB => not r.single_prec, others => '0');
|
|
|
|
round_inc := (SP_LSB => r.single_prec, DP_LSB => not r.single_prec, others => '0');
|
|
|
|
else
|
|
|
|
else
|
|
|
|
round_inc := (DP_RBIT => '1', others => '0');
|
|
|
|
round_inc := (DP_RBIT => '1', others => '0');
|
|
|
|