1
0
mirror of https://github.com/wfjm/w11.git synced 2026-01-13 15:37:43 +00:00
wfjm.w11/tools/tcode/cpu_mmu.mac

1838 lines
70 KiB
Plaintext

; $Id: cpu_mmu.mac 1301 2022-10-06 08:53:46Z mueller $
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright 2022- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
;
; Revision History:
; Date Rev Version Comment
; 2022-09-10 1297 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
; Section C: mmr1+mmr0 register, aborts
; Section D: mmr2+mmr1+mmr0 register, abort recovery
; Section E: traps and pdr aia and aiw bits
; Section F: miscellaneous
;
.include |lib/tcode_std_base.mac|
.include |lib/defs_mmu.mac|
; 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
sipdr7 = sipdr+16
sipar7 = sipar+16
kipdr0 = kipdr+ 0
kdpdr0 = kdpdr+ 0
kipdr6 = kipdr+14
kipar6 = kipar+14
kdpdr6 = kdpdr+14
kdpar6 = kdpar+14
kipdr7 = kipdr+16
kipar7 = kipar+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 ===============================================
;
; 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 18 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)
;
; 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
;
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
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
;
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
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
hbitne #m0.ena,mmr0 ; test bit ;! MMU 18
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 stll seen ??? ;! MMU 22
; test RESET
reset ; should clear mmr0 and mmr3
htsteq mmr0 ; check mmr0 cleared ;! MMU off
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
mov #vhuemt,v..emt
clr v..emt+2 ; pr0 kernel
; enable mmu
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 #<vc0/100>,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 #<cp.cmu!cp.pmu>,-(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 #<vc0/100>,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 #<cp.cms!cp.pms>,-(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
mov #v..emt+2,v..emt ; restore emt catcher
clr v..emt+2
;
9999$: iot ; end of test B3.1
;
; Test B3.2 -- run code in user mode with D space enabled ++++++++++++
; code vc1 is executed in user and in supervisor mode
; the code runs in seg0 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:
; set up emt handler
mov #vhuemt,v..emt
clr v..emt+2 ; pr0 kernel
; enable mmu
mov #m3.dum,mmr3 ; user d dspace, no 22bit
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
;
; 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 #<vc1/100>,uipar0
mov #<8.*md.plf>!md.arw,udpdr0
mov #<vc1dat/100>,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 #<cp.cmu!cp.pmu>,-(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
;
; test MFPD (data access)
;
mov #<vc1v0-vc1dat>,r5 ; initialize data pointer
mfpd (r5) ; read vc1v0
hcmpeq (sp)+,#157472
mfpd @#<vc1v2-vc1dat> ; 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$
;
; test MFPI (data access)
;
mov #<vc1-vc1>,r5 ; initialize data pointer
mfpi (r5) ; read 1st instruction word
hcmpeq (sp)+,vc1
;
; test MTPI and MFPI, incl cc (data access)
;
mov #<vc1ida-vc1>,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$
;
; Test MTPD,MFPD with @(sp)+
; Note: (sp)+ is not a useful address mode for MTPD
; It will use the cm sp as address in pm.
; So @(sp)+ is the only mode with sp in src worth to be tested
;
clr vc1v0
push #<vc1v0-vc1dat> ; 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 #<vc1v0-vc1dat> ; D addr of vc1v0
mfpd @(sp)+
hcmpeq (sp)+,#054322 ; check
;
; Test MTPI,MFPI with @(sp)+
;
clr vc1ida
push #<vc1ida-vc1> ; 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 #<vc1ida-vc1> ; I addr of vc1ida
mfpi @(sp)+
hcmpeq (sp)+,#012322 ; check
;
; 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)+,#<vc1stk-vc1dat> ; check
mfpi sp ; read user mode sp (same for I and D)
hcmbeq (sp)+,#<vc1stk-vc1dat> ; 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
;
; 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
mov #v..emt+2,v..emt ; restore emt catcher
clr v..emt+2
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
;
; Section C: mmr1+mmr0 register, aborts ======================================
;
; Test C1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; 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: mov #vhmmua,v..mmu
clr v..mmu+2 ; 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
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
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: mov #vhmmua,v..mmu
clr v..mmu+2 ; 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
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
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.7 as 1-to-1 (psw access)
; ui.0 as 1-to-1 (for read access)
;
tc0203: mov #vhmmua,v..mmu
clr v..mmu+2 ; pr0 kernel
reset
mov kipdr0,sipdr0 ; super 0: 1-to-1
clr sipar0
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 #020100,sp ; set SP into 1st click page 1, non-resident
mov #1010$,vhvmmu
mov #1001$,r2
jsr pc,(r2) ; will fail
1001$: halt
1010$: .word m0.anr!m0.pms!<1*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!<1*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!<1*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 #020040,sp ; set SP into 1st click page 1, non-resident
mov #2010$,vhvmmu
rts pc ; will fail
halt
2010$: .word m0.anr!m0.pms!<1*m0.pno>!m0.ena ; mmr0
; dddddrrrdddddrrr
.word ^b0000000000010110 ; mmr1 +2,6
;
2100$: mov #2110$,vhvmmu
mov #1,r2 ; not used
mtpi (r2) ; will fail
halt
2110$: .word m0.anr!m0.pms!<1*m0.pno>!m0.ena ; mmr0
; dddddrrrdddddrrr
.word ^b0000000000010110 ; mmr1 +2,6
;
2200$: mov #2210$,vhvmmu
mov #1,r2 ; not used
mtpd (r2) ; will fail
halt
2210$: .word m0.anr!m0.pms!<1*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 sipdr7
clr sipar7
clr uipdr0
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
9999$: iot ; end of test C2.3
;
;
; Section D: mmr2+mmr1+mmr0 register, abort recovery =========================
;
; 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
mov #vhuemt,v..emt
clr v..emt+2 ; pr0 kernel
; set up mmu handler
mov #2000$,v..mmu
mov #cp.pr7,v..mmu+2
; 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 #<vc2/100>,uipar0
mov #<8.*md.plf>!md.arw,udpdr0
mov #<vc2dat/100>,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 #<cp.cmu!cp.pmu>,-(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
;
; SimH wrongly sets m0.ico, skip mmr0 check for SimH
cmpb systyp,#sy.sih
beq 1010$
hcmpeq 3000$,#<m0.ale!m0.pmu!m0.dsp!<1*m0.pno>!m0.ena>
;
1010$: hcmpeq 3001$,#^b1111011000010100 ; -2,sp;2,r4
hcmpeq 3002$,#<vc2l1-vc2>
;
; reset user mode pdr/par
clr uipdr0
clr uipar0
clr udpdr0
clr udpar0
clr udpdr1
clr udpar1
;
reset ; mmu off ;! MMU off
mov #v..emt+2,v..emt ; restore emt catcher
clr v..emt+2
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
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
asr r3
asr r3
asr r3 ; 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 #<m0.anr!m0.ale!m0.ard>,mmr0 ; clear abort bits
rti ; return and restart instruction
;
3000$: .word 0 ; save mmr0
3001$: .word 0 ; save mmr1
3002$: .word 0 ; save mmr2
;
9999$: iot ; end of test D1.1
;
; Section E: traps and pdr aia and aiw bits ==================================
;
; Test E1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; 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, 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, no additional bits
; trp=0;pdr 0 0 0 - any par write clears aia,aiw
;
; Uses page 6 with plf=1 and varying acf
;
te0101: mov #vhmmut,v..mmu ; setup MMU trap handler
clr v..mmu+2 ; 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, 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, 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
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
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: mov #vhmmut,v..mmu ; setup MMU trap handler
clr v..mmu+2 ; 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
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
9999$: iot ; end of test E1.2
;
; Section F: miscellaneous ===================================================
;
; 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
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
;
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
;
; Summary
;; END OF ALL TESTS - loop closure ============================================
;
mov tstno,r0 ; hack, for easy monitoring ...
hcmpeq tstno,#17. ; all tests done ?
;
jmp loop
;
; kernel handlers ============================================================
;
; 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
mov mmr0,r0
bic #m0.ico,r0 ; mask ico (for Simh compatibility)
hcmpeq r0,(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
;
; Test codes that will be mapped in user or supervisor mode ==================
; They are located at 100000 and above and are position-independent code.
; That allows to assemble and load them together with the main code.
;
; vc0 - simple code ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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
;
. = 100000
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 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
; 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 #<vc1v0-vc1dat>,sp ; initialize stack
mov #<vc1v0-vc1dat>,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 ++++++++++++++++++++++++++++++++++++++++++++++++++
; 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 #<vc2dat-vc2dat>,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
;
.end start