OSBYTE 142; Default vector table; Default MOS variables table; Reset entry point - 732 bytes (4.4%)
- §1. Default vector table
- §2. MOS Variables Default Values
- §3. Reset entry point
- §4. clearRAM
- §5. setUpSystemVIA
- §6. Read the keyboard 8 times with internal key numbers 9-1
- §7. Initialise keyboard lights, Work out what variables to reset
- §8. Reset OS Variables
- §9. Copy the default vectors and MOS variables
- §10. Put a SPACE in the first key pressed variable
- §11. Set system and user VIA registers
- §12. Check for initialising JIM device
- §13. Enable interrupts
- §14. Clear all sounds; Initialise the Serial ULA; Reset soft key definitions
- §15. Read ROM Types
- §16. Check for speech system
- §17. Initialise screen, execute any BOOT interception code
- §18. Initialise Tube
- §19. Initialize ROMs, claim memory from OSHWM
- §20. Show bootup message
- §21. Execute user BREAK intercept, set keyboard LEDs
- §22. Get !BOOT options, and ask ROMs to handle it
- §23. Select the *ROM filing system
- §24. Execute !BOOT
- §25. Select TAPE filing system
- §26. Look for language ROM
- §27. No language ROM present, so check for second processor
- §28. brkNoLanguageError
- §29. resetAndEnterLanguageROM
- §30. OSBYTE 142 - Enter language ROM (at $8000)
- §31. tubeCopyLanguageROMToSecondProcessorLocal
- §32. Read a byte from a given ROM
- §33. Select ROM
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 *****************************
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...
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...
.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...
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...
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...
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...
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...
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...
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...
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...
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...
.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...
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