在上篇设计了一个极简单的CPU,并定义了相应的寄存器和指令集。接下来就是利用定义的寄存器和指令集完成一个程序,最后实现一个虚拟机来运行这个程序。
这个程序由汇编语言编写,并且手工编译成机器码。为了简单起见,设定CPU的寻址范围为64字节。程序代码为:
CODE:
04 12 I_JMP 12 //直接跳转到内存12的地址
DATA:
00 00 01 00 07 0F 08 07 00 00 00 00 00 00 00 00 //03-11为数据区
CODE:
02 03 04 I_ADD 03 04 //将03和04地址内容相加,结果送入03地址
02 05 06 I_ADD 05 06 //将05和06地址内容相加,结果送入05地址
03 03 07 I_CMP 03 07 //比较03和07地址内容
05 1E 20 I_JCP 1E 20 //根据寄存器R_CMP的值决定跳转到1E或20地址
04 23 I_JMP 23 //直接跳转到23地址
01 03 02 I_MOV 03 02 //把02地址内容送至03地址
03 05 07 I_CMP 05 07 //比较05和07地址内容
05 29 2B I_JCP 29 2B //根据寄存器R_CMP的值决定跳转到29或2B地址
04 2E I_JMP 2E //直接跳转到2E地址
01 05 02 I_MOV 05 02 //把02地址内容送至05地址
04 12 I_JMP 12 //直接跳转到内存12的地址
接着用任意16进制编辑器将机器码和数据输入,然后另存为一个文件,这里另存为rom.bin。如下图:
最后,需要将程序载入内存,为虚拟机运行程序做准备,对应代码为:
#define MEMSIZE 64 unsigned char* RAM; int loadROM(void); int memInit(void); void memFree(void); int loadROM(void) { FILE* rom; if ((rom = fopen("rom.bin", "r")) == NULL) { MessageBox(NULL, "Cannot find rom file", "Warning", MB_OK); return 1; } fread((void*)RAM, sizeof(char), MEMSIZE, rom); fclose(rom); return 0; } int memInit(void) { RAM = (unsigned char*)GlobalAlloc(GMEM_FIXED,MEMSIZE); if (RAM == NULL) { MessageBox(NULL, "Cannot allocate enough memory", "Error", MB_OK); return 1; } return 0; } void memFree(void) { GlobalFree(RAM); }
当然,也可以用int数组来保存这段程序,但这里只是希望看起来更像是真正的外部程序。