cpu.ha (25012B)
1 // THE GOAT 2 3 use fmt; 4 use math::checked; 5 use os; 6 7 use interconnect; 8 use cpu::instruction; 9 10 let flag = false; 11 12 export type CPU = struct{ 13 // Program Counter 14 pc: u32, 15 next_pc: u32, 16 current_pc: u32, 17 // Status Register 18 sr: u32, 19 // hi register 20 hi: u32, 21 // lo register 22 lo: u32, 23 // Cop0 register 13: Cause register 24 cause: u32, 25 // Cop0 register 14: EPC 26 epc: u32, 27 28 // Set by the current instruction if a branch occured and the next 29 // instruction will be on the delay slot 30 branch: bool, 31 // If the current instruction executes on the delay slot 32 delay_slot: bool, 33 out_regs: [32]u32, 34 load: (u32, u32), 35 regs: [32]u32, 36 inter: interconnect::Interconnect, 37 next_instruction: instruction::instruction, 38 }; 39 40 export type EXCEPTION = enum { 41 LOAD_ADDRESS_ERROR = 0x4, 42 STORE_ADDRESS_ERROR = 0x5, 43 SYSCALL = 0x8, 44 BREAK = 0x9, 45 ILLEGAL_INSTRUCTION = 0xa, 46 COPROCESSOR_ERROR = 0xb, 47 OVERFLOW = 0xc, 48 }; 49 50 export fn new(inter: interconnect::Interconnect) CPU = { 51 let regs: [32]u32 = [0xdeadbeef...]; 52 regs[0] = 0; 53 let pc: u32 = 0xbfc00000; 54 let cpu = CPU { 55 pc = pc, 56 next_pc = pc + 4, 57 current_pc = 0, 58 sr = 0, 59 hi = 0xdeadbeef, 60 lo = 0xdeadbeef, 61 cause = 0, 62 epc = 0, 63 branch = false, 64 delay_slot = false, 65 regs = regs, 66 out_regs = regs, 67 load = (0, 0), 68 inter = inter, 69 next_instruction = instruction::new(0x0), 70 }; 71 72 return cpu; 73 }; 74 75 fn set_reg(cpu: *CPU, reg: u32, val: u32) void = { 76 cpu.out_regs[reg] = val; 77 cpu.out_regs[0] = 0; 78 }; 79 80 fn reg(cpu: *CPU, reg: u32) u32 = { 81 return cpu.out_regs[reg]; 82 }; 83 84 fn load32(cpu: *CPU, addr: u32) u32 = { 85 return interconnect::load32(cpu.inter, addr); 86 }; 87 88 fn load16(cpu: *CPU, addr: u32) u16 = { 89 return interconnect::load16(cpu.inter, addr); 90 }; 91 92 fn load8(cpu: *CPU, addr: u32) u8 = { 93 return interconnect::load8(cpu.inter, addr); 94 }; 95 96 fn store32(cpu: *CPU, addr: u32, val: u32) void = { 97 interconnect::store32(cpu.inter, addr, val); 98 return; 99 }; 100 101 fn store16(cpu: *CPU, addr: u32, val: u16) void = { 102 interconnect::store16(cpu.inter, addr, val); 103 return; 104 }; 105 106 fn store8(cpu: *CPU, addr: u32, val: u8) void = { 107 interconnect::store8(cpu.inter, addr, val); 108 return; 109 }; 110 111 fn op_lui(cpu: *CPU, instruction: instruction::instruction) void = { 112 let i = instruction; 113 let v = i.imm << 16; 114 115 set_reg(cpu, i.t, v); 116 }; 117 118 fn op_ori(cpu: *CPU, instruction: instruction::instruction) void = { 119 let i = instruction.imm; 120 let t = instruction.t; 121 let s = instruction.s; 122 123 let v = reg(cpu, s) | i; 124 125 set_reg(cpu, t, v); 126 }; 127 128 fn op_andi(cpu: *CPU, instruction: instruction::instruction) void = { 129 let i = instruction.imm; 130 let t = instruction.t; 131 let s = instruction.s; 132 133 let v = reg(cpu, s) & i; 134 135 set_reg(cpu, t, v); 136 }; 137 138 fn op_or(cpu: *CPU, instruction: instruction::instruction) void = { 139 let d = instruction.d; 140 let t = instruction.t; 141 let s = instruction.s; 142 143 let v = reg(cpu, instruction.s) | reg(cpu, instruction.t); 144 145 set_reg(cpu, d, v); 146 }; 147 148 fn op_xor(cpu: *CPU, instruction: instruction::instruction) void = { 149 let d = instruction.d; 150 let t = instruction.t; 151 let s = instruction.s; 152 153 let v = reg(cpu, instruction.s) ^ reg(cpu, instruction.t); 154 155 set_reg(cpu, d, v); 156 }; 157 158 fn op_xori(cpu: *CPU, instruction: instruction::instruction) void = { 159 let i = instruction.imm; 160 let t = instruction.t; 161 let s = instruction.s; 162 163 let v = reg(cpu, instruction.s) ^ i; 164 165 set_reg(cpu, t, v); 166 }; 167 168 fn op_nor(cpu: *CPU, instruction: instruction::instruction) void = { 169 let d = instruction.d; 170 let t = instruction.t; 171 let s = instruction.s; 172 173 let v = ~(reg(cpu, instruction.s) | reg(cpu, instruction.t)); 174 175 set_reg(cpu, d, v); 176 }; 177 178 fn op_and(cpu: *CPU, instruction: instruction::instruction) void = { 179 let d = instruction.d; 180 let t = instruction.t; 181 let s = instruction.s; 182 183 let v = reg(cpu, s) & reg(cpu, t); 184 185 set_reg(cpu, d, v); 186 }; 187 188 fn op_sw(cpu: *CPU, instruction: instruction::instruction) void = { 189 190 if (cpu.sr & 0x10000 != 0) { 191 fmt::println("Ignoring store while cache is isolated")!; 192 return; 193 }; 194 195 let i = instruction.imm_se; 196 let t = instruction.t; 197 let s = instruction.s; 198 199 let addr = reg(cpu, s) + i; 200 let v = reg(cpu, t); 201 202 if (addr % 4 == 0) { 203 store32(cpu, addr, v); 204 205 } else { 206 exception(cpu, EXCEPTION::STORE_ADDRESS_ERROR); 207 }; 208 209 }; 210 211 fn op_swl(cpu: *CPU, instruction: instruction::instruction) void = { 212 let i = instruction.imm_se; 213 let t = instruction.t; 214 let s = instruction.s; 215 216 let addr = reg(cpu, s) + i; 217 let v = reg(cpu, t); 218 219 let aligned_addr = addr & ~3; 220 let cur_mem = load32(cpu, aligned_addr); 221 222 let mem = switch(addr & 3) { 223 case 0 => yield (cur_mem & 0xffffff00) | (v >> 24); 224 case 1 => yield (cur_mem & 0xffff0000) | (v >> 16); 225 case 2 => yield (cur_mem & 0xff000000) | (v >> 8); 226 case 3 => yield (cur_mem & 0x00000000) | (v >> 0); 227 case => fmt::fatalf("UNREACHABLE!"); 228 }; 229 230 store32(cpu, addr, mem); 231 232 }; 233 234 fn op_swr(cpu: *CPU, instruction: instruction::instruction) void = { 235 let i = instruction.imm_se; 236 let t = instruction.t; 237 let s = instruction.s; 238 239 let addr = reg(cpu, s) + i; 240 let v = reg(cpu, t); 241 242 let aligned_addr = addr & ~3; 243 let cur_mem = load32(cpu, aligned_addr); 244 245 let mem = switch(addr & 3) { 246 case 0 => yield (cur_mem & 0x00000000) | (v << 0); 247 case 1 => yield (cur_mem & 0x000000ff) | (v << 8); 248 case 2 => yield (cur_mem & 0x0000ffff) | (v << 16); 249 case 3 => yield (cur_mem & 0x00ffffff) | (v << 24); 250 case => fmt::fatalf("UNREACHABLE!"); 251 }; 252 253 store32(cpu, addr, mem); 254 255 }; 256 257 fn op_sh(cpu: *CPU, instruction: instruction::instruction) void = { 258 259 if (cpu.sr & 0x10000 != 0) { 260 fmt::println("Ignoring store while cache is isolated")!; 261 return; 262 }; 263 264 let i = instruction.imm_se; 265 let t = instruction.t; 266 let s = instruction.s; 267 268 let addr = reg(cpu, s) + i; 269 let v = reg(cpu, t); 270 271 if (addr % 2 == 0) { 272 store16(cpu, addr, v: u16); 273 } else { 274 exception(cpu, EXCEPTION::STORE_ADDRESS_ERROR); 275 }; 276 277 }; 278 279 fn op_sb(cpu: *CPU, instruction: instruction::instruction) void = { 280 281 if (cpu.sr & 0x10000 != 0) { 282 fmt::println("Ignoring store while cache is isolated")!; 283 return; 284 }; 285 286 let i = instruction.imm_se; 287 let t = instruction.t; 288 let s = instruction.s; 289 290 let addr = reg(cpu, s) + i; 291 let v = reg(cpu, t); 292 293 store8(cpu, addr, v: u8); 294 }; 295 296 fn op_sll(cpu: *CPU, instruction: instruction::instruction) void = { 297 let i = instruction.shift; 298 let t = instruction.t; 299 let d = instruction.d; 300 301 let v = reg(cpu, t) << i; 302 303 set_reg(cpu, d, v); 304 }; 305 306 fn op_sllv(cpu: *CPU, instruction: instruction::instruction) void = { 307 let d = instruction.d; 308 let s = instruction.s; 309 let t = instruction.t; 310 311 let v = reg(cpu, t) << (reg(cpu, s) & 0x1f); 312 313 set_reg(cpu, d, v); 314 }; 315 316 fn op_slt(cpu: *CPU, instruction: instruction::instruction) void = { 317 let d = instruction.d; 318 let s = instruction.s; 319 let t = instruction.t; 320 321 let s = reg(cpu, s): i32; 322 let t = reg(cpu, t): i32; 323 324 let v: u32 = if (s < t) 1 else 0; 325 326 set_reg(cpu, d, v: u32); 327 }; 328 329 fn op_sltu(cpu: *CPU, instruction: instruction::instruction) void = { 330 let d = instruction.d; 331 let s = instruction.s; 332 let t = instruction.t; 333 334 let v: u32 = if (reg(cpu, s) < reg(cpu, t)) 1 else 0; 335 336 set_reg(cpu, d, v); 337 }; 338 339 fn op_slti(cpu: *CPU, instruction: instruction::instruction) void = { 340 let i = instruction.imm_se: i32; 341 let s = instruction.s; 342 let t = instruction.t; 343 344 let s = reg(cpu, s): i32; 345 346 let v: u32 = if (s < i) 1 else 0; 347 348 set_reg(cpu, t, v: u32); 349 }; 350 351 fn op_sltiu(cpu: *CPU, instruction: instruction::instruction) void = { 352 let i = instruction.imm_se; 353 let s = instruction.s; 354 let t = instruction.t; 355 356 let v: u32 = if (reg(cpu, s) < i) 1 else 0; 357 358 set_reg(cpu, t, v: u32); 359 }; 360 361 fn op_addiu(cpu: *CPU, instruction: instruction::instruction) void = { 362 let i = instruction.imm_se; 363 let t = instruction.t; 364 let s = instruction.s; 365 366 let v = reg(cpu, s) + i; 367 368 set_reg(cpu, t, v); 369 }; 370 371 fn op_addi(cpu: *CPU, instruction: instruction::instruction) void = { 372 let i = instruction.imm_se: i32; 373 let t = instruction.t; 374 let s = instruction.s; 375 376 let s = reg(cpu, s): i32; 377 378 let (v, overflowed) = math::checked::addi32(s, i); 379 380 if (overflowed) { 381 exception(cpu, EXCEPTION::OVERFLOW); 382 } else { 383 set_reg(cpu, t, v: u32); 384 }; 385 386 }; 387 388 fn op_addu(cpu: *CPU, instruction: instruction::instruction) void = { 389 let d = instruction.d; 390 let t = instruction.t; 391 let s = instruction.s; 392 393 let v = reg(cpu, s) + reg(cpu, t); 394 395 set_reg(cpu, d, v); 396 }; 397 398 fn op_add(cpu: *CPU, instruction: instruction::instruction) void = { 399 let s = instruction.s; 400 let t = instruction.t; 401 let d = instruction.d; 402 403 let s = reg(cpu, s): i32; 404 let t = reg(cpu, t): i32; 405 406 let (v, overflowed) = math::checked::addi32(s, t); 407 408 if (overflowed) { 409 exception(cpu, EXCEPTION::OVERFLOW); 410 } else { 411 set_reg(cpu, d, v: u32); 412 }; 413 414 }; 415 416 fn op_subu(cpu: *CPU, instruction: instruction::instruction) void = { 417 let s = instruction.s; 418 let t = instruction.t; 419 let d = instruction.d; 420 421 let v = reg(cpu, s) - reg(cpu, t); 422 423 set_reg(cpu, d, v); 424 }; 425 426 fn op_sub(cpu: *CPU, instruction: instruction::instruction) void = { 427 let s = instruction.s; 428 let t = instruction.t; 429 let d = instruction.d; 430 431 let s = reg(cpu, s): i32; 432 let t = reg(cpu, t): i32; 433 434 let (v, overflowed) = math::checked::subi32(s, t); 435 436 if (overflowed) { 437 exception(cpu, EXCEPTION::OVERFLOW); 438 } else { 439 set_reg(cpu, d, v: u32); 440 }; 441 442 }; 443 444 fn op_mtc0(cpu: *CPU, instruction: instruction::instruction) void = { 445 let cpu_r = instruction.t; 446 let cop_r = instruction.d; 447 448 let v = reg(cpu, cpu_r); 449 450 switch (cop_r) { 451 case 3,5,6,7,9,11 => if (v != 0) fmt::fatalf("Unhandled write to cop0 register"); 452 case 12 => cpu.sr = v; 453 case 13 => if (v != 0) fmt::fatalf("Unhandled write to CAUSE register"); 454 case => fmt::fatalf("Unhandled cop0 register {:.08X}", cop_r); 455 }; 456 }; 457 458 fn op_mfc0(cpu: *CPU, instruction: instruction::instruction) void = { 459 let cpu_r = instruction.t; 460 let cop_r = instruction.d; 461 462 let v: u32 = 0; 463 464 switch (cop_r) { 465 case 12 => v = cpu.sr; 466 case 13 => v = cpu.cause; 467 case 14 => v = cpu.epc; 468 case => fmt::fatalf("Unhandled read from cop0 register{:X}", cop_r); 469 }; 470 471 cpu.load = (cpu_r, v); 472 }; 473 474 fn op_rfe(cpu: *CPU, instruction: instruction::instruction) void = { 475 if (instruction.instr & 0x3f != 0b010000) 476 fmt::fatalf("Invalid cop0 instruction {:X}", instruction.instr); 477 478 let mode = cpu.sr & 0x3f; 479 cpu.sr &= ~0x3f; 480 cpu.sr |= mode >> 2; 481 }; 482 483 fn op_cop0(cpu: *CPU, instruction: instruction::instruction) void = { 484 485 switch (instruction.cop_opcode) { 486 case 0b00000 => op_mfc0(cpu, instruction); 487 case 0b00100 => op_mtc0(cpu, instruction); 488 case 0b10000 => op_rfe(cpu, instruction); 489 case => fmt::fatalf("Unhandled cop0 instruction {:X} - cop op_code {:X}", instruction.instr, instruction.cop_opcode); 490 }; 491 }; 492 493 fn op_cop1(cpu: *CPU, instruction: instruction::instruction) void = { 494 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 495 }; 496 497 fn op_cop2(cpu: *CPU, instruction: instruction::instruction) void = { 498 fmt::fatalf("Unhandled GTE instruction: {:.08X}", instruction.instr); 499 }; 500 501 fn op_cop3(cpu: *CPU, instruction: instruction::instruction) void = { 502 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 503 }; 504 505 fn op_lwc0(cpu: *CPU, instruction: instruction::instruction) void = { 506 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 507 }; 508 509 fn op_lwc1(cpu: *CPU, instruction: instruction::instruction) void = { 510 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 511 }; 512 513 fn op_lwc2(cpu: *CPU, instruction: instruction::instruction) void = { 514 fmt::fatalf("Unhandled GTE LWC: {:X}", instruction.instr); 515 }; 516 517 fn op_lwc3(cpu: *CPU, instruction: instruction::instruction) void = { 518 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 519 }; 520 521 fn op_swc0(cpu: *CPU, instruction: instruction::instruction) void = { 522 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 523 }; 524 525 fn op_swc1(cpu: *CPU, instruction: instruction::instruction) void = { 526 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 527 }; 528 529 fn op_swc2(cpu: *CPU, instruction: instruction::instruction) void = { 530 fmt::fatalf("Unhandled GTE SWC: {:X}", instruction.instr); 531 }; 532 533 fn op_swc3(cpu: *CPU, instruction: instruction::instruction) void = { 534 exception(cpu, EXCEPTION::COPROCESSOR_ERROR); 535 }; 536 537 fn op_lw(cpu: *CPU, instruction: instruction::instruction) void = { 538 let i = instruction.imm_se; 539 let t = instruction.t; 540 let s = instruction.s; 541 542 let addr = reg(cpu, s) + i; 543 544 if (addr % 4 == 0) { 545 let v = load32(cpu, addr); 546 cpu.load = (t, v); 547 } else { 548 exception(cpu, EXCEPTION::LOAD_ADDRESS_ERROR); 549 }; 550 551 }; 552 553 fn op_lwl(cpu: *CPU, instruction: instruction::instruction) void = { 554 let i = instruction.imm_se; 555 let t = instruction.t; 556 let s = instruction.s; 557 558 let addr = reg(cpu, s) + i; 559 560 let cur_v = cpu.out_regs[t]; 561 562 let aligned_addr = addr & ~3; 563 let aligned_word = load32(cpu, aligned_addr); 564 565 let v = switch(addr & 3) { 566 case 0 => yield (cur_v & 0x00ffffff) | (aligned_word << 24); 567 case 1 => yield (cur_v & 0x0000ffff) | (aligned_word << 16); 568 case 2 => yield (cur_v & 0x000000ff) | (aligned_word << 8); 569 case 3 => yield (cur_v & 0x00000000) | (aligned_word << 0); 570 case => fmt::fatalf("UNREACHABLE!"); 571 }; 572 573 cpu.load = (t, v); 574 575 }; 576 577 fn op_lwr(cpu: *CPU, instruction: instruction::instruction) void = { 578 let i = instruction.imm_se; 579 let t = instruction.t; 580 let s = instruction.s; 581 582 let addr = reg(cpu, s) + i; 583 584 let cur_v = cpu.out_regs[t]; 585 586 let aligned_addr = addr & ~3; 587 let aligned_word = load32(cpu, aligned_addr); 588 589 let v = switch(addr & 3) { 590 case 0 => yield (cur_v & 0x00000000) | (aligned_word >> 0); 591 case 1 => yield (cur_v & 0xff000000) | (aligned_word >> 8); 592 case 2 => yield (cur_v & 0xffff0000) | (aligned_word >> 16); 593 case 3 => yield (cur_v & 0xffffff00) | (aligned_word >> 24); 594 case => fmt::fatalf("UNREACHABLE!"); 595 }; 596 597 cpu.load = (t, v); 598 599 }; 600 601 fn op_lb(cpu: *CPU, instruction: instruction::instruction) void = { 602 let i = instruction.imm_se; 603 let t = instruction.t; 604 let s = instruction.s; 605 606 let addr = reg(cpu, s) + i; 607 608 let v = load8(cpu, addr): i8; 609 610 cpu.load = (t, v: u32); 611 }; 612 613 fn op_lbu(cpu: *CPU, instruction: instruction::instruction) void = { 614 let i = instruction.imm_se; 615 let t = instruction.t; 616 let s = instruction.s; 617 618 let addr = reg(cpu, s) + i; 619 620 let v = load8(cpu, addr); 621 622 cpu.load = (t, v: u32); 623 }; 624 625 fn op_lh(cpu: *CPU, instruction: instruction::instruction) void = { 626 let i = instruction.imm_se; 627 let t = instruction.t; 628 let s = instruction.s; 629 630 let addr = reg(cpu, s) + i; 631 632 let v = load16(cpu, addr): i16; 633 cpu.load = (t, v: u32); 634 }; 635 636 637 fn op_lhu(cpu: *CPU, instruction: instruction::instruction) void = { 638 let i = instruction.imm_se; 639 let t = instruction.t; 640 let s = instruction.s; 641 642 let addr = reg(cpu, s) + i; 643 644 if (addr % 2 == 0) { 645 let v = load16(cpu, addr); 646 cpu.load = (t, v: u32); 647 } else { 648 exception(cpu, EXCEPTION::LOAD_ADDRESS_ERROR); 649 }; 650 }; 651 652 fn op_sra(cpu: *CPU, instruction: instruction::instruction) void = { 653 // DEBUG 654 // Casting shift value to i32 because hare doesn't support 655 // bitwise operations on signed values. 656 let i = instruction.shift: i32; 657 let t = instruction.t; 658 let d = instruction.d; 659 660 let t = reg(cpu, t): i32; 661 662 let v = t >> i; 663 664 cpu.load = (d, v: u32); 665 }; 666 667 fn op_srav(cpu: *CPU, instruction: instruction::instruction) void = { 668 // DEBUG 669 // The same thing as sra.. but here we cast a value of u32 670 // to i32. that must have some implications. keep an eye on this 671 let d = instruction.d; 672 let s = instruction.s; 673 let t = instruction.t; 674 675 let t = reg(cpu, t): i32; 676 let s = reg(cpu, s): i32; 677 678 let v = t >> (s & 0x1f); 679 680 cpu.load = (d, v: u32); 681 }; 682 683 fn op_srlv(cpu: *CPU, instruction: instruction::instruction) void = { 684 let d = instruction.d; 685 let s = instruction.s; 686 let t = instruction.t; 687 688 let t = reg(cpu, t); 689 let s = reg(cpu, s); 690 691 let v = t >> (s & 0x1f); 692 693 cpu.load = (d, v: u32); 694 }; 695 696 fn op_srl(cpu: *CPU, instruction: instruction::instruction) void = { 697 let i = instruction.shift; 698 let t = instruction.t; 699 let d = instruction.d; 700 701 let v = reg(cpu, t) >> i; 702 703 cpu.load = (d, v: u32); 704 }; 705 706 fn op_div(cpu: *CPU, instruction: instruction::instruction) void = { 707 let s = instruction.s; 708 let t = instruction.t; 709 710 let n = reg(cpu, s): i32; 711 let d = reg(cpu, t): i32; 712 713 if (d == 0) { 714 cpu.hi = n: u32; 715 if (n >= 0) { 716 cpu.lo = 0xffffffff; 717 } else { 718 cpu.lo = 1; 719 }; 720 } else if (((n: u32) == 0x80000000) && d == -1) { 721 cpu.hi = 0; 722 cpu.lo = 0x80000000; 723 } else { 724 cpu.hi = (n % d): u32; 725 cpu.lo = (n / d): u32; 726 }; 727 728 }; 729 730 fn op_divu(cpu: *CPU, instruction: instruction::instruction) void = { 731 let s = instruction.s; 732 let t = instruction.t; 733 734 let n = reg(cpu, s); 735 let d = reg(cpu, t); 736 737 if (d == 0) { 738 cpu.hi = n; 739 cpu.lo = 0xffffffff; 740 } else { 741 cpu.hi = n % d; 742 cpu.lo = n / d; 743 }; 744 745 }; 746 747 fn op_multu(cpu: *CPU, instruction: instruction::instruction) void = { 748 let s = instruction.s; 749 let t = instruction.t; 750 751 let a = reg(cpu, s): u64; 752 let b = reg(cpu, t): u64; 753 754 let v = a * b; 755 756 cpu.hi = (v >> 32): u32; 757 cpu.lo = v: u32; 758 759 }; 760 761 fn op_mult(cpu: *CPU, instruction: instruction::instruction) void = { 762 let s = instruction.s; 763 let t = instruction.t; 764 765 let a = (reg(cpu, s): i32): u64; 766 let b = (reg(cpu, t): i32): u64; 767 768 let v = (a * b): u64; 769 770 cpu.hi = (v >> 32): u32; 771 cpu.lo = v: u32; 772 773 }; 774 775 fn op_mflo(cpu: *CPU, instruction: instruction::instruction) void = { 776 let d = instruction.d; 777 let lo = cpu.lo; 778 set_reg(cpu, d, lo); 779 }; 780 781 fn op_mtlo(cpu: *CPU, instruction: instruction::instruction) void = { 782 let s = instruction.s; 783 cpu.lo = reg(cpu, s); 784 }; 785 786 fn op_mfhi(cpu: *CPU, instruction: instruction::instruction) void = { 787 let d = instruction.d; 788 let hi = cpu.hi; 789 set_reg(cpu, d, hi); 790 }; 791 792 fn op_mthi(cpu: *CPU, instruction: instruction::instruction) void = { 793 let s = instruction.s; 794 cpu.hi = reg(cpu, s); 795 }; 796 797 798 // Jump - Branch Instructions 799 800 fn op_j(cpu: *CPU, instruction: instruction::instruction) void = { 801 let i = instruction.imm_jump; 802 cpu.next_pc = (cpu.pc & 0xf0000000) | (i << 2); 803 cpu.branch = true; 804 }; 805 806 fn op_jr(cpu: *CPU, instruction: instruction::instruction) void = { 807 let s = instruction.s; 808 cpu.next_pc = reg(cpu, s); 809 cpu.branch = true; 810 }; 811 812 fn op_jal(cpu: *CPU, instruction: instruction::instruction) void = { 813 let ra = cpu.next_pc; 814 set_reg(cpu, 31, ra); 815 op_j(cpu, instruction); 816 }; 817 818 fn op_jalr(cpu: *CPU, instruction: instruction::instruction) void = { 819 let d = instruction.d; 820 let s = instruction.s; 821 822 let ra = cpu.next_pc; 823 824 set_reg(cpu, d, ra); 825 826 cpu.next_pc = reg(cpu, s); 827 828 cpu.branch = true; 829 }; 830 831 fn op_bne(cpu: *CPU, instruction: instruction::instruction) void = { 832 let i = instruction.imm_se; 833 let t = instruction.t; 834 let s = instruction.s; 835 836 if (reg(cpu, s) != reg(cpu, t)) 837 branch(cpu, i); 838 }; 839 840 fn op_beq(cpu: *CPU, instruction: instruction::instruction) void = { 841 let i = instruction.imm_se; 842 let t = instruction.t; 843 let s = instruction.s; 844 845 if (reg(cpu, s) == reg(cpu, t)) 846 branch(cpu, i); 847 }; 848 849 fn op_bgtz(cpu: *CPU, instruction: instruction::instruction) void = { 850 let i = instruction.imm_se; 851 let s = instruction.s; 852 853 let v = reg(cpu, s): i32; 854 855 if (v > 0) branch(cpu, i); 856 }; 857 858 fn op_blez(cpu: *CPU, instruction: instruction::instruction) void = { 859 let i = instruction.imm_se; 860 let s = instruction.s; 861 862 let v = reg(cpu, s): i32; 863 864 if (v <= 0) branch(cpu, i); 865 }; 866 867 fn op_bxx(cpu: *CPU, instruction: instruction::instruction) void = { 868 let i = instruction.imm_se; 869 let s = instruction.s; 870 871 //fmt::printfln("INSTR: {:.032b}", instruction.instr)!; 872 //fmt::printfln("SHIFTED: {:.032b} {}", instruction.instr >> 16, (instruction.instr >> 16) & 1)!; 873 //fmt::printfln("SHIFTED: {:.032b} {}", instruction.instr >> 20, (instruction.instr >> 20) & 1 != 0)!; 874 875 let is_bgez = (instruction.instr >> 16) & 1; 876 let is_link = (instruction.instr >> 20) & 1 != 0; 877 878 let v = reg(cpu, s): i32; 879 880 let test: u32 = if (v < 0) 1 else 0; 881 882 test ^= is_bgez; 883 884 if (test != 0) { 885 if (is_link) { 886 let ra = cpu.pc; 887 set_reg(cpu, 31, ra); 888 }; 889 branch(cpu, i); 890 }; 891 }; 892 893 fn branch(cpu: *CPU, _off: u32) void = { 894 let off = _off << 2; 895 cpu.next_pc += off; 896 cpu.next_pc -= 4; 897 cpu.branch = true; 898 }; 899 900 901 fn exception(cpu: *CPU, cause: EXCEPTION) void = { 902 // Exception handler address depends on the `BEV` bit; 903 let handler: u32 = if (cpu.sr & (1 << 22) != 0 ) 0xbfc00180 else 0x80000080; 904 905 // fmt::printfln("CPU SR: {:.032b}, mode: {:.032b} ", cpu.sr, cpu.sr & ~0x3f)!; 906 let mode = cpu.sr & 0x3f; 907 cpu.sr &= ~0x3f; 908 cpu.sr |= (mode << 2) & 0x3f; 909 910 cpu.cause = (cause: u32) << 2; 911 //fmt::printfln("{:.08b} - {:.08b}", 0b00000001, ~0b000000001i8 )!; 912 cpu.epc = cpu.current_pc; 913 914 if (cpu.delay_slot) { 915 // So.. When an exception occurs in a delay slot `EPC` points to 916 // the branch instruction AND bit 31 of `CAUSE` register is set 917 cpu.epc -= 4; 918 cpu.cause |= 1 << 31; 919 }; 920 921 cpu.pc = handler; 922 cpu.next_pc = cpu.pc + 4; 923 924 return; 925 }; 926 927 fn op_break(cpu: *CPU, instruction: instruction::instruction) void = { 928 exception(cpu, EXCEPTION::BREAK); 929 }; 930 931 fn op_exception(cpu: *CPU, instruction: instruction::instruction) void = { 932 exception(cpu, EXCEPTION::SYSCALL); 933 }; 934 935 fn op_illegal(cpu: *CPU, instruction: instruction::instruction) void = { 936 fmt::printfln("Illegal instruction {:X}!", instruction.instr)!; 937 exception(cpu, EXCEPTION::ILLEGAL_INSTRUCTION); 938 }; 939 940 export fn run_next_instruction(cpu: *CPU) void = { 941 let pc = cpu.pc; 942 943 // Save the address for the current instruction in case of an exception 944 cpu.current_pc = cpu.pc; 945 946 if (cpu.current_pc % 4 != 0) { 947 exception(cpu, EXCEPTION::LOAD_ADDRESS_ERROR); 948 return; 949 }; 950 951 let instruction = instruction::new(load32(cpu, pc)); 952 953 cpu.delay_slot = cpu.branch; 954 cpu.branch = false; 955 956 cpu.pc = cpu.next_pc; 957 958 cpu.next_pc = cpu.next_pc + 4; 959 960 // Execute the pending load 961 let (reg, val) = cpu.load; 962 963 set_reg(cpu, reg, val); 964 965 cpu.load = (0, 0); 966 967 decode_and_execute(cpu, instruction); 968 969 cpu.regs = cpu.out_regs; 970 }; 971 972 fn decode_and_execute(cpu: *CPU, instruction: instruction::instruction) void = { 973 //fmt::printfln("{:X} {:b} - {:b}", cpu.out_regs[3], instruction.func, instruction.sub)!; 974 switch (instruction.func) { 975 case 0b000000 => 976 switch (instruction.sub) { 977 case 0b000000 => op_sll(cpu, instruction); 978 case 0b000100 => op_sllv(cpu, instruction); 979 case 0b100101 => op_or(cpu, instruction); 980 case 0b100110 => op_xor(cpu, instruction); 981 case 0b100111 => op_nor(cpu, instruction); 982 case 0b100100 => op_and(cpu, instruction); 983 case 0b101011 => op_sltu(cpu, instruction); 984 case 0b101010 => op_slt(cpu, instruction); 985 case 0b100001 => op_addu(cpu, instruction); 986 case 0b100000 => op_add(cpu, instruction); 987 case 0b001000 => op_jr(cpu, instruction); 988 case 0b001001 => op_jalr(cpu, instruction); 989 case 0b100011 => op_subu(cpu, instruction); 990 case 0b100010 => op_sub(cpu, instruction); 991 case 0b000011 => op_sra(cpu, instruction); 992 case 0b000111 => op_srav(cpu, instruction); 993 case 0b000110 => op_srlv(cpu, instruction); 994 case 0b000010 => op_srl(cpu, instruction); 995 case 0b011010 => op_div(cpu, instruction); 996 case 0b011011 => op_divu(cpu, instruction); 997 case 0b011000 => op_mult(cpu, instruction); 998 case 0b011001 => op_multu(cpu, instruction); 999 case 0b010010 => op_mflo(cpu, instruction); 1000 case 0b010011 => op_mtlo(cpu, instruction); 1001 case 0b010000 => op_mfhi(cpu, instruction); 1002 case 0b010001 => op_mthi(cpu, instruction); 1003 case 0b001101 => op_break(cpu, instruction); 1004 case 0b001100 => op_exception(cpu, instruction); 1005 case => fmt::fatalf("PC: {:.08X}, Unhandled instruction 0X{:.08X} - 0b{:.032b}", cpu.pc, instruction.instr, instruction.instr); 1006 }; 1007 case 0b001111 => op_lui(cpu, instruction); 1008 case 0b001101 => op_ori(cpu, instruction); 1009 case 0b001110 => op_xori(cpu, instruction); 1010 case 0b101011 => op_sw(cpu, instruction); 1011 case 0b101010 => op_swl(cpu, instruction); 1012 case 0b101110 => op_swr(cpu, instruction); 1013 case 0b001001 => op_addiu(cpu, instruction); 1014 case 0b001000 => op_addi(cpu, instruction); 1015 case 0b000010 => op_j(cpu, instruction); 1016 case 0b010000 => op_cop0(cpu, instruction); 1017 case 0b010001 => op_cop1(cpu, instruction); 1018 case 0b010010 => op_cop2(cpu, instruction); 1019 case 0b010011 => op_cop3(cpu, instruction); 1020 case 0b000101 => op_bne(cpu, instruction); 1021 case 0b100011 => op_lw(cpu, instruction); 1022 case 0b100010 => op_lwl(cpu, instruction); 1023 case 0b100110 => op_lwr(cpu, instruction); 1024 case 0b110000 => op_lwc0(cpu, instruction); 1025 case 0b110001 => op_lwc1(cpu, instruction); 1026 case 0b110010 => op_lwc2(cpu, instruction); 1027 case 0b110011 => op_lwc3(cpu, instruction); 1028 case 0b111000 => op_swc0(cpu, instruction); 1029 case 0b111001 => op_swc1(cpu, instruction); 1030 case 0b111010 => op_swc2(cpu, instruction); 1031 case 0b111011 => op_swc3(cpu, instruction); 1032 case 0b101001 => op_sh(cpu, instruction); 1033 case 0b000011 => op_jal(cpu, instruction); 1034 case 0b001100 => op_andi(cpu, instruction); 1035 case 0b101000 => op_sb(cpu, instruction); 1036 case 0b100000 => op_lb(cpu, instruction); 1037 case 0b100100 => op_lbu(cpu, instruction); 1038 case 0b100101 => op_lhu(cpu, instruction); 1039 case 0b100001 => op_lh(cpu, instruction); 1040 case 0b000100 => op_beq(cpu, instruction); 1041 case 0b000111 => op_bgtz(cpu, instruction); 1042 case 0b000110 => op_blez(cpu, instruction); 1043 case 0b000001 => op_bxx(cpu, instruction); 1044 case 0b001010 => op_slti(cpu, instruction); 1045 case 0b001011 => op_sltiu(cpu, instruction); 1046 case => op_illegal(cpu, instruction);//fmt::fatalf("CPU: {:X}, Unhandled instruction 0X{:.08X} - 0b{:.032b}", cpu.pc, instruction.instr, instruction.instr); 1047 }; 1048 };