diff options
| -rw-r--r-- | atk16_emu/emu.py | 19 | ||||
| -rw-r--r-- | atk16_emu/peripherals.py | 30 |
2 files changed, 42 insertions, 7 deletions
diff --git a/atk16_emu/emu.py b/atk16_emu/emu.py index 3f0fa41..43dfdf1 100644 --- a/atk16_emu/emu.py +++ b/atk16_emu/emu.py @@ -119,6 +119,7 @@ class Machine: self.rh = Register(16) self.pc = Counter(16) + self.ipc = Register(16) self.fr = ALUFlags( carry = False, overflow = False, @@ -128,10 +129,11 @@ class Machine: self.steps_taken = 0 self.running = False + self.is_in_irq = False self.peripherals_enabled = peripherals_enabled if peripherals_enabled: - self.peripherals = Peripherals() + self.peripherals = Peripherals(set_irq_line=self.set_irq_line) else: self.peripherals = DummyPeripherals() @@ -176,6 +178,9 @@ class Machine: new_machine.pc = Counter(self.pc.bits) new_machine.pc.value = self.pc.value + new_machine.ipc = Register(self.ipc.bits) + new_machine.ipc.value = self.ipc.value + new_machine.fr = ALUFlags( carry = self.fr.carry, overflow = self.fr.overflow, @@ -262,6 +267,14 @@ class Machine: raise ValueError(f"Invalid flag number: {n}") + def set_irq_line(self, line: int): + if not self.is_in_irq: + self.ipc.value = self.pc.value + isr_addr_pointer = 0x10 + line # see bootstrap.atk16 vector table + isr_addr = self.mem_read(isr_addr_pointer) + self.pc.value = isr_addr + self.is_in_irq = True + def step(self): if not self.running: raise RuntimeError("Machine is not running") @@ -345,6 +358,7 @@ class Machine: case ISRP0(): # interrupt service routine, read store PC in IPC register, set PC to ISRA value + raise NotImplementedError() case ISRP1(): @@ -353,7 +367,8 @@ class Machine: case RTI(): # return from interrupt routine, read PC from IPC register - raise NotImplementedError() + self.pc.value = self.ipc.value + self.is_in_irq = False case HLT(): self.running = False diff --git a/atk16_emu/peripherals.py b/atk16_emu/peripherals.py index 54020f4..343f32d 100644 --- a/atk16_emu/peripherals.py +++ b/atk16_emu/peripherals.py @@ -2,21 +2,26 @@ import pygame import sys import random from .memory import RAM, ROM +from typing import Callable + +IRQ_LINE_KEYBOARD = 0 class Peripherals: - def __init__(self): + def __init__(self, set_irq_line: Callable[[int], None]): pygame.init() self.graphics = Graphics() self.keyboard = Keyboard() self.terminal = Terminal() + self.set_irq_line = set_irq_line + def step(self): for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit(0) elif event.type == pygame.KEYDOWN: - print(f"key pressed: {event.key}") - self.keyboard.latest_pressed = event.key + self.keyboard.set_latest_pressed(event.key) + self.set_irq_line(IRQ_LINE_KEYBOARD) self.graphics.step() @@ -62,7 +67,7 @@ class TPU: def write_char(self, addr: int, char: int): # address: 5 bits y, 6 bits x - self.text_mem.write(addr, char) + self.text_mem.write(addr, char & 0xFF) class Graphics: def __init__(self): @@ -70,10 +75,14 @@ class Graphics: surface_scale = 4 self.screen = pygame.display.set_mode((320 * surface_scale, 240 * surface_scale)) + pygame.display.set_caption("ATK16 Emulator") self.clock = pygame.time.Clock() self.tpu = TPU() self.active_picture_unit: TPU | None = None + self.step_counter = 0 + self.draw_frame_every_n_steps = 500 # arbitrary, perf related + def activate_tpu(self): self.active_picture_unit = self.tpu @@ -84,13 +93,17 @@ class Graphics: self.active_picture_unit = None def step(self): - if self.active_picture_unit: + if self.active_picture_unit and self.step_counter >= self.draw_frame_every_n_steps: self.active_picture_unit.frame() self.screen.blit(pygame.transform.scale(self.tpu.surface, self.screen.get_size()), (0, 0)) pygame.display.flip() self.clock.tick(60) + self.step_counter = 0 + else: + self.step_counter += 1 + def write(self, addr: int, char: int): # take only the lower 11 bits self.tpu.write_char(addr & 0x7FF, char) @@ -119,6 +132,13 @@ class Keyboard: # mimic electronic behaviour my assigning a random value at start self.latest_pressed: int = random.randrange(0, 2 ** 16) + def set_latest_pressed(self, i: int): + if i < 0 or i > 0xFFFF: + # sometimes the keycodes are out of range, don't know why + return + + self.latest_pressed = i + def read(self) -> int: return self.latest_pressed |
