在 VHDL 中无法将无符号组件实现到 ALU 的条件

Trouble implementing unsigned component to conditions of ALU in VHDL

我必须创建一个 ALU,它具有 add、add unsigned、sub、sub unsigned 和、or、xor、nor、slt 和 slt unsigned 的条件。我很难实现包含未签名条件的设计。我在代码中指出了发生错误的地方。此外,ALU 的每个其他方面都工作正常,只有未签名的部分我需要帮助。我正在研究 unsigned 和 std_logic 但我无法找到与我类似的问题。

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
use ieee.NUMERIC_STD.all;

entity ALU is
Port (A, B     : in  STD_LOGIC_VECTOR (31 downto 0);
      ALUCntl  : in  STD_LOGIC_VECTOR (3 downto 0);
      Carryin  : in  STD_LOGIC;
      ALUOut   : out STD_LOGIC_VECTOR (31 downto 0);
      Zero     : out STD_LOGIC;
      Carryout : out STD_LOGIC;
      Overflow : out STD_LOGIC);
end ALU; 


architecture Behavioral of ALU is
signal ALU_Result, slt, sltu : std_logic_vector (31 downto 0);
signal add_result,sub_result,a32,b32: std_logic_vector(32 downto 0);
-- create separate a and b for unsigned 
signal add_u,sub_u,a32u,b32u: unsigned(32 downto 0);
signal c32: std_logic_vector(32 downto 0):=(others=>'0');
signal add_ov,sub_ov:std_logic;

begin
with ALUCntl select
ALU_Result <=add_result(31 downto 0) when "0010", -- add
            sub_result(31 downto 0) when "0110", -- sub
            slt     when "0111", -- set less than
            std_logic_vector(add_u(31 downto 0)) when "0100", -- add unsigned 
            std_logic_vector(sub_u(31 downto 0)) when "0101", -- sub unsigned
            sltu    when "1000", -- set less than unsigned
            A AND B when "0000",
            A OR  B when "0001",
            A XOR B when "0011",
            A NOR B when "1100",
            A when others;---condition for all other alu control signals
ALUOut  <= ALU_Result; 
----Set less than-----------------------------------
process(a32,b32)
begin
if (a32 < b32) then 
    slt <= x"00000001";
else
    slt <= x"00000000";
end if;
end process;
process(a32u,b32u)
begin
if (a32u < b32u) then 
    sltu <= x"00000001";
else
    sltu <= x"00000000";
end if;
end process;
----Addition Operation and carry out generation-----    
a32   <='0'& A;
b32   <='0'& B;
c32(0)<=Carryin;
add_result<=std_logic_vector(signed(a32) + signed(b32) + signed(c32));
sub_result<=std_logic_vector(signed(a32) - signed(b32));

a32u   <=unsigned('0'& A);
b32u   <=unsigned('0'& B);
add_u<=a32u + b32u + unsigned(c32);
sub_u<=a32u - b32u;

---Zero flag-----------------------------   
Zero <= '1' when ALU_Result =x"00000000" else '0';

---Overflow flag---------------------------------------
add_ov<= (A(31)and B(31)       and (not alu_result(31))) or ((not A(31))and (not B(31)) and alu_result(31));
sub_ov<= (A(31)and (not B(31)) and (not alu_result(31))) or ((not A(31))and B(31)       and alu_result(31)); 
with ALUCntl select
  Overflow<= add_ov when "0010" | "0100",
             sub_ov when "0110" | "0101",
             'Z' when others;

---Carryout-------------------------------------------------
With ALUCntl select 
Carryout<= add_result(32) when "0010",
            sub_result(32) when "0110",
            add_u(32)      when "0100",
            sub_u(32)      when "0101",
            'Z' when others;
end Behavioral;

因此,无需查看详细信息,我可以告诉您为什么第一个错误会出现编译问题。首先,让我们看看您的信号。它们都声明为无符号类型。

signal add_u,sub_u,a32u,b32u: unsigned(32 downto 0);

但是,您的 ALUOut 输出端口是 STD_LOGIC_VECTOR 类型。您会遇到问题,因为 signedSTD_LOGIC_VECTOR 不同。幸运的是,在这些类型之间进行转换非常容易。实际上,我一直把 this nandland conversion cheatsheet 放在手边。

尝试以下操作。它应该将您的签名类型转换为 STD_LOGIC_VECTOR.

ALU_Result <=add_result(31 downto 0) when "0010", -- add
            sub_result(31 downto 0) when "0110", -- sub
            slt     when "0111", -- set less than

            ----- Getting an error that indexed name is not STD_LOGIC_VECTOR --
            STD_LOGIC_VECTOR(add_u(31 downto 0)) when "0100", -- add unsigned 
            STD_LOGIC_VECTOR(sub_u(31 downto 0)) when "0101", -- sub unsigned

因此,作为速成课程复习,我将描述我对 std_logic_vector、已签名和未签名的看法。再一次,nandland has a good review of these types。这是我的想象:

  1. std_logic_vector不知道STD_LOGIC的向量应该是有符号表示还是无符号表示。因此,任何加法、减法和乘法运算都将不起作用。
  2. signed 正在将 std_logic 的向量解释为使用二进制补码形式。这允许对带符号的类型进行加法、减法和乘法
  3. unsigned 类似于有符号,但假定整数是无符号表示。

如果您尝试不使用 signedunsigned 进行作业,那么您将需要实施逻辑。但是,您可以让有符号和无符号类型为您实现逻辑。

所以让我们添加两种std_logic_vector。正如您在下面看到的,我将 A 和 B 向量转换为 signed/unsigned,然后再转换回 std_logic_vector

