edea

A ps1 emulator in harelang
Log | Files | Refs

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 };