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

📄 timing.inc

📁 NES game Emulator in Linux.c and asm codes.
💻 INC
📖 第 1 页 / 共 3 页
字号:
 popa
%else
 RELATCH_HDMA
%endif

 Update_FPS_Counter

 pusha
 call C_LABEL(update_sound_block)
 popa

 xor eax,eax
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
EXPORT_C IRQFirstRender ; Check HDMA, IRQ, Render
section .data
.str:db " irqfirstrender ",0
section .text

 report_event

 mov dword [Last_Trip],0

;mov dword [C_LABEL(EventTrip)],CYCLES_DISPLAY_START
 mov dword [FixedTrip],CYCLES_DISPLAY_START
;mov dword [Event_Handler],Render_Event
 mov dword [Fixed_Event],Render_Event
 mov dword [Render_Next_Event],HDMA_Event
 mov dword [Render_Next_Trip],CYCLES_HDMA_START
 mov dword [HDMA_Next_Event],C_LABEL(IRQRender)

 Render_Start_Frame ; Reset framebuffer render address

 Update_Cycles

 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
EXPORT_C IRQRender  ; Check HDMA, IRQ, Render
section .data
.str:db " irqrender ",0
section .text

 report_event

 mov dword [Last_Trip],0

 Update_Cycles

;mov dword [C_LABEL(EventTrip)],CYCLES_DISPLAY_START
 mov dword [FixedTrip],CYCLES_DISPLAY_START
;mov dword [Event_Handler],Render_Event
 mov dword [Fixed_Event],Render_Event

 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 cmp [C_LABEL(LastRenderLine)],eax
 jbe .end_of_display
 jmp CPU_START_IRQ      ; Return to CPU
ALIGNC
.end_of_display:
 mov eax,[NMI_Event_Handler]
 mov [Render_Next_Event],eax
 mov dword [Render_Next_Trip],CYCLES_NEW_SCANLINE
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
VBL_Update_Controllers:
section .data
.str:db " update controllers ",0
section .text

 report_event

 mov dword [Last_Trip],0

 Update_Cycles

 mov eax,[C_LABEL(Current_Line_Timing)]
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 sub eax,[Vblank_Start]
 cmp eax,byte 3
 jb .no_controller_update

EXTERN_C update_controllers
 call C_LABEL(update_controllers)
 mov dword [Event_Handler],VBL
 mov dword [Fixed_Event],VBL
 and byte [HVBJOY],~HVBJOY_CONTROLLERS_BUSY ; Controllers ready
.no_controller_update:
 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
VBL:
section .data
.str:db " vblank ",0
section .text

 report_event

 mov dword [Last_Trip],0

 Update_Cycles

 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 cmp [C_LABEL(LastVBLLine)],eax ; Needs adjustment for odd line?
 ja .not_end_of_frame
 mov dword [Event_Handler],IRQNewFrame
 mov dword [Fixed_Event],IRQNewFrame
.not_end_of_frame:
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
EXPORT_C IRQFirst   ; Check HDMA, IRQ, Render
section .data
.str:db " irqfirst ",0
section .text

 report_event

 mov dword [Last_Trip],0

;mov dword [C_LABEL(EventTrip)],CYCLES_HDMA_START
 mov dword [FixedTrip],CYCLES_HDMA_START
;mov dword [Event_Handler],HDMA_Event
 mov dword [Fixed_Event],HDMA_Event
 mov dword [HDMA_Next_Event],IRQNoRender

 Render_Start_Frame_Skipped

 Update_Cycles

 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
IRQNoRender:            ; Check HDMA, IRQ
section .data
.str:db " irqnorender ",0
section .text

 report_event

 mov dword [Last_Trip],0

 Update_Cycles

 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 cmp [C_LABEL(LastRenderLine)],eax
 jbe .end_of_display
;mov dword [C_LABEL(EventTrip)],CYCLES_HDMA_START
 mov dword [FixedTrip],CYCLES_HDMA_START
;mov dword [Event_Handler],HDMA_Event
 mov dword [Fixed_Event],HDMA_Event
 jmp CPU_START_IRQ      ; Return to CPU
ALIGNC
.end_of_display:
 mov eax,[NMI_Event_Handler]
 mov [Event_Handler],eax
 mov [Fixed_Event],eax
 jmp CPU_START_IRQ      ; Return to CPU

ALIGNC
EXPORT_C NMI
 UpdateDisplay  ;*
 mov ax,[C_LABEL(Real_SNES_Palette)]
 push eax

 mov al,[C_LABEL(fixedpalettecheck)]
 test al,al
 jz .Do_Copy

.Fixed_Back_Color_Add_Hack:
 mov eax,[C_LABEL(COLDATA)]
