我实现了一些 VHDL 代码以在编译时导出 FSM 状态编码,这些代码可由 Xilinx ChipScope 读回。此功能已使用 Xilinx ISE 14.7、iSim 14.7 和 Mentor Graphic 的 QuestaSim 10.2c 进行了测试。我的设计也可以与 Altera FPGA 的替代顶层进行综合,但 Quartus II 似乎在return line.all;.
Quartus II (14.0) 错误信息:
- 错误 (10351):sata_PhysicalLayer.vhdl(504) 处的 VHDL 子程序主体错误:函数“dbg_GenerateEncodings”并不总是返回值
- 错误 (10346):debug.vhdl(47) 处的 VHDL 错误:正式端口或参数“编码”必须具有实际值或默认值
- 错误 (10657):sata_PhysicalLayer.vhdl(514) 处的 VHDL 子程序错误:未能详细调用子程序“dbg_ExportEncoding”
下面,我将描述我的代码。
VHDL 代码
该设计使用 3 个函数来导出 FSM 状态编码:
- 将当前本地 FSM 状态编码为二进制值 -> dbg_EncodeState
(此函数的结果连接到 ILA 端口) - 将本地 FSM 的所有状态转换为分号分隔的字符串 -> dbg_GenerateEncodings
- 格式化此字符串并将其元素写入令牌文件-> dbg_ExportEncoding
(此函数位于包中)
FSM 声明:
TYPE T_STATE IS (
ST_HOST_RESET,
ST_HOST_SEND_COMRESET,
ST_HOST_SEND_COMRESET_WAIT,
[...]
ST_HOST_SEND_ALIGN,
ST_HOST_TIMEOUT,
ST_HOST_LINK_OK
);
-- OOB-Statemachine
SIGNAL State : T_STATE := ST_HOST_RESET;
SIGNAL NextState : T_STATE;
局部函数 - 每个实体函数:
function dbg_EncodeState(st : T_STATE) return STD_LOGIC_VECTOR is
begin
return to_slv(T_STATE'pos(st), log2ceilnz(T_STATE'pos(T_STATE'high) + 1));
end function;
function dbg_GenerateEncodings return string is
variable l : STD.TextIO.line;
begin
for i in T_STATE loop
STD.TextIO.write(l, str_replace(T_STATE'image(i), "st_host_", ""));
STD.TextIO.write(l, ';');
end loop;
return l.all;
end function;
全局函数 - 在 debug.pkg.vhdl 中定义:
impure function dbg_ExportEncoding(Name : STRING; encodings : string; tokenFileName : STRING) return BOOLEAN is
file tokenFile : TEXT open WRITE_MODE is tokenFileName;
variable cnt, base : integer;
variable l : line;
begin
report "Exporting encoding of '" & Name & "' to '" & tokenFileName & "'..." severity note;
report "dbg_ExportEncoding: '" & encodings & "'" severity note;
-- write file header
write(l, "# Encoding file for '" & Name & "'"); writeline(tokenFile, l);
write(l, "#"); writeline(tokenFile, l);
write(l, "# ChipScope Token File Version"); writeline(tokenFile, l);
write(l, "@FILE_VERSION=1.0.0"); writeline(tokenFile, l);
write(l, "#"); writeline(tokenFile, l);
write(l, "# Default token value"); writeline(tokenFile, l);
write(l, "@DEFAULT_TOKEN="); writeline(tokenFile, l);
write(l, "#"); writeline(tokenFile, l);
-- write state entires
cnt := 0;
base := encodings'left;
for i in encodings'range loop
if encodings(i) = ';' then
-- Leave the str_trim call in!
-- Otherwise, the new parser of ISE 14.7 fails to slice properly.
write(l, str_trim(encodings(base to i-1)));
write(l, character'('='));
write(l, raw_format_nat_hex(cnt));
writeline(tokenFile, l);
cnt := cnt + 1;
base := i+1;
end if;
end loop;
file_close(tokenFile);
return true;
end function;
代码的最后一部分是实体中的一个虚拟常量,它调用导出函数:
CONSTANT test : boolean := dbg_ExportEncoding("OOBControl (Host)", dbg_GenerateEncodings, MY_PROJECT_DIR & "CSP/FSM_OOB_Host.tok");
使用的辅助功能:
- log2ceilnz(x) 计算以二进制编码 x 符号所需的位
- to_slv 将所有内容转换为 std_logic_vector;在这种情况下,一个整数到 slv
- str_replace 用字符串替换字符串
- str_trim 返回从 str'low 到第一次出现 NUL 的字符串
- raw_format_nat_hex 将自然格式化为十六进制字符串
附加说明:
所有 vhdl 文件都标记为 VHDL-2008。
我的问题:
- 有人在 Quartus 环境中使用过 line.all 吗?
- 有解决方法吗?
- 有没有更好的解决方案来实现导出任务而不使用恒定长度的字符串?
解决方法:
我将函数 dbg_GenerateEncodings 包装在生成语句中:
genXilinx : if (VENDOR = VENDOR_XILINX) generate
function dbg_GenerateEncodings return string is
[...]
constant test : boolean := dbg_ExportEncoding("OOBControl (Host)", dbg_GenerateEncodings, MY_PROJECT_DIR & "CSP/FSM_OOB_Host.tok");
begin
end generate;
与 XST 相比,Quartus 不检查生成块内的函数。