; > 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
; 18-Nov-94     RCM             Morris changes
; 24-Jun-96	BAR		Change the IOMD ID code checking code,
;				instead of checking for ARM7500 and skipping
;				ARM7500 specifi code if not equal, not
;				checks for original (RriscPC) IOM ID code
;				and skip if equal, thus ARM7500 and
;				ARM7500FE parts still do correct test.
; 08-Jul-96     BAR             Ensure r0 is cleared before checking IOMD vsn no.
;
;------------------------------------------------------------------------

;
; 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
 [ MorrisSupport
        MOV     r12, #IOMD_Base
        MOV     r0,#0                   ; Clear out r0
        LDRB    r1,[r12,#IOMD_ID1]	; load r1 with IOMD ID high byte
        ORR     r0,r0,r1, LSL #8	; Or r0 and r1 - shifted left 8, put in r0
        LDRB    r1,[r12,#IOMD_ID0]	; load r1 with IOMD ID low byte
        ORR     r0,r0,r1		; Or r0 and r1, put in r0
        LDR     r1,=ts_IOMD_ID1		; get Ref IOMD ID code #1 (Original)
        CMPS    r0,r1                   ; check for IOMD ID Code #1
	BEQ	ts_LineTestIOMD         ; Original IOMD, not 7500 or 7500FE, assume RiscPC hardware
;
; Here bceause its an ARM7500 or ARM7500 'FE' variant : Morris H/W
;
        MOV     r11, #IOMD_DRAMWID_DRAM_32bit * &0F     ;set all 4 banks to be 32bit initially
 	LDR	r1, =ts_IOMD_ID3
	TEQ	r0, r1					; are we on FE part?
	ORREQ	r11, r11, #IOMD_DRAMWID_EDO_Enable :OR: IOMD_DRAMWID_RASCAS_3 :OR: IOMD_DRAMWID_RASPre_4
							; if so, then enable EDO and slower RASCAS and RASPre times

; ts_LineTest for Morris
;
        MOV     r14, #IOMD_Base
        STRB    r11, [r14, #IOMD_DRAMWID]

; enable 32-bit addressing of data, also forces 26 bit mode, if ARM 6/7 (since P bit zero)
        MOV     r0,#MMUC_D
        SetCop  r0,CR_Control

  [ StrongARM_POST
        Ensure26bit_ARM8A r0
  ]

        MOV     r0,#0
        MOV_fiq r9,r0                                   ; r9-fiq records low DRAM address for use elsewhere

        MOV     r10, #0                                 ;indicate no RAM found yet
        MOV     r9, #IOMD_DRAMWID_DRAM_16bit            ;bit to OR into DRAMWID to set 16bit
        MOV     r12, #DRAM0PhysRam
;
; r12    DRAM address
; r9    IOMD_DRAMWID_DRAM_16bit for current DRAM bank
; r11   current IOMD_DRAMWID register contents
;
;ExamineDRAMBank                                        ;examine first/next DRAM bank
2005
;
        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

        LDMIA   r12, {r1, r2}                            ;Preserve the two locations that we widdle on

        ADRL    r3, funnypatterns                       ;We write different values to two locations
        LDMIA   r3, {r3, r4}                            ; incase bus capacitance holds our value
        STMIA   r12, {r3, r4}
        LDMIA   r12, {r5, r6}                            ;Reread test locations
        EORS    r5, r5, r3                              ;Both locations should read correctly
        EOR     r6, r6, r4                              ; if memory is 32bits wide
       ;TEQ     r5, #0
        TEQEQ   r6, #0
        BEQ     %FT2010                                   ;32bit wide memory

        TST     r5, #&00FF                              ;If the bottom 16bits of each location
        TSTEQ   r5, #&FF00                              ; are correct, the memory is 16bits wide
        TSTEQ   r6, #&00FF
        TSTEQ   r6, #&FF00
        BNE     %FT2050                                 ;No memory in this bank

        ORR     r11, r11, r9                            ;Bank is 16bits wide
2010
        STMIA   r12, {r1, r2}                            ;Restore the two locations we widdled on
                                                        ;Must do BEFORE poking the DRAMWID register
        MOV     r14, #IOMD_Base                         ;
        STRB    r11, [r14, #IOMD_DRAMWID]               ;
;
; minimum ram test
;
        MOV     r0, r12
        ADD     r1, r12, #A18
        BL      DistinctAddresses
        BNE     %FT2050                                 ;Less than 512KBytes, so ignore this bank

        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     %FT2012
        MOV_fiq r9,r0
2012


        MOV     r6, #0                                  ;Fragment address
        MOV     r7, #0                                  ;Fragment address
        MOV     r8, #A19                                ; now go through address lines A19-A25
2015
        MOV     r0, r12
        ADD     r1, r12, r8                              ; see if this address line is unique
        BL      DistinctAddresses
        BNE     %FT2020                                   ; 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     %BT2015
        BEQ     %FT2035                           ;Bank fully occupied, DON'T test for higher fragments
2020
;
; Found some DRAM, at address r0, size r8.
; There may be one or two higher address lines connected, so scan upto A25 looking for
; extra DRAM chunks.
;
        MOV     r1, r8
2025
        TEQ     r1, #A25
        BEQ     %FT2035                           ;No higher active address lines found ie one lump of DRAM
        ADD     r1, r0, r1,LSL #1
        BL      DistinctAddresses
        SUB     r1, r1, r0                              ;Recover bit value
        BNE     %BT2025
;
; Got a 2nd fragment, at address r1 (also of size r8)
;
        MOV     r6, r1
2030
        TEQ     r1, #A25
        BEQ     %FT2035                           ;No higher active address lines found ie two lumps of DRAM
        ADD     r1, r0, r1,LSL #1
        BL      DistinctAddresses
        SUB     r1, r1, r0                              ;Recover bit value
        BNE     %BT2030
;
; Got another active address line (ie total four fragments)
;
        MOV     r7, r1
;
2035
;
; Found 1, 2 or 4 lumps of DRAM
;
;NoRamInBank
2050
        MOV     r13, r8
        TEQ     r6, #0
        MOVNE   r13, r13, LSL #1
        TEQNE   r7, #0
        MOVNE   r13, r13, LSL #1                        ; 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     %FT2055                                 ; 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     %FT2055
        FAULT   #R_LINFAILBIT                           ; if so, it's faulty.
        MOV     r13,#0                                  ; so ignore it
2055
2055
;
; 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     %FT2060

        ADRL    r4,%FT75                                ; announce start of address line test
        BL      ts_SendText
        MOV     r1,r12                                  ; test address lines in this block
        MOV     r0,r13, LSR #2                          ; bank may be in 4 fragments
        BL      ts_Addrline
        BEQ     %FT2056
        ADRL    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

2056
        ADR     r4,%FT77                                ; announce start of byte test
        BL      ts_SendText
        MOV     r1,r12
        BL      ts_Byteword
        BEQ     %FT2060
        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
2060


; 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 #1                          ; shunt up position in DRAMWID
        CMP     r9, #&0010                              ; if more banks to do
        BLT     %BT2005                                 ; then loop

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

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


 ]

ts_LineTestIOMD
        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]

; enable 32-bit addressing of data, also forces 26 bit mode, if ARM 6/7 (since P bit zero)
        MOV     r0,#MMUC_D
        SetCop  r0,CR_Control

  [ StrongARM_POST
        Ensure26bit_ARM8A r10
  ]

        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)
        ADRL    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.
        ADRL    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