-
Notifications
You must be signed in to change notification settings - Fork 107
hackCpuVm
ccckmit edited this page Feb 24, 2019
·
1 revision
#include <stdio.h>
#include <assert.h>
#include <stdint.h>
int imTop = 0;
int16_t im[32768], m[65536];
#define BIT0 0x0001
#define BIT1 0x0002
#define BIT2 0x0004
int run(uint16_t *im, int16_t *m) {
int16_t D = 0, A = 0, PC = 0;
uint16_t I = 0;
uint16_t a, c, d, j;
while (1) {
int16_t aluOut = 0, AM = 0;
if (PC >= imTop) {
printf("exit program !\n");
break;
}
I = im[PC];
printf("PC=%04X I=%04X", PC, I);
PC ++;
if ((I & 0x8000) == 0) { // A 指令
A = I;
} else { // C 指令
a = (I & 0x1000) >> 12;
c = (I & 0x0FC0) >> 6;
d = (I & 0x0038) >> 3;
j = (I & 0x0007) >> 0;
//
if (a == 0) AM = A; else AM = m[A];
switch (c) { // 處理 c1..6, 計算 aluOut
case 0x2A: aluOut = 0; break; // "0", "101010"
case 0x3F: aluOut = 1; break; // "1", "111111"
case 0x3A: aluOut = -1; break; // "-1", "111010"
case 0x0C: aluOut = D; break; // "D", "001100"
case 0x30: aluOut = AM; break; // "AM", "110000"
case 0x0D: aluOut = D^0xFFFF; break; // "!D", "001101"
case 0x31: aluOut = AM^0xFFFF; break; // "!AM", "110001"
case 0x0F: aluOut = -D; break; // "-D", "001111"
case 0x33: aluOut = -AM; break; // "-AM", "110011"
case 0x1F: aluOut = D+1; break; // "D+1", "011111"
case 0x37: aluOut = AM+1; break; // "AM+1","110111"
case 0x0E: aluOut = D-1; break; // "D-1", "001110"
case 0x32: aluOut = AM-1; break; // "AM-1","110010"
case 0x02: aluOut = D+AM; break; // "D+AM","000010"
case 0x13: aluOut = D-AM; break; // "D-AM","010011"
case 0x07: aluOut = AM-D; break; // "AM-D","000111"
case 0x00: aluOut = D&AM; break; // "D&AM","000000"
case 0x15: aluOut = D|AM; break; // "D|AM","010101"
default: assert(0);
}
if (d&BIT2) A = aluOut;
if (d&BIT1) D = aluOut;
if (d&BIT0) m[A] = aluOut;
switch (j) {
case 0x0: break; //
case 0x1: if (aluOut > 0) PC = A; break; // JGT
case 0x2: if (aluOut == 0) PC = A; break; // JEQ
case 0x3: if (aluOut >= 0) PC = A; break; // JGE
case 0x4: if (aluOut < 0) PC = A; break; // JLT
case 0x5: if (aluOut != 0) PC = A; break; // JNE
case 0x6: if (aluOut <= 0) PC = A; break; // JLE
case 0x7: PC = A; break; // JMP
}
}
printf(" A=%04X D=%04X m[A]=%04X", PC, A, D, m[A]);
if ((I & 0x8000) != 0) printf(" a=%X c=%02X d=%X j=%X", a, c, d, j);
printf("\n");
}
}
// run: ./vm <file.bin>
int main(int argc, char *argv[]) {
char *binFileName = argv[1];
FILE *binFile = fopen(binFileName, "rb");
imTop = fread(im, sizeof(uint16_t), 32768, binFile);
fclose(binFile);
run(im, m);
}
執行結果
$ gcc asm.c c6.c -o asm
$ ./asm ../add/Add
上面的組譯器指令會產生 ../add/Add.bin 檔,於是我們可以用虛擬機執行該機器碼檔案!
$ gcc vm.c -o vm
$ ./vm ../add/Add.bin
PC=0000 I=0002 A=0001 D=0002 m[A]=0000
PC=0001 I=EC10 A=0002 D=0002 m[A]=0002 a=0 c=30 d=2 j=0
PC=0002 I=0003 A=0003 D=0003 m[A]=0002
PC=0003 I=E090 A=0004 D=0003 m[A]=0005 a=0 c=02 d=2 j=0
PC=0004 I=0000 A=0005 D=0000 m[A]=0005
PC=0005 I=E308 A=0006 D=0000 m[A]=0005 a=0 c=0C d=1 j=0
exit program !
- GTK -- https://openhome.cc/Gossip/GTKGossip/index.html
- 可用來模擬螢幕