def __init__(self): self.memory = Memory() self.registers = [ Word(Byte(0b0), Byte(0b0), Byte(0b0), Byte(0b0)) for _ in Register ] self.registers[Register.sp] = Word.from_int(self.memory.size - 1 - 4) self.stdout = [] self.stdin = [] self.flags = set()
def read_word(self, address): return Word( self.memory[address + 0], self.memory[address + 1], self.memory[address + 2], self.memory[address + 3], )
def define_word(input_stream): ''' Extract the name, paren comment, and body for the word. Add the newly compiled word to Words. ''' name, open_paren = input_stream.take(2) if open_paren != "(": input_stream.clear() raise SyntaxError("definitions need a stack comment in ( )!") comment = take_tokens("(", ")", input_stream) body = take_tokens(":", ";", input_stream) for word in body: if must_be_defined(word) and word != name: input_stream.clear() raise RunTimeError( f"""You must define `{word}` before invoking it!""") redefined = name in Words.keys() Words[name] = Word(comment, body) if redefined: print(f"""`{name}` was redefined.""")
def read_word(stream): b1, = stream.read_int(7) b2, = stream.read_int(7) b3, = stream.read_int(7) b4, = stream.read_int(7) return Word(Byte(b1), Byte(b2), Byte(b3), Byte(b4))
def reset_app(): global machine machine = Machine() orc = orc_parser.parse("chall2.exe") segment = orc.segments[1] base = segment.base.int_value() offset = segment.offset.int_value() data = orc.data for i in range(segment.size.int_value()): machine.memory.write_byte(Word.from_int(base + i), data[offset + i]) machine.registers[Register.pc] = Word.from_int(base)
def run(self, machine): current = machine.registers[Register.pc].int_value() offset = machine.registers[self.value_register].int_value() return MachineUpdate( registers={ Register.pc: Word.from_int(current + offset + self.size), })
def run(self, machine): if Flag.ZF not in machine.flags: return MachineUpdate() current = machine.registers[Register.pc].int_value() offset = machine.registers[self.value_register].int_value() updated_pc = Word.from_int(current + offset + self.size) return MachineUpdate(registers={ Register.pc: updated_pc, })
def run(self, machine): if (Flag.SF in machine.flags) == (Flag.OF in machine.flags): return MachineUpdate() current = machine.registers[Register.pc].int_value() offset = self.value_word.int_value() updated_pc = Word.from_int(current + offset + self.size) return MachineUpdate(registers={ Register.pc: updated_pc, })
def subtract_word(word1, word2): flags = set() int_result = word1.int_value() - word2.int_value() if int_result == 0: flags.add(Flag.ZF) sign_bit = 1 << 27 if int_result & sign_bit: flags.add(Flag.SF) return Word.from_int(int_result), flags
def add_word(word1, word2): flags = set() int_sum = word1.int_value() + word2.int_value() if int_sum == 0: flags.add(Flag.ZF) sign_bit = 1 << 27 overflow_bit = 1 << 28 if int_sum & sign_bit: flags.add(Flag.SF) if int_sum & overflow_bit: flags.add(Flag.CF) if not ((word1.int_value() & sign_bit) ^ (word2.int_value() & sign_bit)): flags.add(Flag.OF) return Word.from_int(int_sum), flags
def test_one_minus_one_sets_zero_flag(): word, flags = subtract_word(Word.from_int(1), Word.from_int(1)) assert (word.int_value() == 0) assert (flags == set([Flag.ZF]))
def test_set_zero_flag(): word, flags = add_word(Word.from_int(0), Word.from_int(0)) assert (word.int_value() == 0) assert (flags == set([Flag.ZF]))
def test_three_minus_one(): word, flags = subtract_word(Word.from_int(3), Word.from_int(1)) assert (word.int_value() == 2) assert (not flags)
def test_overflow_flag_on_7th_bit(): word, flags = add_word(Word(Byte(0), Byte(0), Byte(0), Byte(0b1111111)), Word(Byte(0), Byte(0), Byte(0), Byte(0b0000001))) assert (word.int_value() == 0) assert (flags == set([Flag.CF]))
def test_signed_flag(): word, flags = add_word(Word(Byte(0), Byte(0), Byte(0), Byte(0b1000000)), Word(Byte(0), Byte(0), Byte(0), Byte(0b1))) assert (word == Word(Byte(0), Byte(0), Byte(0), Byte(0b1000001))) assert (flags == set([Flag.SF]))
def render_emulator(): instruction = machine.next_instruction() if not instruction: instruction_view = "--" else: instruction_view = instruction.human() available_actions = set() if instruction: available_actions.add("step") instruction_views = [] for address, instruction in machine.glob_instructions(): instruction_views.append( DisassembledInstructionView( address == machine.registers[Register.pc].int_value(), Word.from_int(address).hex_str(human=True), instruction.debug_str(), instruction_helper.bytes_str(instruction), instruction.human() ) ) disassembled_view = DisassembledView(instruction_views) registers_view = [ RegisterView(register.name, machine.registers[register.value].hex_str()) for register in Register ] memory = machine.memory columns = 4 memory_view = MemoryView(columns, [ MemoryRowView( Word.from_int(row * columns * 4).hex_str(human=True), [ memory.read_word((row * columns + column) * 4).hex_str() for column in range(columns) if (row * columns + column) * 4 < memory.size ] ) for row in range(math.ceil(memory.size / (columns * 4))) ]) stack_pointer = machine.registers[Register.sp].int_value() stack_view = StackView(1, [ StackRowView( row == 0, Word.from_int(stack_pointer + row * 4).hex_str(human=True), [ memory.read_word(stack_pointer + row * 4).hex_str(human=True) ] ) for row in range(((memory.size - 1) - stack_pointer) // 4) ]) flags_view = [ FlagView(flag.name, flag.value in machine.flags) for flag in Flag ] stdout_view = "".join([ chr(char.int_value) for char in machine.stdout ]) return render_template( "emulator.html", instruction=instruction_view, registers=registers_view, flags=flags_view, disassembled=disassembled_view, stack=stack_view, memory=memory_view, stdout=stdout_view, available_actions=available_actions )
def test_unsigned_overflow_when_7th_bits_match(): word, flags = add_word(Word(Byte(0), Byte(0), Byte(0), Byte(0b1000000)), Word(Byte(0), Byte(0), Byte(0), Byte(0b1000000))) assert (word.int_value() == 0) assert (flags == set([Flag.OF, Flag.CF]))
def test_full_word_addition_with_carry_across_bytes(): word, flags = add_word( Word(Byte(0b1000000), Byte(0b0), Byte(0b1), Byte(0b0011)), Word(Byte(0b1000000), Byte(0b0), Byte(0b1), Byte(0b1000))) assert (word == Word(Byte(0b0), Byte(0b1), Byte(0b10), Byte(0b1011))) assert (not flags)
def test_one_plus_one(): word, flags = add_word(Word.from_int(1), Word.from_int(1)) assert (word.int_value() == 2) assert (not flags)
def run(filename, break_, input_): orc = orc_parser.parse(filename) machine = emulator.Machine() if input_: machine.stdin = list(input_) for segment in orc.segments: for i in range(segment.size.int_value()): memory_location = Word.from_int(segment.base.int_value() + i) data_location = segment.offset.int_value() + i data_value = orc.data[data_location] machine.memory.write_byte(memory_location, data_value) machine.registers[Register.pc] = orc.entry_point instruction = machine.next_instruction() while instruction: print(machine.registers[Register.pc].hex_str(human=True), instruction.human()) if machine.registers[Register.pc].int_value() == break_: command = input("> ").strip() while command: if command == "debug": breakpoint() elif command == "continue": break elif command == "step": machine.run(instruction) instruction = machine.next_instruction() if instruction: print(instruction.human()) elif command == "registers": for register in Register: print( f"{register.name}: {machine.registers[register].hex_str()}" ) elif command.startswith("print"): _, variable = command.split(" ") if variable.startswith("0x"): address_hex = variable address = hex_parser.int_from_by7e_hex(address_hex) word = machine.memory.read_word(address) else: register_name = variable register = Register[register_name] word = machine.registers[register] print(word) elif command.startswith("memory"): _, address_hex = command.split(" ") address = hex_parser.int_from_by7e_hex(address_hex) for section in range(4): section_address = address + section * 4 word = machine.memory.read_word(section_address) formatted_address = Word.from_int( section_address).hex_str(human=True) print(formatted_address, word.hex_str()) elif command.startswith("disassemble"): _, address_hex = command.split(" ") address = hex_parser.int_from_by7e_hex(address_hex) for fake_address, fake_instruction in machine.glob_instructions( address): formatted_address = Word.from_int( fake_address).hex_str(human=True) print(formatted_address, fake_instruction.human()) elif command == "web": import app app.routes.override_app(machine) app.app.run() elif command == "help": print(help_str) else: print("Unknown command:", command) command = input("> ").strip() machine.run(instruction) instruction = machine.next_instruction() # print("".join([ str(char) for char in machine.stdout ])) print("".join([chr(char.int_value) for char in machine.stdout]))
def test_signed_flag(): # result = -2 -> (2 == 0b0000010) # 2's complement -> 0b1111101 + 0b1 -> 0b1111110 word, flags = subtract_word(Word.from_int(1), Word.from_int(3)) assert (word == Word(Byte(0b1111110), Byte(0x7f), Byte(0x7f), Byte(0x7f))) assert (flags == set([Flag.SF]))
def disassemble_instruction(stream, strict=False): if stream.is_empty(): return type_code, = stream.read_int(3) # print("type code", bin(type_code)) if type_code in op_names: if stream.is_empty(): # Our file was padded with 7 bits to complete the byte # Made it look like we had an instruction when we don't return op_code, = stream.read_int(4) # print("op code:", op_code) op_name = op_names[type_code][op_code] elif type_code == 0b110: # todo: will crash if these are the last bits of a stream # and we got here due to padding op_name = "RET" elif type_code == 0b111: op_name = "NOP" else: if strict: raise ValueError else: return if type_code == 0b010: source, = stream.read_int(4) source_out = Register(source).name dest, = stream.read_int(4) dest_out = Register(dest).name skip, = stream.read_int(6) assert (skip == 0) return instruction.type1_register_factory(op_name, Register(source), Register(dest)) elif type_code == 0b011: dest, = stream.read_int(4) dest_out = Register(dest).name skip, = stream.read_int(3) assert (skip == 0) source_word = Word(*stream.read_bytes(4)) source_out = source_word.hex_str() return instruction.type1_constant_factory(op_name, Register(dest), source_word) elif type_code == 0b100: value, = stream.read_int(4) value_out = Register(value).name skip, = stream.read_int(3) assert (skip == 0) return instruction.type2_register_factory(op_name, Register(value)) elif type_code == 0b101: value_word = Word(*stream.read_bytes(4)) value_out = value_word.hex_str() return instruction.type2_constant_factory(op_name, value_word) elif type_code == 0b110: skip, = stream.read_int(4) assert (skip == 0) return ops.ret.RetInstruction() elif type_code == 0b111: skip, = stream.read_int(4) assert (skip == 0) return ops.nop.NopInstruction() else: if strict: raise ValueError else: return