vhdl - 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
通过报告语句触发错误。)
解决方案
关于返回向量的长度:
encode_cmd
遇到非法操作码时,您的函数会返回一个空向量。因此,返回的向量的总长度encode_opcode
不是 32 而是 24..."00000000"
如果您在所有情况下都需要 32 位结果,则返回或任何其他 8 位长向量。关于丢失的错误消息:它显示在 Modelsim 中。由于您没有展示您所做的事情,
rom_contents
我们无法猜测矢量长度不匹配是否会引发模拟错误。如果是这样,是不是 Quartus 优先于report "Illegal command...
并且后者永远不会被解雇?或者可能是您错过了错误消息,因为它不是最后一个打印的?
笔记:
- 如果您希望在遇到非法操作码时真正停止模拟,请尝试
severity failure
代替severity error
,或者找到您的模拟器的选项,该选项选择模拟停止的严重级别。 - 您使用哪些是已解析
std_logic
的std_logic_vector
类型。考虑到您的设计,我怀疑您是否真的有多种驾驶情况。您可能应该考虑std_ulogic
andstd_ulogic_vector
,因为它会更安全。并且由于您显然使用了 VHDL 2008 风格,它与signed
and相同unsigned
,您可以用u_signed
and代替u_unsigned
。总而言之,它带来的好处是不需要的多个驱动器情况会引发错误。
交换意见后的编辑:
Quartus 是一个合成器。因此,它有可能在门级仿真之前综合您的设计。如果这是真的,那么您必须意识到一些重要的事情:report
综合过程会忽略语句,因为它们没有硬件等效项。因此,您对 Quartus 的期望最好的是,它检测到一个report
语句总是到达并决定在综合过程中显示它。在某些情况下这是可能的,因为合成器试图通过传播常量来简化设计:
constant condition: boolean := true;
...
if condition then
report 'Foo bar';
end if;
变成:
report 'Foo bar';
report
不幸的是,在更复杂的示例中,例如您的示例,要检测到始终到达语句要困难得多。这是因为只有在给定数量的时钟周期之后,当您的地址到达有故障的 ROM 条目时,才能到达它。不要指望逻辑合成器检测到这一点。
解决方案:
- 例如,使用 GHDL 或 Modelsim 等真正的模拟器来验证您的设计。
- 实现一个真正的错误信号,而不是一个抽象的、面向模拟的
report
语句。并在综合后仿真期间(以及在硬件目标上执行期间)监控此信号。这将是处理器真正无效指令异常的第一步。
关于 VHDL 2008 的注意事项:如果您 '-'
在 case 语句中使用(不关心)值作为匹配任何值的一种方式,那么我认为您正在使用 VHDL 2008。如果我没记错的话,它是在 2008 年推出的。在此之前,它是一个与任何其他值一样的值(ieee.numeric_std.std_match
函数中除外)。
推荐阅读
- c# - 为什么我的并行任务代码不能达到 100% 的 CPU 利用率?
- c++ - 我可以在没有 Xcode 的 Mac 上使用 UnrealEngine 和 C++
- reactjs - 使用反应时将3d模型导入巴比伦
- postgresql - PL/pgSQL 函数中的语句是否按顺序运行?
- android - RXAndroid/RXJava2:链接三个改造请求并再次重复相同的过程
- python-requests - 我应该如何实现对响应生效的 Auth 处理程序?
- javascript - JavaScript - 如何为 GET 设置请求标头(真正的 GET,将您重定向到 url 的那个)
- javascript - Firebase Web 创建用户并在实时数据库中写入数据无法正常工作
- php - Wordpress Woocommerce 在商店页面上显示属性
- oracle-apex - 会话状态作为应用程序中的页面