Adds COPY command.
This commit is contained in:
parent
8b84163c56
commit
e313356054
3 changed files with 133 additions and 4 deletions
|
@ -5,7 +5,17 @@
|
||||||
|
|
||||||
Instruction code[] =
|
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 },
|
// { VM_EXEC_X, VM_EXEC_X, VM_INPUT_ZERO, VM_INPUT_ZERO, VM_CMD_COPY, 0, VM_FLAG_NO, VM_OUTPUT_DISCARD, 0 },
|
||||||
|
{
|
||||||
|
VM_EXEC_X,
|
||||||
|
VM_EXEC_X,
|
||||||
|
VM_INPUT_ZERO,
|
||||||
|
VM_INPUT_ZERO,
|
||||||
|
VM_CMD_COPY,
|
||||||
|
0,
|
||||||
|
VM_FLAG_NO,
|
||||||
|
VM_OUTPUT_DISCARD,
|
||||||
|
1337 },
|
||||||
};
|
};
|
||||||
|
|
||||||
void dump_proc(Process *process)
|
void dump_proc(Process *process)
|
||||||
|
@ -32,7 +42,10 @@ int main(int argc, const char **argv)
|
||||||
Process process = { &module, 0, 0, 0, 0 };
|
Process process = { &module, 0, 0, 0, 0 };
|
||||||
Process *p = &process;
|
Process *p = &process;
|
||||||
|
|
||||||
|
vm_push(p, 10);
|
||||||
|
dump_proc(p);
|
||||||
int stillAlive = vm_step_process(p);
|
int stillAlive = vm_step_process(p);
|
||||||
|
dump_proc(p);
|
||||||
|
|
||||||
printf("Process %s.\n", (stillAlive ? "still running" : "terminated"));
|
printf("Process %s.\n", (stillAlive ? "still running" : "terminated"));
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,115 @@
|
||||||
#include "vm.h"
|
#include "vm.h"
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint32_t input0;
|
||||||
|
uint32_t input1;
|
||||||
|
uint32_t argument;
|
||||||
|
|
||||||
|
uint32_t output;
|
||||||
|
} CommandInfo;
|
||||||
|
|
||||||
|
static void cmd_copy(CommandInfo *info)
|
||||||
|
{
|
||||||
|
info->output = info->input0;
|
||||||
|
}
|
||||||
|
|
||||||
int vm_step_process(Process *process)
|
int vm_step_process(Process *process)
|
||||||
{
|
{
|
||||||
vm_assert(process != NULL, "process must not be NULL.");
|
vm_assert(process != NULL, "process must not be NULL.");
|
||||||
Instruction instr = process->module->code[process->codePointer];
|
Instruction instr = process->module->code[process->codePointer++];
|
||||||
|
|
||||||
return 0;
|
int exec = 1;
|
||||||
|
switch(instr.execZ)
|
||||||
|
{
|
||||||
|
case VM_EXEC_X:
|
||||||
|
/* Don't modify execution. */
|
||||||
|
break;
|
||||||
|
case VM_EXEC_0:
|
||||||
|
if((process->flags & VM_FLAG_Z) != 0)
|
||||||
|
exec = 0;
|
||||||
|
break;
|
||||||
|
case VM_EXEC_1:
|
||||||
|
if((process->flags & VM_FLAG_Z) == 0)
|
||||||
|
exec = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vm_assert(0, "Invalid instruction: execZ undefined.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(instr.execN)
|
||||||
|
{
|
||||||
|
case VM_EXEC_X:
|
||||||
|
/* Don't modify execution. */
|
||||||
|
break;
|
||||||
|
case VM_EXEC_0:
|
||||||
|
if((process->flags & VM_FLAG_N) != 0)
|
||||||
|
exec = 0;
|
||||||
|
break;
|
||||||
|
case VM_EXEC_1:
|
||||||
|
if((process->flags & VM_FLAG_N) == 0)
|
||||||
|
exec = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
vm_assert(0, "Invalid instruction: execN undefined.");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only do further instruction execution when
|
||||||
|
// the execution condition is met.
|
||||||
|
if(exec)
|
||||||
|
{
|
||||||
|
CommandInfo info;
|
||||||
|
switch(instr.input0)
|
||||||
|
{
|
||||||
|
case VM_INPUT_ZERO: info.input0 = 0; break;
|
||||||
|
case VM_INPUT_POP: info.input0 = vm_pop(process); break;
|
||||||
|
case VM_INPUT_PEEK: info.input0 = vm_peek(process); break;
|
||||||
|
case VM_INPUT_ARG: info.input0 = instr.argument; break;
|
||||||
|
default: vm_assert(0, "Invalid instruction: input0 undefined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(instr.input1)
|
||||||
|
{
|
||||||
|
case VM_INPUT_ZERO: info.input1 = 0; break;
|
||||||
|
case VM_INPUT_POP: info.input1 = vm_pop(process); break;
|
||||||
|
default: vm_assert(0, "Invalid instruction: input1 undefined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
info.argument = instr.argument;
|
||||||
|
|
||||||
|
switch(instr.command)
|
||||||
|
{
|
||||||
|
case VM_CMD_COPY: cmd_copy(&info); break;
|
||||||
|
default: vm_assert(0, "Invalid instruction: command undefined.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(instr.flags)
|
||||||
|
{
|
||||||
|
case VM_FLAG_YES:
|
||||||
|
process->flags = 0;
|
||||||
|
if(info.output == 0)
|
||||||
|
process->flags |= VM_FLAG_Z;
|
||||||
|
else if((info.output & (1<<31)) != 0)
|
||||||
|
process->flags |= VM_FLAG_N;
|
||||||
|
break;
|
||||||
|
case VM_FLAG_NO: break;
|
||||||
|
default:
|
||||||
|
vm_assert(0, "Invalid instruction: invalid flags.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(instr.output)
|
||||||
|
{
|
||||||
|
case VM_OUTPUT_DISCARD: break;
|
||||||
|
case VM_OUTPUT_PUSH: vm_push(process, info.output); break;
|
||||||
|
case VM_OUTPUT_JUMP: process->codePointer = info.output; break;
|
||||||
|
default:
|
||||||
|
vm_assert(0, "Invalid instruction: invalid output.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return process->codePointer < process->module->length;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_push(Process *process, uint32_t value)
|
void vm_push(Process *process, uint32_t value)
|
||||||
|
|
|
@ -50,12 +50,15 @@ extern "C" {
|
||||||
#define VM_MATH_SHR 14
|
#define VM_MATH_SHR 14
|
||||||
|
|
||||||
#define VM_FLAG_NO 0
|
#define VM_FLAG_NO 0
|
||||||
#define VM_FLAG_YES 0
|
#define VM_FLAG_YES 1
|
||||||
|
|
||||||
#define VM_OUTPUT_DISCARD 0
|
#define VM_OUTPUT_DISCARD 0
|
||||||
#define VM_OUTPUT_PUSH 1
|
#define VM_OUTPUT_PUSH 1
|
||||||
#define VM_OUTPUT_JUMP 2
|
#define VM_OUTPUT_JUMP 2
|
||||||
|
|
||||||
|
#define VM_FLAG_Z (1<<0)
|
||||||
|
#define VM_FLAG_N (1<<1)
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
unsigned int execZ : 2;
|
unsigned int execZ : 2;
|
||||||
|
@ -100,10 +103,19 @@ typedef struct
|
||||||
*/
|
*/
|
||||||
int vm_step_process(Process *process);
|
int vm_step_process(Process *process);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pushes a value onto the process' stack.
|
||||||
|
*/
|
||||||
void vm_push(Process *process, uint32_t value);
|
void vm_push(Process *process, uint32_t value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Pops a value from the process' stack.
|
||||||
|
*/
|
||||||
uint32_t vm_pop(Process *process);
|
uint32_t vm_pop(Process *process);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Returns the top value of the process' stack.
|
||||||
|
*/
|
||||||
uint32_t vm_peek(Process *process);
|
uint32_t vm_peek(Process *process);
|
||||||
|
|
||||||
void vm_assert(int assertion, const char *msg);
|
void vm_assert(int assertion, const char *msg);
|
||||||
|
|
Loading…
Reference in a new issue