more updown tests
This commit is contained in:
parent
cb9cafc3fb
commit
e9b71fecd5
1 changed files with 181 additions and 113 deletions
200
pdptests.py
200
pdptests.py
|
@ -62,15 +62,19 @@ class TestMethods(unittest.TestCase):
|
||||||
|
|
||||||
# Kernel instruction space PDR registers
|
# Kernel instruction space PDR registers
|
||||||
ns.KISD0 = cls.ioaddr(p, p.mmu.APR_KERNEL_OFFS)
|
ns.KISD0 = cls.ioaddr(p, p.mmu.APR_KERNEL_OFFS)
|
||||||
|
ns.KISD7 = ns.KISD0 + 0o16
|
||||||
|
|
||||||
# Kernel data space PDR registers
|
# Kernel data space PDR registers
|
||||||
ns.KDSD0 = ns.KISD0 + 0o20
|
ns.KDSD0 = ns.KISD0 + 0o20
|
||||||
|
ns.KDSD7 = ns.KDSD0 + 0o16
|
||||||
|
|
||||||
# Kernel instruction space PAR registers
|
# Kernel instruction space PAR registers
|
||||||
ns.KISA0 = ns.KDSD0 + 0o20
|
ns.KISA0 = ns.KDSD0 + 0o20
|
||||||
|
ns.KISA7 = ns.KISA0 + 0o16
|
||||||
|
|
||||||
# Kernel data space PAR registers
|
# Kernel data space PAR registers
|
||||||
ns.KDSA0 = ns.KISA0 + 0o20
|
ns.KDSA0 = ns.KISA0 + 0o20
|
||||||
|
ns.KDSA7 = ns.KDSA0 + 0o16
|
||||||
|
|
||||||
# User mode similar
|
# User mode similar
|
||||||
ns.UISD0 = cls.ioaddr(p, p.mmu.APR_USER_OFFS)
|
ns.UISD0 = cls.ioaddr(p, p.mmu.APR_USER_OFFS)
|
||||||
|
@ -660,17 +664,24 @@ class TestMethods(unittest.TestCase):
|
||||||
def test_mmu_updown(self):
|
def test_mmu_updown(self):
|
||||||
# test the page length field support in both up and down directions
|
# test the page length field support in both up and down directions
|
||||||
|
|
||||||
|
# XXX whether it was wise to code this test as a magnum opus
|
||||||
|
# of assembler prowess is well open to debate. On the plus
|
||||||
|
# side, it certainly exercises a bunch of features besides
|
||||||
|
# just testing the MMU page length functionality.
|
||||||
|
|
||||||
cn = self.usefulconstants()
|
cn = self.usefulconstants()
|
||||||
|
p = self.make_pdp()
|
||||||
|
|
||||||
# Two tests - up and down.
|
# Two tests - up and down.
|
||||||
#
|
#
|
||||||
# In both tests, KERNEL I space page 0 is mapped to physical 0
|
# In both tests, KERNEL I space page 0 is mapped to physical 0
|
||||||
# and I/D separation is NOT enabled for KERNEL.
|
# and KERNEL I space page 7 is mapped to the I/O page.
|
||||||
|
# I/D separation is NOT enabled for KERNEL.
|
||||||
|
#
|
||||||
#
|
#
|
||||||
# USER I space is mapped to 0o20000.
|
# USER I space is mapped to 0o20000.
|
||||||
# All 64K of USER D space is mapped to 64K of physical memory
|
# All 64K of USER D space is mapped to 64K of physical memory
|
||||||
# ranging from 0o200000 (not a typo) to 0o
|
# from 0o200000 (not a typo) to 0o400000 (not a typo), but with
|
||||||
# from 0o200000 (not a typo) .. 0o400000 (not a typo), but with
|
|
||||||
# a bizarre segment length scheme according to UP or DOWN phase of
|
# a bizarre segment length scheme according to UP or DOWN phase of
|
||||||
# the test as below. I/D separation is (obviously) enabled for USER.
|
# the test as below. I/D separation is (obviously) enabled for USER.
|
||||||
# All 64K of that memory is filled with sequential words such
|
# All 64K of that memory is filled with sequential words such
|
||||||
|
@ -693,22 +704,25 @@ class TestMethods(unittest.TestCase):
|
||||||
# same 0, 1, 2 .. progression (of valid "blocks") but they
|
# same 0, 1, 2 .. progression (of valid "blocks") but they
|
||||||
# are at the end of the segments.
|
# are at the end of the segments.
|
||||||
|
|
||||||
# this programs the MMU as above, according to dirbit (0 = up)
|
# these instructions do initialization common to both up/down cases
|
||||||
# NOTE: the physical memory is filled in elsewhere
|
kernel_addr = 0o4000 # arbitrary start for all this
|
||||||
def mmusetup(dirbit): # "dirbit" as in PDR direction bit
|
|
||||||
with ASM() as a:
|
with ASM() as a:
|
||||||
a.mov(0o20000, 'sp') # start system stack at 8k
|
a.mov(0o20000, 'sp') # start system stack at 8k
|
||||||
# KERNEL I SPACE
|
# KERNEL I SPACE
|
||||||
# PAR to physical 0
|
# PAR 0 to physical 0
|
||||||
|
# PAR 7 to physical 760000 and 22bit not turned on
|
||||||
|
#
|
||||||
# PDR 77406 = read/write, full length
|
# PDR 77406 = read/write, full length
|
||||||
a.clr(a.ptr(cn.KISA0))
|
a.clr(a.ptr(cn.KISA0))
|
||||||
|
a.mov(0o760000 >> 6, a.ptr(cn.KISA7))
|
||||||
a.mov(0o077406, a.ptr(cn.KISD0))
|
a.mov(0o077406, a.ptr(cn.KISD0))
|
||||||
|
a.mov(0o077406, a.ptr(cn.KISD7))
|
||||||
|
|
||||||
# USER I SPACE
|
# USER I SPACE
|
||||||
a.mov(0o20000 >> 6, a.ptr(cn.UISA0))
|
a.mov(0o20000 >> 6, a.ptr(cn.UISA0))
|
||||||
a.mov(0o077406, a.ptr(cn.UISD0))
|
a.mov(0o077406, a.ptr(cn.UISD0))
|
||||||
|
|
||||||
# USER D SPACE ...
|
# USER D SPACE going UP...
|
||||||
a.mov(cn.UDSD0, 'r3') # will walk through D0 .. D7
|
a.mov(cn.UDSD0, 'r3') # will walk through D0 .. D7
|
||||||
# NOTE: A0 .. A7 is 040(r3)
|
# NOTE: A0 .. A7 is 040(r3)
|
||||||
a.clr('r0') # r0: segno*2 = (0, 2, 4, .., 14)
|
a.clr('r0') # r0: segno*2 = (0, 2, 4, .., 14)
|
||||||
|
@ -719,59 +733,115 @@ class TestMethods(unittest.TestCase):
|
||||||
a.mov('r4', '040(r3)') # set U PAR; don't bump r3 yet
|
a.mov('r4', '040(r3)') # set U PAR; don't bump r3 yet
|
||||||
a.add(0o200, 'r4') # 0o200 = 8192>>6
|
a.add(0o200, 'r4') # 0o200 = 8192>>6
|
||||||
|
|
||||||
|
a.mov('r0', 'r2') # r2 = segno*2
|
||||||
|
a.ash(3, 'r2') # r2 = segno*16
|
||||||
|
a.swab('r2') # really (segno*16)<<8
|
||||||
|
a.add(0o06, 'r2') # ACF r/w segment
|
||||||
|
a.mov('r2', '(r3)+') # set U PDR
|
||||||
|
a.inc('r0') # bump r0 by two
|
||||||
|
a.inc('r0')
|
||||||
|
a.cmp('r0', 16) # and loop until done all 8 segments
|
||||||
|
a.blt('PARloop')
|
||||||
|
|
||||||
|
a.bis(1, a.ptr(cn.MMR3)) # enable I/D sep just for USER
|
||||||
|
a.mov(1, a.ptr(cn.MMR0)) # turn on MMU
|
||||||
|
a.mov(0o140340, '-(sp)') # push user-ish PSW to K stack
|
||||||
|
a.clr('-(sp)') # new user PC = 0
|
||||||
|
a.clr('r0') # user test expects r0 to start zero
|
||||||
|
|
||||||
|
# this halt will be right before the first run of user mode test
|
||||||
|
a.halt()
|
||||||
|
|
||||||
|
# the subsequent p.run() picks up here and starts the user code!
|
||||||
|
a.rtt()
|
||||||
|
|
||||||
|
# these instructions are the trap handlers for both
|
||||||
|
# the MMU abort and the trap 0 "all good". The only difference
|
||||||
|
# is that only the MMU abort puts 666 into r5.
|
||||||
|
a.label('TrapMMU')
|
||||||
|
a.mov(0o666, 'r5')
|
||||||
|
a.label('Trap0')
|
||||||
|
a.halt()
|
||||||
|
|
||||||
|
# when test code starts again with p.run(), restarts here...
|
||||||
|
a.clr('(sp)') # just knows the user loop starts at zero
|
||||||
|
a.rtt() # back for another iteration
|
||||||
|
|
||||||
|
# these instructions will be used to switch over
|
||||||
|
# to the DOWN phase of the test. Similar to the UP but
|
||||||
|
# don't have to do the PARs (they stay the same) and the
|
||||||
|
# pln calculations are different.
|
||||||
|
|
||||||
|
a.label('DOWN')
|
||||||
|
a.mov(cn.UDSD0, 'r3')
|
||||||
|
a.clr('r0')
|
||||||
|
a.label('PARloopDOWN')
|
||||||
# compute segno * 8 in r2 (r0 starts as segno*2)
|
# compute segno * 8 in r2 (r0 starts as segno*2)
|
||||||
a.mov('r0', 'r2')
|
a.mov('r0', 'r2')
|
||||||
a.ash(3, 'r2')
|
a.ash(3, 'r2')
|
||||||
|
|
||||||
if dirbit:
|
|
||||||
# pln = 0o177 - (segno * 16)
|
# pln = 0o177 - (segno * 16)
|
||||||
a.mov(0o177, 'r1')
|
a.mov(0o177, 'r1')
|
||||||
a.sub('r2', 'r1')
|
a.sub('r2', 'r1')
|
||||||
a.mov('r1', 'r2')
|
a.mov('r1', 'r2')
|
||||||
a.swab('r2')
|
a.swab('r2')
|
||||||
a.add(0o10, 'r2') # the downward growing case
|
a.add(0o16, 'r2') # the downward growing case
|
||||||
else:
|
|
||||||
# pln = segno * 16 ... already in r2
|
|
||||||
# pln << 8
|
|
||||||
a.swab('r2')
|
|
||||||
|
|
||||||
a.add(0o06, 'r2')
|
|
||||||
a.mov('r2', '(r3)+') # set U PDR
|
a.mov('r2', '(r3)+') # set U PDR
|
||||||
|
|
||||||
a.inc('r0')
|
a.inc('r0')
|
||||||
a.inc('r0')
|
a.inc('r0')
|
||||||
a.cmp('r0', 16)
|
a.cmp('r0', 16)
|
||||||
a.blt('PARloop')
|
a.blt('PARloopDOWN')
|
||||||
|
|
||||||
return a
|
# this halt will be right before the first run of user mode test
|
||||||
|
a.halt()
|
||||||
|
|
||||||
for dirbit in (0o00, 0o10):
|
a.clr('r0') # initial loop condition
|
||||||
p = self.make_pdp()
|
a.clr('(sp)') # just knows the user loop starts at zero
|
||||||
# trap handler for MMU faults; puts 0o666 into r5 and halts
|
a.rtt()
|
||||||
trap_h_location = 0o3000
|
|
||||||
with ASM() as th:
|
# Now for something extra frosty... relocate just segment 4
|
||||||
th.mov(0o666, 'r5')
|
# (arbitrarily chosen) of the user memory to a different
|
||||||
trap0_offs = th.label('Trap0')
|
# physical page and run the test again to ensure it still works.
|
||||||
th.halt()
|
# This will make use of KERNEL A1 and A2 segments to map the
|
||||||
th.clr('(sp)') # just know the loop starts at zero
|
# relocation (note: I space because no sep I/D for kernel here)
|
||||||
th.rtt()
|
a.label('BONUS')
|
||||||
self.loadphysmem(p, th.instructions(), trap_h_location)
|
|
||||||
|
# copy UDSA4 into KISA1 - mapping old segment into kernel space
|
||||||
|
a.mov(a.ptr(cn.UDSA0 + 4*2), a.ptr(cn.KISA0 + 2)) # i.e., A1
|
||||||
|
|
||||||
|
# the new location for this data will be physical 0o600000
|
||||||
|
# (not a typo) which becomes 0o6000 in the PAR
|
||||||
|
a.mov(0o6000, a.ptr(cn.KISA0 + 4)) # i.e., A2
|
||||||
|
|
||||||
|
# the standard PDR access/full-length/etc bits
|
||||||
|
a.mov(0o077406, a.ptr(cn.KISD0 + 2))
|
||||||
|
a.mov(0o077406, a.ptr(cn.KISD0 + 4))
|
||||||
|
|
||||||
|
# count r0, source address r1, destination r2
|
||||||
|
a.mov(4096, 'r0')
|
||||||
|
a.mov(8192, 'r1')
|
||||||
|
a.mov(8192*2, 'r2')
|
||||||
|
a.mov('(r1)+', '(r2)+')
|
||||||
|
a.literal(0o077002) # SOB to the copy
|
||||||
|
|
||||||
|
# switch the user page to the new mapping
|
||||||
|
a.mov(0o6000, a.ptr(cn.UDSA0 + 4*2))
|
||||||
|
|
||||||
|
# and the standard initialization/resume dance
|
||||||
|
a.halt()
|
||||||
|
a.clr('r0')
|
||||||
|
a.clr('(sp)') # just knows the user loop starts at zero
|
||||||
|
a.rtt()
|
||||||
|
|
||||||
# poke the trap handler vector (250)
|
# poke the trap handler vector (250)
|
||||||
pcps = [trap_h_location, 0]
|
pcps = [kernel_addr + (a.labels['TrapMMU'] * 2), 0]
|
||||||
|
|
||||||
self.loadphysmem(p, pcps, 0o250)
|
self.loadphysmem(p, pcps, 0o250)
|
||||||
|
|
||||||
# same for the "trap 0" handler but skip to trap0_offs
|
# same for the "trap 0" handler but skip to trap0_offs
|
||||||
pcps[0] += (trap0_offs*2)
|
pcps = [kernel_addr + (a.labels['Trap0'] * 2), 0]
|
||||||
self.loadphysmem(p, pcps, 0o34)
|
self.loadphysmem(p, pcps, 0o34)
|
||||||
|
|
||||||
# set the physical memory that will be mapped to user D
|
# all those kernel instructions
|
||||||
# space to this pattern so the test can verify the mapping
|
self.loadphysmem(p, a.instructions(), kernel_addr)
|
||||||
checksum = 0o123456 # arbitrary
|
|
||||||
user_phys_DSPACEbase = 0o200000
|
|
||||||
words = (checksum - (user_phys_DSPACEbase + o) & 0o177777
|
|
||||||
for o in range(0, 65536, 2))
|
|
||||||
self.loadphysmem(p, words, user_phys_DSPACEbase)
|
|
||||||
|
|
||||||
# user mode program:
|
# user mode program:
|
||||||
# read the given address: mov (r0)+,r1
|
# read the given address: mov (r0)+,r1
|
||||||
|
@ -792,40 +862,27 @@ class TestMethods(unittest.TestCase):
|
||||||
u.mov(0o42, 'r5')
|
u.mov(0o42, 'r5')
|
||||||
u.trap(0)
|
u.trap(0)
|
||||||
u.halt() # never get here, this is illegal
|
u.halt() # never get here, this is illegal
|
||||||
|
|
||||||
self.loadphysmem(p, u.instructions(), user_phys_ISPACEaddr)
|
self.loadphysmem(p, u.instructions(), user_phys_ISPACEaddr)
|
||||||
|
|
||||||
a = mmusetup(dirbit)
|
# set the physical memory that will be mapped to user D
|
||||||
a.bis(1, a.ptr(cn.MMR3)) # enable I/D sep just for USER
|
# space to this pattern so the test can verify the mapping
|
||||||
a.mov(1, a.ptr(cn.MMR0)) # turn on MMU
|
checksum = 0o123456 # arbitrary
|
||||||
a.mov(0o20000, 'sp') # establish kernel stack
|
user_phys_DSPACEbase = 0o200000
|
||||||
a.mov(0o140340, '-(sp)') # push user-ish PSW to K stack
|
words = (checksum - (user_phys_DSPACEbase + o) & 0o177777
|
||||||
a.clr('-(sp)') # new user PC = 0
|
for o in range(0, 65536, 2))
|
||||||
a.clr('r0') # user test expects r0 to start zero
|
self.loadphysmem(p, words, user_phys_DSPACEbase)
|
||||||
|
|
||||||
a.halt()
|
# finally ready to run the kernel setup instructions
|
||||||
rtt_offs = a.label('RTT') * 2
|
p.run(pc=kernel_addr)
|
||||||
a.rtt()
|
|
||||||
|
|
||||||
addr = 0o4000
|
|
||||||
self.loadphysmem(p, a.instructions(), addr)
|
|
||||||
|
|
||||||
p.run(pc=addr) # note HALT prior to RTT
|
|
||||||
|
|
||||||
def good(dirbit, segno, o):
|
|
||||||
if dirbit:
|
|
||||||
minvalidoffset = 8192 - (64 + ((segno * 64) * 16))
|
|
||||||
return o >= minvalidoffset
|
|
||||||
else:
|
|
||||||
maxvalidoffset = 63 + ((segno * 64) * 16)
|
|
||||||
return o <= maxvalidoffset
|
|
||||||
|
|
||||||
|
# this will be used for both up/down testing, based on goodf
|
||||||
|
def _test(goodf):
|
||||||
for segno in range(8):
|
for segno in range(8):
|
||||||
for o in range(4096):
|
for o in range(4096):
|
||||||
p.run() # picks up at rtt pc
|
p.run() # picks up at rtt pc
|
||||||
physval = (checksum -
|
physval = (checksum -
|
||||||
((segno * 8192) + (o * 2))) & 0o177777
|
((segno * 8192) + (o * 2))) & 0o177777
|
||||||
if good(dirbit, segno, o*2):
|
if goodf(segno, o*2):
|
||||||
r5_expected = 0o42
|
r5_expected = 0o42
|
||||||
r1_expected = physval
|
r1_expected = physval
|
||||||
else:
|
else:
|
||||||
|
@ -834,6 +891,17 @@ class TestMethods(unittest.TestCase):
|
||||||
self.assertEqual(p.r[1], r1_expected)
|
self.assertEqual(p.r[1], r1_expected)
|
||||||
self.assertEqual(p.r[5], r5_expected)
|
self.assertEqual(p.r[5], r5_expected)
|
||||||
|
|
||||||
|
# run the UP test:
|
||||||
|
_test(lambda _segno, _o: _o <= (63 + ((_segno * 64) * 16)))
|
||||||
|
|
||||||
|
# run the code to convert over to DOWN MMU format, and then the test
|
||||||
|
p.run(pc=kernel_addr + (a.labels['DOWN'] * 2))
|
||||||
|
_test(lambda _segno, _o: _o >= 8192 - (64 + ((_segno * 64) * 16)))
|
||||||
|
|
||||||
|
# last but not least, the BONUS test
|
||||||
|
p.run(pc=kernel_addr + (a.labels['BONUS'] * 2))
|
||||||
|
_test(lambda _segno, _o: _o >= 8192 - (64 + ((_segno * 64) * 16)))
|
||||||
|
|
||||||
def test_ubmap(self):
|
def test_ubmap(self):
|
||||||
p = self.make_pdp()
|
p = self.make_pdp()
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue