68000 software - high-level language interface
When input/output devices are addressed, virtual addresses cannot be used. Only physical addresses can be used and a user is unable to directly access physical addresses for security reasons.
In such cases, a user must request the operating system to perform the data transfer, as only the operating system (running under Supervisor status) has the necessary privilege to bypass the address translation of a PMMU.
This is achieved by the use of a set of predefined TRAP calls and device drivers.
One example is given below which is a call to a Unix function to create a file called
name with a mode which specifies whether the file is for read-only,
read-write, write-only or to append data, for example. TRAP #0 is the trap for
file-system requests, the parameter given in register D0 specifies the file operation
(8=create, 6=close etc.).
creat(char *name, int mode); /* this is the C call to the O.S. */
;the compiler converts this to machine code as follows:
movl #8, d0
movl #name, a0
movl mode d1
trap #0
On return from the trap, a file descriptor is returned in D0.
|
Passing parameters
Parameters are normally passed from one routine to another, using the stack.
For example:
is a function call which places the parameters on the stack in
reverse order, followed by the
return address for the ensuing JSR instruction.
The Stack Pointer (SP) is left pointing to the return address (RA) entry.
The called routine (abcd) accesses parameters relative to SP, i.e.
1st parameter is at | SP+4
|
2nd parameter is at | SP+8
|
3rd parameter is at | SP+12
|
In some RISC processors, the convention is to use registers rather than memory
to pass parameters. Since the number of parameters is unknown and may sometimes
be quite large, up to the first 4 parameters may be passed in registers and the
rest on the stack, as above.
LINK and UNLINK
Subroutines can often call other subroutines. In addition, automatic variables
are created on the stack. This can give rise to a complex set of data
saved on the stack. The stack needs to be restored to its original state
before the RTS is executed, as this needs to find a valid return address.
LINK and UNLINK are provided to create a stack frame and to enable the
stack to be restored quickly and easily.
The LINK instruction (e.g. LINK An, #-offset) causes the following actions:
An | --> | -(Sp) | push An onto the stack
|
SP | --> | An | copy Sp into An
|
SP+disp | --> | Sp | decrement Sp by offset
|
So LINK a6,#-16 has the following effect on the stack:
where Sp is left pointing to the new TOS, a6 (the link register) points to
the old a6 location and 4 words are reserved on the stack for
the subroutine's use. These locations will never be overwritten by the
stack during the execution of this subroutine.
Software example
An example is given of how a high-level language (such as C) is interfaced to a microprocessor operating system (such as Unix).
Particular attention is given to how variables are stored and how a paged memory management unit affects the software.
main()
{
int x,y;
char z;
.
abcd(x, y, z);
.
}
|
abcd(int u, int v, char w)
{
int a;
.
.
.
}
|
If the subroutine abcd() were written instead in 68000 assembly language, to run on a 68000-based paged memory management systems, the following instructions are necessary.
The stack locations used in this example were given in the lecture.
Note 1
Note 2
Note 3
Note 4
Note 5
Note 6
Note 7
Note 8
Note 9
Note 10
Note 11
|
regs
rmask
_abcd:
|
=16
=0xc3
link a6,#-regs
tstb sp@(-136)
.
.
moveml #rmask, a6@(-regs)
.
movl a6@(8), a2
movl a6@(12), a3
movl a6@(16), d0
.
subql #4, sp
.
.
movl d1, d0
moveml a6@(-regs), #rmask
unlk a6
rts
|
Note 1 | regs is a constant declaration
|
---|
Note 2 | rmask is a 16-bit value which determines the registers
which will be used in the later moveml instructions.
A7 | A6 | A5 | A4 | A3 | A2 | A1 | A0 |
D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
0 | 0 | 0 | 0 | 1 | 1 | 0 | 0 |
0 | 0 | 0 | 0 | 0 | 0 | 1 | 1 |
0xC3 = A3, A2, D1, D0
|
---|
Note 3 | The LINK instruction is explained above
|
---|
Note 4 | This instruction probes the stack just before
the moveml instruction. Should a page fault occur during
the move-multiple-register instruction, which is indivisible, then
this cannot be corrected. This is because the BERR trap which will
be entered as a result of the page fault also uses the stack.
So probing the stack 136 bytes further down
(in this example) should provoke a page fault if the stack is close
to a page boundary, and will ensure that sufficient RAM is available
to allow the stack to grow downwards.
|
---|
Note 5 | Here the registers a2, a1, d1, d0 are saved on the stack
(at ascending addresses) in the
memory locations reserved in the LINK instruction above. These registers are used
in the routine, so are saved before use. They will be restored later.
|
---|
Note 6 | The parameters passed on the stack are copied into registers for
use in this subroutine.
|
---|
Note 7 | The stack pointer is decremented to make space for the
automatic variable w.
|
---|
Note 8 | The result is held in d0 (as in the return() statement.
|
---|
Note 9 | This restores the registers saved in Note 5 above.
|
---|
Note 10 | UNLK copies a6 into Sp and then a6 is popped off the stack
restoring the old value. Sp is now pointing to the return address (RA).
|
---|
Note 11 | Return to the calling program using RA.
|
---|
Back