📄 nes6502.c
字号:
c_flag = data >> 7; \
data <<= 1; \
write_func(addr, data); \
A |= data; \
SET_NZ_FLAGS(A); \
ADD_CYCLES(cycles); \
}
/* undocumented */
#define SRE(cycles, read_func, write_func, addr) \
{ \
read_func(addr, data); \
c_flag = data & 1; \
data >>= 1; \
write_func(addr, data); \
A ^= data; \
SET_NZ_FLAGS(A); \
ADD_CYCLES(cycles); \
}
#define STA(cycles, read_func, write_func, addr) \
{ \
read_func(addr); \
write_func(addr, (uint8)A); \
ADD_CYCLES(cycles); \
}
#define STX(cycles, read_func, write_func, addr) \
{ \
read_func(addr); \
write_func(addr, (uint8)X); \
ADD_CYCLES(cycles); \
}
#define STY(cycles, read_func, write_func, addr) \
{ \
read_func(addr); \
write_func(addr, (uint8)Y); \
ADD_CYCLES(cycles); \
}
#define TAX() \
{ \
X = A; \
SET_NZ_FLAGS(X);\
ADD_CYCLES(2); \
}
#define TAY() \
{ \
Y = A; \
SET_NZ_FLAGS(Y);\
ADD_CYCLES(2); \
}
/* undocumented (triple-NOP) */
#define TOP() \
{ \
PC += 2; \
ADD_CYCLES(4); \
}
#define TSX() \
{ \
X = S; \
SET_NZ_FLAGS(X);\
ADD_CYCLES(2); \
}
#define TXA() \
{ \
A = X; \
SET_NZ_FLAGS(A);\
ADD_CYCLES(2); \
}
#define TXS() \
{ \
S = X; \
ADD_CYCLES(2); \
}
#define TYA() \
{ \
A = Y; \
SET_NZ_FLAGS(A); \
ADD_CYCLES(2); \
}
/* internal CPU context */
static nes6502_context cpu;
/* memory region pointers */
#undef ram
#undef stack
static uint8 *ram = NULL, *stack = NULL;
static uint8 dead_page[NES6502_BANKSIZE];
#define ram ram_l
#define stack stack_l
/*
** Zero-page helper macros
*/
#define ZP_READBYTE(addr) ram[(addr)]
#define ZP_WRITEBYTE(addr, value) ram[(addr)] = (uint8) (value)
#if 1
#define bank_readbyte(address) \
/* cpu.mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK] */ \
mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK]
#define slow_bank_readbyte(address) \
cpu.mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK]
#define bank_writebyte(address, value) \
/* cpu.mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK] = (value) */ \
mem_page[(address) >> NES6502_BANKSHIFT][(address) & NES6502_BANKMASK] = (value)
#define zp_readword(address) \
((*(ram + (address) + 1) << 8) | *(ram + (address)))
#define bank_readword(address) \
/* (*(cpu.mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK) + 1) << 8) | (*(cpu.mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK))) */ \
(*(mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK) + 1) << 8) | (*(mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK)))
#define slow_bank_readword(address) \
(*(cpu.mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK) + 1) << 8) | (*(cpu.mem_page[(address) >> NES6502_BANKSHIFT] + ((address) & NES6502_BANKMASK)))
#else
INLINE uint32 zp_readword(register uint8 address)
{
#ifdef HOST_LITTLE_ENDIAN
// for ARM / MIPS (WindowsCE) 2002/01/15
return (*(ram + address + 1) << 8) | *(ram + address);
/* TODO: this fails if host architecture doesn't support byte alignment */
//return (uint32) (*(uint16 *)(ram + address));
#else
#ifdef TARGET_CPU_PPC
return __lhbrx(ram, address);
#else
uint32 x = (uint32) *(uint16 *)(ram + address);
return (x << 8) | (x >> 8);
#endif /* TARGET_CPU_PPC */
#endif /* HOST_LITTLE_ENDIAN */
}
INLINE uint8 bank_readbyte(register uint32 address)
{
return cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK];
}
INLINE uint32 bank_readword(register uint32 address)
{
#ifdef HOST_LITTLE_ENDIAN
// for ARM / MIPS (WindowsCE) 2002/01/15
return (*(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK) + 1) << 8) | (*(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)));
/* TODO: this fails if src address is $xFFF */
/* TODO: this fails if host architecture doesn't support byte alignment */
//return (uint32) (*(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK)));
#else
#ifdef TARGET_CPU_PPC
return __lhbrx(cpu.mem_page[address >> NES6502_BANKSHIFT], address & NES6502_BANKMASK);
#else
uint32 x = (uint32) *(uint16 *)(cpu.mem_page[address >> NES6502_BANKSHIFT] + (address & NES6502_BANKMASK));
return (x << 8) | (x >> 8);
#endif /* TARGET_CPU_PPC */
#endif /* HOST_LITTLE_ENDIAN */
}
INLINE void bank_writebyte(register uint32 address, register uint8 value)
{
cpu.mem_page[address >> NES6502_BANKSHIFT][address & NES6502_BANKMASK] = value;
}
#endif
/* read a byte of 6502 memory */
#if 0
static uint8 mem_readbyte(uint32 address)
{
nes6502_memread *mr;
/* TODO: following cases are N2A03-specific */
/* RAM */
if (address < 0x800)
return ram[address];
/* always paged memory */
else if (address >= 0x8000)
return bank_readbyte(address);
/* check memory range handlers */
else
{
for (mr = cpu.read_handler; mr->min_range != 0xFFFFFFFF; mr++)
{
if (address >= mr->min_range && address <= mr->max_range)
return mr->read_func(address);
}
}
/* return paged memory */
return bank_readbyte(address);
}
#else
/*
#define mem_readbyte(address) \
((address < 0x800) ? ram[address] : mem_rbyte(mem_page, address))
static uint8 mem_rbyte(uint8 **mem_page, uint32 address)
{
if (address >= 0x8000)
return bank_readbyte(address);
else
return cpu.read_handler->read_func(address);
}
*/
#define mem_readbyte(address) \
((address < 0x800) ? ram[address] : \
((address >= 0x8000) ? bank_readbyte(address) : read_func(address)))
#endif
/* write a byte of data to 6502 memory */
#if 0
static void mem_writebyte(uint32 address, uint8 value)
{
nes6502_memwrite *mw;
/* RAM */
if (address < 0x800)
{
ram[address] = value;
return;
}
/* check memory range handlers */
else
{
for (mw = cpu.write_handler; mw->min_range != 0xFFFFFFFF; mw++)
{
if (address >= mw->min_range && address <= mw->max_range)
{
mw->write_func(address, value);
return;
}
}
}
/* write to paged memory */
bank_writebyte(address, value);
}
#else
/*
#define mem_writebyte(address, value) \
if (address < 0x800) { \
ram[address] = value; \
} else { \
write_handler_write(address, value);\
}
static void write_handler_write(uint32 address, uint8 value)
{
cpu.write_handler->write_func(address, value);
}
*/
#define mem_writebyte(address, value) \
if (address < 0x800) { \
ram[address] = value; \
} else { \
write_func(address, value); \
}
#endif
#undef ram
#undef stack
/* set the current context */
void nes6502_setcontext(nes6502_context *context)
{
int loop;
ASSERT(context);
memcpy(&cpu, context, sizeof(nes6502_context));
for (loop = 0; loop < NES6502_NUMBANKS; loop++)
{
if (NULL == cpu.mem_page[loop])
cpu.mem_page[loop] = dead_page;
}
nes6502_update_fast_pc(); // Rick
ram = cpu.mem_page[0]; /* quick zero-page/RAM references */
stack = ram + STACK_OFFSET;
cpu.jammed = FALSE;
}
/* get the current context */
void nes6502_getcontext(nes6502_context *context)
{
int loop;
ASSERT(context);
memcpy(context, &cpu, sizeof(nes6502_context));
for (loop = 0; loop < NES6502_NUMBANKS; loop++)
{
if (dead_page == context->mem_page[loop])
context->mem_page[loop] = NULL;
}
}
/* Rick */
void nes6502_update_fast_pc()
{
if (current_PC) {
//update PC in execute()
uint32 t;
*current_PC -= (uint32)(*current_last_bank_ptr);
t = *current_PC >> NES6502_BANKSHIFT; \
*current_last_bank_ptr = cpu.mem_page[t] - (t << NES6502_BANKSHIFT);
*current_PC += (uint32)(*current_last_bank_ptr);
}
}
/* Rick */
nes6502_context * nes6502_getcontextptr()
{
return &cpu;
}
/* DMA a byte of data from ROM */
uint8 nes6502_getbyte(uint32 address)
{
return slow_bank_readbyte(address);
}
/* get number of elapsed cycles */
uint32 nes6502_getcycles(boolean reset_flag)
{
uint32 cycles = cpu.total_cycles;
if (reset_flag)
cpu.total_cycles = 0;
return cycles;
}
#define GET_GLOBAL_REGS() \
{ \
PC = cpu.pc_reg; \
PC_TO_PTR(); \
A = cpu.a_reg; \
X = cpu.x_reg; \
Y = cpu.y_reg; \
SCATTER_FLAGS(cpu.p_reg); \
S = cpu.s_reg; \
}
#define STORE_LOCAL_REGS() \
{ \
PTR_TO_PC(); \
cpu.pc_reg = PC; \
cpu.a_reg = A; \
cpu.x_reg = X; \
cpu.y_reg = Y; \
cpu.p_reg = COMBINE_FLAGS(); \
cpu.s_reg = S; \
}
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#define OPCODES_BY_FREQUENCY
#ifndef OPCODES_BY_FREQUENCY
/* Execute instructions until count expires
**
** Returns the number of cycles *actually* executed, which will be
** anywhere from remaining_cycles to remaining_cycles + 6
*/
int nes6502_execute(int remaining_cycles)
{
//int old_cycles = cpu.total_cycles;
int org_rem_cycles = remaining_cycles;
int executed;
uint32 temp, addr; /* for macros */
uint8 btemp, baddr; /* for macros */
uint8 data;
/* flags */
//uint8 n_flag, v_flag, b_flag;
//uint8 d_flag, i_flag, z_flag, c_flag;
uint32 n_flag, v_flag, b_flag;
uint32 i_flag, z_flag, c_flag;
/* local copies of regs */
uint32 PC;
uint8 * last_bank_ptr;
uint32 A, X, Y, S;
#undef ram
#undef stack
uint8* ram_l = ram;
uint8* stack_l = stack;
uint8** mem_page = cpu.mem_page;
#define ram ram_l
#define stack stack_l
#ifdef NES6502_JUMPTABLE
#define OPCODE_BEGIN(xx) op##xx:
#define OPCODE_END \
if (remaining_cycles <= 0) \
goto end_execute; \
goto *opcode_table[bank_readbyte(PC++)];
static void *opcode_table[256] =
{
&&op00, &&op01, &&op02, &&op03, &&op04, &&op05, &&op06, &&op07,
&&op08, &&op09, &&op0A, &&op0B, &&op0C, &&op0D, &&op0E, &&op0F,
&&op10, &&op11, &&op12, &&op13, &&op14, &&op15, &&op16, &&op17,
&&op18, &&op19, &&op1A, &&op1B, &&op1C, &&op1D, &&op1E, &&op1F,
&&op20, &&op21, &&op22, &&op23, &&op24, &&op25, &&op26, &&op27,
&&op28, &&op29, &&op2A, &&op2B, &&op2C, &&op2D, &&op2E, &&op2F,
&&op30, &&op31, &&op32, &&op33, &&op34, &&op35, &&op36, &&op37,
&&op38, &&op39, &&op3A, &&op3B, &&op3C, &&op3D, &&op3E, &&op3F,
&&op40, &&op41, &&op42, &&op43, &&op44, &&op45, &&op46, &&op47,
&&op48, &&op49, &&op4A, &&op4B, &&op4C, &&op4D, &&op4E, &&op4F,
&&op50, &&op51, &&op52, &&op53, &&op54, &&op55, &&op56, &&op57,
&&op58, &&op59, &&op5A, &&op5B, &&op5C, &&op5D, &&op5E, &&op5F,
&&op60, &&op61, &&op62, &&op63, &&op64, &&op65, &&op66, &&op67,
&&op68, &&op69, &&op6A, &&op6B, &&op6C, &&op6D, &&op6E, &&op6F,
&&op70, &&op71, &&op72, &&op73, &&op74, &&op75, &&op76, &&op77,
&&op78, &&op79, &&op7A, &&op7B, &&op7C, &&op7D, &&op7E, &&op7F,
&&op80, &&op81, &&op82, &&op83, &&op84, &&op85, &&op86, &&op87,
&&op88, &&op89, &&op8A, &&op8B, &&op8C, &&op8D, &&op8E, &&op8F,
&&op90, &&op91, &&op92, &&op93, &&op94, &&op95, &&op96, &&op97,
&&op98, &&op99, &&op9A, &&op9B, &&op9C, &&op9D, &&op9E, &&op9F,
&&opA0, &&opA1, &&opA2, &&opA3, &&opA4, &&opA5, &&opA6, &&opA7,
&&opA8, &&opA9, &&opAA, &&opAB, &&opAC, &&opAD, &&opAE, &&opAF,
&&opB0, &&opB1, &&opB2, &&opB3, &&opB4, &&opB5, &&opB6, &&opB7,
&&opB8, &&opB9, &&opBA, &&opBB, &&opBC, &&opBD, &&opBE, &&opBF,
&&opC0, &&opC1, &&opC2, &&opC3, &&opC4, &&opC5, &&opC6, &&opC7,
&&opC8, &&opC9, &&opCA, &&opCB, &&opCC, &&opCD, &&opCE, &&opCF,
&&opD0, &&opD1, &&opD2, &&opD3, &&opD4, &&opD5, &&opD6, &&opD7,
&&opD8, &&opD9, &&opDA, &&opDB, &&opDC, &&opDD, &&opDE, &&opDF,
&&opE0, &&opE1, &&opE2, &&opE3, &&opE4, &&opE5, &&opE6, &&opE7,
&&opE8, &&opE9, &&opEA, &&opEB, &&opEC, &&opED, &&opEE, &&opEF,
&&opF0, &&opF1, &&opF2, &&opF3, &&opF4, &&opF5, &&opF6, &&opF7,
&&opF8, &&opF9, &&opFA, &&opFB, &&opFC, &&opFD, &&opFE, &&opFF
};
#else /* !NES6502_JUMPTABLE */
#define OPCODE_BEGIN(xx) case 0x##xx:
/* #define OPCODE_END break; */
#define OPCODE_END goto next_opcode;
#endif /* !NES6502_JUMPTABLE */
GET_GLOBAL_REGS();
if (cpu.int_pending && remaining_cycles)
{
if (0 == i_flag)
{
cpu.int_pending = 0;
IRQ();
}
}
/* check for DMA cycle burning */
if (cpu.burn_cycles && remaining_cycles)
{
int burn_for;
burn_for = MIN(remaining_cycles, cpu.burn_cycles);
ADD_CYCLES(burn_for);
cpu.burn_cycles -= burn_for;
}
#ifdef NES6502_JUMPTABLE
/* fetch first instruction */
OPCODE_END
#else /* !NES6502_JUMPTABLE */
current_PC = &PC;
current_last_bank_ptr = &last_bank_ptr;
/* Continue until we run out of cycles */
next_opcode:
while (remaining_cycles > 0)
{
#ifdef NES6502_DISASM
log_printf(nes6502_disasm(PC, COMBINE_FLAGS(), A, X, Y, S));
#endif /* NES6502_DISASM */
/* Fetch and execute instruction */
//switch (bank_readbyte(PC++))
/* uint8 c = bank_readbyte(PC);
PC++;
*/
switch (*(uint8 *)PC++)
{
#endif /* !NES6502_JUMPTABLE */
OPCODE_BEGIN(00) /* BRK */
BRK();
OPCODE_END
OPCODE_BEGIN(01) /* ORA ($nn,X) */
ORA(6, INDIR_X_BYTE);
OPCODE_END
OPCODE_BEGIN(02) /* JAM */
OPCODE_BEGIN(12) /* JAM */
OPCODE_BEGIN(22) /* JAM */
OPCODE_BEGIN(32) /* JAM */
OPCODE_BEGIN(42) /* JAM */
OPCODE_BEGIN(52) /* JAM */
OPCODE_BEGIN(62) /* JAM */
OPCODE_BEGIN(72) /* JAM */
OPCODE_BEGIN(92) /* JAM */
OPCODE_BEGIN(B2) /* JAM */
OPCODE_BEGIN(D2) /* JAM */
OPCODE_BEGIN(F2) /* JAM */
JAM();
/* kill the CPU */
remaining_cycles = 0;
OPCODE_END
OPCODE_BEGIN(03) /* SLO ($nn,X) */
SLO(8, INDIR_X, mem_writebyte, addr);
OPCODE_END
OPCODE_BEGIN(04) /* NOP $nn */
OPCODE_BEGIN(44) /* NOP $nn */
OPCODE_BEGIN(64) /* NOP $nn */
DOP(3);
OPCODE_END
OPCODE_BEGIN(05) /* ORA $nn */
ORA(3, ZERO_PAGE_BYTE);
OPCODE_END
OPCODE_BEGIN(06) /* ASL $nn */
ASL(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
OPCODE_END
OPCODE_BEGIN(07) /* SLO $nn */
SLO(5, ZERO_PAGE, ZP_WRITEBYTE, baddr);
OPCODE_END
OPCODE_BEGIN(08) /* PHP */
PHP();
OPCODE_END
OPCODE_BEGIN(09) /* ORA #$nn */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -