OSBYTE 142; Default vector table; Default MOS variables table; Reset entry point - 732 bytes (4.4%)


§1. Default vector table.

 Default handlers for vectors, used at RESET time.
.defaultVectorTable = $d940
        value                     name           address      address label
    !word .badCommandError        USERV          $0200-1      .vectorUSERV
    !word .brkHandler             BRKV           $0202-3      .vectorBRKV
    !word .irq1Handler            IRQ1V          $0204-5      .vectorIRQ1V
    !word .irq2Handler            IRQ2V          $0206-7      .vectorIRQ2V
    !word .oscliEntryPoint        CLIV           $0208-9      .vectorCLIV
    !word .osbyteEntryPoint       BYTEV          $020A-B      .vectorBYTEV
    !word .oswordEntryPoint       WORDV          $020C-D      .vectorWORDV
    !word .oswrchEntryPoint       WRCHV          $020E-F      .vectorWRCHV
    !word .osrdchEntryPoint       RDCHV          $0210-1      .vectorRDCHV
.defaultFileSystemVectors = $d952
    !word .osfileEntryPoint       FILEV          $0212-3      .vectorFILEV
    !word .osargsEntryPoint       ARGSV          $0214-5      .vectorARGSV
    !word .osbgetEntryPoint       BGETV          $0216-7      .vectorBGETV
    !word .osbputEntryPoint       BPUTV          $0218-9      .vectorBPUTV
    !word .return                 GBPBV          $021A-B      .vectorGBPBV
    !word .osfindEntryPoint       FINDV          $021C-D      .vectorFINDV
    !word .fscEntryPoint          FSCV           $021E-F      .vectorFSCV
    !word .return                 EVNTV          $0220-1      .vectorEVNTV
    !word .return                 UPTV           $0222-3      .vectorUPTV
    !word .return                 NETV           $0224-5      .vectorNETV
    !word .return                 VDUV           $0226-7      .vectorVDUV
    !word .keyEntryPoint          KEYV           $0228-9      .vectorKEYV
    !word .insEntryPoint          INSBV          $022A-B      .vectorINSV
    !word .remEntryPoint          REMVB          $022C-D      .vectorREMV
    !word .cnpEntryPoint          CNPV           $022E-F      .vectorCNPV
    !word .return                 IND1V          $0230-1      .vectorIND1V
    !word .return                 IND2V          $0232-3      .vectorIND2V
    !word .return                 IND3V          $0234-5      .vectorIND3V
.defaultVectorTableEnd = $d976

