;> MEM4H_SCR ; ; RISC OS 2+ BOOT TEST SOFTWARE. ; MEMORY TEST 4 VERSION H. BRIAN RICE 12-01-90. ; 04-Apr-90 ArtG 0.1 Added ts_count_cams, improved reporting ; 11-Apr-90 ArtG 0.2 Use RISC OS routine BangCams for ; alternate MEMC configurations. ; 17-Apr-90 ArtG 0.3 rationalise page-counting code ; ; This file will be called by MEM6x_SCR for the purposes of assembly. ; This file will perform quick walking bit test on the CAM Entry points. ; The test code for this test was taken from the A680 test code. ; ; The module requires the running of the memory sizing routine used by ; the OS to set up the page size for this module. ; ; This test module was designed to operate on all current and future ; machines. The module is designed to handle up to 512 physical pages ; which is the maximum number of pages in a 16 MByte FOX. ; ; A 16 MB FOX has 4 MEMCs in use, each MEMC is addressed by Bits 7 and ; 12 of the logical to physical address translator. The use of bit 12 ; does have a problem in that on machines with 0.5MB of memory this is ; used to define the logical page number. Machine with 1MB or greater bit ; 12 is not used, therefore this test may hit problems on A305's. The ; intention is that A305 owners will upgrade to A310's when upgrading to ; RISC OS 2+. ; ; Because FOX can have up to 4 MEMCs fitted the following addressing is ; used to determine the MEMC accessed, bit 12, bit 7 ; 0 0 = Master MEMC = MEMC 0 ; 0 1 = Slave MEMC 1 = MEMC 1 ; 1 0 = Slave MEMC 2 = MEMC 2 ; 1 1 = Slave MEMC 3 = MEMC 3 ; ; ; This test will initialise the CAM entries for up to 512 physical pages. ; The physical pages will be mapped to logical page 5. Each page will have ; a copy of test routine vectors and a page marker. The page marker consists ; of the page number and a code to indicate which MEMC was used. The code for ; the MEMC used is as follows :- MEMC 0 0001 1110 = &1E ; MEMC 1 0010 1101 = &2D ; MEMC 2 0100 1011 = &4B ; MEMC 3 1000 0111 = &87 ; ; The page marker is arranged as follows &mm5Apppp ; | | ; | \-- Page Number &0000 ‰ &01FF. ; \--------MEMC Code as above. ; ; The patterns are chosen so that if two or more MEMCs are accessed ; together and both RAM outputs get enabled onto the data bus simultaneously, ; then there is a reasonable chance that the data returned will show the ; presence of a fault. ; ; When the CAM entries have been initialised the module will then check that ; all the pages are mapped correctly. A simple walking one pattern is used ; to check that the page is not present anywhere else in the memory area. ; This isn't really sufficient, but keeps the test time low. ; ; The tests are performed with the memory protection level set to 0. ; ; This version uses the "my abort" routine in MEM5x_SCR instead of the ; ts_dab_exp0 .. 5 method as taken from the A680 code. ; ts_rst_msg = "RST",0 ts_uni_msg = "UDF",0 ts_swi_msg = "SWI",0 ts_pab_msg = "PAB",0 ts_dab_msg = "DAB",0 ts_aex_msg = "ADX",0 ts_irq_msg = "IRQ",0 ts_fiq_msg = "FIQ",0 ts_bxc_msg = &85,"@",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ALIGN ts_rst ; Unused exception vectors ADR r4, ts_rst_msg B ts_bad_exception ts_uni ADR r4, ts_uni_msg B ts_bad_exception ts_swi ADR r4, ts_swi_msg B ts_bad_exception ts_pab ADR r4, ts_pab_msg B ts_bad_exception ts_dab_unexp ADR r4, ts_dab_msg B ts_bad_exception ts_aex ADR r4, ts_aex_msg B ts_bad_exception ts_irq ADR r4, ts_irq_msg B ts_bad_exception ts_fiq ADR r4, ts_fiq_msg B ts_bad_exception ts_bad_exception SUBS r8, r14, #8 ; remember aborted instruction BL ts_SendText ADR r4, ts_bxc_msg ; display aborted address BL ts_MoreText B Reset ; ts_rom_base * ROM ; Base address of the OS ROMS. ts_phys_mem * (32*1024*1024) ; Physical Memory area. ts_pagemark * &005A0000 ; + phys page number + MEMC code. ts_pmark_pos * 32 ; Position of page mark (avoiding vectors). ts_cam_base * &3800000 ; Base address of the CAM table in MEMC. ts_vrest * &5 ; Unused page which all pages are mapped to. ts_MAX_CAMS * 512 ; Most CAMs ever expected ts_memc_codes = &1E, &2D, &4B, &87 ; List of the memc_codes to be used. ; ts_logpages ; List of Logical pages. & &0001 & &0002 & &0004 & &0008 & &0010 & &0020 & &0040 & &0080 & &0100 & &0200 & &03FF & &03FE & &03FD & &03FB & &03F7 & &03EF & &03DF & &03BF & &037F & &02FF & &01FF & &0000 ; Terminator for the list. ts_logpagesend ; End of the list. ; ; ; Exception vectors : copied to start of each page to ensure that they will always ; exist on page zero when arbitrary pages are mapped there. ; ts_vectors B (ts_vectors-ts_start)+ts_rom_base+ts_rst B (ts_vectors-ts_start)+ts_rom_base+ts_uni B (ts_vectors-ts_start)+ts_rom_base+ts_swi B (ts_vectors-ts_start)+ts_rom_base+ts_pab ts_dab_vector B (ts_vectors-ts_start)+ts_rom_base+ts_dab B (ts_vectors-ts_start)+ts_rom_base+ts_aex B (ts_vectors-ts_start)+ts_rom_base+ts_irq B (ts_vectors-ts_start)+ts_rom_base+ts_fiq ; *************************************************************************** ; ts_CAM ; ; CAM test (full or partial) ; Start of the CAM test, all physical pages have a copy of the vectors ; so they may be mapped as page 0. Then each page is mapped at a series ; of (walking 1, walking 0) logical pages and tested to be correctly ; mapped. Other pages are set to an unused logical page by set_cam_idle ; to prevent any CAM clashes. ; ; Copy the test vectors and page marker into all the pages. ; ROUT ; Local Branches. MOV r13, lr ; Preserve link register in r13. BL ts_count_CAMs ; get log2 pagesize MOV r0, #ts_MAX_CAMS ; r0 = last page to test SUB r0, r0, #1 0 BL ts_copy_vectors ; Gosub ts_vectors. SUBS r0, r0, #&01 ; bump down to next page BGE %B0 ; repeatuntil all pages set. ; ; 'C' pseudocode for the test routine. ; ; for (i = &1ff; i >= 0; i--) ; set_cam_idle(i); ; ; find maximum page number. ; if (max_page != ts_count_CAMS) ; report CAM number error ; ; for (phys = &max_page; phys >= 0; phys--) { ; for (logp = &logpages[0]; logp < &logpages[sizof(logpages)]; logp++) { ; if (*logp == 0) { ; set_cam(*logp, phys); ; check_mapped(*logp, phys); ; } else { ; int zphys = (phys + 1) % num_pages; ; set_cam(0, zphys); ; set_cam(*logp, phys); ; check_mapped(*logp, phys); ; set_cam_idle(zphys); ; } ; } ; set_cam_idle(phys); ; } ; ; Idle the pages. ; ROUT ; Local Branches. MOV r12, #ts_MAX_CAMS ; always clear all 512 - just in case 4 MEMCs. SUB r12, r12, #&01 ; Subtract 1 to make max page #. 0 MOV r1, r12 ; r1 = page number. BL ts_set_cam_idle SUBS r12, r12, #&01 ; bump to next page downwards BGE %B0 ; repeatuntil page 0 done ; ; We need to find out what the maximum number of pages is, after running the above routine ; all the pages will have the pagemark programed in to each page. As stated in the intro ; programing the pages from the top down will ensure that, irrespective of the number of ; MEMCs available, that the bottom pages are programed correctly. Therefore if we start ; at the top, read in a page, check it's page number & memc code are correct, if so then ; that is possibly the maximum page number. If not then subtract 1 from the page number and ; try again until a possible good page is found. ; ROUT ; Local Branches. BL ts_count_CAMs ; get log2 pagesize to r1 MOV r8, #ts_MAX_CAMS ; r8= max. number of physical pages. 0 SUBS r8, r8, #&01 ; Subtract 1 to make it r8 - 1 Pages. BEQ ts_bad_CAM_count ; no pages ? - shouldn't hit this! ; ; Calculate the expected page marker, in r4, for the current page, in r8. ; ADR r4, ts_memc_codes ; r4 = address of table with the memc codes. LDRB r4, [r4, r8, LSR#7] ; r4 = Loc pointed to by r4 + (r1 >> 7). ORR r4, r8, r4, LSL #24 ; r4 = page number OR (MEMC code << 24). ORR r4, r4, #ts_pagemark ; r4 = page id OR magic number ; ; The calculated page marker is now in r4, ref_p_mark. ; Current page in r8 - convert to physical address in r9. ; the pagesize power-of-2 is in r1 (from ts_count_CAMs) ; MOV r9, r8, LSL r1 ; convert PPN to phys offset ORR r9, r9, #ts_phys_mem ; add offset to start of phys mem ; ; r9 now has the address of the current page - read the page marker for that page. ; LDR r9, [r9, #ts_pmark_pos] ; r9 = contents of loc pointed to by ; r9 + ts_pmark_pos. ; ; Check that read_p_mark is valid. ; ; Either the value read is the expected pagemark, junk (no memory) or an ; aliased pagemark - if it's aliased, then either the memory or the MEMC ; isn't decoded that far. ; Bump down and try a bit lower, until it's OK. ; CMP r4, r9 ; Is page-mark expected value ? BNE %B0 ; ; Found a pagemarker in the proper place. Check that the number of pages that ; appear to be present are the same as the number found by ts_count_CAMs ; (i.e. the memory size / page size). ; SUB r0, r0, #1 ; convert count -> max page number CMPS r0, r8 BNE ts_bad_CAM_count ; ; If all is well, we should have the maximum usable page number in r8. ; ; Need to reset page 0 in the CAM entries, currently all pages are mapped to page 5. ; We need to have logical page 0 mapped to physical page 0. ; MOV r0, #&00 ; r0 = &00, the page to map. MOV r1, #&00 ; r1 = &00, the page to map to. MOV r2, #&00 ; r2 = &00, set the protection level. BL ts_set_camp ; ; Check we can still see the data abort vector at physical page zero ; - no good continuing if we can't. ; MOV r0, #ts_phys_mem LDR r0, [r0, #(ts_dab_vector - ts_vectors)] LDR r1, ts_dab_vector CMPS r0, r1 BNE ts_bad_dab_vector ; ; Now lets get on with the testing. ; 2 ADRL r10, ts_logpages ; logp = &logpages[0] 3 LDR r0, [r10] ; r0 = page to test CMP r0, #&00 ; last entry ? BNE %F4 MOV r1, r8 ; r1 = r8, page under test BL ts_set_cam ; Gosub ts_set_cam. LDR r0, [r10] ; r0 current logical test page MOV r1, r8 ; r1 = current test page BL ts_check_mapped ; Gosub ts_check_mapped. B %F5 4 ADD r12, r8, #&01 BL ts_count_CAMs ; get total number of pages SUB r0,r0,#1 ; make a mask for useable page AND r0,r0,#&7f ; numbers - min(128, num_pages) AND r12, r12, r0 ; r12 -> (r12 + 1) masked MOV r0, #&00 ; to useable page numbers. MOV r1, r12 BL ts_set_cam ; Setup a page for vectors LDR r0, [r10] ; r0 = current logical test page. MOV r1, r8 ; r1 = current physical test page. BL ts_set_cam ; Setup a page to test LDR r0, [r10] ; look up logical page again. MOV r1, r8 ; recall physical page. BL ts_check_mapped ; check the ts_set_cam worked. MOV r1, r12 ; unmap the vector page BL ts_set_cam_idle 5 ADD r10, r10, #&04 ; next entry in test list. ADRL r0, ts_logpagesend ; r0 = ts_logpagesend. CMP r10, r0 ; repeat until list of logical BLO %B3 ; pages all done. MOV r1, r8 ; unmap the page we just tested BL ts_set_cam_idle SUBS r8, r8, #1 ; bump phys page counter down. ANDS r8,r8,r8 BGE %B2 ; If r8 >= 0 Then branch back to 2. ANDS r0,r0,#0 MOV pc,r13 ; all done and passed ; ; **************************************************************************** ; ts_copy_vectors ; ; Copies the vectors to the physical page in r0 (preserved) also copies ; pagemark + phypage. ; Expects r1 (preserved) to hold log2 of pagesize ; ROUT ; Local Branches. ADR r2, ts_vectors ; r2 = source address LDMIA r2, {r4-r11} ; r4 - r11 = loc pointed to by r2, post inc. MOV r3, r0, LSL r1 ; r3 = r0 * 2**r1 . ORR r3, r3, #ts_phys_mem ; r3 = r3 OR ts_phys_mem. STMIA r3, {r4-r11} ; loc pointed to by r3, post inc = r4 to r11. ; ; find out which memc is handling the page (r0), then assign the appropiate memc_code. ; Add in the page number and pagemark, then store into the required position in the ; page in question. ; ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. LDRB r2, [r2, r0, LSR#7] ; r2 = memc code for this phys page. ORR r2, r0, r2, LSL #24 ; OR in phys page number. ORR r2, r2, #ts_pagemark ; OR in pagemark. STR r2, [r3, #ts_pmark_pos] ; loc pointed to by r1 + ts_pmark_pos = pagemark. MOV pc, lr ; Return to caller. ; ; **************************************************************************** ; ts_set_cam_idle ; ; This module will program the physical page (r1) to the logical page 5, ts_vrest and ; continue onto the next section ts_set_cam. ; ROUT ; Local Branches. MOV r0, #ts_vrest ; r0 = ts_vrest, = unused logical page. ; ; **************************************************************************** ; ts_set_cam ; ; This module will program the physical page (r1) to the logical page (r0) at ; protection mode 0 and continue onto the next section ts_set_camp. ; MOV r2, #&00 ; r2 = &00, memory prot level 0. ; ; **************************************************************************** ; ts_set_camp ; ; This module will map a range the physical pages (r1) to the logical page (r0) and ; set the protection mode (r2). This module will return to the location from where ; either itself or ts_set_cam or ts_set_cam_idle were called from. ; ; Corrupts r0,r1,r2,r3,r4,r6,r9,r11 ; ; Calls the RISC OS routine BangCam to do the PPNO, LPNO bit switching. ; First, jumble the registers to suit BangCam .. ; ; r2 = CAM entry (PPNO) ; r3 = logical address ; r9 = current MEMC setting (for pagesize) ; r11 = PPL ; MOV r3,r0 ; logical page number MOV r11,r2 ; protection level MOV r2,r1 ; physical page number MOV_fiq r0, r11_fiq ; MEMC configuration MOV r9, r0 ; keep a copy in r9 MOV r1, r9, LSR #2 AND r1, r1, #3 ; calculate pagesize shift ADD r1, r1, #12 MOV r3, r3, LSL r1 ; convert LPN to logaddr B BangCam ; return thro' BangCam ; ; **************************************************************************** ; ts_check_mapped ; ; This routine will check that the CAM has been programed correctly and that the required ; page is responding when asked. A quick test is made to check that other pages are not ; responding as well. ; ; logical page in r0, ; physical page in r1, ; test that they are the same. ; ; No return value : reports faults directly and returns thro' r13 ; ; Uses (corrupts) r0,r1,r2,r3,r4,r5,r6,r7 ; ; Find out which memc is handling the page (r1), then assign the appropiate memc_code. ; Add in the page number and pagemark, then compare that pagemark with those found ; in memory at the expected logical and physical addresses. ; ; This code assumes that any system with multiple MEMCs will always have 32K pages. ; ROUT ; Local Branches. MOV r3, r0 ; save the current logical pagenumber. MOV r5, lr ; Preserve link register in case of Abort. ADR r2, ts_memc_codes ; r2 = address of table with the memc codes. LDRB r2, [r2, r1, LSR#7] ; fetch the memc code for this page. ORR r2, r1, r2, LSL #24 ; build the page number into the pagemark ORR r2, r2, #ts_pagemark ; build in the pagemark magic number ; ; r2 should now have the page_mark for the current page (r1). ; calculate the shift to convert page number to memory offset. ; MODE FIQ_mode MOV r4, r11_fiq, LSR #2 ; pagesize / 4K MODE SVC_mode AND r4, r4, #3 ADD r4, r4, #12 ; ; if the mapping failed completely, the test might abort ; MOV r6, #&00 ; r6 = &00, clear expected abort flag. MOV r7, #&94 ; r7 = &94, set abort expected flag. ; ; make the pointers and test the contents ; MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. LDR r0, [r0, #ts_pmark_pos] ; r0 = contents of loc in r0 + ts_pmark_pos. CMP r6, #94 ; did that fetch abort ? ADREQ r4, %F14 ; mapping totally failed BEQ ts_CAM_fail MOV r1, r1, LSL r4 ; r1 = PPN * pagesize. ORR r1, r1, #ts_phys_mem ; r1 = r1 ORed with ts_phys_mem. LDR r1, [r1, #ts_pmark_pos] ; r1 = contents of loc in r1 + ts_pmark_pos. CMP r0, r1 ; Are the read pagemarks equal ?? ADRNE r4, %F10 BNE ts_CAM_fail ; Failed : mapping not equal. CMP r0, r2 ; ADRNE r4, %F11 BNE ts_CAM_fail ; Failed : map equal, but corrupt ; ; test that the page doesn't exist anywhere else ; MOV r2, #1 0 EOR r0, r2, r3 ; Flip a (walking) bit in the LPN. CMP r0, #ts_vrest ; Is r0 = ts_vrest ?? Where all the pages are ; mapped to. BEQ %F1 ; If r0 = ts_vrest then branch forward to 1. ; ; The following instruction should abort. ; MOV r0, r0, LSL r4 ; r0 = LPN * pagesize. MOV r6, #&00 ; r6 = &00, clear abort handled flag. MOV r7, #&94 ; r7 = &94, set abort expected flag. LDR r0, [r0, #ts_pmark_pos] ; get a possible pagemark from this page. CMP r6, #&94 ; Did we go thro' the abort handler ? BEQ %F1 ; If equal then an abort happened, good ! ; ; Not aborted - is it page zero, where the vectors live ? ; TEQS r2, r3 BEQ %F1 ; yes - that SHOULDN'T abort ; ; Fault - is the page mapped there the same as our test page ? ; CMP r0, r1 ADREQ r4, %F12 ; Failed : phys page also mapped here ADRNE r4, %F13 ; Failed : page not unmapped EOR r3, r2, r3 ; remake the duff LPN for the error display B ts_CAM_fail ; If equal then no abort happened, not good !! 1 MOV r2, r2, LSL#1 ; bump to next-bit-set page number CMP r2, #(ts_MAX_CAMS :SHL: 1) ; Hit number of logical pages ? BLT %B0 ; If r2 < maximum number then loop again. MOV r7, #0 ; no longer expecting aborts MOV pc, r5 ; Return to caller. ; ; Indicate that CAM mapping test failed (PPN is not at LPN) ; Display r8, the physical page number and r3, the logical page. ; ; ***This error exit returns to the CALLER of check_mapped, thro' r13*** ; 10 = "CAM map",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 11 = "CAM pmk",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 12 = "CAM als",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 13 = "CAM unm",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 14 = "CAM abo",&88,&ff,&ff,&ff,".",&ff,&ff,&ff,&ff,0 ALIGN ts_CAM_fail MOV r0, r8, LSL #16 ; physical page # LDR r1, =&ffff AND r1, r1, r3 ORR r0, r0, r1 ; add logical page # MOV r8, r0, LSL #4 MOV r6, #0 ; no longer expecting aborts ORRS r0, r0, #1 MOV pc, r13 ; ; ************************************************************************** ; ; Routine to return expected number of physical pages in r0. ; Uses memory size determination from r10_fiq and page mode from r11_fiq. ; Returns pagesize as power-of-two in r1, for pagenumber->address calcs. ts_count_CAMs MODE FIQ_mode MOV r0,r10_fiq,LSR #12 ; get values determined MOV r1,r11_fiq,LSR #2 ; by MemSize MODE SVC_mode AND r1,r1,#3 ; memory / pagesize MOV r0,r0,LSR r1 ADD r1,r1,#12 ; page bit-shift value MOVS pc,lr ; ; ************************************************************************** ; ROUT ; Indicate that an unexpected number of CAM pages were found. ; ; Display as "CAM ## eee.fff" ; ; where eee is the expected maximum page number (r0), fff is the number ; of of the highest page actually found (r8). 0 = "CAM ##",&89,&ff,&ff,&ff,".",&ff,&ff,&ff,0 ALIGN ts_bad_CAM_count ADD r8, r8, r0, LSL #12 MOV r8, r8, LSL #8 ADR r4, %B0 ORRS r0, r0 ,#1 MOV pc, r13 ; ; ************************************************************************** ; ; Indicate that the DAB vector wasn't visible in physmem 0 = "CAM vec",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff,0 ALIGN ts_bad_dab_vector ADR r4, %B0 EOR r8,r0,r1 ; indicate which bits are lost ORRS r0, r0, #1 MOV pc, r13 ; ; ************************************************************************** ; Routine to indicate that an unexpected abort was found. 0 = "DAB @",&88,&ff,&ff,&ff,&ff,&ff,&ff,&ff,&ff, 0 ALIGN ts_unxvect ADR r4, %B0 SUBS r8, r14_svc, #8 ; indicate the aborting instruction BL ts_SendText ORRS r0, r0, #1 MOV pc, r13 LTORG END