2020-05-18 16:10:53 -04:00
# include "stdafx.h"
2020-05-21 20:57:00 -04:00
# include "Console.h"
2020-05-18 16:10:53 -04:00
# include "GbCpu.h"
2020-05-19 21:31:33 -04:00
# include "Gameboy.h"
2020-05-18 16:10:53 -04:00
# include "GbMemoryManager.h"
# include "../Utilities/Serializer.h"
2020-06-18 00:58:22 -04:00
void GbCpu : : Init ( Console * console , Gameboy * gameboy , GbMemoryManager * memoryManager )
2020-05-18 16:10:53 -04:00
{
2020-05-21 20:57:00 -04:00
_console = console ;
2020-05-19 21:31:33 -04:00
_gameboy = gameboy ;
2020-05-18 16:10:53 -04:00
_memoryManager = memoryManager ;
2021-03-10 11:13:28 -05:00
2020-05-18 16:10:53 -04:00
_state = { } ;
2020-06-18 00:58:22 -04:00
_state . PC = 0 ;
_state . SP = 0xFFFF ;
2020-05-18 16:10:53 -04:00
}
GbCpu : : ~ GbCpu ( )
{
}
GbCpuState GbCpu : : GetState ( )
{
return _state ;
}
2020-06-09 22:40:35 -04:00
bool GbCpu : : IsHalted ( )
{
return _state . Halted ;
}
2020-05-18 16:10:53 -04:00
void GbCpu : : Exec ( )
{
uint8_t irqVector = _memoryManager - > ProcessIrqRequests ( ) ;
2021-03-10 11:13:28 -05:00
if ( irqVector ) {
if ( _state . IME ) {
2020-05-21 20:57:00 -04:00
uint16_t oldPc = _state . PC ;
2020-05-18 16:10:53 -04:00
IncCycleCount ( ) ;
IncCycleCount ( ) ;
2020-05-23 12:38:31 -04:00
PushByte ( _state . PC > > 8 ) ;
irqVector = _memoryManager - > ProcessIrqRequests ( ) ; //Check IRQ line again before jumping (ie_push)
PushByte ( ( uint8_t ) _state . PC ) ;
2020-05-18 16:10:53 -04:00
IncCycleCount ( ) ;
2021-03-10 11:13:28 -05:00
switch ( irqVector ) {
case 0 :
//IRQ request bit is no longer set, jump to $0000 (ie_push test)
_state . PC = 0 ;
break ;
case GbIrqSource : : VerticalBlank : _state . PC = 0x40 ; break ;
case GbIrqSource : : LcdStat : _state . PC = 0x48 ; break ;
case GbIrqSource : : Timer : _state . PC = 0x50 ; break ;
case GbIrqSource : : Serial : _state . PC = 0x58 ; break ;
case GbIrqSource : : Joypad : _state . PC = 0x60 ; break ;
2020-05-18 16:10:53 -04:00
}
2021-03-10 11:13:28 -05:00
if ( irqVector ) {
2020-05-23 12:38:31 -04:00
//Only clear IRQ bit if an IRQ was processed
_memoryManager - > ClearIrqRequest ( irqVector ) ;
}
2020-05-18 16:10:53 -04:00
_state . IME = false ;
2020-05-21 20:57:00 -04:00
_console - > ProcessInterrupt < CpuType : : Gameboy > ( oldPc , _state . PC , false ) ;
2020-05-18 16:10:53 -04:00
}
_state . Halted = false ;
}
2021-03-10 11:13:28 -05:00
if ( _state . Halted ) {
2020-05-18 16:10:53 -04:00
IncCycleCount ( ) ;
return ;
}
2021-03-10 11:13:28 -05:00
if ( _state . EiPending ) {
2020-05-23 12:38:31 -04:00
_state . EiPending = false ;
_state . IME = true ;
}
2020-05-18 16:10:53 -04:00
ExecOpCode ( ReadOpCode ( ) ) ;
}
void GbCpu : : ExecOpCode ( uint8_t opCode )
{
2021-03-10 11:13:28 -05:00
switch ( opCode ) {
case 0x00 : NOP ( ) ; break ;
case 0x01 : LD ( _regBC , ReadCodeWord ( ) ) ; break ;
case 0x02 : LD_Indirect ( _regBC , _state . A ) ; break ;
case 0x03 : INC ( _regBC ) ; break ;
case 0x04 : INC ( _state . B ) ; break ;
case 0x05 : DEC ( _state . B ) ; break ;
case 0x06 : LD ( _state . B , ReadCode ( ) ) ; break ;
case 0x07 : RLCA ( ) ; break ;
case 0x08 : LD_Indirect16 ( ReadCodeWord ( ) , _state . SP ) ; break ;
case 0x09 : ADD ( _regHL , _regBC ) ; break ;
case 0x0A : LD ( _state . A , Read ( _regBC ) ) ; break ;
case 0x0B : DEC ( _regBC ) ; break ;
case 0x0C : INC ( _state . C ) ; break ;
case 0x0D : DEC ( _state . C ) ; break ;
case 0x0E : LD ( _state . C , ReadCode ( ) ) ; break ;
case 0x0F : RRCA ( ) ; break ;
case 0x10 : STOP ( ) ; break ;
case 0x11 : LD ( _regDE , ReadCodeWord ( ) ) ; break ;
case 0x12 : LD_Indirect ( _regDE , _state . A ) ; break ;
case 0x13 : INC ( _regDE ) ; break ;
case 0x14 : INC ( _state . D ) ; break ;
case 0x15 : DEC ( _state . D ) ; break ;
case 0x16 : LD ( _state . D , ReadCode ( ) ) ; break ;
case 0x17 : RLA ( ) ; break ;
case 0x18 : JR ( ReadCode ( ) ) ; break ;
case 0x19 : ADD ( _regHL , _regDE ) ; break ;
case 0x1A : LD ( _state . A , Read ( _regDE ) ) ; break ;
case 0x1B : DEC ( _regDE ) ; break ;
case 0x1C : INC ( _state . E ) ; break ;
case 0x1D : DEC ( _state . E ) ; break ;
case 0x1E : LD ( _state . E , ReadCode ( ) ) ; break ;
case 0x1F : RRA ( ) ; break ;
case 0x20 : JR ( ( _state . Flags & GbCpuFlags : : Zero ) = = 0 , ReadCode ( ) ) ; break ;
case 0x21 : LD ( _regHL , ReadCodeWord ( ) ) ; break ;
case 0x22 : LD_Indirect ( _regHL , _state . A ) ; _regHL . Inc ( ) ; break ;
case 0x23 : INC ( _regHL ) ; break ;
case 0x24 : INC ( _state . H ) ; break ;
case 0x25 : DEC ( _state . H ) ; break ;
case 0x26 : LD ( _state . H , ReadCode ( ) ) ; break ;
case 0x27 : DAA ( ) ; break ;
case 0x28 : JR ( ( _state . Flags & GbCpuFlags : : Zero ) ! = 0 , ReadCode ( ) ) ; break ;
case 0x29 : ADD ( _regHL , _regHL ) ; break ;
case 0x2A : LD ( _state . A , Read ( _regHL ) ) ; _regHL . Inc ( ) ; break ;
case 0x2B : DEC ( _regHL ) ; break ;
case 0x2C : INC ( _state . L ) ; break ;
case 0x2D : DEC ( _state . L ) ; break ;
case 0x2E : LD ( _state . L , ReadCode ( ) ) ; break ;
case 0x2F : CPL ( ) ; break ;
case 0x30 : JR ( ( _state . Flags & GbCpuFlags : : Carry ) = = 0 , ReadCode ( ) ) ; break ;
case 0x31 : LD ( _state . SP , ReadCodeWord ( ) ) ; break ;
case 0x32 : LD_Indirect ( _regHL , _state . A ) ; _regHL . Dec ( ) ; break ;
case 0x33 : INC_SP ( ) ; break ;
case 0x34 : INC_Indirect ( _regHL ) ; break ;
case 0x35 : DEC_Indirect ( _regHL ) ; break ;
case 0x36 : LD_Indirect ( _regHL , ReadCode ( ) ) ; break ;
case 0x37 : SCF ( ) ; break ;
case 0x38 : JR ( ( _state . Flags & GbCpuFlags : : Carry ) ! = 0 , ReadCode ( ) ) ; break ;
case 0x39 : ADD ( _regHL , _state . SP ) ; break ;
case 0x3A : LD ( _state . A , Read ( _regHL ) ) ; _regHL . Dec ( ) ; break ;
case 0x3B : DEC_SP ( ) ; break ;
case 0x3C : INC ( _state . A ) ; break ;
case 0x3D : DEC ( _state . A ) ; break ;
case 0x3E : LD ( _state . A , ReadCode ( ) ) ; break ;
case 0x3F : CCF ( ) ; break ;
case 0x40 : LD ( _state . B , _state . B ) ; break ;
case 0x41 : LD ( _state . B , _state . C ) ; break ;
case 0x42 : LD ( _state . B , _state . D ) ; break ;
case 0x43 : LD ( _state . B , _state . E ) ; break ;
case 0x44 : LD ( _state . B , _state . H ) ; break ;
case 0x45 : LD ( _state . B , _state . L ) ; break ;
case 0x46 : LD ( _state . B , Read ( _regHL ) ) ; break ;
case 0x47 : LD ( _state . B , _state . A ) ; break ;
case 0x48 : LD ( _state . C , _state . B ) ; break ;
case 0x49 : LD ( _state . C , _state . C ) ; break ;
case 0x4A : LD ( _state . C , _state . D ) ; break ;
case 0x4B : LD ( _state . C , _state . E ) ; break ;
case 0x4C : LD ( _state . C , _state . H ) ; break ;
case 0x4D : LD ( _state . C , _state . L ) ; break ;
case 0x4E : LD ( _state . C , Read ( _regHL ) ) ; break ;
case 0x4F : LD ( _state . C , _state . A ) ; break ;
case 0x50 : LD ( _state . D , _state . B ) ; break ;
case 0x51 : LD ( _state . D , _state . C ) ; break ;
case 0x52 : LD ( _state . D , _state . D ) ; break ;
case 0x53 : LD ( _state . D , _state . E ) ; break ;
case 0x54 : LD ( _state . D , _state . H ) ; break ;
case 0x55 : LD ( _state . D , _state . L ) ; break ;
case 0x56 : LD ( _state . D , Read ( _regHL ) ) ; break ;
case 0x57 : LD ( _state . D , _state . A ) ; break ;
case 0x58 : LD ( _state . E , _state . B ) ; break ;
case 0x59 : LD ( _state . E , _state . C ) ; break ;
case 0x5A : LD ( _state . E , _state . D ) ; break ;
case 0x5B : LD ( _state . E , _state . E ) ; break ;
case 0x5C : LD ( _state . E , _state . H ) ; break ;
case 0x5D : LD ( _state . E , _state . L ) ; break ;
case 0x5E : LD ( _state . E , Read ( _regHL ) ) ; break ;
case 0x5F : LD ( _state . E , _state . A ) ; break ;
case 0x60 : LD ( _state . H , _state . B ) ; break ;
case 0x61 : LD ( _state . H , _state . C ) ; break ;
case 0x62 : LD ( _state . H , _state . D ) ; break ;
case 0x63 : LD ( _state . H , _state . E ) ; break ;
case 0x64 : LD ( _state . H , _state . H ) ; break ;
case 0x65 : LD ( _state . H , _state . L ) ; break ;
case 0x66 : LD ( _state . H , Read ( _regHL ) ) ; break ;
case 0x67 : LD ( _state . H , _state . A ) ; break ;
case 0x68 : LD ( _state . L , _state . B ) ; break ;
case 0x69 : LD ( _state . L , _state . C ) ; break ;
case 0x6A : LD ( _state . L , _state . D ) ; break ;
case 0x6B : LD ( _state . L , _state . E ) ; break ;
case 0x6C : LD ( _state . L , _state . H ) ; break ;
case 0x6D : LD ( _state . L , _state . L ) ; break ;
case 0x6E : LD ( _state . L , Read ( _regHL ) ) ; break ;
case 0x6F : LD ( _state . L , _state . A ) ; break ;
case 0x70 : LD_Indirect ( _regHL , _state . B ) ; break ;
case 0x71 : LD_Indirect ( _regHL , _state . C ) ; break ;
case 0x72 : LD_Indirect ( _regHL , _state . D ) ; break ;
case 0x73 : LD_Indirect ( _regHL , _state . E ) ; break ;
case 0x74 : LD_Indirect ( _regHL , _state . H ) ; break ;
case 0x75 : LD_Indirect ( _regHL , _state . L ) ; break ;
case 0x76 : HALT ( ) ; break ;
case 0x77 : LD_Indirect ( _regHL , _state . A ) ; break ;
case 0x78 : LD ( _state . A , _state . B ) ; break ;
case 0x79 : LD ( _state . A , _state . C ) ; break ;
case 0x7A : LD ( _state . A , _state . D ) ; break ;
case 0x7B : LD ( _state . A , _state . E ) ; break ;
case 0x7C : LD ( _state . A , _state . H ) ; break ;
case 0x7D : LD ( _state . A , _state . L ) ; break ;
case 0x7E : LD ( _state . A , Read ( _regHL ) ) ; break ;
case 0x7F : LD ( _state . A , _state . A ) ; break ;
case 0x80 : ADD ( _state . B ) ; break ;
case 0x81 : ADD ( _state . C ) ; break ;
case 0x82 : ADD ( _state . D ) ; break ;
case 0x83 : ADD ( _state . E ) ; break ;
case 0x84 : ADD ( _state . H ) ; break ;
case 0x85 : ADD ( _state . L ) ; break ;
case 0x86 : ADD ( Read ( _regHL ) ) ; break ;
case 0x87 : ADD ( _state . A ) ; break ;
case 0x88 : ADC ( _state . B ) ; break ;
case 0x89 : ADC ( _state . C ) ; break ;
case 0x8A : ADC ( _state . D ) ; break ;
case 0x8B : ADC ( _state . E ) ; break ;
case 0x8C : ADC ( _state . H ) ; break ;
case 0x8D : ADC ( _state . L ) ; break ;
case 0x8E : ADC ( Read ( _regHL ) ) ; break ;
case 0x8F : ADC ( _state . A ) ; break ;
case 0x90 : SUB ( _state . B ) ; break ;
case 0x91 : SUB ( _state . C ) ; break ;
case 0x92 : SUB ( _state . D ) ; break ;
case 0x93 : SUB ( _state . E ) ; break ;
case 0x94 : SUB ( _state . H ) ; break ;
case 0x95 : SUB ( _state . L ) ; break ;
case 0x96 : SUB ( Read ( _regHL ) ) ; break ;
case 0x97 : SUB ( _state . A ) ; break ;
case 0x98 : SBC ( _state . B ) ; break ;
case 0x99 : SBC ( _state . C ) ; break ;
case 0x9A : SBC ( _state . D ) ; break ;
case 0x9B : SBC ( _state . E ) ; break ;
case 0x9C : SBC ( _state . H ) ; break ;
case 0x9D : SBC ( _state . L ) ; break ;
case 0x9E : SBC ( Read ( _regHL ) ) ; break ;
case 0x9F : SBC ( _state . A ) ; break ;
case 0xA0 : AND ( _state . B ) ; break ;
case 0xA1 : AND ( _state . C ) ; break ;
case 0xA2 : AND ( _state . D ) ; break ;
case 0xA3 : AND ( _state . E ) ; break ;
case 0xA4 : AND ( _state . H ) ; break ;
case 0xA5 : AND ( _state . L ) ; break ;
case 0xA6 : AND ( Read ( _regHL ) ) ; break ;
case 0xA7 : AND ( _state . A ) ; break ;
case 0xA8 : XOR ( _state . B ) ; break ;
case 0xA9 : XOR ( _state . C ) ; break ;
case 0xAA : XOR ( _state . D ) ; break ;
case 0xAB : XOR ( _state . E ) ; break ;
case 0xAC : XOR ( _state . H ) ; break ;
case 0xAD : XOR ( _state . L ) ; break ;
case 0xAE : XOR ( Read ( _regHL ) ) ; break ;
case 0xAF : XOR ( _state . A ) ; break ;
case 0xB0 : OR ( _state . B ) ; break ;
case 0xB1 : OR ( _state . C ) ; break ;
case 0xB2 : OR ( _state . D ) ; break ;
case 0xB3 : OR ( _state . E ) ; break ;
case 0xB4 : OR ( _state . H ) ; break ;
case 0xB5 : OR ( _state . L ) ; break ;
case 0xB6 : OR ( Read ( _regHL ) ) ; break ;
case 0xB7 : OR ( _state . A ) ; break ;
case 0xB8 : CP ( _state . B ) ; break ;
case 0xB9 : CP ( _state . C ) ; break ;
case 0xBA : CP ( _state . D ) ; break ;
case 0xBB : CP ( _state . E ) ; break ;
case 0xBC : CP ( _state . H ) ; break ;
case 0xBD : CP ( _state . L ) ; break ;
case 0xBE : CP ( Read ( _regHL ) ) ; break ;
case 0xBF : CP ( _state . A ) ; break ;
case 0xC0 : RET ( ( _state . Flags & GbCpuFlags : : Zero ) = = 0 ) ; break ;
case 0xC1 : POP ( _regBC ) ; break ;
case 0xC2 : JP ( ( _state . Flags & GbCpuFlags : : Zero ) = = 0 , ReadCodeWord ( ) ) ; break ;
case 0xC3 : JP ( ReadCodeWord ( ) ) ; break ;
case 0xC4 : CALL ( ( _state . Flags & GbCpuFlags : : Zero ) = = 0 , ReadCodeWord ( ) ) ; break ;
case 0xC5 : PUSH ( _regBC ) ; break ;
case 0xC6 : ADD ( ReadCode ( ) ) ; break ;
case 0xC7 : RST ( 0x00 ) ; break ;
case 0xC8 : RET ( ( _state . Flags & GbCpuFlags : : Zero ) ! = 0 ) ; break ;
case 0xC9 : RET ( ) ; break ;
case 0xCA : JP ( ( _state . Flags & GbCpuFlags : : Zero ) ! = 0 , ReadCodeWord ( ) ) ; break ;
case 0xCB : PREFIX ( ) ; break ;
case 0xCC : CALL ( ( _state . Flags & GbCpuFlags : : Zero ) ! = 0 , ReadCodeWord ( ) ) ; break ;
case 0xCD : CALL ( ReadCodeWord ( ) ) ; break ;
case 0xCE : ADC ( ReadCode ( ) ) ; break ;
case 0xCF : RST ( 0x08 ) ; break ;
case 0xD0 : RET ( ( _state . Flags & GbCpuFlags : : Carry ) = = 0 ) ; break ;
case 0xD1 : POP ( _regDE ) ; break ;
case 0xD2 : JP ( ( _state . Flags & GbCpuFlags : : Carry ) = = 0 , ReadCodeWord ( ) ) ; break ;
case 0xD3 : InvalidOp ( ) ; break ;
case 0xD4 : CALL ( ( _state . Flags & GbCpuFlags : : Carry ) = = 0 , ReadCodeWord ( ) ) ; break ;
case 0xD5 : PUSH ( _regDE ) ; break ;
case 0xD6 : SUB ( ReadCode ( ) ) ; break ;
case 0xD7 : RST ( 0x10 ) ; break ;
case 0xD8 : RET ( ( _state . Flags & GbCpuFlags : : Carry ) ! = 0 ) ; break ;
case 0xD9 : RETI ( ) ; break ;
case 0xDA : JP ( ( _state . Flags & GbCpuFlags : : Carry ) ! = 0 , ReadCodeWord ( ) ) ; break ;
case 0xDB : InvalidOp ( ) ; break ;
case 0xDC : CALL ( ( _state . Flags & GbCpuFlags : : Carry ) ! = 0 , ReadCodeWord ( ) ) ; break ;
case 0xDD : InvalidOp ( ) ; break ;
case 0xDE : SBC ( ReadCode ( ) ) ; break ;
case 0xDF : RST ( 0x18 ) ; break ;
case 0xE0 : LD_Indirect ( 0xFF00 | ReadCode ( ) , _state . A ) ; break ;
case 0xE1 : POP ( _regHL ) ; break ;
case 0xE2 : LD_Indirect ( 0xFF00 | _state . C , _state . A ) ; break ;
case 0xE3 : InvalidOp ( ) ; break ;
case 0xE4 : InvalidOp ( ) ; break ;
case 0xE5 : PUSH ( _regHL ) ; break ;
case 0xE6 : AND ( ReadCode ( ) ) ; break ;
case 0xE7 : RST ( 0x20 ) ; break ;
case 0xE8 : ADD_SP ( ReadCode ( ) ) ; break ;
case 0xE9 : JP_HL ( ) ; break ;
case 0xEA : LD_Indirect ( ReadCodeWord ( ) , _state . A ) ; break ;
case 0xEB : InvalidOp ( ) ; break ;
case 0xEC : InvalidOp ( ) ; break ;
case 0xED : InvalidOp ( ) ; break ;
case 0xEE : XOR ( ReadCode ( ) ) ; break ;
case 0xEF : RST ( 0x28 ) ; break ;
case 0xF0 : LD ( _state . A , Read ( 0xFF00 | ReadCode ( ) ) ) ; break ;
case 0xF1 : POP_AF ( ) ; break ;
case 0xF2 : LD ( _state . A , Read ( 0xFF00 | _state . C ) ) ; break ;
case 0xF3 : DI ( ) ; break ;
case 0xF4 : InvalidOp ( ) ; break ;
case 0xF5 : PUSH ( _regAF ) ; break ;
case 0xF6 : OR ( ReadCode ( ) ) ; break ;
case 0xF7 : RST ( 0x30 ) ; break ;
case 0xF8 : LD_HL ( ReadCode ( ) ) ; break ;
case 0xF9 : LD ( _state . SP , _regHL ) ; IncCycleCount ( ) ; break ;
case 0xFA : LD ( _state . A , Read ( ReadCodeWord ( ) ) ) ; break ;
case 0xFB : EI ( ) ; break ;
case 0xFC : InvalidOp ( ) ; break ;
case 0xFD : InvalidOp ( ) ; break ;
case 0xFE : CP ( ReadCode ( ) ) ; break ;
case 0xFF : RST ( 0x38 ) ; break ;
2020-05-18 16:10:53 -04:00
}
}
void GbCpu : : IncCycleCount ( )
2020-05-30 23:23:35 -04:00
{
_memoryManager - > Exec ( ) ;
_memoryManager - > Exec ( ) ;
}
void GbCpu : : HalfCycle ( )
2020-05-18 16:10:53 -04:00
{
_memoryManager - > Exec ( ) ;
}
uint8_t GbCpu : : ReadOpCode ( )
{
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-06-02 20:42:58 -04:00
uint8_t value = _memoryManager - > Read < MemoryOperationType : : ExecOpCode > ( _state . PC ) ;
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-05-18 16:10:53 -04:00
_state . PC + + ;
return value ;
}
uint8_t GbCpu : : ReadCode ( )
{
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-06-02 20:42:58 -04:00
uint8_t value = _memoryManager - > Read < MemoryOperationType : : ExecOperand > ( _state . PC ) ;
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-05-18 16:10:53 -04:00
_state . PC + + ;
return value ;
}
uint16_t GbCpu : : ReadCodeWord ( )
{
uint8_t low = ReadCode ( ) ;
uint8_t high = ReadCode ( ) ;
return ( high < < 8 ) | low ;
}
uint8_t GbCpu : : Read ( uint16_t addr )
{
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-06-02 20:42:58 -04:00
uint8_t value = _memoryManager - > Read < MemoryOperationType : : Read > ( addr ) ;
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
return value ;
2020-05-18 16:10:53 -04:00
}
void GbCpu : : Write ( uint16_t addr , uint8_t value )
{
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-05-18 16:10:53 -04:00
_memoryManager - > Write ( addr , value ) ;
2020-05-30 23:23:35 -04:00
HalfCycle ( ) ;
2020-05-18 16:10:53 -04:00
}
bool GbCpu : : CheckFlag ( uint8_t flag )
{
return ( _state . Flags & flag ) ! = 0 ;
}
void GbCpu : : SetFlag ( uint8_t flag )
{
_state . Flags | = flag ;
}
void GbCpu : : ClearFlag ( uint8_t flag )
{
_state . Flags & = ~ flag ;
}
void GbCpu : : SetFlagState ( uint8_t flag , bool state )
{
2021-03-10 11:13:28 -05:00
if ( state ) {
2020-05-18 16:10:53 -04:00
SetFlag ( flag ) ;
2021-03-10 11:13:28 -05:00
} else {
2020-05-18 16:10:53 -04:00
ClearFlag ( flag ) ;
}
}
void GbCpu : : PushByte ( uint8_t value )
{
_state . SP - - ;
Write ( _state . SP , value ) ;
}
void GbCpu : : PushWord ( uint16_t value )
{
PushByte ( value > > 8 ) ;
PushByte ( ( uint8_t ) value ) ;
}
uint8_t GbCpu : : PopByte ( )
{
uint8_t val = Read ( _state . SP ) ;
_state . SP + + ;
return val ;
}
uint16_t GbCpu : : PopWord ( )
{
uint8_t low = PopByte ( ) ;
uint8_t high = PopByte ( ) ;
return ( high < < 8 ) | low ;
}
void GbCpu : : LD ( uint8_t & dst , uint8_t value )
{
dst = value ;
}
void GbCpu : : LD ( uint16_t & dst , uint16_t value )
{
dst = value ;
}
void GbCpu : : LD ( Register16 & dst , uint16_t value )
{
dst . Write ( value ) ;
}
void GbCpu : : LD_Indirect ( uint16_t dst , uint8_t value )
{
Write ( dst , value ) ;
}
void GbCpu : : LD_Indirect16 ( uint16_t dst , uint16_t value )
{
Write ( dst , ( uint8_t ) value ) ;
Write ( dst + 1 , value > > 8 ) ;
}
//ld HL,SP+dd F8 12 00hc HL = SP +/- dd ;dd is 8bit signed number
void GbCpu : : LD_HL ( int8_t value )
{
int result = ( uint8_t ) _state . SP + ( uint8_t ) value ;
//"Both of these set carry and half-carry based on the low byte of SP added to the UNSIGNED immediate byte. The Negative and Zero flags are always cleared."
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( ( uint8_t ) _state . SP ^ result ^ value ) & 0x10 ) ! = 0 ) ;
SetFlagState ( GbCpuFlags : : Carry , result > 0xFF ) ;
_regHL . Write ( _state . SP + value ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
IncCycleCount ( ) ;
}
// inc r xx 4 z0h- r=r+1
void GbCpu : : INC ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( dst ^ 1 ^ ( dst + 1 ) ) & 0x10 ) ! = 0 ) ;
dst + + ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
}
// inc rr x3 8 ---- rr = rr+1 ;rr may be BC,DE,HL,SP
void GbCpu : : INC ( Register16 & dst )
{
//16-bit inc does not alter flags
IncCycleCount ( ) ;
dst . Write ( dst . Read ( ) + 1 ) ;
}
// inc rr x3 8 ---- rr = rr+1 ;rr may be BC,DE,HL,SP
void GbCpu : : INC_SP ( )
{
IncCycleCount ( ) ;
_state . SP + + ;
}
// inc (HL) 34 12 z0h- (HL)=(HL)+1
void GbCpu : : INC_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
INC ( val ) ;
Write ( addr , val ) ;
}
// dec r xx 4 z1h- r=r-1
void GbCpu : : DEC ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : HalfCarry , ( dst & 0x0F ) = = 0x00 ) ;
dst - - ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
SetFlag ( GbCpuFlags : : AddSub ) ;
}
// dec rr xB 8 ---- rr = rr-1 ;rr may be BC,DE,HL,SP
void GbCpu : : DEC ( Register16 & dst )
{
//16-bit dec does not alter flags
IncCycleCount ( ) ;
dst . Write ( dst . Read ( ) - 1 ) ;
}
// dec (HL) 35 12 z1h- (HL)=(HL)-1
void GbCpu : : DEC_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
DEC ( val ) ;
Write ( addr , val ) ;
}
// dec rr xB 8 ---- rr = rr-1 ;rr may be BC,DE,HL,SP
void GbCpu : : DEC_SP ( )
{
_state . SP - - ;
IncCycleCount ( ) ;
}
// add A,r 8x 4 z0hc A=A+r
// add A,n C6 nn 8 z0hc A=A+n
// add A,(HL) 86 8 z0hc A=A+(HL)
void GbCpu : : ADD ( uint8_t value )
{
int result = _state . A + value ;
//SetFlagState(GbCpuFlags::HalfCarry, (_state.A & 0xF) + (value & 0xF) > 0xF);
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( _state . A ^ value ^ result ) & 0x10 ) ! = 0 ) ;
_state . A = ( uint8_t ) result ;
SetFlagState ( GbCpuFlags : : Carry , result > 0xFF ) ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
}
//add SP,dd E8 16 00hc SP = SP +/- dd ;dd is 8bit signed number
void GbCpu : : ADD_SP ( int8_t value )
{
int result = ( uint8_t ) _state . SP + ( uint8_t ) value ;
//"Both of these set carry and half-carry based on the low byte of SP added to the UNSIGNED immediate byte. The Negative and Zero flags are always cleared."
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( ( uint8_t ) _state . SP ^ result ^ value ) & 0x10 ) ! = 0 ) ;
SetFlagState ( GbCpuFlags : : Carry , result > 0xFF ) ;
_state . SP + = value ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
IncCycleCount ( ) ;
IncCycleCount ( ) ;
}
// add HL,rr x9 8 -0hc HL = HL+rr ;rr may be BC,DE,HL,SP
void GbCpu : : ADD ( Register16 & reg , uint16_t value )
{
int result = reg . Read ( ) + value ;
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( reg . Read ( ) ^ value ^ result ) & 0x1000 ) ! = 0 ) ;
reg . Write ( ( uint16_t ) result ) ;
SetFlagState ( GbCpuFlags : : Carry , result > 0xFFFF ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
IncCycleCount ( ) ;
}
// adc A,r 8x 4 z0hc A=A+r+cy
// adc A,n CE nn 8 z0hc A=A+n+cy
// adc A,(HL) 8E 8 z0hc A=A+(HL)+cy
void GbCpu : : ADC ( uint8_t value )
{
uint8_t carry = ( ( _state . Flags & GbCpuFlags : : Carry ) > > 4 ) ;
int result = _state . A + value + carry ;
SetFlagState ( GbCpuFlags : : HalfCarry , ( _state . A & 0x0F ) + ( value & 0x0F ) + carry > 0x0F ) ;
_state . A = ( uint8_t ) result ;
SetFlagState ( GbCpuFlags : : Carry , result > 0xFF ) ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
}
//sub r 9x 4 z1hc A = A - r
//sub n D6 nn 8 z1hc A = A - n
//sub(HL) 96 8 z1hc A = A - (HL)
void GbCpu : : SUB ( uint8_t value )
{
int result = ( int ) _state . A - value ;
SetFlagState ( GbCpuFlags : : HalfCarry , ( _state . A & 0x0F ) < ( value & 0x0F ) ) ;
_state . A = ( uint8_t ) result ;
SetFlagState ( GbCpuFlags : : Carry , result < 0 ) ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
SetFlag ( GbCpuFlags : : AddSub ) ;
}
// sbc A,r 9x 4 z1hc A=A-r-cy
// sbc A,n DE nn 8 z1hc A=A-n-cy
// sbc A,(HL) 9E 8 z1hc A=A-(HL)-cy
void GbCpu : : SBC ( uint8_t value )
{
uint8_t carry = ( ( _state . Flags & GbCpuFlags : : Carry ) > > 4 ) ;
int result = ( int ) _state . A - value - carry ;
SetFlagState ( GbCpuFlags : : HalfCarry , ( _state . A & 0x0F ) < ( value & 0x0F ) + carry ) ;
_state . A = ( uint8_t ) result ;
SetFlagState ( GbCpuFlags : : Carry , result < 0 ) ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
SetFlag ( GbCpuFlags : : AddSub ) ;
}
// and r Ax 4 z010 A = A & r
// and n E6 nn 8 z010 A = A & n
// and (HL) A6 8 z010 A = A & (HL)
void GbCpu : : AND ( uint8_t value )
{
_state . A & = value ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Carry ) ;
SetFlag ( GbCpuFlags : : HalfCarry ) ;
}
//or r Bx 4 z000 A = A | r
//or n F6 nn 8 z000 A = A | n
//or (HL) B6 8 z000 A = A | (HL)
void GbCpu : : OR ( uint8_t value )
{
_state . A | = value ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Carry ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
// xor r Ax 4 z000
// xor n EE nn 8 z000
// xor (HL) AE 8 z000
void GbCpu : : XOR ( uint8_t value )
{
_state . A ^ = value ;
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Carry ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
// cp r Bx 4 z1hc compare A-r
// cp n FE nn 8 z1hc compare A-n
// cp (HL) BE 8 z1hc compare A-(HL)
void GbCpu : : CP ( uint8_t value )
{
int result = ( int ) _state . A - value ;
SetFlagState ( GbCpuFlags : : Carry , result < 0 ) ;
SetFlagState ( GbCpuFlags : : HalfCarry , ( ( _state . A ^ value ^ result ) & 0x10 ) ! = 0 ) ;
SetFlagState ( GbCpuFlags : : Zero , ( uint8_t ) result = = 0 ) ;
SetFlag ( GbCpuFlags : : AddSub ) ;
}
void GbCpu : : NOP ( )
{
2021-03-10 11:13:28 -05:00
2020-05-18 16:10:53 -04:00
}
void GbCpu : : InvalidOp ( )
{
2020-06-20 21:37:26 -04:00
//Disable all IRQs
_memoryManager - > Write ( 0xFFFF , 0 ) ;
//Halt CPU to lock it up permanently
_state . Halted = true ;
2020-05-18 16:10:53 -04:00
}
void GbCpu : : STOP ( )
{
2021-03-10 11:13:28 -05:00
if ( _gameboy - > IsCgb ( ) & & _memoryManager - > GetState ( ) . CgbSwitchSpeedRequest ) {
2020-05-19 21:31:33 -04:00
_memoryManager - > ToggleSpeed ( ) ;
2021-03-10 11:13:28 -05:00
} else {
2020-05-19 21:31:33 -04:00
_state . Halted = true ;
}
2020-05-18 16:10:53 -04:00
}
void GbCpu : : HALT ( )
{
2021-03-10 11:13:28 -05:00
if ( _state . IME | | _memoryManager - > ProcessIrqRequests ( ) = = 0 ) {
2020-06-09 22:17:52 -04:00
_state . Halted = true ;
2021-03-10 11:13:28 -05:00
} else {
2020-06-09 22:17:52 -04:00
//HALT bug, execution continues, but PC isn't incremented for the first byte
HalfCycle ( ) ;
uint8_t opCode = _memoryManager - > Read < MemoryOperationType : : ExecOpCode > ( _state . PC ) ;
HalfCycle ( ) ;
ExecOpCode ( opCode ) ;
}
2020-05-18 16:10:53 -04:00
}
// cpl 2F 4 -11- A = A xor FF
void GbCpu : : CPL ( )
{
_state . A ^ = 0xFF ;
SetFlag ( GbCpuFlags : : AddSub ) ;
SetFlag ( GbCpuFlags : : HalfCarry ) ;
}
//rl r CB 1x 8 z00c rotate left through carry
void GbCpu : : RL ( uint8_t & dst )
{
uint8_t carry = ( uint8_t ) CheckFlag ( GbCpuFlags : : Carry ) ;
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x80 ) ! = 0 ) ;
dst = ( dst < < 1 ) | carry ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//rl (HL) CB 16 16 z00c rotate left through carry
void GbCpu : : RL_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
RL ( val ) ;
Write ( addr , val ) ;
}
//rlc r CB 0x 8 z00c rotate left
void GbCpu : : RLC ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x80 ) ! = 0 ) ;
dst = ( dst < < 1 ) | ( ( dst & 0x80 ) > > 7 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//rlc (HL) CB 06 16 z00c rotate left
void GbCpu : : RLC_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
RLC ( val ) ;
Write ( addr , val ) ;
}
//rr r CB 1x 8 z00c rotate right through carry
void GbCpu : : RR ( uint8_t & dst )
{
uint8_t carry = ( uint8_t ) CheckFlag ( GbCpuFlags : : Carry ) < < 7 ;
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x01 ) ! = 0 ) ;
dst = ( dst > > 1 ) | carry ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//rr (HL) CB 1E 16 z00c rotate right through carry
void GbCpu : : RR_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
RR ( val ) ;
Write ( addr , val ) ;
}
//rrc r CB 0x 8 z00c rotate right
void GbCpu : : RRC ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x01 ) ! = 0 ) ;
dst = ( dst > > 1 ) | ( ( dst & 0x01 ) < < 7 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//rrc (HL) CB 0E 16 z00c rotate right
void GbCpu : : RRC_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
RRC ( val ) ;
Write ( addr , val ) ;
}
//rra 1F 4 000c rotate akku right through carry
void GbCpu : : RRA ( )
{
RR ( _state . A ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
}
//rrca 0F 4 000c rotate akku right
void GbCpu : : RRCA ( )
{
RRC ( _state . A ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
}
//rlca 07 4 000c rotate akku left
void GbCpu : : RLCA ( )
{
RLC ( _state . A ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
}
//rla 17 4 000c rotate akku left through carry
void GbCpu : : RLA ( )
{
RL ( _state . A ) ;
ClearFlag ( GbCpuFlags : : Zero ) ;
}
//srl r CB 3x 8 z00c shift right logical (b7=0)
void GbCpu : : SRL ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x01 ) ! = 0 ) ;
dst = ( dst > > 1 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//srl (HL) CB 3E 16 z00c shift right logical (b7=0)
void GbCpu : : SRL_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
SRL ( val ) ;
Write ( addr , val ) ;
}
//sra r CB 2x 8 z00c shift right arithmetic (b7=b7)
void GbCpu : : SRA ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x01 ) ! = 0 ) ;
dst = ( dst & 0x80 ) | ( dst > > 1 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//sra (HL) CB 2E 16 z00c shift right arithmetic (b7=b7)
void GbCpu : : SRA_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
SRA ( val ) ;
Write ( addr , val ) ;
}
//sla r CB 2x 8 z00c shift left arithmetic (b0=0)
void GbCpu : : SLA ( uint8_t & dst )
{
SetFlagState ( GbCpuFlags : : Carry , ( dst & 0x80 ) ! = 0 ) ;
dst = ( dst < < 1 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//sla (HL) CB 26 16 z00c shift left arithmetic (b0=0)
void GbCpu : : SLA_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
SLA ( val ) ;
Write ( addr , val ) ;
}
//swap r CB 3x 8 z000 exchange low/hi-nibble
void GbCpu : : SWAP ( uint8_t & dst )
{
dst = ( ( dst & 0x0F ) < < 4 ) | ( dst > > 4 ) ;
SetFlagState ( GbCpuFlags : : Zero , dst = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : Carry ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//swap (HL) CB 36 16 z000 exchange low/hi-nibble
void GbCpu : : SWAP_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
SWAP ( val ) ;
Write ( addr , val ) ;
}
2021-03-10 11:13:28 -05:00
template < uint8_t bit >
2020-05-18 16:10:53 -04:00
void GbCpu : : BIT ( uint8_t src )
{
SetFlagState ( GbCpuFlags : : Zero , ( src & ( 1 < < bit ) ) = = 0 ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
SetFlag ( GbCpuFlags : : HalfCarry ) ;
}
2021-03-10 11:13:28 -05:00
template < uint8_t bit >
2020-05-18 16:10:53 -04:00
void GbCpu : : RES ( uint8_t & dst )
{
dst & = ~ ( 1 < < bit ) ;
}
2021-03-10 11:13:28 -05:00
template < uint8_t bit >
2020-05-18 16:10:53 -04:00
void GbCpu : : RES_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
RES < bit > ( val ) ;
Write ( addr , val ) ;
}
2021-03-10 11:13:28 -05:00
template < uint8_t bit >
2020-05-18 16:10:53 -04:00
void GbCpu : : SET ( uint8_t & dst )
{
dst | = ( 1 < < bit ) ;
}
2021-03-10 11:13:28 -05:00
template < uint8_t bit >
2020-05-18 16:10:53 -04:00
void GbCpu : : SET_Indirect ( uint16_t addr )
{
uint8_t val = Read ( addr ) ;
SET < bit > ( val ) ;
Write ( addr , val ) ;
}
// daa 27 4 z-0x decimal adjust akku
void GbCpu : : DAA ( )
{
2021-03-10 11:13:28 -05:00
if ( CheckFlag ( GbCpuFlags : : AddSub ) ) {
if ( CheckFlag ( GbCpuFlags : : Carry ) ) {
2020-05-18 16:10:53 -04:00
_state . A - = 0x60 ;
}
2021-03-10 11:13:28 -05:00
if ( CheckFlag ( GbCpuFlags : : HalfCarry ) ) {
2020-05-18 16:10:53 -04:00
_state . A - = 0x06 ;
}
2021-03-10 11:13:28 -05:00
} else {
if ( CheckFlag ( GbCpuFlags : : Carry ) | | _state . A > 0x99 ) {
2020-05-18 16:10:53 -04:00
_state . A + = 0x60 ;
SetFlag ( GbCpuFlags : : Carry ) ;
}
2021-03-10 11:13:28 -05:00
if ( CheckFlag ( GbCpuFlags : : HalfCarry ) | | ( _state . A & 0x0F ) > 0x09 ) {
2020-05-18 16:10:53 -04:00
_state . A + = 0x6 ;
}
}
SetFlagState ( GbCpuFlags : : Zero , _state . A = = 0 ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//jp nn C3 nn nn 16 ---- jump to nn, PC=nn
void GbCpu : : JP ( uint16_t dstAddr )
{
_state . PC = dstAddr ;
IncCycleCount ( ) ;
}
//jp HL E9 4 ---- jump to HL, PC=HL
void GbCpu : : JP_HL ( )
{
_state . PC = _regHL ;
}
//jp f,nn xx nn nn 16;12 ---- conditional jump if nz,z,nc,c
void GbCpu : : JP ( bool condition , uint16_t dstAddr )
{
2021-03-10 11:13:28 -05:00
if ( condition ) {
2020-05-18 16:10:53 -04:00
_state . PC = dstAddr ;
IncCycleCount ( ) ;
}
}
//jr PC+dd 18 dd 12 ---- relative jump to nn (PC=PC+/-7bit)
void GbCpu : : JR ( int8_t offset )
{
_state . PC + = offset ;
IncCycleCount ( ) ;
}
//jr f,PC+dd xx dd 12;8 ---- conditional relative jump if nz,z,nc,c
void GbCpu : : JR ( bool condition , int8_t offset )
{
2021-03-10 11:13:28 -05:00
if ( condition ) {
2020-05-18 16:10:53 -04:00
_state . PC + = offset ;
IncCycleCount ( ) ;
}
}
//call nn CD nn nn 24 ---- call to nn, SP=SP-2, (SP)=PC, PC=nn
void GbCpu : : CALL ( uint16_t dstAddr )
{
2020-05-23 11:45:29 -04:00
IncCycleCount ( ) ;
2020-05-18 16:10:53 -04:00
PushWord ( _state . PC ) ;
_state . PC = dstAddr ;
}
//call f,nn xx nn nn 24;12 ---- conditional call if nz,z,nc,c
void GbCpu : : CALL ( bool condition , uint16_t dstAddr )
{
2021-03-10 11:13:28 -05:00
if ( condition ) {
2020-05-23 00:45:22 -04:00
IncCycleCount ( ) ;
2020-05-18 16:10:53 -04:00
PushWord ( _state . PC ) ;
_state . PC = dstAddr ;
}
}
//ret C9 16 ---- return, PC=(SP), SP=SP+2
void GbCpu : : RET ( )
{
_state . PC = PopWord ( ) ;
IncCycleCount ( ) ;
}
//ret f xx 20;8 ---- conditional return if nz,z,nc,c
void GbCpu : : RET ( bool condition )
{
IncCycleCount ( ) ;
2021-03-10 11:13:28 -05:00
if ( condition ) {
2020-05-18 16:10:53 -04:00
_state . PC = PopWord ( ) ;
IncCycleCount ( ) ;
}
}
//reti D9 16 ---- return and enable interrupts (IME=1)
void GbCpu : : RETI ( )
{
_state . PC = PopWord ( ) ;
_state . IME = true ;
IncCycleCount ( ) ;
}
//rst n xx 16 ---- call to 00,08,10,18,20,28,30,38
void GbCpu : : RST ( uint8_t value )
{
2020-05-23 11:20:05 -04:00
IncCycleCount ( ) ;
2020-05-18 16:10:53 -04:00
PushWord ( _state . PC ) ;
_state . PC = value ;
}
void GbCpu : : POP ( Register16 & reg )
{
reg . Write ( PopWord ( ) ) ;
}
void GbCpu : : PUSH ( Register16 & reg )
{
IncCycleCount ( ) ;
2020-05-23 11:20:05 -04:00
PushWord ( reg ) ;
2020-05-18 16:10:53 -04:00
}
void GbCpu : : POP_AF ( )
{
_regAF . Write ( PopWord ( ) & 0xFFF0 ) ;
}
//scf 37 4 -001 cy=1
void GbCpu : : SCF ( )
{
SetFlag ( GbCpuFlags : : Carry ) ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
//ccf 3F 4 -00c cy=cy xor 1
void GbCpu : : CCF ( )
{
_state . Flags ^ = GbCpuFlags : : Carry ;
ClearFlag ( GbCpuFlags : : AddSub ) ;
ClearFlag ( GbCpuFlags : : HalfCarry ) ;
}
void GbCpu : : EI ( )
{
2020-05-23 12:38:31 -04:00
_state . EiPending = true ;
2020-05-18 16:10:53 -04:00
}
void GbCpu : : DI ( )
{
_state . IME = false ;
}
void GbCpu : : PREFIX ( )
{
2021-03-10 11:13:28 -05:00
switch ( ReadCode ( ) ) {
case 0x00 : RLC ( _state . B ) ; break ;
case 0x01 : RLC ( _state . C ) ; break ;
case 0x02 : RLC ( _state . D ) ; break ;
case 0x03 : RLC ( _state . E ) ; break ;
case 0x04 : RLC ( _state . H ) ; break ;
case 0x05 : RLC ( _state . L ) ; break ;
case 0x06 : RLC_Indirect ( _regHL ) ; break ;
case 0x07 : RLC ( _state . A ) ; break ;
case 0x08 : RRC ( _state . B ) ; break ;
case 0x09 : RRC ( _state . C ) ; break ;
case 0x0A : RRC ( _state . D ) ; break ;
case 0x0B : RRC ( _state . E ) ; break ;
case 0x0C : RRC ( _state . H ) ; break ;
case 0x0D : RRC ( _state . L ) ; break ;
case 0x0E : RRC_Indirect ( _regHL ) ; break ;
case 0x0F : RRC ( _state . A ) ; break ;
case 0x10 : RL ( _state . B ) ; break ;
case 0x11 : RL ( _state . C ) ; break ;
case 0x12 : RL ( _state . D ) ; break ;
case 0x13 : RL ( _state . E ) ; break ;
case 0x14 : RL ( _state . H ) ; break ;
case 0x15 : RL ( _state . L ) ; break ;
case 0x16 : RL_Indirect ( _regHL ) ; break ;
case 0x17 : RL ( _state . A ) ; break ;
case 0x18 : RR ( _state . B ) ; break ;
case 0x19 : RR ( _state . C ) ; break ;
case 0x1A : RR ( _state . D ) ; break ;
case 0x1B : RR ( _state . E ) ; break ;
case 0x1C : RR ( _state . H ) ; break ;
case 0x1D : RR ( _state . L ) ; break ;
case 0x1E : RR_Indirect ( _regHL ) ; break ;
case 0x1F : RR ( _state . A ) ; break ;
case 0x20 : SLA ( _state . B ) ; break ;
case 0x21 : SLA ( _state . C ) ; break ;
case 0x22 : SLA ( _state . D ) ; break ;
case 0x23 : SLA ( _state . E ) ; break ;
case 0x24 : SLA ( _state . H ) ; break ;
case 0x25 : SLA ( _state . L ) ; break ;
case 0x26 : SLA_Indirect ( _regHL ) ; break ;
case 0x27 : SLA ( _state . A ) ; break ;
case 0x28 : SRA ( _state . B ) ; break ;
case 0x29 : SRA ( _state . C ) ; break ;
case 0x2A : SRA ( _state . D ) ; break ;
case 0x2B : SRA ( _state . E ) ; break ;
case 0x2C : SRA ( _state . H ) ; break ;
case 0x2D : SRA ( _state . L ) ; break ;
case 0x2E : SRA_Indirect ( _regHL ) ; break ;
case 0x2F : SRA ( _state . A ) ; break ;
case 0x30 : SWAP ( _state . B ) ; break ;
case 0x31 : SWAP ( _state . C ) ; break ;
case 0x32 : SWAP ( _state . D ) ; break ;
case 0x33 : SWAP ( _state . E ) ; break ;
case 0x34 : SWAP ( _state . H ) ; break ;
case 0x35 : SWAP ( _state . L ) ; break ;
case 0x36 : SWAP_Indirect ( _regHL ) ; break ;
case 0x37 : SWAP ( _state . A ) ; break ;
case 0x38 : SRL ( _state . B ) ; break ;
case 0x39 : SRL ( _state . C ) ; break ;
case 0x3A : SRL ( _state . D ) ; break ;
case 0x3B : SRL ( _state . E ) ; break ;
case 0x3C : SRL ( _state . H ) ; break ;
case 0x3D : SRL ( _state . L ) ; break ;
case 0x3E : SRL_Indirect ( _regHL ) ; break ;
case 0x3F : SRL ( _state . A ) ; break ;
case 0x40 : BIT < 0 > ( _state . B ) ; break ;
case 0x41 : BIT < 0 > ( _state . C ) ; break ;
case 0x42 : BIT < 0 > ( _state . D ) ; break ;
case 0x43 : BIT < 0 > ( _state . E ) ; break ;
case 0x44 : BIT < 0 > ( _state . H ) ; break ;
case 0x45 : BIT < 0 > ( _state . L ) ; break ;
case 0x46 : BIT < 0 > ( Read ( _regHL ) ) ; break ;
case 0x47 : BIT < 0 > ( _state . A ) ; break ;
case 0x48 : BIT < 1 > ( _state . B ) ; break ;
case 0x49 : BIT < 1 > ( _state . C ) ; break ;
case 0x4A : BIT < 1 > ( _state . D ) ; break ;
case 0x4B : BIT < 1 > ( _state . E ) ; break ;
case 0x4C : BIT < 1 > ( _state . H ) ; break ;
case 0x4D : BIT < 1 > ( _state . L ) ; break ;
case 0x4E : BIT < 1 > ( Read ( _regHL ) ) ; break ;
case 0x4F : BIT < 1 > ( _state . A ) ; break ;
case 0x50 : BIT < 2 > ( _state . B ) ; break ;
case 0x51 : BIT < 2 > ( _state . C ) ; break ;
case 0x52 : BIT < 2 > ( _state . D ) ; break ;
case 0x53 : BIT < 2 > ( _state . E ) ; break ;
case 0x54 : BIT < 2 > ( _state . H ) ; break ;
case 0x55 : BIT < 2 > ( _state . L ) ; break ;
case 0x56 : BIT < 2 > ( Read ( _regHL ) ) ; break ;
case 0x57 : BIT < 2 > ( _state . A ) ; break ;
case 0x58 : BIT < 3 > ( _state . B ) ; break ;
case 0x59 : BIT < 3 > ( _state . C ) ; break ;
case 0x5A : BIT < 3 > ( _state . D ) ; break ;
case 0x5B : BIT < 3 > ( _state . E ) ; break ;
case 0x5C : BIT < 3 > ( _state . H ) ; break ;
case 0x5D : BIT < 3 > ( _state . L ) ; break ;
case 0x5E : BIT < 3 > ( Read ( _regHL ) ) ; break ;
case 0x5F : BIT < 3 > ( _state . A ) ; break ;
case 0x60 : BIT < 4 > ( _state . B ) ; break ;
case 0x61 : BIT < 4 > ( _state . C ) ; break ;
case 0x62 : BIT < 4 > ( _state . D ) ; break ;
case 0x63 : BIT < 4 > ( _state . E ) ; break ;
case 0x64 : BIT < 4 > ( _state . H ) ; break ;
case 0x65 : BIT < 4 > ( _state . L ) ; break ;
case 0x66 : BIT < 4 > ( Read ( _regHL ) ) ; break ;
case 0x67 : BIT < 4 > ( _state . A ) ; break ;
case 0x68 : BIT < 5 > ( _state . B ) ; break ;
case 0x69 : BIT < 5 > ( _state . C ) ; break ;
case 0x6A : BIT < 5 > ( _state . D ) ; break ;
case 0x6B : BIT < 5 > ( _state . E ) ; break ;
case 0x6C : BIT < 5 > ( _state . H ) ; break ;
case 0x6D : BIT < 5 > ( _state . L ) ; break ;
case 0x6E : BIT < 5 > ( Read ( _regHL ) ) ; break ;
case 0x6F : BIT < 5 > ( _state . A ) ; break ;
case 0x70 : BIT < 6 > ( _state . B ) ; break ;
case 0x71 : BIT < 6 > ( _state . C ) ; break ;
case 0x72 : BIT < 6 > ( _state . D ) ; break ;
case 0x73 : BIT < 6 > ( _state . E ) ; break ;
case 0x74 : BIT < 6 > ( _state . H ) ; break ;
case 0x75 : BIT < 6 > ( _state . L ) ; break ;
case 0x76 : BIT < 6 > ( Read ( _regHL ) ) ; break ;
case 0x77 : BIT < 6 > ( _state . A ) ; break ;
case 0x78 : BIT < 7 > ( _state . B ) ; break ;
case 0x79 : BIT < 7 > ( _state . C ) ; break ;
case 0x7A : BIT < 7 > ( _state . D ) ; break ;
case 0x7B : BIT < 7 > ( _state . E ) ; break ;
case 0x7C : BIT < 7 > ( _state . H ) ; break ;
case 0x7D : BIT < 7 > ( _state . L ) ; break ;
case 0x7E : BIT < 7 > ( Read ( _regHL ) ) ; break ;
case 0x7F : BIT < 7 > ( _state . A ) ; break ;
case 0x80 : RES < 0 > ( _state . B ) ; break ;
case 0x81 : RES < 0 > ( _state . C ) ; break ;
case 0x82 : RES < 0 > ( _state . D ) ; break ;
case 0x83 : RES < 0 > ( _state . E ) ; break ;
case 0x84 : RES < 0 > ( _state . H ) ; break ;
case 0x85 : RES < 0 > ( _state . L ) ; break ;
case 0x86 : RES_Indirect < 0 > ( _regHL ) ; break ;
case 0x87 : RES < 0 > ( _state . A ) ; break ;
case 0x88 : RES < 1 > ( _state . B ) ; break ;
case 0x89 : RES < 1 > ( _state . C ) ; break ;
case 0x8A : RES < 1 > ( _state . D ) ; break ;
case 0x8B : RES < 1 > ( _state . E ) ; break ;
case 0x8C : RES < 1 > ( _state . H ) ; break ;
case 0x8D : RES < 1 > ( _state . L ) ; break ;
case 0x8E : RES_Indirect < 1 > ( _regHL ) ; break ;
case 0x8F : RES < 1 > ( _state . A ) ; break ;
case 0x90 : RES < 2 > ( _state . B ) ; break ;
case 0x91 : RES < 2 > ( _state . C ) ; break ;
case 0x92 : RES < 2 > ( _state . D ) ; break ;
case 0x93 : RES < 2 > ( _state . E ) ; break ;
case 0x94 : RES < 2 > ( _state . H ) ; break ;
case 0x95 : RES < 2 > ( _state . L ) ; break ;
case 0x96 : RES_Indirect < 2 > ( _regHL ) ; break ;
case 0x97 : RES < 2 > ( _state . A ) ; break ;
case 0x98 : RES < 3 > ( _state . B ) ; break ;
case 0x99 : RES < 3 > ( _state . C ) ; break ;
case 0x9A : RES < 3 > ( _state . D ) ; break ;
case 0x9B : RES < 3 > ( _state . E ) ; break ;
case 0x9C : RES < 3 > ( _state . H ) ; break ;
case 0x9D : RES < 3 > ( _state . L ) ; break ;
case 0x9E : RES_Indirect < 3 > ( _regHL ) ; break ;
case 0x9F : RES < 3 > ( _state . A ) ; break ;
case 0xA0 : RES < 4 > ( _state . B ) ; break ;
case 0xA1 : RES < 4 > ( _state . C ) ; break ;
case 0xA2 : RES < 4 > ( _state . D ) ; break ;
case 0xA3 : RES < 4 > ( _state . E ) ; break ;
case 0xA4 : RES < 4 > ( _state . H ) ; break ;
case 0xA5 : RES < 4 > ( _state . L ) ; break ;
case 0xA6 : RES_Indirect < 4 > ( _regHL ) ; break ;
case 0xA7 : RES < 4 > ( _state . A ) ; break ;
case 0xA8 : RES < 5 > ( _state . B ) ; break ;
case 0xA9 : RES < 5 > ( _state . C ) ; break ;
case 0xAA : RES < 5 > ( _state . D ) ; break ;
case 0xAB : RES < 5 > ( _state . E ) ; break ;
case 0xAC : RES < 5 > ( _state . H ) ; break ;
case 0xAD : RES < 5 > ( _state . L ) ; break ;
case 0xAE : RES_Indirect < 5 > ( _regHL ) ; break ;
case 0xAF : RES < 5 > ( _state . A ) ; break ;
case 0xB0 : RES < 6 > ( _state . B ) ; break ;
case 0xB1 : RES < 6 > ( _state . C ) ; break ;
case 0xB2 : RES < 6 > ( _state . D ) ; break ;
case 0xB3 : RES < 6 > ( _state . E ) ; break ;
case 0xB4 : RES < 6 > ( _state . H ) ; break ;
case 0xB5 : RES < 6 > ( _state . L ) ; break ;
case 0xB6 : RES_Indirect < 6 > ( _regHL ) ; break ;
case 0xB7 : RES < 6 > ( _state . A ) ; break ;
case 0xB8 : RES < 7 > ( _state . B ) ; break ;
case 0xB9 : RES < 7 > ( _state . C ) ; break ;
case 0xBA : RES < 7 > ( _state . D ) ; break ;
case 0xBB : RES < 7 > ( _state . E ) ; break ;
case 0xBC : RES < 7 > ( _state . H ) ; break ;
case 0xBD : RES < 7 > ( _state . L ) ; break ;
case 0xBE : RES_Indirect < 7 > ( _regHL ) ; break ;
case 0xBF : RES < 7 > ( _state . A ) ; break ;
case 0xC0 : SET < 0 > ( _state . B ) ; break ;
case 0xC1 : SET < 0 > ( _state . C ) ; break ;
case 0xC2 : SET < 0 > ( _state . D ) ; break ;
case 0xC3 : SET < 0 > ( _state . E ) ; break ;
case 0xC4 : SET < 0 > ( _state . H ) ; break ;
case 0xC5 : SET < 0 > ( _state . L ) ; break ;
case 0xC6 : SET_Indirect < 0 > ( _regHL ) ; break ;
case 0xC7 : SET < 0 > ( _state . A ) ; break ;
case 0xC8 : SET < 1 > ( _state . B ) ; break ;
case 0xC9 : SET < 1 > ( _state . C ) ; break ;
case 0xCA : SET < 1 > ( _state . D ) ; break ;
case 0xCB : SET < 1 > ( _state . E ) ; break ;
case 0xCC : SET < 1 > ( _state . H ) ; break ;
case 0xCD : SET < 1 > ( _state . L ) ; break ;
case 0xCE : SET_Indirect < 1 > ( _regHL ) ; break ;
case 0xCF : SET < 1 > ( _state . A ) ; break ;
case 0xD0 : SET < 2 > ( _state . B ) ; break ;
case 0xD1 : SET < 2 > ( _state . C ) ; break ;
case 0xD2 : SET < 2 > ( _state . D ) ; break ;
case 0xD3 : SET < 2 > ( _state . E ) ; break ;
case 0xD4 : SET < 2 > ( _state . H ) ; break ;
case 0xD5 : SET < 2 > ( _state . L ) ; break ;
case 0xD6 : SET_Indirect < 2 > ( _regHL ) ; break ;
case 0xD7 : SET < 2 > ( _state . A ) ; break ;
case 0xD8 : SET < 3 > ( _state . B ) ; break ;
case 0xD9 : SET < 3 > ( _state . C ) ; break ;
case 0xDA : SET < 3 > ( _state . D ) ; break ;
case 0xDB : SET < 3 > ( _state . E ) ; break ;
case 0xDC : SET < 3 > ( _state . H ) ; break ;
case 0xDD : SET < 3 > ( _state . L ) ; break ;
case 0xDE : SET_Indirect < 3 > ( _regHL ) ; break ;
case 0xDF : SET < 3 > ( _state . A ) ; break ;
case 0xE0 : SET < 4 > ( _state . B ) ; break ;
case 0xE1 : SET < 4 > ( _state . C ) ; break ;
case 0xE2 : SET < 4 > ( _state . D ) ; break ;
case 0xE3 : SET < 4 > ( _state . E ) ; break ;
case 0xE4 : SET < 4 > ( _state . H ) ; break ;
case 0xE5 : SET < 4 > ( _state . L ) ; break ;
case 0xE6 : SET_Indirect < 4 > ( _regHL ) ; break ;
case 0xE7 : SET < 4 > ( _state . A ) ; break ;
case 0xE8 : SET < 5 > ( _state . B ) ; break ;
case 0xE9 : SET < 5 > ( _state . C ) ; break ;
case 0xEA : SET < 5 > ( _state . D ) ; break ;
case 0xEB : SET < 5 > ( _state . E ) ; break ;
case 0xEC : SET < 5 > ( _state . H ) ; break ;
case 0xED : SET < 5 > ( _state . L ) ; break ;
case 0xEE : SET_Indirect < 5 > ( _regHL ) ; break ;
case 0xEF : SET < 5 > ( _state . A ) ; break ;
case 0xF0 : SET < 6 > ( _state . B ) ; break ;
case 0xF1 : SET < 6 > ( _state . C ) ; break ;
case 0xF2 : SET < 6 > ( _state . D ) ; break ;
case 0xF3 : SET < 6 > ( _state . E ) ; break ;
case 0xF4 : SET < 6 > ( _state . H ) ; break ;
case 0xF5 : SET < 6 > ( _state . L ) ; break ;
case 0xF6 : SET_Indirect < 6 > ( _regHL ) ; break ;
case 0xF7 : SET < 6 > ( _state . A ) ; break ;
case 0xF8 : SET < 7 > ( _state . B ) ; break ;
case 0xF9 : SET < 7 > ( _state . C ) ; break ;
case 0xFA : SET < 7 > ( _state . D ) ; break ;
case 0xFB : SET < 7 > ( _state . E ) ; break ;
case 0xFC : SET < 7 > ( _state . H ) ; break ;
case 0xFD : SET < 7 > ( _state . L ) ; break ;
case 0xFE : SET_Indirect < 7 > ( _regHL ) ; break ;
case 0xFF : SET < 7 > ( _state . A ) ; break ;
2020-05-18 16:10:53 -04:00
}
}
void GbCpu : : Serialize ( Serializer & s )
{
s . Stream (
2020-05-27 22:50:27 -04:00
_state . PC , _state . SP , _state . A , _state . Flags , _state . B ,
2020-05-24 22:04:47 -04:00
_state . C , _state . D , _state . E , _state . H , _state . L , _state . IME , _state . Halted ,
_state . EiPending
2020-05-18 16:10:53 -04:00
) ;
}
2020-10-11 13:57:01 +03:00
void GbCpu : : SetReg ( GbRegister reg , uint16_t value )
{
switch ( reg )
{
case GbRegister : : GbRegPC :
2021-03-10 11:13:28 -05:00
{
_state . PC = value ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegSP :
2021-03-10 11:13:28 -05:00
{
_state . SP = value ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegA :
2021-03-10 11:13:28 -05:00
{
_state . A = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegFlags :
2021-03-10 11:13:28 -05:00
{
_state . Flags = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegB :
2021-03-10 11:13:28 -05:00
{
_state . B = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegC :
2021-03-10 11:13:28 -05:00
{
_state . C = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegD :
2021-03-10 11:13:28 -05:00
{
_state . D = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegE :
2021-03-10 11:13:28 -05:00
{
_state . E = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegH :
2021-03-10 11:13:28 -05:00
{
_state . H = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
case GbRegister : : GbRegL :
2021-03-10 11:13:28 -05:00
{
_state . L = value & 0xFF ;
} break ;
2020-10-11 13:57:01 +03:00
}
}