; Copyright 1996 Acorn Computers Ltd
;
; Licensed under the Apache License, Version 2.0 (the "License");
; you may not use this file except in compliance with the License.
; You may obtain a copy of the License at
;
;     http://www.apache.org/licenses/LICENSE-2.0
;
; Unless required by applicable law or agreed to in writing, software
; distributed under the License is distributed on an "AS IS" BASIS,
; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
; See the License for the specific language governing permissions and
; limitations under the License.
;
; > $.Source.PMF.osinit

        GBLL    ErrorsInR0
ErrorsInR0 SETL Module                  ; if FALSE, use XOS_GenerateError for
                                        ; RAM version
                                        ; if TRUE, return error ptr in R0

        GBLL    ProtectStationID        ; if TRUE, disallow OSBYTE &A2,0,n
ProtectStationID SETL {TRUE}:LAND::LNOT:STB

 [ STB
	; STB and NC machines probably want Num lock off.
KBStat_Default	*	KBStat_NoShiftLock :OR: KBStat_NoNumLock
 |
	; Desktop machines probably want Num lock on.
KBStat_Default	*	KBStat_NoShiftLock
 ]

; *****************************************************************************

ExecuteInit ROUT
        Push    R14

       ; Point to OsbyteVars
       ; and initialise them

        BYTEWS  WsPtr

        LDRB    R1, LastBREAK           ; 0 => soft, 1 => power-on, 2 => hard
        CMP     R1, #1
        ADRCC   R2, SoftResetVars
        ADREQ   R2, PowerOnResetVars
        ADRHI   R2, HardResetVars

        LDRCCB  R3, NoIgnore            ; preserve NoIgnore over soft reset
        MOVCS   R3, #0                  ; if hard or power-on reset, zero it
        STRCS   R3, TimerAlpha +0       ; and zero both copies of TIME
        STRCS   R3, TimerAlpha +4
        STRCS   R3, TimerBeta +0
        STRCS   R3, TimerBeta +4
        MOV     R4, R1                  ; preserve LastBREAK

        MOV     R1, WsPtr               ; start at the beginning
        ADR     R11, ByteVarInitTable

ByteVarInitLoop
        LDRB    R0, [R11], #1           ; copy a byte from table
        STRB    R0, [R1], #1            ; to vars
        TEQ     R1, R2                  ; at end ?
        BNE     ByteVarInitLoop         ; [no, then loop]

        STRB    R3, NoIgnore            ; put NoIgnore back
        STRB    R4, LastBREAK           ; put LastBREAK back

; Initialise buffer pointers

        MOV     R0, #4*(NBuffers-1)     ; index to pointer
        MOV     R1, #0                  ; value to store
BuffPtrInitLoop
        STR     R1, [R0, #BuffInPtrs]
        STR     R1, [R0, #BuffOutPtrs]
        SUBS    R0, R0, #4
        BPL     BuffPtrInitLoop

; mark printer as dormant

        STR     R1, PrinterActive       ; (R1=0)

; Initialise event semaphores

        ADR     R0, EventSemaphores
        ADD     R2, R0, #32
10
        STR     R1, [R0], #4            ; clear all 32 event semaphores
        TEQ     R0, R2
        BNE     %BT10

        STRB    R1, FlashState
        STRB    R1, SerialInHandle      ; zero serial handles
        STRB    R1, SerialOutHandle

; Initialise LatchB and soft copy

;        MOV     R1, #0          ; AND with 0 (was omitted on earlier MOS) ; R1 already zero
        MOV     R0, #0          ; EOR with 0
        BL      UpdateLatchB

 [ DriversInKernel
        MOV     R1, #DIVRESET6850       ; reset 6551
        MOV     R2, #0
        BL      ModifyControl6850
 ]

; set up IOC timer 0 before we read from CMOS (cos it uses timer for delays)

        MOV     R1, #IOC
        LDR     R0, =20000-1    ; R0 = Timer delay (units of 0.5 microsecond)
                                ; 20000*0.5E-6 = 0.01 Seconds 100Hz
                                ; TMD 21-May-93: "-1" correction applied

        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

        LDRB    R0, LastBREAK
        TEQ     R0, #0
        BEQ     %FT20

        BL      ReadMachineType
        BL      ReadUniqueID
        BL      ReadHardCMOSDefaults
20
        BL      ReadCMOSDefaults
 [ StorkPowerSave
        BL      PowerHardware           ;On Stork, ensure Combo chip, Winnie, Floppy etc are powered
 ]
        [ STB
        BL      ConfigureCombo
        |
 [ IO_Type = "IOMD"
        BL      Configure37C665         ;RiscPC, Kryten and Stork use only SMC 37C665
 |
        BL      Configure82C710         ;Earlier code copes with 82C710,82C711 and 37C665
 ]
        ]

 [ DriversInKernel
; reset ACIA

        LDR     R11, =ACIA

        LDRB    R0, ACIAStatus          ; set up DCD, DSR bits in SerialFlags
        AND     R0, R0, #(ACIADSR :OR: ACIADCD)
        MOV     R0, R0, LSL #DCDDSRShift
        STR     R0, SerialFlags         ; other bits are zero

        LDRB    R0, ACIACommand
        ORR     R0, R0, #ACIADTR        ; enable transmit and receive
        STRB    R0, ACIACommand
 ]

        MOV     R1, #IOC

        [ :LNOT: NewClockChip
        MOV     R0, #0
        STRB    R0, SecondsTime         ; zero seconds and centiseconds
        STRB    R0, CentiTime

        LDRB    R0, [R1, #IOCControl]   ; load IOC control register
        AND     R0, R0, #rtc_minutes_bit
        STRB    R0, MinTick             ; Initialise the minute odd/even flag

        MOV     R0, #1
        STRB    R0, SecondsDirty        ; mark the seconds as dirty (non-zero)
        ]

 [ DriversInKernel
        MOV     R0, #timer0_bit :OR: pack_bit :OR: vsync_bit
 |
        MOV     r0, #timer0_bit :OR: vsync_bit
 ]
        STRB    R0, [R1, #IOCIRQCLRA]   ; clear pending tim0, vsync irqs (+ pack irq if appropriate)
        LDRB    R0, [R1, #IOCIRQMSKA]
        ORR     R0, R0, #timer0_bit :OR: vsync_bit
        STRB    R0, [R1, #IOCIRQMSKA]   ; Enable timer 0 + vsync irqs

 [ DriversInKernel
        LDRB    R0, [R1, #IOCIRQMSKB]   ; enable 6551 interrupt
        ORR     R0, R0, #serial_bit
        STRB    R0, [R1, #IOCIRQMSKB]
 ]

 [ E2ROMSupport :LAND: STB
; Don't set time to value held in RTC if the RTC chip is not fitted
; system time will default to epoch: Midnight 1st Jan 1900
	MOV	R1, #0
	LDRB	R0, [r1, #RTCFitted]
	TEQ	R0, #1
	BEQ	%FT28
; Set default time to UNIX epoch (1970) +1day not RISCOS epoch (1900) so time() doesn't return -1
secs0070 *	(86400*(365*70+18))	; from time() in risc_oslib.c.armsys
	LDR	R7, =(secs0070 * 100)	; centiseconds LSW
	MOV	R8, #&33		; centiseconds MSW
	BL	Store5ByteInRealTime
	B	%FT30
28
 ]
        BL      CheckYear               ; check for year wrap scenario
        BL      RTCToRealTime

; insert soft key 10
30
        MOV     R2, #&CA
        BL      RDCHS
        Pull    PC

        LTORG

; *****************************************************************************
;
;       ReadHardCMOSDefaults - Read CMOS values for a hard/power-on reset
;       NB must be called in supervisor mode

ReadHardCMOSDefaults
        Push    R14

        MOV     R0, #PigCMOS
        BL      Read
        STRB    R0, PrinterIgnore

        MOV     R0, #PSITCMOS
        BL      Read
        TST     R0, #2                  ; NoIgnore bit
        MOVEQ   R1, #0
        MOVNE   R1, #&80
        STRB    R1, NoIgnore

        MOV     R1, R0, LSR #5          ; printer type now in bits 0..2
        STRB    R1, PrinterDrivType

        MOV     R0, #MODETVCMOS
        BL      Read
        MOV     R2, R0, LSR #4          ; bit0:=interlace, bits 1-3 := vertical
        AND     R1, R2, #1
        STRB    R1, TVInterlace
        MOV     R2, R2, LSL #31-3       ; bits 29-31 := vertical
        MOV     R2, R2, ASR #29         ; sign extend
        STRB    R2, TVVertical

        MOV     R0, #DBTBCMOS
        BL      Read
        LDRB    R1, StartOptions
        TST     R0, #&10                ; bit 4 = boot bit
        ORREQ   R1, R1, #8              ; noboot => set bit 3
        BICNE   R1, R1, #8              ; boot => clear bit 3
        STRB    R1, StartOptions

        LDR     R2, =VduDriverWorkSpace+CursorFlags
        ANDS    R1, R0, #8              ; noscroll bit - put 0 or 1
        MOVNE   R1, #1                  ; in bottom byte of CursorFlags
        STRB    R1, [R2]                ; leave other bytes alone

        MOV     R0, #CountryCMOS        ; read country CMOS and store in var
        BL      Read                    ; but don't bind 'Default' to a fixed
        STRB    R0, Country             ; country at this stage

 [ :LNOT: DriversInKernel
        BL      SetUpPrinterBuffer
 ]
        Pull    PC

; *****************************************************************************
;
;       ReadCMOSDefaults - Read CMOS values for any reset
;       NB must be called in supervisor mode

ReadCMOSDefaults
        Push    R14

 [ DriversInKernel
        MOV     R0, #PSITCMOS
        BL      Read
        MOV     R1, R0, LSR #2          ; baud bits now in bits 0..2
        AND     R1, R1, #7              ; 0 => 75, ... ,7 => 19200
        ADD     R1, R1, #1              ; 1 => 75, ... ,8 => 19200
        Push    R1
        BL      DoOsbyte07
        Pull    R1
        BL      DoOsbyte08
 ]

        MOV     R0, #DBTBCMOS
        BL      Read
        TST     R0, #2                  ; NZ => loud
        MOVEQ   R1, #&D0                ; (quiet)
        MOVNE   R1, #&90                ; (LOUD)
        STRB    R1, BELLinfo

 [ DriversInKernel
        MOV     R1, R0, LSR #5          ; bits 5..7 -> bits 0..2
        MOV     R1, R1, LSL #2          ; put in bits 2..4
        ORR     R1, R1, #&42            ; or in default 6850 bits
        MOV     R2, #0                  ; replace old value
        BL      ModifyControl6850
 ]

        MOV     R0, #StartCMOS
        BL      Read
        MOVS    R0, R0, LSL #(32-5)     ; bit 5 -> carry, bit 4 -> N bit
        MOVPL   R0, #KBStat_Default + KBStat_ShiftEnable    ; SHCAPS
        MOVMI   R0, #KBStat_Default + KBStat_NoCapsLock     ; NOCAPS
        MOVCS   R0, #KBStat_Default                         ; CAPS
        STRB    R0, KeyBdStatus

 [ ModeSelectors
        BL      Read_Configd_MonitorType
        LDR     r1, =VduDriverWorkSpace+CurrentMonitorType ; set current to default
        STR     r0, [r1]
 ]

        Pull    R14

; and drop thru to ...

ReadKeyDefaults
        Push    R14

        MOV     R0, #KeyDelCMOS         ; Read the default out of CMOS RAM
        BL      Read                    ; comes back in R0
        STRB    R0, KeyRepDelay

        MOV     R0, #KeyRepCMOS         ; Read the default out of CMOS RAM
        BL      Read                    ; comes back in R0
        STRB    R0, KeyRepRate

        Pull    PC

; *****************************************************************************
;
;       PostInit - Called by Sam after modules have been initialised
;

PostInit ROUT
        Push    R14
        BYTEWS  WsPtr
        LDRB    R0, LastBREAK           ; get reset type
        TEQ     R0, #0
        BEQ     %FT10                   ; [soft reset, skip]

 [ StorkPowerSave
        SWI     XPortable_ReadFeatures
        BVC     %FT01
;
        MOV     R0, #0
        MOV     R1, #0
        SWI     XPortable_Speed         ; attempt to make the portable go fast!
        MOVVC   R1, #PortableFeature_Speed
        MOVVS   R1, #0
01
        AND     R0, R1, #(PortableFeature_Speed :OR: PortableFeature_Idle :OR: PortableFeature_Stop)
        STRB    r0, [r0, #PortableFlags]
 |
        MOV     r0, #0                  ; allow SWI Portable_Speed to be issued
        STRB    r0, [r0, #PortableFlag]
 ]

        [ BleedinDaveBell
        MOV     R0, #1                  ; indicate keyboard UK
        MOV     R1, #101                ; indicate alphabet Latin1
        |
        MOV     R0, #2                  ; indicate keyboard Master
        MOV     R1, #100                ; indicate alphabet Bfont
        ]
        STRB    R0, Keyboard
        STRB    R1, Alphabet
        STRB    R1, KeyAlphabet         ; alphabet corresponding to keyboard

10
        Pull    R14
        B       KeyPostInit

	[ :LNOT: STB
; *****************************************************************************
;
;       SWI OS_ResyncTime
;
; in:   r0  = 0 - Real time clock soft copy only
;       r0 <> 0   reserved for future expansion
;
; out:  r0 preserved
;
ResyncTimeSWI
        Push    "LR"
        BL      CheckYear               ;may have been frozen over new year!
        BL      RTCToRealTime
        Pull    "LR"
        ExitSWIHandler
	]

; *****************************************************************************
;
;       UpdateLatchB - update latch B and soft copy
;
;       LATCHB := (LATCHB AND R1) EOR R0
;

UpdateLatchB
        Push    "R2, R3, R14"
        MOV     R14, PC
        ORR     R2, R14, #I_bit
        TEQP    R2, #0                  ; disable IRQ

        MOV     R2, #0
        LDRB    R3, [R2, #LatchBSoftCopy]
        AND     R3, R3, R1
        EOR     R3, R3, R0
        STRB    R3, [R2, #LatchBSoftCopy]

 [ IO_Type <> "IOMD"                          ; there ain't no Latch B on IOMD!
        LDR     R2, =LatchB
        STRB    R3, [R2]
 ]

        TEQP    R14, #0
        Pull    "R2, R3, PC"

        [ STB
; *****************************************************************************
;
;       UpdateCLines - update IOMD_CLINES 8bit IO port
; In:
;	r3: new value
;	r4: mask of bits to set
;
; Out:
;	All regs preserved

UpdateCLines ENTRY "r0, r1"
	LDR	r0, =(IOMD_Base + IOMD_CLINES)
	LDRB	r1, [r0]
	ORR	r1, r1, #IOMD_C_ReadMask	; Set readable bits
	BIC	r1, r1, r4			; Clear bits to write
	ORR	r1, r1, r3			; Set bits to write
	STRB	r1, [r0]
	EXIT


; *****************************************************************************
        |
; *****************************************************************************
;
;       UpdateMonitorTypeLatch - update monitor type latch and soft copy
;
;       Returns the result in R4

UpdateMonitorTypeLatch
        Push    "R2, R3, R14"
        MOV     R14, PC
        ORR     R2, R14, #I_bit
        TEQP    R2, #0                  ; disable IRQ

        MOV     R2, #0
        LDRB    R3, [R2, #CLine_Softcopy]
        MOV     R3, #1                  ;Set our bit only
        STRB    R3, [R2, #CLine_Softcopy]

        MOV     R2, #IOMD_Base
        STRB    R3, [R2, #IOMD_CLINES]  ;Write the new reg out
        LDRB    R3, [R2, #IOMD_CLINES]  ;Read it back

        AND     R4, R3, #1              ;Clear all but our bit into R4

        TEQP    R14, #0                 ;Re-enable IRQ
        Pull    "R2, R3, PC"


; *****************************************************************************
        ]

; The initial values for all of the osbyte variables
; as decreed by arthur.

ByteVarInitTable
                        ; The main osbyte variables, accessed
                        ; via calls &A6 to &FF

  DCW OsbyteVars-&A6    ; VarStart  #  2     ; &A6,&A7
  = 0,0                 ; ROMPtr    #  2     ; &A8,&A9
  = 0,0                 ; ROMInfo   #  2     ; &AA,&AB
  = 0,0                 ; KBTran    #  2     ; &AC,&AD
  = 0,0                 ; VDUvars   #  2     ; &AE,&AF
                        ;
  = 0                   ; CFStime   #  1     ; &B0
  = 0                   ; InputStream #  1   ; &B1
  = &FF                 ; KeyBdSema #  1     ; &B2
                        ;
  = &00                 ; ROMPollSema # 1    ; &B3
  = &80                 ; OSHWM     #  1     ; &B4 (hi-byte of &8000)
                        ;
  = 1                   ; RS423mode #  1     ; &B5
  = 0                   ; NoIgnore  #  1     ; &B6
  = &00                 ; CFSRFS    #  1     ; &B7
  = &00,&00             ; VULAcopy  #  2     ; &B8,&B9
                        ;
  = &00                 ; ROMatBRK  #  1     ; &BA
  = &FF                 ; BASICROM  #  1     ; &BB
                        ;
  = &04                 ; ADCchanel #  1     ; &BC
  = &04                 ; ADCmaxchn #  1     ; &BD
  = &00                 ; ADCconv   #  1     ; &BE
                        ;
  = &FF                 ; RS432use     #  1  ; &BF
  = &42                 ; RS432conflag #  1  ; &C0
                        ;
  = 0   ;&19            ; FlashCount # 1     ; &C1      /* changed to fx 9 0 by RCM 31/10/91 */
  = &19                 ; SpacPeriod # 1     ; &C2
  = 0   ;&19            ; MarkPeriod # 1     ; &C3      /* changed to fx 9 0 by RCM 31/10/91 */
                        ;
  = &32                 ; KeyRepDelay # 1    ; &C4
  = &08                 ; KeyRepRate  # 1    ; &C5
                        ;
  = &00                 ; ExecFileH   # 1    ; &C6
  = &00                 ; SpoolFileH  # 1    ; &C7
                        ;
  = &00                 ; ESCBREAK    # 1    ; &C8 (200)
                        ;
  = &00                 ; KeyBdDisable # 1   ; &C9
  = KBStat_Default      ; KeyBdStatus  # 1   ; &CA
                        ;
  = &11                 ; RS423HandShake # 1 ; &CB
  = &00                 ; RS423InputSupr # 1 ; &CC
  = &00                 ; RS423CFSFlag   # 1 ; &CD
                        ;
  = &00                 ; EconetOScall # 1   ; &CE
  = &00                 ; EconetOSrdch # 1   ; &CF
  = &00                 ; EconetOSwrch # 1   ; &D0
                        ;
  = &00                 ; SpeechSupr # 1     ; &D1
  = &00                 ; SoundSupr # 1      ; &D2
                        ;
  = &01                 ; BELLchannel # 1    ; &D3
  = &90                 ; BELLinfo    # 1    ; &D4
  = &64                 ; BELLfreq    # 1    ; &D5
  = &06                 ; BELLdur     # 1    ; &D6
                        ;
  = &81                 ; StartMessSupr # 1  ; &D7
                        ;
  = &00                 ; SoftKeyLen # 1     ; &D8
                        ;
  = &00                 ; PageModeLineCount # 1          ; &D9
                        ;
  = &00                 ; VDUqueueItems # 1  ; &DA
                        ;
  = &09                 ; TABch # 1          ; &DB
  = &1B                 ; ESCch # 1          ; &DC
                        ;
  = &01,&D0,&E0,&F0     ; IPbufferCh # 4     ; &DD,&DE,&DF,&E0
  = &01,&80,&90,&00     ; RedKeyCh   # 4     ; &E1,&E2,&E3,&E4
                        ;
  = &00                 ; ESCaction  # 1     ; &E5
  = &00                 ; ESCeffect  # 1     ; &E6
                        ;
  = &00                 ; u6522IRQ # 1       ; &E7
  = &00                 ; s6850IRQ # 1       ; &E8
  = &00                 ; s6522IRQ # 1       ; &E9
                        ;
  = &00                 ; TubeFlag # 1       ; &EA
                        ;
  = &00                 ; SpeechFlag # 1     ; &EB
                        ;
  = &00                 ; WrchDest # 1       ; &EC
  = &00                 ; CurEdit  # 1       ; &ED
                        ;

  = &30                 ; KeyBase            ; &EE
  = &01                 ; Shadow             ; &EF
  = &00                 ; Country            ; &F0
                        ;
  = &00                 ; UserFlag # 1       ; &F1
                        ;
  = &64                 ; SerULAreg # 1      ; &F2
                        ;
  = &05                 ; TimerState # 1     ; &F3
                        ;
  = &FF                 ; SoftKeyConsist # 1 ; &F4
                        ;
  = &01                 ; PrinterDrivType   # 1          ; &F5
  = &0A                 ; PrinterIgnore     # 1          ; &F6
                        ;
  = &01,&00,&00         ; BREAKvector # 3    ; &F7,&F8,&F9
                        ;
  = &00                 ; DRIVER             ; &FA
  = &00                 ; DISPLAY            ; &FB
                        ;
  = &FF                 ; LangROM # 1        ; &FC
                        ;
  = &01                 ; LastBREAK # 1      ; &FD
                        ;
  = &0F                 ; KeyOpt # 1         ; &FE
                        ;
  = &08                 ; StartOptions # 1   ; &FF
                        ;
                        ;
ByteVarInitTableEnd

ByteVarInitTableSize * ByteVarInitTableEnd - ByteVarInitTable

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

        LTORG

oldirqowner & IRQ

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ReadMachineType - Determine machine type and store it in IOSystemType
;

ReadMachineType ENTRY "r0-r12"
 [ IO_Type = "IOMD"
  [ MorrisSupport
        MOV     r12, #IOMD_Base
   [ {TRUE} ; ARM7500FE support
	LDRB	r0, [r12, #IOMD_ID0]
	LDRB	r11, [r12, #IOMD_ID1]
	ORR	r0, r0, r11, LSL #8
	LDR	r11, =IOMD_Original
	TEQ	r0, r11
	MOVEQ	r11, #0					; assume Medusa
	MOVNE	r11, #IOST_7500				; else assume Morris
	TEQ	r11, #IOST_7500				; and set EQ if Morris to do conditional stuff below
   |
        LDRB    r0, [r12, #IOMD_ID0]
        CMP     r0, #&E7
        LDRB    r0, [r12, #IOMD_ID1]
        CMPEQ   r0, #&5B
        MOVEQ   r11, #IOST_7500                         ;EQ, Morris
        MOVNE   r11, #0                                 ;NE, assume Medusa
   ]
;
; On Kryten,	Morris pin Event2 is tied low so bit Nevent2 is a ONE
; On Stork,	Morris pin Event2 is tied high so bit Nevent2 is a ZERO
; On STB/NCD,	Morris pin Event2 is tied high so bit Nevent2 is a ZERO, but we don't have a LCD
; 		controller or battery manager so we'll not set IOST_BATMAN
;
        LDREQB  r0, [r12, #IOMD_IRQSTD]         ;EQ, Morris
   [ BatManSupport
        TSTEQ   r0, #IOMD_Nevent2_bit
        ORREQ   r11, r11, #IOST_BATMAN          ;EQ, Stork ie Morris & BATMAN
   ]
        ORR     r0, r11, #IOST_IOEB             ; pretend we've got IOEB
;
; r11 holds  0                        for  IOMD   (Risc PC)
;        or  IOST_7500                for  Morris (Kryten, Falcon, Omega)
;        or  IOST_7500 + IOST_BATMAN  for  Morris (Stork)
  |
        MOV     r0, #IOST_IOEB                  ; pretend we've got IOEB
  ]
 |
        TEQP    pc, #SVC_mode + I_bit + F_bit   ; disable IRQs and FIQs
        MOVNV   r0, r0
        LDR     r1, =IOEB_ASICPresent
        MOV     r0, #&FA
        STRB    r0, [r1]
        LDRB    r0, [r1]
        TEQP    pc, #SVC_mode + I_bit
        AND     r0, r0, #&0F
        TEQ     r0, #5                          ; must read 5 is ASIC present
        MOVNE   r0, #0                          ; no IOEB, LC or 82C710
        BNE     %FT10

; there is an IOEB ASIC present, so it's safe to test for LC ASIC

        LDR     r1, =LC_ASICPresent
        LDRB    r0, [r1]
        AND     r0, r0, #&0E                    ; bits 3210 should be 010x
        TEQ     r0, #&04
        MOVNE   r0, #IOST_IOEB                  ; IOEB but no LC
        MOVEQ   r0, #IOST_IOEB :OR: IOST_LC     ; IOEB and LC
10
 ]
        MOV     r1, #0                          ; normal Hsync and address pointer
        STRB    r0, [r1, #IOSystemType]

; now read monitor lead type.

        TEQ     r0, #0                          ; no IOEB
        MOVEQ   r2, #&FF                        ; then return all ones for monitor lead type
        BEQ     %FT90

      [ MPEGPoduleNTSCNotPALMask <> 0
        !       1, "Sorry, I don't do MPEGPoduleNTSCNotPALMask any more"
      ]

        [ STB
        LDR     r0, =VIDC                       ; on VIDC20 we invert HSYNC by writing to External Register

  [ MorrisSupport				; On Morris, monitor auto-detect has been moved to IOMD_CLINES
    [ IOMD_C_MonitorType <> 0
	ASSERT	(IOMD_C_MonitorType = (1<<0))	; this code only understands auto-detect in bit 0
    ]
	TST     R11, #IOST_7500
        LDREQ	r3, =IOMD_MonitorType		; Not Morris, address is in old place
        LDRNE   r3, =(IOMD_Base + IOMD_CLINES)
  |
        LDR     r3, =IOMD_MonitorType
  ] ; MorrisSupport

        LDR     r1, =VIDCExternal+Ext_InvertCompVSYNC+Ext_DACsOn+Ext_ERegExt ; normal HSYNC value
        STR     r1, [r0]
        ORR     r2, r1, #Ext_InvertHSYNC        ; value for inverted HSYNC

        LDRB    r4, [r3]                        ; base value
  [ MorrisSupport
    [ IOMD_C_PALNTSCType <> 0
	ASSERT	(IOMD_C_PALNTSCType = (1<<4))	; this code only understands PAL/NTSC auto-detect in bit 4
	AND	r4, r4, #(IOMD_C_MonitorType :OR: IOMD_C_PALNTSCType)
	ORR	r4, r4, r4, LSR #1		; Shift PAL/NTSC bit into bit 3
        AND     r4, r4, #&0F                    ; only use bits 0..3
    |
	AND	r4, r4, #IOMD_C_MonitorType	; only one bit
    ]
  |
        AND     r4, r4, #&0F                    ; only use bits 0..3
  ]
        MOV     r5, #0                          ; bits 0..3   = bits which have ever changed
                                                ; bits 4..7   = bits whose deinverted value was high last time
                                                ; bits 8..11  = bits whose deinverted value just went high-low
                                                ; bits 12..15 = bits whose deinverted value just went high-low-low
                                                ; bits 16..19 = bits which could be hsync
                                                ;  ie after every high-low there was low-low (after deinversion)
                                                ; bits 20..23 = bits which are definitely random
        MOV     r10, #&0F                       ; used inside CheckBits
        MOV     r12, #256                       ; number of iterations
20
        STR     r2, [r0]
        LDRB    r6, [r3]                        ; read value with inverted sync
        STR     r1, [r0]
        LDRB    r7, [r3]                        ; read value with normal sync

  [ MorrisSupport
    [ IOMD_C_PALNTSCType <> 0
	AND	r6, r6, #(IOMD_C_MonitorType :OR: IOMD_C_PALNTSCType)
	ORR	r6, r6, r6, LSR #1		; Shift PAL/NTSC bit into bit 3
        AND     r6, r6, #&0F                    ; only use bits 0..3
	AND	r7, r7, #(IOMD_C_MonitorType :OR: IOMD_C_PALNTSCType)
	ORR	r7, r7, r7, LSR #1		; Shift PAL/NTSC bit into bit 3
        AND     r7, r7, #&0F                    ; only use bits 0..3
    |
	AND	r6, r6, #IOMD_C_MonitorType	; only one bit
	AND	r7, r7, #IOMD_C_MonitorType
    ]
  |
        AND     r6, r6, #&0F                    ; only use bits 0..3
        AND     r7, r7, #&0F
  ]
        EOR     r8, r6, r4                      ; bits which have changed from steady value to inverted one
        ORR     r5, r5, r8                      ; OR into mask of bits which have ever changed
        EOR     r8, r7, r4                      ; bits which have changed from steady value to normal one
        ORR     r5, r5, r8                      ; OR into mask of bits which have ever changed
        EOR     r6, r6, #&0F                    ; deinvert inverted value
        BL      CheckBits                       ; call check routine with first value
        MOV     r6, r7
        BL      CheckBits                       ; call check routine with second value
        SUBS    r12, r12, #1
        BNE     %BT20
        | ; STB

 [ VIDC_Type = "VIDC20"
        LDR     r0, =VIDC                       ; on VIDC20 we invert HSYNC by writing to External Register
 |
        LDR     r0, =VIDCClockSelect            ; on VIDC1 we write to latch instead
 ]
 [ IO_Type = "IOMD"
        LDR     r3, =IOMD_MonitorType
 |
        LDR     r3, =IOEB_MonitorType
 ]

 [ VIDC_Type = "VIDC20"
        LDR     r1, =VIDCExternal+Ext_InvertCompVSYNC+Ext_DACsOn+Ext_ERegExt ; normal HSYNC value
        STR     r1, [r0]
        ORR     r2, r1, #Ext_InvertHSYNC        ; value for inverted HSYNC
 |
        STRB    r1, [r0]                        ; set up normal Hsync
        MOV     r2, #4                          ; inverted Hsync
 ]

 [ MorrisSupport
        TST     R11, #IOST_7500
        BLNE    UpdateMonitorTypeLatch          ;Result back in R4
        LDREQB  r4, [r3]
 |
        LDRB    r4, [r3]                        ; base value
 ]
        AND     r4, r4, #&0F                    ; only use bits 0..3
        MOV     r5, #0                          ; bits 0..3   = bits which have ever changed
                                                ; bits 4..7   = bits whose deinverted value was high last time
                                                ; bits 8..11  = bits whose deinverted value just went high-low
                                                ; bits 12..15 = bits whose deinverted value just went high-low-low
                                                ; bits 16..19 = bits which could be hsync
                                                ;  ie after every high-low there was low-low (after deinversion)
                                                ; bits 20..23 = bits which are definitely random
        MOV     r10, #&0F                       ; used inside CheckBits
        MOV     r12, #256                       ; number of iterations
20
 [ VIDC_Type = "VIDC20"
        STR     r2, [r0]
 |
        STRB    r2, [r0]
 ]

 [ MorrisSupport
        TST     R11, #IOST_7500
        BLNE    UpdateMonitorTypeLatch          ;Result back in R4
        MOVNE   r6, r4
        LDREQB  r6, [r3]
 |
        LDRB    r6, [r3]                        ; read value with inverted sync
 ]

 [ VIDC_Type = "VIDC20"
        STR     r1, [r0]
 |
        STRB    r1, [r0]
 ]

 [ MorrisSupport
        TST     R11, #IOST_7500
        BLNE    UpdateMonitorTypeLatch          ;Result back in R4
        MOVNE   r7,r4
        LDREQB  r7,[r3]
 |
        LDRB    r7, [r3]                        ; read value with normal sync
 ]
        AND     r6, r6, #&0F
        AND     r7, r7, #&0F
        EOR     r8, r6, r4                      ; bits which have changed from steady value to inverted one
        ORR     r5, r5, r8                      ; OR into mask of bits which have ever changed
        EOR     r8, r7, r4                      ; bits which have changed from steady value to normal one
        ORR     r5, r5, r8                      ; OR into mask of bits which have ever changed
        EOR     r6, r6, #&0F                    ; deinvert inverted value
        BL      CheckBits                       ; call check routine with first value
        MOV     r6, r7
        BL      CheckBits                       ; call check routine with second value
        SUBS    r12, r12, #1
        BNE     %BT20



        ] ; STB

; now process result

        LDR     r1, =VIDCExternal+Ext_InvertCompVSYNC+Ext_InvertCompHSYNC+Ext_DACsOn+Ext_ERegExt        ; put back default value
        STR     r1, [r0]

        BIC     r4, r4, r5                      ; don't put port value in for bits that have changed
        BIC     r5, r5, r5, LSR #16             ; make bits 0..3 of r5 indicate random bits

        ANDS    r2, r4, #1                      ; for each bit pair 00 => low, 01 => high, 10 => Hsync, 11 => random
        TST     r5, #1 :SHL: 16
        MOVNE   r2, #2 :SHL: 0
        TST     r5, #1
        MOVNE   r2, #3 :SHL: 0

        TST     r4, #2
        ORRNE   r2, r2, #1 :SHL: 2
        TST     r5, #2 :SHL: 16
        ORRNE   r2, r2, #2 :SHL: 2
        TST     r5, #2
        ORRNE   r2, r2, #3 :SHL: 2

        TST     r4, #4
        ORRNE   r2, r2, #1 :SHL: 4
        TST     r5, #4 :SHL: 16
        ORRNE   r2, r2, #2 :SHL: 4
        TST     r5, #4
        ORRNE   r2, r2, #3 :SHL: 4

        TST     r4, #8
        ORRNE   r2, r2, #1 :SHL: 6
        TST     r5, #8 :SHL: 16
        ORRNE   r2, r2, #2 :SHL: 6
        TST     r5, #8
        ORRNE   r2, r2, #3 :SHL: 6

  [ IO_Type = "IOMD" :LAND: {FALSE}
        ASSERT  IOMD_MonitorIDMask = 1
        AND     r2, r2, #3                      ; only bit 0 of ID valid on IOMD-based systems
  ]

  [ STB :LAND: IOMD_C_TVMode <> 0				; set the TVMode to 0 (VGA) if id bits1,0 != 01 (TV)
        AND	r3, r2, #2_11			; bits we're interested in
	CMP	r3, #2_01			; TV?
	BEQ	%FT90				; yes
	MOV	r3, #0
	MOV	r4, #IOMD_C_TVMode
	BL	UpdateCLines
  ]
90
        MOV     r1, #0
        STRB    r2, [r1, #MonitorLeadType]
        EXIT

CheckBits ROUT
        AND     r8, r10, r5, LSR #12            ; bits that were H-L-L
        BIC     r8, r8, r6                      ; bits that are H-L-L-L
        ORR     r5, r5, r8, LSL #16             ; OR into bits that could be hsync
        ORR     r8, r5, r5, LSR #4
        AND     r8, r6, r8, LSR #8              ; bits that just went H-L-H or H-L-L-H
        AND     r8, r8, r5, LSR #16             ; bits that just went H-L-H or H-L-L-H and could have been hsync
        ORR     r5, r5, r8, LSL #20             ; they're definitely random now
        BIC     r5, r5, r8, LSL #16             ; and they're definitely not hsync now
        AND     r8, r5, #&FF :SHL: 4            ; get H bits, and H-L bits
        BIC     r8, r8, r6, LSL #4              ; knock out bits that were H and are now H
        BIC     r8, r8, r6, LSL #8              ; knock out bits that were H-L and are now H
        BIC     r5, r5, #&FF :SHL: 8            ; knock out all H-L and H-L-L bits
        ORR     r5, r5, r8, LSL #4              ; put in new H-L and H-L-L bits
        BIC     r5, r5, #&F :SHL: 4             ; knock out old H bits
        ORR     r5, r5, r6, LSL #4              ; put in new H bits
        BIC     r5, r5, r5, LSR #20             ; knock out H bits if we know it's random
        MOV     pc, lr

; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       TranslateMonitorLeadType - Determine monitor type and default mode + sync from monitor lead type
;
; in:   Monitor lead type in variable MonitorLeadType (surprisingly!)
;
; out:  r3 = default mode to use
;       r4 = default monitortype to use
;       r5 = default sync to use
;

TranslateMonitorLeadType ENTRY "r0-r2"
        MOV     r1, #Service_MonitorLeadTranslation
        LDRB    r2, [r1, #MonitorLeadType-Service_MonitorLeadTranslation]
        SWI     XOS_ServiceCall
        TEQ     r1, #0                          ; if service claimed, then exit with these numbers
        EXIT    EQ

        ADR     r0, MonitorLeadList
10
        LDR     r14, [r0], #4
        EOR     r1, r2, r14, LSR #24            ; differences
        EOR     r14, r14, #&FF000000            ; make don't cares into zero
        TST     r14, #&C0000000
        BICEQ   r1, r1, #&C0                    ; knock out difference pairs if don't care
        TST     r14, #&30000000
        BICEQ   r1, r1, #&30
        TST     r14, #&0C000000
        BICEQ   r1, r1, #&0C
        TST     r14, #&03000000
        BICEQ   r1, r1, #&03
        TEQ     r1, #0                          ; if still have differences, then loop
        BNE     %BT10

        MOV     r0, #&FF
        AND     r3, r0, r14                     ; mode in bits 0..7
        AND     r4, r0, r14, LSR #8             ; monitortype in bits 8..15
        AND     r5, r0, r14, LSR #16            ; sync in bits 16..23
        EXIT

        MACRO
        MonitorLeadItem $lead, $mode, $monitortype, $sync
        ASSERT $lead < 256
        ASSERT $mode < 256
        ASSERT $monitortype < 256
        ASSERT $sync < 256
        DCD     (($lead):SHL:24):OR:(($sync):SHL:16):OR:(($monitortype):SHL:8):OR:($mode)
        MEND

 [ IO_Type = "IOMD"
MonitorLeadList
  [ STB
   [ IOMD_C_MonitorType = 0					; no auto-detect bit
     [ IOMD_C_PALNTSCType = 0					; no PAL/NTSC bits:
        MonitorLeadItem 4_3333,  12, 0, 1                       ; PAL TV assumed
     | ; IOMD_C_PALNTSCType = 0
        MonitorLeadItem 4_0333,  12, 0, 1                       ; PAL TV
        MonitorLeadItem 4_1333,  46, 8, 1                       ; NTSC TV
     ] ; IOMD_C_PALNTSCType = 0
   |
     [ :LNOT: ChrontelSupport
       [ IOMD_C_PALNTSCType = 0					; no PAL/NTSC bits:
        MonitorLeadItem 4_3331,  12, 0, 1                       ; PAL TV assumed
       | ; IOMD_C_PALNTSCType = 0				; wealth of bits:
        MonitorLeadItem 4_0331,  12, 0, 1                       ; PAL TV
        MonitorLeadItem 4_1331,  46, 8, 1                       ; NTSC TV
       ] ; IOMD_C_PALNTSCType = 0
     ] ; :LNOT: ChrontelSupport
   ] ; IOMD_C_MonitorType = 0
	MonitorLeadItem 4_3333,  28, 3, 0                       ; VGA-capable monitors 256 colours
  | ; STB
        MonitorLeadItem 4_3330,  27, 3, 0                       ; VGA-capable monitors
        MonitorLeadItem 4_3333,  12, 0, 1                       ; Others - assume TV standard
  ]; STB
 | ;IO_Type = "IOMD"
MonitorLead_MonoVGA     *       4_3101
MonitorLead_ColourVGA   *       4_3110
MonitorLead_ColourSVGA  *       4_3010          ; should be type 4, but for the LiteOn we bodge it to 1
MonitorLead_Multisync   *       4_3211
MonitorLead_TV          *       4_3112
MonitorLead_NoConnect   *       4_3111
MonitorLead_Undefined   *       4_3333

MonitorLeadList
        MonitorLeadItem MonitorLead_Multisync,  27, 1, 1
        MonitorLeadItem MonitorLead_MonoVGA,    27, 3, 0
        MonitorLeadItem MonitorLead_ColourVGA,  27, 3, 0
        MonitorLeadItem MonitorLead_ColourSVGA, 27, 1, 0        ; bodge for LiteOn (should be 27, 4, 0)
        MonitorLeadItem MonitorLead_Undefined,  12, 0, 1        ; used for all other combinations
 ]

 [ StorkPowerSave
;
; List of latch addresses and initial values.
;
PowerTab
        DCD     HWLatchPA, InitLatchPA
        DCD     HWLatchPB, InitLatchPB
        DCD     HWLatchMC, InitLatchMC
        DCD     HWLatchMA, InitLatchMA
        DCD     0

PowerHardware           ;On Stork, ensure Combo chip, Winnie, Floppy etc are powered
        ENTRY "r0,r1"

        MOV     r0, #0
        LDRB    lr, [r0, #IOSystemType]
        TST     lr, #IOST_BATMAN
        EXIT    EQ              ;EQ, not Stork, so hardware already powered
;
; On Stork.
;
; Now would be a good time to hit the power control latches
; to ensure everything is powered up.
;
        ADR     R14, PowerTab
05
        LDMIA   R14!, {R0, R1}
        TEQ     R0, #0
        STRNEB  R1, [R0]
        BNE     %BT05

10
        EXIT
 ]

        [ STB
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ConfigureCombo - Configure SMC 665/669 or UMC 8669 if present
;

ComboBase	*	&03010000       ; Base address of combo chip = PC/AT I/O 000H

; SMC-type stuff
SMC_CSR		*	&03F0 * 4	; Configuration Select Register (CSR)
SMC_CSRalt669	*	&0370 * 4	; Alternative Configuration Select Register on SMC 669
					; (this register is used if RTS2 is high on reset, which we don't have direct control of)
SMC_config	*	&55		; value to write to enter configuration mode
SMC_endconfig	*	&AA		; value to write to end configuration mode
SMC_IDreg	*	&0D		; device ID register
SMC_data	*	&03F1 * 4	; Configuration Access Port (data)
SMC_665		*	&65		; 665 ID
SMC_669		*	&03		; 669 ID

; UMC-type stuff
UMC_CSR		*	&0108 * 4	; Configuration Select Register (CSR)
UMC_config	*	&AA		; value to write to enter configuration mode
UMC_endconfig	*	&55		; value to write to end configuration mode
UMC_data	*	&0109 * 4	; Configuration Access Port (data)


;
; Configure SMC 37C665/669 or UMC8669 combo chip
; Note that older devices (eg 82C710, 82C711, SMC651) are no longer supported
	ASSERT	:LNOT: OldComboSupport

ConfigureCombo ENTRY "r0-r2"
        TEQP    pc, #SVC_mode + I_bit + F_bit   ; Disable FIQ and IRQ
        LDR     r0, =ComboBase		; R0->  Base address of combo chip

; See if we have a SMC665/669 and try to configure it
	ADD	r2, r0, #SMC_CSR	; first try in normal place

        MOV     lr, #SMC_config
        STRB    lr, [r2]		; Write &55 to CSR twice
        STRB    lr, [r2]		; to enter configuration mode

        MOV     lr, #SMC_IDreg
        STRB    lr, [r2]
        LDRB    lr, [r2, #SMC_data-SMC_CSR]
        TEQ     lr, #SMC_665		; 665 ?
	ADREQ	r1, ConfigSMC665Table
	BEQ	%FT20
        TEQ     lr, #SMC_669		; 669 ?
	BEQ	%FT18

; Not a SMC chip at the normal place, but the SMC 669 may move its configuration registers
; to &370 if RTS2 was high on trailing edge of reset, so try there

        ADD	r2, r0, #SMC_CSRalt669

        MOV     lr, #SMC_config
        STRB    lr, [r2]		; Write &55 to CSR twice
        STRB    lr, [r2]		; to enter configuration mode

        MOV     lr, #SMC_IDreg
        STRB    lr, [r2]
        LDRB    lr, [r2, #SMC_data-SMC_CSR]
        TEQ     lr, #SMC_669		; 669 ?
	BEQ	%FT18

; Not a SMC chip that we recognise, maybe we have a UMC8669
	ADR	r1, ConfigUMC8669Table
10
        LDRB    lr, [r1], #1		; get "Index Entry Valid"
        STRB    lr, [r0, #UMC_CSR]
        TEQ     lr, #UMC_endconfig	; end of table?
	BEQ	%FT12
        LDRB    lr, [r1], #1		; get config index
        STRB    lr, [r0, #UMC_CSR]
        LDRB	lr, [r1], #1		; get config data
        STRB	lr, [r0, #UMC_data]	; and write it
        BNE     %BT10

12
; UMC8669 is not self-identifying, so see if what we wrote is still there
        MOV     lr, #UMC_config
        STRB    lr, [r0, #UMC_CSR]	; Write &AA to enter config mode
	MOV	lr, #&C0
        STRB    lr, [r0, #UMC_CSR]	; CR0
	LDRB	r2, [r0, #UMC_data]
        MOV     lr, #UMC_endconfig	; maybe don't need to do this
        STRB    lr, [r0, #UMC_CSR]	; exit config mode
	TEQ	r2, #2_00111110		; Value for CR0 from ConfigUMC8669Table

        				;�665s and 669s offer the same features as far as
        MOVEQ	r1, #IOST_37C665	; OS_ReadSysInfo(3) is concerned, so use same value for both
	MOVNE	r1, #0			; Don't know what this is, give up
        B	%FT30

;	SMC config loop
18
	ADR	r1, ConfigSMC669Table
20
        LDRB    lr, [r1], #1			; get config index
        STRB    lr, [r2]
        TEQ     lr, #SMC_endconfig		; end of table?
        LDRNEB  lr, [r1], #1			; if not then get config data
        STRNEB  lr, [r2, #SMC_data-SMC_CSR]	; and write it
        BNE     %BT20
        					;�665s and 669s offer the same features as far as
        MOV     r1, #IOST_37C665		; OS_ReadSysInfo(3) is concerned, so use same value for both

;	Record type of chip found
30
        MOV     r0, #0
        LDRB    lr, [r0, #IOSystemType]
        BIC     lr, lr, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665
        ORR     lr, lr, r1
        STRB    lr, [r0, #IOSystemType]

        TEQP    pc, #SVC_mode + I_bit   ; Restore IRQ/FIQ state
        EXIT


ConfigSMC665Table
 [ ComboIRQsActiveHigh
	DCB     &01, 2_10010111		; Enable config, COM3@338, COM4@238, IRQs active hi,
					; // is extended & powered @278
 |
	DCB     &01, 2_10000111		; Enable config, COM3@338, COM4@238, IRQs active low,
					; // is extended & powered @278
 ]
	DCB     &02, 2_11011100		; COM2 powered & enabled @2F8, COM1 powered & enabled @3F8
					; (default)
	DCB     &03, 2_01111000		; floppy stuff (default)
        DCB     &04, 2_00000011		; EPP v1.9, MIDI disabled, normal //floppy,
					; // uses ECP & EPP modes
	DCB     &05, 0			; 4 drive support, don't swap drives, normal density,
					; FDC burst mode, IDE@1F0-7,3F6-7, FDC@3F0-7 (default)
;	DCB     &06, &FF		; floppy drive types (default)
;	DCB     &07, 0			; don't auto-powerdown anything (default)
;	DCB     &08, 0			; ADRA7:4 address decode (default)
;	DCB     &09, 0			; ADRA10:8 address decode (default)
;	DCB     &0A, 0			; FIFO threshold for ECP // = ??? (default)
;	DCB	&0B, 0			; floppy data rates (default)
;	DCB	&0C, 0			; UART2 & UART1 standard speed, UART2 standard mode,
					; UART2 full duplex, XMIT active hi, RCV active hi (default)
        DCB     &00, 2_10111011         ; Valid config, OSC & BR on, FDC enabled & powered,
					; IDE AT & enabled
        DCB     SMC_endconfig, 0	; Exit config mode

ConfigSMC669Table
	DCB     &01, 2_10010100         ; Enable config, // is extended, // is  powered
	DCB     &02, 2_10001000         ; COM2 powered, COM1 powered (default)
	DCB     &03, 2_01110000		; floppy stuff (bit 3 now reserved)
	DCB     &04, 2_00000011		; IR rx&tx on COM2 rx & tx pins, EPP v1.9, MIDI disabled,
					; normal //floppy, uses ECP & EPP modes
	DCB     &05, 0			; 4 drive support, don't swap drives, normal density,
					; FDC burst mode (default)
;	DCB     &06, &FF		; floppy drive types (default)
;	DCB     &07, 0			; don't auto-powerdown anything
;	DCB     &08, 0			; ADRA7:4 address decode (default)
;	DCB     &09, 0			; ADRx disabled, ADRA10:8 address decode (default)
;	DCB     &0A, 0			; FIFO threshold for ECP // = ??? (default)
;	DCB	&0B, 0			; floppy data rates (default)
;	DCB	&0C, 0			; UART2 & UART1 standard speed, UART2 standard mode,
					; UART2 full duplex, XMIT active hi, RCV active hi (default)
	DCB	&10, 2_01000000		; 24MHz input to PLL (*not* default)
;	DCB	&1E, &80		; GAMECS disabled (default)
;	DCB	&1F, 0			; floppy drive types (default)
	DCB	&20, &FC		; FDC@3F0-7
	DCB	&21, &7C		; IDE@1F0-7
	DCB	&22, &FD		; IDE Alternate Status Register @3F6
	DCB	&23, &9E		; //@278
	DCB	&24, &FE		; COM1@3F8
	DCB	&25, &BE		; COM2@2F8
	DCB	&26, 0			; no FDC DMA, no // DMA (default)
	DCB	&27, 2_01100101		; FDC uses IRQ_F, // uses IRQ_E
	DCB	&28, 2_01000011		; UART1 uses IRQ_D, UART2 uses IRQ_C
	DCB	&29, 0			; IRQIN does not use any IRQ_x (default)
        DCB     &00, 2_10001010         ; Valid config, FDC powered, IDE enabled
        DCB     SMC_endconfig, 0	; Exit config mode

ConfigUMC8669Table
	DCB     UMC_config, &C0, 2_00111110	; IR full-duplex, games off, IDE on,
						; // in EPP & ECP mode, UART2 on, UART1 on, FDC off
	DCB     UMC_config, &C1, 2_00101111	; Direct access PnP register, Disable PnP,
						; IDE@1F0-7,3F6-7, //@278, COM2@2F8, COM1@3F8,
						; FDC@3F0-7
	DCB     UMC_config, &C2, 2_10000001	; Not supspended, IR unselected/disabled,
						; don't swap floppy, IBM mode floppy,
						; floppy is R/W (default)
        DCB     UMC_endconfig, 0		; Exit config mode

        ALIGN
        |
; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       Configure82C710 - Configure 82C710/82C711/SMC 665 if present
;

; 82C710 stuff

CnTbase         *       &03010000       ; Base address of 82C710 = PC/AT I/O 000H
CRI710          *       &0390
CRI710Off       *       CRI710*4        ; 82C710 Configuration Register Index port
CAP710Off       *       CRI710Off +4    ; 82C710 Configuration Access Port (data)
ConRegA710      *       &02FA*4
ConRegB710      *       &03FA*4

CRI711Off       *       &03F0*4         ; 82C711 Configuration Register Index port
CAP711Off       *       CRI711Off +4    ; 82C711 Configuration Access Port (data)


 [ IO_Type <> "IOMD"
Configure82C710 ENTRY "r0,r1"
        MOV     r0, #0
        LDRB    lr, [r0, #IOSystemType]
        TST     lr, #IOST_IOEB          ; no IOEB, then don't bother
        EXIT    EQ

        TEQP    pc, #SVC_mode + I_bit + F_bit   ; Disable FIQ and IRQ
        LDR     r0, =CnTbase            ; R0-> 82C710 base address

; First try to configure 82C711 or SMC665

        MOV     lr, #&55
        STRB    lr, [r0, #CRI711Off]    ; Write &55 to CRI711 twice
        STRB    lr, [r0, #CRI711Off]    ; to enter configuration mode

        MOV     lr, #&0D                ; Check for SMC 665
        STRB    lr, [r0, #CRI711Off]
        LDRB    lr, [r0, #CAP711Off]
        TEQ     lr, #&65
        ADREQ   r1, ConfigSMCTable      ; different table for SMC 665
        ADRNE   r1, Config711Table      ; R1-> 82C711 configuration data
        Push    "lr"                    ; need to test for 665 again
20
        LDRB    lr, [r1], #1            ; get config index
        STRB    lr, [r0, #CRI711Off]
        TEQ     lr, #&AA                ; end of table?
        LDRNEB  lr, [r1], #1            ; if not then get config data
        STRNEB  lr, [r0, #CAP711Off]    ; and write it
        BNE     %BT20

        Pull    "lr"
        TEQ     lr, #&65                ; if we configured SMC 665 then
        MOVEQ   r1, #IOST_37C665        ;   set flag in IOSystemType
        BEQ     %FT30                   ;   and no need to faff about for 710/711

; Now try to configure 82C710 (won't work on 711)

        MOV     lr, #&55                ; Magic number from 82C710 data sheet
        STRB    lr, [r0, #ConRegA710]   ; Start configuration mode
        MVN     lr, lr                  ; Complement the magic number
        STRB    lr, [r0, #ConRegB710]
        MOV     lr, #&36                ; Another magic number from C&T
        STRB    lr, [r0, #ConRegB710]
        MOV     r1, #CRI710 /4          ; 82C710 configuration address /4
        STRB    r1, [r0, #ConRegB710]   ; Write configuration address
        MVN     lr, r1                  ; Complement the data
        STRB    lr, [r0, #ConRegA710]   ; Complete configuration sequence

        ADR     r1, Config710Table      ; R1-> 82C710 configuration data
10
        LDRB    lr, [r1], #1            ; Get next 82C710 config reg index, R1++
        STRB    lr, [r0, #CRI710Off]    ; Write index
        TEQ     lr, #&0F                ; Configuration register selected?
        LDRB    lr, [r1], #1            ; Get config data, R1++
        STRB    lr, [r0, #CAP710Off]    ; Write config data
        BNE     %BT10                   ; Repeat until config register written

; now if we're on 82C710 then 1st serial port is at &3F8
; and if we're on 82C711 then 1st serial port is at &2F8

        STRB    lr, [r0, #&2FF * 4]     ; store &AA in serial scratchpad register for 82C711 port 1
        MOV     lr, #&55
        STRB    lr, [r0, #&3FF * 4]     ; store &55 in serial scratchpad register for 82C710
        STRB    lr, [r0, #CRI711Off]    ; Write &55 to CRI711 twice
        STRB    lr, [r0, #CRI711Off]    ; to reenter configuration mode
        MOV     lr, #&02                ; select config register 2
        STRB    lr, [r0, #CRI711Off]
        MOV     lr, #2_00011100         ; move 1st serial port to &3F8
        STRB    lr, [r0, #CAP711Off]
        MOV     lr, #&AA
        STRB    lr, [r0, #CRI711Off]    ; exit config mode

        MOV     r1, #0                  ; by default no 82C710 or 82C711
        LDRB    lr, [r0, #&3FF * 4]     ; read scratchpad register
        TEQ     lr, #&55                ; &55 => 82C710
        MOVEQ   r1, #IOST_82C710
        TEQ     lr, #&AA
        MOVEQ   r1, #IOST_82C711
30
        MOV     r0, #0
        LDRB    lr, [r0, #IOSystemType]
        BIC     lr, lr, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665
        ORR     lr, lr, r1
        STRB    lr, [r0, #IOSystemType]

        TEQP    pc, #SVC_mode + I_bit   ; Restore IRQ/FIQ state
        EXIT
 ]

 [ IO_Type <> "IOMD"
Config710Table ; Index, Data            ; 82C710 configuration data
        DCB     &01, 2_01000000         ; Bi-dir parallel
        DCB     &02, 2_00001000         ; Default, UART clock
        DCB     &04, &FE                ; Default, UART base address= &3F8 (COM1)
        DCB     &06, &9E                ; Default, Parallel base address= &278 (LPT3)
        DCB     &09, &9E                ; GPCS=&278 (so writes to printer control go to PAL too)
        DCB     &0A, 2_00001010         ; GPCS A1=1 (to detect printer control), GPCS enabled
        DCB     &0B, 2_01110000         ; IRQs active lo, GPCS is an o/p
        DCB     &0C, 2_10100001         ; IDE/FDC enabled, mouse disabled
        DCB     &0D, 0                  ; Default, mouse address
        DCB     &0E, 2_00000000         ; Default, test modes disabled
        DCB     &00, 2_10101100         ; Valid config, OSC/BR on, Ser/Par enable
        DCB     &0F, 0                  ; Write config register == end of list

Config711Table
        DCB     &01, 2_10000111         ; Enable config read, IRQ active low, parallel powered/extended, default addr.
        DCB     &02, 2_00001101         ; 2nd serial port disabled, 1st enabled at &2F8 (to be moved to &3F8 later)
        DCB     &03, 0                  ; Test mode disabled
        DCB     &00, 2_10111011         ; Valid config, OSC/BR on, FDC enabled/powered, IDE AT,enabled
        DCB     &AA, 0                  ; Exit config mode
 ]

ConfigSMCTable
        DCB     &01, 2_10000111         ; Enable config read, IRQ active low, parallel powered/extended, default addr.
        DCB     &02, 2_00011100         ; 2nd serial port disabled, 1st enabled at &3F8
        DCB     &03, &78                ; extra stuff for SMC
        DCB     &04, 2_00000011         ; allow extended parallel port modes
        DCB     &05, 0
        DCB     &06, &FF
        DCB     &07, 0
        DCB     &08, 0
        DCB     &09, 0
        DCB     &0A, 0
        DCB     &00, 2_10111011         ; Valid config, OSC/BR on, FDC enabled/powered, IDE AT,enabled
        DCB     &AA, 0                  ; Exit config mode

        ALIGN

 [ IO_Type = "IOMD"
;
; Simplified version of Configure82C710 programs SMC 37C665 only.
;
Configure37C665 ENTRY "r0,r1"
        TEQP    pc, #SVC_mode + I_bit + F_bit   ; Disable FIQ and IRQ
        LDR     r0, =CnTbase            ; R0-> SMC 665 base address

; First try to configure the SMC665

        MOV     lr, #&55
        STRB    lr, [r0, #CRI711Off]    ; Write &55 to CRI711 twice
        STRB    lr, [r0, #CRI711Off]    ; to enter configuration mode

        MOV     lr, #&0D                ; Check for SMC 665
        STRB    lr, [r0, #CRI711Off]
        LDRB    lr, [r0, #CAP711Off]
        TEQ     lr, #&65
        MOVNE   r1, #0                  ;NE: not a SMC 665 this should never happen
        BNE     %FT30                   ;NE: on a RiscPC, Kryten or Stork

        ADR     r1, ConfigSMCTable      ; R1-> SMC 665 configuration data
20
        LDRB    lr, [r1], #1            ; get config index
        STRB    lr, [r0, #CRI711Off]
        TEQ     lr, #&AA                ; end of table?
        LDRNEB  lr, [r1], #1            ; if not then get config data
        STRNEB  lr, [r0, #CAP711Off]    ; and write it
        BNE     %BT20

        MOV     r1, #IOST_37C665
30
        MOV     r0, #0
        LDRB    lr, [r0, #IOSystemType]
        BIC     lr, lr, #IOST_82C710 :OR: IOST_82C711 :OR: IOST_37C665
        ORR     lr, lr, r1
        STRB    lr, [r0, #IOSystemType]

        TEQP    pc, #SVC_mode + I_bit   ; Restore IRQ/FIQ state
        EXIT
 ]

        ]


; +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
;       ReadUniqueID - Read unique machine ID
;
; 10-Dec-93  BCockburn  Modified to leave raw 64 bit ID from chip in RawMachineID

defaultlatch *  20000-1 ; TMD 21-May-93: "-1" correction applied

Tsyc    *       5       ; time between frames - minimum of 1�s, so give it a bit more
Trstl   *       500     ; time reset pulse held low - minimum of 480�s, so give it a bit more
Trsth   *       500     ; time reset pulse held high - minimum of 480�s, so give it a bit more
Tlow0   *       80      ; time for write0 low - min 60�s, max 120�s
Tlow1   *       5       ; time for write1 low - min 1�s, max 15�s
Tslot   *       90      ; time for total read/write slot - min 60�s, max 120�s
Trdlow  *       5       ; time for read slot low before release - min 1�s, max 15�s
Trddat  *       3       ; time after read slot high before read it

        ASSERT  Tslot-Tlow0 > Tsyc
        ASSERT  Trdlow+Trddat < 15

; Macro to set wire to a given state, and optionally count transitions (starting at low) while waiting for a given time

        MACRO
        SetWire $hilo, $time, $monstate, $count
        LCLS    reg
 [ "$hilo"="LOW"
reg     SETS    "r4"
 |
        ASSERT  "$hilo"="HIGH"
reg     SETS    "r5"
 ]
 [ ($time) = 0
        STRB    $reg, [r1, #IOCControl]         ; set appropriate level on line
 |
        ASSERT  ($time) < 32768
        MOV     r12, #(($time)*2):AND:&FF
        STRB    r12, [r1, #Timer0LL]            ; program low latch
        MOV     r12, #(($time)*2):SHR:8
        STRB    r12, [r1, #Timer0LH]            ; program high latch
        STRB    $reg, [r1, #IOCControl]         ; set appropriate level on line
        STRB    r12, [r1, #Timer0GO]            ; and start timer
        LDRB    r12, [r1, #IOCIRQSTAA]          ; dummy instruction to avoid bug in IOC
        LDRB    r12, [r1, #IOCIRQSTAA]          ; dummy instruction (repeated for FE)
        STRB    r11, [r1, #IOCIRQCLRA]          ; immediately clear IRQ bit
  [ "$monstate"<>""
        MOV     $monstate, #0
  ]
  [ "$count"<>""
        MOV     $count, #0
  ]
10
        LDRB    r12, [r1, #IOCIRQSTAA]
        TST     r12, r11
  [ "$count"<>""
        ADDEQ   $count, $count, #1
  ]
  [ "$monstate"=""
        BEQ     %BT10                                   ; not timed out, so just loop
  |
        BNE     %FT30                                   ; timed out
        LDRB    r12, [r1, #IOCControl]
        TST     r12, #IOEB_unique_machine_ID_bit
        BEQ     %BT10                                   ; if still low then loop to 10

        ADD     $monstate, $monstate, #1                ; increment number of transitions
20
        LDRB    r12, [r1, #IOCIRQSTAA]
        TST     r12, r11
   [ "$count"<>""
        ADDEQ   $count, $count, #1
   ]
        BNE     %FT30                                   ; timed out
        LDRB    r12, [r1, #IOCControl]
        TST     r12, #IOEB_unique_machine_ID_bit
        BNE     %BT20                                   ; if still high then loop to 20
        ADD     $monstate, $monstate, #1                ; increment number of transitions
        B       %BT10
30
  ]
 ]
        MEND

ReadUniqueID    ENTRY "r0-r12"
        MOV     r0, #0
        LDR     r1, =IOC
        TEQP    pc, #SVC_mode + I_bit + F_bit
        LDRB    r3, [r0, #IOCControlSoftCopy]
        BIC     r4, r3, #IOEB_unique_machine_ID_bit     ; r4 is value to pull ID line low
        ORR     r5, r3, #IOEB_unique_machine_ID_bit     ; r5 is value to pull ID line high
        MOV     r11, #timer0_bit
        BL      SendResetPulse
        BVS     ResetFailed
        BL      SendCommandWord

        MOV     r7, #-8                                 ; -no. of bytes to store = 8 bits type + 48 bits ID + 8 bits checksum
10
        BL      GetAByte
        STRB    r6, [r7, #RawMachineID+8]
        ADDS    r7, r7, #1
        BNE     %BT10

        BL      RestoreIOCState
        BL      CheckCRC
        BVS     IDError
        EXIT

ResetFailed
        BL      RestoreIOCState
IDError
        MOV     r0, #0
        STR     r0, [r0, #RawMachineID+0]            ; indicate no ID by putting zero here
        STR     r0, [r0, #RawMachineID+4]
        EXIT

RestoreIOCState ENTRY
        STRB    r3, [r1, #IOCControl]                   ; put back old value
        MOV     r12, #defaultlatch :AND: &FF
        STRB    r12, [r1, #Timer0LL]                    ; and restore old timer 0 latch values
        MOV     r12, #defaultlatch :SHR: 8
        STRB    r12, [r1, #Timer0LH]
        STRB    r12, [r1, #Timer0GO]
        TEQP    pc, #SVC_mode + I_bit                   ; restore old interrupt state
        EXIT

SendResetPulse ROUT
        SetWire HIGH, Tsyc
        SetWire LOW, Trstl,,r6
        SetWire HIGH, Trsth,r10
        TEQ     r6, #0
;        ADREQ   r0, IOCBugHappenedError
        ORREQS  pc, lr, #V_bit
        CMP     r10, #3                                 ; H-L-H is ok
        BICEQS  pc, lr, #V_bit
;        ADRHI   r0, TooManyTransitionsError             ; H-L-H-L...
;        CMP     r10, #2
;        ADREQ   r0, NeverWentHighAgainError             ; H-L
;        CMP     r10, #1
;        ADREQ   r0, NeverWentLowError                   ; H
;        ADRCC   r0, NeverWentHighError                  ; stayed low permanently even though we released it
        ORRS    pc, lr, #V_bit

 [ {FALSE} ; only for debugging
NeverWentHighError
        =       "Never went high", 0
NeverWentLowError
        =       "Never went low", 0
NeverWentHighAgainError
        =       "Never went high again", 0
TooManyTransitionsError
        =       "Too many transitions", 0
IOCBugHappenedError
        =       "IOC bug happened", 0
        ALIGN
 ]

SendCommandWord ROUT
        LDR     r6, =&10F               ; &0F is command word
10
        MOVS    r6, r6, LSR #1
        BICEQS  pc, lr, #V_bit
        BCS     SendOne
        SetWire LOW, Tlow0
        SetWire HIGH, Tslot-Tlow0
        B       %BT10

SendOne
        SetWire LOW, Tlow1
        SetWire HIGH, Tslot-Tlow1
        B       %BT10

GetAByte ROUT
        MOV     r6, #&80
10
        SetWire LOW, Trdlow
        SetWire HIGH, Trddat
        LDRB    r10, [r1, #IOCControl]
        SetWire HIGH, Tslot-Trdlow-Trddat
        MOVS    r10, r10, LSR #IOEB_ID_bit_number+1    ; move bit into carry
        MOVS    r6, r6, RRX
        BCC     %BT10
        MOV     r6, r6, LSR #24
        BICS    pc, lr, #V_bit

CheckCRC ROUT
        LDR     r1, =RawMachineID               ; pointer to current byte
        MOV     r2, #0
        MOV     r3, #7                          ; number of bytes to do
10
        LDRB    r4, [r1], #1
        EOR     r2, r2, r4
        MOV     r4, #8                          ; number of bits to do
20
        MOVS    r2, r2, LSR #1                  ; shift bit out into carry
        EORCS   r2, r2, #&8C                    ; feedback carry into other bits
        SUBS    r4, r4, #1                      ; one less bit to do
        BNE     %BT20                           ; loop until done whole byte
        SUBS    r3, r3, #1                      ; one less byte to do
        BNE     %BT10                           ; loop until done all 7 bytes
        LDRB    r4, [r1], #1                    ; read CRC
        TEQ     r4, r2                          ; if incorrect
        ORRNES  pc, lr, #V_bit                  ; then exit indicating error
        BICS    pc, lr, #V_bit

        LTORG

        END