1
0
mirror of https://github.com/wfjm/w11.git synced 2026-04-10 23:40:26 +00:00

pdp11_mmu.vhd: BUGFIX: correct trap and PDR A logic

- tools/asm-11/lib/defs_mmu.mac: rename md.a??, saner names for ACF
- tcode/cpu_mmu.mac: add E1.1, test m0.trp, pdr aia/aiw transitions (verify fix)

Closes #34
Closes #33
Closes #26
Closes #25
This commit is contained in:
wfjm
2022-09-09 09:01:06 +02:00
parent fe5cb6d757
commit 1644863a58
5 changed files with 458 additions and 50 deletions

View File

@@ -36,7 +36,7 @@ The full set of tests is only run for tagged releases.
- remove Atlys support (only test designs, a w11 design was never done)
- cleanup SimH setup files (\*.scmd), use autoconfig, set disk types
- cleanup code base, use page,mmr\*,pdr,par instead of segment,ssr\*,sdr,sar
- sysid encodes now system type, allows to distingish w11,SimH,e11
- sysid encodes now system type, allows to distinguish w11,SimH,e11
- added dasm-11, a PDP-11 disassembler
### New features
- new verification codes
@@ -90,12 +90,15 @@ The full set of tests is only run for tagged releases.
- *.scmd: set sysid to 110234 --> emu Simh
- *.ecmd: set sysid to 120345 --> emu e11
### Bug Fixes
- rtl/w11a
- pdp11_mmu: BUGFIX: correct trap and PDR A logic, see
[ECO-033](ECO-033-MMU_AFC-1_PDR-A.md)
- src/librwxxtpp
- RtclRw11Cpu.cpp: quit before mem write if asm-11 error seen
- tools/asm-11/lib
- tcode_std_start.mac: fix sdreg probe code
- tools/mcode
- m9312/bootw11.mac: proper init of unit number in getnam
- src/librwxxtpp
- RtclRw11Cpu.cpp: quit before mem write if asm-11 error seen
<!-- --------------------------------------------------------------------- -->
---

View File

@@ -0,0 +1,58 @@
# ECO-033: MMU: ACF=1 trap and PDR A fix (2022-09-07)
### Scope
- was in w11a since 2009
- affects: all w11a systems
### Symptom summary
- part 1: ACF=1 traps on any access
Test 055 of `ekbee1` fails with
```
MEMORY MANAGEMENT TRAP OR ABORT HAD INCORRECT CONDITION
EXPECTD ERROR AUTOI/D VIRTUAL
CONDITN REGISTR REGISTR ADDRESS TESTNO PC AT ABORT
020011 030011 013427 054032 000055 054040
```
- part 2: `PDR` A bit is set for every access
This was discovered in a code review. The `PDR` A bit was set for
all accesses. The `PDR` A bit should be set only when
_"trap condition met by the Access Control Field (ACF)"_ is fulfilled.
Thus for
```
ACF=001 read-only trap and A bit on read
ACF=100 read/write trap and A bit on read or write
ACF=101 read/write trap and A bit on write
```
`ekbee1` only checks whether this bit is set when expected, but does
_not_ verify that is stays '0' when it should.
### Analysis
- part 1: ACF=1 traps on any access
Caused by a simple mistake in the `ACF` handling in pdp11_mmu.vhd
```vhdl
case PARPDR.acf is -- evaluate accecc control field
when "001" => -- read-only; trap on read
if CNTL.wacc='1' or CNTL.macc='1' then
abo_rdonly := '1';
end if;
dotrap := '1'; -- <== BUG, should be 'not write'
```
- part 2: PDR A bit is set for every access
Caused simplistic AIB handling in pdp11_mmu.vhd
```vhdl
if doabort = '0' then
AIB_SETA <= '1'; -- <== BUG, should be 'dotrap'
AIB_SETW <= CNTL.wacc or CNTL.macc;
end if;
```
### Fixes
- part 1: `AIB_SETA <= dotrap;`
- part 2: `dotrap := not iswrite;`
### Hindsight
Took 13 years to fix. The MMU traps and `PDR` A and W bits are 11/45 and 11/70
specific and not used by any operating system. Only tests like `ekbee1` use
this functionality.

View File

@@ -1,4 +1,4 @@
-- $Id: pdp11_mmu.vhd 1279 2022-08-14 08:02:21Z mueller $
-- $Id: pdp11_mmu.vhd 1294 2022-09-07 14:21:20Z mueller $
-- SPDX-License-Identifier: GPL-3.0-or-later
-- Copyright 2006-2022 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
--
@@ -17,6 +17,7 @@
--
-- Revision History:
-- Date Rev Version Comment
-- 2022-09-05 1294 1,4.4 BUGFIX: correct trap and PDR A logic
-- 2022-08-13 1279 1.4.3 ssr->mmr rename
-- 2011-11-18 427 1.4.2 now numeric_std clean
-- 2010-10-23 335 1.4.1 use ib_sel
@@ -264,9 +265,10 @@ begin
variable abo_rdonly : slbit := '0';
variable mmr_freeze : slbit := '0';
variable doabort : slbit := '0';
variable dotrap : slbit := '0';
variable dotrap : slbit := '0';
variable dotrace : slbit := '0';
variable iswrite : slbit := '0';
begin
nmmr0 := R_MMR0;
@@ -277,7 +279,8 @@ begin
mmr_freeze := R_MMR0.abo_nonres or R_MMR0.abo_length or R_MMR0.abo_rdonly;
dotrace := not(CNTL.cacc or mmr_freeze);
iswrite := CNTL.wacc or CNTL.macc;
apf := VADDR(15 downto 13);
bn := VADDR(12 downto 6);
@@ -285,7 +288,7 @@ begin
abo_length := '0';
abo_rdonly := '0';
doabort := '0';
dotrap := '0';
dotrap := '0';
if PARPDR.ed = '0' then -- ed=0: upward expansion
if unsigned(bn) > unsigned(PARPDR.plf) then
@@ -297,19 +300,39 @@ begin
end if;
end if;
-- ACF decision logic
-- w11 has 4 memory cycle types, the ACF is based only on read or write
-- wacc='0' macc'0' : read cycle --> read
-- wacc='1' macc'0' : write cycle --> write
-- wacc='0' macc'1' : read part of rmw --> write
-- wacc='1' macc'1' : write part of rmw --> write
-- Depending of ACF the MMU aborts, queues a trap, sets A and W bit in PDR
-- ACF abort trap Comment
-- 000 nonres - non-resident: abort all accesses
-- 001 rdonly R read-only: abort on write, trap on read
-- 010 rdonly read-only: abort on write
-- 011 nonres - unused: abort all accesses
-- 100 - R+W read/write: no abort, trap on read or write
-- 101 - W read/write: no abort, trap on write
-- 110 - - read/write: no abort, no trap
-- 111 nonres - unused: abort all accesses
--
-- The PDR W bit is set for non-aborted write accesses
-- The PDR A bit is set if the trap condition is fulfilled and not aborted
case PARPDR.acf is -- evaluate accecc control field
when "000" => -- page non-resident
abo_nonres := '1';
when "001" => -- read-only; trap on read
if CNTL.wacc='1' or CNTL.macc='1' then
if iswrite='1' then
abo_rdonly := '1';
end if;
dotrap := '1';
dotrap := not iswrite;
when "010" => -- read-only
if CNTL.wacc='1' or CNTL.macc='1' then
if iswrite='1' then
abo_rdonly := '1';
end if;
@@ -317,7 +340,7 @@ begin
dotrap := '1';
when "101" => -- read/write; trap on write
dotrap := CNTL.wacc or CNTL.macc;
dotrap := iswrite;
when "110" => null; -- read/write;
@@ -358,8 +381,8 @@ begin
doabort := abo_nonres or abo_length or abo_rdonly;
if doabort = '0' then
AIB_SETA <= '1';
AIB_SETW <= CNTL.wacc or CNTL.macc;
AIB_SETA <= dotrap;
AIB_SETW <= iswrite;
end if;
if mmr_freeze = '0' then

View File

@@ -1,4 +1,4 @@
; $Id: defs_mmu.mac 1291 2022-09-03 07:00:27Z mueller $
; $Id: defs_mmu.mac 1295 2022-09-07 16:28:55Z mueller $
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright 2015-2022 by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
;
@@ -53,8 +53,8 @@
md.dwn = 000010 ; ed field 1, down expansion
md.an7 = 000007 ; abort all; reserved
md.arw = 000006 ; allow r+w; no traps
md.atw = 000005 ; allow r+w; trap w
md.atr = 000004 ; allow r+w; trap r+w
md.art = 000005 ; allow r+w; trap w
md.att = 000004 ; allow r+w; trap r+w
md.an3 = 000003 ; abort all; reserved
md.aro = 000002 ; allow r; abort w; no traps
md.art = 000001 ; allow r; abort w; trap r
md.ara = 000002 ; allow r; abort w; no traps
md.ata = 000001 ; allow r; abort w; trap r

View File

@@ -1,17 +1,18 @@
; $Id: cpu_mmu.mac 1291 2022-09-03 07:00:27Z mueller $
; $Id: cpu_mmu.mac 1295 2022-09-07 16:28:55Z mueller $
; SPDX-License-Identifier: GPL-3.0-or-later
; Copyright 2022- by Walter F.J. Mueller <W.F.J.Mueller@gsi.de>
;
; Revision History:
; Date Rev Version Comment
; 2022-08-31 1291 1.0 Initial version
; 2022-09-06 1294 1.0 Initial version
; 2022-07-24 1262 0.1 First draft
;
; Test CPU MMU: all aspects of the MMU
; Section A: pdr,par registers
; Section B: mmr0,mmr3 registers, mapping, instructions
; Section C: mmr1+mmr0 register, aborts and traps
; Section C: mmr1+mmr0 register, aborts
; Section D: mmr2+mmr1+mmr0 register, abort recovery
; Section E: traps and pdr aia and aiw bits
;
.include |lib/tcode_std_base.mac|
.include |lib/defs_mmu.mac|
@@ -35,6 +36,21 @@
kipar6 = kipar+14
kipdr7 = kipdr+16
kipar7 = kipar+16
p0p1p2 = <1*100>+2 ; page 0, +1 click, +2
p0p1p4 = <1*100>+4 ; page 0, +1 click, +4
p1base = <1*20000> ; page 1
p1p0p2 = p1base+2 ; page 1, +2
p1m1p0 = p1base+<127.*100> ; page 1, 128-1 click
p2base = <2*20000> ; page 2
p2m1p0 = p2base+<127.*100> ; page 1, 128-1 click
p2m1m4 = p2base+<127.*100>-4 ; page 1, 128-1 click, -4
p3base = <3*20000> ; page 3
p4base = <4*20000> ; page 4
p5base = <5*20000> ; page 5
p6base = <6*20000> ; page 6
p6p1p2 = p6base+<1*100>+2 ; page 6, +1 click, +2
p7base = <7*20000> ; page 7
;
; Section A: pdr,par registers ===============================================
;
@@ -564,7 +580,7 @@ tb0302:
;
9999$: iot ; end of test B3.2
;
; Section C: mmr1+mmr0 register, aborts and traps ============================
; Section C: mmr1+mmr0 register, aborts ======================================
;
; Test C1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
@@ -646,7 +662,7 @@ tc0101: mov #1000$,r1 ; ptr to abort bit table
; Test C2.1 -- test unary/binary instructions ++++++++++++++++++++++++
; Excercise access to kernel page 6 and inspect mmr0 and mmr1
;
tc0201: mov #vhemmu,v..mmu
tc0201: mov #vhmmua,v..mmu
clr v..mmu+2 ; pr0 kernel
reset
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
@@ -692,7 +708,7 @@ tc0201: mov #vhemmu,v..mmu
.word ^b0000000011110100 ; mmr1 -2,4
;
; write abort in mapped area (write access)
1300$: mov #<0.*md.plf>!md.aro,kipdr6 ; plf= 0.;ed=0;acf=r
1300$: mov #<0.*md.plf>!md.ara,kipdr6 ; plf= 0.;ed=0;acf=r
mov #140002,r2
tstb (r2)+ ; read ok
mov #1310$,vhvmmu
@@ -738,7 +754,7 @@ tc0201: mov #vhemmu,v..mmu
mov #2001$,r2
tst @(r2)+ ; will fail
halt
2001$: .word 140102 ; probed address
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
@@ -778,7 +794,7 @@ tc0201: mov #vhemmu,v..mmu
mov #3201$,r4
mov @(r4)+,(r3)+ ; will fail
halt
3201$: .word 140102 ; probed address
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
@@ -820,12 +836,12 @@ tc0201: mov #vhemmu,v..mmu
mov 4201$,r5
cmp (r2)+,@(r5)+ ; will fail
halt
4201$: .word 140102 ; probed address
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.aro,kipdr6 ; plf= 0.;ed=0;acf=r
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
@@ -870,7 +886,7 @@ tc0201: mov #vhemmu,v..mmu
.word ^b0000000000010011 ; mmr1 +2,3
;
; length + read-only abort
5200$: mov #<0.*md.plf>!md.aro,kipdr6 ; plf= 0.;ed=0;acf=r
5200$: mov #<0.*md.plf>!md.ara,kipdr6 ; plf= 0.;ed=0;acf=r
mov #5210$,vhvmmu
mov #140102,r4
com (r4)+ ; will fail
@@ -893,14 +909,14 @@ tc0201: mov #vhemmu,v..mmu
; udpdr1 1 click up acr=2 read
; udpdr2 1 click dn acr=6 w/r
;
tc0202: mov #vhemmu,v..mmu
tc0202: mov #vhmmua,v..mmu
clr v..mmu+2 ; pr0 kernel
reset
mov #cp.pmu,cp.psw ; pm to user
mov #m3.dum,mmr3 ; enable user D space
mov #<0.*md.plf>!md.arw,kipdr6 ; plf= 0.;ed=0;acf=w/r
mov #<0.*md.plf>!md.aro,uipdr0 ; plf= 0.;ed=0;acf=r
mov #<0.*md.plf>!md.aro,udpdr1 ; plf= 0.;ed=0;acf=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
;
@@ -914,7 +930,7 @@ tc0202: mov #vhemmu,v..mmu
;
; MPPI: I space page 1 non-resident
1000$: mov #1010$,vhvmmu
mov #020000,r2
mov #p1base,r2
mfpi (r2)+ ; will fail, page 1 unmapped
halt
1010$: .word m0.anr!m0.pmu!<1*m0.pno>!m0.ena ; mmr0
@@ -923,7 +939,7 @@ tc0202: mov #vhemmu,v..mmu
;
; MFPI: I space page 0 length abort
1100$: mov #1110$,vhvmmu
mov #000102,r3
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
@@ -933,7 +949,7 @@ tc0202: mov #vhemmu,v..mmu
; MFPI @(R)+: 1st access fails (in kernel space)
1200$: mov #cp.pmu,cp.psw ; pm to user
mov #1210$,vhvmmu
mov #140102,r4
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
@@ -946,7 +962,7 @@ tc0202: mov #vhemmu,v..mmu
mov #1301$,r5
mfpi @(r5)+ ; will fail
halt
1301$: .word 000104 ; probed address
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
@@ -954,7 +970,7 @@ tc0202: mov #vhemmu,v..mmu
; MFPD: D space page 1 length abort (has ed=1)
1400$: mov #cp.pmu,cp.psw ; pm to user
mov #1410$,vhvmmu
mov #037700,r3
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
@@ -974,7 +990,7 @@ tc0202: mov #vhemmu,v..mmu
; MTPD: D space page 3 non-resident
2000$: mov #cp.pmu,cp.psw ; pm to user
mov #2010$,vhvmmu
mov #060000,r2
mov #p3base,r2
push #1234
mtpd (r2)+ ; will fail, page 3 unmapped
halt
@@ -985,7 +1001,7 @@ tc0202: mov #vhemmu,v..mmu
; MTPD: D space page 1 read-only
2100$: mov #cp.pmu,cp.psw ; pm to user
mov #2110$,vhvmmu
mov #020002,r3
mov #p1p0p2,r3 ; page 1, +2
push #1234
mtpd (r3)+ ; will fail
halt
@@ -995,7 +1011,7 @@ tc0202: mov #vhemmu,v..mmu
;
; MTPD: D space page 2 length
2200$: mov #2210$,vhvmmu
mov #057700,r4
mov #p2m1p0,r4
push #1234
mtpd -(r4) ; will fail
halt
@@ -1005,7 +1021,7 @@ tc0202: mov #vhemmu,v..mmu
;
; MTPD @(R)+: 1st access fails (in kernel space)
2300$: mov #2310$,vhvmmu
mov #140102,r5
mov #p6p1p2,r5 ; page 6, +1 click, +2
push #1234
mtpd @(r5)+ ; will fail
halt
@@ -1019,7 +1035,7 @@ tc0202: mov #vhemmu,v..mmu
push #1234
mtpd @(r3)+ ; will fail
halt
2401$: .word 057600 ; probed address
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
@@ -1054,7 +1070,7 @@ tc0202: mov #vhemmu,v..mmu
; si.7 as 1-to-1 (psw access)
; ui.0 as 1-to-1 (for read access)
;
tc0203: mov #vhemmu,v..mmu
tc0203: mov #vhmmua,v..mmu
clr v..mmu+2 ; pr0 kernel
reset
mov kipdr0,sipdr0 ; super 0: 1-to-1
@@ -1281,26 +1297,316 @@ td0101:
3002$: .word 0 ; save mmr2
;
9999$: iot ; end of test D1.1
;
; Section E: traps and pdr aia and aiw bits ==================================
;
; Test E1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Test E1.1 -- test m0.trp, pdr aia/aiw transitions ++++++++++++++++++
; Summary
; PDR MMR0 action aia aiw trp Trap Comment
; acf=6 ent=0 tst (r3) 0 0 0 no no ai, no trap
; clr (r3) 0 1 0 no clr sets aiw
; tst (r3) 0 1 0 no aiw stays
; pdr->pdr 0 0 0 - any pdr write clears aia,aiw
; clr (r3) 0 1 0 no clr sets aiw
; pdr+1 write 0 0 0 - any pdr write clears aia,aiw
; clr (r3) 0 1 0 no clr sets aiw
; par->par 0 0 0 - any par write clears aia,aiw
;
; acf=6 ent=1 tst (r3) 0 0 0 no no trap
; clr (r3) 0 1 0 no no trap
;
; acf=4 ent=0 tst (r3) 1 0 1 no trp set, aia set
; clr (r3) 1 1 1 no trp stays, aiw set
; trp=0;pdr 0 0 0 - any par write clears aia,aiw
;
; acf=4 ent=1 tst (r3) 1 0 1 yes trap taken, trp set, aia set
; clr (r3) 1 1 1 no no trap, aia set
; trp=0;pdr 0 0 0 - any pdr write clears aia,aiw
; clr (r3) 1 1 1 yes trap taken, trp,aia,aiw set
; tst (r3) 1 1 1 no no trap, no additional bits
; trp=0;pdr 0 0 0 - any par write clears aia,aiw
;
; Uses page 6 with plf=1 and varying acf
;
te0101: mov #vhmmut,v..mmu ; setup MMU trap handler
clr v..mmu+2 ; pr0 kernel
reset
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
mov #kipdr6,r4 ; keep in register
mov #p6base,r3 ; probed address
clr vhvmmu ; dont expect traps initially
;
; acf=6 ent=0 tst (r3) 0 0 0 no no ai, no trap
mov #md.plf!md.arw,(r4) ; set pdr
tst (r3) ; probe read
hbiteq mmr0,#m0.trp ; check trp=0
hcmpeq (r4),#md.plf!md.arw ; check aia,aiw=0
;
; clr (r3) 0 1 0 no clr sets aiw
clr (r3) ; probe write
hbiteq mmr0,#m0.trp ; check trp=0
hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1
;
; tst (r3) 0 1 0 no aiw stays
tst (r3) ; probe read
hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1
;
; pdr->pdr 0 0 0 - any pdr write clears aia,aiw
mov (r4),(r4) ; write pdr->pdr, should clear aiw
hcmpeq (r4),#md.plf!md.arw ; check aiw=0
;
; clr (r3) 0 1 0 no clr sets aiw
clr (r3) ; probe write
hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1
;
; pdr+1 write 0 0 0 - any pdr write clears aia,aiw
movb #1,1(r4) ; write pdr+1, should clear aiw
hcmpeq (r4),#md.plf!md.arw ; check aiw=0
;
; clr (r3) 0 1 0 no clr sets aiw
clr (r3) ; probe write
hcmpeq (r4),#md.plf!md.aiw!md.arw ; check aiw=1
;
; par->par 0 0 0 - any par write clears aia,aiw
mov kipar6,kipar6 ; write par->par, should clear aiw
hcmpeq (r4),#md.plf!md.arw ; check aiw=0
;
; acf=6 ent=1 tst (r3) 0 0 0 no no trap
mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps enabled
tst (r3) ; probe read
;
; clr (r3) 0 1 0 no no trap
clr (r3) ; probe write
;
; acf=4 ent=0 tst (r3) 1 0 1 no trp set, aia set
mov #md.plf!md.att,(r4) ; set pdr
mov #m0.ena,mmr0 ; enable mmu with traps disabled
tst (r3) ; probe read
hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.att ; check aia=1
;
; clr (r3) 1 1 1 no trp stays, aiw set
clr (r3) ; probe write
hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1
;
; trp=0;pdr 0 0 0 - any par write clears aia,aiw
bic #m0.trp,mmr0 ; clear trp
hbiteq mmr0,#m0.trp ; check trp=0
mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw
hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0
;
; acf=4 ent=1 tst (r3) 1 0 1 yes trap taken, trp set, aia set
mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps enabled
mov #1010$,vhvmmu
tst (r3) ; probe read
halt ; expect trap
1010$: hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.att ; check aia=1
;
; clr (r3) 1 1 1 no no trap, aia set
clr (r3) ; probe write
hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1
;
; trp=0;pdr 0 0 0 - any pdr write clears aia,aiw
bic #m0.trp,mmr0 ; clear trp
mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw
hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0
;
; clr (r3) 1 1 1 yes trap taken, trp,aia,aiw set
mov #1020$,vhvmmu
clr (r3) ; probe write
halt ; expect trap
1020$: hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1
;
; tst (r3) 1 1 1 no no trap, no additional bits
tst (r3) ; probe read
hbitne mmr0,#m0.trp ; check trp=1
hcmpeq (r4),#md.plf!md.aia!md.aiw!md.att ; check aia=1,aiw=1
;
; trp=0;pdr 0 0 0 - any par write clears aia,aiw
bic #m0.trp,mmr0 ; clear trp
mov (r4),(r4) ; write pdr->pdr, should clear aia and aiw
hcmpeq (r4),#md.plf!md.att ; check aia=0,aiw=0
;
9000$: reset ; mmu off ;! MMU off
clr cp.psw
mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
9999$: iot ; end of test E1.1
;
; Test E1.2 -- systematic abort/trap testing for all valid afc +++++++
; Summary
; afc action handler abort aia aiw trap Comment
; 0 tst (r3) r-abo anr 0 0 no
; 0 add r0,(r3) w-abo anr 0 0 no
; 1 tst (r3) r-trap - 1 0 yes
; 1 add r0,(r3) w-abo ard 0 0 no
; 2 tst (r3) r-ok - 0 0 no
; 2 add r0,(r3) w-abo ard 0 0 no
; 4 tst (r3) r-trap - 1 0 yes
; 4 clr (r3) w-trap - 1 1 yes
; 5 tst (r3) r-ok - 0 0 no
; 5 clr (r3) w-trap - 1 1 yes
; 6 tst (r3) r-ok - 0 0 no
; 6 mov r0,(r3) w-ok - 0 1 no
;
te0102: mov #vhmmut,v..mmu ; setup MMU trap handler
clr v..mmu+2 ; pr0 kernel
reset
mov #m0.ent!m0.ena,mmr0 ; enable mmu with traps ;! MMU 18
clr vhvmmu ; dont expect traps initially
;
mov #3000$,r5 ; ptr to data table
mov #kipdr6,r4 ; keep in register
mov #p6base,r3 ; probed address
mov #vhvmmu,r2 ; ptr to vhvmmu
;
1000$: mov (r5)+,(r4) ; load pdr
jmp @(r5)+ ; execute case handler
;
; case r-ok: read, no abort, no trap
1100$: clr (r2) ; no abort/trap expected
tst (r3) ; probe read
br 1900$ ; to ok-check
;
; case r-abo: read, abort
1200$: mov #vhmmua,v..mmu ; setup MMU abort handler
mov (r5)+,1210$
mov #1210$,(r2)
tst (r3) ; probe read
halt ; expect abort
1210$: .word 0,0
br 1910$ ; to abo-check
;
; case r-trap: read, trap
1300$: mov #vhmmut,v..mmu ; setup MMU trap handler
mov #1900$,(r2) ; to ok-check
tst (r3) ; probe read
halt ; expect trap
;
; case w-ok: write, no abort, no trap
1400$: clr (r2) ; no abort/trap expected
mov r0,(r3) ; probe write
br 1900$ ; to ok-check
;
; case w-abo: write, abort
1500$: mov #vhmmua,v..mmu ; setup MMU abort handler
mov (r5)+,1510$
mov #1510$,(r2)
add r0,(r3) ; probe write
halt ; expect abort
1510$: .word 0,0
br 1910$ ; to tr-check
;
; case w-trap: write, trap
1600$: mov #vhmmut,v..mmu ; setup MMU trap handler
mov #1900$,(r2)
clr (r3) ; probe write
halt ; expect trap
;
1900$: tst (r5)+ ; drop unused mmr0 info
1910$: mov (r5)+,r0 ; get pdrexp
hcmpeq (r4),r0 ; check pdr
mov (r4),(r4) ; clear pdr aia,aiw
bic #m0.trp,mmr0 ; clear mmr0 trp flag
tst (r5) ; look at next case
beq 9000$ ; if eq end sentinel found ?
br 1000$ ; if ne go for next case
;
3000$: .word md.plf ; afc=0 + read: - anr -------
.word 1200$ ; r-abo
.word m0.anr!m0.ent!<6*m0.pno>!m0.ena ; mmr0
.word md.plf ; pdf: no aib
;
.word md.plf ; afc=0 + write: - anr -------
.word 1500$ ; w-abo
.word m0.anr!m0.ent!<6*m0.pno>!m0.ena ; mmr0
.word md.plf ; pdf: no aib
;
.word md.plf!md.ata ; afc=1 + read: - trp aia ---
.word 1300$ ; r-trap
.word 0 ; mmr0
.word md.plf!md.aia!md.ata ; pdf: aia
;
.word md.plf!md.ata ; afc=1 + write: - ard -------
.word 1500$ ; w-abo
.word m0.ard!m0.ent!<6*m0.pno>!m0.ena ; mmr0
.word md.plf!md.ata ; pdf: no aib
;
.word md.plf!md.ara ; afc=2 + read: -------------
.word 1100$ ; r-ok
.word 0 ; mmr0
.word md.plf!md.ara ; pdf: no aib
;
.word md.plf!md.ara ; afc=2 + write: - ard -------
.word 1500$ ; w-abo
.word m0.ard!m0.ent!<6*m0.pno>!m0.ena ; mmr0
.word md.plf!md.ara ; pdf: no aib
;
.word md.plf!md.att ; afc=4 + read: - trp aia ---
.word 1300$ ; r-trap
.word 0 ; mmr0
.word md.plf!md.aia!md.att ; pdf: aia
;
.word md.plf!md.att ; afc=4 + write - trp aia,aiw
.word 1600$ ; w-trap
.word 0 ; mmr0
.word md.plf!md.aia!md.aiw!md.att ; pdf: aia aiw
;
.word md.plf!md.art ; afc=5 + read: -------------
.word 1100$ ; r-ok
.word 0 ; mmr0
.word md.plf!md.art ; pdf: no aib
;
.word md.plf!md.art ; afc=5 + write: - trp aia,aiw
.word 1600$ ; w-trap
.word 0 ; mmr0
.word md.plf!md.aia!md.aiw!md.art ; pdf: aia aiw
;
.word md.plf!md.arw ; afc=6 + read: -------------
.word 1100$ ; r-ok
.word 0 ; mmr0
.word md.plf!md.arw ; pdf: no aib
;
.word md.plf!md.arw ; afc=6 + write: - aiw -------
.word 1400$ ; w-ok
.word 0 ; mmr0
.word md.plf!md.aiw!md.arw ; pdf: aiw
;
.word 0 ; end sentinel ------------------------------
;
9000$: reset ; mmu off ;! MMU off
clr cp.psw
mov #<127.*md.plf>!md.arw,kipdr6 ; restore kernel mapping
mov #v..mmu+2,v..mmu ; restore mmu catcher
clr v..mmu+2
9999$: iot ; end of test E1.2
;
; END OF ALL TESTS - loop closure ============================================
;
mov tstno,r0 ; hack, for easy monitoring ...
hcmpeq tstno,#13. ; all tests done ?
hcmpeq tstno,#15. ; all tests done ?
;
jmp loop
;
; kernel handlers ============================================================
;
; vhemmu - expected mmu abort/trap handler +++++++++++++++++++++++++++++++++++
; used to catch expected MMU aborts or traps
; 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 context
; 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
;
vhemmu: mov vhvmmu,r1 ; get context
vhmmua: mov vhvmmu,r1 ; get context
beq 1000$ ; if 0 halt
mov mmr0,r0
bic #m0.ico,r0 ; mask ico (for Simh compatibility)
@@ -1313,6 +1619,24 @@ vhemmu: mov vhvmmu,r1 ; get context
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