📄 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 + -