signal A, B: std_logic_vector(31 downto 0);
signal result: std_logic_vector(31 + 1 downto 0);
-- Lets add them together as though they were unsigned
-- We pad a 0 to the end of the value to extend its length
result <= std_logic_vector(unsigned('0' & A) + unsigned(B));
-- Lets add them together as though they were signed
-- We copy the last bit of A for signed values
result <= std_logic_vector(signed((A(31) & & A) + signed(B));

希望对您有所帮助!

我已经彻底看完了。主要问题是类型转换,所以我在添加它们的地方进行了评论。我还调整了一些代码,通过为命令名称添加常量(这通常是一种很好的做法)和用于命令选择的 case 语句来使其更具可读性。 std_logic_unsigned 是一个已弃用的非标准库。

我已根据您对有关处理无符号逻辑的原始问题的更新对其进行了更新。我还添加了几个常量和三个子类型,以符合只有一个版本的设计原则。

library ieee;
use ieee.std_logic_1164.all;
--use ieee.std_logic_unsigned.all;  -- Not advisable to use this non standard library.
use ieee.numeric_std.all;

entity ALU is
    generic
    (
        ALU_BITS: natural := 32  -- Added a generic parameter to specify the number of bits in the ALU.
    );
    port
    (
        A, B     : in  std_logic_vector (ALU_BITS - 1 downto 0);
        ALUCntl  : in  std_logic_vector (3 downto 0);
        Carryin  : in  std_logic;
        ALUOut   : out std_logic_vector (ALU_BITS - 1 downto 0);
        Zero     : out std_logic;
        Carryout : out std_logic;
        Overflow : out std_logic
    );
end ALU;

architecture Behavioral of ALU is

    -- Added some constants and subtypes to make the code more readable and maintainable.

    constant ALU_MSB: natural := ALU_BITS - 1;

    subtype TALURegister is std_logic_vector(ALU_MSB downto 0);
    subtype TALURegisterX is std_logic_vector(ALU_BITS downto 0);
    subtype TALURegisterXU is unsigned(ALU_BITS downto 0);

    constant ALU_REGISTER_ZERO: TALURegister := (others => '0');
    constant ALU_REGISTER_ONE : TALURegister := (ALU_MSB downto 1 => '0') & '1';

    constant CMD_ADD   : std_logic_vector := "0010";
    constant CMD_SUB   : std_logic_vector := "0110";
    constant CMD_SLT   : std_logic_vector := "0111";
    constant CMD_SLT_U : std_logic_vector := "1000";
    constant CMD_ADD_U : std_logic_vector := "0100";
    constant CMD_SUB_U : std_logic_vector := "0101";
    constant CMD_AND   : std_logic_vector := "0000";
    constant CMD_OR    : std_logic_vector := "0001";
    constant CMD_XOR   : std_logic_vector := "0011";
    constant CMD_NOR   : std_logic_vector := "1100";

    signal ALU_Result, slt, sltu : TALURegister;
    signal add_result, sub_result, a32, b32: TALURegisterX;

    -- create separate a and b for unsigned
    signal add_u, sub_u, a32u, b32u: TALURegisterXU;
    signal c32: TALURegisterX := (others => '0');
    signal add_ov, sub_ov: std_logic;

    begin
        -- Alternative command selection using a case statement.
        process(ALUCntl, add_result, sub_result, slt, sltu, add_u, sub_u, A, B)
        begin
            case ALUCntl is
                when CMD_ADD    =>  ALU_Result <= add_result(ALU_MSB downto 0);
                when CMD_SUB    =>  ALU_Result <= sub_result(ALU_MSB downto 0);
                when CMD_SLT    =>  ALU_Result <= slt;
                when CMD_SLT_U  =>  ALU_Result <= sltu;
                when CMD_ADD_U  =>  ALU_Result <= TALURegister(add_u(ALU_MSB downto 0));  -- Added type conversion.
                when CMD_SUB_U  =>  ALU_Result <= TALURegister(sub_u(ALU_MSB downto 0));  -- Added type conversion.
                when CMD_AND    =>  ALU_Result <= A and B;
                when CMD_OR     =>  ALU_Result <= A or B;
                when CMD_XOR    =>  ALU_Result <= A xor B;
                when CMD_NOR    =>  ALU_Result <= A nor B;
                when others     =>  ALU_Result <= A;
            end case;
        end process;

        -- with ALUCntl select
            -- ALU_Result <=
                -- add_result(ALU_MSB downto 0) when CMD_ADD, -- add
                -- sub_result(ALU_MSB downto 0) when CMD_SUB, -- sub
                -- slt     when CMD_SLT, -- set less than

                -- - Getting an error that indexed name is not STD_LOGIC_VECTOR --
                -- TALURegister(add_u(ALU_MSB downto 0)) when CMD_ADD_U, -- add unsigned  -- Added type conversion.
                -- TALURegister(sub_u(ALU_MSB downto 0)) when CMD_SUB_U, -- sub unsigned  -- Added type conversion.
                ---------------------------------------------------------

                -- sltu    when CMD_SLT_U, -- set less than unsigned
                -- A AND B when CMD_AND,
                -- A OR  B when CMD_OR,
                -- A XOR B when CMD_XOR,
                -- A NOR B when CMD_NOR,
                -- A when others;---condition for all other alu control signals

        ALUOut  <= ALU_Result;

        ----Set less than-----------------------------------
        process(a32, b32)
        begin
            if (a32 < b32) then
                slt <= ALU_REGISTER_ONE;
            else
                slt <= ALU_REGISTER_ZERO;
            end if;
        end process;

        ----Set less than unsigned--------------------------
        process(a32u, b32u)
        begin
        if (a32u < b32u) then
            sltu <= ALU_REGISTER_ONE;
        else
            sltu <= ALU_REGISTER_ZERO;
        end if;
        end process;

        ----Addition Operation and carry out generation-----
        a32     <= '0' & A;
        b32     <= '0' & B;
        c32(0)  <= Carryin;
        add_result <= TALURegisterX(signed(a32) + signed(b32) + signed(c32));  -- Added type conversion.
        sub_result <= TALURegisterX(signed(a32) - signed(b32));                -- Added type conversion.

        -- Getting "'0' definitions found" errors here --
        a32u  <= TALURegisterXU('0' & A);            -- Added type conversion.
        b32u  <= TALURegisterXU('0' & B);            -- Added type conversion.
        add_u <= a32u + b32u + TALURegisterXU(c32);  -- Added type conversion.
        sub_u <= a32u - b32u;

        -------------------------------------------------
        ---Zero flag-----------------------------
        Zero <= '1' when ALU_Result = ALU_REGISTER_ZERO else '0';

        ---Overflow flag---------------------------------------
        add_ov <= (A(ALU_MSB) and B(ALU_MSB)       and (not alu_result(ALU_MSB))) or ((not A(ALU_MSB)) and (not B(ALU_MSB)) and alu_result(ALU_MSB));
        sub_ov <= (A(ALU_MSB) and (not B(ALU_MSB)) and (not alu_result(ALU_MSB))) or ((not A(ALU_MSB)) and B(ALU_MSB)       and alu_result(ALU_MSB));
        with ALUCntl select
            Overflow <=
                add_ov when CMD_ADD | CMD_ADD_U,
                sub_ov when CMD_SUB | CMD_SUB_U,
                'Z' when others;

        ---Carryout-------------------------------------------------
        with ALUCntl select
            Carryout <=
                add_result(ALU_BITS) when CMD_ADD,
                sub_result(ALU_BITS) when CMD_SUB,
                add_u(ALU_BITS)      when CMD_ADD_U,
                sub_u(ALU_BITS)      when CMD_SUB_U,
                'Z' when others;
end Behavioral;