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

📄 timing.inc

📁 NES game Emulator in Linux.c and asm codes.
💻 INC
📖 第 1 页 / 共 3 页
字号:
 add ebx,DOTS_IN_REFRESH        ; Adjust for memory refresh cycles
.before_refresh:

 cmp ebx,DOTS_PER_SCANLINE
 jb .before_next_line
 sub ebx,DOTS_PER_SCANLINE
 inc edx            ; Adjust if we're on the next line
.before_next_line:

 and bh,1
 and al,bl
 or bh,al
 mov [Latched_H],ebx    ; Cycles / 4 = rough H counter

 mov ebx,[C_LABEL(Current_Line_Timing)]
 mov al,0xFE
 add ebx,edx        ; fixup for next line

 mov edx,[C_LABEL(LastVBLLine)]
 cmp ebx,edx
 jbe .before_next_frame
 sub ebx,edx        ; fixup for next frame
 dec ebx
.before_next_frame:

 and bh,1
 and al,bl
 or bh,al
 mov [Latched_V],ebx

 pop ebx
.no_change:
 mov al,0x21    ;open bus kludge
 ret

ALIGNC
EXPORT SNES_R213C ; OPHCT
 xor byte [OPHCT],1
 jz .return_high
 mov al,[Latched_H]
 ret
.return_high:
 mov al,[Latched_H+1]
 ret

ALIGNC
EXPORT SNES_R213D ; OPVCT
 xor byte [OPVCT],1
 jz .return_high
 mov al,[Latched_V]
 ret
.return_high:
 mov al,[Latched_V+1]
 ret

; Write to 40xx handlers
ALIGNC
EXPORT SNES_W4016 ; JOYC1
 test al,1
 jnz .no_ready_reset
 push eax
 mov al,[JOYC1]
 test al,1
 jz .no_reset
 mov al,16
 mov [C_LABEL(Controller1_Pos)],al
 mov [C_LABEL(Controller23_Pos)],al
 mov [C_LABEL(Controller45_Pos)],al
.no_reset:
 pop eax
.no_ready_reset:
 mov [JOYC1],al
 add R_65c816_Cycles,_5A22_LEGACY_CYCLE - _5A22_FAST_CYCLE
 ret

ALIGNC
EXPORT SNES_W4017 ; JOYC2
 add R_65c816_Cycles,_5A22_LEGACY_CYCLE - _5A22_FAST_CYCLE
 ret

; Read from 40xx handlers
%if 0
 SNEeSe 0.13, random speculation time, this register or at least bit 0
  handles input for controller 1

 v0.15 17th bit is an indication of joypad connected status

 $4016 is very similar in function (almost identical) to the register at
  the same address on the NES/Famicom

%endif

ALIGNC
EXPORT SNES_R4016 ; JOYC1
 test byte [JOYC1],1
 jz .read_enabled
 mov al,0

.fixup_read:
 ;merge in open bus bits
 mov dl,[C_LABEL(Last_Bus_Value_A)]
 and dl,JOYC1_OPEN_BUS_BITS

 or al,dl

 add R_65c816_Cycles,_5A22_LEGACY_CYCLE - _5A22_FAST_CYCLE
 ret

.read_enabled:
 push ecx
 push ebx
 cmp byte [C_LABEL(CONTROLLER_1_TYPE)],1    ; Is mouse plugged in?
 je .do_mouse

 mov cl,[C_LABEL(Controller1_Pos)]
 dec cl
 mov ebx,[C_LABEL(JOY1L)]
 mov [C_LABEL(Controller1_Pos)],cl
 ror ebx,cl
 mov al,1
 and al,bl
 pop ebx
 pop ecx
 jmp .fixup_read

.unused:
 mov byte [C_LABEL(Controller1_Pos)],16
 mov al,1           ; Joypad connected
 pop ebx
 pop ecx
 jmp .fixup_read

ALIGNC
.do_mouse:
 mov cl,[C_LABEL(Controller1_Pos)]
 dec cl
 and cl,0x0F
 mov [C_LABEL(Controller1_Pos)],cl
 mov bx,[C_LABEL(MickeyRead)]
 shr bx,cl
 mov al,1
 and al,bl
 pop ebx
 pop ecx
 jmp .fixup_read

ALIGNC
EXPORT SNES_R4017 ; JOYC2
 test byte [JOYC1],1
 jz .read_enabled
 mov al,0

.fixup_read:

 ;merge in open bus bits
 mov dl,[C_LABEL(Last_Bus_Value_A)]
 or al,JOYC2_ALWAYS_HIGH_BITS
 and dl,JOYC2_OPEN_BUS_BITS

 or al,dl

 add R_65c816_Cycles,_5A22_LEGACY_CYCLE - _5A22_FAST_CYCLE
 ret

.read_enabled:
 push ecx
 push ebx
 cmp byte [C_LABEL(CONTROLLER_2_TYPE)],1    ; Is mouse plugged in?
 je .do_mouse

 mov cl,[C_LABEL(Controller23_Pos)]
 dec cl
 mov ebx,[C_LABEL(JOY2L)]
 mov [C_LABEL(Controller23_Pos)],cl
 ror ebx,cl
 mov al,bl
 and al,1
 pop ebx
 pop ecx
 jmp .fixup_read

.unused:
 mov byte [C_LABEL(Controller23_Pos)],16
 mov al,1           ; (???) Return 0 this bit is for mtap I think
 pop ebx
 pop ecx
 jmp .fixup_read

ALIGNC
.do_mouse:
 mov cl,[C_LABEL(Controller23_Pos)]
 dec cl
 and cl,0x0F
 mov [C_LABEL(Controller23_Pos)],cl
 mov bx,[C_LABEL(MickeyRead)]
 shr bx,cl
 mov al,bl
 and al,1
 pop ebx
 pop ecx
 jmp .fixup_read


; Read from 42xx handlers
ALIGNC
EXPORT SNES_R4210 ; RDNMI
 mov al,[RDNMI]
 test al,al
 js .got_nmi_source

 mov edx,[C_LABEL(Current_Line_Timing)]
 cmp edx,[C_LABEL(LastRenderLine)]
 jb .no_reset

 test byte [RDNMI_mask],RDNMI_VBLANK_START
 jns .no_reset

 GET_CYCLES edx

 shr edx,2

 ;if we're on the next scanline, add 1 to the scanline count
 cmp edx,USABLE_DOTS_PER_SCANLINE       ;dot count excluding refresh period
 sbb edx,edx
;inc edx        ;don't add 1, as comparing against NMI line - 1

 add edx,[C_LABEL(Current_Line_Timing)]

 cmp edx,[C_LABEL(LastRenderLine)]
 jb .no_reset

 or al,RDNMI_VBLANK_START

.got_nmi_source:
 and al,[RDNMI_mask]    ; ensure only one NMI per frame
 jns .no_reset  ;RDNMI_VBLANK_START not set

 test byte [C_LABEL(NMITIMEN)],0x80
 jz .no_nmi             ; NMI masked off?

 cmp byte [NMI_pin],NMI_None
 jne .no_nmi

 mov byte [NMI_pin],NMI_Raised ;*NMI
 ; event should trigger after this opcode, triggering NMI
.no_nmi:

 mov byte [RDNMI],VERSION_NUMBER_5A22   ; clear NMI source
 mov byte [RDNMI_mask],0x7F
.no_reset:
 ;merge in open bus bits
 mov dl,[C_LABEL(Last_Bus_Value_A)]
 and dl,RDNMI_OPEN_BUS_BITS

 or al,dl
 ret

ALIGNC
EXPORT SNES_R4211 ; TIMEUP
 mov al,[IRQ_pin]
 and al,0x80
 jz .no_irq
 and byte [IRQ_pin],~0x80   ; Clear Internal IRQ
.no_irq:

 ;merge in open bus bits
 mov dl,[C_LABEL(Last_Bus_Value_A)]
 and dl,TIMEUP_OPEN_BUS_BITS

 or al,dl

 ret

ALIGNC
EXPORT SNES_R4212 ; HVBJOY
; Excerpts: Neill Corlett's "SNES Timing: The Brutal Truth" Version: 1.0b
;  <-22 dots-> <------------256 dots--------------> <-62 dots->
; 5. Something freaky
; -------------------
; On every scanline, starting at dot 128, the CPU appears to be frozen for 40
; master cycles.  DMA is also apparently frozen during this time.  This happens
; whether the scanline is visible or not, and whether HDMA is enabled or not.
;
; My current theory is that this time is used for refreshing RAM.
; *End excerpts*
 GET_CYCLES edx
 mov al,[HVBJOY]
 cmp edx,CYCLES_HBLANK_START    ; Hblank after display
 jae .hblank
 cmp edx,CYCLES_DISPLAY_START   ; Hblank before display
 jae .no_hblank
.hblank:
 or al,HVBJOY_IN_HBLANK ; We're in Hblank...
.no_hblank:

 ;merge in open bus bits
 mov dl,[C_LABEL(Last_Bus_Value_A)]
 and dl,HVBJOY_OPEN_BUS_BITS

 or al,dl
 ret

ALIGNC
EXPORT SNES_R4213 ; RDIO
 mov al,[C_LABEL(RDIO)]
 and al,[C_LABEL(WRIO)]
 ret

ALIGNC
EXPORT SNES_R4214 ; RDDIVL
 mov al,[RDDIVL]
 ret

ALIGNC
EXPORT SNES_R4215 ; RDDIVH
 mov al,[RDDIVH]
 ret

ALIGNC
EXPORT SNES_R4216 ; RDMPYL
 mov al,[RDMPYL]
 ret

ALIGNC
EXPORT SNES_R4217 ; RDMPYH
 mov al,[RDMPYH]
 ret

ALIGNC
EXPORT SNES_R4218 ; JOY1L
 cmp byte [C_LABEL(CONTROLLER_1_TYPE)],1    ; Is mouse plugged in?
 je .mouse
 mov al,[C_LABEL(JOY1L)]
 ret

.mouse:
 mov al,[C_LABEL(MouseButtons)]
 or al,0x01
 ret

ALIGNC
EXPORT SNES_R4219 ; JOY1H
 mov al,[C_LABEL(JOY1H)]
 ret

ALIGNC
EXPORT SNES_R421A ; JOY2L
 cmp byte [C_LABEL(CONTROLLER_2_TYPE)],1    ; Is mouse plugged in?
 je .mouse
 mov al,[C_LABEL(JOY2L)]
 ret

.mouse:
 mov al,[C_LABEL(MouseButtons)]
 or al,0x01
 ret

ALIGNC
EXPORT SNES_R421B ; JOY2H
 mov al,[C_LABEL(JOY2H)]
 ret

ALIGNC
EXPORT SNES_R421C ; JOY3L
 mov al,[C_LABEL(JOY3L)]
 ret

ALIGNC
EXPORT SNES_R421D ; JOY3H
 mov al,[C_LABEL(JOY3H)]
 ret

ALIGNC
EXPORT SNES_R421E ; JOY4L
 mov al,[C_LABEL(JOY4L)]
 ret

ALIGNC
EXPORT SNES_R421F ; JOY4H
 mov al,[C_LABEL(JOY4H)]
 ret

; Write to 42xx handlers
ALIGNC
EXPORT SNES_W4200 ; NMITIMEN
; a0yx000b  a=NMI on/off,y=vert count,x=horiz count,b=joy read
 cmp [C_LABEL(NMITIMEN)],al
 je .no_change

 push ebx
 mov bl,[C_LABEL(NMITIMEN)]
 xor bl,al
 mov [C_LABEL(NMITIMEN)],al
 jns .no_nmi_change

 test byte [RDNMI],RDNMI_VBLANK_START
 jz .no_nmi_change

.nmi_change:
 test al,0x80
 jnz .nmi_on
.nmi_off:
 mov byte [NMI_pin],NMI_None
 jmp .no_nmi_change

.nmi_on:
 mov byte [NMI_pin],NMI_Raised

 ;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_Setup_Event
 mov [Fixed_Event],edx
 mov [Event_Handler],edx
 SAVE_CYCLES edx
 mov [FixedTrip],edx
 mov [C_LABEL(EventTrip)],edx
 LOAD_CYCLES edx

.no_nmi_change:
 test bl,0x30
 jz .no_irq_change

 mov edx,eax
 shr edx,4
 sbb edx,edx
 and edx,[HTimer_Set]
 mov [HTimer],edx

 call IRQ_Check
.no_irq_change:
 pop ebx
.no_change:
 and byte [IRQ_pin],~0x80   ; Clear Internal IRQ
 ret

ALIGNC
EXPORT SNES_W4201 ; WRIO
 mov dl,[C_LABEL(WRIO)]
 xor dl,al
 mov [C_LABEL(WRIO)],al
 jns .no_latch

 call SNES_R2137

 mov al,[C_LABEL(WRIO)]
.no_latch:
 ret

ALIGNC
EXPORT SNES_W4202 ; WRMPYA
 mov [WRMPYA],al
 ret

ALIGNC
EXPORT SNES_W4203 ; WRMPYB
 push eax
 mov [WRMPYB],al
 mul byte [WRMPYA]  ; Do the multiplication
 mov [RDMPY],ax
 pop eax
 ret

