        SUBT    => NewReset

DuffEntry *     31*1024*1024+32*1024    ; Never any memory at this address

                   GBLL   KeyboardDebungling
KeyboardDebungling SETL   {FALSE}

; reset code needs to know where CTRL, SHIFT and R are in the kbd matrix
; these are codes given by the keyboard

     [ A1Keyboard
A1CTRLLCol   *  K1kdda + (K1CtrlLeft :AND: 15)
A1CTRLLRow   *  K1kdda + (K1CtrlLeft :SHR: 4)
A1CTRLRCol   *  K1kdda + (K1CtrlRight :AND: 15)
A1CTRLRRow   *  K1kdda + (K1CtrlRight :SHR: 4)
A1SHIFTLCol  *  K1kdda + (K1ShiftLeft :AND: 15)
A1SHIFTLRow  *  K1kdda + (K1ShiftLeft :SHR: 4)
A1SHIFTRCol  *  K1kdda + (K1ShiftRight :AND: 15)
A1SHIFTRRow  *  K1kdda + (K1ShiftRight :SHR: 4)
A1R_Col      *  K1kdda +  10
A1R_Row      *  K1kdda +  2
A1T_Col      *  K1kdda +  11
A1T_Row      *  K1kdda +  2
A1Del_Col    *  K1kdda +  4
A1Del_Row    *  K1kdda +  3
A1Copy_Col   *  K1kdda +  5
A1Copy_Row   *  K1kdda +  3
     ]

     [ A500Keyboard
; old (A500) keyboard positions

A500CTRLRow    *   KEYDOWN + &C
A500CTRLCol    *   KEYDOWN +  0
A500SHIFTRow   *   KEYDOWN + &A
A500SHIFTCol   *   KEYDOWN +  0
A500R_Row      *   KEYDOWN +  2
A500R_Col      *   KEYDOWN +  7
A500T_Row      *   KEYDOWN +  2
A500T_Col      *   KEYDOWN +  6
A500Del_Row    *   KEYDOWN +  5
A500Del_Col    *   KEYDOWN +  7
A500Copy_Row   *   KEYDOWN +  0
A500Copy_Col   *   KEYDOWN +  8
    ]

SoftReset       * 0                     ; Reset types
PowerOnReset    * 1
ControlReset    * 2

; CMOS RAM resetting stuff:
CMOSLimit       * &F0

; number of microseconds to wait for keyboard (approx)
KeyWait * 100000  ; wait 1/10 sec

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; CAM manipulation utility routines

BangCamUpdate ROUT

