; > TestSrc.Begin TTL RISC OS 2+ Power-On Self-Test ; ; Startup code for RISC OS ROM Self-Test. ; ; Performs ROM test patterns, determines test strategy and enters ; external or internal test code. ; ; A minimal set of opcodes should be used (ideally, only B, LDR and ADDS) ; so that a processor test may be validly included in the internal test ; sequence. ; ;------------------------------------------------------------------------ ; History ; ; Date Name Rel Comment ; ---- ---- --- ------- ; 23-Feb-93 ArtG 2.00 Experimental ARM 600 / Jordan mods ; 20-Oct-93 ARTG 2.02 Changed to new conditional assembly scheme ; 18-Nov-94 RCM 2.05 Morris changes ; ;------------------------------------------------------------------------ ; TS_STATUS should be one of : ; ; 'R' RISC OS POST ; 'S' Standalone version (with a2 memory test instead of RISCOS) ; 'T' Test build - development only ; TS_STATUS * "R" ; Medusa POST version 2.0x ; TS_RELEASE * 20 TS_CHANGES * 5 GBLL POSTenabled POSTenabled SETL {TRUE} ; don't permit POST for ordinary startup ts_Rom_bits * 21 ; Widest ROM address ts_Rom_length * 1 :SHL: ts_Rom_bits ; Longest ROM ts_highaddr_bit * 1 :SHL: 25 ; ARM address width ts_Alias_bits * (1 :SHL: 23) ; I/F output bits ts_recover_time * (1 :SHL: 8) ; inter-twiddle delay ts_pause_time * 200 ; Display pause time ts_S5_base * &3350000 ; IO register base address ts_IOEB_ID * (ts_S5_base + &50) ; IOE_B ASIC identification ts_IOEB_ident * &5 ; the value found there ts_PCaddress * &3010000 ; PC IO world base address ts_ReadyByte_00 * &90 ; signal 'Here I am' to ExtIO ts_BBRAM * &A0 ; IIC address of clock/ram chip ts_RamChunk * &2000 ; gap between data line tests ts_MaxRamTest * 4*1024*1024 ; Max. DRAM tested on normal reset ts_VIDCPhys * &3400000 ; Real location of VIDC ; ; Border colours used for self-test indicators ; [ VIDC_Type = "VIDC1a" C_ARMOK * &40000000+&70C ; testing ROM C_RAMTEST * &40000000+&C70 ; testing RAM C_FAULT * &40000000+&00F ; failed tests C_PASSED * &40000000+&7C0 ; all passed C_WARMSTART * &40000000+&777 ; not tested ] [ VIDC_Type = "VIDC20" C_ARMOK * &40000000+&7000C0 ; testing ROM C_RAMTEST * &40000000+&C07000 ; testing RAM C_FAULT * &40000000+&0000F0 ; failed tests C_PASSED * &40000000+&70C000 ; all passed C_WARMSTART * &40000000+&707070 ; not tested ] ; ; Responses to external commands ; ErrorCmd * &00FF ; ; Control bitmasks used to indicate results of test to RISCOS ; R_SOFT * 0 ; not a power-on reset R_HARD * 1 ; Self-test run due to POR R_EXTERN * 2 ; external tests performed R_TESTED * 4 ; Self-test run due to test link R_MEMORY * 8 ; Memory has been tested R_ARM3 * &10 ; ARM 3 fitted R_MEMSKIP * &20 ; long memory test disabled R_IOEB * &40 ; PC-style IO controller R_VRAM * &80 ; VRAM present R_STATUS * &1ff ; bits that aren't a fault R_CHKFAILBIT * &100 ; CMOS contents failed checksum R_ROMFAILBIT * &200 ; ROM failed checksum R_CAMFAILBIT * &400 ; CAM failed R_PROFAILBIT * &800 ; MEMC protection failed R_IOCFAILBIT * &1000 ; IOC register test failed R_INTFAILBIT * &2000 ; Cannot clear interrupts R_VIDFAILBIT * &4000 ; VIDC flyback failure R_SNDFAILBIT * &8000 ; Sound DMA failure R_CMSFAILBIT * &10000 ; CMOS unreadable R_LINFAILBIT * &20000 ; Page zero RAM failure R_MEMFAILBIT * &40000 ; Main RAM test failure R_CACFAILBIT * &80000 ; ARM 3 Cache test failure ; [ MorrisSupport Kludge * 96 | Kludge * 0 ] SUBT Exception vectors ; ; These vectors are available for use while the Rom is mapped into ; low memory addresses. The Reset vector will be copied to low RAM ; as part of a software reset sequence : therefore it must perform ; a fixed operation to ensure compatibility with future versions ; of RISC-OS. ; Reset ts_start $DoMorrisROMHeader [ :LNOT: MorrisSupport [ ResetIndirected LDR pc,.+ResetIndirection ; load pc from vector at &118 | B ts_RomPatt + PhysROM ; Jump to normal ROM space ] ] 01 & ts_Rom_length ; gets patched by ROM builder 02 & (ts_ROM_cvectors - ROM) ; pointer to code vector table 03 & (ts_ROM_dvectors - ROM) ; pointer to data vector table 04 & (ts_ROM_bvectors - ROM) ; pointer to branch table B Reset ; not currently used B Reset B Reset ts_ROMSIZE * %BT01 - ts_start ts_CVECTORS * %BT02 - ts_start ts_DVECTORS * %BT03 - ts_start ts_BVECTORS * %BT04 - ts_start ! 0, "ts_Rom_length held at ":CC::STR:(%BT01 - ROM) ; ; Selftest version ID ; 00 ASSERT %B00 <= (ts_start + &2c + Kludge) % ((ts_start + &2c + Kludge) - %B00) ts_ID & ((TS_STATUS :SHL: 24) + (TS_RELEASE :SHL: 16) + TS_CHANGES) ts_ID_text ts_himsg = "SELFTEST" ; **DISPLAY_TEXT** = &89 ; Cursor position = TS_STATUS = ("0" + (TS_RELEASE / 10)) = "." = ("0" + (TS_RELEASE :MOD: 10)) = ("0" + (TS_CHANGES :MOD: 10)) = 0 ; ; These vector tables permit access by the external (or downloaded) test ; software to data and code in the POST modules. ; Find the start of these tables through the 2nd and 3rd vectors at ; the start of the ROM. ; ts_ROM_dvectors 01 & ts_ID ; Selftest identification number 02 & (ts_ID_text - ROM) ; Selftest identification text ; ; vectors ORd with these flags to assure proper mode when ; executed by host thro' vector table. ; ts_runflags * (I_bit :OR: F_bit :OR: SVC_mode) ts_ROM_cvectors & ts_RomPatt :OR: ts_runflags & ts_User_startup :OR: ts_runflags & ts_Self_test_startup :OR: ts_runflags & ts_Dealer_startup :OR: ts_runflags & ts_Forced_startup :OR: ts_runflags & ts_GetCommand :OR: ts_runflags & ts_Softstart :OR: ts_runflags & ts_Hardstart :OR: ts_runflags ; ; ROM branch vectors - intended primarily so downloaded programs ; may use standard subroutines. This table should be in a fixed place. ; 00 ASSERT %B00 <= (ts_start + 128 + Kludge) % ((ts_start + 128 + Kludge) - %B00) ts_ROM_bvectors B ts_RomPatt B ts_GetCommand B ts_SendByte B ts_SendWord B ts_GetByte B ts_GetWord B ts_SendText B ts_MoreText B ts_SendLCDCmd ; ; Pad out until the location of the ResetIndirection vector ; ASSERT .-ROM <= ResetIndirection % ResetIndirection-(.-ROM) & ts_RomPatt-ROM+PhysROM ; ; ROM test code ; ; Note : the register order in ADDS ...pc.. is often critical. ; If we want to adjust pc, use ADDS pc,rn,pc so that the PSR is ; rewritten with it's original value. ; If we want to do some pc-relative arithmetic, use ADDS rn,pc,rn ; so that the bits from PSR are NOT used in the address calculation. ; SUBT Macros MACRO MODE $mode_bits TEQP psr,#($mode_bits :OR: I_bit :OR: F_bit) NOP MEND MACRO MOV_fiq $dest,$src MODE FIQ_mode MOV $dest,$src MODE SVC_mode MEND MACRO FAULT $code MODE FIQ_mode ORR r12_fiq,r12_fiq,$code MODE SVC_mode MEND MACRO M32_fiq $dest,$src,$tmp1,$tmp2 SetMode FIQ32_mode,$tmp1,$tmp2 MOV $dest,$src msr AL,CPSR_all,$tmp2 MEND MACRO FAULT32 $code,$tmp SetMode FIQ32_mode,$tmp ORR r12_fiq,r12_fiq,$code SetMode SVC32_mode,$tmp MEND [ StrongARM_POST ; ensure 26-bit mode for StrongARM or ARM 8 (since there is no 26 bit configuration) MACRO Ensure26bit_ARM8A $tmp ARM_read_ID $tmp AND $tmp, $tmp, #&F000 CMP $tmp, #&A000 CMPNE $tmp, #&8000 mrs EQ, $tmp, CPSR_all BICEQ $tmp, $tmp, #&10 msr EQ, CPSR_all, $tmp MEND ] ; ; Define an area of storage with the required set of data bus patterns ; These are used both for testing the complete width of the data bus ; during ROM pattern testing, and will provide a tidy set of patterns ; if the reset is held, while the ARM increments addresses. ; SUBT ROM Address and Data Patterns DataPatterns GBLA dmask dmask SETA &80000000 DCD &FFFFFFFF ; first two : all set DCD &0 ; all clear GBLA OldOpt ; don't list all the walking OldOpt SETA {OPT} ; patterns OPT OptNoList WHILE dmask > 0 ; then for each bit DCD &$dmask ; set it DCD :NOT: &$dmask ; and clear it dmask SETA dmask :SHR: 1 WEND OPT OldOpt DEnd OPT OptList ; ; ; Read the ROM at a series of addresses ; such that : a) all the address lines are exercised individually ; b) all the data lines are exercised individually ; ; Data and address lines are exercised as walking-0 and walking-1. ; The test is performed as a series of LDR operations to avoid using ; a larger instruction set. ; ts_RomPatt ROUT ; Patterns which will exercise most of the data bus. ; All are arbitrary instructions with NV execution DCD &F0000000 ; walking 1 OldOpt SETA {OPT} ; patterns OPT OptNoList dmask SETA &08000000 WHILE dmask > 0 DCD dmask :OR: &F0000000 dmask SETA dmask :SHR: 1 WEND DCD &FFFFFFFF ; walking 0 dmask SETA &08000000 WHILE dmask > 0 DCD (:NOT: dmask) :OR: &F0000000 dmask SETA dmask :SHR: 1 WEND OPT OldOpt ; Now some proper code : ; Initialise address pointer and make MemC safe LDR r0,%01 ADD pc,r0,pc 01 & 0 ; useful constant [ IO_Type = "IOC-A1" ;;!! unsafe if we execute ROM at zero LDR r1,%02 ADD pc,r0,pc 02 ;;!! This remaps MEMC's ROM & &E000C :OR: MEMCADR ;;!! addressing if it hasn't STR r1,[r1] ;;!! already happened. ] LDR r5,%03 ; Load r5 with a constant which ADD pc,r0,pc ; may be added to ROM plus a 03 ; walking-zero bitmask to create & ts_Rom_length - 3 ; a valid word address in ROM. LDR r2,%04 ; Offset from ROM start to here ADD pc,r0,pc 04 & ROM - pcfromstart ADD r2,pc,r2 ; pointer to start of ROM ADD r3,r2,r0 ; pointer to start of ROM pcfromstart ADD r4,r2,r0 ; pointer to start of ROM ; assembly-time loop - only 32 iterations required OldOpt SETA {OPT} GBLA doffset doffset SETA DataPatterns WHILE doffset < DEnd LDR r0,doffset ; walking 1 data pattern LDR r1,doffset+4 ; walking 0 data pattern LDR r6,[r2] ; walking 1 address pattern LDR r6,[r3] ; walking 0 address pattern [ (doffset - DataPatterns) > ((32 - ts_Rom_bits) * 8) [ (doffset - DataPatterns) < (31 * 8) ADD r2,r4,r0 ; r2 = ROM + walking 1 pattern ADD r3,r4,r1 ; r3 = ROM + walking 0 pattern ADD r3,r3,r5 ; adjust to a valid address ] ] OPT OptNoList doffset SETA doffset + 8 WEND ASSERT (. - doffset < 4095) ; in range without barrel shift ? OPT OldOpt ; ; External interface drivers - ; provides entry points to send byte- and word- and string-sized objects ; and to receive byte- and word-sized objects ; ; Continue into GetCommand, which determines adapter type (or no adapter) ; and jumps to an ExtCmd handler, ts_User_startup, ts_Forced_startup or ; ts_Dealer_startup as appropriate. ; B ts_GetCommand GET TestSrc.ExtIO ; ; External command handlers - respond to commands given through the ; external test interface. ; GET TestSrc.ExtCmd SUBT Selftest ; ; There is no attached test interface. Is this a power-on reset ? ; Addressing IOC will make MEMC1a remap the ROM to high memory if ; it hasn't already done it, so be careful to ensure that the ; ARM is addressing normally-addressed ROM when this code runs. ; ts_User_startup ROUT LDR r0,%01 ADD pc,r0,pc 01 & 0 ; ; IOMD will only access the ROM until a write to IOMD has been made - ; make this write also switch on refresh so the DRAM has a chance to ; get running before the memory test starts. ; [ MEMC_Type = "IOMD" LDR r1,%02 ADD pc,r0,pc 02 & (IOMD_Base+IOMD_VREFCR) LDR r2,%03 ADD pc,r0,pc 03 & IOMD_VREFCR_REF_16 STR r2, [r1,#0] ] [ POSTenabled LDR r1,%12 ; load address of IOC IRQ register ADD pc,r0,pc 12 & IOC+IOCIRQSTAA LDR r1, [r1,#0] ; Get IRQSTAA register (hence POR bit) LDR r2, %13 ADD pc,r0,pc ; Constant to shift por to bit 31 13 & por_bit :SHL: 1 14 ADD r1,r1,r1 ADDS r2,r2,r2 BCC %14 ; loop until por_bit is at bit 31 ADDS r1,r1,r1 ; then shift it into carry BCC ts_Self_test_end ; POR bit clear - do soft reset. ; it's a power-on reset, so assume we can't be in 32-bit mode for ARM 6/7 [ StrongARM_POST ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config) ; note that MOV_fiq macro assumes 26-bit, so must sort this now Ensure26bit_ARM8A r0 ] MOV_fiq r12_fiq, #R_HARD B ts_Self_test_startup | B CONT ; if user POST disabled ] ; ; Perform self - tests ; ; Any distinction between test operation for Power-up, Display-only ; and Forced tests needs to be made between these three entry points. ; ; This is where tests start if a dumb test link is fitted ; (a diode from A21 to *ROMCS, disabling the ROMs when A21 is high) ts_Forced_startup ROUT [ StrongARM_POST ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config) ; note that MOV_fiq macro assumes 26-bit, so must sort this now Ensure26bit_ARM8A r0 ] MOV_fiq r12_fiq, #R_TESTED B ts_Self_test_startup ; This is where the tests start if an external display adapter is fitted ts_Dealer_startup ROUT [ StrongARM_POST ; make sure we are in 26-bit mode (ARM 6/7 reset in 26-bit config) ; note that MOV_fiq macro assumes 26-bit, so must sort this now Ensure26bit_ARM8A r4 ] MOV_fiq r12_fiq, #R_EXTERN LDR r4,%FT02 ; make a pointer to signon string 01 ADD r4,pc,r4 ADD pc,r0,pc 02 & (ts_himsg - %BT01 - 8) ADD r14,pc,r0 ; make a return address for this 'call' ASSERT (.+4 = ts_Self_test_startup) ; PC must point there already ! B ts_SendText ts_Self_test_startup ROUT ; This is where the power-on test starts (every user gets this) ; ; Processor test would go here .... if there was one. ; [ MorrisSupport ; ; On startup Morris defaults to dividing all its clocks by two and ; accessing ROM at the slowest possible access speed. So check for ; Morris and set to sensible values. ; MOV r2, #IOMD_Base LDRB r0, [r2, #IOMD_ID0] CMP r0, #&E7 LDRB r0, [r2, #IOMD_ID1] CMPEQ r0, #&D4 BEQ %FT10 [ RO371Timings MOV r0, #0 ;Calling from POST BL TimeCPU ;just sets things according to assumed bus speeds for each IOMD id, in this case | ; else if not RO371Timings ; ; PSwindell wants all prescalers set to divide by 1 ; MOV r0, #IOMD_CLKCTL_CpuclkNormal + IOMD_CLKCTL_MemclkNormal + IOMD_CLKCTL_IOclkNormal STRB r0, [r2, #IOMD_CLKCTL] ; initialise all prescalers to div1 ; ; Set ROM speed, take care to preserve 16-bit mode bit... ; ; According to RJKing on 6/5/94, Kryten will use burst mode roms: use 93nS burst, 156nS initial. ; ; We assume that the extension ROMs are the same access time and width as the main OS ROMS. ; LDRB r1, [r2, #IOMD_ROMCR0] AND r1, r1, #&40 ; clear all but 16-bit mode bit [ :LNOT: AutoSpeedROMS [ NormalSpeedROMS ;Normal code ORR r1, r1, #IOMD_ROMCR_Normal + IOMD_ROMCR_156 + IOMD_ROMCR_Burst93 ; initialise ROM speed to 156.25nS, 93.75nS burst ; the fast EPROMS used for Kryten testing should be able to cope even though they aren't ; burst devices | ;Slow ROM access for PSwindells test EPROMS. Paul requested 156nS (or slower), burst off. ORR r1, r1, #IOMD_ROMCR_Normal + IOMD_ROMCR_187 + IOMD_ROMCR_BurstOff ! 0, "*** WARNING *** Slow ROM version ment for PSwindell" ] STRB r1, [r2, #IOMD_ROMCR0] STRB r1, [r2, #IOMD_ROMCR1] ; and do the same for extension ROMs (just in case) | MOV r0, #0 ;Don't muck with the CPU coprocessor regs BL TimeCPU ;This times the memory bus & sets the ROM speed accordingly ] ] ;RO371Timings conditional ; 10 ] ; ; From this point on we assume we can safely use all the processor ; ; Initialise VIDC : Sync mode 0, border covers screen ; ts_InitVIDC [ IO_Type = "IOMD" ; If POSTbox fitted, ROM may still be mapped everywhere MOV r2, #IOMD_Base MOV r0, #IOMD_VREFCR_REF_16 ; switch on DRAM refresh STR r0, [r2, #IOMD_VREFCR] ; choose monitor settings from ID bit 0 MOV r1,#ts_VIDCPhys ADRL r2,TestVIDCTAB LDR r0,=IOMD_MonitorType LDR r0,[r0] ANDS r0,r0,#IOMD_MonitorIDMask ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) | ; not IOMD MOV r1,#ts_VIDCPhys ADRL r2,TestVIDCTAB ] 10 LDR r0, [r2],#4 CMP r0, #-1 STRNE r0, [r1] BNE %BT10 [ :LNOT: StrongARM_POST ;skip POST for StrongARM or ARM8 ARM_read_ID r0 AND r0,r0,#&F000 CMP r0,#&A000 ;if we are a StrongARM... CMPNE r0,#&8000 ;or an ARM8... LDREQ r0,=C_WARMSTART ;the colour that indicates no POST performed STREQ r0,[r1] BEQ ts_Hardstart ;RISC OS - right now! ] [ ARM810support :LAND: (:LNOT: ARM810_POST) ;just too horrible to fix POST for ARM 8 at the moment ARM_read_ID r0 AND r0,r0,#&F000 CMP r0,#&8000 ;if we are an ARM 8 LDREQ r0,=C_WARMSTART ;the colour that indicates no POST performed STREQ r0,[r1] BEQ ts_Hardstart ;RISC OS - right now! ] LDR r0,=C_ARMOK ; set initial screen colour STR r0, [r1] B ts_RomTest LTORG ROUT ; ; Calculate ROM checksum : display status and calculated checksum. ; 1 = "ROM :",0 2 = "ROM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = "ROM size",&8A,&ff,&ff,&ff,&ff,&ff,&ff,0 ALIGN ts_RomTest ADR r4,%BT1 BL ts_SendText BL ts_ROM_checksum BEQ %20 ADR r4,%BT2 ; Failed message FAULT #R_ROMFAILBIT ; set ROM bit in r12_fiq MOV r8,r0 ; calculated checksum BL ts_SendText BL ts_ROM_alias ; Checksum failed :- ADR r4,%BT3 ; hunt for first alias MOV r8,r0, LSL #8 BL ts_SendText ; and report it. 20 [ IO_Type = "IOC-A1" ; Don't use RISC OS MemSize ; until much later - it sets up ; the ARM600 MMU as well. B ts_MEMCset ; ; Do MEMC setup and memory size determination (the first time). ; LTORG ROUT 1 = "M Size :",0 2 = "M Size",&89,&ff,&ff,&ff,&ff,".",&ff,&ff,0 ALIGN ts_MEMCset MOV r12,#0 ADR r4,%BT1 BL ts_SendText LDR r1,=(&E000C :OR: MEMCADR) ; MemSize expects 32k page STR r1,[r1] BL MemSize ; ; MemSize returns with r0 = page size (now in bytes, *NOT* in MEMC control patterns), ; r1 = memory size (in bytes) ; r2 = MEMC control value ; ; Translate these into a number that looks like : ; ; mmmm.pp ; ; where mmmm is memory size in hex Kbytes, pp is page size in hex Kbytes. ; MODE FIQ_mode ; Save memory size and MOV r11_fiq,r2 ; MEMC setup value for MOV r10_fiq,r1 ; later use MODE SVC_mode MOV r8, r0, LSR #2 ; MemSize now returns actual page size in r0 ADD r8,r8,r1,LSL #6 ADR r4,%BT2 BL ts_SendText ] ; ; Test data, address and byte strobe lines. ; On MEMC systems, this calls MemSize and tests the memory that finds. ; On IOMD systems, memory sizing is performed along with the data line ; tests, and that result is used for address line testing. ; B ts_LineTest GBLS tsGetMem1 tsGetMem1 SETS "GET TestSrc.Mem1" :CC: MEMC_Type $tsGetMem1 ; ; Test IOC. ; This shuld require vector space to work (for testing interrupts), ; but the current version just reports the status register contents. ; ; Display is ccaabbff ; ; where cc is the control register ; aa is IRQ status register A ; bb is IRQ status register B ; ff is FIQ status register ; B ts_IOCTest LTORG ROUT [ IO_Type = "IOMD" 1 = "IOMD :",0 2 = "IOMD-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = "IOMD-V" 4 = &88,&ff,&ff,&ff,&ff," V.",&ff,0 | 1 = "IOC :",0 2 = "IOC-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = "IOC" 4 = &88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ] ALIGN ts_IOCTest ADR r4,%BT1 BL ts_SendText BL ts_IOCreg ; check register integrity BEQ %FT8 ADR r4,%BT2 BL ts_SendText ; report if failure FAULT #R_IOCFAILBIT 8 ADR r4,%BT1 BL ts_SendText BL ts_IOCstat BEQ %FT10 ; fail message only printed if ADR r4,%BT3 ; ID code unrecognised BL ts_SendText FAULT #R_IOCFAILBIT ; .. and set error bit if IOMD code is wrong B %FT11 10 ADR r4,%BT4 ; print the status value BL ts_MoreText 11 [ IO_Type = "IOMD" B ts_CMOStest | B ts_IOEBtest ] LTORG ROUT ; ; Check for presence of IOEB ASIC ; [ IO_Type = "IOEB" 1 = "IOEB :",0 2 = "IOEB",&88,"exists",0 ALIGN ts_IOEBtest ADR r4,%BT1 BL ts_SendText LDR r0,=ts_IOEB_ID ; read an ID register in the IOEB ASIC LDRB r0, [r0] AND r0, r0, #&f CMPS r0, #ts_IOEB_ident ; if it looks right ( == 5) .. BNE %10 FAULT #R_IOEB ; set that bit in the result word ADR r4, %BT2 BL ts_SendText 10 B ts_CMOStest ] ; IOEB IO world ; ; Read CMOS ; Check the checksum, read the memory test flag. ; 1 = "SRAM :",0 2 = "SRAM-F",0 3 = "SRAM-C",&8e,&ff,&ff,0 ALIGN ts_CMOStest ADR r4,%BT1 BL ts_SendText [ ChecksumCMOS LDR r0,=(ts_BBRAM + &4000) MOV r1,#&C0 ; Get first RAM area MOV r2,#CMOSxseed BL ts_CMOSread BNE %20 MOV r2, r0 LDR r0,=(ts_BBRAM + &1000) ; Accumulate the second RAM area MOV r1,#&2F BL ts_CMOSread BNE %20 RSB r2, r0, #0 ; Subtract from the checksum byte LDR r0,=(ts_BBRAM + &3F00) MOV r1,#1 BL ts_CMOSread BNE %20 MOV r8, r0, LSL #24 ANDS r0, r0, #&FF ; A zero result ? MOV r1, #R_CHKFAILBIT ADR r4,%BT3 ; Report checksum failure BNE %21 ; failed .. report error ] ; end ChecksumCMOS LDR r0,=(ts_BBRAM + &FC00) ; Read Misc1CMOS byte MOV r1,#1 MOV r2,#0 BL ts_CMOSread BNE %20 ANDS r0,r0,#&80 ; Test the memory-test-disable bit BEQ %25 FAULT #R_MEMSKIP ; If set, skip the memory test B %25 20 MOV r1,#R_CMSFAILBIT ; Real fault - set the fault bit ADR r4,%BT2 ; Report fault accessing IIC ; (Bitmap & POST display) 21 FAULT r1 BL ts_SendText ; Report one fault or another 25 B ts_IOinit LTORG ROUT ; ; Initialize various machine registers - e.g, turn off the floppy ; drive, etc, etc. ; 1 = "IOinit:",0 ALIGN ts_IOinit ADR r4,%BT1 BL ts_SendText ADRL r2,ts_IOinitab 10 LDR r0,[r2],#4 ; Get address LDR r1,[r2],#4 ; Get initialization data CMPS r0,#(-1) STRNE r1,[r0] ; write to IO port BNE %10 B Speedset ; ; Use the RISC OS MEMC setup code to guess the proper processor / memory ; configuration. The memory speed can then be set up correctly for ; fastest possible working, and the memory array tested in the ; configuration RISC OS expects. ; ; Display the results of the TimeCPU test as : ; ; ssss.m.r ; ; where ssss is the processor speed in hex kHz, ; m is 0 for MEMC, 1 for MEMC1a ; r is the MEMC rom speed switch setting. ; ROUT 1 = "Speed :",0 2 = "Speed",&88,&ff,&ff,&ff,&ff,".",&ff,".",&ff,0 ALIGN Speedset ADR r4,%BT1 BL ts_SendText [ MEMC_Type = "IOMD" MOV r9,#0 | MOV_fiq r0, r11_fiq ; get MEMC setup MOV r9,r0 ; compare IOC and CPU clocks ] MOV r0, #0 ; Make sure TimeCPU doesn't fiddle with the cache BL TimeCPU MOV r0,r9 MOV_fiq r11_fiq,r0 MOV r8,r7,LSL #16 TST r7, #1 :SHL: 16 ; test bit 16 of r7 : ADDNE r8,r8,#&1000 ; MEMC1 / MEMC1a detected AND r9,r9,#&C0 ; get High ROM access bits ADD r8,r8,r9, LSL #2 ADR r4,%BT2 BL ts_SendText B RAMtest ; ; Long RAM test, ideally exercising all memory. ; In order to keep boot time short, the following scheme is used : ; ; Normal power-on boot - test VRAM and up to 4M of first DRAM entry ; CMOS disable set - test nothing ; Test hardware fitted - test entire memory ; ROUT 1 = "RAM :",0 2 = "RAM bad",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = &89,"skipped",0 4 = "RAM :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ALIGN RAMtest ADR r4,%BT1 BL ts_SendText ; ; if (R_MEMSKIP && R_HARD) ; skip all the remaining tests ; if (!R_LINFAILBIT) ; perform the long memory test ; MOV_fiq r0,r12_fiq ; skip this test if data line fault AND r1,r0,#(R_MEMSKIP :OR: R_HARD) ; or the user didn't want it TEQS r1,#(R_MEMSKIP :OR: R_HARD) ANDNE r1,r1,#R_LINFAILBIT TEQNE r1,#R_LINFAILBIT BNE %12 ADR r4,%BT3 ; skipping memory test .... BL ts_MoreText B ts_Report 12 LDR r1,=C_RAMTEST ; doing at least part of the long memory test LDR r0,=ts_VIDCPhys ; write the border colour STR r1,[r0] BL MemSize ; Set MMU up, mapping (some) RAM at logical address 0 ; Note that this returns with the MMU enabled, ; the ROM remapped to it's ORGed address, RSB r4,r4,#PhysROM ; and r4 the offset from physical to ORGed ROM addresses ADD r4,r4,#PhysSpace SetMode SVC32_mode,r0 ; Must do this, as PhysSpace is outside 26 bit addressing ADD pc,pc,r4 ; Jump into the ROM at its image in PhysSpace NOP ; this instruction skipped by pc adjustment ; ; Modify the PhysRamTable so only VRAM and the first ts_MaxRamTest of DRAM gets tested ; M32_fiq r0,r12_fiq,r1,r2 ; get the test condition flags ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) BNE %FT16 ; do full test if test adapter is present MOV r9,#PhysRamTable ADD r10,r9,#(PhysRamTableEnd-PhysRamTable) 14 LDR r1,[r9, #4] ADD r0,r0,r1 ; r0 = running sum of memory sizes SUBS r2,r0,#ts_MaxRamTest ; r2 = excess over ts_MaxRamTest SUBHI r1,r1,r2 ; r1 = current size truncated STRHI r1,[r9, #4] MOVHI r0,#ts_MaxRamTest ; truncate running sum to MaxRamTest ADD r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) CMPS r9,r10 BNE %BT14 16 FAULT32 #R_MEMORY,r0 ; memory tests were attempted MOV r9,#VideoPhysAddr LDR r8,[r9] ; report the test address ADRL r4,%BT4 BL ts_SendText LDR r0,[r9] ; get VRAM start address and size LDR r1,[r9,#4] ADD r0,r0,#PhysSpace BL ts_RamTest BNE %FT20 ; failed - abort ram testing ; ; VRAM (or 1st MB of DRAM, if no VRAM fitted) looks OK - move the translation ; table there so memory tests can proceed without smashing it. ; MOV r9,#PhysRamTable LDR r0,[r9,#VideoPhysAddr-PhysRamTable] ; get address of video RAM LDR r1,[r9,#DRAMPhysAddrA-PhysRamTable] ; get address of 1st DRAM bank LDR r3, =DRAMOffset_L2PT ADD r1, r1, r3 ; make r1 -> L2PT ADD r0, r0, r3 ; make r0 -> temporary L2PT BL ts_remap_ttab ; copy ttab at r1 to r0 and change table base ; ; Now run the RAM test at each DRAMPhysAddr until the end of the table or a zero entry ; is reached. Mark tested entries by setting the PhysSpace address, so a pointer to the ; next entry need not be kept. ; 18 MOV r9,#DRAMPhysAddrA ADD r10,r9,#(PhysRamTableEnd-DRAMPhysAddrA) 19 CMPS r9,r10 ; reached end of table ? LDRNE r0,[r9] TSTNE r0,r0 ; reached unused entries ? LDRNE r1,[r9,#4] ; or blanked-out entries ? TSTNE r1,r1 BEQ %FT21 ; .. all passed OK TSTS r0,#PhysSpace ADDNE r9,r9,#(DRAMPhysAddrB-DRAMPhysAddrA) BNE %BT19 ; this entry done .. find the next MOV r8,r0 ; report address of this block ADRL r4,%BT4 BL ts_SendText LDR r0,[r9] ; start testing it ADD r0,r0,#PhysSpace LDR r1,[r9, #4] STR r0,[r9] ; mark block so it isn't retested MOV r2,#PhysRamTable LDMIA r2,{r3-r14} ; save the PhysRamTable STMIA r0,{r3-r14} BL ts_RamTest LDMIA r13,{r1-r11,r14} ; restore the PhysRamTable MOV r13,#PhysRamTable STMIA r13,{r1-r11,r14} BEQ %BT18 ; if it passed, go look for another block 20 FAULT32 #R_MEMFAILBIT,r2 ; failed - report fault address ADRL r4,%BT2 MOV r11,r1 ; Save failed data MOV r8,r0 ; first failing address BL ts_SendText MOV r4,r12 ; get fault message MOV r8,r11 ; and fault data BL ts_SendText 21 [ MEMM_Type = "MEMC1" ; ; Test the CAMs - for each fitted MEMC, go through all the CAM entries ; remapping logical memory and testing against physical correspondence. ; Then try out the protection bits in each CAM entry and various ; processor modes. ; These tests return pointers to their own fault report strings. ; B ts_CAMtest ROUT 1 = "CAMs :",0 2 = "PPLs :",0 3 = &89,"skipped",0 ALIGN ts_CAMtest LDR r4,=%BT1 BL ts_SendText MOV_fiq r0,r12_fiq ; skip this test if memory fault MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) ANDS r0,r0,r1 BEQ %08 LDR r4,=%BT3 BL ts_MoreText B %20 08 BL ts_CAM BEQ %10 BL ts_SendText FAULT #R_CAMFAILBIT 10 LDR r4,=%BT2 BL ts_SendText MOV_fiq r0,r12_fiq ; skip this test if memory fault MOV r1,#(R_LINFAILBIT :OR: R_MEMFAILBIT) ANDS r0,r0,r1 BEQ %18 LDR r4,=%BT3 BL ts_MoreText B %20 18 BL ts_memc_prot BEQ %20 BL ts_SendText FAULT #R_PROFAILBIT 20 ] ; ; After testing memory and translation, turn MMU off again before running remainder ; of tests. This simplifies finishing up (where system must be put back into 26-bit ; mode before initialising RISCOS) if memory tests were deselected. ; Take care to poke the real translation table - it's been relocated to video ; RAM during the memory tests. ; ts_restore_physical [ StrongARM_POST ;make sure ARM810 cache or StrongARM data cache is cleaned/flushed, because we are going to remap ARM_read_ID r5 AND r5,r5,#&F000 CMP r5,#&8000 BNE %FT22 ;ARM810 ;;; ARM8_cleanflush_IDC r5 ;not implemented yet B %FT24 22 CMP r5,#&A000 BNE %FT24 ;StrongARM ;tricky...we'll read 16k of data in current ROM space, to act as clean and flush of current data MOV r3,pc BIC r3,r3,#31 ;32 byte aligned ARMA_clean_DC r3,r5,r7 24 ] ;StrongARM_POST MOV r5, pc ; obtain current address SUB r5, r5,#PhysSpace ; adjust to point to unmapped version MOV r5, r5, LSR #20 ; divide by 1MB MOV r7, r5, LSL #20 ; r7 = physical address of base of section ORR r7, r7, #(AP_None * L1_APMult) ORR r7, r7, #L1_Section MOV r3, #VideoPhysAddr ; find the copied translation table LDR r3, [r3] ADD r3, r3, #PhysSpace ADD r3, r3, #DRAMOffset_L1PT STR r7, [r3, r5, LSL #2] ; store replacement entry in L1 (not U,C or B) [ StrongARM_POST ;flush cache if ARM 6/7 (ARM 8,StrongARM already sorted, above) ;flush TLB(s) ARM_read_ID r4 AND r4,r4,#&F000 CMP r4,#&8000 ;ARM 8? CMPNE r4,#&A000 ;or StrongARM? MCRNE ARM_config_cp,0,R0,ARM67_cacheflush_reg,C0,0 ;flush 6/7 cache MCRNE ARM_config_cp,0,R0,ARM67_TLBflush_reg,C0,0 ;flush 6/7 TLB MCREQ ARM_config_cp,0,R0,ARM8A_TLB_reg,C7,0 ;flush 8/StrongARM TLB(s) | SetCop r7, CR_IDCFlush ; flush cache + TLB just in case SetCop r7, CR_TLBFlush ; (data written is irrelevant) ] ; The ROM should now be mapped at the present address less PhysSpace, which is where it ; would be if the MMU were turned off. MOV r4,#PhysSpace SUB pc,pc,r4 NOP ; this instruction is skipped ; now turn the MMU off, also ensures 26 bit mode, if ARM 6/7 (since P bit zero) MOV r7, #MMUC_D SetCop r7, CR_Control [ StrongARM_POST Ensure26bit_ARM8A r7 MOV r7, #MMUC_D ;avoid corrupting r7, just in case ] B ts_VIDCtest ; ; The VIDC tests check vertical blanking frequency in a fixed video ; mode and measure the time taken for sound DMA. ; ROUT 1 = "VIDC :",0 2 = "Virq bad",&88,' ',&ff,'.',&ff,&ff,&ff,&ff,&ff,0 3 = "Sirq bad",&8B,&ff,&ff,&ff,&ff,&ff,0 4 = &8A,"Mid0 ",&ff,0 ALIGN ts_VIDCtest ADR r4,%BT1 BL ts_SendText [ IO_Type = "IOMD" LDR r0,=IOMD_MonitorType ; Indicate monitor ID bit's value LDR r0,[r0] AND r0,r0,#IOMD_MonitorIDMask MOV r8,r0,LSL #28 ADR r4,%BT4 BL ts_MoreText ] [ MorrisSupport MOV r3, #IOMD_Base LDRB r0, [r3, #IOMD_ID0] CMP r0, #&E7 LDRB r0, [r3, #IOMD_ID1] CMPEQ r0, #&D4 ; skip Virq test on Morris BNE %FT10 ] BL ts_VIDC_period BEQ %10 ADR r4,%B2 MOV r8, r0, LSL #8 BL ts_SendText ; Display Virq fail msg FAULT #R_VIDFAILBIT 10 [ IO_Type = "IOMD" ; RCM thinks this is no longer needed - all IOMD's are issue two ; besides, the test takes no account of Morris reusing the number space! ; MOV r3,#IOMD_Base ; skip Sirq test on version 1 IOMD ; LDRB r0,[r3,#IOMD_VERSION] ; CMPS r0,#1 ; BEQ %FT20 ] BL ts_SIRQ_period BEQ %20 ADR r4,%B3 MOV r8, r0, LSL #12 BL ts_SendText ; Display Sirq fail msg FAULT #R_SNDFAILBIT 20 MOV r1,#ts_VIDCPhys ; Restore full-screen ADRL r2,TestVIDCTAB ; border colour. [ IO_Type = "IOMD" LDR r0,=IOMD_MonitorType LDR r0,[r0] ANDS r0,r0,#IOMD_MonitorIDMask ADDEQ r2,r2,#(TestVVIDCTAB-TestVIDCTAB) ] 30 LDR r0, [r2],#4 CMP r0, #-1 STRNE r0, [r1] BNE %BT30 LDR r0,=C_ARMOK ; set initial screen colour STR r0, [r1] B ts_ARMtype_test ; ; Read the ARM3 identification register. ; If memory tests failed, this won't be performed since the vector ; page must exist for error recovery on ARM2 systems. ; ROUT 1 = "ARM ID:",0 2 = "ARM ID",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = &89,"skipped",0 ALIGN ts_ARMtype_test ADR r4,%BT1 BL ts_SendText MOV_fiq r0,r12_fiq ; skip this test if memory fault LDR r1,=((R_LINFAILBIT :OR: R_MEMFAILBIT) :OR: (R_CAMFAILBIT :OR: R_PROFAILBIT)) ANDS r0,r0,r1 BEQ %05 ADR r4,%BT3 BL ts_MoreText B %08 ; and quit 05 BL ts_ARM_type MOVS r8, r0 ; ready to display ID code ADR r4,%BT2 BEQ %FT07 ; ARM 2 : skip cache test FAULT #R_ARM3 ; not really a fault, just status 07 BL ts_SendText 08 B ts_Report ; ; Report the test results to the user ; ; If this was a forced test (test adapter fitted) then pause even when ; test passed : otherwise, pause only on error. ; ts_passmsg = "PASS :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ts_failmsg = "FAIL :",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ts_R00 & 00 ts_Report ROUT MOV_fiq r7,r12_fiq ; check for fault bits set LDR r0,=R_STATUS BICS r0,r7,r0 ADREQ r4, ts_passmsg ; tests passed LDREQ r9,=C_PASSED ADRNE r4, ts_failmsg ; tests failed LDRNE r9,=C_FAULT LDR r0,=ts_VIDCPhys ; write the border colour STR r9,[r0] MOV r8,r7 BL ts_SendText ; write the message and fault code ; if the test adapter is present, leave green screen awhile ; otherwise, wait only if there's a fault. LDR r3,=ts_recover_time 00 ADDS r3,r3,r3 ; 16-loop delay BCC %B00 ; - let the adapter recover ; from previous bus activity ADR r2,ts_R00 ORR r2,r2,#ts_Alias_bits LDR r3,[r2] MOV r2,#-1 ADDS r3,r3,r2 BCS ts_Report_wait MOV_fiq r0,r12_fiq LDR r2,=R_STATUS BICS r0,r0,r2 BEQ ts_Hardstart ts_Report_wait ROUT ; ; Indicate fault found : Set the border to the fault colour and flash ; the disk LED, using the fault bitmap in r12_fiq to modulate the flashing. ts_oldLED_on * &be0000 ; assert SEL0 and INUSE ts_oldLED_off * &ff0000 ; on machines with 1772 controller ts_oldLEDaddr * (ts_S5_base :OR: &40) ts_710LED_on * &100000 ; assert SEL0 and MotorEN0 ts_710LED_off * &110000 ; on machines with 82C710 controller ts_710LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) ts_665LED_on * &10 ; assert SEL0 and MotorEN0 ts_665LED_off * &11 ; on machines with 37665 controller ; and Medusa low-byte I/O world ts_665LEDaddr * (ts_PCaddress :OR: (&3f2 :SHL: 2)) 01 MOV_fiq r6,r12_fiq LDR r2,=&11111111 LDR r7,=(35000 * 8) ; 1/4 second pause loop count [ IO_Type = "IOMD" LDRNE r1,=ts_665LEDaddr ; set up for Medusa disc address MOVNE r8,#ts_665LED_on MOVNE r9,#ts_665LED_off | TST r6, #R_IOEB ; determine original / 710 disc controller LDREQ r1,=ts_oldLEDaddr ; set up for Archimedes disc address MOVEQ r8,#ts_oldLED_on MOVEQ r9,#ts_oldLED_off LDRNE r1,=ts_710LEDaddr ; set up for Brisbane disc address MOVNE r8,#ts_710LED_on MOVNE r9,#ts_710LED_off ] 02 MOV r0,r7 03 SUBS r0,r0,#1 ; pause for a 1/4 second BNE %03 MOV r0,r8 ; turn the LED on STR r0,[r1] MOV r0,r7 04 SUBS r0,r0,#1 ; pause for a 1/4 second BNE %04 ADDS r6,r6,r6 ; if a '1' is to be written, BCC %06 MOV r0,r7,LSL #1 ; then pause another 1/2 second 05 SUBS r0,r0,#1 BNE %05 06 MOV r0, r9 ; turn the LED off STR r0,[r1] ; ; Count down 32 bits. Every 4 bits, insert an extra pause to simplify ; reading the flashes. ; ADDS r2,r2,r2 BCC %08 MOV r0,r7,LSL #2 ; then pause another second 05 SUBS r0,r0,#1 BNE %05 08 ANDS r2,r2,r2 ; all the bits displayed now ? BNE %02 MOV_fiq r0,r12_fiq ; restore the faultcode bits ANDS r0,r0,#(R_EXTERN :OR: R_TESTED) ; If test adapter present, BNE Reset ; repeat test forever B CONT ; otherwise, run RISC OS ts_Hardstart MOVS r0,#R_HARD ; and report a hard start B CONT ; to RISC OS ; ; Tests skipped : fall into RISC-OS ; ts_Self_test_end LDR r1,=C_WARMSTART LDR r0,=ts_VIDCPhys ; write the border colour STR r1,[r0] ts_Softstart MOVS r0,#R_SOFT ; soft reset indicator B CONT ROUT ; ; This table consists of a series of address/data pairs for IO ; initialization. ; Note that these addresses are likely to be in the IO world, ; and hence the data written is that from the MOST significant ; 16 bits of the data bus. ; An 'address' of -1 terminates the table. ; ts_IOinitab [ IO_Type = "IOMD" | & ts_S5_base :OR: &10, &000000 ; Printer port data & ts_S5_base :OR: &18, &000000 ; FDC control & printer strobes & ts_S5_base :OR: &40, &ff0000 ; FDD select lines & ts_S5_base :OR: &48, &000000 ; VIDC clock control ] & (-1) ; ; ;--------------------------------------------------------------------------- LTORG ; Include test modules executed by call, rather than inline GET TestSrc.Mem2 GET TestSrc.Mem3 GET TestSrc.Mem4 GET TestSrc.Mem5 GET TestSrc.Vidc GET TestSrc.Ioc GET TestSrc.Cmos GET TestSrc.Arm3 END