[comp.sys.mac.programmer] >32k arrays

jackiw@cs.swarthmore.edu (Nick Jackiw) (06/29/90)

spellbinder@uwav1.u.washington.edu writes:
> 
> Here is a compiler question for those programmers out in net-land.
> 
>    type ArrayRecord = record
>                          arraySize : longint;
>                          signal : array [ 0..1 ] of real;
>                          end;
>         ArrayRecordPtr = ^ArrayRecord;
>         ArrayRecordHdl = ^ArrayRecordPtr;
> 
> The procedure knows how much data there is by getting the arraySize variable.
> 
> Now I'm writing this code in THINK Pascal version 2.03. It works fine when the
> amount of memory dedicated to the signal array is less than 32K, but when it
> gets bigger than this, then things start to mess up. So basically, for array
> sizes less than 8K data points, everything's fine. My idea is that THINK Pascal
> has a problem getting a value at an offset greater than 32K from the start
> of the variable. I have verified my idea by changing signal to become
> an array of double and an array of extended and each time the procedure
> craps out when the data exceeds 32K. My feeling is that the compiler is not
> generating the correct code to access values beyond 32K.
> 
> My questions are this:
> 
>    1) Is there another explanation for the problem?
> 
>    2) Are there any work arounds in THINK Pascal version 2.03?
> 
>    3) Will THINK Pascal 3.01 avoid the problem?
> 
> Thanks in advance.
> 
> Blair Zajac                    Zajac@phast.phys.washington.edu

Your diagnosis is correct: Pascal uses the 68K's "Address Register
Indirect With Displacement" addressing mode to access array data,
and this mode's displacement (the offset) is limited to a sign-
extended 16-bit displacement integer.  Thus, you're limited to 32K
arrays.

[A side note: in that it's sign-extended, it'd be possible to access
64K worth of data, if your base address was the arrayStart+32K, I think.
Not that any Pascal compiler I've seen does this, of course...]

The work around is the same for THINK 2 and 3--you'll have to calculate
your own offset.  The best way to do this is with a bit of inline
assembler:

type RealPtr=^real;

function MyData(Where:ArrayRecordHdl; Index:integer):realPtr;

inline $3017, $c0fc, $0004, $206f, $0002, $2050, $d1c0, $2f48, $0006, $5c4f;

To access your data, where formerly you used

   ArrayRecordHdl^^[50]

now use 

MyData(ArrayRecordHdl,50)^

Note that the third word of the in-line is $0004: this is the hardwired
size of a single element of data in byte (1 REAL=4 bytes). The code
compiles as:

	MOVE.W   (A7),D0	; Get the index off the stack
	MULU.W   #4,D0		; Multiply by the element size (32bit result)
	MOVEA.L	 2(A7),A0	; Get a handle to the array
	MOVEA.L	 (A0),A0	; Dereference it
	ADDA.L 	 D0,A0		; Add it to the calculated offset
	MOVE.L	 A0,6(A7)	; Put resulting ptr back on the stack
	ADDQ.W	 #6,A7		; and throw away arguments

Be sure to change $0004 to SizeOf(elem) if your elements ever change from
being real.  This code generates is a bit less efficient than Pascal's
native array indexing, but it gets you past the 32K problem. Note the
complete lack of range checking...hope it's okay.


--
---
jackiw@cs.swarthmore.edu  |  Smoggo: Can you prevent the detonation of
jackiw@swarthmr.bitnet    |          the thermonuclear device?
Applelink: D3717          |   Jimbo: No ... I cannot.