%if 1
 push ebx
 mov bx,[C_LABEL(Real_SNES_Palette)]
 push ecx
 push edx
 mov ecx,((1<<5)+(1<<10)+(1<<15))
 mov edx,ebx

 ; get LSBs
 and edx,ecx
 and ebx,~((1<<5)+(1<<10)+(1<<15))
 and ecx,eax
 and eax,~((1<<5)+(1<<10)+(1<<15))
 ; add LSBs
 add ecx,edx
 mov edx,((2<<5)+(2<<10)+(2<<15))
 ; add colors
 add eax,ebx
 and edx,ecx
 mov ebx,((1<<5)+(1<<10)+(1<<15))
 add eax,edx
 and ecx,ebx
 and ebx,eax
 add eax,ecx
 ; Perform saturation

 ; save carry bits
 mov edx,ebx
 ; correct for carry/overflow into LSBs of adjacent color components
 sub eax,ebx
 shr edx,5      ; shift carry bits down to color LSBs
 neg edx        ; subtract from zero to get mask...
 add edx,ebx    ; add in carry bits to correct for borrows
 or eax,edx     ; apply saturation mask

.Add_Hack_End:
 pop edx
 pop ecx
 pop ebx
%endif
 mov [C_LABEL(Real_SNES_Palette)],ax

 mov byte [C_LABEL(PaletteChanged)],1

.Do_Copy:
 cmp byte [C_LABEL(FPS_ENABLED)],0
 jz .no_fps_counter
%ifndef SNEeSe_No_GUI
 call C_LABEL(ShowFPS)
%endif
.no_fps_counter:
 cmp byte [C_LABEL(BREAKS_ENABLED)],0
 jz .no_breaks_counter
%ifndef SNEeSe_No_GUI
 call C_LABEL(ShowBreaks)
%endif
.no_breaks_counter:
 mov dword [C_LABEL(BreaksLast)],0
%ifndef SINGLE_STEP
 call C_LABEL(Copy_Screen)
 mov eax,[C_LABEL(Current_Line_Render)]
 mov [C_LABEL(Last_Frame_Line)],eax
%endif
;call C_LABEL(Display_Debug)

 pop eax
 mov [C_LABEL(Real_SNES_Palette)],ax
EXPORT_C NMI_NoRender
section .data
.str:db " nmi_norender ",0
section .text

 report_event

 mov dword [Last_Trip],0

 mov dword [Event_Handler],VBL_Update_Controllers
 mov dword [Fixed_Event],VBL_Update_Controllers
 Update_Cycles

 mov al,[HVBJOY]
 ; VBlank on, controllers being read
 or al,HVBJOY_IN_VBLANK | HVBJOY_CONTROLLERS_BUSY
 mov [HVBJOY],al

 mov al,RDNMI_VBLANK_START | VERSION_NUMBER_5A22
 and al,[RDNMI_mask]    ; ensure only one vblank NMI per frame
 mov [RDNMI],al         ; Set NMI enabled bit in 0x4210

 mov eax,[C_LABEL(Current_Line_Timing)]
 inc eax
 mov [C_LABEL(Current_Line_Timing)],eax
 mov [Vblank_Start],eax
CheckNMI:
%ifdef DEBUG
 mov al,[CPU_LABEL(PB)]
 mov [C_LABEL(OLD_PB)],al   ; Save program bank
 mov eax,[CPU_LABEL(PC)]
 mov [C_LABEL(OLD_PC)],eax  ; Save program counter
%endif
 cmp byte [NMI_pin],NMI_Raised  ;NMI input raised previously?
 je .setup_nmi

 cmp byte [NMI_pin],NMI_Acknowledged
 jz .CHECK_KEYS

 test byte [RDNMI],RDNMI_VBLANK_START
 jz .CHECK_KEYS

 test byte [C_LABEL(NMITIMEN)],0x80
 jz .CHECK_KEYS         ; NMI off? (via hardware register)

 cmp byte [CPU_Execution_Mode],CEM_In_DMA
 je .CHECK_KEYS

 mov byte [NMI_pin],NMI_Raised          ;raise NMI input

.setup_nmi:
 ;setup chain to next timing event
 mov eax,[Fixed_Event]
 mov edx,[FixedTrip]
 mov [NMI_Next_Event],eax
 mov [NMI_Next_Trip],edx

 ;NMI executes after one opcode
 mov eax,[C_LABEL(SNES_Cycles)]
 inc eax
 mov [FixedTrip],eax
 mov [C_LABEL(EventTrip)],eax
 mov eax,NMI_Event
 mov [Fixed_Event],eax
 mov [Event_Handler],eax

.CHECK_KEYS:
 call C_LABEL(UPDATE_KEYS)
 test eax,eax
 jnz .break



; Return to emulation
 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 jmp CPU_START_IRQ      ; Return to CPU

