首页 > 解决方案 > VHDL 报告语句被忽略

问题描述

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

厌倦了手动编写操作码位模式,我想创建非常简单的“汇编程序”来创建位模式。

这是这种汇编器的当前实现:

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 的返回值的长度会静默变为 24。(如果没有错误,长度应该是 32。)

将 enum 用于命令太难了,因为某些命令看起来像AND, XOR, GFu>, GT<=

我正在使用 Quartus Prime Lite 版本 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)而标记错误。

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

标签: vhdlquartus

解决方案


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

  2. 关于丢失的错误消息:它显示在 Modelsim 中。由于您没有展示您所做的事情,rom_contents我们无法猜测矢量长度不匹配是否会引发模拟错误。如果是这样,是不是 Quartus 优先于report "Illegal command...并且后者永远不会被解雇?或者可能是您错过了错误消息,因为它不是最后一个打印的?

笔记:

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

交换意见后的编辑:

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语句。并在综合后仿真期间(以及在硬件目标上执行期间)监控此信号。这将是处理器真正无效指令异常的第一步。

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


推荐阅读