我尝试用VHDL编写ALU模块来计算复数。我试图保持一切简单,不要使用任何花哨的算法,如Booth或Vedic进行乘法运算。基本上,我使用简单的“+”,“ - ”,“*”运算符分为“记录”数组:
-- a complex number
type ComplexNr is record
Re : signed(3 downto 0);
Im : signed(3 downto 0);
end record;
对于加法/减法和乘法的输出结果,我使用相同长度的向量,因此输入向量的双倍大小,即如果Input_1和Input_2是4位,我的结果向量是8位长。现在,如果我进行乘法运算,一切正常,但是当我进行加法/减法时,未使用的位在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;
所以假设我用0010添加0001,我得到“0011UUUU”添加。你通常如何解决这个问题?我是否必须使用0显式初始化未使用的位?
下面是顶部设计,它调用加法/减法和乘法函数。请注意,我将结果向量初始化为零一次。 - 这还不够吗?如果需要,我将提供测试台,但我只分配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;
答案 0 :(得分:1)
您的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,signed&#34; +&#34; )。
您可以调整总和(和差异,显示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章编译和仿真,表3-7:fuse,vhpcomp和vlogcomp命令选项--rangecheck选项的条目告诉我们&#34; ISim总是将索引检查到数组中是否在允许的范围内。&#34;没有提到我可以发现有一个元素在表达式中为目标中的每个元素。
参见IEEE Std 106-2008,10.6.2简单变量赋值,10.6.2.1概述,第5段:
为了执行目标是变量名的变量赋值,首先计算变量名和表达式。然后检查表达式的值是否属于变量的子类型,除非是具有复合类型的变量(在这种情况下,赋值涉及子类型转换)。 ...
和10.6.2.2复合变量赋值:
如果赋值语句的目标是表示复合变量(包括切片)的名称,则分配给目标的值将隐式转换为复合变量的子类型;此子类型转换的结果将成为复合变量的新值。
这意味着复合变量的每个元素的新值由匹配元素(见9.2.3)在通过表达式求值获得的相应复合值中指定。子类型转换检查复合变量的每个元素在复合值中是否存在匹配元素,反之亦然。如果此检查失败,则会发生错误。
填写空白以创建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;
给出:
(这是通过在带有GTKWave的Mac上的OS X上托管的ghdl-0.33完成的)