§2. MOS Variables Default Values.

 Read/written by OSBYTEs 166-252
    !word .mosVariablesMinus166   MOS variables address (add OSBYTE number)     $0236-7
                                  *FX 166/7
    !word .extendedVectorSpace    Address of ROM pointer table                  $0238-9
                                  *FX 168/9
    !word .romTypeTable           ROM information table address                 $023A-B
                                  *FX 170/1
    !word .keyDataTable1 - 16     Key translation table address                 $023C-D
                                  *FX 172/3
    !word .vduVariablesStart      VDU variables start                           $023E-F
                                  *FX 174/5
    !byte 0                       vertical sync counter                         $0240
                                  *FX 176
    !byte 0                       current input buffer number                   $0241
                                  *FX 177
    !byte $FF                     keyboard interrupt enable flag ($FF=enabled)  $0242
                                  *FX 178
    !byte 0                       primary OSHWM (default PAGE)                  $0243
                                  *FX 179
    !byte 0                       current OSHWM (PAGE)                          $0244
                                  *FX 180
    !byte 1                       RS-423 Mode                                   $0245
                                  *FX 181
    !byte 0                       character definition explosion state          $0246
                                  *FX 182
    !byte 0                       Filing system flag ROM=2; tape=0              $0247
                                  *FX 183
    !byte 0                       current Video ULA control register            $0248
                                  *FX 184
    !byte 0                       current palette setting                       $0249
                                  *FX 185
    !byte 0                       number of ROM enabled at last BRK             $024A
                                  *FX 186
    !byte $FF                     number of BASIC ROM                           $024B
                                  *FX 187
    !byte 4                       current ADC channel number                    $024C
                                  *FX 188
    !byte 4                       maximum ADC channel number                    $024D
                                  *FX 189
    !byte 0                       ADC conversion type: 0 or $0C=12 bit; 8=8 Bit $024E
                                  *FX 190
    !byte $FF                     RS-423 busy flag (bit 7 clear=busy)           $024F
                                  *FX 191
    !byte $56                     curent ACIA control register setting          $0250
                                  *FX 192
    !byte $19                     flash counter                                 $0251
                                  *FX 193
    !byte $19                     mark period count                             $0252
                                  *FX 194
    !byte $19                     space period count                            $0253
                                  *FX 195
    !byte 50                      keyboard Auto-repeat delay                    $0254
                                  *FX 196
    !byte 8                       keyboard Auto-repeat rate                     $0255
                                  *FX 197
    !byte 0                       *EXEC file handle  (0 -not allocated)         $0256
                                  *FX 198
    !byte 0                       *SPOOL file handle (0 -not allocated)         $0257
                                  *FX 199
    !byte 0                       bit 0 Escape enable/disable                   $0258
                                  *FX 200
                                  bit 1 BREAK normal/clear memory
    !byte 0                       Econet disable keyboard flag                  $0259
                                  *FX 201
    !byte %00100000               keyboard status    bit 3=1 SHIFT pressed      $025A
                                  *FX 202
                                                     bit 4=0 CAPS LOCK
                                                     bit 5=0 SHIFT LOCK
                                                     bit 6=1 CTRL pressed
                                                     bit 7=1 SHIFT enabled
    !byte 9                       buffer space left at buffer full signal       $025B
                                  *FX 203
    !byte 0                       RS-423 input suppression flag                 $025C
                                  *FX 204
    !byte 0                       cassette/RS-423 flag (0=tape, $40=RS-423)     $025D
                                  *FX 205
    !byte 0                       Econet OS call interception flag (bit 7)      $025E
                                  *FX 206
    !byte 0                       Econet OSRDCH interception flag (bit 7)       $025F
                                  *FX 207
    !byte 0                       Econet OSWRCH interception flag (bit 7)       $0260
                                  *FX 208
    !byte $50                     speech enable/disable flag ($50/$20)          $0261
                                  *FX 209
    !byte 0                       sound output disable flag                     $0262
                                  *FX 210
    !byte 3                       BELL channel number                           $0263
                                  *FX 211
    !byte $90                     BELL amplitude (or envelope number)           $0264
                                  *FX 212
    !byte 100                     BELL pitch (approx Treble C, 523.013Hz)       $0265
                                  *FX 213
    !byte 6                       BELL duration (in 20ths of a second)          $0266
                                  *FX 214
    !byte $81                     bit 7=0 ignore start up message               $0267
                                  *FX 215
                                  bit 0=1 lock up if !BOOT error from *disc* and no language
                                  set
    !byte 0                       length of KEY string                          $0268
                                  *FX 216
    !byte 0                       PRINT line counter                            $0269
                                  *FX 217
    !byte 0                       2s compliment of number of items in VDU queue $026A
                                  *FX 218
    !byte 9                       TAB key value                                 $026B
                                  *FX 219
    !byte $1B                     ESCAPE Character                              $026C
                                  *FX 220

    The following four bytes are how characters are interpreted when placed into an input
    buffer

    !byte $01                     C0-CF                                         $026D
                                  *FX 221
    !byte $D0                     D0-DF                                         $026E
                                  *FX 222
    !byte $E0                     E0-EF                                         $026F
                                  *FX 223
    !byte $F0                     F0-FF                                         $0270
                                  *FX 224

    The next four bytes are the key status (soft key or codes) for:
    
               function key
         SHIFT-function key
          CTRL-function key
    CTRL-SHIFT-function key
    
    0 means ignore key
    1 means expand as the normal soft key number
    2-$FF means expand as the normal soft key number + this value

    !byte $01                     80-8F                                         $0271
                                  *FX 225
    !byte $80                     90-9F                                         $0272
                                  *FX 226
    !byte $90                     A0-AF                                         $0273
                                  *FX 227
    !byte $00                     B0-BF                                         $0274
                                  *FX 228

    !byte $00                     ESCAPE key status (0=ESC, 1=ASCII)            $0275
                                  *FX 229
    !byte $00                     ESCAPE action                                 $0276
                                  *FX 230
.allBitsSet = $d9b7
    !byte $FF                     User VIA 6522 Bit IRQ mask                    $0277
                                  *FX 231
    !byte $FF                     ACIA 6850 Bit IRQ bit mask                    $0278
                                  *FX 232
    !byte $FF                     System VIA 6522 IRQ bit mask                  $0279
                                  *FX 233
    !byte $00                     Tube presence flag                            $027A
                                  *FX 234
    !byte $00                     speech processor presence flag                $027B
                                  *FX 235
    !byte $00                     character destination status                  $027C
                                  *FX 236
    !byte $00                     cursor editing state                          $027D
                                  *FX 237

.softResetHWM = $d9be
************************* SOFT reset high water mark **********************************

    !byte $00                     unused                                        $027E
                                  *FX 238
    !byte $00                     unused                                        $027F
                                  *FX 239
    !byte $00                     country code (0=UK,1=US)                      $0280
                                  *FX 240
    !byte $00                     user flag                                     $0281
                                  *FX 241
    !byte $64                     serial ULA control register setting           $0282
                                  *FX 242
    !byte $05                     current system clock store pointer            $0283
                                  *FX 243
    !byte $FF                     soft key status (inconsistent)                $0284
                                  *FX 244
    !byte $01                     printer destination (parallel printer)        $0285
                                  *FX 245
    !byte 10                      printer ignore character (line feed)          $0286
                                  *FX 246

.hardResetHWM = $d9c7
************************* HARD reset high water mark **********************************

    !byte $00                     user BREAK routine address JMP                $0287
                                  *FX 247
    !byte $00                     user BREAK routine address low                $0288
                                  *FX 248
    !byte $00                     user BREAK routine address high               $0289
                                  *FX 249
    !byte $00                     unused                                        $028A
                                  *FX 250
    !byte $00                     unused                                        $028B
                                  *FX 251
    !byte $FF                     current language ROM number                   $028C
                                  *FX 252

.powerOnResetHWM = $d9cd
********************** RESET High Water mark for Power on *****************************

§3. Reset entry point.

 Called on:
       * Power on
       * when a HARD BREAK occurs      (CTRL BREAK keys)
       * when a SOFT BREAK occurs      (BREAK key)

 On Entry:
       On power on: 6522 System VIA IER bits 0 to 6 will all be clear
       On BREAK   : 6522 System VIA IER bits 0 to 6 at least one bit will be set

 This code runs through a list of steps:

     * Store an RTI instruction at $0D00 (to stop executing any more NMI routines)
     * Disable interrupts (stop executing any more IRQs)
     * Clear decimal flag (decimal mode is never used within the OS. IRQ interrupts turn
       it off while they run. Decimal mode must be off before calling any OS routine)
     * Reset the stack pointer
     * Clear RAM if needed (also detect amount of RAM present, either 16k or 32k, and
       record this)
     * Initialise System VIA registers
     * Read keyboard
     * Initialise OS vectors and variables ($0200 upwards, amount depending on type of
       reset)
     * Initialise JIM (which gives access to an optional 64k or more of Paged Memory)
     * Enable some interrupts
     * Clear sounds
     * Initialise ROMs
     * Initialise speech system if present
     * Clear the screen
     * Insert F10 key code into keyboard buffer if needed (implements effect of *KEY 10)
     * Execute user boot code if present
     * Set cassette options
     * Initialise Tube
     * Initialise ROMs (post Tube initialisation)
     * Show 'BBC Computer 32K' message (or "16K", or no memory number on a SOFT BREAK)
     * Initialise keyboard LEDs
     * Select Filing System ROM
     * Execute !BOOT if needed
     * Find best language to enter, and enter it
.resetEntryPoint = $d9cd
    LDA #$40                                            the numerical value of the RTI opcode
    STA .nmiEntryPoint                                  store RTI instruction at the start
                                                        of the NMI routine

    SEI                                                 disable interrupts just in case
    CLD                                                 clear decimal flag
    LDX #$FF                                            reset stack to where it should be
    TXS                                                 ($01FF)
    LDA .systemVIAInterruptEnableRegister               read interupt enable register of the
                                                        system VIA
    ASL                                                 shift bit 7 (reading IER always
                                                        returns 1 in bit 7) into carry
    PHA                                                 save what's left (for use later when
                                                        setting page 2: just before
                                                        .setUpPage2)
    BEQ .clearRAM                                       if (power on) then branch
    LDA .escapeAndBreakEffect                           read BREAK Action flags (set by
                                                        *FX200,n)
    LSR                                                 divide by 2 to get the break action
    CMP #1                                              
    BNE .setUpSystemVIA                                 if (break action says we don't need
                                                        to clear RAM) then branch
    LSR                                                 set A=0 (since A=1 at this point)
    fall through...

§4. clearRAM.

 Clears all of RAM except the first byte in each Page. This avoids overwriting the RTI instruction at $0D00.
.clearRAM = $d9e7
    LDX #4                                              start clearing memory from page 4
                                                        ($0400)
    STX $01                                             store a non-zero number at $01
    STA $00                                             store A (currently zero) at $00

    TAY                                                 and set Y (loop counter) to zero
-
    STA ($00),Y                                         clear RAM
    CMP $01                                             check high byte of address
    BEQ +                                               if (zero) then branch:

    This happens when we clear byte $4001 on a 16k machine the RAM memory addressing loops
    it around to write a zero into $0001. We are done at this point and branch out to avoid
    overwriting the rest of zero page.

    INY                                                 increment loop counter
    BNE -                                               if (not zero) then branch (loop back)
    INY                                                 increment again (Y=1) this avoids
                                                        overwriting RTI instruction at $D00
    INX                                                 increment X
    INC $01                                             increment high byte of address
    BPL -                                               loop until A=$80 then exit

+
    STX .systemAvailableRAM                             writes marker for available RAM
                                                        ($40=16k; $80=32k)
    STX .softKeyConsistencyFlag                         write non-zero value in soft key
                                                        consistency flag
    fall through...

§5. setUpSystemVIA.

.setUpSystemVIA = $da03
    LDX #%00001111                                      set System VIA PORT B to output on
                                                        bits 0-3; input on bits 4-7
    STX .systemVIADataDirectionRegisterB                

The next loop writes 14, 13, 12, 11, 10, 9, 8 in turn to System VIA Register B which:
      - turns CAPS LOCK off;
      - sets the hardware scroll address to $3000;
      - enables keyboard auto scanning;
      - enable read/write speech;
      - disable sound;

(See .systemVIARegisterB)
-
    DEX                                                 loop counter
    STX .systemVIARegisterB                             write system VIA register B
    CPX #9                                              
    BCS -                                               if (X>=9) then branch (loop back and
                                                        do it again)
    fall through...

