Jaap's Psion II Page

System services for the CM/XP part 2


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


Table interpreter services.

The following 4 services are used for table programs. A table consists of a list of bytes, which is interpreted by the IT$STRT service like a program. The advantage of this is that the user can supply a machine code subroutine to run for most table bytes, thus making the code more compact. Table programs are used in the ROM mainly for complex floating point system services (and for password codes on the LZ).

In a table program, the bytes $00-$14 have predetermined actions and the bytes $15-$FF are available for user defined actions. The first word of a table contains an offset to the list of addresses of the machine code subroutines that define the user actions. This list starts with the address that is to be called when action $15 is encountered, and ends with the address belonging to the highest defined action byte. The table program itself starts from the third byte of the table, i.e. immediately after the list offset.

The table program has 32 bytes of variable space assigned to it at ITT_REGS ($234D-$236C) and also its own independent stack area at ITT_STAK ($236D-$23AC).

Many actions need parameters and these of course usually follow immediately after the action byte. The predefined actions often use a single byte in the range $E0-$FF to denote the 32 byte variables, and numbers in the range $00-$DF as ordinary numbers. If an address in the table is given as a parameter then the address is given as an offset from the start of the table. Note that the start of the table is the word pointing to the user action address list, not the start of the table program.

The following functions are predefined:
00  RETURN: Return from a table subroutine, i.e. pulls a table address from the table stack and continues the table program there.
01  CALL: Calls a table subroutine also passing the given parameters. The action byte is followed by: - a byte denoting the number of bytes passed to the subroutine. - the subroutine address (as offset from table start) - the list of bytes to pass to the subroutine. The parameters to be passed are put in the table variables before calling the subroutine, so at most 32 bytes can be passed along, and the previous values of the variables $E0-$?? are overwritten. See also action 10.
02  BRANCH FALSE: Branches if the result of a previous comparison was false, see the actions 08 and 09. The relative jump following the action byte is different from the relative jumps in ordinary machine code, in that the branch is calculated from the current action byte. Thus a branch of 2 will do nothing. Negative branches are allowed.
03  BRANCH TRUE: Like action 02, except that it branches if the result of a previous comparison was true.
04  CASE: Jumps to one of a list table addresses depending on a variable. The action byte is followed by a variable ($E0-$FF) and a table address. The address points to a case-list which is in the following format: byte, table address; byte, table address; .... etc. If the variable matches one of the bytes on the list, CASE will cause a jump to the associated address. A byte of $FF can be used in the last list entry to denote the ELSE case, which will be called whenever the variable doesn't match any of the earlier entries.
05  VECTOR: Jumps to one of a list table addresses depending on a variable, like the BASIC instruction ON x GOTO. The action byte is followed by a variable, and a table address. The table address points to a list of table addresses. If the variable contains 0 the interpreter takes the first table address on the list and jumps to it, 1 uses the second address etc.
06  JUMP: Jumps to the given table address.
07  BRANCH: Branches a given distance. See action 02.
08  EQUAL: The action byte is followed by two bytes, which can be numbers or variables. This action tests whether the two values are equal.
09  UNEQUAL: The action byte is followed by two bytes, which can be numbers or variables. This action tests whether the two values are different.
0A  ASSIGN: The action byte is followed by a variable, and a byte value that may be either a number or a variable. This action assigns the value to the given variable.
0B  ADD: The action byte is followed by a variable, and a byte value that may be either a number or a variable. This action adds the value to the given variable.
0C  SUB: The action byte is followed by a variable, and a byte value that may be either a number or a variable. This action subtracts the value from the given variable.
0D  PUSH: Pushes the given address on the table stack. This first subtracts two from the stack pointer ITA_SPTR and then stores the given word at this new value of ITA_SPTR. See also action 0F.
0E  CALLMC: Calls the machine code routine at the given address. Note that the address is an absolute address, not a table offset. The variable $E0 is passed in the B register when the routine is called.
0F  POP: Pops a word off the table stack, by adding two to the stack pointer ITA_SPTR. Note that the value that was on the top of the stack is lost. For this reason, the table stack is not used for temporarily storing data, just for storing return addresses when table subroutines are called. User defined actions can use the stack for other purposes.
10  JSR: Calls the table subroutine at the given address, without passing any parameters. See also action 01. The subroutine is exited by the action 00.
11  RANGE: The action byte is followed by three bytes, which can be numbers or variables. This action tests whether the first value lies between the other two, i.e. whether v2<=v1<=v3.
12  PEEK: The action byte is followed by a variable and a table address. This action stores the contents of the table address in the variable.
13  POKE: The action byte is followed by a byte (variable or number) and a table address. This action stores the given value at the table address.
14  END: Ends the table program normally, returning to next instruction after the IT$STRT call with register B=0 and the zero flag set. This can also be called in a table subroutine.

The system variable ITA_PCNT ($D7) is used as a table program counter. At the start of a user action routine, ITA_PCNT still points to the action byte. The user routine must end with B containing the number to add to ITA_PCNT for it to point to the next table instruction (i.e. 1 if no parameters were used).
To quit the table program during a user action, pull one return address from the machine stack, load B with an error code and perform a RTS instruction.
The system variable ITA_SPTR ($DB) contains the table stack pointer, which contains the address of the last word pushed on the stack.
The system variable ITA_UVC ($234B) points to the absolute address of the list of user action addresses.
The system variable ITA_BAS ($D9) points to the absolute address of the table, i.e. the address given when IT$STRT was called.
The system variable ITA_TEST ($DD) contains the result of comparisons, i.e. the result from actions 08, 09 and 11. Actions 02 and 03 test whether this value is zero (false) or non-zero (true). User actions may of course use this byte in other ways.

066 42 IT$GVAL
INPUT: B=Offset to parameter (1=first byte after action byte)
OUTPUT: B=Contents of variable (if byte is $E0-$FF) or else parameter value
A,X=preserved
Used in user defined actions to get the value of a byte parameter.

067 43 IT$RADD
INPUT: B=Offset to parameter (1=first byte after action byte)
OUTPUT: X=Address of table variable
A,B=preserved
Used in user defined actions to get the memory address of a table variable that is passed as a parameter.

068 44 IT$STRT
INPUT: D=Address of table program
OUTPUT: B=error code or zero
This is the table interpreter. When called, it will start interpreting the given table program. The table program-counter ITA_PCNT always points to the current byte being interpreted, initially pointing to the third byte of the table. The table is interpreted until the END action (with value 20) is fetched, upon which IT$STRT returns with the B register cleared and the Z-flag set. User defined actions may quit the table program by pulling one return address from the machine stack, loading B with an error code and performing a RTS instruction. In this case IT$STRT will return with B containing the error code, and the zero flag set only if B=0. Note that this cannot be called recursively, i.e. from within a user defined action.

069 45 IT$TADD
INPUT: B=Offset to parameter (1=first byte after action byte)
OUTPUT: D=Parameter value
X=preserved
Used in user defined actions to get the value of a word parameter. Note that if the word is a table offset, then adding ITA_BAS will give the absolute address.

Keyboard services.

The keyboard is checked by the OCI interrupt routine, which normally occurs 20 times a second. The routine first calls the keyboard poll routine (its address is held in bta_poll, $205A), which scans the keyboard. If it reports that there are keys being pressed, then the keyboard translation routine (its address is held in bta_tran, $205C) is called which returns which character that corresponds to, taking into account the state of the Caps/Num locks, auto-repeat delays etc. The ascii value of the key is then saved in the keyboard buffer.

The keyboard buffer holds any keys that have been pressed until the organiser's software is ready to use them. It can contain up to 16 keys, and is found at kbt_buff, $20B0-F. It is a wraparound buffer, so it can be considered to be a loop without a fixed beginning. The offset to the oldest key is held in kbb_back ($73), the number of keys is kbb_nkys ($74).

073 49 KB$INIT
INPUT: None.
OUTPUT: None.
Initialises the keyboard interrupts. This is performed when the machine is cold booted. It does all the following things:
1. The keyboard buffer is cleared.
2. The keyboard interrupt rate KBW_TDEL is set to $B3DD (=50ms)
3. The auto-repeat variables KBB_DLAY, KBB_REPT are set to 14 and 0.
4. The keyboard status flags, in KBB_STAT are set to 0.
5. The length of the key click, KBB_CLIK, is set to 1.
6. The interrupts are enabled: FREE RUNNING COUNTER (i.e. Timer1) is cleared, TIMER 1 OUTPUT COMPARE REGISTER 1 is set to $B3DD (so that the first Output Compare Interrupt is in 50ms) bit 3 of TIMER 1 CONTROL STATUS REGISTER 1 is set, to enable the OCI interrupt, the I flag is cleared to enable all interrupts.

