Skip to content

Commit

Permalink
refactor: virtual cpu
Browse files Browse the repository at this point in the history
  • Loading branch information
MeerkatBoss committed Oct 14, 2022
1 parent e85231a commit 9e4447a
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 149 deletions.
69 changes: 50 additions & 19 deletions lib/asm/asm_cmd.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,55 @@

#define _ ,

ASM_CMD(NOP, 0x00, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(ADD, 0x01, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(INC, 0x02, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(SUB, 0x03, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(DEC, 0x04, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(MUL, 0x05, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(DIV, 0x06, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(PUSH,0x07, {.arg_count = 1 _ .arg_list = {{.perms = ARG_RD}}})

ASM_CMD(POP, 0x08, {.arg_count = 0 _ .arg_list = {}})

ASM_CMD(HALT,0x09, {.arg_count = 0 _ .arg_list = {}})
ASM_CMD(NOP, 0x00, {.arg_count = 0 _ .arg_list = {}}, {})

ASM_CMD(ADD, 0x01, {.arg_count = 0 _ .arg_list = {}},
{
PUSH(POP + POP);
})

ASM_CMD(INC, 0x02, {.arg_count = 0 _ .arg_list = {}},
{
PUSH(POP + 1);
})

ASM_CMD(SUB, 0x03, {.arg_count = 0 _ .arg_list = {}},
{
int op1 = POP _ op2 = POP;
PUSH(op2 - op1);
})

ASM_CMD(DEC, 0x04, {.arg_count = 0 _ .arg_list = {}},
{
PUSH(POP - 1);
})

ASM_CMD(MUL, 0x05, {.arg_count = 0 _ .arg_list = {}},
{
PUSH(POP * POP);
})

ASM_CMD(DIV, 0x06, {.arg_count = 0 _ .arg_list = {}},
{
int op1 = POP _ op2 = POP;
ASSERT(op1 != 0, "Attempted division by zero");
PUSH(op2 / op1);
})

ASM_CMD(PUSH,0x07, {.arg_count = 1 _ .arg_list = {{.perms = ARG_RD}}},
{
asm_arg argument = NEXT_ARG;
PUSH(*argument.val_ptr);
})

ASM_CMD(POP, 0x08, {.arg_count = 0 _ .arg_list = {}},
{
printf("%d\n", POP);
})

ASM_CMD(HALT,0x09, {.arg_count = 0 _ .arg_list = {}},
{
STOP;
})

#undef _
2 changes: 1 addition & 1 deletion src/vcpu/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
add_executable(vcpu main.cpp vcpu_utils.cpp)

target_link_libraries(vcpu PRIVATE libargparser libasm liblogs libstack)
target_link_libraries(vcpu PRIVATE libargparser libasm liblogs libstack libinput)

target_include_directories(vcpu PRIVATE
${CMAKE_CURRENT_LIST_DIR})
41 changes: 19 additions & 22 deletions src/vcpu/main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "logger.h"
#include "vcpu_utils.h"

enum status
{
STATUS_SUCCESS,
Expand All @@ -10,33 +11,29 @@ enum status
int main(int argc, char** argv)
{
add_default_file_logger();
add_logger(
{
.name = "Console output",
.stream = stdout,
.logging_level = LOG_ERROR,
.settings_mask = LGS_USE_ESCAPE | LGS_KEEP_OPEN
});

LOG_ASSERT_ERROR(argc == 2, return STATUS_INPUT_ERROR,
"Incorrect program usage.", NULL);

size_t cmd_count = 0;
int* commands = read_cmd_array(argv[1], &cmd_count);
LOG_ASSERT_ERROR(commands != NULL, return STATUS_INPUT_ERROR,
"Corrupt program file.", NULL);

Stack stack = {};
int constructed = StackCtor(&stack);
LOG_ASSERT_ERROR(constructed == 0, return STATUS_RUNTIME_ERROR,
"Error initializing stack.", NULL);

size_t iptr = 0;
while(iptr < cmd_count)
{
size_t shift = 0;
int status = execute_command(commands + iptr, &stack, &shift);
LOG_ASSERT_ERROR(status != -1, return STATUS_INPUT_ERROR,
"Invalid command sequence.", NULL);
if (status == 1) break;
iptr += shift;
}
proc_state vcpu = proc_ctor(argv[1]);
LOG_ASSERT_ERROR(vcpu.cmd != NULL, return STATUS_INPUT_ERROR,
"Failed to read program.", NULL);

free(commands);
StackDtor(&stack);
int res = proc_run(&vcpu);
LOG_ASSERT_ERROR(res != -1,
{
proc_dtor(&vcpu);
return STATUS_INPUT_ERROR;
},
"Failed to execute program.", NULL);

proc_dtor(&vcpu);
return STATUS_SUCCESS;
}
176 changes: 86 additions & 90 deletions src/vcpu/vcpu_utils.cpp
Original file line number Diff line number Diff line change
@@ -1,116 +1,112 @@
#include <stdio.h>
#include <string.h>
#include <sys/mman.h>

#include "vcpu_utils.h"
#include "text_lines.h"
#include "logger.h"
#include "assembler.h"

int* read_cmd_array(const char* filename, size_t* array_len)
proc_state proc_ctor(const char* program_file)
{
const size_t SIGNATURE_LENGTH = 4;
FILE* program_file = fopen(filename, "r");
LOG_ASSERT_FATAL(program_file != NULL, "Cannot open file \'%s\'", filename);

char signature_buf[SIGNATURE_LENGTH + 1] = "";
unsigned int version = 0;
size_t length = 0;

int read_status = fscanf(program_file, "%4s %u %zu",
signature_buf, &version, &length);
LOG_ASSERT(read_status == 3, return NULL);
LOG_ASSERT(strcmp(signature_buf, STR_SIGN) == 0, return NULL);
LOG_ASSERT(version == LATEST_VERSION, return NULL);
char* bytes = NULL;
size_t file_size = map_file(program_file, &bytes, 0);
LOG_ASSERT_ERROR(file_size >= HEADER_SIZE, return {},
"Could not open file \'%s\'", program_file);
padded_header *hdr = (padded_header*) bytes;
LOG_ASSERT_ERROR(strncmp(hdr->header.signature, STR_SIGN, 4) == 0,
return {},
"Invalid signature \'%.4s\'", hdr->header.signature);
LOG_ASSERT_ERROR(hdr->header.version == LATEST_VERSION,
return {},
"Version %u not supported", hdr->header.version);

Stack* value_stack = (Stack*) calloc(1, sizeof(*value_stack));
Stack* call_stack = (Stack*) calloc(1, sizeof(*value_stack));
StackCtor(value_stack);
StackCtor(call_stack);

return {
.program_length = hdr->header.opcnt,
.mapping_size = file_size,
.registers = {0, 0, 0, 0, 0},
.cmd = (int*)(bytes + HEADER_SIZE),
.value_stack = value_stack,
.call_stack = call_stack
};
}

int* array = (int*)calloc(length, sizeof(*array));

for (size_t i = 0; i < length; i++)
{
read_status = fscanf(program_file, "%d", array + i);
LOG_ASSERT(read_status == 1,
{
free(array);
return NULL;
});
}
*array_len = length;
return array;
void proc_dtor(proc_state* cpu)
{
int err = munmap((char*)cpu->cmd - HEADER_SIZE, cpu->mapping_size);
LOG_ASSERT_ERROR(err != -1, return,
"Invalid cpu instance", NULL);
StackDtor(cpu->value_stack);
StackDtor(cpu->call_stack);
free(cpu->value_stack);
free(cpu->call_stack);
}

static unsigned int get_operands(Stack* stack, size_t n_op, int* op1, int* op2);
static asm_arg next_parameter(const int* cmd_array, int* ip);

#define CMD (cpu->cmd)
#define STACK (cpu->value_stack)
#define CALL_STACK (cpu->call_stack)
#define IP (cpu->registers[REG_IP])
#define PUSH(value) StackPush(cpu->value_stack, (value))
#define POP StackPopCopy(cpu->value_stack, NULL)
#define NEXT_ARG next_parameter(CMD, &IP)
#define STOP return 0
#define ASSERT(cond, msg) LOG_ASSERT_ERROR(cond, return -1, msg, NULL)

int execute_command(const int* cmd_array, Stack* stack, size_t* shift)
int proc_run(proc_state *cpu)
{
#define BINARY_OP_CASE(command, operation) case command:\
err = get_operands(stack, 2, &op1, &op2);\
LOG_ASSERT(!err, return -1);\
err = StackPush(stack, op2 operation op1);\
LOG_ASSERT(!err, return -1);\

size_t iptr = 0;
int command = cmd_array[iptr++];
int op1 = 0, op2 = 0;
unsigned int err = 0;
switch (command)

#define ASM_CMD(name, num, args, code, ...)\
case num: code; break;

while (IP < cpu->program_length)
{
case CMD_NOP: break;

BINARY_OP_CASE(CMD_ADD, +) break;
BINARY_OP_CASE(CMD_SUB, -) break;
BINARY_OP_CASE(CMD_MUL, *) break;
BINARY_OP_CASE(CMD_DIV, /) break;

case CMD_INC:
err = get_operands(stack, 1, &op1, NULL);
LOG_ASSERT(!err, return -1);
err = StackPush(stack, op1 + 1);
LOG_ASSERT(!err, return -1);
break;
case CMD_DEC:
err = get_operands(stack, 1, &op1, NULL);
LOG_ASSERT(!err, return -1);
err = StackPush(stack, op1 - 1);
LOG_ASSERT(!err, return -1);
break;
case CMD_PUSH:
op1 = cmd_array[iptr++];
err = StackPush(stack, op1);
LOG_ASSERT(!err, return -1);
break;
case CMD_POP:
err = get_operands(stack, 1, &op1, NULL);
LOG_ASSERT(!err, return -1);
printf("%d\n", op1);
break;

case CMD_HALT:
return 1;
switch (CMD[IP])
{
#include "asm_cmd.h"

default:
LOG_ASSERT(0 && "Invalid command encountered", return -1);
break;
default:
LOG_ASSERT_ERROR(0, return -1,
"Failed to execute command at [%x]", IP);
break;
}

IP++;
StackDump(cpu->value_stack);
}
*shift = iptr;

StackDump(stack);
#undef ASM_CMD

return 0;

}

static unsigned int get_operands(Stack* stack, size_t n_op, int* op1, int* op2)
#undef CMD
#undef STACK
#undef CALL_STACK
#undef IP
#undef PUSH
#undef POP
#undef NEXT_ARG
#undef STOP
#undef ASSERT

static asm_arg next_parameter(const int* cmd_array, int* ip)
{
LOG_ASSERT(n_op == 1 || n_op == 2, return 1);

LOG_ASSERT(op1 != NULL, return 1);
unsigned int err = 0;
*op1 = StackPopCopy(stack, &err);
LOG_ASSERT(!err, return 1);
static int argument = 0;

if (n_op == 2)
{
LOG_ASSERT(op2 != NULL, return 1);
*op2 = StackPopCopy(stack, &err);
argument = cmd_array[++*ip];

LOG_ASSERT(!err, return 1);
}
return 0;
return {
.val_ptr = &argument,
.perms = ARG_RD
};
}

41 changes: 24 additions & 17 deletions src/vcpu/vcpu_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,30 @@

#include "int_stack.h"

/**
* @brief
* Allocate and read commands array from specified file
* @param[in] filename Name of program file
* @param[out] array_len Length of allocated array
* @return Allocated array
*/
int* read_cmd_array(const char* filename, size_t* array_len);
enum vcpu_reg
{
REG_IP = 0,
REG_RAX = 1,
REG_RBX = 2,
REG_RCX = 3,
REG_RDX = 4
};

/**
* @brief
* Read and execute command from commands array
* @param[in] cmd_array Commands array
* @param[inout] stack Program stack
* @param[out] shift Instruction pointer shift
* @return 0 upon success, -1 otherwise
*/
int execute_command(const int* cmd_array, Stack* stack, size_t* shift);
const int REG_COUNT = 5;

struct proc_state
{
size_t program_length;
size_t mapping_size;
int registers[REG_COUNT];
int* cmd;
Stack* value_stack;
Stack* call_stack;
};

proc_state proc_ctor(const char* program_file);
void proc_dtor(proc_state* cpu);

int proc_run(proc_state *cpu);

#endif

0 comments on commit 9e4447a

Please sign in to comment.