§6. Read the keyboard 8 times with internal key numbers 9-1.

 This reads the state of the CTRL key and the 'keyboard links', a set of DIP switches next
 to the keyboard. See .scanKeyboard for internal key numbers.

 These are rotated into the 8 bits of .interruptAccumulator for further processing
    INX                                                 X=9 (loop counter)
-
    TXA                                                 Start of loop to interrogate keyboard
    JSR .interrogateKeyboard                            with A = 9...1 which reads keyboard
                                                        links 9-2 and CTRL key
    CPX #$80                                            set carry if the 'key' or 'link' is
                                                        'pressed' or 'set'
    ROR .interruptAccumulator                           rotate carry into MSB into bit 7 of
                                                        .interruptAccumulator
    TAX                                                 get back value of X for loop
    DEX                                                 decrement it
    BNE -                                               if (not zero) then branch (do loop
                                                        again)

    At this point Carry(C) and .interruptAccumulator holds:
    C = }
    0 = } screen MODE on startup
    1 = }
    2 = if clear reverse SHIFT BREAK action
    3 = }
    4 = } set disc drive timings
    5 = not used
    6 = not used
    7 = CTRL key

    STX .lastResetType                                  set last reset type = 0
    ROL .interruptAccumulator                           

    At this point .interruptAccumulator holds keyboard links:
    0 = }
    1 = } screen MODE on startup
    2 = }
    3 = if clear reverse SHIFT BREAK action
    4 = }
    5 = } set disc drive timings
    6 = not used
    7 = not used
    C = CTRL key

    fall through...

§7. Initialise keyboard lights, Work out what variables to reset.

    JSR .keyboardIndicators                             set LEDs. carry flag (CTRL key) is
                                                        put into bit zero of A
    ROR                                                 put bit zero of A (CTRL key) into
                                                        carry flag

    set up page 2 based on reset type
    LDX #<.softResetLWM                                 X = low water mark for setting OS
                                                        variables (writes to range $200+X ->
                                                        $2FF)
    LDY #.powerOnResetHWM - .defaultVectorTable         Y = high water mark for writing
                                                        default values into OS variables
                                                        (writes to range $200+Y -> $0200)
    PLA                                                 get back A (which is
                                                        .systemVIAInterruptEnableRegister
                                                        shifted left once)
    BEQ +                                               if (A=0) then branch (power on
                                                        reset, with X=$9C Y=$8D)
    LDY #.softResetHWM - .defaultVectorTable            set value for soft reset HWM
    BCC .setUpPage2                                     if (soft reset) then branch
    LDY #.hardResetHWM - .defaultVectorTable            hard reset
    INC .lastResetType                                  reset type=1
+
    INC .lastResetType                                  'power on' or hard reset
    LDA .interruptAccumulator                           get keyboard links set
    EOR #%11111111                                      invert all bits
    STA .startUpOptions                                 and record as start up options
    LDX #<.hardResetLWM                                 
    fall through...

§8. Reset OS Variables.

 On Entry:
       .lastResetType is reset type:

        0    Soft reset    X=<.softResetLWM    Y=.softResetHWM    - .defaultVectorTable
        1    Power on      X=<.hardResetLWM    Y=.powerOnResetHWM - .defaultVectorTable
        2    Hard reset    X=<.hardResetLWM    Y=.hardResetHWM    - .defaultVectorTable

   - Set variables at $200+X and up to zero or 255
   - Copy default values for variables into $0200+Y-1 and below from .defaultVectorTable
.setUpPage2 = $da42
    LDA #0                                              A=0
-
    CPX #$CE                                            this loop writes zero into the
                                                        addresses in range $0290/C to
                                                        $02CD...
    BCC +                                               
    LDA #$FF                                            ... and writes 255 into addresses in
                                                        range $02CE to $02FF
+
    STA .page2Start,X                                   
    INX                                                 
    BNE -                                               
                                                        At this point A=$FF and X=0
    STA .userVIADataDirectionRegisterA                  set port A of user VIA to all
                                                        outputs (printer out)
    TXA                                                 A=0
    LDX #$E2                                            loop counter
-
    STA $00,X                                           }
    INX                                                 } this loop stores zero in zero-page
                                                        } memory locations $E2 to $FF
    BNE -                                               }
    fall through...

§9. Copy the default vectors and MOS variables.

 Y is the loop counter (set up above, depending on boot type).
-
    LDA .defaultVectorTable - 1,Y                       read data from default table+Y
    STA .page2Start - 1,Y                               write data to $0200+Y
    DEY                                                 decrement loop counter
    BNE -                                               branch back
    fall through...

§10. Put a SPACE in the first key pressed variable.

    LDA #.internalKeyNumberSPACEBAR                     }
    STA .firstKeyPressedInternal                        } store SPACE in
                                                        } .firstKeyPressedInternal
    JSR .setupACIA                                      set up ACIA
                                                        X=0
    fall through...

§11. Set system and user VIA registers.

    LDA #$7F                                            Disable interrupts (top bit clear
                                                        and all others set means disable all
                                                        interrupts)
    INX                                                 X=1
