You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

VHDL单精度浮点加法器仿真出现边界检查错误求助

单精度浮点加法器VHDL仿真边界检查错误解决

执行仿真命令 ghdl -r fp_add_TB --vcd=add_fp_TB.vcd 时出现以下边界检查错误:

:error: bound check failure at fp_adder_32_bits_corretto.vhdl:51
in process .fp_add_tb(testbench).dut@fp_add(dataflow).P6
from: process work.fp_add(dataflow).P6 at fp_adder_32_bits_corretto.vhdl:51


原代码

主代码

library IEEE;
use IEEE.std_logic_1164.all; 
use IEEE.numeric_std.all;

ENTITY add_fp is
  port(A, B : IN std_logic_vector(31 downto 0);
       sum: OUT std_logic_vector(31 downto 0)
  );  
end entity add_fp;

ARCHITECTURE dataflow OF add_fp IS    
-- extraction to signals of exponent, mantissa, sign
-- single precision: exp = 8 bits, mantissa = 23 bits
  SIGNAL sign_A, sign_B, sign_sum: std_logic;
  SIGNAL frac_A, frac_B: std_logic_vector(22 downto 0);  
  signal exp_A, exp_B: std_logic_vector(7 downto 0);
  
-- sum and difference of the mantissa (fractional) part
-- (with an extra bit for rounding)
  SIGNAL frac_shifted_a, frac_shifted_b, frac_sum: std_logic_vector(23 downto 0); 

  
-- exp differences
  signal exp_diff, exp_fin: std_logic_vector(7 downto 0);

--carry out
signal carry_out: BIT; 
  
BEGIN
  -- input signals
  sign_A <= A(31);
  sign_B <= B(31);
  exp_A <= A(30 downto 23);
  exp_B <= B(30 downto 23);
  frac_A <= A(22 downto 0);
  frac_B <= B (22 downto 0);

  -- Shift in order to get same exponents
  frac_shifted_a <= (others => '0');
  frac_shifted_b <= (others => '0');
  frac_sum <= (others => '0');

  PROCESS(exp_A, exp_B, frac_A, frac_B)
  begin
    if exp_A < exp_B then
      exp_diff <= std_logic_vector(unsigned(exp_B) - unsigned(exp_A));
      frac_shifted_a <= std_logic_vector(unsigned(frac_A) srl to_integer(unsigned(exp_diff)));
      exp_fin<= exp_B;

    elsif exp_A > exp_B then
      exp_diff <= std_logic_vector(unsigned(exp_A) - unsigned(exp_B));
      frac_shifted_b <= std_logic_vector(unsigned(frac_B) srl to_integer(unsigned(exp_diff)));
      exp_fin <= exp_A;

    end if;
  end process;

  -- sum of the fractional parts
  process(frac_shifted_a, frac_shifted_b)
  begin
    frac_sum <=  std_logic_vector(unsigned(frac_shifted_a) +  unsigned(frac_shifted_b));
  end process;

  -- fractional part normalization (carry out bit)
  PROCESS(exp_fin, frac_sum)
  BEGIN
    carry_out <= '0';
    IF frac_sum(23) = '1' THEN
     frac_sum <= std_logic_vector(unsigned(frac_sum) sll 1);
      exp_fin <= std_logic_vector(unsigned(exp_fin) + 1);
     carry_out <= '1';
   END IF;
  END PROCESS;

  -- Fractional part rounding 
  PROCESS(exp_fin, frac_sum)
  BEGIN
    IF frac_sum(0) = '1' THEN
   frac_sum <= std_logic_vector(unsigned(frac_sum) + 2);   -- + 10
    END IF;
  END PROCESS;

  -- sign calculation
--here probably I have to consider if A > B or viceversa, but this is not the point of my question
    sign_sum <= sign_A xor sign_B;
 
-- renormalization after the rounding
process(frac_sum, exp_fin)
begin
if carry_out = '0' and frac_sum(23) = '1' then
 frac_sum <= std_logic_vector(unsigned(frac_sum) sll 1);
      exp_fin <= std_logic_vector(unsigned(exp_fin) + 1);
end if;
end process;

  -- final result
  sum <= sign_sum & exp_fin & frac_sum(23 downto 1);
END architecture dataflow;

测试平台代码

library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity fp_add_TB is
end entity fp_add_TB;

architecture testbench of fp_add_TB is
  -- Component declaration
  component fp_add is
    port (
      A, B : in std_logic_vector(31 downto 0);
      sum : out std_logic_vector(31 downto 0)
    );
  end component fp_add;

  -- Signals
  signal A, B, sum : std_logic_vector(31 downto 0);

begin
  -- Instantiate the DUT (Device Under Test)
  DUT : fp_add
    port map (
      A => A,
      B => B,
      sum => sum
    );

  -- Stimulus process
  process
  begin
    -- Test vector 1
    A <= "01000000010000000000000000000000"; -- 3.0
    B <= "01000000001000000000000000000000"; -- 1.5
    wait for 10 ns;

    -- Test vector 2
    A <= "11000000010000000000000000000000"; -- -3.0
    B <= "01000000001000000000000000000000"; -- 1.5
    wait for 10 ns;

    -- Test vector 3
    A <= "00111111100000000000000000000000"; -- 0.5
    B <= "00000000000000000000000000000000"; -- 0.0
    wait for 10 ns;

    -- Add more test vectors as needed
    
    -- Stop simulation
    wait;
  end process;

