; 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.i2cutils ; Authors JBiggs (m2), PFellows, TDobson, AGodwin ; *********************************** ; *** C h a n g e L i s t *** ; *********************************** ; Date Name Description ; ---- ---- ----------- ; 28-Mar-95 JRH Added support for E2ROMs and/or CMOS, conditioned on ; E2ROMSupport which is defined elsewhere ; Uses RTCFitted and NVRamSize in KernelWS ; 03-Jul-96 JRH Took out code conditioned on :LNOT: NewClockChip ; Fixed support for E2ROM. E2 works in the same gross way as ; CMOS. Any E2 fitted > 256 bytes will not be accessed by these ; routines. ; 07-Dec-96 AMG Renaissance. Leave this file as is, allowing the E2ROMSupport ; switch to disable non-STB bits ; 12-Jun-97 TMD (Really) fix OTP access problem. ; 17-Sep-98 KJB Add support for 16K 24C128 EEPROM. ; 21-Sep-98 KJB Add OS_NVMemory SWI. ; 30-Jul-99 KJB Add support for 8K 24C64 EEPROM. ; 23-Sep-99 KJB Remove support for 24C64, add support for 4K and 8K protectable ATMEL parts. PhysChecksum * (((CheckSumCMOS + &30) :MOD: &F0) + &10) ; Device addresses RTCAddressPHI * &a0 ; Philips RTC + 240 byte CMOS E2ROMAddress2K * &e0 ; 24C174 device - 2K E2ROMAddress2K_OTP * &60 ; 24C174 device - OTP section E2ROMAddress4K * &a4 ; 24C32 device - 4K (top 1K protectable) E2ROMAddress8K_prot * &a2 ; 24C64 device - 8K (top 2K protectable) E2ROMAddress8K * &ae ; 24C64 device - 8K E2ROMAddress16K * &a8 ; 24C128 device - 16K E2ROMAddress32K * &a6 ; 24CS256 device - 32K (top 2K possibly OTP) ; ***************************************************************************** ; ; HexToBCD - Convert byte in hex to BCD ; ; in: R0 = byte in hex ; ; out: R0 = byte in BCD (ie R0 := (R0 DIV 10)*16 + R0 MOD 10) ; All other registers preserved ; HexToBCD ROUT Push "R1,R2, R14" MOV R1, #10 DivRem R2, R0, R1, R14 ; R2=R0 DIV 10; R0=R0 MOD 10 ADD R0, R0, R2, LSL #4 Pull "R1,R2, PC" ; ***************************************************************************** ; ; BCDToHex - Convert byte in BCD to hex ; ; in: R0 = byte in BCD (ie x*16 + y) ; ; out: R0 = byte in hex (ie x*10 + y) ; All other registers preserved ; BCDToHex ROUT Push "R14" MOV R14, R0, LSR #4 ; R14 := x ADD R14, R14, R14, LSL #1 ; R14 := x*3 SUB R0, R0, R14, LSL #1 ; R0 := R0 - x*6 = x*10 Pull "PC" ; ***************************************************************************** ; ; HTBSR9 - hex to BCD and store at "next free byte" R9 ; HTBS9 ROUT Push R14 BL HexToBCD STRB R0, [R9], #1 Pull PC ; ***************************************************************************** ; ; Write - Write a byte of CMOS RAM specified by logical address ; ; in: R0 = address in CMOS RAM ; R1 = data ; ; out: All registers preserved ; WriteWithError ROUT Push "R0-R4, R14" BL MangleCMOSAddress BCC %FT05 ADD R13, R13, #4 ; junk stacked R0 ADR R0, ErrorBlock_CoreNotWriteable [ International BL TranslateError | SETV ] Pull "R1-R4,PC" MakeErrorBlock CoreNotWriteable WriteWithoutProtection ; allowing write to "OTP" and protected section Push "R0-R4, R14" BL MangleCMOSAddress Pull "R0-R4, PC", CS ; if invalid, then exit MOV R2, R0 MOV R3, R1 CMP R0, #&10 MOVLO R4, #&1000000 ; don't change checksum for OTP BLO %FT10 B %FT08 ; do change checksum for protected region Write Push "R0-R4, R14" BL MangleCMOSAddress Pull "R0-R4, PC", CS ; if invalid, then exit 05 [ E2ROMSupport CMP r0, #&10 Pull "R0-R4, PC", CC ; don't write to OTP section ] [ E2ROMSupport LDR R14, =ZeroPage ; don't write to protected section LDRB R14, [R14, #NVRamWriteSize] CMP R0, R14, LSL #8 ; (note assumption that NVRamWriteSize is Pull "R0-R4, PC", HS ; outside mangled region). ] MOV R2, R0 MOV R3, R1 08 [ ChecksumCMOS BL ReadStraight ; calculate new checksum : MOV R4, R0 TEQ R4, R3 ; don't bother with write if Pull "R0-R4, PC", EQ ; oldcontents == newcontents MOV R0, #PhysChecksum BL ReadStraight SUB R0, R0, R4 ; = oldsum - oldcontents ADD R4, R0, R3 ; + newcontents AND R4, R4, #&FF CMPS R2, #PhysChecksum ; don't write new checksum ... ORREQ R4, R4, #&1000000 ; if checksum is being written ] 10 CMP r2, #&100 ; check small cache limit BCS %FT15 LDR R1, =ZeroPage+CMOSRAMCache ; update cache, but always write to STRB R3, [R1, R2] ; real hardware as well 15 [ HAL Push "R2,R3,sb,R12" AddressHAL CallHAL HAL_NVMemoryType AND R0, R0, #NVMemoryFlag_Provision TEQ R0, #NVMemoryFlag_None ; If there's no NVmemory, all we have is the internal cache. Pull "R2,R3,sb,R12", EQ Pull "R0-R4,PC", EQ TEQ R0, #NVMemoryFlag_HAL BNE %FT20 ; Go and do IIC stuff. ; Make the HAL call - we have to write the data into a buffer. Pull "R0" STRB R3, [sp, #-4]! MOV R1, sp MOV R2, #1 CallHAL HAL_NVMemoryWrite TST R4, #&1000000 BNE %FT18 LDR R1, =ZeroPage+CMOSRAMCache STRB R4, [R1, #PhysChecksum] STRB R4, [sp] MOV R0, #PhysChecksum MOV R1, sp MOV R2, #1 CallHAL HAL_NVMemoryWrite 18 ADD sp, sp, #4 Pull "R3,sb,R12" Pull "R0-R4,PC" 20 Pull "R2,R3,sb,R12" ] [ E2ROMSupport MOV R0, R2 BL GetI2CAddress ; convert to device address + offset MOV R2, R0 ; save the offset | MOV R1, #RTCAddressPHI ] AND R0, R1, #&FF ; device address for write ORR R0, R0, #1:SHL:29 ; retry TST R1, #&100 ; NE if two byte offset SUB R13, R13, #4 MOV R14, R13 MOVNE R1, R2, LSR #8 STRNEB R1, [R14], #1 ; offset (MSB) STRB R2, [R14], #1 ; offset (LSB) STRB R3, [R14], #1 ; data MOV R1, R13 SUB R2, R14, R13 BL IIC_Op ADD R13, R13, #4 [ ChecksumCMOS TST R4, #&1000000 ; loop again to write new checksum MOV R3, R4 MOV R2, #PhysChecksum ORR R4, R4, #&1000000 ; but ensure it only happens once BEQ %BT10 ] Pull "R0-R4, PC" ; ***************************************************************************** ; ; WriteBlock - Write a block of CMOS RAM specified by logical address ; ; in: R0 = address in CMOS RAM ; R1 = address to copy from ; R2 = length ; ; out: All registers preserved ; WriteBlock ROUT Push "R0-R4,R14" [ E2ROMSupport LDR R14, =ZeroPage LDRB R4, [R14, #NVRamWriteSize] LDRB R14, [R14, #NVRamSize] MOV R4, R4, LSL #8 MOV R14, R14, LSL #8 | MOV R14, #240 MOV R4, R14 ] CMP R0, R14 BHS %FT90 ADDS R3, R0, R2 ; R3 = end address - check unsigned overflow BCS %FT90 CMP R3, R14 BHI %FT90 CMP R0, R4 ; ignore writes totally outside writable area BHS %FT80 SUBS R14, R3, R4 SUBGT R2, R2, R14 ; truncate writes partially outside writable area TEQ R2, #0 BEQ %FT80 CMP R0, #CheckSumCMOS ; are we going to write the checksum byte? BHI %FT03 CMP R3, #CheckSumCMOS BHI %FT05 03 ; we're not writing the checksum byte manually, so we need to update it MOV R4, R1 MOV R1, #0 BL ChecksumBlock ; find the checksum of what we're about to ORR R3, R1, #&80000000 ; overwrite MOV R1, R4 B %FT08 05 MOV R3, #0 08 MOV R4, #0 10 BL WriteSubBlock BVS %FT80 TEQ R2, #0 BNE %BT10 TST R3, #&80000000 ; were we going to write the checksum? BEQ %FT80 MOV R0, #CheckSumCMOS BL Read ; get old checksum byte ADD R0, R0, R4 ; add new data checksum SUB R1, R0, R3 ; subtract old checksum MOV R0, #CheckSumCMOS BL Write ; write back new checksum 80 Pull "R0-R4,PC" 90 ADD SP, SP, #4 ; junk stacked R0 ADR R0, ErrorBlock_CoreNotWriteable [ International BL TranslateError | SETV ] Pull "R1-R4,PC" ; ***************************************************************************** ; ; WriteSubBlock - Write a block of CMOS RAM specified by logical address. ; Assumes the address is valid, and will only read as much ; as it can in a single IIC transaction. ; ; in: R0 = address in CMOS RAM ; R1 = address to copy from ; R2 = length ; ; out: R0-R2 updated to reflect the amount written. ; R4 incremented by sum of bytes written. ; WriteSubBlock ROUT Push "R3,R5-R6,R14" MOV R6, R4 ; establish end of the current contiguous block, and the logical->physical address offset. CMP R0, #1 ; 00 -> 40 uncached MOVLO R3, #1 MOVLO R4, #&40-&00 BLO %FT10 CMP R0, #&C0 ; [01..C0) -> [41..100) cached MOVLO R3, #&C0 MOVLO R4, #&41-&01 BLO %FT10 CMP R0, #&F0 ; [C0..F0) -> [10..40) cached MOVLO R3, #&F0 MOVLO R4, #&10-&C0 BLO %FT10 CMP R0, #&100 ADDHS R3, R0, R2 ; [100..) -> [100..) uncached MOVHS R4, #0 BHS %FT10 ; [F0..100) -> not written MOV R3, #&100 ADD R14, R0, R2 CMP R3, R14 MOVHI R3, R14 SUB R14, R3, R0 ADD R0, R0, R14 ADD R1, R1, R14 SUB R2, R2, R14 Pull "R3,R5-R6,PC" ; R3 = logical end of current segment (exclusive) ; R4 = offset from logical to physical address for this segment 10 ADD R14, R0, R2 CMP R3, R14 MOVHI R3, R14 [ E2ROMSupport ; R3 = logical end of possible transaction (exclusive). Now check we don't cross page boundaries. LDR R14, =ZeroPage LDRB R14, [R14, #NVRamPageSize] MOV R5, #1 MOV R14, R5, LSL R14 ; R14 = (1<<pagesize) ADD R5, R0, R4 ; R5 = physical start address ADD R5, R5, R14 SUB R14, R14, #1 BIC R5, R5, R14 ; R5 = physical end of page with start address in SUB R5, R5, R4 ; R5 = logical end of page with start address in CMP R5, R3 MOVLO R3, R5 ; adjust R3 to not cross page boundary ] CMP R0, #&100 ; check it's a cacheable segment BHS %FT15 LDR R14, =ZeroPage+CMOSRAMCache Push "R3, R4" ADD R3, R3, R4 ; R3 = physical end address ADD R4, R4, R0 ; R4 = physical address ADD R3, R3, R14 ; R3 = cache end address ADD R4, R4, R14 ; R4 = cache address SUB R14, R3, R4 ; R14 = bytes being written MOV R5, R1 ; remember R1 12 LDRB R14, [R1], #1 ; update cache copy STRB R14, [R4], #1 CMP R4, R3 BLO %BT12 MOV R1, R5 ; restore R1, and continue to update real memory Pull "R3, R4" 15 Push "R0-R2" ADD R0, R0, R4 ; R0 = physical address [ HAL Push "sb, R12" MOV R5, R0 ; save address AddressHAL CallHAL HAL_NVMemoryType AND R0, R0, #NVMemoryFlag_Provision TEQ R0, #NVMemoryFlag_None ; If there's no NVmemory, tough - we just return. Pull "sb,R12", EQ Pull "R0-R2", EQ MOVEQ R2, #0 ; nothing written Pull "R3,R5-R6,PC", EQ TEQ R0, #NVMemoryFlag_HAL MOV R0, R5 ; restore address BNE %FT17 ; do IIC things. ; Make the HAL call CallHAL HAL_NVMemoryWrite ; returns bytes wrtten in R0 MOV R5, R0 Pull "sb,R12" Pull "R0-R2" ADD R0, R0, R5 SUB R2, R2, R5 16 SUBS R5, R5, #1 ; update checksum LDRCSB R14, [R1], #1 ADDCS R6, R6, R14 BCS %BT16 MOV R4, R6 Pull "R3,R5-R6,PC" 17 Pull "sb,R12" ] [ E2ROMSupport BL GetI2CAddress ; convert to device address and offset | MOV R1, #RTCAddressPHI ] MOV R2, R0 ; save the offset SUB R13, R13, #12*2+4 MOV R14, R13 TST R1, #&100 ; 2-byte address? MOVNE R0, R2, LSR #8 STRNEB R0, [R14], #1 ; offset (MSB) STRB R2, [R14], #1 ; offset (LSB) SUB R14, R14, R13 STR R14, [R13, #12] ; transfer 1 length AND R14, R1, #&FF ORR R0, R14, #1:SHL:29 ; (retry) STR R0, [R13, #4] ; transfer 1 address ORR R14, R14, #1:SHL:31 ; (no repeated start) STR R14, [R13, #16] ; transfer 2 address STR R13, [R13, #8] ; transfer 1 data ADD R14, R13, #12*2+4 LDMIA R14, {R0-R2} SUB R5, R3, R0 ; R5 = bytes being written ADD R0, R0, R5 ; update return R0 SUB R2, R2, R5 ; update return R2 STMIB R14, {R0,R2} STR R1, [R13, #20] ; transfer 2 data STR R5, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV LDR R1, [R13, #20] ; recover data pointer ADD R13, R13, #12*2+4+4 20 LDRB R0, [R1], #1 SUBS R5, R5, #1 ADD R6, R6, R0 ; update checksum counter BNE %BT20 ; V clear MOV R4, R6 Pull "R0,R2,R3,R5,R6,PC" ; ***************************************************************************** ; ; Read - Read a byte of CMOS RAM specified by logical address ; ReadStraight - Read a byte of CMOS RAM specified by physical address ; ReadWithError - Read a byte of CMOS RAM specified by logical address, giving error if out of range ; ; in: R0 = address in CMOS RAM ; ; out: R0 = data (illegal address return 0, or error for ReadWithError) ; All other registers preserved ; ReadStraight ROUT Push "R1,R2,R14" B %FT10 ReadWithError Push "R1,R2,R14" BL MangleCMOSAddress BCC %FT10 ADR R0, ErrorBlock_CoreNotReadable [ International BL TranslateError | SETV ] Pull "R1,R2,PC" MakeErrorBlock CoreNotReadable Read Push "R1,R2,R14" BL MangleCMOSAddress MOVCS R0, #0 ; pretend illegal addresses contain 0 Pull "R1,R2,PC", CS 10 TEQ R0, #&40 ; is it Econet station number BEQ %FT15 ; if so then don't use cache CMP R0, #&10 ; don't cache the clock [ E2ROMSupport BHS %FT13 ; If our CMOS is actually inside an RTC, read direct (the cache is nonsense) LDR R14, =ZeroPage LDRB R14, [R14, #NVRamBase] TEQ R14, #RTCAddressPHI BEQ %FT15 | BLO %FT15 ] 13 CMP R0, #&100 ; check small cache limit LDRCC R2, =ZeroPage+CMOSRAMCache ; if in range LDRCCB R0, [R2, R0] ; read from cache Pull "R1,R2,PC", CC ; and exit 15 ; else drop thru into real CMOS reading code [ HAL Push "R3,R4,sb,R12" MOV R4, R0 ; save address AddressHAL CallHAL HAL_NVMemoryType AND R0, R0, #NVMemoryFlag_Provision TEQ R0, #NVMemoryFlag_None ; If there's no NVmemory, pretend addresses contain 0 Pull "R3,R4,sb,R12", EQ MOVEQ R0, #0 Pull "R1,R2,PC", EQ TEQ R0, #NVMemoryFlag_HAL MOV R0, R4 ; restore address BNE %FT20 ; Make the HAL call - we have to provide a buffer. SUB sp, sp, #4 ; make some space on the stack MOV R1, sp MOV R2, #1 CallHAL HAL_NVMemoryRead LDRB R0, [sp], #4 ; read back from stack and restore Pull "R3,R4,sb,R12" Pull "R1,R2,PC" 20 Pull "R3,R4, sb,R12" ] [ E2ROMSupport BL GetI2CAddress ; convert to device address and offset | MOV R1, #RTCAddressPHI ] SUB R13, R13, #2*12+4 MOV R14, R13 TST R1, #&100 MOVNE R2, R0, LSR #8 STRNEB R2, [R14], #1 ; offset (MSB) STRB R0, [R14], #1 ; offset (LSB) SUB R14, R14, R13 STR R13, [R13, #8] ; transfer 1 data STR R14, [R13, #12] ; transfer 1 length AND R14, R1, #&FF ORR R2, R14, #1:SHL:29 ; retry STR R2, [R13, #4] ; transfer 1 address ORR R14, R14, #1 ; device address for read STR R14, [R13, #16] ; transfer 2 address ADD R14, R13, #3 STR R14, [R13, #20] ; transfer 2 data MOV R14, #1 STR R14, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV LDRB R0, [R13, #3] ADD R13, R13, #2*12+4 Pull "R1,R2,PC" ; ***************************************************************************** ; ; ReadBlock - Read a block of CMOS RAM specified by logical address ; ; in: R0 = address in CMOS RAM ; R1 = address to copy to ; R2 = length ; ; out: All registers preserved ; ReadBlock ROUT Push "R0-R3,R14" [ E2ROMSupport LDR R14, =ZeroPage LDRB R14, [R14, #NVRamSize] MOV R14, R14, LSL #8 | MOV R14, #240 ] CMP R0, R14 BHS %FT90 ADDS R3, R0, R2 ; R3 = end address - check unsigned overflow BCS %FT90 CMP R3, R14 BHI %FT90 TEQ R2, #0 BEQ %FT80 10 BL ReadSubBlock BVS %FT80 TEQ R2, #0 BNE %BT10 80 Pull "R0-R3,PC" 90 ADD SP, SP, #4 ; junk stacked R0 ADR R0, ErrorBlock_CoreNotReadable [ International BL TranslateError | SETV ] Pull "R1-R3,PC" ; ***************************************************************************** ; ; ReadSubBlock - Read a block of CMOS RAM specified by logical address. ; Assumes the address is valid, and will only read as much ; as it can in a single IIC transaction. ; ; in: R0 = address in CMOS RAM ; R1 = address to copy to ; R2 = length ; ; out: R0-R2 updated to reflect the amount read. ; ReadSubBlock ROUT Push "R3-R5,R14" ; establish end of the current contiguous block, and the logical->physical address offset. CMP R0, #1 ; 00 -> 40 uncached MOVLO R3, #1 MOVLO R4, #&40-&00 BLO %FT10 CMP R0, #&C0 ; [01..C0) -> [41..100) cached MOVLO R3, #&C0 MOVLO R4, #&41-&01 BLO %FT10 CMP R0, #&F0 ; [C0..F0) -> [10..40) cached MOVLO R3, #&F0 MOVLO R4, #&10-&C0 BLO %FT10 CMP R0, #&100 ; [F0..100) -> [00..10) cached MOVLO R3, #&100 MOVLO R4, #&00-&F0 ADDHS R3, R0, R2 ; [100..) -> [100..) uncached MOVHS R4, #0 ; R3 = logical end of current segment (exclusive) ; R4 = offset from logical to physical address for this segment 10 ADD R14, R0, R2 CMP R3, R14 MOVHI R3, R14 ; R3 = logical end of this transaction (exclusive) TEQ R0, #0 ; check it's a cacheable segment BEQ %FT15 CMP R0, #&100 BHS %FT15 LDR R14, =ZeroPage+CMOSRAMCache ADD R3, R3, R4 ; R3 = physical end address ADD R4, R4, R0 ; R4 = physical address ADD R3, R3, R14 ; R3 = cache end address ADD R4, R4, R14 ; R4 = cache address SUB R14, R3, R4 ; R14 = bytes being read ADD R0, R0, R14 ; update return R0 SUB R2, R2, R14 ; update return R2 12 LDRB R14, [R4], #1 CMP R4, R3 STRB R14, [R1], #1 BLO %BT12 Pull "R3-R5,PC" ; V will be clear 15 Push "R0-R2" ADD R0, R0, R4 ; R0 = physical start address ADD R3, R3, R4 ; R3 = physical end address [ HAL Push "sb" SUB R2, R3, R0 MOV R5, R0 ; save address AddressHAL Push "R1-R3,R12" CallHAL HAL_NVMemoryType Pull "R1-R3,R12" AND R0, R0, #NVMemoryFlag_Provision TEQ R0, #NVMemoryFlag_None ; If there's no NVmemory, tough - we just return. MOVEQ R2, #0 ; nothing read Pull "sb", EQ Pull "R3-R5,PC", EQ TEQ R0, #NVMemoryFlag_HAL MOV R0, R5 ; restore address BNE %FT17 ; do IIC things. ; Make the HAL call Push "R12" CallHAL HAL_NVMemoryRead ; returns bytes read in R0 Pull "R12" MOV R4, R0 Pull "sb" Pull "R0-R2" ADD R0, R0, R4 ADD R1, R1, R4 SUB R2, R2, R4 Pull "R3-R5,PC" 17 Pull "sb" ] SUB R5, R3, R0 ; R5 = bytes being read [ E2ROMSupport BL GetI2CAddress ; convert to device address and offset | MOV R1, #RTCAddressPHI ] MOV R2, R0 ; save the offset SUB R13, R13, #12*2+4 MOV R14, R13 TST R1, #&100 ; 2-byte address? MOVNE R0, R2, LSR #8 STRNEB R0, [R14], #1 ; offset (MSB) STRB R2, [R14], #1 ; offset (LSB) SUB R14, R14, R13 STR R14, [R13, #12] ; transfer 1 length AND R14, R1, #&FF ORR R0, R14, #1:SHL:29 ; retry STR R0, [R13, #4] ; transfer 1 address ORR R14, R14, #1 ; device address for read STR R14, [R13, #16] ; transfer 2 address STR R13, [R13, #8] ; transfer 1 data ADD R14, R13, #12*2+4 LDMIA R14, {R0-R2} ADD R0, R0, R5 ; update return R0 SUB R2, R2, R5 ; update return R2 STMIB R14, {R0,R2} STR R1, [R13, #20] ; transfer 2 data STR R5, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV LDR R1, [R13, #20] ; recover data pointer ADD R1, R1, R5 ADD R13, R13, #12*2+4+4 CLRV Pull "R0,R2,R3-R5,PC" ; ***************************************************************************** ; ; ChecksumBlock - Checksum a block of CMOS RAM specified by logical address ; Assumes the address is valid. ; ; in: R0 = address in CMOS RAM ; R1 = initial checksum ; R2 = length ; ; out: R1 incremented by sum of bytes in range ; ChecksumBlock ROUT Push "R0,R2,R14" 10 BL ChecksumSubBlock BVS %FT80 TEQ R2, #0 BNE %BT10 80 Pull "R0,R2,PC" ; ***************************************************************************** ; ; ChecksumSubBlock - Checksum a block of CMOS RAM specified by logical address. ; Assumes the address is valid, and will only read as much ; as it can in a single IIC transaction. Skips over ; 239 (the checksum byte itself), and 240-255 (OTP area). ; ; in: R0 = address in CMOS RAM ; R1 = initial checksum ; R2 = length ; ; out: R0-R2 updated to reflect the data read. ; ChecksumSubBlock ROUT Push "R3-R5,R14" ; establish end of the current contiguous block, and the logical->physical address offset. CMP R0, #1 ; 00 -> 40 uncached MOVLO R3, #1 MOVLO R4, #&40-&00 BLO %FT10 CMP R0, #&C0 ; [01..C0) -> [41..100) cached MOVLO R3, #&C0 MOVLO R4, #&41-&01 BLO %FT10 CMP R0, #&EF ; [C0..EF) -> [10..3F) cached MOVLO R3, #&EF MOVLO R4, #&10-&C0 BLO %FT10 CMP R0, #&100 ADDHS R3, R0, R2 ; [100..) -> [100..) uncached MOVHS R4, #0 BHS %FT10 ; [EF..100) -> not checksummed MOV R3, #&100 ADD R14, R0, R2 CMP R3, R14 MOVHI R3, R14 SUB R14, R3, R0 ADD R0, R0, R14 SUB R2, R2, R14 Pull "R3-R5,PC" ; R3 = logical end of current segment (exclusive) ; R4 = offset from logical to physical address for this segment 10 ADD R14, R0, R2 CMP R3, R14 MOVHI R3, R14 ; R3 = logical end of this transaction (exclusive) TEQ R0, #0 ; check it's a cacheable segment BEQ %FT15 CMP R0, #&100 BHS %FT15 LDR R14, =ZeroPage+CMOSRAMCache ADD R3, R3, R4 ; R3 = physical end address ADD R4, R4, R0 ; R4 = physical address ADD R3, R3, R14 ; R3 = cache end address ADD R4, R4, R14 ; R4 = cache address SUB R14, R3, R4 ; R14 = bytes being read ADD R0, R0, R14 ; update return R0 SUB R2, R2, R14 ; update return R2 12 LDRB R14, [R4], #1 CMP R4, R3 ADD R1, R1, R14 BLO %BT12 Pull "R3-R5,PC" 15 Push "R0-R2" ADD R0, R0, R4 ; R0 = physical start address ADD R3, R3, R4 ; R3 = physical end address [ HAL Push "sb,R12" MOV R5, R0 ; save address AddressHAL Push "R1-R3" CallHAL HAL_NVMemoryType Pull "R1-R3" AND R4, R0, #NVMemoryFlag_Provision MOV R0, R5 ; restore address TEQ R4, #NVMemoryFlag_None TEQNE R4, #NVMemoryFlag_HAL BNE %FT17 ; do IIC things. SUB R14, R3, R0 LDR R1, [R13,#8] LDR R3, [R13,#16] ADD R1, R1, R14 SUB R3, R3, R14 STR R1, [R13,#8] STR R3, [R13,#16] TEQ R4, #NVMemoryFlag_None ; If there's no NVmemory, tough - we just return. Pull "sb,R12", EQ Pull "R0-R5,PC", EQ Push "R6" MOV R4, #0 ADD R6, R5, R14 SUB R13, R13, #4 16 MOV R0, R5 MOV R1, sp MOV R2, #1 CallHAL HAL_NVMemoryRead LDRB R14, [R13] ADD R4, R4, R14 ADD R5, R5, #1 TEQ R5, R6 BNE %BT16 ADD R13, R13, #4 Pull "R6,sb,R12" Pull "R0-R2" ADD R1,R1,R4 Pull "R3-R5,PC" 17 Pull "sb,R12" ] SUB R5, R3, R0 ; R5 = bytes being read [ E2ROMSupport BL GetI2CAddress ; convert to device address and offset | MOV R1, #RTCAddressPHI ] MOV R2, R0 ; save the offset SUB R13, R13, #12*2+4 MOV R14, R13 TST R1, #&100 ; 2-byte address? MOVNE R0, R2, LSR #8 STRNEB R0, [R14], #1 ; offset (MSB) STRB R2, [R14], #1 ; offset (LSB) SUB R14, R14, R13 STR R14, [R13, #12] ; transfer 1 length AND R14, R1, #&FF ORR R0, R14, #1:SHL:29 ; retry STR R0, [R13, #4] ; transfer 1 address ORR R14, R14, #1 ; device address for read ORR R14, R14, #1:SHL:30 ; checksum only please STR R14, [R13, #16] ; transfer 2 address STR R13, [R13, #8] ; transfer 1 data ADD R14, R13, #12*2+4 LDMIA R14, {R0-R2} ADD R0, R0, R5 ; update return R0 SUB R2, R2, R5 ; update return R2 STMIB R14, {R0,R2} MOV R4, R1 ; remember checksum STR R5, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV LDR R1, [R13, #20] ; read back checksum ADD R1, R1, R4 ; update checksum ADD R13, R13, #12*2+4+4 Pull "R0,R2,R3-R5,PC" ; ***************************************************************************** ; ; GetI2CAddress - Convert NVRam physical address to i2c device address ; and offset ; ; in: R0 = NVRam physical address (&00..size of NVRam) ; ; out: R0 preserved ; ; C=0 => NVRam address is valid ; R0 = physical address within i2c device ; R1 = i2c device address for writing. Increment this device address ; by 1 for reading. Bit 8 is set if device requires 2-byte physical address. ; ; C=1 => NVRam address is out of range of CMOS or E2ROM chips ; R0 preserved ; R1 preserved [ E2ROMSupport GetI2CAddress ROUT Push "R14" LDR R14, =ZeroPage ; get no 256 byte blocks and calculate end address LDRB R14, [R14, #NVRamSize] MOV R14, R14, LSL #8 CMP R0, R14 Pull "PC",CS ; indicate invalid ; address is < end address -> is valid LDR R1, =ZeroPage LDRB R1, [R1, #NVRamBase] CMP R14, #2*1024 ; is the device bigger than 2K? If so, new addressing scheme ORRHI R1, R1, #&100 ; set magic bit => 2 byte address BHI %FT50 MOVS R14, R0, LSR #8 ; put top bits of physical address into device address ORRNE R1, R1, R14, LSL #1 ANDNE R0, R0, #&FF ; and use address within 256 byte block 50 CLC Pull "PC" ; indicate valid ] ; ***************************************************************************** ; ; MangleCMOSAddress - Convert from logical to physical address ; ; Doesn't check if address is larger than the amount of NVRam installed ; ; in: R0 = logical address (&00...) ; ; out: C=0 => valid logical address ; R0 = physical address (&40..&FF,&10..&3F,&00..0F,&100..) ; ; C=1 => invalid logical address ; R0 preserved ; MangleCMOSAddress ROUT [ E2ROMSupport Push "R14" LDR R14, =ZeroPage ; read no 256 byte blocks and calculate end address LDRB R14, [R14, #NVRamSize] MOV R14, R14, LSL #8 CMP R0, R14 ; if >= end address then Pull "R14" MOVCS PC, R14 ; invalid (exit C set) CMP R0, #&100 ; if < end address && >= &100 then BLO %FT05 CLC MOV PC, R14 ; valid (no mungeing) ] 05 CMP R0, #&F0 ; if < &100 && >= &f0 then [ E2ROMSupport BCC %FT10 SUB R0, R0, #&F0 ; map &F0->&FF to &00->0F for OTP section CLC MOV PC, R14 | MOVCS PC, R14 ; invalid ] 10 ADD R0, R0, #&40 ; now in range &40..&13F CMP R0, #&100 SUBCS R0, R0, #(&100-&10) ; now in range &40..&FF, &10..&3F CLC MOV PC, R14 ; valid ; ***************************************************************************** ; ; ValChecksum - test to see if the CMOS checksum is OK ; ; This routine performs MangleCMOSAddress inherently. ; ; The checksum does not include physical locations &00->&0F, even ; if they are OTP section (as this is usually used for a unique id ; which will be different for every machine and can't be changed). ; ; in: none ; ; out: R0 = calculated checksum ; Z set if checksum is valid ; All other registers preserved ; [ ChecksumCMOS ValChecksum Entry "R1-R2" MOV R0, #0 MOV R1, #CMOSxseed [ E2ROMSupport LDR R2, =ZeroPage ; read number of 256 byte blocks and calculate end address LDRB R2, [R2, #NVRamSize] MOV R2, R2, LSL #8 | MOV R2, #240 ] BL ChecksumBlock ; ; R1 contains the actual checksum. Compare it with the recorded checksum ; 40 MOV R0, #CheckSumCMOS BL Read AND R2, R0, #&FF ; value from checksum location AND R0, R1, #&FF ; calculated value into R0 CMPS R0, R2 EXIT ] ; ***************************************************************************** ; ; MakeChecksum - calculate and write a correct checksum ; ; in: none ; ; out: R0 = calculated checksum ; All other registers preserved ; [ ChecksumCMOS MakeChecksum ROUT Push "R1-R2,R14" MOV R0, #0 MOV R1, #CMOSxseed [ E2ROMSupport LDR R2, =ZeroPage LDRB R2, [R2, #NVRamSize] MOV R2, R2, LSL #8 | MOV R2, #240 ] BL ChecksumBlock MOV R0, #CheckSumCMOS BL Write Pull "R1-R2,PC" ] LTORG ; ***************************************************************************** ; ; InitCMOSCache - Initialise cache of CMOS RAM ; in: - ; ; out: R0 = 0 for failure InitCMOSCache Entry "r1-r6, sb,r12" [ E2ROMSupport ; Need to set the slowest speed so we can probe LDR R4, =ZeroPage MOV R3, #10 ; Default speed setting (5�s delays) STRB R3, [R4, #NVRamSpeed] [ HAL AddressHAL CallHAL HAL_NVMemoryType MOV R5, R0 ANDS R0, R0, #NVMemoryFlag_Provision ASSERT NVMemoryFlag_None = 0 BEQ InitCMOSCache_NoCMOS ; If it's only a maybe, then we probe TEQ R0, #NVMemoryFlag_MaybeIIC BEQ %FT03 ; Else we read the size CallHAL HAL_NVMemorySize ; returns number of bytes but.. MOV R0, R0, LSR#8 ; .. expecting no. of 256 blocks STRB R0, [R4, #NVRamSize] TST R5, #NVMemoryFlag_ProtectAtEnd STREQB R0, [R4, #NVRamWriteSize] BEQ %FT02 CallHAL HAL_NVMemoryProtectedSize LDRB R1, [R4, #NVRamSize] SUB R0, R1, R0, LSR#8 STRB R0, [R4, #NVRamWriteSize] 02 CallHAL HAL_NVMemoryPageSize ; returns size in bytes but.. TEQ R0, #0 ; .. expecting power of 2 MVNEQ R0, #0 MOV R1, #0 22 MOVS R0, R0, LSR #1 ADDNE R1, R1, #1 BNE %BT22 STRB R1, [R4, #NVRamPageSize] CallHAL HAL_NVMemoryIICAddress STRB R0, [R4, #NVRamBase] MOV R0, #0 CallHAL HAL_IICType MOV R3, #10 TST R0, #IICFlag_Fast MOVNE R3, #3 TST R0, #IICFlag_HighSpeed MOVNE R3, #1 STRB R3, [R4, #NVRamSpeed] ; If we're using IIC then read in the cache manually AND R0, R5, #NVMemoryFlag_Provision TEQ R0, #NVMemoryFlag_IIC BEQ %FT06 ; Else use HAL routine. MOV R0, #0 LDR R1, =ZeroPage+CMOSRAMCache MOV R2, #&100 CallHAL HAL_NVMemoryRead TEQ R0, #&100 MOVNE R0, #0 ; Failure exit condition EXIT 03 ] ; No HAL,so determine what hardware we've got fitted by probing, ; R4 holds the number of 256 byte blocks that we've found MOV R3, #10 ; assume 100kHz to start with MOV R5, #4 ; assume 16 byte page size to start with MOV R6, #0 ; assume not protected ; Have we got a 2K device ? MOV r1, #E2ROMAddress2K MOV r0, #(E2ROMAddress2K+14) BL DummyAccess MOVVC R4, #8 MOVVC R3, #3 ; Fast speed setting (1.5�s delays) BVC %FT5 ; Have we got a 16K device ? MOV r1, #E2ROMAddress16K MOV r0, #E2ROMAddress16K BL DummyAccess MOVVC R4, #64 MOVVC R5, #6 ; 64 byte page size MOVVC R3, #3 ; Fast speed setting (1.5�s delays) BVC %FT5 ; Have we got a 4K device? MOV r1, #E2ROMAddress4K MOV r0, #E2ROMAddress4K BL DummyAccess MOVVC R4, #16 MOVVC R6, #12 ; Only bottom 3K writable MOVVC R5, #5 ; 32 byte page size MOVVC R3, #3 ; Fast speed setting (1.5�s delays) BVC %FT5 ; Have we got an 8K device? MOV r1, #E2ROMAddress8K MOV r0, #E2ROMAddress8K BL DummyAccess MOVVC R4, #32 MOVVC R5, #5 ; 32 byte page size MOVVC R3, #3 ; Fast speed setting (1.5�s delays) BVC %FT5 ; Have we got a protected 8K device? MOV r1, #E2ROMAddress8K_prot MOV r0, #E2ROMAddress8K_prot BL DummyAccess MOVVC R4, #32 MOVVC R6, #24 ; Only bottom 6K writable MOVVC R5, #5 ; 32 byte page size MOVVC R3, #3 ; Fast speed setting (1.5�s delays) BVC %FT5 ; Have we got a 32K device? MOV r1, #E2ROMAddress32K MOV r0, #E2ROMAddress32K BL DummyAccess MOVVC R4, #128 ; 128,120,6,1 MOVVC R6, #120 ; Only bottom 30K writable MOVVC R5, #6 ; 64 byte page size MOVVC R3, #1 ; Hyper-fast speed setting (0.5�s delays - 1MHz part) BVC %FT5 ; Any storage in the Philips RTC? MOV R1, #RTCAddressPHI MOV R0, #RTCAddressPHI BL DummyAccess MOV R5, #8 ; 256 byte page size for CMOS MOVVC R4, #1 BVC %FT5 ; We ain't got anything! InitCMOSCache_NoCMOS LDR R2, =ZeroPage MOV R5, #8 STRB R5, [R2, #NVRamPageSize] ; Act as though we have 256 bytes of MOV R1, #1 ; single page CMOS. STRB R1, [R2, #NVRamSize] STRB R1, [R2, #NVRamWriteSize] MOV R0, #0 ; Exit failure EXIT 5 ; Set the NVRam count LDR R2, =ZeroPage STRB R1, [R2, #NVRamBase] STRB R4, [R2, #NVRamSize] STRB R5, [R2, #NVRamPageSize] TEQ R6, #0 MOVEQ R6, R4 STRB R6, [R2, #NVRamWriteSize] CMP R3, #I2Cticks ; clamp speed to maximum bus speed MOVLO R3, #I2Cticks STRB R3, [R2, #NVRamSpeed] 06 ; Initialise the cache LDR R3, =ZeroPage+CMOSRAMCache TEQ R4, #8 ; check for 2K part MOVNE r0, #&00 ; if not, then start at 0 anyway and read non-OTP data into location 0..15 BNE %FT07 BL ReadOTPArea MOV r0, #&10 ; read rest of it from 16 onwards 07 BL GetI2CAddress ; and convert to device address and offset MOV R2, R0 ; save the offset MOV R4, #&100 ; stop at &100 | ; No E2ROM support, assume just a Philips RTC MOV R1, #RTCAddressPHI MOV R2, #&10 MOV R4, #&100 ; stop at address &100 LDR R3, =ZeroPage+CMOSRAMCache ] ; Note - R4 MUST be &100 to prevent crossover between 256-byte pages ; (for devices with multiple addresses) 09 SUB R13, R13, #2*12+4 AND R0, R1, #&FF STR R0, [R13, #4] ; transfer 1 address ADD R0, R0, #1 ; read address STR R0, [R13, #16] ; transfer 2 address TST R1, #&100 ; 2-byte address? MOV R14, R13 MOVNE R0, R2, LSR #8 STRNEB R0, [R14], #1 ; memory word address (MSB) STRB R2, [R14], #1 ; memory word address (LSB) STR R13, [R13, #8] ; transfer 1 data SUB R14, R14, R13 STR R14, [R13, #12] ; transfer 1 length ADD R14, R3, R2 STR R14, [R13, #20] ; transfer 2 data SUB R14, R4, R2 STR R14, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV ADD R13, R13, #2*12+4 MOV R0, #1 EXIT [ E2ROMSupport ReadOTPArea Entry SUB R13, R13, #2*12+4 MOV R0, #0 STRB R0, [R13, #0] ; offset 0 MOV R0, #E2ROMAddress2K_OTP STR R0, [R13, #4] ; transfer 1 address STR R13, [R13, #8] ; transfer 1 data MOV R0, #1 STR R0, [R13, #12] ; transfer 1 length MOV R0, #E2ROMAddress2K_OTP + 1 STR R0, [R13, #16] ; transfer 2 address STR R3, [R13, #20] ; transfer 2 data MOV R0, #16 STR R0, [R13, #24] ; transfer 2 length ADD R0, R13, #4 MOV R1, #2 BL IIC_OpV ADD R13, R13, #2*12+4 EXIT ] ; ***************************************************************************** ; ; DummyAccess - do a dummy access of the specified device to find out ; if it is present ; ; in: R0 = Write address of device ; ; out: All registers preserved ; V=0 => device is present ; V=1 => device is not present [ E2ROMSupport DummyAccess [ {TRUE} ; Blooming 80321 HW IIC can't do just START address STOP Entry "R0-R2",4 ORR R0, R0, #1 MOV R1, R13 MOV R2, #1 BL IIC_Op | Entry "R1,R2" MOV R1, #0 MOV R2, #0 BL IIC_Op ] EXIT ; Exit with V set appropriately ] ; ***************************************************************************** ; ; SWI OS_NVMemory ; ; in: R0 = reason code ; NVMemorySWI Entry BL NVMemorySub PullEnv ORRVS LR, LR, #V_bit ExitSWIHandler NVMemorySub CMP R0, #7 ADDLS PC, PC, R0, LSL #2 B NVMemory_Unknown B NVMemory_Size B NVMemory_Read B NVMemory_Write B NVMemory_ReadBlock B NVMemory_WriteBlock B NVMemory_Unknown ; Reserved for Kernel-5_41 divergence B NVMemory_ResetValue B NVMemory_SetStation NVMemory_Unknown ADRL R0, ErrorBlock_HeapBadReason [ International Push LR BL TranslateError Pull LR ] RETURNVS ; ----------------------------------------------------------------------------- ; OS_NVMemory 0 - find NV memory size ; ; in: R0 = 0 ; ; out: R1 = NV memory size in bytes ; NVMemory_Size [ E2ROMSupport [ ZeroPage = 0 LDRB R1, [R0, #NVRamSize] | LDR R1, =ZeroPage LDRB R1, [R1, #NVRamSize] ] MOV R1, R1, LSL #8 | MOV R1, #240 ] MOV PC, LR ; ----------------------------------------------------------------------------- ; OS_NVMemory 1 - read a byte ; ; in: R0 = 1 ; R1 = location ; ; out: R2 = value ; NVMemory_Read Entry "R4" MRS R4, CPSR BIC R0, R4, #I32_bit MSR CPSR_c, R0 ; enable interrupts - this may take some time MOV R0, R1 BL ReadWithError MOVVC R2, R0 MOVVC R0, #1 ; must preserve R0 ORRVS R4, R4, #V_bit MSR CPSR_cf, R4 ; restore interrupt state EXIT ; ----------------------------------------------------------------------------- ; OS_NVMemory 2 - write a byte ; ; in: R0 = 2 ; R1 = location ; R2 = value ; NVMemory_Write ROUT [ ProtectStationID TEQ R1, #NetStnCMOS ; just ignore writes MOVEQ PC, R14 ] Entry "R1,R4" MRS R4, CPSR BIC R0, R4, #I32_bit MSR CPSR_c, R0 ; enable interrupts - this may take some time MOV R0, R1 MOV R1, R2 BL WriteWithError MOVVC R0, #2 ; must preserve R0 ORRVS R4, R4, #V_bit MSR CPSR_cf, R4 ; restore interrupt state EXIT ; ----------------------------------------------------------------------------- ; OS_NVMemory 3 - read a block ; ; in: R0 = 3 ; R1 = location ; R2 = buffer ; R3 = length ; NVMemory_ReadBlock Entry "R1-R4" MRS R4, CPSR BIC R0, R4, #I32_bit MSR CPSR_c, R0 ; enable interrupts - this may take some time MOV R0, R1 MOV R1, R2 MOV R2, R3 BL ReadBlock MOVVC R0, #3 ; must preserve R0 ORRVS R4, R4, #V_bit MSR CPSR_cf, R4 ; restore interrupt state EXIT ; ----------------------------------------------------------------------------- ; OS_NVMemory 4 - write a block ; ; in: R0 = 4 ; R1 = location ; R2 = buffer ; R3 = length ; NVMemory_WriteBlock ROUT Entry "R1-R4" MRS R4, CPSR BIC R0, R4, #I32_bit MSR CPSR_c, R0 ; enable interrupts - this may take some time [ ProtectStationID ASSERT NetStnCMOS = 0 TEQ R1, #NetStnCMOS BNE %FT10 ADD R1, R1, #1 ADD R2, R2, #1 TEQ R3, #0 SUBNE R3, R3, #1 ; steer clear of station ID ] 10 MOV R0, R1 MOV R1, R2 MOV R2, R3 BL WriteBlock MOVVC R0, #4 ; must preserve R0 ORRVS R4, R4, #V_bit MSR CPSR_cf, R4 ; restore interrupt state EXIT ; ----------------------------------------------------------------------------- ; OS_NVMemory 6 - query CMOS value that would be used on a Delete-Power-On reset ; ; in: R0 = 6 ; R1 = location ; ; out: R2 = value, or -1 if the value is unknown/untouched ; NVMemory_ResetValue ROUT Entry "R3" MOV R2, #-1 ; assume outside our remit TEQ R1, #NetStnCMOS EXIT EQ ASSERT CheckSumCMOS = CMOSLimit - 1 CMP R1, #CheckSumCMOS EXIT CS TEQ R1, #MouseCMOS BEQ %FT20 ; code driven TEQ R1, #PrintSoundCMOS BEQ %FT30 ; code driven [ STB :LAND: :DEF: IOMD_C_PALNTSCType TEQ R1, #TerritoryCMOS BEQ %FT40 ; code driven TEQ R1, #CountryCMOS BEQ %FT41 ; code driven TEQ R1, #TimeZoneCMOS BEQ %FT42 ; code driven ] ADR R3, DefaultCMOSTable 10 LDRB R2, [R3], #2 ; table is of location/value pairs... TEQ R2, #&FF ; ...terminated by &FF MOVEQ R2, #0 ; not in the table, so must be zero EXIT EQ TEQ R2, R1 ; location match? LDREQB R2, [R3, #-1] EXIT EQ B %BT10 20 [ HAL [ "$Machine"="IOMD" Push "R0-R1,R9,R12" AddressHAL MOV R0, #0 MOV R1, #&400 ; SSpace hopefully exists CallHAL HAL_ControllerAddress LDRB R1, [R0, #IOMD_ID1] LDRB R0, [R0, #IOMD_ID0] ORR R0, R0, R1, LSL #8 LDR R1, =IOMD_Original TEQ R0, R1 ; Select quadrature or PS2 as appropriate MOVEQ R2, #PointerDevice_QuadMouse ; Risc PC MOVNE R2, #PointerDevice_PS2Mouse ; A7000 et al Pull "R0-R1,R9,R12" | ; Everyone else is on USB MOV R2, #PointerDevice_USB ] | Push "R0-R1" MOV R3, #IOMD_Base LDRB R1, [R3, #IOMD_ID1] LDRB R0, [R3, #IOMD_ID0] ORR R0, R0, R1, LSL #8 LDR R1, =IOMD_Original TEQ R0, R1 MOVEQ R2, #PointerDevice_QuadMouse ; Risc PC MOVNE R2, #PointerDevice_PS2Mouse ; A7000 et al Pull "R0-R1" ] EXIT 30 [ HAL MOV R2, #2_10100100 ; ^^^ interpolate at low rates, 16 bit DAC, fully programmable rates ; ^^^^^ tbs chars valid, escape with GSTrans | Push "R0-R1" MOV R3, #IOMD_Base LDRB R1, [R3, #IOMD_ID1] LDRB R0, [R3, #IOMD_ID0] ORR R0, R0, R1, LSL #8 LDR R1, =IOMD_7500 TEQ R0, R1 LDRNE R1, =IOMD_7500FE TEQNE R0, R1 [ STB MOVEQ R2, #2_00000100 ; Cheapskates | MOVEQ R2, #2_10100100 ; A7000 et al always have 16 bit sound ] BEQ %FT31 ; on Issue A's the protection bit is only weakly pulled up, ; so force it high, then read it back LDR R3, =IOMD_MonitorType LDR R1, [R3] ORR R1, R1, #IOMD_SoundsystemLinkBit STR R1, [R3] LDR R1, [R3] TST R1, #IOMD_SoundsystemLinkBit MOVEQ R2, #2_10100100 ; if zero, must be Rimmer, so assume 16bit sound hardware present MOVNE R2, #2_00000100 ; 8 bit sound on the motherboard (can't detect plugin upgrades) 31 Pull "R0-R1" ] EXIT [ STB :LAND: :DEF: IOMD_C_PALNTSCType 40 MOV R2, #0 ; PAL = territory UK MOV R3, #49 ; NTSC = territory USA B %FT44 41 MOV R2, #1 ; PAL = country UK MOV R3, #48 ; NTSC = country USA B %FT44 42 MOV R2, #0 ; PAL = 0 from UTC (GMT) MOV R3, #&E0 ; NTSC = -8 hours from UTC (USA Pacific) B %FT44 44 MOV R14, #IOMD_Base LDRB R14, [R14, #IOMD_CLINES] TST R14, #IOMD_C_PALNTSCType MOVNE R2, R3 ; Select NTSC when line high EXIT ] ; ----------------------------------------------------------------------------- ; OS_NVMemory 7 - set station ; ; in: R0 = 7 ; R1 = pointer to pass phrase ; R2 = value ; NVMemory_SetStation ROUT Entry "R1-R4" MRS R4, CPSR BIC R0, R4, #I32_bit MSR CPSR_c, R0 ; enable interrupts - this may take some time [ ProtectStationID MOV R2, R1 10 LDRB R0, [R2], #1 CMP R0, #' ' BCS %BT10 MOV R3, #1 SUB R2, R2, #1 MOV R0, #0 SWI XOS_CRC EOR R0, R0, #&009D EORS R0, R0, #&2300 MOVNE R0, #-1 ; duff address to cause 'not writable' error ASSERT NetStnCMOS = 0 LDR R1, [SP, #Proc_RegOffset + 4] | MOV R0, #NetStnCMOS MOV R1, R2 ] BL WriteWithError MOVVC R0, #7 ; must preserve R0 ORRVS R4, R4, #V_bit MSR CPSR_cf, R4 ; restore interrupt state EXIT [ ValidateCMOS :LAND: STB DefaultCMOSTable ; Minimalist table DCB KeyDelCMOS, 32 DCB KeyRepCMOS, 8 DCB MODETVCMOS, &10 ; TV 0,1 DCB StartCMOS, (1:SHL:7):OR:(2:SHL:3) ; NONUM, NOCAPS DCB DBTBCMOS, (1:SHL:4) ; Boot DCB YearCMOS+0, 00 DCB YearCMOS+1, 20 [ IOMD_C_MonitorType = 0 :LAND: IOMD_C_PALNTSCType = 0 ; TV if we don't have a MonitorType auto-detect bit DCB VduCMOS, Sync_Separate :OR: MonitorType0 | ; auto-detect if we have a MonitorType auto-detect bit DCB VduCMOS, Sync_Auto :OR: MonitorTypeAuto ] DCB CountryCMOS, 1 ; UK DCB MouseStepCMOS, 2 DCB SystemSpeedCMOS, (1:SHL:2):OR:(1:SHL:4):OR:(0:SHL:5) ; Delete-etc reset ; WimpMode auto ; Cache on | DefaultCMOSTable ; Normal table DCB KeyDelCMOS, 32 [ "$Machine"="CortexA8" :LOR: "$Machine"="CortexA9" DCB FileLangCMOS, fsnumber_SCSIFS ; SCSIFS for OMAP3, etc. | [ "$Machine"="ARM11ZF" :LOR: "$Machine"="RPi" DCB FileLangCMOS, fsnumber_SDFS ; SDFS for Pi, etc. | DCB FileLangCMOS, fsnumber_adfs ; ADFS ] ] DCB FontCMOS, 64 ; KJB 13-Dec-02: Changed to 256K from 64K DCB PigCMOS, 10 DCB KeyRepCMOS, 8 DCB RMASizeCMOS, 0 DCB SpriteSizeCMOS, 0 DCB SysHeapCMOS, 8 DCB MODETVCMOS, &10 ; TV 0,1 DCB NetFSIDCMOS, 254 DCB NetPSIDCMOS, 235 DCB PSITCMOS, (3:SHL:2) :OR: (1:SHL:5) ; Baud 3 ; Print 1 DCB DBTBCMOS, (1:SHL:4) :OR: (4:SHL:5) ; Boot (changed from NoBoot 01-Sep-93) ; Data 4 DCB StartCMOS, (4:SHL:0) :OR: (2:SHL:3) :OR: (1:SHL:6) :OR: (0:SHL:7) ; ^ ^ ^ ^ ; ADFS DR.4 NOCAPS NODIR (moot) NUM [ :LNOT: STB DCB NewADFSCMOS+0, &41 ; floppies=1, ST506=0, IDE=1 (changed 01-Sep-93) ] DCB NewADFSCMOS+1, 4_3333 ; step 3 for each drive DCB NewADFSCMOS+2, 1 ; ADFSBuffers 1 DCB SoundCMOS, &F0 ; speaker on, volume 7, channel 1 DCB LanguageCMOS, 11 ; typically module number of 'Desktop' DCB YearCMOS+0, 00 DCB YearCMOS+1, 20 DCB NetFilerCMOS, (0:SHL:0) :OR: (1:SHL:1) :OR: (0:SHL:2) ; FS list order by name ; Use $.Arthurlib ; Large icons DCB DesktopCMOS, 2_01000000 ; verbose ON DCB WimpFlagsCMOS, 2_01101111 ; instant effects, drags off screen DCB ProtectionCMOS, 2_01110110 ; allow only peek and user RPC DCB MouseStepCMOS, 2 DCB FileSwitchCMOS, (1:SHL:0) :OR: (1:SHL:1) :OR: (0:SHL:2) :OR: (0:SHL:3) :OR: (0:SHL:6) ; Truncate names ; Use DragASprite (changed 01-Sept-93) ; Interactive file copying ; Wimp dither colours off ; Last shutdown ordinary DCB DesktopFeaturesCMOS,(1:SHL:0) :OR: (8:SHL:1) :OR: (0:SHL:7) ; 3D look ; Homerton.Medium ; Tiled window background [ STB DCB SystemSpeedCMOS, (1:SHL:0):OR:(0:SHL:1):OR:(1:SHL:2):OR:(0:SHL:3):OR:(1:SHL:4):OR:(0:SHL:5):OR:(1:SHL:6):OR:(0:SHL:7) ; AUN ROMBoot Enabled ; AUN auto-station numbering off ; Delete-etc reset ; Power saving off ; WimpMode auto ; Cache on ; Broadcast loader disabled ; Broadcast loader colours off | DCB SystemSpeedCMOS, (0:SHL:0):OR:(0:SHL:1):OR:(1:SHL:2):OR:(0:SHL:3):OR:(1:SHL:4):OR:(0:SHL:5):OR:(1:SHL:6):OR:(0:SHL:7) ; AUN BootNet Disabled ; AUN auto-station numbering off ; Delete-etc reset ; Power saving off ; WimpMode auto ; Cache on ; Broadcast loader disabled ; Broadcast loader colours off ] [ STB ; FontMaxCMOS yes, omitting is deliberate! DCB FontMax2CMOS, &2C ; 32 point DCB FontMax3CMOS, &38 ; 32 point | DCB FontMaxCMOS, 64 ; 4096k DCB FontMax2CMOS, 36:EOR:12 ; 36 point DCB FontMax3CMOS, 36:EOR:24 ; 36 point DCB FontMax4CMOS, 16 ; 16 point ] DCB AlarmAndTimeCMOS, 2_00010000 ; !Alarm autosave on DCB FSLockCMOS+5, &EA ; Checksum for no password DCB SparrowMarker, FreewayNoAutoAddress ; Stop Freeway assigning addresses to interfaces DCB NetworkFlags, LanManFStransport ; LMTransport is NetBIOS over IP DCB WimpDragMoveLimitCMOS, (1:SHL:7) ; WimpIconiseButton [ "$Machine"="CortexA8" :LOR: "$Machine"="CortexA9" :LOR: "$Machine"="ARM11ZF" :LOR: "$Machine"="RPi" DCB CDROMFSCMOS, &C0 ; drives = 0, buffer size = 256K | DCB CDROMFSCMOS, &C1 ; drives = 1, buffer size = 256K ] ] DCB &FF ALIGN END