-
    STA .systemVIAInterruptFlagRegister,X               Set
                                                        .systemVIAInterruptEnableRegister
                                                        and .systemVIAInterruptFlagRegister
    STA .userVIAInterruptFlagRegister,X                 Set
                                                        .userVIAInterruptEnableRegister and
                                                         .userVIAInterruptFlagRegister
    DEX                                                 X--
    BPL -                                               loop back if X >= 0
    fall through...

§12. Check for initialising JIM device.

    CLI                                                 briefly allow interrupts (JIM based
                                                        hardware can cause an
                                                        interrupt here, which will set
                                                        .interruptAccumulator to $7F,
                                                        according to the comments in the
                                                        original source code)
    SEI                                                 then disallow again (N.B. All VIA
                                                        IRQs are disabled)
    BIT .interruptAccumulator                           if bit six is set, then we have JIM
                                                        hardware to initialize.
    BVC +                                               if (bit six clear) then branch over
                                                        next instruction
    JSR .jimPagedEntryJumper                            This calls the JIM paged entry point
                                                        (to initialise JIM based hardware.)
+
    fall through...

§13. Enable interrupts.

 Initialises System VIA registers to enable a default set of interrupts:

       The Vertical sync interrupt (50Hz)
       The Analogue to Digital Converter complete interrupt
       A timer interrupt for Speech
       The 100Hz timer

 Initialises the 100Hz timer to $270E = 9998 uS (two less than expected because the latch
 reload costs 2uS)

 Initialises other devices to default settings (light pen strobe, printer, user port)
    LDX #%11110010                                      enable some System VIA interrupts:
    STX .systemVIAInterruptEnableRegister                 1   Vertical sync
                                                          4   Analogue conversion finished
                                                          5   Timer 2 counter (for speech)
                                                          6   Timer 1 counter (100Hz)
    LDX #%00000100                                      set system VIA PCR
    STX .systemVIAPeripheralControlRegister             set the PCR:
                        CA1 has negative active edge       (vertical sync)
                        CA2 positive edges active on input (keyboard)
                        CB1 has negative active edge       (end of analogue conversion)
                        CB2 negative active edges on input (light pen strobe)

    LDA #%01100000                                      set system VIA ACR
    STA .systemVIAAuxiliaryControlRegister              Disable latches and shift register
                                                        (bits 0-4 = %00000)
                                                        timer 2 countdown (for Speech)
                                                        with pulses on input pin PB6
                                                        (bit 5 = %1)
                                                        timer 1 free-run mode (100Hz timer)
                                                        with PB7 disabled
                                                        (bit 6-7 = %01)

    LDA #$0E                                            set system VIA Timer 1 counter (Low)
    STA .systemVIATimer1LatchLow                        this becomes effective when Timer 1
                                                        Counter High set

    STA .userVIAPeripheralControlRegister               set user VIA PCR:
                        CA1 interrupt on -ve edge     (usually printer Acknowledge)
                        CA2 high output               (usually printer strobe)
                        CB1 interrupt on -ve edge     (user port)
                        CB2 negative edge             (user port)

    STA .adcStartConversionRegister                     Start analogue to digital conversion
                                                        A=%1110, meaning channel 2 of range
                                                        0-3,
                                                        twelve bit conversion.

    CMP .userVIAPeripheralControlRegister               check user VIA PCR
    BEQ +                                               if (printer present) then branch
    INC .userVIAIRQBitMask                              increment user VIA mask to 0 to
                                                        ignore all user VIA interrupts
+
    LDA #$27                                            set Timer 1 (high byte) to $27.
                                                        this sets Timer 1 to $270E (=9998 uS)
    STA .systemVIATimer1LatchHigh                       so interrupt occurs
                                                        every 100th of a second
    STA .systemVIATimer1CounterHigh                     set counter (high byte) which
                                                        actually starts the timer
    fall through...

§14. Clear all sounds; Initialise the Serial ULA; Reset soft key definitions.

.resetClearAllSounds = $daaa
    JSR .clearSoundChannels                             clear the sound channels

    Initialise the serial ULA
    LDA .serialULARegisterCopy                          read serial ULA control register (OS
                                                        copy)
    AND #$7F                                            zero bit 7
    JSR .setSerialULADirectly                           and set up serial ULA

    reset function keys
    LDX .softKeyConsistencyFlag                         get soft key status flag
    BEQ .selectROMLoop                                  if (keys OK) then branch
    JSR .osbyte18EntryPoint                             reset function keys
    fall through...