075 4B KB$TEST
INPUT: None.
OUTPUT: B=key, or 0 if no key found
A,X=preserved
Tests the keyboard buffer and returns the ASCII value of the key found, just like the OPL function KEY. This service is surprisingly complex: First it tries to find a key in the unget buffer, KBB_WAIT ($76). If a key is found there, the service returns it but does NOT clear the unget buffer. If the unget buffer is empty, it will then test the ordinary keyboard buffer. If a key is found there, the service returns it after removing it from the buffer and putting it in the unget buffer. If still no key has been found, then it does the following: 1. The packs are switched off using PK$PKOF, provided this option hasn't been disabled by clearing the variable KBB_PKOF ($20C1). 2. Auto switchoff is tested: If TMB_SWOF is non-zero (i.e. auto- switchoff is enabled) and TMW_TOUT is zero (i.e. the auto- switchoff time has elapsed) then BT$SWOF is called, switching off the Psion. 3. The battery is tested and if it is too low, the BATTERY TOO LOW error 194 is raised and the Psion switches off after 4 seconds. Normally the keyboard is polled during an OCI interrupt, but if the interrupts are disabled, this service will poll the keyboard itself before doing all the actions described above.

072 48 KB$GETK
INPUT: None.
OUTPUT: B=Key
A,X=preserved
Waits for a key to be pressed, and returns its ASCII value. This service performs the same list of tasks as KB$TEST, except that instead of returning zero when no key is pressed, it performs a SLP instruction to conserve power and again tests for a keypress. This is repeated until a keypress has been detected. Unlike KB$TEST, the key is removed from the unget buffer KBB_WAIT. This service also initialises the auto-switchoff timeout counter TMW_TOUT to the value of TMW_TCNT, so that it waits for the maximum possible time before switching off.

070 46 KB$BREK
INPUT: None.
OUTPUT: None.
Tests whether the ON/CLEAR key is pressed, and returns with the carry flag set if this is so. It tests this by testing the keyboard directly, and by testing the keyboard buffer. If ON has been pressed, it will wait until it is released, and flush the keyboard buffer.

071 47 KB$FLSH
INPUT: None.
OUTPUT: None.
Flushes the keyboard buffer. The variables KBB_BACK, KBB_NKYS, KBB_PREV and KBB_WAIT are all set to zero.

076 4C KB$UGET
INPUT: B=key to unget
OUTPUT: D,X=preserved
The ASCII value in the B register is put in the unget buffer, KBB_WAIT provided that buffer is empty. All registers are preserved.

074 4A KB$STAT
INPUT: B=new keyboard status
OUTPUT: None.
B=preserved
Sets the keyboard state. The value of B is put in KBB_STAT ($7B), and the display is updated to reflect this. To use this service, read the value of KBB_STAT, change the necessary bits, and call the service. The bits of KBB_STAT have the following meanings: Bit 0: Clear when Caps lock. Bit 1: Set when Caps, Num or Special lock is being pressed. Bit 2: Set when Special lock on. (i.e. shift-rightarrow, used for special symbols in foreign languages) Bit 3-5: Not Used Bit 6: Set when Num lock. Bit 7: Set when shift is pressed. Note that bits 0,2 and 6 can be safely changed. The other bits are best left unchanged. The shape of the cursor will be updated by this service if necessary.

Language services.

078 4E LG$RLED
INPUT: TT_FF=Name of file
TLB_MODE=command to be performed on file (3=EDIT, 4=LIST, 7=RUN, 8=DELETE)
LGB_LANT=file type ($82-$8F)
OUTPUT: None.
Performs one of the program menu commands RUN/LIST/EDIT/DELETE on an existing block file. Note that the RUN command can only be used on a procedure file (type $83) while the other commands can be applied to any text block file. The name of the file to use must be in the find buffer RTT_FF ($22C9). If the file does not exist, the error will be displayed immediately using the ER$MESS service. If a new file needs to be created, the LG$NEWP service should be used instead. The command to be performed on the file should be set in the system variable TLB_MODE ($A3). The following values are allowed: 3 to EDIT, 4 to LIST, 7 to RUN, and 8 to DELETE. The file type must be supplied in the system variable LGB_LANT ($23E0) and must me in the range $82-$8F. When the edit option is chosen then the file editor is used, so that pressing MODE will call up the editing menu which has the options TRAN,SAVE,QUIT (and Find,Home,End,Zap,Xtran on the LZ). To suppress the TRAN (and Xtran) options when non-OPL text files are edited, make the system variable LGB_MENU ($23E1) non-zero. When the editor is exited using the Save option, the edited file is saved, and if Quit is chosen the original file is preserved and any changes made are lost.

077 4D LG$NEWP
INPUT: As LG$RLED above
OUTPUT: None.
Makes a new text block file. Identical to LG$RLED except that a new file is created instead of an existing one being edited. Note that if Quit is chosen when exiting the editor, no new file is created.

