--
|
|
-- File Name: MemoryPkg.vhd
|
|
-- Design Unit Name: MemoryPkg
|
|
-- Revision: STANDARD VERSION
|
|
--
|
|
-- Maintainer: Jim Lewis email: jim@synthworks.com
|
|
-- Contributor(s):
|
|
-- Jim Lewis email: jim@synthworks.com
|
|
--
|
|
-- Description
|
|
-- Package defines a protected type, MemoryPType, and methods
|
|
-- for efficiently implementing memory data structures
|
|
--
|
|
-- Developed for:
|
|
-- SynthWorks Design Inc.
|
|
-- VHDL Training Classes
|
|
-- 11898 SW 128th Ave. Tigard, Or 97223
|
|
-- http://www.SynthWorks.com
|
|
--
|
|
-- Revision History:
|
|
-- Date Version Description
|
|
-- 05/2005: 0.1 Initial revision
|
|
-- 06/2015: 2015.06 Updated for Alerts, ...
|
|
-- Numerous revisions for VHDL Testbenches and Verification
|
|
-- 01/2016: 2016.01 Update for buf.all(buf'left)
|
|
-- 11/2016: 2016.11 Refinement to MemRead to return value, X (if X), U (if not initialized)
|
|
--
|
|
--
|
|
-- Copyright (c) 2005 - 2016 by SynthWorks Design Inc. All rights reserved.
|
|
--
|
|
-- Verbatim copies of this source file may be used and
|
|
-- distributed without restriction.
|
|
--
|
|
-- This source file is free software; you can redistribute it
|
|
-- and/or modify it under the terms of the ARTISTIC License
|
|
-- as published by The Perl Foundation; either version 2.0 of
|
|
-- the License, or (at your option) any later version.
|
|
--
|
|
-- This source is distributed in the hope that it will be
|
|
-- useful, but WITHOUT ANY WARRANTY; without even the implied
|
|
-- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
-- PURPOSE. See the Artistic License for details.
|
|
--
|
|
-- You should have received a copy of the license with this source.
|
|
-- If not download it from,
|
|
-- http://www.perlfoundation.org/artistic_license_2_0
|
|
--
|
|
use std.textio.all ;
|
|
library IEEE ;
|
|
use IEEE.std_logic_1164.all ;
|
|
use IEEE.numeric_std.all ;
|
|
use IEEE.numeric_std_unsigned.all ;
|
|
use IEEE.math_real.all ;
|
|
|
|
use work.TextUtilPkg.all ;
|
|
use work.TranscriptPkg.all ;
|
|
use work.AlertLogPkg.all ;
|
|
|
|
package MemoryPkg is
|
|
type MemoryPType is protected
|
|
------------------------------------------------------------
|
|
procedure MemInit ( AddrWidth, DataWidth : in integer ) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemWrite ( Addr, Data : in std_logic_vector ) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemRead (
|
|
Addr : in std_logic_vector ;
|
|
Data : out std_logic_vector
|
|
) ;
|
|
impure function MemRead ( Addr : std_logic_vector ) return std_logic_vector ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemErase ;
|
|
procedure deallocate ;
|
|
|
|
------------------------------------------------------------
|
|
procedure SetAlertLogID (A : AlertLogIDType) ;
|
|
procedure SetAlertLogID (Name : string ; ParentID : AlertLogIDType := ALERTLOG_BASE_ID ; CreateHierarchy : Boolean := TRUE) ;
|
|
impure function GetAlertLogID return AlertLogIDType ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadH ( -- Hexadecimal File Read
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) ;
|
|
procedure FileReadH (FileName : string ; StartAddr : std_logic_vector) ;
|
|
procedure FileReadH (FileName : string) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadB ( -- Binary File Read
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) ;
|
|
procedure FileReadB (FileName : string ; StartAddr : std_logic_vector) ;
|
|
procedure FileReadB (FileName : string) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteH ( -- Hexadecimal File Write
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) ;
|
|
procedure FileWriteH (FileName : string ; StartAddr : std_logic_vector) ;
|
|
procedure FileWriteH (FileName : string) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteB ( -- Binary File Write
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) ;
|
|
procedure FileWriteB (FileName : string ; StartAddr : std_logic_vector) ;
|
|
procedure FileWriteB (FileName : string) ;
|
|
|
|
end protected MemoryPType ;
|
|
|
|
end MemoryPkg ;
|
|
|
|
package body MemoryPkg is
|
|
constant BLOCK_WIDTH : integer := 10 ;
|
|
|
|
type MemoryPType is protected body
|
|
|
|
type MemBlockType is array (integer range <>) of integer ;
|
|
type MemBlockPtrType is access MemBlockType ;
|
|
type MemArrayType is array (integer range <>) of MemBlockPtrType ;
|
|
type ArrayPtrVarType is access MemArrayType ;
|
|
|
|
variable ArrayPtrVar : ArrayPtrVarType := NULL ;
|
|
variable AddrWidthVar : integer := -1 ; -- set by MemInit - merges addr length and initialized checks.
|
|
variable DataWidthVar : natural := 1 ; -- set by MemInit
|
|
variable BlockkWidthVar : natural := 0 ; -- set by MemInit
|
|
|
|
variable AlertLogIDVar : AlertLogIDType := OSVVM_ALERTLOG_ID ;
|
|
|
|
type FileFormatType is (BINARY, HEX) ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemInit ( AddrWidth, DataWidth : In integer ) is
|
|
------------------------------------------------------------
|
|
begin
|
|
if AddrWidth <= 0 then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemInit. AddrWidth = " & to_string(AddrWidth) & " must be > 0.", FAILURE) ;
|
|
return ;
|
|
end if ;
|
|
if DataWidth <= 0 then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemInit. DataWidth = " & to_string(DataWidth) & " must be > 0.", FAILURE) ;
|
|
return ;
|
|
end if ;
|
|
|
|
AddrWidthVar := AddrWidth ;
|
|
DataWidthVar := DataWidth ;
|
|
BlockkWidthVar := minimum(BLOCK_WIDTH, AddrWidth) ;
|
|
ArrayPtrVar := new MemArrayType(0 to 2**(AddrWidth-BlockkWidthVar)-1) ;
|
|
end procedure MemInit ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemWrite ( Addr, Data : in std_logic_vector ) is
|
|
------------------------------------------------------------
|
|
variable BlockAddr, WordAddr : integer ;
|
|
alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
|
|
begin
|
|
|
|
-- Check Bounds of Address and if memory is initialized
|
|
if Addr'length /= AddrWidthVar then
|
|
if (ArrayPtrVar = NULL) then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemWrite: Memory not initialized, Write Ignored.", FAILURE) ;
|
|
else
|
|
Alert(AlertLogIDVar, "MemoryPType.MemWrite: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
|
|
end if ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Check Bounds on Data
|
|
if Data'length /= DataWidthVar then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemWrite: Data'length: " & to_string(Data'length) & " /= Memory Data Width: " & to_string(DataWidthVar), FAILURE) ;
|
|
return ;
|
|
end if ;
|
|
|
|
if is_X( Addr ) then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemWrite: Address X, Write Ignored.") ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Slice out upper address to form block address
|
|
if aAddr'high >= BlockkWidthVar then
|
|
BlockAddr := to_integer(aAddr(aAddr'high downto BlockkWidthVar)) ;
|
|
else
|
|
BlockAddr := 0 ;
|
|
end if ;
|
|
|
|
-- If empty, allocate a memory block
|
|
if (ArrayPtrVar(BlockAddr) = NULL) then
|
|
ArrayPtrVar(BlockAddr) := new MemBlockType(0 to 2**BlockkWidthVar-1) ;
|
|
end if ;
|
|
|
|
-- Address of a word within a block
|
|
WordAddr := to_integer(aAddr(BlockkWidthVar -1 downto 0)) ;
|
|
|
|
-- Write to BlockAddr, WordAddr
|
|
if (Is_X(Data)) then
|
|
ArrayPtrVar(BlockAddr)(WordAddr) := -1 ;
|
|
else
|
|
ArrayPtrVar(BlockAddr)(WordAddr) := to_integer( Data ) ;
|
|
end if ;
|
|
end procedure MemWrite ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemRead (
|
|
------------------------------------------------------------
|
|
Addr : In std_logic_vector ;
|
|
Data : Out std_logic_vector
|
|
) is
|
|
variable BlockAddr, WordAddr : integer ;
|
|
alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
|
|
begin
|
|
-- Check Bounds of Address and if memory is initialized
|
|
if Addr'length /= AddrWidthVar then
|
|
if (ArrayPtrVar = NULL) then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemRead: Memory not initialized. Returning U", FAILURE) ;
|
|
else
|
|
Alert(AlertLogIDVar, "MemoryPType.MemRead: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
|
|
end if ;
|
|
Data := (Data'range => 'U') ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Check Bounds on Data
|
|
if Data'length /= DataWidthVar then
|
|
Alert(AlertLogIDVar, "MemoryPType.MemRead: Data'length: " & to_string(Data'length) & " /= Memory Data Width: " & to_string(DataWidthVar), FAILURE) ;
|
|
Data := (Data'range => 'U') ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- If Addr X, data = X
|
|
if is_X( aAddr ) then
|
|
Data := (Data'range => 'X') ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Slice out upper address to form block address
|
|
if aAddr'high >= BlockkWidthVar then
|
|
BlockAddr := to_integer(aAddr(aAddr'high downto BlockkWidthVar)) ;
|
|
else
|
|
BlockAddr := 0 ;
|
|
end if ;
|
|
|
|
-- Empty Block, return all U
|
|
if (ArrayPtrVar(BlockAddr) = NULL) then
|
|
Data := (Data'range => 'U') ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Address of a word within a block
|
|
WordAddr := to_integer(aAddr(BlockkWidthVar -1 downto 0)) ;
|
|
|
|
if ArrayPtrVar(BlockAddr)(WordAddr) >= 0 then
|
|
-- Get the Word from the Array
|
|
Data := to_slv(ArrayPtrVar(BlockAddr)(WordAddr), Data'length) ;
|
|
|
|
elsif ArrayPtrVar(BlockAddr)(WordAddr) = -1 then
|
|
-- X in Word, return all X
|
|
Data := (Data'range => 'X') ;
|
|
|
|
else
|
|
-- Location Uninitialized, return all X
|
|
Data := (Data'range => 'U') ;
|
|
|
|
end if ;
|
|
end procedure MemRead ;
|
|
|
|
------------------------------------------------------------
|
|
impure function MemRead ( Addr : std_logic_vector ) return std_logic_vector is
|
|
------------------------------------------------------------
|
|
variable BlockAddr, WordAddr : integer ;
|
|
alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ;
|
|
variable Data : std_logic_vector(DataWidthVar-1 downto 0) ;
|
|
begin
|
|
MemRead(Addr, Data) ;
|
|
return Data ;
|
|
end function MemRead ;
|
|
|
|
------------------------------------------------------------
|
|
procedure MemErase is
|
|
-- Deallocate the memory, but not the array of pointers
|
|
------------------------------------------------------------
|
|
begin
|
|
for BlockAddr in ArrayPtrVar'range loop
|
|
if (ArrayPtrVar(BlockAddr) /= NULL) then
|
|
deallocate (ArrayPtrVar(BlockAddr)) ;
|
|
end if ;
|
|
end loop ;
|
|
end procedure ;
|
|
|
|
------------------------------------------------------------
|
|
procedure deallocate is
|
|
-- Deallocate all allocated memory
|
|
------------------------------------------------------------
|
|
begin
|
|
MemErase ;
|
|
deallocate(ArrayPtrVar) ;
|
|
AddrWidthVar := -1 ;
|
|
DataWidthVar := 1 ;
|
|
BlockkWidthVar := 0 ;
|
|
end procedure ;
|
|
|
|
------------------------------------------------------------
|
|
procedure SetAlertLogID (A : AlertLogIDType) is
|
|
------------------------------------------------------------
|
|
begin
|
|
AlertLogIDVar := A ;
|
|
end procedure SetAlertLogID ;
|
|
|
|
------------------------------------------------------------
|
|
procedure SetAlertLogID(Name : string ; ParentID : AlertLogIDType := ALERTLOG_BASE_ID ; CreateHierarchy : Boolean := TRUE) is
|
|
------------------------------------------------------------
|
|
begin
|
|
AlertLogIDVar := GetAlertLogID(Name, ParentID, CreateHierarchy) ;
|
|
end procedure SetAlertLogID ;
|
|
|
|
------------------------------------------------------------
|
|
impure function GetAlertLogID return AlertLogIDType is
|
|
------------------------------------------------------------
|
|
begin
|
|
return AlertLogIDVar ;
|
|
end function GetAlertLogID ;
|
|
|
|
------------------------------------------------------------
|
|
-- PT Local
|
|
procedure FileReadX (
|
|
-- Hexadecimal or Binary File Read
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
DataFormat : FileFormatType ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
-- Format:
|
|
-- @hh..h -- Address in hex
|
|
-- hhh_XX_ZZ -- data values in hex - space delimited
|
|
-- "--" or "//" -- comments
|
|
file MemFile : text open READ_MODE is FileName ;
|
|
|
|
variable Addr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
|
|
variable SmallAddr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
|
|
variable BigAddr : std_logic_vector(AddrWidthVar - 1 downto 0) ;
|
|
variable Data : std_logic_vector(DataWidthVar - 1 downto 0) ;
|
|
variable LineNum : natural ;
|
|
variable ItemNum : natural ;
|
|
variable AddrInc : std_logic_vector(AddrWidthVar - 1 downto 0) ;
|
|
variable buf : line ;
|
|
variable ReadValid : boolean ;
|
|
variable Empty : boolean ;
|
|
variable MultiLineComment : boolean ;
|
|
variable NextChar : character ;
|
|
variable StrLen : integer ;
|
|
begin
|
|
MultiLineComment := FALSE ;
|
|
if StartAddr'length /= AddrWidthVar and EndAddr'length /= AddrWidthVar then
|
|
if (ArrayPtrVar = NULL) then
|
|
Alert(AlertLogIDVar, "MemoryPType.FileReadX: Memory not initialized, FileRead Ignored.", FAILURE) ;
|
|
else
|
|
Alert(AlertLogIDVar, "MemoryPType.FileReadX: Addr'length: " & to_string(Addr'length) & " /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
|
|
end if ;
|
|
return ;
|
|
end if ;
|
|
|
|
Addr := StartAddr ;
|
|
LineNum := 0 ;
|
|
|
|
if StartAddr <= EndAddr then
|
|
SmallAddr := StartAddr ;
|
|
BigAddr := EndAddr ;
|
|
AddrInc := (AddrWidthVar -1 downto 0 => '0') + 1 ;
|
|
else
|
|
SmallAddr := EndAddr ;
|
|
BigAddr := StartAddr ;
|
|
AddrInc := (others => '1') ; -- -1
|
|
end if;
|
|
|
|
ReadLineLoop : while not EndFile(MemFile) loop
|
|
ReadLine(MemFile, buf) ;
|
|
LineNum := LineNum + 1 ;
|
|
ItemNum := 0 ;
|
|
|
|
ItemLoop : loop
|
|
EmptyOrCommentLine(buf, Empty, MultiLineComment) ;
|
|
exit ItemLoop when Empty ;
|
|
ItemNum := ItemNum + 1 ;
|
|
NextChar := buf.all(buf'left) ;
|
|
|
|
if (NextChar = '@') then
|
|
-- Get Address
|
|
read(buf, NextChar) ;
|
|
ReadHexToken(buf, Addr, StrLen) ;
|
|
exit ReadLineLoop when AlertIf(AlertLogIDVar, StrLen = 0, "MemoryPType.FileReadX: Address length 0 on line: " & to_string(LineNum), FAILURE) ;
|
|
exit ItemLoop when AlertIf(AlertLogIDVar, Addr < SmallAddr,
|
|
"MemoryPType.FileReadX: Address in file: " & to_hstring(Addr) &
|
|
" < StartAddr: " & to_hstring(StartAddr) & " on line: " & to_string(LineNum)) ;
|
|
exit ItemLoop when AlertIf(AlertLogIDVar, Addr > BigAddr,
|
|
"MemoryPType.FileReadX: Address in file: " & to_hstring(Addr) &
|
|
" > EndAddr: " & to_hstring(BigAddr) & " on line: " & to_string(LineNum)) ;
|
|
|
|
elsif DataFormat = HEX and ishex(NextChar) then
|
|
-- Get Hex Data
|
|
ReadHexToken(buf, data, StrLen) ;
|
|
exit ReadLineLoop when AlertIfNot(AlertLogIDVar, StrLen > 0,
|
|
"MemoryPType.FileReadH: Error while reading data on line: " & to_string(LineNum) &
|
|
" Item number: " & to_string(ItemNum), FAILURE) ;
|
|
log("MemoryPType.FileReadX: MemWrite(Addr => " & to_hstring(Addr) & ", Data => " & to_hstring(Data) & ")", DEBUG) ;
|
|
MemWrite(Addr, data) ;
|
|
Addr := Addr + AddrInc ;
|
|
|
|
elsif DataFormat = BINARY and isstd_logic(NextChar) then
|
|
-- Get Binary Data
|
|
-- read(buf, data, ReadValid) ;
|
|
ReadBinaryToken(buf, data, StrLen) ;
|
|
-- exit ReadLineLoop when AlertIfNot(AlertLogIDVar, ReadValid,
|
|
exit ReadLineLoop when AlertIfNot(AlertLogIDVar, StrLen > 0,
|
|
"MemoryPType.FileReadB: Error while reading data on line: " & to_string(LineNum) &
|
|
" Item number: " & to_string(ItemNum), FAILURE) ;
|
|
log("MemoryPType.FileReadX: MemWrite(Addr => " & to_hstring(Addr) & ", Data => " & to_string(Data) & ")", DEBUG) ;
|
|
MemWrite(Addr, data) ;
|
|
Addr := Addr + AddrInc ;
|
|
|
|
else
|
|
-- Invalid Text, Issue Warning and skip it
|
|
Alert(AlertLogIDVar,
|
|
"MemoryPType.FileReadX: Invalid text on line: " & to_string(LineNum) &
|
|
" Item: " & to_string(ItemNum) & ". Skipping text: " & buf.all) ;
|
|
exit ItemLoop ;
|
|
end if ;
|
|
|
|
end loop ItemLoop ;
|
|
end loop ReadLineLoop ;
|
|
|
|
-- -- must read EndAddr-StartAddr number of words if both start and end specified
|
|
-- if (StartAddr /= 0 or (not EndAddr) /= 0) and (Addr /= EndAddr) then
|
|
-- Alert("MemoryPType.FileReadH: insufficient data values", WARNING) ;
|
|
-- end if ;
|
|
file_close(MemFile) ;
|
|
end FileReadX ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadH (
|
|
-- Hexadecimal File Read
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
begin
|
|
FileReadX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileReadH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadH (FileName : string ; StartAddr : std_logic_vector) is
|
|
-- Hexadecimal File Read
|
|
------------------------------------------------------------
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileReadX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileReadH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadH (FileName : string) is
|
|
-- Hexadecimal File Read
|
|
------------------------------------------------------------
|
|
constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileReadX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileReadH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadB (
|
|
-- Binary File Read
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
begin
|
|
FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileReadB ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadB (FileName : string ; StartAddr : std_logic_vector) is
|
|
-- Binary File Read
|
|
------------------------------------------------------------
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileReadB ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileReadB (FileName : string) is
|
|
-- Binary File Read
|
|
------------------------------------------------------------
|
|
constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileReadX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileReadB ;
|
|
|
|
------------------------------------------------------------
|
|
-- PT Local
|
|
procedure FileWriteX (
|
|
-- Hexadecimal or Binary File Write
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
DataFormat : FileFormatType ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
-- Format:
|
|
-- @hh..h -- Address in hex
|
|
-- hhhhh -- data one per line in either hex or binary as specified
|
|
file MemFile : text open WRITE_MODE is FileName ;
|
|
alias normStartAddr : std_logic_vector(StartAddr'length-1 downto 0) is StartAddr ;
|
|
alias normEndAddr : std_logic_vector(EndAddr'length-1 downto 0) is EndAddr ;
|
|
variable StartBlockAddr : natural ;
|
|
variable EndBlockAddr : natural ;
|
|
variable StartWordAddr : natural ;
|
|
variable EndWordAddr : natural ;
|
|
variable Data : std_logic_vector(DataWidthVar - 1 downto 0) ;
|
|
variable FoundData : boolean ;
|
|
variable buf : line ;
|
|
begin
|
|
if StartAddr'length /= AddrWidthVar and EndAddr'length /= AddrWidthVar then
|
|
-- Check StartAddr and EndAddr Widths and Memory not initialized
|
|
if (ArrayPtrVar = NULL) then
|
|
Alert(AlertLogIDVar, "MemoryPType.FileWriteX: Memory not initialized, FileRead Ignored.", FAILURE) ;
|
|
else
|
|
AlertIf(AlertLogIDVar, StartAddr'length /= AddrWidthVar, "MemoryPType.FileWriteX: StartAddr'length: "
|
|
& to_string(StartAddr'length) &
|
|
" /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
|
|
AlertIf(AlertLogIDVar, EndAddr'length /= AddrWidthVar, "MemoryPType.FileWriteX: EndAddr'length: "
|
|
& to_string(EndAddr'length) &
|
|
" /= Memory Address Width: " & to_string(AddrWidthVar), FAILURE) ;
|
|
end if ;
|
|
return ;
|
|
end if ;
|
|
|
|
if StartAddr > EndAddr then
|
|
-- Only support ascending addresses
|
|
Alert(AlertLogIDVar, "MemoryPType.FileWriteX: StartAddr: " & to_hstring(StartAddr) &
|
|
" > EndAddr: " & to_hstring(EndAddr), FAILURE) ;
|
|
return ;
|
|
end if ;
|
|
|
|
-- Slice out upper address to form block address
|
|
if AddrWidthVar >= BlockkWidthVar then
|
|
StartBlockAddr := to_integer(normStartAddr(AddrWidthVar-1 downto BlockkWidthVar)) ;
|
|
EndBlockAddr := to_integer( normEndAddr(AddrWidthVar-1 downto BlockkWidthVar)) ;
|
|
else
|
|
StartBlockAddr := 0 ;
|
|
EndBlockAddr := 0 ;
|
|
end if ;
|
|
|
|
BlockAddrLoop : for BlockAddr in StartBlockAddr to EndBlockAddr loop
|
|
next BlockAddrLoop when ArrayPtrVar(BlockAddr) = NULL ;
|
|
if BlockAddr = StartBlockAddr then
|
|
StartWordAddr := to_integer(normStartAddr(BlockkWidthVar-1 downto 0)) ;
|
|
else
|
|
StartWordAddr := 0 ;
|
|
end if ;
|
|
if BlockAddr = EndBlockAddr then
|
|
EndWordAddr := to_integer(normEndAddr(BlockkWidthVar-1 downto 0)) ;
|
|
else
|
|
EndWordAddr := 2**BlockkWidthVar-1 ;
|
|
end if ;
|
|
FoundData := FALSE ;
|
|
WordAddrLoop : for WordAddr in StartWordAddr to EndWordAddr loop
|
|
if (ArrayPtrVar(BlockAddr)(WordAddr) < 0) then
|
|
-- X in Word, return all X
|
|
Data := (Data'range => 'X') ;
|
|
FoundData := FALSE ;
|
|
else
|
|
-- Get the Word from the Array
|
|
Data := to_slv(ArrayPtrVar(BlockAddr)(WordAddr), Data'length) ;
|
|
if not FoundData then
|
|
-- Write Address
|
|
write(buf, '@') ;
|
|
hwrite(buf, to_slv(BlockAddr, AddrWidthVar-BlockkWidthVar) & to_slv(WordAddr, BlockkWidthVar)) ;
|
|
writeline(MemFile, buf) ;
|
|
end if ;
|
|
FoundData := TRUE ;
|
|
end if ;
|
|
if FoundData then -- Write Data
|
|
if DataFormat = HEX then
|
|
hwrite(buf, Data) ;
|
|
writeline(MemFile, buf) ;
|
|
else
|
|
write(buf, Data) ;
|
|
writeline(MemFile, buf) ;
|
|
end if;
|
|
end if ;
|
|
end loop WordAddrLoop ;
|
|
end loop BlockAddrLoop ;
|
|
file_close(MemFile) ;
|
|
end FileWriteX ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteH (
|
|
-- Hexadecimal File Write
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
begin
|
|
FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileWriteH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteH (FileName : string ; StartAddr : std_logic_vector) is
|
|
-- Hexadecimal File Write
|
|
------------------------------------------------------------
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileWriteH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteH (FileName : string) is
|
|
-- Hexadecimal File Write
|
|
------------------------------------------------------------
|
|
constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileWriteX(FileName, HEX, StartAddr, EndAddr) ;
|
|
end FileWriteH ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteB (
|
|
-- Binary File Write
|
|
------------------------------------------------------------
|
|
FileName : string ;
|
|
StartAddr : std_logic_vector ;
|
|
EndAddr : std_logic_vector
|
|
) is
|
|
begin
|
|
FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileWriteB ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteB (FileName : string ; StartAddr : std_logic_vector) is
|
|
-- Binary File Write
|
|
------------------------------------------------------------
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileWriteB ;
|
|
|
|
------------------------------------------------------------
|
|
procedure FileWriteB (FileName : string) is
|
|
-- Binary File Write
|
|
------------------------------------------------------------
|
|
constant StartAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '0') ;
|
|
constant EndAddr : std_logic_vector(AddrWidthVar - 1 downto 0) := (others => '1') ;
|
|
begin
|
|
FileWriteX(FileName, BINARY, StartAddr, EndAddr) ;
|
|
end FileWriteB ;
|
|
|
|
end protected body MemoryPType ;
|
|
|
|
end MemoryPkg ;
|