Adds push/pop/peek to VM. Corrects some mistakes in the instructions.
This commit is contained in:
parent
29bea1a335
commit
8b84163c56
4 changed files with 88 additions and 3 deletions
|
@ -17,6 +17,7 @@ control stack access or control flow.
|
||||||
|----------|---------------|-------------------------------------------------|
|
|----------|---------------|-------------------------------------------------|
|
||||||
| SP | Stack Pointer | Stores the current 'top' position of the stack. |
|
| SP | Stack Pointer | Stores the current 'top' position of the stack. |
|
||||||
| BP | Base Pointer | Stores the current stack frame position. |
|
| BP | Base Pointer | Stores the current stack frame position. |
|
||||||
|
| CP | Code Pointer | Stores the instruction which is executed next. |
|
||||||
| FG | Flag Register | Stores the state of the flags. |
|
| FG | Flag Register | Stores the state of the flags. |
|
||||||
|
|
||||||
### Stack Pointer
|
### Stack Pointer
|
||||||
|
|
|
@ -3,10 +3,38 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
Instruction code[] =
|
||||||
|
{
|
||||||
|
{ VM_EXEC_X, VM_EXEC_X, VM_INPUT_ZERO, VM_INPUT_ZERO, VM_CMD_COPY, 0, VM_FLAG_NO, VM_OUTPUT_DISCARD, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
void dump_proc(Process *process)
|
||||||
|
{
|
||||||
|
printf("[ ");
|
||||||
|
for(int i = 1; i <= process->stackPointer; i++) {
|
||||||
|
printf("%d ", process->stack[i]);
|
||||||
|
}
|
||||||
|
printf("]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_assert(int assertion, const char *msg)
|
||||||
|
{
|
||||||
|
if(assertion != 0)
|
||||||
|
return;
|
||||||
|
printf("Assertion failed: %s\n", msg);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, const char **argv)
|
int main(int argc, const char **argv)
|
||||||
{
|
{
|
||||||
|
Module module = { code, 1 };
|
||||||
|
|
||||||
|
Process process = { &module, 0, 0, 0, 0 };
|
||||||
|
Process *p = &process;
|
||||||
|
|
||||||
|
int stillAlive = vm_step_process(p);
|
||||||
|
|
||||||
|
printf("Process %s.\n", (stillAlive ? "still running" : "terminated"));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -1 +1,34 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
int vm_step_process(Process *process)
|
||||||
|
{
|
||||||
|
vm_assert(process != NULL, "process must not be NULL.");
|
||||||
|
Instruction instr = process->module->code[process->codePointer];
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_push(Process *process, uint32_t value)
|
||||||
|
{
|
||||||
|
vm_assert(process != NULL, "process must not be NULL.");
|
||||||
|
vm_assert(process->stackPointer < VM_STACKSIZE, "Stack overflow");
|
||||||
|
process->stack[++process->stackPointer] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vm_pop(Process *process)
|
||||||
|
{
|
||||||
|
vm_assert(process != NULL, "process must not be NULL.");
|
||||||
|
uint32_t psp = process->stackPointer;
|
||||||
|
uint32_t val = process->stack[process->stackPointer--];
|
||||||
|
|
||||||
|
// Underflow check works because unsigned overflow is defined ;)
|
||||||
|
vm_assert(psp >= process->stackPointer, "Stack underflow");
|
||||||
|
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t vm_peek(Process *process)
|
||||||
|
{
|
||||||
|
vm_assert(process != NULL, "process must not be NULL.");
|
||||||
|
return process->stack[process->stackPointer];
|
||||||
|
}
|
||||||
|
|
|
@ -72,8 +72,16 @@ typedef struct
|
||||||
_Static_assert(sizeof(Instruction) == 8, "Instruction must be 8 bytes large.");
|
_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.");
|
_Static_assert(offsetof(Instruction, argument) == 4, "Argument must be must be 8 bytes large.");
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
Instruction *code;
|
||||||
|
uint32_t length;
|
||||||
|
} Module;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
|
Module *module;
|
||||||
|
|
||||||
uint32_t codePointer;
|
uint32_t codePointer;
|
||||||
uint32_t stackPointer;
|
uint32_t stackPointer;
|
||||||
uint32_t basePointer;
|
uint32_t basePointer;
|
||||||
|
@ -82,8 +90,23 @@ typedef struct
|
||||||
uint32_t stack[VM_STACKSIZE];
|
uint32_t stack[VM_STACKSIZE];
|
||||||
} Process;
|
} Process;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @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);
|
||||||
|
|
||||||
|
void vm_push(Process *process, uint32_t value);
|
||||||
|
|
||||||
|
uint32_t vm_pop(Process *process);
|
||||||
|
|
||||||
|
uint32_t vm_peek(Process *process);
|
||||||
|
|
||||||
|
void vm_assert(int assertion, const char *msg);
|
||||||
|
|
||||||
#if defined(__cplusplus)
|
#if defined(__cplusplus)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue