Reputation: 33
I am currently learning ROM modeling using VHDL. Right now, I've modeled a 32x8 ROM and I've instantiated it as an empty cons array on my main module because I plan to import a file through the test bench code that contains the data per line. My question is, after importing and reading a line from the file, how are you supposed to add this signal the ROM component? My current code for my testbench so far is as follows:
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use STD.textio.all;
use IEEE.STD_LOGIC_textio.all;
entity ROM_tb is
end;
architecture bench of ROM_tb is
component ROM
Port (
address : in STD_LOGIC_VECTOR (4 downto 0);
data : out STD_LOGIC_VECTOR(7 downto 0));
end component;
signal address: STD_LOGIC_VECTOR (4 downto 0);
signal data: STD_LOGIC_VECTOR(7 downto 0);
signal content : STD_LOGIC_VECTOR(7 downto 0); -- signal file content holder
-- file objects instantiation
file file_VECTORS : text;
begin
uut: ROM port map ( address => address,
data => data );
stimulus: process
--file objects declarations
variable f_LINE : line; -- file pointer
variable f_CONTENT : STD_LOGIC_VECTOR(7 downto 0); -- file content holder
variable f_i : INTEGER := 0; -- ROM MA location index
variable i : INTEGER := 0;
begin
file_open(file_VECTORS, "ROM-data.txt", read_mode);
while not endfile(file_VECTORS) loop
readline(file_VECTORS, f_LINE);
read(f_LINE, f_CONTENT);
content <= f_content;
--ROM(f_i) <= content; I was hoping to do something like this...
f_i := f_i + 1;
end loop;
while i < 32 loop
wait for 35 ns;
address <= conv_STD_LOGIC_VECTOR(i, 5);
i := i+1;
end loop;
wait;
end process;
end;
I instantiated the necessary file objects and processed a while loop which will read my 8-bit data per line. For every line, I plan to pass the variable content to a signal and have this signal store it to the ROM array and I am not sure how.
Upvotes: 1
Views: 911
Reputation:
Without the entity and architecture for ROM nor the contents of ROM_data.txt your question and answer can't be validated. Besides a "ROM" contained in an array of signal or variable values in the undisclosed ROM architecture any place a tool suite would allow you to provide the initial value of a RAM or value of ROM programmatically (e.g. Xilinx, not Intel) you could also use an impure function to provide the value of a constant of the array type in a declaration:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all; -- to_integer instead of std_logic_arith conv_integer
use ieee.math_real.all; -- for ceiling, log2
entity rom is -- generic ROM with std_logic_vector address and output
generic ( -- default values supplied for plugin to OPs usage
filename: string := "ROM_DATA.txt";
rom_width: natural := 8;
rom_depth: natural := 32
);
port (
address: in std_logic_vector
(integer(ceil(log2(real(rom_depth)))) - 1 downto 0);
data: out std_logic_vector (rom_width - 1 downto 0)
);
end entity;
architecture foo of rom is
type rom_array is array
(0 to rom_depth - 1) of std_logic_vector (rom_width - 1 downto 0);
impure function initromfromfile (romfilename: in string)
return rom_array is
use std.textio.all;
file romfile: text open read_mode is romfilename;
variable romfileline: line;
variable vrom: rom_array;
variable rom_value: bit_vector(7 downto 0);
begin
for i in vrom'range loop -- contents of file are ordered
if endfile(romfile) then -- file can be shorter than rom array
vrom(i) := (others => '0');
else
readline(romfile, romfileline); -- 1 datum per line
read(romfileline, rom_value);
vrom(i) := to_stdlogicvector(rom_value);
end if;
end loop;
return vrom;
end function;
constant romval: rom_array := initromfromfile(filename);
begin
data <= romval(to_integer(unsigned(address))); -- read
end architecture;
Here there are defaults for a generic ROM for width, depth and the initialization file name.
For a file ROM_DATA.txt:
11111110
11101101
11111010
11001110
11011110
10101101
10111110
11101111
that has fewer data values than the ROM array size the remaining values will be zero filled.
The initialization is performed in the declaration of the object holding the ROM value (and array type).
The functionality can be easily tested:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity rom_tb is
end entity;
architecture foo of rom_tb is
signal address: std_logic_vector (4 downto 0);
signal data: std_logic_vector (7 downto 0);
-- for IEEE Std 1076 revisions earlier than 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;
begin
ROM0:
entity work.rom -- no generic map and generic values will default
port map (
address => address,
data => data
);
ROM_DUMP:
process
begin
for i in 0 to 2 ** address'length - 1 loop
address <= std_logic_vector (to_unsigned(i, address'length));
wait for 0 ns; -- delta cycle for address to update
wait for 0 ns; -- delta cycle for data to update
report "rom(" & integer'image(i) & ") = " & to_string(data);
end loop;
wait;
end process;
end architecture;
When run:
ghdl -a rom.vhdl
ghdl -e rom_tb
ghdl -r rom_tb
../../src/ieee/v93/numeric_std-body.vhdl:2098:7:@0ms:(assertion warning): NUMERIC_STD.TO_INTEGER: metavalue detected, returning 0
rom.vhdl:80:13:@0ms:(report note): rom(0) = 11111110
rom.vhdl:80:13:@0ms:(report note): rom(1) = 11101101
rom.vhdl:80:13:@0ms:(report note): rom(2) = 11111010
rom.vhdl:80:13:@0ms:(report note): rom(3) = 11001110
rom.vhdl:80:13:@0ms:(report note): rom(4) = 11011110
rom.vhdl:80:13:@0ms:(report note): rom(5) = 10101101
rom.vhdl:80:13:@0ms:(report note): rom(6) = 10111110
rom.vhdl:80:13:@0ms:(report note): rom(7) = 11101111
rom.vhdl:80:13:@0ms:(report note): rom(8) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(9) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(10) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(11) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(12) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(13) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(14) = 00000000
rom.vhdl:80:13:@0ms:(report note): rom(15) = 00000000
...
rom.vhdl:80:13:@0ms:(report note): rom(31) = 00000000
You can see the ROM was initialized and available at time 0 (after elaboration).
The warning comes from address not having a default value that can be interpreted as a binary number (all 'U's) during initialization. Once address has been assigned the warning no longer occurs.
The use of IEEE package numeric_std instead of Synopsys package std_logic_arith keeps in mind the IEEE package is maintained (and expanded over revisions) while the Synopsys package is not.
The use of the variable of bit_vector allows the use std.standard.read without recourse to Synopsys package std_logic_textio.
IEEE Std 1076-2008 and later revisions provide a std_logic_1164 package that provides a READ procedure compatible with std_logic_vector subtypes as well as octal and hex read procedures. Revisions -2008 and later also provide predefined to_string functions for all single dimensional array types as well as IEEE packages numeric_std_unsigned supplanting Synopsys package std_logic_unsigned.
The generic rom entity declaration allows other sizes of ROM to be supported by providing values for the depth and width. The generic constant supplied for the filename allows multiple ROMs to be supported by using different file names.
There are several different ways of providing initial values to ROMs and RAMs available for the vhdl tag on Stackoverflow by search.
In general Read Only Memory (ROM) shouldn't be writable.
Upvotes: 1
Reputation: 33
I don't know if there are other ways but I solved my problem by just adding a r/w pin on my main module and just transferred contents from the testbench by having r/w on LOW, and do the reading on HIGH. Simple enough. I hope this helps future designers.
library IEEE;
use IEEE.Std_logic_1164.all;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
use STD.textio.all;
use IEEE.STD_LOGIC_textio.all;
entity ROM_tb is
end;
architecture bench of ROM_tb is
component ROM
Port (
rd : in STD_LOGIC;
data_in : in STD_LOGIC_VECTOR (7 downto 0);
address : in STD_LOGIC_VECTOR (4 downto 0);
data_out : out STD_LOGIC_VECTOR(7 downto 0));
end component;
signal rd: STD_LOGIC;
signal data_in: STD_LOGIC_VECTOR (7 downto 0);
signal address: STD_LOGIC_VECTOR (4 downto 0);
signal data_out: STD_LOGIC_VECTOR(7 downto 0);
signal content : STD_LOGIC_VECTOR(7 downto 0);
-- file objects instantiation
file file_VECTORS : text;
begin
uut: ROM port map (
rd => rd,
data_in => data_in,
address => address,
data_out => data_out );
stimulus: process
--file objects declarations
variable f_LINE : line;
variable f_CONTENT : STD_LOGIC_VECTOR(7 downto 0);
variable f_i : INTEGER := 0;
variable i : INTEGER := 0;
begin
file_open(file_VECTORS, "ROM_data.txt", read_mode);
while not endfile(file_VECTORS) loop
readline(file_VECTORS, f_LINE);
read(f_LINE, f_CONTENT);
content <= f_CONTENT;
rd <= '0';
data_in <= content;
address <= conv_STD_LOGIC_VECTOR(f_i, 5);
f_i := f_i + 1;
wait for 35 ns;
end loop;
while i < 32 loop
wait for 35 ns;
rd <= '1';
address <= conv_STD_LOGIC_VECTOR(i, 5);
i := i+1;
end loop;
wait;
end process;
end;
Upvotes: 0