⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 nes6502.c

📁 PocketNester的c++源代码,很好的学习例子,仅供大家学习
💻 C
📖 第 1 页 / 共 5 页
字号:
   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 + -