IDIV_NORMB, IDIV_NORMB2, IDIV_NORMB3,
IDIV_CLZA, IDIV_CLZA2, IDIV_CLZA3,
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_DIV6, IDIV_DIV7, IDIV_DIV8, IDIV_DIV9,
IDIV_EXT_TBH, IDIV_EXT_TBH2, IDIV_EXT_TBH3,
-- Split a DP floating-point number into components and work out its class.
-- 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 exp_nz : std_ulogic;
variable exp_ao : std_ulogic;
variable frac_nz : std_ulogic;
+ variable low_nz : std_ulogic;
variable cls : std_ulogic_vector(2 downto 0);
begin
r.negative := fpr(63);
exp_nz := or (fpr(62 downto 52));
exp_ao := and (fpr(62 downto 52));
frac_nz := or (fpr(51 downto 0));
+ low_nz := or (fpr(31 downto 0));
if is_int = '0' then
r.exponent := signed(resize(unsigned(fpr(62 downto 52)), EXP_BITS)) - to_signed(1023, EXP_BITS);
if exp_nz = '0' then
when "110" => r.class := INFINITY;
when others => r.class := NAN;
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
r.mantissa := fpr;
r.exponent := (others => '0');
variable j, k : integer;
variable flm : std_ulogic_vector(7 downto 0);
variable int_input : std_ulogic;
+ variable is_32bint : std_ulogic;
variable mask : 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 round_inc : std_ulogic_vector(63 downto 0);
variable rbit_inc : std_ulogic;
variable mult_mask : std_ulogic;
+ variable sign_bit : std_ulogic;
+ variable rnd_b32 : std_ulogic;
variable int_result : std_ulogic;
variable illegal : std_ulogic;
begin
v.complete := '0';
v.do_intr := '0';
int_input := '0';
+ is_32bint := '0';
if r.complete = '1' or r.do_intr = '1' then
v.instr_done := '0';
v.fe_mode := or (e_in.fe_mode);
v.dest_fpr := e_in.frt;
v.single_prec := e_in.single;
- v.longmask := e_in.single;
+ v.is_signed := e_in.is_signed;
v.rc := e_in.rc;
v.is_cmp := e_in.out_cr;
- int_input := '0';
- if e_in.op = OP_FPOP_I then
+ 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
+ int_input := '1';
+ 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.tiny := '0';
v.is_sqrt := '0';
v.add_bsmall := '0';
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.div_close := '0';
- adec := decode_dp(e_in.fra, int_input);
- bdec := decode_dp(e_in.frb, int_input);
- cdec := decode_dp(e_in.frc, int_input);
+ adec := decode_dp(e_in.fra, int_input, is_32bint, e_in.is_signed);
+ bdec := decode_dp(e_in.frb, int_input, is_32bint, e_in.is_signed);
+ cdec := decode_dp(e_in.frc, int_input, '0', '0');
v.a := adec;
v.b := bdec;
v.c := cdec;
shiftin0 := '0';
rbit_inc := '0';
mult_mask := '0';
+ rnd_b32 := '0';
int_result := '0';
illegal := '0';
case r.state is
else
v.state := DO_FRI;
end if;
- when "01001" =>
+ when "01001" | "01011" =>
-- integer divides and mods, major opcode 31
v.opsel_a := AIN_B;
v.state := DO_IDIVMOD;
v.shift := to_signed(-UNIT_BIT, EXP_BITS);
v.first := '1';
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
v.shift := to_signed(64 - UNIT_BIT, EXP_BITS);
v.state := IDIV_EXTDIV;
v.opsel_a := AIN_C;
v.state := IDIV_EXT_TBH;
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 =>
-- Dividing A by C, r.shift = -56; A is in R
-- Put A into the bottom 64 bits of Ahi/A/Alo
-- and also negate R if the answer is negative
opsel_ainv <= 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
v.state := IDIV_DONE;
else
v.state := IDIV_OVFCHK;
end if;
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
v.state := IDIV_ZERO;
else
when BIN_R =>
in_b0 := r.r;
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');
else
round_inc := (DP_RBIT => '1', others => '0');