; > TestSrc.Mem1IOMD

        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
; ----          ----            -------
; 1-Jun-93      ArtG            Derived from Mem1 for use on Medusa
;
;
;------------------------------------------------------------------------

;
; Test the data and address and byte strobe lines for uniqueness.
;

        LTORG
        ROUT

1
        =       "VRAM  :",0
2
        =       "VRAM-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
3
        =       "DRAM ",&ff,":",0
4
        =       "Data  :",0
5
        =       &88,&ff,&ff," MByte",0

        ALIGN

ts_LineTest

        ADR     r4,%BT1
        BL      ts_SendText                             ; Start data line tests on VRAM

        MOV     r0,#0
        MOV_fiq r9,r0                                   ; r9-fiq records VRAM or low DRAM address

        MOV     r12, #IOMD_Base
        MOV     r2, #IOMD_VREFCR_VRAM_256Kx64 :OR: IOMD_VREFCR_REF_16 ; assume 2 banks of VRAM by default
        STRB    r2, [r12, #IOMD_VREFCR]

; Find the size, using MemSize's method

        MOV     r0, #VideoPhysRam                       ; point at VRAM
        ADD     r1, r0, #A2                             ; test A2
        BL      DistinctAddresses
        MOVEQ   r9, #2                                  ; we've got 2M of VRAM
        BEQ     %FT21

        MOV     r2, #IOMD_VREFCR_VRAM_256Kx32 :OR: IOMD_VREFCR_REF_16
        STRB    r2, [r12, #IOMD_VREFCR]
        ADD     r1, r0, #A2                             ; check for any VRAM at all
        BL      DistinctAddresses
        MOVEQ   r9, #1                                  ; we've got 1M of VRAM
        MOVNE   r9, #0                                  ; no VRAM
21
        BNE     %FT22
        MOV_fiq r9,r0                                   ; record VRAM address
        FAULT   #R_VRAM                                 ; indicate VRAM present

; Report size .. if this is non-zero and the data line test fails,
; RISC OS will have problems.

22
        ADR     r4,%BT5                                 ; Add size (in hex Mbyte)
        MOV     r8,r9, LSL #24                          ; to "VRam : " message
        BL      ts_MoreText     

; Worked out what size VRAM is, and set up IOMD register. 
; Do a data line test on the resulting array, repeated at oddword address to 
; ensure both banks get tested with walking 0 and walking 1

        ADR     r4,%BT4
        BL      ts_SendText
        MOV     r1, #VideoPhysRam
        BL      ts_Dataline
        ADDEQ   r1,r1,#4
        BLEQ    ts_Dataline
        BEQ     %FT25                   ; looks OK - carry on with VRAM test
;
; Data line test failed. Report the bitmap that failed, then carry on.
;
        ADR     r4,%BT2
        MOV     r8,r0                   ; report data fault mask
        BL      ts_SendText
        B       %FT30

;
; If there was some VRAM found here, and it passed the dataline test,
; do the address and bytestrobe tests on it too.
;

25
        ADRL    r4,%FT75                                ; announce start of address line test
        BL      ts_SendText
        MOV     r1,#VideoPhysRam
        MOV     r0,r9,LSL #20                           ; size in MB determined before dataline test
        BL      ts_Addrline
        BEQ     %FT26
        ADRL    r4,%FT76                                ; failed - report error mask
        MOV     r8,r0
        BL      ts_SendText
        FAULT   #R_LINFAILBIT                           ; and record failure
        B       %FT30
26
        ADRL    r4,%FT77                                ; announce start of byte test
        BL      ts_SendText
        MOV     r1,#VideoPhysRam
        BL      ts_Byteword
        ADDEQ   r1,r1,#4                                ; retest at an oddword boundary
        BLEQ    ts_Byteword
        BEQ     %FT27
        ADRL    r4,%FT78                                ; failed - report error mask
        MOV     r8,r0,LSL #16
        BL      ts_SendText
        FAULT   #R_LINFAILBIT                           ; and record failure
27


; Similarly, test each DRAM bank in turn, reporting failures or sizes for each

30
        MOV     r11, #IOMD_DRAMCR_DRAM_Large * &55      ; set all banks to be large initially
        MOV     r14, #IOMD_Base
        STRB    r11, [r14, #IOMD_DRAMCR]
        MOV     r0,#MMUC_D                              ; enable 32-bit addressing of data
        SetCop  r0,CR_Control

        MOV     r10, #0                                 ; indicate no RAM found yet
        MOV     r9, #IOMD_DRAMCR_DRAM_Small             ; bit to OR into DRAMCR
        MOV     r12, #DRAM0PhysRam
35
        MOV     r8,r12,LSL #2                           ; indicate bank under test
        AND     r8,r8,#(3 :SHL: 28)
        ADR     r4,%BT3
        BL      ts_SendText

        MOV     r8,#0                                   ; r8 indicates RAM found in this bank
        MOV     r0, r12
        ADD     r1, r12, #A10                           ; this should be OK for both configurations
        BL      DistinctAddresses
        BNE     %FT50                                   ; [no RAM in this bank at all]

        MOV_fiq r2,r9                                   ; if this is the first bank of DRAM or VRAM,
        TEQS    r2,#0                                   ; put it's address in r9_fiq
        BNE     %FT36
        MOV_fiq r9,r0

36      ADD     r1, r12, #A11                           ; test for 256K DRAM
        BL      DistinctAddresses
        ORRNE   r11, r11, r9                            ; it is, so select small multiplexing
        MOVNE   r14, #IOMD_Base
        STRNEB  r11, [r14, #IOMD_DRAMCR]                ; store new value of DRAMCR, so we can use memory immediately
        MOVNE   r8, #1024*1024                          ; must be 1Mbyte at this address
        BNE     %FT50

; it's bigger than 256K words, so test address lines A21-A25 in sequence
; we assume that the size of each bank is a power of 2

        MOV     r8, #A21                                ; now go through address lines A21-A25
40
        ADD     r1, r12, r8                             ; see if this address line is unique
        BL      DistinctAddresses
        BNE     %FT50                                   ; if we've failed then r8 is true size, so exit
        MOV     r8, r8, LSL #1                          ; else shift up to next
        TEQ     r8, #A26                                ; only test up to A25
        BNE     %BT40

50
        MOV     r13,r8                                  ; remember size of this bank in bytes
        MOV     r8,r13,LSL #(24 - 20)                   ; and display it in 2 digits, in MBytes.
        ADR     r4,%BT5
        BL      ts_MoreText

        ADRL    r4,%FT73                                ; announce data line test
        BL      ts_SendText
        MOV     r1,r12                                  ; do walking bit test
        BL      ts_Dataline
        BEQ     %FT55                                   ; looks OK, carry on to next bank

        ADRL    r4,%FT74                                ; bit test failed, so report it
        MOV     r8,r0
        BL      ts_SendText                             ; and bit fault mask

        CMPS    r13,#0                                  ; was any RAM thought to be here ?
        BEQ     %FT55
        FAULT   #R_LINFAILBIT                           ; if so, it's faulty.
        MOV     r13,#0                                  ; so ignore it
55

;
; If there was some RAM found here, and it passed the dataline test,
; do the address and bytestrobe tests on it too.
;
        CMPS    r13,#0
        BEQ     %FT60

        ADR     r4,%FT75                                ; announce start of address line test
        BL      ts_SendText
        MOV     r1,r12                                  ; test address lines in this block
        MOV     r0,r13
        BL      ts_Addrline
        BEQ     %FT56
        ADR     r4,%FT76                                ; failed - report error mask
        MOV     r8,r0
        BL      ts_SendText
        FAULT   #R_LINFAILBIT                           ; and record failure
        MOV     r13,#0                                  ; then forget this memory block

56
        ADR     r4,%FT77                                ; announce start of byte test
        BL      ts_SendText
        MOV     r1,r12
        BL      ts_Byteword
        BEQ     %FT60
        ADR     r4,%FT78                                ; failed - report error mask
        MOV     r8,r0,LSL #16
        BL      ts_SendText
        FAULT   #R_LINFAILBIT                           ; and record failure
        MOV     r13,#0                                  ; then forget this memory block
60


; If the RAM found still seems OK, add it's size into the r10 accumulator
; Working or not, carry on to check the next bank.

        ADD     r10,r10,r13                             ; accumulate DRAM if any found 
        ADD     r12, r12, #DRAM1PhysRam-DRAM0PhysRam    ; move onto next bank
        MOV     r9, r9, LSL #2                          ; shunt up position in DRAMCR
        CMP     r9, #&100                               ; if more banks to do
        BCC     %BT35                                   ; then loop

        ADR     r4,%FT70
        BL      ts_SendText                             ; None found .. print message

        MOVS    r8,r10,LSL #(24 - 20)                   ; all finished ..
        ADREQ   r4,%FT71                                ; did we find any DRAM?
        ADRNE   r4,%FT72
        BNE     %FT65
        FAULT   #R_LINFAILBIT                           ; fault if we didn't
65
        BL      ts_MoreText
        B       ts_endline


70
        =       "DRAM",0
71
        =       &88,"Failed",0
72
        =       &88,&ff,&ff," MByte",0
73
        =       "Data  :",0
74
        =       "Data-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
75
        =       "Addrs :",0
76
        =       "Addrs-F",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
77
        =       "Byte  :",0
78
        =       "Byte-F",&88,&ff,&ff,&ff,&ff,0


;
; Data line test.
;
; In  : 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 (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++;
;       return result and address
;

ts_Dataline     ROUT

;
; 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 
        MOV     pc,r14                  ; return r0 with error map (or 0)



;
; Address line test
;
; In  : r0  - size of memory block
;       r1  - start address of memory block
;
; 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,r1                ; (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,r1
        STR     r4,[r3]

        MOV     r5,#4                   ; initialize pattern
02
        MVN     r4,r5
        EOR     r3,r5,r1                ; 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,r1
        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  :  r1 - memory start
;
; Out :  r0 - Failure indication
;
; This test ensures that individual bytes may be written to each part of a word
; without affecting the other bytes in the word.
;
;       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;                       /* pass */
;

ts_Byteword     ROUT

        LDR     r3,=&AABBCCDD           ; word signature
        MOV     r0,#0
        MOV     r2,r0
;
; 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 (0, 1, 2 or 3)

        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]              ; read (probable) inverse data to precharge bus
        LDR     r4,[r1]                 ; read modified word
        CMPS    r4,r5
        MOV     r5,#1
        MOV     r4,r2,LSL #2
        ORRNE   r0,r0,r5,LSL r4         ; 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
        MOV     pc,r14                  ; Result : return address and fault mask.

;
; End of RAM line tests
;

ts_endline

        END