; > 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