📄 mode7.asm
字号:
%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
; Mode 7 matrix rendering / hardware port emulation.
%define SNEeSe_ppu_mode7_asm
%include "misc.inc"
%include "ppu/sprites.inc"
%include "ppu/screen.inc"
%include "ppu/ppu.inc"
section .text
EXPORT_C mode7_start
;%define old_sprites
EXTERN Ready_Line_Render,BaseDestPtr
EXTERN_C SNES_Screen8
EXTERN_C MosaicCount,MosaicLine
EXTERN Tile_priority_bit
section .data
ALIGND
EXPORT M7_Handler_Table
dd M7_REPEAT,M7_CLIP,M7_CLIP,M7_CHAR0
dd M7P_REPEAT,M7P_CLIP,M7P_CLIP,M7P_CHAR0
section .bss
ALIGNB
EXPORT Mode7_AHX,skipl ; M7A * (BG1HOFS - M7X) + (M7X << 8)
EXPORT Mode7_VY ,skipl ; BG1VOFS - M7Y
EXPORT Mode7_CHXY,skipl ; M7C * (BG1HOFS - M7X) + (M7Y << 8)
; M7A * (BG1HOFS - M7X) + (M7X << 8) + M7B * (line + BG1VOFS - M7Y)
EXPORT Mode7_Line_X,skipl
; M7C * (BG1HOFS - M7X) + (M7Y << 8) + M7D * (line + BG1VOFS - M7Y)
EXPORT Mode7_Line_Y,skipl
EXPORT_C M7A ,skipl
EXPORT_C M7B ,skipl
EXPORT_C M7C ,skipl
EXPORT_C M7D ,skipl
EXPORT_C M7X_13 ,skipl
EXPORT_C M7Y_13 ,skipl
EXPORT_C M7H_13 ,skipl
EXPORT_C M7V_13 ,skipl
EXPORT_C M7X ,skipl
EXPORT_C M7Y ,skipl
;M7A, M7C are taken from here to help handle X-flip
EXPORT_C M7A_X ,skipl
EXPORT_C M7C_X ,skipl
;M7A, M7C are taken from here to help handle X-flip and mosaic
EXPORT_C M7A_XM ,skipl
EXPORT_C M7C_XM ,skipl
MPY: skipl ; Mode 7 multiplication result
MPYL equ MPY ; Mode 7 multiplication result: low byte
MPYM equ MPY+1 ; Mode 7 multiplication result: middle byte
MPYH equ MPY+2 ; Mode 7 multiplication result: high byte
EXPORT M7_Handler,skipl
EXPORT M7_Handler_EXTBG,skipl
EXPORT_C EXTBG_Mask,skipb ; mask applied to BG enable for EXTBG
EXPORT_C M7SEL,skipb ; ab0000yx ab=mode 7 repetition info,y=flip vertical,x=flip horizontal
EXPORT Redo_M7,skipb ; vhyxdcba
M7_Used: skipb
M7_Unused: skipb
Redo_16x8: skipb
; BG1 area | BG2 area = displayed mode 7 background
; BG2 area = EXTBG, high priority
; BG1 area + BG2 area on main screen; both screens in 8-bit rendering
MERGED_WIN_DATA Mode7_Main,4
; BG1 area + BG2 area on sub screen (currently unused)
MERGED_WIN_DATA Mode7_Sub,4
;!BG1 area on main screen; both screens in 8-bit rendering
MERGED_WIN_DATA BG1_Main_Off,3
;!BG1 area on sub screen (currently unused)
MERGED_WIN_DATA BG1_Sub_Off,3
;!BG2 area on main screen; both screens in 8-bit rendering
MERGED_WIN_DATA BG2_Main_Off,3
;!BG2 area on sub screen (currently unused)
MERGED_WIN_DATA BG2_Sub_Off,3
;!BG1 area & BG2 area = EXTBG, low priority
;main screen; both in 8-bit
MERGED_WIN_DATA Mode7_Main_EXTBG_Low,3
;sub screen
MERGED_WIN_DATA Mode7_Sub_EXTBG_Low,3
; BG1 area & BG2 area = EXTBG, normal priority
;main screen; both in 8-bit
MERGED_WIN_DATA Mode7_Main_EXTBG_Normal,3
;sub screen
MERGED_WIN_DATA Mode7_Sub_EXTBG_Normal,3
; BG1 area & !BG2 area = no EXTBG
;main screen; both in 8-bit
MERGED_WIN_DATA Mode7_Main_EXTBG_Off,3
;sub screen
MERGED_WIN_DATA Mode7_Sub_EXTBG_Off,3
%define SM7_Local_Bytes 16
%define SM7_Current_Line esp+12
%define SM7_BaseDestPtr esp+8
%define SM7_Lines esp+4
%define SM7_Layers esp
; edx = address of window 1 bands
; esi = address of window 2 bands
; cl = count of window 1 bands
; ch = count of window 2 bands
; ebp = 0
; edi = address for output window area (BG_WIN_DATA)
section .text
ALIGNC
EXPORT_C SCREEN_MODE_7
push ebx
push edi
EXTERN_C Layer_Disable_Mask
and al,[C_LABEL(Layer_Disable_Mask)]
and ah,[C_LABEL(Layer_Disable_Mask)]
push ebp
; we don't have to worry about if EXTBG is disabled, as BG2
; will be masked off here if it is
; if SETINI:6 (EXTBG enable) is clear, ignore BG2 enable (EXTBG)
push eax
test eax,0x303
jnz .background_on
.background_off:
mov edi,[C_LABEL(SNES_Screen8)] ; (256+16)*(240+1) framebuffer
; Clear the framebuffer
mov ebx,[SM7_BaseDestPtr]
mov ebp,[SM7_Lines]
add edi,ebx
; Clear the framebuffer
call C_LABEL(Clear_Scanlines)
test dword [SM7_Layers],0x1010
jz .no_sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,[SM7_Lines]
;inc ebx
mov dl,0x00
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,[SM7_Lines]
;inc ebx
mov dl,0x10
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,[SM7_Lines]
;inc ebx
mov dl,0x20
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,[SM7_Lines]
;inc ebx
mov dl,0x30
call Plot_Sprites
.no_sprites:
add esp,byte SM7_Local_Bytes
ret
;%1 = priority (0 = low, 1 = low/none, 2 = high)
%macro Render_Mode7_Background 1
%if %1 == 2
test byte [SM7_Layers],2
jz %%no_plot
mov al,[M7_Unused]
test al,al
jz %%no_plot
%else
%if %1 == 0
test byte [SM7_Layers],1
jnz %%no_plot
%endif
%if %1 == 1
test byte [SM7_Layers],1
jz %%no_plot
%endif
mov al,0
mov [M7_Used],al
mov [M7_Unused],al
%endif
mov edi,[SM7_BaseDestPtr]
add edi,[C_LABEL(SNES_Screen8)]
%if %1 == 2
mov byte [Tile_priority_bit],0
%else
mov byte [Tile_priority_bit],0x80
%endif
mov ebp,256 ; Horizontal count
mov edx,0 ; First pixel
%if %1 == 1
mov al,[SM7_Layers]
test al,2
jz %%no_extbg
call dword [M7_Handler_EXTBG]
jmp %%no_plot
%%no_extbg:
;Window clipping likely affects EXTBG (TM/TS bit 1 'BG2')...
push edi
xor ebp,ebp
mov edi,C_LABEL(TableWinMode7_Main_EXTBG_Off)
mov edx,C_LABEL(TableWinMainBG1)
mov esi,C_LABEL(TableWinSubBG1)
mov al,[C_LABEL(TM)]
mov bl,[C_LABEL(TS)]
and al,1
jz %%no_merge_sub
and bl,al
jz %%no_merge_main
call C_LABEL(Intersect_Window_Area_OR)
mov esi,C_LABEL(TableWinMode7_Main_EXTBG_Off)
jmp %%got_bands
%%no_merge_main:
mov esi,edx
%%no_merge_sub:
%%got_bands:
mov al,[Win_Count+esi]
test al,al
jz .done
mov edi,[esp]
push eax
push esi
;mov [R8x8_Runs_Left],eax
;mov [R8x8_Output],edi
;mov [R8x8_RunListPtr],esi
xor edx,edx
;mov [R8x8R_Plotter],ecx ;renderer
mov dl,[Win_Bands+esi]
xor ecx,ecx
mov cl,[Win_Bands+esi+1]
sub cl,dl
setz ch
dec al
mov ebp,ecx
je .last_run
.not_last_run:
;mov [R8x8_Runs_Left],al
mov [esp+4],al
call dword [M7_Handler]
;mov esi,[R8x8_RunListPtr]
mov esi,[esp]
;mov edi,[R8x8_Output]
mov edi,[esp+8]
xor edx,edx
xor ecx,ecx
mov dl,[Win_Bands+esi+2]
mov cl,[Win_Bands+esi+3]
add esi,byte 2
sub cl,dl
;mov [R8x8_RunListPtr],esi
mov [esp],esi
mov ebp,ecx
;mov al,[R8x8_Runs_Left]
mov al,[esp+4]
dec al
jne .not_last_run
.last_run:
call dword [M7_Handler]
add esp,byte 8
.done:
add esp,byte 4
%else
call dword [M7_Handler_EXTBG]
%endif
%%no_plot:
%endmacro
.background_on:
and ah,3
or al,ah
mov [SM7_Layers],al
call Recalc_Mode7
jmp .first_line
.next_line:
inc dword [SM7_Current_Line]
.first_line:
mov edx,[SM7_Current_Line]
; Handle vertical mosaic
mov al,[MosaicBG1]
test al,al
jz .no_mosaic
mov eax,[Mosaic_Size_Select]
mov dl,[C_LABEL(MosaicLine)+edx+eax]
.no_mosaic:
; End vertical mosaic
mov al,[C_LABEL(M7SEL)]
test al,2
jz .no_flip_y
xor edx,-1
add edx,256
.no_flip_y:
mov ecx,[Mode7_VY]
mov ebx,[C_LABEL(M7B)]
add edx,ecx
imul ebx,edx
imul edx,[C_LABEL(M7D)]
mov ecx,[Mode7_AHX]
mov esi,[Mode7_CHXY]
add ebx,ecx
add edx,esi
test al,1
jz .no_flip_x
mov ecx,[C_LABEL(M7A)]
mov esi,[C_LABEL(M7C)]
sub ebx,ecx
sub edx,esi
shl ecx,8
shl esi,8
add ebx,ecx
add edx,esi
.no_flip_x:
mov [Mode7_Line_X],ebx
mov [Mode7_Line_Y],edx
mov edi,[C_LABEL(SNES_Screen8)] ; (256+16)*(240+1) framebuffer
; Clear the framebuffer
mov ebx,[SM7_BaseDestPtr]
mov ebp,1
add edi,ebx
; Clear the framebuffer
call C_LABEL(Clear_Scanlines_Preload)
Render_Mode7_Background 0
test byte [SM7_Layers],0x10
jz .no_sprites_0
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x00
call Plot_Sprites
.no_sprites_0:
Render_Mode7_Background 1
test byte [SM7_Layers],0x10
jz .no_sprites_1
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x10
call Plot_Sprites
.no_sprites_1:
Render_Mode7_Background 2
test byte [SM7_Layers],0x10
jz .no_sprites_23
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x20
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x30
call Plot_Sprites
.no_sprites_23:
test byte [SM7_Layers+1],0x10
jz .no_sprites_alt
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x00
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x10
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x20
call Plot_Sprites
mov ebx,[SM7_Current_Line]
mov edi,[SM7_BaseDestPtr]
mov ebp,1
;inc ebx
mov dl,0x30
call Plot_Sprites
.no_sprites_alt:
mov edi,[SM7_BaseDestPtr]
add edi,GfxBufferLinePitch
dec dword [SM7_Lines]
mov [SM7_BaseDestPtr],edi ; Point screen to next line
jnz C_LABEL(SCREEN_MODE_7).next_line
add esp,byte SM7_Local_Bytes
ret
%macro SIGN_EXTEND 2 ;reg,bits
and (%1),(1 << (%2)) - 1
xor (%1),1 << ((%2) - 1)
sub (%1),1 << ((%2) - 1)
%endmacro
%macro SIGN_EXTEND_ALT 4 ;reg,reg2,bits,bit
mov %2,%1
and %1,1 << (%4)
and %2,(1 << (%3)) - 1
xor %1,1 << (%4)
sar %1,(%4) - (%3)
sub %2,1 << (%3)
add %1,%2
%endmacro
Recalc_Mode7:
mov dl,[Redo_M7]
and dl,0x05 ; Need to do any recalculating?
jz .end_recalc_ac
mov al,[C_LABEL(M7SEL)]
shl al,8
mov ebx,[C_LABEL(M7A)]
mov eax,[C_LABEL(M7C)]
sbb edx,edx
xor ebx,edx
xor eax,edx
and edx,byte 1
add ebx,edx
add eax,edx
mov [C_LABEL(M7A_X)],ebx
mov [C_LABEL(M7C_X)],eax
mov dl,[MosaicBG1]
test dl,dl
jz .end_recalc_ac
imul ebx,[Mosaic_Size]
imul eax,[Mosaic_Size]
mov [C_LABEL(M7A_XM)],ebx
mov [C_LABEL(M7C_XM)],eax
.end_recalc_ac:
mov dl,[Redo_M7]
and dl,0xF5 ; Need to do any recalculating?
jz .end_recalc
test dl,0xA0 ; Recalculate V or Y?
jz .end_recalc_vy
mov eax,[C_LABEL(BG1VOFS)]
shl eax,(32 - 13)
mov edi,[C_LABEL(M7Y)]
shl edi,(32 - 13)
sar eax,(32 - 13)
sar edi,(32 - 13)
;mov [C_LABEL(M7V_13)],eax
sub eax,edi ;(V - Y)
mov [C_LABEL(M7Y_13)],edi
;there are only 11 significant result bits - a hidden sign bit (13) and the
;low 10 result bits
SIGN_EXTEND_ALT eax,ecx,10,13
mov [Mode7_VY],eax ;(V - Y)
.end_recalc_vy:
test dl,0x75 ; Recalculate A, C, H, X, or Y?
jz .end_recalc
;test dl,0x50 ; Recalculate H or X?
;jnz .recalc_hx
mov eax,[C_LABEL(BG1HOFS)]
shl eax,(32 - 13)
mov edi,[C_LABEL(M7X)]
shl edi,(32 - 13)
sar eax,(32 - 13)
sar edi,(32 - 13)
;mov [C_LABEL(M7H_13)],eax
sub eax,edi ;(H - X)
;mov [C_LABEL(M7X_13)],edi
;there are only 11 significant result bits - a hidden sign bit (13) and the
;low 10 result bits
SIGN_EXTEND_ALT eax,ecx,10,13
test dl,0x51 ; Recalculate A, H, or X?
jz .recalc_c
push eax
;mov ebx,[C_LABEL(M7X_13)]
mov ebx,edi
imul eax,[C_LABEL(M7A)]
shl ebx,8
add eax,ebx
mov [Mode7_AHX],eax ;A * (H - X) + (X << 8)
pop eax
test dl,0x74 ; Recalculate C, H, X, or Y?
jz .end_recalc
.recalc_c:
mov ebx,[C_LABEL(M7Y_13)]
imul eax,[C_LABEL(M7C)]
shl ebx,8
add eax,ebx
mov [Mode7_CHXY],eax ;C * (H - X) + (Y << 8)
.end_recalc:
mov byte [Redo_M7],0 ; Done with recalculating
ret
;%1 = mode, %2 = priority, %3 = label
%macro M7_Generate_Handler 3
ALIGNC
%3:
mov eax,[Mode7_Line_X]
mov ebx,[Mode7_Line_Y]
mov cl,[MosaicBG1]
add edi,edx
test cl,cl
jnz %3_Mosaic
mov ecx,[C_LABEL(M7A_X)]
imul ecx,edx
imul edx,[C_LABEL(M7C_X)]
add eax,ecx
add ebx,edx
mov ecx,[C_LABEL(M7A_X)]
mov esi,[C_LABEL(M7C_X)]
jmp .first_pixel
M7_HANDLE_%1 %2,0
ALIGNC
%3_Mosaic:
mov esi,[Mosaic_Size_Select]
xor ecx,ecx
mov cl,[C_LABEL(MosaicLine)+edx+esi]
mov dl,[C_LABEL(MosaicCount)+edx+esi]
mov esi,[C_LABEL(M7A_X)]
imul esi,ecx
imul ecx,[C_LABEL(M7C_X)]
add eax,esi
add ebx,ecx
mov ecx,[C_LABEL(M7A_XM)]
mov esi,[C_LABEL(M7C_XM)]
push ecx
mov ecx,edx
jmp .check_partial
M7_HANDLE_%1 %2,1
%endmacro
;%1 = mode
%macro M7_Generate_Handlers 1
;No priority
M7_Generate_Handler %1, 0, M7_%1
;EXTBG
M7_Generate_Handler %1, 1, M7P_%1
%endmacro
;ebp = pixel count
;eax,ebx = X,Y
;X + M7A, Y + M7C
;%1 = priority, %2 = mosaic
%macro M7_HANDLE_REPEAT 2
.pixel_loop:
add eax,ecx
add ebx,esi
.first_pixel:
%if %2
;ecx = max repetition count of first pixel from MosaicSize lookup
mov ecx,[Mosaic_Size]
.check_partial:
cmp ebp,ecx
ja .partial
mov ecx,ebp
.partial:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -