From cc6c92335d57f822c277f8f2744d5746bcc19824 Mon Sep 17 00:00:00 2001 From: kris Date: Sat, 23 Feb 2019 23:44:29 +0000 Subject: [PATCH] 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. --- memory_map.py | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/memory_map.py b/memory_map.py index 57d1f66..bcbf9dc 100644 --- a/memory_map.py +++ b/memory_map.py @@ -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: