Jaap's Psion II Page

System services for the CM/XP part 1


Part 1:
Allocator cells and their system services.
    AL$FREE AL$GRAB AL$GROW AL$REPL
    AL$SHNK AL$SIZE AL$ZERO
Hardware services
    BT$NMDN BT$NMEN BT$NOF BT$NON
    BT$PPRG BT$SWOF
Sound services
    BZ$ALRM BZ$BELL BZ$TONE
Display services
    DP$EMIT DP$PRNT DP$REST DP$SAVE
    DP$STAT DP$VIEW DP$WRDY
Device services
    DV$BOOT DV$CLER DV$LKUP DV$LOAD DV$VECT
Editor services
    ED$EDIT ED$EPOS ED$VIEW
Error services
    ER$LKUP ER$MESS
File services
    FL$BACK FL$BCAT FL$BDEL FL$BOPN
    FL$BSAV FL$CATL FL$COPY FL$CRET
    FL$DELN FL$ERAS FL$FFND FL$FIND
    FL$FREC FL$NEXT FL$OPEN FL$PARS
    FL$READ FL$RECT FL$RENM FL$RSET
    FL$SETP FL$SIZE FL$WRIT
Complex Floating point services
    FN$ATAN FN$COS FN$EXP FN$LN
    FN$LOG FN$POWR FN$RND FN$SIN
    FN$SQRT FN$TAN

Part 2:
Table interpreter services.
    IT$GVAL IT$RADD IT$STRT IT$TADD
Keyboard services.
    KB$INIT KB$TEST KB$GETK KB$BREK
    KB$FLSH KB$UGET KB$STAT
Language services.
    LG$RLED LG$NEWP LN$STRT
Menu services.
    MN$DISP
Floating point arithmetic services.
    MT$BTOF MT$FADD MT$FBDC MT$FBEX
    MT$FBGN MT$FBIN MT$FDIV MT$FMUL
    MT$FNGT MT$FSUB
Pack services.
    PK$PKOF PK$QADD PK$RBYT PK$READ
    PK$RWRD PK$SADD PK$SAVE PK$SETP
    PK$SKIP
Run services.
    RM$RUNP
Top level services.
    TL$ADDI TL$CPYX TL$DELI TL$XXMD
    TL$RSTR TL$LSET
Timing services.
    TM$DAYV TM$TGET TM$UPDT TM$WAIT
Utility display services.
    UT$DDSP UT$DISP UT$CDSP
Utility services.
    UT$CPYB UT$ENTR UT$FILL UT$ICPB
    UT$ISBF UT$LEAV UT$SDIV UT$SMUL
    UT$SPLT UT$UDIV UT$UMUL UT$UTOB
    UT$XCAT UT$XTOB UT$YSNO

LZ Services
Hardware services
    BT$TOFF
Display services
    DP$CPRN DP$CSET DP$MSET DP$PVEW
    DP$UDG XT$BAR
Editor services
    TL$ZZMD
Error services
    ER$PRNT
File services
    FL$FDEL FL$GETX FL$NCAT FL$VALX
    FL$WCAT FL$WCPY FL$WDEL FL$WFND
    FL$WPAR XF$SORT XT$DIRM
Complex Floating point services
    FN$ASIN FN$ACOS FN$MAX FN$MEAN
    FN$MIN FN$STD FN$SUM FN$VAR
Keyboard services.
    KB$CONK
Language services.
    LG$EDIT LG$ENTR LN$XSTT
Menu services.
    MN$1DSP MN$TITL MN$XDSP
Timing services.
    TM$DNAM TM$MNAM TM$NDYS TM$TSET
    TM$WEEK
Top level services.
    AM$ENTR CA$ENTR DI$ENTR NT$ENTR
    TI$ENTR WL$ENTR XF$ENTR XT$ENTR
Utility services.
    UT$CMPB UT$SORT UT$WILD


Allocator cells and their system services.

The allocator cells allow you to reserve any amount memory of memory safely during the execution of a program. These cells each contain a certain amount of memory and can be grown or shrunk of more or less memory is needed. These cells lie adjacent in memory so by changing the size of a cell all cells above it will be moved up or down so that there is no unused memory between them. Thus the address of a cell is not fixed.

The start addresses of the 32 available cells are held in the system variables between $2000 and $203F. These addresses of these system variables are called tags. Thus the cell with tag $2000 has its base address stored at $2000. If a cell is not used, then zero is stored at the tag address.

Many of the cells are already permanently in use by the Psion. These are:

2000 Permanent cell, used for code/data from booted devices. The base address of this cell never moves so once code is loaded it will not be moved.
2002 Top level menu cell
2004 Diary cell
2006 Language text cell, used for editing/translating OPL/CALC.
2008 Symbol table cell, used when translating OPL/CALC.
200A Global record cell, used when translating OPL/CALC.
200C QCODE output cell, used when translating/running OPL/CALC.
200E Field name symbol table 1, contains field names for OPL file A.
2010 Field name symbol table 2, contains field names for OPL file B.
2012 Field name symbol table 3, contains field names for OPL file C.
2014 Field name symbol table 4, contains field names for OPL file D.
2016 File buffer 1, buffers for files opened in OPL.
2018 File buffer 2
201A File buffer 3
201C File buffer 4
201E Database cell, contains all data held in pack A:.
2020 Notepad cell. Used on LZ only.
2022 Dummy spreadsheet cell. LZ only.
2024-203E 14 free cells for use by applications

000 00 AL$FREE
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
OUTPUT: None.
UTW_S0-3=trashed
Frees a cell. A cell is freed by making its entry zero in the allocator table. This is the reverse of AL$GRAB. If the cell is already free, this has no effect.

001 01 AL$GRAB
INPUT: D=Size of space to allocate
OUTPUT: X=Tag of the cell allocated ($2000-$203E).
UTW_S0-3=trashed
Allocates a new memory cell. It returns 'No Alloc Cells' error 255 if all cells are already in use, and 'Out of Memory' 254 if there is not enough memory to get a cell of the requested size.

002 02 AL$GROW
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
D=Number of bytes the cell is to be grown
UTW_S0=Offset into cell where to insert the new bytes. Must not be larger than the length of the cell.
OUTPUT: None.
UTW_S0-3=trashed
Increases the size of a cell. Opposite of AL$SHNK. It returns 'Out of Memory' error 254 if there is not enough memory to grow the cell by the requested amount.

003 03 AL$REPL
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
UTW_S0=Offset into cell of the part to be replaced.
D=Size of part to be replaced. UTW_S0+D must not be larger than the size of the cell.
UTW_S1=Size of the new part.
OUTPUT: None.
UTW_S0-3=trashed
Changes the size of a cell by calling AL$GROW or AL$SHNK as appropriate. This is generally used when you wish to replace part of a cell by something which has a different length. It returns 'Out of Memory' error 254 if there is not enough memory to perform the requested action.

004 04 AL$SHNK
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
D=Number of bytes the cell is to be shrunk
UTW_S0=Offset into cell where to remove the new bytes. UTW_S0+D must not be larger than the length of the cell.
OUTPUT: None.
UTW_S0-3=trashed
Decreases the size of a cell. Opposite of AL$GROW.

005 05 AL$SIZE
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
OUTPUT: D=Size of the cell.
X=Preserved
UTW_S0=trashed
Returns the size of a cell.

006 06 AL$ZERO
INPUT: X=Tag of the cell, must be in the correct range, ($2000-$203E).
OUTPUT: None.
UTW_S0-3=trashed
Shrinks a cell to zero size but does not de-allocate it.

Hardware services

007 07 BT$NMDN
INPUT: None
OUTPUT: D,X=Preserved
Switches off the non-maskable interrupts. To enable them again use the BT$NMEN service. This is a very unusual feature as in most computers the non-maskable interrupts by their very nature cannot be disabled. The NMI's are used to control the system clock, so by using this service the system time will be invalid. To switch off the NMI's without losing the system time you must use BT$NOF instead.

008 08 BT$NMEN
INPUT: None
OUTPUT: D,X=Preserved
Enables NMI's which have been switched off by BT$NMDN.

009 09 BT$NOF
INPUT: None
OUTPUT: D,X=Preserved
Switches off the non-maskable interrupts but without losing the system time. To enable them again use the BT$NON service. The system clock will not be updated while the NMI's are off, but the number of NMI's that would have occurred are counted. When the NMI's are enabled the clock is then updated appropriately. The counter used to count the elapsed number of NMI's is the keyboard & clock counter so it is also used when scanning the keyboard. therefore the keyboard interrupts must also be disabled before this service is called and no keyboard system services should be used afterwards. Also, the counter can only count up to a value of 2048 so the NMI's should be enabled before 2048 seconds (about 34 minutes) have elapsed.

010 0A BT$NON
INPUT: None.
OUTPUT: None.
D,X=trashed
Enables NMI's which have been switched off by BT$NOF. Note that this service waits till the next NMI occurs so there may be a delay of up to one second.

011 0B BT$PPRG
INPUT: None.
OUTPUT: None.
D,X=Preserved
This system service routine will push or pop the seven system variables UTW_R0 to UTW_R6 ($4D - $5A) on the stack. This makes available some more scratch variables for you to use. This service needs one data byte which immediately follows the SWI 0B instruction. This data byte indicates which of the seven system variables are used and whether they are to be pushed on or pulled off the stack.

The byte contains this information in the following way:
BIT 7 - If set then pull the variables else push them.
BIT 6 - If set then push or pull UTW_R6 ($4D)
BIT 5 - If set then push or pull UTW_R5 ($4F)
BIT 4 - If set then push or pull UTW_R4 ($51)
BIT 3 - If set then push or pull UTW_R3 ($53)
BIT 2 - If set then push or pull UTW_R2 ($55)
BIT 1 - If set then push or pull UTW_R1 ($57)
BIT 0 - If set then push or pull UTW_R0 ($59)

This is best illustrated by an example of its use:
OS BT$PPRG DATA $3 Saves UTW_R1 and UTW_R0 on the stack ... ... Routine which can use $57-$5A ... OS BT$PPRG DATA $83 Restores UTW_R1 and UTW_R0 from the stack

Note that no RTS is used. When saving variables the service call returns to the next instruction after the data byte, but when restoring the variables, it will act as a RTS instruction.

012 0C BT$SWOF
INPUT: None.
OUTPUT: None.
D,X=trashed
Switches off the Psion, like the main menu OFF option. When switched on again, program execution continues with the instruction immediately following the SWI $0C instruction.

Sound services.

013 0D BZ$ALRM
INPUT: None.
OUTPUT: None.
D,X=trashed
UTW_Sx=preserved
Emits the normal ALARM noise. Note that keyboard interrupts are disabled temporarily.

014 0E BZ$BELL
INPUT: None.
OUTPUT: None.
D,X=trashed
UTW_Sx=preserved
Emits a standard beep, the same as if control character 16 has been printed. This service simply uses the BZ$TONE routine with the values X=$0032 and D=$0038. Note that keyboard interrupts are disabled temporarily.

015 0F BZ$TONE
INPUT: D=Pitch of note
X=Length of note in milliseconds (0-$7FFF).
OUTPUT: None.
D,X=trashed
UTW_Sx=preserved
Emits a note. The frequency in Hertz can be calculated from D by the formula Freq = 921600 / ( 78 + 2 * D register ). Note that keyboard interrupts are disabled temporarily.

Display services.

016 10 DP$EMIT
INPUT: A=Ascii code of character to print
OUTPUT: None. All registers and scratch variables preserved.
Prints a single character. The cursor position will be updated, as will the display buffer. Note characters 0 to 7 will display UDG's and that control codes can be used (see introduction).

017 11 DP$PRNT
INPUT: X=Address of string to print
B=Length of string to print
OUTPUT: None.
X=points to byte following the string.
Prints the string by printing the characters one at a time using DP$EMIT.

018 12 DP$REST
INPUT: None.
OUTPUT: None.
X,D=trashed
UTW_S0-3=trashed
Restores the screen to its previously saved state. DP$SAVE must have been used first to save the screen position before this service is used. See DP$SAVE for further details.

019 13 DP$SAVE
INPUT: None.
OUTPUT: None.
X,D=trashed
UTW_S0-3=trashed
Saves the current screen contents and the cursor position and state. This information is stored at DPT_SAVE ($2090), DPB_SPOS ($67) and DPB_SCUS ($68) respectively. The original contents of these variables is overwritten. The screen can then be restored by the DP$REST service. This service is used during when an alarm is sounded, so you must make sure that no alarms will go off between your own DP$SAVE and DP$REST calls. Note that the LZ uses the 4 line buffer DPT_4SAV ($7F62) instead, even when in two line mode.

020 14 DP$STAT
INPUT: A=position to move cursor to (0-31 / 0-79 on LZ)
B=status to change cursor to:
  Bit 7 set for cursor on
  Bit 0 set if cursor is underline only
OUTPUT: None.
D=trashed
X=preserved
Moves the cursor and has changes its status. The values of A and B are stored at DPB_CPOS and DPB_CUST and the display updated by this service.

021 15 DP$VIEW
INPUT: X=Address of string to view, 0 for previous string.
A=Line to view string on (0-1 / 0-3 on LZ). Set bit 7 to disallow changing the scroll direction.
B=Length of string to view.
UTW_S0=Initial pause before scrolling (in 20th of a sec)
OUTPUT: B=Key pressed
Displays a string in the same way as the OPL VIEW instruction.

After exiting this service, it can be resumed where it left off by calling the service again with X equal to zero. In this case no other display routines should be used between the subsequent calls of this service. Never attempt to use X=0 on the initial call of this service.

Though the cursor is switched off during this service, the cursor status prior to the call is preserved. The cursor position is lost however.

022 16 DP$WRDY
INPUT: None
OUTPUT: None
X=preserved
UTW_S0=preserved
Waits until the system variable DPW_REDY is zero. This variable is decreased on every interrupt, so every 50ms. If the interrupts are disabled, this service will use its own 50ms delay routine instead and will therefore still work.

Device services.

A device is any pack or peripheral that contains boot code. When the Psion is cold booted, or when ON is pressed in the main menu, the DV$BOOT service will be performed. This loads in the boot code from that pack or peripheral into memory, trying the low Ram (0400-1FFF) first or else in the permanent allocator cell (with tag $2000).

Device code is split up into several separate routines, also called vectors. Three vectors have special meanings:
Vector 0 is the install vector. It is called by DV$BOOT as soon as it has loaded the code into memory. It is used for example to add an item to the main menu.
Vector 1 is the remove vector. It is called by DV$CLER. After it has been called, it must be safe for the code to be removed from memory. It is used for example to remove an item from the main menu.
Vector 2 is the language vector. It is called in OPL whenever a procedure name has been encountered. The Psion first checks all devices to see if one of these will accept it, only then does it look for procedures of that name. This is used to add extra commands to the language. See DV$LKUP.

Further vectors are generally used for the extra commands that vector 2 accepts. See DV$LKUP and DV$VECT for more information.

Device code is stored on a pack in Psion relocatable code format. This consists of the following:
  A word containing length of the code,
  the code itself,
  a word checksum, the sum of all the bytes of the code
  a word containing the number of fix-ups,
  a list of fix-ups (0000 specifying the first word of the code block)
  a word checksum, the sum of all the fix-ups in the fix-up list

The code block is such that all absolute jumps and other absolute references are coded as if the block was at address 0. The fix-up list contains the addresses of those absolute references, again with 0000 specifying the first word of the code. When the code is loaded into memory, the fix-up list is used to adjust all the absolute references so that the code will run properly. Relocatable code is loaded by the service DV$LOAD, and DV$BOOT uses that to load the device code. Device code is in relocatable format, and its code block consists of the following:
0/1  Program length. When loaded into memory, the program length is stored here so that the services can skip through the device code of all the devices easily.
2  Pack. When loaded into memory, the pack that this device is on is stored here. The device code can use this to look up data from its pack without having to load it permanently into memory. This allows for code to be written using overlays, to minimise the amount of memory the code uses at any one time.
3  Device number. Same as in the pack header. This number should be unique amongst the devices connected to the organiser.
4  Version number. Same as in the pack header.
5  Number of vectors. Usually at least 3.
6+  Vector list. List containing the address of each vector. These addresses must be fixed-up.
?  Rest of code.

023 17 DV$BOOT
INPUT: None.
OUTPUT: None.
D,X=trashed
UTW_S0=trashed
Boots all devices which are plugged into the Organiser. First DV$CLER is called to deactivate all previous device code, and the code is removed from memory. Then the current devices are checked, and code is loaded into memory using DV$LOAD. The devices are loaded in order of the priority byte in the pack header. Note that if an error occurs it is handled immediately, by saving the screen contents (using DP$SAVE), displaying the error message (using ER$MESS), and restoring the screen contents afterwards (DP$REST). On the LZ 2-line mode is used for printing by the remove or install device vectors unless the device routine itself sets the display to 4-line mode first.

024 18 DV$CLER
INPUT: None.
OUTPUT: None.
D,X=trashed
UTW_S0-5=trashed
The Remove vector (vector 1) is called of all of the devices that are currently in memory. After this has been done, all the device code can be removed from memory because all the device code is no longer active. The code is not removed however. To remove it, zero the permanent cell, and set dva_top ($232B) equal to dva_bot ($2329). Note that on the LZ 2-line mode is used for printing by the remove device vectors unless the device routine itself sets the display to 4-line mode.

025 19 DV$LKUP
INPUT: X=Address of lbc string of procedure name.
OUTPUT: A=Device number
B=Vector number
UTW_S0-5=trashed
The language vector (vector 2) of each of the devices is called, so that it can check if the procedure name it is given should be accepted by the device. If the device accepts the procedure name, its language vector returns its device number and the vector that handles the task of that procedure in registers A and B respectively, so this can then be returned by DV$LKUP. If the device refuses the procedure, then it should return with the carry flag set. If DV$LKUP finds that no device will handle the procedure name, a 'Device Missing' error 230 is returned, and the carry flag is set. Note that if a device is willing to handle the task, then the carry flag is clear and A and B are set correctly for DV$VECT to be called immediately. This is how peripherals like the Comms link adds extra commands to the OPL language.

026 1A DV$LOAD
INPUT: X=Pack address of relocatable code block.
D=Memory address at which to load the relocatable code block.
UTW_S0=Address used to fix up the relocatable code block.
OUTPUT: None.
Loads a relocatable code block from a pack into memory, and fixes up all the specified absolute addresses in the code. The absolute addresses are fixed up by adding UTW_S0 to them. Thus UTW_S0 is the intended execution address, i.e. the address where the code is expected to be when it is finally run. Normally this is the same as D, the address where this service loads the code. This service assumes that the correct pack has already been activated with the PK$SETP service.

The following errors can be generated:
200 bad read error
229 device load error
240 unknown pack type
242 pack has changed
243 bad device name
246 no pack in slot

027 1B DV$VECT
INPUT: A=Device number
B=Vector number
X,UTW_S0=data to be passed to the device routine
(UTW_S1-4=trashed on entry to device routine)
OUTPUT: Depends on vector routine.
Finds and calls a vector routine of a device. If the device is not found, then the 'Device Missing' error 230 is returned. If the device is found but there are fewer than B vectors supported then 'Bad Device Call' error 231 is returned. Otherwise the appropriate part of the device code is run. Note that the X register and UTW_S0 is passed on to the device routine, so that these can contain parameters for the routine. The device vector routine can return values in the registers, flags or scratch variables, and these are passed on unchanged by DV$VECT.

The following errors can be generated:
230 device missing
231 bad device call
and any others that the device may return.


Editor services.

028 1C ED$EDIT
INPUT: See ED$EPOS below.
OUTPUT: See ED$EPOS below.
Calls the line-editor ED$EPOS with the cursor position on the first character of the editing string. See there for full details and entry requirements.

029 1D ED$EPOS
INPUT: A=Flags:
  Bit 0 set for multi-line editing, clear for single-line.
  Bit 1 set for up/down to exit editor in single-line editing. LZ only.
  Bit 7 clear for MODE to exit editor, set if MODE to be ignored.
B=Maximum allowed length of the edited string.
X=ignored.
RTT_BF=String to be edited.
UTW_S0=Initial cursor position, 0=start of string, any number past end places cursor at end of string.
OUTPUT: B=keypress used to exit editor.
RTT_BF=Edited string.
A,X=trashed.
Calls the built in editor.
There are two editing modes, single-line and multi-line editing. In multi-line editing, the up and down arrow keys move to another line. The down arrow key will also create a new empty line if necessary when at the bottom of the editing string. In single-line editing, the up and down keys move the cursor to the start and end of the line (unless otherwise specified on the LZ organiser). In multi-line editing, the lines are separated in the buffer by TABs (i.e. character 9). TAB characters should not be used in the initial editing string when single-line editing is requested. The editing will occur on the screen at the current cursor position, and any text to the left (and also above in multi-line editing) is treated as a prompt. Before editing starts, the editing area to the right of the cursor position (and also below in multi-line editing) is cleared.

030 1E ED$VIEW
INPUT: X=Non-zero for first call, zero to continue display of same string.
RTT_BF=String to display.
UTW_S0=Initial pause before scrolling (in 20th of a sec)
OUTPUT: B=keypress used to exit editor.
Clears the screen and then displays a string in the same way as the OPL function DISP. The lines are separated by TABs (character 9). The arrow keys control which line is being scrolled and its direction. If another key is pressed, the service exits. The X register must be non-zero when the service is first called. If called again with X zero, the display will continue at the point it was interrupted.

Error services.

031 1F ER$LKUP
INPUT: B=Error code to look up.
OUTPUT: X=lbc string of error message.
D=trashed
UTW-Sx=preserved.
Gives the error message belonging to an error code, like the OPL function ERR$. If the error code has no standard error message then the default message '*** ERROR ***' (or 'UNKNOWN ERR x' on an LZ) is returned.

032 20 ER$MESS
INPUT: B=Error code to look up.
OUTPUT: None.
X=preserved
D=trashed
Displays an error message and the string 'press SPACE key' and then waits for the space or ON/CLEAR key to be pressed. Note that with error number 194, the low battery error, the organiser will be switched off after four seconds. The LZ in 4-line mode will use all four lines of the display.

File services.

Programmers should note that calls to the FL$ services are allowed to be interspersed with PK$ calls - which may change currently selected device or change the current pack address - provided that PK$SETP is called to re-select the correct device for the file system before calling any further FL$ services. As always, any programs directly accessing the datapack hardware should notify the OS by calling PK$SETP.

033 21 FL$BACK
INPUT: None
OUTPUT: X=new current record number
D=preserved
Performs like the OPL command BACK, setting the current record number to the previous record. Should not be called when FLW_CREC = 0 or 1 because then there is no previous record. On exit X contains the new current record number, i.e. the new value of FLW_CREC. Register D is preserved.

034 22 FL$BCAT
INPUT: A=1 on the first call, 0 for subsequent calls.
B=pack (0-3)
X=Address to store result (which will be lbc string of filename, in form 'D:NAME')
UTW_S0l=File type to look for (81-8F)
OUTPUT: None.
Performs much like the OPL function DIR$ except that it works on all file types. When called, this service will store the name of the next file it finds. Register A should contain 1 on the first call to FL$BCAT so that the search can be initialised, and 0 on subsequent calls so that the search will be continued from where it left off. If no more files are found then the service exits with the error 'FILE NOT FOUND', 238. Note that calling this service to look for files of type $81 is equivalent to using FL$CATL.

The following errors can be generated:
238 file not found (normal completion of service)
194 battery too low
200 read pack error
237 bad record type
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

035 23 FL$BDEL
INPUT: X=address of filename (lbc string of form 'D:NAME')
B=file type (must be in range $82-$8F)
OUTPUT: None.
Deletes a block file, i.e. a file of type between $82 and $8F. If a file is removed from a RAM device then the space the file used is freed up. This service can not be used to delete files of type $81. For ordinary files the service FL$DELN is used instead. LZ users, see also FL$WDEL.

The following errors can be generated:
194 battery too low
200 read pack error
234 file not found
236 bad file name
237 bad record type
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

036 24 FL$BOPN
INPUT: X=address of filename (lbc string of form 'D:NAME')
B=block file type ($82-$8F)
OUTPUT: D=length of data block in file
Opens a block file. On exit, the current pack and pack address are set so that the data can be read immediately using PK$READ. If the file does not exist then a 'FILE NOT FOUND' error 234 is returned.

The following errors can be generated:
194 battery too low
200 read pack error
234 file not found
236 bad file name
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

037 25 FL$BSAV
INPUT: X=address of filename (lbc string of form 'D:NAME')
B=block file type ($82-$8F)
UTW_S0=length of data block
OUTPUT: None.
Saves the block file name and length in preparation for saving the actual data block of the file. On exit, the current pack and pack address is all set for PK$SAVE to save the data block of the file. This service does check whether the file fits on the device before writing anything.

The following errors can be generated:
194 battery too low
200 read pack error
235 file exists
236 bad file name
239 pack full
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

038 26 FL$CATL
INPUT: A=1 on the first call, 0 for subsequent calls.
B=pack (0-3)
X=Address to store result (which will be lbc string of filename, in form 'D:NAME')
OUTPUT: None.
Performs like the OPL function DIR$. When called, this service will store the name of the next ordinary file found. Register A should contain 1 on the first call to FL$CATL so that the search can be initialised, and 0 on subsequent calls so that the search will be continued from where it left off. If no more files are found then the service exits with error 238, 'FILE NOT FOUND'. Note that a similar service for other file types is performed by FL$BCAT.

The following errors can be generated:
238 file not found (normal completion of service)
194 battery too low
200 read pack error
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

039 27 FL$COPY
INPUT: D=address of source filename (lbc string of form 'D:NAME' or 'D:')
X=address of target filename (lbc string of form 'D:NAME' or 'D:')
UTW_S0h=block file type ($82-$8F) or 0 for ordinary files.
UTW_S0l=contains 1 for object only procedure copy, 0 otherwise.
OUTPUT: None.
Copies ordinary files or block files from one device to another, like the OPL command COPY. If the target filename is different from the source name then the file is in effect renamed. Note that because this service does not change the data block in any way, a procedure will still show the old filename when printed. If the target filename contains only the target device name then the file will be copied with the same name. If both filenames contain only device names, then all relevant files will be copied. If an ordinary file is copied, and the target device already contains a file of the same name then the records will be appended. If this happens with a block file then it will overwrite the file on the target device. LZ users, see also FL$WCPY.

The following errors can be generated:
194 battery too low
200 read pack error
232 pak not copyable
233 directory full
234 file not found
236 bad file name
238 end of file
239 pack full
240 unknown pack
241 pack not blank
242 pak changed
243 bad device name
244 read only pack
245 write pack error
246 no pack

040 28 FL$CRET
INPUT: X=address of filename (lbc string of form 'D:NAME')
OUTPUT: A=record type of file
Creates an ordinary file, like the OPL command CREATE. If a file of the given name already exists then an error 235 'FILE EXISTS' is returned.

The following errors can be generated:
194 battery too low
200 read pack error
233 directory full
235 file exists
236 bad file name
239 pack full
240 unknown pack
241 pack not blank
242 pak changed
243 bad device name
244 read only pack
245 write pack error
246 no pack

041 29 FL$DELN
INPUT: X=address of filename (lbc string of form 'D:NAME')
OUTPUT: None.
Delete an ordinary file like the OPL command DELETE. To delete block files the service FL$BDEL is used instead. LZ users, see also FL$WDEL.

The following errors can be generated:
194 battery too low
200 read pack error
234 file not found
236 bad file name
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

042 2A FL$ERAS
INPUT: None.
OUTPUT: None.
Erases the current record from the current file, like the OPL command ERASE. The current file position is not changed, even if the last record has just been erased. If an attempt is made to erase after the last record of the file then an 'END OF FILE' error 238 is returned.

The following errors can be generated:
194 battery too low
200 read pack error
237 bad record type
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

043 2B FL$FFND
INPUT: A=length of string to search for
B=file/record type to look through
X=address of string to search for
OUTPUT: None.
Tries to find a record of a given type on the current pack which starts with a given string. The search begins at the start of the pack and stops at the first match, or when no matches are found at all. If a matching record is found, the whole record is stored at RTB_BL as a lbc string. If there is no match an 'END OF FILE' error 238 is returned. This service is normally used to check whether a particular filename exists on a pack. In this case, B is a file type between $81 and $8F, and the string is the beginning of a filename. Note that searching for the string 'ABC' will find the name 'ABCD' too. Since filenames are stored as 8 byte string padded with spaces if necessary, searching for 'ABC     ' will only find the correctly named file. This service can also be used for ordinary file records, in which case register B is the data record type of the file to search through so must be in the range $90-$FE. The FL$FIND service is more flexible in this respect however.

The following errors can be generated:
194 battery too low
200 read pack error
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

044 2C FL$FIND
INPUT: D=address of lbc string to search for
X=address to store record found, as lbc string
OUTPUT: A=current record type
Searches the current datapack for the next record of the current type containing a given string. This therefore works exactly like the OPL command FIND, in that it find the next occurrence of a string in a particular file. If a matching record is found, it becomes the current one, and its contents are stored at address X. If there is no match, the file position is left at the end of the file and an 'END OF FILE' error 238 is returned.

The following errors can be generated:
194 battery too low
200 read pack error
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

045 2D FL$FREC
INPUT: D=record number to examine
OUTPUT: A=length of the record
B=current record type
X=low bytes of pack address of record
UTW_S0=high byte of pack address of record
Returns information about the D'th record of the current record type on the current datapack. If the record is found then its three byte address and its length are returned. If no such record exists because there are less than D records on the pack then an "END OF FILE" error 238 is returned.

The following errors can be generated:
194 battery too low
200 read pack error
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

046 2E FL$NEXT
INPUT: None.
OUTPUT: None.
Moves to the next record in the current file by incrementing the current record number. This service is like the OPL command NEXT. It does not perform any checks to see is the end of the file has been reached or passed. This will be checked for when the file is next accessed.

047 2F FL$OPEN
INPUT: X=address of filename (lbc string of form 'D:NAME' or 'NAME')
OUTPUT: A=record type of file
Opens an existing ordinary file. If the device is not named, the file is assumed to be on the current device. If the file does not exist a "FILE NOT FOUND" error is returned.

The following errors can be generated:
194 battery too low
200 read pack error
234 file not found
236 bad file name
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

048 30 FL$PARS
INPUT: X=address of filename (lbc string of form 'D:NAME' or 'NAME')
D=address to store standard format filename
UTW_S0h=default device if no device given in name.
OUTPUT: None.
Checks whether a file name is legal, and if so it is converted to a standard format. This format is a 9 byte string; a device byte (0-3) followed by a filename which has been padded with spaces to make it 8 characters long. The errors "BAD FILE NAME" 236, or "BAD DEVICE NAME" 243 will be returned if the filename or the default device is illegal.

The following errors can be generated:
236 bad file name
243 bad device name

049 31 FL$READ
INPUT: X=Address to store the record
OUTPUT: B=Record type
Reads in the current record, storing it in memory. Note that the current record number is not altered.

The following errors can be generated:
194 battery too low
200 read pack error
238 end of file
240 unknown pack
241 pack not blank
243 bad device name
245 write pack error
246 no pack

050 32 FL$RECT
INPUT: B=Record type (must be $81-$FE)
OUTPUT: None.
Sets the current record type. This is normally set to a value in the range $90-$FE, the record data types of ordinary files. Note that record type $90 is always the MAIN file. However, by choosing a value in the $81-$8F range the filename records will be used by later file services instead.

