


 Floatingpoint unit for Microwatt








library ieee;




use ieee.std_logic_1164.all;




use ieee.numeric_std.all;








library work;




use work.insn_helpers.all;




use work.decode_types.all;




use work.crhelpers.all;




use work.helpers.all;




use work.common.all;








entity fpu is




port (




clk : in std_ulogic;




rst : in std_ulogic;








e_in : in Execute1toFPUType;




e_out : out FPUToExecute1Type;








w_out : out FPUToWritebackType




);




end entity fpu;








architecture behaviour of fpu is




type fp_number_class is (ZERO, FINITE, INFINITY, NAN);








constant EXP_BITS : natural := 13;








type fpu_reg_type is record




class : fp_number_class;




negative : std_ulogic;




exponent : signed(EXP_BITS1 downto 0);  unbiased




mantissa : std_ulogic_vector(63 downto 0);  10.54 format




end record;








type state_t is (IDLE,




DO_MCRFS, DO_MTFSB, DO_MTFSFI, DO_MFFS, DO_MTFSF,

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



DO_FMR,




DO_FCFID,




DO_FRSP,

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



FINISH, NORMALIZE,




ROUND_UFLOW, ROUND_OFLOW,




ROUNDING, ROUNDING_2, ROUNDING_3,




DENORM);








type reg_type is record




state : state_t;




busy : std_ulogic;




instr_done : std_ulogic;




do_intr : std_ulogic;




op : insn_type_t;




insn : std_ulogic_vector(31 downto 0);




dest_fpr : gspr_index_t;




fe_mode : std_ulogic;




rc : std_ulogic;




is_cmp : std_ulogic;




single_prec : std_ulogic;




fpscr : std_ulogic_vector(31 downto 0);




a : fpu_reg_type;




b : fpu_reg_type;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



r : std_ulogic_vector(63 downto 0);  10.54 format




x : std_ulogic;




result_sign : std_ulogic;




result_class : fp_number_class;




result_exp : signed(EXP_BITS1 downto 0);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



shift : signed(EXP_BITS1 downto 0);




writing_back : std_ulogic;




int_result : std_ulogic;




cr_result : std_ulogic_vector(3 downto 0);




cr_mask : std_ulogic_vector(7 downto 0);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



old_exc : std_ulogic_vector(4 downto 0);




update_fprf : std_ulogic;




quieten_nan : std_ulogic;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



tiny : std_ulogic;




denorm : std_ulogic;




round_mode : std_ulogic_vector(2 downto 0);




end record;








signal r, rin : reg_type;








signal fp_result : std_ulogic_vector(63 downto 0);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



signal opsel_a : std_ulogic_vector(1 downto 0);




signal opsel_b : std_ulogic_vector(1 downto 0);




signal opsel_r : std_ulogic_vector(1 downto 0);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



signal opsel_ainv : std_ulogic;




signal opsel_amask : 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);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



signal carry_in : std_ulogic;




signal lost_bits : std_ulogic;




signal r_hi_nz : std_ulogic;




signal r_lo_nz : std_ulogic;




signal misc_sel : std_ulogic_vector(3 downto 0);








 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 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 RES_SUM : std_ulogic_vector(1 downto 0) := "00";




constant RES_SHIFT : std_ulogic_vector(1 downto 0) := "01";




constant RES_MISC : 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




 number in the range 64..63, with negative values indicating




 right shifts.




function shifter_64(inp: std_ulogic_vector(119 downto 0);




shift: std_ulogic_vector(6 downto 0))




return std_ulogic_vector is




variable s1 : std_ulogic_vector(94 downto 0);




variable s2 : std_ulogic_vector(70 downto 0);




variable result : std_ulogic_vector(63 downto 0);




begin




case shift(6 downto 5) is




when "00" =>




s1 := inp(119 downto 25);




when "01" =>




s1 := inp(87 downto 0) & "0000000";




when "10" =>




s1 := x"0000000000000000" & inp(119 downto 89);




when others =>




s1 := x"00000000" & inp(119 downto 57);




end case;




case shift(4 downto 3) is




when "00" =>




s2 := s1(94 downto 24);




when "01" =>




s2 := s1(86 downto 16);




when "10" =>




s2 := s1(78 downto 8);




when others =>




s2 := s1(70 downto 0);




end case;




case shift(2 downto 0) is




when "000" =>




result := s2(70 downto 7);




when "001" =>




result := s2(69 downto 6);




when "010" =>




result := s2(68 downto 5);




when "011" =>




