Files
VMBL/src/vmbl.c

252 lines
6.1 KiB
C
Raw Normal View History

2025-12-19 18:31:41 +11:00
#include "vmbl.h"
#include <stdio.h>
2025-12-20 13:29:49 +11:00
#include <stdlib.h>
#include <string.h>
2025-12-19 18:31:41 +11:00
VMBL_Exception VBML_ExecuteInstruction(VMBL_State *vmblState, VMBL_Instruction instruction) {
switch (instruction.type)
{
case INSTRUCTION_PUSH:
if (vmblState->stackSize >= VMBL_STACK_SIZE) {
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
}
2025-12-20 16:55:40 +11:00
vmblState->stack[vmblState->stackSize++] = instruction.opperands[0];
2025-12-19 18:31:41 +11:00
break;
case INSTRUCTION_ADD:
if (vmblState->stackSize < 2) {
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
vmblState->stack[vmblState->stackSize - 2] += vmblState->stack[vmblState->stackSize - 1];
vmblState->stackSize--;
break;
2025-12-20 16:55:40 +11:00
case INSTRUCTION_SUB:
if (vmblState->stackSize < 2) {
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
vmblState->stack[vmblState->stackSize - 2] -= vmblState->stack[vmblState->stackSize - 1];
vmblState->stackSize--;
break;
case INSTRUCTION_MUL:
if (vmblState->stackSize < 2) {
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
vmblState->stack[vmblState->stackSize - 2] *= vmblState->stack[vmblState->stackSize - 1];
vmblState->stackSize--;
break;
case INSTRUCTION_DIV:
if (vmblState->stackSize < 2) {
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
vmblState->stack[vmblState->stackSize - 2] /= vmblState->stack[vmblState->stackSize - 1];
vmblState->stackSize--;
break;
2025-12-19 18:31:41 +11:00
2025-12-20 13:29:49 +11:00
case INSTRUCTION_DUPLICATE:
2025-12-20 16:55:40 +11:00
if (vmblState->stackSize - instruction.opperands[0] <= 0) {
2025-12-20 13:29:49 +11:00
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
2025-12-19 18:31:41 +11:00
2025-12-20 13:29:49 +11:00
if (vmblState->stackSize >= VMBL_STACK_SIZE) {
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
}
2025-12-20 16:55:40 +11:00
if (instruction.opperands[0] < 0) {
2025-12-20 13:29:49 +11:00
return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND };
}
2025-12-20 16:55:40 +11:00
vmblState->stack[vmblState->stackSize++] = vmblState->stack[vmblState->stackSize - 1 - instruction.opperands[0]];
2025-12-20 13:29:49 +11:00
break;
case INSTRUCTION_JUMP:
2025-12-20 16:55:40 +11:00
vmblState->ip = instruction.opperands[0];
2025-12-20 13:29:49 +11:00
break;
case INSTRUCTION_HALT:
vmblState->halted = true;
break;
2025-12-20 16:55:40 +11:00
case INSTRUCTION_EQUAL:
if (instruction.opperands[0] < 0 || instruction.opperands[1] < 0) {
return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND };
}
if (vmblState->stackSize >= VMBL_STACK_SIZE || instruction.opperands[0] > VMBL_STACK_SIZE || instruction.opperands[1] > VMBL_STACK_SIZE) {
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
}
vmblState->stack[vmblState->stackSize] = vmblState->stack[vmblState->stackSize-instruction.opperands[0]] == vmblState->stack[vmblState->stackSize-instruction.opperands[1]];
break;
case INSTRUCTION_EQUAL_TOP:
if (vmblState->stackSize >= VMBL_STACK_SIZE) {
return (VMBL_Exception){ EXCEPTION_STACK_OVERFLOW };
}
vmblState->stack[vmblState->stackSize++] = vmblState->stack[vmblState->stackSize-1] == vmblState->stack[vmblState->stackSize-2];
break;
case INSTRUCTION_JUMP_CONDITIONAL:
if (instruction.opperands[0] < 0) {
return (VMBL_Exception) { EXCEPTION_INVALID_OPPERAND };
}
if (vmblState->stack[vmblState->stackSize--]) {
vmblState->ip = instruction.opperands[0];
}
break;
case INSTRUCTION_POP:
if (vmblState->stackSize <= 0) {
return (VMBL_Exception){ EXCEPTION_STACK_UNDERFLOW };
}
vmblState->stackSize--;
break;
2025-12-20 13:29:49 +11:00
default:
2025-12-19 18:31:41 +11:00
return (VMBL_Exception) { EXCEPTION_INVALID_OPCODE };
break;
}
return (VMBL_Exception) { EXCEPTION_NONE };
}
void VMBL_Dump(VMBL_State vmblState, VMBL_Exception exception) {
fprintf(stderr, "EXCEPTION: %s\n\n", exceptionAsCString(exception));
fprintf(stderr, "Stack:\n");
if (vmblState.stackSize > 0) {
for (size_t i = 0; i < vmblState.stackSize; i++) {
2025-12-20 16:55:40 +11:00
fprintf(stderr, " 0x%lX: %ld\n", i, vmblState.stack[i]);
2025-12-19 18:31:41 +11:00
}
} else {
fprintf(stderr, " [empty]\n");
}
2025-12-20 13:29:49 +11:00
}
void VMBL_StartVM(VMBL_State *vmblState) {
for (;;)
{
// fetch next instruction
if (vmblState->ip >= VMBL_PROGRAM_SIZE) {
VMBL_Dump(*vmblState, (VMBL_Exception){ EXCEPTION_INVALID_INSTRUCTION_ACCESS});
return;
}
VMBL_Instruction instruction = vmblState->program[vmblState->ip++];
2025-12-20 16:55:40 +11:00
//printf("%s 0x%lx, 0x%lx, 0x%lx\n", instructionTypeToCStr(instruction.type), instruction.opperands[0], instruction.opperands[1], instruction.opperands[2]);
2025-12-20 13:29:49 +11:00
VMBL_Exception exception = VBML_ExecuteInstruction(vmblState, instruction);
if (exception.type != EXCEPTION_NONE) {
2025-12-20 16:55:40 +11:00
//VMBL_Dump(*vmblState, exception);
2025-12-20 13:29:49 +11:00
return;
}
if (vmblState->halted) {
return;
}
}
}
// executable operations
void VMBL_LoadExecutable(VMBL_State *vmblState, VMBL_Instruction *program, size_t programSize) {
if (programSize > VMBL_PROGRAM_SIZE) {
fprintf(stderr, "VMBL: failed to load program from memory because it is %ld words in size, while the max size is %d.", programSize, VMBL_PROGRAM_SIZE);
exit(1);
}
2025-12-20 16:55:40 +11:00
memcpy(&vmblState->program, program, sizeof(program) * programSize);
2025-12-20 13:29:49 +11:00
vmblState->programSize = programSize;
}
void VMBL_LoadExecutableFromFile(VMBL_State *vmblState, const char* filePath) {
FILE *file = fopen(filePath, "rb");
if (file == NULL) {
perror("VMBL: Failed to open file");
exit(1);
}
fseek(file, 0, SEEK_END);
long size = ftell(file);
rewind(file);
size_t programSize = size / sizeof(vmblState->program[0]);
VMBL_Instruction program[programSize];
fread(program, sizeof(program[0]), programSize, file);
VMBL_LoadExecutable(vmblState, program, programSize);
fclose(file);
}
void VMBL_SaveExecutable(const char* filePath, VMBL_Instruction *program, size_t programSize) {
FILE *file = fopen(filePath, "wb");
if (file == NULL) {
perror("VMBL: Failed to open file");
exit(1);
}
2025-12-20 16:55:40 +11:00
fwrite(program, sizeof(program), programSize, file);
2025-12-20 13:29:49 +11:00
fclose(file);
}
char *instructionTypeToCStr(InstructionType type) {
switch (type)
{
case INSTRUCTION_PUSH:
return "PUSH";
break;
case INSTRUCTION_ADD:
return "ADD ";
break;
case INSTRUCTION_DUPLICATE:
return "DUP ";
break;
case INSTRUCTION_JUMP:
return "JMP ";
break;
case INSTRUCTION_HALT:
return "HALT";
break;
2025-12-20 16:55:40 +11:00
case INSTRUCTION_EQUAL:
return "EQ ";
break;
case INSTRUCTION_EQUAL_TOP:
return "EQT ";
break;
case INSTRUCTION_JUMP_CONDITIONAL:
return "JC ";
break;
2025-12-20 13:29:49 +11:00
default:
return "??? ";
break;
}
2025-12-19 18:31:41 +11:00
}