项目中设计的VM指令集说明
VM指令集:
1.Save & Load:IMM(immediate的缩写,加载立即数),LEA(load effective address),LC(load char), LI(load integer),SC(save char),SI(save integer),PUSH(将寄存器数据推到栈顶)
2.算数逻辑运算:ADD,SUB,MUL,DIV,MOD,OR,XOR,AND,SHL(左移),SHR(右移),IQ(相等),NE(不等),LT(less then),LE(less equal),GT(great then),GE(great equal)
3.分支跳转:JMP,JZ(jump zero),JNZ(jump not zero),CALL,NVAR(new stack frame for variable),DARG(delete stack frame for argument),RET(return)
4.Native-Call:OPEN(打开文件),CLOSE(关闭文件),READ(读取文件),(没有WRITE写文件,因为c4源码里面没有用到write方法,这这里并没有实现write指令),PRTF(printf,相当于实现了一个write,输出到了标准输出,也就是fd=1的地方),MACC,FREE,MSET,MCMP(MEM compare),EXIT(终止程序)
1.Save & Load
// load & save
if (op == IMM) ax = *pc++; //意思是解析完当前的代码PC指的是IMM
//pc会移动到IMM要操作的立即数的位置,然后*pc取出要操作的立即数给通用寄存器ax,然后pc++,继续往后移动pc,往后执行代码
else if (op == LEA) ax = (int)(bp + *pc++); //LEA的操作简化
//这里的LEA是自定义的与x86直接运算+8不同(对x86来说LEA AX,是说*(bp+8)->ax)
else if (op == LC) ax = *(char*)ax; // load char,ax中现在装的是一个地址,把地址对应的值移到ax中,下面的LI同理
else if (op == LI) ax = *(int*)ax; // load int
else if (op == SC) *(char*)*sp++ = ax; //sp里面存的是一个地址,然后(char*)将地址强制转换为char*类型,
//然后再对地址dereference(就是*),拿到地址所在的char的空间,把ax中的数据存入这个空间,然后sp++,当前的sp的位置就用完了,sp指针就向上移动,释放了原来sp的存储
else if (op == SI) *(int*)*sp++ = ax; // save int to stack
else if (op == PUSH) *--sp = ax; // push ax to stack,这里设计的是sp指向有数据的位置的栈顶指针,满栈的类型,所以要先--sp,再dereference sp的地址后,在对应位置存入ax
满栈(full stack):栈指针指向最后压入栈的数据,数据入栈时,sp先减一(或加一)再入栈。(也就是SP指的位置本身是有数据的)
空栈(empty stack):栈指针指向下一个将要放入数据的位置,数据入栈时,先入栈sp再减一(或加一)。(也就是SP指的位置本身是空的)
2.算数逻辑运算
// arithmetic
else if (op == OR) ax = *sp++ | ax; //逻辑运算
else if (op == XOR) ax = *sp++ ^ ax;
else if (op == AND) ax = *sp++ & ax;
else if (op == EQ) ax = *sp++ == ax; //逻辑判断,结果应该是true和false,但是这个版本没有bool类型,所以输出0或者1
else if (op == NE) ax = *sp++ != ax;
else if (op == LT) ax = *sp++ < ax;
else if (op == LE) ax = *sp++ <= ax;
else if (op == GT) ax = *sp++ > ax;
else if (op == GE) ax = *sp++ >= ax;
else if (op == SHL) ax = *sp++ << ax; //位运算
else if (op == SHR) ax = *sp++ >> ax;
else if (op == ADD) ax = *sp++ + ax; //算术运算
else if (op == SUB) ax = *sp++ - ax;
else if (op == MUL) ax = *sp++ * ax;
else if (op == DIV) ax = *sp++ / ax;
else if (op == MOD) ax = *sp++ % ax;
JMP:直接调到所给的地址的位置
JZ ax:判断 ax=0跳转,ax!=0不跳转
JNZ ax:判断 ax!=0跳转,ax=0不跳转
// jump
else if (op == JMP) pc = (int*)*pc; // jump
else if (op == JZ) pc = ax ? pc + 1 : (int*)*pc; // jump if ax == 0
else if (op == JNZ) pc = ax ? (int*)*pc : pc + 1; // jump if ax != 0