result := s2(67 downto 4);




when "100" =>




result := s2(66 downto 3);




when "101" =>




result := s2(65 downto 2);




when "110" =>




result := s2(64 downto 1);




when others =>




result := s2(63 downto 0);




end case;




return result;




end;








 Generate a mask with 0bits on the left and 1bits on the right which




 selects the bits will be lost in doing a right shift. The shift




 parameter is the bottom 6 bits of a negative shift count,




 indicating a right shift.




function right_mask(shift: unsigned(5 downto 0)) return std_ulogic_vector is




variable result: std_ulogic_vector(63 downto 0);




begin




result := (others => '0');




for i in 0 to 63 loop




if i >= shift then




result(63  i) := '1';




end if;




end loop;




return result;




end;








 Split a DP floatingpoint 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




variable r : fpu_reg_type;




variable exp_nz : std_ulogic;




variable exp_ao : std_ulogic;




variable frac_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));




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




r.exponent := to_signed(1022, EXP_BITS);




end if;




r.mantissa := "000000000" & exp_nz & fpr(51 downto 0) & "00";




cls := exp_ao & exp_nz & frac_nz;




case cls is




when "000" => r.class := ZERO;




when "001" => r.class := FINITE;  denormalized




when "010" => r.class := FINITE;




when "011" => r.class := FINITE;




when "110" => r.class := INFINITY;




when others => r.class := NAN;




end case;




else




r.mantissa := fpr;




r.exponent := (others => '0');




if (fpr(63) or exp_nz or frac_nz) = '1' then




r.class := FINITE;




else




r.class := ZERO;




end if;




end if;




return r;




end;








 Construct a DP floatingpoint result from components




function pack_dp(sign: std_ulogic; class: fp_number_class; exp: signed(EXP_BITS1 downto 0);




mantissa: std_ulogic_vector; single_prec: std_ulogic; quieten_nan: std_ulogic)

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



return std_ulogic_vector is




variable result : std_ulogic_vector(63 downto 0);




begin




result := (others => '0');




result(63) := sign;




case class is




when ZERO =>




when FINITE =>




if mantissa(54) = '1' then




 normalized number




result(62 downto 52) := std_ulogic_vector(resize(exp, 11) + 1023);




end if;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



result(51 downto 29) := mantissa(53 downto 31);




if single_prec = '0' then




result(28 downto 0) := mantissa(30 downto 2);




end if;




when INFINITY =>




result(62 downto 52) := "11111111111";




when NAN =>




result(62 downto 52) := "11111111111";




result(51) := quieten_nan or mantissa(53);




result(50 downto 29) := mantissa(52 downto 31);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



if single_prec = '0' then




result(28 downto 0) := mantissa(30 downto 2);




end if;




end case;




return result;




end;





FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



 Determine whether to increment when rounding




 Returns rounding_inc & inexact




 Assumes x includes the bottom 29 bits of the mantissa already




 if single_prec = 1 (usually arranged by setting set_x = 1 earlier).




function fp_rounding(mantissa: std_ulogic_vector(63 downto 0); x: std_ulogic;




single_prec: std_ulogic; rn: std_ulogic_vector(2 downto 0);




sign: std_ulogic)




return std_ulogic_vector is




variable grx : std_ulogic_vector(2 downto 0);




variable ret : std_ulogic_vector(1 downto 0);




variable lsb : std_ulogic;




begin




if single_prec = '0' then




grx := mantissa(1 downto 0) & x;




lsb := mantissa(2);




else




grx := mantissa(30 downto 29) & x;




lsb := mantissa(31);




end if;




ret(1) := '0';




ret(0) := or (grx);




case rn(1 downto 0) is




when "00" =>  round to nearest




if grx = "100" and rn(2) = '0' then




ret(1) := lsb;  tie, round to even




else




ret(1) := grx(2);




end if;




when "01" =>  round towards zero




when others =>  round towards +/ inf




if rn(0) = sign then




 round towards greater magnitude




ret(1) := ret(0);




end if;




end case;




return ret;




end;








 Determine result flags to write into the FPSCR




function result_flags(sign: std_ulogic; class: fp_number_class; unitbit: std_ulogic)




return std_ulogic_vector is




begin




case class is




when ZERO =>




return sign & "0010";




when FINITE =>




return (not unitbit) & sign & (not sign) & "00";




when INFINITY =>




return '0' & sign & (not sign) & "01";




when NAN =>




return "10001";




end case;




end;








begin




fpu_0: process(clk)




begin




