added syscalls and a stack to the 8086 emulation
This commit is contained in:
parent
244be9f1ae
commit
c95b1b0045
@ -9,8 +9,11 @@
|
||||
namespace bio {
|
||||
namespace emu {
|
||||
|
||||
using instruction_set = std::vector<native_callable<int, int, unsigned char*, bool*, std::vector<int>*, std::map<std::string, unsigned long long>*>>;
|
||||
|
||||
using register_set = std::map<std::string, unsigned long long>;
|
||||
using syscall = native_callable<void, ptr<register_set>, ptr<unsigned char>, std::vector<int>*>;
|
||||
using syscall_set = std::map<short, syscall>;
|
||||
using instruction = native_callable<int, int, unsigned char*, bool*, std::vector<int>*, std::map<std::string, unsigned long long>*, std::vector<int>*, ptr<syscall_set>>;
|
||||
using instruction_set = std::vector<instruction>;
|
||||
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<memsize> memory;
|
||||
std::vector<symbol> symbols;
|
||||
std::vector<int> callStack;
|
||||
std::map<std::string, unsigned long long> registers;
|
||||
|
||||
std::vector<int> 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");
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -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) {
|
||||
|
||||
54
biosandbox/SysCalls.cpp
Normal file
54
biosandbox/SysCalls.cpp
Normal file
@ -0,0 +1,54 @@
|
||||
#include "SysCalls.h"
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
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();
|
||||
}
|
||||
11
biosandbox/SysCalls.h
Normal file
11
biosandbox/SysCalls.h
Normal file
@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "bsuml.h"
|
||||
#include "Emulation.h"
|
||||
|
||||
namespace bio {
|
||||
namespace emu {
|
||||
namespace syscalls {
|
||||
syscall_definition(print);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -139,6 +139,7 @@
|
||||
<ClCompile Include="Intel.cpp" />
|
||||
<ClCompile Include="main.cpp" />
|
||||
<ClCompile Include="Network.cpp" />
|
||||
<ClCompile Include="SysCalls.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="BinFile.h" />
|
||||
@ -148,6 +149,7 @@
|
||||
<ClInclude Include="Network.h" />
|
||||
<ClInclude Include="Object.h" />
|
||||
<ClInclude Include="Playables.h" />
|
||||
<ClInclude Include="SysCalls.h" />
|
||||
<ClInclude Include="TestFramework.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
|
||||
@ -36,6 +36,9 @@
|
||||
<ClCompile Include="BinFile.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SysCalls.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="bsuml.h">
|
||||
@ -62,5 +65,8 @@
|
||||
<ClInclude Include="TestFramework.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SysCalls.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@ -23,12 +23,15 @@ unsigned char* memory, \
|
||||
bool* emu_return, \
|
||||
ptr<::std::vector<int>> 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<int>* 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<int>> callstack, \
|
||||
ptr<::std::map<::std::string, \
|
||||
unsigned long long>> registers, \
|
||||
::std::vector<int>* 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<int>* 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<int>* cs, \
|
||||
::std::map<::std::string,unsigned long long>* r, \
|
||||
::std::vector<int>* 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<unsigned char> memory, ptr<::std::vector<int>> stack)
|
||||
|
||||
#define memory_dependent template<int memsize>
|
||||
#define memory_passdown(x) x<memsize>
|
||||
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
bio::tests::test iapxTest{
|
||||
"iAPX Test Suite",
|
||||
[]() -> bool {
|
||||
ptr<bio::Intel::iAPX86<1024>> i8086 = new bio::Intel::iAPX86<1024>;
|
||||
ptr<bio::Intel::iAPX86<SHRT_MAX>> i8086 = new bio::Intel::iAPX86<SHRT_MAX>;
|
||||
|
||||
std::filesystem::directory_iterator it("code/tests/bin");
|
||||
|
||||
|
||||
BIN
gameenv/code/tests/bin/test3
Normal file
BIN
gameenv/code/tests/bin/test3
Normal file
Binary file not shown.
4
gameenv/code/tests/buildtests.bat
Normal file
4
gameenv/code/tests/buildtests.bat
Normal file
@ -0,0 +1,4 @@
|
||||
@echo off
|
||||
nasm test.asm -o "bin/test"
|
||||
nasm test2.asm -o "bin/test2"
|
||||
nasm test3.asm -o "bin/test3"
|
||||
25
gameenv/code/tests/test3.asm
Normal file
25
gameenv/code/tests/test3.asm
Normal file
@ -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
|
||||
@ -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
|
||||
- call functions and return
|
||||
- create engine syscalls (``0x0ff0`` acts as a printf variant)
|
||||
- push and pop from a stack
|
||||
Loading…
x
Reference in New Issue
Block a user