📄 fpu_lth.vhd
字号:
type fpu_result_type is record -- roundnorm <-> out
frac : std_logic_vector(51 downto 0);
exp : std_logic_vector(10 downto 0);
sign : std_logic;
cc : std_logic_vector(1 downto 0);
exc : std_logic_vector(5 downto 0);
end record;
-------------------------------------------------------------------------------
-- Declaration of input and output signal from the different pipeline
-- registers.
-------------------------------------------------------------------------------
signal de, de_in : op_decode_stage_type;
signal pren, pren_in : prenorm_stage_type;
signal as, as_in : addsub_stage_type;
signal posn, posn_in : postnorm_stage_type;
signal rnd, rnd_in : roundnorm_stage_type;
signal rnd_out : fpu_result_type;
-------------------------------------------------------------------------------
-- Type and signals used by generate busy process. In the fututure this process
-- might be integrated into the pipeline but for now a seperat process is used.
-------------------------------------------------------------------------------
type fpu_state is (start, get_operand, pre_norm, add_sub, post_norm,
rnd_norm, hold_val);
signal state, next_state : fpu_state;
signal result_ready : std_logic;
begin -- rtl
de_in.opcode <= FpInst;
-------------------------------------------------------------------------------
-- Opcode decode and unpacking stage
-------------------------------------------------------------------------------
decode_stage: process (de, fprf_dout1, fprf_dout2)
variable single : std_logic;
variable exp1 : std_logic_vector(10 downto 0);
variable exp2 : std_logic_vector(10 downto 0);
variable frac1 : std_logic_vector(51 downto 0);
variable frac2 : std_logic_vector(51 downto 0);
variable frac1_zero : std_logic;
variable frac2_zero : std_logic;
variable exp1_max : std_logic;
variable exp2_max : std_logic;
variable exp1_min : std_logic;
variable exp2_min : std_logic;
begin
-- Get sign bit for op1
pren_in.sign1 <= fprf_dout1(63);
-- Unpack exponent and fraction depending on the precision mode. Note that
-- if single precision is used som bit filling must be done for the
-- exponent and fraction since double precision is used internally.
if de.opcode(1 downto 0) = "01" then -- If single precision
single := '1';
exp1 := "000" & fprf_dout1(62 downto 55);
frac1 := "0" & zero(27 downto 0) & fprf_dout1(54 downto 32);
exp2 := "000" & fprf_dout2(62 downto 55);
frac2 := "0" & zero(27 downto 0) & fprf_dout2(54 downto 32);
else
-- If double precision
single := '0';
exp1 := fprf_dout1(62 downto 52);
frac1 := fprf_dout1(51 downto 0);
exp2 := fprf_dout2(62 downto 52);
frac2 := fprf_dout2(51 downto 0);
end if;
-- Check if fracions zero
if frac1 = zero(51 downto 0) then
frac1_zero := '1';
else
frac1_zero := '0';
end if;
if frac2 = zero(51 downto 0) then
frac2_zero := '1';
else
frac2_zero := '0';
end if;
-- Check if exp is max or min
if (exp1(7 downto 0) = "11111111") and
((single = '1') or (exp1(10 downto 8) = "111")) then
exp1_max := '1';
exp1_min := '0';
elsif exp1 = "00000000000" then
exp1_max := '0';
exp1_min := '1';
else
exp1_max := '0';
exp1_min := '0';
end if;
if (exp2(7 downto 0) = "11111111") and
((single = '1') or (exp2(10 downto 8) = "111")) then
exp2_max := '1';
exp2_min := '0';
elsif exp2 = "00000000000" then
exp2_max := '0';
exp2_min := '1';
else
exp2_max := '0';
exp2_min := '0';
end if;
-- Detect special numbers
pren_in.op1_denorm <= exp1_min;
pren_in.op2_denorm <= exp2_min;
pren_in.op1_inf <= exp1_max and frac1_zero;
pren_in.op2_inf <= exp2_max and frac2_zero;
pren_in.op1_SNaN <= exp1_max and (not frac1_zero) and
not (frac1(51) or (frac1(22) and single));
pren_in.op2_SNaN <= exp2_max and (not frac2_zero) and
not (frac2(51) or (frac2(22) and single));
pren_in.op1_NaN <= exp1_max and (not frac1_zero) and
(frac1(51) or (frac1(22) and single));
pren_in.op2_NaN <= exp2_max and (not frac2_zero) and
(frac2(51) or (frac2(22) and single));
-- Decode instruction. If operation is sub or cmp then negate op2 sign.
-- Unimplemented opcodes will result in addition.
case de.opcode(8 downto 0) is
when FSUBS | FSUBD => pren_in.sign2 <= not fprf_dout2(63);
pren_in.comp <= '0';
pren_in.gen_ex <= '0';
when FCMPS | FCMPD => pren_in.sign2 <= not fprf_dout2(63);
pren_in.comp <= '1';
pren_in.gen_ex <= '0';
when FCMPES | FCMPED => pren_in.sign2 <= not fprf_dout2(63);
pren_in.comp <= '1';
pren_in.gen_ex <= '1';
when others => pren_in.sign2 <= fprf_dout2(63);
pren_in.comp <= '0';
pren_in.gen_ex <= '0';
end case;
pren_in.single <= single;
pren_in.frac1 <= frac1;
pren_in.exp1 <= exp1;
pren_in.frac2 <= frac2;
pren_in.exp2 <= exp2;
end process decode_stage;
-------------------------------------------------------------------------------
-- Prenorm stage
-------------------------------------------------------------------------------
prenorm_stage: process (pren)
variable switch_ops : std_logic;
variable sign_diff : std_logic_vector(11 downto 0);
variable abs_diff : std_logic_vector(11 downto 0);
variable all_zero : std_logic_vector(11 downto 0);
variable shift_amount : std_logic_vector(5 downto 0);
variable adj_op : std_logic_vector(54 downto 0);
variable shifted_op : std_logic_vector(54 downto 0);
variable sticky_bit : std_logic;
begin
all_zero := (others => '0');
-- Calculate differens
-- pragma translate_off
if not is_x(pren.exp1 & pren.exp2) then
-- pragma translate_on
sign_diff := ("0" & pren.exp1) - ("0" & pren.exp2);
-- pragma translate_off
end if;
-- pragma translate_on
switch_ops := sign_diff(11); -- Switch needed
-- If negative get absolute value
if sign_diff(11) = '1' then
-- pragma translate_off
if not is_x(all_zero & sign_diff) then
-- pragma translate_on
abs_diff := all_zero - sign_diff;
-- pragma translate_off
end if;
-- pragma translate_on
else
abs_diff := sign_diff(11 downto 0);
end if;
-- Not needed to shift more then the length of the fraction
-- pragma translate_off
if not is_x(abs_diff) then
-- pragma translate_on
if abs_diff > 52 then
shift_amount := "110100";
else
shift_amount := abs_diff(5 downto 0);
end if;
-- pragma translate_off
end if;
-- pragma translate_on
-- Do switch of operands if needed. Then retrieve the hidden bit for the
-- larger operand and append overflow, guard, round and sticky bit. For the
-- smaller operand retrive hidden bit and append guard and round bit.
if switch_ops = '1' then
if (pren.single='1') then -- single precision
as_in.a <=zero(29 downto 0) & (not pren.op2_denorm) & pren.frac2(22 downto 0) & "000";
adj_op := zero(28 downto 0) & (not pren.op1_denorm) & pren.frac1(22 downto 0) & "00";
else
as_in.a <= "0" & (not pren.op2_denorm) & pren.frac2 & "000";
adj_op := (not pren.op1_denorm) & pren.frac1 & "00";
end if;
as_in.exp <= pren.exp2;
as_in.sign_a <= pren.sign2;
as_in.sign_b <= pren.sign1;
else
if (pren.single='1') then -- single precision
as_in.a <=zero(29 downto 0) & (not pren.op1_denorm) & pren.frac1(22 downto 0) & "000";
adj_op := zero(28 downto 0) & (not pren.op2_denorm) & pren.frac2(22 downto 0) & "00";
else
as_in.a <= "0" & (not pren.op1_denorm) & pren.frac1 & "000";
adj_op := (not pren.op2_denorm) & pren.frac2 & "00";
end if;
as_in.exp <= pren.exp1;
as_in.sign_a <= pren.sign1;
as_in.sign_b <= pren.sign2;
end if;
-- Shift smaller operand right and get sticky bit.
right_shifter_sticky(adj_op,shift_amount,shifted_op,sticky_bit);
-- Add overflow and sticky bit for shifted smaller operand.
as_in.b <= "0" & shifted_op & sticky_bit;
as_in.swaped <= switch_ops;
as_in.op1_inf <= pren.op1_inf;
as_in.op2_inf <= pren.op2_inf;
as_in.op1_NaN <= pren.op1_NaN;
as_in.op2_NaN <= pren.op2_Nan;
as_in.op1_SNaN <= pren.op1_SNaN;
as_in.op2_SNaN <= pren.op2_SNaN;
as_in.single <= pren.single;
as_in.comp <= pren_in.comp;
as_in.gen_ex <= pren_in.gen_ex;
end process prenorm_stage;
-------------------------------------------------------------------------------
-- Add/Sub stage
-------------------------------------------------------------------------------
addsub_stage: process (as)
variable signs : std_logic_vector(1 downto 0);
variable result : std_logic_vector(56 downto 0);
variable temp : std_logic_vector(56 downto 0);
variable neg_value : std_logic;
variable all_zero : std_logic_vector(56 downto 0);
variable unordered : std_logic;
variable zero_fraction : std_logic;
variable cc_bit0 : std_logic;
variable cc_bit1 : std_logic;
variable SNaN : std_logic;
variable NaN : std_logic;
variable inf : std_logic;
begin
all_zero := (others => '0');
signs := as.sign_a & as.sign_b;
-- Perform operation based on the sign of the operands
case signs is
when "00" =>
-- pragma translate_off
if not is_x(as.a & as.b) then
-- pragma translate_on
result := as.a + as.b;
-- pragma translate_off
end if;
-- pragma translate_on
posn_in.sign <= '0';
neg_value := '0';
when "01" =>
-- pragma translate_off
if not is_x(as.a & as.b) then
-- pragma translate_on
result := as.a - as.b;
-- pragma translate_off
end if;
-- pragma translate_on
posn_in.sign <= result(56);
neg_value := result(56);
when "10" =>
-- pragma translate_off
if not is_x(as.a & as.b) then
-- pragma translate_on
result := as.a - as.b;
-- pragma translate_off
end if;
-- pragma translate_on
posn_in.sign <= not result(56);
neg_value := result(56);
when "11" =>
-- pragma translate_off
if not is_x(as.a & as.b) then
-- pragma translate_on
result := as.a + as.b;
-- pragma translate_off
end if;
-- pragma translate_on
posn_in.sign <= '1';
neg_value := '0';
when others => null;
end case;
-- If result is negative set fraction = -result else set fraction = result
-- pragma translate_off
if not is_x(all_zero & result) then
-- pragma translate_on
temp := all_zero - result;
-- pragma translate_off
end if;
-- pragma translate_on
if neg_value = '1' then
posn_in.frac <= temp(56 downto 0);
else
posn_in.frac <= result(56 downto 0);
end if;
-- Check if result is zero
if result = all_zero then
zero_fraction := '1';
posn_in.exp <= "00000000000";
else
zero_fraction := '0';
posn_in.exp <= as.exp;
end if;
-- Check if unordered operands i.e. any operand is some sort of NaN
unordered := as.op1_NaN or as.op2_NaN or as.op1_SNaN or as.op2_SNaN;
-- Check if result should be a SNaN.
SNaN := as.op1_SNaN or as.op2_SNaN or (unordered and as.gen_ex);
-- Check if result should be a NaN i.e. unordered opearands that don't
-- result in a SNaN or two inf values with different signs.
NaN := (unordered and (not SNaN)) or
(as.op1_inf and as.op2_inf and (signs(1) xor signs(0)));
-- Check if result should be inf.
inf := (as.op1_inf or as.op2_inf) and (not NaN) and (not SNaN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -