Technical Reference
Memory Usage
Filing System
System Timing
System Board
Power Supply Board
Interface Slots
Low Level
Comms Link
Psion Link
Utility System
LZ Passwords
System Services

Technical Reference Manual


All Organisers:



Model LZ only:




The eight alarms are stored in a fixed length 48 byte area AMT_TAB ($22F9).

Each entry contains a date-time in the usual format, with a flag indicating the type of alarm.

0 0 - 99 year (1900 - 1999) 0 - 255 year (1900 - 2155)
1 0 - 11 month 0 - 11 month
2 0 - 30 day 0 - 30 day
3 0 - 23 hour 0 - 23 hour
4 0 - 59 minutes 0 - 59 minutes
5 0 - 4 0 Alarm not Set
1 Once
2 Weekly
3 Daily
4 Hourly
0 - 133 0 Alarm not Set
1 Hourly
2 Daily
3 Workdays
4 Weekly
5 Once
sound flag
  64 Siren
128 Chimes


A system variable AMB_WRKD is provided on the LZ machines to indicated which days are workdays.

An alarm entry is canceled by setting byte 5 to zero. Before setting or modifying any alarms, byte 5 should be cleared and then set last of all. This is to prevent interrupts from checking that entry.

Note that although there is no way of manually setting an alarm outside the current week, this limitation need not apply to user programs which manipulate AMT_TAB directly. You can set an alarm to ring at any time between 1900 and end of 1999 (LZ: 2155).

The date-time of a repeating alarm is updated each time it rings; an alarm entry does not contain the original date-time.


Both the diary and the alarms are scanned approximately every minute by the 50ms maskable interrupts which scan the keyboard. Users wishing to alter the alarm or diary alarm action, see vector BTA_OCI, or the BZ$ALRM service.

Every minute an NMI makes a request for alarm checking by setting the flag AMB_DOIT provided the following conditions are met:

  • BTB_IGNM <> 0 (else NMI does nothing)
  • AMB_EI <> 0
  • TMB_SECS = 0 (we are on a minute boundary)

The flag AMB_EI is provided specifically so that user programs can disable alarm checking.

If all these conditions are met, the alarm is not actually checked immediately: this is left to the next maskable interrupt which rings any pending alarms whenever AMB_DOIT is set. This means that alarms are checked as soon as possible after each minute boundary, but any time-critical activities such as writing to datapacks and other operations can delay alarms by using the SEI instruction.

Alarms will never occur while the interrupt mask is set. Also certain activities such as device booting (DV$ calls), storage management (AL$ calls), or modification of the diary or alarms can cause an ALARM to ring late. If interrupts are not required, then an SEI instruction is all that is required to disable alarm checking. If interrupts are required the following code must be used to maintain compatibility with all OS versions:

        LDA     A,AMB_EI 
        PSH     A
        TPA                     ; preserve interrupt mask 
        CLR     AMB_EI          ; prevent NMI setting AMB_DOIT 
        CLR     AMB_DOIT        ; in case AMB_DOIT already set 
        TAP                     ; restore interrupt mask
        ... ; user program alarm checking now off 
;       ...
; the next two lines are optional 
        INC     AMB_EI          ; set AMB_DOIT if check required ** 
        INC     AMB_DOIT        ; on next interrupt              **
        PUL     A 
        STA     A,AMB_EI        ; restart normal checking

The two lines ** will cause the next 50 ms interrupt to perform a check without waiting for the next minute boundary. This will minimize any late running of the alarms. The AMB_DOIT flag can also be set to request more frequent checking than once each minute. However, AMB_DOIT must at no time be set non-zero when AMB_EI is zero as this may cause problems with some early OS versions. Note also that AMB_EI should not be set to $FF.

The 50 ms interrupt first checks the DIARY then the eight alarms. All alarms are sounded even if they are overdue. The earliest DIARY alarm will sound, then the lowest numbered ALARM alarm. If more than one DIARY or ALARM alarm are due, they will ring in pairs (DIARY,ALARM) each minute.

Before a DIARY alarm sounds, the alarm flag (byte 6) in that entry is cleared. Before an ALARM alarm sounds, the repeat time is added on for repeating alarms, and byte 5 is cleared for non-repeating alarms.

The system service DP$SAVE is called to save the screen, and the time and diary text or "ALARM" is displayed for one minute or until ON/CLEAR is pressed. The screen is then restored with a call to DP$REST. The ON/CLEAR key is polled directly, so the keyboard buffer is not affected.

