📄 mode7.asm
字号:
sub ebp,ecx
push ebp
mov ebp,ecx
%endif
push eax
push ebx
;before:
;eax = X offset
;ebx = Y offset
;during:
;ecx = (eax >> 8) & 7
;edx = (ebx >> 8) & 7
;ecx = ecx + edx * 8
;eax = (eax >> 11) & 0x7F
;ebx = (ebx >> 3) & (0x7F << 8)
;eax = ebx + eax * 2
;after:
;eax = X tile
;ebx = Y tile
;ecx = X offset in tile
;edx = Y offset in tile
mov ecx,eax
mov edx,ebx
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, ebx is Y 0-1023
; Tile Position*128 (words) cos thats width of map
shr ebx,3
and eax,0x7F << 11
shr eax,10 ; Screen map X offset
and ebx,0x7F << 8 ; Screen map Y offset
shr edx,4
and ecx,7 << 8 ; Get pixel shift within tile
shr ecx,7
and edx,byte 7 << 4
add ecx,edx ; Add X+Y offsets together
mov dl,[C_LABEL(VRAM)+eax+ebx] ; Got Tile Number
shl edx,7 ; Get offset to tile data
%if %1
mov al,[Tile_priority_bit]
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
xor al,cl
and cl,0x7F
%else
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
test cl,cl
%endif
jz .no_pixel
%if %1
test al,al
jns .bad_priority
%endif
%if %2
.again:
mov [edi],cl
inc edi
dec ebp
jnz .again
%else
mov [edi],cl
%endif
%if %1
mov [M7_Used],cl
%endif
.no_pixel:
pop ebx
pop eax
%if %2
mov ecx,[esp+4]
add edi,ebp
pop ebp
test ebp,ebp
%else
mov ecx,[C_LABEL(M7A_X)]
inc edi
dec ebp
%endif
jnz .pixel_loop
%if %2
add esp,byte 4
%endif
ret
%if %1
ALIGNC
.bad_priority:
mov al,0xFF
pop ebx
mov [M7_Unused],al
pop eax
%if %2
mov ecx,[esp+4]
add edi,ebp
pop ebp
test ebp,ebp
%else
mov ecx,[C_LABEL(M7A_X)]
inc edi
dec ebp
%endif
jnz .pixel_loop
%if %2
add esp,byte 4
%endif
ret
%endif
%endmacro
; New for v0.16, tile 0 repeat support
;%1 = priority, %2 = mosaic
%macro M7_HANDLE_CHAR0 2
.pixel_loop:
add eax,ecx
add ebx,esi
.first_pixel:
%if %2
mov ecx,[Mosaic_Size]
.check_partial:
cmp ebp,ecx
ja .partial
mov ecx,ebp
.partial:
sub ebp,ecx
push ebp
mov ebp,ecx
%endif
cmp eax,0x3FFFF ; If outside screen range we use tile 0
ja .use_tile_0
cmp ebx,0x3FFFF
ja .use_tile_0
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, bbx is Y 0-1023
push eax
push ebx
mov ecx,eax
mov edx,ebx
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, ebx is Y 0-1023
shr ecx,7
and eax,0x7F << 11
shr edx,4
and ebx,0x7F << 11
shr eax,10 ; Get Tile Position (in 128 by 128 map)
and ecx,byte 7 << 1 ; Get pixel shift within tile
shr ebx,3 ; Tile Position*128 (words) cos thats width of map
and edx,byte 7 << 4
add ecx,edx ; Add X+Y offsets together
mov dl,[C_LABEL(VRAM)+eax+ebx] ; Got Tile Number
shl edx,7 ; Get offset to tile data
%if %1
mov al,[Tile_priority_bit]
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
xor al,cl
and cl,0x7F
%else
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
test cl,cl
%endif
jz .no_pixel
%if %1
test al,al
jns .bad_priority
%endif
%if %2
.again:
mov [edi],cl
inc edi
dec ebp
jnz .again
%else
mov [edi],cl
%endif
%if %1
mov [M7_Used],cl
%endif
.no_pixel:
pop ebx
pop eax
%if %2
mov ecx,[esp+4]
add edi,ebp
pop ebp
test ebp,ebp
jnz .pixel_loop
%else
mov ecx,[C_LABEL(M7A_X)]
inc edi
dec ebp
jnz .pixel_loop
%endif
%if %2
add esp,byte 4
%endif
ret
%if %1
ALIGNC
.bad_priority:
mov al,0xFF
pop ebx
mov [M7_Unused],al
pop eax
%if %2
mov ecx,[esp+4]
add edi,ebp
pop ebp
test ebp,ebp
%else
mov ecx,[C_LABEL(M7A_X)]
inc edi
dec ebp
%endif
jnz .pixel_loop
%if %2
add esp,byte 4
%endif
ret
%endif
ALIGNC
.use_tile_0:
mov ecx,eax
mov edx,ebx
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, ebx is Y 0-1023
shr ecx,7
and edx,7 << 8
shr edx,4
and ecx,byte 7 << 1 ; Get pixel shift within tile
%if %1
mov dl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
mov cl,[Tile_priority_bit]
xor cl,dl
and dl,0x7F
%else
mov dl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
test dl,dl
%endif
jz .no_pixel_2
%if %1
test cl,cl
jns .bad_priority
%endif
%if %2
.t0_again:
mov [edi],dl
inc edi
dec ebp
jnz .t0_again
%else
mov [edi],dl
%endif
%if %1
mov [M7_Used],dl
%endif
.no_pixel_2:
%if %2
mov ecx,[esp+4]
add edi,ebp
pop ebp
test ebp,ebp
%else
mov ecx,[C_LABEL(M7A_X)]
inc edi
dec ebp
%endif
jnz .pixel_loop
%if %2
add esp,byte 4
%endif
ret
%endmacro
;%1 = priority, %2 = mosaic
%macro M7_HANDLE_CLIP 2
.pixel_loop:
add eax,ecx
add ebx,esi
.first_pixel:
%if %2
mov ecx,[Mosaic_Size]
.check_partial:
cmp ebp,ecx
ja .partial
mov ecx,ebp
.partial:
sub ebp,ecx
push ebp
mov ebp,ecx
mov ecx,[esp+4]
%endif
cmp eax,0x3FFFF ; If outside screen range we simply skip the pixel
ja .pixel_covered
cmp ebx,0x3FFFF
ja .pixel_covered
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, ebx is Y 0-1023
push eax
push ebx
mov ecx,eax
mov edx,ebx
; Convert Screen X,Y location to SNES Pic location
; Assumes eax is X coord 0-1023, ebx is Y 0-1023
shr ecx,7
and eax,0x7F << 11
shr edx,4
and ebx,0x7F << 11
shr eax,10 ; Get Tile Position (in 128 by 128 map)
and ecx,byte 7 << 1 ; Get pixel shift within tile
shr ebx,3 ; Tile Position*128 (words) cos thats width of map
and edx,byte 7 << 4
add ecx,edx ; Add X+Y offsets together
mov dl,[C_LABEL(VRAM)+eax+ebx] ; Got Tile Number
shl edx,7 ; Get offset to tile data
%if %1
mov al,[Tile_priority_bit]
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
xor al,cl
and cl,0x7F
%else
mov cl,[C_LABEL(VRAM)+edx+ecx+1] ; Add X+Y offset
test cl,cl
%endif
jz .no_pixel
%if %1
test al,al
jns .bad_priority
%endif
%if %2
.again:
mov [edi],cl
inc edi
dec ebp
jnz .again
%else
mov [edi],cl
%endif
%if %1
mov [M7_Used],cl
%endif
.no_pixel:
pop ebx
pop eax
%if %2
mov ecx,[esp+4]
%else
mov ecx,[C_LABEL(M7A_X)]
%endif
%if %1 == 0
.pixel_covered:
%endif
%if %2
add edi,ebp
pop ebp
test ebp,ebp
jnz .pixel_loop
%else
inc edi
dec ebp
jnz .pixel_loop
%endif
%if %2
add esp,byte 4
%endif
ret
%if %1
ALIGNC
.bad_priority:
mov al,0xFF
pop ebx
mov [M7_Unused],al
pop eax
%if %2
mov ecx,[esp+4]
%else
mov ecx,[C_LABEL(M7A_X)]
%endif
.pixel_covered:
%if %2
add edi,ebp
pop ebp
test ebp,ebp
%else
inc edi
dec ebp
%endif
jnz .pixel_loop
%if %2
add esp,byte 4
%endif
ret
%endif
%endmacro
M7_Generate_Handlers REPEAT
M7_Generate_Handlers CHAR0
M7_Generate_Handlers CLIP
ALIGNC
EXPORT_C Reset_Mode_7
; Set eax to 0, as we're setting most everything to 0...
xor eax,eax
mov [C_LABEL(M7SEL)],al
mov byte [Redo_M7],0xFF
mov dword [M7_Handler],M7_REPEAT
mov dword [M7_Handler_EXTBG],M7P_REPEAT
mov byte [Redo_16x8],0
mov [MPY],eax
mov [C_LABEL(M7A)],eax
mov [C_LABEL(M7B)],eax
mov [C_LABEL(M7C)],eax
mov [C_LABEL(M7D)],eax
mov [C_LABEL(M7X_13)],eax
mov [C_LABEL(M7Y_13)],eax
;mov [C_LABEL(M7H_13)],eax
;mov [C_LABEL(M7V_13)],eax
mov [C_LABEL(M7X)],eax
mov [C_LABEL(M7Y)],eax
ret
Do_16x8_Multiply:
push ebx
movsx ebx,byte [C_LABEL(M7B)+1]
mov byte [Redo_16x8],0
imul ebx,[C_LABEL(M7A)] ; I think signed is used makes most sense!
mov [MPY],ebx
mov al,[edx]
pop ebx
ret
ALIGNC
EXPORT SNES_R2134 ; MPYL
mov edx,MPYL
cmp byte [Redo_16x8],0
jnz Do_16x8_Multiply
mov al,[edx]
ret
ALIGNC
EXPORT SNES_R2135 ; MPYM
mov edx,MPYM
cmp byte [Redo_16x8],0
jnz Do_16x8_Multiply
mov al,[edx]
ret
ALIGNC
EXPORT SNES_R2136 ; MPYH
mov edx,MPYH
cmp byte [Redo_16x8],0
jnz Do_16x8_Multiply
mov al,[edx]
ret
ALIGNC
EXPORT SNES_W211A ; M7SEL ; New for 0.12
cmp al,[C_LABEL(M7SEL)]
je .no_change
UpdateDisplay ;*
push ebx
push eax
mov [C_LABEL(M7SEL)],al
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 dl,[C_LABEL(M7SEL)]
mov [C_LABEL(M7A_X)],ebx
shr edx,6
mov [C_LABEL(M7C_X)],eax
and edx,3
mov eax,[M7_Handler_Table+edx*4]
mov [M7_Handler],eax
mov ebx,[M7_Handler_Table+edx*4+16]
pop eax
mov [M7_Handler_EXTBG],ebx
pop ebx
.no_change:
ret
ALIGNC
EXPORT SNES_W211B ; M7A
UpdateDisplay ;*M7
; Used for matrix render and 16-bit M7A * 8-bit = 24-bit multiply
push eax
mov ah,al
mov al,[C_LABEL(M7A)+1]
cwde
mov [C_LABEL(M7A)],eax
mov al,0x01 ; Recalculate A
or [Redo_M7],al
mov byte [Redo_16x8],-1
pop eax
ret
ALIGNC
EXPORT SNES_W211C ; M7B
UpdateDisplay ;*M7
; Used for matrix render and 16-bit * 8-bit M7B high byte = 24-bit multiply
push eax
mov ah,al
mov al,[C_LABEL(M7B)+1]
cwde
mov [C_LABEL(M7B)],eax
mov al,0x02 ; Recalculate B
or [Redo_M7],al
mov byte [Redo_16x8],-1
pop eax
ret
ALIGNC
EXPORT SNES_W211D ; M7C
UpdateDisplay ;*M7
push eax
mov ah,al
mov al,[C_LABEL(M7C)+1]
cwde
mov [C_LABEL(M7C)],eax
mov al,0x04 ; Recalculate C
or [Redo_M7],al
pop eax
ret
ALIGNC
EXPORT SNES_W211E ; M7D
UpdateDisplay ;*M7
push eax
mov ah,al
mov al,[C_LABEL(M7D)+1]
cwde
mov [C_LABEL(M7D)],eax
mov al,0x08 ; Recalculate D
or [Redo_M7],al
pop eax
ret
ALIGNC
EXPORT SNES_W211F ; M7X
UpdateDisplay ;*M7
push eax
mov ah,al
mov al,[C_LABEL(M7X)+1]
mov [C_LABEL(M7X)],ax
mov al,0x10 ; Recalculate X
or [Redo_M7],al
pop eax
ret
ALIGNC
EXPORT SNES_W2120 ; M7Y
UpdateDisplay ;*M7
push eax
mov ah,al
mov al,[C_LABEL(M7Y)+1]
mov [C_LABEL(M7Y)],ax
mov al,0x20 ; Recalculate Y
or [Redo_M7],al
pop eax
ret
section .text
ALIGNC
section .data
ALIGND
section .bss
ALIGNB
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -