How to write new line to file in VHDL? - vhdl

I would like to separate my data with new line character in an output file, but the following codes result in error "can't resolve overload for procedure call":
write(out_line, "\n");
write(out_line, "");
write(out_line, '');
An example code how I want to use it:
ENTITY writer IS
PORT ( clk : IN STD_LOGIC := '0'; start : IN STD_LOGIC := '0');
END ENTITY;
ARCHITECTURE arch OF writer IS
SIGNAL vect : STD_LOGIC_VECTOR (2 downto 0) := "000";
TYPE state_type IS (init, write_file);
SIGNAL state : state_type := init;
BEGIN
PROCESS (clk, start)
FILE out_file : text;
VARIABLE out_line : line;
BEGIN
IF rising_edge(clk) THEN
CASE state IS
WHEN init =>
IF start = '1' THEN
state <= write_file;
ELSE
state <= init;
END IF;
WHEN write_file =>
state => init;
FOR i IN 0 TO 10 LOOP
write(out_line, vect);
writeline(out_file, out_line);
-- write(out_line, "\n"); <--
-- write(out_line, ""); <--
-- write(out_line, ''); <-- None of these work
writeline(out_file, out_line);
END LOOP;
END CASE;
END IF;
END PROCESS;
END ARCHITECTURE;
So I would like to know, is it possible in VHDL? If yes, how?

