예제 #1
0
 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()
예제 #2
0
 def read_word(self, address):
     return Word(
         self.memory[address + 0],
         self.memory[address + 1],
         self.memory[address + 2],
         self.memory[address + 3],
     )
예제 #3
0
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.""")
예제 #4
0
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))
예제 #5
0
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)
예제 #6
0
    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),
            })
예제 #7
0
    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,
        })
예제 #8
0
    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,
        })
예제 #9
0
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
예제 #10
0
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
예제 #11
0
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]))
예제 #12
0
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]))
예제 #13
0
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)
예제 #14
0
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]))
예제 #15
0
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]))
예제 #16
0
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
    )
예제 #17
0
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]))
예제 #18
0
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)
예제 #19
0
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)
예제 #20
0
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]))
예제 #21
0
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]))
예제 #22
0
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