mirror of
https://github.com/wfjm/w11.git
synced 2026-01-19 01:47:47 +00:00
- tools/bin
- asm-11
- add minimal .list,.nlist (cnd,me,meb) directive support
- add -(n)list options
- tools/asm-11
- tests(-err): some tuneups
- mlib: some macros added, some tuneups
- tools/tcode/cpu_(details|mmu).mac: use rt?jmp, hta??? macros
2863 lines
116 KiB
Plaintext
2863 lines
116 KiB
Plaintext
; $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 <W.F.J.Mueller@gsi.de>
|
|
;
|
|
; 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<m3.eub!m3.e22!m3.dkm!m3.dsm!m3.dum>,(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 #<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
|
|
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 #<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
|
|
;
|
|
; part 2: test MTPD and MFPD -----------------------------------------
|
|
;
|
|
; 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$
|
|
;
|
|
; part 3: test MTPI and MFPI -----------------------------------------
|
|
;
|
|
; 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$
|
|
;
|
|
; 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 #<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
|
|
;
|
|
; part 5: 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
|
|
;
|
|
;
|
|
; 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)+,#<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
|
|
;
|
|
; 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 #<vc4/100>,uipar0
|
|
mov #<8.*md.plf>!md.arw,udpdr1
|
|
mov #<vc4dat/100>,udpar1
|
|
; 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 #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 #<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
|
|
hcmpeq 3000$,#<m0.ale!m0.pmu!m0.dsp!<1*m0.pno>!m0.ena>
|
|
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
|
|
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 #<m0.anr!m0.ale!m0.ard>,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 #<vc3/100>,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+<vc3l1-vc3> ; mmu(trap) after clr of cp.pir
|
|
htacmp #032,#p2base+<vc3l2-vc3> ; 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 #<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 ++ 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 #<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
|
|
;
|
|
; 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 #<vc4stk-vc4dat+p1base>,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
|