busy : std_ulogic;
instr_done : std_ulogic;
do_intr : std_ulogic;
+ illegal : std_ulogic;
op : insn_type_t;
insn : std_ulogic_vector(31 downto 0);
+ nia : std_ulogic_vector(63 downto 0);
+ instr_tag : instr_tag_t;
dest_fpr : gspr_index_t;
fe_mode : std_ulogic;
rc : std_ulogic;
constant BIN_ZERO : std_ulogic_vector(1 downto 0) := "00";
constant BIN_R : std_ulogic_vector(1 downto 0) := "01";
- constant BIN_MASK : std_ulogic_vector(1 downto 0) := "10";
+ constant BIN_RND : std_ulogic_vector(1 downto 0) := "10";
constant BIN_PS6 : std_ulogic_vector(1 downto 0) := "11";
constant RES_SUM : std_ulogic_vector(1 downto 0) := "00";
e_out.busy <= r.busy;
e_out.exception <= r.fpscr(FPSCR_FEX);
- e_out.interrupt <= r.do_intr;
w_out.valid <= r.instr_done and not r.do_intr;
+ w_out.instr_tag <= r.instr_tag;
w_out.write_enable <= r.writing_back;
w_out.write_reg <= r.dest_fpr;
w_out.write_data <= fp_result;
w_out.write_cr_mask <= r.cr_mask;
w_out.write_cr_data <= r.cr_result & r.cr_result & r.cr_result & r.cr_result &
r.cr_result & r.cr_result & r.cr_result & r.cr_result;
+ w_out.interrupt <= r.do_intr;
+ w_out.intr_vec <= 16#700#;
+ w_out.srr0 <= r.nia;
+ w_out.srr1 <= (47-44 => r.illegal, 47-43 => not r.illegal, others => '0');
fpu_1: process(all)
variable v : reg_type;
variable mulexp : signed(EXP_BITS-1 downto 0);
variable maddend : std_ulogic_vector(127 downto 0);
variable sum : std_ulogic_vector(63 downto 0);
+ variable round_inc : std_ulogic_vector(63 downto 0);
begin
v := r;
illegal := '0';
-- capture incoming instruction
if e_in.valid = '1' then
v.insn := e_in.insn;
+ v.nia := e_in.nia;
v.op := e_in.op;
+ v.instr_tag := e_in.itag;
v.fe_mode := or (e_in.fe_mode);
v.dest_fpr := e_in.frt;
v.single_prec := e_in.single;
elsif r.b.exponent > to_signed(127, EXP_BITS) then
v.state := ROUND_OFLOW;
else
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
else
-- sum overflowed, shift right
opsel_r <= RES_SHIFT;
set_x := '1';
- v.shift := to_signed(-2, EXP_BITS);
if exp_huge = '1' then
v.state := ROUND_OFLOW;
else
end if;
elsif r.r(54) = '1' then
set_x := '1';
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
elsif (r_hi_nz or r_lo_nz or r.r(1) or r.r(0)) = '0' then
-- r.x must be zero at this point
opsel_r <= RES_MULT;
opsel_s <= S_MULT;
set_s := '1';
- v.shift := to_signed(56, EXP_BITS);
if multiply_to_f.valid = '1' then
- if multiply_to_f.result(121) = '1' then
- v.state := FMADD_5;
- else
- v.state := FMADD_6;
- end if;
+ v.state := FMADD_5;
end if;
when FMADD_5 =>
- -- negate R:S:X
- v.result_sign := not r.result_sign;
- opsel_ainv <= '1';
- carry_in <= not (s_nz or r.x);
- opsel_s <= S_NEG;
- set_s := '1';
+ -- negate R:S:X if negative
+ if r.r(63) = '1' then
+ v.result_sign := not r.result_sign;
+ opsel_ainv <= '1';
+ carry_in <= not (s_nz or r.x);
+ opsel_s <= S_NEG;
+ set_s := '1';
+ end if;
v.shift := to_signed(56, EXP_BITS);
v.state := FMADD_6;
-- r.shift = b.exponent - 52
opsel_r <= RES_SHIFT;
set_x := '1';
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
when FINISH =>
elsif exp_huge = '1' then
v.state := ROUND_OFLOW;
else
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
end if;
elsif exp_huge = '1' then
v.state := ROUND_OFLOW;
else
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
-- have to denormalize before rounding
opsel_r <= RES_SHIFT;
set_x := '1';
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
else
-- enabled underflow exception case
renormalize := '1';
v.state := NORMALIZE;
else
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
end if;
else
-- enabled overflow exception
v.result_exp := r.result_exp - bias_exp;
- v.shift := to_signed(-2, EXP_BITS);
v.state := ROUNDING;
end if;
round := fp_rounding(r.r, r.x, r.single_prec, r.round_mode, r.result_sign);
v.fpscr(FPSCR_FR downto FPSCR_FI) := round;
if round(1) = '1' then
- -- set mask to increment the LSB for the precision
- opsel_b <= BIN_MASK;
- carry_in <= '1';
+ -- increment the LSB for the precision
+ opsel_b <= BIN_RND;
v.shift := to_signed(-1, EXP_BITS);
v.state := ROUNDING_2;
else
in_b0 := (others => '0');
when BIN_R =>
in_b0 := r.r;
- when BIN_MASK =>
- in_b0 := mask;
+ when BIN_RND =>
+ round_inc := (31 => r.single_prec, 2 => not r.single_prec, others => '0');
+ in_b0 := round_inc;
when others =>
-- BIN_PS6, 6 LSBs of P/4 sign-extended to 64
in_b0 := std_ulogic_vector(resize(signed(r.p(7 downto 2)), 64));
end if;
sum := std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);
if opsel_mask = '1' then
- sum := sum and not mask;
+ sum(1 downto 0) := "00";
+ if r.single_prec = '1' then
+ sum(30 downto 2) := (others => '0');
+ end if;
end if;
case opsel_r is
when RES_SUM =>
v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);
end if;
+ v.illegal := illegal;
if illegal = '1' then
v.instr_done := '0';
- v.do_intr := '0';
+ v.do_intr := '1';
v.writing_back := '0';
v.busy := '0';
v.state := IDLE;
end if;
rin <= v;
- e_out.illegal <= illegal;
end process;
end architecture behaviour;