Created
February 18, 2021 07:49
-
-
Save RossComputerGuy/3cbb6837a67d2a748f0ccf1346b7ac40 to your computer and use it in GitHub Desktop.
Simple Emulator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
REG_NAMES = [ | |
'ADDR', | |
] | |
INSTRS = { | |
'nop': ( 0, False ), | |
'set': ( 1, True ), | |
'mmove': ( 2, True ), | |
'rmove': ( 3, True ), | |
'rmm': ( 4, True ), | |
'mmr': ( 5, True ), | |
'add': ( 6, True ), | |
'sub': ( 7, True ), | |
'mul': ( 8, True ), | |
'div': ( 9, True ), | |
'print': ( 10, True ), | |
'mrun': ( 11, True ) | |
} | |
class CPU: | |
def __init__(self): | |
self.mem = bytearray([0] * 1024) | |
self.regs = bytearray([0] * 16) | |
self.pc = 0 | |
self.running = False | |
self.mrun = False | |
def write_reg(self, regname, value): | |
if regname in REG_NAMES: | |
self.regs[REG_NAMES.index(regname)] = value | |
else: | |
raise RuntimeError('Unknown register name: {}'.format(regname)) | |
def read_reg(self, regname): | |
if regname in REG_NAMES: | |
return self.regs[REG_NAMES.index(regname)] | |
else: | |
raise RuntimeError('Unknown register name: {}'.format(regname)) | |
def fetch(self): | |
if self.mrun == False: | |
str_instr = input('Instruction: ').lower().split(' ') | |
instr = { 'op': 0, 'val': 0 } | |
for key, value in INSTRS.items(): | |
if str_instr[0] == key: | |
instr['op'] = value[0] | |
if value[1] == True: | |
instr['val'] = int(str_instr[1]) | |
return instr | |
instr['op'] = int(str_instr[0]) | |
instr['val'] = int(str_instr[1]) | |
else: | |
return { 'op': (self.mem[self.pc] << 8) | self.mem[self.pc + 1], 'val': (self.mem[self.pc + 2] << 8) | self.mem[self.pc + 3] } | |
def execute(self, instr): | |
if instr['op'] == 0x0: | |
self.running = False | |
elif instr['op'] == 1: | |
# Set address | |
self.write_reg('ADDR', instr['val']) | |
elif instr['op'] == 2: | |
# Move data to memory | |
self.mem[self.read_reg('ADDR')] = instr['val'] | |
elif instr['op'] == 3: | |
# Move data to register | |
self.regs[self.read_reg('ADDR')] = instr['val'] | |
elif instr['op'] == 4: | |
# Move register to memory | |
self.mem[self.read_reg('ADDR')] = self.regs[instr['val']] | |
elif instr['op'] == 5: | |
# Move memory to register | |
self.regs[instr.val] = self.mem[self.read_reg('ADDR')] | |
elif instr['op'] == 6: | |
# Add value in register | |
self.regs[self.read_reg('ADDR')] += instr['val'] | |
elif instr['op'] == 7: | |
# Subtract value in register | |
self.regs[self.read_reg('ADDR')] -= instr['val'] | |
elif instr['op'] == 8: | |
# Multiply value in register | |
self.regs[self.read_reg('ADDR')] *= instr['val'] | |
elif instr['op'] == 9: | |
# Divide value in register | |
self.regs[self.read_reg('ADDR')] /= instr['val'] | |
elif instr['op'] == 10: | |
# Prints a register | |
val = self.regs[self.read_reg('ADDR')] | |
if instr['val'] == 0: | |
print(chr(val)) | |
elif instr['val'] == 1: | |
print(val) | |
else: | |
raise RuntimeError('Unknown print type: {}'.format(instr['val'])) | |
elif instr['op'] == 11: | |
# Toggles the "memory run" flag | |
self.mrun = instr['val'] == 1 | |
else: | |
raise RuntimeError('Unknown opcode: {}'.format(instr['op'])) | |
if self.mrun == True: | |
self.pc += 4 | |
def cycle(self): | |
self.execute(self.fetch()) | |
def main(): | |
cpu = CPU() | |
cpu.running = True | |
while cpu.running: | |
try: | |
cpu.cycle() | |
except ZeroDivisionError: | |
print('Error: Division by zero') | |
except ValueError: | |
print('Error: value is too big') | |
except RuntimeError: | |
print('Error: something is wrong with your code') | |
except TypeError: | |
print('Error: wrong type') | |
except KeyboardInterrupt: | |
cpu.running = False | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment