├── .gitignore ├── README.md └── mac ├── test.asm ├── test_file.c ├── vm_1.c ├── vm_2.c ├── vm_lc_3.c ├── vm_lc_3_1.c ├── vm_lc_3_2.c └── vm_lc_3_all.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Prerequisites 2 | *.d 3 | 4 | # Object files 5 | *.o 6 | *.ko 7 | *.obj 8 | *.elf 9 | 10 | # Linker output 11 | *.ilk 12 | *.map 13 | *.exp 14 | 15 | # Precompiled Headers 16 | *.gch 17 | *.pch 18 | 19 | # Libraries 20 | *.lib 21 | *.a 22 | *.la 23 | *.lo 24 | 25 | # Shared objects (inc. Windows DLLs) 26 | *.dll 27 | *.so 28 | *.so.* 29 | *.dylib 30 | 31 | # Executables 32 | *.exe 33 | *.out 34 | *.app 35 | *.i*86 36 | *.x86_64 37 | *.hex 38 | 39 | # Debug files 40 | *.dSYM/ 41 | *.su 42 | *.idb 43 | *.pdb 44 | *.sym 45 | *.obj 46 | 47 | # Kernel Module Compile Results 48 | *.mod* 49 | *.cmd 50 | .tmp_versions/ 51 | modules.order 52 | Module.symvers 53 | Mkfile.old 54 | dkms.conf 55 | 56 | .vscode -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # virtual-machine 2 | 3 | 一起来动手实现一个虚拟机,自定义指令集,只需使用简单的 c 语言。这对弄懂程序运行的底层原理绝对有好处,还可体验一下手写指令的快感哟。 4 | 5 | 相关文章如下: 6 | 7 | * [听说你想写个虚拟机(一)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484228&idx=1&sn=704addfc6b1e50c7dedf1ad61787358d&chksm=cf558c8cf822059a11e9062f73266ebc32562f2437a29c9a06ce4ff9d298b637b6b699edd20d&token=2075620006&lang=zh_CN#rd) 8 | 9 | * [听说你想写个虚拟机(二)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484277&idx=1&sn=b1955c7e5ea5951d7207bbe185a18591&chksm=cf558cbdf82205ab7c3dff66ec3814bbbcb1fb820a0a0df17a2cc2d8b5292a20fb6fbb1a5aee&token=2075620006&lang=zh_CN#rd) 10 | 11 | * [听说你想写个虚拟机(三)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484485&idx=1&sn=98db26d76fd6bf8a4570ce2db91da420&chksm=cf558b8df822029bf41c8acf943e4844411e349487f4b2f64d00dc1cf1acd3c563d9163ca42f&token=2075620006&lang=zh_CN#rd) 12 | 13 | * [听说你想写个虚拟机(四)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484737&idx=1&sn=1cd1c09748f613e7dfc67b6ff7fec18f&chksm=cf558a89f822039f1dd0dddaed2525de1d3f3a365eeecbec29551578c4bab8b2c2e7a78ef3aa&token=2075620006&lang=zh_CN#rd) 14 | 15 | * [听说你想写个虚拟机(五)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484807&idx=1&sn=41e63bb7910051ed401008cebfc04dcf&chksm=cf558a4ff822035994f7ed1f989e8b45f4dfcbe86a1a590590ac757c794704cb012dd4ced9f4&token=520345456&lang=zh_CN#rd) 16 | 17 | * [听说你想写个虚拟机(六)?](https://mp.weixin.qq.com/s?__biz=Mzg4MjU2Mzc1MQ==&mid=2247484888&idx=1&sn=eed78a1d777c227f21f75890b5d51bb9&chksm=cf558a10f822030620d2837e35d945913629bf6aba3e0d944262ea5e6dc29c6885c19df2ae46&token=520345456&lang=zh_CN#rd) 18 | 19 | 20 | 「听说你想写个虚拟机(x)」系列已全部完结,欢迎阅读~ 21 | 22 | 23 | 文章会同步发布到[简书](https://www.jianshu.com/u/9d9cf9760217)和公众号「微微笑的蜗牛」,欢迎关注。在公众号输入框回复「蜗牛」,可添加微信进行交流~ 24 | 25 | 26 | ![](https://cdn.jsdelivr.net/gh/silan-liu/picRepo/img20210131124048.jpg) 27 | 28 | -------------------------------------------------------------------------------- /mac/test.asm: -------------------------------------------------------------------------------- 1 | .ORIG x3000 2 | LEA R0, HELLO_STR 3 | PUTs 4 | HALT 5 | HELLO_STR .STRINGZ "Hello World!" 6 | WIDTH .FILL x4000 7 | .END -------------------------------------------------------------------------------- /mac/test_file.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main() 5 | { 6 | const char *path = "test"; 7 | 8 | FILE *file = fopen(path, "rwb"); 9 | 10 | uint16_t data = 0xf025; 11 | 12 | fwrite(&data, sizeof(data), 1, file); 13 | 14 | uint16_t *p = malloc(sizeof(uint16_t)); 15 | 16 | fread(p, sizeof(data), 1, file); 17 | 18 | printf("read:%0x,%0x\n", *p & 0xff, *p >> 8); 19 | 20 | fclose(file); 21 | 22 | uint16_t t = 65; 23 | char *p1 = (char *)&t; 24 | printf("%0d,%0d\n", p1[0], p1[1]); 25 | 26 | char c1 = getchar(); 27 | printf("address:%0x, %0x\n", c1, &c1); 28 | 29 | printf("%d\n", sizeof("123")); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /mac/vm_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 指令定义 5 | typedef enum 6 | { 7 | PSH, // PSH 5; ::将数据放入栈中 8 | ADD, // ADD; ::取出栈中的两个数据相加后,结果放入栈中 9 | POP, // POP; ::取出栈顶数据,并打印 10 | HLT, // HLT; ::停止程序 11 | } InstructionSet; 12 | 13 | // 程序 14 | const int program[] = { 15 | PSH, 5, 16 | PSH, 6, 17 | ADD, 18 | POP, 19 | HLT}; 20 | 21 | int ip = 0; 22 | int sp = -1; 23 | int stack[256]; 24 | 25 | bool running = true; 26 | 27 | void eval(int instr) 28 | { 29 | switch (instr) 30 | { 31 | case HLT: 32 | running = false; 33 | break; 34 | 35 | case PSH: 36 | sp++; 37 | stack[sp] = program[++ip]; 38 | break; 39 | 40 | case POP: 41 | { 42 | int popValue = stack[sp--]; 43 | printf("poped %d\n", popValue); 44 | } 45 | 46 | break; 47 | 48 | case ADD: 49 | { 50 | // 从栈中取出两个数,相加,再 push 回栈 51 | int a = stack[sp--]; 52 | int b = stack[sp--]; 53 | int sum = a + b; 54 | sp++; 55 | stack[sp] = sum; 56 | } 57 | 58 | break; 59 | 60 | default: 61 | break; 62 | } 63 | } 64 | 65 | int main() 66 | { 67 | while (running) 68 | { 69 | int instr = program[ip]; 70 | eval(instr); 71 | ip++; 72 | } 73 | 74 | return 0; 75 | } -------------------------------------------------------------------------------- /mac/vm_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 指令定义 5 | typedef enum 6 | { 7 | PSH, // PSH 5; ::将数据放入栈中 8 | POP, // POP; ::栈顶指针-1 9 | SET, // SET reg, 3; ::给寄存器赋值 10 | HLT, // HLT; ::停止程序 11 | MOV, // MOV reg1, reg2; ::将寄存器 reg2 中的值放入 reg1 12 | ADD, // ADD; ::取出栈中的两个数据相加后,结果放入栈中 13 | SUB, // SUB; ::取出栈中的两个数据相减后,结果放入栈中 14 | DIV, // DIV; ::取出栈中的两个数据相除后,结果放入栈中 15 | MUL, // MUL; ::取出栈中的两个数据相乘后,结果放入栈中 16 | STR, // STR reg; ::将寄存器的数据放入栈中 17 | LDR, // LDR reg; ::将栈顶数据放入寄存器 18 | IF, // IF reg, value, ip; ::如果 reg 的值等于 value,则跳转到新 ip 指向的指令。 19 | LOGR, // LOG reg; ::打印寄存器中的数据 20 | } InstructionSet; 21 | 22 | // 寄存器类型定义 23 | typedef enum 24 | { 25 | A, 26 | B, 27 | C, 28 | D, 29 | E, 30 | F, // A-F 通用寄存器 31 | IP, // IP 寄存器 32 | SP, // 栈顶指针寄存器 33 | NUM_OF_REGISTERS 34 | } Registers; 35 | 36 | // 寄存器 37 | int registers[NUM_OF_REGISTERS]; 38 | 39 | // 程序 40 | const int program[] = { 41 | 42 | IF, B, 0, 6, 43 | PSH, 1, 44 | PSH, 2, 45 | PSH, 3, 46 | PSH, 4, 47 | PSH, 5, 48 | PSH, 6, 49 | PSH, 7, 50 | PSH, 8, 51 | ADD, 52 | MUL, 53 | DIV, 54 | SUB, 55 | POP, 56 | SET, C, 2, 57 | LOGR, C, 58 | MOV, B, A, 59 | STR, B, 60 | LDR, C, 61 | HLT}; 62 | 63 | #define sp (registers[SP]) 64 | #define ip (registers[IP]) 65 | 66 | int stack[256]; 67 | 68 | bool is_jump = false; 69 | bool running = true; 70 | 71 | void printStack() 72 | { 73 | printf("\n\n=========begin print stack:=========\n\n"); 74 | 75 | for (int i = 0; i <= sp; i++) 76 | { 77 | printf("%d ", stack[i]); 78 | 79 | // 4 个一行 80 | if ((i + 1) % 4 == 0) 81 | { 82 | printf("\n"); 83 | } 84 | } 85 | 86 | printf("\n\n=========print stack done=========\n\n"); 87 | } 88 | 89 | void printRegisters() 90 | { 91 | printf("\n\n=========begin print registers:=========\n\n"); 92 | for (int i = 0; i < NUM_OF_REGISTERS; i++) 93 | { 94 | printf("%d ", registers[i]); 95 | } 96 | 97 | printf("\n\n=========print registers done=========\n\n"); 98 | } 99 | 100 | void eval(int instr) 101 | { 102 | is_jump = false; 103 | 104 | switch (instr) 105 | { 106 | case HLT: 107 | { 108 | running = false; 109 | break; 110 | } 111 | 112 | case PSH: 113 | { 114 | stack[++sp] = program[++ip]; 115 | break; 116 | } 117 | 118 | case POP: 119 | { 120 | sp--; 121 | break; 122 | } 123 | 124 | case ADD: 125 | { 126 | // 从栈中取出两个数,相加,再 push 回栈 127 | int a = stack[sp--]; 128 | int b = stack[sp--]; 129 | 130 | int result = a + b; 131 | 132 | stack[++sp] = result; 133 | 134 | registers[A] = result; 135 | 136 | break; 137 | } 138 | 139 | case SUB: 140 | { 141 | // 从栈中取出两个数,相减,再 push 回栈 142 | int a = stack[sp--]; 143 | int b = stack[sp--]; 144 | 145 | int result = b - a; 146 | 147 | // 入栈 148 | stack[++sp] = result; 149 | registers[A] = result; 150 | 151 | break; 152 | } 153 | 154 | case MUL: 155 | { 156 | // 从栈中取出两个数,相乘,再 push 回栈 157 | int a = stack[sp--]; 158 | int b = stack[sp--]; 159 | 160 | int result = a * b; 161 | 162 | // 入栈 163 | stack[++sp] = result; 164 | registers[A] = result; 165 | 166 | break; 167 | } 168 | 169 | case DIV: 170 | { 171 | // 从栈中取出两个数,相除,再 push 回栈 172 | int a = stack[sp--]; 173 | int b = stack[sp--]; 174 | 175 | if (a != 0) 176 | { 177 | int result = b / a; 178 | 179 | // 入栈 180 | stack[++sp] = result; 181 | registers[A] = result; 182 | } 183 | else 184 | { 185 | printf("exception occur, divid 0 \n"); 186 | } 187 | 188 | break; 189 | } 190 | 191 | case MOV: 192 | { 193 | // 将一个寄存器的值放到另一个寄存器中 194 | // 目的寄存器 195 | int dr = program[++ip]; 196 | 197 | // 源寄存器 198 | int sr = program[++ip]; 199 | 200 | // 源寄存器的值 201 | int sourceValue = registers[sr]; 202 | registers[dr] = sourceValue; 203 | 204 | break; 205 | } 206 | 207 | case STR: 208 | { 209 | // 将指定寄存器中的参数,放入栈中 210 | int r = program[++ip]; 211 | stack[++sp] = registers[r]; 212 | break; 213 | } 214 | 215 | case LDR: 216 | { 217 | int value = stack[sp]; 218 | int r = program[++ip]; 219 | registers[r] = value; 220 | break; 221 | } 222 | 223 | case IF: 224 | { 225 | // 如果寄存器的值和后面的数值相等,则跳转 226 | int r = program[++ip]; 227 | if (registers[r] == program[++ip]) 228 | { 229 | ip = program[++ip]; 230 | 231 | is_jump = true; 232 | printf("jump if:%d\n", ip); 233 | } 234 | else 235 | { 236 | ip += 1; 237 | } 238 | break; 239 | } 240 | 241 | case SET: 242 | { 243 | // set register value 244 | int r = program[++ip]; 245 | int value = program[++ip]; 246 | 247 | registers[r] = value; 248 | break; 249 | } 250 | 251 | case LOGR: 252 | { 253 | int r = program[++ip]; 254 | int value = registers[r]; 255 | printf("log register_%d %d\n", r, value); 256 | break; 257 | } 258 | 259 | default: 260 | { 261 | printf("Unknown Instruction %d!\n", instr); 262 | break; 263 | } 264 | } 265 | } 266 | 267 | int main() 268 | { 269 | // 初始化寄存器 270 | sp = -1; 271 | ip = 0; 272 | 273 | while (running) 274 | { 275 | int instr = program[ip]; 276 | eval(instr); 277 | 278 | if (!is_jump) 279 | { 280 | ip++; 281 | } 282 | } 283 | 284 | printStack(); 285 | 286 | printRegisters(); 287 | 288 | return 0; 289 | } 290 | -------------------------------------------------------------------------------- /mac/vm_lc_3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 内存区 5 | uint16_t mem[UINT16_MAX]; 6 | 7 | // 载入地址 8 | uint16_t origin; 9 | 10 | // 程序运行状态 11 | int running = 1; 12 | 13 | // 寄存器定义 14 | typedef enum 15 | { 16 | R_R0, 17 | R_R1, 18 | R_R2, 19 | R_R3, 20 | R_R4, 21 | R_R5, 22 | R_R6, 23 | R_R7, 24 | R_PC, 25 | R_COND, 26 | R_COUNT 27 | } Registers; 28 | 29 | // 寄存器数组 30 | uint16_t reg[R_COUNT]; 31 | 32 | // 宏便捷定义 33 | // PC 寄存器 34 | #define PC (reg[R_PC]) 35 | 36 | // 标志寄存器 37 | #define COND (reg[R_COND]) 38 | 39 | // 指令定义 40 | typedef enum 41 | { 42 | OP_BR = 0, // 条件分支 43 | OP_ADD = 1, // 加法 44 | OP_LD = 2, // load 45 | OP_ST = 3, // store 46 | OP_JSR = 4, // jump resgister 47 | OP_AND = 5, // 与运算 48 | OP_LDR = 6, // load register 49 | OP_STR = 7, // store register 50 | OP_RTI = 8, // unused 51 | OP_NOT = 9, // 取反 52 | OP_LDI = 10, // load indirect 53 | OP_STI = 11, // store indirect 54 | OP_JMP = 12, // jump 55 | OP_RES = 13, // reserved 56 | OP_LEA = 14, // load effective address 57 | OP_TRAP = 15, // trap,陷阱,相当于中断 58 | } InstructionSet; 59 | 60 | // 标志定义 61 | typedef enum 62 | { 63 | FL_POS = 1 << 0, // 正数 64 | FL_ZRO = 1 << 1, // 0 65 | FL_NEG = 1 << 2 //负数 66 | } ConditionFlags; 67 | 68 | // 中断类型 69 | typedef enum 70 | { 71 | TRAP_GETC = 0x20, // 从键盘输入 72 | TRAP_OUT = 0x21, //输出字符 73 | TRAP_PUTS = 0x22, // 输出字符串 74 | TARP_IN = 0x23, 75 | TRAP_PUTSP = 0x24, 76 | TRAP_HALT = 0x25, // 退出程序 77 | } TrapSet; 78 | 79 | // 从内存读取数据 80 | uint16_t mem_read(int address) 81 | { 82 | if (address < 0 || address >= UINT16_MAX) 83 | { 84 | printf("memory read error!\n"); 85 | exit(4); 86 | } 87 | 88 | return mem[address]; 89 | } 90 | 91 | // 将 data 写入内存地址为 address 处 92 | void mem_write(uint16_t address, uint16_t data) 93 | { 94 | if (address < 0 || address >= UINT16_MAX) 95 | { 96 | printf("memory write error!\n"); 97 | exit(3); 98 | } 99 | 100 | mem[address] = data; 101 | } 102 | 103 | uint16_t swap16(uint16_t x) 104 | { 105 | // 两个字节交换 106 | return (x << 8) | (x >> 8); 107 | } 108 | 109 | // 文件存储是大端字节序,需转换为小端 110 | void read_image_file(FILE *file) 111 | { 112 | // 读取 2 字节 113 | fread(&origin, sizeof(origin), 1, file); 114 | 115 | // 大端转小端 116 | origin = swap16(origin); 117 | 118 | uint16_t max_read = UINT16_MAX - origin; 119 | uint16_t *p = mem + origin; 120 | 121 | // 读取文件内容到 p 指向的地址,以 2 字节为单位 122 | size_t read = fread(p, sizeof(uint16_t), max_read, file); 123 | 124 | // 大端转小端 125 | while (read-- > 0) 126 | { 127 | *p = swap16(*p); 128 | ++p; 129 | } 130 | } 131 | 132 | // 读取指令文件 133 | int read_image(const char *image_path) 134 | { 135 | FILE *file = fopen(image_path, "rb"); 136 | if (!file) 137 | { 138 | return 0; 139 | } 140 | 141 | read_image_file(file); 142 | 143 | fclose(file); 144 | return 1; 145 | } 146 | 147 | // 符号扩展 148 | uint16_t sign_extend(uint16_t x, int bit_count) 149 | { 150 | // 最高位 1 151 | if ((x >> (bit_count - 1)) & 0x1) 152 | { 153 | x |= 0xFFFF << bit_count; 154 | } 155 | 156 | return x; 157 | } 158 | 159 | // 更新标志寄存器 160 | void update_flags(uint16_t r) 161 | { 162 | uint16_t value = reg[r]; 163 | if (value == 0) 164 | { 165 | COND = FL_ZRO; 166 | } 167 | else if ((value >> 15) & 0x1) 168 | { 169 | // 最高位 1,负数 170 | COND = FL_NEG; 171 | } 172 | else 173 | { 174 | COND = FL_POS; 175 | } 176 | } 177 | 178 | // 加法指令,两种模式 179 | // add r0, r1, imm, 立即数模式 180 | // add r0, r1, r2,寄存器模式 181 | void add(int instr) 182 | { 183 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 184 | uint16_t r0 = (instr >> 9) & 0x7; 185 | 186 | // 源寄存器 r1,6~8 位, 187 | uint16_t r1 = (instr >> 6) & 0x7; 188 | 189 | // add 模式 190 | uint16_t flag = (instr >> 5) & 0x1; 191 | 192 | // 立即数模式 193 | if (flag) 194 | { 195 | // 低五位,取出立即数。 196 | uint16_t data = instr & 0x1F; 197 | 198 | printf("add imm mode, imm:%d\n", data); 199 | 200 | // 符号扩展,若高位是 1,则全部补 1 201 | uint16_t value = sign_extend(data, 5); 202 | 203 | printf("add imm mode, sign_extend imm:%d\n", value); 204 | 205 | reg[r0] = reg[r1] + value; 206 | } 207 | else 208 | { 209 | puts("add reg mode"); 210 | 211 | // 寄存器模式 212 | // 取出源寄存器 2,低 3 位 213 | uint16_t r2 = instr & 0x7; 214 | 215 | reg[r0] = reg[r1] + reg[r2]; 216 | } 217 | 218 | printf("reg_%d value:%d\n", r0, reg[r0]); 219 | 220 | // 更新标志寄存器 221 | update_flags(r0); 222 | } 223 | 224 | // 与运算,同 add ,两种模式 225 | void and (uint16_t instr) 226 | { 227 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 228 | uint16_t r0 = (instr >> 9) & 0x7; 229 | 230 | // 源寄存器 r1,6~8 位, 231 | uint16_t r1 = (instr >> 6) & 0x7; 232 | 233 | // add 模式 234 | uint16_t flag = (instr >> 5) & 0x1; 235 | 236 | // 立即数模式 237 | if (flag) 238 | { 239 | // 低五位,取出立即数。 240 | uint16_t data = instr & 0x1F; 241 | 242 | printf("add imm mode, imm:%d\n", data); 243 | 244 | // 符号扩展,若高位是 1,则全部补 1 245 | uint16_t value = sign_extend(data, 5); 246 | 247 | printf("add imm mode, sign_extend imm:%d\n", value); 248 | 249 | reg[r0] = reg[r1] & value; 250 | } 251 | else 252 | { 253 | puts("add reg mode"); 254 | 255 | // 寄存器模式 256 | // 取出源寄存器 2,低 3 位 257 | uint16_t r2 = instr & 0x7; 258 | 259 | reg[r0] = reg[r1] & reg[r2]; 260 | } 261 | 262 | printf("reg_%d value:%d\n", r0, reg[r0]); 263 | 264 | // 更新标志寄存器 265 | update_flags(r0); 266 | } 267 | 268 | // NOT r0, r1。将 r1 取反后,放入 r0 269 | void not(uint16_t instr) 270 | { 271 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 272 | uint16_t r0 = (instr >> 9) & 0x7; 273 | 274 | // 源寄存器 r1,6~8 位, 275 | uint16_t r1 = (instr >> 6) & 0x7; 276 | 277 | reg[r0] = ~reg[r1]; 278 | update_flags(r0); 279 | } 280 | 281 | // 标志条件跳转 282 | // br cond_flag, pc_offset 283 | void branch(uint16_t instr) 284 | { 285 | uint16_t cond_flag = (instr >> 9) & 0x7; 286 | uint16_t pc_offset = sign_extend(instr & 0x1FF, 9); 287 | 288 | // 传入标识与标志寄存器的值相符,N,P,Z 289 | if (cond_flag & COND) 290 | { 291 | PC += pc_offset; 292 | } 293 | } 294 | 295 | // jump r 296 | // 跳转到寄存器中的值 297 | void jump(uint16_t instr) 298 | { 299 | uint16_t r1 = (instr >> 6) & 0x7; 300 | PC = reg[r1]; 301 | } 302 | 303 | // load indirect,从内存中获取数据,放入寄存器。间接模式 304 | // 以 pc 寄存器作为偏移基准 305 | // ldi dr, pc_offset 306 | // [[pc+pc_offset]],pc+pc_offset 中的内容是数据的地址。 307 | void load_indirect(uint16_t instr) 308 | { 309 | uint16_t pc_offset = instr & 0x1ff; 310 | 311 | // 符号扩展 312 | pc_offset = sign_extend(pc_offset, 9); 313 | 314 | uint16_t r = (instr >> 9) & 0x7; 315 | 316 | // 取出存储数据的地址 317 | uint16_t address = mem_read(PC + pc_offset); 318 | 319 | // 取出数据 320 | uint16_t data = mem_read(address); 321 | 322 | // 更新寄存器 323 | reg[r] = data; 324 | 325 | // 更新标志寄存器 326 | update_flags(r); 327 | } 328 | 329 | // 将地址放入寄存器 r 330 | // 以 pc 寄存器作为偏移基准 331 | // lea r, pc_offset 332 | void load_effective_address(uint16_t instr) 333 | { 334 | uint16_t pc_offset = instr & 0x1ff; 335 | 336 | // 符号扩展 337 | pc_offset = sign_extend(pc_offset, 9); 338 | 339 | uint16_t address = PC + pc_offset; 340 | 341 | uint16_t r = (instr >> 9) & 0x7; 342 | 343 | // 更新寄存器 344 | reg[r] = address; 345 | 346 | // 更新标志寄存器 347 | update_flags(r); 348 | } 349 | 350 | // jump resgister 351 | // 偏移量跳转 352 | void jump_subroutine(uint16_t instr) 353 | { 354 | uint16_t long_flag = (instr >> 11) & 0x1; 355 | 356 | // R7 保存 pc 值 357 | reg[R_R7] = PC; 358 | 359 | if (long_flag) 360 | { 361 | // long_pc_offset 362 | uint16_t long_pc_offset = sign_extend(instr & 0x7ff, 11); 363 | PC += long_pc_offset; 364 | } 365 | else 366 | { 367 | uint16_t r1 = (instr >> 6) & 0x7; 368 | PC = reg[r1]; 369 | } 370 | } 371 | 372 | // ld r, pc_offset 373 | // 以 pc 寄存器作为偏移基准 374 | // 将距离下一条指令 pc_offset 处里的数据取出来,放入 r 中。 375 | void load(uint16_t instr) 376 | { 377 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 378 | uint16_t r0 = (instr >> 9) & 0x7; 379 | reg[r0] = mem_read(PC + pc_offset); 380 | update_flags(r0); 381 | } 382 | 383 | // ldr r0, r1, offset 384 | // 以 r1 作为偏移基准 385 | // 将距离 r1,offset 处的数据取出来,放入 r0。 386 | void load_register(uint16_t instr) 387 | { 388 | uint16_t r0 = (instr >> 9) & 0x7; 389 | 390 | uint16_t r1 = (instr >> 6) & 0x7; 391 | 392 | uint16_t offset = sign_extend(instr & 0x3f, 6); 393 | 394 | uint16_t address = reg[r1] + offset; 395 | uint16_t value = mem_read(address); 396 | 397 | reg[r0] = value; 398 | update_flags(r0); 399 | } 400 | 401 | // st r, pc_offset 402 | // 以 pc 寄存器作为偏移基准 403 | // 将 r 中的数据放入距离下一条指令,pc_offset 的地址中。 404 | void store(uint16_t instr) 405 | { 406 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 407 | uint16_t r0 = (instr >> 9) & 0x7; 408 | 409 | uint16_t address = PC + pc_offset; 410 | uint16_t value = reg[r0]; 411 | 412 | mem_write(address, value); 413 | } 414 | 415 | // sti r, pc_offset,间接存储,pc+pc_offset 是待存储数据地址的地址。 416 | void store_indirect(uint16_t instr) 417 | { 418 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 419 | uint16_t r0 = (instr >> 9) & 0x7; 420 | 421 | uint16_t indirect_address = PC + pc_offset; 422 | uint16_t address = mem_read(indirect_address); 423 | 424 | uint16_t value = reg[r0]; 425 | 426 | mem_write(address, value); 427 | } 428 | 429 | // str r0, r1, offsets 430 | // 以 r1 作为偏移基准 431 | void store_register(uint16_t instr) 432 | { 433 | // r0 434 | uint16_t r0 = (instr >> 9) & 0x7; 435 | 436 | // r1 437 | uint16_t r1 = (instr >> 6) & 0x7; 438 | 439 | uint16_t offset = sign_extend(instr & 0x3f, 6); 440 | 441 | uint16_t address = reg[r1] + offset; 442 | uint16_t value = reg[r0]; 443 | 444 | mem_write(address, value); 445 | } 446 | 447 | // 将 r0 寄存器中地址处的字符串打印出来。1 个字符占 2 字节。 448 | void trap_puts() 449 | { 450 | printf("trap_puts"); 451 | 452 | uint16_t address = reg[R_R0]; 453 | uint16_t *c = mem + address; 454 | 455 | while (*c) 456 | { 457 | putc((char)*c, stdout); 458 | ++c; 459 | } 460 | 461 | fflush(stdout); 462 | } 463 | 464 | // 等待输入一个字符,最后存入 r0 465 | void trap_getc() 466 | { 467 | reg[R_R0] = (uint16_t)getchar(); 468 | } 469 | 470 | // 将 r0 中的字符打印出来 471 | void trap_out() 472 | { 473 | putc((char)reg[R_R0], stdout); 474 | fflush(stdout); 475 | } 476 | 477 | // 提示输入一个字符,将字符打印,并放入 R0 478 | void trap_in() 479 | { 480 | printf("Enter a character:"); 481 | char c = getchar(); 482 | putc(c, stdout); 483 | reg[R_R0] = (uint16_t)c; 484 | } 485 | 486 | // 将 r0 地址处的字符串出来,一个字符一字节 487 | void trap_put_string() 488 | { 489 | uint16_t *c = mem + reg[R_R0]; 490 | while (*c) 491 | { 492 | // 低 8 位 493 | char char1 = (*c) & 0xff; 494 | putc(char1, stdout); 495 | 496 | // 高 8 位 497 | char char2 = (*c) >> 8; 498 | if (char2) 499 | { 500 | putc(char2, stdout); 501 | } 502 | 503 | ++c; 504 | } 505 | 506 | fflush(stdout); 507 | } 508 | 509 | // 中断,op = 1111 510 | void trap(int instr) 511 | { 512 | // trap_code,低 8 位 513 | uint16_t trap_code = instr & 0xff; 514 | printf("trap_code:%d\n", trap_code); 515 | 516 | switch (trap_code) 517 | { 518 | case TRAP_GETC: 519 | { 520 | trap_getc(); 521 | break; 522 | } 523 | 524 | case TRAP_OUT: 525 | { 526 | trap_out(); 527 | break; 528 | } 529 | 530 | case TRAP_PUTS: 531 | { 532 | trap_puts(); 533 | break; 534 | } 535 | 536 | case TARP_IN: 537 | { 538 | trap_in(); 539 | break; 540 | } 541 | 542 | case TRAP_PUTSP: 543 | { 544 | trap_put_string(); 545 | break; 546 | } 547 | 548 | case TRAP_HALT: 549 | { 550 | puts("Halt"); 551 | running = 0; 552 | break; 553 | } 554 | 555 | default: 556 | { 557 | printf("Unknown TrapCode!\n"); 558 | break; 559 | } 560 | } 561 | } 562 | 563 | int main(int argc, const char *argv[]) 564 | { 565 | if (argc < 2) 566 | { 567 | printf("no lc3 image file ...\n"); 568 | exit(2); 569 | } 570 | 571 | for (int i = 0; i < argc; i++) 572 | { 573 | if (!read_image(argv[i])) 574 | { 575 | printf("failed to load image %s\n", argv[i]); 576 | exit(1); 577 | } 578 | } 579 | 580 | // 设置初始值 581 | PC = origin; 582 | 583 | while (running) 584 | { 585 | // 读取指令 586 | u_int16_t instr = mem_read(PC++); 587 | 588 | // 指令操作码占 4 位 589 | u_int16_t op = instr >> 12; 590 | 591 | switch (op) 592 | { 593 | case OP_ADD: 594 | { 595 | add(instr); 596 | break; 597 | } 598 | 599 | case OP_AND: 600 | { 601 | and(instr); 602 | break; 603 | } 604 | 605 | case OP_NOT: 606 | { 607 | not(instr); 608 | break; 609 | } 610 | 611 | case OP_BR: 612 | { 613 | branch(instr); 614 | break; 615 | } 616 | 617 | case OP_JMP: 618 | { 619 | jump(instr); 620 | break; 621 | } 622 | 623 | case OP_JSR: 624 | { 625 | jump_subroutine(instr); 626 | break; 627 | } 628 | 629 | case OP_LD: 630 | { 631 | load(instr); 632 | break; 633 | } 634 | 635 | case OP_LDI: 636 | { 637 | load_indirect(instr); 638 | break; 639 | } 640 | 641 | case OP_LDR: 642 | { 643 | load_register(instr); 644 | break; 645 | } 646 | 647 | case OP_LEA: 648 | { 649 | load_effective_address(instr); 650 | break; 651 | } 652 | 653 | case OP_ST: 654 | { 655 | store(instr); 656 | break; 657 | } 658 | 659 | case OP_STI: 660 | { 661 | store_indirect(instr); 662 | break; 663 | } 664 | 665 | case OP_STR: 666 | { 667 | store_register(instr); 668 | break; 669 | } 670 | 671 | case OP_TRAP: 672 | { 673 | trap(instr); 674 | break; 675 | } 676 | 677 | default: 678 | { 679 | printf("Unknown OpCode!\n"); 680 | } 681 | break; 682 | } 683 | } 684 | 685 | return 0; 686 | } -------------------------------------------------------------------------------- /mac/vm_lc_3_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 内存区 5 | uint16_t mem[UINT16_MAX] = { 6 | // ADD R0,R1,R2 7 | 0x1042, 8 | 9 | // ADD R1,R2,#6 10 | 0x12A6, 11 | 12 | // JSR 2;下一条是第 4 条指令,跳转到第 4+2=6 条指令 13 | 0x4802, 14 | 15 | // JMP R1;跳转到第 6 条指令 16 | 0xC040, 17 | 18 | // RTI 19 | 0X8000, 20 | 21 | //RES 22 | 0XD000, 23 | 24 | // NOT R3, R1 25 | 0x967F, 26 | 27 | // trap-halt 28 | 0xf000, 29 | }; 30 | 31 | // 程序运行状态 32 | int running = 1; 33 | 34 | // 寄存器定义 35 | typedef enum 36 | { 37 | R_R0, 38 | R_R1, 39 | R_R2, 40 | R_R3, 41 | R_R4, 42 | R_R5, 43 | R_R6, 44 | R_R7, 45 | R_PC, 46 | R_COND, 47 | R_COUNT 48 | } Registers; 49 | 50 | // 寄存器数组 51 | uint16_t reg[R_COUNT]; 52 | 53 | // 宏便捷定义 54 | // PC 寄存器 55 | #define PC (reg[R_PC]) 56 | 57 | // 标志寄存器 58 | #define COND (reg[R_COND]) 59 | 60 | // 指令定义 61 | typedef enum 62 | { 63 | OP_BR = 0, // 条件分支 64 | OP_ADD = 1, // 加法 65 | OP_LD = 2, // load 66 | OP_ST = 3, // store 67 | OP_JSR = 4, // jump resgister 68 | OP_AND = 5, // 与运算 69 | OP_LDR = 6, // load register 70 | OP_STR = 7, // store register 71 | OP_RTI = 8, // unused 72 | OP_NOT = 9, // 取反 73 | OP_LDI = 10, // load indirect 74 | OP_STI = 11, // store indirect 75 | OP_JMP = 12, // jump 76 | OP_RES = 13, // reserved 77 | OP_LEA = 14, // load effective address 78 | OP_TRAP = 15, // trap,陷阱,相当于中断 79 | } InstructionSet; 80 | 81 | // 标志定义 82 | typedef enum 83 | { 84 | FL_POS = 1 << 0, // 正数 85 | FL_ZRO = 1 << 1, // 0 86 | FL_NEG = 1 << 2 //负数 87 | } ConditionFlags; 88 | 89 | // 符号扩展 90 | uint16_t sign_extend(uint16_t x, int bit_count) 91 | { 92 | // 最高位 1 93 | if ((x >> (bit_count - 1)) & 0x1) 94 | { 95 | x |= 0xFFFF << bit_count; 96 | } 97 | 98 | return x; 99 | } 100 | 101 | // 更新标志寄存器 102 | void update_flags(uint16_t r) 103 | { 104 | uint16_t value = reg[r]; 105 | if (value == 0) 106 | { 107 | COND = FL_ZRO; 108 | } 109 | else if ((value >> 15) & 0x1) 110 | { 111 | // 最高位 1,负数 112 | COND = FL_NEG; 113 | } 114 | else 115 | { 116 | COND = FL_POS; 117 | } 118 | } 119 | 120 | // 加法指令,两种模式 121 | // add r0, r1, imm, 立即数模式 122 | // add r0, r1, r2,寄存器模式 123 | void add(int instr) 124 | { 125 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 126 | uint16_t r0 = (instr >> 9) & 0x7; 127 | 128 | // 源寄存器 r1,6~8 位, 129 | uint16_t r1 = (instr >> 6) & 0x7; 130 | 131 | // add 模式 132 | uint16_t flag = (instr >> 5) & 0x1; 133 | 134 | // 立即数模式 135 | if (flag) 136 | { 137 | // 低五位,取出立即数。 138 | uint16_t data = instr & 0x1F; 139 | 140 | // 符号扩展,若高位是 1,则全部补 1 141 | uint16_t value = sign_extend(data, 5); 142 | 143 | reg[r0] = reg[r1] + value; 144 | } 145 | else 146 | { 147 | // 寄存器模式 148 | // 取出源寄存器 2,低 3 位 149 | uint16_t r2 = instr & 0x7; 150 | 151 | reg[r0] = reg[r1] + reg[r2]; 152 | } 153 | 154 | // 更新标志寄存器 155 | update_flags(r0); 156 | } 157 | 158 | // 与运算,同 add ,两种模式 159 | void and (uint16_t instr) 160 | { 161 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 162 | uint16_t r0 = (instr >> 9) & 0x7; 163 | 164 | // 源寄存器 r1,6~8 位, 165 | uint16_t r1 = (instr >> 6) & 0x7; 166 | 167 | // add 模式 168 | uint16_t flag = (instr >> 5) & 0x1; 169 | 170 | // 立即数模式 171 | if (flag) 172 | { 173 | // 低五位,取出立即数。 174 | uint16_t data = instr & 0x1F; 175 | 176 | printf("add imm mode, imm:%d\n", data); 177 | 178 | // 符号扩展,若高位是 1,则全部补 1 179 | uint16_t value = sign_extend(data, 5); 180 | 181 | printf("add imm mode, sign_extend imm:%d\n", value); 182 | 183 | reg[r0] = reg[r1] & value; 184 | } 185 | else 186 | { 187 | puts("add reg mode"); 188 | 189 | // 寄存器模式 190 | // 取出源寄存器 2,低 3 位 191 | uint16_t r2 = instr & 0x7; 192 | 193 | reg[r0] = reg[r1] & reg[r2]; 194 | } 195 | 196 | printf("reg_%d value:%d\n", r0, reg[r0]); 197 | 198 | // 更新标志寄存器 199 | update_flags(r0); 200 | } 201 | 202 | // NOT r0, r1。将 r1 取反后,放入 r0 203 | void not(uint16_t instr) 204 | { 205 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 206 | uint16_t r0 = (instr >> 9) & 0x7; 207 | 208 | // 源寄存器 r1,6~8 位, 209 | uint16_t r1 = (instr >> 6) & 0x7; 210 | 211 | reg[r0] = ~reg[r1]; 212 | update_flags(r0); 213 | } 214 | 215 | // 标志条件跳转 216 | // br cond_flag, pc_offset 217 | void branch(uint16_t instr) 218 | { 219 | uint16_t cond_flag = (instr >> 9) & 0x7; 220 | uint16_t pc_offset = sign_extend(instr & 0x1FF, 9); 221 | 222 | // 传入标识与标志寄存器的值相符,N,P,Z 223 | if (cond_flag & COND) 224 | { 225 | PC += pc_offset; 226 | } 227 | } 228 | 229 | // jump r 230 | // 跳转到寄存器中的值 231 | void jump(uint16_t instr) 232 | { 233 | uint16_t r1 = (instr >> 6) & 0x7; 234 | PC = reg[r1]; 235 | } 236 | 237 | // jump resgister 238 | // 偏移量跳转 239 | void jump_subroutine(uint16_t instr) 240 | { 241 | uint16_t long_flag = (instr >> 11) & 0x1; 242 | 243 | // R7 保存 pc 值 244 | reg[R_R7] = PC; 245 | 246 | if (long_flag) 247 | { 248 | // long_pc_offset 249 | uint16_t long_pc_offset = sign_extend(instr & 0x7ff, 11); 250 | PC += long_pc_offset; 251 | } 252 | else 253 | { 254 | uint16_t r1 = (instr >> 6) & 0x7; 255 | PC = reg[r1]; 256 | } 257 | } 258 | 259 | // op = 1111 260 | void trap(int instr) 261 | { 262 | running = 0; 263 | } 264 | 265 | int main(int argc, const char *argv[]) 266 | { 267 | // 设置初始值 268 | PC = 0; 269 | 270 | // 用于打印当前执行操作码 271 | const char *op_list[] = {"BR", "ADD", "LD", "ST", "JSR", "AND", "LDR", "STR", "RTI", "NOT", "LDI", "STI", "JMP", "RES", "LEA", "TRAP"}; 272 | 273 | while (running) 274 | { 275 | // 读取指令 276 | u_int16_t instr = mem[PC++]; 277 | 278 | // 指令操作码占 4 位 279 | u_int16_t op = instr >> 12; 280 | 281 | printf("exe op:%s\n", op_list[op]); 282 | 283 | switch (op) 284 | { 285 | case OP_ADD: 286 | { 287 | add(instr); 288 | break; 289 | } 290 | 291 | case OP_AND: 292 | { 293 | and(instr); 294 | break; 295 | } 296 | 297 | case OP_NOT: 298 | { 299 | not(instr); 300 | break; 301 | } 302 | 303 | case OP_BR: 304 | { 305 | branch(instr); 306 | break; 307 | } 308 | 309 | case OP_JMP: 310 | { 311 | jump(instr); 312 | break; 313 | } 314 | 315 | case OP_JSR: 316 | { 317 | jump_subroutine(instr); 318 | break; 319 | } 320 | 321 | case OP_TRAP: 322 | { 323 | trap(instr); 324 | break; 325 | } 326 | 327 | case OP_RTI: 328 | case OP_RES: 329 | break; 330 | 331 | default: 332 | { 333 | printf("Unknown OpCode!\n"); 334 | } 335 | break; 336 | } 337 | } 338 | 339 | printf("r0,%d\n", reg[R_R0]); 340 | printf("r1,%d\n", reg[R_R1]); 341 | printf("r3,%d\n", reg[R_R3]); 342 | 343 | return 0; 344 | } -------------------------------------------------------------------------------- /mac/vm_lc_3_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 内存区 5 | uint16_t mem[UINT16_MAX] = { 6 | // ld r0,9 7 | 0x2009, 8 | 9 | // add r0, r0, 1 10 | 0x1021, 11 | 12 | // st r0,7 13 | 0x3007, 14 | 15 | // ldi, r1, 8 16 | 0xa208, 17 | 18 | // add r1, r1, 2 19 | 0x1262, 20 | 21 | // sti r1, 6 22 | 0xb206, 23 | 24 | // lea r2, 4 25 | 0xe404, 26 | 27 | // RTI 28 | 0x8000, 29 | 0x8000, 30 | 31 | // trap-halt 32 | 0xf000, 33 | 34 | // 数据 35 | 0x1, 36 | 0x2, 37 | 0xf, 38 | 0x0, 39 | 0x0, 40 | 0x3, 41 | }; 42 | 43 | // 程序运行状态 44 | int running = 1; 45 | 46 | // 寄存器定义 47 | typedef enum 48 | { 49 | R_R0, 50 | R_R1, 51 | R_R2, 52 | R_R3, 53 | R_R4, 54 | R_R5, 55 | R_R6, 56 | R_R7, 57 | R_PC, 58 | R_COND, 59 | R_COUNT 60 | } Registers; 61 | 62 | // 寄存器数组 63 | uint16_t reg[R_COUNT]; 64 | 65 | // 宏便捷定义 66 | // PC 寄存器 67 | #define PC (reg[R_PC]) 68 | 69 | // 标志寄存器 70 | #define COND (reg[R_COND]) 71 | 72 | // 指令定义 73 | typedef enum 74 | { 75 | OP_BR = 0, // 条件分支 76 | OP_ADD = 1, // 加法 77 | OP_LD = 2, // load 78 | OP_ST = 3, // store 79 | OP_JSR = 4, // jump resgister 80 | OP_AND = 5, // 与运算 81 | OP_LDR = 6, // load register 82 | OP_STR = 7, // store register 83 | OP_RTI = 8, // unused 84 | OP_NOT = 9, // 取反 85 | OP_LDI = 10, // load indirect 86 | OP_STI = 11, // store indirect 87 | OP_JMP = 12, // jump 88 | OP_RES = 13, // reserved 89 | OP_LEA = 14, // load effective address 90 | OP_TRAP = 15, // trap,陷阱,相当于中断 91 | } InstructionSet; 92 | 93 | // 标志定义 94 | typedef enum 95 | { 96 | FL_POS = 1 << 0, // 正数 97 | FL_ZRO = 1 << 1, // 0 98 | FL_NEG = 1 << 2 //负数 99 | } ConditionFlags; 100 | 101 | // 从内存读取数据 102 | uint16_t mem_read(int address) 103 | { 104 | if (address < 0 || address >= UINT16_MAX) 105 | { 106 | printf("memory read error!\n"); 107 | exit(4); 108 | } 109 | 110 | return mem[address]; 111 | } 112 | 113 | // 将 data 写入内存地址为 address 处 114 | void mem_write(uint16_t address, uint16_t data) 115 | { 116 | if (address < 0 || address >= UINT16_MAX) 117 | { 118 | printf("memory write error!\n"); 119 | exit(3); 120 | } 121 | 122 | mem[address] = data; 123 | } 124 | 125 | // 符号扩展 126 | uint16_t sign_extend(uint16_t x, int bit_count) 127 | { 128 | // 最高位 1 129 | if ((x >> (bit_count - 1)) & 0x1) 130 | { 131 | x |= 0xFFFF << bit_count; 132 | } 133 | 134 | return x; 135 | } 136 | 137 | // 更新标志寄存器 138 | void update_flags(uint16_t r) 139 | { 140 | uint16_t value = reg[r]; 141 | if (value == 0) 142 | { 143 | COND = FL_ZRO; 144 | } 145 | else if ((value >> 15) & 0x1) 146 | { 147 | // 最高位 1,负数 148 | COND = FL_NEG; 149 | } 150 | else 151 | { 152 | COND = FL_POS; 153 | } 154 | } 155 | 156 | // 加法指令,两种模式 157 | // add r0, r1, imm, 立即数模式 158 | // add r0, r1, r2,寄存器模式 159 | void add(int instr) 160 | { 161 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 162 | uint16_t r0 = (instr >> 9) & 0x7; 163 | 164 | // 源寄存器 r1,6~8 位, 165 | uint16_t r1 = (instr >> 6) & 0x7; 166 | 167 | // add 模式 168 | uint16_t flag = (instr >> 5) & 0x1; 169 | 170 | // 立即数模式 171 | if (flag) 172 | { 173 | // 低五位,取出立即数。 174 | uint16_t data = instr & 0x1F; 175 | 176 | // 符号扩展,若高位是 1,则全部补 1 177 | uint16_t value = sign_extend(data, 5); 178 | 179 | reg[r0] = reg[r1] + value; 180 | 181 | printf("add imm dr:%d, sr:%d, value:%d", r0, r1, value); 182 | } 183 | else 184 | { 185 | // 寄存器模式 186 | // 取出源寄存器 2,低 3 位 187 | uint16_t r2 = instr & 0x7; 188 | 189 | reg[r0] = reg[r1] + reg[r2]; 190 | } 191 | 192 | printf("reg_%d value:%d\n", r0, reg[r0]); 193 | 194 | // 更新标志寄存器 195 | update_flags(r0); 196 | } 197 | 198 | // 与运算,同 add ,两种模式 199 | void and (uint16_t instr) 200 | { 201 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 202 | uint16_t r0 = (instr >> 9) & 0x7; 203 | 204 | // 源寄存器 r1,6~8 位, 205 | uint16_t r1 = (instr >> 6) & 0x7; 206 | 207 | // add 模式 208 | uint16_t flag = (instr >> 5) & 0x1; 209 | 210 | // 立即数模式 211 | if (flag) 212 | { 213 | // 低五位,取出立即数。 214 | uint16_t data = instr & 0x1F; 215 | 216 | printf("add imm mode, imm:%d\n", data); 217 | 218 | // 符号扩展,若高位是 1,则全部补 1 219 | uint16_t value = sign_extend(data, 5); 220 | 221 | printf("add imm mode, sign_extend imm:%d\n", value); 222 | 223 | reg[r0] = reg[r1] & value; 224 | } 225 | else 226 | { 227 | puts("add reg mode"); 228 | 229 | // 寄存器模式 230 | // 取出源寄存器 2,低 3 位 231 | uint16_t r2 = instr & 0x7; 232 | 233 | reg[r0] = reg[r1] & reg[r2]; 234 | } 235 | 236 | printf("reg_%d value:%d\n", r0, reg[r0]); 237 | 238 | // 更新标志寄存器 239 | update_flags(r0); 240 | } 241 | 242 | // NOT r0, r1。将 r1 取反后,放入 r0 243 | void not(uint16_t instr) 244 | { 245 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 246 | uint16_t r0 = (instr >> 9) & 0x7; 247 | 248 | // 源寄存器 r1,6~8 位, 249 | uint16_t r1 = (instr >> 6) & 0x7; 250 | 251 | reg[r0] = ~reg[r1]; 252 | update_flags(r0); 253 | } 254 | 255 | // 标志条件跳转 256 | // br cond_flag, pc_offset 257 | void branch(uint16_t instr) 258 | { 259 | uint16_t cond_flag = (instr >> 9) & 0x7; 260 | uint16_t pc_offset = sign_extend(instr & 0x1FF, 9); 261 | 262 | // 传入标识与标志寄存器的值相符,N,P,Z 263 | if (cond_flag & COND) 264 | { 265 | PC += pc_offset; 266 | } 267 | } 268 | 269 | // jump r 270 | // 跳转到寄存器中的值 271 | void jump(uint16_t instr) 272 | { 273 | uint16_t r1 = (instr >> 6) & 0x7; 274 | PC = reg[r1]; 275 | } 276 | 277 | // load indirect,从内存中获取数据,放入寄存器。间接模式 278 | // 以 pc 寄存器作为偏移基准 279 | // ldi dr, pc_offset 280 | // [[pc+pc_offset]],pc+pc_offset 中的内容是数据的地址。 281 | void load_indirect(uint16_t instr) 282 | { 283 | uint16_t pc_offset = instr & 0x1ff; 284 | 285 | // 符号扩展 286 | pc_offset = sign_extend(pc_offset, 9); 287 | 288 | uint16_t r = (instr >> 9) & 0x7; 289 | 290 | // 取出存储数据的地址 291 | uint16_t address = mem_read(PC + pc_offset); 292 | 293 | // 取出数据 294 | uint16_t data = mem_read(address); 295 | 296 | // 更新寄存器 297 | reg[r] = data; 298 | 299 | printf("ldi r:%d, address:%d, data:%d\n", r, address, data); 300 | 301 | // 更新标志寄存器 302 | update_flags(r); 303 | } 304 | 305 | // 将地址放入寄存器 r 306 | // 以 pc 寄存器作为偏移基准 307 | // lea r, pc_offset 308 | void load_effective_address(uint16_t instr) 309 | { 310 | uint16_t pc_offset = instr & 0x1ff; 311 | 312 | // 符号扩展 313 | pc_offset = sign_extend(pc_offset, 9); 314 | 315 | uint16_t address = PC + pc_offset; 316 | 317 | uint16_t r = (instr >> 9) & 0x7; 318 | 319 | // 更新寄存器 320 | reg[r] = address; 321 | 322 | // 更新标志寄存器 323 | update_flags(r); 324 | } 325 | 326 | // jump resgister 327 | // 偏移量跳转 328 | void jump_subroutine(uint16_t instr) 329 | { 330 | uint16_t long_flag = (instr >> 11) & 0x1; 331 | 332 | // R7 保存 pc 值 333 | reg[R_R7] = PC; 334 | 335 | if (long_flag) 336 | { 337 | // long_pc_offset 338 | uint16_t long_pc_offset = sign_extend(instr & 0x7ff, 11); 339 | PC += long_pc_offset; 340 | } 341 | else 342 | { 343 | uint16_t r1 = (instr >> 6) & 0x7; 344 | PC = reg[r1]; 345 | } 346 | } 347 | 348 | // ld r, pc_offset 349 | // 以 pc 寄存器作为偏移基准 350 | // 将距离下一条指令 pc_offset 处里的数据取出来,放入 r 中。 351 | void load(uint16_t instr) 352 | { 353 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 354 | uint16_t r0 = (instr >> 9) & 0x7; 355 | reg[r0] = mem_read(PC + pc_offset); 356 | update_flags(r0); 357 | } 358 | 359 | // ldr r0, r1, offset 360 | // 以 r1 作为偏移基准 361 | // 将距离 r1,offset 处的数据取出来,放入 r0。 362 | void load_register(uint16_t instr) 363 | { 364 | uint16_t r0 = (instr >> 9) & 0x7; 365 | 366 | uint16_t r1 = (instr >> 6) & 0x7; 367 | 368 | uint16_t offset = sign_extend(instr & 0x3f, 6); 369 | 370 | uint16_t address = reg[r1] + offset; 371 | uint16_t value = mem_read(address); 372 | 373 | reg[r0] = value; 374 | update_flags(r0); 375 | } 376 | 377 | // st r, pc_offset 378 | // 以 pc 寄存器作为偏移基准 379 | // 将 r 中的数据放入距离下一条指令,pc_offset 的地址中。 380 | void store(uint16_t instr) 381 | { 382 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 383 | uint16_t r0 = (instr >> 9) & 0x7; 384 | 385 | uint16_t address = PC + pc_offset; 386 | uint16_t value = reg[r0]; 387 | 388 | mem_write(address, value); 389 | } 390 | 391 | // sti r, pc_offset,间接存储,pc+pc_offset 是待存储数据地址的地址。 392 | void store_indirect(uint16_t instr) 393 | { 394 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 395 | uint16_t r0 = (instr >> 9) & 0x7; 396 | 397 | uint16_t indirect_address = PC + pc_offset; 398 | uint16_t address = mem_read(indirect_address); 399 | 400 | uint16_t value = reg[r0]; 401 | 402 | mem_write(address, value); 403 | } 404 | 405 | // str r0, r1, offsets 406 | // 以 r1 作为偏移基准 407 | void store_register(uint16_t instr) 408 | { 409 | // r0 410 | uint16_t r0 = (instr >> 9) & 0x7; 411 | 412 | // r1 413 | uint16_t r1 = (instr >> 6) & 0x7; 414 | 415 | uint16_t offset = sign_extend(instr & 0x3f, 6); 416 | 417 | uint16_t address = reg[r1] + offset; 418 | uint16_t value = reg[r0]; 419 | 420 | mem_write(address, value); 421 | } 422 | 423 | // op = 1111 424 | void trap(int instr) 425 | { 426 | running = 0; 427 | } 428 | 429 | int main(int argc, const char *argv[]) 430 | { 431 | // 设置初始值 432 | PC = 0; 433 | 434 | printf("mem 10,%d\n", mem_read(10)); 435 | printf("mem 11,%d\n", mem_read(11)); 436 | printf("mem 12,%d\n", mem_read(12)); 437 | printf("mem 15,%d\n", mem_read(15)); 438 | 439 | // 用于打印当前执行操作码 440 | const char *op_list[] = {"BR", "ADD", "LD", "ST", "JSR", "AND", "LDR", "STR", "RTI", "NOT", "LDI", "STI", "JMP", "RES", "LEA", "TRAP"}; 441 | 442 | while (running) 443 | { 444 | // 读取指令 445 | u_int16_t instr = mem_read(PC++); 446 | 447 | // 指令操作码占 4 位 448 | u_int16_t op = instr >> 12; 449 | 450 | printf("exe op:%s\n", op_list[op]); 451 | 452 | switch (op) 453 | { 454 | case OP_ADD: 455 | { 456 | add(instr); 457 | break; 458 | } 459 | 460 | case OP_AND: 461 | { 462 | and(instr); 463 | break; 464 | } 465 | 466 | case OP_NOT: 467 | { 468 | not(instr); 469 | break; 470 | } 471 | 472 | case OP_BR: 473 | { 474 | branch(instr); 475 | break; 476 | } 477 | 478 | case OP_JMP: 479 | { 480 | jump(instr); 481 | break; 482 | } 483 | 484 | case OP_JSR: 485 | { 486 | jump_subroutine(instr); 487 | break; 488 | } 489 | 490 | case OP_LD: 491 | { 492 | load(instr); 493 | break; 494 | } 495 | 496 | case OP_LDI: 497 | { 498 | load_indirect(instr); 499 | break; 500 | } 501 | 502 | case OP_LDR: 503 | { 504 | load_register(instr); 505 | break; 506 | } 507 | 508 | case OP_LEA: 509 | { 510 | load_effective_address(instr); 511 | break; 512 | } 513 | 514 | case OP_ST: 515 | { 516 | store(instr); 517 | break; 518 | } 519 | 520 | case OP_STI: 521 | { 522 | store_indirect(instr); 523 | break; 524 | } 525 | 526 | case OP_STR: 527 | { 528 | store_register(instr); 529 | break; 530 | } 531 | 532 | case OP_TRAP: 533 | { 534 | trap(instr); 535 | break; 536 | } 537 | 538 | case OP_RTI: 539 | case OP_RES: 540 | break; 541 | 542 | default: 543 | { 544 | printf("Unknown OpCode!\n"); 545 | } 546 | break; 547 | } 548 | } 549 | 550 | printf("r0,%d\n", reg[R_R0]); 551 | printf("r1,%d\n", reg[R_R1]); 552 | printf("r2,%d\n", reg[R_R2]); 553 | 554 | printf("mem 10,%d\n", mem_read(10)); 555 | printf("mem 11,%d\n", mem_read(11)); 556 | printf("mem 15,%d\n", mem_read(15)); 557 | 558 | return 0; 559 | } -------------------------------------------------------------------------------- /mac/vm_lc_3_all.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | // 内存区 5 | uint16_t mem[UINT16_MAX]; 6 | 7 | // 载入地址 8 | uint16_t origin; 9 | 10 | // 程序运行状态 11 | int running = 1; 12 | 13 | // 寄存器定义 14 | typedef enum 15 | { 16 | R_R0, 17 | R_R1, 18 | R_R2, 19 | R_R3, 20 | R_R4, 21 | R_R5, 22 | R_R6, 23 | R_R7, 24 | R_PC, 25 | R_COND, 26 | R_COUNT 27 | } Registers; 28 | 29 | // 寄存器数组 30 | uint16_t reg[R_COUNT]; 31 | 32 | // 宏便捷定义 33 | // PC 寄存器 34 | #define PC (reg[R_PC]) 35 | 36 | // 标志寄存器 37 | #define COND (reg[R_COND]) 38 | 39 | // 指令定义 40 | typedef enum 41 | { 42 | OP_BR = 0, // 条件分支 43 | OP_ADD = 1, // 加法 44 | OP_LD = 2, // load 45 | OP_ST = 3, // store 46 | OP_JSR = 4, // jump resgister 47 | OP_AND = 5, // 与运算 48 | OP_LDR = 6, // load register 49 | OP_STR = 7, // store register 50 | OP_RTI = 8, // unused 51 | OP_NOT = 9, // 取反 52 | OP_LDI = 10, // load indirect 53 | OP_STI = 11, // store indirect 54 | OP_JMP = 12, // jump 55 | OP_RES = 13, // reserved 56 | OP_LEA = 14, // load effective address 57 | OP_TRAP = 15, // trap,陷阱,相当于中断 58 | } InstructionSet; 59 | 60 | // 标志定义 61 | typedef enum 62 | { 63 | FL_POS = 1 << 0, // 正数 64 | FL_ZRO = 1 << 1, // 0 65 | FL_NEG = 1 << 2 //负数 66 | } ConditionFlags; 67 | 68 | // 中断类型 69 | typedef enum 70 | { 71 | TRAP_GETC = 0x20, // 从键盘输入 72 | TRAP_OUT = 0x21, //输出字符 73 | TRAP_PUTS = 0x22, // 输出字符串 74 | TARP_IN = 0x23, 75 | TRAP_PUTSP = 0x24, 76 | TRAP_HALT = 0x25, // 退出程序 77 | } TrapSet; 78 | 79 | // 从内存读取数据 80 | uint16_t mem_read(int address) 81 | { 82 | if (address < 0 || address >= UINT16_MAX) 83 | { 84 | printf("memory read error!\n"); 85 | exit(4); 86 | } 87 | 88 | return mem[address]; 89 | } 90 | 91 | // 将 data 写入内存地址为 address 处 92 | void mem_write(uint16_t address, uint16_t data) 93 | { 94 | if (address < 0 || address >= UINT16_MAX) 95 | { 96 | printf("memory write error!\n"); 97 | exit(3); 98 | } 99 | 100 | mem[address] = data; 101 | } 102 | 103 | // 符号扩展 104 | uint16_t sign_extend(uint16_t x, int bit_count) 105 | { 106 | // 最高位 1 107 | if ((x >> (bit_count - 1)) & 0x1) 108 | { 109 | x |= 0xFFFF << bit_count; 110 | } 111 | 112 | return x; 113 | } 114 | 115 | // 更新标志寄存器 116 | void update_flags(uint16_t r) 117 | { 118 | uint16_t value = reg[r]; 119 | if (value == 0) 120 | { 121 | COND = FL_ZRO; 122 | } 123 | else if ((value >> 15) & 0x1) 124 | { 125 | // 最高位 1,负数 126 | COND = FL_NEG; 127 | } 128 | else 129 | { 130 | COND = FL_POS; 131 | } 132 | } 133 | 134 | // 加法指令,两种模式 135 | // add r0, r1, imm, 立即数模式 136 | // add r0, r1, r2,寄存器模式 137 | void add(int instr) 138 | { 139 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 140 | uint16_t r0 = (instr >> 9) & 0x7; 141 | 142 | // 源寄存器 r1,6~8 位, 143 | uint16_t r1 = (instr >> 6) & 0x7; 144 | 145 | // add 模式 146 | uint16_t flag = (instr >> 5) & 0x1; 147 | 148 | // 立即数模式 149 | if (flag) 150 | { 151 | // 低五位,取出立即数。 152 | uint16_t data = instr & 0x1F; 153 | 154 | // 符号扩展,若高位是 1,则全部补 1 155 | uint16_t value = sign_extend(data, 5); 156 | 157 | reg[r0] = reg[r1] + value; 158 | 159 | printf("add imm dr:%d, sr:%d, value:%d\n", r0, r1, value); 160 | } 161 | else 162 | { 163 | // 寄存器模式 164 | // 取出源寄存器 2,低 3 位 165 | uint16_t r2 = instr & 0x7; 166 | 167 | reg[r0] = reg[r1] + reg[r2]; 168 | } 169 | 170 | printf("reg_%d value:%d\n", r0, reg[r0]); 171 | 172 | // 更新标志寄存器 173 | update_flags(r0); 174 | } 175 | 176 | // 与运算,同 add ,两种模式 177 | void and (uint16_t instr) 178 | { 179 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 180 | uint16_t r0 = (instr >> 9) & 0x7; 181 | 182 | // 源寄存器 r1,6~8 位, 183 | uint16_t r1 = (instr >> 6) & 0x7; 184 | 185 | // add 模式 186 | uint16_t flag = (instr >> 5) & 0x1; 187 | 188 | // 立即数模式 189 | if (flag) 190 | { 191 | // 低五位,取出立即数。 192 | uint16_t data = instr & 0x1F; 193 | 194 | printf("add imm mode, imm:%d\n", data); 195 | 196 | // 符号扩展,若高位是 1,则全部补 1 197 | uint16_t value = sign_extend(data, 5); 198 | 199 | printf("add imm mode, sign_extend imm:%d\n", value); 200 | 201 | reg[r0] = reg[r1] & value; 202 | } 203 | else 204 | { 205 | puts("add reg mode"); 206 | 207 | // 寄存器模式 208 | // 取出源寄存器 2,低 3 位 209 | uint16_t r2 = instr & 0x7; 210 | 211 | reg[r0] = reg[r1] & reg[r2]; 212 | } 213 | 214 | printf("reg_%d value:%d\n", r0, reg[r0]); 215 | 216 | // 更新标志寄存器 217 | update_flags(r0); 218 | } 219 | 220 | // NOT r0, r1。将 r1 取反后,放入 r0 221 | void not(uint16_t instr) 222 | { 223 | // 取出目的寄存器 r0,9~11,占 3 位,与上 111 224 | uint16_t r0 = (instr >> 9) & 0x7; 225 | 226 | // 源寄存器 r1,6~8 位, 227 | uint16_t r1 = (instr >> 6) & 0x7; 228 | 229 | reg[r0] = ~reg[r1]; 230 | update_flags(r0); 231 | } 232 | 233 | // 标志条件跳转 234 | // br cond_flag, pc_offset 235 | void branch(uint16_t instr) 236 | { 237 | uint16_t cond_flag = (instr >> 9) & 0x7; 238 | uint16_t pc_offset = sign_extend(instr & 0x1FF, 9); 239 | 240 | // 传入标识与标志寄存器的值相符,N,P,Z 241 | if (cond_flag & COND) 242 | { 243 | PC += pc_offset; 244 | } 245 | } 246 | 247 | // jump r 248 | // 跳转到寄存器中的值 249 | void jump(uint16_t instr) 250 | { 251 | uint16_t r1 = (instr >> 6) & 0x7; 252 | PC = reg[r1]; 253 | } 254 | 255 | // load indirect,从内存中获取数据,放入寄存器。间接模式 256 | // 以 pc 寄存器作为偏移基准 257 | // ldi dr, pc_offset 258 | // [[pc+pc_offset]],pc+pc_offset 中的内容是数据的地址。 259 | void load_indirect(uint16_t instr) 260 | { 261 | uint16_t pc_offset = instr & 0x1ff; 262 | 263 | // 符号扩展 264 | pc_offset = sign_extend(pc_offset, 9); 265 | 266 | uint16_t r = (instr >> 9) & 0x7; 267 | 268 | // 取出存储数据的地址 269 | uint16_t address = mem_read(PC + pc_offset); 270 | 271 | // 取出数据 272 | uint16_t data = mem_read(address); 273 | 274 | // 更新寄存器 275 | reg[r] = data; 276 | 277 | printf("ldi r:%d, address:%d, data:%d\n", r, address, data); 278 | 279 | // 更新标志寄存器 280 | update_flags(r); 281 | } 282 | 283 | // 将地址放入寄存器 r 284 | // 以 pc 寄存器作为偏移基准 285 | // lea r, pc_offset 286 | void load_effective_address(uint16_t instr) 287 | { 288 | uint16_t pc_offset = instr & 0x1ff; 289 | 290 | // 符号扩展 291 | pc_offset = sign_extend(pc_offset, 9); 292 | 293 | uint16_t address = PC + pc_offset; 294 | 295 | uint16_t r = (instr >> 9) & 0x7; 296 | 297 | // 更新寄存器 298 | reg[r] = address; 299 | 300 | // 更新标志寄存器 301 | update_flags(r); 302 | } 303 | 304 | // jump resgister 305 | // 偏移量跳转 306 | void jump_subroutine(uint16_t instr) 307 | { 308 | uint16_t long_flag = (instr >> 11) & 0x1; 309 | 310 | // R7 保存 pc 值 311 | reg[R_R7] = PC; 312 | 313 | if (long_flag) 314 | { 315 | // long_pc_offset 316 | uint16_t long_pc_offset = sign_extend(instr & 0x7ff, 11); 317 | PC += long_pc_offset; 318 | } 319 | else 320 | { 321 | uint16_t r1 = (instr >> 6) & 0x7; 322 | PC = reg[r1]; 323 | } 324 | } 325 | 326 | // ld r, pc_offset 327 | // 以 pc 寄存器作为偏移基准 328 | // 将距离下一条指令 pc_offset 处里的数据取出来,放入 r 中。 329 | void load(uint16_t instr) 330 | { 331 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 332 | uint16_t r0 = (instr >> 9) & 0x7; 333 | reg[r0] = mem_read(PC + pc_offset); 334 | update_flags(r0); 335 | } 336 | 337 | // ldr r0, r1, offset 338 | // 以 r1 作为偏移基准 339 | // 将距离 r1,offset 处的数据取出来,放入 r0。 340 | void load_register(uint16_t instr) 341 | { 342 | uint16_t r0 = (instr >> 9) & 0x7; 343 | 344 | uint16_t r1 = (instr >> 6) & 0x7; 345 | 346 | uint16_t offset = sign_extend(instr & 0x3f, 6); 347 | 348 | uint16_t address = reg[r1] + offset; 349 | uint16_t value = mem_read(address); 350 | 351 | reg[r0] = value; 352 | update_flags(r0); 353 | } 354 | 355 | // st r, pc_offset 356 | // 以 pc 寄存器作为偏移基准 357 | // 将 r 中的数据放入距离下一条指令,pc_offset 的地址中。 358 | void store(uint16_t instr) 359 | { 360 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 361 | uint16_t r0 = (instr >> 9) & 0x7; 362 | 363 | uint16_t address = PC + pc_offset; 364 | uint16_t value = reg[r0]; 365 | 366 | mem_write(address, value); 367 | } 368 | 369 | // sti r, pc_offset,间接存储,pc+pc_offset 是待存储数据地址的地址。 370 | void store_indirect(uint16_t instr) 371 | { 372 | uint16_t pc_offset = sign_extend(instr & 0x1ff, 9); 373 | uint16_t r0 = (instr >> 9) & 0x7; 374 | 375 | uint16_t indirect_address = PC + pc_offset; 376 | uint16_t address = mem_read(indirect_address); 377 | 378 | uint16_t value = reg[r0]; 379 | 380 | mem_write(address, value); 381 | } 382 | 383 | // str r0, r1, offsets 384 | // 以 r1 作为偏移基准 385 | void store_register(uint16_t instr) 386 | { 387 | // r0 388 | uint16_t r0 = (instr >> 9) & 0x7; 389 | 390 | // r1 391 | uint16_t r1 = (instr >> 6) & 0x7; 392 | 393 | uint16_t offset = sign_extend(instr & 0x3f, 6); 394 | 395 | uint16_t address = reg[r1] + offset; 396 | uint16_t value = reg[r0]; 397 | 398 | mem_write(address, value); 399 | } 400 | 401 | // 将 r0 寄存器中地址处的字符串打印出来。1 个字符占 2 字节。 402 | void trap_puts() 403 | { 404 | uint16_t address = reg[R_R0]; 405 | 406 | printf("trap_puts begin address:%d\n", address); 407 | 408 | uint16_t *c = mem + address; 409 | 410 | while (*c) 411 | { 412 | putc((char)*c, stdout); 413 | ++c; 414 | } 415 | 416 | fflush(stdout); 417 | puts("\ntrap_puts end ..."); 418 | } 419 | 420 | // 等待输入一个字符,最后存入 r0 421 | void trap_getc() 422 | { 423 | puts("trap_getc begin ..."); 424 | 425 | // 清空输入缓冲区 426 | fflush(stdin); 427 | reg[R_R0] = (uint16_t)getchar(); 428 | 429 | puts("trap_getc end ..."); 430 | } 431 | 432 | // 将 r0 中的字符打印出来 433 | void trap_out() 434 | { 435 | puts("trap_out begin ..."); 436 | 437 | putc((char)reg[R_R0], stdout); 438 | fflush(stdout); 439 | 440 | puts("\ntrap_out end ..."); 441 | } 442 | 443 | // 提示输入一个字符,将字符打印,并放入 R0 444 | void trap_in() 445 | { 446 | puts("trap_in begin ..."); 447 | 448 | // 清空输入缓冲区 449 | fflush(stdin); 450 | 451 | printf("Enter a character:"); 452 | char c = getchar(); 453 | putc(c, stdout); 454 | reg[R_R0] = (uint16_t)c; 455 | 456 | puts("\ntrap_in end ..."); 457 | } 458 | 459 | // 将 r0 地址处的字符串出来,一个字符一字节 460 | void trap_put_string() 461 | { 462 | puts("trap_put_string begin ..."); 463 | 464 | uint16_t *c = mem + reg[R_R0]; 465 | while (*c) 466 | { 467 | // 低 8 位 468 | char char1 = (*c) & 0xff; 469 | putc(char1, stdout); 470 | 471 | // 高 8 位 472 | char char2 = (*c) >> 8; 473 | if (char2) 474 | { 475 | putc(char2, stdout); 476 | } 477 | 478 | ++c; 479 | } 480 | 481 | fflush(stdout); 482 | puts("\ntrap_put_string end ..."); 483 | } 484 | 485 | // op = 1111 486 | void trap(int instr) 487 | { 488 | // trap_code,低 8 位 489 | uint16_t trap_code = instr & 0xff; 490 | 491 | switch (trap_code) 492 | { 493 | case TRAP_GETC: 494 | { 495 | trap_getc(); 496 | break; 497 | } 498 | 499 | case TRAP_OUT: 500 | { 501 | trap_out(); 502 | break; 503 | } 504 | 505 | case TRAP_PUTS: 506 | { 507 | trap_puts(); 508 | break; 509 | } 510 | 511 | case TARP_IN: 512 | { 513 | trap_in(); 514 | break; 515 | } 516 | 517 | case TRAP_PUTSP: 518 | { 519 | trap_put_string(); 520 | break; 521 | } 522 | 523 | case TRAP_HALT: 524 | { 525 | puts("Halt"); 526 | running = 0; 527 | break; 528 | } 529 | 530 | default: 531 | { 532 | printf("Unknown TrapCode!\n"); 533 | break; 534 | } 535 | } 536 | } 537 | 538 | uint16_t swap16(uint16_t x) 539 | { 540 | // 两个字节交换 541 | return (x << 8) | (x >> 8); 542 | } 543 | 544 | // 文件存储是大端字节序,需转换为小端 545 | void read_image_file(FILE *file) 546 | { 547 | // 读取 2 字节 548 | fread(&origin, sizeof(origin), 1, file); 549 | 550 | // 大端转小端 551 | origin = swap16(origin); 552 | 553 | uint16_t max_read = UINT16_MAX - origin; 554 | uint16_t *p = mem + origin; 555 | 556 | // 读取文件内容到 p 指向的地址,以 2 字节为单位 557 | size_t read = fread(p, sizeof(uint16_t), max_read, file); 558 | 559 | // 大端转小端 560 | while (read-- > 0) 561 | { 562 | *p = swap16(*p); 563 | ++p; 564 | } 565 | } 566 | 567 | // 读取指令文件 568 | int read_image(const char *image_path) 569 | { 570 | FILE *file = fopen(image_path, "rb"); 571 | if (!file) 572 | { 573 | return 0; 574 | } 575 | 576 | read_image_file(file); 577 | 578 | fclose(file); 579 | return 1; 580 | } 581 | 582 | int main(int argc, const char *argv[]) 583 | { 584 | if (argc < 2) 585 | { 586 | printf("no lc3 image file ...\n"); 587 | exit(2); 588 | } 589 | 590 | for (int i = 0; i < argc; i++) 591 | { 592 | if (!read_image(argv[i])) 593 | { 594 | printf("failed to load image %s\n", argv[i]); 595 | exit(1); 596 | } 597 | } 598 | 599 | printf("origin:%0x\n", origin); 600 | 601 | // 设置初始值 602 | PC = origin; 603 | 604 | // 用于打印当前执行操作码 605 | const char *op_list[] = {"BR", "ADD", "LD", "ST", "JSR", "AND", "LDR", "STR", "RTI", "NOT", "LDI", "STI", "JMP", "RES", "LEA", "TRAP"}; 606 | 607 | while (running) 608 | { 609 | // 读取指令 610 | u_int16_t instr = mem_read(PC++); 611 | 612 | // 指令操作码占 4 位 613 | u_int16_t op = instr >> 12; 614 | 615 | printf("\n======= exe op:%s =======\n\n", op_list[op]); 616 | 617 | switch (op) 618 | { 619 | case OP_ADD: 620 | { 621 | add(instr); 622 | break; 623 | } 624 | 625 | case OP_AND: 626 | { 627 | and(instr); 628 | break; 629 | } 630 | 631 | case OP_NOT: 632 | { 633 | not(instr); 634 | break; 635 | } 636 | 637 | case OP_BR: 638 | { 639 | branch(instr); 640 | break; 641 | } 642 | 643 | case OP_JMP: 644 | { 645 | jump(instr); 646 | break; 647 | } 648 | 649 | case OP_JSR: 650 | { 651 | jump_subroutine(instr); 652 | break; 653 | } 654 | 655 | case OP_LD: 656 | { 657 | load(instr); 658 | break; 659 | } 660 | 661 | case OP_LDI: 662 | { 663 | load_indirect(instr); 664 | break; 665 | } 666 | 667 | case OP_LDR: 668 | { 669 | load_register(instr); 670 | break; 671 | } 672 | 673 | case OP_LEA: 674 | { 675 | load_effective_address(instr); 676 | break; 677 | } 678 | 679 | case OP_ST: 680 | { 681 | store(instr); 682 | break; 683 | } 684 | 685 | case OP_STI: 686 | { 687 | store_indirect(instr); 688 | break; 689 | } 690 | 691 | case OP_STR: 692 | { 693 | store_register(instr); 694 | break; 695 | } 696 | 697 | case OP_TRAP: 698 | { 699 | trap(instr); 700 | break; 701 | } 702 | 703 | case OP_RTI: 704 | case OP_RES: 705 | break; 706 | 707 | default: 708 | { 709 | printf("Unknown OpCode!\n"); 710 | } 711 | break; 712 | } 713 | } 714 | return 0; 715 | } --------------------------------------------------------------------------------