TYPE dram_array IS array( 0 to 1048576) OF std_logic_vector(15 downto 0);
read_write : PROCESS (mode)
VARIABLE memory : dram_array;
VARIABLE index : integer := 0;
VARIABLE input_reg : std_logic_vector(15 downto 0);
VARIABLE output_reg : std_logic_vector(15 downto 0);
index := to_unsigned(address);
IF mode = read THEN
output_reg(15 downto 0) <= memory(index)(15 downto 0);
ELSIF mode = write THEN
memory(index)(15 downto 0) := input_reg(15 downto 0);
END IF;
END PROCESS read_write;
Note: I have very little VHDL programming experience, so please bear with me
if my terminology is incorrect.
I currently have a test bench program that is separate from my main functional
VHDL program. My test bench program reads a test vector file and supplies the
input signals (address, data, enables, etc) to my main functional program. I
would like to be able to read an initialization file with the test bench
program and somehow initialize the memory variable.
I know that global variables are not allowed in VHDL, so I would like to know
if anyone has any suggestions on how I might accomplish this task.
Thanks in advance,
Derek
>Subject: How can I initialize variable in VHDL?
>From: dm...@hp.memh.ti.com (Derek May)
>Date: 14 Jul 1995 20:48:02 GMT
First let me point out that your memory will consume approx 16M (16
milliion) bytes of memory. This
is likely to cause performance problems in just about every VHDL
simulator. Unless you really need
to store 'X's and 'Z's in each memory location, you might consider using
an array of integers to store
the memory contents. This will reduce the memory requirements of the
simulator by a factor of four.
It also simplifies initializing the memory from a file.
To initialize the memory write a procedure that will open a file and read
a memory address and value
on each line and place it in the memory. Something like this:
procedure load( mem : inout dram_array; fn : in string ) is
variable l : line;
file fp : text is in fn;
variable addr : integer;
variable data : integer;
begin
while not endfile(fp) loop
readline(l, fp);
read(addr, l);
read(data, l);
mem(addr) := data;
end loop;
end procedure;
The file contents would then look something like this:
0 10
1 65443
2 3373
3 1245
100 8989
etc.
This is a very simple approach. More sophisticated methods are possible.
As for using an integer memory, the read_write process would only need a
couple of small changes.
You need to add a type conversion when reading or writing the memory.
I'll leave the bodies of these
functions as an exercise to the user. Here is where they go:
TYPE dram_array IS array( 0 to 1_048_576) OF integer;
function toInteger ( sv : std_logic_vector ) return integer;
function toSLV ( i : integer ) return std_logic_vector;
read_write : PROCESS (mode)
VARIABLE init : boolean := FALSE;
VARIABLE memory : dram_array;
VARIABLE index : integer := 0;
VARIABLE input_reg : std_logic_vector(15 downto 0);
VARIABLE output_reg : std_logic_vector(15 downto 0);
begin
IF init THEN
index := to_unsigned(address);
IF mode = read THEN
output_reg(15 downto 0) <= toSLV( memory(index) );
ELSIF mode = write THEN
memory(index) := toInteger( input_reg );
END IF;
ELSE
load( memory, "memdata.dat" );
init := TRUE;
END IF;
END PR
Enclosed is a memory model extracted from the testbench chapter (p. 254)
of my book "VHDL Coding Styles and Methodologies", Kluwer Academics.
It is close to your model, and demonstrates how a memory can be
initialized from a file. The model includes a package for the type
conversion (character to Std_Logic).
Of course, this presents one solution of the many possible solutions .
--------------------------------------------------------------------------
-----
-- Title : Memory Component
-- Description : Model a memory which is initialized by a file.
-- Memory Operation: Memory is initialized at startup from
-- file "memdata.txt.
--
-- READ <- write at this edge
--
-- RdWrF --------+ +------
-- +______+
--
-- CeF ---+ +---+ +------
-- +--+ +-------+
--------------------------------------------------------------------------
-----
-- Revisions :
-- Date Author Revision Comments
-- Sun Dec 11 12:24:46 1994 cohen Rev A Creation
--------------------------------------------------------------------------
-----
library IEEE;
use IEEE.Std_Logic_1164.all;
package Mem_Pkg is
constant DataWidth_c : natural; -- Data width
constant AddrWidth_c : natural; -- Address width
constant MaxDepth_c : natural;
function CharToStd(Char_v : character) return Std_Logic;
end Mem_Pkg;
package body Mem_Pkg is
constant DataWidth_c : natural := 8; -- deferred constant
constant AddrWidth_c : natural := 16; -- Address width
constant MaxDepth_c : natural := 2 ** AddrWidth_c; -- 64K
function CharToStd(Char_v : character) return Std_Logic is
begin
case Char_v is
when '1' => return '1';
when '0' => return '0';
when others =>
return '0';
assert false
report "Input Character is NOT a 1 or 0"
severity warning;
end case; -- Char_v
end CharToStd;
end Mem_Pkg;
library IEEE; -- used because Std_Logic
use IEEE.Std_Logic_1164.all; -- signals are resolved
library ATEP_Lib;
use ATEP_Lib.Mem_Pkg.all;
use ATEP_Lib.Mem_Pkg;
entity Memory_Nty is
generic (FileName_g : String(1 to 12):= "memdata_.txt");
port(
MemAddr : in natural;
MemData : inout Std_Logic_Vector(Mem_Pkg.DataWidth_c - 1 downto
0);
RdWrF : in Std_Logic;
CeF : in Std_Logic); -- Chip Select
end Memory_Nty;
architecture Memory_a of Memory_Nty is
begin -- Memory_a
Memory_Lbl : process(MemAddr, MemData, RdWrF, CeF)
use Std.TextIO.all; -- localize TextIO to this process
use Std.TextIO;
subtype Data_Typ is
Std_Logic_Vector(Mem_Pkg.DataWidth_c - 1 downto 0);
subtype MemSize_Typ is integer range 0 to Mem_Pkg.MaxDepth_c - 1;
type Mem_Typ is array(MemSize_Typ) of Data_Typ;
variable Memory_v : Mem_Typ;
variable Initialization_v : boolean := true;
file MemData_f : TextIO.text is in FileName_g;
procedure MemoryData -- Preload memory from a file, VHDL'87
(variable FileName_v : in TextIO.text;
variable Memory_v : inout Mem_Typ) is
variable InLine_v : TextIO.line;
variable MemAddress_v : MemSize_Typ := 0; -- 0 to 64k
variable Word_v : Data_Typ;
variable WordIndex_v : natural;
begin
File_Lbl : while not TextIO.Endfile(MemData_f) loop
-- Read 1 line from the input file
TextIO.ReadLine(MemData_f, InLine_v);
-- Test if InLine_v is an empty line,
next File_Lbl when InLine_v'length = 0; -- null line
if InLine_v'length < DataWidth_c then -- error
assert false
report "Data width in file is less than defined width"
severity warning;
next File_Lbl;
-- detect lines of 80 characters with spaces
elsif InLine_v(DataWidth_c) = ' ' then -- error
assert false
report "Data width in file is less than defined width"
severity warning;
next File_Lbl;
end if;
-- Read a data word
WordIndex_v := InLine_v'left;
-- Convert characters to Std_Logic and fill a data word
LoadWord_Lbl : for W_i in Mem_Pkg.DataWidth_c - 1 downto 0 loop
Word_v(W_i) := Mem_Pkg.CharToStd(InLine_v(WordIndex_v));
WordIndex_v := WordIndex_v + 1;
end loop LoadWord_Lbl;
-- Store word in memory and increment address index
Memory_v(MemAddress_v) := Word_v;
MemAddress_v := MemAddress_v + 1;
end loop File_Lbl;
end MemoryData;
begin -- process Memory_Lbl
-- Load memory if in initialization
if Initialization_v then
MemoryData(FileName_v => MemData_f,
Memory_v => Memory_v);
Initialization_v := false;
end if;
-- Normal operation
if CeF = '0' then -- memory transaction
if RdWrF'event and
RdWrF'last_value = '0'and -- positive transition
RdWrF = '1' then -- of RdWrF
Memory_v(MemAddr) := MemData; -- WRITE OPERATION
elsif RdWrF = '1' then -- memory read
MemData <= Memory_v(MemAddr);
end if;
else
MemData <= (others => 'Z');
end if;
end process Memory_Lbl;
end Memory_a;
-- Example of data in "memdata.txt"
10000000
1111000
01001101 -- Only 1st 8 characters are read
10101001
11111
00000000
10000000
11110000
01001101
-- If line is less than 8 characters (in this case), then its an error.