§15. Read ROM Types.

 Check each sideways ROM (aka Paged ROM) and make a catalogue of their types X = 0...15

 Note that the OS itself is not a Paged ROM. As originally shipped, BASIC is the only
 Paged ROM present. The OS supports 16 Paged ROMS (0-15). There are only five slots in
 the original machine, so extra hardware is required to support more Paged ROMs.

 ROM Header
 ----------
 $8000 = language entry point      (.romLanguageEntry)
 $8003 = service entry point       (.romServiceEntry)
 $8006 = ROM Type byte (see below) (.romTypeByte)
 $8007 = copyright message         (.romCopyrightOffsetPointer)
 $8009 = offset to title string    (.romTitleString)

 ROM Type Byte
 -------------
 bits 0-3  Processor Type (see below)
 bit 4     not used (Electron only)
 bit 5     Language ROM has a relocation address provided. The ROM can only run on the second
           processor when located at that address.
 bit 6     If set, this is a language ROM (and can be chosen on RESET). Otherwise this is
           a utility or Filing System ROM.
 bit 7     ROM has a service entry. All ROMs should have this bit set. (The BASIC ROM is the
           exception, it does not have this bit set).

 Processor Type
 --------------
 Language ROMs can be copied across to a second processor and run there. Processor codes
 have been assigned:

  0 = 6502 BASIC
  1 = 6502 Turbo code
  2 = 6502 machine code
  3 = 68000 code
  4 = -
  5 = -
  6 = -
  7 = PDP-11 code
  8 = Z80 code
  9 = 32016 code
 10 = -
 11 = 80186 code
 12 = 80286 code
 13 = ARM code
 14 = -
 15 = -
.selectROMLoop = $dabd
    JSR .selectROM                                      select ROM X
    LDX #3                                              set X to point to offset in table
    LDY .romCopyrightOffsetPointer                      get copyright offset from ROM
-
    LDA .romStartAddress,Y                              get first byte
    CMP .copyrightString,X                              compare it with table byte
    BNE .noCopyright                                    if (no copyright) then branch
    INY                                                 point to next byte in ROM
    DEX                                                 point to previous byte in ")C(",0
                                                        string
    BPL -                                               if (still +ve) then branch (go back
                                                        to check next byte)
                                                        this point is reached if 4 bytes
                                                        indicate valid ROM

    Check the first 1K of each ROM against higher priority ROMs to ensure that
    there are no matches. If a match is found, ignore the lower priority ROM
    LDX .currentlySelectedROM                           get RAM copy of ROM number in X
    LDY .currentlySelectedROM                           and Y

.nextROM = $dad5
    INY                                                 increment Y to check
    CPY #16                                             check ROM number against 16
    BCS .romComparisonDone                              if (ROM number is 16 or more) then
                                                        branch (done checking each ROM,
                                                        store catalogue byte)
    TYA                                                 put Y in A
    EOR #$FF                                            invert it
    STA .tempStoreFA                                    and store at .tempStoreFA
    LDA #$7F                                            }
    STA .tempStoreFB                                    } store $7F at .tempStoreFB to get
                                                        } address $7FFF-Y

.nextByteInROM = $dae3
    STY .romSelectRegister                              switch the ROM into the memory map
    LDA (.tempStoreFA),Y                                get byte
    STX .romSelectRegister                              switch the original ROM into the
                                                        memory map
    CMP (.tempStoreFA),Y                                and compare with previous byte called
    BNE .nextROM                                        if (not the same) then branch (go
                                                        back and do it again with next ROM)
    INC .tempStoreFA                                    increment .tempStoreFA to point to
                                                        new location
    BNE .nextByteInROM                                  if (.tempStoreFA is not zero) then
                                                        branch (check next byte)
    INC .tempStoreFB                                    increment tempStoreFB (high byte of
                                                        address)
    LDA .tempStoreFB                                    load it
    CMP #$84                                            check if it has reached $84 = $80 +
                                                        (4*256 bytes), i.e. 1k checked
    BCC .nextByteInROM                                  if (not checked 1k yet) then branch
                                                        (check next 256 bytes)

.noCopyright = $dafb
    LDX .currentlySelectedROM                           X=current ROM
    BPL +                                               if (+ve) then branch

.romComparisonDone = $daff
    LDA .romTypeByte                                    get rom type byte
    STA .romTypeTable,X                                 store it in catalogue
    AND #$8F                                            check for BASIC
    BNE +                                               if (not BASIC) then branch
    STX .basicROMNumber                                 store X at BASIC pointer
+
    INX                                                 increment X to point to next ROM
    CPX #16                                             check X against 16
    BCC .selectROMLoop                                  if (15 or less) then branch (back
                                                        for next ROM)
    fall through...

§16. Check for speech system.

    BIT .systemVIARegisterB                             check for speech system
    BMI .skipSpeech                                     if (bit 7 set) then branch (no
                                                        speech system fitted)

    DEC .speechSystemPresentFlag                        .speechSystemPresentFlag set to $FF
                                                        to indicate speech present

-
    LDY #$FF                                            Y=$FF (speech 'reset' command)
    JSR .osbyte159EntryPoint                            initialise speech generator
    DEX                                                 loop counter X from 16 to zero
    BNE -                                               branch back unless zero

    STX .systemVIATimer2CounterLow                      
    STX .systemVIATimer2CounterHigh                     clear Timer 2 to zero (used for
                                                        Speech)
    fall through...

§17. Initialise screen, execute any BOOT interception code.

.skipSpeech = $db27
    LDA .startUpOptions                                 get back start up options (bits 0-2
                                                        are MODE)
    JSR .initialiseScreenOnReset                        then jump to screen initialisation

    *KEY 10 facility (insert the *KEY 10 character code into the keyboard buffer)
    LDY #.charKEY10                                     }
    JSR .insertByteIntoKeyboardBuffer                   } enter $CA in keyboard buffer. This
                                                        } activates the *KEY 10 facility.

    execute any user BOOT interception code, if present (with carry clear)
    JSR .osbyte247EntryPoint                            call user boot routine if present,
                                                        with carry clear
                                                        it's called again later with carry
                                                        set

    JSR .setupTapeOptions                               set up cassette options [normally
                                                        at 300 baud, but if the user BOOT
                                                        interception code sets Z then
                                                        1200 baud]
    fall through...

§18. Initialise Tube.

    LDA #%10000001                                      test for Tube to FIFO buffer 1
    STA .tubeULAStatusRegister                          
    LDA .tubeULAStatusRegister                          test for Tube presence
    ROR                                                 put bit 0 into carry
    BCC +                                               if (no Tube present) then branch
    LDX #.romServiceCallTubeMainInitialisation          }
    JSR .osbyte143EntryPoint                            } initialise Tube system (issue ROM
                                                        } service call)
    BNE +                                               if (Tube not initialised) then branch
    DEC .tubePresentFlag                                set Tube flag to show it's active
    fall through...

§19. Initialize ROMs, claim memory from OSHWM.

 Note that OSBYTE 143 issues the service call to all ROMs in turn (in slot order 15-0).
+
    LDY #>.initialOSHWM                                 set default value of PAGE: $0E00
    LDX #.romServiceCallAbsoluteWorkspaceClaim          issue claim absolute workspace call
    JSR .osbyte143EntryPoint                            via .osbyte143EntryPoint
    LDX #.romServiceCallPrivateWorkspaceClaim           send private workspace claim call
    JSR .osbyte143EntryPoint                            via .osbyte143EntryPoint
    STY .defaultOSHWM                                   set primary OSHWM
    STY .currentOSHWM                                   set current OSHWM
    LDX #.romServiceCallTubeSystemPostInitialisation    send to the Tube with the 'post
                                                        initialisation' reason (e.g.
                                                        second processor can decide to
                                                        explode the character set etc.)
    LDY .tubePresentFlag                                Y=$FF if Tube present else Y=0
    JSR .osbyte143EntryPoint                            and make call via
                                                        .osbyte143EntryPoint
    fall through...

§20. Show bootup message.

 The startup message can only be suppressed if a ROM requests it on initialisation. Otherwise
 the .startupMessageSuppressionAndBootOptions variable was reset to its default value when
 resetting MOS variables above.
    AND .startupMessageSuppressionAndBootOptions        check (result of post-init AND bit 7
                                                        of
                                                        
                                                        .startupMessageSuppressionAndBootOptions)
    BPL .skipStartupMessage                             if (result clear) then branch (skip
                                                        startup message)
    LDY #.bootMessage - .vduBaseAddress - 1             
    JSR .displayString                                  output 'BBC Computer ' message
    LDA .lastResetType                                  0=soft reset, anything else continue
    BEQ .outputTwoNewlines                              if (soft reset) then branch (skip
                                                        forward)
    LDY #.bootMessageMemory32 - .vduBaseAddress - 1     set to point to 32k message
    BIT .systemAvailableRAM                             read available RAM ($40 = 16k
                                                        $80 = 32k)
    BMI +                                               if (32k RAM available) then branch
    LDY #.bootMessageMemory16 - .vduBaseAddress - 1     set to point to 16K message
+
    JSR .displayString                                  write message with '16K' or '32K'

.outputTwoNewlines = $db82
    LDY #.bootMessageEnding  - .vduBaseAddress - 1      and two newlines
    JSR .displayString                                  
    fall through...

§21. Execute user BREAK intercept, set keyboard LEDs.

.skipStartupMessage = $db87
    SEC                                                 
    JSR .osbyte247EntryPoint                            call user break intercept if present
                                                        (with carry set)
    JSR .osbyte118EntryPoint                            set up keyboard LEDs to reflect
                                                        current keyboard status
                                                        also tests for SHIFT pressed
    fall through...

§22. Get !BOOT options, and ask ROMs to handle it.

 Note that OSBYTE 143 issues the service call to all ROMs in turn (in slot order 15-0).
 This stops when one of the ROMs returns zero, indicating it will accept the auto-boot.
    PHP                                                 remember flags
    PLA                                                 and recall flags in A = nvbdizc
    LSR                                                 
    LSR                                                 
    LSR                                                 
    LSR                                                 A=0000nvbd
    EOR .startUpOptions                                 EOR with start up options, in
                                                        particular check bit 3 (if clear
                                                        reverse SHIFT BREAK action)
    AND #8                                              isolate bit 3 only
    TAY                                                 Y=0 (execute !BOOT) or 8 (don't
                                                        execute !BOOT)
    LDX #.romServiceCallAutoBoot                        X = rom service call for auto-boot
    JSR .osbyte143EntryPoint                            ask each ROM in turn if they want
                                                        to handle it
    BEQ .checkForFindingLanguageROM                     if (a ROM accepts this call) then
                                                        branch (to enter language ROM)
    TYA                                                 put result from ROM (Y register) in
                                                        A (to test if it's zero)
    BNE .setTapeFSAndFindLanguageROM                    if (Y != 0, i.e. no filing system
                                                        accepts it) then branch
    fall through...

§23. Select the *ROM filing system.

    LDA #141                                            }
    JSR .osbyte141EntryPoint                            } select ROM filing system
    fall through...

§24. Execute !BOOT.

    LDX #<.runBootString                                
    LDY #>.runBootString                                
    DEC .startupMessageSuppressionAndBootOptions        decrement boot options
    JSR .OSCLI                                          and execute */!BOOT
    INC .startupMessageSuppressionAndBootOptions        restore boot options
    BNE .checkForFindingLanguageROM                     ALWAYS branch, don't reset filing
                                                        system

§25. Select TAPE filing system.

.setTapeFSAndFindLanguageROM = $dbb8
    LDA #0                                              }
    TAX                                                 } set tape filing system
    JSR .setTapeOrROMFS                                 }
    fall through...

§26. Look for language ROM.

 Looks for the 'best' language ROM (the language with the highest ROM slot number) and
 enters it
.checkForFindingLanguageROM = $dbbe
    LDA .lastResetType                                  get last RESET Type
    BNE .findBestLanguageROM                            if (not soft reset) then branch

    LDX .languageROMNumber                              get current language ROM number
    BPL .resetAndEnterLanguageROM                       if (language available) then branch
                                                        (initialise and enter ROM)

.findBestLanguageROM = $dbc8
    LDX #15                                             set pointer to highest available ROM
-
    LDA .romTypeTable,X                                 get ROM type from map
    ROL                                                 put bit 6 into bit 7
    BMI .resetAndEnterLanguageROM                       if (bit 7 set then ROM has a
                                                        language entry) then branch
                                                        (initialise and enter ROM)

    DEX                                                 
    BPL -                                               search for language until X=255
    fall through...

§27. No language ROM present, so check for second processor.

 If present, ask the second processor to copy an appropriate language ROM onto the second
 processor and run there. The Tube interface is implemented by the 'DNFS' ROM. Initialising
 the DNFS ROM copies Tube service code into the current language workspace at $0400-$07FF.
 Calling .tubeCopyLanguageROMToSecondProcessor ($0400) is therefore calling into the Tube
 service code, to find and copy the code of an appropriate language ROM into the second
 processor and run it there. The language ROM identifies the processor type it's designed
 for by the ROM header's processor type byte (See .selectROMLoop).
    LDA #0                                              No language found.
    BIT .tubePresentFlag                                check if Tube is present
    BMI .tubeCopyLanguageROMToSecondProcessorLocal      if (Tube present) then branch (call
                                                        into Tube code)
    fall through...

§28. brkNoLanguageError.

.brkNoLanguageError = $dbda
    BRK                                                 
    !byte $F9                                           error number
    !text "Language?",0                                 message

§29. resetAndEnterLanguageROM.

.resetAndEnterLanguageROM = $dbe6
    CLC                                                 
    fall through...

§30. OSBYTE 142 - Enter language ROM (at $8000).

 On Entry:
       X = ROM number
       C set if OSBYTE call;
       C clear if initialisation
.osbyte142EntryPoint = $dbe7
    PHP                                                 save flags
    STX .languageROMNumber                              put X in current ROM number
    JSR .selectROM                                      select that ROM
    LDA #>(.romTitleString - 1)                         } AY=address of ROM title string
    LDY #<(.romTitleString - 1)                         }
    JSR .displayStringAY                                display text string held in ROM at
                                                        .romTitleString
    STY .languageVersionString                          save Y on exit (end of language
                                                        string)
    JSR .OSNEWL                                         two line feeds
    JSR .OSNEWL                                         are output
    PLP                                                 then get back flags
    LDA #1                                              A=1 required for language entry
    BIT .tubePresentFlag                                check if the Tube is present
    BMI .tubeCopyLanguageROMToSecondProcessorLocal      and branch if so
    JMP .romLanguageEntry                               enter language at $8000

§31. tubeCopyLanguageROMToSecondProcessorLocal.

.tubeCopyLanguageROMToSecondProcessorLocal = $dc08
    JMP .tubeCopyLanguageROMToSecondProcessor           enter Tube environment

§32. Read a byte from a given ROM.

 On Entry:
       Y = ROM number
 $F6/$F7 = address
.osrdrmEntryPoint = $dc0b
    LDX .currentlySelectedROM                           get current ROM number into X
    STY .currentlySelectedROM                           store new number
    STY .romSelectRegister                              switch the ROM into the memory map
    LDY #0                                              get current PHROM address
    LDA (.romAddressLow),Y                              and get byte
    fall through...

§33. Select ROM.

 On Entry:
       X = ROM number (0-15)
.selectROM = $dc16
    STX .currentlySelectedROM                           RAM copy of current ROM
    STX .romSelectRegister                              switch the ROM into the memory map
    RTS