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

📄 bg16om.asm

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

%define SNEeSe_ppu_bg16om_asm

%include "misc.inc"
%include "ppu/ppu.inc"
%include "ppu/tiles.inc"
%include "ppu/screen.inc"


%define RO16x16M_MAX_LINE_COUNT 8

%define RO16x16M_Local_Bytes 72+8+24
%define RO16x16M_Countdown esp+68+8+24
%define RO16x16M_Current_Line_Mosaic esp+64+8+24
%define RO16x16M_Plotter_Table esp+60+8+24
%define RO16x16M_Clipped esp+56+8+24
%define RO16x16M_BG_Table esp+52+8+24
%define RO16x16M_Current_Line esp+48+8+24
%define RO16x16M_BaseDestPtr esp+44+8+24
%define RO16x16M_Lines esp+40+8+24

; contains bit for determining planes to affect
%define RO16x16M_OC_Flag esp+36+8+24

; Same as LineAddress(Y), additional vars for offset change code
%define RO16x16M_LineAddressOffset  esp+32+8+24
%define RO16x16M_LineAddressOffsetY esp+28+8+24

%define RO16x16M_FirstTile esp+24+8+24

; Scroll-adjusted tile map address for offset
;  change code when tile offset not changed
%define RO16x16M_MapAddress_Current esp+20+8+24

; Current render line # for offset change layers
; Used for vertical mosaic effect
%define RO16x16M_Current_Line_Offset esp+16+8+24

%define RO16x16M_TMapAddress esp+12+8+24
%define RO16x16M_BMapAddress esp+8+8+24
%define RO16x16M_RMapDifference esp+4+8+24

%define RO16x16MR_LastRunCount esp+8+24

;Plotter table, adjusted for line count
%define RO16x16MR_Plotter_Table esp+4+24
;Line count for updating remaining lines and output pointer
%define RO16x16MR_LineCount esp+24

%define RO16x16M_Runs_Left esp+20
%define RO16x16M_Output esp+16
%define RO16x16M_RunListPtr esp+12
%define RO16x16MR_VMapOffset esp+8
;VMapOffset can be eliminated by merging its value with VL/VRMapAddress?

%define RO16x16MR_BG_Table RO16x16_BG_Table
%define RO16x16MR_Next_Pixel esp+4
%define RO16x16MR_Pixel_Count esp
%define RO16x16MR_Inner (4)
%define RO16x16M_Inner (8)

;VMapOffset = bg_line_offset (vscroll + current line) / bg tile size *
; 32 words (per line)
;Plotter = background plotting handler, passed:
; ebx = VRAM screen address of first tile
;  cl = tile count to plot
; edi = pointer to destination surface, leftmost pixel of first tile
;  (even if clipped)

 ; ebx = tile address offset from first tile on line
 ;  (nextpixel + (hscroll & 7)) / 8 * 2
 ; esi = offset screen map address of first offset-change capable tile
 ;  to be drawn
 ;  VLMapAddressBG3 + OffsetChangeMap_VOffset +
 ;   HScroll_3 / 8 * 2 - (ebx ? 2 : 0)
 ; cl = # tiles
 ; ch = offset-change enable bit

;BG_Table = pointer to background structure
;Next_Pixel = first pixel in run to be plotted
;     (local) hscroll-adjusted pixel to be plotted next (not always updated)
;Pixel_Count = count of pixels in run to be plotted
;edx = pointer to background structure (same as passed on stack)
;edi = native pointer to destination surface, start of first line
; to be drawn in output

%if 0
C-pseudo code
void Render_Offset_16x16M_Run
(BGTABLE *bgtable, UINT8 *output, int vmapoffset, int nextpixel,
 int numpixels,
 void (**plotter_table)(UINT16 *offset_screen_address, int tile_offset,
  UINT8 pixeloffset, UINT8 pixelcount, UINT8 *output))
)
{
 UINT16 *offset_screen_address;
 int clipped_count = Mosaic_Count[nextpixel];
 int tile_offset;

 output += nextpixel;

 nextpixel = Mosaic_Line[nextpixel];
 tile_offset = (nextpixel + (bgtable->hscroll & 7)) / 8;

 nextpixel += (bgtable->hscroll & 7) + bg3table.hscroll & 0xF8;
 if (nextpixel < 0x108)
 {
  offset_screen_address = (UINT16 *) (bg3table.vlmapaddress + vmapoffset +
   nextpixel / 8 * 2 - (tile_offset ? 2 : 0));
 }
 else
 {
  nextpixel -= 0x100;
  offset_screen_address = (UINT16 *) (bg3table.vrmapaddress + vmapoffset +
   nextpixel / 8 * 2 - (tile_offset ? 2 : 0));
 }

 nextpixel -= 8;

 if (clipped_count != Mosaic_Size)
 {
  ; left clipped

  plotter_table[(tile_offset ? 1 : 0](offset_screen_address, tile_offset,
   nextpixel & 7, min(numpixels, clipped_count), output);

  if (numpixels <= clipped_count) return;

  offset_screen_address += ((nextpixel & 7) + Mosaic_Size) >> 3;
  tile_offset += ((nextpixel & 7) + Mosaic_Size) >> 3;
  output += clipped_count;
  numpixels -= clipped_count;
  nextpixel += Mosaic_Size;
 }

 if (nextpixel <= 0xFF)
 {
  int count = min(numpixels, 255 - nextpixel + Mosaic_Count[255 - nextpixel];
  plotter (screen_address, nextpixel & 7, count, output);
  plotter_table[(tile_offset ? 1 : 0](offset_screen_address, tile_offset,
   nextpixel & 7, count, output);
 
  if (numpixels <= count) return;
 
  tile_offset += ((nextpixel & 7) + count) >> 3;
  output += count;
  numpixels -= count;
  nextpixel += count;
 }

 offset_screen_address = (UINT16 *) (bg3table.vrmapaddress + vmapoffset) +
  (nextpixel - 0x100) / 8;

 plotter_table[1](offset_screen_address, tile_offset,
  nextpixel & 7, numpixels, output);
}
%endif
ALIGNC
Render_Offset_16x16M_Run:
 mov ecx,[RO16x16MR_Next_Pixel+RO16x16MR_Inner]
 mov esi,[Mosaic_Size_Select]
 xor eax,eax
 add edi,ecx    ;first pixel
 mov al,[C_LABEL(MosaicCount)+ecx+esi]
 mov [RO16x16MR_LastRunCount+RO16x16MR_Inner],eax
 mov al,[C_LABEL(MosaicLine)+ecx+esi]
 mov ecx,[HScroll_3]

 mov ebx,[HScroll+edx]
 and ecx,0xF8
 and ebx,byte 7
 add ebx,eax
 add ecx,ebx

 mov eax,[VLMapAddressBG3]
 mov edx,[RO16x16MR_VMapOffset+RO16x16MR_Inner]
 cmp ecx,0x108
 jb .do_before_wrap
 sub ecx,0x100
 mov eax,[VRMapAddressBG3]
.do_before_wrap:

 shr ebx,3
 mov ebp,ecx
 add eax,edx

 shr ecx,3      ;(nextpixel / 8)
 add ebx,byte -1

 ;hscroll + first pixel, relative to screen of first tile to be plotted
 sbb edx,edx
 sub ebp,byte 8
 inc ebx
 and edx,byte 2
 add ebx,ebx
 lea esi,[eax+ecx*2]

 sub esi,edx
 mov ecx,[Mosaic_Size]
 add edx,edx
 mov eax,[RO16x16MR_LastRunCount+RO16x16MR_Inner]
 mov [RO16x16MR_Next_Pixel+RO16x16MR_Inner],ebp
 cmp eax,ecx
 jz .do_unclipped_before_wrap

 mov ecx,[RO16x16MR_Pixel_Count+RO16x16MR_Inner]
 and ebp,byte 7
 cmp ecx,eax

 ; left clipped
 jle .last_run

 sub ecx,eax
 mov [RO16x16MR_LastRunCount+RO16x16MR_Inner],ebp
 mov [RO16x16MR_Pixel_Count+RO16x16MR_Inner],ecx    ;count -= Mosaic_Count[nextpixel]

 mov ecx,eax

 mov eax,[RO16x16MR_Plotter_Table+RO16x16MR_Inner]
 call [eax+edx]

 mov eax,[Mosaic_Size]
 add [RO16x16MR_Next_Pixel+RO16x16MR_Inner],eax
 mov ebp,[RO16x16MR_LastRunCount+RO16x16MR_Inner]
 add eax,ebp

 shr eax,3
 add eax,eax
 add ebx,eax
 lea esi,[esi+eax-2]

 mov edx,4

.do_unclipped_before_wrap:
 mov eax,0xFF
 mov ebp,[RO16x16MR_Next_Pixel+RO16x16MR_Inner]
 sub eax,ebp
 jl .do_after_wrap
 jb .no_fixup

; int count = min(numpixels, 255 - nextpixel + Mosaic_Count[255 - nextpixel];
; plotter (screen_address, nextpixel & 7, count, output);
 mov ebp,[Mosaic_Size_Select]
 xor ecx,ecx
 mov cl,[C_LABEL(MosaicCount)+eax+ebp]
 mov ebp,[RO16x16MR_Next_Pixel+RO16x16MR_Inner]
 add eax,ecx

.no_fixup:
 mov ecx,[RO16x16MR_Pixel_Count+RO16x16MR_Inner]
 and ebp,byte 7
 cmp ecx,eax
 jle .last_run

 add [RO16x16MR_Next_Pixel+RO16x16MR_Inner],eax ;nextpixel += count
 sub ecx,eax
 mov [RO16x16MR_Pixel_Count+RO16x16MR_Inner],ecx    ;numpixels -= count
 mov ecx,eax

; if (numpixels <= 0) return;
; output += count;

 mov eax,[RO16x16MR_Plotter_Table+RO16x16MR_Inner]
 call [eax+edx]

 shr ebp,3
 add ebp,ebp
 add ebx,ebp

 mov ebp,[RO16x16MR_Next_Pixel+RO16x16MR_Inner]

.do_after_wrap:
 mov edx,0xFF
 and edx,ebp
 mov esi,[RO16x16MR_VMapOffset+RO16x16MR_Inner]
 shr edx,3
 and ebp,byte 7
 add edx,edx
 mov ecx,[RO16x16MR_Pixel_Count+RO16x16MR_Inner]
 add esi,edx
 mov edx,[VRMapAddressBG3]
 add esi,edx

 mov edx,4

.last_run:
 mov eax,[RO16x16MR_Plotter_Table+RO16x16MR_Inner]
 call [eax+edx]

 ret

; -Tile on left edge of screen not affected by V-offset change
; -Offset change map is scrollable - always 8x8

%macro Render_Offset_16x16M 1
ALIGNC
EXPORT_C Render_Offset_16x16M_C%1
%ifndef NO_NP_RENDER
 mov ecx,C_LABEL(Plot_Lines_NP_Offset_16x16M_Table_C%1)
 test al,al
 jnz .have_plotter
%endif

 mov ecx,C_LABEL(Plot_Lines_V_Offset_16x16M_Table_C%1)
.have_plotter:

 jmp Render_Offset_16x16M_Base
%endmacro

Render_Offset_16x16M 2
Render_Offset_16x16M 4
Render_Offset_16x16M 8

ALIGNC
Render_Offset_16x16M_Base:
 push dword [MosaicCountdown]
 push dword [LineCounter+edx]
 push ecx
 push esi
 push edx ;BG_Table
 push ebx ;Current_Line
 push edi ;BaseDestPtr
 push ebp ;Lines
 sub esp,byte RO16x16M_Local_Bytes-32

 ; ch contains bit for determining planes to affect
 mov ch,[OC_Flag+edx]
 mov eax,[SetAddress+edx]
 mov [RO16x16M_OC_Flag],ch
 mov [TilesetAddress],eax

.next_line:
 mov edx,[RO16x16M_BG_Table]

 mov eax,[RO16x16M_Current_Line_Mosaic]
;mov eax,[RO16x16M_Current_Line]
;mov ebx,[Mosaic_Size_Select]
;xor ecx,ecx
;mov cl,[C_LABEL(MosaicCount)+eax+ebx]
;mov al,[C_LABEL(MosaicLine)+eax+ebx]
;mov [RO16x16M_Current_Line_Offset],eax
;mov [RO16x16MR_LineCount],ecx
 call Sort_Screen_Height

 mov eax,[RO16x16M_Current_Line_Mosaic]
 SORT_TILES_16_TALL [RO16x16M_MapAddress_Current]

 ; Corrupts eax,ecx,ebp
 mov eax,[TLMapAddress+edx]
 mov ecx,[RO16x16M_Current_Line_Mosaic]
 mov edi,[BLMapAddress+edx]
 mov ebp,[VScroll+edx]
 mov [RO16x16M_TMapAddress],eax
 add ecx,ebp
 mov [RO16x16M_BMapAddress],edi
 mov ebp,[RO16x16M_MapAddress_Current]

 and ch,2
;global Tile_Height
;Tile_Height equ $-1    ; 1 = 8x8, 16x8, 2 = 16x16
 jz .current_line_in_screen_map_top
 mov eax,edi
.current_line_in_screen_map_top:
 add eax,ebp

 mov ebp,[HScroll+edx]
 mov [RO16x16M_MapAddress_Current],eax
 shr ebp,3
 mov eax,[TRMapAddress+edx]
 mov ecx,[TLMapAddress+edx]
 mov [RO16x16M_FirstTile],ebp   ;FirstTile = (HScroll / 8)

 sub eax,ecx
 mov [RO16x16M_RMapDifference],eax

 mov ecx,[RO16x16M_Countdown]
 test ecx,ecx
 jnz .no_reload
 mov ecx,[Mosaic_Size]
 mov [RO16x16M_Countdown],ecx
.no_reload:
 mov ebp,[RO16x16M_Lines]

 cmp ecx,ebp
 ja .no_multi
 mov ebp,ecx
.no_multi:
 cmp ebp,byte RO16x16M_MAX_LINE_COUNT
 jb .not_too_many
 mov ebp,RO16x16M_MAX_LINE_COUNT
.not_too_many:
 mov [RO16x16MR_LineCount],ebp

 mov ecx,[RO16x16M_Plotter_Table]
 lea eax,[ecx+ebp*8-8]
 mov [RO16x16MR_Plotter_Table],eax  ;renderer

 mov eax,[C_LABEL(SNES_Screen8)]
 mov edi,[RO16x16M_BaseDestPtr]
 add edi,eax

 mov esi,[RO16x16M_Clipped]
 mov al,[Win_Count+edx+esi]

 test al,al
 jz .done

 mov ebx,[OffsetChangeMap_VOffset]
 mov [RO16x16M_Runs_Left],eax
 lea edx,[Win_Bands+edx+esi]

 mov [RO16x16M_Output],edi
 mov [RO16x16M_RunListPtr],edx
 mov [RO16x16MR_VMapOffset],ebx ;vertical screen map address
 xor ebx,ebx
 mov bl,[edx]

 xor ecx,ecx
 mov cl,[edx+1]
 mov edx,[RO16x16M_BG_Table]
 sub cl,bl
 setz ch

 mov [RO16x16MR_Next_Pixel],ebx
 mov [RO16x16MR_Pixel_Count],ecx

 dec al
 je .last_run

.not_last_run:
 mov [RO16x16M_Runs_Left],al
 call Render_Offset_16x16M_Run

 mov edx,[RO16x16M_RunListPtr]
 mov edi,[RO16x16M_Output]
 xor ebx,ebx
 xor ecx,ecx
 mov bl,[edx+2]

 mov cl,[edx+3]
 add edx,byte 2
 sub cl,bl
 mov [RO16x16M_RunListPtr],edx
 mov edx,[RO16x16M_BG_Table]

 mov [RO16x16MR_Next_Pixel],ebx
 mov [RO16x16MR_Pixel_Count],ecx

 mov al,[RO16x16M_Runs_Left]
 dec al
 jne .not_last_run
.last_run:
 call Render_Offset_16x16M_Run

.done:

 mov ebp,[RO16x16MR_LineCount]

 mov eax,[RO16x16M_Current_Line]
 mov ecx,[RO16x16M_Lines]
 mov edx,[RO16x16M_Countdown]
 add eax,ebp
 sub edx,ebp
 jne .no_update_linecounter
 mov [RO16x16M_Current_Line_Mosaic],eax
.no_update_linecounter:
 mov edi,[RO16x16M_BaseDestPtr]
 mov [RO16x16M_Current_Line],eax
 mov eax,ebp
 mov [RO16x16M_Countdown],edx
 shl eax,8
 lea edx,[edi+ebp*GfxBufferLineSlack]
 add eax,edx
 sub ecx,ebp
 mov [RO16x16M_BaseDestPtr],eax
 mov [RO16x16M_Lines],ecx

%ifndef LAYERS_PER_LINE
;cmp dword [RO16x16M_Lines],0
 jnz .next_line
%endif

 mov edx,[RO16x16M_BG_Table]
 mov al,[Tile_Priority_Used]
 mov [Priority_Used+edx],al
 mov ah,[Tile_Priority_Unused]
 mov [Priority_Unused+edx],ah

 add esp,byte RO16x16M_Local_Bytes
 ret

;%1 = label, %2 = priority - 0 = none, 1 = low, 2 = high, %3 = lines
%macro Plot_Lines_Offset_16x16M_C4 3
ALIGNC
%if %2 > 0
%%wrong_priority_last:
%if %2 == 1 || %2 == 3
 mov [Tile_Priority_Unused],cl
%endif
 add edi,ecx
 add ebp,ecx
%%return:
 ret

ALIGNC
%1_check:
 pop ebp
 pop ebx
 pop esi

 mov eax,[Mosaic_Size]
%%wrong_priority_same_tile:
 cmp ecx,eax
 jbe %%wrong_priority_last
%if %2 == 1 || %2 == 3
 mov [Tile_Priority_Unused],al
%endif
 add edi,eax
 add ebp,eax
 sub ecx,eax

 cmp ebp,byte 8
 jb %%wrong_priority_same_tile
%endif

%%next_tile:
 mov eax,ebp
 and ebp,byte 7
 shr eax,3
 add ebx,eax        ; Update screen pointer
 lea esi,[esi+eax*2-2]

EXPORT_C %1     ; Define label, entry point
 lea eax,[esi+2]
 mov dh,[1+esi]     ; Offset change map
 push eax
 push ebx
 push ebp

 mov ebp,[RO16x16M_FirstTile+RO16x16M_Inner+12]
 mov eax,[OffsetChangeVMap_VOffset]
 test dh,[RO16x16M_OC_Flag+RO16x16M_Inner+12]   ; H-offset enabled?
 jz .have_h_offset
 mov dl,[esi]
 mov ebp,edx
 shr ebp,3
.have_h_offset:

 mov dh,[1+esi+eax] ; Vertical offset change map
 test dh,[RO16x16M_OC_Flag+RO16x16M_Inner+12]   ; V-offset enabled?
 jz .No_VChange
 mov dl,[esi+eax]
 mov eax,[RO16x16M_Current_Line_Offset+RO16x16M_Inner+12]
 add eax,edx

.calc_v_offset:
 and ah,2
 mov esi,[RO16x16M_TMapAddress+RO16x16M_Inner+12]
 jz .line_in_screen_map_top
 mov esi,[RO16x16M_BMapAddress+RO16x16M_Inner+12]
.line_in_screen_map_top:

 ; al contains real Y offset for next tile
 shl eax,2          ; Get screen offset
 push ecx
 mov ecx,0x1F0*4    ; Current line + V scroll * 32words
 and ecx,eax
 and eax,byte 0x0F*4    ; Offset into table of line offsets
 mov edx,16*8+7
 mov eax,[Tile_Offset_Table_16_8+eax]
 sub edx,eax
 add esi,ecx
 pop ecx
 jmp .have_v_offset

.LeftEdge:
 push esi
 push ebx
 push ebp

 mov ebp,[RO16x16M_FirstTile+RO16x16M_Inner+12]

.No_VChange:
 mov eax,[LineAddress]
 mov esi,[RO16x16M_MapAddress_Current+RO16x16M_Inner+12]
 mov edx,[LineAddressY]

.have_v_offset:
 add ebp,ebx
 mov [RO16x16M_LineAddressOffset+RO16x16M_Inner+12],eax
 mov ebx,ebp
 and ebp,byte 63    ; X offset wrap
 and ebx,byte 64
 mov [RO16x16M_LineAddressOffsetY+RO16x16M_Inner+12],edx
 mov ebx,[RO16x16M_RMapDifference+RO16x16M_Inner+12]
 jz  .tile_in_screen_map_left
 add esi,ebx
.tile_in_screen_map_left:
 mov ebx,ebp
 and ebp,byte ~1

 mov al,[esi+ebp+1] ; Combine X and Y offsets into tile map
 Check_Tile_Priority %2, %1_check

 mov si,[esi+ebp]   ; Get tile #
 mov ebp,[RO16x16M_LineAddressOffsetY+RO16x16M_Inner+12]
 test al,al         ; Check Y flip
 js .flip_y
 mov ebp,[RO16x16M_LineAddressOffset+RO16x16M_Inner+12]

.flip_y:
 shl esi,3
 mov edx,eax
 add esi,ebp
 and edx,byte 7*4   ; Get palette
 and ebx,byte 1
 add al,al      ; Get X flip (now in MSB)
 mov ebp,[TilesetAddress]
 mov edx,[palette_4bpl+edx]
 mov eax,[Mosaic_Size]
 js %%xflip

 lea esi,[esi+ebx*8]
 and esi,0x3FF * 8 + 7  ; Clip to tileset
 add esi,ebp
 and esi,0xFFFF * 2 / 8 ; Clip to VRAM

 pop ebp
 lea esi,[C_LABEL(TileCache4)+esi*8]

%%flip_none_same_tile:
 cmp ecx,eax
 ja %%flip_none_partial
 mov eax,ecx
%%flip_none_partial:
 mov bl,[esi+ebp]
%if %2 == 1 || %2 == 3
 mov [Tile_Priority_Used],al
%endif
 and bl,dl
 jz %%flip_none_empty_run

;eax = count, esi = source base, ebp = offset, edi = dest, ecx = # left
;edx = palette, bl = pixel
 add ebp,eax
 sub ecx,eax

%%flip_none_next_pixel:
%assign PLM16x16_Dest_Offset 0
%rep %3
 mov [edi+PLM16x16_Dest_Offset],bl
%assign PLM16x16_Dest_Offset (PLM16x16_Dest_Offset + GfxBufferLinePitch)
%endrep
%undef PLM16x16_Dest_Offset
 inc edi
 dec eax
 jnz %%flip_none_next_pixel

 mov eax,[Mosaic_Size]
 test ecx,ecx
 jz %%flip_none_return

 cmp ebp,byte 8
 jb %%flip_none_same_tile

 pop ebx
 pop esi
 jmp %%next_tile

%%flip_none_empty_run:
 add edi,eax

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -