www.pudn.com > sn068s.zip > MODE7.ASM


 
; Mode 7 matrix rendering / hardware port emulation. 
 
%include "misc.ni" 
%include "sprites.ni" 
%include "screen.ni" 
%include "PPU.ni" 
 
section .text 
EXPORT_C mode7_start 
 
;%define old_sprites 
extern Ready_Line_Render,BaseDestPtr,_SNES_Screen8 
extern _MosaicLine 
extern Tile_priority_bit 
 
section .data 
ALIGND 
EXPORT M7_Handler_Table 
dd M7_REPEAT,M7_REPEAT_X,M7_REPEAT_Y,M7_REPEAT_XY 
dd M7_CLIP,M7_CLIP_X,M7_CLIP_Y,M7_CLIP_XY 
dd M7_CLIP,M7_CLIP_X,M7_CLIP_Y,M7_CLIP_XY 
dd M7_CHAR0,M7_CHAR0_X,M7_CHAR0_Y,M7_CHAR0_XY 
dd M7P_REPEAT,M7P_REPEAT_X,M7P_REPEAT_Y,M7P_REPEAT_XY 
dd M7P_CLIP,M7P_CLIP_X,M7P_CLIP_Y,M7P_CLIP_XY 
dd M7P_CLIP,M7P_CLIP_X,M7P_CLIP_Y,M7P_CLIP_XY 
dd M7P_CHAR0,M7P_CHAR0_X,M7P_CHAR0_Y,M7P_CHAR0_XY 
 
section .bss 
ALIGNB 
EXPORT Mode7_AHX,skipl  ; M7A * (BG1VOFS - M7X) + (M7X << 8) 
EXPORT Mode7_VY ,skipl  ; BG1VOFS - M7Y 
EXPORT Mode7_CHXY,skipl ; M7C * (BG1HOFS - M7X) + (M7Y << 8) 
 
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 
 
MPYL:   skipb   ; Mode 7 multiplication result: low byte 
MPYM:   skipb   ; Mode 7 multiplication result: middle byte 
MPYH:   skipb   ; Mode 7 multiplication result: high byte 
        skipb 
 
EXPORT M7_Handler,skipl 
EXPORT M7_Handler_EXTBG,skipl 
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 
 
%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 
 
section .text 
ALIGNC 
EXPORT SCREEN_MODE_7 
 
 push ebx 
 push edi 
 mov al,[_TM] 
 mov ah,[_TS] 
extern _Layer_Disable_Mask 
 and al,[_Layer_Disable_Mask] 
 and ah,[_Layer_Disable_Mask] 
 push ebp 
 push eax 
 
 mov eax,[SM7_Layers] 
 test al,3 
 jnz .background_main 
 
 ;Hack in sub screen mode 7 if it's enabled 
 and ah,3 
 jz .background_off 
 
 or al,ah 
 mov [SM7_Layers],al 
 
.background_main: 
 and eax,byte 1 
 jnz near .background_on 
 
 ; we only reach here when bit 0 clear, bit 1 set 
 test byte [_SETINI],0x40 
 jnz near .background_on 
.background_off: 
 
 mov edi,[_SNES_Screen8]    ; (256+16)*(240+1) framebuffer 
 ; Clear the framebuffer 
 mov ebx,[SM7_BaseDestPtr] 
 xor eax,eax 
 add edi,ebx 
 mov ebp,[SM7_Lines] 
 
 mov ecx,256/4 
 push es 
 mov edx,ds 
 mov es,edx 
 cld 
 
.background_off_clear_loop: 
 ; Load area to clear into cache 
 mov bl,[edi+0] 
 mov dl,[edi+16] 
 mov bl,[edi+32] 
 mov dl,[edi+48] 
 mov bl,[edi+64] 
 mov dl,[edi+80] 
 mov bl,[edi+96] 
 mov dl,[edi+112] 
 mov bl,[edi+128] 
 mov dl,[edi+144] 
 mov bl,[edi+160] 
 mov dl,[edi+176] 
 mov bl,[edi+192] 
 mov dl,[edi+208] 
 mov bl,[edi+224] 
 mov dl,[edi+240] 
 
 rep stosd 
 
 add edi,byte GfxBufferLineSlack    ; Point screen to next line 
 dec ebp 
 mov ecx,256/4 
 jnz .background_off_clear_loop 
 
 pop es 
 
 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 [_SETINI],0x40 
 jz %%no_plot 
 
 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,[_SNES_Screen8] 
 
%if %1 == 2 
 mov byte [Tile_priority_bit],0 
%else 
 mov byte [Tile_priority_bit],0x80 
%endif 
 
 ; Handle vertical mosaic 
 mov ebx,[SM7_Current_Line] 
 mov al,[MosaicBG1] 
 test al,al 
 jz %%no_mosaic 
 mov eax,[Mosaic_Size_Select] 
 mov bl,[_MosaicLine+ebx+eax] 
%%no_mosaic: 
 ; End vertical mosaic 
 
 mov ebp,256            ; Horizontal Count 
 
%if %1 == 1 
 test byte [_SETINI],0x40 
 jz %%no_extbg 
 
 test byte [SM7_Layers],2 
 jz %%no_extbg 
 
 call dword [M7_Handler_EXTBG] 
 jmp short %%no_plot 
 
%%no_extbg: 
 call dword [M7_Handler] 
%else 
 call dword [M7_Handler_EXTBG] 
%endif 
%%no_plot: 
%endmacro 
 
.background_on: 
 call Recalc_Mode7 
 
 jmp short .first_line 
 
.next_line: 
 inc dword [SM7_Current_Line] 
 
.first_line: 
 mov edi,[_SNES_Screen8]    ; (256+16)*(240+1) framebuffer 
 ; Clear the framebuffer 
 mov ebx,[SM7_BaseDestPtr] 
 xor eax,eax 
 add edi,ebx 
%if 0 
 mov ebp,[SM7_Lines] 
%endif 
 
 mov ecx,256/4 
 push es 
 mov edx,ds 
 mov es,edx 
 cld 
 
.clear_loop: 
 ; Load area to clear into cache 
 mov bl,[edi+0] 
 mov dl,[edi+16] 
 mov bl,[edi+32] 
 mov dl,[edi+48] 
 mov bl,[edi+64] 
 mov dl,[edi+80] 
 mov bl,[edi+96] 
 mov dl,[edi+112] 
 mov bl,[edi+128] 
 mov dl,[edi+144] 
 mov bl,[edi+160] 
 mov dl,[edi+176] 
 mov bl,[edi+192] 
 mov dl,[edi+208] 
 mov bl,[edi+224] 
 mov dl,[edi+240] 
 
 rep stosd 
 
%if 0 
 add edi,byte GfxBufferLineSlack    ; Point screen to next line 
 dec ebp 
 mov ecx,256/4 
 jnz .clear_loop 
%endif 
 
 pop es 
 
 Render_Mode7_Background 0 
 
 test dword [SM7_Layers],0x1010 
 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 dword [SM7_Layers],0x1010 
 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 dword [SM7_Layers],0x1010 
 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: 
 
 mov edi,[SM7_BaseDestPtr] 
 add edi,GfxBufferLinePitch 
 dec dword [SM7_Lines] 
 mov [SM7_BaseDestPtr],edi  ; Point screen to next line 
 jnz near SCREEN_MODE_7.next_line 
 
 add esp,byte SM7_Local_Bytes 
 ret 
 
Recalc_Mode7: 
 mov dl,[Redo_M7] 
 test dl,0xF5   ; Need to do any recalculating? 
 jz near .end_recalc 
 
 test dl,0xA0   ; Recalculate V or Y? 
 jz .end_recalc_vy 
 
 mov eax,[_BG1VOFS] 
 shl eax,(32 - 13) 
 mov edi,[_M7Y] 
 shl edi,(32 - 13) 
 sar eax,(32 - 13) 
 sar edi,(32 - 13) 
;mov [_M7V_13],eax 
 sub eax,edi 
 mov [_M7Y_13],edi 
 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,[_BG1HOFS] 
 shl eax,(32 - 13) 
 mov edi,[_M7X] 
 shl edi,(32 - 13) 
 sar eax,(32 - 13) 
 sar edi,(32 - 13) 
;mov [_M7H_13],eax 
 sub eax,edi 
;mov [_M7X_13],edi 
 
 test dl,0x51   ; Recalculate A, H, or X? 
 jz .recalc_c 
 
 push eax 
;mov ebx,[_M7X_13] 
 mov ebx,edi 
 imul eax,[_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,[_M7Y_13] 
 imul eax,[_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 = xflip, %3 = label, %4 = ylabel 
%macro M7_PROLOG 3 
ALIGNC 
%3: 
 xor ebx,-1 
 add ebx,262    ;* 
%2: 
%if %1 
 add edi,255 
%endif 
 mov eax,ebx 
 mov ecx,[Mode7_VY] 
 add eax,ecx 
 add ebx,ecx 
 imul eax,[_M7B] 
 imul ebx,[_M7D] 
 mov ecx,[Mode7_AHX] 
 mov edx,[Mode7_CHXY] 
 add eax,ecx 
 add ebx,edx 
 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 jmp short .first_pixel 
%endmacro 
 
;%1 = xflip, %2 = priority, %3 = label, %4 = ylabel 
%macro M7__REPEAT 4 
%%return: 
 ret 
 
M7_PROLOG %1,%3,%4 
 
.pixel_loop: 
 add eax,ecx 
 add ebx,edx 
.first_pixel: 
 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) & (0x3F8 >> 3) 
;ebx = (ebx >> 3) & (0x3F8 << 5) 
;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 %ax is X coord 0-1023, %bx is Y 0-1023 
 shr ecx,7 
 and eax,0x3F8 << 8 
 shr edx,4 
 and ebx,0x3F8 << 8 
 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,[_VRAM+eax+ebx] ; Got Tile Number 
 
 shl edx,7          ; Get offset to tile data 
 add edx,ecx        ; Add X+Y offset 
 
%if %2 
 mov cl,[Tile_priority_bit] 
 mov al,[_VRAM+edx+1] 
 xor cl,al 
 
 and al,0x7F 
%else 
 mov al,[_VRAM+edx+1] 
 test al,al 
%endif 
 jz .no_pixel 
 
%if %2 
 test cl,cl 
 jns .bad_priority 
%endif 
 
 mov [edi],al 
 
%if %2 
 mov [M7_Used],al 
%endif 
 
.no_pixel: 
 pop ebx 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz .pixel_loop 
 
 ret 
 
%if %2 
ALIGNC 
.bad_priority: 
 mov al,0xFF 
 pop ebx 
 mov [M7_Unused],al 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz near .pixel_loop 
 
 ret 
%endif 
 
%endmacro 
 
; New for v0.16, tile 0 repeat support 
;%1 = xflip, %2 = priority, %3 = label, %4 = ylabel 
%macro M7__CHAR0 4 
%%return: 
 ret 
 
M7_PROLOG %1,%3,%4 
 
.pixel_loop: 
 add eax,ecx 
 add ebx,edx 
.first_pixel: 
 
 cmp eax,0x3FFFF    ; If outside screen range we use tile 0 
 ja near .use_tile_0 
 cmp ebx,0x3FFFF 
 ja near .use_tile_0 
 
; Convert Screen X,Y location to SNES Pic location 
 
                ; Assumes %ax is X coord 0-1023, %bx is Y 0-1023 
 push eax 
 push ebx 
 
 mov ecx,eax 
 mov edx,ebx 
 
; Convert Screen X,Y location to SNES Pic location 
 
                ; Assumes %ax is X coord 0-1023, %bx is Y 0-1023 
 shr ecx,7 
 and eax,0x3F8 << 8 
 shr edx,4 
 and ebx,0x3F8 << 8 
 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,[_VRAM+eax+ebx] ; Got Tile Number 
     
 shl edx,7          ; Get offset to tile data 
 add edx,ecx        ; Add X+Y offset 
 
%if %2 
 mov cl,[Tile_priority_bit] 
 mov al,[_VRAM+edx+1] 
 xor cl,al 
 
 and al,0x7F 
%else 
 mov al,[_VRAM+edx+1] 
 test al,al 
%endif 
 jz .no_pixel 
 
%if %2 
 test cl,cl 
 jns .bad_priority 
%endif 
 
 mov [edi],al 
 
%if %2 
 mov [M7_Used],al 
%endif 
 
.no_pixel: 
 pop ebx 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz .pixel_loop 
 
 ret 
 
%if %2 
ALIGNC 
.bad_priority: 
 mov al,0xFF 
 pop ebx 
 mov [M7_Unused],al 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz near .pixel_loop 
 
 ret 
%endif 
 
ALIGNC 
.use_tile_0: 
 mov ecx,eax 
 mov edx,ebx 
 
; Convert Screen X,Y location to SNES Pic location 
 
                ; Assumes %ax is X coord 0-1023, %bx is Y 0-1023 
 shr ecx,7 
 shr edx,4 
 and ecx,byte 7 << 1    ; Get pixel shift within tile 
 and edx,byte 7 << 4 
 add edx,ecx    ; Add X+Y offsets together 
     
%if %2 
 mov cl,[Tile_priority_bit] 
 mov dl,[_VRAM+edx+1] 
 xor cl,dl 
 
 and dl,0x7F 
%else 
 mov dl,[_VRAM+edx+1] 
 test dl,dl 
%endif 
 jz .no_pixel_2 
 
%if %2 
 test cl,cl 
 jns .bad_priority 
%endif 
 
 mov [edi],dl 
 
%if %2 
 mov [M7_Used],dl 
%endif 
 
.no_pixel_2: 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz near .pixel_loop 
 
 ret 
 
%endmacro 
 
;%1 = xflip, %2 = priority, %3 = label, %4 = ylabel 
%macro M7__CLIP 4 
%%return: 
 ret 
 
M7_PROLOG %1,%3,%4 
 
.pixel_loop: 
 add eax,ecx 
 add ebx,edx 
.first_pixel: 
 
 cmp eax,0x3FFFF    ; If outside screen range we simply skip the pixel 
 ja near .pixel_covered 
 cmp ebx,0x3FFFF 
 ja near .pixel_covered 
 
; Convert Screen X,Y location to SNES Pic location 
 
                ; Assumes %ax is X coord 0-1023, %bx is Y 0-1023 
 push eax 
 push ebx 
 
 mov ecx,eax 
 mov edx,ebx 
 
; Convert Screen X,Y location to SNES Pic location 
 
                ; Assumes %ax is X coord 0-1023, %bx is Y 0-1023 
 shr ecx,7 
 and eax,0x3F8 << 8 
 shr edx,4 
 and ebx,0x3F8 << 8 
 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,[_VRAM+eax+ebx] ; Got Tile Number 
     
 shl edx,7          ; Get offset to tile data 
 add edx,ecx        ; Add X+Y offset 
 
%if %2 
 mov cl,[Tile_priority_bit] 
 mov al,[_VRAM+edx+1] 
 xor cl,al 
 
 and al,0x7F 
%else 
 mov al,[_VRAM+edx+1] 
 test al,al 
%endif 
 jz .no_pixel 
 
%if %2 
 test cl,cl 
 jns .bad_priority 
%endif 
 
 mov [edi],al 
 
%if %2 
 mov [M7_Used],al 
%endif 
 
.no_pixel: 
 pop ebx 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
%if %2 == 0 
.pixel_covered: 
%endif 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz .pixel_loop 
 
 ret 
 
%if %2 
ALIGNC 
.bad_priority: 
 mov al,0xFF 
 pop ebx 
 mov [M7_Unused],al 
 pop eax 
 mov ecx,[_M7A] 
 mov edx,[_M7C] 
 
.pixel_covered: 
 
%if %1 
 dec edi 
%else 
 inc edi 
%endif 
 
 dec ebp 
 jnz near .pixel_loop 
 
 ret 
%endif 
 
%endmacro 
 
M7__REPEAT 0, 0, M7_REPEAT, M7_REPEAT_Y 
M7__REPEAT 1, 0, M7_REPEAT_X, M7_REPEAT_XY 
M7__CHAR0  0, 0, M7_CHAR0, M7_CHAR0_Y 
M7__CHAR0  1, 0, M7_CHAR0_X, M7_CHAR0_XY 
M7__CLIP   0, 0, M7_CLIP, M7_CLIP_Y 
M7__CLIP   1, 0, M7_CLIP_X, M7_CLIP_XY 
 
M7__REPEAT 0, 1, M7P_REPEAT, M7P_REPEAT_Y 
M7__REPEAT 1, 1, M7P_REPEAT_X, M7P_REPEAT_XY 
M7__CHAR0  0, 1, M7P_CHAR0, M7P_CHAR0_Y 
M7__CHAR0  1, 1, M7P_CHAR0_X, M7P_CHAR0_XY 
M7__CLIP   0, 1, M7P_CLIP, M7P_CLIP_Y 
M7__CLIP   1, 1, M7P_CLIP_X, M7P_CLIP_XY 
 
ALIGNC 
EXPORT_C Reset_Mode_7 
 ; Set eax to 0, as we're setting most everything to 0... 
 xor eax,eax 
 
 mov [_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 [MPYL],eax 
 mov [_M7A],eax 
 mov [_M7B],eax 
 mov [_M7C],eax 
 mov [_M7D],eax 
 mov [_M7X_13],eax 
 mov [_M7Y_13],eax 
;mov [_M7H_13],eax 
;mov [_M7V_13],eax 
 mov [_M7X],eax 
 mov [_M7Y],eax 
 
 ret 
 
Do_16x8_Multiply: 
 push ebx 
 movsx ebx,byte [_M7B+1] 
 mov byte [Redo_16x8],0 
 imul ebx,[_M7A]    ; I think signed is used makes most sense! 
 mov [MPYL],ebx 
 mov al,[edi] 
 pop ebx 
 ret 
 
ALIGNC 
EXPORT SNES_R2134 ; MPYL 
 mov edi,MPYL 
 cmp byte [Redo_16x8],0 
 jnz Do_16x8_Multiply 
 mov al,[edi] 
 ret 
 
ALIGNC 
EXPORT SNES_R2135 ; MPYM 
 mov edi,MPYM 
 cmp byte [Redo_16x8],0 
 jnz Do_16x8_Multiply 
 mov al,[edi] 
 ret 
 
ALIGNC 
EXPORT SNES_R2136 ; MPYH 
 mov edi,MPYH 
 cmp byte [Redo_16x8],0 
 jnz Do_16x8_Multiply 
 mov al,[edi] 
 ret 
 
ALIGNC 
EXPORT SNES_W211A ; M7SEL   ; New for 0.12 
 cmp al,[_M7SEL] 
 je .no_change 
 SyncRender     ;* 
 push ebx 
 push eax 
 mov bl,al 
 mov [_M7SEL],al 
 shr ebx,4 
 and eax,3 
 and ebx,0x0C 
 add ebx,eax 
 mov eax,[M7_Handler_Table+ebx*4] 
 mov [M7_Handler],eax 
 mov ebx,[M7_Handler_Table+ebx*4+16*4] 
 pop eax 
 mov [M7_Handler_EXTBG],ebx 
 pop ebx 
 
.no_change: 
 ret 
 
ALIGNC 
EXPORT SNES_W211B ; M7A 
 SyncRender     ;*M7 
 ; Used for matrix render and 16-bit M7A * 8-bit = 24-bit multiply 
 push eax 
 mov ah,al 
 mov al,[_M7A+1] 
 cwde 
 mov [_M7A],eax 
 mov al,0x01    ; Recalculate A 
 or [Redo_M7],al 
 mov byte [Redo_16x8],-1 
 pop eax 
 ret 
 
ALIGNC 
EXPORT SNES_W211C ; M7B 
 SyncRender     ;*M7 
 ; Used for matrix render and 16-bit * 8-bit M7B high byte = 24-bit multiply 
 push eax 
 mov ah,al 
 mov al,[_M7B+1] 
 cwde 
 mov [_M7B],eax 
 mov al,0x02    ; Recalculate B 
 or [Redo_M7],al 
 mov byte [Redo_16x8],-1 
 pop eax 
 ret 
 
ALIGNC 
EXPORT SNES_W211D ; M7C 
 SyncRender     ;*M7 
 push eax 
 mov ah,al 
 mov al,[_M7C+1] 
 cwde 
 mov [_M7C],eax 
 mov al,0x04    ; Recalculate C 
 or [Redo_M7],al 
 pop eax 
 ret 
 
ALIGNC 
EXPORT SNES_W211E ; M7D 
 SyncRender     ;*M7 
 push eax 
 mov ah,al 
 mov al,[_M7D+1] 
 cwde 
 mov [_M7D],eax 
 mov al,0x08    ; Recalculate D 
 or [Redo_M7],al 
 pop eax 
 ret 
 
ALIGNC 
EXPORT SNES_W211F ; M7X 
 SyncRender     ;*M7 
 push eax 
 mov ah,al 
 mov al,[_M7X+1] 
 mov [_M7X],ax 
 
;shl eax,0x13 
;sar eax,0x13 
;mov [_M7X_13],eax 
 mov al,0x10    ; Recalculate X 
 or [Redo_M7],al 
 pop eax 
 ret 
 
ALIGNC 
EXPORT SNES_W2120 ; M7Y 
 SyncRender     ;*M7 
 push eax 
 mov ah,al 
 mov al,[_M7Y+1] 
 mov [_M7Y],ax 
 
;shl eax,0x13 
;sar eax,0x13 
;mov [_M7Y_13],eax 
 mov al,0x20    ; Recalculate Y 
 or [Redo_M7],al 
 pop eax 
 ret 
 
section .text 
ALIGNC 
section .data 
ALIGND 
section .bss 
ALIGNB