The following will consistently give you a single blank line:
write(out_line, string'(""));
writeline(out_file, out_line);
I suspect what #Dani posted may be tool dependent. For example while on one popular simulator, the following produces one line feed:
write(out_line, LF);
writeline(out_file, out_line);
However when I add a space after the LF, I get two lines:
write(out_line, LF & ' ');
writeline(out_file, out_line);

Creating a minimal, complete and verifiable example from the question's incomplete sample code:
library ieee; -- ADDED
use ieee.std_logic_1164.all; -- ADDED
use std.textio.all; -- ADDED
-- use ieee.std_logic_textio.all; -- ADDED for revisions earlier than -2008
ENTITY writer IS
-- PORT ( clk : IN STD_LOGIC := '0'; start : IN STD_LOGIC := '0');
END ENTITY;
ARCHITECTURE arch OF writer IS
SIGNAL vect : STD_LOGIC_VECTOR (2 downto 0) := "000";
-- TYPE state_type IS (init, write_file);
-- SIGNAL state : state_type := init;
BEGIN
PROCESS -- (clk, start)
FILE out_file : text;
VARIABLE out_line : line;
BEGIN
file_open(out_file, "some_file", WRITE_MODE); -- ADDED
-- IF rising_edge(clk) THEN
-- CASE state IS
-- WHEN init =>
-- IF start = '1' THEN
-- state <= write_file;
-- ELSE
-- state <= init;
-- END IF;
-- WHEN write_file =>
-- state => init;
FOR i IN 0 TO 10 LOOP
write(out_line, vect);
writeline(out_file, out_line);
-- write(out_line, "\n"); <--
-- write(out_line, ""); <--
-- write(out_line, ''); <-- None of these work
writeline(out_file, out_line);
END LOOP;
-- END CASE;
-- END IF;
wait; -- ADDED
END PROCESS;
END ARCHITECTURE;
demonstrates a way to get a blank line in the output:
some_file contents:
000
000
000
000
000
000
000
000
000
000
000
The second writeline procedure call produces an empty line without an intervening write procedure call.
Why is seen in IEEE Std 1076-2008 16.4 Package TEXTIO:
Procedures READLINE, WRITELINE, and TEE declared in package TEXTIO read and write entire lines of a file of type TEXT. Procedure READLINE causes the next line to be read from the file and returns as the value of parameter L an access value that designates an object representing that line. If parameter L contains a non-null access value at the start of the call, the procedure may deallocate the object designated by that value. The representation of the line does not contain the representation of the end of the line. It is an error if the file specified in a call to READLINE is not open or, if open, the file has an access mode other than read-only (see 5.5.2). Procedures WRITELINE and TEE each cause the current line designated by parameter L to be written to the file and returns with the value of parameter L designating a null string. Procedure TEE additionally causes the current line to be written to the file OUTPUT. If parameter L contains a null access value at the start of the call, then a null string is written to the file or files. If parameter L contains a non-null access value at the start of the call, the procedures may deallocate the object designated by that value. It is an error if the file specified in a call to WRITELINE or TEE is not open or, if open, the file has an access mode other than write-only.
The language does not define the representation of the end of a line. An implementation shall allow all possible values of types CHARACTER and STRING to be written to a file. However, as an implementation is permitted to use certain values of types CHARACTER and STRING as line delimiters, it might not be possible to read these values from a TEXT file.
A line feed (LF) format effector occurring as an element of a string written to a file of type TEXT, either using procedure WRITELINE or TEE, or using the WRITE operation implicitly defined for the type TEXT, is interpreted by the implementation as signifying the end of a line. The implementation shall transform the LF into the implementation-defined representation of the end of a line.
...
For each WRITE, OWRITE, and HWRITE procedure, after data is appended to the string value designated by the parameter L, L designates the entire line. The procedure may modify the value of the object designated by the parameter L at the start of the call or may deallocate the object.
If deallocation occurs out_line will have a value of null after a writeline call and a null string is written in the immediately following writeline call which also provides an end of line.
If the object value accessed by out_line is a null array (having no elements, 5.3.2.2 Index constraints and discrete ranges, a null string) the immediately following writeline call will result in an end of line being written to the file.
In essence your code example already contains one of these methods for writing a blank line, which depends on whether deallocation is used conditionally (may).
Variants of allocate() and free() can be relatively expensive in terms of execution time and when the size of the allocated object and it's element size is known a smaller 'allocated' object can be written to the same object space saving simulation time. The simulation kernel representation of an array object can have bounds separate from the array value, deallocation and re-allocation can be reserved for when the object size is larger than the previously allocated size or an explicit deallocate call occurs.
There's also a requirement that an implementation translate an LF character to an end of line in a write to a file. This is the other mechanism that allows you to write an LF character as the last or only character to a line and get a following blank line.
You could also explicitly write a null string to out_line
write(out_line, string'(""));
prior to the second writeline call. The qualified expression provides the type of the string literal unlike the attempt commented out in the original question where the type of the string literal can't be determined. See 9.3.2 Literals "... The type of a string or bit string literal shall be determinable solely from the context in which the literal appears, excluding the literal itself but using the fact that the type of the literal shall be a one-dimensional array of a character type. ...". The procedure write would be ambiguous in this context, failing overload resolution (12.5 The context of overload resolution).

Finally after a lot of searching and trying I found that the following code works:
write(out_line, lf);
writeline(out_file, out_line);
I found that write(out_line, cr); does the same thing, and write(out_line, nul); adds ' ' character between the outputs.

Related

How to use a 'case' in VHDL blocks

I want to re-use some code block and to make it more readable I tried to put it in a block.
The code block is used to save some data to some buffers. This also includes a case statement. This block is used in a few states in a statemachine.
someBlock: block
begin
destinationAddr <= destinationAddr_i;
sourceAddr <= sourceAddr_i
case type is
when typeA =>
someData <= dataA;
dataLength <= 1;
when typeB =>
someData <= dataB;
dataLength <= 2;
when typeC =>
someData <= dataC;
dataLength <= 3;
end case;
end block;
The code is just an example of what I'm trying to do. I want this code to be inserted in the place I call someBlock.
If I make this block Sigasi and Vivado complain about the case statement. (mismatched input 'case', expecting 'end'). I placed the block declaration after the architecture begin but not inside a process.
Is this the wrong way to use a block? Is there some other way of making a 'function' that can manipulate all signals in the architecture?
edit:
ok figured it out. I tried using a procedure before, i placed it in the architecture but not in the process. The signals weren't accessible according to vivado because it couldn't be sure there wouldn't be multiple drivers (from different processes). If I place the procedure in the process it does work.
Thanks for the help everyone :)
First of all, type is a reserved word and cannot be used for an object name. You also cannot use a case statement based on a checking an object type.
It is complaining because the inside of a Block statement is not a sequential region of the code. Case statements must be used in a sequential region, such as a process, function or procedure. In addition, blocks cannot be re-used, they are there simply to add a local region for scoping purposes.
To make it re-useable, you probably want to use a procedure instead. This would be declared in a declarative region - ie. before a "begin". Here is an example:
procedure mux(constant s : in std_logic;
constant bits : in std_logic_vector(1 downto 0);
signal o : out std_logic
) is
begin
case s is
when '1' => o <= bits(1);
when '0' => o <= bits(0);
when others => o <= 'X'; -- for simulation only
end case;
end procedure;
begin
-- create a synchronous mux
process(clk)
begin
if rising_edge(clk) then
mux(s0, ipA, opA);
end if;
end process;
-- you can call it outside a process also - this infers an async process, sensitive to s1, ipB, opB
mux(s1, ipB, opB);
end architecture;

Reading text length in Vivado

I need to get the length of a text file in Vivado during simulation. I tried below piece of code but I got an error.
file my_input : TEXT open READ_MODE is "/home/sukru/MD5.dat";
variable my_line : LINE;
variable input_line : LINE;
variable length : integer;
readline(my_input, input_line);
read(input_line, length);
writeline(output, input_line); -- optional, write to std out
write(input_line, integer'(length));
writeline(output, input_line);
The error message is this.
Error: TEXTIO function READ: read a non-integer, an integer is expected
a
-2147483648
I can read text's index but the length is non-sense value. Someone direct me how can I get the length of any text file.
VHDL at present has no way of interfacing to the host operating system to determine a file length.
There's an equivalency between bytes and the VHDL type character (see IEEE Std 1076-2008).
Normative references
...
ISO/IEC 8859-1:1998, Information technology—8-bit single-byte coded graphic character sets—Part 1: Latin alphabet No. 1.
Also see 16.3 Package standard, type character where all 256 enumeration values for a single-byte character are included.
That means we can count characters in a file:
use std.textio.all;
entity length_in_bytes is
end entity;
architecture foo of length_in_bytes is
impure function file_length (file_name: string) return integer is
type char_file is file of character;
file file_in: char_file open read_mode is file_name;
variable char_buffer: character;
variable length: integer := 0;
begin
while not ENDFILE(file_in) loop
read(file_in, char_buffer);
length := length + 1;
end loop;
file_close(file_in);
-- report file_name & " length = " & integer'image(length);
return length;
end function;
signal filelength: natural;
begin
filelength <= file_length("md5.dat");
process
begin
wait for 0 ns; -- skip default signal value;
report "file md5.dat length = " & integer'image(filelength);
wait;
end process;
end architecture;
The length returned by the function call will match the length the host operating system provides.
The file_close leaves the file unlocked for further use and reads of an open file are sequential from file open.
This line reads a line from the file:
readline(my_input, input_line);
This line tries to read an integer (destructively) from the line:
read(input_line, length);
It doesn't return the length of the file (or the line). You don't supply the file you are trying to read (it would have been better had you done so - see this ), but my guess is that it doesn't contain an integer and hence your error message.
If you want to get the length of any text file, you need to read every line in the file, find each's length and add them. It is easy to find the length of each line, because type line does have a 'length attribute, so the length of each line will be:
input_line'length
(Though note that the 'length attribute does not include the end-of-line character.) By the way, this line won't display what you've just read, because the read (if successful) is destructive:
writeline(output, input_line); -- optional, write to std out
(A "destructive read" is a read which removes the data as well as reading it.)

Why is there a space between the write statements in VHDL

In the following code after the second write statement there is a space inserted and I don't understand why
write(output_line,string'(" when x"""));
write(output_line,address_map(1 to address_count));
write(output_line,string'(""""));
I expect to get --- when x"adressmap" but instead receive -----when x"adressmap "
I do not want this extra space between the p and quotation mark any idea on why this is happening?
With this:
use std.textio.all;
entity foo is
end entity;
architecture fum of foo is
constant address_map: string := "address_map";
constant address_count: natural := address_map'LENGTH;
begin
process
variable output_line: line;
variable output_line_length: natural;
variable read_buff: string (1 to 80);
begin
write(output_line,string'(" when x"""));
write(output_line,address_map(1 to address_count));
write(output_line,string'(""""));
output_line_length := output_line'length;
read(output_line, read_buff(1 to output_line_length));
report "output_line = " & read_buff(1 to output_line_length);
wait;
end process;
end architecture;
I get:
% foo
foo.vhdl:21:9:#0ms:(report note): output_line = when x"address_map"
Which doesn't demonstrate the extra space in the quoted portion of string accessed to by output_line.
This tells us your extra space is coming from some declaration or statement you haven't provided. Your code isn't a Minimal, Complete, and Verifiable example.
It seems likely you're making a mistake with address_count in your actual code.
You could note providing an mcve would likely have pointed you to the discrepancy.

Is it possible to check the length of an input text file?

In my VHDL project, my input is going to be extracted from a text file containing n bits of 1's and 0's. I am trying to make it as general as possible. I am familiar with how to read and write on a text file using test-bench, but I don't know how to check its length.
My code normally takes 64 bit as input, pass them through all the blocks and generate an output. If the remaining bits length is less than 64 then it passes through a specific block.
Let's say the text file contains 1000 bits. 15 x 64 = 960. 960 bits will pass through all blocks, the remaining 40 will pass by a specific block. This looks straight forward but in order for me to do such operations i need to know the length of the text file. If anyone can help that would be very beneficial.
The VHDL data structure length should be considered, not the file length since that is implementation specific and not VHDL specified.
If the bits are in one long string that is to be chopped up into 64-bit pieces with a remainder, then the entire string can be read into a VHDL line type, and reading from that line to a std_logic_vector type can then depend on the remaining bits (characters) in the line.
Below is a code example doing so:
library ieee;
use std.textio.all;
use ieee.std_logic_textio.all; -- Synopsys package; required for VHDL-2002 only
architecture syn of tb is
begin
process is
variable myl_v : line;
file txt_file : text;
variable slv_v : std_logic_vector(63 downto 0);
begin
file_open(txt_file, "input.txt", read_mode);
readline(txt_file, myl_v);
while myl_v'length > 0 loop
if myl_v'length >= slv_v'length then -- Full slv_v
report "Full...: " & myl_v.all(1 to slv_v'length);
read(myl_v, slv_v);
else -- Reduced slv_v
report "Reduced: " & myl_v.all(1 to myl_v'length);
read(myl_v, slv_v(myl_v'length - 1 downto 0)); -- Place reduced at LSBs
end if;
end loop;
file_close(txt_file);
wait;
end process;
end architecture;
Btw, to answer the question of "length of an input text file", then the length in characters can be determined by reading as many characters from the file as possible, for example with code like:
impure function file_length_in_characters(filename : string) return natural is
type char_file_t is file of character;
file char_file : char_file_t;
variable char_v : character;
variable res_v : natural;
begin
res_v := 0;
file_open(char_file, filename, read_mode);
while not endfile(char_file) loop
read(char_file, char_v);
res_v := res_v + 1;
end loop;
file_close(char_file);
return res_v;
end function;

Does Quartus II support line.all?

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:
Supported. File I/O cannot be synthesized; therefore, calls to TEXTIO
functions are ignored.
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.

Resources