exec.c (11080B)
1 #include <stdint.h> 2 #include <inttypes.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <string.h> 6 7 #include "exec.h" 8 #include "mem.h" 9 #include "decode.h" 10 #include "trap.h" 11 12 static inline void print_bin16(uint16_t x) { 13 for (int i = 15; i >= 0; i--) { 14 putchar((x >> i) & 1 ? '1' : '0'); 15 /*if (i % 4 == 0) putchar(' '); grouping */ 16 } 17 } 18 19 static inline void print_bin32(uint32_t x) { 20 for (int i = 31; i >= 0; i--) { 21 putchar((x >> i) & 1 ? '1' : '0'); 22 } 23 } 24 25 static inline void print_binless(uint32_t x, int a) { 26 for (int i = a-1; i >= 0; i--) { 27 putchar((x >> i) & 1 ? '1' : '0'); 28 } 29 } 30 31 static void 32 raise_trap(cpu_state_t *cpu, trap_cause_t trapinfo, uint32_t tval) 33 { 34 cpu->status = CPU_TRAPPED; 35 cpu->trap.cause = trapinfo; 36 cpu->trap.pc = cpu->pc; 37 cpu->trap.tval = tval; 38 return; 39 } 40 41 static inline trap_cause_t 42 validate_instruction_address(int64_t addr) 43 { 44 if (addr < 0 || addr > (int64_t)MEMSIZE - INT64_C(4)) 45 return TRAP_INSTRUCTION_ACCESS_FAULT; 46 47 if ((addr & INT64_C(3)) != 0) 48 return TRAP_INSTRUCTION_MISALIGNED; 49 50 return TRAP_NONE; 51 } 52 53 static trap_cause_t 54 get_valid_branch_target(uint32_t pc, int32_t offset, uint32_t *target) 55 { 56 int64_t candidate = (int64_t)pc + (int64_t)offset; 57 58 trap_cause_t valid = validate_instruction_address(candidate); 59 if (valid != TRAP_NONE) 60 return valid; 61 62 *target = (uint32_t)candidate; 63 return valid; 64 } 65 66 static trap_cause_t 67 get_valid_jalr_target(uint32_t base, int32_t offset, uint32_t *target) 68 { 69 int64_t candidate = ((int64_t)base + (int64_t)offset) 70 & ~INT64_C(1); 71 trap_cause_t valid = validate_instruction_address(candidate); 72 if (valid != TRAP_NONE) 73 return valid; 74 75 *target = (uint32_t)candidate; 76 return valid; 77 } 78 79 static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 80 (void)mem; /* suppressing unused parameters warning */ 81 itype_t i; 82 decode_itype(&i, inst); 83 84 uint32_t x; uint32_t shamt; 85 uint32_t uimm = (uint32_t)i.imm; 86 switch(i.funct3) { 87 case 0x0: 88 x = cpu->x[i.rs1]+uimm; 89 break; 90 case 0x1: 91 if (i.funct7 == 0x00) { 92 shamt = i.imm & 31; 93 x = cpu->x[i.rs1] << shamt; 94 } else { 95 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 96 return; 97 } 98 break; 99 case 0x2: 100 x = ((int32_t)cpu->x[i.rs1] < (int32_t)i.imm) ? 1 : 0; 101 break; 102 case 0x3: 103 x = (cpu->x[i.rs1] < uimm) ? 1 : 0; 104 break; 105 case 0x4: 106 x = cpu->x[i.rs1]^uimm; 107 break; 108 case 0x5: 109 shamt = i.imm & 31; 110 switch(i.funct7) { 111 case 0x00: 112 x = cpu->x[i.rs1] >> shamt; 113 break; 114 case 0x20: 115 x = (uint32_t)((int32_t)cpu->x[i.rs1] >> shamt); 116 break; 117 default: 118 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 119 return; 120 } 121 break; 122 case 0x6: 123 x = cpu->x[i.rs1]|uimm; 124 break; 125 case 0x7: 126 x = cpu->x[i.rs1]&uimm; 127 break; 128 default: 129 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 130 return; 131 } 132 133 if (i.rd != 0) { 134 cpu->x[i.rd] = x; 135 } 136 137 cpu->pc += 4; 138 } 139 140 static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 141 (void)mem; /* suppressing unused parameters warning */ 142 rtype_t r; 143 decode_rtype(&r, inst); 144 145 uint32_t x; 146 uint32_t shamt; 147 switch(r.funct3) { 148 case 0x0: 149 switch(r.funct7) { 150 case 0x00: 151 x = cpu->x[r.rs1]+cpu->x[r.rs2]; 152 break; 153 case 0x20: 154 x = cpu->x[r.rs1]-cpu->x[r.rs2]; 155 break; 156 default: 157 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 158 return; 159 } 160 break; 161 case 0x1: 162 shamt = cpu->x[r.rs2] & 31; 163 x = cpu->x[r.rs1] << shamt; 164 break; 165 case 0x2: 166 x = ((int32_t)cpu->x[r.rs1] < (int32_t)cpu->x[r.rs2]) ? 1 : 0; 167 break; 168 case 0x3: 169 x = (cpu->x[r.rs1] < cpu->x[r.rs2]) ? 1 : 0; 170 break; 171 case 0x4: 172 x = cpu->x[r.rs1]^cpu->x[r.rs2]; 173 break; 174 case 0x5: 175 switch(r.funct7) { 176 case 0x00: 177 shamt = cpu->x[r.rs2] & 31; 178 x = cpu->x[r.rs1] >> shamt; 179 break; 180 case 0x20: 181 shamt = cpu->x[r.rs2] & 31; 182 x = (uint32_t)((int32_t)cpu->x[r.rs1] >> shamt); 183 break; 184 default: 185 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 186 return; 187 } 188 break; 189 case 0x6: 190 x = cpu->x[r.rs1]|cpu->x[r.rs2]; 191 break; 192 case 0x7: 193 x = cpu->x[r.rs1]&cpu->x[r.rs2]; 194 break; 195 default: 196 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 197 return; 198 } 199 200 if (r.rd != 0) { 201 cpu->x[r.rd] = x; 202 } 203 204 cpu->pc += 4; 205 } 206 207 static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 208 itype_t i; 209 decode_itype(&i, inst); 210 211 uint32_t addr = (uint32_t)i.imm + cpu->x[i.rs1]; 212 213 uint32_t x; 214 switch(i.funct3) { 215 case 0x0: 216 if (addr > MEMSIZE - 1) { 217 raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); 218 return; 219 } 220 221 x = (uint32_t)(int32_t)(int8_t)mem[addr]; 222 break; 223 case 0x1: 224 if ((addr & UINT32_C(0x1)) != 0) { 225 raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); 226 return; 227 } 228 229 if (addr + 1 > MEMSIZE - 1) { 230 raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); 231 return; 232 } 233 234 uint16_t half = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8); 235 x = (uint32_t)(int32_t)(int16_t)half; 236 break; 237 case 0x2: 238 if ((addr & UINT32_C(0x3)) != 0) { 239 raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); 240 return; 241 } 242 243 if (addr + 3 > MEMSIZE - 1) { 244 raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); 245 return; 246 } 247 248 /* TODO: clean up */ 249 x = (uint32_t)(int32_t)( 250 ((uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8)) 251 | 252 (((uint16_t)mem[addr+2] | ((uint16_t)mem[addr+3] << 8)) 253 << 16) 254 ); 255 break; 256 case 0x4: 257 if (addr > MEMSIZE - 1) { 258 raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); 259 return; 260 } 261 262 x = (uint32_t)(uint8_t)mem[addr]; 263 break; 264 case 0x5: 265 if ((addr & UINT32_C(0x1)) != 0) { 266 raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); 267 return; 268 } 269 270 if (addr + 1 > MEMSIZE - 1) { 271 raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); 272 return; 273 } 274 275 uint16_t uhalf = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8); 276 x = (uint32_t)uhalf; 277 break; 278 default: 279 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 280 return; 281 } 282 283 if (i.rd != 0) { 284 cpu->x[i.rd] = x; 285 } 286 cpu->pc += 4; 287 } 288 289 static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 290 stype_t s; 291 decode_stype(&s, inst); 292 293 uint32_t addr = (uint32_t)s.imm + cpu->x[s.rs1]; 294 295 /* TODO: helpers, better checks */ 296 switch(s.funct3) { 297 case 0x0: 298 if (addr > MEMSIZE - 1) { 299 raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); 300 return; 301 } 302 303 mem[addr] = cpu->x[s.rs2] & 255; 304 break; 305 case 0x1: 306 if ((addr & UINT32_C(0x1)) != 0) { 307 raise_trap(cpu, TRAP_STORE_MISALIGNED, inst); 308 return; 309 } 310 311 if (addr + 1 > MEMSIZE - 1) { 312 raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); 313 return; 314 } 315 316 if (addr % 2 == 0) { 317 mem[addr] = (uint8_t)cpu->x[s.rs2]; 318 mem[addr+1] = (uint8_t)(cpu->x[s.rs2] >> 8); 319 } 320 break; 321 case 0x2: 322 if ((addr & UINT32_C(0x3)) != 0) { 323 raise_trap(cpu, TRAP_STORE_MISALIGNED, inst); 324 return; 325 } 326 327 if (addr + 3 > MEMSIZE - 1) { 328 raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); 329 return; 330 } 331 if (addr % 4 == 0) { 332 mem[addr] = (uint8_t)cpu->x[s.rs2]; 333 mem[addr+1] = (uint8_t)(cpu->x[s.rs2] >> 8); 334 mem[addr+2] = (uint8_t)(cpu->x[s.rs2] >> 16); 335 mem[addr+3] = (uint8_t)(cpu->x[s.rs2] >> 24); 336 } 337 break; 338 default: 339 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 340 return; 341 } 342 343 cpu->pc += 4; 344 } 345 346 static void exec_btype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 347 (void)mem; /* suppressing unused parameters warning */ 348 btype_t b; 349 decode_btype(&b, inst); 350 351 int jump = 0; 352 switch (b.funct3) { 353 case 0x0: 354 if (cpu->x[b.rs1] == cpu->x[b.rs2]) 355 jump = 1; 356 break; 357 case 0x1: 358 if (cpu->x[b.rs1] != cpu->x[b.rs2]) 359 jump = 1; 360 break; 361 case 0x4: 362 if ((int32_t)cpu->x[b.rs1] < (int32_t)cpu->x[b.rs2]) 363 jump = 1; 364 break; 365 case 0x5: 366 if ((int32_t)cpu->x[b.rs1] >= (int32_t)cpu->x[b.rs2]) 367 jump = 1; 368 break; 369 case 0x6: 370 if (cpu->x[b.rs1] < cpu->x[b.rs2]) 371 jump = 1; 372 break; 373 case 0x7: 374 if (cpu->x[b.rs1] >= cpu->x[b.rs2]) 375 jump = 1; 376 break; 377 default: 378 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 379 return; 380 } 381 382 if (jump == 1) { 383 uint32_t target; 384 trap_cause_t cause = get_valid_branch_target(cpu->pc, 385 b.imm, 386 &target); 387 if (cause != TRAP_NONE) { 388 raise_trap(cpu, cause, inst); 389 return; 390 } 391 cpu->pc = target; 392 } else { 393 cpu->pc += 4; 394 } 395 } 396 397 static void exec_itype_jalr(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 398 (void)mem; /* suppressing unused parameters warning */ 399 itype_t i; 400 decode_itype(&i, inst); 401 402 uint32_t x; 403 if (i.funct3 != 0x0) { 404 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 405 return; 406 } 407 408 x = cpu->pc + 4; 409 410 uint32_t target; 411 trap_cause_t cause = get_valid_jalr_target(cpu->x[i.rs1], i.imm, 412 &target); 413 if (cause != TRAP_NONE) { 414 raise_trap(cpu, cause, inst); 415 return; 416 } 417 418 cpu->pc = target; 419 420 if (i.rd != 0) { 421 cpu->x[i.rd] = x; 422 } 423 } 424 425 static void exec_jtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { 426 (void)mem; /* suppressing unused parameters warning */ 427 jtype_t j; 428 decode_jtype(&j, inst); 429 430 uint32_t target; 431 trap_cause_t cause = get_valid_branch_target(cpu->pc, 432 (int32_t)j.imm, 433 &target); 434 if (cause != TRAP_NONE) { 435 raise_trap(cpu, cause, inst); 436 return; 437 } 438 439 if (j.rd != 0) { 440 uint32_t x = cpu->pc + 4; 441 cpu->x[j.rd] = x; 442 } 443 cpu->pc = target; 444 } 445 446 static void 447 exec_utype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) 448 { 449 (void)mem; /* suppressing unused parameters warning */ 450 utype_t u; 451 decode_utype(&u, inst); 452 453 if (u.rd != 0) 454 cpu->x[u.rd] = u.imm << 12; 455 456 cpu->pc += 4; 457 } 458 459 static void 460 exec_utype_auipc(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) 461 { 462 (void)mem; /* suppressing unused parameters warning */ 463 utype_t u; 464 decode_utype(&u, inst); 465 466 if (u.rd != 0) 467 cpu->x[u.rd] = cpu->pc + (u.imm << 12); 468 469 cpu->pc += 4; 470 } 471 472 static void 473 exec_itype_control(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) 474 { 475 (void)mem; /* suppressing unused parameters warning */ 476 itype_t i; 477 decode_itype(&i, inst); 478 479 if (i.funct3 != 0x0) { 480 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 481 return; 482 } 483 484 if (i.imm == 0x0) { 485 raise_trap(cpu, TRAP_ECALL, inst); 486 return; 487 } else if (i.imm == 0x1) { 488 raise_trap(cpu, TRAP_EBREAK, inst); 489 return; 490 } else { 491 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 492 return; 493 } 494 495 } 496 497 static void 498 exec_itype_fence(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) 499 { 500 (void)mem; /* suppressing unused parameters warning */ 501 itype_t i; 502 decode_itype(&i, inst); 503 504 if (i.funct3 != 0x0) { 505 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 506 return; 507 } 508 509 cpu->pc += 4; 510 } 511 512 /* Function pointer dispatch */ 513 typedef void (*exec_fn)(cpu_state_t *, uint32_t inst, uint8_t *mem); 514 515 static exec_fn opcode_table[128] = { 516 [0x33] = exec_rtype, 517 [0x13] = exec_itype, 518 [0x03] = exec_itype_loads, 519 [0x67] = exec_itype_jalr, 520 [0x73] = exec_itype_control, 521 [0x0f] = exec_itype_fence, 522 [0x23] = exec_stype, 523 [0x63] = exec_btype, 524 [0x6f] = exec_jtype, 525 [0x37] = exec_utype, 526 [0x17] = exec_utype_auipc 527 }; 528 /***/ 529 530 void 531 cpu_step(cpu_state_t *cpu, uint8_t *mem) 532 { 533 uint32_t inst = load_u32_le(mem, cpu->pc); /* load little endian */ 534 535 /* decode opcode */ 536 uint16_t opcode = inst & 127; 537 538 exec_fn fn = opcode_table[opcode]; 539 540 if (!fn) { 541 raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); 542 return; 543 } 544 545 fn(cpu,inst,mem); 546 }