home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Falcon 030 Power 2
/
F030_POWER2.iso
/
ST_STE
/
MAGS
/
ICTARI08.ARJ
/
ictari.08
/
ASSEMBLY
/
TECH_1.TXT
< prev
Wrap
Text File
|
1994-02-27
|
10KB
|
166 lines
ASSEMBLER PROGRAMMING TECHNIQUES FOR THE ATARI ST
=================================================
by Peter Hibbs.
PASSING IN-LINE PARAMETERS TO SUB-ROUTINES
==========================================
In common with all micro-processors, the ATARIs 68000 processor uses
sub-routines for sections of code which may be repeated more than once
within a program and it is often necessary to pass data to a sub-
routine from the calling program.
There are several methods of passing data to a sub-routine. The
simplest method is to load the required values into data or address
registers and then call the sub-routine which then fetches the data
from these registers. This system is useful where the data values are
variable and sufficient registers are available but is not ideal where
a large amount of data (such as a string of text) is to be transferred.
Another method (which is used extensively by the ATARI GEM and BIOS) is
to push the data values (or the address of a string of data) onto the
stack and then the sub-routine has to recover the data from the stack.
This method is fairly flexible but is somewhat untidy especially where
several strings of data may need to be passed to the routine.
A third method (which does not seem to be used much in ATARI software)
is to pass the data as in-line data embedded in the calling program
immediately after the sub-routine call. This method is only suitable
for fixed data, however, since its value is determined at assembly
time. This system has the advantage though that the data concerned is
easily visible at the point in the program where it is used and not in
some look-up table somewhere else in the source code. Also the values
(such as the string data or addresses) can be easily altered during
program development.
This article describes this technique with an example of a sub-routine
which use in-line data. With the powerful instruction set of the 68000
processor the task of accessing the data in the calling program from
the sub-routine is quite simple. For example, consider the following
code where the data string 'text string',0 is to be passed to the sub-
routine PRINT which then sends it to the printer port.
bsr print call sub-routine
dc.b 'text string',0 data to be passd
even
The calling program calls the required sub-routine and immediately
follows it with the byte constants of the required string and
terminated with a NUL (0) character. Note that since the string
consists of byte size data it could end on an odd address which would
cause the processor to generate an 'address' error on return to the
calling program. The 'even' pseudo-instruction pads out the string with
a NUL character so that the next instruction after the call always
starts at an even address.
In the sub-routine the code would look something like this :-
print movem.l a0/d0,-(sp) save any registers
move.l 8(sp),a0 fetch string address
sub-routine code execute sub-routine
move.l a0,8(sp) a0=end of string+1
movem.l (sp)+,a0/d0 restore registers
rts return
When a sub-routine is called, the stack pointer is first decremented
and then the current return address is pushed onto the stack (4 bytes)
with the stack pointer pointing at the last byte saved. On entry to the
routine any registers which may be corrupted by the routine are first
pushed onto the stack (as required). The next instruction (using the
'address register indirect with displacement' addressing mode) copies
the return address from the stack into register a0. The displacement
value required in this case is 8 since the previous instruction saved 8
bytes (i.e. two longwords) onto the stack. Address register a0 will now
be pointing at the first byte of the data string in the calling program
code, the sub-routine fetches the data and processes it as required.
When all the data has been processed, address register a0 must be
pointing at the next word after the data string in the calling program
code (i.e. the next main program instruction).
At the end of the sub-routine the address in address register a0 is
copied back into the stack using the same displacement instruction so
that the return instruction will return program execution to the
correct point in the calling program. The saved registers are restored
and the RTS instruction returns control to the calling program.
The following sub-routine demonstrates a practical example of this
technique.
It is often necessary in programs to load a memory buffer with a text
string such as a filename or message. This example copies a string of
data bytes into a specified memory buffer. The calling program
specifies the address of the buffer (as one longword) followed by the
data string which is terminated with a NUL value. Since all data
strings in the ATARI operating system are usually terminated with a NUL
value, this character is also copied into the buffer as well as acting
as a terminator.
The format for the call from the main program is :-
bsr copy_string call sub-routine
dc.l buffer address of buffer
dc.b 'text string',0 string data+NUL
even ensure even address
.
.
buffer ds.b 20 destination buffer
The operation of the sub-routine is fairly self-explanatory, address
register a0 is used as a pointer to the data string, register a1 is
used as a pointer to the memory buffer and register d0 holds the data
between each fetch and store instruction.
One problem which arises when byte size data is being passed to a sub-
routine is that the data may end on an odd address. Since the processor
can only fetch instructions from even addresses, the return address
must be incremented to the next even address if it finishes on an odd
address but not changed if it finishes on an even address. When the
data transfer has been completed bit 0 of the address register a0 is
tested to see if it is a 1 (odd address) or 0 (even address).
Unfortunately, the 68000 instruction set does not include a bit test
instruction which allows this to be done on an address register so the
a0 register is first copied into the data register d0. The least
significant bit of d0 is tested and if it is a 0 the routine is
terminated after first restoring the saved registers. If the bit is a 1
(an odd address) the a0 register is incremented by one and the routine
terminated as before. The 'even' pseudo-instruction in the calling
program ensures that the processor fetches the next instruction from
the correct address.
COPY_STRING SUB-ROUTINE.
;ENTRY destination address defined as in-line data.
; data string defined as in-line data.
;EXIT string data copied into defined buffer
; no registers changed.
copy_string movem.l a0-a1/d0,-(sp) save regs (12 bytes)
move.l 12(sp),a0 fetch return address
move.l (a0)+,a1 fetch destination addr
copy_string1 move.b (a0)+,(a1)+ copy byte to buffer
bne copy_string1 was it 0 ?, no repeat
move.l a0,d0 copy a0 to d0
btst #0,d0 is address even ?
beq copy_string2 branch if yes
addq.l #1,a0 inc address if not
copy_string2 move.l a0,12(sp) copy ret addr to stack
movem.l (sp)+,a0-a1/d0 restore regs
rts return
The above routine was written with the DEVPAC 2 editor/assembler
program from HiSoft. There is one point that the programmer should note
however. When using the Monitor program to debug the main program, the
in-line data following the sub-routine will confuse the debugger
program when single stepping with the CTRL T option (executing a sub-
routine without stepping through it). When single stepping through a
program the CTRL Z option should be used and the sub-routine stepped
through otherwise the debugger program will try and execute the in-line
data as instructions.