.break:
 mov ebx,[CPU_LABEL(PB_Shifted)]
 mov bx,[CPU_LABEL(PC)]

 LOAD_CYCLES
 GET_BYTE
 mov [C_LABEL(Map_Byte)],al


 mov eax,[C_LABEL(Current_Line_Timing)] ; Get current scanline
 call IRQ_Check_Newline
 
.no_irq_check:
 ret


ALIGNC
NMI_Setup_Event:
section .data
.str:db " nmi setup ",0
section .text

 report_event

 ;NMI executes after one opcode
 mov eax,[C_LABEL(SNES_Cycles)]
 inc eax
 mov [FixedTrip],eax
 mov [C_LABEL(EventTrip)],eax
 mov eax,NMI_Event
 mov [Fixed_Event],eax
 mov [Event_Handler],eax

 jmp CPU_START.execute_opcode


ALIGNC
NMI_Event:
section .data
.str:db " nmi ",0
section .text

 report_event

 mov eax,[NMI_Next_Event]
 mov [Fixed_Event],eax
 mov eax,[NMI_Next_Trip]
 mov [FixedTrip],eax

 mov al,[CPU_Execution_Mode]
 cmp al,CEM_In_DMA
 je .no_nmi
 cmp al,CEM_Clock_Stopped
 je .no_nmi
 cmp al,CEM_Waiting_For_Interrupt
 jne .no_wai

%ifdef WAI_DELAY
 ; WAI delay after interrupt signal: 2 IO
 add dword [C_LABEL(SNES_Cycles)],byte 12   ;*
%endif

 inc word [CPU_LABEL(PC)]

 mov byte [CPU_Execution_Mode],CEM_Normal_Execution

.no_wai:
 mov byte [NMI_pin],NMI_Acknowledged    ;acknowledge NMI input

 push edi
 LOAD_BASE
 LOAD_CYCLES

 add R_65c816_Cycles,byte 12    ; NMI processing: 2 IO
 JUMP_NOT_FLAG SNES_FLAG_E,.E0_NMI      ; Are we in emulation mode?

.E1_NMI:
 ; Emulation mode NMI

 mov eax,[CPU_LABEL(PC)]
 E1_PUSH_W
;CLR_FLAG SNES_FLAG_B   ; Clear break bit on stack
 E1_SETUPFLAGS 0        ; put flags into SNES packed flag format
;SET_FLAG SNES_FLAG_B
 E1_PUSH_B

 mov ebx,0xFFFA         ; Get Emulation mode IRQ vector

 jmp .NMI_completion

ALIGNC
.E0_NMI:
 ; Native mode NMI

 mov al,[CPU_LABEL(PB)]
 E0_PUSH_B
 mov eax,[CPU_LABEL(PC)]
 E0_PUSH_W
 E0_SETUPFLAGS          ; put flags into SNES packed flag format
 E0_PUSH_B

 mov ebx,0xFFEA         ; Get Native mode IRQ vector
.NMI_completion:
 xor eax,eax
 GET_WORD
 mov [CPU_LABEL(PC)],eax    ; Setup PC vector
 mov byte [CPU_LABEL(PB)],0     ; Setup bank
;SET_FLAG SNES_FLAG_I   ; Disable IRQs
 STORE_FLAGS_I 1
;CLR_FLAG SNES_FLAG_D   ; Disable decimal mode
 STORE_FLAGS_D 0
 SAVE_CYCLES
 pop edi
.no_nmi:
 call IRQ_Check_Late    ; chain

 LOAD_CYCLES
 test R_Cycles,R_Cycles
 jl .no_chain
 jmp dword [Event_Handler]
.no_chain:

 jmp CPU_START  ; Return to CPU

ALIGNC
IRQ_Event:
section .data
.str:db " irq ",0
section .text

 report_event

 mov eax,[C_LABEL(EventTrip)]
 mov [Last_Trip],eax

 mov dh,0x80        ; Internal IRQ
 or [IRQ_pin],dh

 mov al,[CPU_Execution_Mode]
 cmp al,CEM_In_DMA
 je .no_irq
 cmp al,CEM_Clock_Stopped
 je .no_irq
 cmp al,CEM_Instruction_After_IRQ_Enable
 je .no_irq
 cmp al,CEM_Waiting_For_Interrupt
 jne .no_wai

%ifdef WAI_DELAY
 ; WAI delay after interrupt signal: 2 IO
 add dword [C_LABEL(SNES_Cycles)],byte 12   ;*
%endif

 inc word [CPU_LABEL(PC)]

 mov byte [CPU_Execution_Mode],CEM_Normal_Execution

