2024-08-31 23:57:44 +02:00

1658 lines
30 KiB
Dart

import 'package:dartboy/emulator/bus.dart';
import 'package:dartboy/emulator/utils.dart';
class _F extends BitFieldU8 {
_F() : super({});
_F.fromU8(int u8) : super.fromU8(u8);
Bit get c => value(4);
Bit get h => value(5);
Bit get n => value(6);
Bit get z => value(7);
}
class Cpu {
Cpu({
required this.bus,
});
int _a = 0;
_F _f = _F();
int _bc = 0;
int _de = 0;
int _hl = 0;
int _sp = 0;
int _pc = 0;
int _stalls = 0;
bool _ime = false;
bool _halted = false;
int _left = -1;
Bus bus;
void reset() {
_a = 0x01;
_f = _F.fromU8(0xB0);
_bc = 0x0013;
_de = 0x00D8;
_hl = 0x014D;
_sp = 0xFFFE;
_pc = 0x0100;
_stalls = 0;
}
void tick() {
if (_stalls > 0) {
_stalls -= 1;
return;
}
_stalls += 4;
if (_ime && _interrupt()) {
_ime = false;
_halted = false;
}
if (_halted) {
return;
}
if (_left > 0) _left -= 1;
if (_left == 0) {
return;
}
final opecode = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
_doMnemonic(opecode);
}
int get _b => (_bc & 0xFF00) >> 8;
int get _c => _bc & 0x00FF;
int get _d => (_de & 0xFF00) >> 8;
int get _e => _de & 0x00FF;
int get _h => (_hl & 0xFF00) >> 8;
int get _l => _hl & 0x00FF;
int get _af => (_a << 8) | _f.toU8();
set _b(int val) {
_bc &= 0x00FF;
_bc |= (val << 8).toU16();
}
set _c(int val) {
_bc &= 0xFF00;
_bc |= val;
}
set _d(int val) {
_de &= 0x00FF;
_de |= (val << 8).toU16();
}
set _e(int val) {
_de &= 0xFF00;
_de |= val;
}
set _h(int val) {
_hl &= 0x00FF;
_hl |= (val << 8).toU16();
}
set _l(int val) {
_hl &= 0xFF00;
_hl |= val;
}
set _af(int val) {
_a = (val >> 8).toU8();
_f = _F.fromU8(val & 0x00F0);
}
int _r8(int index) {
switch (index) {
case 0:
return _b;
case 1:
return _c;
case 2:
return _d;
case 3:
return _e;
case 4:
return _h;
case 5:
return _l;
case 6:
return bus.read(_hl);
case 7:
return _a;
default:
throw ArgumentError.value(index);
}
}
void _setR8(int index, int val) {
switch (index) {
case 0:
_b = val;
break;
case 1:
_c = val;
break;
case 2:
_d = val;
break;
case 3:
_e = val;
break;
case 4:
_h = val;
break;
case 5:
_l = val;
break;
case 6:
bus.write(_hl, val);
break;
case 7:
_a = val;
break;
default:
throw ArgumentError.value(index);
}
}
int _r16(int index, bool high) {
switch (index) {
case 0:
return _bc;
case 1:
return _de;
case 2:
return _hl;
case 3:
if (high) {
return _af;
} else {
return _sp;
}
default:
throw ArgumentError.value(index);
}
}
void _setR16(int index, int val, bool high) {
switch (index) {
case 0:
_bc = val;
break;
case 1:
_de = val;
break;
case 2:
_hl = val;
break;
case 3:
if (high) {
_af = val;
} else {
_sp = val;
}
break;
default:
throw ArgumentError.value(index);
}
}
bool _carryPositive(int left, int right) {
return (left & 0xFF) + (right & 0xFF) > 0xFF;
}
bool _carryNegative(int left, int right) {
return (left & 0xFF) < (right & 0xFF);
}
bool _halfCarryPositive(int left, int right) {
return (left & 0x0F) + (right & 0x0F) > 0x0F;
}
bool _halfCarryNegative(int left, int right) {
return (left & 0x0F) < (right & 0x0F);
}
bool _carryPositiveU16(int left, int right) {
return (left & 0xFFFF) + (right & 0xFFFF) > 0xFFFF;
}
bool _halfCarryPositiveU16U12(int left, int right) {
return (left & 0x0FFF) + (right & 0x0FFF) > 0x0FFF;
}
bool _interrupt() {
int interrupt = 0x0040;
if (bus.ie.vBlank.val && bus.irqVBlank) {
bus.irqVBlank = false;
_call(interrupt);
return true;
}
interrupt += 0x0008;
if (bus.ie.lcdStat.val && bus.irqLcdStat) {
bus.irqLcdStat = false;
_call(interrupt);
return true;
}
interrupt += 0x0008;
if (bus.ie.timer.val && bus.irqTimer) {
bus.irqTimer = false;
_call(interrupt);
return true;
}
interrupt += 0x0008;
if (bus.ie.serial.val && bus.irqSerial) {
bus.irqSerial = false;
_call(interrupt);
return true;
}
interrupt += 0x0008;
if (bus.ie.joypad.val && bus.irqJoypad) {
bus.irqJoypad = false;
_call(interrupt);
return true;
}
return false;
}
void _doMnemonic(int opecode) {
switch (opecode) {
case 0x00:
_nop();
return;
case 0x76:
_halt();
return;
case 0x10:
_stop();
return;
case 0xF3:
_di();
return;
case 0xFB:
_ei();
return;
case 0x0A:
_loadU8AAddrBc();
return;
case 0x1A:
_loadU8AAddrDe();
return;
case 0x02:
_loadU8AddrBcA();
return;
case 0x12:
_loadU8AddrDeA();
return;
case 0xFA:
_loadU8AAddrIm16();
return;
case 0xEA:
_loadU8AddrIm16A();
return;
case 0xF2:
_loadU8AAddrIndexC();
return;
case 0xE2:
_loadU8AddrIndexCA();
return;
case 0xF0:
_loadU8AAddrIndexIm8();
return;
case 0xE0:
_loadU8AddrIndexIm8A();
return;
case 0x3A:
_loadDecU8AAddrHl();
return;
case 0x32:
_loadDecU8AddrHlA();
return;
case 0x2A:
_loadIncU8AAddrHl();
return;
case 0x22:
_loadIncU8AddrHlA();
return;
case 0x08:
_loadU16AddrIm16Sp();
return;
case 0xF8:
_loadU16HlIndexIm8Sp();
return;
case 0xF9:
_loadU16SpHl();
return;
case 0xC6:
_addU8AIm8();
return;
case 0xCE:
_addCarryU8AIm8();
return;
case 0xD6:
_subU8AIm8();
return;
case 0xDE:
_subCarryU8AIm8();
return;
case 0xE6:
_andU8AIm8();
return;
case 0xF6:
_orU8AIm8();
return;
case 0xEE:
_xorU8AIm8();
return;
case 0xFE:
_cpU8AIm8();
return;
case 0xE8:
_addU16SpIm8();
return;
case 0x07:
_rlcaU8();
return;
case 0x17:
_rlaU8();
return;
case 0x0F:
_rrcaU8();
return;
case 0x1F:
_rraU8();
return;
case 0x27:
_decimalAdjustU8A();
return;
case 0x2F:
_complementU8A();
return;
case 0x3F:
_complementCarry();
return;
case 0x37:
_setCarryFlag();
return;
case 0xC3:
_jpU16();
return;
case 0xC2:
_jpU16Nz();
return;
case 0xCA:
_jpU16Z();
return;
case 0xD2:
_jpU16Nc();
return;
case 0xDA:
_jpU16C();
return;
case 0xE9:
_jpU16Hl();
return;
case 0x18:
_jrU8ImU8();
return;
case 0x20:
_jrU8Nz();
return;
case 0x28:
_jrU8Z();
return;
case 0x30:
_jrU8Nc();
return;
case 0x38:
_jrU8C();
return;
case 0xCD:
_callU16();
return;
case 0xC4:
_callU16Nz();
return;
case 0xCC:
_callU16Z();
return;
case 0xD4:
_callU16Nc();
return;
case 0xDC:
_callU16C();
return;
case 0xC9:
_ret();
return;
case 0xC0:
_retNz();
return;
case 0xC8:
_retZ();
return;
case 0xD0:
_retNc();
return;
case 0xD8:
_retC();
return;
case 0xD9:
_reti();
return;
case 0xCB:
{
final prefixed = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
_doMnemonicPrefixed(prefixed);
return;
}
}
if (0x40 <= opecode && opecode <= 0x7F) {
_loadU8RR(decodeX(opecode), decodeY(opecode));
return;
}
if (0x06 <= opecode && opecode <= 0x3E && (opecode & 7 == 6)) {
_loadU8RIm8(decodeX(opecode));
return;
}
if (0x01 <= opecode && opecode <= 0x31 && (opecode & 15 == 1)) {
_loadU16RrIm16(decodeR(opecode));
return;
}
if (0xC5 <= opecode && opecode <= 0xF5 && (opecode & 15 == 5)) {
_pushU16Rr(decodeR(opecode));
return;
}
if (0xC1 <= opecode && opecode <= 0xF1 && (opecode & 15 == 1)) {
_popU16Rr(decodeR(opecode));
return;
}
if (0x80 <= opecode && opecode <= 0x87) {
_addU8AR(decodeY(opecode));
return;
}
if (0x88 <= opecode && opecode <= 0x8f) {
_addCarryU8AR(decodeY(opecode));
return;
}
if (0x90 <= opecode && opecode <= 0x97) {
_subU8AR(decodeY(opecode));
return;
}
if (0x98 <= opecode && opecode <= 0x9F) {
_subCarryU8AR(decodeY(opecode));
return;
}
if (0xA0 <= opecode && opecode <= 0xA7) {
_andU8AR(decodeY(opecode));
return;
}
if (0xB0 <= opecode && opecode <= 0xB7) {
_orU8AR(decodeY(opecode));
return;
}
if (0xA8 <= opecode && opecode <= 0xAF) {
_xorU8AR(decodeY(opecode));
return;
}
if (0xB8 <= opecode && opecode <= 0xBF) {
_cpU8AR(decodeY(opecode));
return;
}
if (0x04 <= opecode && opecode <= 0x3C && (opecode & 7 == 4)) {
_incU8R(decodeX(opecode));
return;
}
if (0x05 <= opecode && opecode <= 0x3D && (opecode & 7 == 5)) {
_decU8R(decodeX(opecode));
return;
}
if (0x09 <= opecode && opecode <= 0x39 && (opecode & 15 == 9)) {
_addU16HlRr(decodeR(opecode));
return;
}
if (0x03 <= opecode && opecode <= 0x33 && (opecode & 15 == 3)) {
_incU16Rr(decodeR(opecode));
return;
}
if (0x0B <= opecode && opecode <= 0x3B && (opecode & 15 == 11)) {
_decU16Rr(decodeR(opecode));
return;
}
if (0xC7 <= opecode && (opecode & 7 == 7)) {
_restart(decodeX(opecode));
return;
}
throw ArgumentError.value(opecode);
}
void _doMnemonicPrefixed(int opecode) {
if (0x30 <= opecode && opecode <= 0x37) {
_swapU8R(decodeY(opecode));
return;
}
if (0x00 <= opecode && opecode <= 0x07) {
_rlcU8R(decodeY(opecode));
return;
}
if (0x10 <= opecode && opecode <= 0x17) {
_rlU8R(decodeY(opecode));
return;
}
if (0x08 <= opecode && opecode <= 0x0F) {
_rrcU8R(decodeY(opecode));
return;
}
if (0x18 <= opecode && opecode <= 0x1F) {
_rrU8R(decodeY(opecode));
return;
}
if (0x20 <= opecode && opecode <= 0x27) {
_slaU8R(decodeY(opecode));
return;
}
if (0x28 <= opecode && opecode <= 0x2F) {
_sraU8R(decodeY(opecode));
return;
}
if (0x38 <= opecode && opecode <= 0x3F) {
_srlU8R(decodeY(opecode));
return;
}
if (0x40 <= opecode && opecode <= 0x7F) {
_bitU8BitR(decodeY(opecode), decodeX(opecode));
return;
}
if (0xC0 <= opecode && opecode <= 0xFF) {
_setU8BitR(decodeY(opecode), decodeX(opecode));
return;
}
if (0x80 <= opecode && opecode <= 0xBF) {
_resetU8BitR(decodeY(opecode), decodeX(opecode));
return;
}
throw ArgumentError.value(opecode);
}
void _nop() {}
void _halt() {
_halted = true;
}
void _stop() {}
void _di() {
_ime = false;
}
void _ei() {
_ime = true;
}
void _loadU8RIm8(int index) {
final val = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
_setR8(index, val);
}
void _loadU8RR(int left, int right) {
final val = _r8(right);
_setR8(left, val);
}
void _loadU8AAddrBc() {
final val = bus.read(_bc);
_a = val;
}
void _loadU8AAddrDe() {
final val = bus.read(_de);
_a = val;
}
void _loadU8AddrBcA() {
bus.write(_bc, _a);
}
void _loadU8AddrDeA() {
bus.write(_de, _a);
}
void _loadU8AAddrIm16() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
final val = bus.read(addr);
_a = val;
}
void _loadU8AddrIm16A() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
final val = _a;
bus.write(addr, val);
}
void _loadU8AAddrIndexC() {
final index = _c;
final addr = 0xFF00 + index;
final val = bus.read(addr);
_a = val;
}
void _loadU8AddrIndexCA() {
final index = _c;
final addr = 0xFF00 + index;
bus.write(addr, _a);
}
void _loadU8AAddrIndexIm8() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final addr = 0xFF00 + index;
final val = bus.read(addr);
_a = val;
}
void _loadU8AddrIndexIm8A() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final addr = 0xFF00 + index;
bus.write(addr, _a);
}
void _loadDecU8AAddrHl() {
final val = bus.read(_hl);
_hl = _hl.wrappingSubU16(1);
_a = val;
}
void _loadDecU8AddrHlA() {
bus.write(_hl, _a);
_hl = _hl.wrappingSubU16(1);
}
void _loadIncU8AAddrHl() {
final val = bus.read(_hl);
_hl = _hl.wrappingAddU16(1);
_a = val;
}
void _loadIncU8AddrHlA() {
bus.write(_hl, _a);
_hl = _hl.wrappingAddU16(1);
}
void _loadU16RrIm16(int index) {
final val = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
_setR16(index, val, false);
}
void _loadU16AddrIm16Sp() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
final val = _sp;
bus.writeWord(addr, val);
}
void _loadU16HlIndexIm8Sp() {
final baseAddr = _sp;
final indexAddr = bus.read(_pc).toI8();
_pc = _pc.wrappingAddU16(1);
_hl = baseAddr.wrappingAddU16(indexAddr);
_f.z.reset();
_f.n.reset();
_f.h.val = _halfCarryPositive(baseAddr.toU8(), indexAddr.toU8());
_f.c.val = _carryPositive(baseAddr.toU8(), indexAddr.toU8());
}
void _loadU16SpHl() {
_sp = _hl;
_stalls += 8;
}
void _pushU16Rr(int index) {
final val = _r16(index, true);
_sp = _sp.wrappingSubU16(2);
bus.writeWord(_sp, val);
_stalls += 16;
}
void _popU16Rr(int index) {
final val = bus.readWord(_sp);
_sp = _sp.wrappingAddU16(2);
_setR16(index, val, true);
_stalls += 12;
}
void _addU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left.wrappingAddU8(right);
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.val = _halfCarryPositive(left, right);
_f.c.val = _carryPositive(left, right);
_stalls += 4;
}
void _addU8AIm8() {
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final left = _a;
final result = left.wrappingAddU8(right);
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.val = _halfCarryPositive(left, right);
_f.c.val = _carryPositive(left, right);
_stalls += 8;
}
void _addCarryU8AR(int index) {
final c = _f.c.val ? 1 : 0;
final right = _r8(index);
final left = _a;
final result1 = left.wrappingAddU8(right);
final result2 = result1.wrappingAddU8(c);
final c1 = _carryPositive(left, right);
final h1 = _halfCarryPositive(left, right);
final c2 = _carryPositive(result1, c);
final h2 = _halfCarryPositive(result1, c);
_a = result2;
_f.z.val = result2 == 0;
_f.n.reset();
_f.h.val = h1 || h2;
_f.c.val = c1 || c2;
_stalls += 4;
}
void _addCarryU8AIm8() {
final c = _f.c.val ? 1 : 0;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final left = _a;
final result1 = left.wrappingAddU8(right);
final result2 = result1.wrappingAddU8(c);
final c1 = _carryPositive(left, right);
final h1 = _halfCarryPositive(left, right);
final c2 = _carryPositive(result1, c);
final h2 = _halfCarryPositive(result1, c);
_a = result2;
_f.z.val = result2 == 0;
_f.n.reset();
_f.h.val = h1 || h2;
_f.c.val = c1 || c2;
_stalls += 8;
}
void _subU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left.wrappingSubU8(right);
_a = result;
_f.z.val = result == 0;
_f.n.set();
_f.h.val = _halfCarryNegative(left, right);
_f.c.val = _carryNegative(left, right);
_stalls += 4;
}
void _subU8AIm8() {
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result = left.wrappingSubU8(right);
_a = result;
_f.z.val = result == 0;
_f.n.set();
_f.h.val = _halfCarryNegative(left, right);
_f.c.val = _carryNegative(left, right);
_stalls += 8;
}
void _subCarryU8AR(int index) {
final c = _f.c.val ? 1 : 0;
final left = _a;
final right = _r8(index);
final result1 = left.wrappingSubU8(right);
final result2 = result1.wrappingSubU8(c);
_a = result2;
final c1 = _carryNegative(left, right);
final h1 = _halfCarryNegative(left, right);
final c2 = _carryNegative(result1, c);
final h2 = _halfCarryNegative(result1, c);
_f.z.val = result2 == 0;
_f.n.set();
_f.h.val = h1 || h2;
_f.c.val = c1 || c2;
_stalls += 4;
}
void _subCarryU8AIm8() {
final c = _f.c.val ? 1 : 0;
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result1 = left.wrappingSubU8(right);
final result2 = result1.wrappingSubU8(c);
_a = result2;
final c1 = _carryNegative(left, right);
final h1 = _halfCarryNegative(left, right);
final c2 = _carryNegative(result1, c);
final h2 = _halfCarryNegative(result1, c);
_f.z.val = result2 == 0;
_f.n.set();
_f.h.val = h1 || h2;
_f.c.val = c1 || c2;
_stalls += 8;
}
void _andU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left & right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.set();
_f.c.reset();
_stalls += 4;
}
void _andU8AIm8() {
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result = left & right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.set();
_f.c.reset();
_stalls += 8;
}
void _orU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left | right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.reset();
_stalls += 4;
}
void _orU8AIm8() {
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result = left | right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.reset();
_stalls += 8;
}
void _xorU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left ^ right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.reset();
_stalls += 4;
}
void _xorU8AIm8() {
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result = left ^ right;
_a = result;
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.reset();
_stalls += 8;
}
void _cpU8AR(int index) {
final left = _a;
final right = _r8(index);
final result = left.wrappingSubU8(right);
_f.z.val = result == 0;
_f.n.set();
_f.h.val = _halfCarryNegative(left, right);
_f.c.val = _carryNegative(left, right);
_stalls += 4;
}
void _cpU8AIm8() {
final left = _a;
final right = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
final result = left.wrappingSubU8(right);
_f.z.val = result == 0;
_f.n.set();
_f.h.val = _halfCarryNegative(left, right);
_f.c.val = _carryNegative(left, right);
_stalls += 8;
}
void _incU8R(int index) {
final left = _r8(index);
const right = 1;
final result = left.wrappingAddU8(right);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.val = _halfCarryPositive(left, right);
_stalls += 4;
}
void _decU8R(int index) {
final left = _r8(index);
const right = 1;
final result = left.wrappingSubU8(right);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.set();
_f.h.val = _halfCarryNegative(left, right);
_stalls += 4;
}
void _addU16HlRr(int index) {
final left = _hl;
final right = _r16(index, false);
final result = left.wrappingAddU16(right);
_hl = result;
_f.n.reset();
_f.h.val = _halfCarryPositiveU16U12(left, right);
_f.c.val = _carryPositiveU16(left, right);
_stalls += 8;
}
void _addU16SpIm8() {
final left = _sp;
final right = bus.read(_pc).toI8();
_pc = _pc.wrappingAddU16(1);
final result = left.wrappingAddU16(right);
_sp = result;
_f.z.reset();
_f.n.reset();
_f.h.val = _halfCarryPositive(left.toU8(), right.toU8());
_f.c.val = _carryPositive(left.toU8(), right.toU8());
_stalls += 16;
}
void _incU16Rr(int index) {
final left = _r16(index, false);
const right = 1;
final result = left.wrappingAddU16(right);
_setR16(index, result, false);
_stalls += 8;
}
void _decU16Rr(int index) {
final left = _r16(index, false);
const right = 1;
final result = left.wrappingSubU16(right);
_setR16(index, result, false);
_stalls += 8;
}
void _rlcaU8() {
final val = _a;
final c = (val >> 7) & 1;
final result = val.rotateLeftU8();
_a = result;
_f.z.reset();
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 4;
}
void _rlaU8() {
final val = _a;
final c = (val >> 7) & 1;
final result = (val << 1).toU8() | (_f.c.val ? 1 : 0);
_a = result;
_f.z.reset();
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 4;
}
void _rrcaU8() {
final val = _a;
final c = val & 1;
final result = val.rotateRightU8();
_a = result;
_f.z.reset();
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 4;
}
void _rraU8() {
final val = _a;
final c = val & 1;
final result = (val >> 1).toU8() | ((_f.c.val ? 1 : 0) << 7);
_a = result;
_f.z.reset();
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 4;
}
void _rlcU8R(int index) {
final val = _r8(index);
final c = (val >> 7) & 1;
final result = val.rotateLeftU8();
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _rlU8R(int index) {
final val = _r8(index);
final c = (val >> 7) & 1;
final result = (val << 1).toU8() | (_f.c.val ? 1 : 0);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _rrcU8R(int index) {
final val = _r8(index);
final c = val & 1;
final result = val.rotateRightU8();
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _rrU8R(int index) {
final val = _r8(index);
final c = val & 1;
final result = (val >> 1).toU8() | ((_f.c.val ? 1 : 0) << 7);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _slaU8R(int index) {
final val = _r8(index);
final c = (val >> 7) & 1;
final result = (val << 1).toU8();
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _sraU8R(int index) {
final val = _r8(index);
final c = val & 1;
final result = (val >> 1).toU8() | oneHot(isSet(val, 7), 7);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _srlU8R(int index) {
final val = _r8(index);
final c = val & 1;
final result = (val >> 1).toU8();
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.val = c == 1;
_stalls += 8;
}
void _bitU8BitR(int index, int bit) {
final left = _r8(index);
final right = bit;
final result = (left >> right) & 1;
_f.z.val = result == 0;
_f.n.reset();
_f.h.set();
_stalls += 8;
}
void _setU8BitR(int index, int bit) {
final left = _r8(index);
final right = bit;
final result = left | (1 << right);
_setR8(index, result);
_stalls += 8;
}
void _resetU8BitR(int index, int bit) {
final left = _r8(index);
final right = bit;
final result = left & ~(1 << right);
_setR8(index, result);
_stalls += 8;
}
void _jpU16() {
final addr = bus.readWord(_pc);
_pc = addr;
_stalls += 16;
}
void _jpU16Nz() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (!_f.z.val) {
_pc = addr;
}
_stalls += 16;
}
void _jpU16Z() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (_f.z.val) {
_pc = addr;
}
_stalls += 16;
}
void _jpU16Nc() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (!_f.c.val) {
_pc = addr;
}
_stalls += 16;
}
void _jpU16C() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (_f.c.val) {
_pc = addr;
}
_stalls += 16;
}
void _jpU16Hl() {
_pc = _hl;
_stalls += 4;
}
void _jrU8ImU8() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
_pc = _pc.wrappingAddU16(index.toI8());
_stalls += 12;
}
void _jrU8Nz() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
if (!_f.z.val) {
_pc = _pc.wrappingAddU16(index.toI8());
}
_stalls += 12;
}
void _jrU8Z() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
if (_f.z.val) {
_pc = _pc.wrappingAddU16(index.toI8());
}
_stalls += 12;
}
void _jrU8Nc() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
if (!_f.c.val) {
_pc = _pc.wrappingAddU16(index.toI8());
}
_stalls += 12;
}
void _jrU8C() {
final index = bus.read(_pc);
_pc = _pc.wrappingAddU16(1);
if (_f.c.val) {
_pc = _pc.wrappingAddU16(index.toI8());
}
_stalls += 12;
}
void _call(int addr) {
_sp = _sp.wrappingSubU16(2);
bus.writeWord(_sp, _pc);
_pc = addr;
_stalls += 24;
}
void _callU16() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
_call(addr);
}
void _callU16Nz() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (!_f.z.val) {
_call(addr);
}
}
void _callU16Z() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (_f.z.val) {
_call(addr);
}
}
void _callU16Nc() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (!_f.c.val) {
_call(addr);
}
}
void _callU16C() {
final addr = bus.readWord(_pc);
_pc = _pc.wrappingAddU16(2);
if (_f.c.val) {
_call(addr);
}
}
void _restart(int param) {
final addr = param * 0x08;
_sp = _sp.wrappingSubU16(2);
bus.writeWord(_sp, _pc);
_pc = addr;
_stalls += 16;
}
void _ret() {
final addr = bus.readWord(_sp);
_sp = _sp.wrappingAddU16(2);
_pc = addr;
_stalls += 16;
}
void _retNz() {
final addr = bus.readWord(_sp);
if (!_f.z.val) {
_sp = _sp.wrappingAddU16(2);
_pc = addr;
}
_stalls += 20;
}
void _retZ() {
final addr = bus.readWord(_sp);
if (_f.z.val) {
_sp = _sp.wrappingAddU16(2);
_pc = addr;
}
_stalls += 20;
}
void _retNc() {
final addr = bus.readWord(_sp);
if (!_f.c.val) {
_sp = _sp.wrappingAddU16(2);
_pc = addr;
}
_stalls += 20;
}
void _retC() {
final addr = bus.readWord(_sp);
if (_f.c.val) {
_sp = _sp.wrappingAddU16(2);
_pc = addr;
}
_stalls += 20;
}
void _reti() {
final addr = bus.readWord(_sp);
_sp = _sp.wrappingAddU16(2);
_pc = addr;
_ime = true;
_stalls += 16;
}
void _swapU8R(int index) {
final val = _r8(index);
final high = val & 0xF0;
final low = val & 0x0F;
final result = (high >> 4) | (low << 4);
_setR8(index, result);
_f.z.val = result == 0;
_f.n.reset();
_f.h.reset();
_f.c.reset();
_stalls += 8;
}
void _decimalAdjustU8A() {
if (!_f.n.val) {
if (_f.c.val || _a > 0x99) {
_a = _a.wrappingAddU8(0x60);
_f.c.set();
}
if (_f.h.val || (_a & 0x0F) > 0x09) {
_a = _a.wrappingAddU8(0x06);
}
} else {
if (_f.c.val) {
_a = _a.wrappingSubU8(0x60);
}
if (_f.h.val) {
_a = _a.wrappingSubU8(0x06);
}
}
_f.z.val = _a == 0;
_f.h.reset();
_stalls += 4;
}
void _complementU8A() {
final val = _a;
final result = (~val).toU8();
_a = result;
_f.n.set();
_f.h.set();
_stalls += 4;
}
void _complementCarry() {
final c = _f.c.val;
final result = !c;
_f.n.reset();
_f.h.reset();
_f.c.val = result;
_stalls += 4;
}
void _setCarryFlag() {
_f.n.reset();
_f.h.reset();
_f.c.set();
_stalls += 4;
}
}