ALIGNC
EXPORT SNES_W4204 ; WRDIVL
 mov [WRDIVL],al
 ret

ALIGNC
EXPORT SNES_W4205 ; WRDIVH
 mov [WRDIVH],al
 ret

ALIGNC
EXPORT SNES_W4206 ; WRDIVB
 push eax
 push ebx
;push edx
 test al,al
 jz .divide_by_zero
 xor ebx,ebx
 xor edx,edx    ; Divide uses DX:AX / BX
 mov bl,al
 mov ax,[WRDIV]
 div bx         ; Result is ax=quotient,dx=remainder
 mov [RDDIV],ax
 mov [RDMPY],dx
;pop edx
 pop ebx
 pop eax
 ret

.divide_by_zero:
 mov ax,[WRDIV]
 mov [RDMPY],ax
 mov word [RDDIV],0xFFFF
;pop edx
 pop ebx
 pop eax
 ret

Update_HTimer:
 cmp edx,DOTS_PER_SCANLINE
 jae .Invalid_HTimer

 shl edx,2

 ; Do some magic for the memory refresh 'missing' cycles
 cmp edx,CYCLES_REFRESH_START   ; Before memory refresh
 jb .not_in_refresh
 cmp edx,CYCLES_REFRESH_END     ; During memory refresh
 jb .in_refresh
 sub edx,byte CYCLES_IN_REFRESH
 jmp .not_in_refresh
ALIGNC
.in_refresh:
 mov edx,CYCLES_REFRESH_START   ; During memory refresh
.not_in_refresh:
 mov [HTimer_Set],edx
 test byte [C_LABEL(NMITIMEN)],0x10
 jz .no_change
 mov [HTimer],edx
 push ebx
 call IRQ_Check
 pop ebx
.no_change:
 ret

ALIGNC
.Invalid_HTimer:
 mov edx,-1
 jmp .not_in_refresh

ALIGNC
EXPORT SNES_W4207 ; HTIMEL
 mov edx,[C_LABEL(HTIMEL)]
 cmp al,dl
 je .no_change
 mov dl,al
 mov [C_LABEL(HTIMEL)],edx

 call Update_HTimer
.no_change:
 ret

ALIGNC
EXPORT SNES_W4208 ; HTIMEH
 push eax
 mov edx,[C_LABEL(HTIMEL)]
 and al,1
 cmp al,dh
 je .no_change
 mov dh,al
 mov [C_LABEL(HTIMEL)],edx

 call Update_HTimer

.no_change:
 pop eax
 ret

ALIGNC
EXPORT SNES_W4209 ; VTIMEL
 mov edx,[C_LABEL(VTIMEL)]
 cmp al,dl
 je .no_change
 mov [C_LABEL(VTIMEL)],al
 test byte [C_LABEL(NMITIMEN)],0x20
 jz .no_change
 push ebx
 call IRQ_Check
 pop ebx
.no_change:
 ret

ALIGNC
EXPORT SNES_W420A ; VTIMEH   ; Handled in screen core!
 push eax
 mov edx,[C_LABEL(VTIMEL)]
 and al,1
 cmp al,dh
 je .no_change
 mov [C_LABEL(VTIMEH)],al
 test byte [C_LABEL(NMITIMEN)],0x20
 jz .no_change
 push ebx
 call IRQ_Check
 pop ebx
.no_change:
 pop eax
 ret


ALIGNC
EXPORT SNES_W420B ; MDMAEN
 mov [C_LABEL(MDMAEN)],al

 test al,al
 jz .no_dma

 push ebx

 SAVE_CYCLES ebx

 ;setup event chain for DMA
 mov edx,[FixedTrip]

 mov [FixedTrip],ebx
 mov [C_LABEL(EventTrip)],ebx

 mov [DMA_Next_Trip],edx

 mov ebx,[Fixed_Event]
 mov edx,DMA_Event
 mov [DMA_Next_Event],ebx
 mov [Fixed_Event],edx
 mov [Event_Handler],edx

 LOAD_CYCLES edx

 pop ebx

.no_dma:
 ret


ALIGNC
EXPORT SNES_W420D ; MEMSEL    ; FastROM switch
 push eax
 push ecx
 push edx
 push eax
EXTERN_C set_upper_rom_speed
 call C_LABEL(set_upper_rom_speed)
 pop eax
 pop edx
 pop ecx
 pop eax
 ret

⌨️ 快捷键说明

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