def __execute_debug_command(command: list, machine: EmulatorBase, profile: Profile): if config.disable_debug: return if len(command) == 1: command_str: str = command[0] if command_str.lower() == 'break': debug.breakpoint() elif command_str.lower() == 'ram': ram = machine.exec_command(None, 'get_ram_ref', []) debug.ram_display(ram, profile.adressing.bin_len, 0, None) elif command_str.lower() == 'regs': regs = machine.exec_command(None, 'get_regs_ref', []) print(regs) elif command[0] == 'log': pos = machine.get_current_pos(None) debug.log(f"{pos} {' '.join(command[1:])}") elif '(' in command and ')' in command: cmd: str = command[0] start = command.index('(') end = command.index(')') if start != 1: raise error.EmulationError(f"Bad debug cmd: {command}") args = [token for token in command[(start + 1):end] if token != ','] if cmd.startswith("ram") and len(args) == 2: min_adress, max_adress = int(args[0]), int(args[1]) ram = machine.exec_command(None, 'get_ram_ref', []) debug.ram_display(ram, profile.adressing.bin_len, min_adress, max_adress) else: machine.exec_command(None, cmd, args)
def pack_adresses(instructions): output = dict() for adress, data in instructions.items(): for i, cell in enumerate(data): if (adress + i) in output: raise error.EmulationError( f"Output data is overlapping: adress: {adress+i} is arleady occuped by value: {output[adress+i]}" ) output[adress + i] = cell return output
def emulate(output, context): print("Custom emulation pipeline") profile: core.profile.profile.Profile = context['profile'] emul: dict = profile.emul save_settings = emul["output"]["save"] data_settings = emul["output"]["data"] emulation_settings = emul["emulation"] config.override_from_dict(save_settings) save_pipeline = core.pipeline.make_save_pipeline() output, context = core.pipeline.exec_pipeline(save_pipeline, output, context, progress_bar_name='Saving Binary') process = [emulation_settings["path"], *emulation_settings["args"]] print(f"Calling: {' '.join(process)}") print("Emulation Output:\n") try: subprocess.check_call(process) except subprocess.CalledProcessError as err: raise error.EmulationError(f"Emulation Error: {err}")
def parse_command(self): low = Binary(int(self.RAM[self.ROM_COUNTER]), bit_lenght=8) cu = int(low[4:]) r1 = int(low[:2]) r2 = int(low[2:4]) if cu == 0: r1r2 = int(low[:4]) if r1r2 == 0: print("Shuting with error") self.is_running_flag = False elif r1r2 == 1: self.is_running_flag = False elif r1r2 == 2: self.inc_counter() n1 = int(self.RAM[self.ROM_COUNTER]) self.jump(n1) return elif r1r2 == 3: self.inc_counter() n1 = int(self.RAM[self.ROM_COUNTER]) self.jump_flag(n1) return elif r1r2 == 4: self.interutp(None, None) elif r1r2 == 5: self.clear_screen() else: raise error.EmulationError("Command is not implemented") elif cu == 1: if r2 == 0: self.inc_counter() n1 = int(self.RAM[self.ROM_COUNTER]) self.mov_const_reg(n1, r1) elif r2 == 1: self.alu_reg_inc(r1) elif r2 == 2: self.alu_reg_dec(r1) elif r2 == 3: raise elif cu == 2: self.mov_reg_reg(r2, r1) elif cu == 3: self.alu_reg_reg_add(r2, r1) elif cu == 4: self.alu_reg_reg_sub(r2, r1) elif cu == 5: self.alu_reg_reg_rsh(r2, r1) elif cu == 6: self.alu_reg_reg_lsh(r2, r1) elif cu == 7: self.alu_reg_reg_and(r2, r1) elif cu == 8: self.alu_reg_reg_or(r2, r1) elif cu == 9: self.alu_reg_reg_xor(r2, r1) elif cu == 10: #JUMP EQUAL zf, _ = self.alu_reg_reg_cmp(r2, r1) if zf == True: self.inc_counter() n1 = self.RAM[self.ROM_COUNTER] self.jump(n1) return else: self.inc_counter() elif cu == 11: #JUMP GREATER zf, of = self.alu_reg_reg_cmp(r2, r1) if zf == False and of == True: self.inc_counter() n1 = self.RAM[self.ROM_COUNTER] self.jump(n1) return else: self.inc_counter() elif cu == 12: self.read_reg_pointer(r2, r1) elif cu == 13: self.inc_counter() n1 = self.RAM[self.ROM_COUNTER] self.read_ram_reg(n1, r1) elif cu == 14: self.write_pointer_reg(r1, r2) elif cu == 15: self.inc_counter() n1 = self.RAM[self.ROM_COUNTER] self.write_const_reg(r1, n1) else: raise error.EmulationError("Unreachable") self.inc_counter()
def ret(self): if len(self.ROMStack) == 0: raise error.EmulationError("ROM") addres = self.ROMStack.pop() self.jump(addres)
def call(self, _target_true): if len(self.ROMStack) < 15: self.ROMStack.append(self.ROM_COUNTER) else: raise error.EmulationError("rom stack overflow") self.jump(_target_true)
def emulate(program, context): global GLOBAL_CURR_ADRESS profile: Profile = context["profile"] emulator = profile.emul try: machine: EmulatorBase = emulator.get_emulator() except: raise error.EmulationError( "File with emulator definition should define the 'get_emulator' function" ) if machine is None or not isinstance(machine, EmulatorBase): raise error.EmulationError( f"Function get_emulator returned unvalid instance of machine expected: 'EmulatorBase', got '{machine}'" ) print() print("Writing data to device") __write_program(program, context, machine) __write_data(program, context, machine) debug_instructions = context["debug_instructions"] print("Starting Emulation") emulate_start_time = time.thread_time_ns() emulation_cycles = 1 machine_cycles = 0 while machine.is_running(): pos = machine.get_current_pos(None) GLOBAL_CURR_ADRESS = pos if pos in debug_instructions: for instruction in (i for i in debug_instructions[pos] if 'pre' in i): __execute_debug_command(instruction['pre'], machine, profile) machine.next_tick() if pos in debug_instructions: for instruction in (i for i in debug_instructions[pos] if 'post' in i): __execute_debug_command(instruction['post'], machine, profile) emulation_cycles += 1 machine_cycles += machine.get_machine_cycles() emulate_end_time = time.thread_time_ns() print("Emulation finished") print(f"Took: {(emulate_end_time-emulate_start_time)/1000000.0}ms") try: print( f"Per command: {(emulate_end_time-emulate_start_time)/emulation_cycles/1000.0:0.2f}μs" ) except: print( f"Per command: {(emulate_end_time-emulate_start_time)/emulation_cycles/1000.0:0.2f}us" ) print( f"Machine took: {machine_cycles} steps, estimated execution time: {machine_cycles/float(profile.info.speed):0.1f}s" )
def generate_ram_display(RAM, rows=16, subrows=1, ADRESS_AS_HEX=True, VALUE_AS="bin", ADD_ASCII_VIEW=True, WORD_SIZE=8, start=0, end=None): """ It just works. """ if start != 0: start = start + (rows - start % rows) - rows else: start = 0 if end is not None: end = end + (rows - end % rows) else: end = len(RAM) if rows % subrows != 0: raise error.EmulationError( "Row number should be dividable by subrow count.") def generate_value(PAD=-1, MODE="dec"): ADRESS = "" try: val = RAM[adress + i] except IndexError: raise if MODE == "dec": PAD = len(str(int(2**WORD_SIZE) - 1)) + 1 ADRESS = str(val) elif MODE == "hex": PAD = len(str(hex(2**WORD_SIZE - 1)[2:])) + 1 ADRESS = str(formatter.padhex(val, 2, False)) elif MODE == "bin": PAD = len(str(bin(2**WORD_SIZE - 1)[2:])) + 1 ADRESS = formatter.padbin(val, 8, False) return '{}{}'.format(" " * (PAD - len(ADRESS)), ADRESS) totalrows = rows rows //= subrows LINE_START = 0 subrow_cunter = 0 OUTPUT = "\n" if config.RAM_DEBUG_MODE == "simple": return '\n'.format(RAM) elif config.RAM_DEBUG_MODE == "row": try: for adress in range(0, len(RAM), rows): if not (adress in range(start, end)): continue if subrow_cunter == 0: LINE_START = adress rows_data = "" for i in range(rows): rows_data += generate_value(-1, VALUE_AS) if ADD_ASCII_VIEW: if subrow_cunter == (subrows - 1): asciirep = "" for i in range(totalrows): char_id = RAM[LINE_START + i] asciirep += chr( char_id ) if char_id >= 32 and char_id < 127 else "." rows_data += "\t{}".format(asciirep) if ADRESS_AS_HEX: OUTPUT += " {}:{}{}".format( formatter.padhex(adress, len(hex(len(RAM) - 1)[2:])), rows_data, " " if subrow_cunter != (subrows - 1) else "\n") else: OUTPUT += " {}:{}{}".format( adress, rows_data, " " if subrow_cunter != (subrows - 1) else "\n") subrow_cunter = (subrow_cunter + 1) % subrows except Exception as err: pass return OUTPUT