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