📄 fpu_lth.vhd
字号:
-- Calculate condition codes. cc_bit1 := ((not zero_fraction) and (not neg_value) and (not as.swaped)) or unordered; cc_bit0 := ((not zero_fraction) and (as.swaped or (neg_value and (not as.swaped)))) or unordered; -- Set condition codes if comp signal is 1. if as.comp = '1' then posn_in.cc <= cc_bit1 & cc_bit0; else posn_in.cc <= (others => '0'); end if; -- Set exceptions posn_in.exc <= SNaN & inf & "000"; -- Check if operation results in specal value posn_in.res_SNaN <= SNaN; posn_in.res_NaN <= NaN; posn_in.res_inf <= inf; posn_in.single <= as.single; posn_in.res_zero <= zero_fraction; posn_in.comp <= as.comp; end process addsub_stage;--------------------------------------------------------------------------------- Postnorm stage------------------------------------------------------------------------------- posnorm_stage: process (posn) variable mask : std_logic_vector(55 downto 0); variable leading_one : std_logic_vector(55 downto 0); variable leading_zeros : std_logic_vector(55 downto 0); variable shifts_needed : std_logic_vector(5 downto 0); variable shift_amount : std_logic_vector(5 downto 0); variable exp : std_logic_vector(10 downto 0); variable frac : std_logic_vector(56 downto 0); variable overflow : std_logic; variable underflow : std_logic; begin -- If supernormal (overflow bit set) shift left by one step and inc exp if ((posn.single = '1') and (posn.frac(27) = '1')) or (posn.frac(56) = '1') then frac := "0" & posn.frac(56 downto 1);-- pragma translate_off if not is_x(posn.exp) then-- pragma translate_on exp := posn.exp + 1;-- pragma translate_off end if;-- pragma translate_on underflow := '0'; else -- Get number of leading zeros, if single precision is used don't count -- leading 29 zeroes. (Overflow bit is not counted) if posn.single = '1' then lz_counter((posn.frac(26 downto 0) & "0" & zero(27 downto 0)),shifts_needed); else lz_counter(posn.frac(55 downto 0),shifts_needed); end if; -- If the shift amount needed is larger then the exponent then underflow -- has occured, check that fraction is not zero.-- pragma translate_off if not is_x(shifts_needed & posn.exp) then-- pragma translate_on if (unsigned(shifts_needed) > unsigned(posn.exp)) and (posn.res_zero = '0') then shift_amount := posn.exp(5 downto 0); exp := (others => '0'); underflow := '1'; else shift_amount := shifts_needed;-- pragma translate_off if not is_x( posn.exp & shift_amount) then-- pragma translate_on exp := posn.exp - shift_amount;-- pragma translate_off end if;-- pragma translate_on underflow := '0'; end if;-- pragma translate_off end if;-- pragma translate_on -- Perform left shift left_shifter(posn.frac,shift_amount,frac); end if; -- Check if overflow has occured, also check that result is not any NaN if (exp(7 downto 0) = "11111111") and ((posn.single = '1') or (exp(10 downto 8) = "111")) and (posn.res_SNaN = '0') and (posn.res_NaN = '0') then overflow := '1'; else overflow := '0'; end if; -- If operation is not some sort of compare set overflow/underflow -- exceptions caused in this pipeline stage if (posn.comp = '0') then rnd_in.exc <= posn.exc(4) & overflow & underflow & posn.exc(1 downto 0); else rnd_in.exc <= posn.exc(4) & "00" & posn.exc(1 downto 0); end if; rnd_in.frac <= frac; rnd_in.exp <= exp; rnd_in.cc <= posn.cc; rnd_in.res_NaN <= posn.res_NaN; rnd_in.res_SNaN <= posn.res_SNaN; rnd_in.res_inf <= posn.res_inf or overflow; rnd_in.single <= posn.single; rnd_in.comp <= posn.comp; rnd_in.sign <= posn.sign; end process posnorm_stage; --------------------------------------------------------------------------------- Round and normalize stage------------------------------------------------------------------------------- roundnorm_stage: process (rnd, RoundingMode) variable rounded_value : std_logic_vector(53 downto 0); variable rounded_norm_value : std_logic_vector(52 downto 0); variable exp_norm : std_logic_vector(10 downto 0); variable exp : std_logic_vector(10 downto 0); variable fraction : std_logic_vector(51 downto 0); variable all_zero : std_logic_vector(51 downto 0); variable overflow : std_logic; variable inexact : std_logic; variable NaNs : std_logic; begin all_zero := (others => '0'); -- Perform rounding according to selected rounding mode case RoundingMode is when "00" => if rnd.frac(2) = '1' and rnd.frac(3 downto 0) /= "0000" then-- pragma translate_off if not is_x(rnd.frac(56 downto 3)) then-- pragma translate_on rounded_value := rnd.frac(56 downto 3) + 1;-- pragma translate_off end if;-- pragma translate_on else rounded_value := rnd.frac(56 downto 3); end if; when "01" => rounded_value := rnd.frac(56 downto 3); when "10" => if rnd.sign = '0' and rnd.frac(2) = '1' then-- pragma translate_off if not is_x(rnd.frac(56 downto 3)) then-- pragma translate_on rounded_value := rnd.frac(56 downto 3) + 1;-- pragma translate_off end if;-- pragma translate_on else rounded_value := rnd.frac(56 downto 3); end if; when "11" => if rnd.sign = '1' and rnd.frac(2) = '1' then-- pragma translate_off if not is_x(rnd.frac(56 downto 3)) then-- pragma translate_on rounded_value := rnd.frac(56 downto 3) + 1;-- pragma translate_off end if;-- pragma translate_on else rounded_value := rnd.frac(56 downto 3); end if; when others => null; end case; -- Normalize if needed i.e. if overflow bit set shift fraction one step -- left and inc exp. if (rnd.single = '1' and rounded_value(24) = '1') or rounded_value(36) = '1' then rounded_norm_value := rounded_value(53 downto 1);-- pragma translate_off if not is_x(rnd.exp) then-- pragma translate_on exp_norm := rnd.exp + 1;-- pragma translate_off end if;-- pragma translate_on else rounded_norm_value := rounded_value(52 downto 0); exp_norm := rnd.exp; end if; -- Check if overflow has occured if (exp_norm(7 downto 0) = "11111111") and ((rnd.single = '1') or (exp_norm(10 downto 8) = "111")) and (rnd.res_SNaN = '0') and (rnd.res_NaN = '0') then overflow := '1'; else overflow := '0'; end if; -- Check if result is inexact inexact := (rnd.frac(2) or rnd.frac(1) or rnd.frac(0)) and (not rnd.comp); -- Check if result is some sort of NaN NaNs := rnd.res_NaN or rnd.res_SNaN; -- Set fraction and exponent. if NaNs = '1' then fraction := rnd.res_NaN & "1" & all_zero(49 downto 0); exp := (others => '1'); elsif overflow = '1' or rnd.res_inf = '1' then fraction := (others => '0'); exp := (others => '1'); else fraction := rounded_norm_value(51 downto 0); exp := exp_norm; end if; -- Set exception bits. If operaration is some sort of compare then -- overflow, underflow and inexact interrupt can not occure. if rnd.comp = '1' then rnd_out.exc <= "0" & rnd.exc(4) & "0000"; else rnd_out.exc <= "0" & rnd.exc(4) & (overflow or rnd.exc(3)) & rnd.exc(2 downto 1) & inexact; end if; -- Put out result if rnd.single = '1' then rnd_out.frac <= fraction(22 downto 0) & "0" & zero(27 downto 0); else rnd_out.frac <= fraction; end if; rnd_out.exp <= exp; rnd_out.sign <= rnd.sign; rnd_out.cc <= rnd.cc; end process roundnorm_stage;--------------------------------------------------------------------------------- FPU busy signal generation process------------------------------------------------------------------------------- gen_busy: process (state, FpOp, FpLd) begin -- Default assignments FpBusy <= '0'; next_state <= state; result_ready <= '0'; -- Calculate nextstate and output case state is when start => if FpOp = '1' then next_state <= get_operand; end if; when get_operand => FpBusy <= '1'; if FpLd = '1' then next_state <= pre_norm; end if; when pre_norm => FpBusy <= '1'; next_state <= add_sub; when add_sub => FpBusy <= '1'; next_state <= post_norm; when post_norm => FpBusy <= '1'; next_state <= rnd_norm; when rnd_norm => result_ready <= '1'; if FpOp = '1' then next_state <= get_operand; else next_state <= hold_val; end if; when hold_val => if FpOp = '1' then next_state <= get_operand; end if; when others => null; end case; end process gen_busy; process (ss_clock, Reset) begin if Reset = '1' then state <= start; elsif ss_clock = '1' and ss_clock'event then state <= next_state; end if; end process;--------------------------------------------------------------------------------- Pipeline registers------------------------------------------------------------------------------- -- Gated ff holding opcode de_gated : process (ss_clock, FpOp) begin if ss_clock = '1' and ss_clock'event then if FpOp = '1' then de <= de_in; end if; end if; end process de_gated; -- Gated ff holding unpacked operands and control signals pren_gated : process (ss_clock, FpLd) begin if ss_clock = '1' and ss_clock'event then if FpLd = '1' then pren <= pren_in; end if; end if; end process pren_gated; -- Normal ff for the other pipeline stages pipe_regs: process (ss_clock) begin -- process pipe_regs if ss_clock = '1' and ss_clock'event then as <= as_in; posn <= posn_in; rnd <= rnd_in; end if; end process pipe_regs; -- Gated ff with asynchronous reset holding the FPU output values out_gated_reset: process (ss_clock, Reset, result_ready) begin -- process out_gated_reset if Reset = '1' then FracResult <= (others => '0'); ExpResult <= (others => '0'); SignResult <= '0'; Excep <= (others => '0'); ConditionCodes <= (others => '0'); elsif ss_clock = '1' and ss_clock'event then if result_ready = '1' then FracResult <= rnd_out.frac; ExpResult <= rnd_out.exp; SignResult <= rnd_out.sign; Excep <= rnd_out.exc; ConditionCodes <= rnd_out.cc; end if; end if; end process out_gated_reset; end rtl;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -