I implemented some VHDL code to exports FSM state encodings at compile time, which can be read back by Xilinx ChipScope. This functionality is tested with Xilinx ISE 14.7, iSim 14.7 and Mentor Graphic's QuestaSim 10.2c. My design can be synthesized with an alternative top-level as well for Altera FPGAs, but Quartus II seems to have a problem with return line.all;
.
Quartus II (14.0) error messages:
- Error (10351): VHDL Subprogram Body error at sata_PhysicalLayer.vhdl(504): function "dbg_GenerateEncodings" does not always return a value
- Error (10346): VHDL error at debug.vhdl(47): formal port or parameter "encodings" must have actual or default value
- Error (10657): VHDL Subprogram error at sata_PhysicalLayer.vhdl(514): failed to elaborate call to subprogram "dbg_ExportEncoding"
In the following, I'll describe my code.
VHDL Code
The design uses 3 functions to export the FSM state encodings:
- encode the current local FSM state as a binary value -> dbg_EncodeState
(the result of this function is connected to the ILA ports) - transform all states of the local FSM into a semicolon separated string -> dbg_GenerateEncodings
- format this string and write it's elements into a token-file -> dbg_ExportEncoding
(this function is located in a package)
FSM declaration:
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;
local functions - per entity functions:
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;
global function - defined in 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;
The last portion of code is a dummy constant in the entity, which calls the export function:
CONSTANT test : boolean := dbg_ExportEncoding("OOBControl (Host)", dbg_GenerateEncodings, MY_PROJECT_DIR & "CSP/FSM_OOB_Host.tok");
used auxilary functions:
- log2ceilnz(x) calculates the needed bits to encode x symbols in binary
- to_slv converts everything into a std_logic_vector; in this case a integer to slv
- str_replace replaces a string by a string
- str_trim returns a string from str'low to the first occurrence of NUL
- raw_format_nat_hex formats a natural to a hex string
Additional Notes:
All vhdl files are marked as VHDL-2008.
My Questions:
- Has anyone experience with line.all in a Quartus environment?
- Is there a workaround?
- Is there a better solution to achieve the export task without using strings of constant length?
Work around:
I wrapped my function dbg_GenerateEncodings in a generate statement:
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;
In contrast to XST, Quartus does not check functions inside a generate block.
See Quartus II VHDL Support, Section 14 Predefined language environment, the table entry 14.3, Construct TEXTIO, the rightmost column VHDL 1993 Support:
If you can't use TEXTIO for synthesis you could imagine a pointer to a line buffer might not be of any use either.
There's this issue of how you could write to a FILE from an FPGA. without any knowledge of the host operating system or specifying a physical interface.
You can manage to synthesize the remainder of your design by surrounding unsupported constructs with translate off and translate on directives. See VHDL Synthesis Attributes and Directives.