079 4F LN$STRT
INPUT: B=function (0=tran proc, 1=tran calc, 2=locate error in calc, 3=loc err in proc)
X=offset in Q-code where error occurred (error-locating only, else ignored. Must be in range)
OUTPUT: B=error code if there is one.
X=offset in textcell where error occurred if there is one.
Qcode-cell=translated output if translating
Runs the translator. There are four functions available, values 0 and 1 mean the service will translate procedures or calculator expressions respectively. Values 2 and 3 mean that the service locates errors in calculator expressions or procedures respectively. When translating, the result is put in the QCode output cell, the allocator cell with tag $200C. If an error occurs, B is the error number and X is the offset to the error in the textcell (the alloc cell with tag $2006). On the LZ machines, the current display mode DPB_MODE determines whether the translation is for 2 or 4-line machines. LZ users, see also LN$XSTT.

Menu services.

080 50 MN$DISP
INPUT: X=Address of menu string.
D=Bit mask of keys that exit the menu (bit n set if char n+1 exits).
OUTPUT: B=keypress used to exit menu (gives Exe if a letter key was used)
UTW_S0=number of the chosen item (0=first item)
A=non-zero
  X=Address of menu item in the menu string.
A=zero
  X=Associated address of menu item
Displays a menu and allows a choice to be made, like the OPL function MENU. The menu string consists of a list of menu items, each with a leading byte-count and followed by an associated word. This word is usually the address of the relevant subroutine or zero. The top level menu uses zero for items associated with OPL procedures (the LZ also uses 1 for Notepad files, 2 for ordinary files). The menu list is terminated by a zero byte. The D register contains the terminating bit mask, which determines which keypresses exit the menu. If the nth bit is set then the key with code n+1 will exit the menu, so bit 0 corresponds to the ON/CLEAR key, bit 12 to the EXE key etc. Never call this service with D=0 or it can never be exited.

On exit, there are two possibilities. If register A is non-zero (generally 1) then the chosen menu item had a zero word associated with it. If register A is zero on exit, then the chosen menu item had a non-zero word associated with it.

If a letter has been pressed to choose the only item in the menu starting with that letter then the service acts as if EXE has been pressed (so that the service will exit with B=13 if bit 12 in the mask was set). Note that the keyboard is put into alpha shift.

On the LZ, the system variable MNB_CPTZ ($209C) is used to decide whether the menu should be capitalized or not when in 4-line mode. The default is 0, meaning that all menu's are capitalized. If it is 1, then all menu's are displayed exactly as they were stored.

An undocumented feature is that the menu routine uses dpb_vsiz ($65) to hold the number of items in the menu and dpb_vlin ($64) to hold the currently selected one (0=first item etc).


Floating point arithmetic services.

081 51 MT$BTOF
INPUT: X=Address of start of string to convert
D=Address to store floating point number
OUTPUT: X=Address of first unused character in string
D=trashed
Converts an ASCII string to a floating point number, like the OPL function VAL. Note that the first character in the string that cannot be incorporated in the number signifies the end of the number, so no length need to passed to the service. Error 252 'string to number error' may be returned.

082 52 MT$FADD
INPUT: Acc=First floating point number
Oper=Second floating point number
OUTPUT: Acc=Sum of the two floating point numbers
Adds two floating point numbers. The numbers are in the fp operator and the fp accumulator, and the result is left in the fp accumulator. Error 253 'exponent overflow' may be returned.

083 53 MT$FBDC
INPUT: A=Maximum length of output string
B=Number of decimal places needed
X=Address to store the resulting string
OUTPUT: B=Length of string
Converts the floating point accumulator into an ASCII string in decimal format, i.e. without an exponent and rounded off to a fixed number of decimal places, somewhat like the OPL function FIX$. Error 250 'Number to string error' may be returned.

084 54 MT$FBEX
INPUT: A=Maximum length of output string
B=Number of decimal places needed
X=Address to store the resulting string
OUTPUT: B=Length of string
Converts the floating point accumulator into an ASCII string in exponential format, i.e. with an exponent and rounded off to a fixed number of decimal places, somewhat like the OPL function SCI$. Error 250 'Number to string error' may be returned.

085 55 MT$FBGN
INPUT: A=Maximum length of output string
B=Number of decimal places needed, negative if no fixed point.
X=Address to store the resulting string
OUTPUT: B=Length of string
Converts the floating point accumulator into an ASCII string in general format, i.e. whichever of the three standard formats is most suitable, somewhat like the OPL function GEN$. Error 250 'Number to string error' may be returned.

086 56 MT$FBIN
INPUT: A=Maximum length of output string
X=Address to store the resulting string
OUTPUT: B=Length of string
Converts the floating point accumulator into an ASCII string in integer format, i.e. without an exponent and rounded off to an integer, somewhat like the OPL function NUM$. Error 250 'Number to string error' may be returned.

