I need to read a file in VHDL but there is an error:
"Line 57: Readline called past the end of file mif_file"
impure function init_mem(mif_file_name : in string) return mem_type is
file mif_file : text open read_mode is mif_file_name;
variable mif_line : line;
variable temp_bv : bit_vector(DATA_WIDTH-1 downto 0);
variable temp_mem : mem_type;
begin
for i in mem_type'range loop
readline(mif_file, mif_line);
read(mif_line, temp_bv);
temp_mem(i) := to_stdlogicvector(temp_bv);
end loop;
return temp_mem;
end function;
As stated in the comment section, you are trying to read more than you have in the file, you can avoid the error by checking if you reached the end of the file in your for loop and in that case assign a default value instead.
impure function init_mem(mif_file_name : in string) return mem_type is
file mif_file : text open read_mode is mif_file_name;
variable mif_line : line;
variable temp_bv : bit_vector(DATA_WIDTH-1 downto 0);
variable temp_mem : mem_type;
begin
for i in mem_type'range loop
if(not endfile(mif_file)) then
readline(mif_file, mif_line);
read(mif_line, temp_bv);
temp_mem(i) := to_stdlogicvector(temp_bv);
else
temp_mem(i) := default_value_to_be_defined;
end if;
end loop;
return temp_mem;
end function;
Or you can exit the for loop if you don't want to set a default value
impure function init_mem(mif_file_name : in string) return mem_type is
file mif_file : text open read_mode is mif_file_name;
variable mif_line : line;
variable temp_bv : bit_vector(DATA_WIDTH-1 downto 0);
variable temp_mem : mem_type;
begin
for i in mem_type'range loop
if(not endfile(mif_file)) then
readline(mif_file, mif_line);
read(mif_line, temp_bv);
temp_mem(i) := to_stdlogicvector(temp_bv);
else
exit;
end if;
end loop;
return temp_mem;
end function;
Related
In a VHDL testbench, I have a function that parses a csv file in order to initialize a test array.
When running the function in the elaboration phase to set the values of a constant, the function behaves differently than when using the same function in simulation (e.g. initializing a signal during a reset)
The function code is:
constant cn_DATA_WIDTH : natural := 10;
constant cn_DATA_DEPTH : natural := 400;
type tav_data_array is array (0 to cn_DATA_DEPTH - 1) of std_logic_vector(cn_DATA_WIDTH - 1 downto 0);
function f_init_data_from_file (
s_file_path : in string;
i_column_index : in integer := 0
) return tav_data_array is
-- file parsing
file f_data_file_buf : text is in s_file_path;
variable vl_data_file_line : line;
variable vi_data_entry : integer;
variable vc_comma : character;
variable vb_good_num : boolean;
-- destination
variable vav_data_array : tav_data_array;
begin
-- Skip first line that contains header
readline (f_data_file_buf, vl_data_file_line);
for line_index in vav_data_array'range loop
readline (f_data_file_buf, vl_data_file_line);
read (vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = 0"
severity failure;
for column_index in 1 to i_column_index loop
read(vl_data_file_line, vc_comma);
read(vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = " & integer'image(column_index)
severity failure;
end loop;
vav_data_array(line_index) := std_logic_vector(to_unsigned(vi_data_entry, cn_DATA_WIDTH));
end loop;
return vav_data_array;
end function;
Function usage in elaboration:
constant cav_data : tav_data_array :=
f_init_data_from_file (
s_file_path => "my_path" ,
i_column_index => 3
);
Result: The test array is not initialized with the expected data. The data used for the initialization is column 0 instead of column 3.
Function usage in elaboration:
signal sav_data : tav_data_array;
-- ...
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
sav_data <=
f_init_data_from_file (
s_file_path => "my_path" ,
i_column_index => 3
);
else
-- ...
end if;
end if;
end process;
In this case, the data used for initialization is the proper one. Column 3 is used as expected.
Is there a reason for this different behavior? Or is this a bug with the tools I am using for simulation (Xilinx Vivado 2018.2)?
EDIT to create MRVE:
As requested, this is a minimal reproducible example. Some of the parameters
Source code:
-- MRVE
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;
-- File parsing
use STD.textio.all;
use ieee.std_logic_textio.all;
entity file_bug_mrve is
end file_bug_mrve;
architecture a_file_bug_mrve of file_bug_mrve is
-- Actual data are 12 bits
constant cn_DATA_WIDTH : natural := 12;
constant cn_DATA_DEPTH : natural := 4; -- testbench is planned for 400 high priority cycles
type tav_data_array is array (0 to cn_DATA_DEPTH - 1) of std_logic_vector(cn_DATA_WIDTH - 1 downto 0);
-- Parse csv data file to retrieve all entries at specified columns
function f_init_data_from_file (
s_file_path : in string;
i_column_index : in integer := 0
) return tav_data_array is
-- file parsing
file f_data_file_buf : text is in s_file_path;
variable vl_data_file_line : line;
variable vi_data_entry : integer;
variable vc_comma : character;
variable vb_good_num : boolean;
-- destination
variable vav_data_array : tav_data_array;
begin
-- Skip first line
readline (f_data_file_buf, vl_data_file_line);
for line_index in vav_data_array'range loop
readline (f_data_file_buf, vl_data_file_line);
read (vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = 0"
severity failure;
for column_index in 1 to i_column_index loop
read(vl_data_file_line, vc_comma);
read(vl_data_file_line, vi_data_entry, vb_good_num);
assert vb_good_num
report "Failed reading file : " & s_file_path
& ", at line = " & integer'image(line_index)
& ", at column = " & integer'image(column_index)
severity failure;
end loop;
vav_data_array(line_index) := std_logic_vector(to_unsigned(vi_data_entry, cn_DATA_WIDTH));
end loop;
return vav_data_array;
end function;
constant cs_RSP_DATA_IN_FILE_PATH : string := "../../src/xls/file_bug_mrve.csv";
constant cn_RSP_DATA_IN_COLUMN_INDEX : natural := 3;
-- registers emulation
-- Setting init data to be processed in elaboration does not work
-- Data will be initialized with first column instead of third
signal sav_data : tav_data_array :=
f_init_data_from_file (
s_file_path => cs_RSP_DATA_IN_FILE_PATH ,
i_column_index => cn_RSP_DATA_IN_COLUMN_INDEX
);
-- infa Simulation
constant ct_CLOCK_PERIOD_100 : time := 10 ns;
constant ct_TEST_COMPLETION_TIME : time := ct_CLOCK_PERIOD_100 * 10;
signal s_clk : std_logic;
signal s_rst : std_logic;
signal sb_end : boolean := false;
begin
-- -----------------------------------------------------------------------------------------------------------------
-- Clock process definitions
-- -----------------------------------------------------------------------------------------------------------------
p_Clock_100 : process
begin
s_clk <= '0';
wait for ct_CLOCK_PERIOD_100/2;
s_clk <= '1';
wait for ct_CLOCK_PERIOD_100/2;
if sb_end then
wait;
end if;
end process;
-- -----------------------------------------------------------------------------------------------------------------
-- Main Stimulus process
-- -----------------------------------------------------------------------------------------------------------------
p_stimulous : process
begin
--
s_rst <= '0';
-- 1 clock cycle reset to avoid loading file multiple times
wait until rising_edge(s_clk);
s_rst <= '1';
wait until rising_edge(s_clk);
s_rst <= '0';
wait for ct_TEST_COMPLETION_TIME;
sb_end <= true;
end process;
p_main : process(s_clk)
begin
if rising_edge(s_clk) then
if s_rst = '1' then
-- Setting init data to be processed in simulation works
-- Data will be initialized with forth column as expected
sav_data <=
f_init_data_from_file (
s_file_path => cs_RSP_DATA_IN_FILE_PATH ,
i_column_index => cn_RSP_DATA_IN_COLUMN_INDEX
);
else
-- Nothing to do in MRVE
end if;
end if;
end process p_main;
end a_file_bug_mrve;
CSV file:
Ch0,Ch1,Ch2,Ch3
1,5,9,13
2,6,10,14
3,7,11,15
4,8,12,16
I am fairly new to VHDL and I am running some snippets from a code I was given to see what it is doing. There is a custom array type I want to see in the console, but I get and error when I try to write it.
entity hello_world is
end entity hello_world;
library STD;
library IEEE;
use IEEE.std_logic_1164.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
use IEEE.numeric_std.all;
architecture test of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
begin
my_print : process is
variable my_line : line;
begin
write(my_line, string'("Value of max_new"));
write(my_line, max_new);
writeline(output, my_line);
wait;
end process my_print;
end architecture test;
The error I get while running the simulation is:
Error: type error near 'max_new': expected type 'std_ulogic'. Error: formal 'l' of mode inout must have an associated actual. Error: formal 'value' has no actual or default value. Error: indexed name prefix type 'void' is not an array type
If I understood correctly, row type is an array of size 3, in each position I have a vector made of 4 bits. new_type is an array of size 2, in each position I have a row_type, which is an array of size 3 with a 4 bits vector in each position. Is this correct? Since it is initialized to 0, I expect to see only that.
I am using Vivado 2018.3 for the simulation.
Any help would be highly appreciated!
You could also author your own write procedure:
entity hello_world is
end entity hello_world;
-- library STD;
library IEEE;
use IEEE.std_logic_1164.all;
use STD.textio.all;
use IEEE.std_logic_textio.all;
-- use IEEE.numeric_std.all;
architecture test of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
procedure write (l: inout line; new_type_val: in new_type) is
begin
write (l, string'("("));
for i in new_type'range loop
write (l, string'("("));
for j in row_type'range loop
write (l, string'(""""));
write(l, new_type_val(i)(j));
write (l, string'(""""));
if j /= row_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
if i /= new_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
end procedure;
begin
my_print:
process is
variable my_line: line;
begin
write(my_line, string'("Value of max_new = "));
write(my_line, max_new);
writeline(output, my_line);
wait;
end process my_print;
end architecture test;
ghdl -r hello_world
Value of max_new = (("0000","0000","0000"),("0000","0000","0000"))
using preexisting write procedure overloads as building blocks.
You can also use type specific conversions to strings eliminating the dependence on Synopsys package std_logic_textio as well as introducing the ability to use report statements:
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
architecture no_std_logic_textio of hello_world is
type row_type is array(0 to 2) of std_logic_vector(3 downto 0);
type new_type is array(0 to 1) of row_type;
signal max_new : new_type := (others => (others => (others => '0')));
-- For VHDL version < -2008:
function to_string (inp: std_logic_vector) return string is
variable image_str: string (1 to inp'length);
alias input_str: std_logic_vector (1 to inp'length) is inp;
begin
for i in input_str'range loop
image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
end loop;
return image_str;
end function;
function to_string (nt: new_type) return string is
variable l: line;
begin
write (l, string'("("));
for i in new_type'range loop
write (l, string'("("));
for j in row_type'range loop
write (l, '"' & to_string(nt(i)(j)) & '"');
if j /= row_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
if i /= new_type'right then
write(l, string'(","));
end if;
end loop;
write (l, string'(")"));
return l.all;
end function;
begin
my_print:
process is
variable my_line: line;
begin
write (my_line, string'("value of max_new = "));
write(my_line, to_string(max_new));
writeline(output, my_line);
report LF & HT & "max_new = " & to_string(max_new);
wait;
end process my_print;
end architecture no_std_logic_textio;
And this demonstrates both writing to output and a report statement:
ghdl -r hello_world
value of max_new = (("0000","0000","0000"),("0000","0000","0000"))
hello_world.vhdl:95:9:#0ms:(report note):
max_new = (("0000","0000","0000"),("0000","0000","0000"))
The function write of std.textio can take the following arguments as value (https://www.hdlworks.com/hdl_corner/vhdl_ref/VHDLContents/TEXTIOPackage.htm) :
bit
bit_vector
boolean
character
integer
real
string
time
IEEE.std_logic_textio add std_logic and his derivated to this list but Array is not handled by write.
You can print your array like that :
my_print : process is
variable my_line : line;
begin
write(my_line, string'("Value of max_new"));
for I in 0 to 1 loop
for J in 0 to 2 loop
write(my_line, max_new(I)(J));
end loop;
end loop;
writeline(output, my_line);
wait;
end process my_print;
In Verilog, I can check if a file exists by opening the file and then checking if the file descriptor is zero, and if it is not to assume the file doesn't exist. For example, as follows:
module testbench;
function file_exists;
input [80*8:0] filename;
integer file;
integer error;
begin
file = $fopen(filename, "r");
if (!file) begin
$display("\nFile Open Failed with Error Code = %x", error);
file_exists = 0;
end
else begin
$fclose(file);
file_exists = 1;
end
end
endfunction
integer x;
initial begin
x = file_exists("sdfsdf.txt");
$display("x: %0b", x);
end
endmodule
How can I do the same thing in vhdl?
When you open a file, for example:
file_open(status, file_handle, “my_file.txt”, read_mode);
You get a status of type file_open_status. It can have a number of values: open_ok, status_error, name_error and mode_error. You'll get name_error if the file isn't found
use ieee.std_logic_1164.all;
use std.textio.all;
entity testebench is
end entity;
architecture sim of testbench is
impure function file_exists(
filename : in string
) return boolean is
variable open_status :FILE_OPEN_STATUS;
file infile :text;
begin
file_open(open_status, infile, filename, read_mode);
if open_status /= open_ok then
return false;
else
file_close(infile);
return true;
end if;
end function;
begin
process
f1 :boolean;
begin
f1 = file_exists("fgsfgsdfg.txt")
report "found: " & boolean'image(f1);
end process;
end architecture;
is it possible to write a module code for a test bench? I have a test bench code that reads a text file and shows it in the Isim but I want to put this data on a port and process it. how can I get it out of simulation environment? how can I write a module for that in VHDL? thank you
, the code is here:
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
use STD.textio.all; --Dont forget to include this library for file operations.
ENTITY read_file IS
END read_file;
ARCHITECTURE beha OF read_file IS
signal bin_value : std_logic_vector(2 downto 0):="000";
BEGIN
--Read process
process
file file_pointer : text;
variable line_content : string(1 to 3);
variable line_num : line;
variable j : integer := 0;
variable char : character:='0';
begin
--Open the file read.txt from the specified location for reading(READ_MODE).
file_open(file_pointer,"C:\read.txt",READ_MODE);
while not endfile(file_pointer) loop --till the end of file is reached continue.
readline (file_pointer,line_num); --Read the whole line from the file
--Read the contents of the line from the file into a variable.
READ (line_num,line_content);
--For each character in the line convert it to binary value.
--And then store it in a signal named 'bin_value'.
for j in 1 to 3 loop
char := line_content(j);
if(char = '0') then
bin_value(3-j) <= '0';
else
bin_value(3-j) <= '1';
end if;
end loop;
wait for 10 ns; --after reading each line wait for 10ns.
end loop;
file_close(file_pointer); --after reading all the lines close the file.
wait;
end process;
end beha;
I've written a simple function which does log2 computation of any integer number and then "ceils" it to the next integer:
function log2ceil(intVal: integer) return natural is
variable i : natural;
variable bitCount : natural;
begin
i := (intVal - 1);
bitCount := 0;
while (i > 0) loop
bitCount := bitCount + 1;
i:=shiftRightInt(i,1);
end loop;
return bitCount;
end log2ceil;
function shiftRightInt(ValueToShift: integer; NrToShift:natural) return integer is
begin
return to_integer(shift_right(to_unsigned(ValueToShift, 32), NrToShift));
end shiftRightInt;
Works, fine. The problem is with the simulation. Every time I try to simulate it with a simple function call in a test bench:
stim: process
begin
wait for 10 ns;
log2ceil(3);
wait;
end process;
it gives me following error:
ERROR: [VRFC 10-1472] type error near log2ceil ; expected type void
Why does it expect type Void? And how can I avoid getting this error?
Your tool isn't giving a very helpful error message. The problem is that you are referencing a function in log2ceil that has not yet been declared. Given the order you define things, shiftRightInt isn't visible yet.
When I compile your code with Modelsim, I get:
`
(vcom-1136) Unknown identifier "shiftRightInt".
Edit: After including your process I got the error #user1155120 pointed out. In Modelsim:
No feasible entries for subprogram "log2ceil".
As user1155120 noted, you are calling a function in a procedure context. You need to assign the return value to something.
First, you can swap the order of declarations. I.e.:
function shiftRightInt(ValueToShift: integer; NrToShift:natural) return integer is
begin
return to_integer(shift_right(to_unsigned(ValueToShift, 32), NrToShift));
end shiftRightInt;
function log2ceil(intVal: integer) return natural is
variable i : natural;
variable bitCount : natural;
begin
i := (intVal - 1);
bitCount := 0;
while (i > 0) loop
bitCount := bitCount + 1;
i:=shiftRightInt(i,1);
end loop;
return bitCount;
end log2ceil;
The other is to define a "prototype" of shiftRightInt:
function shiftRightInt(ValueToShift: integer; NrToShift:natural) return integer;
function log2ceil(intVal: integer) return natural is
variable i : natural;
variable bitCount : natural;
begin
i := (intVal - 1);
bitCount := 0;
while (i > 0) loop
bitCount := bitCount + 1;
i:=shiftRightInt(i,1);
end loop;
return bitCount;
end log2ceil;
function shiftRightInt(ValueToShift: integer; NrToShift:natural) return integer is
begin
return to_integer(shift_right(to_unsigned(ValueToShift, 32), NrToShift));
end shiftRightInt;
The code:
stim: process
begin
wait for 10 ns;
log2ceil(3);
wait;
end process;
is describing a procedure call, but log2ceil is a function. Procedures have a return type of void, whereas your function returns an integer.
You need to provide a dummy variable to collect the return value:
stim: process
variable dummy : natural;
begin
wait for 10 ns;
dummy := log2ceil(3);
wait;
end process;
The error message is a bit cryptic, but correct!