长向量 addition/subtraction 中未使用的位

Unused bits in addition/subtraction of long vectors

我尝试用 VHDL 编写 ALU 模块来计算复数。我尽量保持一切简单,不使用任何花哨的算法,如 Booth 或 Vedic 进行乘法运算。所以基本上,我使用简单的“+”、“-”、“*”运算符来划分“记录”数组:

-- a complex number
    type ComplexNr is record
        Re : signed(3 downto 0);
        Im : signed(3 downto 0);
    end record;

对于 Addition/Subtraction 和乘法的输出结果,我使用相同长度的向量,因此输入向量的大小加倍,即如果 Input_1 和 Input_2 是 4 位,我的结果向量长 8 位。现在,如果我做乘法,一切正常,但是当我做 addition/subtraction 时,未使用的位在 iSim 中显示为“U”。

乘法和加法的代码相当简单:

-- complex multiplication
function c_mult(a, b : ComplexNr) return Complex_res is
    variable RetVal : Complex_res;
begin
    RetVal.Re := a.Re * b.Re - a.Im * b.Im;
    RetVal.Im := a.Re * b.Im + a.Im * b.Re;
    return (RetVal);

end function c_mult;

-- complex addition
function c_add(a, b : ComplexNr) return Complex_res is
    variable RetVal : Complex_res;
begin
    RetVal.Re := a.Re + b.Re;
    RetVal.Im := a.Im + b.Im;
    return (RetVal);

end function c_add;

假设我将 0001 与 0010 相加,我得到“0011UUUU”作为加法。你通常如何解决这个问题?我必须明确地用 0 初始化未使用的位吗?

下面是顶层设计,调用了addition/subtraction和乘法函数。请注意,我将结果向量初始化为零一次。 - 还不够吗?如果需要我会提供测试台,但我只是分配 X 和 Y 值,仅此而已。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

library work;
use work.complex_numbers.all;

entity cmplx_arithm is
    Port(
        -- Inputs:
        CLK       : in  STD_LOGIC;
        X         : in  STD_LOGIC_VECTOR(3 downto 0);   -- real X
        X_i       : in  STD_LOGIC_VECTOR(3 downto 0);   -- imag X
        Y         : in  STD_LOGIC_VECTOR(3 downto 0);   -- real Y
        Y_i       : in  STD_LOGIC_VECTOR(3 downto 0);   -- iamg Y

        -- Outputs:
        mux_res_r : out STD_LOGIC_VECTOR(7 downto 0);   -- mux result
        mux_res_i : out STD_LOGIC_VECTOR(7 downto 0);
        add_res_r : out STD_LOGIC_VECTOR(7 downto 0);   -- add result
        add_res_i : out STD_LOGIC_VECTOR(7 downto 0);
        sub_res_r : out STD_LOGIC_VECTOR(7 downto 0);   -- sub result
        sub_res_i : out STD_LOGIC_VECTOR(7 downto 0)
    );
end cmplx_arithm;

architecture Behavioral of cmplx_arithm is

    -- set the result values to zero
     constant init_to_zero : Complex_res := (
                               Re => (others =>'0'),
                               Im => (others=> '0')
                               );


    signal A : ComplexNr;
    signal B : ComplexNr;

    signal resultMux : Complex_res := init_to_zero;
    signal resultAdd : Complex_res := init_to_zero;
    signal resultSub : Complex_res := init_to_zero;

begin
    A.Re <= signed(X);
    A.Im <= signed(X_i);
    B.Re <= signed(Y);
    B.Im <= signed(Y_i);

    -- multiplication
    process(clk)
    begin
        if (rising_edge(clk)) then
            resultMux <= c_mult(A, B);
        end if;
    end process;

    -- addition
    process(clk)
    begin
        if (rising_edge(clk)) then
            resultAdd <= c_add(A, B);
        end if;
    end process;

    -- subtraction
    process(clk)
    begin
        if (rising_edge(clk)) then
            resultSub <= c_sub(A, B);
        end if;
    end process;

    mux_res_r  <= std_logic_vector(resultMux.Re);
    mux_res_i  <= std_logic_vector(resultMux.Im);
    add_res_r  <= std_logic_vector(resultAdd.Re);
    add_res_i  <= std_logic_vector(resultAdd.Im);
    sub_res_r  <= std_logic_vector(resultSub.Re);
    sub_res_i  <= std_logic_vector(resultSub.Im);

end Behavioral;

你的c_add和(大概)c_sub没有写对

function c_add(a, b : ComplexNr) return Complex_res is
    variable RetVal : Complex_res;
begin
    RetVal.Re := a.Re + b.Re;
    RetVal.Im := a.Im + b.Im;
    return (RetVal);

end function c_add;

您所涉及的 Complex_res 的记录元素的长度是两倍长,但加法(和减法)的长度将与任一操作数的最长长度相匹配(包 numeric_std,签名为“+”)。

您可以调整总和(和差异,c_add 显示):

    resize(RetVal.Re := a.Re + b.Re,8);
    resize(RetVal.Im := a.Im + b.Im,8);

请注意,如果 iSIM 完全符合 VHDL 标准,您将遇到运行时边界检查错误(除非禁用

ISim User Guide(UG660,v14.3)第3章编译与仿真,Table3-7:fuse、vhpcomp和vlogcomp命令选项的--rangecheck选项条目告诉我们"ISim always checks an index into an array for being within the allowed range." 没有提到我发现有检查目标中的每个元素的表达式中是否有一个元素。

参见 IEEE Std 106-2008,10.6.2 简单变量赋值,10.6.2.1 概述,第 5 段:

For the execution of a variable assignment whose target is a variable name, the variable name and the expression are first evaluated. A check is then made that the value of the expression belongs to the subtype of the variable, except in the case of a variable that is of a composite type (in which case the assignment involves a subtype conversion). ...

和10.6.2.2复合变量赋值:

If the target of an assignment statement is a name denoting a composite variable (including a slice), the value assigned to the target is implicitly converted to the subtype of the composite variable; the result of this subtype conversion becomes the new value of the composite variable.

This means that the new value of each element of the composite variable is specified by the matching element (see 9.2.3) in the corresponding composite value obtained by evaluation of the expression. The subtype conversion checks that for each element of the composite variable there is a matching element in the composite value, and vice versa. An error occurs if this check fails.

填空创建 Minimal, Complete, and Verifiable example:

library ieee;
use ieee.numeric_std.all;

package complex_numbers is
    type ComplexNr is record
        Re: signed (3 downto 0);
        Im: signed (3 downto 0);
    end record;

    type Complex_res is record
        Re: signed (7 downto 0);
        Im: signed (7 downto 0);
    end record;

    function c_mult(a, b:  ComplexNr) return Complex_res;
    function c_add(a, b:  ComplexNr) return Complex_res;
    function c_sub(a, b:  ComplexNr) return Complex_res;
end package;

package body complex_numbers is
    -- complex multiplication
    function c_mult(a, b:  ComplexNr) return Complex_res is
        variable RetVal:  Complex_res;
    begin
        RetVal.Re := a.Re * b.Re - a.Im * b.Im;
        RetVal.Im := a.Re * b.Im + a.Im * b.Re;
        return (RetVal);
    end function c_mult;

    -- complex addition
    function c_add(a, b:  ComplexNr) return Complex_res is
        variable RetVal:  Complex_res;
    begin
        RetVal.Re := resize(a.Re + b.Re,8);
        RetVal.Im := resize(a.Im + b.Im,8);
        return (RetVal);
    end function c_add;

    -- complex subtraction
    function c_sub(a, b:  ComplexNr) return Complex_res is
        variable RetVal:  Complex_res;
    begin
        RetVal.Re := resize(a.Re - b.Re,8);
        RetVal.Im := resize(a.Im - b.Im,8);
        return (RetVal);
    end function c_sub;   
end package body;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

library work;
use work.complex_numbers.all;

entity cmplx_arithm is
    port (
        -- Inputs:
        CLK:        in  std_logic;
        X:          in  std_logic_vector(3 downto 0);   -- real X
        X_i:        in  std_logic_vector(3 downto 0);   -- imag X
        Y:          in  std_logic_vector(3 downto 0);   -- real Y
        Y_i:        in  std_logic_vector(3 downto 0);   -- iamg Y

        -- Outputs:
        mult_res_r:  out std_logic_vector(7 downto 0);   -- mult result
        mult_res_i:  out std_logic_vector(7 downto 0);
        add_res_r:   out std_logic_vector(7 downto 0);   -- add result
        add_res_i:   out std_logic_vector(7 downto 0);
        sub_res_r:   out std_logic_vector(7 downto 0);   -- sub result
        sub_res_i:   out std_logic_vector(7 downto 0)
    );
end entity cmplx_arithm;

architecture Behavioral of cmplx_arithm is

    -- set the result values to zero
     constant init_to_zero:  Complex_res := (
                               Re => (others =>'0'),
                               Im => (others=> '0')
                               );

    signal A:  ComplexNr;
    signal B:  ComplexNr;

    signal resultmult:  Complex_res := init_to_zero;
    signal resultAdd:  Complex_res := init_to_zero;
    signal resultSub:  Complex_res := init_to_zero;

begin
    A.Re <= signed(X);
    A.Im <= signed(X_i);
    B.Re <= signed(Y);
    B.Im <= signed(Y_i);

    -- multiplication
    process(clk)
    begin
        if rising_edge(clk) then
            resultmult <= c_mult(A, B);
        end if;
    end process;

    -- addition
    process(clk)
    begin
        if rising_edge(clk) then
            resultAdd <= c_add(A, B);
        end if;
    end process;

    -- subtraction
    process(clk)
    begin
        if rising_edge(clk) then
            resultSub <= c_sub(A, B);
        end if;
    end process;

    mult_res_r  <= std_logic_vector(resultmult.Re);
    mult_res_i  <= std_logic_vector(resultmult.Im);
    add_res_r   <= std_logic_vector(resultAdd.Re);
    add_res_i   <= std_logic_vector(resultAdd.Im);
    sub_res_r   <= std_logic_vector(resultSub.Re);
    sub_res_i   <= std_logic_vector(resultSub.Im);

end architecture Behavioral;

library ieee;
use ieee.std_logic_1164.all;

entity cmplx_arithm_tb is
end entity;

architecture foo of cmplx_arithm_tb is
    signal clk:        std_logic := '0';
    signal x:          std_logic_vector(3 downto 0);
    signal x_i:        std_logic_vector(3 downto 0);
    signal y:          std_logic_vector(3 downto 0);
    signal y_i:        std_logic_vector(3 downto 0);

    signal mult_res_r:  std_logic_vector(7 downto 0);
    signal mult_res_i:  std_logic_vector(7 downto 0);
    signal add_res_r:   std_logic_vector(7 downto 0);
    signal add_res_i:   std_logic_vector(7 downto 0);
    signal sub_res_r:   std_logic_vector(7 downto 0);
    signal sub_res_i:   std_logic_vector(7 downto 0);
begin
DUT:
    entity work.cmplx_arithm
        port map (
            CLK => clk,
            X => x,
            X_i => x_i,
            Y => y,
            Y_i => y_i,
            mult_res_r => mult_res_r,
            mult_res_i => mult_res_i,
            add_res_r => add_res_r,
            add_res_i => add_res_i,
            sub_res_r => sub_res_r,
            sub_res_i => sub_res_i
        );

CLOCK:
    process
    begin
        wait for 5 ns;
        clk <= not clk;
        if now > 40 ns then
            wait;
        end if;
    end process;
STIMULUS:
    process
    begin
        wait for 10 ns;
        x <= "0100";
        x_i <= "0010";
        y <= "0010";
        y_i <= "0001";
        wait;
    end process;
end architecture;

给出:

(这是在 OS X 上使用 GTKWave 在 Mac 上托管的 ghdl-0.33 完成的)