Topic : The GFA-Basic Compendium
Author : GFA Systemtechnik GmbH
Version : GFABasic.HYP v2.98 (12/31/2023)
Subject : Documentation/Programming
Nodes : 899
Index Size : 28056
HCP-Version : 3
Compiled on : Atari
@charset : atarist
@lang :
@default : Document not found
@help : Help
@options : +g -i -s +z
@width : 75
@hostname : STRNGSRV
@hostname : CAB
@hostname : HIGHWIRE
@hostname : THING
View Ref-FileExternal Arrays
by
Rev 4 3/12/2018
________________________
Normally an array's memory resides inside GFA's variable memory area, as
defined by the compiler command $M. Have you ever wanted to point an array at
the screen buffer, or force an array to use a certain type of ram? The command
ABSOLUTE does not accept arrays, but with this technique, you can get around
that.
For a lack of a better term I will refer to this type of an array as external.
This means the ram used by the array is outside of GFA's normal variable
memory area. The key to this technique is the array descriptor which contains
a pointer to the ram used by the array.
This will also let you free the memory of an array or re-dimension it, without
it shifting other arrays in memory.
Here's an example using a 1 dimensional byte array:
' create an array as small as possible, so
' that it uses virtually no variable ram ($M)
' this creates the array descriptor,
' but it has only 1 element assuming option base 0
DIM test|(0)
'
' allocate the ram needed for the array
' for each dimension add 4 extra bytes
' for option base 0 add 1 extra element
buffer%=MALLOC(4+24+1) !-> dim test|(24)
IF buffer%=0
PRINT "malloc() failed!"
EDIT
ENDIF
'
' modify the array descriptor to point
' at the newly allocated memory block
' and set it's dimension(s)
LONG{buffer%}=24 !set 1st dimension
LONG{*test|()}=buffer% !redirect to the memory block
ARRAYFILL test|(),0 !we must clear it, ram will be dirty
'
' test the array with some values
FOR i&=0 TO 23
test|(i&)=i&
NEXT i&
'
' dump the values using the array
FOR i&=0 TO 23
PRINT test|(i&);" ";
NEXT i&
PRINT
'
' dump the values directly from the memory block
' so we can see that the array has accessed it
FOR i&=0 TO 23
PRINT BYTE{buffer%+4+i&};" ";
NEXT i&
PRINT
'
' free the array
~MFREE(buffer%)
EDIT
' example outputs:
' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
' 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
There are some rules if one uses this technique:
1) Never, ever use ERASE. Internally GFA also stores a block-size and
back-trailer and these only come into play if one uses ERASE. Since the ram for
the array is outside of GFA's normal variable memory area it will surely crash.
I say again, never, ever use ERASE!
2) If you have some normal arrays and some external arrays, do not try to ERASE
a normal array either. This causes GFA to shift arrays in memory to fill the
empty gap. It will then likely crash if it tries to move an external array.
Again, do not use ERASE!
3) To re-dimension an external array, simply modify the array descriptor again.
Did I mention never, ever use ERASE! ;o)
4) Extreme care must be taken when setting the memory block size and
dimension(s).
If you follow these 3 rules this technique works quite well. I've used it in my
own programs for quite sometime. This technique works interpreted or compiled.
Note: This technique works with any type of numerical array with any number of
dimensions, however it's untested with string arrays. String arrays are a
special animal in themselves and since each string in the array requires a
string descriptor it's managed a bit differently. There's no way to force GFA
to move the actual string data to your memory block, it's hard coded to use
GFA's variable memory area. The list of string descriptors however will end up
(in theory) in the external memory block, thus I suspect this technique would
only relocate 6 bytes per element. Thus:
DIM t$(24) -> MALLOC(4+((24+1)*6)) !assuming option base 0
I don't see much benefit in this, therefore I never bothered to test it.