Fixed errors
This commit is contained in:
parent
1e84226754
commit
b4ad6d084c
|
@ -1,2 +1,3 @@
|
|||
*.ods#
|
||||
docs/*.pdf
|
||||
__pycache__
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue