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

📄 nes6502.c

📁 PocketNester的c++源代码,很好的学习例子,仅供大家学习
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
** Nofrendo (c) 1998-2000 Matthew Conte (matt@conte.com)
**
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of version 2 of the GNU Library General 
** Public License as published by the Free Software Foundation.
**
** This program is distributed in the hope that it will be useful, 
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
** Library General Public License for more details.  To obtain a 
** copy of the GNU Library General Public License, write to the Free 
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Any permitted reproduction of these routines, in whole or in part,
** must bear this legend.
**
**
** nes6502.c
**
** NES custom 6502 (2A03) CPU implementation
** $Id: nes6502.c,v 1.6 2003/03/24 14:50:51 Rick Exp $
*/

/*
** changes for nester:
** changes are marked with DCR
**
** removed dis6502 #include
** nullified ASSERT
** nullified INLINE
**
** - Darren Ranalli
*/


#if defined(__GNUC__)       // gcc 3.0.3 arm-wince-pe?
typedef long unsigned int size_t;
typedef int ssize_t;
typedef unsigned long time_t;
typedef unsigned long clock_t;
typedef short wchar_t;
#define NULL ((void*)0)
#endif

#include <stdlib.h>
#include <stdio.h>
#include "types.h"
#include "nes6502.h"
//#include "dis6502.h" //DCR

// from nesterJppc
#define ram		ram_l
#define stack	stack_l

//DCR
#define ASSERT(CONDITION)

//DCR
#define INLINE __inline // for WindowsCE

//#define  NES6502_DISASM

#if defined(__GNUC__) && !defined(NES6502_DISASM)
#define  NES6502_JUMPTABLE
#endif /* __GNUC__ */


//cpu.total_cycles += (x); 
#define  ADD_CYCLES(x) \
{ \
   remaining_cycles -= (x); \
}

// Rick
static uint32 * current_PC = NULL;
static uint8 ** current_last_bank_ptr = NULL;

#define PC_TO_PTR() \
	{ \
		uint32 t = PC >> NES6502_BANKSHIFT; \
		/* last_bank_ptr = cpu.mem_page[t] - (t << NES6502_BANKSHIFT); */\
		last_bank_ptr = mem_page[t] - (t << NES6502_BANKSHIFT); \
		PC += (uint32)last_bank_ptr; \
	}

#define PTR_TO_PC() \
	PC -= (uint32)last_bank_ptr;

/*
** Check to see if an index reg addition overflowed to next page
*/
#define PAGE_CROSS_CHECK(addr, reg) \
{ \
   if ((reg) > (uint8) (addr)) \
      ADD_CYCLES(1); \
}

#define EMPTY_READ(value)  /* empty */

/*
** Addressing mode macros
*/

/* Immediate */
#if 0

#define IMMEDIATE_BYTE(value) \
{ \
   /* value = bank_readbyte(PC++); */ \
   value = bank_readbyte(PC); \
   PC++; \
}

/* Absolute */
#define ABSOLUTE_ADDR(address) \
{ \
   address = bank_readword(PC); \
   PC += 2; \
}

#else

#define IMMEDIATE_BYTE(value) \
	value = *(uint8 *)PC++;

#define ABSOLUTE_ADDR(address) \
{ \
   address = *(uint8 *)PC | ((uint16)(*((uint8 *)PC + 1)) << 8); \
   PC += 2; \
}

#endif


#define ABSOLUTE(address, value) \
{ \
   ABSOLUTE_ADDR(address); \
   value = mem_readbyte(address); \
}

#define ABSOLUTE_BYTE(value) \
{ \
   ABSOLUTE(temp, value); \
}

/* Absolute indexed X */
#define ABS_IND_X_ADDR(address) \
{ \
   ABSOLUTE_ADDR(address); \
   address = (address + X) & 0xFFFF; \
   PAGE_CROSS_CHECK(address, X); \
}

#define ABS_IND_X(address, value) \
{ \
   ABS_IND_X_ADDR(address); \
   value = mem_readbyte(address); \
}

#define ABS_IND_X_BYTE(value) \
{ \
   ABS_IND_X(temp, value); \
}

/* Absolute indexed Y */
#define ABS_IND_Y_ADDR(address) \
{ \
   ABSOLUTE_ADDR(address); \
   address = (address + Y) & 0xFFFF; \
   PAGE_CROSS_CHECK(address, Y); \
}

#define ABS_IND_Y(address, value) \
{ \
   ABS_IND_Y_ADDR(address); \
   value = mem_readbyte(address); \
}

#define ABS_IND_Y_BYTE(value) \
{ \
   ABS_IND_Y(temp, value); \
}

/* Zero-page */
#define ZERO_PAGE_ADDR(address) \
{ \
   IMMEDIATE_BYTE(address); \
}

#define ZERO_PAGE(address, value) \
{ \
   ZERO_PAGE_ADDR(address); \
   value = ZP_READBYTE(address); \
}

#define ZERO_PAGE_BYTE(value) \
{ \
   ZERO_PAGE(btemp, value); \
}

/* Zero-page indexed X */
#define ZP_IND_X_ADDR(address) \
{ \
   ZERO_PAGE_ADDR(address); \
   address += X; \
}

#define ZP_IND_X(address, value) \
{ \
   ZP_IND_X_ADDR(address); \
   value = ZP_READBYTE(address); \
}

#define ZP_IND_X_BYTE(value) \
{ \
   ZP_IND_X(btemp, value); \
}

/* Zero-page indexed Y */
/* Not really an adressing mode, just for LDx/STx */
#define ZP_IND_Y_ADDR(address) \
{ \
   ZERO_PAGE_ADDR(address); \
   address += Y; \
}

#define ZP_IND_Y_BYTE(value) \
{ \
   ZP_IND_Y_ADDR(btemp); \
   value = ZP_READBYTE(btemp); \
}  

/* Indexed indirect */
#define INDIR_X_ADDR(address) \
{ \
   IMMEDIATE_BYTE(btemp); \
   btemp += X; \
   address = zp_readword(btemp); \
}

#define INDIR_X(address, value) \
{ \
   INDIR_X_ADDR(address); \
   value = mem_readbyte(address); \
} 

#define INDIR_X_BYTE(value) \
{ \
   INDIR_X(temp, value); \
}

/* Indirect indexed */
#define INDIR_Y_ADDR(address) \
{ \
   IMMEDIATE_BYTE(btemp); \
   address = (zp_readword(btemp) + Y) & 0xFFFF; \
   PAGE_CROSS_CHECK(address, Y); \
}

#define INDIR_Y(address, value) \
{ \
   INDIR_Y_ADDR(address); \
   value = mem_readbyte(address); \
} 

#define INDIR_Y_BYTE(value) \
{ \
   INDIR_Y(temp, value); \
}



/* Stack push/pull */
#define  PUSH(value)             stack[S--] = (uint8) (value)
#define  PULL()                  stack[++S]


/*
** flag register helper macros
*/

/* Theory: Z and N flags are set in just about every
** instruction, so we will just store the value in those
** flag variables, and mask out the irrelevant data when
** we need to check them (branches, etc).  This makes the
** zero flag only really be 'set' when z_flag == 0.
** The rest of the flags are stored as true booleans.
*/

/* Scatter flags to separate variables */
#define  SCATTER_FLAGS(value) \
{ \
   n_flag = (value) & N_FLAG; \
   v_flag = (value) & V_FLAG; \
   b_flag = (value) & B_FLAG; \
   /* d_flag = (value) & D_FLAG; */ \
   i_flag = (value) & I_FLAG; \
   z_flag = !((value) & Z_FLAG); \
   c_flag = (value) & C_FLAG; \
}

/* Combine flags into flag register */
/*
#define  COMBINE_FLAGS() \
( \
   (n_flag & N_FLAG) | \
   (v_flag ? V_FLAG : 0) | \
   R_FLAG | \
   (b_flag ? B_FLAG : 0) | \
   (d_flag ? D_FLAG : 0) | \
   (i_flag ? I_FLAG : 0) | \
   (z_flag ? 0 : Z_FLAG) | \
   (c_flag ? C_FLAG : 0) \
)
*/
// from nesterJppc
#define  COMBINE_FLAGS() \
( \
   (n_flag & N_FLAG) | \
   R_FLAG | i_flag | b_flag | c_flag | \
   (v_flag ? V_FLAG : 0) | \
   (z_flag ? 0 : Z_FLAG) \
)


/* Set N and Z flags based on given value */
#define  SET_NZ_FLAGS(value)     n_flag = z_flag = (value);

/* For BCC, BCS, BEQ, BMI, BNE, BPL, BVC, BVS */
#define RELATIVE_BRANCH(condition) \
{ \
   if (condition) \
   { \
      IMMEDIATE_BYTE(btemp); \
	  PTR_TO_PC(); \
      if (((int8) btemp + (PC & 0x00FF)) & 0x100) \
         ADD_CYCLES(1); \
      ADD_CYCLES(3); \
      PC += ((int8) btemp); \
	  PC_TO_PTR(); \
   } \
   else \
   { \
      PC++; \
      ADD_CYCLES(2); \
   } \
}

#define JUMP(address) \
{ \
   PC = bank_readword((address)); \
   PC_TO_PTR(); \
}

/*
** Interrupt macros
*/
#define NMI_PROC() \
{ \
   PTR_TO_PC(); \
   PUSH(PC >> 8); \
   PUSH(PC & 0xFF); \
   b_flag = 0; \
   PUSH(COMBINE_FLAGS()); \
   i_flag = I_FLAG; /* i_flag = 1; */\
   JUMP(NMI_VECTOR); \
}

#define IRQ_PROC() \
{ \
   PTR_TO_PC(); \
   PUSH(PC >> 8); \
   PUSH(PC & 0xFF); \
   b_flag = 0; \
   PUSH(COMBINE_FLAGS()); \
   i_flag = I_FLAG; /* i_flag = 1; */\
   JUMP(IRQ_VECTOR); \
}

#define NMI() \
{ \
   NMI_PROC(); \
   ADD_CYCLES(INT_CYCLES); \
}

#define IRQ() \
{ \
   IRQ_PROC(); \
   ADD_CYCLES(INT_CYCLES); \
}

/*
** Instruction macros
*/

/* Warning! NES CPU has no decimal mode, so by default this does no BCD! */
#ifdef NES6502_DECIMAL
#define ADC(cycles, read_func) \
{ \
   read_func(data); \
   if (d_flag) \
   { \
      temp = (A & 0x0F) + (data & 0x0F) + (c_flag ? 1 : 0); \
      if (temp >= 10) \
         temp = (temp - 10) | 0x10; \
      temp += (A & 0xF0) + (data & 0xF0); \
      z_flag = (A + data + (c_flag ? 1 : 0)) & 0xFF; \
      n_flag = temp; \
      v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
      if (temp > 0x9F) \
         temp += 0x60; \
      c_flag = (temp > 0xFF); \
      A = (uint8) temp; \
   } \
   else \
   { \
      temp = A + data + (c_flag ? 1 : 0); \
      c_flag = (temp > 0xFF); \
      v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
      A = (uint8) temp; \
      SET_NZ_FLAGS(A); \
   }\
   ADD_CYCLES(cycles); \
}
#else
#define ADC(cycles, read_func) \
{ \
   read_func(data); \
   temp = A + data + c_flag; /* temp = A + data + (c_flag ? 1 : 0); */\
   c_flag = (temp > 0xFF); \
   v_flag = ((~(A ^ data)) & (A ^ temp) & 0x80); \
   A = (uint8) temp; \
   SET_NZ_FLAGS(A); \
   ADD_CYCLES(cycles); \
}
#endif /* NES6502_DECIMAL */

/* undocumented */
#define ANC(cycles, read_func) \
{ \
   read_func(data); \
   A &= data; \
   SET_NZ_FLAGS(A); \
   c_flag = n_flag >> 7; /* c_flag = (n_flag & N_FLAG) ? 1 : 0;*/ \
   ADD_CYCLES(cycles); \
}

#define AND(cycles, read_func) \
{ \
   read_func(data); \
   A &= data; \
   SET_NZ_FLAGS(A); \
   ADD_CYCLES(cycles); \
}

/* undocumented */
#define ANE(cycles, read_func) \
{ \
   read_func(data); \
   A = (A | 0xEE) & X & data; \
   SET_NZ_FLAGS(A); \
   ADD_CYCLES(cycles); \
}

/* undocumented */
#ifdef NES6502_DECIMAL
#define ARR(cycles, read_func) \
{ \
   read_func(data); \
   data &= A; \
   if (d_flag) \
   { \
      temp = (data >> 1) | (c_flag ? 0x80 : 0); \
      SET_NZ_FLAGS(temp); \
      v_flag = (temp ^ data) & 0x40; \
      if (((data & 0x0F) + (data & 0x01)) > 5) \
         temp = (temp & 0xF0) | ((temp + 0x6) & 0x0F); \
      if (((data & 0xF0) + (data & 0x10)) > 0x50) \
      { \
         temp = (temp & 0x0F) | ((temp + 0x60) & 0xF0); \
         c_flag = 1; \
      } \
      else \
         c_flag = 0; \
      A = (uint8) temp; \
   } \
   else \
   { \
      A = (data >> 1) | (c_flag ? 0x80 : 0); \
      SET_NZ_FLAGS(A); \
      c_flag = A & 0x40; \
      v_flag = ((A >> 6) ^ (A >> 5)) & 1; \
   }\
   ADD_CYCLES(cycles); \
}
#else
#define ARR(cycles, read_func) \
{ \
   read_func(data); \
   data &= A; \
   A = (data >> 1) | (c_flag << 7); \
   SET_NZ_FLAGS(A); \
   c_flag = (A >> 6) & C_FLAG; \
   v_flag = ((A >> 6) ^ (A >> 5)) & 1; \
   ADD_CYCLES(cycles); \
}
#endif /* NES6502_DECIMAL */

#define ASL(cycles, read_func, write_func, addr) \
{ \
   read_func(addr, data); \
   c_flag = data >> 7; \
   data <<= 1; \
   write_func(addr, data); \
   SET_NZ_FLAGS(data); \
   ADD_CYCLES(cycles); \
}

#define ASL_A() \
{ \
   c_flag = A >> 7; \
   /* A <<= 1; */\
   A = (uint8)(A << 1); \
   SET_NZ_FLAGS(A); \
   ADD_CYCLES(2); \
}

/* undocumented */
#define ASR(cycles, read_func) \
{ \
   read_func(data); \
   data &= A; \
   c_flag = data & 0x01; \
   A = data >> 1; \
   SET_NZ_FLAGS(A); \
   ADD_CYCLES(cycles); \
}

#define BCC() \
{ \
   RELATIVE_BRANCH(0 == c_flag); \
}

#define BCS() \
{ \
   RELATIVE_BRANCH(0 != c_flag); \
}

#define BEQ() \
{ \
   RELATIVE_BRANCH(0 == z_flag); \
}

#define BIT(cycles, read_func) \
{ \
   read_func(data); \
   z_flag = data & A; \
   /* move bit 7/6 of data into N/V flags */ \
   n_flag = data; \
   v_flag = data & V_FLAG; \
   ADD_CYCLES(cycles); \
}

#define BMI() \

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -