VM1
Posted: Mon Nov 09, 2020 11:04 pm
I don't know if this is worth the effort. I switch between being excited about it, and just feeling tired.
After failing to implement Lox using cc65 (Lox is just too powerful (https://craftinginterpreters.com/the-lox-language.html)), I then borrowed some ideas from http://c-jump.com/CIS77/CPU/IsaDesign/lecture.html and started writing an interpreter.
I wanted something... well something upon which I could build a slow but useful scripting language.
BUT I didn't want Lua's opcodes. Why not?? Well I felt that perhaps it was not so well suited to the 6502. Fixed opcode length is not space friendly. Now I could just ADAPT the opcode set to be variable-length, to be friendlier to a 6502...
Well anyway, here are my opcodes to "VM1". They are of the form:
<OPCODE (3 bits)>. <register (2 bits)>. <modifier (3 bits)>
There are four general-purpose, 16 bit registers: A,B,C,D. I'd want to map those to four of the extended "registers" in the X16's zero page, but I'm not sure.
Some instructions have a two byte operand following it. For example, the jumps.
...I think I should probably have opcodes that load A, X, Y, and do a JSR...
#define OP_SPECIAL 0
#define OP_OR 1
#define OP_AND 2
#define OP_CMP 3
#define OP_SUB 4
#define OP_ADD 5
#define OP_LOD 6
#define OP_STO 7
#define REG_A 0 // LOD into these
#define REG_B 1
#define REG_C 2
#define REG_D 3
#define MEM_A 0 // STO into these
#define MEM_B 1
#define MEM_C 2
#define MEM_D 3
#define MEM_BIND 4
#define MEM_BOFFSIND 5
#define MEM_OFFSIND 6
#define MEM_CONSTANT 7
#define SPECIAL_ZOP 0 // 000 Opcodes
#define SPECIAL_JMP 1
#define SPECIAL_NOT 2
#define SPECIAL_ILLEGAL 3
#define ZOP_ILLEGAL0 0 // Zero Operand Instructions
#define ZOP_ILLEGAL1 1
#define ZOP_ILLEGAL2 2
#define ZOP_HCF 3 // Halt, Catch Fire
#define ZOP_ILLEGAL4 4
#define ZOP_ILLEGAL5 5
#define ZOP_ILLEGAL6 6
#define ZOP_PUTSTR 7 // prints string referenced from A (null terminated)
#define JEQ 0 // Special Jumps
#define JNE 1
#define JLT 2
#define JLE 3
#define JGT 4
#define JGE 5
#define JMP 6
#define JUMP_ILLEGAL 7
My interpreter loop is mostly just a big ol' switch statement.
... for loop ... *ip gets us the current operator... and the operand, if any ...
switch(ot.op)
{
case OP_OR: printf("or\n"); r[ot.reg] |= val; break;
case OP_AND: printf("and\n"); r[ot.reg] &= val; break;
case OP_CMP: printf("cmp\n"); cmp_flag = (r[ot.reg] < val)? -1 : (r[ot.reg] > val); break;
case OP_SUB: printf("sub\n"); r[ot.reg] -= val; break;
case OP_ADD: printf("add\n"); r[ot.reg] += val; break;
...etc...