Here is a simple example function that reads a *.hex file from disk and initializes a RAM.
A hex file stores one RAM word per line in hexadecimal encoding (ASCII chars: 0-9, A-F, a-f)
At first a memory needs to be defined by word_t
and ram_t
. The generics or constants DATA_BITS and DEPTH define the memory layout:
subtype word_t is std_logic_vector(DATA_BITS - 1 downto 0);
type ram_t is array(0 to DEPTH - 1) of word_t;
Secondly, a function is defined to read a file and return a initialization vector:
-- Read a *.hex file
impure function ocram_ReadMemFile(FileName : STRING) return ram_t is
file FileHandle : TEXT open READ_MODE is FileName;
variable CurrentLine : LINE;
variable TempWord : STD_LOGIC_VECTOR((div_ceil(word_t'length, 4) * 4) - 1 downto 0);
variable Result : ram_t := (others => (others => '0'));
begin
for i in 0 to DEPTH - 1 loop
exit when endfile(FileHandle);
readline(FileHandle, CurrentLine);
hread(CurrentLine, TempWord);
Result(i) := resize(TempWord, word_t'length);
end loop;
return Result;
end function;
A signal for the RAM is defined and initialized:
signal ram : ram_t := ocram_ReadMemFile(FILENAME);
This example should work in all simulators and in Xilinx ISE in synthesis, too. If you need a synthesizable example for Altera altsyncram, have a look at the complete files in our PoC-Library.
For example PoC.mem.ocram.tdp (true dual port memory).
No. Your testbench isn't correct.
You have two superfluous use clauses:
-- use ieee.numeric_std.all;
-- use ieee.std_logic_misc.all;
Your process tb_process
should have wait;
end loop;
allowing the simulation to complete when you've finished processing input stimulus from my_input.txt
.
About then you'll notice all your results in my_output.txt
are all 0
, which is caused by delta cycle delay in assignment to signal z_tb
in entity my_and
. Your process also has delayed assignments to x_tb
and y_tb
which need to be taken into account.
No signal update occurs during the execution of any process (and all signal updates occur within processes, concurrent statements are elaborated into process statements or process statements and block statements). Essentially you need to suspend the process before any of these assignments take effect.
The cure is one or more wait statements which will suspend execution. The following shows two, a wait for 5 ns;
and a wait for 0 ns;
. They can be collapsed in to one wait statement. The purpose is to show that you need at least a delta cycle delay following assignments to x_tb
and y_tb
taking effect for z_tb
to be updated. If there were a delayed signal assignment for z
(z_tb
) in entity my_and
that delay would also be added to the first wait statement.
tb_process:
process
file my_input: TEXT open READ_MODE is "my_input.txt";
file my_output: TEXT open WRITE_MODE is "my_output.txt";
variable my_line: LINE;
variable my_input_line: LINE;
variable my_output_line: LINE;
variable x_bit: bit;
variable y_bit: bit;
variable z_bit: bit;
begin
while not endfile(my_input) loop
readline(my_input,my_line);
read(my_line,x_bit);
read(my_line,y_bit);
x_tb <= to_stdulogic(x_bit) after 5 ns;
y_tb <= to_stdulogic(y_bit) after 5 ns;
wait for 5 ns; -- added
wait for 0 ns; -- added
z_bit := to_bit(z_tb);
-- report "x_bit = " & bit'image(x_bit);
-- report "y_bit = " & bit'image(y_bit);
-- report "z_tb = " & std_ulogic'image(z_tb);
write(my_output_line,z_bit);
writeline(my_output,my_output_line);
-- wait for 10 ns; -- removed
end loop;
wait;
end process;
Note the wait for 10 ns;
is commented out, it's not needed when your process has a linear model of time allowing signal assignments to take affect (has (an) other wait statement(s)).
The above modification to your process statement with a zero delay model for my_and
gives:
more my_output.txt
0
0
0
1
Which is the expected output.
Notice the commented report statements which can be used to debug the process statement. If you don't have enough delay the first report for z_tb
will show a 'U'
.
Best Answer
Not surprisingly,
readline
reads one line of text and stores it into the variable you confusingly namedline_num
. Your input file seem to have only one line of text, which starts with1
.read
is called with aline_content
output argument which is a single character, so it reads the first character of the line and outputs it inline_content
. That's why you only see a single1
in the output.You have to split your input file into multiple lines (each containing a single character). Alternatively, you can make a single call to
readline
and then iterate through yourline_num
variable by callingread
on it multiple times.In any case, rename
line_num
toline_buf
or something similar. It looks confusing, especially side by side withline_content
, which doesn't hold the line contents as its name advertises.