忽略 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。)
使用枚举作为命令太难了,因为一些命令看起来像 AND
、XOR
、GFu>
、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
错误。)
关于返回向量的长度:您的 encode_cmd
函数 returns 遇到非法操作码时为空向量。因此,encode_opcode
返回的向量的总长度不是 32,而是 24... Return "00000000"
或任何其他 8 位长向量,如果您在所有情况下都需要 32 位结果.
关于丢失的错误消息:它出现在 Modelsim 中。由于您没有显示您对 rom_contents
做了什么,我们无法猜测向量长度不匹配是否会引发模拟错误。如果是这样,是不是在 Quartus 中它优先于 report "Illegal command...
而后者永远不会被解雇?还是您错过了错误消息,因为它不是最后打印的?
备注:
- 如果您希望模拟在遇到非法操作码时真正停止,请尝试使用
severity failure
而不是 severity error
,或者找到您的模拟器的选项,该选项可以选择高于该模拟的严重性级别停止。
- 您使用
std_logic
和 std_logic_vector
,它们是已解析的类型。考虑到您的设计,我怀疑您是否真的有多种驱动情况。您应该考虑 std_ulogic
和 std_ulogic_vector
,因为这样会更安全。当您显然使用 VHDL 2008 风格时,它与 signed
和 unsigned
相同,您可以用 u_signed
和 u_unsigned
代替。总而言之,它带来的好处是不需要的多个驱动器情况会引发错误。
EDITS 交换意见后:
Quartus 是一个合成器。因此,它有可能在门级仿真之前综合您的设计。如果这是真的,那么您必须意识到一些重要的事情:综合过程会忽略 report
语句,因为它们没有等效的硬件。因此,您对 Quartus 最好的期望是它检测到 report
语句总是到达并决定在综合过程中显示它。在某些情况下这是可能的,因为合成器试图通过传播常量来简化设计:
constant condition: boolean := true;
...
if condition then
report 'Foo bar';
end if;
变成:
report 'Foo bar';
不幸的是,在更复杂的示例中,例如您的示例,检测到始终达到 report
语句要困难得多。这是因为它仅在给定数量的时钟周期后到达,此时您的地址到达错误的 ROM 条目。不要指望逻辑合成器检测到这一点。
解决方案:
- 使用真实的模拟器,例如 GHDL 或 Modelsim,来验证您的设计。
- 实现一个真实的错误信号,而不是一个抽象的、面向模拟的
report
语句。并在 post 综合仿真期间(以及在您的硬件目标上执行期间)监视此信号。这将是您的处理器真正 无效指令 异常的第一步。
关于 VHDL 2008 的注意事项:如果您在 case 语句中使用 '-'
(无关)值作为匹配任何值的方式,那么我认为您使用的是 VHDL 2008。如果我没记错的话,它是在 2008 年推出的。在此之前,它是一个与任何其他值一样的值(ieee.numeric_std.std_match
函数除外)。
为了学习 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。)
使用枚举作为命令太难了,因为一些命令看起来像 AND
、XOR
、GFu>
、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
错误。)
关于返回向量的长度:您的
encode_cmd
函数 returns 遇到非法操作码时为空向量。因此,encode_opcode
返回的向量的总长度不是 32,而是 24... Return"00000000"
或任何其他 8 位长向量,如果您在所有情况下都需要 32 位结果.关于丢失的错误消息:它出现在 Modelsim 中。由于您没有显示您对
rom_contents
做了什么,我们无法猜测向量长度不匹配是否会引发模拟错误。如果是这样,是不是在 Quartus 中它优先于report "Illegal command...
而后者永远不会被解雇?还是您错过了错误消息,因为它不是最后打印的?
备注:
- 如果您希望模拟在遇到非法操作码时真正停止,请尝试使用
severity failure
而不是severity error
,或者找到您的模拟器的选项,该选项可以选择高于该模拟的严重性级别停止。 - 您使用
std_logic
和std_logic_vector
,它们是已解析的类型。考虑到您的设计,我怀疑您是否真的有多种驱动情况。您应该考虑std_ulogic
和std_ulogic_vector
,因为这样会更安全。当您显然使用 VHDL 2008 风格时,它与signed
和unsigned
相同,您可以用u_signed
和u_unsigned
代替。总而言之,它带来的好处是不需要的多个驱动器情况会引发错误。
EDITS 交换意见后:
Quartus 是一个合成器。因此,它有可能在门级仿真之前综合您的设计。如果这是真的,那么您必须意识到一些重要的事情:综合过程会忽略 report
语句,因为它们没有等效的硬件。因此,您对 Quartus 最好的期望是它检测到 report
语句总是到达并决定在综合过程中显示它。在某些情况下这是可能的,因为合成器试图通过传播常量来简化设计:
constant condition: boolean := true;
...
if condition then
report 'Foo bar';
end if;
变成:
report 'Foo bar';
不幸的是,在更复杂的示例中,例如您的示例,检测到始终达到 report
语句要困难得多。这是因为它仅在给定数量的时钟周期后到达,此时您的地址到达错误的 ROM 条目。不要指望逻辑合成器检测到这一点。
解决方案:
- 使用真实的模拟器,例如 GHDL 或 Modelsim,来验证您的设计。
- 实现一个真实的错误信号,而不是一个抽象的、面向模拟的
report
语句。并在 post 综合仿真期间(以及在您的硬件目标上执行期间)监视此信号。这将是您的处理器真正 无效指令 异常的第一步。
关于 VHDL 2008 的注意事项:如果您在 case 语句中使用 '-'
(无关)值作为匹配任何值的方式,那么我认为您使用的是 VHDL 2008。如果我没记错的话,它是在 2008 年推出的。在此之前,它是一个与任何其他值一样的值(ieee.numeric_std.std_match
函数除外)。