diff --git a/biosandbox/Emulation.h b/biosandbox/Emulation.h index 0094e6d..6375fdf 100644 --- a/biosandbox/Emulation.h +++ b/biosandbox/Emulation.h @@ -9,8 +9,11 @@ namespace bio { namespace emu { - using instruction_set = std::vector*, std::map*>>; - + using register_set = std::map; + using syscall = native_callable, ptr, std::vector*>; + using syscall_set = std::map; + using instruction = native_callable*, std::map*, std::vector*, ptr>; + using instruction_set = std::vector; memory_dependent using mem_buffer = unsigned char[memsize]; struct symbol { @@ -29,13 +32,16 @@ namespace bio { memory_dependent class emulator_base { public: - + + int instructionPointer; instruction_set isa; mem_buffer memory; std::vector symbols; std::vector callStack; - std::map registers; - + std::vector stack; + register_set registers; + syscall_set syscalls; + virtual void load_app(application& app) = 0; virtual bool run_symbol(int symbol) = 0; void clear_registers() { @@ -50,7 +56,6 @@ namespace bio { memory_dependent class linear_emulator_base : public memory_passdown(emulator_base) { public: - int instructionPointer; bool run_symbol(int symbol) { // check symbol ID is within symbol count if (symbol > this->symbols.size() && symbol != -1) @@ -71,16 +76,24 @@ namespace bio { ); // apply instruction pointer - if (symbol >= 0) instructionPointer = this->symbols[symbol].offset; - else instructionPointer = 0; + if (symbol >= 0) this->instructionPointer = this->symbols[symbol].offset; + else this->instructionPointer = 0; // execute bool returned = false; - until(returned || instructionPointer >= memsize) { + until(returned || this->instructionPointer >= memsize) { this->instructionPointer += - this->isa[this->memory[instructionPointer]](instructionPointer, this->memory, &returned, &this->callStack, &this->registers); + this->isa[this->memory[this->instructionPointer]]( + this->instructionPointer, + this->memory, + &returned, + &this->callStack, + &this->registers, + &this->stack, + &this->syscalls + ); - if (instructionPointer < 0 || instructionPointer > memsize) { + if (this->instructionPointer < 0 || this->instructionPointer > memsize) { throw std::out_of_range("Symbol causes instruction pointer to err out of memory"); } } diff --git a/biosandbox/Intel.cpp b/biosandbox/Intel.cpp index 8f2c758..0b0f892 100644 --- a/biosandbox/Intel.cpp +++ b/biosandbox/Intel.cpp @@ -47,6 +47,18 @@ isa_instruction_template(bio::Intel::ISAs::iAPX86::dec_16b_reg_template) { } +isa_instruction_template(bio::Intel::ISAs::iAPX86::push_16b_reg_to_stack_template) { + stack->push_back((*registers)[args]); + return 1; +} + +isa_instruction_template(bio::Intel::ISAs::iAPX86::pop_stack_to_16b_reg_template) { + (*registers)[args] = stack->at(stack->size() - 1); + stack->pop_back(); + return 1; +} + + isa_instruction(bio::Intel::ISAs::iAPX86::invalid) { std::println("Invalid (or unimplemented) opcode used - {} at {}", memory[position], position); @@ -134,6 +146,13 @@ isa_instruction(bio::Intel::ISAs::iAPX86::ret_c3) { isa_instruction(bio::Intel::ISAs::iAPX86::call_e8) { short jump; memcpy(&jump, memory + (position + 1), 2); + + if (syscalls->find(jump + position + 3) != syscalls->end()) { + (*syscalls)[jump + position + 3](registers, memory, stack); + return 3; + } + 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 82bb7b6..a92c785 100644 --- a/biosandbox/Intel.h +++ b/biosandbox/Intel.h @@ -1,6 +1,7 @@ #pragma once #include "bsuml.h" #include "Emulation.h" +#include "SysCalls.h" namespace bio { @@ -13,6 +14,10 @@ namespace bio { isa_instruction_template(inc_16b_reg_template); isa_instruction_template(dec_16b_reg_template); + isa_instruction_template(push_16b_reg_to_stack_template); + isa_instruction_template(pop_stack_to_16b_reg_template); + + isa_instruction(invalid); isa_instruction(add_01); @@ -47,6 +52,18 @@ namespace bio { 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[0x50] = isa_instruction_templater(ISAs::iAPX86::push_16b_reg_to_stack_template, "ax"); + this->isa[0x51] = isa_instruction_templater(ISAs::iAPX86::push_16b_reg_to_stack_template, "cx"); + this->isa[0x52] = isa_instruction_templater(ISAs::iAPX86::push_16b_reg_to_stack_template, "dx"); + this->isa[0x53] = isa_instruction_templater(ISAs::iAPX86::push_16b_reg_to_stack_template, "bx"); + + this->isa[0x58] = isa_instruction_templater(ISAs::iAPX86::pop_stack_to_16b_reg_template, "ax"); + this->isa[0x59] = isa_instruction_templater(ISAs::iAPX86::pop_stack_to_16b_reg_template, "cx"); + this->isa[0x5A] = isa_instruction_templater(ISAs::iAPX86::pop_stack_to_16b_reg_template, "dx"); + this->isa[0x5B] = isa_instruction_templater(ISAs::iAPX86::pop_stack_to_16b_reg_template, "bx"); + + this->isa[0x83] = ISAs::iAPX86::grp1_83; this->isa[0x90] = ISAs::iAPX86::nop_90; @@ -61,6 +78,10 @@ namespace bio { times(sizeof(this->memory)) { this->memory[___i] = '\0'; } + + + this->syscalls[4080] = bio::emu::syscalls::print; + } void load_app(bio::emu::application& app) { diff --git a/biosandbox/SysCalls.cpp b/biosandbox/SysCalls.cpp new file mode 100644 index 0000000..e4e5278 --- /dev/null +++ b/biosandbox/SysCalls.cpp @@ -0,0 +1,54 @@ +#include "SysCalls.h" +#include +#include + +syscall_definition(bio::emu::syscalls::print) { + + std::string format = (const char*)(memory + (*registers)["ax"]); + + std::string output; + + bool inPercentage = false; + + unsigned char currentArgument = 1; + + + for (char& c : format) { + if (inPercentage) { + switch (c) { + case 'i': + { + short s = (*stack)[stack->size() - (1 + currentArgument)]; + output += std::to_string((short)(s)); + inPercentage = false; + currentArgument++; + } + break; + case 's': + { + std::string s = (const char*)(memory + (*stack)[stack->size() - (1 + currentArgument)]); + output += s; + inPercentage = false; + currentArgument++; + } + break; + case '%': + output += '%'; + inPercentage = false; + break; + } + } + else { + if (c == '%') inPercentage = true; + else { + output += c; + } + } + } + + + std::print("{}", output); + + format.clear(); + output.clear(); +} \ No newline at end of file diff --git a/biosandbox/SysCalls.h b/biosandbox/SysCalls.h new file mode 100644 index 0000000..21b6ac2 --- /dev/null +++ b/biosandbox/SysCalls.h @@ -0,0 +1,11 @@ +#pragma once +#include "bsuml.h" +#include "Emulation.h" + +namespace bio { + namespace emu { + namespace syscalls { + syscall_definition(print); + } + } +} \ No newline at end of file diff --git a/biosandbox/biosandbox.vcxproj b/biosandbox/biosandbox.vcxproj index 23b8902..ecef4fa 100644 --- a/biosandbox/biosandbox.vcxproj +++ b/biosandbox/biosandbox.vcxproj @@ -139,6 +139,7 @@ + @@ -148,6 +149,7 @@ + diff --git a/biosandbox/biosandbox.vcxproj.filters b/biosandbox/biosandbox.vcxproj.filters index 1ddb26d..5b9435c 100644 --- a/biosandbox/biosandbox.vcxproj.filters +++ b/biosandbox/biosandbox.vcxproj.filters @@ -36,6 +36,9 @@ Source Files + + Source Files + @@ -62,5 +65,8 @@ Header Files + + Header Files + \ No newline at end of file diff --git a/biosandbox/bsuml.h b/biosandbox/bsuml.h index dddba10..5cfc8eb 100644 --- a/biosandbox/bsuml.h +++ b/biosandbox/bsuml.h @@ -23,12 +23,15 @@ 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 +unsigned long long>> registers,\ +::std::vector* stack, \ +::bio::emu::syscall_set* syscalls) + // position = current instruction pointer position + // memory = memory buffer + // emureturn = end of symbol + // callstack = callstack pointer + // registers = registers pointer +// stack = stack pointer #define isa_instruction_template(x) int x(int position, \ unsigned char* memory, \ @@ -36,6 +39,8 @@ bool* emu_return, \ ptr<::std::vector> callstack, \ ptr<::std::map<::std::string, \ unsigned long long>> registers, \ +::std::vector* stack, \ +::bio::emu::syscall_set* syscalls, \ ::std::string args) // position = current instruction pointer position // memory = memory buffer @@ -45,10 +50,18 @@ unsigned long long>> registers, \ // 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);\ +[](int p, \ +unsigned char* m, \ +bool* er, \ +::std::vector* cs, \ +::std::map<::std::string,unsigned long long>* r, \ +::std::vector* st,\ +::bio::emu::syscall_set* sc) -> int{\ + return x(p, m, er, cs, r, st, sc, args);\ } +#define syscall_definition(x) void x(ptr<::bio::emu::register_set> registers, ptr memory, ptr<::std::vector> stack) + #define memory_dependent template #define memory_passdown(x) x diff --git a/biosandbox/main.cpp b/biosandbox/main.cpp index e9816da..b5d27fd 100644 --- a/biosandbox/main.cpp +++ b/biosandbox/main.cpp @@ -7,7 +7,7 @@ bio::tests::test iapxTest{ "iAPX Test Suite", []() -> bool { - ptr> i8086 = new bio::Intel::iAPX86<1024>; + ptr> i8086 = new bio::Intel::iAPX86; std::filesystem::directory_iterator it("code/tests/bin"); diff --git a/gameenv/code/tests/bin/test3 b/gameenv/code/tests/bin/test3 new file mode 100644 index 0000000..27b6141 Binary files /dev/null and b/gameenv/code/tests/bin/test3 differ diff --git a/gameenv/code/tests/buildtests.bat b/gameenv/code/tests/buildtests.bat new file mode 100644 index 0000000..e815936 --- /dev/null +++ b/gameenv/code/tests/buildtests.bat @@ -0,0 +1,4 @@ +@echo off +nasm test.asm -o "bin/test" +nasm test2.asm -o "bin/test2" +nasm test3.asm -o "bin/test3" diff --git a/gameenv/code/tests/test3.asm b/gameenv/code/tests/test3.asm new file mode 100644 index 0000000..ac519fb --- /dev/null +++ b/gameenv/code/tests/test3.asm @@ -0,0 +1,25 @@ +section .text: +main: + mov ax, world + push ax + mov dx, problem + push dx + pop cx + mov ax, hello + push ax + mov ax, trash + push ax + pop bx + mov ax, format + push ax + call 0x0ff0 ; printf + pop bx + pop bx + pop bx + ret +section .data: + world: db "world", 0 + hello: db "hello", 0 + trash: db "garbage", 0 + problem: db "problem", 0 + format: db "%s, %s!", 10, 0 \ No newline at end of file diff --git a/readme.md b/readme.md index 446ea77..4308204 100644 --- a/readme.md +++ b/readme.md @@ -13,4 +13,6 @@ All features the 8086 emulator of the engine supports are demonstrated in the [t - subtraction on (A/C/D/B)X from (A/C/D/B)X - move on (A/C/D/B)X from immediate - increment/decrement (A/C/D/B)X -- call functions and return \ No newline at end of file +- call functions and return +- create engine syscalls (``0x0ff0`` acts as a printf variant) +- push and pop from a stack \ No newline at end of file