end architecture testbench;

错误原因

  1. 多进程冲突驱动:frac_sum和exp_fin被4个独立进程同时赋值,违反VHDL信号驱动规则,导致信号值不确定,触发边界检查错误。
  2. 分支逻辑缺失:当exp_A = exp_B时,第一个进程未对exp_fin、frac_shifted_a、frac_shifted_b赋值,这些信号保持初始全0,后续计算异常。
  3. 类型不匹配:carry_out用BIT类型,其他信号为std_logic,隐性转换可能引发错误。
  4. 移位逻辑缺陷:多次对frac_sum执行左移操作,未考虑信号长度限制,容易触发位溢出。

修复后的主代码

library IEEE;
use IEEE.std_logic_1164.all; 
use IEEE.numeric_std.all;

ENTITY add_fp is
  port(A, B : IN std_logic_vector(31 downto 0);
       sum: OUT std_logic_vector(31 downto 0)
  );  
end entity add_fp;

ARCHITECTURE dataflow OF add_fp IS    
  SIGNAL sign_A, sign_B, sign_sum: std_logic;
  SIGNAL frac_A, frac_B: std_logic_vector(22 downto 0);  
  signal exp_A, exp_B: std_logic_vector(7 downto 0);
  
  SIGNAL frac_shifted_a, frac_shifted_b: std_logic_vector(23 downto 0); 
  SIGNAL frac_sum_final: std_logic_vector(23 downto 0);
  signal exp_diff, exp_fin: std_logic_vector(7 downto 0);
  signal carry_out: std_logic; 
  
BEGIN
  -- 拆分输入信号
  sign_A <= A(31);
  sign_B <= B(31);
  exp_A <= A(30 downto 23);
  exp_B <= B(30 downto 23);
  frac_A <= A(22 downto 0);
  frac_B <= B (22 downto 0);

  -- 对齐指数并移位尾数
  PROCESS(exp_A, exp_B, frac_A, frac_B)
  begin
    -- 初始化移位后的尾数(补上单精度隐含的1)
    frac_shifted_a <= '1' & frac_A;
    frac_shifted_b <= '1' & frac_B;
    exp_fin <= exp_A;
    
    if exp_A < exp_B then
      exp_diff <= std_logic_vector(unsigned(exp_B) - unsigned(exp_A));
      frac_shifted_a <= std_logic_vector(unsigned(frac_shifted_a) srl to_integer(unsigned(exp_diff)));
      exp_fin <= exp_B;
    elsif exp_A > exp_B then
      exp_diff <= std_logic_vector(unsigned(exp_A) - unsigned(exp_B));
      frac_shifted_b <= std_logic_vector(unsigned(frac_shifted_b) srl to_integer(unsigned(exp_diff)));
      exp_fin <= exp_A;
    end if;
  end process;

  -- 尾数求和、归一化、舍入逻辑合并为一个进程
  PROCESS(frac_shifted_a, frac_shifted_b, exp_fin)
    variable temp_sum : unsigned(24 downto 0); -- 用变量避免多驱动冲突
    variable temp_exp : unsigned(7 downto 0);
  BEGIN
    temp_sum := unsigned('0' & frac_shifted_a) + unsigned('0' & frac_shifted_b);
    temp_exp := unsigned(exp_fin);
    carry_out := '0';
    
    -- 第一次归一化
    if temp_sum(24) = '1' then
      temp_sum := temp_sum sll 1;
      temp_exp := temp_exp + 1;
      carry_out := '1';
    end if;
    
    -- 舍入处理
    if temp_sum(0) = '1' then
      temp_sum := temp_sum + 2;
      -- 舍入后二次归一化
      if temp_sum(24) = '1' then
        temp_sum := temp_sum sll 1;
        temp_exp := temp_exp + 1;
      end if;
    end if;
    
    frac_sum_final <= std_logic_vector(temp_sum(23 downto 0));
    exp_fin <= std_logic_vector(temp_exp);
  END PROCESS;

  -- 符号计算(仅示例,实际需根据绝对值大小调整)
  sign_sum <= sign_A xor sign_B;

  -- 组装最终结果
  sum <= sign_sum & exp_fin & frac_sum_final(23 downto 1);
END architecture dataflow;

修复说明

  1. 合并驱动逻辑:将尾数求和、归一化、舍入逻辑合并到一个进程中,使用变量临时存储中间值,彻底避免多进程驱动信号冲突。
  2. 补充分支逻辑:处理exp_A = exp_B的情况,初始化移位后的尾数为1&frac,符合单精度浮点数隐含1的格式规则。
  3. 统一类型:将carry_out改为std_logic类型,消除类型不匹配引发的隐性转换错误。
  4. 优化移位逻辑:使用宽一位的变量存储求和结果,避免移位溢出,同时处理舍入后的二次归一化需求。

内容的提问来源于stack exchange,提问作者Test Prova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 15:57:06