Adds explink and expdump.

This commit is contained in:
Felix Queißner 2016-06-29 12:32:55 +02:00
parent 3611f351eb
commit ac03695764
9 changed files with 662 additions and 452 deletions

View file

@ -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;
}

View file

@ -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
View 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
View 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(&section, 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
View 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;
}

View file

@ -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;
};

View file

@ -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));
}

View file

@ -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
View 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