087 57 MT$FDIV
INPUT: Acc=First floating point number
Oper=Second floating point number
OUTPUT: Acc=Result of the division of operator by accumulator.
Divides two floating point numbers. Errors 253 'exponent overflow' and 251 (divide by zero) may be returned.

088 58 MT$FMUL
INPUT: Acc=First floating point number
Oper=Second floating point number
OUTPUT: Acc=Product of operator and accumulator.
Oper=preserved
Multiplies two floating point numbers. Error 253 'exponent overflow' may be returned.

089 59 MT$FNGT
INPUT: X=Address of floating point number to negate (has 7 byte mantissa)
OUTPUT: None.
B,X=preserved
Negates a floating point number. Note that the number is assumed to have a mantissa of seven bytes, so for numbers with a 6 byte mantissa X must point to the address one byte below the number.

090 5A MT$FSUB
INPUT: Acc=First floating point number
Oper=Second floating point number
OUTPUT: Acc=Result of the subtraction of operator from accumulator.
Subtracts two floating point numbers. Note that this routine simply calls MT$FADD after negating the operator. Error 253 'exponent overflow' may be returned.

Pack services.

091 5B PK$PKOF
INPUT: None
OUTPUT: None.
Turns off all packs. PK$SETP or PK$SADD must be called before using the packs again.

092 5C PK$QADD
INPUT: None
OUTPUT: B=Highest byte of pack address (will always be 0 on CM organiser)
X=Lowest bytes of pack address
Returns the current pack address.

093 5D PK$RBYT
INPUT: None
OUTPUT: B=Byte read from pack
A,X=preserved
Reads a single byte from the current position in the current pack. The current pack position is incremented by one. Care must be taken not to read past the end of the pack.

094 5E PK$READ
INPUT: D=Number of byte to read from pack
X=Address to copy the bytes to.
OUTPUT: None.
Copies a number of consecutive bytes from the current position on the current pack to memory. The current pack position is updated to point the next available byte. Note that if the slot has not been previously selected by PK$SETP then garbage will be returned.

095 5F PK$RWRD
INPUT: None
OUTPUT: D=Word read from pack
X=preserved
Reads a word from the current position in the current pack. The current pack position is incremented by two. Care must be taken not to read past the end of the pack.

096 60 PK$SADD
INPUT: B=High byte of address to set pack to (ignored on CM)
X=Lowest bytes of address to set pack to
OUTPUT: None.
Sets the current pack address. If necessary the PK$SETP will be called first to power up the packs. If the address is past the end of the pack then a Bad Read Error is generated and the pack address is indeterminate.

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

097 61 PK$SAVE
INPUT: D=Number of bytes to save
X=Memory address of bytes to save
OUTPUT: None.
Copy a block of consecutive bytes from memory to the current position on the current pack. The current pack position is updated to point to the next available byte, or if there was an error it points to the offending byte.

The following errors can be generated:
194 battery too low
239 pack full
244 read only pack
245 write pack error
254 out of memory

098 62 PK$SETP
INPUT: A=Non-zero if pack change is to be an error, zero otherwise.
B=Pack to select (0-3)
OUTPUT: A=Pack type
X=Size of pack in 8K units (not for pack A:)
Sets the current pack, and configures the operating system to access it. This routine must be run before using any other pack routines if the packs have been turned off. In preparing the system to use a pack, the variable PKA_PKID is set to point to the pack correct ID string in PKT_ID, the packs are powered up if necessary (PKB_CPAK is $FF when packs are off) and the pack address is set to 0 (PKW_CMAD for pack A, or PKB_HPAD and PKW_CPAD for a datapak). If a datapak is chosen then a battery check is also performed.

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

099 63 PK$SKIP
INPUT: D=Skips a number of bytes on the pack (0-$7FFF)
OUTPUT: None.
Adds D to the current pack address, thus skipping D bytes.

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


Run services.

100 64 RM$RUNP
INPUT: B=zero for procedure, non-zero for calculator
X=Address of lbc string containing procedure name
OUTPUT: None.
Loads and runs an OPL procedure or runs the calculator. If running a procedure, it cannot have any parameters. Note that the run-time stack is cleared, and all files closed and the language is re-initialised before running. This service should therefore not be called from within a procedure. Note also that the procedure should be known to exist before this service is called. On the LZ the display mode is set to 2-line mode to run OPL which was written for 2 line displays.

Top level services.

101 65 TL$ADDI
INPUT: B=Position at which to insert item (0=first item, 1=second, etc. If past end, e.g. $FF, then item inserted before OFF)
RTT_BUF=Menu item to insert (followed by associated word)
OUTPUT: None.
Inserts a new item in the top level menu. The word that is associated with the menu item should be 0 for an OPL procedure (or 1 for a notepad and 2 for a file on the LZ) or the address of the machine code subroutine to be called when the item is chosen. Note that this service does not recognize the standard items FIND, SAVE etc. so this service can be used to replace standard system menu items.

The following errors can be generated:
197 bad procedure name
202 menu too big
254 out of memory

102 66 TL$CPYX
INPUT: None.
OUTPUT: None.
Performs the COPY option which is in the top level menu (or in the Utils menu on the LZ), complete with "FROM" and "TO" prompts. Any errors are handled directly by displaying them using ER$MESS.

103 67 TL$DELI
INPUT: X=Address of name of menu item to find and remove (lbc string)
OUTPUT: None.
Deletes a top level menu item.

104 68 TL$XXMD
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 input length (possibly 0)
X=Address of prompt to display (lbc string, e.g. 'FIND' shows 'FIND A:')
TLB_CPAK=Initial pack
RTT_BUF=String to be edited
OUTPUT:
TLB_CPAK=Chosen pack
Carry=set if ON/Clear used to exit.
Clears the screen, displays a prompt, a pack name and a colon, then allows the editing of a string (usually considered to be a filename). The MODE key changes the chosen pack. The system variable TLB_CPAK ($A2) can be set to the default pack beforehand, and read afterwards to see which pack is chosen. This service calls the editor ED$EDIT, see there for more information. LZ users, see also TL$ZZMD.

127 7F TL$RSTR
INPUT: None.
OUTPUT: None.
Restores several top-level functions to their initial state. This service first boots all devices, asks which language is to be set (on multi-lingual machines), initialises World and Notes (on LZ machines), and resets the top- level menu. The system time, the alarms, the diary and all files are left unaffected. Only available on versions 2.7 and above.

128 80 TL$LSET
INPUT: B=Language to set:
  0=English
  1=French
  2=German
  3=Spanish
  4=Italian
  5=Portuguese
  6=Swedish
  7=Danish
  8=Norwegian
  9=Dutch
  10=Turkish
OUTPUT: None.
Sets the language. On the LZ only English and two other languages are available. If the language requested is not available, then English is used instead. Note that the top-level menu is reset so any inserted items are removed. If there is not enough memory for the new menu, then error 254 'out of memory' is returned and the language remains unchanged. Only available on multi-lingual machines.

Timing services.

105 69 TM$DAYV
INPUT: X=Address of three byte date (year 0-99/0-255, month 0-11, day 0-30)
OUTPUT: B=Weekday number (0-6, 0=Monday)
X=Address of three byte string containing day name (e.g. 'MON')
Calculates the day of the week from a given date.

106 6A TM$TGET
INPUT: X=Address of six byte buffer to copy time to.
OUTPUT: None.
X=preserved
Copies the system time to an address in memory. This service makes sure that the system time is not being updated by an NMI at the time of copying.

107 6B TM$UPDT
INPUT: A=Number of minutes to add
B=Number of seconds to add
X=Address of 6 byte buffer containing date/time to adjust.
OUTPUT: None.
Adds a number of minutes and seconds to a date/time. This should not be used directly on the system variables containing the system time when an NMI is imminent.

108 6C TM$WAIT
INPUT: D=Number of clock ticks to wait
OUTPUT: None.
Waits for a given length of time. If the keyboard interrupts are enabled, it will simply wait count these until D of them have occurred. These interrupts occur every 50 ms unless KBW_TDEL has been changed. If the interrupts are disabled this service uses its own 50 ms pause so that it will still work.

Utility display services

Format control strings.

The following two system services can be used to display information on the screen at the current cursor position. They use a format control string which controls the way the information is displayed.

In the simplest case, the format control string is simply a string of characters to be displayed. The characters '%', '+', '-' and '}' are reserved for special purposes as described below. Control characters can be used, except for 0 which signals the end of the format control string. The LZ has an extra control character available, viz. 31 which will centralize the next string on the current line, clearing the left and right sides of the line.

The character '%' can be followed by a letter to indicate what kind of information is to be displayed and in what way. Here is the list of letters and what they do:
  %a  display ASCII character
  %i  display signed integer word in decimal
  %j  display signed integer byte in decimal
  %u  display unsigned integer word in decimal
  %v  display unsigned integer byte in decimal
  %x  display unsigned integer word in hex
  %y  display unsigned integer byte in hex
  %s  display a lbc string
  %b  display text buffer (address and length byte given)
  %f  fill field (for this type a field width must be included; see below)

These combinations need further information on what is to be displayed. Both the following system services assume that this information has been pushed onto the machine stack. Thus if the byte $F0 were pushed on the stack and one of the following services were called with the format string '%v' then '240' would be printed on the screen.

These combinations can also be used for left justifying the data to be displayed. This is done by inserting the length of the field to be used between the '%' character and the control letter in ASCII decimal format. Thus if '%10v' were used to display the byte $F0 then '240       ' would be printed, which is ten characters long. Note that with the '%' character the data is always left justified, so if a field width is included spaces are added to the right.

The control character '+' can also be used for left justifying. This time however the character to be used to fill out the field must be given as well as the field width. Thus using '+X10v' to print $F0 will show the string '240XXXXXXX'.

The control character '-' can be used for right justifying. This is used in the same way as '+' so the character to be used to fill out the field must be given as must the field width. Thus using '-010v' to print $F0 will show the string '0000000240'. Note how the first '0' is the fill character and not part of the field width.

The field width can be up to 99 characters wide, and if the string does not fit on the screen it will scroll vertically upwards. If the data to be displayed does not fit inside the given field width then only some of the characters can be displayed. With '%' and '+' the data is left justified so the leftmost characters are displayed, and similarly with '-' the rightmost. For example '-02v' shows $F0 as '40', while '+02v' or '%2v' shows it as '24'.

The character '}' is used as shorthand for '-02v'. This shows the last two digits of a single unsigned byte, including a leading 0 if necessary.

To display the characters '%', '+', '-' and '}' themselves simply precede them by '%'. Thus '%+' displays '+' and '%%' displays '%'.

The control letter 'f' is used when a sequence of characters is needed. For example, '%16f' displays 16 spaces. A field width must be given in this case. To display a sequence of another character you must use '+', for example '+*16f' shows 16 asterisks.

All the control letters (except for 'f') need to know what number or string is to be displayed, and this information is taken from the stack. For example, to display a time ' 7:45' when A contains the hours and B the minutes, then you must use PSHB, PSHA followed by one of the following system services with the control string '- 2v:}'. Note that the hours are pushed last so that they are popped from the stack first and hence displayed first.

When the control letter 'b' is used a text buffer is displayed. To use this option, you must push the length (1 byte) of the text first, followed by the address of the buffer. For control letter 's' only the address needs to be pushed as the string stored there has a lbc.

It goes without saying that you must be sure that the correct amount of data is pushed or else the stack is corrupted. Care must also be taken that the data is pushed in the correct order, that the control letters in the format control string are in lower case, and that the format control string ends with a zero byte.

LZ users (and probably users of other multi-lingual machines) should note that if format control strings from the ROM are used (i.e. strings at an address with bit 15 set) then the characters $60 to $FF are used to denote various system messages, which will then be displayed in the current language.

110 6E UT$DDSP
INPUT: D=Address of format control string to display.
OUTPUT: None.
The format control string at given address in memory is displayed. Any data that the string needs is taken from the machine stack. The string is printed from the current cursor position.

111 6F UT$DISP
INPUT: None.
OUTPUT: None.
The format control string which follows immediately after the UT$DISP call is displayed. The program then continues at the instruction following the string. Any data that the string needs is taken from the machine stack. The string is printed from the current cursor position.

126 7E UT$CDSP
INPUT: None.
OUTPUT: None.
Exactly the same as UT$DISP except that the screen is cleared first. Thus the format control string which follows immediately after the UT$CDSP call is displayed. The program then continues at the instruction following the string. Any data that the string needs is taken from the machine stack. The string is printed from the current cursor position. Only available on versions 2.5 and above.

Utility services

109 6D UT$CPYB
INPUT: D=Target address to copy to.
X=Source address to copy from.
UTW_S0=Number of bytes to copy.
OUTPUT: None.
Copies UTW_S0 bytes from X to D. The two areas can overlap as this service can cope with this. Note that if UTW_S0=0 or if X=D, the routine does nothing. The copying rate is about 81K per second.

112 70 UT$ENTR
INPUT: X=Address of routine to enter.
D=parameters
UTW_S1-5=parameters
OUTPUT: B=Error code returned from routine
Carry=set if B is non-zero.
Calls a routine at address X. This routine can end in an RTS instruction, but it can also be ended by calling UT$LEAV. If any of this main routine's subroutines calls UT$LEAV then the main routine is exited too and the program continues with the instruction immediately after the UT$ENTR call. This means that something akin to error handling occurs. If a program is called by UT$ENTR then it can be exited at any point, and in any subroutine simply by calling UT$LEAV. Normally B is set to hold an error code before calling UT$LEAV, or 0 if no error is to occur. Before control is returned to the instruction after the UT$ENTR call, the carry flag is set whenever B is non-zero. Note that UT$ENTR calls can be nested and in that case a call to UT$LEAV returns to the instruction after the most recent UT$ENTR call. Parameters to the routine can be passed in register D, or in the scratch variables UTW_S1 to UTW_S5. Note that UTW_S0 is trashed by UT$ENTR, though the routine itself can use it.

