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

676 lines
24 KiB
Plaintext

; $Id: cpu_mmu.mac 1272 2022-08-07 17:37:51Z 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-06 1272 1.0.1 ssr->mmr rename
; 2022-07-28 1264 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 register and traps
; Section D: mmr2 register and aborts
;
.include |lib/tcode_std_base.mac|
.include |lib/defs_mmu.mac|
; some useful definitions
uipdr0 = uipdr+ 0
uipar0 = uipar+ 0
udpdr0 = udpdr+ 0
udpar0 = udpar+ 0
sipdr0 = sipdr+ 0
sipar0 = sipar+ 0
kipar6 = kipar+14
kipar7 = kipar+16
;
; Section A: pdr,par registers ===============================================
;
; Test A1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Test A1.1 -- test that pdr/par are 16 bit write/readable +++++++++++
; Write unique patterns to first and last pdr/par of each mode and read back
;
ta0101: mov #000401,r5 ; pattern master
;;; mov #077717,r5 ; bit mask for pdr
;
; write 000401,001002,002004,004010,... for pdr; complement for par
mov r5,r0 ; start pattern
mov #12.,r1 ; number tested regs
mov #9000$,r2
1000$: mov (r2)+,r3
mov r0,(r3) ; write pdr
add r5,r0
dec r0
mov r0,40(r3) ; write par
add r5,r0
sob r1,1000$
;
; read back
mov r5,r0 ; start pattern
mov #12.,r1 ; number of modes
mov #9000$,r2
1100$: mov (r2)+,r3
hcmpeq (r3),r0 ; check pdr
add r5,r0
dec r0
hcmpeq 40(r3),r0 ; check par
add r5,r0
sob r1,1100$
;
; complement all pattern
mov #12.,r1 ; number of modes
mov #9000$,r2
1200$: mov (r2)+,r3
mov (r3),r4 ; complement pdr only writable bits
com r4
bic #100360,r4 ; mask non-writable (incl A and W)
mov r4,(r3)
com 40(r3) ; complement par
sob r1,1200$
;
; and read back again
; pdr only slf,ed and acf fields are checked
; par all 18 bits are write/readable
mov r5,r0 ; start pattern
com r0 ; complemented
mov #12.,r1 ; number of modes
mov #9000$,r2
1300$: mov (r2)+,r3
mov r0,r4
bic #100360,r4 ; mask non-writable (incl A and W)
hcmpeq (r3),r4 ; check pdr only writable bits
sub r5,r0
inc r0
hcmpeq 40(r3),r0 ; check par
sub r5,r0
sob r1,1300$
;
jmp 9999$
;
9000$: .word uipdr ; usr i page dsc base 0
.word uipdr+16
.word udpdr ; usr d page dsc base 0
.word udpdr+16
.word sipdr ; sup i page dsc base 0
.word sipdr+16
.word sdpdr ; sup d page dsc base 0
.word sdpdr+16
.word kipdr ; ker i page dsc base 0
.word kipdr+16
.word kdpdr ; ker d page dsc base 0
.word kdpdr+16
;
9999$: iot ; end of test A1.1
;
; Test A1.2 -- setup 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$
; setup kernel I
mov #kipdr,r0
mov #<127.*md.slf>!md.arw,r1 ; slf=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)
; setup kernel D
mov #kdpdr,r0
mov r1,16(r0) ; kdpdr7 slf=127; ed=0(up); acf=6(w/r)
mov #kdpar,r0
mov #177600,16(r0) ; kdpar7 (map I/O page)
;
jmp 9999$
;
1000$: .word uipdr
.word sipdr
.word kipdr
;
9999$: iot ; end of test A1.2
;
; Section B: mmr0,mmr3 registers, mapping, instructions ======================
; Test whether address mapping works (traps and aborts avoided)
;
; Test B1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Test mmr0, mmr3 write/read and clear by RESET
;
; This test verifies
; x xxx xxx xxx xxx xxx NZVC Instruction / Remark
; 0 000 000 000 000 101 ---- RESET (clear mmr0,mmr3)
;
; Test B1.1 -- test mmr0 write/read ++++++++++++++++++++++++++++++++++
; Test all writable bits except m0.ena
;
tb0101: mov #mmr0,r0 ; ptr to mmr0
mov #m0.ico,r1 ; instruction complete flag
mov #1010$,r4 ; ptr to data
mov #1011$,r3 ; ptr to data end
100$: mov (r4),(r0) ; write mmr0
mov (r0),r5 ; read mmr0
bic r1,r5 ; mask instruction complete
hcmpeq r5,(r4)+ ; check
cmp r4,r3 ; more to do ?
blo 100$
;
reset ; mmr0 has 5 bits set, check clear
mov (r0),r5 ; read mmr0
bic r1,r5 ; mask instruction complete
htsteq r5 ; check mmr0 cleared
jmp 9999$
;
1010$: .word m0.anr ; abort flags
.word m0.ale
.word m0.ard
.word m0.trp ; trap flag
.word m0.ent ; trap enable
.word m0.anr!m0.ale!m0.ard!m0.trp!m0.ent
1011$:
;
9999$: iot ; end of test B1.1
;
; Test B1.2 -- test mmr3 write/read ++++++++++++++++++++++++++++++++++
; Test all writable bits; mmu is off, and unibus map not used
;
tb0102: mov #mmr3,r0 ; ptr to mmr3
mov #1010$,r4 ; ptr to data
mov #1011$,r3 ; ptr to data end
100$: mov (r4),(r0) ; write mmr3
hcmpeq (r0),(r4)+ ; check
cmp r4,r3 ; more to do ?
blo 100$
;
reset ; mmr3 has 5 bits set, check clear
htsteq (r0) ; check mmr3 cleared
jmp 9999$
;
1010$: .word m3.eub
.word m3.e22
.word m3.dkm
.word m3.dsm
.word m3.dum
.word m3.eub!m3.e22!m3.dkm!m3.dsm!m3.dum
1011$:
;
9999$: iot ; end of test B1.2
;
; Test B2: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Test kernel mode mapping
;
; Test B2.1 -- test 1-to-1 kernel mode mapping +++++++++++++++++++++++
; simply enable MMU, shouldnt make a difference
; test that 18bit mode extends I/O page addressing
; test that RESET clears mmr0 and mmr3
;
tb0201: mov #123456,1000$
; enable mmu in 18bit mode
clr mmr3 ; no d dspace, no 22bit
mov #m0.ena,mmr0 ; enable mmu
hbitne #m0.ena,mmr0 ; test bit ;! MMU 18
hcmpeq 1000$,#123456 ; check marker
; verify I/O page mapping in 18bit mode (007600 must be OK)
mov #kipar7,r0 ; ptr to kipar7
bic #170000,(r0) ; clear to 4 bits in kipar7
hcmpeq (r0),#007600 ; kipar7 still seen ???
bis #170000,(r0) ; restore kipar7
hcmpeq (r0),#177600
; enable mmu in 22bit mode; check that mmr3 still seen
mov #m3.e22,mmr3
hcmpeq mmr3,#m3.e22 ; test mmr3 stll seen ??? ;! MMU 22
; test RESET
reset ; should clear mmr0 and mmr3
htsteq mmr0 ; check mmr0 cleared ;! MMU off
htsteq mmr3 ; check mmr3 cleared
jmp 9999$
;
1000$: .word 0
;
9999$: iot ; end of test B2.1
;
; Test B2.2 -- test variable kernel mode mapping +++++++++++++++++++++
; change seg6 mapping
; test that 18bit mode discards the 4 MSB of the par
;
tb0202: mov #kipar6,r0 ; ptr to kipar6
mov #140000,r5 ; seg6 base
mov #140000,(r5) ; init markers
clr 2(r5)
mov #140100,100(r5) ; init markers
clr 102(r5)
;
clr mmr3 ; no d dspace, no 22bit
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
; check in 1-to-1 mapping
hcmpeq (r5),#140000
htsteq 2(r5)
hcmpeq 100(r5),#140100
htsteq 102(r5)
; move seg6 mapping up by one click
inc (r0) ; move kipar6 base up
hcmpeq (r0),#001401
hcmpeq 0(r5),#140100
mov #010000,2(r5) ; write marker
; set MSBs in kipar6, should be discarded in 18bit mode, check markers
bis #170000,(r0)
hcmpeq (r0),#171401
hcmpeq (r5),#140100 ; check marker
bic #170000,(r0)
hcmpeq (r0),#001401
; move seg6 mapping down by one click
dec (r0) ; move kipar6 base up
hcmpeq (r0),#001400
mov #020000,2(r5) ; write marker
hcmpeq 2(r5),#020000 ; check marker
hcmpeq 102(r5),#010000 ; check marker
; disable MMU
reset ; mmu off ;! MMU off
;
9999$: iot ; end of test B2.2
;
; Test B3: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; Test user and supervisor mode
;
; Test B3.1 -- run code in user/supervisor mode ++++++++++++++++++++++
; code vc0 is executed in user and in supervisor mode
; the code runs in seg0 with D space disabled
;
tb0301:
; setup emt handler
mov #vhuemt,v..emt
clr v..emt+2 ; pr0 kernel
; enable mmu
clr mmr3 ; no d dspace, no 22bit
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
;
; run code vc0 in user mode --------------------------------
;
; set user mode pdr/par, only short segment 0
mov #<8.*md.slf>!md.arw,uipdr0
mov #<vc0/100>,uipar0
; setup data for user mode run
mov #023456,vc0v0;
mov #000123,vc0v1
mov #077321,vc0v2
; start code in user mode
mov #1000$,vhustp ; setup continuation address
mov #cp.cmu,-(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 segment 0
mov #<8.*md.slf>!md.arw,sipdr0
mov #<vc0/100>,sipar0
; setup data for user mode run
mov #017171,vc0v0
mov #000321,vc0v1
mov #100123,vc0v2
; start code in supervisor mode
mov #2000$,vhustp ; setup continuation address
mov #cp.cms,-(sp) ; next psw: supervisor mode
clr -(sp) ; will start at 0
rti ; and launch it
halt
2000$: ; continuation point
; check psw
ccc ; clear cc -> psw reflects pm setting
hcmpeq cp.psw,#cp.pms ; check pm
; check data
hcmpeq vc0v0,#160606
hcmpeq vc0v2,#100444
; reset supervsior mode pdr/par
clr sipdr0
clr sipar0
;
reset ; mmu off ;! MMU off
mov #v..emt+2,v..emt ; restore emt catcher
clr v..emt+2
;
9999$: iot ; end of test B3.1
;
; Test B3.2 -- run code in user mode with D space enabled ++++++++++++
; code vc1 is executed in user and in supervisor mode
; the code runs in seg0 with D space enabled
;
; This test verifies
; x xxx xxx xxx xxx xxx NZVC Instruction / Remark
; 0 000 110 101 ddd ddd NZ0- MFPI
; 0 000 110 110 ddd ddd NZ0- MTPI
; 1 000 110 101 ddd ddd NZ0- MFPD
; 1 000 110 110 ddd ddd NZ0- MTPD
;
tb0302:
; setup emt handler
mov #vhuemt,v..emt
clr v..emt+2 ; pr0 kernel
; enable mmu
mov #m3.dum,mmr3 ; user d dspace, no 22bit
mov #m0.ena,mmr0 ; enable mmu ;! MMU 18
;
; run code vc1 in user mode --------------------------------
;
; set user mode pdr/par, only short segment 0; I and D
mov #<8.*md.slf>!md.arw,uipdr0
mov #<vc1/100>,uipar0
mov #<8.*md.slf>!md.arw,udpdr0
mov #<vc1dat/100>,udpar0
; setup data for user mode run
mov #020305,vc1v0
mov #000212,vc1v1
mov #033121,vc1v2
; start code in user mode
mov #1000$,vhustp ; setup continuation address
mov #cp.cmu,-(sp) ; next psw: user mode
clr -(sp) ; will start at 0
rti ; and launch it
halt
1000$: ; continuation point
; check psw
ccc ; clear cc -> psw reflects pm setting
hcmpeq cp.psw,#cp.pmu ; check pm
; check data
hcmpeq vc1v0,#157472
hcmpeq vc1v2,#033333
;
; psw has now pm=user and cm=kernel; good setup to test MFPI and friends
;
; test MFPD (data access)
;
mov #<vc1v0-vc1dat>,r5 ; initialize data pointer
mfpd (r5) ; read vc1v0
hcmpeq (sp)+,#157472
mfpd @#<vc1v2-vc1dat> ; read vc1v2
hcmpeq (sp)+,#033333
;
; test MTPD and MFPD, incl cc (data access)
;
mov #2010$,r4 ; ptr to test data
mov #2011$,r3 ; ptr to test end
2000$: push (r4)+
ccc ; C=0
mtpd (r5) ; write vc1v0
hcmpeq cp.psw,(r4)+ ; check cc
hcmpeq vc1v0,-4(r4) ; check target
scc ; C=1
mfpd (r5)
hcmpeq cp.psw,(r4)+ ; check cc
cmp r4,r3 ; more to do ?
blo 2000$
;
; test MFPI (data access)
;
mov #<vc1-vc1>,r5 ; initialize data pointer
mfpi (r5) ; read 1st instruction word
hcmpeq (sp)+,vc1
;
; test MTPI and MFPI, incl cc (data access)
;
mov #<vc1ida-vc1>,r5 ; initialize data pointer
mov #3010$,r4 ; ptr to test data
mov #3011$,r3 ; ptr to test end
3000$: push (r4)+
scc ; C=1
mtpi (r5) ; write vc1ida
hcmpeq cp.psw,(r4)+ ; check cc
hcmpeq vc1ida,-4(r4) ; check target
ccc ; C=0
mfpi (r5)
hcmpeq cp.psw,(r4)+ ; check cc
cmp r4,r3 ; more to do ?
blo 3000$
;
; Test MFPD,MFPI and MTPD,MTPI for sp register access
; accessing sp will access user mode stack pointer (which is != kernel stack)
;
; read sp via mfpd and mfpi
mfpd sp ; read user mode sp
hcmbeq (sp)+,#<vc1stk-vc1dat> ; check
mfpi sp ; read user mode sp (same for I and D)
hcmbeq (sp)+,#<vc1stk-vc1dat> ; check
; write sp via mtpd, readback via mfpi
mov sp,r4 ; remember kernel stack
mov #77,r5
push r5
mtpd sp ; change user stack
hcmpeq sp,r4 ; check kernel stack unchanged
mfpi sp ; read back user stack
hcmpeq (sp)+,r5 ; check
; write sp via mtpi, readback via mfpd
mov #177,r5
push r5
mtpi sp ; change user stack
hcmpeq sp,r4 ; check kernel stack unchanged
mfpd sp ; read back user stack
hcmpeq (sp)+,r5 ; check
;
; Test MFPD,MFPI and MTPD,MTPI for register r0-r5 access
; accessing r0-r5 simply acccesses common registers
; that is usually not used, but should work
;
; write registers via mtpd,mtpi
push #277
mtpd r5 ; effective mov #277,r5
push #377
mtpi r4 ; effective mov #377,r4
hcmpeq r5,#277 ; check
hcmpeq r4,#377 ; check
; read registers via mtpd,mtpi
mov #477,r5
mov #577,r4
mfpd r5
hcmpeq (sp)+,#477 ; check
mfpd r4
hcmpeq (sp)+,#577 ; check
;
; reset user mode pdr/par
clr uipdr0
clr uipar0
clr udpdr0
clr udpar0
;
reset ; mmu off ;! MMU off
mov #v..emt+2,v..emt ; restore emt catcher
clr v..emt+2
jmp 9999$
;
; test data for m*pd tests (C=0 for T and C=1 for F)
2010$: .word 000000,cp.pmu!cp0z00,cp.pmu!cp0z0c
.word 000001,cp.pmu!cp0000,cp.pmu!cp000c
.word 100000,cp.pmu!cpn000,cp.pmu!cpn00c
2011$:
;
; test data for m*pi tests (C=1 for T and C=0 for F)
3010$: .word 000000,cp.pmu!cp0z0c,cp.pmu!cp0z00
.word 000001,cp.pmu!cp000c,cp.pmu!cp0000
.word 100000,cp.pmu!cpn00c,cp.pmu!cpn000
3011$:
;
9999$: iot ; end of test B3.2
;
; Section C: mmr1 register and traps =========================================
;
; Test C1: ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
;
; Test C1.1 -- test mmr1 response via set abort in mmr0 trick ++++++++
; Test method (concept seen in ekbee1)
; - start with mmr1 cleared, mmr1 will track
; - write one of the 3 abort bits in mmr1 (all three are tested)
; - that will freeze mmr1
; - the register signature of the write can be inspected
;
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
; Simh only adds 'general purpose register updates, thus not pc
; w11 updates mmr1 in this case, as is also expected in ekbee1
; case commented out to ensure that cpu_mmu.mac runs on both
;; reset
;; mov -(r1),@#mmr0 ; r1,-2,pc,2 00010 111 11110 001 via ale
;; hcmpeq (r3),#^b0001011111110001;
;
reset
jmp 9999$
;
1000$: .word m0.anr
.word m0.ale
.word m0.ard
;
9999$: iot ; end of test C1.1
;
; END OF ALL TESTS - loop closure ============================================
;
mov tstno,r0 ; hack, for easy monitoring ...
hcmpeq tstno,#9. ; all tests done ?
;
jmp loop
;
; kernel handlers ============================================================
;
; 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 on word of vector push
mov vhustp,(sp) ; setup kernel return address
mov vhuhlt,vhustp ; reset stop address by catcher
rts pc ; end return to continuation address
vhustp: .word vhuhlt
vhuhlt: halt
;
; Test codes that will be mapped in user or supervisor mode ==================
; They are located at 100000 and above and are position-independent code.
; That allows to assemble and load them together with the main code.
;
; vc0 - simple code ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
; uses jsr, has stack below 1000 (no problem in user/supervisor mode)
; does operations with vc0v0, vc0v1, vc0v2
; these location are usually set before and checked afterwards in kernel mode
;
. = 100000
vc0: jmp 100$
.blkw 14. ; small stack space
100$: mov #40,sp ; initialize stack
call 1000$
emt 100 ; will end user/supervisor code
;
1000$: com vc0v0
call 2000$
return
2000$: add vc0v1,vc0v2
return
;
vc0v0: .word 0
vc0v1: .word 0
vc0v2: .word 0
;
; vc1 - simple I/D code ++++++++++++++++++++++++++++++++++++++++++++++++++++++
; uses jsr, has stack below 1000 (no problem in user/supervisor mode)
; does operations with vc1v0, vc1v1, vc1v2
; these location 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, MTPI target
;
. = 102000 ; D space
vc1dat: .blkw 16. ; small stack space
vc1stk:
vc1v0: .word 0
vc1v1: .word 0
vc1v2: .word 0
;
.end start