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