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

📄 65c816.asm

📁 NES game Emulator in Linux.c and asm codes.
💻 ASM
📖 第 1 页 / 共 5 页
字号:
%if 0

SNEeSe, an Open Source Super NES emulator.


Copyright (c) 1998-2004 Charles Bilyue'.
Portions Copyright (c) 2003-2004 Daniel Horchner.

This is free software.  See 'LICENSE' for details.
You must read and accept the license prior to use.

%endif

; SNEeSe 65c816 CPU emulation core
; Originally written by Lee Hammerton in AT&T assembly
; Maintained/rewritten/ported to NASM by Charles Bilyue'
;
; Compile under NASM

; To do: move cycle addition into opcode handlers
;        improved bus speed selection

;CPU instruction tracker is broken!
;DO NOT UNCOMMENT THE FOLLOWING LINE!
;%define TRACKERS 1048576

%define VERSION_NUMBER_5A22 2

;%define SINGLE_STEP

;%define WATCH_FLAG_BREAKS
;%define FAST_STACK_ACCESS_NATIVE_MODE
%define FAST_STACK_ACCESS_EMULATION_MODE

; This file contains:
;  CPU core info
;  Reset
;  Execution Loop
;  Invalid Opcode Handler
;  Flag format conversion tables
;  Variable definitions (registers, interrupt vectors, etc.)
;  CPU opcode emulation handlers
;  CPU opcode handler tables
;  CPU opcode timing tables
;
; CPU core info:
;  All general registers are now used in 65c816 emulation:
;   EAX,EBX are used by the memory mapper;
;   ECX is used to hold P register;
;   EDX is used as memory mapper work register;
;   EBP is used to hold scanline cycle counter;
;   ESI is used by the opcode fetcher;
;   EDI is used to hold base address to CPU register set.
;
;    Accumulator         - CPU_LABEL(A)
;    X index             - CPU_LABEL(X)
;    Y index             - CPU_LABEL(Y)
;    Stack pointer       - CPU_LABEL(S)
;    Direct address      - CPU_LABEL(D)
;    Program Counter     - CPU_LABEL(PC)
;    Program Bank        - CPU_LABEL(PB), CPU_LABEL(PB_Shifted)
;    Data Bank           - CPU_LABEL(DB), CPU_LABEL(DB_Shifted)
;    Processor status    - _P,_P_B,_P_W
;                True x86 layout = |V|-|-|-|S|Z|-|A|-|-|-|C|
;       Native mode 65816 layout =       |E|N|V|M|X|D|I|Z|C|
;    Emulation mode 65816 layout =       |E|N|V|1|B|D|I|Z|C|
;                            Using       |E|N|Z|I|D|X|M|V|C|
;                                                  |B|1|
;
; Identifiers/labels
;  Identifiers beginning with "R_" are register aliases.
;  Identifiers beginning with "B_" are 'based' data (1-byte offset) aliases.
;  Identifiers beginning with "_" MAY BE local aliases for more
;   complex global identifiers.
;  FUTURE: Change prefix for complex identifier local aliases to "I_" or "L_".
;   (Internal or Local)
; CPU timing
;  According to Neill Corlett's SNES timing doc, main CPU clock is
;   21.47727MHz, 1360 clocks/scanline.
;
;  SNES PPU timing and interrupt timing is specific to ROM country,
;   set by ROM loader.
;  65c816 runs with many waitstates added in for bus access, bringing
;   effective CPU speed between 2.68MHz (minimum) and 3.58MHz (maximum).
;
;  Now adding base opcode cycle counts, *8 for SlowROM banks and *6 for
;   FastROM banks. This is INACCURATE! But close enough for now.
;
; Core Flaws
;  'Fast' native mode stack is incorrect outside WRAM (0000-1FFF) - values
;   read are undefined (no read is done) and values written are ignored:
;   should fallback, disabled for now.
;
; SPC relative timing calculation (for parallel execution)
;
;  SPC execution is on-demand, and CPU and SPC synchronize on
;   certain CPU events and on CPU<>SPC communication. Executed CPU
;   cycles are counted and depleted when SPC execution catches up.
;
;

%include "misc.inc"
%include "cycles.inc"
%include "cpu/cpumem.inc"
%include "ppu/screen.inc"
%include "cpu/regs.inc"
%include "ppu/ppu.inc"
%include "cpu/dma.inc"

EXTERN_C Map_Address,Map_Byte
EXTERN_C OLD_PB,OLD_PC
EXTERN_C RomAddress
EXTERN_C LastIns,InsAddress

EXTERN_C FRAME_SKIP_MIN,FRAME_SKIP_MAX,Timer_Counter_Throttle
EXTERN_C SNES_Screen8
EXTERN_C PaletteChanged
EXTERN_C BrightnessLevel
EXTERN_C Real_SNES_Palette,fixedpalettecheck,SetPalette
EXTERN_C ShowFPS,ShowBreaks
EXTERN_C Copy_Screen
EXTERN_C update_sound, update_sound_block

EXTERN_C SPC_ENABLED
EXTERN_C SPC_Cycles
EXTERN_C TotalCycles
EXTERN_C Wrap_SPC_Cyclecounter
EXTERN_C SPC_START

EXTERN_C SPC_CPU_cycle_divisor
EXTERN_C SPC_CPU_cycle_multiplicand

EXTERN_C InvalidOpcode,InvalidJump
EXTERN Invalidate_Tile_Caches
EXTERN_C Reset_CGRAM

%ifdef DEBUG
EXTERN_C Frames
;EXTERN_C Timer_Counter_FPS
%endif

section .text
EXPORT_C CPU_text_start
section .data
EXPORT_C CPU_data_start
section .bss
EXPORT_C CPU_bss_start

%define CPU_LABEL(x) C_LABEL(cpu_65c816_ %+ x)

%define R_Base      R_65c816_Base   ; Base pointer to register set
%define R_Cycles    R_65c816_Cycles ; Cycle counter
%define R_PBPC      R_65c816_PBPC
%define R_PC        R_65c816_PC

;  True 65816 layout, Native Mode    = |E|N|V|M|X|D|I|Z|C|
;  True 65816 layout, Emulation Mode = |E|N|V|1|B|D|I|Z|C|

; These are the bits for flag set/clr operations
; |E|N|Z|I|D|X|M|V|C|
;           |B|1|

SNES_FLAG_C equ 1   ; Carry
SNES_FLAG_V equ 2   ; Overflow
SNES_FLAG_M equ 4   ; When E=0: Memory/accumulator operations 8-bit
SNES_FLAG_1 equ 4   ; When E=1: This bit is always set
SNES_FLAG_X equ 8   ; When E=0: Index registers 8-bit
SNES_FLAG_B equ 8   ; When E=1: Break (clear only on stack after IRQ/NMI)
SNES_FLAG_D equ 0x10    ; Decimal ADC/SBC mode
SNES_FLAG_I equ 0x20    ; Interrupt Disable
SNES_FLAG_Z equ 0x40    ; Zero result
SNES_FLAG_N equ 0x80    ; Negative result
SNES_FLAG_E equ 0x100   ; Emulation mode

SNES_FLAG_B1 equ (SNES_FLAG_B | SNES_FLAG_1)
SNES_FLAG_MX equ (SNES_FLAG_M | SNES_FLAG_X)
SNES_FLAG_NZ equ (SNES_FLAG_N | SNES_FLAG_Z)
SNES_FLAG_NZC equ (SNES_FLAG_NZ | SNES_FLAG_C)

REAL_SNES_FLAG_C equ 1  ; See descriptions above
REAL_SNES_FLAG_Z equ 2
REAL_SNES_FLAG_I equ 4
REAL_SNES_FLAG_D equ 8
REAL_SNES_FLAG_X equ 0x10
REAL_SNES_FLAG_B equ 0x10
REAL_SNES_FLAG_M equ 0x20
REAL_SNES_FLAG_1 equ 0x20
REAL_SNES_FLAG_V equ 0x40
REAL_SNES_FLAG_N equ 0x80
REAL_SNES_FLAG_E equ 0x100

section .bss
ALIGNB
%define B_IRQ_Nvector       [R_Base-CPU_Register_Base+C_LABEL(IRQ_Nvector)]
%define B_NMI_Nvector       [R_Base-CPU_Register_Base+C_LABEL(NMI_Nvector)]
%define B_BRK_Nvector       [R_Base-CPU_Register_Base+C_LABEL(BRK_Nvector)]
%define B_COP_Nvector       [R_Base-CPU_Register_Base+C_LABEL(COP_Nvector)]
%define B_IRQ_Evector       [R_Base-CPU_Register_Base+C_LABEL(IRQ_Evector)]
%define B_NMI_Evector       [R_Base-CPU_Register_Base+C_LABEL(NMI_Evector)]
%define B_COP_Evector       [R_Base-CPU_Register_Base+C_LABEL(COP_Evector)]
%define B_RES_Evector       [R_Base-CPU_Register_Base+C_LABEL(RES_Evector)]
%define B_PB_Shifted        [R_Base-CPU_Register_Base+CPU_LABEL(PB_Shifted)]
%define B_PB                [R_Base-CPU_Register_Base+CPU_LABEL(PB)]
%define B_PC                [R_Base-CPU_Register_Base+CPU_LABEL(PC)]
%define B_P                 [R_Base-CPU_Register_Base+CPU_LABEL(P)]
%define B_SNES_Cycles       [R_Base-CPU_Register_Base+C_LABEL(SNES_Cycles)]
%define B_EventTrip         [R_Base-CPU_Register_Base+C_LABEL(EventTrip)]
%define B_A                 [R_Base-CPU_Register_Base+CPU_LABEL(A)]
%define B_B                 byte [R_Base-CPU_Register_Base+CPU_LABEL(B)]
%define B_X                 [R_Base-CPU_Register_Base+CPU_LABEL(X)]
%define B_XH                byte [R_Base-CPU_Register_Base+CPU_LABEL(XH)]
%define B_Y                 [R_Base-CPU_Register_Base+CPU_LABEL(Y)]
%define B_YH                byte [R_Base-CPU_Register_Base+CPU_LABEL(YH)]
%define B_D                 [R_Base-CPU_Register_Base+CPU_LABEL(D)]
%define B_DL                byte [R_Base-CPU_Register_Base+CPU_LABEL(DL)]
%define B_DH                byte [R_Base-CPU_Register_Base+CPU_LABEL(DH)]
%define B_S                 [R_Base-CPU_Register_Base+CPU_LABEL(S)]
%define B_SL                byte [R_Base-CPU_Register_Base+CPU_LABEL(SL)]
%define B_SH                byte [R_Base-CPU_Register_Base+CPU_LABEL(SH)]
%define B_DB_Shifted        [R_Base-CPU_Register_Base+CPU_LABEL(DB_Shifted)]
%define B_DB                [R_Base-CPU_Register_Base+CPU_LABEL(DB)]
%define B_OpTable           [R_Base-CPU_Register_Base+OpTable]
%define B_FixedTrip         [R_Base-CPU_Register_Base+FixedTrip]
%define B_SPC_last_cycles   [R_Base-CPU_Register_Base+SPC_last_cycles]
%define B_SPC_CPU_cycles    [R_Base-CPU_Register_Base+SPC_CPU_cycles]
%define B_SPC_cycles_left   [R_Base-CPU_Register_Base+SPC_cycles_left]
%define B_SPC_CPU_cycles_mul    [R_Base-CPU_Register_Base+SPC_CPU_cycles_mul]

%if 1
%define B_E_flag            [R_Base-CPU_Register_Base+_E_flag]
%define B_N_flag            [R_Base-CPU_Register_Base+_N_flag]
%define B_V_flag            [R_Base-CPU_Register_Base+_V_flag]
%define B_M1_flag           [R_Base-CPU_Register_Base+_M1_flag]
%define B_XB_flag           [R_Base-CPU_Register_Base+_XB_flag]
%define B_D_flag            [R_Base-CPU_Register_Base+_D_flag]
%define B_I_flag            [R_Base-CPU_Register_Base+_I_flag]
%define B_Z_flag            [R_Base-CPU_Register_Base+_Z_flag]
%define B_C_flag            [R_Base-CPU_Register_Base+_C_flag]
%else
%define B_E_flag [_E_flag]
%define B_N_flag [_N_flag]
%define B_V_flag [_V_flag]
%define B_M1_flag [_M1_flag]
%define B_XB_flag [_XB_flag]
%define B_D_flag [_D_flag]
%define B_I_flag [_I_flag]
%define B_Z_flag [_Z_flag]
%define B_C_flag [_C_flag]
%endif

EXPORT_C IRQ_Nvector,skipl
EXPORT_C IRQ_Noffset,skipl
EXPORT_C NMI_Nvector,skipl
EXPORT_C NMI_Noffset,skipl
EXPORT_C BRK_Nvector,skipl
EXPORT_C BRK_Noffset,skipl
EXPORT_C COP_Nvector,skipl
EXPORT_C COP_Noffset,skipl
EXPORT_C IRQ_Evector,skipl
EXPORT_C IRQ_Eoffset,skipl
EXPORT_C NMI_Evector,skipl
EXPORT_C NMI_Eoffset,skipl
EXPORT_C COP_Evector,skipl
EXPORT_C COP_Eoffset,skipl
EXPORT_C RES_Evector,skipl
EXPORT_C RES_Eoffset,skipl

; v0.25 - New system for CPU timings... there are now ten paired tables,
; not five single tables. Each pair of tables has a 256-byte SlowROM
; table first, then a 256-byte FastROM table immediately following.
; The address of the current table pair is OpTable+0x400.

; v0.25 - OpTable holds pointer to current opcode emulation/timing tables,
; removes the need for multiple CPU loops.

CPU_Register_Base:

EXPORT CPU_LABEL(PB_Shifted),skipl  ; Program Bank
EXPORT_EQU CPU_LABEL(PB),CPU_LABEL(PB_Shifted) + 2

EXPORT CPU_LABEL(PC),skipl  ; Program Counter
EXPORT CPU_LABEL(P) ,skipl  ; Processor status (flags)
EXPORT_C SNES_Cycles,skipl  ; Scanline cycle count for CPU (0-EventTrip)
EXPORT_C EventTrip  ,skipl  ; Cycle of next event on this scanline

EXPORT CPU_LABEL(A) ,skipl  ; Accumulator
EXPORT_EQU CPU_LABEL(B),CPU_LABEL(A)+1

EXPORT CPU_LABEL(X) ,skipl  ; X and Y indices
EXPORT CPU_LABEL(Y) ,skipl
EXPORT_EQU CPU_LABEL(XH),CPU_LABEL(X)+1
EXPORT_EQU CPU_LABEL(YH),CPU_LABEL(Y)+1

EXPORT CPU_LABEL(D) ,skipl  ; Direct address
EXPORT_EQU CPU_LABEL(DL),CPU_LABEL(D)
EXPORT_EQU CPU_LABEL(DH),CPU_LABEL(D)+1

EXPORT CPU_LABEL(S) ,skipl  ; Stack pointer
EXPORT_EQU CPU_LABEL(SL),CPU_LABEL(S)
EXPORT_EQU CPU_LABEL(SH),CPU_LABEL(S)+1


EXPORT CPU_LABEL(DB_Shifted),skipl  ; Data Bank
EXPORT_EQU CPU_LABEL(DB),CPU_LABEL(DB_Shifted) + 2

OpTable:skipl

EXPORT FixedTrip    ,skipl  ; Cycle of next fixed event on this scanline

EXPORT SPC_last_cycles      ,skipl
EXPORT SPC_CPU_cycles       ,skipl
EXPORT SPC_cycles_left      ,skipl
EXPORT SPC_CPU_cycles_mul   ,skipl

; For when I make the back color +/- hacks really do +/-
EXPORT RealColor0   ,skipl

_D_flag:skipb
_N_flag:skipb
_M1_flag:skipb
_XB_flag:skipb
_C_flag:skipb
_I_flag:skipb
EXPORT CPU_Execution_Mode,skipb
;CPU executing instructions normally
%define CEM_Normal_Execution 0

;CPU executing instruction immediately following one which
; caused an I-flag transition of high to low (CLI, PLP, RTI)
; The CPU will not acknowledge an IRQ until this instruction
; is completed.
%define CEM_Instruction_After_IRQ_Enable 1

;CPU in a state where no instructions are executed (this
; number and all above it)
%define CEM_Do_Not_Execute 2

;CPU is performing DMA transfer
%define CEM_In_DMA 2

;CPU is waiting for an interrupt after executing WAI opcode
%define CEM_Waiting_For_Interrupt 3
;CPU has stopped its clock after executing STP opcode
%define CEM_Clock_Stopped 4

EXPORT IRQ_pin      ,skipb
_E_flag:skipb
_Z_flag:skipb
EXPORT In_CPU,skipb         ; nonzero if CPU is executing

;NMI not raised
%define NMI_None 0
;NMI raised and acknowledged
%define NMI_Acknowledged 1
;NMI raised and not acknowledged
%define NMI_Raised 2

EXPORT NMI_pin      ,skipb
EXPORT_C FPS_ENABLED            ,skipb
_V_flag:skipb
EXPORT_C BREAKS_ENABLED         ,skipb

section .data

ALIGND
OpTableE0:
dd  C_LABEL(OpE0_0x00)    ,C_LABEL(OpE0M0_0x01)     ; 00
dd  C_LABEL(OpE0_0x02)    ,C_LABEL(OpM0_0x03)
dd  C_LABEL(OpE0M0_0x04)  ,C_LABEL(OpE0M0_0x05)
dd  C_LABEL(OpE0M0_0x06)  ,C_LABEL(OpE0M0_0x07)
dd  C_LABEL(OpE0_0x08)    ,C_LABEL(OpM0_0x09)
dd  C_LABEL(OpM0_0x0A)    ,C_LABEL(OpE0_0x0B)
dd  C_LABEL(OpM0_0x0C)    ,C_LABEL(OpM0_0x0D)
dd  C_LABEL(OpM0_0x0E)    ,C_LABEL(OpM0_0x0F)
dd  C_LABEL(OpE0_0x10)    ,C_LABEL(OpE0M0X0_0x11)   ; 10
dd  C_LABEL(OpE0M0_0x12)  ,C_LABEL(OpM0_0x13)
dd  C_LABEL(OpE0M0_0x14)  ,C_LABEL(OpE0M0_0x15)
dd  C_LABEL(OpE0M0_0x16)  ,C_LABEL(OpE0M0_0x17)
dd  C_LABEL(Op_0x18)      ,C_LABEL(OpM0X0_0x19)
dd  C_LABEL(OpM0_0x1A)    ,C_LABEL(OpE0_0x1B)
dd  C_LABEL(OpM0_0x1C)    ,C_LABEL(OpM0X0_0x1D)
dd  C_LABEL(OpM0_0x1E)    ,C_LABEL(OpM0_0x1F)
dd  C_LABEL(OpE0_0x20)    ,C_LABEL(OpE0M0_0x21)     ; 20
dd  C_LABEL(OpE0_0x22)    ,C_LABEL(OpM0_0x23)
dd  C_LABEL(OpE0M0_0x24)  ,C_LABEL(OpE0M0_0x25)
dd  C_LABEL(OpE0M0_0x26)  ,C_LABEL(OpE0M0_0x27)
dd  C_LABEL(OpE0_0x28)    ,C_LABEL(OpM0_0x29)
dd  C_LABEL(OpM0_0x2A)    ,C_LABEL(OpE0_0x2B)
dd  C_LABEL(OpM0_0x2C)    ,C_LABEL(OpM0_0x2D)
dd  C_LABEL(OpM0_0x2E)    ,C_LABEL(OpM0_0x2F)
dd  C_LABEL(OpE0_0x30)    ,C_LABEL(OpE0M0X0_0x31)   ; 30
dd  C_LABEL(OpE0M0_0x32)  ,C_LABEL(OpM0_0x33)
dd  C_LABEL(OpE0M0_0x34)  ,C_LABEL(OpE0M0_0x35)
dd  C_LABEL(OpE0M0_0x36)  ,C_LABEL(OpE0M0_0x37)
dd  C_LABEL(Op_0x38)      ,C_LABEL(OpM0X0_0x39)
dd  C_LABEL(OpM0_0x3A)    ,C_LABEL(Op_0x3B)
dd  C_LABEL(OpM0X0_0x3C)  ,C_LABEL(OpM0X0_0x3D)
dd  C_LABEL(OpM0_0x3E)    ,C_LABEL(OpM0_0x3F)
dd  C_LABEL(OpE0_0x40)    ,C_LABEL(OpE0M0_0x41)     ; 40
dd  C_LABEL(ALL_INVALID)  ,C_LABEL(OpM0_0x43)
dd  C_LABEL(OpX0_0x44)    ,C_LABEL(OpE0M0_0x45)
dd  C_LABEL(OpE0M0_0x46)  ,C_LABEL(OpE0M0_0x47)
dd  C_LABEL(OpE0M0_0x48)  ,C_LABEL(OpM0_0x49)
dd  C_LABEL(OpM0_0x4A)    ,C_LABEL(OpE0_0x4B)
dd  C_LABEL(Op_0x4C)      ,C_LABEL(OpM0_0x4D)
dd  C_LABEL(OpM0_0x4E)    ,C_LABEL(OpM0_0x4F)
dd  C_LABEL(OpE0_0x50)    ,C_LABEL(OpE0M0X0_0x51)   ; 50

⌨️ 快捷键说明

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