;> MEM2C
;
; RISC OS 2+ BOOT TEST SOFTWARE
; MEMORY TEST 2 VERSION A.
; BRIAN RICE 30-10-89
; 06-Apr-90     ArtG    0.1     Test variable memory size
;
; This file will perform a simple test on all DRAM.
; The test code for this test was taken from thhe A680 Quick memory
; test software. The software was copied straight but the number of times
; the test looped arround was cut down to two loops, because of time
; constraints when testing the memory.

Test_wks_msize      * &40               ; Space for test block size
Test_wks_return1    * &44 		; Space for return addresses
Test_wks_return2    * &48
Test_code_off       * &4C               ; Where testing starts

test_size           * 13 * 4            ; Size of test group
test_mem_rsvd       * Test_code_off+test_mem_template_end-test_mem_template

;
; Quick test the RAM (pre boot style)
;

ts_RamTest ROUT
	MOV	r13,r0
	STR	r14,[r13,#Test_wks_return1]
	STR	r1,[r13,#Test_wks_msize]

	LDR    r0, test_quick_pattern
	BL     test_mem_code
	ORRS   r0,r0,r0
	BNE    test_mem_quit
;
	LDR    r0, test_quick_pattern
	MVN    r0, r0		 ; inverse pattern
	BL     test_mem_code
	ORRS   r0,r0,r0

test_mem_quit
	ADR	r12,%22
	BEQ     %10

; If fault detected, exit with zero flag clear, r0 pointing to failing
; location, r1 containing faulty data and r2 pointing a suitable error
; message indicating whether all-0 or all-1 data was expected.

	LDR     r2,[r14]	        ; fetch failing instructiom
	ANDS    r2,r2,#1	        ; calculate expected data
	ADREQ   r12,%20	        	; and load suitable message
	ADRNE   r12,%21
	MOVS    r0,r0			; with zero flag set for PASS.
10
	LDR	pc,[r13,#Test_wks_return1]

; Fail messages indicate incorrect data read after WRote 0 or Wrote 1
; to all bits at that location.

20
	=       "WR-0 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
21
	=       "WR-1 RD",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0
22
	=	"??",0

	ALIGN

test_quick_pattern  & &0f76

; Large Memory test. Generates the write + test routines in memory
; then calls them. The routine tests patterns as defined by the bottom
; 13 bits of r0.
;
; N.B. The test start address must be calculated to ensure that
;      the loops finish exactly with r0 equal to End_memory
;
; The routine returns with eq true if the memory is OK.


test_mem_code
	ROUT

	STR	r14, [r13, #Test_wks_return2]
;
; Copy the ram test code into low ram, modifying MOV instructions
; to MVN in accordance with the test pattern.
;
	ADR    r1, test_mem_template
	ADD    r2, r13,        #Test_code_off
	LDMIA  r1!, {r3-r4}		; copy initial 2 instrucions
	STMIA  r2!, {r3-r4}
	MOV    r4, #1
0	MOVS   r0, r0,         ROR #1
	LDR    r3, [r1],       #4
	ORRCS  r3, r3,         #&00400000 ; Convert MOV => MVN
	STR     r3, [r2],      #4
	ADD     r4, r4,        #1
	CMP     r4, #13
	BLE     %B0
;
; Copy the load loop control and verify start instructions
;
	LDMIA   r1!, {r5-r9}
	STMIA   r2!, {r5-r9}
;
; Copy and modify the CMP instructions
;
	MOV     r0, r0,        ROR #32-13
	MOV     r4, #1
1	MOVS    r0, r0,        ROR #1
	LDR     r3, [r1],      #4
	ORRCS   r3, r3,        #&00200000 ; Convert CMP => cmn
	ORRCS   r3, r3,        #&00000001 ; Convert  #0 =>  #1
	STR     r3, [r2],      #4
	ADD     r4, r4,        #1
	CMP     r4,	  #13
	BLE     %B1
;
; Copy the verify loop control and finishing-up instructions
;
	LDMIA   r1!, {r5-r12}
	STMIA   r2!, {r5-r12}
	LDMIA   r1!, {r5-r12}
	STMIA   r2!, {r5-r12}
	LDMIA   r1!, {r5-r12}
	STMIA   r2!, {r5-r12}

; check we've copied enough
	ASSERT  ((test_mem_stadd - test_mem_chk) = (24 * 4))
;
; Calculate the test start and end addresses
;
	LDR	r0, [r13, #Test_wks_msize]	; size of test area
	ADD     r14, r13, r0			; end of test area
	SUB     r1, r0, #test_mem_rsvd		; testable size

	MOV     r2, #test_size		; adjust r1 to (r1 / 13*4) * (13*4)
	DivRem  r3, r1, r2, r4
	MUL     r1, r3, r2
	SUB     r0, r14, r1			; rounded test start address

; Do it.
	MOV     r1, #Test_code_off
	ADD     r1, r1, r13			; pointer to copied code
	MOV     pc, r1

;
; The following code is copied  (and modified) into RAM for execution
;

test_mem_template
	ROUT
	STR     r0, test_mem_stadd      ; save initial RAM address
	STR	r13, test_mem_base	; save test area base address
	MOV     r1, #0		; Converted to MVN if bit = 1
	MOV     r2, #0		; Converted to MVN if bit = 1
	MOV     r3, #0		; Converted to MVN if bit = 1
	MOV     r4, #0		; Converted to MVN if bit = 1
	MOV     r5, #0		; Converted to MVN if bit = 1
	MOV     r6, #0		; Converted to MVN if bit = 1
	MOV     r7, #0		; Converted to MVN if bit = 1
	MOV     r8, #0		; Converted to MVN if bit = 1
	MOV     r9, #0		; Converted to MVN if bit = 1
	MOV     r10, #0	         ; Converted to MVN if bit = 1
	MOV     r11, #0	         ; Converted to MVN if bit = 1
	MOV     r12, #0	         ; Converted to MVN if bit = 1
	MOV     r13, #0	         ; Converted to MVN if bit = 1
0
	STMIA   r0!, {r1-r13}
	CMP     r0, r14
	BLO     %B0

	LDR     r0, test_mem_stadd
1
	LDMIA   r0!, {r1-r13}
2
	CMP     r1, #0		; Converted to cmn   if bit = 1
	CMPEQ   r2, #0		; Converted to cmneq if bit = 1
	CMPEQ   r3, #0		; Converted to cmneq if bit = 1
	CMPEQ   r4, #0		; Converted to cmneq if bit = 1
	CMPEQ   r5, #0		; Converted to cmneq if bit = 1
	CMPEQ   r6, #0		; Converted to cmneq if bit = 1
	CMPEQ   r7, #0		; Converted to cmneq if bit = 1
	CMPEQ   r8, #0		; Converted to cmneq if bit = 1
	CMPEQ   r9, #0		; Converted to cmneq if bit = 1
	CMPEQ   r10, #0	        ; Converted to cmneq if bit = 1
	CMPEQ   r11, #0	        ; Converted to cmneq if bit = 1
	CMPEQ   r12, #0	        ; Converted to cmneq if bit = 1
	CMPEQ   r13, #0	        ; Converted to cmneq if bit = 1
test_mem_chk
	BNE     %F5		; go report fault data
	CMP     r0, r14
	BLO     %B1		; else loop for next batch
	MOVS    r0, #0		; All OK : return with NULL r0
4
	LDR	r13,test_mem_base
	LDR	pc, [r13, #Test_wks_return2]

; Failed : repeat the last batch of tests one at a time, to determine
; the first failing address and data.
; Note that the test instructions are copied to %8 to permit individual
; execution, and %7 is overwritten with an instruction used to copy
; the failing data into r1. Change this code very carefully !

5
	LDR     r14,%2			; Obtain first test in the set
	STR     r14,%8			; and re-execute it
	SUB     r0,r0,#(13*4)	   	; adjust pointer to bad data
	ADR     r14,%2			; point to first test.
7
	B       %8		    	; make sure %8 is refetched
8
	&       0		     	; redo the test here :
	BNE     %4		    	; if it failed, exit with
				    	; r0  =  ptr to memory
				    	; r1  =  wrongly read data
				    	; r14 => failing instruction

	LDR     r1,[r14,#4]!	    	;fetch next instruction
	AND     r1,r1,#&f0000		;make an instruction
	MOV     r1,r1,LSR #16		;to copy the next register
	ORR     r1,r1,#&E1000000	;down to r1
	ORR     r1,r1,#&00A00000	;e.g. CMPEQ r10,#0
	ORR     r1,r1,#&00001000
	STR     r1,%7		 	;and put it at %7
	LDR     r1,[r14]	        ;then copy the next test
	STR     r1,%8		 	;to %8
	ADD     r0,r0,#4	        ;bump the fault pointer
	B       %7		    	;and execute %7 and %8.

test_mem_stadd				; address of first test location
	&       0
test_mem_base
	&	0			; address of test block

test_mem_template_end

;
; Copy the L2 page table from r1 to r0, then remap the translation table's
; base address in the MMU to point to an L1 page table within it.
;
	ROUT

ts_remap_ttab

   [ StrongARM_POST
    ;make sure ARM810 cache or StrongARM data cache is cleaned/flushed, because we are going to remap
        ARM_read_ID r3
        AND     r3,r3,#&F000
        CMP     r3,#&8000
        BNE     %FT22
;ARM810
;;;        ARM8_cleanflush_IDC r3 ;not implemented yet
        B       %FT24
22
        CMP     r3,#&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,r4,r5
24
  ] ;StrongARM_POST

	MOV	r2,#FixedAreasL2Size
	ADD	r0,r0,r2		; point to locations in PhysSpace
	ADD	r0,r0,#PhysSpace
	ADD	r1,r1,r2
	ADD	r1,r1,#PhysSpace
10
	ASSERT	((FixedAreasL2Size :AND: ((8*4)-1)) = 0)
	LDMDB	r1!,{r3-r10}		; copy the page & section tables
	STMDB	r0!,{r3-r10}
	SUBS	r2,r2,#(8*4)
	BNE	%BT10

	SUB	r9,r1,r0		; r9 = offset from original to copy
        ADD     r0, r0, #DRAMOffset_L1PT-DRAMOffset_L2PT	; r0 -> copy of L1Phys
	SUB	r10, r0, #PhysSpace	; keep real address of L1PT for MMU
	ADD	r2,r0,#((1 :SHL: (32-20))*4)	; size of L1PT - 1 word per meg of memory
11	LDR	r3,[r0],#4		; check each L1 table entry
	ANDS	r4,r3,#3
	CMPS	r4,#L1_Page		; if it's page mapped ..
	SUBEQ	r3,r3,r9		; adjust the page table base address
	STREQ	r3,[r0,#-4]
	CMPS	r0,r2			; repeat for all the level 1 table
	BNE	%BT11

        SetCop  r10, CR_TTabBase	; set up MMU pointer to L1

  [ 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  r0, CR_IDCFlush		; flush cache + TLB just in case
        SetCop  r0, CR_TLBFlush		; (data written is irrelevant)
  ]

	MOV	pc,r14


 END