# VHDL: reading integers from a text file, storing them in array, and writing in text format again

In a certain simulation testbench using questasim, I am trying to read the files with integers numbers which looks like,

0000
0001
0005
3864
2290
1234
.
.
.
0002
0004
0006
4532
3457
.
.
.


My aim here is to read the text file, store first few numbers in an array of integers and write that array in text output, my attempted code looks like,

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_textio.all;
use std.textio.all;

entity HFA_tb is
end HFA_tb;

architecture behave of HFA_tb is

--clock 100 MHz change to any value suitable
constant c_CLOCK_PERIOD : time:= 100 ns;
signal r_CLOCK      : std_logic  := '0';
--**signal r_ENABLE     : std_logic  := '0';
signal r_hitstart   : integer;   ---output of single threshold
signal r_hitend     : integer;
signal r_hitpeak    : integer;
signal r_peaktime   : integer;
signal r_hitsum     : integer;
signal r_opready    : std_logic := '0';

--more signal

--describe HFA component here (Unit Under Test)

component HFA is
port (
clk          : in std_logic;
hitstart_o   : out integer;   ---output of single threshold
hitend_o     : out integer;
hitpeak_o    : out integer;
peaktime_o   : out integer;
hitsum_o     : out integer;

);
end component HFA;

begin

--Instatiate the unit under test
UUT : HFA
port map (
clk         => r_CLOCK,
hitstart_o  => r_hitstart,
hitend_o    => r_hitend,
hitpeak_o   => r_hitpeak,
peaktime_o  => r_peaktime,
hitsum_o    => r_hitsum,
);

p_CLK_GEN : process is
begin
wait for c_CLOCK_PERIOD/2;
r_CLOCK <= not r_CLOCK;
end process p_CLK_GEN;

--main testing logic for reading from text file; feed in the loop and     check output

process
file in_buffer       :   text;
file out_buffer      :   text;
variable v_ILINE     :   line;
variable v_OLINE     :   line;
variable line_counter :  integer :=0;
variable block_length :  integer :=0;
variable block_counter : integer :=0;
type header is array (0 to 2) of integer;

begin

file_open(out_buffer,"/home/eu18461/Data/DUNE/QuestaSim_Examples/HFA_test4_SliceTest/results.txt",write_mode);

while not endfile(in_buffer) loop
if line_counter=0 then
f1 : for k in 0 to 2 loop
line_counter := line_counter+1;
end loop f1;
end if;

if line_counter /= 2 and block_length /= 9 then
f2 : for k in 0 to 2 loop
line_counter := line_counter+1;
block_length := block_length+1;
end loop f2;
end if;

if block_length=9 then
f3 : for k in 0 to 2 loop
line_counter := line_counter+1;
block_length := 0;
exit;
end if;
end loop f3;
end if;

wait for c_CLOCK_PERIOD;

end loop;

if endfile(in_buffer) then

write(v_OLINE, string'("hit_start_time"));
writeline(out_buffer, v_OLINE);

write(v_OLINE, r_hitstart);
writeline(out_buffer, v_OLINE);

end if;

wait for c_CLOCK_PERIOD;

file_close(in_buffer);

file_close(out_buffer);

wait;

end process;
end behave;


Updated the code, my desired output text should look like,

 Int1 int2 int3 Op1 op2 op3 Op3 ...
Int11 int12 int13 op1 op2 op3 ...
.
.
.
Intx inty intZ op1 op2 op3 ...


Here int1, Int2 ...etc represent the integers from the input text file, these no. goes upto a fixed block length. I want to store them, and send the remaining integers to my processing block, after the process I want the output in row format as shown in the text file and again repeat the process. Any hints will be much appreciated. Here the for loop no. indicate the integers storing length and block length after which the process i s repeated.

• Do we really need to could lines here ... Where is line 107? Dec 18 '18 at 22:21
• I have altered the code now. Dec 20 '18 at 20:35

Wish I could comment, b/c there are a lot of syntactical issues here.

You defined a type called H and then tried to assign something to the type: H(0) := v_adcValue which is illegal and may explain the first part of the error. You must define the type and then declare a variable or signal of the defined type, which can then receive assignment.

It looks like you may have meant to declare a signal called header of type H, based on this line: header(k) <= v_adcValue, but the declaration of header is missing. Or perhaps you removed it, as suggested by:

** Error: (vcom-1583) Illegal type converson from 'std.STANDARD.INTEGER' to 'header' (numeric to array).

You're also trying to use to_string() on the non-existent signal header. The function is overloaded for many built-in types as of VHDL-2008, but not user-defined types, like an array of integers.

Your MONITOR process has no wait statement. It will execute immediately at the start of sim and create an infinite loop. It needs something to trigger it periodically, otherwise your simulation will be stuck executing that process continually and never advance past a delta cycle until it hits the iteration limit.

EDIT

You could write the first values directly to the output line as they are read in. This will preserve the 4 digit padding format your input file has. Note - I added another line variable called temp to the file process:

...

if line_counter=0 then
v_OLINE := new string'(""); --Needs to be initialized
f1 : for k in 0 to 2 loop
temp := new string'(v_ILINE.all&" "); --Create new line with added space
v_OLINE := new string'(v_OLINE.all&temp.all); --Concatenate new line to existing
line_counter := line_counter+1;
end loop f1;
...


If you then output the line (after loop f1):

    v_OLINE := new string'(v_OLINE(1 to v_OLINE'length-1)); --Remove ending space
writeline(out_buffer,v_OLINE);


then, for input of:

0000
0001
0005

0000 0001 0005

Of course, you'll want to wait to write that line to file until you get back the values from your other process. After your wait for c_CLOCK_PERIOD;, you would simply write another loop for putting your additional data into the output line before writing to file.

You'll need another array in addition to H for your secondary chunk of integers from the input file, and for the processed data to be written out. Since you're processing that data elsewhere, I recommend making these arrays signals rather than variables.

If you need to output your processed data with 4-wide fields (like '0000', '0002', etc), you can define a string variable, "zeros", of length 4 in your file process to help pad your values:

-- "proc_data" is your processed data array
for k in 0 to <needed_length> loop
zeros := (others=>'0');
zeros(zeros'length-integer'image(proc_data(k))'length+1 to zeros'length) := integer'image(proc_data(k));
write(v_OLINE,zeros);
write(v_OLINE,string'(" "));
end loop;
v_OLINE := new string'(v_OLINE(1 to v_OLINE'length-1)); --Remove ending space
writeline(out_buffer,v_OLINE);


Be sure none of your processed integers are longer then 4, or you'll get a length mismatch. Or just adjust zeroes to the max. length needed.

This is about all I can suggest. You'll have to work out the details on how many loop iterations you need for your data, etc, but this should give you enough.

• Thanks, I very much appreciate your response. The code is now compiling successfully. Any hints to get my desired output.txt will be really useful. Cheers! Dec 20 '18 at 20:36
• Updated my answer. Dec 21 '18 at 22:48