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;
错误原因
- 多进程冲突驱动:
frac_sum和exp_fin被4个独立进程同时赋值,违反VHDL信号驱动规则,导致信号值不确定,触发边界检查错误。 - 分支逻辑缺失:当
exp_A = exp_B时,第一个进程未对exp_fin、frac_shifted_a、frac_shifted_b赋值,这些信号保持初始全0,后续计算异常。 - 类型不匹配:
carry_out用BIT类型,其他信号为std_logic,隐性转换可能引发错误。 - 移位逻辑缺陷:多次对
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;
修复说明
- 合并驱动逻辑:将尾数求和、归一化、舍入逻辑合并到一个进程中,使用变量临时存储中间值,彻底避免多进程驱动信号冲突。
- 补充分支逻辑:处理
exp_A = exp_B的情况,初始化移位后的尾数为1&frac,符合单精度浮点数隐含1的格式规则。 - 统一类型:将
carry_out改为std_logic类型,消除类型不匹配引发的隐性转换错误。 - 优化移位逻辑:使用宽一位的变量存储求和结果,避免移位溢出,同时处理舍入后的二次归一化需求。
内容的提问来源于stack exchange,提问作者Test Prova
相关产品推荐
相关产品推荐

