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 bio {
|
||||||
namespace emu {
|
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];
|
memory_dependent using mem_buffer = unsigned char[memsize];
|
||||||
|
|
||||||
struct symbol {
|
struct symbol {
|
||||||
@ -30,11 +33,14 @@ namespace bio {
|
|||||||
memory_dependent class emulator_base {
|
memory_dependent class emulator_base {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
int instructionPointer;
|
||||||
instruction_set isa;
|
instruction_set isa;
|
||||||
mem_buffer<memsize> memory;
|
mem_buffer<memsize> memory;
|
||||||
std::vector<symbol> symbols;
|
std::vector<symbol> symbols;
|
||||||
std::vector<int> callStack;
|
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 void load_app(application& app) = 0;
|
||||||
virtual bool run_symbol(int symbol) = 0;
|
virtual bool run_symbol(int symbol) = 0;
|
||||||
@ -50,7 +56,6 @@ namespace bio {
|
|||||||
|
|
||||||
memory_dependent class linear_emulator_base : public memory_passdown(emulator_base) {
|
memory_dependent class linear_emulator_base : public memory_passdown(emulator_base) {
|
||||||
public:
|
public:
|
||||||
int instructionPointer;
|
|
||||||
bool run_symbol(int symbol) {
|
bool run_symbol(int symbol) {
|
||||||
// check symbol ID is within symbol count
|
// check symbol ID is within symbol count
|
||||||
if (symbol > this->symbols.size() && symbol != -1)
|
if (symbol > this->symbols.size() && symbol != -1)
|
||||||
@ -71,16 +76,24 @@ namespace bio {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// apply instruction pointer
|
// apply instruction pointer
|
||||||
if (symbol >= 0) instructionPointer = this->symbols[symbol].offset;
|
if (symbol >= 0) this->instructionPointer = this->symbols[symbol].offset;
|
||||||
else instructionPointer = 0;
|
else this->instructionPointer = 0;
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
bool returned = false;
|
bool returned = false;
|
||||||
until(returned || instructionPointer >= memsize) {
|
until(returned || this->instructionPointer >= memsize) {
|
||||||
this->instructionPointer +=
|
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");
|
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) {
|
isa_instruction(bio::Intel::ISAs::iAPX86::invalid) {
|
||||||
std::println("Invalid (or unimplemented) opcode used - {} at {}", memory[position], position);
|
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) {
|
isa_instruction(bio::Intel::ISAs::iAPX86::call_e8) {
|
||||||
short jump;
|
short jump;
|
||||||
memcpy(&jump, memory + (position + 1), 2);
|
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);
|
callstack->push_back(position + 3);
|
||||||
|
|
||||||
return jump + 3;
|
return jump + 3;
|
||||||
}
|
}
|
||||||
@ -1,6 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "bsuml.h"
|
#include "bsuml.h"
|
||||||
#include "Emulation.h"
|
#include "Emulation.h"
|
||||||
|
#include "SysCalls.h"
|
||||||
|
|
||||||
namespace bio {
|
namespace bio {
|
||||||
|
|
||||||
@ -13,6 +14,10 @@ namespace bio {
|
|||||||
isa_instruction_template(inc_16b_reg_template);
|
isa_instruction_template(inc_16b_reg_template);
|
||||||
isa_instruction_template(dec_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(invalid);
|
||||||
|
|
||||||
isa_instruction(add_01);
|
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[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[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[0x83] = ISAs::iAPX86::grp1_83;
|
||||||
this->isa[0x90] = ISAs::iAPX86::nop_90;
|
this->isa[0x90] = ISAs::iAPX86::nop_90;
|
||||||
|
|
||||||
@ -61,6 +78,10 @@ namespace bio {
|
|||||||
times(sizeof(this->memory)) {
|
times(sizeof(this->memory)) {
|
||||||
this->memory[___i] = '\0';
|
this->memory[___i] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this->syscalls[4080] = bio::emu::syscalls::print;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void load_app(bio::emu::application& app) {
|
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="Intel.cpp" />
|
||||||
<ClCompile Include="main.cpp" />
|
<ClCompile Include="main.cpp" />
|
||||||
<ClCompile Include="Network.cpp" />
|
<ClCompile Include="Network.cpp" />
|
||||||
|
<ClCompile Include="SysCalls.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="BinFile.h" />
|
<ClInclude Include="BinFile.h" />
|
||||||
@ -148,6 +149,7 @@
|
|||||||
<ClInclude Include="Network.h" />
|
<ClInclude Include="Network.h" />
|
||||||
<ClInclude Include="Object.h" />
|
<ClInclude Include="Object.h" />
|
||||||
<ClInclude Include="Playables.h" />
|
<ClInclude Include="Playables.h" />
|
||||||
|
<ClInclude Include="SysCalls.h" />
|
||||||
<ClInclude Include="TestFramework.h" />
|
<ClInclude Include="TestFramework.h" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
|||||||
@ -36,6 +36,9 @@
|
|||||||
<ClCompile Include="BinFile.cpp">
|
<ClCompile Include="BinFile.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="SysCalls.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="bsuml.h">
|
<ClInclude Include="bsuml.h">
|
||||||
@ -62,5 +65,8 @@
|
|||||||
<ClInclude Include="TestFramework.h">
|
<ClInclude Include="TestFramework.h">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="SysCalls.h">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -23,12 +23,15 @@ unsigned char* memory, \
|
|||||||
bool* emu_return, \
|
bool* emu_return, \
|
||||||
ptr<::std::vector<int>> callstack, \
|
ptr<::std::vector<int>> callstack, \
|
||||||
ptr<::std::map<::std::string, \
|
ptr<::std::map<::std::string, \
|
||||||
unsigned long long>> registers)
|
unsigned long long>> registers,\
|
||||||
// position = current instruction pointer position
|
::std::vector<int>* stack, \
|
||||||
// memory = memory buffer
|
::bio::emu::syscall_set* syscalls)
|
||||||
// emureturn = end of symbol
|
// position = current instruction pointer position
|
||||||
// callstack = callstack pointer
|
// memory = memory buffer
|
||||||
// registers = registers pointer
|
// emureturn = end of symbol
|
||||||
|
// callstack = callstack pointer
|
||||||
|
// registers = registers pointer
|
||||||
|
// stack = stack pointer
|
||||||
|
|
||||||
#define isa_instruction_template(x) int x(int position, \
|
#define isa_instruction_template(x) int x(int position, \
|
||||||
unsigned char* memory, \
|
unsigned char* memory, \
|
||||||
@ -36,6 +39,8 @@ bool* emu_return, \
|
|||||||
ptr<::std::vector<int>> callstack, \
|
ptr<::std::vector<int>> callstack, \
|
||||||
ptr<::std::map<::std::string, \
|
ptr<::std::map<::std::string, \
|
||||||
unsigned long long>> registers, \
|
unsigned long long>> registers, \
|
||||||
|
::std::vector<int>* stack, \
|
||||||
|
::bio::emu::syscall_set* syscalls, \
|
||||||
::std::string args)
|
::std::string args)
|
||||||
// position = current instruction pointer position
|
// position = current instruction pointer position
|
||||||
// memory = memory buffer
|
// memory = memory buffer
|
||||||
@ -45,10 +50,18 @@ unsigned long long>> registers, \
|
|||||||
// args = template arguments
|
// args = template arguments
|
||||||
|
|
||||||
#define isa_instruction_templater(x, args) \
|
#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{\
|
[](int p, \
|
||||||
return x(p, m, er, cs, r, args);\
|
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_dependent template<int memsize>
|
||||||
#define memory_passdown(x) x<memsize>
|
#define memory_passdown(x) x<memsize>
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@
|
|||||||
bio::tests::test iapxTest{
|
bio::tests::test iapxTest{
|
||||||
"iAPX Test Suite",
|
"iAPX Test Suite",
|
||||||
[]() -> bool {
|
[]() -> 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");
|
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
|
||||||
@ -14,3 +14,5 @@ All features the 8086 emulator of the engine supports are demonstrated in the [t
|
|||||||
- move on (A/C/D/B)X from immediate
|
- move on (A/C/D/B)X from immediate
|
||||||
- increment/decrement (A/C/D/B)X
|
- 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