2019-02-11 19:18:47 -05:00
# include "stdafx.h"
# include "CpuTypes.h"
# include "Cpu.h"
2019-02-11 22:41:34 -05:00
# include "MemoryManager.h"
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
//TODO: PER doesn't load the right number of bytes?
2019-02-11 19:18:47 -05:00
/************************
Add / substract operations
* * * * * * * * * * * * * * * * * * * * * * * * */
void Cpu : : Add8 ( uint8_t value )
{
uint32_t result ;
if ( CheckFlag ( ProcFlags : : Decimal ) ) {
result = ( _state . A & 0x0F ) + ( value & 0x0F ) + ( _state . PS & ProcFlags : : Carry ) ;
if ( result > 0x09 ) result + = 0x06 ;
result = ( _state . A & 0xF0 ) + ( value & 0xF0 ) + ( result > 0x0F ? 0x10 : 0 ) + ( result & 0x0F ) ;
} else {
result = ( uint32_t ) _state . A + value + ( _state . PS & ProcFlags : : Carry ) ;
}
if ( ~ ( _state . A ^ value ) & ( _state . A ^ result ) & 0x80 ) {
SetFlags ( ProcFlags : : Overflow ) ;
} else {
ClearFlags ( ProcFlags : : Overflow ) ;
}
if ( CheckFlag ( ProcFlags : : Decimal ) & & result > 0x9F ) {
result + = 0x60 ;
}
ClearFlags ( ProcFlags : : Carry | ProcFlags : : Negative | ProcFlags : : Zero ) ;
SetZeroNegativeFlags ( ( uint8_t ) result ) ;
if ( result & 0x100 ) {
SetFlags ( ProcFlags : : Carry ) ;
}
_state . A = ( uint8_t ) result ;
}
void Cpu : : Add16 ( uint16_t value )
{
uint32_t result ;
if ( CheckFlag ( ProcFlags : : Decimal ) ) {
result = ( _state . A & 0x0F ) + ( value & 0x0F ) + ( _state . PS & ProcFlags : : Carry ) ;
if ( result > 0x09 ) result + = 0x06 ;
result = ( _state . A & 0xF0 ) + ( value & 0xF0 ) + ( result > 0x0F ? 0x10 : 0 ) + ( result & 0x0F ) ;
if ( result > 0x9F ) result + = 0x60 ;
result = ( _state . A & 0xF00 ) + ( value & 0xF00 ) + ( result > 0xFF ? 0x100 : 0 ) + ( result & 0xFF ) ;
if ( result > 0x9FF ) result + = 0x600 ;
result = ( _state . A & 0xF000 ) + ( value & 0xF000 ) + ( result > 0xFFF ? 0x1000 : 0 ) + ( result & 0xFFF ) ;
} else {
result = ( uint32_t ) _state . A + value + ( _state . PS & ProcFlags : : Carry ) ;
}
if ( ~ ( _state . A ^ value ) & ( _state . A ^ result ) & 0x8000 ) {
SetFlags ( ProcFlags : : Overflow ) ;
} else {
ClearFlags ( ProcFlags : : Overflow ) ;
}
if ( CheckFlag ( ProcFlags : : Decimal ) & & result > 0x9FFF ) {
result + = 0x6000 ;
}
ClearFlags ( ProcFlags : : Carry | ProcFlags : : Negative | ProcFlags : : Zero ) ;
SetZeroNegativeFlags ( ( uint16_t ) result ) ;
if ( result & 0x10000 ) {
SetFlags ( ProcFlags : : Carry ) ;
}
_state . A = ( uint16_t ) result ;
}
void Cpu : : ADC ( )
{
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Add8 ( GetByteValue ( ) ) ;
} else {
Add16 ( GetWordValue ( ) ) ;
}
}
void Cpu : : Sub8 ( uint8_t value )
{
uint32_t result ;
if ( CheckFlag ( ProcFlags : : Decimal ) ) {
result = ( _state . A & 0x0F ) + ( value & 0x0F ) + ( _state . PS & ProcFlags : : Carry ) ;
if ( result < = 0x0F ) result - = 0x06 ;
result = ( _state . A & 0xF0 ) + ( value & 0xF0 ) + ( result > 0x0F ? 0x10 : 0 ) + ( result & 0x0F ) ;
} else {
result = ( uint32_t ) _state . A + value + ( _state . PS & ProcFlags : : Carry ) ;
}
if ( ~ ( _state . A ^ value ) & ( _state . A ^ result ) & 0x80 ) {
SetFlags ( ProcFlags : : Overflow ) ;
} else {
ClearFlags ( ProcFlags : : Overflow ) ;
}
if ( CheckFlag ( ProcFlags : : Decimal ) & & result < = 0xFF ) {
result - = 0x60 ;
}
ClearFlags ( ProcFlags : : Carry | ProcFlags : : Negative | ProcFlags : : Zero ) ;
SetZeroNegativeFlags ( ( uint8_t ) result ) ;
if ( result & 0x100 ) {
SetFlags ( ProcFlags : : Carry ) ;
}
_state . A = ( uint8_t ) result ;
}
void Cpu : : Sub16 ( uint16_t value )
{
uint32_t result ;
if ( CheckFlag ( ProcFlags : : Decimal ) ) {
result = ( _state . A & 0x0F ) + ( value & 0x0F ) + ( _state . PS & ProcFlags : : Carry ) ;
if ( result < = 0x0F ) result - = 0x06 ;
result = ( _state . A & 0xF0 ) + ( value & 0xF0 ) + ( result > 0x0F ? 0x10 : 0 ) + ( result & 0x0F ) ;
if ( result < = 0xFF ) result - = 0x60 ;
result = ( _state . A & 0xF00 ) + ( value & 0xF00 ) + ( result > 0xFF ? 0x100 : 0 ) + ( result & 0xFF ) ;
if ( result < = 0xFFF ) result - = 0x600 ;
result = ( _state . A & 0xF000 ) + ( value & 0xF000 ) + ( result > 0xFFF ? 0x1000 : 0 ) + ( result & 0xFFF ) ;
} else {
result = ( uint32_t ) _state . A + value + ( _state . PS & ProcFlags : : Carry ) ;
}
if ( ~ ( _state . A ^ value ) & ( _state . A ^ result ) & 0x8000 ) {
SetFlags ( ProcFlags : : Overflow ) ;
} else {
ClearFlags ( ProcFlags : : Overflow ) ;
}
if ( CheckFlag ( ProcFlags : : Decimal ) & & result < = 0xFFFF ) {
result - = 0x6000 ;
}
ClearFlags ( ProcFlags : : Carry | ProcFlags : : Negative | ProcFlags : : Zero ) ;
SetZeroNegativeFlags ( ( uint16_t ) result ) ;
if ( result & 0x10000 ) {
SetFlags ( ProcFlags : : Carry ) ;
}
_state . A = ( uint16_t ) result ;
}
void Cpu : : SBC ( )
{
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Sub8 ( ~ GetByteValue ( ) ) ;
} else {
Sub16 ( ~ GetWordValue ( ) ) ;
}
}
/****************
Branch operations
* * * * * * * * * * * * * * * */
void Cpu : : BCC ( )
{
BranchRelative ( ! CheckFlag ( ProcFlags : : Carry ) ) ;
}
void Cpu : : BCS ( )
{
BranchRelative ( CheckFlag ( ProcFlags : : Carry ) ) ;
}
void Cpu : : BEQ ( )
{
BranchRelative ( CheckFlag ( ProcFlags : : Zero ) ) ;
}
void Cpu : : BMI ( )
{
BranchRelative ( CheckFlag ( ProcFlags : : Negative ) ) ;
}
void Cpu : : BNE ( )
{
BranchRelative ( ! CheckFlag ( ProcFlags : : Zero ) ) ;
}
void Cpu : : BPL ( )
{
BranchRelative ( ! CheckFlag ( ProcFlags : : Negative ) ) ;
}
void Cpu : : BRA ( )
{
BranchRelative ( true ) ;
}
void Cpu : : BRL ( )
{
_state . PC = ( uint16_t ) ( _state . PC + ( int16_t ) _operand ) ;
}
void Cpu : : BVC ( )
{
BranchRelative ( ! CheckFlag ( ProcFlags : : Overflow ) ) ;
}
void Cpu : : BVS ( )
{
BranchRelative ( CheckFlag ( ProcFlags : : Overflow ) ) ;
}
void Cpu : : BranchRelative ( bool branch )
{
int8_t offset = _operand ;
if ( branch ) {
_state . PC = ( uint16_t ) ( _state . PC + offset ) ;
}
}
/***************************
Set / clear flag instructions
* * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Cpu : : CLC ( )
{
ClearFlags ( ProcFlags : : Carry ) ;
}
void Cpu : : CLD ( )
{
ClearFlags ( ProcFlags : : Decimal ) ;
}
void Cpu : : CLI ( )
{
ClearFlags ( ProcFlags : : IrqDisable ) ;
}
void Cpu : : CLV ( )
{
ClearFlags ( ProcFlags : : Overflow ) ;
}
void Cpu : : SEC ( )
{
SetFlags ( ProcFlags : : Carry ) ;
}
void Cpu : : SED ( )
{
SetFlags ( ProcFlags : : Decimal ) ;
}
void Cpu : : SEI ( )
{
SetFlags ( ProcFlags : : IrqDisable ) ;
}
void Cpu : : REP ( )
{
ClearFlags ( ( uint8_t ) _operand ) ;
}
void Cpu : : SEP ( )
{
SetFlags ( ( uint8_t ) _operand ) ;
}
/******************************
Increment / decrement operations
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void Cpu : : DEX ( )
{
IncDecReg ( _state . X , - 1 ) ;
}
void Cpu : : DEY ( )
{
IncDecReg ( _state . Y , - 1 ) ;
}
void Cpu : : INX ( )
{
IncDecReg ( _state . X , 1 ) ;
}
void Cpu : : INY ( )
{
IncDecReg ( _state . Y , 1 ) ;
}
void Cpu : : DEC ( )
{
IncDec ( - 1 ) ;
}
void Cpu : : INC ( )
{
IncDec ( 1 ) ;
}
void Cpu : : IncDecReg ( uint16_t & reg , int8_t offset )
{
SetRegister ( reg , reg + offset , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : IncDec ( int8_t offset )
{
if ( _instAddrMode = = AddrMode : : Acc ) {
SetRegister ( _state . A , _state . A + offset , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
} else {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
uint8_t value = GetByteValue ( ) + offset ;
SetZeroNegativeFlags ( value ) ;
Write ( _operand , value ) ;
} else {
uint16_t value = GetWordValue ( ) + offset ;
SetZeroNegativeFlags ( value ) ;
WriteWord ( _operand , value ) ;
}
}
}
/********************
Compare instructions
* * * * * * * * * * * * * * * * * * * * */
void Cpu : : Compare ( uint16_t reg , bool eightBitMode )
{
if ( eightBitMode ) {
uint8_t value = GetByteValue ( ) ;
if ( ( uint8_t ) reg > = value ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
uint8_t result = ( uint8_t ) reg - value ;
SetZeroNegativeFlags ( result ) ;
} else {
uint16_t value = GetWordValue ( ) ;
if ( reg > = value ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
uint16_t result = reg - value ;
SetZeroNegativeFlags ( result ) ;
}
}
void Cpu : : CMP ( )
{
Compare ( _state . A , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : CPX ( )
{
Compare ( _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : CPY ( )
{
Compare ( _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
/*****************
Jump instructions
* * * * * * * * * * * * * * * * * */
void Cpu : : JML ( )
{
_state . K = ( _operand > > 16 ) & 0xFF ;
_state . PC = ( uint16_t ) _operand ;
}
void Cpu : : JMP ( )
{
_state . PC = ( uint16_t ) _operand ;
}
void Cpu : : JSL ( )
{
PushByte ( _state . K ) ;
PushWord ( _state . PC - 1 ) ;
_state . K = ( _operand > > 16 ) & 0xFF ;
_state . PC = ( uint16_t ) _operand ;
}
void Cpu : : JSR ( )
{
PushWord ( _state . PC - 1 ) ;
_state . PC = ( uint16_t ) _operand ;
}
void Cpu : : RTI ( )
{
if ( _state . EmulationMode ) {
_state . PS = PopByte ( ) ; //TODO: incorrect
_state . PC = PopWord ( ) ;
} else {
_state . PS = PopByte ( ) ; //TODO: incorrect
_state . PC = PopWord ( ) ;
_state . K = PopByte ( ) ;
}
}
void Cpu : : RTL ( )
{
_state . PC = PopWord ( ) ;
_state . PC + + ;
_state . K = PopByte ( ) ;
}
void Cpu : : RTS ( )
{
_state . PC = PopWord ( ) ;
_state . PC + + ;
}
/**********
Interrupts
* * * * * * * * * * */
void Cpu : : ProcessInterrupt ( uint16_t vector )
{
if ( _state . EmulationMode ) {
PushWord ( _state . PC + 1 ) ;
PushByte ( _state . PS | 0x20 ) ;
SetFlags ( ProcFlags : : IrqDisable ) ;
ClearFlags ( ProcFlags : : Decimal ) ;
_state . PC = ReadDataWord ( vector ) ;
} else {
PushByte ( _state . K ) ;
PushWord ( _state . PC + 1 ) ;
PushByte ( _state . PS ) ;
SetFlags ( ProcFlags : : IrqDisable ) ;
ClearFlags ( ProcFlags : : Decimal ) ;
_state . PC = ReadDataWord ( vector ) ;
}
}
void Cpu : : BRK ( )
{
ProcessInterrupt ( _state . EmulationMode ? Cpu : : LegacyBreakVector : Cpu : : BreakVector ) ;
}
void Cpu : : COP ( )
{
ProcessInterrupt ( _state . EmulationMode ? Cpu : : LegacyCoprocessorVector : Cpu : : CoprocessorVector ) ;
}
/******************
Bitwise operations
* * * * * * * * * * * * * * * * * * */
void Cpu : : AND ( )
{
SetRegister ( _state . A , _state . A & GetByteValue ( ) , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : EOR ( )
{
SetRegister ( _state . A , _state . A ^ GetByteValue ( ) , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : ORA ( )
{
SetRegister ( _state . A , _state . A | GetByteValue ( ) , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
/****************
Shift operations
* * * * * * * * * * * * * * * * */
template < typename T > T Cpu : : ShiftLeft ( T value )
{
T result = value < < 1 ;
if ( value & ( 1 < < ( sizeof ( T ) * 8 - 1 ) ) ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
SetZeroNegativeFlags ( result ) ;
return result ;
}
template < typename T > T Cpu : : RollLeft ( T value )
{
T result = value < < 1 | ( _state . PS & ProcFlags : : Carry ) ;
if ( value & ( 1 < < ( sizeof ( T ) * 8 - 1 ) ) ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
SetZeroNegativeFlags ( result ) ;
return result ;
}
template < typename T > T Cpu : : ShiftRight ( T value )
{
T result = value > > 1 ;
if ( value & 0x01 ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
SetZeroNegativeFlags ( result ) ;
return result ;
}
template < typename T > T Cpu : : RollRight ( T value )
{
T result = value > > 1 | ( ( _state . PS & 0x01 ) < < ( sizeof ( T ) * 8 - 1 ) ) ;
if ( value & 0x01 ) {
SetFlags ( ProcFlags : : Carry ) ;
} else {
ClearFlags ( ProcFlags : : Carry ) ;
}
SetZeroNegativeFlags ( result ) ;
return result ;
}
void Cpu : : ASL ( )
{
if ( _instAddrMode = = AddrMode : : Acc ) {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
_state . A = ShiftLeft < uint8_t > ( ( uint8_t ) _state . A ) ;
} else {
_state . A = ShiftLeft < uint16_t > ( _state . A ) ;
}
} else {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Write ( _operand , ShiftLeft < uint8_t > ( GetByteValue ( ) ) ) ;
} else {
WriteWord ( _operand , ShiftLeft < uint16_t > ( GetWordValue ( ) ) ) ;
}
}
}
void Cpu : : LSR ( )
{
if ( _instAddrMode = = AddrMode : : Acc ) {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
_state . A = ShiftRight < uint8_t > ( ( uint8_t ) _state . A ) ;
} else {
_state . A = ShiftRight < uint16_t > ( _state . A ) ;
}
} else {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Write ( _operand , ShiftRight < uint8_t > ( GetByteValue ( ) ) ) ;
} else {
WriteWord ( _operand , ShiftRight < uint16_t > ( GetWordValue ( ) ) ) ;
}
}
}
void Cpu : : ROL ( )
{
if ( _instAddrMode = = AddrMode : : Acc ) {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
_state . A = RollLeft < uint8_t > ( ( uint8_t ) _state . A ) ;
} else {
_state . A = RollLeft < uint16_t > ( _state . A ) ;
}
} else {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Write ( _operand , RollLeft < uint8_t > ( GetByteValue ( ) ) ) ;
} else {
WriteWord ( _operand , RollLeft < uint16_t > ( GetWordValue ( ) ) ) ;
}
}
}
void Cpu : : ROR ( )
{
if ( _instAddrMode = = AddrMode : : Acc ) {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
_state . A = RollRight < uint8_t > ( ( uint8_t ) _state . A ) ;
} else {
_state . A = RollRight < uint16_t > ( _state . A ) ;
}
} else {
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
Write ( _operand , RollRight < uint8_t > ( GetByteValue ( ) ) ) ;
} else {
WriteWord ( _operand , RollRight < uint16_t > ( GetWordValue ( ) ) ) ;
}
}
}
/***************
Move operations
* * * * * * * * * * * * * * * */
void Cpu : : MVN ( )
{
//TODO
}
void Cpu : : MVP ( )
{
//TODO
}
/********************
Push / pull operations
* * * * * * * * * * * * * * * * * * * * */
void Cpu : : PEA ( )
{
//Push Effective Address
PushWord ( ( uint16_t ) _operand ) ;
}
void Cpu : : PEI ( )
{
//Push Effective Indirect address
PushWord ( ( uint16_t ) _operand ) ;
}
void Cpu : : PER ( )
{
//Push Effective Relative address
PushWord ( ( uint16_t ) _operand ) ;
}
void Cpu : : PHB ( )
{
PushWord ( _state . DBR ) ;
}
void Cpu : : PHD ( )
{
PushWord ( _state . D ) ;
}
void Cpu : : PHK ( )
{
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
PushByte ( _state . K ) ;
}
void Cpu : : PHP ( )
{
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
PushByte ( _state . PS ) ;
}
void Cpu : : PLB ( )
{
//"PHP, PHK, PHP, PLB, and PLP push and pull one byte from the stack"
SetRegister ( _state . DBR , PopByte ( ) ) ;
}
void Cpu : : PLD ( )
{
//"PHD and PLD push and pull two bytes from the stack."
SetRegister ( _state . D , PopWord ( ) , false ) ;
}
void Cpu : : PLP ( )
{
//"For PLP, (all of) the flags are pulled from the stack. Note that when the e flag is 1, the m and x flag are forced to 1, so after the PLP, both flags will still be 1 no matter what value is pulled from the stack."
if ( _state . EmulationMode ) {
_state . PS = PopByte ( ) | ProcFlags : : MemoryMode8 | ProcFlags : : IndexMode8 ;
} else {
_state . PS = PopByte ( ) ;
}
}
void Cpu : : PHA ( )
{
//"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value. "
PushRegister ( _state . A , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : PHX ( )
{
PushRegister ( _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : PHY ( )
{
PushRegister ( _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : PLA ( )
{
//"When the m flag is 0, PHA and PLA push and pull a 16-bit value, and when the m flag is 1, PHA and PLA push and pull an 8-bit value."
PullRegister ( _state . A , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : PLX ( )
{
PullRegister ( _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : PLY ( )
{
PullRegister ( _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : PushRegister ( uint16_t reg , bool eightBitMode )
{
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
if ( eightBitMode ) {
PushByte ( ( uint8_t ) reg ) ;
} else {
PushWord ( reg ) ;
}
}
void Cpu : : PullRegister ( uint16_t & reg , bool eightBitMode )
{
//"When the x flag is 0, PHX, PHY, PLX, and PLY push and pull a 16-bit value, and when the x flag is 1, PHX, PHY, PLX, and PLY push and pull an 8-bit value."
if ( eightBitMode ) {
SetRegister ( reg , PopByte ( ) , true ) ;
} else {
SetRegister ( reg , PopWord ( ) , false ) ;
}
}
/*********************
Store / load operations
* * * * * * * * * * * * * * * * * * * * * */
void Cpu : : LoadRegister ( uint16_t & reg , bool eightBitMode )
{
if ( eightBitMode ) {
SetRegister ( reg , GetByteValue ( ) , true ) ;
} else {
SetRegister ( reg , GetWordValue ( ) , false ) ;
}
}
void Cpu : : StoreRegister ( uint16_t val , bool eightBitMode )
{
if ( eightBitMode ) {
Write ( _operand , ( uint8_t ) val ) ;
} else {
WriteWord ( _operand , val ) ;
}
}
void Cpu : : LDA ( )
{
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
LoadRegister ( _state . A , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : LDX ( )
{
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
LoadRegister ( _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : LDY ( )
{
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
LoadRegister ( _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : STA ( )
{
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
StoreRegister ( _state . A , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : STX ( )
{
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
StoreRegister ( _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : STY ( )
{
//"When the x flag is 0, LDX, LDY, STX, and STY are 16-bit operations"
StoreRegister ( _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : STZ ( )
{
//"When the m flag is 0, LDA, STA, and STZ are 16-bit operations"
StoreRegister ( 0 , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
/*******************
Bit test operations
* * * * * * * * * * * * * * * * * * * */
template < typename T > void Cpu : : TestBits ( T value )
{
ClearFlags ( ProcFlags : : Zero | ProcFlags : : Overflow | ProcFlags : : Negative ) ;
if ( ( ( T ) _state . A & value ) = = 0 ) {
SetFlags ( ProcFlags : : Zero ) ;
}
if ( value & ( 1 < < ( sizeof ( T ) * 8 - 2 ) ) ) {
SetFlags ( ProcFlags : : Overflow ) ;
}
if ( value & ( 1 < < ( sizeof ( T ) * 8 - 1 ) ) ) {
SetFlags ( ProcFlags : : Negative ) ;
}
}
void Cpu : : BIT ( )
{
if ( CheckFlag ( ProcFlags : : MemoryMode8 ) ) {
TestBits < uint8_t > ( GetByteValue ( ) ) ;
} else {
TestBits < uint16_t > ( GetWordValue ( ) ) ;
}
}
void Cpu : : TRB ( )
{
//TODO
}
void Cpu : : TSB ( )
{
//TODO
}
/******************
Transfer operations
* * * * * * * * * * * * * * * * * * */
void Cpu : : TAX ( )
{
SetRegister ( _state . X , _state . A , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : TAY ( )
{
SetRegister ( _state . Y , _state . A , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : TCD ( )
{
SetRegister ( _state . DBR , ( uint8_t ) _state . A ) ;
}
void Cpu : : TCS ( )
{
_state . SP = _state . A ;
}
void Cpu : : TDC ( )
{
SetRegister ( _state . A , _state . DBR , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : TSC ( )
{
SetRegister ( _state . A , _state . SP , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : TSX ( )
{
SetRegister ( _state . X , _state . SP , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : TXA ( )
{
SetRegister ( _state . A , _state . X , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : TXS ( )
{
_state . SP = _state . X ;
}
void Cpu : : TXY ( )
{
SetRegister ( _state . Y , _state . X , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : TYA ( )
{
SetRegister ( _state . A , _state . Y , CheckFlag ( ProcFlags : : MemoryMode8 ) ) ;
}
void Cpu : : TYX ( )
{
SetRegister ( _state . X , _state . Y , CheckFlag ( ProcFlags : : IndexMode8 ) ) ;
}
void Cpu : : XBA ( )
{
_state . A = ( ( _state . A & 0xFF ) < < 8 ) | ( ( _state . A > > 8 ) & 0xFF ) ;
SetZeroNegativeFlags ( ( uint8_t ) _state . A ) ;
}
void Cpu : : XCE ( )
{
_state . EmulationMode = ( _state . PS & ProcFlags : : Carry ) ? true : false ;
}
/*****************
No operation ( NOP )
* * * * * * * * * * * * * * * * * */
void Cpu : : NOP ( )
{
//1-byte NOP
}
void Cpu : : WDM ( )
{
//2-byte NOP
}
/****************
Misc . operations
* * * * * * * * * * * * * * * * */
void Cpu : : STP ( )
{
//Stop the CPU
}
void Cpu : : WAI ( )
{
//Wait for interrupt
}
2019-02-11 22:41:34 -05:00
Cpu : : Cpu ( shared_ptr < MemoryManager > memoryManager )
2019-02-11 19:18:47 -05:00
{
typedef Cpu C ;
Func opTable [ 256 ] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
& C : : BRK , & C : : ORA , & C : : COP , & C : : ORA , & C : : TSB , & C : : ORA , & C : : ASL , & C : : ORA , & C : : PHP , & C : : ORA , & C : : ASL , & C : : PHD , & C : : TSB , & C : : ORA , & C : : ASL , & C : : ORA , // 0
& C : : BPL , & C : : ORA , & C : : ORA , & C : : ORA , & C : : TRB , & C : : ORA , & C : : ASL , & C : : ORA , & C : : CLC , & C : : ORA , & C : : INC , & C : : TCS , & C : : TRB , & C : : ORA , & C : : ASL , & C : : ORA , // 1
& C : : JSR , & C : : AND , & C : : JSL , & C : : AND , & C : : BIT , & C : : AND , & C : : ROL , & C : : AND , & C : : PLP , & C : : AND , & C : : ROL , & C : : PLD , & C : : BIT , & C : : AND , & C : : ROL , & C : : AND , // 2
& C : : BMI , & C : : AND , & C : : AND , & C : : AND , & C : : BIT , & C : : AND , & C : : ROL , & C : : AND , & C : : SEC , & C : : AND , & C : : DEC , & C : : TSC , & C : : BIT , & C : : AND , & C : : ROL , & C : : AND , // 3
& C : : RTI , & C : : EOR , & C : : WDM , & C : : EOR , & C : : MVP , & C : : EOR , & C : : LSR , & C : : EOR , & C : : PHA , & C : : EOR , & C : : LSR , & C : : PHK , & C : : JMP , & C : : EOR , & C : : LSR , & C : : EOR , // 4
& C : : BVC , & C : : EOR , & C : : EOR , & C : : EOR , & C : : MVN , & C : : EOR , & C : : LSR , & C : : EOR , & C : : CLI , & C : : EOR , & C : : PHY , & C : : TCD , & C : : JMP , & C : : EOR , & C : : LSR , & C : : EOR , // 5
& C : : RTS , & C : : ADC , & C : : PER , & C : : ADC , & C : : STZ , & C : : ADC , & C : : ROR , & C : : ADC , & C : : PLA , & C : : ADC , & C : : ROR , & C : : RTL , & C : : JMP , & C : : ADC , & C : : ROR , & C : : ADC , // 6
& C : : BVS , & C : : ADC , & C : : ADC , & C : : ADC , & C : : STZ , & C : : ADC , & C : : ROR , & C : : ADC , & C : : SEI , & C : : ADC , & C : : PLY , & C : : TDC , & C : : JMP , & C : : ADC , & C : : ROR , & C : : ADC , // 7
& C : : BRA , & C : : STA , & C : : BRL , & C : : STA , & C : : STY , & C : : STA , & C : : STX , & C : : STA , & C : : DEY , & C : : BIT , & C : : TXA , & C : : PHB , & C : : STY , & C : : STA , & C : : STX , & C : : STA , // 8
& C : : BCC , & C : : STA , & C : : STA , & C : : STA , & C : : STY , & C : : STA , & C : : STX , & C : : STA , & C : : TYA , & C : : STA , & C : : TXS , & C : : TXY , & C : : STZ , & C : : STA , & C : : STZ , & C : : STA , // 9
& C : : LDY , & C : : LDA , & C : : LDX , & C : : LDA , & C : : LDY , & C : : LDA , & C : : LDX , & C : : LDA , & C : : TAY , & C : : LDA , & C : : TAX , & C : : PLB , & C : : LDY , & C : : LDA , & C : : LDX , & C : : LDA , // A
& C : : BCS , & C : : LDA , & C : : LDA , & C : : LDA , & C : : LDY , & C : : LDA , & C : : LDX , & C : : LDA , & C : : CLV , & C : : LDA , & C : : TSX , & C : : TYX , & C : : LDY , & C : : LDA , & C : : LDX , & C : : LDA , // B
& C : : CPY , & C : : CMP , & C : : REP , & C : : CMP , & C : : CPY , & C : : CMP , & C : : DEC , & C : : CMP , & C : : INY , & C : : CMP , & C : : DEX , & C : : WAI , & C : : CPY , & C : : CMP , & C : : DEC , & C : : CMP , // C
& C : : BNE , & C : : CMP , & C : : CMP , & C : : CMP , & C : : PEI , & C : : CMP , & C : : DEC , & C : : CMP , & C : : CLD , & C : : CMP , & C : : PHX , & C : : STP , & C : : JML , & C : : CMP , & C : : DEC , & C : : CMP , // D
& C : : CPX , & C : : SBC , & C : : SEP , & C : : SBC , & C : : CPX , & C : : SBC , & C : : INC , & C : : SBC , & C : : INX , & C : : SBC , & C : : NOP , & C : : XBA , & C : : CPX , & C : : SBC , & C : : INC , & C : : SBC , // E
& C : : BEQ , & C : : SBC , & C : : SBC , & C : : SBC , & C : : PEA , & C : : SBC , & C : : INC , & C : : SBC , & C : : SED , & C : : SBC , & C : : PLX , & C : : XCE , & C : : JSR , & C : : SBC , & C : : INC , & C : : SBC // F
} ;
typedef AddrMode M ;
AddrMode addrMode [ 256 ] = {
//0 1 2 3 4 5 6 7 8 9 A B C D E F
2019-02-11 22:41:34 -05:00
M : : Stk , M : : DirIdxIndX , M : : Stk , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Stk , M : : ImmM , M : : Acc , M : : Stk , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // 0
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : Dir , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Acc , M : : Imp , M : : Abs , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // 1
2019-02-11 22:41:34 -05:00
M : : Abs , M : : DirIdxIndX , M : : AbsLng , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Stk , M : : ImmM , M : : Acc , M : : Stk , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // 2
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : DirIdxX , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Acc , M : : Imp , M : : AbsIdxX , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // 3
2019-02-11 22:41:34 -05:00
M : : Stk , M : : DirIdxIndX , M : : Imm8 , M : : StkRel , M : : BlkMov , M : : Dir , M : : Dir , M : : DirIndLng , M : : Stk , M : : ImmM , M : : Acc , M : : Stk , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // 4
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : BlkMov , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Stk , M : : Imp , M : : AbsLng , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // 5
2019-02-11 22:41:34 -05:00
M : : Stk , M : : DirIdxIndX , M : : Stk , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Stk , M : : ImmM , M : : Acc , M : : Stk , M : : AbsInd , M : : Abs , M : : Abs , M : : AbsLng , // 6
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : DirIdxX , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Stk , M : : Imp , M : : AbsIdxXInd , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // 7
2019-02-11 22:41:34 -05:00
M : : Rel , M : : DirIdxIndX , M : : RelLng , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Imp , M : : ImmM , M : : Imp , M : : Stk , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // 8
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : DirIdxX , M : : DirIdxX , M : : DirIdxY , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Imp , M : : Imp , M : : Abs , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // 9
2019-02-11 22:41:34 -05:00
M : : ImmX , M : : DirIdxIndX , M : : ImmX , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Imp , M : : ImmM , M : : Imp , M : : Stk , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // A
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : DirIdxX , M : : DirIdxX , M : : DirIdxY , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Imp , M : : Imp , M : : AbsIdxX , M : : AbsIdxX , M : : AbsIdxY , M : : AbsLngIdxX , // B
2019-02-11 22:41:34 -05:00
M : : ImmX , M : : DirIdxIndX , M : : Imm8 , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Imp , M : : ImmM , M : : Imp , M : : Imp , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // C
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : Stk , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Stk , M : : Imp , M : : AbsIndLng , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX , // D
2019-02-11 22:41:34 -05:00
M : : ImmX , M : : DirIdxIndX , M : : Imm8 , M : : StkRel , M : : Dir , M : : Dir , M : : Dir , M : : DirIndLng , M : : Imp , M : : ImmM , M : : Imp , M : : Imp , M : : Abs , M : : Abs , M : : Abs , M : : AbsLng , // E
2019-02-11 19:18:47 -05:00
M : : Rel , M : : DirIndIdxY , M : : DirInd , M : : StkRelIndIdxY , M : : Stk , M : : DirIdxX , M : : DirIdxX , M : : DirIndLngIdxY , M : : Imp , M : : AbsIdxY , M : : Stk , M : : Imp , M : : AbsIdxXInd , M : : AbsIdxX , M : : AbsIdxX , M : : AbsLngIdxX // F
} ;
memcpy ( _opTable , opTable , sizeof ( opTable ) ) ;
memcpy ( _addrMode , addrMode , sizeof ( addrMode ) ) ;
2019-02-11 22:41:34 -05:00
_memoryManager = memoryManager ;
2019-02-11 19:18:47 -05:00
_state = { } ;
2019-02-11 22:41:34 -05:00
_state . PC = ReadDataWord ( Cpu : : ResetVector ) ;
_state . SP = 0x1FF ;
2019-02-11 19:18:47 -05:00
_state . EmulationMode = true ;
SetFlags ( ProcFlags : : MemoryMode8 ) ;
SetFlags ( ProcFlags : : IndexMode8 ) ;
}
Cpu : : ~ Cpu ( )
{
}
void Cpu : : Reset ( )
{
}
void Cpu : : Exec ( )
{
uint8_t opCode = GetOpCode ( ) ;
_instAddrMode = _addrMode [ opCode ] ;
_operand = FetchEffectiveAddress ( ) ;
( this - > * _opTable [ opCode ] ) ( ) ;
opCount + + ;
}
uint32_t Cpu : : GetBank ( )
{
return _state . DBR < < 16 ;
}
uint32_t Cpu : : GetProgramAddress ( )
{
return ( _state . K < < 16 ) | _state . PC ;
}
uint32_t Cpu : : GetDataAddress ( uint16_t addr )
{
return ( _state . DBR < < 16 ) | addr ;
}
uint8_t Cpu : : GetOpCode ( )
{
uint8_t opCode = ReadCode ( _state . PC , MemoryOperationType : : ExecOpCode ) ;
_state . PC + + ;
return opCode ;
}
void Cpu : : DummyRead ( )
{
ReadCode ( _state . PC , MemoryOperationType : : DummyRead ) ;
}
uint8_t Cpu : : ReadOperandByte ( )
{
return ReadCode ( _state . PC + + , MemoryOperationType : : ExecOperand ) ;
}
uint16_t Cpu : : ReadOperandWord ( )
{
uint8_t lsb = ReadOperandByte ( ) ;
uint8_t msb = ReadOperandByte ( ) ;
return ( msb < < 8 ) | lsb ;
}
uint32_t Cpu : : ReadOperandLong ( )
{
uint8_t b1 = ReadOperandByte ( ) ;
uint8_t b2 = ReadOperandByte ( ) ;
uint8_t b3 = ReadOperandByte ( ) ;
return ( b3 < < 16 ) | ( b2 < < 8 ) | b1 ;
}
uint8_t Cpu : : ReadCode ( uint16_t addr , MemoryOperationType type )
{
2019-02-12 22:13:09 -05:00
return _memoryManager - > Read ( ( _state . K < < 16 ) | addr , type ) ;
2019-02-11 19:18:47 -05:00
}
uint8_t Cpu : : ReadData ( uint32_t addr , MemoryOperationType type )
{
2019-02-12 22:13:09 -05:00
return _memoryManager - > Read ( addr , type ) ;
2019-02-11 19:18:47 -05:00
}
uint16_t Cpu : : ReadDataWord ( uint32_t addr , MemoryOperationType type )
{
uint8_t lsb = ReadData ( addr ) ;
uint8_t msb = ReadData ( addr + 1 ) ;
return ( msb < < 8 ) | lsb ;
}
uint32_t Cpu : : ReadDataLong ( uint32_t addr , MemoryOperationType type )
{
uint8_t b1 = ReadData ( addr ) ;
uint8_t b2 = ReadData ( addr + 1 ) ;
uint8_t b3 = ReadData ( addr + 2 ) ;
return ( b3 < < 16 ) | ( b2 < < 8 ) | b1 ;
}
void Cpu : : Write ( uint32_t addr , uint8_t value , MemoryOperationType type )
{
2019-02-12 22:13:09 -05:00
_memoryManager - > Write ( addr , value , type ) ;
2019-02-11 19:18:47 -05:00
}
void Cpu : : WriteWord ( uint32_t addr , uint16_t value , MemoryOperationType type )
{
Write ( addr , ( uint8_t ) value ) ;
Write ( addr + 1 , ( uint8_t ) ( value > > 8 ) ) ;
}
uint8_t Cpu : : GetByteValue ( )
{
2019-02-11 22:41:34 -05:00
if ( _instAddrMode < = AddrMode : : ImmM ) {
2019-02-11 19:18:47 -05:00
return ( uint8_t ) _operand ;
} else {
return ReadData ( _operand ) ;
}
}
uint16_t Cpu : : GetWordValue ( )
{
2019-02-11 22:41:34 -05:00
if ( _instAddrMode < = AddrMode : : ImmM ) {
2019-02-11 19:18:47 -05:00
return ( uint16_t ) _operand ;
} else {
return ReadDataWord ( _operand ) ;
}
}
void Cpu : : PushByte ( uint8_t value )
{
if ( _state . EmulationMode ) {
_state . SP = 0x100 | ( _state . SP & 0xFF ) ;
Write ( _state . SP , value ) ;
_state . SP = 0x100 | ( ( _state . SP - 1 ) & 0xFF ) ;
} else {
Write ( _state . SP , value ) ;
_state . SP - - ;
}
}
uint8_t Cpu : : PopByte ( )
{
if ( _state . EmulationMode ) {
_state . SP = 0x100 | ( ( _state . SP + 1 ) & 0xFF ) ;
} else {
_state . SP + + ;
}
2019-02-11 22:41:34 -05:00
return ReadData ( _state . SP ) ;
2019-02-11 19:18:47 -05:00
}
void Cpu : : PushWord ( uint16_t value )
{
PushByte ( value > > 8 ) ;
PushByte ( ( uint8_t ) value ) ;
}
uint16_t Cpu : : PopWord ( )
{
uint8_t lo = PopByte ( ) ;
uint8_t hi = PopByte ( ) ;
return lo | hi < < 8 ;
}
uint16_t Cpu : : GetDirectAddress ( uint8_t baseAddress , uint16_t offset , bool allowEmulationMode )
{
if ( allowEmulationMode & & _state . EmulationMode & & ( _state . D & 0xFF ) = = 0 ) {
//TODO: Check if new instruction or not (PEI)
return ( uint16_t ) ( ( _state . D & 0xFF00 ) | ( ( baseAddress + offset ) & 0xFF ) ) ;
} else {
return ( uint16_t ) ( _state . D + baseAddress + offset ) ;
}
}
uint32_t Cpu : : FetchEffectiveAddress ( )
{
switch ( _instAddrMode ) {
2019-02-11 22:41:34 -05:00
case AddrMode : : Abs : return GetBank ( ) | ReadOperandWord ( ) ;
case AddrMode : : AbsIdxXInd : return ReadDataWord ( ( _state . K < < 16 ) | ReadOperandWord ( ) ) ; //JMP/JSR
case AddrMode : : AbsIdxX : return ( GetBank ( ) | ReadOperandWord ( ) ) + _state . X ;
case AddrMode : : AbsIdxY : return ( GetBank ( ) | ReadOperandWord ( ) ) + _state . Y ;
case AddrMode : : AbsInd : return ReadDataWord ( ReadOperandWord ( ) ) ; //JMP only
case AddrMode : : AbsIndLng : return ReadDataLong ( ReadOperandLong ( ) ) ; //JML only
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : AbsLngIdxX : return ReadOperandLong ( ) + _state . X ;
case AddrMode : : AbsLng : return ReadOperandLong ( ) ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : Acc : DummyRead ( ) ; return 0 ;
2019-02-11 19:18:47 -05:00
case AddrMode : : BlkMov : return ReadOperandWord ( ) ;
2019-02-11 22:41:34 -05:00
case AddrMode : : DirIdxIndX : {
2019-02-11 19:18:47 -05:00
uint8_t operand = ReadOperandByte ( ) ;
uint8_t lsb = ReadData ( GetDirectAddress ( operand , _state . X ) ) ;
uint8_t msb = ReadData ( GetDirectAddress ( operand , _state . X + 1 ) ) ;
return GetBank ( ) | ( msb < < 8 ) | lsb ;
}
2019-02-11 22:41:34 -05:00
case AddrMode : : DirIdxX : return GetDirectAddress ( ReadOperandByte ( ) , _state . X ) ;
case AddrMode : : DirIdxY : return GetDirectAddress ( ReadOperandByte ( ) , _state . Y ) ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : DirIndIdxY : {
2019-02-11 19:18:47 -05:00
uint8_t operand = ReadOperandByte ( ) ;
uint8_t lsb = ReadData ( GetDirectAddress ( operand ) ) ;
uint8_t msb = ReadData ( GetDirectAddress ( operand , 1 ) ) ;
return ( GetBank ( ) | ( msb < < 8 ) | lsb ) + _state . Y ;
}
2019-02-11 22:41:34 -05:00
case AddrMode : : DirIndLngIdxY : {
2019-02-11 19:18:47 -05:00
uint8_t operand = ReadOperandByte ( ) ;
uint8_t b1 = ReadData ( GetDirectAddress ( operand ) ) ;
uint8_t b2 = ReadData ( GetDirectAddress ( operand , 1 ) ) ;
uint8_t b3 = ReadData ( GetDirectAddress ( operand , 2 ) ) ;
return ( ( b3 < < 16 ) | ( b2 < < 8 ) | b1 ) + _state . Y ;
}
2019-02-11 22:41:34 -05:00
case AddrMode : : DirIndLng : {
2019-02-11 19:18:47 -05:00
uint8_t operand = ReadOperandByte ( ) ;
uint8_t b1 = ReadData ( GetDirectAddress ( operand ) ) ;
uint8_t b2 = ReadData ( GetDirectAddress ( operand , 1 ) ) ;
uint8_t b3 = ReadData ( GetDirectAddress ( operand , 2 ) ) ;
return ( b3 < < 16 ) | ( b2 < < 8 ) | b1 ;
}
2019-02-11 22:41:34 -05:00
case AddrMode : : DirInd : {
2019-02-11 19:18:47 -05:00
uint8_t operand = ReadOperandByte ( ) ;
uint8_t lsb = ReadData ( GetDirectAddress ( operand ) ) ;
uint8_t msb = ReadData ( GetDirectAddress ( operand , 1 ) ) ;
return GetBank ( ) | ( msb < < 8 ) | lsb ;
}
2019-02-11 22:41:34 -05:00
case AddrMode : : Dir : return GetDirectAddress ( ReadOperandByte ( ) ) ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : Imm8 : return ReadOperandByte ( ) ;
case AddrMode : : ImmX : return CheckFlag ( ProcFlags : : IndexMode8 ) ? ReadOperandByte ( ) : ReadOperandWord ( ) ;
case AddrMode : : ImmM : return CheckFlag ( ProcFlags : : MemoryMode8 ) ? ReadOperandByte ( ) : ReadOperandWord ( ) ;
case AddrMode : : Imp : DummyRead ( ) ; return 0 ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : RelLng : return ReadOperandWord ( ) ;
case AddrMode : : Rel : return ReadOperandByte ( ) ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : Stk : return _state . SP ;
case AddrMode : : StkRel : return ( uint16_t ) ( ReadOperandByte ( ) + _state . SP ) ;
2019-02-11 19:18:47 -05:00
2019-02-11 22:41:34 -05:00
case AddrMode : : StkRelIndIdxY : {
2019-02-11 19:18:47 -05:00
uint16_t addr = ( uint16_t ) ( ReadOperandByte ( ) + _state . SP ) ;
return ( GetBank ( ) | addr ) + _state . Y ;
}
}
throw new std : : runtime_error ( " Unreacheable code " ) ;
}
void Cpu : : SetRegister ( uint8_t & reg , uint8_t value )
{
SetZeroNegativeFlags ( value ) ;
reg = value ;
}
void Cpu : : SetRegister ( uint16_t & reg , uint16_t value , bool eightBitMode )
{
if ( eightBitMode ) {
SetZeroNegativeFlags ( ( uint8_t ) value ) ;
reg = ( reg & 0xFF00 ) | ( uint8_t ) value ;
} else {
SetZeroNegativeFlags ( value ) ;
reg = value ;
}
}
void Cpu : : SetZeroNegativeFlags ( uint16_t value )
{
ClearFlags ( ProcFlags : : Zero | ProcFlags : : Negative ) ;
if ( value = = 0 ) {
SetFlags ( ProcFlags : : Zero ) ;
} else if ( value & 0x8000 ) {
SetFlags ( ProcFlags : : Negative ) ;
}
}
void Cpu : : SetZeroNegativeFlags ( uint8_t value )
{
ClearFlags ( ProcFlags : : Zero | ProcFlags : : Negative ) ;
if ( value = = 0 ) {
SetFlags ( ProcFlags : : Zero ) ;
} else if ( value & 0x80 ) {
SetFlags ( ProcFlags : : Negative ) ;
}
}
void Cpu : : ClearFlags ( uint8_t flags )
{
_state . PS & = ~ flags ;
}
void Cpu : : SetFlags ( uint8_t flags )
{
_state . PS | = flags ;
}
bool Cpu : : CheckFlag ( uint8_t flag )
{
return ( _state . PS & flag ) = = flag ;
}