aboutsummaryrefslogtreecommitdiffstats
path: root/atk16_emu/emu.py
diff options
context:
space:
mode:
Diffstat (limited to 'atk16_emu/emu.py')
-rw-r--r--atk16_emu/emu.py176
1 files changed, 144 insertions, 32 deletions
diff --git a/atk16_emu/emu.py b/atk16_emu/emu.py
index 680cb71..2f5b79a 100644
--- a/atk16_emu/emu.py
+++ b/atk16_emu/emu.py
@@ -1,6 +1,7 @@
import random
from typing import Literal
from dataclasses import dataclass
+import sys
from .opcodes import *
class Register:
@@ -75,9 +76,6 @@ class ALU:
pass
def process(self, S: int, L: int, R: int):
- if S < 0 or S >= 8:
- raise ValueError(f"Invalid ALU S: {S}")
-
if L < 0 or L >= 2 ** 16:
raise ValueError(f"Invalid ALU L: {L}")
@@ -94,14 +92,34 @@ class ALU:
zero = result == 0,
sign = (result & 0x8000) != 0
))
+ case 1: # L - R
+ py_sum = L - R
+ result = py_sum & 0xFFFF
+ return ALUResult(result, ALUFlags(
+ carry = py_sum < 0,
+ overflow = (L & 0x8000) != (R & 0x8000) and (L & 0x8000) != (result & 0x8000),
+ zero = result == 0,
+ sign = (result & 0x8000) != 0
+ ))
+ case 2: # L and R
+ raise NotImplementedError()
+ case 3: # L or R
+ raise NotImplementedError()
+ case 4: # L xor R
+ raise NotImplementedError()
+ case 5: # L >> R logical
+ raise NotImplementedError()
+ case 6: # L >>> R arithmetic
+ raise NotImplementedError()
+ case 7: # L << R
+ raise NotImplementedError()
- raise NotImplementedError(f"{S}")
-
+ raise ValueError(f"Invalid ALU S: {S}")
class Machine:
def __init__(self):
- self.rom = ROM(16, 16)
- self.ram = RAM(16, 16)
+ self.rom = ROM(15, 16)
+ self.ram = RAM(15, 16)
self.alu = ALU()
self.ra = Register(16)
@@ -125,10 +143,17 @@ class Machine:
def mem_read(self, addr: int):
if addr < 2 ** 15:
- return self.rom.read(addr)
+ return self.rom.read(addr & 0x7FFF)
else:
# TODO: Implement memory-mapped I/O
- return self.ram.read(addr)
+ return self.ram.read(addr & 0x7FFF)
+
+ def mem_write(self, addr: int, value: int):
+ if addr < 2 ** 15:
+ raise ValueError(f"Cannot write to ROM, addr: {addr:>04x}")
+ else:
+ # TODO: Implement memory-mapped I/O
+ self.ram.write(addr & 0x7FFF, value)
def get_nth_register(self, n: int) -> Register:
if n < 0 or n >= 8:
@@ -164,6 +189,15 @@ class Machine:
while self.running:
self.step()
+ def check_nth_flag(self, n: int) -> bool:
+ match n:
+ case 0: return self.fr.carry
+ case 1: return self.fr.overflow
+ case 2: return self.fr.zero
+ case 3: return self.fr.sign
+
+ raise ValueError(f"Invalid flag number: {n}")
+
def step(self):
if not self.running:
raise RuntimeError("Machine is not running")
@@ -174,31 +208,88 @@ class Machine:
instr = self.mem_read(pc_addr)
instruction = self.decode(instr)
- match instruction:
- case ALR(target, left, right, alu_code):
- alu_result = self.alu.process(
- S = alu_code,
- L = self.get_nth_register(left).value,
- R = self.get_nth_register(right).value,
- )
- self.fr = alu_result.flags
+ try:
+ match instruction:
+ case ALR(target, left, right, alu_code):
+ alu_result = self.alu.process(
+ S = alu_code,
+ L = self.get_nth_register(left).value,
+ R = self.get_nth_register(right).value,
+ )
+ self.fr = alu_result.flags
+
+ target_reg = self.get_nth_register(target)
+ target_reg.value = alu_result.value
+
+ case ALI(target, left, imm, alu_code):
+ alu_result = self.alu.process(
+ S = alu_code,
+ L = self.get_nth_register(left).value,
+ R = imm,
+ )
+ self.fr = alu_result.flags
- target_reg = self.get_nth_register(target)
- target_reg.value = alu_result.value
+ target_reg = self.get_nth_register(target)
+ target_reg.value = alu_result.value
- case ALI(target, left, imm, alu_code):
- alu_result = self.alu.process(
- S = alu_code,
- L = self.get_nth_register(left).value,
- R = imm,
- )
- self.fr = alu_result.flags
+ case LDR(to_reg, addr_reg):
+ addr = self.get_nth_register(addr_reg).value
+ value = self.mem_read(addr)
- target_reg = self.get_nth_register(target)
- target_reg.value = alu_result.value
+ target_reg = self.get_nth_register(to_reg)
+ target_reg.value = value
- case HLT():
- self.running = False
+ case STR(addr_reg, from_reg):
+ addr = self.get_nth_register(addr_reg).value
+ value = self.get_nth_register(from_reg).value
+
+ self.mem_write(addr, value)
+
+ case LDI(to_reg, imm):
+ target_reg = self.get_nth_register(to_reg)
+ target_reg.value = imm
+
+ case JPR(addr_reg):
+ addr = self.get_nth_register(addr_reg).value
+ self.pc.value = addr
+
+ case JPI(imm):
+ self.pc.value = (self.pc.value + imm) & 0xFFFF
+
+ case BRR(flag, addr_reg):
+ if self.check_nth_flag(flag):
+ addr = self.get_nth_register(addr_reg).value
+ self.pc.value = addr
+
+ case BRI(flag, addr_imm):
+ if self.check_nth_flag(flag):
+ self.pc.value = (self.pc.value + addr_imm) & 0xFFFF
+
+ case LPC(target_reg):
+ target_reg = self.get_nth_register(target_reg)
+ target_reg.value = self.pc.value
+
+ case NOP():
+ pass
+
+ case ISRP0():
+ # interrupt service routine, read store PC in IPC register, set PC to ISRA value
+ raise NotImplementedError()
+
+ case ISRP1():
+ # interrupt service routine, read store PC in IPC register, set PC to ISRA value
+ raise NotImplementedError()
+
+ case RTI():
+ # return from interrupt routine, read PC from IPC register
+ raise NotImplementedError()
+
+ case HLT():
+ self.running = False
+
+ except:
+ print(f"Error while executing instruction {instr:>016b} at address {pc_addr:>04x}", file=sys.stderr)
+ raise
def decode(self, instr: int):
opcode = (instr & 0xF000) >> 12
@@ -208,7 +299,28 @@ class Machine:
left=(opdata & 0b000111000000) >> 6,
right=(opdata & 0b000000111000) >> 3,
alu_code=opdata & 0b000000000111)
+ case 0b0001: return ALI(target=(opdata & 0b111000000000) >> 9,
+ left=(opdata & 0b000111000000) >> 6,
+ imm=(opdata & 0b000000111000) >> 3,
+ alu_code=opdata & 0b000000000111)
+ case 0b0010: return LDR(to_reg=(opdata & 0b111000000000) >> 9,
+ addr_reg=(opdata & 0b000111000000) >> 6)
+ case 0b0011: return STR(addr_reg=(opdata & 0b000111000000) >> 6,
+ from_reg=(opdata & 0b000000111000) >> 3)
+ case 0b0100: return LDI(to_reg=(opdata & 0b111000000000) >> 9,
+ imm=opdata & 0b000111111111)
+ case 0b0101: return JPR(addr_reg=(opdata & 0b000111000000) >> 6)
+ case 0b0110: return JPI(imm=opdata & 0b000111111111)
+ case 0b0111: return BRR(flag=(opdata & 0b011000000000) >> 9,
+ addr_reg=(opdata & 0b000111000000) >> 6)
+ case 0b1000: return BRI(flag=(opdata & 0b011000000000) >> 9,
+ addr_imm=opdata & 0b000111111111)
+ case 0b1001: return LPC(target_reg=(opdata & 0b111000000000) >> 9)
+ case 0b1010: return NOP()
+ case 0b1011: return NOP()
+ case 0b1100: return ISRP0()
+ case 0b1101: return ISRP1()
+ case 0b1110: return RTI()
case 0b1111: return HLT()
- # TODO: Implement other opcodes
- raise ValueError(f"Invalid instruction: {instr:>16b}")
+ raise ValueError(f"Invalid instruction: {instr:>016b}")