113 71 UT$FILL
INPUT: A=Value to fill bytes with
B=Number of bytes to fill
X=Address of block to fill
OUTPUT: None.
A=preserved
UTW_Sx=preserved
B=0
X=first unfilled byte
Fills a block of B bytes starting from address X with value A. If B is zero then nothing is done. This service is very fast, though for B up to 13 bytes the following is a little faster: STAA 0,X / INX / DECB / BNE FA.

114 72 UT$ICPB
INPUT: A=Length of first string
B=Length of second string
X=Address of first string
UTW_S0=Address of second string
OUTPUT: B=0 if equal, negative if <, positive if >.
N,Z flags=set according to B.
X=preserved
Two ASCII strings are compared, but the upper/lower case is ignored. On exit, the N and Z flags are also set according to the B register, so they are set as if a CMP [String at X],[String at UTW_S0] has been executed. For example "ABCD" < "bcd", "abcd" < "BCD", "A" < "AA", and "ABCD" = "abcd" = "AbcD"

115 73 UT$ISBF
INPUT: A=Length of major string
B=Length of minor string
X=Address of major string
UTW_S0=Address of minor string
OUTPUT: B=Offset within major string where minor string is found (0 if at start), length of major string if not found.
Finds the location of one string inside another, much like the OPL function LOC.

116 74 UT$LEAV
INPUT: B=Error to return, 0 if no error.
OUTPUT: B=Error to return, 0 if no error.
Carry=set if B non-zero.
X=preserved
UTW-Sx=preserved
A=trashed
Jumps to the instruction immediately after the most recent UT$ENTR call and adjusts the stack pointer to the value it was when UT$ENTR was called. Register B contains the error code that should be returned, and UT$LEAV sets the carry flag if this is non-zero. See UT$ENTR for more details.

117 75 UT$SDIV
INPUT: X=First signed integer
D=Second signed integer (Must be non-zero, else infinite loop!)
OUTPUT: X=Quotient, first integer divided by second.
Divides two signed integers.

118 76 UT$SMUL
INPUT: D=Signed integer
X=Signed integer
OUTPUT: D=High bytes of 4-byte signed product.
X=Low bytes of 4-byte signed product.
Multiplies two signed integers.

119 77 UT$SPLT
INPUT: A=Separator character
B=Number of field to extract (0=first field)
X=Address of list of fields
UTW_S0=Length of list of fields
OUTPUT: carry=clear
   X=address of field found
   D=length of field found
carry=set
   UTW_S0=amount the field number exceeded the number of fields available.
Finds the address and length of a particular field in a string. Note that the last field need not have a separator character at the end.

120 78 UT$UDIV
INPUT: X=First unsigned integer
D=Second unsigned integer (Must be non-zero, else infinite loop!)
OUTPUT: X=Quotient, first integer divided by second.
UTW_S2=same as X
Divides two unsigned integers.

121 79 UT$UMUL
INPUT: D=A unsigned integer
X=A unsigned integer
OUTPUT: D=High bytes of 4-byte unsigned product.
X=Low bytes of 4-byte unsigned product.
UTW_S1=same as D
UTW_S2=same as X
Multiplies two unsigned integers.

122 7A UT$UTOB
INPUT: D=Unsigned integer to convert to string
X=Address to store string
OUTPUT: B=Length of string
X=preserved
Converts the unsigned integer into an ASCII string in decimal notation.

123 7B UT$XCAT
INPUT: UTW_S0l=File type to search ($81-8F, 0 for all file types)
OUTPUT: None.
Displays all filenames of the given type on the current pack. The screen is cleared first, then the filenames are displayed one by one. The service waits for EXE to be pressed before displaying the next filename. If there are no more files of the requested type then END OF PACK (or on the LZ 'NO MORE ENTRIES') will be displayed. Pressing ON at any time exits this service. Note that the service does not wait for the ON key to be released. Note that if an error occurs, it will handled immediately by calling ER$MESS after which the service is exited.

124 7C UT$XTOB
INPUT: D=Unsigned integer to convert to hex string
X=Address to store string
OUTPUT: B=Length of string
X=preserved
Converts the unsigned integer into an ASCII string in hexadecimal notation.

125 7D UT$YSNO
INPUT: None.
OUTPUT: B=key pressed
carry=set if 'y' or 'Y' pressed, clear otherwise
Waits for one of 'y' 'Y' 'n' 'N' or ON/CLEAR to be pressed, and returns that key. Note that the service uses KB$STAT to put the keyboard in alpha shift (i.e. releases NumLock), and that the previous keyboard state will be lost.