main.c (8508B)
1 #include "emu.h" 2 3 static void set_zsp(emu_t *e, uint8_t res) { 4 FLAG_PUT(e, F_Z, res == 0); 5 FLAG_PUT(e, F_S, (res & 0x80) != 0); 6 FLAG_PUT(e, F_P, parity_even(res)); 7 } 8 9 uint8_t emu_set(emu_t *e, uint8_t r, uint8_t v) { 10 switch (r) { 11 case REG_A: e->a = v; break; 12 case REG_B: e->b = v; break; 13 case REG_C: e->c = v; break; 14 case REG_D: e->d = v; break; 15 case REG_E: e->e = v; break; 16 case REG_H: e->h = v; break; 17 case REG_L: e->l = v; break; 18 case REG_M: 19 { 20 uint16_t hl = ((uint16_t)e->h << 8) | e->l; 21 e->mem[hl] = v; 22 break; 23 } 24 default: return 0; 25 } 26 return 0; 27 } 28 29 uint8_t emu_get(emu_t *e, uint8_t r) { 30 switch (r) { 31 case REG_A: return e->a; 32 case REG_B: return e->b; 33 case REG_C: return e->c; 34 case REG_D: return e->d; 35 case REG_E: return e->e; 36 case REG_H: return e->h; 37 case REG_L: return e->l; 38 case REG_M: 39 { 40 uint16_t hl = ((uint16_t)e->h << 8) | e->l; 41 return e->mem[hl]; 42 } 43 default: return 0; 44 } 45 } 46 47 int emu_execute(emu_t *e, uint8_t i) { 48 uint8_t part1 = (i >> 6) & 0x03; 49 uint8_t dst = (i >> 3) & 0x07; 50 uint8_t src = i & 0x07; 51 52 switch (part1) { 53 case OP_MV: 54 /* 01110110: hlt */ 55 if (dst == REG_M && src == REG_M) { 56 return 1; 57 } 58 emu_set(e, dst, emu_get(e, src)); 59 e->pc += 1; 60 break; 61 62 case OP_ZZ: 63 { 64 if (src == 0b110) { 65 /* mvi r, data */ 66 emu_set(e, dst, e->mem[e->pc + 1]); 67 e->pc += 2; 68 } else if (src == OP_INC) { 69 /* inr r */ 70 uint8_t old = emu_get(e, dst); 71 uint8_t val = old + 1; 72 FLAG_PUT(e, F_AC, ((old & 0x0F) + 1 > 0x0F)); 73 emu_set(e, dst, val); 74 set_zsp(e, val); 75 e->pc += 1; 76 } else if (src == OP_DEC) { 77 /* dcr r */ 78 uint8_t old = emu_get(e, dst); 79 uint8_t val = old - 1; 80 FLAG_PUT(e, F_AC, ((old & 0x0F) - 1 < 0)); 81 emu_set(e, dst, val); 82 set_zsp(e, val); 83 e->pc += 1; 84 } else if (src == 0b010 && (dst == REG_A || dst == REG_M)) { 85 /* lda / sta */ 86 uint16_t addr = (uint16_t)e->mem[e->pc + 1] | 87 ((uint16_t)e->mem[e->pc + 2] << 8); 88 if (dst == REG_A) { 89 e->a = e->mem[addr]; 90 } else if (dst == REG_M) { 91 e->mem[addr] = e->a; 92 } 93 e->pc += 3; 94 } else { 95 e->pc += 1; 96 } 97 break; 98 } 99 100 case OP_ALU: 101 { 102 uint8_t alu_op = dst; 103 uint8_t val = emu_get(e, src); 104 uint8_t a = e->a; 105 106 switch (alu_op) { 107 case OP_ALU_ADD: 108 { 109 uint16_t res = (uint16_t)a + val; 110 e->a = (uint8_t)res; 111 FLAG_PUT(e, F_CY, res > 0xFF); 112 FLAG_PUT(e, F_AC, ((a & 0x0F) + (val & 0x0F) > 0x0F)); 113 set_zsp(e, e->a); 114 break; 115 } 116 case OP_ALU_ADC: 117 { 118 uint8_t cy = FLAG_GET(e, F_CY); 119 uint16_t res = (uint16_t)a + val + cy; 120 e->a = (uint8_t)res; 121 FLAG_PUT(e, F_CY, res > 0xFF); 122 FLAG_PUT(e, F_AC, ((a & 0x0F) + (val & 0x0F) + cy > 0x0F)); 123 set_zsp(e, e->a); 124 break; 125 } 126 case OP_ALU_SUB: 127 { 128 int16_t res = (int16_t)a - val; 129 e->a = (uint8_t)res; 130 FLAG_PUT(e, F_CY, res < 0); 131 FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) < 0)); 132 set_zsp(e, e->a); 133 break; 134 } 135 case OP_ALU_SBB: 136 { 137 uint8_t cy = FLAG_GET(e, F_CY); 138 int16_t res = (int16_t)a - val - cy; 139 e->a = (uint8_t)res; 140 FLAG_PUT(e, F_CY, res < 0); 141 FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) - cy < 0)); 142 set_zsp(e, e->a); 143 break; 144 } 145 case OP_ALU_ANA: 146 { 147 e->a &= val; 148 FLAG_PUT(e, F_CY, 0); 149 FLAG_PUT(e, F_AC, ((a | val) & 0x08) != 0); 150 set_zsp(e, e->a); 151 break; 152 } 153 case OP_ALU_XRA: 154 { 155 e->a ^= val; 156 FLAG_PUT(e, F_CY, 0); 157 FLAG_PUT(e, F_AC, 0); 158 set_zsp(e, e->a); 159 break; 160 } 161 case OP_ALU_ORA: 162 { 163 e->a |= val; 164 FLAG_PUT(e, F_CY, 0); 165 FLAG_PUT(e, F_AC, 0); 166 set_zsp(e, e->a); 167 break; 168 } 169 case OP_ALU_CMP: 170 { 171 int16_t res = (int16_t)a - val; 172 FLAG_PUT(e, F_CY, res < 0); 173 FLAG_PUT(e, F_AC, ((a & 0x0F) - (val & 0x0F) < 0)); 174 set_zsp(e, (uint8_t)res); 175 break; 176 } 177 } 178 e->pc += 1; 179 break; 180 } 181 182 case OP_OO: 183 { 184 if (src == REG_M) { 185 /* immediate alu */ 186 uint8_t imm = e->mem[e->pc + 1]; 187 uint8_t alu_op = dst; 188 uint8_t a = e->a; 189 190 switch (alu_op) { 191 case OP_ALU_ADD: /* adi */ 192 { 193 uint16_t res = (uint16_t)a + imm; 194 e->a = (uint8_t)res; 195 FLAG_PUT(e, F_CY, res > 0xFF); 196 FLAG_PUT(e, F_AC, ((a & 0x0F) + (imm & 0x0F) > 0x0F)); 197 set_zsp(e, e->a); 198 break; 199 } 200 case OP_ALU_SUB: /* sui */ 201 { 202 int16_t res = (int16_t)a - imm; 203 e->a = (uint8_t)res; 204 FLAG_PUT(e, F_CY, res < 0); 205 FLAG_PUT(e, F_AC, ((a & 0x0F) - (imm & 0x0F) < 0)); 206 set_zsp(e, e->a); 207 break; 208 } 209 case OP_ALU_CMP: /* cpi */ 210 { 211 int16_t res = (int16_t)a - imm; 212 FLAG_PUT(e, F_CY, res < 0); 213 FLAG_PUT(e, F_AC, ((a & 0x0F) - (imm & 0x0F) < 0)); 214 set_zsp(e, (uint8_t)res); 215 break; 216 } 217 } 218 e->pc += 2; 219 } else if (src == OP_JMP) { 220 /* jmp */ 221 uint16_t addr = (uint16_t)e->mem[e->pc + 1] | 222 ((uint16_t)e->mem[e->pc + 2] << 8); 223 e->pc = addr; 224 } else if (src == OP_J) { 225 /* conditional jumps */ 226 bool jump = false; 227 switch (dst) { 228 case 0b000: jump = (FLAG_GET(e, F_Z) == 0); break; /* JNZ */ 229 case 0b001: jump = (FLAG_GET(e, F_Z) != 0); break; /* JZ */ 230 case 0b010: jump = (FLAG_GET(e, F_CY) == 0); break;/* JNC */ 231 case 0b011: jump = (FLAG_GET(e, F_CY) != 0); break;/* JC */ 232 case 0b100: jump = (FLAG_GET(e, F_P) == 0); break; /* JPO */ 233 case 0b101: jump = (FLAG_GET(e, F_P) != 0); break; /* JPE */ 234 case 0b110: jump = (FLAG_GET(e, F_S) == 0); break; /* JP */ 235 case 0b111: jump = (FLAG_GET(e, F_S) != 0); break; /* JM */ 236 } 237 238 if (jump) { 239 uint16_t addr = (uint16_t)e->mem[e->pc + 1] | 240 ((uint16_t)e->mem[e->pc + 2] << 8); 241 e->pc = addr; 242 } else { 243 e->pc += 3; 244 } 245 } else { 246 e->pc += 1; 247 } 248 break; 249 } 250 251 default: 252 return 1; 253 } 254 return 0; 255 } 256 257 void emu_start(emu_t *e) { 258 int running = 1; 259 e->pc = 0; 260 261 while (running) { 262 uint8_t instr = e->mem[e->pc]; 263 int res = emu_execute(e, instr); 264 if (res != 0) break; 265 } 266 } 267 268 EXPORT emu_t* emu_create(void) { 269 emu_t *e = (emu_t*)calloc(1, sizeof(emu_t)); 270 return e; 271 } 272 273 EXPORT void emu_destroy(emu_t *e) { 274 if (e) { 275 free(e); 276 } 277 } 278 279 EXPORT int emu_load_program(emu_t *e, const char *filename) { 280 if (!e || !filename) return -1; 281 282 FILE *f = fopen(filename, "rb"); 283 if (!f) return -1; 284 285 size_t n = fread(e->mem, 1, MEMORY_SIZE, f); 286 fclose(f); 287 288 return (n > 0) ? 0 : -1; 289 } 290 291 EXPORT int emu_step(emu_t *e) { 292 if (!e) return 1; 293 uint8_t instr = e->mem[e->pc]; 294 return emu_execute(e, instr); 295 } 296 297 EXPORT int emu_get_pc(emu_t *e) { 298 return e ? (int)e->pc : 0; 299 } 300 301 EXPORT void emu_set_pc(emu_t *e, int pc) { 302 if (e) { 303 e->pc = (uint16_t)pc; 304 } 305 } 306 307 EXPORT void emu_mem_write(emu_t *e, uint16_t addr, byte val) { 308 if (e) { 309 e->mem[addr] = val; 310 } 311 } 312 313 EXPORT byte emu_mem_read(emu_t *e, uint16_t addr) { 314 return e ? e->mem[addr] : 0; 315 } 316 317 EXPORT byte emu_get_reg(emu_t *e, byte c) { 318 return e ? emu_get(e, c) : 0; 319 }