051 33 FL$RENM
INPUT: D=new filename (lbc string in form 'D:NAME' or 'NAME')
X=old filename (lbc string in form 'D:NAME' or 'NAME')
OUTPUT: None.
Renames an ordinary file, by deleting the old filename record and saving a new one. If both filenames include device names, then the device names must be the same. If the old filename does not include a device name then the current device is assumed. The new filename cannot consist of a device name only. If the devices differ or a filename is illegal then a 'BAD FILE NAME' error is returned.

The following errors can be generated:
194 battery too low
200 read pack error
234 file not found
235 file exists
236 bad file name
239 pack full
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

052 34 FL$RSET
INPUT: D=record number to make current
OUTPUT: None.
Sets the current file position, like the OPL command POSITION. The first record is number 1, and no attempt should be made to set the record number to 0. Like FL$NEXT, this service does not check whether the new current record exists. This will be checked when the non-existent record is accessed.

053 35 FL$SETP
INPUT: B=pack (must be in range 0-3)
OUTPUT: None.
Selects the pack which future file services are to use.

054 36 FL$SIZE
INPUT: None
OUTPUT: X=number of records of the current record type
UTW_S1h=high byte of amount of free space
D=lowest bytes of amount of free space
UTW_S1l=high byte of pack address
UTW_S0=lowest bytes of pack address
Returns the amount of free space the current datapack and where the first free byte is. It also returns the number of records of the current record type. Thus if the record type is between $81 and $8F the number of files of that type is returned, and if the record type is $90 to $FE then the number of data records in the file using that record type is returned. This service is used by the OPL commands SPACE, LAST, and COUNT.

The following errors can be generated:
194 battery too low
200 read pack error
240 unknown pack
241 pack not blank
243 bad device name
244 read only pack
245 write pack error
246 no pack

055 37 FL$WRIT
INPUT: X=Address of lbc string containing data to be saved (max 254 chars, truncated if 255 chars used)
OUTPUT: None.
Appends a new record of the current record type to the current device, much like the OPL command APPEND. The current record number changed so that the record just written becomes the current one. The amount of available free space is checked first to see if the record fits on the pack.

The following errors can be generated:
194 battery too low
200 read pack error
232 pak not copyable
233 directory full
234 file not found
236 bad file name
238 end of file
239 pack full
240 unknown pack
241 pack not blank
242 pak changed
243 bad device name
244 read only pack
245 write pack error
246 no pack


Floating point services.

The following services use the run-time stack, also called the language stack. Its stack pointer is rta_sp ($A5/A6). It holds the address of the last byte of the stack. To push a floating point number onto the stack you must decrement the stack pointer by 8 and place the number in those 8 bytes from the pointer upwards. The services remove any numbers they need from the stack and place the result on it instead. The result is also left in the floating point accumulator ($C5-$CD).

Care must be taken to restore the stack to its previous state. If you push some values on the stack and maybe use these services for calculating from them, then afterwards the stack pointer must restored to the previous value. Any data higher up the stack must be preserved.

There are always at least $100 bytes available on the stack. Do not temporarily point the stack pointer to another memory area with floating point values unless there is at least 60 bytes below it for the services to use for intermediate results.

These services use the table interpreter (IT$STRT).

056 38 FN$ATAN
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its arctangent. Error 253 'exponent overflow' may be returned.

057 39 FN$COS
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its cosine. Error 247 'Function argument error' may be returned.

058 3A FN$EXP
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with the result gained from raising the constant e (2.718281828..) to the power of the given number. Error 247 'Function argument error' may be returned.

059 3B FN$LN
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its natural logarithm (i.e. base e). Error 247 'Function argument error' may be returned.

060 3C FN$LOG
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its logarithm (i.e. base 10). Error 247 'Function argument error' may be returned.

061 3D FN$POWR
INPUT: None
OUTPUT: None
Replaces two floating point numbers on the top of the run-time stack with the result gained be raising one to the power of the other. If X and Y are on the stack, and Y was pushed last, then this service will replace the two numbers with X**Y. Error 247 'Function argument error' may be returned.

062 3E FN$RND
INPUT: None
OUTPUT: None
Pushes a random number between 0 and 1 on the stack.

063 3F FN$SIN
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its sine. Error 247 'Function argument error' may be returned.

064 40 FN$SQRT
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its square root. Error 247 'Function argument error' may be returned.

065 41 FN$TAN
INPUT: None
OUTPUT: None
Replaces the floating point number on the top of the run-time stack with its tangent. Error 247 'Function argument error' may be returned.