(e-mail address removed) (jack kilby) wrote:
:I have a array (ROM with 32 bits columns and 128 rows)in my VHDL code
:and need to give the values to it through test bench.(from a Textio
:file)
: Does anybody know how to do it for a ROM block.Thanks in advance
Here's a package to read Motorola S-records into a memory (assumed to
be a shared variable). Usual disclaimers apply:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
library std;
use std.textio.all;
package memory is
-- Memory array which can be loaded/dumped to files
type T_MEMARRAY is array(natural range <>, natural range <>) of
std_logic;
procedure load_memory ( -- Load from Motorola
S-records
constant FNAME : in string; -- File name
variable MEMORY : inout T_MEMARRAY); -- Memory array
procedure clear_memory (
variable MEMORY : out T_MEMARRAY); -- Memory array
end memory;
-------------------------------------------------------------------
package body memory is
subtype T_8B is unsigned(7 downto 0);
constant f_void : natural := 16#101#; -- Null input line
constant f_error : natural := 16#102#; -- Input-error flag
constant f_eof : natural := 16#103#; -- Input EOF flag
constant maxlen : natural := 32; -- Max. data bytes in
S-record
type hexdata is array(0 to maxlen-1) of T_8B;
type hex_rec is record
locn : natural; -- Memory start address
size : natural; -- Byte count
data : hexdata; -- Byte data
end record;
procedure getbyte( -- Get next byte from line
data : inout line; -- Line to read from
csum : inout natural; -- Checksum
ans : out natural -- Byte value
);
procedure gethexline( -- Read a Motorola S-record
file infile : text; -- File to read
ans : out hex_rec; -- Decoded record
LINUM : inout natural -- Line counter
);
-- purpose: Load memory array from Motorola S-records
procedure load_memory (
constant FNAME : in string; -- File name
variable MEMORY : inout T_MEMARRAY) is
file ROMDAT : text open read_mode is FNAME;
variable XREC : hex_rec; -- Decoded line from file
variable LINUM : natural; -- Line count
variable ONEB : T_8B; -- Byte from file
variable WIDTH, HEIGHT, NBYTES : natural;
variable CLIN, BITO : natural;
begin -- load_memory
WIDTH := MEMORY'length(2); -- Get array dimensions
HEIGHT := MEMORY'length(1);
NBYTES := (WIDTH/8)*HEIGHT;
LINUM := 0;
while not endfile(ROMDAT) loop
gethexline(ROMDAT, XREC, LINUM); -- Process one line
case XREC.size is
when f_void => -- Skip this line
next;
when f_eof =>
exit; -- Done with it
when f_error =>
assert false
report "Error in " & FNAME & ": line " &
natural'image(LINUM)
severity error;
when others => -- Process the data
assert (XREC.locn + XREC.size <= NBYTES)
report "Address over-range in " & FNAME & ": line " &
natural'image(LINUM)
severity warning;
for i in XREC.size-1 downto 0 loop -- Copy in data
ONEB := XREC.data(i);
CLIN := (XREC.locn+i)/(WIDTH/8); -- Cache line / memory
locn.
BITO := 8*((XREC.locn+i) mod (WIDTH/8)); -- Bit offset
for j in ONEB'range loop
MEMORY(CLIN, BITO+j) := ONEB(j);
end loop; -- j
end loop; -- i
end case;
end loop;
end load_memory;
-----------------------------------------------------------------------
-- purpose: Clear memory contents to zero
procedure clear_memory (
variable MEMORY : out T_MEMARRAY) is -- Memory array
begin -- clear_memory
for i in MEMORY'range(1) loop
for j in MEMORY'range(2) loop
MEMORY(i,j) := '0'; -- Clear out
end loop; -- j
end loop; -- i
end clear_memory;
-----------------------------------------------------------------------
--------------------------------------------------------------------------
-- Function: gethex
-- Purpose: Convert ASCII to hexadecimal
-- Input: character
-- Output: natural
--------------------------------------------------------------------------
function gethex( -- Convert ASCII to
hexadecimal
ch : character -- Character to convert
) return natural is -- Decoded value, or f_error
begin
if ('0' <= ch) and (ch <= '9') then
return character'pos(ch) - character'pos('0');
elsif ('A' <= ch) and (ch <= 'F') then
return character'pos(ch) - character'pos('A') + 10;
elsif ('a' <= ch) and (CH <= 'f') then
return character'pos(ch) - character'pos('a') + 10;
else
return f_error;
end if;
end gethex;
--------------------------------------------------------------------------
-- Procedure: getbyte
-- Purpose: Get next byte from line
-- InOut: line, natural
-- Output: natural
--------------------------------------------------------------------------
-- Since the line must be INOUT, this cannot be a function.
procedure getbyte( -- Get next byte from line
data : inout line; -- Line to read from
csum : inout natural; -- Checksum
ans : out natural -- Byte value
) is
variable ch : character;
variable x : natural;
variable res : natural := 0;
variable rdok : boolean; -- Read-function check
begin
ans := f_error; -- Pre-set to trap errors
for i in 1 to 2 loop -- Process two input
characters
if (data'length = 0) then -- End of line?
return;
end if;
read(data, ch, rdok); -- Next character
if not rdok then
return; -- Read errors
end if;
x := gethex(ch); -- To hexadecimal
if (x = f_error) then
ans := f_error; -- Invalid data
return;
end if;
res := (res * 16) + x; -- Big-endian data
end loop;
ans := res; -- Post the result
csum := csum + res;
end getbyte;
--------------------------------------------------------------------------
-- Procedure: gethexline
-- Purpose: Read a line from file, & decode it as a Motorola
S-record
-- Input: text
-- Output: hex_rec
--------------------------------------------------------------------------
-- Since the file must be INOUT, this cannot be a function.
procedure gethexline( -- Read a Motorola S-record
file infile : text; -- File to read
ans : out hex_rec; -- Decoded record
LINUM : inout natural -- Line number
) is
variable data : line; -- Source-file line
variable outrec : hex_rec; -- Record for output
variable ch : character;
variable csum : natural; -- Checksum
variable adlen : natural; -- No. of address bytes
variable bcount : natural; -- Byte counter
variable x : natural;
variable rdok : boolean; -- Read-function check
begin
ans.locn := 0; -- Pre-set to trap errors
ans.size := f_error;
csum := 0;
if endfile(infile) then -- Trap EOF
ans.size := f_eof;
return;
end if;
LINUM := LINUM + 1;
readline(infile, data); -- Fetch the line
read(data, ch, rdok); -- Record type-mark
if not rdok then -- Catch read errors
return;
end if;
case ch is
when '$' => -- Block header data
while not endfile(infile) loop
LINUM := LINUM + 1;
readline(infile, data); -- Get next line
read(data, ch, rdok); -- Record type-mark
if not rdok then -- Catch read errors
return;
end if;
if ch = '$' then -- Mating block-mark
ans.size := f_void;
return; -- Let the caller skip this
line
end if;
end loop;
ans.size := f_eof; -- Premature EOF
return;
when 'S' => -- S-record data
read(data, ch, rdok); -- Record sub-type
if not rdok then
return;
end if;
case ch is
when '1' => -- 2-byte address
adlen := 2;
when '2' => -- 3-byte address
adlen := 3;
when '3' => -- 4-byte address
adlen := 4;
when others => -- Unrecognised type
return;
end case;
getbyte(data, csum, bcount); -- Get byte counter
if (bcount = f_error) or (bcount > maxlen) then
return;
end if;
outrec.size := bcount;
outrec.locn := 0; -- Get the start address
for i in 1 to adlen loop
getbyte(data, csum, x);
if x = f_error then
return; -- Read error
end if;
outrec.locn := (outrec.locn * 256) + x;
end loop; -- i
for i in 0 to bcount-1 loop
getbyte(data, csum, x); -- Get next data byte
if x = f_error then
return;
end if;
outrec.data(i) := to_unsigned(x, 8);
end loop; -- i
getbyte(data, csum, x); -- Get checksum (& add to
count)
while csum > 255 loop -- Reduce modulo-256
csum := csum - 256; -- "mod" can behave oddly!
end loop;
if csum /= 255 then
return; -- Checksum error
end if;
ans := outrec; -- Return data from file
when others => -- Corrupt line
return;
end case;
end gethexline;
end memory;