.no_wai:
 push edi
 LOAD_BASE
 JUMP_FLAG SNES_FLAG_I,.irq_disabled    ; Interrupts disabled?
 LOAD_CYCLES
 add R_65c816_Cycles,byte 12    ; IRQ processing: 2 IO
 JUMP_NOT_FLAG SNES_FLAG_E,.native_irq
 call E1_IRQ
 jmp .irq_return
ALIGNC
.native_irq:
 call E0_IRQ
.irq_return:
 SAVE_CYCLES

.irq_disabled:
 pop edi

.no_irq:
 mov edi,[FixedTrip]
 mov ebx,[Fixed_Event]
 mov [C_LABEL(EventTrip)],edi
 mov [Event_Handler],ebx
 jmp CPU_START  ; Return to CPU

ALIGNC
IRQ_Check_Newline:
 mov bl,[C_LABEL(NMITIMEN)]

 mov edx,[FixedTrip]

 cmp byte [NMI_pin],NMI_Raised
 je .nmi_bypass

 test bl,0x30       ; IRQ enabled?
 jz .no_irq
 test bl,0x20       ; V-IRQ enabled?
 jz .no_virq
 mov ebx,[C_LABEL(Current_Line_Timing)]
 cmp [C_LABEL(VTIMEL)],ebx
 jne .no_irq
.no_virq:
 mov ebx,[HTimer]
 cmp edx,ebx
 jb .no_irq         ; Next static event is before IRQ?

 mov [C_LABEL(EventTrip)],ebx
 mov dword [Event_Handler],IRQ_Event
 ret

.nmi_bypass:
.no_irq:
 mov ebx,[Fixed_Event]
 mov [C_LABEL(EventTrip)],edx
 mov [Event_Handler],ebx
 ret


ALIGNC
; This can only trash ebx/edx!
IRQ_Check:
 SAVE_CYCLES edx
 cmp byte [NMI_pin],NMI_Raised
 je .nmi_bypass

 mov [Last_Trip],edx

 push edx
 mov bl,[C_LABEL(NMITIMEN)]

 mov edx,[FixedTrip]

 test bl,0x30       ; IRQ enabled?
 jz .no_irq
 test bl,0x20       ; V-IRQ enabled?
 jz .no_virq
 mov ebx,[C_LABEL(Current_Line_Timing)]
 cmp [C_LABEL(VTIMEL)],ebx
 jne .no_irq
.no_virq:
 mov ebx,[HTimer]
 cmp edx,ebx
 jb .no_irq         ; Next static event is before IRQ?
 cmp [esp],ebx      ; Check against current cycle
 jae .no_irq        ; Are we after the IRQ position?
 mov [C_LABEL(EventTrip)],ebx
 mov dword [Event_Handler],IRQ_Event
 jmp .fixup_timing

.nmi_bypass:
 mov edx,[FixedTrip]
.no_irq:
 mov ebx,[Fixed_Event]
 mov [C_LABEL(EventTrip)],edx
 mov [Event_Handler],ebx
.fixup_timing:
 LOAD_CYCLES edx
 pop edx
 ret


ALIGNC
; This can only trash ebx/edi!
IRQ_Check_Late:
 mov bl,[C_LABEL(NMITIMEN)]

 mov edi,[FixedTrip]

 cmp byte [NMI_pin],NMI_Raised
 je .nmi_bypass

 test bl,0x30       ; IRQ enabled?
 jz .no_irq
 test bl,0x20       ; V-IRQ enabled?
 jz .no_virq
 mov ebx,[C_LABEL(Current_Line_Timing)]
 cmp [C_LABEL(VTIMEL)],ebx
 jne .no_irq
.no_virq:
 mov ebx,[HTimer]
 cmp edi,ebx
 jb .no_irq         ; Next static event is before IRQ?
 cmp [Last_Trip],ebx    ; Check against last event trip cycle
 jae .no_irq        ; Are we after the IRQ?
 mov [C_LABEL(EventTrip)],ebx
 mov dword [Event_Handler],IRQ_Event
 ret

.nmi_bypass:
.no_irq:
 mov ebx,[Fixed_Event]
 mov [C_LABEL(EventTrip)],edi
 mov [Event_Handler],ebx
 ret

ALIGNC
EXPORT SNES_R2137 ; SLHV  ; This latches the counter for horizontal/vertical data!
 ;counters cannot be latched if I/O port bit 7 held low
 mov al,[C_LABEL(WRIO)]
 and al,[C_LABEL(RDIO)]
 jns .no_change

 push ebx
 GET_CYCLES ebx

 xor edx,edx

 ; Set up H counters to cycles executed / 4, V counter to current scanline

 ; All this below ensures bits 9-15 to be same as bits 1-7
 ; (open bus kludge)
 shr ebx,2
 mov al,0xFE
 cmp ebx,DOTS_BEFORE_REFRESH
 jb .before_refresh

⌨️ 快捷键说明

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