if rising_edge(clk) then




if rst = '1' then




r.state <= IDLE;




r.busy <= '0';




r.instr_done <= '0';




r.do_intr <= '0';




r.fpscr <= (others => '0');




r.writing_back <= '0';




else




assert not (r.state /= IDLE and e_in.valid = '1') severity failure;




r <= rin;




end if;




end if;




end process;








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.write_enable <= r.writing_back;




w_out.write_reg <= r.dest_fpr;




w_out.write_data <= fp_result;




w_out.write_cr_enable <= r.instr_done and (r.rc or r.is_cmp);




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;








fpu_1: process(all)




variable v : reg_type;




variable adec : fpu_reg_type;




variable bdec : fpu_reg_type;




variable fpscr_mask : std_ulogic_vector(31 downto 0);




variable illegal : std_ulogic;




variable j, k : integer;




variable flm : std_ulogic_vector(7 downto 0);




variable int_input : std_ulogic;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



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 misc : std_ulogic_vector(63 downto 0);




variable shift_res : std_ulogic_vector(63 downto 0);




variable round : std_ulogic_vector(1 downto 0);




variable update_fx : std_ulogic;




variable arith_done : std_ulogic;




variable invalid : std_ulogic;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



variable mant_nz : std_ulogic;




variable min_exp : signed(EXP_BITS1 downto 0);




variable max_exp : signed(EXP_BITS1 downto 0);




variable bias_exp : signed(EXP_BITS1 downto 0);




variable new_exp : signed(EXP_BITS1 downto 0);




variable exp_tiny : std_ulogic;




variable exp_huge : std_ulogic;




variable renormalize : std_ulogic;




variable clz : std_ulogic_vector(5 downto 0);




variable set_x : std_ulogic;




variable mshift : signed(EXP_BITS1 downto 0);




begin




v := r;




illegal := '0';




v.busy := '0';




int_input := '0';








 capture incoming instruction




if e_in.valid = '1' then




v.insn := e_in.insn;




v.op := e_in.op;




v.fe_mode := or (e_in.fe_mode);




v.dest_fpr := e_in.frt;




v.single_prec := e_in.single;




v.int_result := '0';




v.rc := e_in.rc;




v.is_cmp := e_in.out_cr;




if e_in.out_cr = '0' then




v.cr_mask := num_to_fxm(1);




else




v.cr_mask := num_to_fxm(to_integer(unsigned(insn_bf(e_in.insn))));




end if;




int_input := '0';




if e_in.op = OP_FPOP_I then




int_input := '1';




end if;




v.quieten_nan := '1';

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



v.tiny := '0';




v.denorm := '0';




v.round_mode := '0' & r.fpscr(FPSCR_RN+1 downto FPSCR_RN);




adec := decode_dp(e_in.fra, int_input);




bdec := decode_dp(e_in.frb, int_input);




v.a := adec;




v.b := bdec;




end if;





FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



r_hi_nz <= or (r.r(55 downto 31));




r_lo_nz <= or (r.r(30 downto 2));








if r.single_prec = '0' then




max_exp := to_signed(1023, EXP_BITS);




min_exp := to_signed(1022, EXP_BITS);




bias_exp := to_signed(1536, EXP_BITS);




else




max_exp := to_signed(127, EXP_BITS);




min_exp := to_signed(126, EXP_BITS);




bias_exp := to_signed(192, EXP_BITS);




end if;




new_exp := r.result_exp  r.shift;




exp_tiny := '0';




exp_huge := '0';




if new_exp < min_exp then




exp_tiny := '1';




end if;




if new_exp > max_exp then




exp_huge := '1';




end if;








v.writing_back := '0';




v.instr_done := '0';

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



v.update_fprf := '0';




v.shift := to_signed(0, EXP_BITS);




opsel_a <= AIN_R;




opsel_ainv <= '0';




opsel_amask <= '0';




opsel_b <= BIN_ZERO;




opsel_r <= RES_SUM;




carry_in <= '0';




misc_sel <= "0000";




fpscr_mask := (others => '1');

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



update_fx := '0';




arith_done := '0';




invalid := '0';

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



renormalize := '0';




set_x := '0';








case r.state is




when IDLE =>




if e_in.valid = '1' then




case e_in.insn(5 downto 1) is




when "00000" =>




v.state := DO_MCRFS;




when "00110" =>




if e_in.insn(8) = '0' then




v.state := DO_MTFSB;




else




v.state := DO_MTFSFI;




end if;




when "00111" =>




if e_in.insn(8) = '0' then




v.state := DO_MFFS;




else




v.state := DO_MTFSF;




end if;




when "01000" =>




v.state := DO_FMR;




when "01100" =>




v.state := DO_FRSP;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



when "01110" =>




 fcfid[u][s]




v.state := DO_FCFID;




when others =>




illegal := '1';




end case;




end if;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



v.x := '0';




v.old_exc := r.fpscr(FPSCR_VX downto FPSCR_XX);








when DO_MCRFS =>




j := to_integer(unsigned(insn_bfa(r.insn)));




for i in 0 to 7 loop




if i = j then




k := (7  i) * 4;




v.cr_result := r.fpscr(k + 3 downto k);




fpscr_mask(k + 3 downto k) := "0000";




end if;




end loop;




v.fpscr := r.fpscr and (fpscr_mask or x"6007F8FF");




v.instr_done := '1';




v.state := IDLE;








when DO_MTFSB =>




 mtfsb{0,1}




j := to_integer(unsigned(insn_bt(r.insn)));




for i in 0 to 31 loop




if i = j then




v.fpscr(31  i) := r.insn(6);




end if;




end loop;




v.instr_done := '1';




v.state := IDLE;








when DO_MTFSFI =>




 mtfsfi




j := to_integer(unsigned(insn_bf(r.insn)));




if r.insn(16) = '0' then




for i in 0 to 7 loop




if i = j then




k := (7  i) * 4;




v.fpscr(k + 3 downto k) := insn_u(r.insn);




end if;




end loop;




end if;




v.instr_done := '1';




v.state := IDLE;








when DO_MFFS =>




v.int_result := '1';




v.writing_back := '1';

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



opsel_r <= RES_MISC;




case r.insn(20 downto 16) is




when "00000" =>




 mffs




when "00001" =>




 mffsce




v.fpscr(FPSCR_VE downto FPSCR_XE) := "00000";




when "10100"  "10101" =>




 mffscdrn[i] (but we don't implement DRN)




fpscr_mask := x"000000FF";




when "10110" =>




 mffscrn




fpscr_mask := x"000000FF";




v.fpscr(FPSCR_RN+1 downto FPSCR_RN) :=




r.b.mantissa(FPSCR_RN+1 downto FPSCR_RN);




when "10111" =>




 mffscrni




fpscr_mask := x"000000FF";




v.fpscr(FPSCR_RN+1 downto FPSCR_RN) := r.insn(12 downto 11);




when "11000" =>




 mffsl




fpscr_mask := x"0007F0FF";




when others =>




illegal := '1';




end case;




v.instr_done := '1';




v.state := IDLE;








when DO_MTFSF =>




if r.insn(25) = '1' then




flm := x"FF";




elsif r.insn(16) = '1' then




flm := x"00";




else




flm := r.insn(24 downto 17);




end if;




for i in 0 to 7 loop




k := i * 4;




if flm(i) = '1' then




v.fpscr(k + 3 downto k) := r.b.mantissa(k + 3 downto k);




end if;




end loop;




v.instr_done := '1';




v.state := IDLE;








when DO_FMR =>

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



opsel_a <= AIN_B;




v.result_class := r.b.class;




v.result_exp := r.b.exponent;




v.quieten_nan := '0';




if r.insn(9) = '1' then




v.result_sign := '0';  fabs




elsif r.insn(8) = '1' then




v.result_sign := '1';  fnabs




elsif r.insn(7) = '1' then




v.result_sign := r.b.negative;  fmr




elsif r.insn(6) = '1' then




v.result_sign := not r.b.negative;  fneg




else




v.result_sign := r.a.negative;  fcpsgn




end if;




v.writing_back := '1';




v.instr_done := '1';




v.state := IDLE;








when DO_FRSP =>




opsel_a <= AIN_B;




v.result_class := r.b.class;




v.result_sign := r.b.negative;




v.result_exp := r.b.exponent;




v.fpscr(FPSCR_FR) := '0';




v.fpscr(FPSCR_FI) := '0';




if r.b.class = NAN and r.b.mantissa(53) = '0' then




 Signalling NAN




v.fpscr(FPSCR_VXSNAN) := '1';




invalid := '1';




end if;




set_x := '1';




if r.b.class = FINITE then




if r.b.exponent < to_signed(126, EXP_BITS) then




v.shift := r.b.exponent  to_signed(126, EXP_BITS);




v.state := ROUND_UFLOW;




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




arith_done := '1';




end if;





FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



when DO_FCFID =>




v.result_sign := '0';




opsel_a <= AIN_B;




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';




v.result_sign := '1';




end if;




v.result_class := r.b.class;




v.result_exp := to_signed(54, EXP_BITS);




v.fpscr(FPSCR_FR) := '0';




v.fpscr(FPSCR_FI) := '0';




if r.b.class = ZERO then




arith_done := '1';




else




v.state := FINISH;




end if;








when FINISH =>




if r.r(63 downto 54) /= "0000000001" then




renormalize := '1';




v.state := NORMALIZE;




else




set_x := '1';




if exp_tiny = '1' then




v.shift := new_exp  min_exp;




v.state := ROUND_UFLOW;




elsif exp_huge = '1' then




v.state := ROUND_OFLOW;




else




v.shift := to_signed(2, EXP_BITS);




v.state := ROUNDING;




end if;




end if;








when NORMALIZE =>




 Shift so we have 9 leading zeroes (we know R is nonzero)




opsel_r <= RES_SHIFT;




set_x := '1';




if exp_tiny = '1' then




v.shift := new_exp  min_exp;




v.state := ROUND_UFLOW;




elsif exp_huge = '1' then




v.state := ROUND_OFLOW;




else




v.shift := to_signed(2, EXP_BITS);




v.state := ROUNDING;




end if;








when ROUND_UFLOW =>




v.tiny := '1';




if r.fpscr(FPSCR_UE) = '0' then




 disabled underflow exception case




 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




 if denormalized, have to normalize before rounding




v.fpscr(FPSCR_UX) := '1';




v.result_exp := r.result_exp + bias_exp;




if r.r(54) = '0' then




renormalize := '1';




v.state := NORMALIZE;




else




v.shift := to_signed(2, EXP_BITS);




v.state := ROUNDING;




end if;




end if;








when ROUND_OFLOW =>




v.fpscr(FPSCR_OX) := '1';




if r.fpscr(FPSCR_OE) = '0' then




 disabled overflow exception




 result depends on rounding mode




v.fpscr(FPSCR_XX) := '1';




v.fpscr(FPSCR_FI) := '1';




if r.round_mode(1 downto 0) = "00" or




(r.round_mode(1) = '1' and r.round_mode(0) = r.result_sign) then




v.result_class := INFINITY;




v.fpscr(FPSCR_FR) := '1';




else




v.fpscr(FPSCR_FR) := '0';




end if;




 construct largest representable number




v.result_exp := max_exp;




opsel_r <= RES_MISC;




misc_sel <= "001" & r.single_prec;




arith_done := '1';




else




 enabled overflow exception




v.result_exp := r.result_exp  bias_exp;




v.shift := to_signed(2, EXP_BITS);




v.state := ROUNDING;




end if;








when ROUNDING =>




opsel_amask <= '1';




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';




v.shift := to_signed(1, EXP_BITS);




v.state := ROUNDING_2;




else




if r.r(54) = '0' then




 result after masking could be zero, or could be a




 denormalized result that needs to be renormalized




renormalize := '1';




v.state := ROUNDING_3;




else




arith_done := '1';




end if;




end if;




if round(0) = '1' then




v.fpscr(FPSCR_XX) := '1';




if r.tiny = '1' then




v.fpscr(FPSCR_UX) := '1';




end if;




end if;








when ROUNDING_2 =>




 Check for overflow during rounding




v.x := '0';




if r.r(55) = '1' then




opsel_r <= RES_SHIFT;




if exp_huge = '1' then




v.state := ROUND_OFLOW;




else




arith_done := '1';




end if;




elsif r.r(54) = '0' then




 Do CLZ so we can renormalize the result




renormalize := '1';




v.state := ROUNDING_3;




else




arith_done := '1';




end if;








when ROUNDING_3 =>




mant_nz := r_hi_nz or (r_lo_nz and not r.single_prec);




if mant_nz = '0' then




v.result_class := ZERO;




arith_done := '1';




else




 Renormalize result after rounding




opsel_r <= RES_SHIFT;




v.denorm := exp_tiny;




v.shift := new_exp  to_signed(1022, EXP_BITS);




if new_exp < to_signed(1022, EXP_BITS) then




v.state := DENORM;




else




arith_done := '1';




end if;




end if;








when DENORM =>




opsel_r <= RES_SHIFT;




arith_done := '1';








end case;





FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



if arith_done = '1' then




 Enabled invalid exception doesn't write result or FPRF




if (invalid and r.fpscr(FPSCR_VE)) = '0' then




v.writing_back := '1';




v.update_fprf := '1';




end if;

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



v.instr_done := '1';




v.state := IDLE;




update_fx := '1';




end if;








 Data path.

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



 This has A and B input multiplexers, an adder, a shifter,




 countleadingzeroes logic, and a result mux.




if r.single_prec = '1' then




mshift := r.shift + to_signed(29, EXP_BITS);




else




mshift := r.shift;




end if;




if mshift < to_signed(64, EXP_BITS) then




mask := (others => '1');




elsif mshift >= to_signed(0, EXP_BITS) then




mask := (others => '0');




else




mask := right_mask(unsigned(mshift(5 downto 0)));




end if;




case opsel_a is




when AIN_R =>




in_a0 := r.r;




when AIN_A =>




in_a0 := r.a.mantissa;




when others =>




in_a0 := r.b.mantissa;




end case;




if (or (mask and in_a0)) = '1' and set_x = '1' then




v.x := '1';




end if;




if opsel_ainv = '1' then




in_a0 := not in_a0;




end if;




if opsel_amask = '1' then




in_a0 := in_a0 and not mask;




end if;




in_a <= in_a0;




case opsel_b is




when BIN_ZERO =>




in_b0 := (others => '0');




when BIN_R =>




in_b0 := r.r;




when BIN_MASK =>




in_b0 := mask;




when others =>




in_b0 := (others => '0');




end case;




in_b <= in_b0;




if r.shift >= to_signed(64, EXP_BITS) and r.shift <= to_signed(63, EXP_BITS) then




shift_res := shifter_64(r.r & x"00000000000000",




std_ulogic_vector(r.shift(6 downto 0)));




else




shift_res := (others => '0');




end if;




case opsel_r is

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



when RES_SUM =>




result <= std_ulogic_vector(unsigned(in_a) + unsigned(in_b) + carry_in);




when RES_SHIFT =>




result <= shift_res;




when others =>

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



case misc_sel is




when "0000" =>




misc := x"00000000" & (r.fpscr and fpscr_mask);




when "0010" =>




 mantissa of max representable DP number




misc := x"007ffffffffffffc";




when "0011" =>




 mantissa of max representable SP number




misc := x"007fffff80000000";




when others =>




misc := x"0000000000000000";




end case;




result <= misc;




end case;




v.r := result;





FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



if opsel_r = RES_SHIFT then




v.result_exp := new_exp;




end if;








if renormalize = '1' then




clz := count_left_zeroes(r.r);




v.shift := resize(signed('0' & clz)  9, EXP_BITS);




end if;








if r.int_result = '1' then




fp_result <= r.r;




else

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



fp_result <= pack_dp(r.result_sign, r.result_class, r.result_exp, r.r,




r.single_prec, r.quieten_nan);

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



end if;




if r.update_fprf = '1' then




v.fpscr(FPSCR_C downto FPSCR_FU) := result_flags(r.result_sign, r.result_class,




r.r(54) and not r.denorm);




end if;








v.fpscr(FPSCR_VX) := (or (v.fpscr(FPSCR_VXSNAN downto FPSCR_VXVC))) or




(or (v.fpscr(FPSCR_VXSOFT downto FPSCR_VXCVI)));




v.fpscr(FPSCR_FEX) := or (v.fpscr(FPSCR_VX downto FPSCR_XX) and




v.fpscr(FPSCR_VE downto FPSCR_XE));

FPU: Implement floating convert from integer instructions
This implements fcfid, fcfidu, fcfids and fcfidus, which convert
64bit integer values in an FPR into a floatingpoint value.
This brings in a lot of the datapath that will be needed in
future, including the shifter, adder, mask generator and
countleadingzeroes logic, along with the machinery for rounding
to singleprecision or doubleprecision, detecting inexact results,
signalling inexactresult exceptions, and updating result flags
in the FPSCR.
Signedoffby: Paul Mackerras <paulus@ozlabs.org>
4 years ago



if update_fx = '1' and




(v.fpscr(FPSCR_VX downto FPSCR_XX) and not r.old_exc) /= "00000" then




v.fpscr(FPSCR_FX) := '1';




end if;




if r.rc = '1' then




v.cr_result := v.fpscr(FPSCR_FX downto FPSCR_OX);




end if;








if illegal = '1' then




v.instr_done := '0';




v.do_intr := '0';




v.writing_back := '0';




v.busy := '0';




v.state := IDLE;




else




v.do_intr := v.instr_done and v 