Adds explink and expdump.
This commit is contained in:
parent
3611f351eb
commit
ac03695764
9 changed files with 662 additions and 452 deletions
210
libvm/exp.c
210
libvm/exp.c
|
@ -1,210 +0,0 @@
|
||||||
#include <stdint.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
const uint32_t EXP_MAGIC = 0x00505845; // 'E' 'X' 'P' '\0'
|
|
||||||
|
|
||||||
struct expfile
|
|
||||||
{
|
|
||||||
uint32_t magicNumber; // MUST BE EXP_MAGIC
|
|
||||||
uint16_t majorVersion; // 1
|
|
||||||
uint16_t minorVersion; // 0
|
|
||||||
uint32_t numMeta; // Number of metadata entries
|
|
||||||
uint32_t numSections; // Number of sections
|
|
||||||
uint32_t posMeta; // File pointer of first metadata entry
|
|
||||||
uint32_t posSections; // File pointer of first section definition;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct expsection
|
|
||||||
{
|
|
||||||
uint32_t type; // Type of the section: 0 = code, 1 = data
|
|
||||||
uint32_t start; // File pointer to the begin of the section
|
|
||||||
uint32_t length; // Length of the section in bytes
|
|
||||||
char name[64]; // Name of the section, null terminated c-string
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct expstring
|
|
||||||
{
|
|
||||||
uint32_t start; // File pointer to the start of the string
|
|
||||||
uint32_t length; // Length of the string in bytes.
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct expmeta
|
|
||||||
{
|
|
||||||
uint32_t type; // Type of the metadata: 0 = uint32_t, 1 = int32_t, 2 = ExpString
|
|
||||||
char key[32]; // Name of the metadata, null terminated c-string
|
|
||||||
union {
|
|
||||||
uint32_t u; // uint32_t
|
|
||||||
int32_t i; // int32_t
|
|
||||||
struct expstring s; // ExpString
|
|
||||||
} value; // Value of the metadata
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
typedef struct expfile expfile_t;
|
|
||||||
typedef struct expsection expsection_t;
|
|
||||||
typedef struct expstring expstring_t;
|
|
||||||
typedef struct expmeta expmeta_t;
|
|
||||||
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ctype.h>
|
|
||||||
|
|
||||||
#define DEBUG_VAL(x) fprintf(stderr, #x " = %d\n", x)
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char const *outfileName = "a.exp";
|
|
||||||
char const *codefileName = NULL;
|
|
||||||
char const *datafileName = NULL;
|
|
||||||
int memsize = 65536;
|
|
||||||
opterr = 0;
|
|
||||||
int c;
|
|
||||||
while ((c = getopt (argc, argv, "c:d:m:o:")) != -1)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 'm':
|
|
||||||
memsize = atoi(optarg);
|
|
||||||
if(memsize <= 0) {
|
|
||||||
fprintf(stderr, "memsize must be larger 0.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case 'o':
|
|
||||||
outfileName = optarg;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
codefileName = optarg;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
datafileName = optarg;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
if (optopt == 'o' || optopt == 'c' || optopt == 'd')
|
|
||||||
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
|
|
||||||
else if (isprint (optopt))
|
|
||||||
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
|
|
||||||
else
|
|
||||||
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int index = optind; index < argc; index++)
|
|
||||||
printf ("Non-option argument %s\n", argv[index]);
|
|
||||||
|
|
||||||
FILE *f = fopen(outfileName, "wb");
|
|
||||||
if(f == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not open file %s\n", outfileName);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
fprintf(stderr, "Out: %s\n", outfileName);
|
|
||||||
fprintf(stderr, "Code: %s\n", codefileName);
|
|
||||||
fprintf(stderr, "Data: %s\n", datafileName);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
int numSections = 0;
|
|
||||||
if(codefileName != NULL) numSections++;
|
|
||||||
if(datafileName != NULL) numSections++;
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
expfile_t fileHeader = {
|
|
||||||
EXP_MAGIC,
|
|
||||||
1, 0, // version
|
|
||||||
0, numSections, // n(meta), n(sections)
|
|
||||||
0, 0, // pos(meta), pos(sections)
|
|
||||||
};
|
|
||||||
|
|
||||||
fwrite(&fileHeader, sizeof(expfile_t), 1, f);
|
|
||||||
fileHeader.posSections = ftell(f);
|
|
||||||
|
|
||||||
DEBUG_VAL(fileHeader.posSections);
|
|
||||||
|
|
||||||
expsection_t codeSection = { 0 };
|
|
||||||
strcpy(codeSection.name, ".code");
|
|
||||||
|
|
||||||
expsection_t dataSection = { 1 };
|
|
||||||
strcpy(dataSection.name, ".data");
|
|
||||||
|
|
||||||
if(codefileName != NULL)
|
|
||||||
fwrite(&codeSection, sizeof(expsection_t), 1, f);
|
|
||||||
if(datafileName != NULL)
|
|
||||||
fwrite(&dataSection, sizeof(expsection_t), 1, f);
|
|
||||||
|
|
||||||
if(codefileName != NULL)
|
|
||||||
{
|
|
||||||
codeSection.start = ftell(f);
|
|
||||||
|
|
||||||
FILE *fc = fopen(codefileName, "rb");
|
|
||||||
if(fc == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not open %s\n", codefileName);
|
|
||||||
fclose(f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[4096];
|
|
||||||
while(!feof(fc))
|
|
||||||
{
|
|
||||||
int len = fread(buffer, 1, 4096, fc);
|
|
||||||
if(len > 0)
|
|
||||||
fwrite(buffer, 1, len, f);
|
|
||||||
codeSection.length += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fc);
|
|
||||||
|
|
||||||
DEBUG_VAL(codeSection.start);
|
|
||||||
DEBUG_VAL(codeSection.length);
|
|
||||||
}
|
|
||||||
if(datafileName != NULL)
|
|
||||||
{
|
|
||||||
dataSection.start = ftell(f);
|
|
||||||
|
|
||||||
FILE *fc = fopen(datafileName, "rb");
|
|
||||||
if(fc == NULL)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "Could not open %s\n", datafileName);
|
|
||||||
fclose(f);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
char buffer[4096];
|
|
||||||
while(!feof(fc))
|
|
||||||
{
|
|
||||||
int len = fread(buffer, 1, 4096, fc);
|
|
||||||
if(len > 0)
|
|
||||||
fwrite(buffer, 1, len, f);
|
|
||||||
dataSection.length += len;
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose(fc);
|
|
||||||
|
|
||||||
DEBUG_VAL(dataSection.start);
|
|
||||||
DEBUG_VAL(dataSection.length);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Now write the header again...
|
|
||||||
rewind(f);
|
|
||||||
fwrite(&fileHeader, sizeof(expfile_t), 1, f);
|
|
||||||
|
|
||||||
fseek(f, fileHeader.posSections, SEEK_SET);
|
|
||||||
if(codefileName != NULL)
|
|
||||||
fwrite(&codeSection, sizeof(expsection_t), 1, f);
|
|
||||||
if(datafileName != NULL)
|
|
||||||
fwrite(&dataSection, sizeof(expsection_t), 1, f);
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
104
libvm/exp.cpp
104
libvm/exp.cpp
|
@ -1,104 +0,0 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <inttypes.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <getopt.h>
|
|
||||||
|
|
||||||
#include <iostream>
|
|
||||||
#define DEBUG_VAL(x) std::cout << #x << " = " << (x) << "\n";
|
|
||||||
|
|
||||||
#include "include/supervm/exp.hpp"
|
|
||||||
#include "include/streams.hpp"
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
char const *outfileName = "a.exp";
|
|
||||||
char const *codefileName = nullptr;
|
|
||||||
char const *datafileName = nullptr;
|
|
||||||
int memsize = 65536;
|
|
||||||
opterr = 0;
|
|
||||||
int c;
|
|
||||||
while ((c = getopt (argc, argv, "c:d:m:o:")) != -1)
|
|
||||||
{
|
|
||||||
switch (c)
|
|
||||||
{
|
|
||||||
case 'm':
|
|
||||||
memsize = atoi(optarg);
|
|
||||||
if(memsize <= 0) {
|
|
||||||
fprintf(stderr, "memsize must be larger 0.\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
case 'o':
|
|
||||||
outfileName = optarg;
|
|
||||||
break;
|
|
||||||
case 'c':
|
|
||||||
codefileName = optarg;
|
|
||||||
break;
|
|
||||||
case 'd':
|
|
||||||
datafileName = optarg;
|
|
||||||
break;
|
|
||||||
case '?':
|
|
||||||
if (optopt == 'o')
|
|
||||||
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
|
|
||||||
else if (isprint (optopt))
|
|
||||||
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
|
|
||||||
else
|
|
||||||
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
|
|
||||||
return 1;
|
|
||||||
default:
|
|
||||||
abort();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (int index = optind; index < argc; index++)
|
|
||||||
printf ("Non-option argument %s\n", argv[index]);
|
|
||||||
|
|
||||||
|
|
||||||
FileStream fs(outfileName, "wb");
|
|
||||||
|
|
||||||
exp::File fileHeader = {
|
|
||||||
.magicNumber = EXP_MAGIC,
|
|
||||||
.majorVersion = 1,
|
|
||||||
.minorVersion = 0,
|
|
||||||
.numMeta = 0,
|
|
||||||
.numSections = 2,
|
|
||||||
.posMeta = 0,
|
|
||||||
.posSections = 0,
|
|
||||||
};
|
|
||||||
|
|
||||||
fileHeader.posSections = fs.write(&fileHeader, sizeof(exp::File));
|
|
||||||
|
|
||||||
DEBUG_VAL(fileHeader.posSections);
|
|
||||||
|
|
||||||
exp::Section codeSection = {
|
|
||||||
.type = 0,
|
|
||||||
.start = 0,
|
|
||||||
.length = 26,
|
|
||||||
};
|
|
||||||
strcpy(codeSection.name, ".code");
|
|
||||||
|
|
||||||
exp::Section dataSection = {
|
|
||||||
.type = 1,
|
|
||||||
.start = 0,
|
|
||||||
.length = 10,
|
|
||||||
};
|
|
||||||
strcpy(dataSection.name, ".data");
|
|
||||||
|
|
||||||
fs.write(&codeSection, sizeof(exp::Section));
|
|
||||||
fs.write(&dataSection, sizeof(exp::Section));
|
|
||||||
|
|
||||||
codeSection.start = fs.write("abcdefghijklmnopqrstuvwxyz", 26);
|
|
||||||
dataSection.start = fs.write("0123456789", 10);
|
|
||||||
|
|
||||||
DEBUG_VAL(codeSection.start);
|
|
||||||
DEBUG_VAL(dataSection.start);
|
|
||||||
|
|
||||||
// Now write the header again...
|
|
||||||
fs.rewind();
|
|
||||||
fs.write(&fileHeader, sizeof(exp::File));
|
|
||||||
|
|
||||||
fs.seek(SeekMode::Start, fileHeader.posSections);
|
|
||||||
fs.write(&codeSection, sizeof(exp::Section));
|
|
||||||
fs.write(&dataSection, sizeof(exp::Section));
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
52
libvm/exp.h
Normal file
52
libvm/exp.h
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(__gcc)
|
||||||
|
#define PACKED __attribute__ ((packed))
|
||||||
|
#else
|
||||||
|
#define PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
static const uint32_t EXP_MAGIC = 0x00505845; // 'E' 'X' 'P' '\0'
|
||||||
|
|
||||||
|
struct expfile
|
||||||
|
{
|
||||||
|
uint32_t magicNumber; // MUST BE EXP_MAGIC
|
||||||
|
uint16_t majorVersion; // 1
|
||||||
|
uint16_t minorVersion; // 0
|
||||||
|
uint32_t numMeta; // Number of metadata entries
|
||||||
|
uint32_t numSections; // Number of sections
|
||||||
|
uint32_t posMeta; // File pointer of first metadata entry
|
||||||
|
uint32_t posSections; // File pointer of first section definition;
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct expsection
|
||||||
|
{
|
||||||
|
uint32_t type; // Type of the section: 0 = code, 1 = data
|
||||||
|
uint32_t start; // File pointer to the begin of the section
|
||||||
|
uint32_t length; // Length of the section in bytes
|
||||||
|
char name[64]; // Name of the section, null terminated c-string
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct expstring
|
||||||
|
{
|
||||||
|
uint32_t start; // File pointer to the start of the string
|
||||||
|
uint32_t length; // Length of the string in bytes.
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
struct expmeta
|
||||||
|
{
|
||||||
|
uint32_t type; // Type of the metadata: 0 = uint32_t, 1 = int32_t, 2 = ExpString
|
||||||
|
char key[32]; // Name of the metadata, null terminated c-string
|
||||||
|
union {
|
||||||
|
uint32_t u; // uint32_t
|
||||||
|
int32_t i; // int32_t
|
||||||
|
struct expstring s; // ExpString
|
||||||
|
} value; // Value of the metadata
|
||||||
|
} PACKED;
|
||||||
|
|
||||||
|
typedef struct expfile expfile_t;
|
||||||
|
typedef struct expsection expsection_t;
|
||||||
|
typedef struct expstring expstring_t;
|
||||||
|
typedef struct expmeta expmeta_t;
|
234
libvm/expdump.c
Normal file
234
libvm/expdump.c
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
#if !defined(__gcc)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "exp.h"
|
||||||
|
#include "vm.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include "getopt.h"
|
||||||
|
#else
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define DEBUG_VAL(x) fprintf(stderr, #x " = %d\n", x)
|
||||||
|
|
||||||
|
const char *commandStrings[] =
|
||||||
|
{
|
||||||
|
// VM_CMD_COPY 0
|
||||||
|
"copy",
|
||||||
|
// VM_CMD_STORE 1
|
||||||
|
"store",
|
||||||
|
// VM_CMD_LOAD 2
|
||||||
|
"load",
|
||||||
|
// VM_CMD_GET 3
|
||||||
|
"get",
|
||||||
|
// VM_CMD_SET 4
|
||||||
|
"set",
|
||||||
|
// VM_CMD_BPGET 5
|
||||||
|
"bpget",
|
||||||
|
// VM_CMD_BPSET 6
|
||||||
|
"bpset",
|
||||||
|
// VM_CMD_CPGET 7
|
||||||
|
"cpget",
|
||||||
|
// VM_CMD_MATH 8
|
||||||
|
"math",
|
||||||
|
// VM_CMD_SPGET 9
|
||||||
|
"spget",
|
||||||
|
// VM_CMD_SPSET 10
|
||||||
|
"spset",
|
||||||
|
// VM_CMD_SYSCALL 11
|
||||||
|
"syscall",
|
||||||
|
// VM_CMD_HWIO 12
|
||||||
|
"hwio",
|
||||||
|
};
|
||||||
|
|
||||||
|
void disassemble(Instruction *list, uint32_t count, FILE *f)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
Instruction instr = list[i];
|
||||||
|
|
||||||
|
fprintf(f, "\t");
|
||||||
|
|
||||||
|
fprintf(f, "%6x ", i);
|
||||||
|
|
||||||
|
switch (instr.execN)
|
||||||
|
{
|
||||||
|
case VM_EXEC_0: fprintf(f, "[ex(n)=0] "); break;
|
||||||
|
case VM_EXEC_1: fprintf(f, "[ex(n)=1] "); break;
|
||||||
|
case VM_EXEC_X: fprintf(f, "[ex(n)=x] "); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (instr.execZ)
|
||||||
|
{
|
||||||
|
case VM_EXEC_0: fprintf(f, "[ex(z)=0] "); break;
|
||||||
|
case VM_EXEC_1: fprintf(f, "[ex(z)=1] "); break;
|
||||||
|
case VM_EXEC_X: fprintf(f, "[ex(z)=x] "); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (instr.input0)
|
||||||
|
{
|
||||||
|
case VM_INPUT_ZERO: fprintf(f, "[i0:zero] "); break;
|
||||||
|
case VM_INPUT_POP: fprintf(f, "[i0:pop] "); break;
|
||||||
|
case VM_INPUT_PEEK: fprintf(f, "[i0:peek] "); break;
|
||||||
|
case VM_INPUT_ARG: fprintf(f, "[i0:arg] "); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (instr.input1)
|
||||||
|
{
|
||||||
|
case VM_INPUT_ZERO: fprintf(f, "[i1:zero] "); break;
|
||||||
|
case VM_INPUT_POP: fprintf(f, "[i1:pop] "); break;
|
||||||
|
case VM_INPUT_PEEK: fprintf(f, "[i1:peek] "); break;
|
||||||
|
case VM_INPUT_ARG: fprintf(f, "[i1:arg] "); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (instr.command <= 12)
|
||||||
|
fprintf(f, "%s", commandStrings[instr.command]);
|
||||||
|
else
|
||||||
|
fprintf(f, "undefined [cmd:%d]", instr.command);
|
||||||
|
|
||||||
|
fprintf(f, " [ci:%d]", instr.cmdinfo);
|
||||||
|
|
||||||
|
switch (instr.flags)
|
||||||
|
{
|
||||||
|
case VM_FLAG_NO: fprintf(f, " [f:no]"); break;
|
||||||
|
case VM_FLAG_YES: fprintf(f, " [f:yes]"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (instr.output)
|
||||||
|
{
|
||||||
|
case VM_OUTPUT_DISCARD: fprintf(f, " [r:discard]"); break;
|
||||||
|
case VM_OUTPUT_JUMP: fprintf(f, " [r:jump]"); break;
|
||||||
|
case VM_OUTPUT_JUMPR: fprintf(f, " [r:jumpr]"); break;
|
||||||
|
case VM_OUTPUT_PUSH: fprintf(f, " [r:push]"); break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(f, "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
opterr = 0;
|
||||||
|
|
||||||
|
int dumpSections = 0;
|
||||||
|
int dumpMetas = 0;
|
||||||
|
|
||||||
|
int disassembleSections = 0;
|
||||||
|
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "smd")) != -1)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 's': dumpSections = 1; break;
|
||||||
|
case 'm': dumpMetas = 1; break;
|
||||||
|
case 'd': disassembleSections = 1; break;
|
||||||
|
case '?':
|
||||||
|
if (optopt == 'o' || optopt == 'c' || optopt == 'd')
|
||||||
|
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
|
||||||
|
else if (isprint(optopt))
|
||||||
|
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int index = optind; index < argc; index++)
|
||||||
|
{
|
||||||
|
const char *fileName = argv[index];
|
||||||
|
FILE *f = fopen(fileName, "rb");
|
||||||
|
if (f == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not open file %s\n", fileName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
expfile_t fileHeader;
|
||||||
|
|
||||||
|
if (fread(&fileHeader, 1, sizeof(expfile_t), f) != sizeof(expfile_t))
|
||||||
|
{
|
||||||
|
fprintf(stderr, "File %s does not contain a valid header.\n", fileName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fileHeader.magicNumber != EXP_MAGIC)
|
||||||
|
{
|
||||||
|
fprintf(
|
||||||
|
stderr, "Invalid magic in %s\n",
|
||||||
|
fileHeader.majorVersion, fileHeader.minorVersion);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (fileHeader.majorVersion != 1 && fileHeader.minorVersion == 0)
|
||||||
|
{
|
||||||
|
fprintf(
|
||||||
|
stderr, "Invalid version %s: %d.%d\n",
|
||||||
|
fileHeader.majorVersion, fileHeader.minorVersion);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We should be sane now...
|
||||||
|
fprintf(stdout, "EXP FILE %s\n", fileName);
|
||||||
|
fprintf(stdout, "Version: %d.%d\n", fileHeader.majorVersion, fileHeader.minorVersion);
|
||||||
|
fprintf(stdout, "Sections: %d\n", fileHeader.numSections);
|
||||||
|
fprintf(stdout, "Metas: %d\n", fileHeader.numMeta);
|
||||||
|
|
||||||
|
if (dumpSections)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "Sections:\n");
|
||||||
|
|
||||||
|
for (int i = 0; i < fileHeader.numSections; i++)
|
||||||
|
{
|
||||||
|
expsection_t section;
|
||||||
|
|
||||||
|
fseek(f, fileHeader.posSections + i * sizeof(expsection_t), SEEK_SET);
|
||||||
|
fread(§ion, 1, sizeof(expsection_t), f);
|
||||||
|
|
||||||
|
fprintf(stdout, " Section #%d\n", i);
|
||||||
|
fprintf(stdout, " Name: %s\n", section.name);
|
||||||
|
fprintf(stdout, " Type: %s\n", (section.type ? "Data" : "Code"));
|
||||||
|
fprintf(stdout, " Start: %d\n", section.start);
|
||||||
|
fprintf(stdout, " Size: %d\n", section.length);
|
||||||
|
|
||||||
|
// Call disassembler
|
||||||
|
if (disassembleSections && section.type == 0)
|
||||||
|
{
|
||||||
|
fprintf(stdout, " Disassembly:\n");
|
||||||
|
|
||||||
|
Instruction *buffer = malloc(section.length);
|
||||||
|
|
||||||
|
fseek(f, section.start, SEEK_SET);
|
||||||
|
int len = fread(buffer, 1, section.length, f);
|
||||||
|
if (len != section.length)
|
||||||
|
fprintf(stderr, "Read invalid size.\n");
|
||||||
|
|
||||||
|
disassemble(
|
||||||
|
buffer,
|
||||||
|
section.length / sizeof(Instruction),
|
||||||
|
stdout);
|
||||||
|
|
||||||
|
free(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
178
libvm/explink.c
Normal file
178
libvm/explink.c
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
#if !defined(__gcc)
|
||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#include "exp.h"
|
||||||
|
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#include "getopt.h"
|
||||||
|
#else
|
||||||
|
#include <getopt.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#define DEBUG_VAL(x) fprintf(stderr, #x " = %d\n", x)
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
char const *outfileName = "a.exp";
|
||||||
|
char const *codefileName = NULL;
|
||||||
|
char const *datafileName = NULL;
|
||||||
|
int memsize = 65536;
|
||||||
|
opterr = 0;
|
||||||
|
int c;
|
||||||
|
while ((c = getopt(argc, argv, "c:d:m:o:")) != -1)
|
||||||
|
{
|
||||||
|
switch (c)
|
||||||
|
{
|
||||||
|
case 'm':
|
||||||
|
memsize = atoi(optarg);
|
||||||
|
if (memsize <= 0) {
|
||||||
|
fprintf(stderr, "memsize must be larger 0.\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
case 'o':
|
||||||
|
outfileName = optarg;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
codefileName = optarg;
|
||||||
|
break;
|
||||||
|
case 'd':
|
||||||
|
datafileName = optarg;
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
if (optopt == 'o' || optopt == 'c' || optopt == 'd')
|
||||||
|
fprintf(stderr, "Option -%c requires an argument.\n", optopt);
|
||||||
|
else if (isprint(optopt))
|
||||||
|
fprintf(stderr, "Unknown option `-%c'.\n", optopt);
|
||||||
|
else
|
||||||
|
fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
|
||||||
|
return 1;
|
||||||
|
default:
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int index = optind; index < argc; index++)
|
||||||
|
printf("Non-option argument %s\n", argv[index]);
|
||||||
|
|
||||||
|
FILE *f = fopen(outfileName, "wb");
|
||||||
|
if (f == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not open file %s\n", outfileName);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
fprintf(stderr, "Out: %s\n", outfileName);
|
||||||
|
fprintf(stderr, "Code: %s\n", codefileName);
|
||||||
|
fprintf(stderr, "Data: %s\n", datafileName);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
int numSections = 0;
|
||||||
|
if (codefileName != NULL) numSections++;
|
||||||
|
if (datafileName != NULL) numSections++;
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
expfile_t fileHeader = {
|
||||||
|
EXP_MAGIC,
|
||||||
|
1, 0, // version
|
||||||
|
0, numSections, // n(meta), n(sections)
|
||||||
|
0, 0, // pos(meta), pos(sections)
|
||||||
|
};
|
||||||
|
|
||||||
|
fwrite(&fileHeader, sizeof(expfile_t), 1, f);
|
||||||
|
fileHeader.posSections = ftell(f);
|
||||||
|
|
||||||
|
DEBUG_VAL(fileHeader.posSections);
|
||||||
|
|
||||||
|
expsection_t codeSection = { 0 };
|
||||||
|
strcpy(codeSection.name, ".code");
|
||||||
|
|
||||||
|
expsection_t dataSection = { 1 };
|
||||||
|
strcpy(dataSection.name, ".data");
|
||||||
|
|
||||||
|
if (codefileName != NULL)
|
||||||
|
fwrite(&codeSection, sizeof(expsection_t), 1, f);
|
||||||
|
if (datafileName != NULL)
|
||||||
|
fwrite(&dataSection, sizeof(expsection_t), 1, f);
|
||||||
|
|
||||||
|
if (codefileName != NULL)
|
||||||
|
{
|
||||||
|
codeSection.start = ftell(f);
|
||||||
|
|
||||||
|
FILE *fc = fopen(codefileName, "rb");
|
||||||
|
if (fc == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not open %s\n", codefileName);
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
while (!feof(fc))
|
||||||
|
{
|
||||||
|
size_t len = fread(buffer, 1, 4096, fc);
|
||||||
|
if (len > 0)
|
||||||
|
fwrite(buffer, 1, len, f);
|
||||||
|
codeSection.length += (uint32_t)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fc);
|
||||||
|
|
||||||
|
DEBUG_VAL(codeSection.start);
|
||||||
|
DEBUG_VAL(codeSection.length);
|
||||||
|
}
|
||||||
|
if (datafileName != NULL)
|
||||||
|
{
|
||||||
|
dataSection.start = ftell(f);
|
||||||
|
|
||||||
|
FILE *fc = fopen(datafileName, "rb");
|
||||||
|
if (fc == NULL)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Could not open %s\n", datafileName);
|
||||||
|
fclose(f);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char buffer[4096];
|
||||||
|
while (!feof(fc))
|
||||||
|
{
|
||||||
|
size_t len = fread(buffer, 1, 4096, fc);
|
||||||
|
if (len > 0)
|
||||||
|
fwrite(buffer, 1, len, f);
|
||||||
|
dataSection.length += (uint32_t)len;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(fc);
|
||||||
|
|
||||||
|
DEBUG_VAL(dataSection.start);
|
||||||
|
DEBUG_VAL(dataSection.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Now write the header again...
|
||||||
|
rewind(f);
|
||||||
|
fwrite(&fileHeader, sizeof(expfile_t), 1, f);
|
||||||
|
|
||||||
|
fseek(f, fileHeader.posSections, SEEK_SET);
|
||||||
|
if (codefileName != NULL)
|
||||||
|
fwrite(&codeSection, sizeof(expsection_t), 1, f);
|
||||||
|
if (datafileName != NULL)
|
||||||
|
fwrite(&dataSection, sizeof(expsection_t), 1, f);
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -1,50 +0,0 @@
|
||||||
#pragma once
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
enum class SeekMode
|
|
||||||
{
|
|
||||||
Start,
|
|
||||||
Current,
|
|
||||||
End,
|
|
||||||
};
|
|
||||||
|
|
||||||
class BaseStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual void rewind() = 0;
|
|
||||||
virtual void seek(SeekMode mode, long int offset) = 0;
|
|
||||||
virtual size_t position() const = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class InputStream :
|
|
||||||
public BaseStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual size_t read(void *ptr, size_t size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class OutputStream :
|
|
||||||
public BaseStream
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual size_t write(void const *ptr, size_t size) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileStream :
|
|
||||||
public virtual InputStream,
|
|
||||||
public virtual OutputStream
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
FILE *file;
|
|
||||||
public:
|
|
||||||
FileStream(const char *fileName, const char *mode);
|
|
||||||
~FileStream();
|
|
||||||
void rewind() override;
|
|
||||||
void seek(SeekMode mode, long int offset) override;
|
|
||||||
size_t position() const override;
|
|
||||||
|
|
||||||
size_t read(void *ptr, size_t size) override;
|
|
||||||
|
|
||||||
size_t write(void const *ptr, size_t size) override;
|
|
||||||
};
|
|
|
@ -1,42 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#define EXP_MAGIC 0x00505845 // 'E' 'X' 'P' '\0'
|
|
||||||
|
|
||||||
namespace exp
|
|
||||||
{
|
|
||||||
struct File
|
|
||||||
{
|
|
||||||
uint32_t magicNumber; // MUST BE EXP_MAGIC
|
|
||||||
uint16_t majorVersion; // 1
|
|
||||||
uint16_t minorVersion; // 0
|
|
||||||
uint32_t numMeta; // Number of metadata entries
|
|
||||||
uint32_t numSections; // Number of sections
|
|
||||||
uint32_t posMeta; // File pointer of first metadata entry
|
|
||||||
uint32_t posSections; // File pointer of first section definition;
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct Section
|
|
||||||
{
|
|
||||||
uint32_t type; // Type of the section: 0 = code, 1 = data
|
|
||||||
uint32_t start; // File pointer to the begin of the section
|
|
||||||
uint32_t length; // Length of the section in bytes
|
|
||||||
char name[64]; // Name of the section, null terminated c-string
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct String
|
|
||||||
{
|
|
||||||
uint32_t start; // File pointer to the start of the string
|
|
||||||
uint32_t length; // Length of the string in bytes.
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
|
|
||||||
struct Meta
|
|
||||||
{
|
|
||||||
uint32_t type; // Type of the metadata: 0 = uint32_t, 1 = int32_t, 2 = ExpString
|
|
||||||
char key[32]; // Name of the metadata, null terminated c-string
|
|
||||||
union {
|
|
||||||
uint32_t u; // uint32_t
|
|
||||||
int32_t i; // int32_t
|
|
||||||
String s; // ExpString
|
|
||||||
} value; // Value of the metadata
|
|
||||||
} __attribute__ ((packed));
|
|
||||||
}
|
|
|
@ -1,46 +0,0 @@
|
||||||
#include "include/streams.hpp"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
FileStream::FileStream(const char *fileName, const char *mode) :
|
|
||||||
file(fopen(fileName, mode))
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
FileStream::~FileStream()
|
|
||||||
{
|
|
||||||
fclose(this->file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileStream::rewind()
|
|
||||||
{
|
|
||||||
::rewind(this->file);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FileStream::seek(SeekMode mode, long int offset)
|
|
||||||
{
|
|
||||||
int sm;
|
|
||||||
switch(mode) {
|
|
||||||
case SeekMode::Start: sm = SEEK_SET; break;
|
|
||||||
case SeekMode::Current: sm = SEEK_CUR; break;
|
|
||||||
case SeekMode::End: sm = SEEK_END; break;
|
|
||||||
}
|
|
||||||
fseek(this->file, offset, sm);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileStream::position() const
|
|
||||||
{
|
|
||||||
return ftell(this->file);
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileStream::read(void *ptr, size_t size)
|
|
||||||
{
|
|
||||||
fread(ptr, size, 1, this->file);
|
|
||||||
return this->position();
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t FileStream::write(void const *ptr, size_t size)
|
|
||||||
{
|
|
||||||
fwrite(ptr, size, 1, this->file);
|
|
||||||
return this->position();
|
|
||||||
}
|
|
198
libvm/vm.h
Normal file
198
libvm/vm.h
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#if defined(__gcc)
|
||||||
|
#define PACKED __attribute__ ((packed))
|
||||||
|
#else
|
||||||
|
#define PACKED
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#else
|
||||||
|
#if defined(_gcc)
|
||||||
|
#define static_assert _Static_assert
|
||||||
|
#else
|
||||||
|
#define static_assert(x,y)
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(VM_STACKSIZE)
|
||||||
|
#define VM_STACKSIZE 512
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Binary Encoding : (enabled, value)
|
||||||
|
#define VM_EXEC_X 0
|
||||||
|
#define VM_EXEC_0 2
|
||||||
|
#define VM_EXEC_1 3
|
||||||
|
|
||||||
|
#define VM_INPUT_ZERO 0
|
||||||
|
#define VM_INPUT_POP 1
|
||||||
|
#define VM_INPUT_PEEK 2
|
||||||
|
#define VM_INPUT_ARG 3
|
||||||
|
|
||||||
|
#define VM_CMD_COPY 0
|
||||||
|
#define VM_CMD_STORE 1
|
||||||
|
#define VM_CMD_LOAD 2
|
||||||
|
#define VM_CMD_GET 3
|
||||||
|
#define VM_CMD_SET 4
|
||||||
|
#define VM_CMD_BPGET 5
|
||||||
|
#define VM_CMD_BPSET 6
|
||||||
|
#define VM_CMD_CPGET 7
|
||||||
|
#define VM_CMD_MATH 8
|
||||||
|
#define VM_CMD_SPGET 9
|
||||||
|
#define VM_CMD_SPSET 10
|
||||||
|
#define VM_CMD_SYSCALL 11
|
||||||
|
#define VM_CMD_HWIO 12
|
||||||
|
|
||||||
|
#define VM_MATH_ADD 0
|
||||||
|
#define VM_MATH_SUB 1
|
||||||
|
#define VM_MATH_MUL 2
|
||||||
|
#define VM_MATH_DIV 3
|
||||||
|
#define VM_MATH_MOD 4
|
||||||
|
#define VM_MATH_AND 5
|
||||||
|
#define VM_MATH_OR 6
|
||||||
|
#define VM_MATH_XOR 7
|
||||||
|
#define VM_MATH_NOT 8
|
||||||
|
#define VM_MATH_ROL 9
|
||||||
|
#define VM_MATH_ROR 10
|
||||||
|
#define VM_MATH_ASL 11
|
||||||
|
#define VM_MATH_ASR 12
|
||||||
|
#define VM_MATH_SHL 13
|
||||||
|
#define VM_MATH_SHR 14
|
||||||
|
|
||||||
|
#define VM_FLAG_NO 0
|
||||||
|
#define VM_FLAG_YES 1
|
||||||
|
|
||||||
|
#define VM_OUTPUT_DISCARD 0
|
||||||
|
#define VM_OUTPUT_PUSH 1
|
||||||
|
#define VM_OUTPUT_JUMP 2
|
||||||
|
#define VM_OUTPUT_JUMPR 3
|
||||||
|
|
||||||
|
#define VM_FLAG_Z (1<<0)
|
||||||
|
#define VM_FLAG_N (1<<1)
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
unsigned int execZ : 2;
|
||||||
|
unsigned int execN : 2;
|
||||||
|
unsigned int input0 : 2;
|
||||||
|
unsigned int input1 : 1;
|
||||||
|
unsigned int command : 6;
|
||||||
|
unsigned int cmdinfo : 16;
|
||||||
|
unsigned int flags : 1;
|
||||||
|
unsigned int output : 2;
|
||||||
|
uint32_t argument;
|
||||||
|
} PACKED Instruction;
|
||||||
|
|
||||||
|
static_assert(sizeof(Instruction) == 8, "Instruction must be 8 bytes large.");
|
||||||
|
static_assert(offsetof(Instruction, argument) == 4, "Argument must be must be 8 bytes large.");
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Instruction *code;
|
||||||
|
uint32_t length;
|
||||||
|
} Module;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t pageSize;
|
||||||
|
uint32_t length;
|
||||||
|
uint8_t **pages;
|
||||||
|
} VirtualMemoryMap;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Module *module;
|
||||||
|
void *tag;
|
||||||
|
|
||||||
|
uint32_t codePointer;
|
||||||
|
uint32_t stackPointer;
|
||||||
|
uint32_t basePointer;
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
uint32_t stack[VM_STACKSIZE];
|
||||||
|
|
||||||
|
VirtualMemoryMap mmap;
|
||||||
|
} Process;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t input0;
|
||||||
|
uint32_t input1;
|
||||||
|
uint32_t argument;
|
||||||
|
uint32_t additional;
|
||||||
|
|
||||||
|
uint32_t output;
|
||||||
|
} CommandInfo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Steps a given process.
|
||||||
|
*
|
||||||
|
* Executes a single instruction and processes input and output.
|
||||||
|
*
|
||||||
|
* @param process The process to be stepped.
|
||||||
|
* @returns 1 if the process is still running or 0 if the process is terminated.
|
||||||
|
*/
|
||||||
|
int vm_step_process(Process *process);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes a value onto the process' stack.
|
||||||
|
*/
|
||||||
|
void vm_push(Process *process, uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pops a value from the process' stack.
|
||||||
|
*/
|
||||||
|
uint32_t vm_pop(Process *process);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the top value of the process' stack.
|
||||||
|
*/
|
||||||
|
uint32_t vm_peek(Process *process);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a byte from process memory.
|
||||||
|
* @arg process
|
||||||
|
* @arg address The address to read from.
|
||||||
|
*/
|
||||||
|
uint8_t vm_read_byte(Process *process, uint32_t address);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes a byte to process memory.
|
||||||
|
* @arg process
|
||||||
|
* @arg address The address to read from.
|
||||||
|
*/
|
||||||
|
void vm_write_byte(Process *process, uint32_t address, uint8_t value);
|
||||||
|
|
||||||
|
// The following functions need to be host-implemented.
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An assertion the VM does.
|
||||||
|
* @param assertion If zero, the assertion failed.
|
||||||
|
* @param msg The message that should be shown when the assertion fails.
|
||||||
|
*/
|
||||||
|
void vm_assert(int assertion, const char *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hosts syscall implementation.
|
||||||
|
* @param process The process that calls the syscall.
|
||||||
|
* @param info Additional information for the syscall. Contains arguments and results.
|
||||||
|
*/
|
||||||
|
void vm_syscall(Process *process, CommandInfo *info);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The hosts hardware IO implementation.
|
||||||
|
* @param process The process that wants to do IO.
|
||||||
|
* @param info Additional information for the HWIO. Contains arguments and results.
|
||||||
|
*/
|
||||||
|
void vm_hwio(Process *process, CommandInfo *info);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#undef static_assert
|
||||||
|
#endif
|
Loading…
Reference in a new issue