; R2 = CAM entry no
; R3 = logaddr
; R9 = current MEMC value
; R11 = PPL
; set and update tables

        MOV     R4, #CamEntries
        ORR     r0, r3, r11, LSL #28  ; top nibble is PPL
        STR     r0, [R4, R2, LSL #2]

BangCam

; r0 corrupted
; r1 corrupted
; R2 = CAM entry no
; R3 = logaddr
; r4 corrupted
; r5 spare!
; r6 corrupted
; r7, r8 spare
; R9 = current MEMC value
; r10 spare
; R11 = PPL
; r12 spare

        AND     R4, R9, #&C           ; pagesize
        ADR     R0, PageMangleTable
        LDR     R0, [R0, R4]          ; load data table pointer
        MOV     R4, #0
01      LDR     R1, [R0], #4
        CMP     R1, #-1
        BEQ     %FT02
        AND     R6, R2, R1
        LDR     R1, [R0], #4
        CMP     R1, #0
        RSBMI   R1, R1, #0
        MOVPL   R6, R6, LSL R1
        MOVMI   R6, R6, LSR R1
        ORR     R4, R4, R6
        B       %BT01

02      LDR     R1, [R0], #4
        CMP     R1, #-1
        BEQ     %FT03
        AND     R6, R3, R1
        LDR     R1, [R0], #4
        CMP     R1, #0
        RSBMI   R1, R1, #0
        MOVPL   R6, R6, LSL R1
        MOVMI   R6, R6, LSR R1
        ORR     R4, R4, R6
        B       %BT02

03      ORR     R4, R4, #CAM
        ORR     R4, R4, R11, LSL #8     ; stuff in PPL
        STR     R4, [R4]                ; and bang the bugger in
        MOV     PC, LR

; Data to drive CAM setting

PageMangleTable
        &       PageMangle4K
        &       PageMangle8K
        &       PageMangle16K
        &       PageMangle32K

; For each page size, pairs of masks and shift factors to put the bits in the
; right place. Two sets: operations on Physical Page Number, operations on
; Logical Page Number.

; Shifts are Shift Left values (<<). Each section terminated by -1

PageMangle4K
; PPN:
        &       2_11111111
        &       0                       ; bits in right place
        &       -1
; LPN:
        &       2_1100000000000:SHL:12
        &       (11-12)-12              ; LPN[12:11] -> A[11:10]
        &       2_0011111111111:SHL:12
        &       (22-10)-12              ; LPN[10:0 ] -> A[22:12]
        &      -1

PageMangle8K
; PPN:
        &       2_10000000              ; PPN[7]   -> A[7]
        &       7-7
        &       2_01000000
        &       0-6                     ; PPN[6]   -> A[0]
        &       2_00111111
        &       6-5                     ; PPN[5:0] -> A[6:1]
        &       -1
; LPN:
        &       2_110000000000:SHL:13
        &       (11-11)-13              ; LPN[11:10] -> A[11:10]
        &       2_001111111111:SHL:13
        &       (22-9)-13               ; LPN[9:0]   -> A[22:13]
        &       -1

PageMangle16K
; PPN:
        &       2_10000000
        &       7-7                     ; PPN[7]   -> A[7]
        &       2_01100000
        &       1-6                     ; PPN[6:5] -> A[1:0]
        &       2_00011111
        &       6-4                     ; PPN[4:0] -> A[6:2]
        &       -1
; LPN:
        &       2_11000000000:SHL:14
        &       (11-10)-14              ; LPN[10:9] -> A[11:10]
        &       2_00111111111:SHL:14
        &       (22-8)-14               ; LPN[8:0]  -> A[22:14]
        &       -1

PageMangle32K
; PPN:
        &       2_10000000
        &       7-7                     ; PPN[7] -> A[7]
        &       2_01000000
        &       1-6                     ; PPN[6] -> A[1]
        &       2_00100000
        &       2-5                     ; PPN[5] -> A[2]
        &       2_00010000
        &       0-4                     ; PPN[4] -> A[0]
        &       2_00001111
        &       6-3                     ; PPN[3:0] -> A[6:3]
        &       -1
; LPN:
        &       2_1100000000:SHL:15
        &       (11-9)-15               ; LPN[9:8] -> A[11:10]
        &       2_0011111111:SHL:15
        &       (22-7)-15               ; LPN[7:0] -> A[22:15]
        &       -1

PageSizes
        &       4*1024                  ; 0 is 4K
        &       8*1024                  ; 4 is 8K
        &       16*1024                 ; 8 is 16
        &       32*1024                 ; C is 32

PageShifts
        =       12, 13, 0, 14           ; 1 2 3 4
        =       0,  0,  0, 15           ; 5 6 7 8

;++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; routine to set up a 32K chunk (for fixed areas)
; Enter with R8 = PageSize, R2 = physram offset, R3 logaddr

SlapIn32K
        MOV     R12, lr
        ADR     R1, PageShifts-1
        LDRB    R1, [R1, R8, LSR #12]
        MOV     R2, R2, LSR R1          ; DivRem  R0, R2, R8, R1
                                        ; R2 := cam entry no
        ADD     R5, R3, #32*1024
SlapInNext
        BL      BangCam
        ADD     R2, R2, #1
        ADD     R3, R3, R8
        CMP     R3, R5
        BNE     SlapInNext
        MOV     PC, R12


AddCamEntries
; R0 points at appropriate part of CAM map
; R2 is address
; R7 no of cam entries*4 for 32K
; R8 PageSize
        MOV     R1, #0
        CMP     r2, #CursorChunkAddress
        ORREQ   r2, r2, #&10000000      ; appropriate PPL
01      STR     R2, [R0, R1]
        ADD     R1, R1, #4
        ADD     R2, R2, R8
        CMP     R1, R7
        BNE     %BT01
        MOVS    pc, lr

FudgeConfigureRMA
        Push   lr
        B      ConfigureRMA

ReadCMOSAndConfigure ROUT
; R0 = index into CMOS RAM of byte with size in
; R1 = place to save amount moved
; R2 = CAM entry number to start at: updated
; R3 = LogRam Address to move memory to
; r11  PPL
; Check for memory left, move as much as poss
        Push    lr
        BL      Read                    ; CMOS byte -> R0

        CMP     r3, #FontCacheAddress
        MOVEQ   r0, r0, LSL #12         ; *4K
        BEQ     NotScreen

        AND     R0, R0, #127            ; mask to same bitfield as status
ConfigureRMA
        MOV     R10, #0
        LDR     R10, [R10, #Page_Size]
        Push    "R1, R3"
        MOV     R1, R10
        MULTIPLY R3, R0, R1
        MOV     R0, R3                  ; get size in bytes
        Pull    "R1, R3"
        CMP     R3, #32*1024*1024       ; screen?
        BNE     NotScreen

; quick buggerypokery for sensible screensize

        CMP     R0, #0
        BNE     CmosScreenWillDo
        LDR     R0, [R0, #RAMLIMIT]
        CMP     R0, #512*1024
        MOVEQ   R0, #80*1024
        MOVNE   R0, #160*1024
CmosScreenWillDo

        CMP     R0, #20*1024            ; ensure mode 0 gettable
        MOVLT   R0, #20*1024
        CMP     R0, #480*1024
        MOVGT   R0, #480*1024

        SUB     R3, R3, R0              ; step back.
NotScreen
        MOV     R5, #0                  ; amount moved
        CMP     R0, #0
        BEQ     NoMoreMemory
        LDR     R8, [R5, #RAMLIMIT]

; now set R6 = first entry not to use
;         R7 = end of gap   "   "  "
;         R8 = last entry we can use

        CMP     R8, #512*1024
        MOVEQ   R6, #(512-96)*1024
        MOVEQ   R7, #512*1024
        MOVNE   R6, #(512-32)*1024
        MOVNE   R7, #(512+64)*1024
        Push    "R2"

        ADRL    R2, PageShifts-1
        LDRB    R2, [R2, R10, LSR #12]
        MOV     R6, R6, LSR R2          ; DivRem  R6, R6, R10, R2
        MOV     R7, R7, LSR R2
        MOV     R8, R8, LSR R2

        Pull    "R2"

CAMZapLoop
        CMP     R2, R6                  ; if at gap, skip
        MOVEQ   R2, R7
        CMP     R2, R8                  ; if no more memory, give in
        BEQ     NoMoreMemory
        ADD     R5, R5, R10
        Push    "R0, R1, R6"
        BL      BangCamUpdate
        Pull    "R0, R1, R6"
        ADD     R2, R2, #1
        ADD     R3, R3, R10
        SUBS    R0, R0, R10
        BGT     CAMZapLoop
NoMoreMemory
        STR     R5, [R1]
        Pull    "PC"

; startup interrupt handler (kbd handler only): uses PhysRam start as flags
; 0 is marker for halfway through key data transmission

                ^ 1
CTRL_Down_Flag  # 1
SHIFT_Down_Flag # 1
KB_There_Flag   # 1

R_Down_Flag     # 1      ; note that these 4 form one word!!
T_Down_Flag     # 1
Del_Down_Flag   # 1
Copy_Down_Flag  # 1

KeyDataPtr      * 8

IRQ_Test_CTRL_or_R_Pressed ROUT
        Push    "r0-r2, R10-R12, lr"
        MOV     R12, #IOC

        MOV     r2, #IOC
        MOV     r0, #32
        BL      DoMicroDelay    ; quick thumb twiddle until it's REALLY there
        LDRB    R11, KARTRx     ; read byte transmitted by keyboard

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""R"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        CMP     R11, #HRDRESET  ; first check for part of reset sequence and reply accordingly

        BEQ     fartaboutfornewkbd

        CMP     R11, #RST1ACK
        MOVEQ   R10, #RST2ACK
        BEQ     send_ack_byte

        CMP     R11, #RST2ACK
        BNE     keytransmission

        MOV     R10, #PhysRam
        LDR     R10, [R10, #KeyDataPtr]
        CMP     R10, #0
        MOVNE   R10, #ACK+SCAN
        BNE     send_ack_byte
        MOV     R10, #ACK

  [ KeyboardDebungling
   Push  R12
   MOV   R12, R10, LSR #4
   TubeChar  R10, R11, "MOV R11, #""k"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R10, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
 ]

        STRB    R10, KARTTx
        BL      PollTxBit
        MOV     R11, #K1rqid
        BL      SendAndPollRxBit

  [ A500Keyboard
        AND     r10, r11, #&F0
        CMP     R11, #IDTYPE            ; a500 kbd?
        ADREQ   R10, DataA500Kbd
        BEQ     gotkbdid
  ]
        SUB     r11, r11, #K1kbid + 1
        CMP     r11, #30
        ADRLSL  R10, DataA1Kbd          ; only accept ID 1-31
        MOVHI   R10, #0                 ; else don't know

gotkbdid
        MOV     R11, #PhysRam
        STR     R10, [R11, #KeyDataPtr]
 [ A1Keyboard
 ASSERT (DataA1Kbd :AND: 255) <> 0
 ]
 [ A500Keyboard
 ASSERT (DataA500Kbd :AND: 255) <> 0
 ]
        STRB    R10, [R11, #KB_There_Flag]
                                        ; only there once ID understood
        MOV     R10, #HRDRESET          ; and from the top
        B       send_ack_byte

keytransmission
; assume it's key info
        MOV     R10, #PhysRam
        LDRB    R10, [R10]      ; the "had a byte" flag
        CMP     R10, #0
        BNE     hadabyteofkey
        MOV     R10, #PhysRam
        STRB    R11, [R10]      ; first part of 2 byte protocol: set flag
        MOV     R10, #ACK+&F
        B       send_ack_byte

fartaboutfornewkbd

kickthebastardagain
        MOV     R11, #HRDRESET
        BL      SendAndPollRxBit        ; get a byte to R11
        BL      PollTxBit
        CMP     R11, #HRDRESET
        BNE     kickthebastardagain
        MOV     R11, #RST1ACK
        BL      SendAndPollRxBit        ; get a byte to R11
        BL      PollTxBit
        CMP     R11, #RST1ACK
        BNE     kickthebastardagain
        MOV     R10, #RST2ACK
        B       send_ack_byte

hadabyteofkey
; now got 1st byte in R10, second byte in R11 : test for CTRL or R
        MOV     R0, #PhysRam
        LDR     R0, [R0, #KeyDataPtr]
10      LDRB    R1, [R0], #1
        CMP     R1, #0
        BEQ     %FT11
        CMP     R1, R10
        LDRB    R1, [R0], #1
        CMPEQ   R1, R11
        LDRB    R1, [R0], #1
        BNE     %BT10
        MOV     R11, #PhysRam
        STRB    R1, [R11, R1]           ; non-zero means pressed
11
        MOV     R10, #ACK+SCAN
send_ack_byte

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R10, LSR #4
   TubeChar  R10, R11, "MOV R11, #""T"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R10, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        STRB    R10, KARTTx             ; assume always able to transmit?
        CMP     R10, #ACK+&F
        MOVNE   R11, #PhysRam
        STRNEB  R11, [R11]            ; clear "one byte of 2 byte seq had" flag
        Pull    "r0-r2, R10-R12, lr"
        SUBS    PC, R14, #4

 DCD 0 ; temp fudge
 
 [ A1Keyboard
  [ @ :AND: 255 = 0
 DCB "S" ; Odd length, should throw us
  ]
DataA1Kbd
    =   A1CTRLLRow,  A1CTRLLCol,  CTRL_Down_Flag
    =   A1CTRLRRow,  A1CTRLRCol,  CTRL_Down_Flag
    =   A1SHIFTRRow, A1SHIFTRCol, SHIFT_Down_Flag
    =   A1SHIFTLRow, A1SHIFTLCol, SHIFT_Down_Flag
    =   A1R_Row,     A1R_Col,     R_Down_Flag
    =   A1T_Row,     A1T_Col,     T_Down_Flag
    =   A1Del_Row,   A1Del_Col,   Del_Down_Flag
    =   A1Copy_Row,  A1Copy_Col,  Copy_Down_Flag
    =   0
 ]

 [ A500Keyboard
  [ @ :AND: 255 = 0
 DCB "K"
  ]
DataA500Kbd
    =   A500CTRLRow,  A500CTRLCol,  CTRL_Down_Flag
    =   A500SHIFTRow, A500SHIFTCol, SHIFT_Down_Flag
    =   A500R_Row,    A500R_Col,    R_Down_Flag
    =   A500T_Row,    A500T_Col,    T_Down_Flag
    =   A500Del_Row,  A500Del_Col,  Del_Down_Flag
    =   A500Copy_Row, A500Copy_Col, Copy_Down_Flag
    =   0
 ]

    ALIGN


PollTxBit ROUT

01      LDRB    R10, [R12, #IOCIRQSTAB]
        TST     R10, #KARTTxBit
        BEQ     %BT01
        MOV     pc, lr


SendAndPollRxBit ROUT

        Push    lr

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""t"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        STRB    R11, KARTTx

01      LDRB    R10, [R12, #IOCIRQSTAB]
        TST     R10, #KARTRxBit
        BEQ     %BT01

        MOV    r2, #IOC
        MOV    r0, #32
        BL     DoMicroDelay
        LDRB   R11, KARTRx              ; purge KART, or get reply

     [ KeyboardDebungling
   Push  R12
   MOV   R12, R11, LSR #4
   TubeChar  R10, R11, "MOV R11, #""r"""
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   AND   R12, R11, #&F
   TubeChar  R10, R11, "ADD R11, R12, #""0"""
   Pull  R12
     ]

        Pull   pc

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Data tables: VIDC := mode 0, all palette black

VIDCTAB & &00000000
        & &04000000
        & &08000000
        & &0C000000
        & &10000000
        & &14000000
        & &18000000
        & &1C000000
        & &20000000
        & &24000000
        & &28000000
        & &2C000000
        & &30000000
        & &34000000
        & &38000000
        & &3C000000
        & &40000000
        & &44000000     ; Cursor -> black
        & &48000000
        & &4C000000     ; Palette programmed (avoid messy screen on reset)

        & &807FC000     ; HCR  Get a stable display up so we get stable signals
        & &8408C000     ; HSWR
        & &881B0000     ; HBSR
        & &94770000     ; HBER
        & &A04E0000     ; VCR
        & &A4024000     ; VSWR
        & &A8050000     ; VBSR
        & &B44E0000     ; VBER
        & &C0000100     ; SFR  NB. TEST BIT !!! - also DFlynn requested value
        & &E00000B2     ; CR   Set 640*256, 1 bit per pixel, rate of 12MHz
                        ; change bottom byte to 22 for Linear Microvitecs (CS)
                        ;                       B2 for Monochrome/Philips (SS)
        & &8C208000     ; HDSR
        & &90708000     ; HDER
        & &98258000     ; HCSR
        & &9C400000     ; HIR
        & &AC098000     ; VDSR
        & &B0498000     ; VDER
        & &B8098000     ; VCSR
        & &BC498000     ; VCER
; don't mess with the stereo image registers: sound code will set them.
        & &FFFFFFFF     ; That's the lot


CONT ROUT                               ; entered here after RESET

; First bang MEMC to ensure safety

        LDR     R0, ResetMemC_Value
        STR     R0, [R0]     ; set ROM access times, refresh on flyback, no DMA

; VInit etc set on ze mode change: no DMA going yet so don't set owt.

        MOV     R1, #VIDCADR    ; Must ALWAYS initialise VIDC on reset or else
        ADR     R2, VIDCTAB     ; we may get vsync interrupts that stiff us
10      LDR     R0, [R2], #4    ; permanently as VIDC is in an undefined state
        CMP     R0, #-1         ; so have mode 0 with all black palette
        STRNE   R0, [R1]
        BNE     %BT10

; Now bang IOC (disable all but keyboard interrupts)

        MOV     R1, #IOC
        MOV     R0, #&FF                ; all inputs
        STRB    R0, [R1, #IOCControl]   ; in case called by Tim

        MOV     R0, #0
        STRB    R0, [R1, #IOCIRQMSKA]   ; kein interrupts
        STRB    R0, [R1, #IOCFIQMSK]    ; knob off, FIQ
        MOV     R0, #KARTRxBit
        STRB    R0, [R1, #IOCIRQMSKB]   ; allow communication with kbd, when I_bit gets cleared

; now bits to allow CMOS read/write : need timer

        LDR     R0, =20000      ; R0 = Timer delay (units of 0.5 microsecond)
                                ; 20000*0.5E-6 = 0.01 Seconds (100Hz ticker)

        STRB    R0, [R1, #Timer0LL]     ; Set up the delay
        MOV     R0, R0, LSR #8
        STRB    R0, [R1, #Timer0LH]
        STRB    R0, [R1, #Timer0GO]     ; and start the ticks

        MOV     R0, #timer0_bit
        STRB    R0, [R1, #IOCIRQCLRA]   ; Clear pending t0 interrupt j.i.c.

; now size memory

        BL      MemSize                 ; Corrupts r2-r5

;;        DREG    r0, "Page size is "
;;        DREG    r1, "Mem. size is "

        MOV     R13, R1                 ; R13 is now the RAM size
        MOV     R9, R2                  ; need this to set soft copy right

        BL      TimeCPU                 ; r7 := CPU speed in kHz/MEMC1a flag

; first ensure nothing dangerous in MEMC

        MOV     R2, #NoOfCamEntries
        LDR     R3, =DuffEntry          ; a non-existant piece of memory
        MOV     R11, #3                 ; knob off, users
EmptyCamEntries
        BL      BangCam                 ; ensure not mapped to anything
        SUBS    R2, R2, #1              ; dangerous
        BPL     EmptyCamEntries

; Put in position all fixed areas of memory
;   32K for cursor etc     : CAM entries for 512-32 to 512K in PhysRam

        MOV     R11, #1                 ; user write protected
        AND     R3, R9, #&C
        ADRL    R2, PageSizes
        LDR     R8, [R2, R3]            ; R8 = PageSize

        MOV     R3, #CursorChunkAddress
        MOV     R2, #(512-32)*1024
        BL      SlapIn32K

        MOV     R3, #SysHeapChunkAddress ; 32K forced in system heap area
; use phys 512+32 to 512+64K if R13<>512K,  512-96 to 512-64K if R13=512K
        CMP     R13, #512*1024
        MOVEQ   R2, #(512-96)*1024
        MOVNE   R2, #(512+32)*1024

        MOV     r11, #0
        BL      SlapIn32K

        MOV     R3, #0                  ; 32K system work area

; use phys 512 to 512+32K if R13<>512K,  512-64 to 512-32K if R13=512K

        CMP     R13, #512*1024
        MOVEQ   R2, #(512-64)*1024
        MOVNE   R2, #512*1024

        BL      SlapIn32K

; the fixed areas give us : IRQ stack (in cursor), SVC stack (in sysheap base)
; and bottom block makes most sense done here

; now keyboard initialisation: initialise baud rate, send dummy, read dummy

        MOV     R12, #IOC               ; code ripped off from pmf.Key
        MOV     R0, #1
        STRB    R0, Timer3Low
        MOV     R0, #0
        STRB    R0, Timer3High
        STRB    R0, Timer3Go            ; baud rate set and going

        STRB    R0, KARTTx              ; send dummy

        MOV     r1, r13
        MOV     r13, #&8000             ; need a quick stack - scratchspace
        Push    r1                      ; probably the best bet.
        MOV     r0, #&800*2             ; magic delay
        MOV     r2, #IOC
        BL      DoMicroDelay
        LDMFD   r13, {r13}              ; finished with stack

        LDRB    R0, KARTRx              ; ensure no wally byte in KARTRx

        BL      PollTxBit
        MOV     R0, #HRDRESET           ; start reset protocol
        STRB    R0, KARTTx

        MOV     R0, #PhysRam
        MOV     R1, #0
        STRB    R1, [R0, #CTRL_Down_Flag] ; clear CTRL down flag, R down flag
        STRB    R1, [R0, #SHIFT_Down_Flag]
        STRB    R1, [R0, #KB_There_Flag]
        STR     R1, [R0, #R_Down_Flag]  ; all CMOS reset flags

    [ A1Keyboard :LAND: A500Keyboard
        STR     R1, [R0, #KeyDataPtr]
    ]

; set up reset interrupt handler (reads, discards keys, setting flags if CTRL or R)
        MOV     R0, #ROM                ; pick up from table
        LDR     R0, [R0, #&18]          ; this gets overwritten while active,
        STR     R0, [R1, #&18]          ; but hopefully by the same value!

        TEQP    pc, #IRQ_mode + I_bit   ; set up IRQ stack
        MOVNV   r0, r0
        LDR     sp_irq, =IRQSTK
        TEQP    pc, #SVC_mode           ; Enable interrupts, back to supervisor mode

; IF por OR FX200 bit set THEN clear memory
        MOV     R0, #IOC
        LDRB    R1, [R0, #IOCIRQSTAA]
        ANDS    R1, R1, #por_bit
        BNE     clear_physram

        LDR     R0, =OsbyteVars + :INDEX: ESCBREAK
        LDRB    R1, [R0]
        CMP     R1, #2                  ; unlike popular rumour, bit 1 ain't
        CMPNE   R1, #3                  ; a flag
        BNE     dont_clear_physram

clear_physram
        MOV     R0, #0
        MOV     R1, #0
        MOV     R2, #0
        MOV     R3, #0
        MOV     R4, #0
        MOV     R5, #0
        MOV     R6, #0
        MOV     R11, #0
        MOV     R8, #PhysRam
        CMP     R13, #512*1024
        ADDEQ   R10, R8, #(512-64)*1024 ; get address that's logram 0
        ADDNE   R10, R8, #512*1024
        ADD     R13, R13, #PhysRam      ; end of memory
        ADD     R8, R8, #4*8            ; skip minimal startup workspace
02      CMP     R8, R10
        ADDEQ   R8, R8, #4*8            ; skip physram that's logram 0
        STMNEIA R8!, {R0-R6, r11}
        CMP     R8, R13
        BNE     %BT02
        SUB     R13, R13, #PhysRam

        LDR     R0, =OsbyteVars + :INDEX: LastBREAK
        MOV     R1, #&80
        STRB    R1, [R0]                ; flag the fact that RAM cleared
dont_clear_physram

        MOV     r0, #0
        STR     r9, [r0, #MEMC_CR_SoftCopy] ; set soft copy.
        STR     r7, [r0, #MemorySpeed]  ; Remember CPU speed/MEMC1a flag
        AND     R8, R9, #&C
        ADRL    R1, PageSizes
        LDR     R8, [R1, R8]
        STR     R8, [R0, #Page_Size]
        STR     R13, [R0, #RAMLIMIT]    ; save sussed memory size in LogRam

        LDR     sp, =SVCSTK             ; set up a stack

; do as much other initialisation as possible, to give keyboard stuff time
; copy handler addresses
        ADRL    R1, ROM+4               ; don't copy to 0: key stuff is using it as workspace!
        MOV     R0, #4

03      LDR     R2, [R1], #4            ; N.B. IRQ handler better be same as the one in there
        STR     R2, [R0], #4
        TEQ     R0, #EndFiq-ROM
        BNE     %BT03

; now the initialised data
        MOV     R0, #IRQ1V

; first save IOC soft copy so can restore it

        LDRB    R2, [R0, #IOCControlSoftCopy-IRQ1V]
        Push    "R2"
        LDRB    R2, [R0, #CannotReset-IRQ1V]
        Push    "R2"

DatCopy LDR     R2, [R1], #4
        STR     R2, [R0], #4
        TEQ     R0, #(EndData-EndFiq+IRQ1V)
        BNE     DatCopy

; Now the SWI despatch + low part of SWI table
        ADRL    R3, DirtyBranch
        LDR     R0, =SWIDespatch
SVCTabCopy                              ; so copy the table
        LDR     R2, [R1], #4
        STR     R2, [R0], #4
        TEQ     R1, R3
        BNE     SVCTabCopy

; pad to 1K table here, rather than use ROM space
        ADRL    R2, NoSuchSWI
        LDR     R4, =1024+SvcTable      ; end of table
PadSVCTable
        CMP     R0, R4
        STRNE   R2, [R0], #4
        BNE     PadSVCTable

; now the dirty branch
        LDR     R1, [R1]
        STR     R1, [R0]

; now the time/date conversions

        LDR     R0, =SvcTable
        ADRL    R1, ConvertStandardDateAndTime
        STR     R1, [R0, #OS_ConvertStandardDateAndTime*4]
        ADD     R1, R1, #ConvertDateAndTime - ConvertStandardDateAndTime ; SKS
        STR     R1, [R0, #OS_ConvertDateAndTime*4]

; other conversion SWIs, all go through same entry point

        ADRL    R1, despatchConvert
        MOV     R2, #OS_ConvertHex1
conversionSWIfill
        STR     R1, [R0, R2, LSL #2]
        ADD     R2, R2, #1
        CMP     R2, #OS_ConvertFileSize+1
        BNE     conversionSWIfill


; Initialise CAO ptr to none.

        MOV     R0, #0
        MOV     R1, #32*1024*1024       ; nothing will be here!!
        STR     R1, [R0, #Curr_Active_Object]

    [ KeyWait <> 0
        MOV     R2, #IOC
        LDR     r0, =KeyWait*2
        BL      DoMicroDelay
    ]

; IF power-on bit set in IOC AND R/T/Del/Copy pressed THEN reset CMOS RAM
; note that memory cleared if POR, so key info has had plenty of time!
        MOV     R0, #IOC
        LDRB    R1, [R0, #IOCIRQSTAA]
        ANDS    R1, R1, #por_bit
        BEQ     no_cmos_reset

        MOV     R0, #PhysRam
        LDR     R7, [R0, #R_Down_Flag]
        CMP     R7, #0
        BEQ     hard_reset              ; power on bit is set anyway

; CMOS reset detectified.
; **************************************************************************
; Note: if this CMOS reset code ever needs changing again, it's probably
; better to rewrite it. The Compact apparently has a table of default
; CMOS values; R-p.o. just writes the table, DEL-p.o. zeroes all, then
; writes the table. With skipping of the time CMOS, and post-prodding of
; the sync, that would probably be a better algorithm.
; **************************************************************************

     SetBorder  R0, R1, 15, 0, 0        ; flash the border as warning!

        MOVS    R3, R7, LSR #16         ; full reset or just system?
        MOVNE   R3, #-1                 ; Del or Copy does all RAM
        MOVEQ   R3, #UserCMOS           ; R or T just system
        MOV     R0, #1
        MOV     R1, #0                  ; zero it first
cmrlp   BL      Write                   ; CMOS(R0) := R1
        ADD     R0, R0, #1
        CMP     R0, R3
        MOVEQ   R0, #&80                ; skip user cmos
        CMP     r0, #YearCMOS
        MOVEQ   r0, #TutuCMOS           ; skip time cmos locns too
        CMP     r3, #UserCMOS           ; system only?
        BNE     skipskipforTC
        CMP     r0, #NewADFSCMOS
        CMPNE   r0, #CountryCMOS        ; skip these if so
        ADDEQ   r0, r0, #1
skipskipforTC
        CMP     R0, #CMOSLimit
        BNE     cmrlp

; now put nice values in where necessary
; first full reset defaults
        CMP     r3, #-1
        BNE     pounds_bleeding_Caspell
        MOV     r0, #CountryCMOS
        MOV     r1, #1                  ; country UK
        BL      Write
        MOV     r0, #NewADFSCMOS
        BL      Write                   ; floppies 1
pounds_bleeding_Caspell

; IF R or Delete pressed THEN set sync 1
        MOV     R0, #PhysRam
        LDRB    R1, [R0, #R_Down_Flag]
        CMP     R1, #0
        LDREQB  R1, [R0, #Del_Down_Flag]
        CMPEQ   R1, #0
        BEQ     nosyncfuckabout
        MOV     R0, #VduCMOS
        MOV     R1, #1
        BL      Write

nosyncfuckabout
        ADR     R8, DefaultCMOSTable

SetCMOSDefaults
        LDRB    R0, [R8], #1
        CMP     R0, #&FF
        BEQ     hard_reset              ; power on bit musta bin set
        LDRB    R1, [R8], #1
        BL      Write
        B       SetCMOSDefaults

DefaultCMOSTable ; list of non-zero options wanted :
; byte pairs of offset, value
; terminated by offset &FF
        =       KeyDelCMOS,     32
        =       FileLangCMOS,   8
        =       FontCMOS,       6
        =       PigCMOS,        10
        =       KeyRepCMOS,     8
        =       RMASizeCMOS,    2
        =       SpriteSizeCMOS, 1
        =       MODETVCMOS,     &10     ; TV 0,1
        =       NetFSIDCMOS,    254
        =       NetPSIDCMOS,    235
        =       PSITCMOS,      (3 :SHL: 2) :OR: (1:SHL:5)
                                        ; Baud 4, print 1
        =       DBTBCMOS,       4:SHL:5 ; Data 4
        =       StartCMOS,     (4 :SHL: 3) :OR: (1 :SHL: 6)
                                        ; CAPS and NODIR
;        =      NewADFSCMOS,    1       ; Floppies 1
; but only want DELETE-power-on to zap this

     [ NewClockChip                     ; only on A1's!
        =       NewADFSCMOS+1,  &FF     ; step 3 for each drive
     ]

        =       NewADFSCMOS+2,  1
        =       SoundCMOS,      &F0     ; speaker on, volume 7, channel 1
        =       CatalogCMOS,    &08
        =       CatalogCMOS+1,  &FF
        =       ExamineCMOS,    &FF
        =       ExamineCMOS+1,  &FF

;        =      CountryCMOS,    1       apparently not!

        =       LanguageCMOS,   3
        =       YearCMOS,       88
        =       YearCMOS+1,     19
        =       TutuCMOS,       2_0100  ; tbs chars valid, ctrlchars '|x'
        =       ANFSCMOS,       2
        =       &FF
        ALIGN


no_cmos_reset                           ; and not power on neither
        Pull    r0                      ; CannotReset flag
        CMP     r0, #0
        BNE     hard_reset

; IF control pressed OR memory implausible (Check SysHpd, CAM map sensible) THEN hard reset

        LDR     R0, =SysHeapStart
        LDR     R8, [R0, #:INDEX: hpdmagic]
        LDR     R2, =magic_heap_descriptor
        CMP     R8, R2                  ; check sysheap initialised
        BNE     hard_reset

; also check CAM map sensible
        MOV     R2, #NoOfCamEntries     ; put sensible values in
                                        ; everywhere when initialising
        MOV     R4, #0
        LDR     R4, [R4, #Page_Size]
        SUB     R4, R4, #1
        ORR     R4, R4, #&FE000000
        MOV     R5, #CamEntries
CamCheck
        LDR     R3, [R5, R2, LSL #2]
        BIC     r3, r3, #&F0000000      ; remove PPL
        TST     R3, R4
        BNE     hard_reset       ; wally entry: not pagesize multiple, or > 16M
        SUBS    R2, R2, #1
        BPL     CamCheck

; leave CTRL test till last, so the keyboard's had as much time to
; wiggle the wet string as we can give it
        MOV     R0, #PhysRam
        LDRB    R1, [R0, #CTRL_Down_Flag]
        CMP     R1, #0
        BNE     hard_reset

soft_reset
; clear out 4K of scratchspace, to use as a reverse CAM soft copy;
; set bytes to indicate page mapped to that address. Can then recalculate
; end of memory.
        MOV     R5, #ScratchSpace
        MOV     R1, #4*1024
        MOV     R2, #0
clrscratch
        SUBS    R1, R1, #4
        STRPL   R2, [R5, R1]
        BPL     clrscratch

        LDR     R2, [R2, #Page_Size]
        ADRL    R8, PageShifts-1
        LDRB    R8, [R8, R2, LSR #12]

        MOV     r2, #0
        LDR     r2, [r2, #RAMLIMIT]
        MOV     r2, r2, LSR r8          ; last valid page
        SUB     r2, r2, #1
        MOV     R7, #CamEntries
        LDR     R12, =DuffEntry

restoreCAMloop
        LDR    R3, [R7, R2, LSL #2]
        MOV    r11, r3, LSR #28
        BIC    r3, r3, #&F0000000

        MOV    R0, R3, LSR R8              ; logram page number
        LDRB   R4, [R5, R0]
        CMP    r4, #0                      ; check for doubly mapped pages
        BEQ    rclon

        ORR    r3, r12, #&30000000         ; force to invalid place if so.
        STR    r3, [R7, R2, LSL #2]
        MOV    r3, r12
        MOV    r11, #3                     ; protected
        MOV    R0, R3, LSR R8
        LDRB   R4, [R5, R0]
rclon
        CMP    r3, #16*1024*1024           ; in application space?
        MOVLT  r11, #0                     ; noprot if so
        STRLT  r3, [R7, R2, LSL #2]
        ADD    R4, R4, #1
        STRB   R4, [R5, R0]                ; sema for interesting pages
        BL     BangCam
        SUBS   R2, R2, #1
        BPL    restoreCAMloop

; now do post-scan to see if we need to do more CAM bashing to get pages back.
; any entries that aren't validateable should be remapped.

        MOV     R7, #0
        MOV     R12, #ScratchSpace
        LDR     R2, [R7, #Page_Size]
findapplend
        LDRB    R3, [R12], #1
        CMP     R3, #0
        ADDNE   R7, R7, R2
        BNE     findapplend
        MOV     R1, #0
        STR     R7, [R1, #AplWorkSize]  ; verified value
        LDR     R3, [R1, #RAMLIMIT]     ; calc last valid page:
        MOV     R3, R3, LSR R8          ; RAMLIMIT >> R8
        MOV     R11, #0                 ; no PPL
        MOV     R4, #CamEntries
testforremap
        SUBS    R3, R3, #1
        BMI     finishedremap
        LDR     R0, [R4, R3, LSL #2]
        BIC     r0, r0, #&F0000000      ; remove PPL
        ADD     R1, R0, R2
        SWI     XOS_ValidateAddress
        BCC     testforremap

        Push    "R2-R4"
        MOV     R0, R0, LSR R8          ; curr logram page number
        LDRB    R4, [R5, R0]
        SUB     R4, R4, #1
        STRB    R4, [R5, R0]            ; dec sema
        MOV     R2, R3                  ; entry no
        MOV     R3, R7                  ; addr to set to
        BL      BangCamUpdate
        Pull    "R2-R4"
holefilled
        ADD     R7, R7, R2
        LDRB    R0, [R12], #1           ; reinspect our reverse map
        CMP     R0, #0
        BNE     holefilled
        MOV     R0, #0
        STR     R7, [R0, #AplWorkSize]
        B       testforremap

finishedremap
        MOV     R12, #NVECTORS-1
        LDR     R11, =VecPtrTab
freenextvec
        LDR     R2, [R11, R12, LSL #2]
loseveclink
        LDR     R3, [R2, #TailPtr]

        MOV     R0, #HeapReason_Free
        LDR     R1, =SysHeapStart
        SWI     XOS_Heap

        MOVVC   R2, R3
        BVC     loseveclink
        CMP     R3, #0                  ; were we at the end of the chain?
        BNE     hard_reset
        SUBS    R12, R12, #1
        BPL     freenextvec
; so that's the code for restore default vectors, basically
        BL      InitVectors
        MOV     R0, #0
        LDR     R1, [R0, #AplWorkSize]
        STR     R1, [R0, #MemLimit]

        LDR     R3, =TickNodeChain
        LDR     R2, [R3]

loseticknodes
        CMP     R2, #0
        BEQ     ticknodesallgone

        LDR     R3, [R2]
        MOV     R0, #HeapReason_Free
        LDR     R1, =SysHeapStart
        SWI     XOS_Heap

        BVS     hard_reset
        MOV     R2, R3
        B       loseticknodes

ticknodesallgone
; and now it's time to free the IRQ structures

        MOV     R12, #(NoInterrupt-1)*12+8      ; last device link offset
        LDR     R11, =DefaultIRQ1V-DefaultIRQ1Vcode+Devices
freenextdev
        LDR     R2, [R11, R12]
losedevlink
        CMP     R2, #0
        BEQ     stepdevice

        LDR     R3, [R2, #8]

        MOV     R0, #HeapReason_Free
        LDR     R1, =SysHeapStart
        SWI     XOS_Heap
        BVS     hard_reset
        MOV     R2, R3
        B       losedevlink
stepdevice
        SUBS    R12, R12, #12
        BPL     freenextdev

; now the PIRQ structures and CallBack_Vector
        LDR     R11, =PIRQ_Chain
        MOV     r4, #PodDesp_Link
losepirqchain
        LDR     R2, [R11]
        CMP     r2, #0                  ; for CallBack_Vector
        BEQ     doobry
losepirqlink
        LDR     R3, [R2, r4]

        MOV     R0, #HeapReason_Free
        LDR     R1, =SysHeapStart
        SWI     XOS_Heap

        MOVVC   R2, R3
        BVC     losepirqlink
        CMP     R3, #0                  ; were we at the end of the chain?
        BNE     hard_reset
        LDR     R2, =PIRQ_Chain
        CMP     R11, R2
        LDR     R2, =PFIQasIRQ_Chain
        MOVEQ   R11, R2
        CMPNE   r11, r2
        LDREQ   r11, =CallBack_Vector
    [ PodDesp_Link <> 0
        MOVEQ   r4, #0
    ]
        BEQ     losepirqchain


doobry  Pull    "R1"                    ; IOCControl restoration
        MOV     R0, #0
        STRB    R1, [R0, #IOCControlSoftCopy]
        MOV     R0, #IOC                ; and bash the hardware
        STRB    R1, [R0, #IOCControl]

        MOV     R0, #SoftReset
        B       ResetPart1Done


hard_reset
        Pull    "R2"                    ; discard old IOC state

; fill in relevant CamMap entries, so can soft start.

        MOV     R8, #0
        LDR     R8, [R8, #Page_Size]
        ADRL    R1, PageShifts-1
        LDRB    R1, [R1, R8, LSR #12]

        MOV     R0, #(512-32)*1024*4
        MOV     R0, R0, LSR R1          ; r0 := cam entry number * 4

        MOV     R7, #32*1024*4
        MOV     R7, R7, LSR R1          ; r7 := cam entry offset for 32K

        ADD     R0, R0, #CamEntries
        MOV     R2, #CursorChunkAddress
        BL      AddCamEntries

        MOV     R12, #0
        LDR     R12, [R12, #RAMLIMIT]
        CMP     R12, #512*1024
        SUBEQ   R0, R0, R7              ; previous entries
        ADDNE   R0, R0, R7              ; next entries
        MOV     R2, #0
        BL      AddCamEntries

; CCs from CMP still valid
        SUBEQ   R0, R0, R7              ; previous entries
        ADDNE   R0, R0, R7              ; next entries
        MOV     R2, #SysHeapChunkAddress
        BL      AddCamEntries

; let's boogie with the CMOS for a bit
; read info and move as much memory as we can

        MOV     R2, #0                  ; CAM entry number to use
        MOV     R0, #ScreenSizeCMOS     ; CMOS byte to read
        MOV     R3, #32*1024*1024       ; where to put it (screen fudged)
        LDR     R1, =VduDriverWorkSpace+TotalScreenSize
                                        ; variable to save size set
        MOV     r11, #0                 ; Unprotected
        BL      ReadCMOSAndConfigure

        MOV     R0, #1                  ; One page. Unprotected
        MOV     R3, #RMAAddress
        ADD     R1, R3, #:INDEX: hpdend ; see comment about SysHeap!
        BL      FudgeConfigureRMA

        MOV     R0, #SpriteSizeCMOS
        MOV     R3, #SpriteSpaceAddress
        LDR     R1, =SpriteSize         ; for Richard. Unprotected
        BL      ReadCMOSAndConfigure

        MOV     R0, #RAMDiscCMOS
        MOV     R3, #RAMDiscAddress
        LDR     R1, =RAMDiscSize        ; for RAMFS
        MOV     r11, #2                 ; protected
        BL      ReadCMOSAndConfigure

        MOV     R0, #FontCMOS
        MOV     R3, #FontCacheAddress
        LDR     R1, =FontCacheSize        ; for Fontmanager
        BL      ReadCMOSAndConfigure      ; still protected

        MOV     r11, #0                 ; Unprotected

; get here with R2 = highest CAM entry used

        MOV     R0, #255
        MOV     R3, #32*1024            ; aplwork start
        LDR     R1, =AplWorkSize        ; aplwork size
        BL      FudgeConfigureRMA       ; stuff rest on AplWork

        MOV     R0, #0
        LDR     R1, [R0, #AplWorkSize]
        ADD     R1, R1, #32*1024
        STR     R1, [R0, #AplWorkSize]
        STR     R1, [R0, #MemLimit]

; now add all the NaffEntries to CamEntries
; R2 highest CAM entry used

        CMP     R2, #NoOfCamEntries
        BGT     CAMallset
        LDR     R0, =CamEntries
        LDR     R1, =DuffEntry+&30000000
WallopDuffOnes
        STR     R1, [R0, R2, LSL #2]
        ADD     R2, R2, #1
        CMP     R2, #NoOfCamEntries
        BLE     WallopDuffOnes

CAMallset
        MOV     R0, #HeapReason_Init    ; initialise system heap
        LDR     R1, =SysHeapStart
        MOV     R3, #32*1024 - (SysHeapStart-SysHeapChunkAddress)
        STR     R3, [R1, #:INDEX: hpdend] ; keep ValidateAddress happy
        SWI     XOS_Heap                  ; bloody tuff if it fails
        BL      InitVectors               ; ready for OsByte to read mode

        MOV     R0, #0                  ; initialise module list to empty
        STR     R0, [R0, #Module_List]
        LDR     R1, =ModuleSWI_HashTab
        MOV     R2, #ModuleSHT_Entries-1
clearmswis
        STR     R0, [R1, R2, LSL #2]
        SUBS    R2, R2, #1
        BGE     clearmswis

        MOV     R0, #IOC
        LDRB    R1, [R0, #IOCIRQSTAA]
        ANDS    R1, R1, #por_bit
        STRNEB  R1, [R0, #IOCIRQCLRA]   ; clear POR if set
        LDREQ   R0, =OsbyteVars + :INDEX: LastBREAK
        LDREQB  R0, [R0]
        TSTEQ   R0, #&80                ; tbs set if memory cleared
        MOVNE   R0, #PowerOnReset
        MOVEQ   R0, #ControlReset


ResetPart1Done                          ; R0 is reset type
        TEQP    PC, #SVC_mode + I_bit   ; interrupts off since kbd bash done
        LDR     R1, =OsbyteVars + :INDEX: LastBREAK
        STRB    R0, [R1]

        MOV     R1, #PhysRam
        LDRB    R0, [R1, #KB_There_Flag]
        LDRB    R1, [R1, #SHIFT_Down_Flag]
        Push    "R0, R1"                ; save until after MOSInit

; copy IRQ handler: not done with rest of copying
; because soft break needs the info to free any claimed blocks.

        LDR     R0, =DefaultIRQ1V
        ADRL    R1, DefaultIRQ1Vcode
        ADRL    R2, DefaultIRQ1Vcode_end
CopyDefaultIRQ1V
        LDR     R3, [R1], #4
        STR     R3, [R0], #4
        CMP     R1, R2
        BNE     CopyDefaultIRQ1V

        LDR     R0, =PIRQ_Chain
        ADRL    R1, Default_PIRQHandler_Node
        STR     R1, [R0]
        STR     R1, [R0, #PFIQasIRQ_Chain-PIRQ_Chain]
 ASSERT Default_PFIQasIRQHandler_Node = Default_PIRQHandler_Node

        MOV     R0, #0                  ; put in IRQ handler, word at 0
        STRB    r0, [r0, #FIQclaim_interlock]
        STRB    r0, [r0, #CallBack_Flag]
        STR     r0, [r0, #CallBack_Vector]
        ADRL    R1, ROM
        LDR     R1, [R1]
        STR     R1, [R0]
        LDR     R1, RealIRQHandler
        STR     R1, [R0, #&18]
        ADRL    R1, (RESET1-8)
        MOV     R1, R1, LSR #2
        ORR     R1, R1, #&EA000000
        STR     R1, [R0]

        MOV     R1, #&100
        STR     R1, [R0, #RCLimit]
        STR     R0, [R0, #ReturnCode]
        STR     R0, [R0, #TickNodeChain]

;now put in error handler and escape handler
        BL      DEFHAN
        BL      DEFHN2
        MOV     R0, #ExceptionDumpArea
        LDR     R1, =DUMPER
        SWI     XOS_ChangeEnvironment

        VDWS    WsPtr                   ; main MOS initialisation
        BL      VduInit
        BL      ExecuteInit
        BL      KeyInit

        TEQP    pc, #SVC_mode
        SWI     XOS_WriteI+22
        LDR     R0, =VduDriverWorkSpace+ModeNo
        LDRB    R0, [R0]                ; restore mode
        SWI     XOS_WriteC
        BVC     ModeOK

        MOV     R0, #114                ; failed, so get rid of any shadow
        MOV     R1, #1
        SWI     XOS_Byte
        SWI     XOS_WriteI+22
        SWI     XOS_WriteI+0            ; and if we can't get mode 0, we're really fooked!!!


ModeOK  SWI     XOS_WriteS

    [ Fix0
        =       10, "$SystemName ", 0
    |
     ; apply "patch" to original image
        =       10, "$SystemName ",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
                                ;" 2 . 0 0   ( d d   m m m   y y y y )  "
    ]
        MOV     R0, #0
        LDR     R0, [R0, #RAMLIMIT]
        MOV     R0, R0, LSR #10         ; /1024
        LDR     R1, =GeneralMOSBuffer
        MOV     R2, #?GeneralMOSBuffer
        SWI     XOS_ConvertInteger4
        SWI     XOS_Write0
        SWI     XOS_WriteS
        =       "K", 10,13, 10, 0       ; title complete

        BL      OscliInit               ; before initialising modules

        MOV     R0, #&FD                ; read last reset type
        MOV     R1, #0
        MOV     R2, #&FF
        SWI     XOS_Byte
        CMP     R1, #SoftReset          ; soft reset?
        BEQ     SkipHardResetPart2

; HardResetPart2
        BL      InitVariables
        BL      ModuleInit              ; initialise modules
                                        ; scan podules, copy modules.

        MOV     R0, #0                  ; shrink sysheap as far as will go.
        SUB     R1, R0, #4*1024*1024
        SWI     XOS_ChangeDynamicArea
        MOV     R0, #ReadCMOS
        MOV     R1, #SysHeapCMOS
        SWI     XOS_Byte
        AND     R2, R2, #2_111111       ; mask to same size as status
        MOV     R0, #0
        LDR     R0, [R0, #Page_Size]
        MULTIPLY R3, R0, R2             ; size spare wanted
        BL      ClaimSysHeapNode
        MOV     R0, #HeapReason_Free
        SWI     XOS_Heap

        MOV     R0, #ReadCMOS
        MOV     R1, #FileLangCMOS
        SWI     XOS_Byte
        MOV     R1, R2
        MOV     R0, #FSControl_SelectFS ; set configured filing system
        SWI     XOS_FSControl


SkipHardResetPart2

        MOV     r0, #0                  ; Set DomainId to 0 every reset
        STR     r0, [r0, #DomainId]     ; before calling anyone

; issue reset service call

        MOV     R1, #Service_Reset
        SWI     XOS_ServiceCall

; now set up the default FIQ owner

        MOV     R1, #Service_ClaimFIQ
        SWI     XOS_ServiceCall

        MOV     R1, #Service_ReleaseFIQ
        SWI     XOS_ServiceCall

        MOV     R0, #FSControl_Shut     ; Open files get closed at reset
        SWI     XOS_FSControl

        BL      PostInit

        MOV     r0, #&FD                ; read last reset type (again!)
        MOV     r1, #0
        MOV     r2, #&FF
        SWI     XOS_Byte
        CMP     r1, #SoftReset          ; a softie?
        SWINE   XOS_WriteI+7            ; go beep! Yaay!

        CMP     r1, #PowerOnReset
        BNE     nomonzap

; if any monitor key pressed, reconfigure, otherwise hang around for a bit
; till keys get a chance to come in again after being reset for the umpteenth
; time by yet another keyboard handler! SKS 07-Jun-88

        MOV     r3, #0
        LDR     r3, [r3, #MetroGnome]
        ADD     r3, r3, #10             ; Hang about for a little while

Monitor0_key    * -107
Monitor1_key    * -108
Monitor2_key    * -125
Monitor3_key    * -109

KeypadStar_key  * -92

HorologicalDelayLoop1
        MOV     r1, #Monitor0_key :AND: &FF
        BL      IsKeyPressedAtReset
        MOVEQ   r3, #MonitorType0
        BEQ     zapmonitortype
        MOV     r1, #Monitor1_key :AND: &FF
        BL      IsKeyPressedAtReset
        MOVEQ   r3, #MonitorType1
        BEQ     zapmonitortype
        MOV     r1, #Monitor2_key :AND: &FF
        BL      IsKeyPressedAtReset
        MOVEQ   r3, #MonitorType2
        BEQ     zapmonitortype
        MOV     r1, #Monitor3_key :AND: &FF
        BL      IsKeyPressedAtReset
        MOVEQ   r3, #MonitorType3
        BEQ     zapmonitortype

        MOV     r0, #0
        LDR     r0, [r0, #MetroGnome]
        CMP     r0, r3
        BLO     HorologicalDelayLoop1
        B       nomonzap

zapmonitortype
        MOV     r0, #ReadCMOS
        MOV     r1, #VduCMOS
        SWI     XOS_Byte
        BIC     r2, r2, #MonitorTypeBits
        ORR     r2, r2, r3
        MOV     r0, #WriteCMOS
        SWI     XOS_Byte

        SWI     XOS_WriteI+22
        SWI     XOS_WriteI+0
        SWI     XOS_WriteS
        =       10,"Monitor type reconfigured.",10,13,10,0
        ALIGN
nomonzap


; Deal with SHIFT pressed/SHIFT-BREAK configured:
; do appropriate FSControl if wanted

        Pull    "R0"                    ; first check kbd there

        CMP     R0, #0
        BEQ     AutoBootCosNoKbd

        MOV     R0, #&FF
        MOV     R1, #0
        MOV     R2, #&FF                ; read shifty state
        SWI     XOS_Byte
        AND     R0, R1, #8              ; picka da bit
        EOR     R0, R0, #8              ; invert sense
        Pull    "R1"
        CMP     R1, #0
        MOVNE   R1, #8
        EORS    R1, R1, R0

Hortoculture_Kicking
        MOVNE   R0, #FSControl_BootupFS
        SWINE   XOS_FSControl
        BLVS    PrintError
        SWIVS   XOS_NewLine

; if either * pressed, drop into * prompt, otherwise hang around for a bit
; till keys get a chance to come in again after being reset for the umpteenth
; time by yet another keyboard handler! SKS 01-Jun-88

        MOV     r3, #0
        LDR     r3, [r3, #MetroGnome]
        ADD     r3, r3, #10             ; Hang about for a little while

HorologicalDelayLoop2
        MOV     r1, #KeypadStar_key :AND: &FF
        BL      IsKeyPressedAtReset
        BEQ     DoStartSuper            ; EQ -> start up supervisor

        MOV     r0, #0
        LDR     r0, [r0, #MetroGnome]
        CMP     r0, r3
        BLO     HorologicalDelayLoop2


; Start configured language module if keypad-* wasn't pressed

        MOV     R0, #ReadCMOS
        MOV     R1, #LanguageCMOS
        SWI     XOS_Byte

        MOV     R0, #ModHandReason_GetNames
        SUB     R1, R2, #1
        MOV     R2, #0                  ; preferred incarnation
        SWI     XOS_Module
        ADRVSL  R3, UtilityMod
        LDR     R2, [R3, #Module_Title]
        CMP     R2, #0
        ADDNE   R1, R3, R2
DoStartSuper
        ADREQL  R1, UtilModTitle        ; ALWAYS enter via SWI: sets CAO etc.
        MOV     R0, #ModHandReason_Enter
        ADRL    R2, crstring            ; no environment
        SWI     XOS_Module
        CMP     r0, r0                  ; set EQ if failed to enter config.lang
        B       DoStartSuper            ; -> force Super entry


AutoBootCosNoKbd
        SWI     XOS_WriteS
        =       7, "No keyboard present - autobooting", 10,13,0
        ALIGN
        CMP     pc, #0                  ; set NE
        B       Hortoculture_Kicking


RealIRQHandler
         B     Initial_IRQ_Code+.-&18

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; In    r1 = INKEY -ve key code to look for

; Out   EQ: key pressed
;       NE: key not pressed

IsKeyPressedAtReset ENTRY "r0-r2"

        MOV     r0, #129
        MOV     r2, #&FF
        SWI     XOS_Byte
        TEQ     r1, #&FF
        TEQEQ   r2, #&FF
        EXIT

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    [ AddTubeBashers
TubeDumpR0     ROUT
        Push  "R1, R2, lr"
        TubeChar r0, r1, "MOV r1, #"" """
        MOV    R1, #7
01      MOV    R0, R0, ROR #28
        AND    R2, R0, #&F
        TubeChar R0, R1, "ADD R1, R2, #""0"""
        SUBS   R1, R1, #1
        BPL    %BT01
        TubeChar r0, r1, "MOV r1, #"" """
        Pull  "R1, R2, PC", ,^

TubeNewl
        TubeChar R0, R1, "MOV R1, #10"
        TubeChar R0, R1, "MOV R1, #13"
        MOVS   pc, lr
    ]

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

KeyboardDebungling SETL {FALSE}

        LNK     MemSize
