I am trying read a text file line by line in clock event to output. But my code just reads the first element in every clock! Where is the problem?
entity filter_tb is
PORT( clk : IN std_logic;
filter_out : OUT real
);
end filter_tb;
architecture filter_tb of filter_tb is
begin
process(clk)
file file_pointer : text;
variable line_content : real;
variable line_num : line;
begin
file_open(file_pointer,"myFile.txt",READ_MODE);
readline(file_pointer, line_num);
read(line_num, line_content);
filter_out <= line_content;
file_close(file_pointer);
end process;
end filter_tb;
myFile.txt:
0.0000000e+00
5.8778525e-01
9.5105652e-01
9.5105652e-01
5.8778525e-01
1.2246468e-16
There are some context clause elements in the root declarative region missing as well as the means to exercise the design model:
library ieee;
use ieee.std_logic_1164.all;
use std.textio.all;
entity filter_tb is
You need to only open and close the file once. This of it as phases: open the file, read data once per clock, when no more data close the file and suspend the process until the end of simulation.
architecture filter_tb of filter_tb is
begin
process -- (clk) -- process now contains wait statement
constant filename: string := "myFile.txt"; -- use more than once
file file_pointer: text;
variable line_content: real;
variable line_num: line;
variable filestatus: file_open_status;
begin
file_open (filestatus, file_pointer, filename, READ_MODE);
report filename & LF & HT & "file_open_status = " &
file_open_status'image(filestatus);
assert filestatus = OPEN_OK
report "file_open_status /= file_ok"
severity FAILURE; -- end simulation
while not ENDFILE (file_pointer) loop
wait until falling_edge(clk); -- once per clock
readline (file_pointer, line_num);
read (line_num, line_content);
filter_out <= line_content;
end loop;
wait until falling_edge(clk); -- the last datum can be used first
file_close (file_pointer);
report filename & " closed.";
wait;
end process;
end architecture filter_tb;
This uses a different file_open
procedure call that also assigns a file_open_status
variable when when reported would make it obvious you were opening the file repetitively.
After there are no more lines to be read the file will be closed. Note the wait statement waiting on a clock edge event in the loop statement, which will read one datum per clock.
The final wait statement suspends the process for the remainder of the simulation.
With top level ports we can add an enclosing testbench:
library ieee;
use ieee.std_logic_1164.all;
entity tb_filter_tb is
end entity;
architecture foo of tb_filter_tb is
signal clk: std_logic := '0';
signal filter_out: real;
begin
DUT:
entity work.filter_tb
port map (
clk => clk,
filter_out => filter_out
);
CLOCK:
process
begin
wait for 5 ns;
clk <= not clk;
if now > 90 ns then
wait;
end if;
end process;
MONITOR:
process
begin
wait until falling_edge(clk);
wait for 0 ns;
report "filter_out = " & real'image(filter_out);
end process;
end architecture;
The monitor process can report the values of filter_out on every active clock edge:
ghdl -r tb_filter_tb filter_tb.vhdl:25:13:@0ms:(report note): myFile.txt file_open_status = open_ok filter_tb.vhdl:80:9:@10ns:(report note): filter_out = 0.0 filter_tb.vhdl:80:9:@20ns:(report note): filter_out = 5.8778525e-1 filter_tb.vhdl:80:9:@30ns:(report note): filter_out = 9.5105652e-1 filter_tb.vhdl:80:9:@40ns:(report note): filter_out = 9.5105652e-1 filter_tb.vhdl:80:9:@50ns:(report note): filter_out = 5.8778525e-1 filter_tb.vhdl:80:9:@60ns:(report note): filter_out = 1.2246468e-16 filter_tb.vhdl:42:9:@70ns:(report note): myFile.txt closed. filter_tb.vhdl:80:9:@70ns:(report note): filter_out = 1.2246468e-16 filter_tb.vhdl:80:9:@80ns:(report note): filter_out = 1.2246468e-16 filter_tb.vhdl:80:9:@90ns:(report note): filter_out = 1.2246468e-16
until simulation ends.