On CM/XPs, BZ$ALRM makes the ALARM sound, while the DIARY beep is a call to BZ$TONE with D = 200 (proportional to 1/frequency), X=50 (note length).


The Organiser II maintains the system time with a 12 bit external counter while switched off. The machine switches on when the counter overflows every 2048 seconds (34 minutes 8 seconds), updates the system time, and switches off again.

The system service BT$SWOF rings any alarms pending, then checks if an alarm is due in the next 34 mins 8 secs. If necessary, BT$SWOF sets the counter to a value greater than zero to switch the machine on early.

When the Organiser II switches on, it rings the alarm then remains on until normal switch-off. Users wishing to alter this behavior see vector BTA_SOF and for vector BTA_WRM.


AMB_WRKD ($20A7 - LZ only)

AMB_WRKD is used to determine which days of the week are workdays. With bit 0 representing Monday, bit 1 Tuesday etc. bits are set for workdays and cleared otherwise. Thus a value of $4f in AMB_WRKD moves the weekend to Friday and Saturday. Setting AMB_WRKD to 0 prevents checking for Workday alarms and removes the option from alarm setting.

Note: AMB_WRKD should not be set to $80. Trying to set a workday alarm, or having an existing one go off will cause the machine to lock-up.


The information in the diary is stored in RAM in an allocated CELL, separate from the RAM device A:, so the diary can not be accessed as a file from OPL or by the top level functions FIND and SAVE.

Entries are kept sorted by date and time in order to allow alarm checking interrupts to scan the diary efficiently. This also enables the SAVE and RESTORE functions to save the whole diary as a block easily.

The diary is held in the third cell, base pointer $2004. Below the diary are the DEVICE and MENU cells, so any operation which grows or shrinks these cells will cause the diary to move. This includes calls to DV$ and TL$ services, device booting at the top level and any changes in the top level menu.

The diary is terminated by a zero byte, not by the end of the cell and so at initialisation time the diary cell just contains this zero byte. It is illegal to shrink the cell to nothing using AL$ZERO or AL$SHNK.

Within the diary cell the entries are stored as follows:

0 1 - 64 length of text 2 - 65 length of text + 1
1 0 - 99 year (1900 - 1999) 0 - 255 year (1900 - 2155)
2 0 - 11 month 0 - 11 month
3 0 - 30 day 0 - 30 day
4 0 - 23 hour 0 - 23 hour
5 0 or 30 minutes 0,15,30,45 minutes
6 0 - 60 if 0 no alarm set else
(number of minutes early+1)
0 - 60 if 0 no alarm set else
(number of minutes early+1)
7... string text of diary entry (1-64 chars) string text of diary entry (1-64 chars)
1-96 duration (in quarter hours)


Example (CM/XP):
(in 1986)
Example (LZ):
Mon 8 May 1989 Wk19 
5:15p ABCDEF 

(alarm set 15 minutes early)

  • $06 (length of "ABCDEF")
  • $56 (=dec 86, year 1986)
  • $00 (month JAN)
  • $0B (day 12)
  • $11 (hour 17)
  • $00 (minutes 0)
  • $10 (alarm 15 minutes early)
  • 6 bytes "ABCDEF"

and then the next entry or $00 as terminator.

(alarm set for 15 minutes early)

  • $07 (length of "ABCDEF" plus one)
  • $59 (= DEC 89, year 1989)
  • $04 (month MAY)
  • $07 (day 8)
  • $11 (hour 17)
  • $0F (minutes 15)
  • $10 (alarm 15 minutes early)
  • 6 bytes "ABCDEF"
  • $02 (duration 30 minutes)

and then the next entry or $00 as terminator.

Bear in mind the following restrictions when manipulating the diary:

  1. Use SEI to prevent alarm checking interrupts while the diary is being modified or during loading from a datapack. Also see the section on interrupts.
  2. All entries must be inserted in chronological order.
  3. No two entries must have the same time.
  4. Entries may not overlap because of their durations. They may, however, meet exactly. No entry must pass midnight owing to its duration.
  5. Text must be less than 65 chars.
  6. The allocator system services must be used to allocate space in the diary.

The following examples scan through each diary entry:

        LDX     $2004   ; X points to 1st byte 
        BRA     2$
1$:     ADD     B,#7    ; skip length byte date alarm flag 
        ABX             ; and skip over text 
