忽略 VHDL 报告语句

VHDL report statement ignored

为了学习 VHDL,我正在使用 VHDL 实现自己的自定义 CPU。

厌倦了手动编写操作码位模式,我想创建非常简单的"assembler"来创建位模式。

这是此类汇编程序的当前实现:

library ieee;
use ieee.std_logic_1164.all;
use work.utility.all;

package assembler is
    function encode_opcode(cmd: string; re: integer; rd: integer; ra: integer; rb: integer; imm: integer) return std_logic_vector;
end;

package body assembler is
    function to_lower(x: character) return character is
        constant posA: integer := character'pos('A');
        constant posZ: integer := character'pos('Z');
        constant posLowerA: integer := character'pos('a');
        constant posX: integer := character'pos(x);
    begin
        if posA <= posX and posX <= posZ then
            return character'val(posX - posA + posLowerA);
        else
            return x;
        end if;
    end;

    function to_lower(x: string) return string is
        variable r: string(x'range);
    begin
        for i in x'range loop
            r(i) := to_lower(x(i));
        end loop;
        return r;
    end;

    function encode_cmd(cmd: string) return std_logic_vector is
        constant cmd2: string(1 to cmd'length) := cmd;
        variable cmd3: string(1 to 5) := "-----";
    begin
        if cmd'length > 5 then
            report "Illegal command: " & cmd severity error;
            return "";
        end if;
        for i in cmd2'range loop
            cmd3(i) := cmd2(i);
        end loop;
        case to_lower(cmd3) is
            -- Group 1: Memory access (omitted)
            -- Group 2: Addition
            when "addu-" => return "00100000";
            when "subu-" => return "00100001";
            when "add--" => return "00100010";
            when "sub--" => return "00100011";
            -- Group 3: Multiplication
            when "multu" => return "00110000";
            when "divu-" => return "00110001";
            when "mult-" => return "00110010";
            when "div--" => return "00110011";
            -- Group 4: Bitwise (omitted)
            -- Group 5: Shift
            when "shf--" => return "01010000";
            when "shfu-" => return "01010001";
            when "rot--" => return "01010010";
            -- Group 6: Branch absolute (omitted)
            -- Group 7: Branch relative (omitted)
            when others =>
                report "Illegal command: " & cmd severity error;
                return "";
        end case;
    end;

    function encode_opcode(cmd: string; re: integer; rd: integer; ra: integer; rb: integer; imm: integer) return std_logic_vector is
    begin
        return encode_cmd(cmd) & encode_unsigned(re, 5) & encode_unsigned(rd, 5) & encode_unsigned(ra, 5) & encode_unsigned(rb, 5) & encode_signed(imm, 4);
    end;
end;

这里是 encode_unsigned 和 encode_signed 函数的定义:

function encode_unsigned(x: integer; n: integer) return std_logic_vector is
begin
    return std_logic_vector(to_unsigned(x, n));
end;

function encode_signed(x: integer; n: integer) return std_logic_vector is
begin
    return std_logic_vector(to_signed(x, n));
end;

这里是encode_opcode函数的用法:

function rom_contents(addr: std_logic_vector) return std_logic_vector is
begin
    case decode_unsigned(addr) is
        when 0 => return encode_opcode("ADDu", 0, 1, 0, 0, 2);
        when 1 => return encode_opcode("ADD", 0, 2, 0, 0, -8);
        when 2 => return encode_signed(11, 32);
        when 3 => return encode_opcode("MULT", 0, 3, 1, 2, 0);
        when 6 => return encode_opcode("ADD", 0, 4, 3, 0, 0);
        when 8 => return encode_opcode("ADD", 0, 16, 0, 0, -8);
        when 9 => return encode_signed(16#12345678#, 32);
        when 11 => return encode_opcode("ROT", 31, 30, 16, 0, 4);
        when 12 => return encode_opcode("ROT", 29, 28, 30, 0, 4);
        when others => return (31 downto 0 => '0');
    end case;
end;

每当我写错并写了 encode_opcode("ROTE", 31, 30, 16, 0, 4); 之类的东西时,我想得到 Illegal command: ROTE 这样的错误消息。但是,它不会创建任何错误消息,并且 encode_opcode 的 return 值的长度静默变为 24。 (如果没有错误,长度应该是32。)

使用枚举作为命令太难了,因为一些命令看起来像 ANDXORGFu>GT<=.

我使用的是 Quartus Prime Lite Edition 版本 18.0

更新:rom_contents 的用法:

entity instruction_memory_controller is
    port (
        clock: in std_logic;
        addr: in std_logic_vector(31 downto 0);
        q: out std_logic_vector(31 downto 0)
    );
end;

architecture RTL of instruction_memory_controller is
begin
    process(clock)
    begin
        if rising_edge(clock) then
            q <= rom_contents(addr);
        end if;
    end process;
end;

当我输入错误的命令时,q <= rom_contnts(addr) 由于大小不匹配(24 对 32)而标记错误。

当我将非法命令的 return 值从 "" 更改为 "XXXXXXXX" 时,它编译时没有任何 error/warning。 (我的预期是它会通过报告语句触发 Illegal command 错误。)

  1. 关于返回向量的长度:您的 encode_cmd 函数 returns 遇到非法操作码时为空向量。因此,encode_opcode 返回的向量的总长度不是 32,而是 24... Return "00000000" 或任何其他 8 位长向量,如果您在所有情况下都需要 32 位结果.

  2. 关于丢失的错误消息:它出现在 Modelsim 中。由于您没有显示您对 rom_contents 做了什么,我们无法猜测向量长度不匹配是否会引发模拟错误。如果是这样,是不是在 Quartus 中它优先于 report "Illegal command... 而后者永远不会被解雇?还是您错过了错误消息,因为它不是最后打印的?

备注:

  • 如果您希望模拟在遇到非法操作码时真正停止,请尝试使用 severity failure 而不是 severity error,或者找到您的模拟器的选项,该选项可以选择高于该模拟的严重性级别停止。
  • 您使用 std_logicstd_logic_vector,它们是已解析的类型。考虑到您的设计,我怀疑您是否真的有多种驱动情况。您应该考虑 std_ulogicstd_ulogic_vector,因为这样会更安全。当您显然使用 VHDL 2008 风格时,它与 signedunsigned 相同,您可以用 u_signedu_unsigned 代替。总而言之,它带来的好处是不需要的多个驱动器情况会引发错误。

EDITS 交换意见后:

Quartus 是一个合成器。因此,它有可能在门级仿真之前综合您的设计。如果这是真的,那么您必须意识到一些重要的事情:综合过程会忽略 report 语句,因为它们没有等效的硬件。因此,您对 Quartus 最好的期望是它检测到 report 语句总是到达并决定在综合过程中显示它。在某些情况下这是可能的,因为合成器试图通过传播常量来简化设计:

constant condition: boolean := true;
...
if condition then
    report 'Foo bar';
end if;

变成:

report 'Foo bar';

不幸的是,在更复杂的示例中,例如您的示例,检测到始终达到 report 语句要困难得多。这是因为它仅在给定数量的时钟周期后到达,此时您的地址到达错误的 ROM 条目。不要指望逻辑合成器检测到这一点。

解决方案:

  1. 使用真实的模拟器,例如 GHDL 或 Modelsim,来验证您的设计。
  2. 实现一个真实的错误信号,而不是一个抽象的、面向模拟的report语句。并在 post 综合仿真期间(以及在您的硬件目标上执行期间)监视此信号。这将是您的处理器真正 无效指令 异常的第一步。

关于 VHDL 2008 的注意事项:如果您在 case 语句中使用 '-'(无关)值作为匹配任何值的方式,那么我认为您使用的是 VHDL 2008。如果我没记错的话,它是在 2008 年推出的。在此之前,它是一个与任何其他值一样的值(ieee.numeric_std.std_match 函数除外)。