Implement a much more efficient mechanism for mapping an array between

(x, y) indexing and (page, offset) indexing.  This uses numpy to
construct a new array by indexing into the old one.

In benchmarking this is something like 100x faster.
This commit is contained in:
kris 2019-02-23 23:44:29 +00:00
parent 4178c191db
commit cc6c92335d

View File

@ -1,4 +1,4 @@
from typing import Tuple
import numpy as np
import screen
@ -24,10 +24,27 @@ class MemoryMap:
for screen_page in (0, 1)
]
# Array mapping (page, offset) to x (byte) and y coords respectively
PAGE_OFFSET_TO_X = np.zeros((32, 256), dtype=np.uint8)
PAGE_OFFSET_TO_Y = np.zeros((32, 256), dtype=np.uint8)
# Mask of which (page, offset) bytes represent screen holes
SCREEN_HOLES = np.full((32, 256), True, dtype=np.bool)
# Dict mapping memory address to (page, y, x_byte) tuple
ADDR_TO_COORDS = {}
for p in range(2):
for y in range(192):
for x in range(40):
for y in range(192):
for x in range(40):
y_base = Y_TO_BASE_ADDR[0][y]
page = y_base >> 8
offset = y_base - (page << 8) + x
PAGE_OFFSET_TO_Y[page - 32, offset] = y
PAGE_OFFSET_TO_X[page - 32, offset] = x
# This (page, offset) is not a screen hole
SCREEN_HOLES[page - 32, offset] = False
for p in range(2):
a = Y_TO_BASE_ADDR[p][y] + x
ADDR_TO_COORDS[a] = (p, y, x)
@ -35,16 +52,19 @@ class MemoryMap:
self.screen_page = screen_page # type: int
self.bytemap = bytemap
def to_page_offset(self, x_byte: int, y: int) -> Tuple[int, int]:
y_base = self.Y_TO_BASE_ADDR[self.screen_page][y]
page = y_base >> 8
# print("y=%d -> page=%02x" % (y, page))
offset = y_base - (page << 8) + x_byte
return page, offset
# XXX move to bytemap class?
@classmethod
def to_memory_map(cls, bytemap: np.ndarray):
# Numpy magic that constructs a new array indexed by (page, offset)
# instead of (y, x).
mmap = bytemap[cls.PAGE_OFFSET_TO_Y, cls.PAGE_OFFSET_TO_X]
# Reset whatever values ended up in the screen holes after this mapping
# (which came from default 0 values in PAGE_OFFSET_TO_X)
mmap[cls.SCREEN_HOLES] = 0
return mmap
def write(self, addr: int, val: int) -> None:
"""Updates screen image to set 0xaddr ^= val"""
"""Updates screen image to set 0xaddr = val"""
try:
_, y, x = self.ADDR_TO_COORDS[addr]
except KeyError: