; $Id: cpu_mmu.mac 1359 2023-01-27 20:58:50Z mueller $ ; SPDX-License-Identifier: GPL-3.0-or-later ; Copyright 2022-2023 by Walter F.J. Mueller ; ; Revision History: ; Date Rev Version Comment ; 2023-01-27 1358 1.1 use .mcall and mlib; use hta??? macros ; 2023-01-05 1346 1.0 Initial version ; 2022-07-24 1262 0.1 First draft ; ; Test CPU MMU: all aspects of the MMU ; Section A: pdr,par registers ; Section B: mmr0,mmr3 registers, mapping, instructions; MTP* and MFP* ; Section C: mmr2+mmr1+mmr0 register, aborts ; Section D: mmr2+mmr1+mmr0 register, abort recovery ; Section E: traps and pdr aia and aiw bits ; Section F: miscellaneous ; ; Overall usage of pages in kernel mode ; page 0 main code ; page 1 main code ; page 2 ; page 3 ; page 4 code mapped in user/super space; test E1.4 code (page 4->5 border) ; page 5 code for test E1.4 (page 4->5 border) ; page 6 data test target ; page 7 iopage ; .include |lib/tcode_std_base.mac| .include |lib/defs_mmu.mac| ; .mcall push,pop .mcall hcmpeq,hcmbeq,htsteq,htstge,hbiteq,hbitne .mcall vecset,vecclr .mcall htabuf,htaadd,htaini,htacmp ; ; some useful definitions uipdr0 = uipdr+ 0 uipar0 = uipar+ 0 udpdr0 = udpdr+ 0 udpar0 = udpar+ 0 udpdr1 = udpdr+ 2 udpar1 = udpar+ 2 udpdr2 = udpdr+ 4 udpar2 = udpar+ 4 sipdr0 = sipdr+ 0 sipar0 = sipar+ 0 sipdr1 = sipdr+ 2 sipar1 = sipar+ 2 sipdr2 = sipdr+ 4 sipar2 = sipar+ 4 sipdr3 = sipdr+ 6 sipar3 = sipar+ 6 sipdr6 = sipdr+14 sipar6 = sipar+14 sipdr7 = sipdr+16 sipar7 = sipar+16 kipdr0 = kipdr+ 0 kipar0 = kipar+ 0 kdpdr0 = kdpdr+ 0 kdpar0 = kdpar+ 0 kipdr1 = kipdr+ 2 kipar1 = kipar+ 2 kdpdr1 = kdpdr+ 2 kdpar1 = kdpar+ 2 kipdr5 = kipdr+12 kipdr6 = kipdr+14 kipar6 = kipar+14 kdpdr6 = kdpdr+14 kdpar6 = kdpar+14 kipdr7 = kipdr+16 kipar7 = kipar+16 kdpdr7 = kdpdr+16 kdpar7 = kdpar+16 p0p1p2 = <1*100>+2 ; page 0, +1 click, +2 p0p1p4 = <1*100>+4 ; page 0, +1 click, +4 p1base = <1*20000> ; page 1 p1p0p2 = p1base+2 ; page 1, +2 p1m1p0 = p1base+<127.*100> ; page 1, 128-1 click p2base = <2*20000> ; page 2 p2m1p0 = p2base+<127.*100> ; page 1, 128-1 click p2m1m4 = p2base+<127.*100>-4 ; page 1, 128-1 click, -4 p3base = <3*20000> ; page 3 p4base = <4*20000> ; page 4 p5base = <5*20000> ; page 5 p6base = <6*20000> ; page 6 p6p1p2 = p6base+<1*100>+2 ; page 6, +1 click, +2 p7base = <7*20000> ; page 7 ; ; Section A: pdr,par registers =============================================== ; A1.1 test that pdr/par are 16 bit write/readable ; A1.2 set up MMU default configuration ; ; Test A1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Test A1.1 -- test that pdr/par are 16 bit write/readable +++++++++++ ; Write unique patterns to first and last pdr/par of each mode and read back ; ta0101: mov #000401,r5 ; pattern master ;;; mov #077717,r5 ; bit mask for pdr ; ; write 000401,001002,002004,004010,... for pdr; complement for par mov r5,r0 ; start pattern mov #12.,r1 ; number tested regs mov #9000$,r2 1000$: mov (r2)+,r3 mov r0,(r3) ; write pdr add r5,r0 dec r0 mov r0,40(r3) ; write par add r5,r0 sob r1,1000$ ; ; read back mov r5,r0 ; start pattern mov #12.,r1 ; number of modes mov #9000$,r2 1100$: mov (r2)+,r3 hcmpeq (r3),r0 ; check pdr add r5,r0 dec r0 hcmpeq 40(r3),r0 ; check par add r5,r0 sob r1,1100$ ; ; complement all pattern mov #12.,r1 ; number of modes mov #9000$,r2 1200$: mov (r2)+,r3 mov (r3),r4 ; complement pdr only writable bits com r4 bic #100360,r4 ; mask non-writable (incl A and W) mov r4,(r3) com 40(r3) ; complement par sob r1,1200$ ; ; and read back again ; pdr only plf,ed and acf fields are checked ; par all 16 bits are write/readable mov r5,r0 ; start pattern com r0 ; complemented mov #12.,r1 ; number of modes mov #9000$,r2 1300$: mov (r2)+,r3 mov r0,r4 bic #100360,r4 ; mask non-writable (incl A and W) hcmpeq (r3),r4 ; check pdr only writable bits sub r5,r0 inc r0 hcmpeq 40(r3),r0 ; check par sub r5,r0 sob r1,1300$ ; jmp 9999$ ; 9000$: .word uipdr ; usr i page dsc base 0 .word uipdr+16 .word udpdr ; usr d page dsc base 0 .word udpdr+16 .word sipdr ; sup i page dsc base 0 .word sipdr+16 .word sdpdr ; sup d page dsc base 0 .word sdpdr+16 .word kipdr ; ker i page dsc base 0 .word kipdr+16 .word kdpdr ; ker d page dsc base 0 .word kdpdr+16 ; 9999$: iot ; end of test A1.1 ; ; Test A1.2 -- set up MMU default configuration ++++++++++++++++++++++ ; Nothing is verified, just sets the MMU for all further tests ; kernel I: 1-to-1 and seg7 to io-page ; kernel D: unmapped but seg7 to io-page ; supervisor and user I and D: unmapped (acf=0) ; ta0102: ; first clear all pdr/par, that disables mapping (acf=0) mov #1000$,r0 mov #3,r1 100$: mov (r0)+,r2 ; ptr to pdr+par I+D set (32 regs) mov #8.,r3 ; 8 chunks of 4 200$: clr (r2)+ clr (r2)+ clr (r2)+ clr (r2)+ sob r3,200$ sob r1,100$ ; set up kernel I mov #kipdr,r0 mov #<127.*md.plf>!md.arw,r1 ; plf=127; ed=0(up); acf=6(w/r) mov r1,(r0)+ ; kipdr0 mov r1,(r0)+ ; kipdr1 mov r1,(r0)+ ; kipdr2 mov r1,(r0)+ ; kipdr3 mov r1,(r0)+ ; kipdr4 mov r1,(r0)+ ; kipdr5 mov r1,(r0)+ ; kipdr6 mov r1,(r0)+ ; kipdr7 mov #kipar,r0 mov #000000,(r0)+ ; kipar0 000000 base mov #000200,(r0)+ ; kipar1 020000 base mov #000400,(r0)+ ; kipar2 040000 base mov #000600,(r0)+ ; kipar3 060000 base mov #001000,(r0)+ ; kipar4 100000 base mov #001200,(r0)+ ; kipar5 120000 base mov #001400,(r0)+ ; kipar6 140000 base mov #177600,(r0)+ ; kipar7 (map I/O page) ; kernel D space is not used in tests, kernel always runs without I/D ; D space is tested, but in supervisor or user mode ; jmp 9999$ ; 1000$: .word uipdr .word sipdr .word kipdr ; 9999$: iot ; end of test A1.2 ; ; Section B: mmr0,mmr3 registers, mapping, instructions ====================== ; Test whether address mapping works (traps and aborts avoided) ; ; B1 mmr0, mmr3 write/read and clear by RESET ; B1.1 test mmr0 write/read ; B1.2 test mmr3 write/read ; B2 kernel mode mapping ; B2.1 test 1-to-1 kernel mode mapping ; B2.2 test variable kernel mode mapping ; B3 user and supervisor mode ; B3.1 run code in user/supervisor mode ; B3.2 run code in user mode with D space; MFP*, MTP* ; part 1: run code vc1 in user mode ; part 2: test MTPD and MFPD ; part 3: test MTPI and MFPI ; part 4: test MTPD,MFPD with @(sp)+ ; part 5: test MTPI,MFPI with @(sp)+ ; part 6: test MFPD,MFPI and MTPD,MTPI for sp register access ; part 7: test MFPD,MFPI and MTPD,MTPI for register r0-r5 access ; B3.3 test MFPI,MTPI with cm=pm=user ; B4 invalid cpu mode 10 ; B4.1 check that cmode=10 causes abort ; B4.2 check MFPI/MTPI SP response for pmode=10 ; ; Test B1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Test mmr0, mmr3 write/read and clear by RESET ; ; This test verifies ; x xxx xxx xxx xxx xxx NZVC Instruction / Remark ; 0 000 000 000 000 101 ---- RESET (clear mmr0,mmr3) ; ; Test B1.1 -- test mmr0 write/read ++++++++++++++++++++++++++++++++++ ; Test all writable bits except m0.ena ; Also ensure that unimplemented bits return zero ; tb0101: mov #mmr0,r0 ; ptr to mmr0 mov #m0.ico,r1 ; instruction complete flag mov #1010$,r4 ; ptr to data mov #1011$,r3 ; ptr to data end 100$: mov (r4),(r0) ; write mmr0 mov (r0),r5 ; read mmr0 bic r1,r5 ; mask instruction complete hcmpeq r5,(r4)+ ; check cmp r4,r3 ; more to do ? blo 100$ ; reset ; mmr0 has 5 bits set, check clear mov (r0),r5 ; read mmr0 bic r1,r5 ; mask instruction complete htsteq r5 ; check mmr0 cleared ; ; ensure unimplemented bits return zero ; Note: m0.mai is currently unimplemented in w11 (reads zero) ; In SimH this bit is writable and reads back, but without function mov #bit11!bit10,(r0) mov (r0),r5 ; read mmr0 bic r1,r5 ; mask instruction complete htsteq r5 ; check mmr0 cleared ; jmp 9999$ ; 1010$: .word m0.anr ; abort flags .word m0.ale .word m0.ard .word m0.trp ; trap flag .word m0.ent ; trap enable .word m0.anr!m0.ale!m0.ard!m0.trp!m0.ent 1011$: ; 9999$: iot ; end of test B1.1 ; ; Test B1.2 -- test mmr3 write/read ++++++++++++++++++++++++++++++++++ ; Test all writable bits; mmu is off, and unibus map not used ; Also ensure that unimplemented bits return zero ; tb0102: mov #mmr3,r0 ; ptr to mmr3 mov #1010$,r4 ; ptr to data mov #1011$,r3 ; ptr to data end 100$: mov (r4),(r0) ; write mmr3 hcmpeq (r0),(r4)+ ; check cmp r4,r3 ; more to do ? blo 100$ ; reset ; mmr3 has 5 bits set, check clear htsteq (r0) ; check mmr3 cleared ; ; ensure unimplemented bits return zero mov #^c,(r0) htsteq (r0) ; check mmr3 stays cleared ; jmp 9999$ ; 1010$: .word m3.eub .word m3.e22 .word m3.dkm .word m3.dsm .word m3.dum .word m3.eub!m3.e22!m3.dkm!m3.dsm!m3.dum 1011$: ; 9999$: iot ; end of test B1.2 ; ; Test B2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Test kernel mode mapping ; ; Test B2.1 -- test 1-to-1 kernel mode mapping +++++++++++++++++++++++ ; simply enable MMU, shouldnt make a difference ; test that 18bit mode extends I/O page addressing ; test that RESET clears mmr0 and mmr3 ; tb0201: mov #123456,1000$ ; enable mmu in 18bit mode clr mmr3 ; no d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 hbitne #m0.ena,mmr0 ; test bit hcmpeq 1000$,#123456 ; check marker ; verify I/O page mapping in 18bit mode (007600 must be OK) mov #kipar7,r0 ; ptr to kipar7 bic #170000,(r0) ; clear to 4 bits in kipar7 hcmpeq (r0),#007600 ; kipar7 still seen ? bis #170000,(r0) ; restore kipar7 hcmpeq (r0),#177600 ; enable mmu in 22bit mode; check that mmr3 still seen mov #m3.e22,mmr3 hcmpeq mmr3,#m3.e22 ; test mmr3 still seen ? ;! MMU 22 ; test RESET reset ; should clear mmr0 and mmr3 ;! MMU off htsteq mmr0 ; check mmr0 cleared htsteq mmr3 ; check mmr3 cleared jmp 9999$ ; 1000$: .word 0 ; 9999$: iot ; end of test B2.1 ; ; Test B2.2 -- test variable kernel mode mapping +++++++++++++++++++++ ; change seg6 mapping ; test that 18bit mode discards the 4 MSB of the par ; tb0202: mov #kipar6,r0 ; ptr to kipar6 mov #140000,r5 ; seg6 base mov #140000,(r5) ; init markers clr 2(r5) mov #140100,100(r5) ; init markers clr 102(r5) ; clr mmr3 ; no d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; check in 1-to-1 mapping hcmpeq (r5),#140000 htsteq 2(r5) hcmpeq 100(r5),#140100 htsteq 102(r5) ; move seg6 mapping up by one click inc (r0) ; move kipar6 base up hcmpeq (r0),#001401 hcmpeq 0(r5),#140100 mov #010000,2(r5) ; write marker ; set MSBs in kipar6, should be discarded in 18bit mode, check markers bis #170000,(r0) hcmpeq (r0),#171401 hcmpeq (r5),#140100 ; check marker bic #170000,(r0) hcmpeq (r0),#001401 ; move seg6 mapping down by one click dec (r0) ; move kipar6 base up hcmpeq (r0),#001400 mov #020000,2(r5) ; write marker hcmpeq 2(r5),#020000 ; check marker hcmpeq 102(r5),#010000 ; check marker ; disable MMU reset ; mmu off ;! MMU off ; 9999$: iot ; end of test B2.2 ; ; Test B3: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Test user and supervisor mode ; ; Test B3.1 -- run code in user/supervisor mode ++++++++++++++++++++++ ; code vc0 is executed in user and in supervisor mode ; the code runs in seg0 with D space disabled ; tb0301: ; set up emt handler vecset v..emt,vhuemt ; set up emt handler, pr0 kernel clr mmr3 ; no d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; run code vc0 in user mode -------------------------------- ; ; set user mode pdr/par, only short page 0 mov #<8.*md.plf>!md.arw,uipdr0 mov #,uipar0 ; set up data for user mode run mov #023456,vc0v0; mov #000123,vc0v1 mov #077321,vc0v2 ; start code in user mode mov #1000$,vhustp ; set up continuation address mov #,-(sp) ; next psw: user mode clr -(sp) ; will start at 0 rti ; and launch it halt 1000$: ; continuation point ; check psw ccc ; clear cc -> psw reflects pm setting hcmpeq cp.psw,#cp.pmu ; check pm ; check data hcmpeq vc0v0,#154321 hcmpeq vc0v2,#077444 ; reset user mode pdr/par clr uipdr0 clr uipar0 ; ; run code vc0 in supervisor mode -------------------------- ; ; set supervisor mode pdr/par, only short page 0 mov #<8.*md.plf>!md.arw,sipdr0 mov #,sipar0 ; set up data for user mode run mov #017171,vc0v0 mov #000321,vc0v1 mov #100123,vc0v2 ; start code in supervisor mode mov #2000$,vhustp ; set up continuation address mov #,-(sp) ; next psw: supervisor mode clr -(sp) ; will start at 0 rti ; and launch it halt 2000$: ; continuation point ; check psw ccc ; clear cc -> psw reflects pm setting hcmpeq cp.psw,#cp.pms ; check pm ; check data hcmpeq vc0v0,#160606 hcmpeq vc0v2,#100444 ; reset supervsior mode pdr/par clr sipdr0 clr sipar0 ; reset ; mmu off ;! MMU off vecclr v..emt ; restore emt catcher ; 9999$: iot ; end of test B3.1 ; ; Test B3.2 -- run code in user mode with D space; mfp*, mtp* ++++++++ ; Code vc1 is executed in user mode, runs in page 0 with D space enabled. ; ; This test verifies ; x xxx xxx xxx xxx xxx NZVC Instruction / Remark ; 0 000 110 101 ddd ddd NZ0- MFPI ; 0 000 110 110 ddd ddd NZ0- MTPI ; 1 000 110 101 ddd ddd NZ0- MFPD ; 1 000 110 110 ddd ddd NZ0- MTPD ; tb0302: vecset v..emt,vhuemt ; set up emt handler, pr0 kernel mov #m3.dum,mmr3 ; user d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; part 1: run code vc1 in user mode ---------------------------------- ; ; set user mode pdr/par, only short page 0; I and D mov #<8.*md.plf>!md.arw,uipdr0 mov #,uipar0 mov #<8.*md.plf>!md.arw,udpdr0 mov #,udpar0 ; set up data for user mode run mov #020305,vc1v0 mov #000212,vc1v1 mov #033121,vc1v2 ; start code in user mode mov #1000$,vhustp ; set up continuation address mov #,-(sp) ; next psw: user mode clr -(sp) ; will start at 0 rti ; and launch it halt ; 1000$: ; continuation point ; check psw ccc ; clear cc -> psw reflects pm setting hcmpeq cp.psw,#cp.pmu ; check pm ; check data hcmpeq vc1v0,#157472 hcmpeq vc1v2,#033333 ; ; psw has now pm=user and cm=kernel; good setup to test MFPI and friends ; ; part 2: test MTPD and MFPD ----------------------------------------- ; ; test MFPD (data access) ; mov #,r5 ; initialize data pointer mfpd (r5) ; read vc1v0 hcmpeq (sp)+,#157472 mfpd @# ; read vc1v2 hcmpeq (sp)+,#033333 ; ; test MTPD and MFPD, incl cc (data access) ; mov #2010$,r4 ; ptr to test data mov #2011$,r3 ; ptr to test end 2000$: push (r4)+ ccc ; C=0 mtpd (r5) ; write vc1v0 hcmpeq cp.psw,(r4)+ ; check cc hcmpeq vc1v0,-4(r4) ; check target scc ; C=1 mfpd (r5) hcmpeq cp.psw,(r4)+ ; check cc hcmpeq (sp)+,-6(r4) ; check data cmp r4,r3 ; more to do ? blo 2000$ ; ; part 3: test MTPI and MFPI ----------------------------------------- ; ; test MFPI (data access) ; mov #,r5 ; initialize data pointer mfpi (r5) ; read 1st instruction word hcmpeq (sp)+,vc1 ; ; test MTPI and MFPI, incl cc (data access) ; mov #,r5 ; initialize data pointer mov #3010$,r4 ; ptr to test data mov #3011$,r3 ; ptr to test end 3000$: push (r4)+ scc ; C=1 mtpi (r5) ; write vc1ida hcmpeq cp.psw,(r4)+ ; check cc hcmpeq vc1ida,-4(r4) ; check target ccc ; C=0 mfpi (r5) hcmpeq cp.psw,(r4)+ ; check cc hcmpeq (sp)+,-6(r4) ; check data cmp r4,r3 ; more to do ? blo 3000$ ; ; part 4: test MTPD,MFPD with @(sp)+ --------------------------------- ; Note: (sp) or (sp)+ are not a useful address mode for MTPD ; It will use the cm sp as address in pm, rarely what one wants ; So @(sp)+ is the only mode with sp in src worth to be tested ; clr vc1v0 push # ; D addr of vc1v0 push #054321 ; data to mtpd mtpd @(sp)+ ; reads data first, then dst addr hcmpeq vc1v0,#054321 ; check at destination inc vc1v0 push # ; D addr of vc1v0 mfpd @(sp)+ hcmpeq (sp)+,#054322 ; check ; ; part 5: test MTPI,MFPI with @(sp)+ --------------------------------- ; clr vc1ida push # ; I addr of vc1ida push #012321 ; data to mtpi mtpi @(sp)+ ; reads data first, then dst addr hcmpeq vc1ida,#012321 ; check at destination inc vc1ida push # ; I addr of vc1ida mfpi @(sp)+ hcmpeq (sp)+,#012322 ; check ; ; ; part 6: test MFPD,MFPI and MTPD,MTPI for sp register access -------- ; accessing sp will access user mode stack pointer (which is != kernel stack) ; ; read sp via mfpd and mfpi mfpd sp ; read user mode sp hcmbeq (sp)+,# ; check mfpi sp ; read user mode sp (same for I and D) hcmbeq (sp)+,# ; check ; write sp via mtpd, readback via mfpi mov sp,r4 ; remember kernel stack mov #77,r5 push r5 mtpd sp ; change user stack hcmpeq sp,r4 ; check kernel stack unchanged mfpi sp ; read back user stack hcmpeq (sp)+,r5 ; check ; write sp via mtpi, readback via mfpd mov #177,r5 push r5 mtpi sp ; change user stack hcmpeq sp,r4 ; check kernel stack unchanged mfpd sp ; read back user stack hcmpeq (sp)+,r5 ; check ; ; part 7: test MFPD,MFPI and MTPD,MTPI for register r0-r5 access ----- ; accessing r0-r5 simply acccesses common registers ; that is usually not used, but should work ; ; write registers via mtpd,mtpi push #277 mtpd r5 ; effective mov #277,r5 push #377 mtpi r4 ; effective mov #377,r4 hcmpeq r5,#277 ; check hcmpeq r4,#377 ; check ; read registers via mtpd,mtpi mov #477,r5 mov #577,r4 mfpd r5 hcmpeq (sp)+,#477 ; check mfpd r4 hcmpeq (sp)+,#577 ; check ; ; reset user mode pdr/par clr uipdr0 clr uipar0 clr udpdr0 clr udpar0 ; reset ; mmu off ;! MMU off clr cp.psw ; crop pm in psw vecclr v..emt ; restore emt catcher jmp 9999$ ; ; test data for m*pd tests (C=0 for T and C=1 for F) 2010$: .word 000000,cp.pmu!cp0z00,cp.pmu!cp0z0c .word 000001,cp.pmu!cp0000,cp.pmu!cp000c .word 100000,cp.pmu!cpn000,cp.pmu!cpn00c 2011$: ; ; test data for m*pi tests (C=1 for T and C=0 for F) 3010$: .word 000000,cp.pmu!cp0z0c,cp.pmu!cp0z00 .word 000001,cp.pmu!cp000c,cp.pmu!cp0000 .word 100000,cp.pmu!cpn00c,cp.pmu!cpn000 3011$: ; 9999$: iot ; end of test B3.2 ; ; Test B3.3 -- test MFPI,MTPI with cm=pm=user ++++++++++++++++++++++++ ; Verifies that MFPI acts like MFPD when cm=pm=user and that MTPI has no ; such restriction and can modify I space when PDR ACF allows. ; Runs code vc4 with D space enabled, code in page 0 and data in page 1. ; tb0303: vecset v..emt,vhuemt ; set up emt handler, pr0 kernel mov #m3.dum,mmr3 ; user d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; set up data clr vc4l1 ; set user mode pdr/par, I page 0 and D page 1 mov #<8.*md.plf>!md.arw,uipdr0 ; I space writable mov #,uipar0 mov #<8.*md.plf>!md.arw,udpdr1 mov #,udpar1 ; start code in user mode mov #1000$,vhustp ; set up continuation address mov #,-(sp) ; next psw: user mode clr -(sp) ; will start at 0 rti ; and launch it halt ; 1000$: ; continuation point hcmpeq #040111,r0 ; check direct D space access to vc4v1 hcmpeq #040222,r1 ; check MFPI access to vc4v2 (D instead of I!) hcmpeq #040333,r2 ; check MFPD access to vc4v3 hcmpeq #040444,vc4l1 ; check modified vc4l1 ; ; reset user mode pdr/par clr uipdr0 clr uipar0 clr udpdr1 clr udpar1 ; reset ; mmu off ;! MMU off clr cp.psw ; crop pm in psw vecclr v..emt ; restore emt catcher ; 9999$: iot ; end of test B3.3 ; ; Test B4: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Test invalid cpu mode 10 ; ; Test B4.1 -- check that cmode=10 causes abort ++++++++++++++++++++++ ; Should abort with m0.anr and m0.ale for all adresses ; w11 aborts with m0.anr, but sets m0.ale only when fail above 1st click ; Test an address above the first click to have full 11/70 style response ; Note: w11 increments PC in case of an abort ; SimH does not increment PC in case of an abort (as 11/70 does) ; tb0401: clr mmr3 ; no d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..mmu,1000$ ; set up local mmu handler ; try to run a code in mode 10 mov #^b1010000000000000,-(sp) ; next psw; cm=pm=10 mov #p6base+200,-(sp) ; start address rti ; fake code start halt ; test abort PC on stack 1000$: cmpb systyp,#sy.sih ; on SimH ? bne 1010$ hcmpeq (sp)+,#p6base+200 ; SimH doesnt increment PC br 1020$ 1010$: hcmpeq (sp)+,#p6base+200+2 ; w11 does increment PC ; test abort PS on stack 1020$: hcmpeq (sp)+,#^b1010000000000000 ; abort PS ; hcmpeq mmr0,#m0.anr!m0.ale!0100!<6*m0.pno>!m0.ena ; check mmr0 hcmpeq mmr2,#p6base+200 ; check mmr2 ; reset ;! MMU off vecclr v..mmu ; restore mmu catcher ; 9999$: iot ; end of test B4.1 ; ; Test B4.2 -- check MFPI/MTPI SP response for pmode=10 ++++++++++++++ ; That is unspecified for all but J11, which will read/write user SP ; w11 return PC on read, the write is a noop ; Test on w11 even though its unspecified behavior ; tb0402: tstb systyp ; skip if not on w11 blt 9999$ ; load values in user and supervisor SP mov #cp.psw,r0 mov #cp.pmu,(r0) push #111222 mtpi sp ; user SP = 111222 mov #cp.pms,(r0) push #111444 mtpi sp ; user SP = 111444 ; read from pm=10 SP mov #^b0010000000000000,(r0) 1000$: mfpi sp ; read pm=10 sp hcmpeq (sp)+,#1000$ ; happens to return PC of mfpi ; write to pm=10 SP push #111666 mtpi sp ; write pm=10 sp hcmpeq sp,#stack ; check kernel sp mov #cp.pms,(r0) mfpi sp hcmpeq (sp)+,#111444 ; check supervisor sp mov #cp.pmu,(r0) mfpi sp hcmpeq (sp)+,#111222 ; check user sp ; clr cp.psw ; sane psw again ; 9999$: iot ; ; Section C: mmr2+mmr1+mmr0 register, aborts ================================= ; C1 MMU response in mmr1 after a write to that fakes an abort ; C2 MMU abort response in mmr0 and mmr1 ; C2.1 test unary/binary instructions ; part 1: unary instructions; test acf to mmr0(15:13) mapping ; part 2: unary instructions; fail in second access ; part 3: binary instructions; fail in src field ; part 4: binary instructions; fail in dst field ; part 5: multiple abort flags ; C2.2 test MFPI,MFPD,MTPI,MFPD dst aborts ; part 1: MFPI, MFPD ; part 2: MTPD, MTPI ; C2.3 test aborts in implied push/pop ; part 1: JSR, MFPI, MFPD (push) ; part 2: RTS, MTPI, MTPD (pop) ; C2.4 mmu abort vs nxm abort ; part 1: MMU allows access to NXM memory --> NXM abort ; part 2: MMU denies access to NXM memory --> MMU abort ; C2.5 mmu abort in vector flow - kernel mode ; C2.6 mmu abort in vector flow - supervisor mode ; C2.7 mmu abort in 1st instruction after vector flow ; C2.8 mmu abort of prefetched instruction ; C2.9 mmu aborts and memory status ; C2.10 mmu abort plus stack limit abort ; ; Test C1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Verify MMU response in mmr1 after a write to that fakes an abort ; ; Test C1.1 -- test mmr1 response via set abort in mmr0 trick ++++++++ ; Test method (concept seen in ekbee1) ; - start with mmr1 cleared, mmr1 will track ; - write one of the 3 abort bits in mmr1 (all three are tested) ; - that will freeze mmr1 ; - the register signature of the write can be inspected ; Note: this gives MMR1 when instruction is not(!) aborted ; in principle, MMR1 might hold other values in the case of an abort ; tc0101: mov #1000$,r1 ; ptr to abort bit table mov #mmr0,r2 ; ptr to mmr0 mov #mmr1,r3 ; ptr to mmr3 ; reset mov (r1),(r2) ; no regs changed ! hcmpeq (r3),#^b0000000000000000; ; reset mov (r1)+,(r2) ; r1,2 00000 000 00010 001 via anr hcmpeq (r3),#^b0000000000010001; ; reset mov -(r1),(r2) ; r1,-2 00000 000 11110 001 via anr hcmpeq (r3),#^b0000000011110001; ; reset mov (r1),(r2)+ ; r2,2 00000 000 00010 010 via anr hcmpeq (r3),#^b0000000000010010; ; reset mov (r1),-(r2) ; r2,-2 00000 000 11110 010 via anr hcmpeq (r3),#^b0000000011110010; ; reset mov (r1)+,(r2)+ ; r1,2,r2,2 00010 010 00010 001 via anr hcmpeq (r3),#^b0001001000010001; ; reset mov -(r1),-(r2) ; r1,-2,r2,-2 11110 010 11110 001 via anr hcmpeq (r3),#^b1111001011110001; ; reset tst (r1)+ ; bump ptr to ale mov (r1)+,(r2)+ ; r1,2,r2,2 00010 010 00010 001 via ale hcmpeq (r3),#^b0001001000010001; ; ; check that index reads are not accounted in mmr1 reset tst (r1)+ ; bump ptr beyond ard mov -(r1),-2(r2) ; r1,-1 00000 000 11110 001 via ard hcmpeq (r3),#^b0000000011110001; ; ; check @(pc)+ behavior ; w11 updates mmr1 in this case, as is also expected in ekbee1 ; Simh only adds 'general purpose register updates', thus not pc ; e11 doesnt like this test either tstb systyp ; skip test if on SimH or e11 blt 100$ ; systyp<0 --> not on w11 reset mov -(r1),@#mmr0 ; r1,-2,pc,2 00010 111 11110 001 via ale hcmpeq (r3),#^b0001011111110001; 100$: ; reset jmp 9999$ ; 1000$: .word m0.anr .word m0.ale .word m0.ard ; 9999$: iot ; end of test C1.1 ; ; Test C2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Verify MMU abort response in mmr0 and mmr1 ; ; Test C2.1 -- test unary/binary instructions ++++++++++++++++++++++++ ; Excercise access to kernel page 6 and inspect mmr0 and mmr1 ; tc0201: vecset v..mmu,vhmmua ; set up mmu handler, pr0 kernel reset mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; part 1: unary instructions; test acf to mmr0(15:13) mapping -------- ; Summary: ; 1000$: tst (r2)+ ; r ; dst anr 1 ; pdr= 0.,0,000 ; 1100$: tst (r3)+ ; r ; dst ale 1 ; pdr= 0.,0,arw ; 1200$: tst -(r4) ; r ; dst ale 1 ; pdr=127.,1,arw ; 1300$: clrb -(r2) ; w ; dst ard 1 ; pdr= 0.,0,aro ; 1400$: inc (r2)+ ; m ; dst ard 1 ; pdr= 0.,0,aro ; 1500$: tstb (r2)+ ; r ; dst anr 1 ; pdr= 0.,0,011 ; 1600$: tstb -(r2) ; r ; dst anr 1 ; pdr= 0.,0,111 ; ; non-resident abort (only) 1000$: clr kipdr6 ; plf= 0.;ed=0;acf=nres mov #1010$,vhvmmu mov #140000,r2 tst (r2)+ ; will fail halt 1010$: .word m0.anr!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; ; length abort, up direction; length 1 click 1100$: mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=w/r mov #1110$,vhvmmu mov #140102,r3 tst (r3)+ ; will fail halt 1110$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010011 ; mmr1 +2,3 ; ; length abort, down direction; length 1 click 1200$: mov #<127.*md.plf>!md.dwn!md.arw,kipdr6 ; plf=127.;ed=1;acf=w/r mov #1210$,vhvmmu mov #157700,r4 tst -(r4) ; will fail halt 1210$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110100 ; mmr1 -2,4 ; ; write abort in mapped area (write access) 1300$: mov #<0.*md.plf>!md.ara,kipdr6 ; plf= 0.;ed=0;acf=r mov #140002,r2 tstb (r2)+ ; read ok mov #1310$,vhvmmu clrb -(r2) ; write will fail halt 1310$: .word m0.ard!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011111010 ; mmr1 -1,2 ; ; write abort in mapped area (wmw access) 1400$: mov #1410$,vhvmmu inc (r2)+ ; rmw will fail halt 1410$: .word m0.ard!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; ; acf=011: reserved, abort all -> handled as non-resident 1500$: mov #^b011,kipdr6 ; plf= 0.;ed=0;acf=011 mov #1510$,vhvmmu tstb (r2)+ ; will fail halt 1510$: .word m0.anr!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000001010 ; mmr1 +1,2 ; ; acf=111: reserved, abort all -> handled as non-resident 1600$: mov #^b111,kipdr6 ; plf= 0.;ed=0;acf=111 mov #1610$,vhvmmu tstb -(r2) ; will fail halt 1610$: .word m0.anr!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011111010 ; mmr1 -1,2 ; ; part 2: unary instructions; fail in second access ------------------ ; Summary: ; 2000$: tst @(r2)+ ; r ; dst ale 2 ; pdr= 0.,0,arw ; 2100$: tst @-(r2) ; r ; dst ale 2 ; pdr= 0.,0,arw ; 2000$: mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=r/w mov #2010$,vhvmmu mov #2001$,r2 tst @(r2)+ ; will fail halt 2001$: .word p6p1p2 ; probed address, page 6, +1 click, +2 2010$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; 2100$: mov #2110$,vhvmmu tst @-(r2) ; will fail halt 2110$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110010 ; mmr1 -2,2 ; ; part 3: binary instructions; fail in src field --------------------- ; Summary: ; 3000$: mov (r2)+,(r3)+ ; r w ; src ale 1 ; pdr= 0.,0,arw ; 3100$: mov -(r2),(r3)+ ; r w ; src ale 1 ; pdr= 0.,0,arw ; 3200$: mov @(r4)+,(r3)+ ; r w ; src ale 2 ; pdr= 0.,0,arw ; 3300$: mov @-(r4),(r3)+ ; r w ; src ale 2 ; pdr= 0.,0,arw ; 3000$: mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=r/w mov #3010$,vhvmmu mov #140102,r2 mov #1,r3 ; not used mov (r2)+,(r3)+ ; will fail halt 3010$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; 3100$: mov #3110$,vhvmmu mov -(r2),(r3)+ ; will fail halt 3110$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110010 ; mmr1 -2,2 ; 3200$: mov #3210$,vhvmmu mov #3201$,r4 mov @(r4)+,(r3)+ ; will fail halt 3201$: .word p6p1p2 ; probed address, page 6, +1 click, +2 3210$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010100 ; mmr1 +2,4 ; 3300$: mov #3310$,vhvmmu movb @-(r4),(r3)+ ; will fail halt 3310$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110100 ; mmr1 -2,4 ; ; part 4: binary instructions; fail in dst field --------------------- ; Summary: ; 4000$: mov (r2)+,-(r3) ; r w ; dst ale 1 ; pdr= 0.,0,arw ; 4100$: mov -(r2),(r3)+ ; r w ; dst ale 1 ; pdr= 0.,0,arw ; 4200$: cmp (r2)+,@(r5)+ ; r r ; dst ale 2 ; pdr= 0.,0,arw ; 4300$: bis -(r2),(r4)+ ; r m ; dst ard 1 ; pdr= 0.,0,aro ; 4400$: bis (r2),-(r4) ; r m ; dst ard 1 ; pdr= 0.,0,aro ; 4000$: mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=r/w mov #4010$,vhvmmu mov #4001$,r2 mov #140104,r3 mov (r2)+,-(r3) ; will fail halt 4001$: .word 123456 4010$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b1111001100010010 ; mmr1 -2,3; +2,2 ; 4100$: mov #4110$,vhvmmu mov -(r2),(r3)+ ; will fail halt 4110$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001001111110010 ; mmr1 +2,3; -2,2 ; 4200$: mov #4210$,vhvmmu mov 4201$,r5 cmp (r2)+,@(r5)+ ; will fail halt 4201$: .word p6p1p2 ; probed address, page 6, +1 click, +2 4210$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001010100010010 ; mmr1 +2,5; +2,2 ; 4300$: mov #<0.*md.plf>!md.ara,kipdr6 ; plf= 0.;ed=0;acf=r mov #4310$,vhvmmu mov #140010,r4 bis -(r2),(r4)+ ; will fail halt 4310$: .word m0.ard!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001010011110010 ; mmr1 +2,4; -2,2 ; ; no inc/dec for src 4400$: mov #4410$,vhvmmu bis (r2),-(r4) ; will fail halt 4410$: .word m0.ard!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110100 ; mmr1 -2,4; ; ; part 5: multiple abort flags --------------------------------------- ; possible: anr + ale (non-resident + length) ; ard + ale (read-only + length) ; Summary: ; 5000$: tst (r2)+ ; r ; dst anr+ale 1 ; pdr= 0.,0,000 ; 5100$: clr (r3)+ ; w ; dst anr 1 ; pdr= 0.,0,000 ; 5200$: com (r4)+ ; m ; dst ale+ard 1 ; pdr= 0.,0,aro ; ; non-resident + length abort 5000$: clr kipdr6 ; plf= 0.;ed=0;acf=nres mov #5010$,vhvmmu mov #140102,r2 tst (r2)+ ; will fail halt 5010$: .word m0.anr!m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; ; non-resident abort + write --> nres only 5100$: mov #5110$,vhvmmu mov #140002,r3 clr (r3)+ ; will fail halt 5110$: .word m0.anr!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010011 ; mmr1 +2,3 ; ; length + read-only abort 5200$: mov #<0.*md.plf>!md.ara,kipdr6 ; plf= 0.;ed=0;acf=r mov #5210$,vhvmmu mov #140102,r4 com (r4)+ ; will fail halt 5210$: .word m0.ale!m0.ard!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010100 ; mmr1 +2,4 ; 9000$: reset ; mmu off ;! MMU off clr cp.psw mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping vecclr v..mmu ; restore mmu catcher 9999$: iot ; end of test C2.1 ; ; Test C2.2 -- test MFPI,MFPD,MTPI,MFPD dst aborts +++++++++++++++++++ ; Environment: psw pm=user; mmr3 user I/D ; kipdr6 1 click up acf=6 w/r ; uipdr0 1 click up acf=2 read ; udpdr1 1 click up acr=2 read ; udpdr2 1 click dn acr=6 w/r ; tc0202: vecset v..mmu,vhmmua ; set up mmu handler, pr0 kernel reset mov #cp.pmu,cp.psw ; pm to user mov #m3.dum,mmr3 ; enable user D space mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=w/r mov #<0.*md.plf>!md.ara,uipdr0 ; plf= 0.;ed=0;acf=r mov #<0.*md.plf>!md.ara,udpdr1 ; plf= 0.;ed=0;acf=r mov #<127.*md.plf>!md.dwn!md.arw,udpdr2 ; plf=127.;ed=1;acf=w/r mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; part 1: -- MFPI, MFPD ---------------------------------------------- ; Summary: ; 1000$: mfpi (r2)+ ; r ; dst anr 1 ; pdr= 0.,0,000 ; 1100$: mfpi (r3)+ ; r ; dst ale 1 ; pdr= 0.,0,aro ; 1200$: mfpi @(r4)+ ; r ; dst ale 1 ; pdr= 0.,0,arw ; 1300$: mfpi @(r5)+ ; r ; dst ale 2 ; pdr= 0.,0,aro ; 1400$: mfpd -(r3) ; r ; dst ale 1 ; pdr=127.,1,arw ; ; MPPI: I space page 1 non-resident 1000$: mov #1010$,vhvmmu mov #p1base,r2 mfpi (r2)+ ; will fail, page 1 unmapped halt 1010$: .word m0.anr!m0.pmu!<1*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010010 ; mmr1 +2,2 ; ; MFPI: I space page 0 length abort 1100$: mov #1110$,vhvmmu mov #p0p1p2,r3 ; page 0, +1 click, +2 mfpi (r3)+ ; will fail halt 1110$: .word m0.ale!m0.pmu!<0*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010011 ; mmr1 +2,3 ; ; MFPI @(R)+: 1st access fails (in kernel space) 1200$: mov #cp.pmu,cp.psw ; pm to user mov #1210$,vhvmmu mov #p6p1p2,r4 ; page 6, +1 click, +2 mfpi @(r4)+ ; will fail halt 1210$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 -> p6 k ; dddddrrrdddddrrr .word ^b0000000000010100 ; mmr1 +2,4 ; ; MFPI @(R)+: 2nd access fails (in user space) 1300$: mov #cp.pmu,cp.psw ; pm to user mov #1310$,vhvmmu mov #1301$,r5 mfpi @(r5)+ ; will fail halt 1301$: .word p0p1p4 ; probed address 1310$: .word m0.ale!m0.pmu!<0*m0.pno>!m0.ena ; mmr0 -> p0 u ; dddddrrrdddddrrr .word ^b0000000000010101 ; mmr1 +2,5 ; ; MFPD: D space page 1 length abort (has ed=1) 1400$: mov #cp.pmu,cp.psw ; pm to user mov #1410$,vhvmmu mov #p1m1p0,r3 ; page 1, 128-1 click mfpd -(r3) ; will fail halt 1410$: .word m0.ale!m0.pmu!m0.dsp!<1*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110011 ; mmr1 -2,3 ; ; part 2: -- MTPD, MTPI ---------------------------------------------- ; Note: mmr1 lsb has stack pop ; Summary: ; 2000$: mtpd (r2)+ ; r ; dst anr 1 ; pdr= 0.,0,000 ; 2100$: mtpd (r3)+ ; r ; dst ard 1 ; pdr= 0.,0,aro ; 2200$: mtpd -(r4) ; r ; dst ale 1 ; pdr=127.,1,arw ; 2300$: mtpd @(R5)+ ; r ; dst ale 1 ; pdr= 0.,0,arw ; 2400$: mtpd @(R3)+ ; r ; dst ale 2 ; pdr=127.,1,arw ; 2500$: mtpi (r2)+ ; r ; dst ard 1 ; pdr= 0.,0,aro ; ; MTPD: D space page 3 non-resident 2000$: mov #cp.pmu,cp.psw ; pm to user mov #2010$,vhvmmu mov #p3base,r2 push #1234 mtpd (r2)+ ; will fail, page 3 unmapped halt 2010$: .word m0.anr!m0.pmu!m0.dsp!<3*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001001000010110 ; mmr1 +2,2; +2,6 ; ; MTPD: D space page 1 read-only 2100$: mov #cp.pmu,cp.psw ; pm to user mov #2110$,vhvmmu mov #p1p0p2,r3 ; page 1, +2 push #1234 mtpd (r3)+ ; will fail halt 2110$: .word m0.ard!m0.pmu!m0.dsp!<1*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001001100010110 ; mmr1 +2,3; +2,6 ; ; MTPD: D space page 2 length 2200$: mov #2210$,vhvmmu mov #p2m1p0,r4 push #1234 mtpd -(r4) ; will fail halt 2210$: .word m0.ale!m0.pmu!m0.dsp!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b1111010000010110 ; mmr1 -2,4; +2,6 ; ; MTPD @(R)+: 1st access fails (in kernel space) 2300$: mov #2310$,vhvmmu mov #p6p1p2,r5 ; page 6, +1 click, +2 push #1234 mtpd @(r5)+ ; will fail halt 2310$: .word m0.ale!<6*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001010100010110 ; mmr1 +2,5; +2,6 ; ; MTPD @(R)+: 2nd access fails (in user space) 2400$: mov #2410$,vhvmmu mov #2401$,r3 push #1234 mtpd @(r3)+ ; will fail halt 2401$: .word p2m1m4 ; probed address, page 1, 128-1 click, -4 2410$: .word m0.ale!m0.pmu!m0.dsp!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001001100010110 ; mmr1 +2,3; +2,6 ; ; MTPI: I space page 0 read-only 2500$: mov #cp.pmu,cp.psw ; pm to user mov #2510$,vhvmmu mov #000020,r2 push #1234 mtpi (r2)+ ; will fail halt 2510$: .word m0.ard!m0.pmu!<0*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0001001000010110 ; mmr1 +2,2; +2,6 ; 9000$: reset ; mmu off ;! MMU off clr cp.psw mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping clr uipdr0 ; reset user mode pdr clr udpdr1 clr udpdr2 vecclr v..mmu ; restore mmu catcher 9999$: iot ; end of test C2.2 ; ; Test C2.3 -- test aborts in implied push/pop +++++++++++++++++++++++ ; jsr,mfp* have an implied push; rts,mft* have an implied pop ; This must be tested in supervisor mode to separate 'stack under test' ; from the kernel stack used in MMU 250 vector handling ; Environment: psw cm=supervisor;pm=user ; si.0 as 1-to-1 (easy switch between kernel and supervisor) ; si.1 as 1-to-1 (easy switch between kernel and supervisor) ; si.7 as 1-to-1 (psw access) ; ui.0 as 1-to-1 (for read access) ; tc0203: vecset v..mmu,vhmmua ; set up mmu handler, pr0 kernel reset mov kipdr0,sipdr0 ; super 0: 1-to-1 clr sipar0 mov kipdr1,sipdr1 ; super 1: 1-to-1 mov kipar1,sipar1 mov kipdr7,sipdr7 ; super 7: 1-to-1 mov kipar7,sipar7 mov kipdr0,uipdr0 ; user 0: 1-to-1 clr uipar0 mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 mov #cp.cms!cp.pmu,cp.psw ; cm to supervisor, pm to user ; ; part 1: -- JSR, MFPI, MFPD (push) ---------------------------------- ; Execute implicit push against a non-resident page ; Summary: ; 1000$: jsr pc,(r2) ; 1100$: mfpi (r2) ; 1200$: mfpd (r2) ; 1000$: mov #p2base+40,sp ; set SP into 1st click page 2, non-resident mov #1010$,vhvmmu mov #1001$,r2 jsr pc,(r2) ; will fail 1001$: halt 1010$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110110 ; mmr1 -2,6 ; 1100$: mov #1110$,vhvmmu mov #swsyid,r2 ; any valid address mfpi (r2) ; will fail halt 1110$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110110 ; mmr1 -2,6 ; 1200$: mov #1210$,vhvmmu mfpd (r2) ; will fail halt 1210$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000011110110 ; mmr1 -2,6 ; ; part 2: -- RTS, MTPI, MTPD (pop) ----------------------------------- ; Execute implicit pop against a non-resident page ; Summary: ; 2000$: rts pc ; 2100$: mtpi (r2) ; 2200$: mtpd (r2) ; ; Simh doesnt update SP and set MMR1 on implicit pops ; Modify expected mmr1 values in case SimH is detected cmpb systyp,#sy.sih bne 1999$ clr 2010$+2 ; expect mmr1 = 0 clr 2110$+2 ; expect mmr1 = 0 clr 2210$+2 ; expect mmr1 = 0 1999$: ; 2000$: mov #p2base+40,sp ; set SP into 1st click page 2, non-resident mov #2010$,vhvmmu rts pc ; will fail halt 2010$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010110 ; mmr1 +2,6 ; 2100$: mov #p2base+40,sp ; set SP into 1st click page 2, non-resident mov #2110$,vhvmmu mov #1,r2 ; not used mtpi (r2) ; will fail halt 2110$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010110 ; mmr1 +2,6 ; 2200$: mov #p2base+40,sp ; set SP into 1st click page 1, non-resident mov #2210$,vhvmmu mov #1,r2 ; not used mtpd (r2) ; will fail halt 2210$: .word m0.anr!m0.pms!<2*m0.pno>!m0.ena ; mmr0 ; dddddrrrdddddrrr .word ^b0000000000010110 ; mmr1 +2,6 ; 9000$: clr cp.psw reset ; mmu off ;! MMU off clr sipdr0 ; reset super/user pdf clr sipdr1 clr sipdr7 clr sipar7 clr uipdr0 vecclr v..mmu ; restore mmu catcher 9999$: iot ; end of test C2.3 ; ; Test C2.4 -- mmu abort vs nxm abort ++++++++++++++++++++++++++++++++ ; On a KB11-C a NXM abort has priority over an MMU abort. An access via ; an acf=7 (reserved) page mapped to non-existing memory is aborted as an ; NXM error (vector 4) and not as an MMU error (vector 250). On a KB11-E ; an MMU error is taken. This behavior is checked in test 122 of ekbee1. ; The w11, and also SimH and e11, follow the KB11-E behavior which is the ; natural and expected behavior. ; tc0204: mov cp.los,kipar6 ; map begin of non-existent memory mov #<127.*md.plf>!md.arw,kipdr6 ; allow access mov #m3.e22,mmr3 ; enable 22-bit mode mov #m0.ena,mmr0 ; enable mmu with traps ;! MMU 22 ; ; part 1: MMU allows access to NXM memory --> NXM abort -------------- ; 1000$: clr cp.err ; clear CPUERR vecset v..iit,1100$ ; set vector 4 handler for NXM abort clr @#p6p1p2 ; access halt 1100$: mov #stack,sp ; vector 4 taken hcmpeq cp.err,#cp.nxm ; NXM error seen vecclr v..iit ; restore iit handler to catcher ; ; part 2: MMU denies access to NXM memory --> MMU abort -------------- ; 2000$: mov #<127.*md.plf>!md.an7,kipdr6 ; deny access via acf=7 clr cp.err ; clear CPUERR vecset v..mmu,2100$ ; set vector 250 handler for MMU abort 2010$: clr @#p6p1p2 ; access halt 2100$: mov #stack,sp ; vector 250 taken htsteq cp.err ; check CPUERR: no NXM expected hcmpeq #m0.anr!<6*m0.pno>!m0.ena,mmr0 ; check mmr0 hcmpeq #2010$,mmr2 ; check mmr2: failed instruction vecclr v..mmu ; restore mmu handler to catcher ; reset ; mmu off ;! MMU off mov #001400,kipar6 ; reset kipar6 mov #<127.*md.plf>!md.arw,kipdr6 ; reset kipdr6 ; 9999$: iot ; end of test C2.4 ; ; Test C2.5 -- mmu abort in vector flow - kernel mode ++++++++++++++++ ; Verifies the MMU abort after the 2nd and 1st push in a vector flow. ; When the handler runs in kernel mode, the vector pushes are to kernel ; stack, and this results in a fatal stack error with an emergency stack ; and a vector 4 flow. ; Tested with a TRAP instruction, page 5 made non-resident, and the ; stack located at begin of page 6. ; Verify that PS and PC at the beginning of the failed vector flow are saved. ; See also cpu_details test A3.5, checks vector push abort by stklim. ; tc0205: mov #<127.*md.plf>,kipdr5 ; page 5 non-resident (afc=0) mov #177777,p6base ; set signatures (will be overwritten) mov #177777,p6base-2 ; set signatures (will stay) mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..iit,200$,cp.pr1!cp000c ; iit handler, PR1+000C as signature vecset v..mmu,110$,cp.pr2!cp00v0 ; mmu handler, PR2+00V0 as signature vecset v..trp,120$,cp.pr3!cp0z00 ; trap handler,PR3+0Z00 as signature ; ; abort on 2nd push mov #p6base+2,sp ; 2nd push will fail spl 4 ccc trap 100 100$: halt ; label after trap 110$: halt ; mmu catcher 120$: halt ; trap catcher ; 200$: htsteq sp ; check emergency stack done hcmpeq (sp),#100$ ; PC: return after trap hcmpeq 2(sp),#cp.pr4 ; PS: should be code signature ; ; abort on 1st push mov #400$,v..iit ; set up iit handler mov #p6base,sp ; 1st push will fail spl 5 scc trap 200 300$: halt ; label after trap ; 400$: htsteq sp ; check emergency stack done hcmpeq (sp),#300$ ; PC: return after trap hcmpeq 2(sp),#cp.pr5!cpnzvc ; PS: should be code signature ; ; check signatures, check that nothing written to page 5 reset ; mmu off ;! MMU off hcmpeq #cp.pr4,p6base ; code signature of 1st push of TRAP hcmpeq #177777,p6base-2 ; must be untouched ; ; restore mov #<127.*md.plf>!md.arw,kipdr5 ; reset kipdr5 vecclr v..iit ; v..iit to catcher vecclr v..mmu ; v..mmu to catcher vecclr v..trp ; v..trp to catcher mov #stack,sp ; SP to default spl 0 ; back to PR0 ; 9999$: iot ; end of test C2.5 ; ; Test C2.6 -- mmu abort in vector flow - supervisor mode ++++++++++++ ; Verifies the MMU abort after the 2nd and 1st push in a vector flow. ; When the handler is not in kernel mode a normal mmu vector 240 flow ; is started. The mmu handler runs in kernel mode with a valid stack. ; Tested with supervisor page 0+6+7 mapped 1-to-1, page 5 set non-resident, ; and a PIRQ handler in supervisor space. ; Verify that PS and PC at the beginning of the failed vector flow are saved. ; Test inspired by ekbee1 test 124. ; Verify also MMR0,MMR2 instruction complete response (unless on SimH) ; tc0206: mov kipdr0,sipdr0 ; super page 0 1-to-1 mov kipar0,sipar0 mov kipdr6,sipdr6 ; super page 6 1-to-1 mov kipar6,sipar6 mov kipdr7,sipdr7 ; super page 7 1-to-1 mov kipar7,sipar7 mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..mmu,200$,cp.pr7!cp000c ; mmu handler, PR7+000C as signature vecset v..pir,110$,cp.cms!cp.pr6!cp00v0 ; PIRQ handler in supervisor ; ; abort on 2nd push ------------------------------ mov #stack,sp ; set kernel SP mov #cp.cms!cp.pr7,cp.psw ; switch to supervisor mode, PR7 mov #p6base+2,sp ; set supervisor SP, 2nd push will fail movb #bit04,cp.pir+1 ; request PIRQ 4 ccc mov #cp.cms!cp.pr1,cp.psw ; to prio PR1 -> trigger PRIQ interrupt 100$: halt ; label after mov 110$: halt ; PIRQ catcher ; 200$: hcmpeq cp.psw,#cp.pms!cp.pr7!cp000c ; MMU handler, in kernel mode clr cp.pir ; cancel PIRQ hcmpeq sp,#stack-4 ; check stack, 1 frame hcmpeq (sp),#100$ ; PC: return after mov hcmpeq 2(sp),#cp.cms!cp.pr1 ; PS: should be code signature ; ; check mmr0,mmr2 instruction complete (unless on SimH) cmpb systyp,#sy.sih beq 290$ hcmpeq #m0.anr!m0.ale!m0.ico!m0.pms!<5*m0.pno>!m0.ena,mmr0 ; check mmr0 hcmpeq #^b1111011011110110,mmr1 ; check mmr1: two SP decrements hcmpeq #v..pir,mmr2 ; check mmr2: failed vector 290$: ; ; abort on 1st push ------------------------------ bic #m0.anr!m0.ale!m0.ard,mmr0 ; clear mmr0 abort flags mov #400$,v..mmu ; mmu handler mov #stack,sp ; set kernel SP mov #cp.cms!cp.pr7,cp.psw ; switch to supervisor mode, PR7 mov #p6base,sp ; set supervisor SP, 1st push will fail movb #bit05,cp.pir+1 ; request PIRQ 5 ccc mov #cp.cms!cp.pr2,cp.psw ; to prio PR2 -> trigger PRIQ interrupt 300$: halt ; label after mov ; 400$: hcmpeq cp.psw,#cp.pms!cp.pr7!cp000c ; MMU handler, in kernel mode clr cp.pir ; cancel PIRQ hcmpeq sp,#stack-4 ; check stack, 1 frame hcmpeq (sp),#300$ ; PC: return after mov hcmpeq 2(sp),#cp.cms!cp.pr2 ; PS: should be code signature ; ; check mmr0,mmr2 instruction complete (unless on SimH) cmpb systyp,#sy.sih beq 490$ hcmpeq #m0.anr!m0.ale!m0.ico!m0.pms!<5*m0.pno>!m0.ena,mmr0 ; check mmr0 hcmpeq #^b0000000011110110,mmr1 ; check mmr1: one SP decrement hcmpeq #v..pir,mmr2 ; check mmr2: failed vector 490$: ; ; restore ---------------------------------------- clr cp.psw ; to kernel reset ; mmu off ;! MMU off clr sipdr0 clr sipar0 clr sipdr6 clr sipar6 clr sipdr7 clr sipar7 vecclr v..mmu ; v..mmu to catcher vecclr v..pir ; v..pir to catcher mov #stack,sp ; SP to default ; 9999$: iot ; end of test C2.6 ; ; Test C2.7 -- mmu abort in 1st instruction after vector flow ++++++++ ; Verifies that 1st instruction after a vector flow has correct MMR0,MMR2 ; instruction complete signature, especially MMR0(ico)=0. Tested with an ; abort of the instruction fetch of 1st instruction. The TRAP handler ; address is set to page 6 which is made non-resident. ; tc0207: clr kipdr6 ; kernel page 6 non-resident mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..trp,p6base+10 ; TRAP handler in page 6 vecset v..mmu,200$ ; mmu handler 100$: trap 100 ; will fail halt 200$: hcmpeq #m0.anr!<6*m0.pno>!m0.ena,mmr0 ; check mmr0: ico=0 htsteq mmr1 ; check mmr1: no regs touched hcmpeq v..trp,mmr2 ; check mmr2: point to 1st instruction ; reset ; mmu off ;! MMU off mov #<127.*md.plf>!md.arw,kipdr6 ; restore kipdr6 vecclr v..mmu ; v..mmu to catcher vecclr v..trp ; v..trp to catcher mov #stack,sp ; SP to default ; 9999$: iot ; end of test C2.7 ; ; Test C2.8 -- mmu abort of prefetched instruction +++++++++++++++++++ ; Verifies that MMR2 points to the correct instruction if the fetch ; of a prefetched instruction fails. Uses the code p5ce14 initially ; written for E1.4 located at the page 4 to page 5 border. ; tc0208: clr kipdr5 ; kernel page 5 non-resident mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..mmu,200$ ; mmu handler clr r2 ; clear counter mov #100$,r3 ; ptr to failed landing jmp @#p5ce14 ; start test code ; 100$: halt ; lands here if no abort 200$: hcmpeq #3,r2 ; check, 3 executed inc hcmpeq #m0.anr!<5*m0.pno>!m0.ena,mmr0 ; check mmr0 htsteq mmr1 ; check mmr1: no regs touched hcmpeq #p5base,mmr2 ; check mmr2: point failed instruction ; reset ; mmu off ;! MMU off mov #<127.*md.plf>!md.arw,kipdr5 ; restore kipdr5 vecclr v..mmu ; v..mmu to catcher mov #stack,sp ; SP to default ; 9999$: iot ; end of test C2.8 ; ; Test C2.9 -- mmu aborts and memory status ++++++++++++++++++++++++++ ; Verifies, a bit late, that an aborted write didnt change memory ; tc0209: clr kipdr6 ; kernel page 6 non-resident mov #177777,p6base-2 ; set signatures (will be overwritten) mov #177777,p6base ; set signatures (will stay) mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..mmu,200$ ; mmu handler mov #p6base-2,r1 clr (r1)+ ; succeeds 100$: clr (r1)+ ; fails halt ; 200$: hcmpeq #m0.anr!<6*m0.pno>!m0.ena,mmr0 ; check mmr0 hcmpeq #^b00010001,mmr1 ; check mmr1: r1 +2 hcmpeq #100$,mmr2 ; check mmr2: point failed instruction ; reset ; mmu off ;! MMU off htsteq p6base-2 ; check signature hcmpeq #177777,p6base ; check signature ; mov #<127.*md.plf>!md.arw,kipdr6 ; restore kipdr6 vecclr v..mmu ; v..mmu to catcher mov #stack,sp ; SP to default ; 9999$: iot ; end of test C2.9 ; ; Test C2.10 -- mmu abort plus stack limit abort +++++++++++++++++++++ ; Consider an instruction that is aborted due to red stack violation an the ; destination address would cause an MMU abort. Tested in ekbee1 test 122 ; 2nd part. The 11/70 and the simulators take a vector 4 and do not set MMR0 ; abort bits. The w11 also takes a vector 4 but will set MMR0 abort bits. ; Verify this w11 specific behavior. ; tc0210: tstb systyp ; skip if not on w11 blt 9999$ ; mov #<127.*md.plf>,kipdr6 ; page 6 non-resident (afc=0) mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 vecset v..iit,200$,cp.pr1!cp000c ; iit handler, PR1+000C as signature vecset v..mmu,110$,cp.pr2!cp00v0 ; mmu handler, PR2+00V0 as signature mov #p6base,cp.slr ; red zone at 140340 mov #p6base+336,sp ; in red zone spl 4 ccc 90$: inc (sp) ; fails (use inc to avoid dstw cc issue) 100$: halt ; label after clr 110$: halt ; mmu catcher ; 200$: htsteq sp ; check emergency stack done hcmpeq (sp),#100$ ; PC: return after trap hcmpeq 2(sp),#cp.pr4 ; PS: should be code signature hcmpeq #m0.anr!<6*m0.pno>!m0.ena,mmr0 ; check mmr0: expect abort htsteq mmr1 ; check mmr1: no regs changed hcmpeq #90$,mmr2 ; check mmr2: instruction ; reset ; mmu off ;! MMU off mov #stack,sp ; SP to default mov #<127.*md.plf>!md.arw,kipdr6 ; reset kipdr6 vecclr v..iit ; v..iit to catcher vecclr v..mmu ; v..mmu to catcher spl 0 ; back to PR0 ; 9999$: iot ; end of test C2.10 ; ; Section D: mmr2+mmr1+mmr0 register, abort recovery ========================= ; D1 code in user mode with D space, simulated SP extend ; D2 vector push abort with simulated SP extend ; ; Test D1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Test D1.1 -- code in user mode with D space, simulated SP extend +++ ; The code is started with short stack page, stack push fails, ; the kernel handler will to stack extension and register roll back. ; td0101: ; set up emt handler vecset v..emt,vhuemt ; set up emt handler, pr0 kernel vecset v..mmu,2000$,cp.pr7 ; set up mmu handler, pr7 kernel ; set up user mode pdr/par; short code/data page 0 ; short stack page 1, base 140000, length 1 click (plf=127.) --> 157700:157776 vc2sek = 157700 ; initial end of stack in kernel view vc2seu = 037700 ; initial end of stack in user view ; mov #<8.*md.plf>!md.arw,uipdr0 mov #,uipar0 mov #<8.*md.plf>!md.arw,udpdr0 mov #,udpar0 mov #<127.*md.plf>!md.arw!md.dwn,udpdr1 mov #<140000/100>,udpar1 ; enable mmu mov #m3.dum,mmr3 ; user d dspace, no 22bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; run code vc2 in user mode -------------------------------- ; ; clear stack area seen by user code clr vc2sek-4 clr vc2sek-2 clr vc2sek clr vc2sek+2 ; clear mmr0:mmr2 save area clr 3000$ clr 3001$ clr 3002$ ; start code in user mode mov #1000$,vhustp ; set up continuation address mov #,-(sp) ; next psw: user mode clr -(sp) ; will start at 0 rti ; and launch it halt 1000$: ; continuation point hcmpeq r5,#0 ; ran sob to end ? mfpd sp ; get user SP hcmpeq (sp)+,#vc2seu-4 ; check expected value hcmpeq vc2sek+2,vc2dat ; 1st push hcmpeq vc2sek+0,vc2dat+2 ; 2nd push hcmpeq vc2sek-2,vc2dat+4 ; 3rd push hcmpeq vc2sek-4,vc2dat+6 ; 4th push hcmpeq 3000$,#!m0.ena> hcmpeq 3001$,#^b1111011000010100 ; -2,sp;2,r4 hcmpeq 3002$,# ; ; reset user mode pdr/par clr uipdr0 clr uipar0 clr udpdr0 clr udpar0 clr udpdr1 clr udpar1 ; reset ; mmu off ;! MMU off vecclr v..emt ; restore emt catcher vecclr v..mmu ; restore mmu catcher jmp 9999$ ; ; the MMU trap handler ; - saves all registers (starting with PC dummp) ; - rolls back register changes seen in MMR1 ; - increases the stack by one click ; - restore all registers ; - restarts the aborted instruction by setting PC to MMR2 ; 2000$: mov mmr0,3000$ ; record mmr0:mmr2 mov mmr1,3001$ mov mmr2,3002$ ; save all registers clr -(sp) ; save dummy PC mfpd sp ; save pm SP push r5 ; and r5..r0 push r4 push r3 push r2 push r1 push r0 ; roll back register changes mov mmr1,r0 ; get mmr1 mov #2,r1 ; handle both halfes 2100$: mov r0,r2 bic #^c7,r2 ; mask out regnum field asl r2 ; word offset add sp,r2 ; address of register on stack movb r0,r3 ; sign extend asr r3 ; and shift 3 bits right asr r3 asr r3 ; to get register correction sub r3,(r2) ; and correct register swab r0 ; go for 2nd half sob r1,2100$ ; and loop ; increase stack by one click --> decrease(!) plf mov #<126.*md.plf>!md.arw!md.dwn,udpdr1 ; restore all registers pop r0 ; restore r0..r5 pop r1 pop r2 pop r3 pop r4 pop r5 mtpd sp ; restore pm SP tst (sp)+ ; pop dummy PC ; roll back PC to re-run aborted instruction mov mmr2,(sp) ; roll back PC bic #,mmr0 ; clear abort bits rtt ; return and restart instruction ; MMU abort re-runs must use rtt to avoid a ; spurious tbit trap in case traced instruction ; 3000$: .word 0 ; save mmr0 3001$: .word 0 ; save mmr1 3002$: .word 0 ; save mmr2 ; 9999$: iot ; end of test D1.1 ; ; Test D2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Test D2.1 -- vector push abort with simulated SP extend ++++++++++++ ; This test is a full mock-up of a vector push abort recovery using the ; MMR0,MMR2 instruction complete functionality. The test setup is ; - the PIRQ handler is delegated to supervisor mode ; - the supervisor stack is too short, the 2nd push of a vector flow ; causes an MMU length abort ; - the MMU handler sees MMR0(7) set to '1', extends the stack, builds ; the return frame on the supervisor stack, and starts the PIRQ handler ; - the PIRQ handler ends with a call to a simulated system service that ; handles the RTI in kernel mode. That is necessary because an RTI from ; supervisor mode can not return to kernel mode (escalation protection). ; To simulate a full function MMU handler the test setup has in addition ; - the PIRQ handler code is in an initially unmapped page. When the code ; is started after the stack recovery, the first instruction fetch will ; cause an MMU abort, now with MMR0(7) set to '0'. The handler will map ; the code page and re-run the instruction. ; - the IO page is mapped to supervisor mode with MMU traps enabled. ; The first IO page access of the PIRQ handler will therefore cause ; an MMU trap, the handler will just log it. ; ; The supervisor mapping is: ; page 0+1 1-to-1, this allows to write to trace area ; page 2 code area, initially non-resident ; page 3 stack area, initially too short ; page 7 IO page, with RW traps enabled ; td0201: tstb systyp ; skip if not on w11 bge 100$ jmp 9999$ ; ; set up supervisor pdr/par vc3sek = 157700 ; initial end of stack in kernel view vc3ses = 077700 ; initial end of stack in supervisor view ; 100$: mov kipdr0,sipdr0 ; SM p0 1-to-1 mov kipar0,sipar0 mov kipdr1,sipdr1 ; SM p1 1-to-1 mov kipar1,sipar1 mov #<8.*md.plf>,sipdr2 ; SM p2 code, non-resident mov #,sipar2 mov #<127.*md.plf>!md.arw!md.dwn,sipdr3 ; SM p3 stack, short mov #<140000/100>,sipar3 mov #<127.*md.plf>!md.att,sipdr7 ; SM p7 IOpage + rw-trap mov kipar7,sipar7 mov #m0.ent!m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; set up handlers ; vecset v..mmu,3000$,cp.pr7 ; MMU handler, lockout interrupts vecset v..emt,4000$,cp.pr7 ; EMT handler, lockout interrupts vecset v..pir,p2base,cp.cms!cp.pr7 ;PIRQ handler (on page 2 in SM,PR7) ; ; now start the game: set SM stack, set r5 and request a PIRQ 4 ; mov #cp.pms,cp.psw ; SM now previous mode push #vc3ses+2 ; SM stack 1 word above end mtpi sp ; and set SM SP mov #2000$,r5 ; ptr to trace area mov #cp.pr1,cp.psw ; code signature PR1 movb #bit04,cp.pir+1 ; request PIRQ 4 200$: ; ; and check state and trace area ; kernel SP back to normal ; supervisor SP back to normal ; sipdr7 has AIA and AIW trace bits set ; hcmpeq #cp.pr1,cp.psw ; check PS hcmpeq #stack,sp ; check kernel SP mov #cp.pms,cp.psw ; SM now previous mode mfpi sp ; get SM SP hcmpeq #vc3ses+2,(sp)+ ; check supervisor SP clr cp.psw ; PSW to default hcmpeq #<127.*md.plf>!md.aia!md.aiw!md.att,sipdr7 ; check sipdr7 ; htaini 2000$,5. ; expect 5 items htacmp #250,#200$ ; mmu(ico=1) after movb to cp.pir+1 htacmp #250,#p2base+2 ; mmu(ico=1) after 1st instruction fetch htacmp #240,#200$ ; PIRQ, sees PC after movb to cp.pir+1 htacmp #250,#p2base+ ; mmu(trap) after clr of cp.pir htacmp #032,#p2base+ ; EMT after emt 100 ; jmp 9000$ ; 2000$: htabuf 5. ; trace area ; ; MMU handler ---------------------------------------------- ; It expects an abort with ico=1, an abort with ico=0 and a trap. ; In these three cases, first the expected environment is checked and ; after that the corrective action is taken. ; Notes: ; - the case of simultaneous MMU abort and trap (abort flags set and ; m0.trp newly set) is not handled in this simple demonstrator. ; - the code uses m*pd even though D-space is not enabled. ; - the code uses RTT to return for an instruction re-execution. That avoids ; a spurious tbit trap in case the aborted instruction was traced. ; 3000$: htstge (r5) ; r5 at fence ? mov #250,(r5)+ ; trace mov (sp),(r5)+ ; ; dispatch call cases based in mmr0 mov mmr0,r0 bit #m0.anr!m0.ale!m0.ard,r0 ; abort seen ? beq 3300$ ; if not branch to trap handling bit #m0.ico,r0 ; ico seen ? beq 3200$ ; if not branch to ico=0 handling ; ; handle abort with ico=1 ------------------------ ; Expect length error for supervisor mode I space page 3. ; Actions: ; - roll-back previous mode SP. ; - extend previous mode stack segment. ; - move stack frame from from kernel to previous mode. ; Note: the push abort leaves on the kernel stack a stack frame identical ; to what would have been on supervisor mode stack without abort. ; - start handler for aborted vector flow. ; Note: MMR2 holds the vector address. So push PS and PC of that vector ; to kernel stack and start handler with an RTT. ; hcmpeq #m0.ale!m0.ent!m0.ico!m0.pms!<3*m0.pno>!m0.ena,r0 ; check mmr0 hcmpeq #240,mmr2 ; check mmr2: PIRQ vector ; ; use MMR1 to correct SM SP mov mmr1,r1 ; get mmr1 mfpd sp ; get SM sp pop r2 cmp #^b0000000011110110,r1 ; mmr1: sp -2 bne 3100$ add #2,r2 ; correct SP by 2 br 3140$ 3100$: cmp #^b1111011011110110,r1 ; mmr1: sp -4 bne 3110$ add #4,r2 ; correct SP by 4 br 3140$ 3110$: halt ; unexpected MMR1 3140$: ; ; extend target stack frame --> decrease(!) plf ; mov #<126.*md.plf>!md.arw!md.dwn,sipdr3 ; ; move stack frame from kernel to target mode (SM) ; sub #4,r2 ; final SM SP mtpd (r2) ; move SM frame PC mtpd 2(r2) ; move SM frame PS push r2 mtpd sp ; update SM SP ; ; use MMR2 to start target handler (PIRQ) ; mov mmr2,r2 ; get vector address push 2(r2) ; handler PS push (r2) ; handler PC bic #m0.anr!m0.ale!m0.ard,mmr0 ; clear abort flags rtt ; and start handler ; ; handle abort with ico=0 ------------------------ ; Expect non-resident error for supervisor mode I space page 2 ; Actions: ; - no register roll-back done, MMR1 expected (and checked) to be 0. ; - make page resident. ; - re-run instruction, MMR2 points to its address. ; 3200$: hcmpeq #m0.anr!m0.ent!m0.pms!<2*m0.pno>!m0.ena,r0 ; check mmr0 htsteq mmr1 ; check mmr1: zero after ifetch hcmpeq #p2base,mmr2 ; check mmr2: PIRQ handler start ; ; make code page resident and re-run instruction ; bis #md.arw,sipdr2 ; code page read-writable mov mmr2,(sp) ; point to failed instruction bic #m0.anr!m0.ale!m0.ard,mmr0 ; clear abort flags rtt ; re-run instruction, use rtt to avoid a ; spurious tbit trap in case traced ; instruction ; ; handle MMU trap -------------------------------- ; Expect trap from cp.pir register access ; Actions: ; - just re-allow traps, even though none are expected ; 3300$: hbitne #m0.trp,r0 ; check mmr1 bic #m0.trp,mmr0 ; re-allow traps rti ; continue ; ; EMT handler ---------------------------------------------- ; The EMT handler simulates a system service that does a kernel mode RTI ; on behalf of the supervisor mode handler. This allows supervisor mode code ; to return to kernel mode code and bypasses the privileged escalation ; protection of RTI/RTT in a controlled manner. ; It simply moves the stack frame from previous mode to kernel mode and ; does an RTI. The EMT return frame on the kernel stack is discarded. ; 4000$: htstge (r5) ; r5 at fence ? mov #032,(r5)+ ; trace mov (sp),(r5)+ ; ; move stack frame from hander to kernel stack ; add #4,sp ; drop return frame mfpd sp ; get SM SP pop r2 mfpd 2(r2) ; move frame PS mfpd (r2) ; move frame PC add #4,r2 ; correct SM SP push r2 mtpd sp ; update SM SP rti ; finish rti from handler ; ; finally restore ------------------------------------------ 9000$: reset ;! MMU off mov #sipdr0,r0 mov #sipar0,r1 mov #4,r2 9010$: clr (r0)+ ; reset sipdr 0-3 clr (r1)+ ; reset sipar 0-3 sob r2,9010$ clr sipdr7 clr sipar7 ; vecclr v..mmu ; restore v..mmu to catcher vecclr v..emt ; restore v..emt to catcher vecclr v..pir ; restore v..pir to catcher ; 9999$: iot ; end of test D2.1 ; ; Section E: traps and pdr aia and aiw bits ================================== ; E1 basic MMU trap and PDR aia/aiw logic ; E1.1 test m0.trp, pdr aia/aiw transitions ; E1.2 systematic abort/trap testing for all valid afc ; E1.3 test trap request logic (trap on non-last access) ; E1.4 test trap request after prefetched instructions ; E2 MMU trap priority behavior ; E2.1 mmu trap + interrupt priority ; ; Test E1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Check basic MMU trap and PDR aia/aiw logic ; ; Test E1.1 -- test m0.trp, pdr aia/aiw transitions ++++++++++++++++++ ; Summary ; PDR MMR0 action aia aiw trp Trap Comment ; acf=6 ent=0 tst (r3) 0 0 0 no no ai, no trap ; clr (r3) 0 1 0 no clr sets aiw ; tst (r3) 0 1 0 no aiw stays ; pdr->pdr 0 0 0 - any pdr write clears aia,aiw ; clr (r3) 0 1 0 no clr sets aiw ; pdr+1 write 0 0 0 - any pdr write clears aia,aiw ; clr (r3) 0 1 0 no clr sets aiw ; par->par 0 0 0 - any par write clears aia,aiw ; ; acf=6 ent=1 tst (r3) 0 0 0 no no trap ; clr (r3) 0 1 0 no no trap ; ; acf=4 ent=0 tst (r3) 1 0 1 no trp set, aia set ; clr (r3) 1 1 1 no trp stays, aiw set ; trp=0;pdr 0 0 0 - any par write clears aia,aiw ; ; acf=4 ent=1 tst (r3) 1 0 1 yes trap taken, trp set, aia set ; clr (r3) 1 1 1 no no trap (trp=1!), aia set ; trp=0;pdr 0 0 0 - any pdr write clears aia,aiw ; clr (r3) 1 1 1 yes trap taken, trp,aia,aiw set ; tst (r3) 1 1 1 no no trap (trp=1!), no bits ; trp=0;pdr 0 0 0 - any par write clears aia,aiw ; ; Uses page 6 with plf=1 and varying acf. ; Checks that m0.trp must be cleared before a 2nd MMU trap is taken ; te0101: vecset v..mmu,vhmmut ; setup MMU trap handler, pr0 kernel reset mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 mov #kipdr6,r4 ; keep in register mov #p6base,r3 ; probed address clr vhvmmu ; dont expect traps initially ; ; acf=6 ent=0 tst (r3) 0 0 0 no no ai, no trap mov #md.plf!md.arw,(r4) ; set pdr tst (r3) ; probe read hbiteq mmr0,#m0.trp ; check trp=0 hcmpeq (r4),#md.plf!md.arw ; check aia,aiw=0 ; ; clr (r3) 0 1 0 no clr sets aiw clr (r3) ; probe write hbiteq mmr0,#m0.trp ; check trp=0 hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1 ; ; tst (r3) 0 1 0 no aiw stays tst (r3) ; probe read hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1 ; ; pdr->pdr 0 0 0 - any pdr write clears aia,aiw mov (r4),(r4) ; write pdr->pdr, should clear aiw hcmpeq (r4),#md.plf!md.arw ; check aiw=0 ; ; clr (r3) 0 1 0 no clr sets aiw clr (r3) ; probe write hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1 ; ; pdr+1 write 0 0 0 - any pdr write clears aia,aiw movb #1,1(r4) ; write pdr+1, should clear aiw hcmpeq (r4),#md.plf!md.arw ; check aiw=0 ; ; clr (r3) 0 1 0 no clr sets aiw clr (r3) ; probe write hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1 ; ; par->par 0 0 0 - any par write clears aia,aiw mov kipar6,kipar6 ; write par->par, should clear aiw hcmpeq (r4),#md.plf!md.arw ; check aiw=0 ; ; acf=6 ent=1 tst (r3) 0 0 0 no no trap mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps enabled tst (r3) ; probe read ; ; clr (r3) 0 1 0 no no trap clr (r3) ; probe write ; ; acf=4 ent=0 tst (r3) 1 0 1 no trp set, aia set mov #md.plf!md.att,(r4) ; set pdr mov #m0.ena,mmr0 ; enable mmu with traps disabled tst (r3) ; probe read hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.att ; check aia=1 ; ; clr (r3) 1 1 1 no trp stays, aiw set clr (r3) ; probe write hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1 ; ; trp=0;pdr 0 0 0 - any par write clears aia,aiw bic #m0.trp,mmr0 ; clear trp hbiteq mmr0,#m0.trp ; check trp=0 mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0 ; ; acf=4 ent=1 tst (r3) 1 0 1 yes trap taken, trp set, aia set mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps enabled mov #1010$,vhvmmu tst (r3) ; probe read halt ; expect trap 1010$: hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.att ; check aia=1 ; ; clr (r3) 1 1 1 no no trap (trp=1!), aia set clr (r3) ; probe write hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1 ; ; trp=0;pdr 0 0 0 - any pdr write clears aia,aiw bic #m0.trp,mmr0 ; clear trp mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0 ; ; clr (r3) 1 1 1 yes trap taken, trp,aia,aiw set mov #1020$,vhvmmu clr (r3) ; probe write halt ; expect trap 1020$: hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1 ; ; tst (r3) 1 1 1 no no trap (trp=1!), no additional bits tst (r3) ; probe read hbitne mmr0,#m0.trp ; check trp=1 hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1 ; ; trp=0;pdr 0 0 0 - any par write clears aia,aiw bic #m0.trp,mmr0 ; clear trp mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0 ; 9000$: reset ; mmu off ;! MMU off clr cp.psw mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping vecclr v..mmu ; restore mmu catcher 9999$: iot ; end of test E1.1 ; ; Test E1.2 -- systematic abort/trap testing for all valid afc +++++++ ; Summary ; afc action handler abort aia aiw trap Comment ; 0 tst (r3) r-abo anr 0 0 no ; 0 add r0,(r3) w-abo anr 0 0 no ; 1 tst (r3) r-trap - 1 0 yes ; 1 add r0,(r3) w-abo ard 0 0 no ; 2 tst (r3) r-ok - 0 0 no ; 2 add r0,(r3) w-abo ard 0 0 no ; 4 tst (r3) r-trap - 1 0 yes ; 4 clr (r3) w-trap - 1 1 yes ; 5 tst (r3) r-ok - 0 0 no ; 5 clr (r3) w-trap - 1 1 yes ; 6 tst (r3) r-ok - 0 0 no ; 6 mov r0,(r3) w-ok - 0 1 no ; te0102: vecset v..mmu,vhmmut ; setup MMU trap handler, pr0 kernel reset mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18 clr vhvmmu ; dont expect traps initially ; mov #3000$,r5 ; ptr to data table mov #kipdr6,r4 ; keep in register mov #p6base,r3 ; probed address mov #vhvmmu,r2 ; ptr to vhvmmu ; 1000$: mov (r5)+,(r4) ; load pdr jmp @(r5)+ ; execute case handler ; ; case r-ok: read, no abort, no trap 1100$: clr (r2) ; no abort/trap expected tst (r3) ; probe read br 1900$ ; to ok-check ; ; case r-abo: read, abort 1200$: mov #vhmmua,v..mmu ; setup MMU abort handler mov (r5)+,1210$ mov #1210$,(r2) tst (r3) ; probe read halt ; expect abort 1210$: .word 0,0 br 1910$ ; to abo-check ; ; case r-trap: read, trap 1300$: mov #vhmmut,v..mmu ; setup MMU trap handler mov #1900$,(r2) ; to ok-check tst (r3) ; probe read halt ; expect trap ; ; case w-ok: write, no abort, no trap 1400$: clr (r2) ; no abort/trap expected mov r0,(r3) ; probe write br 1900$ ; to ok-check ; ; case w-abo: write, abort 1500$: mov #vhmmua,v..mmu ; setup MMU abort handler mov (r5)+,1510$ mov #1510$,(r2) add r0,(r3) ; probe write halt ; expect abort 1510$: .word 0,0 br 1910$ ; to tr-check ; ; case w-trap: write, trap 1600$: mov #vhmmut,v..mmu ; setup MMU trap handler mov #1900$,(r2) clr (r3) ; probe write halt ; expect trap ; 1900$: tst (r5)+ ; drop unused mmr0 info 1910$: mov (r5)+,r0 ; get pdrexp hcmpeq (r4),r0 ; check pdr mov (r4),(r4) ; clear pdr aia,aiw bic #m0.trp,mmr0 ; clear mmr0 trp flag tst (r5) ; look at next case beq 9000$ ; if eq end sentinel found ? br 1000$ ; if ne go for next case ; 3000$: .word md.plf ; afc=0 + read: - anr ------- .word 1200$ ; r-abo .word m0.anr!m0.ent!<6*m0.pno>!m0.ena ; mmr0 .word md.plf ; pdf: no aib ; .word md.plf ; afc=0 + write: - anr ------- .word 1500$ ; w-abo .word m0.anr!m0.ent!<6*m0.pno>!m0.ena ; mmr0 .word md.plf ; pdf: no aib ; .word md.plf!md.ata ; afc=1 + read: - trp aia --- .word 1300$ ; r-trap .word 0 ; mmr0 .word md.plf!md.aia!md.ata ; pdf: aia ; .word md.plf!md.ata ; afc=1 + write: - ard ------- .word 1500$ ; w-abo .word m0.ard!m0.ent!<6*m0.pno>!m0.ena ; mmr0 .word md.plf!md.ata ; pdf: no aib ; .word md.plf!md.ara ; afc=2 + read: ------------- .word 1100$ ; r-ok .word 0 ; mmr0 .word md.plf!md.ara ; pdf: no aib ; .word md.plf!md.ara ; afc=2 + write: - ard ------- .word 1500$ ; w-abo .word m0.ard!m0.ent!<6*m0.pno>!m0.ena ; mmr0 .word md.plf!md.ara ; pdf: no aib ; .word md.plf!md.att ; afc=4 + read: - trp aia --- .word 1300$ ; r-trap .word 0 ; mmr0 .word md.plf!md.aia!md.att ; pdf: aia ; .word md.plf!md.att ; afc=4 + write - trp aia,aiw .word 1600$ ; w-trap .word 0 ; mmr0 .word md.plf!md.aia!md.aiw!md.att ; pdf: aia aiw ; .word md.plf!md.art ; afc=5 + read: ------------- .word 1100$ ; r-ok .word 0 ; mmr0 .word md.plf!md.art ; pdf: no aib ; .word md.plf!md.art ; afc=5 + write: - trp aia,aiw .word 1600$ ; w-trap .word 0 ; mmr0 .word md.plf!md.aia!md.aiw!md.art ; pdf: aia aiw ; .word md.plf!md.arw ; afc=6 + read: ------------- .word 1100$ ; r-ok .word 0 ; mmr0 .word md.plf!md.arw ; pdf: no aib ; .word md.plf!md.arw ; afc=6 + write: - aiw ------- .word 1400$ ; w-ok .word 0 ; mmr0 .word md.plf!md.aiw!md.arw ; pdf: aiw ; .word 0 ; end sentinel ------------------------------ ; 9000$: reset ; mmu off ;! MMU off clr cp.psw mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping vecclr v..mmu ; restore mmu catcher 9999$: iot ; end of test E1.2 ; ; Test E1.3 -- test trap request logic (trap on non-last access) +++++ ; Test cases where an instruction does multiple memory accesses and the ; trap condition is not met on the last one. This verifies that the trap ; request is properly recorded and handled at end of instruction execution. ; Page 6 has traps enabled (afc=4), all others not. ; te0103: mov #mmr0,r2 ; ptr to mmr0 mov #p6base,r3 ; ptr to page6 (MMU traps enabled) mov #1500$,r4 ; ptr to page0 (MMU traps disabled) mov r4,(r3) ; p6base holds ptr to 1500$ clr (r4) ; clear target location clr 2(r4) mov #<127.*md.plf>!md.att,kipdr6 ; enable traps (afc=4) mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18 ; vecset v..mmu,vhmmut ; setup MMU trap handler mov #1010$,vhvmmu mov (r3),r5 ; check r(p6) - trival case halt ; 1010$: mov #1020$,vhvmmu bic #m0.trp,(r2) ; clear trp mov (r3),(r4) ; check r(p6),w(p0) halt ; 1020$: mov #1030$,vhvmmu bic #m0.trp,(r2) ; clear trp mov @(r3)+,2(r4) ; check r(p6),r(p0),r(p0),w(p0) halt ; 1030$: mov #1040$,vhvmmu bic #m0.trp,(r2) ; clear trp inc @-(r3) ; check r(p6),rm(p0),wm(p0) halt ; 1040$: hcmpeq #1500$+1,1500$ ; check proper values in target hcmpeq #1500$,1500$+2 ; as internal consistency check br 2000$ ; 1500$: .word 0 .word 0 ; 2000$: reset ; mmu off ;! MMU off mov #<127.*md.plf>!md.arw,kipdr6 ; reset kipdr6 vecclr v..mmu ; reset v..mmu ; 9999$: iot ; end of test E1.3 ; ; Test E1.4 -- test trap request after prefetched instructions +++++++ ; The w11 starts a prefetch of the next instruction when the decode step ; detects a register-only operate instruction (as the 11/70 does). ; This test checks whether MMU traps are properly detected. ; Page 5 has traps enabled (afc=4). A sequence of 'inc r2' instructions is ; executed which start in page 4 and continue in page 5. The first in page 5 ; should cause an MMU trap. ; te0104: mov #<127.*md.plf>!md.att,kipdr5 ; enable traps (afc=4) mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18 clr r2 ; clear counter mov #1000$,r3 ; ptr to failed landing vecset v..mmu,vhmmut ; setup MMU trap handler mov #1100$,vhvmmu jmp @#p5ce14 ; start test code ; 1000$: nop ; lands here if no trap halt 1100$: hcmpeq #4.,r2 ; check counter ; reset ; mmu off ;! MMU off mov #<127.*md.plf>!md.arw,kipdr5 ; reset kipdr5 vecclr v..mmu ; reset v..mmu ; 9999$: iot ; end of test E1.4 ; ; Test E1.5 -- test trap request after IO page access ++++++++++++++++ ; te0105: mov #<127.*md.plf>!md.att,kipdr7 ; enable traps (afc=4) vecset v..mmu,vhmmut ; setup MMU trap handler mov #1000$,vhvmmu ; ; The write to mmr0 will not trigger a trap on w11 because the trap decision ; is taken during address translation and thus before MMR0 is changed. ; The read access to cp.psw will cause an MMU trap. mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18 tst cp.psw halt ; 1000$: reset ; mmu off ;! MMU off mov #<127.*md.plf>!md.arw,kipdr7 ; reset kipdr7 vecclr v..mmu ; reset v..mmu ; 9999$: iot ; end of test E1.5 ; ; Test E2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; Check MMU trap priority behavior ; ; common handler setup for trap and interrupt priority tests ; vecset v..mmu,vhtmmu,cp.pr7 ; mmu trap handler, PR7 (lockout PIRQ) vecset v..pir,vhtpir,cp.pr7 ; PIRQ handler, PR7 (prevent retrigger) mov #<127.*md.plf>!md.att,kipdr5 ; enable traps in page 5 (afc=4) ; ; Test E2.1 -- mmu trap + interrupt priority +++++++++++++++++++++++++ ; te0201: mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18 mov #1500$,r5 ; set up data pointer ; spl 0 ; ensure PR0 call p5ce21 ; start probe code in page 5 1000$: br 2000$ ; rts will land here ; 1500$: htabuf 3. ; trace area ; 2000$: htaini 1500$,3. ; expect 3 items htacmp #250,#p5ce21+6 ; mmu for movb htacmp #240,#p5ce21+6 ; PIRQ, sees PC after movb htacmp #250,#1000$ ; mmu for rts, PC is return address ; reset ; mmu off ;! MMU off ; 9999$: iot ; end of test E2.1 ; ; common restore for section E2 -------------------------------------- ; mov #<127.*md.plf>!md.arw,kipdr5 ; reset kipdr5 vecclr v..mmu ; restore v..mmu to catcher vecclr v..pir ; restore v..pir to catcher ; ; Section F: miscellaneous =================================================== ; F1 test D-to-I mapping ; F1.1 for (PC) address modes I ; F1.2 for (PC) address modes II ; F2 test LOSIZE register and access to full memory ; ; Test F1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Test F1.1 -- test D-to-I mapping for (PC) address modes I ++++++++++ ; In case of immediate (pc)+ and absolute @(pc)+ addressing the first read ; comes from I space. Same holds for (pc) specifiers. The remaining two modes ; -(pc) and @-(pc) have no practical use and cant even be tested. ; The test runs with D space disabled and the D page 0 set non-resident. ; If any access to D space will cause an MMU abort. Because kernel D page 0 is ; non-resident, the vector fetch will fail and the CPU halts with an F:vecfet. ; ; Summary ; (pc)+ srcr: mov #nnn,r0 ; (pc)+ dstr: tst #nnn ; (pc)+ dstr: cmp r0,#nnn ; (pc)+ dstw: mov r0,#nnn ; @(pc)+ srcr: mov @#val,r0 ; @(pc)+ dstr: tst @#val ; @(pc)+ dstr: cmp r0,@#val ; @(pc)+ dstw: mov r0,@#val ; (pc) srcr: mov (pc),r0 ; (pc) dstr: tst (pc) ; (pc) dstr: cmp r0,(pc) ; (pc) dstw: mov r0,(pc) ; tf0101: mov #m3.dkm,mmr3 ; enable D space for kernel clr kdpdr0 ; ensure D space non-resident mov kipdr6,kdpdr6 ; set up page 6 D space 1-to-1 mov kipar6,kdpar6 ; mov #234,100$+2 ; restore target mov #345,p6base ; restore target mov #ccc,300$ ; restore target clr r2 mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; (pc)+ mov #123,r0 ; src immediate tst #123 ; dstr immediate cmp r0,#123 ; dstr immediate 100$: mov r0,#234 ; dstw immediate (overwrites I space!) ; ; @(pc)+ mov @#p6base,r1 ; src absolute tst @#p6base ; dstr absolute cmp r1,@#p6base ; dstr absolute mov r0,@#p6base ; dstw absolute (write #123 to D space) ; ; (pc) mov (pc),r2 ; src (read next instruction, a ccc) 200$: ccc tst (pc) ; dstr (read next instruction) cmp r2,(pc) ; dstr (read next instruction) mov r2,(pc) ; dstw (overwrites I space!) 300$: scc ; reset ; mmu off ;! MMU off hcmpeq 100$+2,#123 ; I space overwritten ? hcmpeq p6base,#123 ; D space overwritten ? hcmpeq r2,200$ ; read from I space ? hcmpeq 300$,#ccc ; clr kdpdr6 ; reset kdpdr6 clr kdpar6 ; reset kdpar6 vecclr v..mmu ; restore mmu catcher ; 9999$: iot ; end of test F1.1 ; ; Test F1.2 -- test D-to-I mapping for (PC) address modes II +++++++++ ; In case of absolute @(pc)+ addressing the first access goes to I space ; and the second to D space. The test uses page 6 as target and runs with ; D page 6 mapped and the I page 6 set non-resident. ; ; Summary ; @(pc)+ srcr: mov @#val,r0 ; @(pc)+ dstr: cmp r0,@#val ; @(pc)+ dstw: mov r0,@#val ; tf0102: mov #154345,@#p6base ; inititialize target mov #m3.dkm,mmr3 ; enable D space for kernel mov kipdr6,kdpdr6 ; set up page 6 D space 1-to-1 mov kipar6,kdpar6 push kipdr6 ; save I page 6 clr kipdr6 ; ensure I page 6 non-resident mov #m0.ena,mmr0 ; enable mmu ;! MMU 18 ; ; @(pc)+ srcr mov @#p6base,r1 ; @(pc)+ dstr cmp r1,@#p6base beq 100$ halt 100$: mov r1,r2 inc r2 ; @(pc)+ dstw mov r2,@#p6base ; reset ; mmu off ;! MMU off pop kipdr6 ; restore I page 6 clr kdpdr6 ; reset kdpdr6 clr kdpar6 ; reset kdpar6 ; hcmpeq r1,#154345 hcmpeq @#p6base,#154346 ; 9999$: iot ; end of test F1.2 ; ; Test F2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ; ; Test F2.1 -- test LOSIZE register and access to full memory ++++++++ ; Read memory size from LOSIZE, write one word every 64 kB and read back. ; Quite fast: at most 60 words (4M-256k)/64k. ; Tests runs with kernel D space enabled (an exception!) ; tf0201: mov kipdr0,kdpdr0 ; set up kernel D space 1-to-1 mapping mov kipar0,kdpar0 mov kipdr1,kdpdr1 mov kipar1,kdpar1 mov kipdr6,kdpdr6 mov kipar6,kdpar6 mov kipdr7,kdpdr7 mov kipar7,kdpar7 mov #m3.e22!m3.dkm,mmr3 ; enable D space for kernel; 22 bit mov #m0.ena,mmr0 ; enable mmu ;! MMU 22 ; htsteq hisize ; HISIZE must be zero mov losize,r0 ; last accessible click (64B) inc r0 ccc ror r0 ; shift right 10 bits, no sign extend ash #-9.,r0 ; memory size in 64 kB chunks dec r0 ; number of chunks to test ble 2000$ ; quit if memory too small mov #2000,r1 ; step size 64kB in clicks mov #kdpar6,r2 ; ptr to kdpar6 mov #p6base,r3 ; ptr to write/read test location ; write memory mov r0,r4 ; initialize counter mov r1,r5 ; initialize current par 100$: mov r5,(r2) ; set par mov r5,(r3) ; write data add r1,r5 ; bump pointer sob r4,100$ ; read memory mov r0,r4 ; initialize counter mov r1,r5 ; initialize current par 200$: mov r5,(r2) ; set par hcmpeq r5,(r3) ; check data add r1,r5 ; bump pointer sob r4,200$ ; 2000$: reset ; mmu off ;! MMU off clr kdpdr0 clr kdpar0 clr kdpdr1 clr kdpar1 clr kdpdr6 clr kdpar6 clr kdpdr7 clr kdpar7 ; 9999$: iot ; end of test F2.1 ; ; END OF ALL TESTS - loop closure ============================================ ; mov tstno,r0 ; hack, for easy monitoring ... hcmpeq tstno,#33. ; all tests done ? call chkpdr ; kernel pdr/par OK ? ; jmp loop ; ; pdr/par consistency checker ; Verify that all I-space pdr/par are in default configuration set up by A1.2. ; Implentend as subroutine for debug purposes. Always called at end of tests. ; chkpdr: mov #kipdr0,r0 ; check kernel mov #kipar0,r1 mov #<127.*md.plf>!md.arw,r2 ; default pdr clr r3 ; current par mov #200,r4 ; par increment mov #7.,r5 ; check 0...6 100$: mov (r0),(r0) ; clear AI bits with re-write hcmpeq r2,(r0)+ ; check pdr hcmpeq r3,(r1)+ ; check par add r4,r3 ; step to next par value sob r5,100$ mov (r0),(r0) ; clear AI bits with re-write hcmpeq r2,(r0)+ ; check pdr7 hcmpeq #177600,(r1)+ ; check par7 ; mov #sipdr0,r0 ; check supervisor + user mov #sipar0,r1 mov #uipdr0,r2 mov #uipar0,r3 mov #8.,r4 200$: htsteq (r0)+ ; check sipdr htsteq (r1)+ ; check sipar htsteq (r2)+ ; check uipdr htsteq (r3)+ ; check uipar sob r4,200$ return ; ; kernel handlers and helpers ================================================ ; ; vhmmua - expected mmu abort handler ++++++++++++++++++++++++++++++++++++++++ ; used to catch expected MMU aborts ; the pointer to expected mmr0/mmr1 values must be in vhvmmu ; code will continue after the test value context ; execution will clear vhvmmu ; --> vhvmmu must be set for each execution ; the handler uses and modifies r0,r1 ; --> tests should only use r2,...,r5 ; vhmmua: mov vhvmmu,r1 ; get context beq 1000$ ; if 0 halt hcmpeq mmr0,(r1)+ ; check mmr0 hcmpeq mmr1,(r1)+ ; check mmr1 bic #m0.anr!m0.ale!m0.ard,mmr0 ; reset mmr0 abort flags mov r1,(sp) ; set up kernel return address clr vhvmmu ; reset context rti ; end return to continuation address 1000$: halt vhvmmu: .word 0 ; context pointer ; ; vhmmut - expected mmu trap handler +++++++++++++++++++++++++++++++++++++++++ ; used to catch expected MMU traps ; the pointer to continuation address must be in vhvmmu ; execution will clear vhvmmu ; --> vhvmmu must be set for each execution ; the handler uses and modifies r0,r1 ; --> tests should only use r2,...,r5 ; vhmmut: mov vhvmmu,r1 ; get context beq 1000$ ; if 0 halt mov mmr0,r0 hbiteq r0,#m0.anr!m0.ale!m0.ard ; check abort flags 0 hbitne r0,#m0.trp ; check trap flag 1 mov r1,(sp) ; set up kernel return address clr vhvmmu ; reset context rti ; end return to continuation address 1000$: halt ; ; vhuemt - emt handler, drop frame, continue in kernel mode ++++++++++++++++++ ; use to end user/supervisor mode code with an emt xxx ; the kernel continution address must be written to vhustp ; execution will reset vhustp to a catcher value ; --> vhustp must be set for each execution ; vhuemt: tst (sp)+ ; discard one word of vector push mov vhustp,(sp) ; set up kernel return address mov #vhuhlt,vhustp ; reset stop address by catcher rts pc ; end return to continuation address vhustp: .word vhuhlt vhuhlt: halt ; ; vhtmmu - handler for MMU trap tracing ++++++++++++++++++++++++++++++++++++++ ; Writes signature to data area (ptr in r5). ; Signature is vector address + return PC (PC to test proper context). ; Clears MMR0(trp) bit to allow further MMU traps ; vhtmmu: htstge (r5) ; r5 at fence ? bic #m0.trp,mmr0 ; allow further MMU traps htaadd #v..mmu ; track MMU vector, track return PC rti ; ; vhtpir - handler for PIRQ interrupt tracing ++++++++++++++++++++++++++++++++ ; Writes signature to data area (ptr in r5). ; Signature is vector address + return PC (PC to test proper context). ; Clears all PIRQ requests to prevent interrupt loop. ; vhtpir: htstge (r5) ; r5 at fence ? clr cp.pir ; clear all PIRQ interrupts htaadd #v..pir ; track PIRQ vector, track return PC rti ; ; Test codes that will be mapped in user or supervisor mode ================== ; They are located in page 4 at 100000 and above and are position-independent ; code. That allows to assemble and load them together with the main code. ; . = 100000 ; ; vc0 - simple code ++ used from B3.1 ++++++++++++++++++++++++++++++++++++++++ ; uses jsr, has stack below 1000 (no problem in user/supervisor mode) ; does operations with vc0v0, vc0v1, vc0v2 ; these location are usually set before and checked afterwards in kernel mode ; vc0: jmp 100$ .blkw 14. ; small stack space 100$: mov #40,sp ; initialize stack call 1000$ emt 100 ; will end user/supervisor code ; 1000$: com vc0v0 call 2000$ return 2000$: add vc0v1,vc0v2 return ; vc0v0: .word 0 vc0v1: .word 0 vc0v2: .word 0 ; ; vc1 - simple I/D code ++ used from B3.2 ++++++++++++++++++++++++++++++++++++ ; uses jsr, has stack below 1000 (no problem in user/supervisor mode) ; does operations with vc1v0, vc1v1, vc1v2 ; these locations are usually set before and checked afterwards in kernel mode ; . = 101000 ; I space ------------------------------------ vc1: mov #,sp ; initialize stack mov #,r5 ; initialize data pointer call 1000$ emt 100 ; will end user/supervisor code ; 1000$: com (r5) ; will access vc1v0 call 2000$ return 2000$: add 2(r5),4(r5) ; will access vc1v1 and vc1v2 return ; vc1ida: .word 0 ; I space location, M*PI read/write target ; . = 102000 ; D space ------------------------------------ vc1dat: .blkw 16. ; small stack space vc1stk: vc1v0: .word 0 vc1v1: .word 0 vc1v2: .word 0 ; ; vc2 - stack push I/D code ++ used from D1.1 ++++++++++++++++++++++++++++++++ ; set SP just above the stack page end; push data ; expect kernel handler to extend the stack and re-run failed push ; . = 103000 ; I space ------------------------------------ vc2: mov #vc2seu+4,sp ; 4 bytes above initial end mov #,r4 ; initialize data pointer to vc2dat mov #4.,r5 ; set loop count vc2l1: push (r4)+ ; push data sob r5,vc2l1 emt 100 ; will end code ; . = 104000 ; D space ------------------------------------ vc2dat: .word 010111 .word 010222 .word 010333 .word 010444 ; ; vc3 - PIRQ handler code ++ used from D2.1 ++++++++++++++++++++++++++++++++++ ; Simply cancels all PIRQ interrupts. ; Will be mapped to page 2, the code must therefore be position-independent. ; . = 105000 ; I space ------------------------------------ vc3: htstge (r5) ; r5 at fence ? htaadd #v..pir ; track PIRQ vector, track return PC clr @#cp.pir ; cancel PIRQ (use absolute mode!) vc3l1: emt 100 ; delegate RTI to system service vc3l2: halt ; label after emt ; ; vc4 - MFPI/MTPI user mode test code ++ used from B3.3 ++++++++++++++++++++++ ; Returns all values to be checked in registers ; r0: D space access to vc4v1 ; r1: MFPI read of vc4v2; I space requested, but D space received ; r2: MFPD read of vc4v3 ; . = 106000 ; I space ------------------------------------ vc4: mov #,sp ; initialize stack mov @#vc4v1-vc4dat+p1base,r0 ; simple D space access mfpi @#vc4v2-vc4dat+p1base ; reads D space! I would abort! pop r1 ; save value mfpd @#vc4v3-vc4dat+p1base ; read D space pop r2 ; save value push #040444 mtpi vc4l1 ; write to I space allowed emt 100 ; will end code ; vc4l1: .word 0 ; . = 107000 ; D space ------------------------------------ vc4dat: .blkw 16. ; small stack space vc4stk: vc4v1: .word 040111 vc4v2: .word 040222 vc4v3: .word 040333 ; ; p5ce14 Test E1.4 test code +++++++++++++++++++++++++++++++++++++++++ ; located at border of page 4 and page 5 (touching both) ; . = p5base-6 p5ce14: inc r2 ; @117772; r2=1 inc r2 ; @117774; r2=2 inc r2 ; @117776; r2=3 inc r2 ; @120000; r2=4 <-- should trap here inc r2 ; @120002; r2=5 inc r2 ; @120004; r2=6 inc r2 ; @120006; r2=7 jmp (r3) ; return to main code ; ; p5ce21 Test E2.1 test code +++++++++++++++++++++++++++++++++++++++++ ; p5ce21: movb #bit01,cp.pir+1 ; request PIRQ 1 return ; and return to main flow ; .end start