Minor refactor and started to add opcode/XOPs
This commit is contained in:
parent
d4690a2575
commit
eff07ba783
207
vm.c
207
vm.c
|
@ -1,50 +1,5 @@
|
||||||
#include <stdio.h>
|
#include "vm.h"
|
||||||
#include <stdlib.h>
|
#define DEBUG true;
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
/* Virtual machine state */
|
|
||||||
struct lilith
|
|
||||||
{
|
|
||||||
uint64_t *memory;
|
|
||||||
uint64_t reg[16];
|
|
||||||
uint64_t ip;
|
|
||||||
bool halted;
|
|
||||||
bool exception;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Instruction
|
|
||||||
{
|
|
||||||
uint64_t ip;
|
|
||||||
uint8_t opcode;
|
|
||||||
uint32_t XOP;
|
|
||||||
uint32_t Immediate;
|
|
||||||
uint32_t HAL_CODE;
|
|
||||||
uint8_t reg0;
|
|
||||||
uint8_t reg1;
|
|
||||||
uint8_t reg2;
|
|
||||||
uint8_t reg3;
|
|
||||||
bool invalid;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Allocate and intialize memory/state */
|
|
||||||
struct lilith* create_vm(size_t size)
|
|
||||||
{
|
|
||||||
struct lilith* vm;
|
|
||||||
vm = calloc(1, sizeof(struct lilith));
|
|
||||||
vm->memory = calloc(size, sizeof(uint8_t));
|
|
||||||
vm->halted = false;
|
|
||||||
vm->exception = false;
|
|
||||||
return vm;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free up the memory we previously allocated */
|
|
||||||
void destroy_vm(struct lilith* vm)
|
|
||||||
{
|
|
||||||
free(vm->memory);
|
|
||||||
free(vm);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load program tape into Memory */
|
/* Load program tape into Memory */
|
||||||
void load_program(struct lilith* vm, char **argv)
|
void load_program(struct lilith* vm, char **argv)
|
||||||
|
@ -63,107 +18,140 @@ void load_program(struct lilith* vm, char **argv)
|
||||||
fclose(program);
|
fclose(program);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Load instruction addressed at IP */
|
||||||
void read_instruction(struct lilith* vm, struct Instruction *current)
|
void read_instruction(struct lilith* vm, struct Instruction *current)
|
||||||
{
|
{
|
||||||
memset(current, 0, sizeof(struct Instruction));
|
memset(current, 0, sizeof(struct Instruction));
|
||||||
uint8_t opcode, segment1, segment2, segment3;
|
|
||||||
|
|
||||||
/* Store IP for debugging */
|
/* Store IP for debugging */
|
||||||
current->ip = vm->ip;
|
current->ip = vm->ip;
|
||||||
|
|
||||||
/* Read the actual bytes and increment the IP */
|
/* Read the actual bytes and increment the IP */
|
||||||
opcode = vm->memory[vm->ip];
|
current->raw0 = (uint8_t)vm->memory[vm->ip];
|
||||||
vm->ip = vm->ip + 1;
|
vm->ip = vm->ip + 1;
|
||||||
segment1 = vm->memory[vm->ip];
|
current->raw1 = (uint8_t)vm->memory[vm->ip];
|
||||||
vm->ip = vm->ip + 1;
|
vm->ip = vm->ip + 1;
|
||||||
segment2 = vm->memory[vm->ip];
|
current->raw2 = (uint8_t)vm->memory[vm->ip];
|
||||||
vm->ip = vm->ip + 1;
|
vm->ip = vm->ip + 1;
|
||||||
segment3 = vm->memory[vm->ip];
|
current->raw3 = (uint8_t)vm->memory[vm->ip];
|
||||||
vm->ip = vm->ip + 1;
|
vm->ip = vm->ip + 1;
|
||||||
|
unpack_instruction(current);
|
||||||
|
}
|
||||||
|
|
||||||
/* The first byte is always the master opcode */
|
/* Process 4OP Integer instructions */
|
||||||
current->opcode = opcode;
|
bool eval_4OP_Int(struct lilith* vm, struct Instruction* c)
|
||||||
current->invalid = false;
|
{
|
||||||
current->XOP = 0xFFFF;
|
return true;
|
||||||
current->Immediate = 0xFFFF;
|
}
|
||||||
current->HAL_CODE = 0xFFFF;
|
|
||||||
current->reg0 = 0xFF;
|
|
||||||
current->reg1 = 0xFF;
|
|
||||||
current->reg2 = 0xFF;
|
|
||||||
current->reg3 = 0xFF;
|
|
||||||
|
|
||||||
/* Extract the fields from the instruction for easier evaluation */
|
/* Process 3OP Integer instructions */
|
||||||
switch(opcode)
|
bool eval_3OP_Int(struct lilith* vm, struct Instruction* c)
|
||||||
|
{
|
||||||
|
switch(c->raw_XOP)
|
||||||
|
{
|
||||||
|
case 0x000: /* ADD */
|
||||||
|
{
|
||||||
|
vm->reg[c->reg0] = vm->reg[c->reg1] + vm->reg[c->reg2];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process 2OP Integer instructions */
|
||||||
|
bool eval_2OP_Int(struct lilith* vm, struct Instruction* c)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process 1OP Integer instructions */
|
||||||
|
bool eval_1OP_Int(struct lilith* vm, struct Instruction* c)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Process 2OPI Integer instructions */
|
||||||
|
bool eval_2OPI_Int(struct lilith* vm, struct Instruction* c)
|
||||||
|
{
|
||||||
|
/* 0x0E ... 0x2B */
|
||||||
|
switch(c->raw0)
|
||||||
|
{
|
||||||
|
case 0x0E: /* ADDI */
|
||||||
|
{
|
||||||
|
vm->reg[c->reg0] = (int8_t)(vm->reg[c->reg1] + c->raw_Immediate);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0F: /* ADDUI */
|
||||||
|
{
|
||||||
|
vm->reg[c->reg0] = vm->reg[c->reg1] + c->raw_Immediate; break;
|
||||||
|
}
|
||||||
|
default: return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Use Opcode to decide what to do and then have it done */
|
||||||
|
void eval_instruction(struct lilith* vm, struct Instruction* current)
|
||||||
|
{
|
||||||
|
bool invalid = false;
|
||||||
|
|
||||||
|
switch(current->raw0)
|
||||||
{
|
{
|
||||||
case 0x00: /* Deal with NOPs */
|
case 0x00: /* Deal with NOPs */
|
||||||
{
|
{
|
||||||
|
vm->halted = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 0x01:
|
||||||
|
{
|
||||||
|
decode_4OP(current);
|
||||||
|
invalid = eval_4OP_Int(vm, current);
|
||||||
|
if ( invalid) goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x01 ... 0x04: /* Deal with 4OP */
|
case 0x05:
|
||||||
{
|
{
|
||||||
current->XOP = segment1;
|
decode_3OP(current);
|
||||||
current->Immediate = 0;
|
invalid = eval_3OP_Int(vm, current);
|
||||||
current->reg0 = segment2/16;
|
if ( invalid) goto fail;
|
||||||
current->reg1 = segment2%16;
|
|
||||||
current->reg2 = segment3/16;
|
|
||||||
current->reg3 = segment3%16;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x05 ... 0x08: /* Deal with 3OP */
|
case 0x09:
|
||||||
{
|
{
|
||||||
current->XOP = segment1*16 + segment2/16;
|
decode_2OP(current);
|
||||||
current->Immediate = 0;
|
invalid = eval_2OP_Int(vm, current);
|
||||||
current->reg0 = segment2%16;
|
if ( invalid) goto fail;
|
||||||
current->reg1 = segment3/16;
|
|
||||||
current->reg2 = segment3%16;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x09 ... 0x0C: /* Deal with 2OP */
|
case 0x0D:
|
||||||
{
|
{
|
||||||
current->XOP = segment1*256 + segment2;
|
decode_1OP(current);
|
||||||
current->Immediate = 0;
|
invalid = eval_1OP_Int(vm, current);
|
||||||
current->reg0 = segment3/16;
|
if ( invalid) goto fail;
|
||||||
current->reg1 = segment3%16;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0D: /* Deal with 1OP */
|
case 0x0E ... 0x2B:
|
||||||
{
|
{
|
||||||
current->XOP = segment1*4096 + segment2*16 + segment3/16;
|
decode_2OPI(current);
|
||||||
current->Immediate = 0;
|
invalid = eval_2OPI_Int(vm, current);
|
||||||
current->reg0 = segment3%16;
|
if ( invalid) goto fail;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 0x0E ... 0x2B: /* Deal with 2OPI */
|
case 0x2C:
|
||||||
{
|
{
|
||||||
current->XOP = 0;
|
|
||||||
current->Immediate = segment2*256 + segment3;
|
|
||||||
current->reg0 = segment1/16;
|
|
||||||
current->reg1 = segment1%16;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 0x2C ... 0x3B: /* Deal with 1OPI */
|
case 0x3C:
|
||||||
{
|
{
|
||||||
current->XOP = 0;
|
|
||||||
current->Immediate = (segment1%16)*4096 + segment2*256 + segment3;
|
|
||||||
current->HAL_CODE = 0;
|
|
||||||
current->reg0 = segment1/16;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 0x3C: /* Deal with 0OPI */
|
case 0x42:
|
||||||
{
|
{
|
||||||
current->XOP = 0;
|
|
||||||
current->Immediate = segment1*4096 + segment2*256 + segment3;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 0x42: /* Deal with Halcode */
|
|
||||||
{
|
|
||||||
current->XOP = 0;
|
|
||||||
current->HAL_CODE = segment1*4096 + segment2*256 + segment3;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
case 0xFF: /* Deal with illegal instruction */
|
case 0xFF: /* Deal with illegal instruction */
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
|
fail:
|
||||||
|
fprintf(stderr, "Unable to execute the following instruction:\n%c %c %c %c\n", current->raw0, current->raw1, current->raw2, current->raw3);
|
||||||
|
fprintf(stderr, "%s\n", current->operation);
|
||||||
current->invalid = true;
|
current->invalid = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -178,6 +166,7 @@ void execute_vm(struct lilith* vm)
|
||||||
while(!vm->halted)
|
while(!vm->halted)
|
||||||
{
|
{
|
||||||
read_instruction(vm, current);
|
read_instruction(vm, current);
|
||||||
|
eval_instruction(vm, current);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(current);
|
free(current);
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Virtual machine state */
|
||||||
|
struct lilith
|
||||||
|
{
|
||||||
|
uint8_t *memory;
|
||||||
|
uint64_t reg[16];
|
||||||
|
uint64_t ip;
|
||||||
|
bool halted;
|
||||||
|
bool exception;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Unpacked instruction */
|
||||||
|
struct Instruction
|
||||||
|
{
|
||||||
|
uint64_t ip;
|
||||||
|
uint8_t raw0, raw1, raw2, raw3;
|
||||||
|
char opcode[3];
|
||||||
|
uint32_t raw_XOP;
|
||||||
|
char XOP[6];
|
||||||
|
char operation[9];
|
||||||
|
uint32_t raw_Immediate;
|
||||||
|
char Immediate[7];
|
||||||
|
uint32_t HAL_CODE;
|
||||||
|
uint8_t reg0;
|
||||||
|
uint8_t reg1;
|
||||||
|
uint8_t reg2;
|
||||||
|
uint8_t reg3;
|
||||||
|
bool invalid;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Condition Codes */
|
||||||
|
enum condition
|
||||||
|
{
|
||||||
|
Carry = 1 << 5,
|
||||||
|
Borrow = 1 << 4,
|
||||||
|
Overflow = 1 << 3,
|
||||||
|
GreaterThan = 1 << 2,
|
||||||
|
EQual = 1 << 1,
|
||||||
|
LessThan = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Allocate and intialize memory/state */
|
||||||
|
struct lilith* create_vm(size_t size)
|
||||||
|
{
|
||||||
|
struct lilith* vm;
|
||||||
|
vm = calloc(1, sizeof(struct lilith));
|
||||||
|
vm->memory = calloc(size, sizeof(uint8_t));
|
||||||
|
vm->halted = false;
|
||||||
|
vm->exception = false;
|
||||||
|
return vm;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free up the memory we previously allocated */
|
||||||
|
void destroy_vm(struct lilith* vm)
|
||||||
|
{
|
||||||
|
free(vm->memory);
|
||||||
|
free(vm);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 4OP */
|
||||||
|
void decode_4OP(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_XOP = c->raw1;
|
||||||
|
c->XOP[0] = c->operation[2];
|
||||||
|
c->XOP[1] = c->operation[3];
|
||||||
|
c->raw_Immediate = 0;
|
||||||
|
c->reg0 = c->raw2/16;
|
||||||
|
c->reg1 = c->raw2%16;
|
||||||
|
c->reg2 = c->raw3/16;
|
||||||
|
c->reg3 = c->raw3%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 3OP */
|
||||||
|
void decode_3OP(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_XOP = c->raw1*16 + c->raw2/16;
|
||||||
|
c->XOP[0] = c->operation[2];
|
||||||
|
c->XOP[1] = c->operation[3];
|
||||||
|
c->XOP[2] = c->operation[4];
|
||||||
|
c->raw_Immediate = 0;
|
||||||
|
c->reg0 = c->raw2%16;
|
||||||
|
c->reg1 = c->raw3/16;
|
||||||
|
c->reg2 = c->raw3%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 2OP */
|
||||||
|
void decode_2OP(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_XOP = c->raw1*256 + c->raw2;
|
||||||
|
c->XOP[0] = c->operation[2];
|
||||||
|
c->XOP[1] = c->operation[3];
|
||||||
|
c->XOP[2] = c->operation[4];
|
||||||
|
c->XOP[3] = c->operation[5];
|
||||||
|
c->raw_Immediate = 0;
|
||||||
|
c->reg0 = c->raw3/16;
|
||||||
|
c->reg1 = c->raw3%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 1OP */
|
||||||
|
void decode_1OP(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_XOP = c->raw1*4096 + c->raw2*16 + c->raw3/16;
|
||||||
|
c->XOP[0] = c->operation[2];
|
||||||
|
c->XOP[1] = c->operation[3];
|
||||||
|
c->XOP[2] = c->operation[4];
|
||||||
|
c->XOP[3] = c->operation[5];
|
||||||
|
c->XOP[4] = c->operation[6];
|
||||||
|
c->raw_Immediate = 0;
|
||||||
|
c->reg0 = c->raw3%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 2OPI */
|
||||||
|
void decode_2OPI(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_Immediate = c->raw2*256 + c->raw3;
|
||||||
|
c->Immediate[0] = c->operation[4];
|
||||||
|
c->Immediate[1] = c->operation[5];
|
||||||
|
c->Immediate[2] = c->operation[6];
|
||||||
|
c->Immediate[3] = c->operation[7];
|
||||||
|
c->reg0 = c->raw1/16;
|
||||||
|
c->reg1 = c->raw1%16;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with 1OPI */
|
||||||
|
void decode_1OPI(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_Immediate = (c->raw1%16)*4096 + c->raw2*256 + c->raw3;
|
||||||
|
c->Immediate[0] = c->operation[3];
|
||||||
|
c->Immediate[1] = c->operation[4];
|
||||||
|
c->Immediate[2] = c->operation[5];
|
||||||
|
c->Immediate[3] = c->operation[6];
|
||||||
|
c->Immediate[4] = c->operation[7];
|
||||||
|
c->HAL_CODE = 0;
|
||||||
|
c->reg0 = c->raw1/16;
|
||||||
|
}
|
||||||
|
/* Deal with 0OPI */
|
||||||
|
void decode_0OPI(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->raw_Immediate = c->raw1*4096 + c->raw2*256 + c->raw3;
|
||||||
|
c->Immediate[0] = c->operation[2];
|
||||||
|
c->Immediate[1] = c->operation[3];
|
||||||
|
c->Immediate[2] = c->operation[4];
|
||||||
|
c->Immediate[3] = c->operation[5];
|
||||||
|
c->Immediate[4] = c->operation[6];
|
||||||
|
c->Immediate[5] = c->operation[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Deal with Halcode */
|
||||||
|
void decode_HALCODE(struct Instruction* c)
|
||||||
|
{
|
||||||
|
c->HAL_CODE = c->raw1*4096 + c->raw2*256 + c->raw3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Useful unpacking functions */
|
||||||
|
void unpack_byte(uint8_t a, char* c)
|
||||||
|
{
|
||||||
|
char table[16] = {0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46};
|
||||||
|
c[0] = table[a / 16];
|
||||||
|
c[1] = table[a % 16];
|
||||||
|
}
|
||||||
|
|
||||||
|
void unpack_instruction(struct Instruction* c)
|
||||||
|
{
|
||||||
|
unpack_byte(c->raw0, &(c->operation[0]));
|
||||||
|
unpack_byte(c->raw1, &(c->operation[2]));
|
||||||
|
unpack_byte(c->raw2, &(c->operation[4]));
|
||||||
|
unpack_byte(c->raw3, &(c->operation[6]));
|
||||||
|
c->opcode[0] = c->operation[0];
|
||||||
|
c->opcode[1] = c->operation[1];
|
||||||
|
}
|
Loading…
Reference in New Issue