Fixed errors

This commit is contained in:
Kyler 2024-02-24 01:18:23 -07:00
parent 1e84226754
commit b4ad6d084c
5 changed files with 253 additions and 55 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
*.ods#
docs/*.pdf
__pycache__

View File

@ -3,7 +3,11 @@
from typing import BinaryIO
ROM_SIZE = 0x700
MAX_INT = 0x1000
MAX_IMMEDIATE = 0x80
class ConfigurationError(Exception): pass
class Device:
@ -37,10 +41,14 @@ class Memory:
rom: list[int],
devices: list[Device] | None = None,
) -> None:
self._rom = [0] * 0x700
self._rom = [0] * ROM_SIZE
self._devices = (devices or list())[:]
self._ram = [0] * 0x1000
if len(rom) > ROM_SIZE:
raise ConfigurationError(
f"ROM too long: {hex(len(rom))} > {hex(ROM_SIZE)}")
for i, data in enumerate(rom):
self._rom[i] = data % MAX_INT
@ -84,13 +92,29 @@ class Memory:
with open(file, 'b') as f:
while f:
incoming = f.read(3)
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8) | incoming[2])
if len(incoming) == 3:
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8) | incoming[2])
elif len(incoming) == 2:
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8))
elif len(incoming) == 1:
rom.append(incoming[0] << 4)
else:
break
else:
while file:
incoming = file.read(3)
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8) | incoming[2])
if len(incoming) == 3:
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8) | incoming[2])
elif len(incoming) == 2:
rom.append(incoming[0] << 4 | ((incoming[1] & 0xf0) >> 4))
rom.append(((incoming[1] & 0xf) << 8))
elif len(incoming) == 1:
rom.append(incoming[0] << 4)
else:
break
return rom
@ -223,8 +247,14 @@ class Computer:
def interrupt(self, index: int):
self._interrupt_flag.append(index % MAX_INT)
def step(self):
def step(self, verbose: bool = False):
instruction = self._mem[self.program_counter]
if verbose:
print(
f"; {hex(self.program_counter)} : {oct(instruction)} "
f"({hex(instruction)})"
)
self.verbose_step()
if instruction == 0: self.NOP()
elif instruction == 1: self.HLT()
@ -240,28 +270,125 @@ class Computer:
elif instruction & 0xFF8 == 0x38: self.POP(instruction & 0x7)
elif instruction & 0xF80 == 0x80: self.LDI(instruction & 0x7F)
elif instruction & 0xFC0 == 0x100:
self.LSH(instruction & 0x38, instruction & 0x7)
self.LSH((instruction & 0x38) >> 3, instruction & 0x7)
elif instruction & 0xFC0 == 0x140:
self.RSH(instruction & 0x38, instruction & 0x7)
self.RSH((instruction & 0x38) >> 3, instruction & 0x7)
elif instruction & 0xFC0 == 0x180:
self.INC(instruction & 0x38, instruction & 0x7)
self.INC((instruction & 0x38) >> 3, instruction & 0x7)
elif instruction & 0xFC0 == 0x1C0:
self.DEC(instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0x200:
self.AND(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0x400:
self.OR(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0x600:
self.NAD(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0x800:
self.SUB(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0xA00:
self.XOR(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0xC00:
self.NOR(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
elif instruction & 0xE0 == 0xE00:
self.ADD(instruction & 0x1C, instruction & 0x38, instruction & 0x7)
else: raise LookupError()
self.DEC((instruction & 0x38) >> 3, instruction & 0x7)
elif instruction & 0xE00 == 0x200:
self.AND(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0x400:
self.OR(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0x600:
self.NAD(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0x800:
self.SUB(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0xA00:
self.XOR(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0xC00:
self.NOR(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
elif instruction & 0xE00 == 0xE00:
self.ADD(
instruction & 0x7,
(instruction & 0x38) >> 3,
(instruction & 0x1C0) >> 6,
)
else:
raise LookupError(
f"Cannot find instruction "
f"{hex(self.program_counter)}: {oct(instruction)}"
)
def verbose_step(self):
instruction = self._mem[self.program_counter]
if instruction == 0: print("NOP")
elif instruction == 1: print("HLT")
elif instruction == 2: print("INT")
elif instruction == 3: print("BNZ")
elif instruction == 4: print("BLK")
elif instruction == 5: print("ENB")
elif instruction & 0xFF8 == 0x10: print(f"GLA {instruction & 0x7}")
elif instruction & 0xFF8 == 0x18: print(f"GET {instruction & 0x7}")
elif instruction & 0xFF8 == 0x20: print(f"LOD {instruction & 0x7}")
elif instruction & 0xFF8 == 0x28: print(f"STR {instruction & 0x7}")
elif instruction & 0xFF8 == 0x30: print(f"PSH {instruction & 0x7}")
elif instruction & 0xFF8 == 0x38: print(f"POP {instruction & 0x7}")
elif instruction & 0xF80 == 0x80: print(f"LDI {instruction & 0x7F}")
elif instruction & 0xFC0 == 0x100:
print(f"LSH {instruction & 0x7} {(instruction & 0x38) >> 3}")
elif instruction & 0xFC0 == 0x140:
print(f"RSH {instruction & 0x7} {(instruction & 0x38) >> 3}")
elif instruction & 0xFC0 == 0x180:
print(f"INC {instruction & 0x7} {(instruction & 0x38) >> 3}")
elif instruction & 0xFC0 == 0x1C0:
print(f"DEC {instruction & 0x7} {(instruction & 0x38) >> 3}")
elif instruction & 0xE00 == 0x200:
print(
f"AND {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0x400:
print(
f"OR {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0x600:
print(
f"NAD {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0x800:
print(
f"SUB {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0xA00:
print(
f"XOR {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0xC00:
print(
f"NOR {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
elif instruction & 0xE00 == 0xE00:
print(
f"ADD {instruction & 0x7} {(instruction & 0x1C0) >> 6} "
f"{(instruction & 0x38) >> 3}"
)
else:
print(
f"LookupError: Cannot find instruction "
f"{hex(self.program_counter)}: {oct(instruction)}"
)
# === Operations ===
@ -315,7 +442,7 @@ class Computer:
self.program_counter += 1
def LDI(self, Immediate: int):
self.pointer = Immediate % 0x3F
self.pointer = Immediate % MAX_IMMEDIATE
self.program_counter += 1
def LSH(self, REG_D: int, REG_A: int):

View File

@ -6,15 +6,12 @@ from typing import Sequence
from .emulator import Computer, Memory
from .devices import tty
def simple_computer_with_tty(rom: list[int]) -> Computer:
return Computer(Memory(rom, [tty(0x7FE, 0x7FF)]))
def main(argv: Sequence[str]):
def main(argv: Sequence[str] | None = None):
import argparse
from time import sleep
machines = {
'tty': simple_computer_with_tty
'tty': lambda rom: Computer(Memory(rom, [tty(0x7FE, 0x7FF)]))
}
parser = argparse.ArgumentParser(
@ -23,14 +20,36 @@ def main(argv: Sequence[str]):
parser.add_argument('rom_file', type=argparse.FileType('rb'))
parser.add_argument(
'-m', '--machine', choices=machines.keys(), default='tty')
parser.add_argument('-v', '--verbose', action='store_true')
parser.add_argument('-s', '--step', action='store_true')
parser.add_argument('-c', '--clock', default='100')
args = parser.parse_args(argv)
computer = machines[args.machine](Memory.load_rom_file(args.rom_file))
while computer.active:
computer.step()
try:
while computer.active:
if args.verbose:
print(
f"ZR: {hex(0)} \t"
f"PC: {hex(computer.program_counter)} \t"
f"SP: {hex(computer.stack_pointer)} \t"
f"MP: {hex(computer.pointer)}"
)
print(
f"D0: {hex(computer.data_0)} \t"
f"D1: {hex(computer.data_1)} \t"
f"D2: {hex(computer.data_2)} \t"
f"D3: {hex(computer.data_3)}"
)
if args.step:
input("Press enter to step to next instruction...")
computer.step(args.verbose)
if not args.step:
sleep(int(args.clock)/1000)
except KeyboardInterrupt:
print("Keyboard Interrupt: Program Exiting...")
if __name__ == '__main__':
from sys import argv
main(argv)
main()

View File

@ -5,6 +5,7 @@ from collections import namedtuple
from typing import TypeVar, Generic, Iterable, Sequence
INSTRUCTIONS_COUNT = 0x700
MAX_IMMEDIATE = 0x80
class AssemblerError(Exception): pass
class LinkerError(Exception): pass
@ -105,10 +106,16 @@ class Instruction(namedtuple('Instruction', ['bb', 'bl', 'lb', 'll'])):
def __bytes__(self) -> bytes:
value = int(self)
u = value & 0xf00 >> 8
m = value & 0xf0 >> 4
u = (value & 0xf00) >> 8
l = value & 0xff
return bytes((u, l))
def hex_tuple(self) -> tuple[int, int, int]:
value = int(self)
u = (value & 0xf00) >> 8
m = (value & 0xf0) >> 4
l = value & 0xf
return bytes((u, m, l))
return (u, m, l)
def oct_str(self) -> str:
return (
@ -215,10 +222,25 @@ class Program:
def __bytes__(self) -> bytes:
output = bytearray()
for i in range(0, INSTRUCTIONS_COUNT, 2):
instruction = self._get_instruction(i)
u1, m1, l1 = instruction.hex_tuple()
output += bytes(((u1 << 4) | m1, ))
if i + 1 < INSTRUCTIONS_COUNT:
instruction = self._get_instruction(i + 1)
u2, m2, l2 = instruction.hex_tuple()
output += bytes(((l1 << 4) | u2, ))
output += bytes(((m2 << 4) | l2, ))
else:
output += bytes((l1 << 4, ))
return bytes(output)
def hex_str(self) -> str:
output = ""
for i in range(INSTRUCTIONS_COUNT):
instruction = self._get_instruction(i)
output += bytes(instruction)
return bytes(output)
output += f"{hex(int(instruction))}\n"
return output
def labels(self) -> dict[str, int]:
return self._label_map.copy()
@ -229,7 +251,7 @@ class Program:
else: _, value = self._instructions[new_index]
if isinstance(value, Immediate):
return self.instruction_set["LDI"](
f"LDI {self._label_map[value.value]}", -1)
f"LDI {self._label_map[value.value] -1}", -1)
elif isinstance(value, Directive):
raise LinkerError("Unexpected directive!")
else:
@ -300,7 +322,8 @@ class Program:
last_error = e
print(f"Error:\n\t{e}")
if last_error is not None:
raise last_error
# raise last_error
exit()
return instructions
@ -370,17 +393,21 @@ def immediate(line: str, line_number: int) -> Instruction | Immediate:
else:
value = int(args[1], base=0)
return Instruction(
0,
2 + ((value & 0x040) >> 6),
(value & 0x038) >> 3,
value & 0x007,
)
if value >= MAX_IMMEDIATE:
raise AssemblerError(
f"Immediate value too large {line_number}: {args[1]}")
return Instruction(
0,
2 + ((value & 0x040) >> 6),
(value & 0x038) >> 3,
value & 0x007,
)
else:
raise AssemblerError(
f"Invalid number of arguments on line {line_number}: {args[0]}")
def main(argv: Sequence[str]):
def main(argv: Sequence[str] | None = None):
import argparse
parser = argparse.ArgumentParser(
description='ytd 12-bit Computer Linker and Assembler',
@ -388,11 +415,23 @@ def main(argv: Sequence[str]):
parser.add_argument('input_file', type=argparse.FileType('r'))
parser.add_argument('-o', '--output_file', type=argparse.FileType('wb'))
parser.add_argument('-l', '--labels_file', type=argparse.FileType('w'))
parser.add_argument('-x', '--hex_file', type=argparse.FileType('w'))
args = parser.parse_args(argv)
program = Program(args.input_file.read())
try: assert len(bytes(program)) <= INSTRUCTIONS_COUNT * 1.5
except AssertionError:
print(
hex(int(len(bytes(program)) / 1.5)),
'>',
hex(INSTRUCTIONS_COUNT),
':',
hex(int(len(bytes(program)) / 1.5) - INSTRUCTIONS_COUNT),
)
raise
if args.output_file:
args.output_file.write(bytes(program))
@ -400,6 +439,8 @@ def main(argv: Sequence[str]):
for label, location in program.labels().items():
args.labels_file.write(f"{hex(location)}, {label}\n")
if args.hex_file:
args.hex_file.write(program.hex_str())
if __name__ == '__main__':
from sys import argv
main(argv)
main()

View File

@ -2,9 +2,19 @@
; Example 1 - ytd 12-bit Computer
; Fibonacci
.0x5
; .0x5
main:
; Initialize values
; Load Output Device Address
ldi 0x7F
or D3 MP ZR
lsh D3 D3
lsh D3 D3
lsh D3 D3
lsh D3 D3
ldi 0xE
or D3 MP D3
; Initialize Fibonacci values
ldi 1
or D0 MP ZR
or D1 ZR ZR
@ -12,7 +22,7 @@ main:
loop:
; Output current value
ldi 0x7FE
or MP D3 ZR
str D0
; Move values down