⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 fpu_lth.vhd

📁 sparc org, vhdl rtl code
💻 VHD
📖 第 1 页 / 共 3 页
字号:
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 + -