📄 k6502.cpp
字号:
/*===================================================================*//* *//* K6502.cpp : 6502 Emulator *//* *//* 2000/5/10 InfoNES Project ( based on pNesX ) *//* *//*===================================================================*//*-------------------------------------------------------------------*//* Include files *//*-------------------------------------------------------------------*/#include "K6502.h"
#include "InfoNES.h"#include "InfoNES_System.h"/*-------------------------------------------------------------------*//* Operation Macros *//*-------------------------------------------------------------------*//* Clock Op. */#define CLK(a) g_wPassedClocks += (a);/* Addressing Op. *//* Address *//* (Indirect,X) */#define AA_IX K6502_ReadZpW( K6502_Read_Code( PC++ ) + X )/* (Indirect),Y */#define AA_IY K6502_ReadZpW( K6502_Read_Code( PC++ ) ) + Y/* Zero Page */#define AA_ZP K6502_Read_Code( PC++ )/* Zero Page,X */#define AA_ZPX (BYTE)( K6502_Read_Code( PC++ ) + X )/* Zero Page,Y */#define AA_ZPY (BYTE)( K6502_Read_Code( PC++ ) + Y )/* Absolute */#define AA_ABS ( K6502_Read_Code( PC++ ) | (WORD)K6502_Read_Code( PC++ ) << 8 )
/* Absolute2 ( PC-- ) */#define AA_ABS2 ( K6502_Read_Code( PC++ ) | (WORD)K6502_Read_Code( PC ) << 8 )/* Absolute,X */#define AA_ABSX AA_ABS + X/* Absolute,Y */#define AA_ABSY AA_ABS + Y/* Data *//* (Indirect,X) */#define A_IX K6502_Read( AA_IX )/* (Indirect),Y */#define A_IY K6502_ReadIY()/* Zero Page */#define A_ZP K6502_ReadZp( AA_ZP )/* Zero Page,X */#define A_ZPX K6502_ReadZp( AA_ZPX )/* Zero Page,Y */#define A_ZPY K6502_ReadZp( AA_ZPY )/* Absolute */#define A_ABS K6502_Read( AA_ABS )/* Absolute,X */#define A_ABSX K6502_ReadAbsX()/* Absolute,Y */#define A_ABSY K6502_ReadAbsY()/* Immediate */#define A_IMM K6502_Read_Code( PC++ )/* Flag Op. */#define SETF(a) F |= (a)#define RSTF(a) F &= ~(a)#define TEST(a) RSTF( FLAG_N | FLAG_Z ); SETF( g_byTestTable[ a ] )/* Load & Store Op. */#define STA(a) K6502_Write( (a), A );#define STX(a) K6502_Write( (a), X );#define STY(a) K6502_Write( (a), Y );#define LDA(a) A = (a); TEST( A );#define LDX(a) X = (a); TEST( X );#define LDY(a) Y = (a); TEST( Y );/* Stack Op. */#define PUSH(a) K6502_WriteZp( BASE_STACK + SP--, (a) )#define PUSHW(a) PUSH( (a) >> 8 ); PUSH( (a) & 0xff )#define POP(a) a = K6502_ReadZp( BASE_STACK + ++SP )#define POPW(a) POP(a); a |= ( K6502_ReadZp( BASE_STACK + ++SP ) << 8 )/* Logical Op. */#define ORA(a) A |= (a); TEST( A )#define AND(a) A &= (a); TEST( A )#define EOR(a) A ^= (a); TEST( A )#define BIT(a) byD0 = (a); RSTF( FLAG_N | FLAG_V | FLAG_Z ); SETF( ( byD0 & ( FLAG_N | FLAG_V ) ) | ( ( byD0 & A ) ? 0 : FLAG_Z ) );#define CMP(a) wD0 = (WORD)A - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );#define CPX(a) wD0 = (WORD)X - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );#define CPY(a) wD0 = (WORD)Y - (a); RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_byTestTable[ wD0 & 0xff ] | ( wD0 < 0x100 ? FLAG_C : 0 ) );/* Math Op. (A D flag isn't being supported.) */#define ADC(a) byD0 = (a); \ wD0 = A + byD0 + ( F & FLAG_C ); \ byD1 = (BYTE)wD0; \ RSTF( FLAG_N | FLAG_V | FLAG_Z | FLAG_C ); \ SETF( g_byTestTable[ byD1 ] | ( ( ~( A ^ byD0 ) & ( A ^ byD1 ) & 0x80 ) ? FLAG_V : 0 ) | ( wD0 > 0xff ) ); \A = byD1;#define SBC(a) byD0 = (a); \ wD0 = A - byD0 - ( ~F & FLAG_C ); \ byD1 = (BYTE)wD0; \ RSTF( FLAG_N | FLAG_V | FLAG_Z | FLAG_C ); \ SETF( g_byTestTable[ byD1 ] | ( ( ( A ^ byD0 ) & ( A ^ byD1 ) & 0x80 ) ? FLAG_V : 0 ) | ( wD0 < 0x100 ) ); \A = byD1;#define DEC(a) wA0 = a; byD0 = K6502_Read( wA0 ); --byD0; K6502_Write( wA0, byD0 ); TEST( byD0 )#define INC(a) wA0 = a; byD0 = K6502_Read( wA0 ); ++byD0; K6502_Write( wA0, byD0 ); TEST( byD0 )/* Shift Op. */#define ASLA RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_ASLTable[ A ].byFlag ); A = g_ASLTable[ A ].byValue #define ASL(a) RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_ASLTable[ byD0 ].byFlag ); K6502_Write( wA0, g_ASLTable[ byD0 ].byValue )#define LSRA RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_LSRTable[ A ].byFlag ); A = g_LSRTable[ A ].byValue #define LSR(a) RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_LSRTable[ byD0 ].byFlag ); K6502_Write( wA0, g_LSRTable[ byD0 ].byValue ) #define ROLA byD0 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_ROLTable[ byD0 ][ A ].byFlag ); A = g_ROLTable[ byD0 ][ A ].byValue #define ROL(a) byD1 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_ROLTable[ byD1 ][ byD0 ].byFlag ); K6502_Write( wA0, g_ROLTable[ byD1 ][ byD0 ].byValue )#define RORA byD0 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); SETF( g_RORTable[ byD0 ][ A ].byFlag ); A = g_RORTable[ byD0 ][ A ].byValue #define ROR(a) byD1 = F & FLAG_C; RSTF( FLAG_N | FLAG_Z | FLAG_C ); wA0 = a; byD0 = K6502_Read( wA0 ); SETF( g_RORTable[ byD1 ][ byD0 ].byFlag ); K6502_Write( wA0, g_RORTable[ byD1 ][ byD0 ].byValue )/* Jump Op. */#define JSR wA0 = AA_ABS2; PUSHW( PC ); PC = wA0; #define BRA(a) if ( a ) { wA0 = PC; PC += (char)K6502_Read_Code( PC ); CLK( 3 + ( ( wA0 & 0x0100 ) != ( PC & 0x0100 ) ) ); ++PC; } else { ++PC; CLK( 2 ); }#define JMP(a) PC = a;/*-------------------------------------------------------------------*//* Global valiables *//*-------------------------------------------------------------------*//* 6502 Register */
WORD PC;BYTE SP;BYTE F;BYTE A;BYTE X;BYTE Y;
/* The state of the IRQ pin */BYTE IRQ_State;/* Wiring of the IRQ pin */BYTE IRQ_Wiring;/* The state of the NMI pin */BYTE NMI_State;/* Wiring of the NMI pin */BYTE NMI_Wiring;/* The number of the clocks that it passed */WORD g_wPassedClocks;/* A table for the test */BYTE g_byTestTable[ 256 ];/* Value and Flag Data */struct value_table_tag{ BYTE byValue; BYTE byFlag;};/* A table for ASL */struct value_table_tag g_ASLTable[ 256 ];/* A table for LSR */struct value_table_tag g_LSRTable[ 256 ];/* A table for ROL */struct value_table_tag g_ROLTable[ 2 ][ 256 ];/* A table for ROR */struct value_table_tag g_RORTable[ 2 ][ 256 ];/*===================================================================*//* *//* K6502_Init() : Initialize K6502 *//* *//*===================================================================*/void K6502_Init(){/** Initialize K6502** You must call this function only once at first. */ BYTE idx; BYTE idx2; /* The establishment of the IRQ pin */ NMI_Wiring = NMI_State = 1; IRQ_Wiring = IRQ_State = 1; /* Make a table for the test */ idx = 0; do { if ( idx == 0 ) g_byTestTable[ 0 ] = FLAG_Z; else if ( idx > 127 ) g_byTestTable[ idx ] = FLAG_N; else g_byTestTable[ idx ] = 0; ++idx; } while ( idx != 0 ); /* Make a table ASL */ idx = 0; do { g_ASLTable[ idx ].byValue = idx << 1; g_ASLTable[ idx ].byFlag = 0; if ( idx > 127 ) g_ASLTable[ idx ].byFlag = FLAG_C; if ( g_ASLTable[ idx ].byValue == 0 ) g_ASLTable[ idx ].byFlag |= FLAG_Z; else if ( g_ASLTable[ idx ].byValue & 0x80 ) g_ASLTable[ idx ].byFlag |= FLAG_N; ++idx; } while ( idx != 0 ); /* Make a table LSR */ idx = 0; do { g_LSRTable[ idx ].byValue = idx >> 1; g_LSRTable[ idx ].byFlag = 0; if ( idx & 1 ) g_LSRTable[ idx ].byFlag = FLAG_C; if ( g_LSRTable[ idx ].byValue == 0 ) g_LSRTable[ idx ].byFlag |= FLAG_Z; ++idx; } while ( idx != 0 ); /* Make a table ROL */ for ( idx2 = 0; idx2 < 2; ++idx2 ) { idx = 0; do { g_ROLTable[ idx2 ][ idx ].byValue = ( idx << 1 ) | idx2; g_ROLTable[ idx2 ][ idx ].byFlag = 0; if ( idx > 127 ) g_ROLTable[ idx2 ][ idx ].byFlag = FLAG_C; if ( g_ROLTable[ idx2 ][ idx ].byValue == 0 ) g_ROLTable[ idx2 ][ idx ].byFlag |= FLAG_Z; else if ( g_ROLTable[ idx2 ][ idx ].byValue & 0x80 ) g_ROLTable[ idx2 ][ idx ].byFlag |= FLAG_N; ++idx; } while ( idx != 0 ); } /* Make a table ROR */ for ( idx2 = 0; idx2 < 2; ++idx2 ) { idx = 0; do { g_RORTable[ idx2 ][ idx ].byValue = ( idx >> 1 ) | ( idx2 << 7 ); g_RORTable[ idx2 ][ idx ].byFlag = 0; if ( idx & 1 ) g_RORTable[ idx2 ][ idx ].byFlag = FLAG_C; if ( g_RORTable[ idx2 ][ idx ].byValue == 0 ) g_RORTable[ idx2 ][ idx ].byFlag |= FLAG_Z; else if ( g_RORTable[ idx2 ][ idx ].byValue & 0x80 ) g_RORTable[ idx2 ][ idx ].byFlag |= FLAG_N; ++idx; } while ( idx != 0 ); }}/*===================================================================*//* *//* K6502_Reset() : Reset a CPU *//* *//*===================================================================*/void K6502_Reset(){/** Reset a CPU**/ /* Reset Registers */ PC = K6502_ReadW_Code( VECTOR_RESET ); SP = 0xFF; A = X = Y = 0; F = FLAG_Z | FLAG_R; /* Set up the state of the Interrupt pin. */ NMI_State = NMI_Wiring; IRQ_State = IRQ_Wiring; /* Reset Passed Clocks */ g_wPassedClocks = 0;}/*===================================================================*//* *//* K6502_Set_Int_Wiring() : Set up wiring of the interrupt pin *//* *//*===================================================================*/void K6502_Set_Int_Wiring( BYTE byNMI_Wiring, BYTE byIRQ_Wiring ){/** Set up wiring of the interrupt pin* */ NMI_Wiring = byNMI_Wiring; IRQ_Wiring = byIRQ_Wiring;}
static BYTE byCode;
static WORD wA0;
static BYTE byD0;
static BYTE byD1;
static WORD wD0;
static void instruct_00(void)
{
++PC; PUSHW( PC ); SETF( FLAG_B ); PUSH( F ); SETF( FLAG_I ); RSTF( FLAG_D ); PC = K6502_ReadW_Code( VECTOR_IRQ ); CLK( 7 );
}
static void instruct_01(void)
{
ORA( A_IX ); CLK( 6 );
}
static void instruct_05(void)
{
ORA( A_ZP ); CLK( 3 );
}
static void instruct_06(void)
{
ASL( AA_ZP ); CLK( 5 );
}
static void instruct_08(void)
{
PUSH( F ); CLK( 3 );
}
static void instruct_09(void)
{
ORA( A_IMM ); CLK( 2 );
}
static void instruct_0a(void)
{
ASLA; CLK( 2 );
}
static void instruct_0d(void)
{
ORA( A_ABS ); CLK( 4 );
}
static void instruct_0e(void)
{
ASL( AA_ABS ); CLK( 6 );
}
static void instruct_10(void)
{
BRA( !( F & FLAG_N ) );
}
static void instruct_11(void)
{
ORA( A_IY ); CLK( 5 );
}
static void instruct_15(void)
{
ORA( A_ZPX ); CLK( 4 );
}
static void instruct_16(void)
{
ASL( AA_ZPX ); CLK( 6 );
}
static void instruct_18(void)
{
RSTF( FLAG_C ); CLK( 2 );
}
static void instruct_19(void)
{
ORA( A_ABSY ); CLK( 4 );
}
static void instruct_1d(void)
{
ORA( A_ABSX ); CLK( 4 );
}
static void instruct_1e(void)
{
ASL( AA_ABSX ); CLK( 7 );
}
static void instruct_20(void)
{
JSR; CLK( 6 );
}
static void instruct_21(void)
{
AND( A_IX ); CLK( 6 );
}
static void instruct_24(void)
{
BIT( A_ZP ); CLK( 3 );
}
static void instruct_25(void)
{
AND( A_ZP ); CLK( 3 );
}
static void instruct_26(void)
{
ROL( AA_ZP ); CLK( 5 );
}
static void instruct_28(void)
{
POP( F ); SETF( FLAG_R ); CLK( 4 );
}
static void instruct_29(void)
{
AND( A_IMM ); CLK( 2 );
}
static void instruct_2a(void)
{
ROLA; CLK( 2 );
}
static void instruct_2c(void)
{
BIT( A_ABS ); CLK( 4 );
}
static void instruct_2d(void)
{
AND( A_ABS ); CLK( 4 );
}
static void instruct_2e(void)
{
ROL( AA_ABS ); CLK( 6 );
}
static void instruct_30(void)
{
BRA( F & FLAG_N );
}
static void instruct_31(void)
{
AND( A_IY ); CLK( 5 );
}
static void instruct_35(void)
{
AND( A_ZPX ); CLK( 4 );
}
static void instruct_36(void)
{
ROL( AA_ZPX ); CLK( 6 );
}
static void instruct_38(void)
{
SETF( FLAG_C ); CLK( 2 );
}
static void instruct_39(void)
{
AND( A_ABSY ); CLK( 4 );
}
static void instruct_3d(void)
{
AND( A_ABSX ); CLK( 4 );
}
static void instruct_3e(void)
{
ROL( AA_ABSX ); CLK( 7 );
}
static void instruct_40(void)
{
POP( F ); SETF( FLAG_R ); POPW( PC ); CLK( 6 );
}
static void instruct_41(void)
{
EOR( A_IX ); CLK( 6 );
}
static void instruct_45(void)
{
EOR( A_ZP ); CLK( 3 );
}
static void instruct_46(void)
{
LSR( AA_ZP ); CLK( 5 );
}
static void instruct_48(void)
{
PUSH( A ); CLK( 3 );
}
static void instruct_49(void)
{
EOR( A_IMM ); CLK( 2 );
}
static void instruct_4a(void)
{
LSRA; CLK( 2 );
}
static void instruct_4c(void)
{
JMP( AA_ABS ); CLK( 3 );
}
static void instruct_4d(void)
{
EOR( A_ABS ); CLK( 4 );
}
static void instruct_4e(void)
{
LSR( AA_ABS ); CLK( 6 );
}
static void instruct_50(void)
{
BRA( !( F & FLAG_V ) );
}
static void instruct_51(void)
{
EOR( A_IY ); CLK( 5 );
}
static void instruct_55(void)
{
EOR( A_ZPX ); CLK( 4 );
}
static void instruct_56(void)
{
LSR( AA_ZPX ); CLK( 6 );
}
static void instruct_58(void)
{
byD0 = F;
RSTF( FLAG_I ); CLK( 2 );
if ( ( byD0 & FLAG_I ) && IRQ_State != IRQ_Wiring )
{
/* IRQ Interrupt */
/* Execute IRQ if an I flag isn't being set */
if ( !( byD0 & FLAG_I ) )
{
CLK( 7 );
PUSHW( PC );
PUSH( F & ~FLAG_B );
RSTF( FLAG_D );
SETF( FLAG_I );
PC = K6502_ReadW_Code( VECTOR_IRQ );
}
}
}
static void instruct_59(void)
{
EOR( A_ABSY ); CLK( 4 );
}
static void instruct_5d(void)
{
EOR( A_ABSX ); CLK( 4 );
}
static void instruct_5e(void)
{
LSR( AA_ABSX ); CLK( 7 );
}
static void instruct_60(void)
{
POPW( PC ); ++PC; CLK( 6 );
}
static void instruct_61(void)
{
ADC( A_IX ); CLK( 6 );
}
static void instruct_65(void)
{
ADC( A_ZP ); CLK( 3 );
}
static void instruct_66(void)
{
ROR( AA_ZP ); CLK( 5 );
}
static void instruct_68(void)
{
POP( A ); TEST( A ); CLK( 4 );
}
static void instruct_69(void)
{
ADC( A_IMM ); CLK( 2 );
}
static void instruct_6a(void)
{
RORA; CLK( 2 );
}
static void instruct_6c(void)
{
JMP( K6502_ReadW2( AA_ABS ) ); CLK( 5 );
}
static void instruct_6d(void)
{
ADC( A_ABS ); CLK( 4 );
}
static void instruct_6e(void)
{
ROR( AA_ABS ); CLK( 6 );
}
static void instruct_70(void)
{
BRA( F & FLAG_V );
}
static void instruct_71(void)
{
ADC( A_IY ); CLK( 5 );
}
static void instruct_75(void)
{
ADC( A_ZPX ); CLK( 4 );
}
static void instruct_76(void)
{
ROR( AA_ZPX ); CLK( 6 );
}
static void instruct_78(void)
{
SETF( FLAG_I ); CLK( 2 );
}
static void instruct_79(void)
{
ADC( A_ABSY ); CLK( 4 );
}
static void instruct_7d(void)
{
ADC( A_ABSX ); CLK( 4 );
}
static void instruct_7e(void)
{
ROR( AA_ABSX ); CLK( 7 );
}
static void instruct_81(void)
{
STA( AA_IX ); CLK( 6 );
}
static void instruct_84(void)
{
STY( AA_ZP ); CLK( 3 );
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -