📄 65c816.asm
字号:
inc bx ; Preincrement S
%endif
%ifdef FAST_STACK_ACCESS_EMULATION_MODE
FAST_GET_BYTE_STACK_EMULATION_MODE al
%else
GET_BYTE
mov ah,al
%endif
%ifnidni %1,New
inc byte [CPU_LABEL(S)] ; Preincrement SL
mov ebx,[CPU_LABEL(S)] ; S only - bank always 0!
%else
inc bx ; Preincrement S
mov [CPU_LABEL(S)],bl ; Update SL
%endif
%ifdef FAST_STACK_ACCESS_EMULATION_MODE
FAST_GET_BYTE_STACK_EMULATION_MODE ah
%else
GET_BYTE
ror ax,8
%endif
%endmacro
%macro PULL_W 0-1 0
%if S_8bit
E1_PULL_W %1
%else
E0_PULL_W
%endif
%endmacro
; Native mode - push long (S--)
%macro E0_PUSH_L 0
mov ebx,[CPU_LABEL(S)] ; S only - bank always 0!
ror eax,16 ; bank byte
SET_BYTE
dec bx ; Postdecrement S
rol eax,8 ; high byte
SET_BYTE
dec bx ; Postdecrement S
rol eax,8 ; low byte
SET_BYTE
dec bx ; Postdecrement S
mov [CPU_LABEL(S)],ebx ; Set stack pointer
%endmacro
; Emulation mode - push long (SL--*)
%macro E1_PUSH_L_New 0
mov ebx,[CPU_LABEL(S)] ; S only - bank always 0!
ror eax,16 ; bank byte
SET_BYTE
dec bx ; Postdecrement S
rol eax,8 ; high byte
SET_BYTE
dec bx ; Postdecrement S
rol eax,8 ; low byte
SET_BYTE
dec bx ; Postdecrement S
mov [CPU_LABEL(S)],bl ; Set stack pointer
%endmacro
%macro PUSH_L 0
%if S_8bit
E1_PUSH_L_New
%else
E0_PUSH_L
%endif
%endmacro
; Native mode - pull long (++S)
%macro E0_PULL_L 0
mov ebx,[CPU_LABEL(S)] ; S only - bank always 0!
inc bx ; Preincrement S
GET_BYTE
inc bx ; Preincrement S
ror eax,8 ; low byte
GET_BYTE
inc bx ; Preincrement S
ror eax,8 ; high byte
GET_BYTE
ror eax,16 ; bank byte
mov [CPU_LABEL(S)],ebx ; Set stack pointer
%endmacro
; Emulation mode - pull long (++SL*)
%macro E1_PULL_L_New 0
mov ebx,[CPU_LABEL(S)] ; S only - bank always 0!
inc bx ; Preincrement S
GET_BYTE
inc bx ; Preincrement S
ror eax,8 ; low byte
GET_BYTE
inc bx ; Preincrement S
ror eax,8 ; high byte
GET_BYTE
ror eax,16 ; bank byte
mov [CPU_LABEL(S)],bl ; Set stack pointer
%endmacro
%macro PULL_L 0
%if S_8bit
E1_PULL_L_New
%else
E0_PULL_L
%endif
%endmacro
%macro Stack_Fixup 0
%if S_8bit
mov byte B_SH,1
%endif
%endmacro
ALIGNC
EXPORT_C Reset_CPU
pusha
call Reset_DMA
; Reset timing registers
xor eax,eax
mov [Latched_H],eax
mov [Latched_V],eax
mov [OPHCT],al
mov [OPVCT],al
mov byte [RDNMI],VERSION_NUMBER_5A22
mov [MEMSEL],al
mov [HVBJOY],al
mov [C_LABEL(NMITIMEN)],al
mov [C_LABEL(HTIMEL)],eax
mov [C_LABEL(VTIMEL)],eax
mov [HTimer],eax
mov [HTimer_Set],eax
; Reset other registers
mov byte [C_LABEL(WRIO)],0xFF
mov byte [C_LABEL(RDIO)],0xFF
mov [WRMPYA],al
mov [WRDIVL],al
mov [WRDIVH],al
mov [RDDIVL],al
mov [RDDIVH],al
mov [RDMPYL],al
mov [RDMPYH],al
mov [JOYC1],al
mov byte [C_LABEL(Controller1_Pos)],16
mov byte [C_LABEL(Controller23_Pos)],16
mov byte [C_LABEL(Controller45_Pos)],16
mov dword [C_LABEL(JOY1L)],(1<<31)
mov dword [C_LABEL(JOY2L)],(1<<31)
mov dword [C_LABEL(JOY3L)],(1<<31)
mov dword [C_LABEL(JOY4L)],(1<<31)
; Reset hardware ports
call Reset_Ports
; Reset SPC timing
xor eax,eax
mov [SPC_last_cycles],eax
mov [SPC_CPU_cycles],eax
mov [SPC_cycles_left],eax
mov [SPC_CPU_cycles_mul],eax
; Clear interrupt inputs
mov [IRQ_pin],al
mov [NMI_pin],al
; Reset CPU
mov [In_CPU],al
mov [CPU_Execution_Mode],al ;CEM_Normal_Execution == 0
mov dword [OpTable],OpTableE1 ; Set current opcode emulation table
; Clear cycle counts
mov dword [C_LABEL(SNES_Cycles)],0x82 ;32.5 dots before reset (?)
mov [C_LABEL(EventTrip)],eax
LOAD_BASE
LOAD_CYCLES edx
mov dword [CPU_LABEL(S)],0x01FF
mov [CPU_LABEL(A)],eax ; Clear A, D, X, Y
mov [CPU_LABEL(D)],eax
mov [CPU_LABEL(X)],eax
mov [CPU_LABEL(Y)],eax
call E1_RESET
SAVE_CYCLES
mov al,[CPU_LABEL(PB)]
mov [C_LABEL(OLD_PB)],al
%ifdef DEBUG
mov [C_LABEL(Frames)],eax
;mov [C_LABEL(Timer_Counter_FPS)],eax
%endif
; Initialize flags
;FLAGS_TO (SNES_FLAG_B1+SNES_FLAG_E+SNES_FLAG_I)
STORE_FLAGS_E 1
STORE_FLAGS_N 0
STORE_FLAGS_V 0
STORE_FLAGS_1 1
STORE_FLAGS_B 1
STORE_FLAGS_D 0
STORE_FLAGS_I 1
STORE_FLAGS_Z 1
STORE_FLAGS_C 0
;%1 = vector; %2 = label prefix;
;%3 = register with relative address of ROM at 00:E000-FFFF
%macro cache_interrupt_vector 3
movzx eax,word [%1+%3] ; Get interrupt vector
mov [C_LABEL(%2vector)],eax ; Cache vector
%endmacro
; Get all interrupt vectors
mov ebx,[C_LABEL(Read_Bank8Offset)+(0xE000 >> 13) * 4] ; Get address of ROM
cache_interrupt_vector 0xFFFC,RES_E,ebx ; Reset: Emulation mode
cache_interrupt_vector 0xFFEA,NMI_N,ebx ; NMI: Native mode
cache_interrupt_vector 0xFFFA,NMI_E,ebx ; NMI: Emulation mode
cache_interrupt_vector 0xFFEE,IRQ_N,ebx ; IRQ: Native mode
cache_interrupt_vector 0xFFFE,IRQ_E,ebx ; IRQ: Emulation mode
cache_interrupt_vector 0xFFE6,BRK_N,ebx ; BRK: Native mode
cache_interrupt_vector 0xFFE4,COP_N,ebx ; COP: Native mode
cache_interrupt_vector 0xFFF4,COP_E,ebx ; COP: Emulation mode
mov eax,[C_LABEL(RES_Evector)] ; Get Reset vector
mov [CPU_LABEL(PC)],eax ; Setup PC
mov [C_LABEL(OLD_PC)],eax
call IRQNewFrameReset
popa
ret
ALIGNC
EXPORT do_DMA
LOAD_CYCLES
cmp byte [C_LABEL(MDMAEN)],0
jz .dma_done
cmp byte [DMA_Pending_B_Address],0
jge .dma_started
;first bus cycle doesn't overlap
add R_65c816_Cycles,_5A22_SLOW_CYCLE
.dma_started:
DMAOPERATION 0,.early_out
DMAOPERATION 1,.early_out
DMAOPERATION 2,.early_out
DMAOPERATION 3,.early_out
DMAOPERATION 4,.early_out
DMAOPERATION 5,.early_out
DMAOPERATION 6,.early_out
DMAOPERATION 7,.early_out
.dma_done:
mov byte [CPU_Execution_Mode],CEM_Normal_Execution
SAVE_CYCLES
cmp byte [NMI_pin],NMI_Raised
jne .no_nmi
;setup NMI to execute after one opcode
mov edx,[FixedTrip]
mov [NMI_Next_Trip],edx
mov edx,[Fixed_Event]
mov [NMI_Next_Event],edx
mov edx,NMI_Event
mov [Fixed_Event],edx
mov [Event_Handler],edx
mov eax,[C_LABEL(SNES_Cycles)]
inc eax
mov [FixedTrip],eax
mov [C_LABEL(EventTrip)],eax
jmp CPU_START
.no_nmi:
mov byte [CPU_Execution_Mode],CEM_Instruction_After_IRQ_Enable
jmp CPU_START
.early_out:
SAVE_CYCLES
jmp dword [Event_Handler]
ALIGNC
EXPORT_C Do_CPU
pusha
mov byte [C_LABEL(PaletteChanged)],1 ; Make sure we get our palette
mov dword [C_LABEL(Last_Frame_Line)],239
%ifdef SINGLE_STEP
EXTERN_C set_gfx_mode
push byte 0
push byte 0
push byte 0
push byte 0
push byte -1
call _set_gfx_mode
add esp,20
%endif
call CPU_START
popa
ret
; Start of actual CPU execution core
; New for 0.25 - one CPU execution loop, also used for SPC
ALIGNC
EXPORT CPU_START_IRQ
call IRQ_Check_Newline
CPU_START:
LOAD_CYCLES
test R_Cycles,R_Cycles
jge .no_event_wait
.execute_opcode:
mov al,[CPU_Execution_Mode]
test al,al
jz .normal_execution
cmp al,CEM_In_DMA
je do_DMA
cmp al,CEM_Instruction_After_IRQ_Enable
je .instruction_after_irq_enable
xor R_Cycles,R_Cycles
;SAVE_CYCLES
mov edx,[C_LABEL(EventTrip)]
mov [C_LABEL(SNES_Cycles)],edx
.no_event_wait:
jmp dword [Event_Handler]
ALIGNC
.instruction_after_irq_enable:
;set up an event for immediately the next instruction
mov eax,IRQ_Enabled_Event
xor edx,edx
mov [Event_Handler],eax
mov [C_LABEL(EventTrip)],edx
.normal_execution:
LOAD_PC
LOAD_CYCLES
LOAD_BASE
xor eax,eax ; Zero for table offset
mov byte [In_CPU],-1
jmp C_LABEL(CPU_START_NEXT)
ALIGNC
EXPORT_C CPU_RETURN
%ifdef Abort_at_op_num
dec dword [MaxOps]
jz Op_0xDB ;STP
%endif
xor eax,eax ; Zero for table offset
test R_Cycles,R_Cycles
jge HANDLE_EVENT
EXPORT_C CPU_START_NEXT
; This code is for a CPU-tracker dump... #define TRACKERS to make a dump
; of the CPU state before each instruction - uncomment the ret to
; force emulation core to break when buffer fills. TRACKERS must be
; defined to the size of the buffer to be used - which must be a power
; of two, and the variables required by this and the write in Wangle()
; (main.cc) exist only if DEBUG and TRACKERS are also defined in main.cc
; and romload.cc.
%ifdef TRACKERS
%if TRACKERS >= 16
mov edx,[_LastIns] ;
add edx,[_InsAddress] ;
mov al,[CPU_LABEL(PB)] ;
mov [edx],al ;
SAVE_CYCLES ;
SAVE_PC eax ;
mov [1+edx],ah ;
mov [2+edx],al ;
mov al,[CPU_LABEL(B)] ;
mov [3+edx],al ;
mov al,[CPU_LABEL(A)] ;
mov [4+edx],al ;
mov al,[CPU_LABEL(XH)] ;
mov [5+edx],al ;
mov al,[CPU_LABEL(X)] ;
mov [6+edx],al ;
mov al,[CPU_LABEL(YH)] ;
mov [7+edx],al ;
mov al,[CPU_LABEL(Y)] ;
mov [8+edx],al ;
mov al,[CPU_LABEL(SH)] ;
mov [9+edx],al ;
mov al,[
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -