* AUXMEM.INIT.S
* (c) Bobbi 2021 GPL v3
*
* Initialization code running in Apple //e aux memory
* 08-Nov-2022 ResetType OSBYTE set
* 09-Nov-2022 Current language re-entered, reset on Power/Hard Reset
* 12-Dec-2022 Copy loop uses OSvars, single byte for MODBRA jump.
* 15-Dec-2022 Added check for *FX200,2/3 force PowerOn reset.
* BUG: If Ctrl-Break pressed during a service call, wrong ROM gets paged in


***********************************************************
* BBC Micro 'virtual machine' in Apple //e aux memory
***********************************************************

MAXROM      EQU   $F9             ; Max sideways ROM number
FXLANG      EQU   BYTEVARBASE+$FC ; Current language
FXRESET     EQU   BYTEVARBASE+$FD ; Last Reset type
FXOPTIONS   EQU   BYTEVARBASE+$FF ; Startup options


ZP1         EQU   $90             ; $90-$9f are spare Econet space
                                  ; so safe to use
ZP2         EQU   $92
ZP3         EQU   $94

MOSSHIM
            ORG   AUXMOS          ; MOS shim implementation

*
* Shim code to service Acorn MOS entry points using
* Apple II monitor routines
* This code is initially loaded into aux mem at AUXMOS1
* Then relocated into aux LC at AUXMOS by MOSINIT
*
* Initially executing at $2000 until copied to $D000
*
* When first run from loading from disk:
*  Code will be at $2000-$4FFF, then copied to $D000-$FFFF
* When Ctrl-Reset pressed:
*  AUX RESET code jumps to MAIN $D000
*
MOSINIT     SEI                   ; Ensure IRQs disabled
            LDX   #$FF            ; Initialize Alt SP to $1FF
            TXS

* Ensure memory map set up:
            STA   WRCARDRAM       ; Make sure we are writing aux
            STA   80STOREOFF      ; Make sure 80STORE is off
            STA   SET80VID        ; 80 col on
            STA   CLRALTCHAR      ; Alt charset off
            STA   PAGE2           ; PAGE2
            LDA   LCBANK1         ; LC RAM Rd/Wt, 1st 4K bank
            LDA   LCBANK1
* (Move these later to prevent brief glimpse of screen with code in it?)

            LDY   #$00            ; $00=Soft Reset
:MODBRA     SEC                   ; Changed to CLC after first run
            BCC   :NORELOC        ; Subsequent run, skip to code

* Copy code to high memory, (OSCTRL)=>source, (OSLPTR)=>dest
:RELOC      LDA   #<AUXMOS1       ; Source
            STA   OSCTRL+0
            LDA   #>AUXMOS1
            STA   OSCTRL+1
            STY   OSLPTR+0        ; Y=0 from earlier
            LDA   #>AUXMOS        ; AUXMOS is always &xx00
            STA   OSLPTR+1
:L1         LDA   (OSCTRL),Y      ; Copy from source
            STA   (OSLPTR),Y      ; to dest
            INY
            BNE   :L1             ; Do 256 bytes
            INC   OSCTRL+1        ; Update source
            INC   OSLPTR+1        ; Update dest
            BMI   :L1             ; Loop until wrap past &FFFF
*
:L2         LDA   MOSVEND-AUXMOS+AUXMOS1-256,Y
            STA   $FF00,Y         ; Copy MOS API and vectors
            INY                   ; to proper place
            BNE   :L2

            LDA   #$18            ; CLC opcode, next time around, we're
            STA   :MODBRA         ; already in high memory
            LDY   #$02            ; $02=PowerOn
* We only change one byte to protect against a RESET happening halfway between
* two bytes being changed, leaving the code inconsistant.

:NORELOC    JMP   MOSHIGH         ; Ensure executing in high memory from here

* From here onwards we are always executing at $D000 onwards
* Y=ResetType

MOSHIGH     SEI                   ; Ensure IRQs disabled
            LDX   #$FF
            TXS                   ; Initialise stack
            LDA   FX200VAR        ; Check *FX200
            AND   #$02            ; Check if bit 1 set
            BEQ   :SCLR0          ; No, keep existing ResetType
            TAY                   ; Otherwise, force to PowerOn reset
:SCLR0      PHY                   ; Stack ResetType
            LDA   FXLANG          ; A=Language
            LDY   FXSOFTOK        ; Y=Soft Keys Ok

            INX                   ; X=$00
:SCLR       STZ   $0000,X         ; Clear Kernel memory
            STZ   $0200,X
            STZ   $0300,X
            INX
            BNE   :SCLR
            STA   FXLANG          ; Current language
            STY   FXSOFTOK        ; Soft key validity
            PLA
            STA   FXRESET         ; Set ResetType
            BEQ   :INITPG2        ; Soft Reset, preserve settings
            DEX                   ; X=$FF
            STX   FXLANG          ; Current language=none
            STX   FXSOFTOK        ; Invalidate soft keys

:INITPG2    LDX   #ENDVEC-DEFVEC-1
:INITPG2LP  LDA   DEFVEC,X        ; Set up vectors
            STA   $200,X
            DEX
            BPL   :INITPG2LP

            LDA   CYAREG          ; GS speed register
            AND   #$80            ; Speed bit only
            STA   GSSPEED         ; In Alt LC for IRQ/BRK hdlr

            JSR   ROMINIT         ; Build list of sideways ROMs
            JSR   KBDINIT         ; Returns A=startup MODE
            JSR   VDUINIT         ; Initialise VDU driver
            JSR   PRHELLO
            JSR   OSNEWL
            LDA   FXRESET         ; Get ResetType
            BEQ   :INITSOFT       ; Soft reset, skip past
            LDA   #7              ; Beep on HardReset/PowerReset
            JSR   OSWRCH
*
* AppleII MOS beeps anyway, so we always get a Beep
* APPLECORN startup -> BBC Beep
* Press Ctrl-Reset  -> AppleII Beep
*
* Find a language to enter
:INITSOFT   LDX   FXLANG          ; Get current language
            BPL   INITLANG        ; b7=ok, use it
            LDX   ROMMAX          ; Look for a language
:FINDLANG   JSR   ROMSELECT       ; Bring ROM X into memory
            BIT   $8006           ; Check ROM type
            BVS   INITLANG        ; b6=set, use it
            DEX                   ; Step down to next ROM
            BPL   :FINDLANG       ; Loop until all tested
ERRNOLANG   BRK                   ; No language found
            DB    $F9
            ASC   'No Language'
            BRK
*
INITLANG    CLC                   ; CLC=Entering from RESET

* OSBYTE $8E - Enter language ROM
*********************************
* X=ROM number to select, CC=RESET, CS=*COMMAND/OSBYTE
*
BYTE8E      PHP                   ; Save CLC=RESET, SEC=Not RESET
            JSR   ROMSELECT       ; Bring ROM X into memory
            BIT   $8006
            BVC   ERRNOLANG       ; No language in this ROM
            LDA   #$00
            STA   FAULT+0
            LDA   #$80
            STA   FAULT+1
            LDY   #$09
            JSR   PRERRLP         ; Print ROM name with PRERR to set
            STY   FAULT+0         ;  FAULT pointing to version string
            JSR   OSNEWL
            JSR   OSNEWL
            STX   FXLANG          ; Set as current language ROM
            PLP                   ; Get entry type back
            LDA   #$01            ; $01=Entering code with a header
            JMP   ROMAUXADDR


* OSBYTE $8F - Issue service call
*********************************
* X=service call, Y=parameter
*
* SERVICE     TAX                   ; Enter here with A=Service Num
SERVICEX
BYTE8F      LDA   $F4             ; Enter here with X=Service Number
            PHA                   ; Save current ROM
*DEBUG
            LDA   $E0
            AND   #$20            ; Test debug *OPT255,32
            BEQ   :SERVDEBUG
            CPX   #$06
            BEQ   :SERVDONE       ; If debug on, ignore SERV06
:SERVDEBUG
*DEBUG
            TXA                   ; A=service number
            LDX   ROMMAX          ; Start at highest ROM
:SERVLP     JSR   ROMSELECT       ; Bring it into memory
            BIT   $8006
            BPL   :SERVSKIP       ; No service entry
            JSR   $8003           ; Call service entry
            TAX
            BEQ   :SERVDONE
:SERVSKIP   LDX   $F4             ; Restore X=current ROM
            DEX                   ; Step down to next
            BPL   :SERVLP         ; Loop until ROM 0 done
:SERVDONE   PLA                   ; Get caller's ROM back
            PHX                   ; Save return from service call
            TAX
            JSR   ROMSELECT       ; Restore caller's ROM
            PLX                   ; Get return value back
            TXA                   ; Return in A and X and set EQ/NE
            RTS

PRHELLO     LDX   #<HELLO
            LDY   #>HELLO
            JSR   OSPRSTR
            JMP   OSNEWL

BYTE00      BEQ   BYTE00A         ; OSBYTE 0,0 - generate error
            LDX   #$0A            ; Identify Host
            RTS                   ; %000x1xxx host type, 'A'pple
BYTE00A     BRK
            DB    $F7