2$:     LDA     B,0,X   ; get length byte 
        BNE     1$      ; until 0 terminator found
         ADDR% = PEEKW($2004)
         LEN%  = PEEKB(ADDR%)
         WHILE LEN% <> 0
           ADDR% = ADDR% + 7 + LEN%
           LEN%  = PEEKB(ADDR%)


  • CM/XP machines save the diary as a block file of type $82. The file structure is described in the Files chapter. As these files are not human readable, the example OPL program may be used to write a formatted listing of a CM/XP diary to either a file or the commslink.
  • On the LZ the diary is no longer saved as an ordinary data file. Each entry is saved as a separate record - the previous example would be:
    The first field specifies the date of the entry (1989, 05, 08, for 8th May 1989), the time (17 15, for 5:15pm), the duration (02) and the alarm byte (16, for 15 minutes before - again, 00 would mean "no alarm"). The second field is the text of the entry. The order of things in the first field, and the use of zeroes where necessary to keep things the same length (e.g. "02" for a duration of 2) make the file easy to sort in OPL, or otherwise.
    Because a saved record can be edited or even created by a user, the year, month and day sections start from 1, not 0 - e.g., the 1st of the month is saved as "01", to the file, not "00" as in the diarycell.
    Note, though, that the "Restore" option in the diary will restore entries in any order from a file. The "Xrestore" option can be used to load a CM/XP diary from a pack, in which case each entry is given a duration of 2 (=30 minutes).


The Notepad uses the same editor as is used to edit OPL programs. This editor can be invoked directly by calling the system service LG$EDIT (see chapter Editor).

Notepad Structure

The Notepad text is stored in allocator cell 16 (defined as NOTECELL) in exactly the same format as OPL source procedures. On cold boot, the notepad cell is initialized to contain the name "Notepad:" and system variables (see below) are initialized.

The cell is structured as follows:

Each line has a maximum of 255 bytes including the 0 (these bytes are encrypted when not in the editor if a password has been set).

Note that although the notepad name and colon are not editable, if the optional 0 is not included then the first text line including the name has a maximum of 255 bytes. The bytes after the colon can be edited. A line consisting only of the terminating 0 represents a blank line. The notepad can have any number of lines up to the capacity of memory.

If the cell does not have this structure, the editor may display the "PACK READ" error as if a corrupted notepad has been loaded from a datapack or may produce unexpected results.

The notepad is saved onto a pack as a block file of type 87 (defined as BNOTTYP), and has the same structure as a saved OPL procedure with object but instead of the Object Code (OCODE) bytes, notepad header information is stored. Following the header, the file has the same structure as the notepad cell as described above. The OCODE cell is in fact used to hold the header information prior to saving to pack and is zeroed after saving.

The header structure is:

  • 1 word length of Header information
  • 1 byte flags for notepad
    • bit7 - true if numbered
    • bit3 - true if on/clear exits editor
    • bit2 - true if prompt to be capitalized
    • bit1 - true if no title required
    • bit0 - true if changed (used in editor)
  • 1 byte password flag
    • 0 for no password set
    • 9 for password set
  • if password flag is 9: 9 bytes password code (see Passwords)

Note that if this structure is generated by the programmer, the password flag must be set to 0 to signify no password or the program will try to decrypt the file when it is loaded.

System Variables

Four system variables that are permanently maintained for the current notepad can be referenced from outside the notepad editor.

NTB_FLGS ($7FEA - LZ only)

This byte contains flags for the editor. The following bits are currently used:

7 true if numbered may be poked
3 true if on/clear exits editor do not poke
2 true if prompt to be capitalized may be poked
1 true if no title required may be poked
0 true if changed (used in editor) may be poked

The default value for a new notepad is $08 (bit3 set).

Note that if bit3 is cleared then the notepad cannot be exited. This bit is 0 for editing OPL procedures where the menu includes the item EXIT.

NTB_PSSW ($7FEB - LZ only)

This byte is 0 if the current notepad in memory has no password or any non-zero value if a password exists. It must not be poked or the editor may attempt to decrypt unecrypted data or not to decrypt encrypted data etc. with unknown results.

NTW_CLIN ($7FFD - LZ only)

This word contains the current line number in the current notepad. Line 0 is the line containing the notepad name. This defines which line the cursor is on.

This variable may be poked to change the line number but should not be given a value greater than the last line number in the notepad. The maximum line number is 1 less to the number of zero line-delimiters in an unecrypted notepad.

