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

📄 mode7.asm

📁 NES game Emulator in Linux.c and asm codes.
💻 ASM
📖 第 1 页 / 共 2 页
字号:
 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 + -