From b1fb32c0c1f1f2d26585dd5148678ed0d5b34208 Mon Sep 17 00:00:00 2001 From: Safariminer Date: Sun, 28 Dec 2025 16:35:28 -0500 Subject: [PATCH] Add onto 8086 emulation test suite --- biosandbox/Emulation.h | 10 +++- biosandbox/Intel.cpp | 123 ++++++++++++++++++++++++++++++++++++++++- biosandbox/Intel.h | 37 +++++++++++-- biosandbox/bsuml.h | 35 ++++++++++-- biosandbox/main.cpp | 7 ++- gameenv/code/test | Bin 3 -> 55 bytes gameenv/code/test.asm | 48 +++++++++++++++- readme.md | 17 +++++- 8 files changed, 258 insertions(+), 19 deletions(-) diff --git a/biosandbox/Emulation.h b/biosandbox/Emulation.h index df82271..fa767f7 100644 --- a/biosandbox/Emulation.h +++ b/biosandbox/Emulation.h @@ -3,11 +3,13 @@ #include "bsuml.h" #include #include +#include +#include namespace bio { namespace emu { - using instruction_set = std::vector*>>; + using instruction_set = std::vector*, std::map*>>; memory_dependent using mem_buffer = unsigned char[memsize]; @@ -32,6 +34,7 @@ namespace bio { mem_buffer memory; std::vector symbols; std::vector callStack; + std::map registers; virtual void load_app(application& app) = 0; virtual void run_symbol(int symbol) = 0; @@ -67,12 +70,15 @@ namespace bio { bool returned = false; until(returned || instructionPointer >= memsize) { this->instructionPointer += - this->isa[this->memory[instructionPointer]](instructionPointer, this->memory, &returned, &this->callStack); + this->isa[this->memory[instructionPointer]](instructionPointer, this->memory, &returned, &this->callStack, &this->registers); if (instructionPointer < 0 || instructionPointer > memsize) { throw std::out_of_range("Symbol causes instruction pointer to err out of memory"); } } + if (returned) { + std::print("Exited through conventional means [returned out of symbol]\n"); + } } }; diff --git a/biosandbox/Intel.cpp b/biosandbox/Intel.cpp index 6abf0dd..8f2c758 100644 --- a/biosandbox/Intel.cpp +++ b/biosandbox/Intel.cpp @@ -5,18 +5,135 @@ #include +std::string iAPX_reg_lookup(char r) { + switch (r) { + case 0b00000000: + return "ax"; + break; -isa_instruction(bio::Intel::ISAs::iAPX86::invalid) { - std::println("Invalid opcode used - {} at {}", memory[position], position); + case 0b00000001: + return "cx"; + break; + + case 0b00000010: + return "dx"; + break; + + case 0b00000011: + return "bx"; + break; + default: + return "invalid"; + break; + } +} + + +isa_instruction_template(bio::Intel::ISAs::iAPX86::mov_16b_imm_to_reg_template) { + short value; + memcpy(&value, memory + (position + 1), 2); + (*registers)[args] = value; + return 3; +} + +isa_instruction_template(bio::Intel::ISAs::iAPX86::inc_16b_reg_template) { + (*registers)[args]++; return 1; } -isa_instruction(bio::Intel::ISAs::iAPX86::nop) { +isa_instruction_template(bio::Intel::ISAs::iAPX86::dec_16b_reg_template) { + (*registers)[args]--; return 1; } + + +isa_instruction(bio::Intel::ISAs::iAPX86::invalid) { + std::println("Invalid (or unimplemented) opcode used - {} at {}", memory[position], position); + return 1; +} + + +isa_instruction(bio::Intel::ISAs::iAPX86::add_01) { + + + unsigned char mode, src, dest; + + mode = memory[position + 1]; + mode >>= 6; + + src = memory[position + 1]; + src >>= 3; + src &= 0b00000111; + + dest = memory[position + 1]; + dest &= 0b00000111; + + (*registers)[iAPX_reg_lookup(dest)] += (*registers)[iAPX_reg_lookup(src)]; + + return 2; + +} + +isa_instruction(bio::Intel::ISAs::iAPX86::sub_29) { + + + unsigned char mode, src, dest; + + mode = memory[position + 1]; + mode >>= 6; + + src = memory[position + 1]; + src >>= 3; + src &= 0b00000111; + + dest = memory[position + 1]; + dest &= 0b00000111; + + (*registers)[iAPX_reg_lookup(dest)] -= (*registers)[iAPX_reg_lookup(src)]; + + return 2; + +} + +isa_instruction(bio::Intel::ISAs::iAPX86::grp1_83) { + std::println("Unfinished opcode used - {} at {}", memory[position], position); + unsigned char subopcode = memory[position + 1]; + + // adc ax, imm8 + if ((subopcode & 0b11000000) == (subopcode & 0b11110000)) { + short s = (short)(*registers)["ax"]; + s += memory[position + 2]; + (*registers)["ax"] = s; + return 3; + } + + std::println("Unknown GRP1 instruction."); + return 1; +} + +isa_instruction(bio::Intel::ISAs::iAPX86::nop_90) { + return 1; +} + + +isa_instruction(bio::Intel::ISAs::iAPX86::ret_c3) { + + if (callstack->size() == 0) { + *emu_return = true; + return 0; + } + + int lastStackCall = (*callstack)[callstack->size() - 1]; + callstack->pop_back(); + + return lastStackCall - position; + +} + isa_instruction(bio::Intel::ISAs::iAPX86::call_e8) { short jump; memcpy(&jump, memory + (position + 1), 2); + callstack->push_back(position + 3); return jump + 3; } \ No newline at end of file diff --git a/biosandbox/Intel.h b/biosandbox/Intel.h index 4e6994e..82bb7b6 100644 --- a/biosandbox/Intel.h +++ b/biosandbox/Intel.h @@ -9,16 +9,23 @@ namespace bio { namespace ISAs { namespace iAPX86 { + isa_instruction_template(mov_16b_imm_to_reg_template); + isa_instruction_template(inc_16b_reg_template); + isa_instruction_template(dec_16b_reg_template); + isa_instruction(invalid); - isa_instruction(nop); + + isa_instruction(add_01); + isa_instruction(sub_29); + isa_instruction(grp1_83); + isa_instruction(nop_90); + isa_instruction(ret_c3); isa_instruction(call_e8); } } // 8086 emulation - memory_dependent class iAPX86 : public memory_passdown(::bio::emu::linear_emulator_base){ - - + memory_dependent class iAPX86 : public memory_passdown(::bio::emu::linear_emulator_base) { public: @@ -27,9 +34,29 @@ namespace bio { this->isa.push_back(ISAs::iAPX86::invalid); } + this->isa[0x01] = ISAs::iAPX86::add_01; + this->isa[0x29] = ISAs::iAPX86::sub_29; + this->isa[0x40] = isa_instruction_templater(ISAs::iAPX86::inc_16b_reg_template, "ax"); + this->isa[0x41] = isa_instruction_templater(ISAs::iAPX86::inc_16b_reg_template, "cx"); + this->isa[0x42] = isa_instruction_templater(ISAs::iAPX86::inc_16b_reg_template, "dx"); + this->isa[0x43] = isa_instruction_templater(ISAs::iAPX86::inc_16b_reg_template, "bx"); + + this->isa[0x48] = isa_instruction_templater(ISAs::iAPX86::dec_16b_reg_template, "ax"); + this->isa[0x49] = isa_instruction_templater(ISAs::iAPX86::dec_16b_reg_template, "cx"); + this->isa[0x4A] = isa_instruction_templater(ISAs::iAPX86::dec_16b_reg_template, "dx"); + this->isa[0x4B] = isa_instruction_templater(ISAs::iAPX86::dec_16b_reg_template, "bx"); + + this->isa[0x83] = ISAs::iAPX86::grp1_83; + this->isa[0x90] = ISAs::iAPX86::nop_90; + + this->isa[0xB8] = isa_instruction_templater(ISAs::iAPX86::mov_16b_imm_to_reg_template, "ax"); + this->isa[0xB9] = isa_instruction_templater(ISAs::iAPX86::mov_16b_imm_to_reg_template, "cx"); + this->isa[0xBA] = isa_instruction_templater(ISAs::iAPX86::mov_16b_imm_to_reg_template, "dx"); + this->isa[0xBB] = isa_instruction_templater(ISAs::iAPX86::mov_16b_imm_to_reg_template, "bx"); + + this->isa[0xC3] = ISAs::iAPX86::ret_c3; this->isa[0xE8] = ISAs::iAPX86::call_e8; - this->isa[0x90] = ISAs::iAPX86::nop; times(sizeof(this->memory)) { this->memory[___i] = '\0'; diff --git a/biosandbox/bsuml.h b/biosandbox/bsuml.h index 0eb21f2..dddba10 100644 --- a/biosandbox/bsuml.h +++ b/biosandbox/bsuml.h @@ -18,11 +18,36 @@ using native_callable = T(*)(args...); // emulation-related definitions -#define isa_instruction(x) int x(int position, unsigned char* memory, bool* emu_return, ptr> callstack) - // position = current instruction pointer position - // memory = memory buffer - // emureturn = end of symbol -// callstack = callstack pointer +#define isa_instruction(x) int x(int position, \ +unsigned char* memory, \ +bool* emu_return, \ +ptr<::std::vector> callstack, \ +ptr<::std::map<::std::string, \ +unsigned long long>> registers) + // position = current instruction pointer position + // memory = memory buffer + // emureturn = end of symbol + // callstack = callstack pointer +// registers = registers pointer + +#define isa_instruction_template(x) int x(int position, \ +unsigned char* memory, \ +bool* emu_return, \ +ptr<::std::vector> callstack, \ +ptr<::std::map<::std::string, \ +unsigned long long>> registers, \ +::std::string args) + // position = current instruction pointer position + // memory = memory buffer + // emureturn = end of symbol + // callstack = callstack pointer + // registers = registers pointer +// args = template arguments + +#define isa_instruction_templater(x, args) \ +[](int p, unsigned char* m, bool* er, ::std::vector* cs, ::std::map<::std::string,unsigned long long>* r) -> int{\ + return x(p, m, er, cs, r, args);\ +} #define memory_dependent template #define memory_passdown(x) x diff --git a/biosandbox/main.cpp b/biosandbox/main.cpp index 1577248..45fa9f6 100644 --- a/biosandbox/main.cpp +++ b/biosandbox/main.cpp @@ -2,10 +2,15 @@ #include "Intel.h" #include "BinFile.h" -entry{ +entry { ptr> i8086 = new bio::Intel::iAPX86<1024>; ptr bin = new bio::BinFile("code/test"); i8086->load_app(*bin->getApp()); i8086->run_symbol(-1); + + std::println("AX: {}", i8086->registers["ax"]); + std::println("CX: {}", i8086->registers["cx"]); + std::println("DX: {}", i8086->registers["dx"]); + std::println("BX: {}", i8086->registers["bx"]); } \ No newline at end of file diff --git a/gameenv/code/test b/gameenv/code/test index 0fa04771974ab9631bf6645c4b164f193a8a63a0..db2857a799f3e3f938833cdafb35c9c1e3cf6f0e 100644 GIT binary patch literal 55 zcmdnN$nZjj;qXpL2F4SIcNsA-UO2ovg@N(LVa*eVH7^|2ym9!&qyI0S{(te}|BKg9 I