NTB_CPOS ($7FFF - LZ only)

This byte contains the cursor position in the current line in the current notepad.

This variable may be poked to change the cursor position but should not be given a value greater than the length of the current line.


On the LZ entry points to the top-level applications have been included as system services.

They are named as XX$ENTR where XX is the name of the application (e.g. DI$ENTR provides access to the diary functions). Most of these system services take a "function number" to identify which function of the application to run.

Note: function numbers 0, 1 and 2 are standard across the interfaces to the built-in applications ("initialise", "normal entry" and "search"). Values above 2 are application-dependent.

Please note: Using the following calls on a 2-line machine will cause a crash!

The only way to access the built-in applications on CM/XPs is to look up the entry points in the menucell.

Alarm: AM$ENTR

Provides an entry point into the ALARM routines.

The available functions are:

  • Function 0 - Initialise. This clears all alarms and enables alarm checking by setting AMB_EI.
  • Function 1 - Calls the ALARM application as from the top level.
  • Function 2 - Checks for Diary and ordinary alarms due now and in the next 34mins and 8 secs. If an alarm is due it will go off, if one is due in the next 2048 seconds, the number of seconds before the next alarm is returned.
  • Function 3 - Tests for Diary and ordinary alarm due now. If one is due it will go off.
  • Function 4 - Checks for unacknowledged diary alarms. This does the 'Review missed alarms' screen on switch-on. It checks for any DIARY alarms that have gone off but were not acknowledged by pressing ON/CLEAR. If there are any it displays a screen showing how many were missed and will review them.
  • Function 5 - Turns alarms off, preserving the settings.
  • Function 6 - Restores alarms (opposite to function 5).
Calculator: CA$ENTR

Provides an entry point to the calculator exactly like selecting CALC in the top-level menu.

Do not call from OPL, since OPL is not re-entrant unless all its variables are preserved.


Provides an entry point to the PROG application in the top-level menu.

  • Function 1 - Call the PROG application as from the top-level menu.
  • Function 2 - Search block body files on packs for a given string.
Notepad: NT$ENTR

Provides an entrypoint to the NOTEPAD application.

  • Function 0 - Initialise notepad. This is called on cold booting the LZ.
  • Function 1 - Call the notepad as from the top-level menu option "Notes".
  • Function 2 - Search first the current notepad and then all saved notepads for a given string. Note that password protected notepads are not searched.
  • Function 3 - Edit a named notepad as from top-level menu. If the name is not the same as that in the notepad cell, the file is searched for on the packs.
  • Function 4 - Checks whether a notepad file is password protected.

Provides an entry point to the TIME application.

There are two functions available:

  • Function 0 - Initialise. Actually does nothing!
  • Function 1 - Call the TIME application as from the top-level menu.
Utils: XT$ENTR

Provides an entry point to the UTILS application in the top-level menu.

  • Function 0 - Initialises system password (as no password).
  • Function 1 - Call the UTILS application as from the top-level menu.
  • Function 2 - Call the SEARCH option in Utils.
  • Function 3 - Call the INFO option in Utils.
  • Function 4 - Call the PASSW option in Utils.
  • Function 5 - Call the LANG option in Utils.
  • Function 6 - Check the system password if it is set on (called on warm start).
  • Function 7 - Actually reset the machine (called from RESET in Utils).
  • Function 8 - Actually format a rampack (called from FORMAT in Utils).
  • Function 9 - Call the DIR option in Utils.
  • Function 10 - Call the COPY option in Utils.
  • Function 11 - Call the DELETE option in Utils.
World: WL$ENTR

The world application gives the current time (ignoring day light time saving) and dialing code from the base city for 400 cities and 150 countries.

  • Function 0 - Initialises the world application.
    It sets the base to be London, Paris or Bonn depending on the language byte.
    The initial city is always set to New York Manhattan.
  • Function 1 - Runs the world application exactly as from top level menu.
  • Function 2 - Returns the base city and country names.
xFiles: XF$ENTR

Provides an entry point to the XFILES application in the top-level menu.

  • Function 0 - Initialises the current XFILES file to be MAIN.
  • Function 1 - Enter the XFILES application as if from the top-level menu.
  • Function 2 - Search files on all devices for a given string.
  • Function 3 - Find a file as from top-level menu. The file is searched for on all packs in the order A;, B:, C: and if found made the current file in XFILES.
  • Function 4 - Runs the top-level FIND function
  • Function 5 - Runs the top-level SAVE function