BORG for a 68000 SBC - System and Library Calls

1. Introduction

There are three classes to consider:

  1. Trap 0 calls
  2. Other trap calls
  3. Library functions

You can look at the KeyTask code in BORG or in the included example tasks to see how the functions are used.

All these traps and library functions may return an error code for some reason. If no error was detected, then register d0 will contain 0 (zero) on return. Otherwise the value in d0 indicates the error. Error codes are always 32 bits. The leftmost 8 bits is a facility code, which indicates where (i.e. in which module or task) the error was detected. The rightmost 16 bits is the actual error code. Note that the 16-bit value is intended to be unique across the system. So each value has the same meaning wherever the error was detected.

On starting, a task may initialise a byte in the TCB called taskfac. This gives a code value under user control that may be used to identify tasks. In particular, if a task needs to crash BORG, and calls the library function to do that, the task's taskfac will apear in the crash code.

2. Trap 0 calls

Trap 0 calls are basic task functions such as create or terminate task. Registers are used to pass parameters. What the function does is controlled by the value passed in register d0. Parameters for the particular function are passed in d1, d2, a0, and a1, as required.

Note that the trap 0 calls are typically used by KeyTask for manipulating tasks. And trap 0 calls with d0 equal to 1, 2, or 3 are expected to be used only by the task termination code which is entered when a task needs to wind matters up gracefully. See the code for termtask within BORG.

Note also that a task cannot use d0 value 5 to terminate itself. A task needing to terminate need only revert the stack to its state when the task started, and execute an rts instruction.

3. Other trap calls

Other trap calls are for basic system functions such as memory allocation so these will be typically used by static or dynamic tasks.

4. Library functions

A set of simple functions is included with BORG to ease to process of writing the terminal I/O aspects of a task. This set of functions was the minimum set that was useful for creating KeyTask. There are two ways to access these functions:

  1. If your task will be part of the BORG source module, and so will be assembled with it, or if you use a separate source file but will link-edit that together with BORG as a single binary module, then you can just refer to the function names and use a bsr or jsr to reach them. This is how KeyTask operates.
  2. If the task will be an entirely separate module, then the library functions can be accessed via Trap 10. How this is done is described in section 5 below. The memory test example task uses the Trap 10 calls.

Where relevant, note that string related functions all use register a0 as the buffer address, which is updated after return from the function so that it may be used by a subsequent function.

The following are the functions and parameters:

5. Accessing library functions using Trap 10

When using Trap 10 calls to library functions, the registers used in the calling sequences are the same as detailed above. To distinguish between the various functions, it is necessary to follow the Trap 10 with a word containing a unique value. Each function has a value assigned to it. The following table gives the values (and could easily be included in any dynamic task):

; trap10table - include in your dynamic task
_strncpy:      equ       0                        ; underscore avoids any name confusion
_strlen:       equ       1
_bintodec:     equ       2
_bintodecl:    equ       3
_dectobin:     equ       4
_bintohex:     equ       5
_hextobin:     equ       6
_div64:        equ       7
_isalphanum:   equ       8
_isdec:        equ       9
_ishex:        equ       10
_echo:         equ       11
_newline:      equ       12
_readstr:      equ       13
_generrormsg:  equ       14
_errormsg:     equ       15
_crashborg:    equ       16

So, whereas a builtin task (such as KeyTask) might call a library function as follows:

               move.l    #keymdlen,d0             ; Report Module dropped OK
               lea       keymdmsg,a0
               movea.l   a6,a1                    ; Device address
               bsr       echo

instead, a dynamic task would need to replace the subroutine call to echo with the following:

               move.l    #keymdlen,d0             ; Report Module dropped OK
               lea       keymdmsg,a0
               movea.l   a6,a1                    ; Device address
               trap      #10
               dc.w      _echo