@ -40,15 +40,18 @@ architecture behaviour of fpu is
DO_FMR, DO_FMRG,
DO_FCFID, DO_FCTI,
DO_FRSP, DO_FRI,
DO_FADD,
DO_FADD, DO_FMUL,
FRI_1,
ADD_SHIFT, ADD_2, ADD_3,
MULT_1,
INT_SHIFT, INT_ROUND, INT_ISHIFT,
INT_FINAL, INT_CHECK, INT_OFLOW,
FINISH, NORMALIZE,
ROUND_UFLOW, ROUND_OFLOW,
ROUNDING, ROUNDING_2, ROUNDING_3,
DENORM);
DENORM,
RENORM_A, RENORM_A2,
RENORM_C, RENORM_C2);
type reg_type is record
state : state_t;
@ -65,8 +68,10 @@ architecture behaviour of fpu is
fpscr : std_ulogic_vector(31 downto 0);
a : fpu_reg_type;
b : fpu_reg_type;
c : fpu_reg_type;
r : std_ulogic_vector(63 downto 0); -- 10.54 format
x : std_ulogic;
p : std_ulogic_vector(63 downto 0); -- 8.56 format
result_sign : std_ulogic;
result_class : fp_number_class;
result_exp : signed(EXP_BITS-1 downto 0);
@ -84,6 +89,8 @@ architecture behaviour of fpu is
is_subtract : std_ulogic;
exp_cmp : std_ulogic;
add_bsmall : std_ulogic;
is_multiply : std_ulogic;
first : std_ulogic;
end record;
signal r, rin : reg_type;
@ -103,11 +110,17 @@ architecture behaviour of fpu is
signal r_hi_nz : std_ulogic;
signal r_lo_nz : std_ulogic;
signal misc_sel : std_ulogic_vector(3 downto 0);
signal f_to_multiply : MultiplyInputType;
signal multiply_to_f : MultiplyOutputType;
signal msel_1 : std_ulogic_vector(1 downto 0);
signal msel_2 : std_ulogic_vector(1 downto 0);
signal msel_inv : std_ulogic;
-- opsel values
constant AIN_R : std_ulogic_vector(1 downto 0) := "00";
constant AIN_A : std_ulogic_vector(1 downto 0) := "01";
constant AIN_B : std_ulogic_vector(1 downto 0) := "10";
constant AIN_C : std_ulogic_vector(1 downto 0) := "11";
constant BIN_ZERO : std_ulogic_vector(1 downto 0) := "00";
constant BIN_R : std_ulogic_vector(1 downto 0) := "01";
@ -115,8 +128,17 @@ architecture behaviour of fpu is
constant RES_SUM : std_ulogic_vector(1 downto 0) := "00";
constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01";
constant RES_MULT : std_ulogic_vector(1 downto 0) := "10";
constant RES_MISC : std_ulogic_vector(1 downto 0) := "11";
-- msel values
constant MUL1_A : std_ulogic_vector(1 downto 0) := "00";
constant MUL1_B : std_ulogic_vector(1 downto 0) := "01";
constant MUL1_R : std_ulogic_vector(1 downto 0) := "11";
constant MUL2_C : std_ulogic_vector(1 downto 0) := "00";
constant MUL2_R : std_ulogic_vector(1 downto 0) := "11";
-- Left and right shifter with 120 bit input and 64 bit output.
-- Shifts inp left by shift bits and returns the upper 64 bits of
-- the result. The shift parameter is interpreted as a signed
@ -313,6 +335,13 @@ architecture behaviour of fpu is
end;
begin
fpu_multiply_0: entity work.multiply
port map (
clk => clk,
m_in => f_to_multiply,
m_out => multiply_to_f
);
fpu_0: process(clk)
begin
if rising_edge(clk) then
@ -347,6 +376,7 @@ begin
variable v : reg_type;
variable adec : fpu_reg_type;
variable bdec : fpu_reg_type;
variable cdec : fpu_reg_type;
variable fpscr_mask : std_ulogic_vector(31 downto 0);
variable illegal : std_ulogic;
variable j, k : integer;
@ -377,6 +407,10 @@ begin
variable is_add : std_ulogic;
variable qnan_result : std_ulogic;
variable longmask : std_ulogic;
variable set_a : std_ulogic;
variable set_c : std_ulogic;
variable px_nz : std_ulogic;
variable maddend : std_ulogic_vector(127 downto 0);
begin
v := r;
illegal := '0';
@ -407,11 +441,15 @@ begin
v.denorm := '0';
v.round_mode := '0' & r.fpscr(FPSCR_RN+1 downto FPSCR_RN);
v.is_subtract := '0';
v.is_multiply := '0';
v.add_bsmall := '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);
v.a := adec;
v.b := bdec;
v.c := cdec;
v.exp_cmp := '0';
if adec.exponent > bdec.exponent then
v.exp_cmp := '1';
@ -440,10 +478,14 @@ begin
exp_huge := '1';
end if;
-- Compare P with zero
px_nz := or (r.p(57 downto 4));
v.writing_back := '0';
v.instr_done := '0';
v.update_fprf := '0';
v.shift := to_signed(0, EXP_BITS);
v.first := '0';
opsel_a <= AIN_R;
opsel_ainv <= '0';
opsel_amask <= '0';
@ -460,6 +502,13 @@ begin
set_x := '0';
qnan_result := '0';
longmask := r.single_prec;
set_a := '0';
set_c := '0';
f_to_multiply.is_32bit <= '0';
f_to_multiply.valid <= '0';
msel_1 <= MUL1_A;
msel_2 <= MUL2_C;
msel_inv <= '0';
case r.state is
when IDLE =>
@ -503,6 +552,9 @@ begin
v.state := DO_FCTI;
when "10100" | "10101" =>
v.state := DO_FADD;
when "11001" =>
v.is_multiply := '1';
v.state := DO_FMUL;
when others =>
illegal := '1';
end case;
@ -795,6 +847,81 @@ begin
arith_done := '1';
end if;
when DO_FMUL =>
-- fmul[s]
opsel_a <= AIN_A;
v.result_sign := r.a.negative;
v.result_class := r.a.class;
v.result_exp := r.a.exponent;
v.fpscr(FPSCR_FR) := '0';
v.fpscr(FPSCR_FI) := '0';
if r.a.class = FINITE and r.c.class = FINITE then
v.result_sign := r.a.negative xor r.c.negative;
v.result_exp := r.a.exponent + r.c.exponent;
-- Renormalize denorm operands
if r.a.mantissa(54) = '0' then
v.state := RENORM_A;
elsif r.c.mantissa(54) = '0' then
opsel_a <= AIN_C;
v.state := RENORM_C;
else
f_to_multiply.valid <= '1';
v.state := MULT_1;
end if;
else
if (r.a.class = NAN and r.a.mantissa(53) = '0') or
(r.c.class = NAN and r.c.mantissa(53) = '0') then
-- Signalling NAN
v.fpscr(FPSCR_VXSNAN) := '1';
invalid := '1';
end if;
if r.a.class = NAN then
-- result is A
elsif r.c.class = NAN then
v.result_class := NAN;
v.result_sign := r.c.negative;
opsel_a <= AIN_C;
elsif (r.a.class = INFINITY and r.c.class = ZERO) or
(r.a.class = ZERO and r.c.class = INFINITY) then
-- invalid operation, construct QNaN
v.fpscr(FPSCR_VXIMZ) := '1';
qnan_result := '1';
elsif r.a.class = ZERO or r.a.class = INFINITY then
-- result is +/- A
v.result_sign := r.a.negative xor r.c.negative;
else
-- r.c.class is ZERO or INFINITY
v.result_class := r.c.class;
v.result_sign := r.a.negative xor r.c.negative;
end if;
arith_done := '1';
end if;
when RENORM_A =>
renormalize := '1';
v.state := RENORM_A2;
when RENORM_A2 =>
set_a := '1';
v.result_exp := new_exp;
opsel_a <= AIN_C;
if r.c.mantissa(54) = '1' then
v.first := '1';
v.state := MULT_1;
else
v.state := RENORM_C;
end if;
when RENORM_C =>
renormalize := '1';
v.state := RENORM_C2;
when RENORM_C2 =>
set_c := '1';
v.result_exp := new_exp;
v.first := '1';
v.state := MULT_1;
when ADD_SHIFT =>
opsel_r <= RES_SHIFT;
set_x := '1';
@ -848,6 +975,13 @@ begin
v.state := NORMALIZE;
end if;
when MULT_1 =>
f_to_multiply.valid <= r.first;
opsel_r <= RES_MULT;
if multiply_to_f.valid = '1' then
v.state := FINISH;
end if;
when INT_SHIFT =>
opsel_r <= RES_SHIFT;
set_x := '1';
@ -930,6 +1064,9 @@ begin
v.state := ROUNDING;
when FINISH =>
if r.is_multiply = '1' and px_nz = '1' then
v.x := '1';
end if;
if r.r(63 downto 54) /= "0000000001" then
renormalize := '1';
v.state := NORMALIZE;
@ -1099,6 +1236,32 @@ begin
update_fx := '1';
end if;
-- Multiplier data path
case msel_1 is
when MUL1_A =>
f_to_multiply.data1 <= r.a.mantissa(61 downto 0) & "00";
when MUL1_B =>
f_to_multiply.data1 <= r.b.mantissa(61 downto 0) & "00";
when others =>
f_to_multiply.data1 <= r.r(61 downto 0) & "00";
end case;
case msel_2 is
when MUL2_C =>
f_to_multiply.data2 <= r.c.mantissa(61 downto 0) & "00";
when others =>
f_to_multiply.data2 <= r.r(61 downto 0) & "00";
end case;
maddend := (others => '0');
if msel_inv = '1' then
f_to_multiply.addend <= not maddend;
else
f_to_multiply.addend <= maddend;
end if;
f_to_multiply.not_result <= msel_inv;
if multiply_to_f.valid = '1' then
v.p := multiply_to_f.result(63 downto 0);
end if;
-- Data path.
-- This has A and B input multiplexers, an adder, a shifter,
-- count-leading-zeroes logic, and a result mux.
@ -1119,8 +1282,10 @@ begin
in_a0 := r.r;
when AIN_A =>
in_a0 := r.a.mantissa;
when others =>
when AIN_B =>
in_a0 := r.b.mantissa;
when others =>
in_a0 := r.c.mantissa;
end case;
if (or (mask and in_a0)) = '1' and set_x = '1' then
v.x := '1';
@ -1157,6 +1322,8 @@ begin
result <= std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);
when RES_SHIFT =>
result <= shift_res;
when RES_MULT =>
result <= multiply_to_f.result(121 downto 58);
when others =>
case misc_sel is
when "0000" =>
@ -1207,6 +1374,15 @@ begin
end case;
v.r := result;
if set_a = '1' then
v.a.exponent := new_exp;
v.a.mantissa := shift_res;
end if;
if set_c = '1' then
v.c.exponent := new_exp;
v.c.mantissa := shift_res;
end if;
if opsel_r = RES_SHIFT then
v.result_exp := new_exp;
end if;