; > TestSrc.Mem1 TTL RISC OS 2+ POST memory linetest ; ; This test code is used to perform basic integrity tests on DRAM. ; It doesn't test all locations - just walks patterns through data ; and address lines. ; ;------------------------------------------------------------------------ ; History ; ; Date Name Comment ; ---- ---- ------- ; 18-Dec-89 ArtG Initial version ; 1-Jun-93 ArtG Reorganised to allow separate module for Medusa ; ; ;------------------------------------------------------------------------ ; ; Test the data and address and byte strobe lines for uniqueness. ; LTORG ROUT 1 = "Data :",0 2 = "Data @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 3 = "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 4 = "Data-P",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ALIGN ts_LineTest ADR r4,%BT1 BL ts_SendText ; Start data line tests MOV_fiq r0,r10_fiq MOV r1, #PhysRam BL ts_Dataline BEQ ts_address ; OK : continue to next test ; ; Data line test failed. This probably also means that RISCOS got the ; configuration wrong, so set it to 32K pages and repeat - otherwise ; the data line test result may be garbage. ; ADR r4,%BT2 MOV r11,r0 ; save data & report fault address MOV r8,r1,LSL #4 BL ts_SendText MOV r8,r11 ADR r4,%BT3 ; report data fault mask BL ts_SendText LDR r0,=(&E000C :OR: MEMCADR) ; set 32K page size STR r0,[r0] MOV_fiq r11_fiq,r0 MOV r0,#ts_RamChunk ; limit test to 1 block MOV r1,#PhysRam BL ts_Dataline MOV r8,r0 ADR r4,%BT4 ; ready to report data fault mask B ts_linefault ; ; Start the address line tests ; ROUT 4 = "Addrs :",0 5 = "Addrs",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 6 = "Byte :",0 7 = "Byte",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ts_address ADR r4,%BT4 BL ts_SendText ; Start address line tests MOV_fiq r0,r10_fiq BL ts_Addrline ADR r4,%BT5 MOV r8,r0,LSL #4 BEQ %30 ; Failed : report address fault ts_linefault FAULT #R_LINFAILBIT B %31 30 ADR r4,%BT6 ; Start Byte/Word test BL ts_SendText MOV_fiq r0,r10_fiq ; get memory size BL ts_Byteword MOV r8,r0,LSL #4 ; Get result to top of r8 BEQ %40 FAULT #R_LINFAILBIT ADR r4,%BT7 31 BL ts_SendText B %42 ; ; Line tests passed. Do a short test on memory that isn't there, ; in case it's supposed to be and we want to know why it's not .. 40 MOV_fiq r0, r10_fiq ; if there's less than 16Mbytes .. CMP r0, #(16 * 1024 * 1024) BCS %F42 ADR r4, %FT44 ; briefly test the next bit of ram BL ts_SendText ; in case it's a duff expansion MOV_fiq r1,r10_fiq ADD r1,r1,#PhysRam MOV r0,#ts_RamChunk BL ts_Dataline ADR r4, %FT45 MOV r11, r0 ; report the result even if OK MOV r8,r1,LSL #4 BL ts_SendText ; report address MOV r8,r11 ADR r4,%FT46 ; report data fault mask BL ts_SendText ; ; End of line tests ; 42 B ts_IOCTest 44 = "Exp? :",0 45 = "Exp? @",&89,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 46 = "Exp?",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ; ; Data line test. ; ; In : r0 - size of memory ; r1 - start address for test ; ; Out : r0 - failing data pattern ; r1 - address of failure ; ; ; This exercises data lines in attempt to find shorts/opens. ; It goes something like : ; ; for (address = start; address < end of ram; address += ts_RamChunk) ; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) ; *ptr++ = pattern; ; *ptr++ = ~pattern; ; for (ptr = address, pattern = 1; pattern != 0; pattern <<= 1) ; result |= pattern ^ *ptr++; ; result |= ~pattern ^ *ptr++; ; if (result |= 0) ; return result and address ; ts_Dataline ROUT ADD r7,r1,r0 ; end address ; ; Write all walking-zero, walking-one patterns ; 10 MOV r6,r1 ; set pointer for a write loop MOV r5,#1 ; set initial test pattern MVN r4,r5 ; and it's inverse 11 STMIA r6!,{r4-r5} ; write the patterns ADDS r5,r5,r5 ; shift the pattern (into Carry) MVN r4,r5 BCC %BT11 ; repeat until all bits done ; ; Read back and accumulate in r0 any incorrect bits ; MOV r6,r1 ; set pointer for a read loop MOV r5,#1 ; set initial test pattern MVN r4,r5 ; and it's inverse MOV r0,#0 ; accumulate result 21 LDMIA r6!,{r2-r3} ; read the patterns EOR r2,r2,r4 ORR r0,r0,r2 ; OR any failed bits into r0 EOR r3,r3,r5 ORR r0,r0,r2 ADDS r5,r5,r5 ; shift the pattern (into Carry) MVN r4,r5 BCC %BT21 ; repeat until all bits done ; ; After all checks at this address group, report back errors ; MOVS r0,r0 ; check for any result bits set MOVNE pc,r14 ; return on error ; ; Bump to another address group ; ADD r1,r1,#ts_RamChunk CMPS r1,r7 ; test for loop end BLO %10 SUBS r1,r1,#ts_RamChunk ; no fault - last tested address MOVS r0,r0 MOV pc,r14 ; test complete - no failures. ; ; Address line test ; ; In : r0 - size of memeory ; ; Out : r0 - failing address bit mask ; ; This exercises address lines in an attempt to find any which don't ; work (i.e., don't select unique addresses). ; ; It works something like : ; ; MaxRam = PhysRam | (Memory size - 4); ; for (pattern = 4; pattern < memsize; pattern <<= 1 ) ; *(PhysRam ^ pattern) = pattern; ; *(MaxRam ^ pattern) = ~pattern; ; for (pattern = 4; pattern < memsize; pattern <<= 1 ) ; if (*PhysRam == *(PhysRam ^ pattern)) ; result |= pattern; ; if (*MaxRam == *(MaxRam + pattern)) ; result |= pattern; ; return result ; ts_Addrline ROUT MOVS r7,r0 ; Save memory size SUB r6,r0,#4 ; Calculate MaxRam ADD r6,r6,#PhysRam ; (all-bits-set memory address) ; ; Mark (walking one, walking 0) addresses with unique patterns ; LDR r5,=&5A5AA5A5 ; initialize end markers STR r5,[r6] MVN r4,r5 MOV r3,#PhysRam STR r4,[r3] MOV r5,#4 ; initialize pattern 02 MVN r4,r5 EOR r3,r5,#PhysRam ; point to (start ^ pattern) STR r4,[r3] EOR r3,r5,r6 ; point to (end ^ pattern) STR r5,[r3] MOV r5,r5,LSL #1 ; shift test pattern up CMPS r5,r7 ; test bit still inside memory ? BCC %02 ; reached top bit - end this loop ; ; Check (walking one, walking 0) addresses for effectivity ; MOV r5,#4 ; initialize pattern MOV r3,#PhysRam MOV r0,#0 04 MVN r4,r5 EOR r2,r5,r3 ; point to (start ^ pattern) LDR r2,[r2] LDR r1,[r3] CMPS r1,r2 ; do contents differ ? ORREQ r0,r0,r5 ; no - record ineffective bit EOR r2,r5,r6 ; point to (end ^ pattern) LDR r2,[r2] LDR r1,[r6] CMPS r1,r2 ; do contents differ ? ORREQ r0,r0,r5 ; no - record ineffective bit MOV r5,r5,LSL #1 ; shift test pattern up CMPS r5,r7 ; test bit still inside memory ? BCC %04 ; reached top bit - end this loop MOVS r0,r0 ; any result bits set - return error MOV pc,r14 ; ; Byte / word test ; ; In : r0 - memory size ; ; Out : r0 - address of physical ram where failure occured ; ; This test ensures (for each of four possible MEMCs fitted) ; that individual bytes may be written to each part of a word ; without affecting the other bytes in the word. ; ; for (address = PhysRam; address < PhysRam + Memsize; address += 4Mbyte) ; for (byte = 0; byte < 4; byte ++) ; address[0] = word_signature ; address[1] = ~word_signature ; address + byte = byte_signature ; if (address[0] != ; (word_signature & (~ff << byte * 8)) ; | (byte_signature << byte * 8) ) ; result |= (1 << byte) ; if (result != 0 ; result |= address; /* fail at address, byte(s) */ ; return result; ; return result; /* pass */ ; ts_Byteword ROUT ADD r7,r0,#PhysRam ; Set test limit address MOV r1,#PhysRam ; Initial test address LDR r3,=&AABBCCDD ; word signature ; ; MEMC test loop (for addresses 4M, 8M, ...) ; 01 MOV r0,#0 ; clear result register MOV r2,#0 ; clear byte count ; ; byte test loop ( for bytes 0 to 4 ...) ; 02 MVN r4,r3 STMIA r1,{r3,r4} ; write word signature STRB r2,[r1,r2] ; write byte MOV r4,r2,LSL #3 ; calculate expected result MOV r5,#&ff MVN r5,r5,LSL r4 AND r5,r5,r3 ; word signature, byte removed ORR r5,r5,r2,LSL r4 ; byte signature inserted LDR r4,[r1,#4] LDR r4,[r1] ; read modified word CMPS r4,r5 MOV r5,#1 ORRNE r0,r0,r5,LSL r2 ; fault : set bit in result mask ; ; Loop for next byte ; ADD r2,r2,#1 ; Bump byte counter CMPS r2,#4 ; ... until 4 byte strobes tested BLO %BT02 ; ; byte strobes all tested : check for errors ; CMPS r0,#0 ORRNE r0,r0,r1 MOVNE pc,r14 ; Error : return address and fault. ; ; Loop for next MEMC ; ADD r1,r1,#&400000 ; Bump to next MEMC CMPS r1,r7 BLO %01 MOVS r0,#0 ; Passed - return OK MOV pc,r14 END