diff options
author | Tristan Gingold <tgingold@free.fr> | 2022-08-10 16:55:22 +0200 |
---|---|---|
committer | Tristan Gingold <tgingold@free.fr> | 2022-08-10 16:55:22 +0200 |
commit | 4d14b77ce02b89b1a22718ce607b16d823d95c74 (patch) | |
tree | 6090f74b784e4768a6c1d7f8da9890f6da129f93 /testsuite/gna/issue2166/tb4.vhdl | |
parent | 8a3922778cd92df96aaf5771f24d650bb8290559 (diff) | |
download | ghdl-4d14b77ce02b89b1a22718ce607b16d823d95c74.tar.gz ghdl-4d14b77ce02b89b1a22718ce607b16d823d95c74.tar.bz2 ghdl-4d14b77ce02b89b1a22718ce607b16d823d95c74.zip |
testsuite/gna: add a reproducer for #2166
Diffstat (limited to 'testsuite/gna/issue2166/tb4.vhdl')
-rw-r--r-- | testsuite/gna/issue2166/tb4.vhdl | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/testsuite/gna/issue2166/tb4.vhdl b/testsuite/gna/issue2166/tb4.vhdl new file mode 100644 index 000000000..aefaac9e2 --- /dev/null +++ b/testsuite/gna/issue2166/tb4.vhdl @@ -0,0 +1,314 @@ +library OSVVM ; + +use OSVVM.MemorySupportPkg.all ; + +use std.textio.all ; +library IEEE ; + use IEEE.std_logic_1164.all ; + use IEEE.numeric_std.all ; + use IEEE.numeric_std_unsigned.all ; + +package MemoryGenericPkg is + generic ( +-- type integer_vector ; + function SizeMemoryBaseType(Size : integer) return integer ; -- is <> ; + function ToMemoryBaseType (A : std_logic_vector) return integer_vector ; -- is <> ; + function FromMemoryBaseType(A : integer_vector ; Size : integer) return std_logic_vector ; -- is <> ; + function InitMemoryBaseType(Size : integer) return integer_vector -- is <> + ) ; + + type MemoryPType is protected + + ------------------------------------------------------------ + impure function NewID ( + Name : String ; + AddrWidth : integer ; + DataWidth : integer + ) return integer ; + + ------------------------------------------------------------ + procedure MemWrite ( + ID : integer ; + Addr : std_logic_vector ; + Data : std_logic_vector + ) ; + procedure MemRead ( + ID : in integer ; + Addr : in std_logic_vector ; + Data : out std_logic_vector + ) ; + end protected MemoryPType ; + +end MemoryGenericPkg ; + +package body MemoryGenericPkg is + constant BLOCK_WIDTH : integer := 10 ; + + type MemoryPType is protected body + + subtype MemoryBaseType is integer_vector ; + type MemBlockType is array (integer range <>) of MemoryBaseType ; + type MemBlockPtrType is access MemBlockType ; + type MemArrayType is array (integer range <>) of MemBlockPtrType ; + type MemArrayPtrType is access MemArrayType ; + + type MemStructType is record + MemArrayPtr : MemArrayPtrType ; + AddrWidth : integer ; + DataWidth : natural ; + BlockWidth : natural ; + MemoryBaseTypeWidth : natural ; + end record MemStructType ; + + -- New Structure + type ItemArrayType is array (integer range <>) of MemStructType ; + type ItemArrayPtrType is access ItemArrayType ; + + variable Template : ItemArrayType(1 to 1) := (1 => (NULL, -1, 1, 0, 0)) ; -- Work around for QS 2020.04 and 2021.02 + constant MEM_STRUCT_PTR_LEFT : integer := Template'left ; + variable MemStructPtr : ItemArrayPtrType := new ItemArrayType'(Template) ; + variable NumItems : integer := 0 ; +-- constant MIN_NUM_ITEMS : integer := 4 ; -- Temporarily small for testing + constant MIN_NUM_ITEMS : integer := 32 ; -- Min amount to resize array + + ------------------------------------------------------------ + -- Package Local + function NormalizeArraySize( NewNumItems, MinNumItems : integer ) return integer is + ------------------------------------------------------------ + variable NormNumItems : integer := NewNumItems ; + variable ModNumItems : integer := 0; + begin + ModNumItems := NewNumItems mod MinNumItems ; + if ModNumItems > 0 then + NormNumItems := NormNumItems + (MinNumItems - ModNumItems) ; + end if ; + return NormNumItems ; + end function NormalizeArraySize ; + + ------------------------------------------------------------ + -- Package Local + procedure GrowNumberItems ( + ------------------------------------------------------------ + variable ItemArrayPtr : InOut ItemArrayPtrType ; + variable NumItems : InOut integer ; + constant GrowAmount : in integer ; +-- constant NewNumItems : in integer ; +-- constant CurNumItems : in integer ; + constant MinNumItems : in integer + ) is + variable oldItemArrayPtr : ItemArrayPtrType ; + variable NewNumItems : integer ; + begin + NewNumItems := NumItems + GrowAmount ; + -- Array Allocated in declaration to have a single item, but no items (historical mode) + -- if ItemArrayPtr = NULL then + -- ItemArrayPtr := new ItemArrayType(1 to NormalizeArraySize(NewNumItems, MinNumItems)) ; + -- elsif NewNumItems > ItemArrayPtr'length then + if NewNumItems > ItemArrayPtr'length then + oldItemArrayPtr := ItemArrayPtr ; + ItemArrayPtr := new ItemArrayType(1 to NormalizeArraySize(NewNumItems, MinNumItems)) ; + ItemArrayPtr.all(1 to NumItems) := oldItemArrayPtr.all(1 to NumItems) ; + deallocate(oldItemArrayPtr) ; + end if ; + NumItems := NewNumItems ; + end procedure GrowNumberItems ; + + ------------------------------------------------------------ + -- PT Local + procedure MemInit (ID : integer ; AddrWidth, DataWidth : integer ) is + ------------------------------------------------------------ + constant ADJ_BLOCK_WIDTH : integer := minimum(BLOCK_WIDTH, AddrWidth) ; + begin + if AddrWidth <= 0 then + return ; + end if ; +-- if DataWidth <= 0 or DataWidth > 31 then +-- Alert(MemStructPtr(ID).AlertLogID, "MemoryPkg.MemInit/NewID. DataWidth = " & to_string(DataWidth) & " must be > 0 and <= 31.", FAILURE) ; + if DataWidth <= 0 then + return ; + end if ; + + MemStructPtr(ID).AddrWidth := AddrWidth ; + MemStructPtr(ID).DataWidth := DataWidth ; + MemStructPtr(ID).MemoryBaseTypeWidth := SizeMemoryBaseType(DataWidth) ; + MemStructPtr(ID).BlockWidth := ADJ_BLOCK_WIDTH ; + MemStructPtr(ID).MemArrayPtr := new MemArrayType(0 to 2**(AddrWidth-ADJ_BLOCK_WIDTH)-1) ; + end procedure MemInit ; + + ------------------------------------------------------------ + impure function NewID ( + ------------------------------------------------------------ + Name : String ; + AddrWidth : integer ; + DataWidth : integer + ) return integer is + variable NameID : integer ; + begin + -- Add New Memory to Structure + GrowNumberItems(MemStructPtr, NumItems, GrowAmount => 1, MinNumItems => MIN_NUM_ITEMS) ; + -- Construct Memory, Reports agains AlertLogID + MemInit(NumItems, AddrWidth, DataWidth) ; + -- Check NameStore Index vs MemoryIndex + return NumItems ; + end function NewID ; + + ------------------------------------------------------------ + -- PT Local + impure function IdOutOfRange( + ------------------------------------------------------------ + constant ID : in integer ; + constant Name : in string + ) return boolean is + begin + return ID < MemStructPtr'Low or ID > MemStructPtr'High; + end function IdOutOfRange ; + + ------------------------------------------------------------ + procedure MemWrite ( + ------------------------------------------------------------ + ID : integer ; + Addr : std_logic_vector ; + Data : std_logic_vector + ) is + variable BlockWidth : integer ; + variable MemoryBaseTypeWidth : integer ; +-- constant BlockWidth : integer := MemStructPtr(ID).BlockWidth; + variable BlockAddr, WordAddr : integer ; + alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ; +-- subtype MemBlockSubType is MemBlockType(0 to 2**BlockWidth-1) ; + begin + if IdOutOfRange(ID, "MemWrite") then + return ; + end if ; + BlockWidth := MemStructPtr(ID).BlockWidth ; + MemoryBaseTypeWidth := MemStructPtr(ID).MemoryBaseTypeWidth ; + + -- Check Bounds of Address and if memory is initialized + if Addr'length /= MemStructPtr(ID).AddrWidth then + return ; + end if ; + + -- Check Bounds on Data + if Data'length /= MemStructPtr(ID).DataWidth then + return ; + end if ; + + if is_X( Addr ) then + return ; + end if ; + + -- Slice out upper address to form block address + if aAddr'high >= BlockWidth then + BlockAddr := to_integer(aAddr(aAddr'high downto BlockWidth)) ; + else + BlockAddr := 0 ; + end if ; + + -- If empty, allocate a memory block + if (MemStructPtr(ID).MemArrayPtr(BlockAddr) = NULL) then +-- MemStructPtr(ID).MemArrayPtr(BlockAddr) := new MemBlockType'(0 to 2**BlockWidth-1 => InitMemoryBaseType(Data'length)) ; + MemStructPtr(ID).MemArrayPtr(BlockAddr) := new MemBlockType(0 to 2**BlockWidth-1)(MemoryBaseTypeWidth downto 1) ; -- => InitMemoryBaseType(Data'length)) ; + MemStructPtr(ID).MemArrayPtr(BlockAddr)(0 to 2**BlockWidth-1) := (0 to 2**BlockWidth-1 => InitMemoryBaseType(Data'length)) ; +--KO2 MemStructPtr(ID).MemArrayPtr(BlockAddr)(0 to 2**BlockWidth-1) := (others => InitMemoryBaseType(Data'length)) ; + + end if ; + + -- Address of a word within a block + WordAddr := to_integer(aAddr(BlockWidth -1 downto 0)) ; + + -- Write to BlockAddr, WordAddr + MemStructPtr(ID).MemArrayPtr(BlockAddr)(WordAddr) := ToMemoryBaseType(Data) ; + end procedure MemWrite ; + + ------------------------------------------------------------ + procedure MemRead ( + ------------------------------------------------------------ + ID : in integer ; + Addr : in std_logic_vector ; + Data : out std_logic_vector + ) is + variable BlockWidth : integer ; + variable BlockAddr, WordAddr : integer ; + alias aAddr : std_logic_vector (Addr'length-1 downto 0) is Addr ; + begin + if IdOutOfRange(ID, "MemRead") then + return ; + end if ; + BlockWidth := MemStructPtr(ID).BlockWidth ; + + -- Check Bounds of Address and if memory is initialized + if Addr'length /= MemStructPtr(ID).AddrWidth then + Data := (Data'range => 'U') ; + return ; + end if ; + + -- Check Bounds on Data + if Data'length /= MemStructPtr(ID).DataWidth then + 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 >= BlockWidth then + BlockAddr := to_integer(aAddr(aAddr'high downto BlockWidth)) ; + else + BlockAddr := 0 ; + end if ; + + -- Empty Block, return all U + if (MemStructPtr(ID).MemArrayPtr(BlockAddr) = NULL) then + Data := (Data'range => 'U') ; + return ; + end if ; + + -- Address of a word within a block + WordAddr := to_integer(aAddr(BlockWidth -1 downto 0)) ; + + Data := FromMemoryBaseType(MemStructPtr(ID).MemArrayPtr(BlockAddr)(WordAddr), Data'length) ; + + end procedure MemRead ; + end protected body MemoryPType ; +end MemoryGenericPkg ; + +library OSVVM ; + +use OSVVM.MemorySupportPkg.all ; + +package MemoryPkg is new work.MemoryGenericPkg + generic map ( +-- MemoryBaseType => MemoryBaseType_X, + SizeMemoryBaseType => SizeMemoryBaseType_X, + ToMemoryBaseType => ToMemoryBaseType_X, + FromMemoryBaseType => FromMemoryBaseType_X, + InitMemoryBaseType => InitMemoryBaseType_X + ) ; + +library ieee ; +use ieee.std_logic_1164.all ; +use ieee.numeric_std.all ; +use work.MemoryPkg.all; + +entity tb3 is +end; + +architecture behav of tb3 is + shared variable MemoryStore : MemoryPType ; +begin + process + variable MemoryID : integer; + begin + MemoryID := MemoryStore.NewID( + Name => "my_sram", + AddrWidth => 20, + DataWidth => 16); + + MemoryStore.MemWrite(MemoryId, x"00000", x"0000"); + wait; + end process; +end ; |