📄 timing.inc
字号:
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 + -