#include "include/aliases.h" #include "include/flag_access.h" #include "include/reg_access.h" #include "include/sim86_lib.h" #include #include #include #define MEM_SIZE (1 << 16) struct basic_string { char str[4096]; }; u16 get_operand_value(instruction_operand operand); basic_string get_operand_string(instruction_operand operand); void print_instruction(instruction inst); void mov_to_register(const register_access ®, const instruction_operand &source); int main(int argc, char *argv[]) { if (argc < 2) { printf("Usage: sim86 BINARY_FILE\n"); return 1; } u8 memory[MEM_SIZE]; memset((void *)memory, 0, MEM_SIZE); const char *filename = argv[1]; printf("Filename: %s\n", filename); FILE *fp = fopen(filename, "rb"); if (!fp) { printf("Failed to open file %s\n", filename); } fseek(fp, 0, SEEK_END); u32 size = ftell(fp); fseek(fp, 0, SEEK_SET); fread((void *)memory, sizeof(u8), size, fp); fclose(fp); instruction_table table; Sim86_Get8086InstructionTable(&table); u32 offset = 0; bool accessed_registers[REGISTER_COUNT] = {false}; printf("\nDisassembly:\n"); while (offset < size) { instruction decoded; Sim86_Decode8086Instruction(size - offset, memory + offset, &decoded); if (decoded.Op) { offset += decoded.Size; print_instruction(decoded); instruction_operand dest = decoded.Operands[0]; instruction_operand source = decoded.Operands[1]; switch (decoded.Op) { case Op_mov: { if (dest.Type == Operand_Register) { mov_to_register(dest.Register, source); accessed_registers[dest.Register.Index] = true; } break; } case Op_add: { if (dest.Type == Operand_Register) { u16 value = get_register(dest.Register); value += get_operand_value(source); set_flags(value); set_register(dest.Register, value); } break; } case Op_sub: case Op_cmp: { if (dest.Type == Operand_Register) { u16 value = get_register(dest.Register); value -= get_operand_value(source); set_flags(value); if (decoded.Op == Op_sub) { set_register(dest.Register, value); } } break; } case Op_jne: { if (!get_flag(FLAG_ZERO)) { i16 inst_offset = get_operand_value(dest); offset += inst_offset; } } default: break; } } } printf("\nFinal registers:\n"); for (u32 i = 0; i < REGISTER_COUNT; ++i) { if (accessed_registers[i]) { register_access reg = {i, 0, 2}; u16 value = get_register(reg); printf("\t%s: 0x%04x (%d)\n", get_register_name(reg), value, value); } } // Print the instruction pointer register printf("\tip: 0x%04x (%d)\n", offset, offset); printf("\nFinal flags:\n"); print_flags(); return 0; } u16 get_operand_value(instruction_operand operand) { switch (operand.Type) { case Operand_Register: return get_register(operand.Register); break; case Operand_Memory: return 0; break; case Operand_Immediate: return operand.Immediate.Value; break; default: return 0; break; } } basic_string get_operand_string(instruction_operand operand) { basic_string output = {""}; switch (operand.Type) { case Operand_Register: sprintf(output.str, "%s", get_register_name(operand.Register)); break; case Operand_Memory: sprintf(output.str, "%s", "MEM OPERAND"); break; case Operand_Immediate: sprintf(output.str, "%d", operand.Immediate.Value); break; default: break; } return output; } void print_instruction(instruction inst) { printf("\t%s %s, %s\n", Sim86_MnemonicFromOperationType(inst.Op), get_operand_string(inst.Operands[0]).str, get_operand_string(inst.Operands[1]).str); } void mov_to_register(const register_access ®, const instruction_operand &source) { switch (source.Type) { case Operand_Immediate: set_register(reg, source.Immediate.Value); break; case Operand_Register: set_register(reg, get_register(source.Register)); break; default: break; } }