要学习VHDL,我正在用VHDL实现自己的自定义CPU。
由于讨厌手动编写操作码位模式,我想创建一个非常简单的“汇编程序”来创建位模式。
这是这种汇编器的当前实现:
Issued_d
这是encode_unsigned和encode_signed函数的定义:
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_opcode函数的用法:
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;
每当我犯错并写了类似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);
之类的错误消息。但是,它不会创建任何错误消息,并且encode_opcode的返回值长度默默地变为24。 (如果没有错误,则长度应为32。)
使用枚举作为命令太困难了,因为某些命令看起来像Illegal command: ROTE
,AND
,XOR
,GFu>
。
我正在使用Quartus Prime Lite Edition 18.0
更新:rom_contents的用法:
GT<=
当我输入错误的命令时,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;
由于大小不匹配(24对32)而标记为错误。
当我将非法命令的返回值从q <= rom_contnts(addr)
更改为""
时,它的编译没有任何错误/警告。 (我的期望是它会通过报告语句触发"XXXXXXXX"
错误。)
答案 0 :(得分:1)
关于返回向量的长度:当遇到非法操作码时,您的encode_cmd
函数将返回一个空向量。因此,encode_opcode
返回的向量的总长度不是32而是24 ...如果在所有情况下都希望获得32位,则返回"00000000"
或任何其他8位长的向量。
关于缺少的错误消息:它与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
。总而言之,它带来的好处是不需要的多驱动器情况会引发错误。编辑:
Quartus是一个合成器。因此,在门级仿真之前,它有可能综合您的设计。如果这是真的,那么您必须意识到一些重要的事情:report
语句被合成过程忽略,因为它们没有等效的硬件。因此,您对Quartus所能期望的最好的结果就是它检测到始终到达report
语句,并决定在综合过程中显示它。在某些情况下,这是可能的,因为合成器试图通过传播常量来简化设计:
constant condition: boolean := true;
...
if condition then
report 'Foo bar';
end if;
成为:
report 'Foo bar';
不幸的是,在更复杂的示例中(例如您的示例),要检测到始终到达report
语句要困难得多。这是因为只有在给定的时钟周期数之后,当您的地址到达错误的ROM条目时,它才会到达。不要指望逻辑合成器能够检测到这一点。
解决方案:
report
语句。在合成后仿真期间(以及在硬件目标上执行期间)监视此信号。这是迈向处理器真正无效指令异常的第一步。关于VHDL 2008的说明:如果您将case语句中的'-'
(无关紧要)值用作匹配任何值的方式,那么我认为您正在使用VHDL 2008。如果我还记得的话,它是在2008年推出的。在此之前,它是一个与其他任何值一样的值(ieee.numeric_std.std_match
函数中除外)。