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

📄 screen.asm

📁 NES game Emulator in Linux.c and asm codes.
💻 ASM
📖 第 1 页 / 共 3 页
字号:
 mov ecx,256/16
 jnz .clear_mmx_loop

 emms
 ret

ALIGNC
EXPORT_C Update_Display
 ; edx = number of lines to recache
 mov edx,[Ready_Line_Render]
 push eax
 sub edx,[C_LABEL(Current_Line_Render)]
 mov byte [Display_Needs_Update],0

 push ebx
 push ecx
 push edi
 push ebp
 push esi
 push edx

;handle mosaic - setup linecounters for first line drawn
%if 0
LineCounter_BG[no mosaic] = current_line
if (!MosaicCountdown)
{
 LineCounter_BG[mosaic] = current_line
}
%endif
 mov cl,[MosaicCountdown]
 mov al,[MOSAIC]
 mov ebx,[C_LABEL(Current_Line_Render)]
 add cl,255
 sbb cl,cl
 inc ebx
 and al,cl

 test al,1
 jnz .no_update_linecounter_bg1
 mov [LineCounter_BG1],ebx
.no_update_linecounter_bg1:
 test al,2
 jnz .no_update_linecounter_bg2
 mov [LineCounter_BG2],ebx
.no_update_linecounter_bg2:
 test al,4
 jnz .no_update_linecounter_bg3
 mov [LineCounter_BG3],ebx
.no_update_linecounter_bg3:
 test al,8
 jnz .no_update_linecounter_bg4
 mov [LineCounter_BG4],ebx
.no_update_linecounter_bg4:

 mov ah,[C_LABEL(INIDISP)]
 test ah,ah         ; Check for screen off
 js .screen_off

 cmp byte [Redo_Layering],0
 jz .no_layering_recalc_needed
 call C_LABEL(Update_Layering)
.no_layering_recalc_needed:

 xor eax,eax
 mov [Priority_Used_BG1],ax
 mov [Priority_Used_BG2],ax
 mov [Priority_Used_BG3],ax
 mov [Priority_Used_BG4],ax

%ifdef WATCH_RENDER_BREAKS
EXTERN_C BreaksLast
 inc dword [C_LABEL(BreaksLast)]
%endif

 mov al,[SCR_TM]
 mov bl,[BGMODE_Tile_Layer_Mask]
 or al,[SCR_TS]
 and al,bl
 mov [Tile_Layers_Enabled],al
 jz .no_tile_layers

 mov edi,[Tile_Recache_Set_End]
 inc edi
 js .no_tile_recache_needed ; No set to recache?
 sub edi,[Tile_Recache_Set_Begin]
 mov byte [Redo_Offset_Change],0xFF
 call Recache_Tile_Set
 mov edi,-2
 mov [Tile_Recache_Set_Begin],edi
 mov [Tile_Recache_Set_End],edi
.no_tile_recache_needed:

 test byte [Tile_Layers_Enabled],0x10
 jz .no_oam_recache_needed
 call C_LABEL(Check_OAM_Recache)
.no_oam_recache_needed:

 SORT_OFFSET_CHANGE

.no_tile_layers:

 cmp byte [Redo_Windowing],0
 jz .no_window_recalc_needed
 call C_LABEL(Recalc_Window_Effects)
.no_window_recalc_needed:

 mov ebx,[C_LABEL(Current_Line_Render)]
 mov edi,[BaseDestPtr]
 inc ebx
 mov ebp,[esp]

 call dword [Render_Select]

 pop edx
 mov ebx,[C_LABEL(Current_Line_Render)]
 add ebx,edx
 mov [C_LABEL(Current_Line_Render)],ebx

 mov al,[MOSAIC]
 test al,1
 jnz .mosaic_bg1
 mov [LineCounter_BG1],ebx
.mosaic_bg1:
 test al,2
 jnz .mosaic_bg2
 mov [LineCounter_BG2],ebx
.mosaic_bg2:
 test al,4
 jnz .mosaic_bg3
 mov [LineCounter_BG3],ebx
.mosaic_bg3:
 test al,8
 jnz .mosaic_bg4
 mov [LineCounter_BG4],ebx
.mosaic_bg4:

;if (countdown >= linecount) countdown -= linecount;
;else
;{
; line += countdown + MosaicLine[linecount - countdown - 1];
; countdown = MosaicCount[linecount - countdown];
; if (countdown == size) countdown = 0;
;}
 mov eax,[MosaicCountdown]
 mov ebp,eax
 sub eax,edx
 jge .mosaic_fixup_done

 mov esi,[Mosaic_Size_Select]
 xor eax,-1
 xor ecx,ecx
 xor ebx,ebx
 mov cl,[C_LABEL(MosaicCount)+esi+eax+1]  ;1
 mov bl,[C_LABEL(MosaicLine)+esi+eax+1-1] ;6c
 mov eax,[Mosaic_Size] ;1
 add ebx,ebp           ;6c
 cmp ecx,eax           ;
 sbb eax,eax
 and eax,ecx
.mosaic_fixup_done:
 mov [MosaicCountdown],eax

 mov al,[MOSAIC]
 mov ebx,[LineCounter_BG1]
 mov ecx,[LineCounter_BG2]
 mov esi,[LineCounter_BG3]
 mov edi,[LineCounter_BG4]

 test al,1
 jz .no_mosaic_bg1
 add [LineCounter_BG1],ebp
.no_mosaic_bg1:
 test al,2
 jz .no_mosaic_bg2
 add [LineCounter_BG2],ebp
.no_mosaic_bg2:
 test al,4
 jz .no_mosaic_bg3
 add [LineCounter_BG3],ebp
.no_mosaic_bg3:
 test al,8
 jz .no_mosaic_bg4
 add [LineCounter_BG4],ebp
.no_mosaic_bg4:

 pop esi
 pop ebp
 pop edi
 pop ecx
 pop ebx

 mov eax,GfxBufferLinePitch
 imul eax,edx
 add [BaseDestPtr],eax
 pop eax
.return:
 ret

ALIGNC
.screen_off:
 mov ebp,edx
 mov edi,[C_LABEL(SNES_Screen8)]    ; (256+16)*(239+1) framebuffer
 mov ebx,[BaseDestPtr]
 add edi,ebx

 ; Clear the framebuffer
 call C_LABEL(Clear_Scanlines)

 pop edx
 mov ebx,[C_LABEL(Current_Line_Render)]
 add ebx,edx
 mov [C_LABEL(Current_Line_Render)],ebx

 mov al,[MOSAIC]
 test al,1
 jnz .so_mosaic_bg1
 mov [LineCounter_BG1],ebx
.so_mosaic_bg1:
 test al,2
 jnz .so_mosaic_bg2
 mov [LineCounter_BG2],ebx
.so_mosaic_bg2:
 test al,4
 jnz .so_mosaic_bg3
 mov [LineCounter_BG3],ebx
.so_mosaic_bg3:
 test al,8
 jnz .so_mosaic_bg4
 mov [LineCounter_BG4],ebx
.so_mosaic_bg4:

;if (countdown >= linecount) countdown -= linecount;
;else
;{
; line += countdown + MosaicLine[linecount - countdown - 1];
; countdown = MosaicCount[linecount - countdown];
; if (countdown == size) countdown = 0;
;}
 mov eax,[MosaicCountdown]
 mov ebp,eax
 sub eax,edx
 jge .so_mosaic_fixup_done

 mov esi,[Mosaic_Size_Select]
 xor eax,-1
 xor ecx,ecx
 xor ebx,ebx
 mov ecx,[C_LABEL(MosaicCount)+esi+eax+1]
 mov ebx,[C_LABEL(MosaicLine)+esi+eax+1-1]
 mov eax,[Mosaic_Size]
 add ebx,ebp
 cmp ecx,eax
 sbb eax,eax
 and ecx,eax
 mov [MosaicCountdown],cl

 mov al,[MOSAIC]
 mov ebx,[LineCounter_BG1]
 mov ecx,[LineCounter_BG2]
 mov esi,[LineCounter_BG3]
 mov edi,[LineCounter_BG4]

 test al,1
 jz .so_no_mosaic_bg1
 add [LineCounter_BG1],ebp
.so_no_mosaic_bg1:
 test al,2
 jz .so_no_mosaic_bg2
 add [LineCounter_BG2],ebp
.so_no_mosaic_bg2:
 test al,4
 jz .so_no_mosaic_bg3
 add [LineCounter_BG3],ebp
.so_no_mosaic_bg3:
 test al,8
 jz .so_no_mosaic_bg4
 add [LineCounter_BG4],ebp
.so_no_mosaic_bg4:

.so_mosaic_fixup_done:
 mov [MosaicCountdown],eax

 pop esi
 pop ebp
 pop edi
 pop ecx
 pop ebx

 mov eax,GfxBufferLinePitch
 imul eax,edx
 add [BaseDestPtr],eax
 pop eax
 ret

; esi is screen address, works cos we only plot until wraparound!
; ch contains the X counter
; cl contains the screen addition for palette offsetting (2bpl only)
; edi is the address to draw to..
; LineAddress contains the location for the SNES tile data
; LineAddress(Y) must be offset to the correct line for that row
; LineAddressY is used for Y-flip

%if 0
 Mode 2 is a special snes mode - It is known as offset change mode,
  basically the snes has the ability to change the horizontal and/or
  vertical offset of each column on the screen, a pig to emulate but
  here is the information:

  BG1 & BG2 are 16 colour planes (this much was simple to find out)
  BG3 - This does not exist but its address in VRAM is very important!

  What happens is the horizontal and verticle information is written to
  BG2 address's BG2+0 -  BG2+63, this gives 128 bytes (since VRAM is a
  word addressed system). BG2+0 -  BG2+31 is the address for changing
  the horizontal value BG2+32 - BG2+63 is the address for changing the
  vertical value

  There are 32 values per BG mode since there are 32 tiles horizontally across the screen! My
  best guess is this value is immune to scrolling (otherwise it would make more sense to
  give a 64 tile range in case of extra width modes).

  Ok, the only other thing you need to know is what do the values at address BG2+x do.

  Well its the same for horiz as vertical the values are encoded as :

  00           | 01          | 02           | 03          |.......| 62            | 63
  col 0 offset | col 0 flags | col 1 offset | col 1 flags |.......| col 31 offset | col 31 flags

  The flags as far as I can tell are :

   bit 7 6 5 4 3 2 1 0
       ? y x ? ? ? ? ?		where	y = affect bg1
    				x = affect bg0

    			The above information came from me Savoury SnaX

Addendum by TRAC (0.33 -> 0.34)
 BG modes 2/4/6 have offset change support.
 Offset change info is always stored at address set via BG3SC ($2109)?

 Offset change info is stored one word per (width 8) tile, which appears
  to have the format of:

  FEDCBA9786543210
  421xxxoooooooooo

  4 = reserved in modes 2/6 - vertical select in mode 4
  o = offset
  1 = enable for first layer
  2 = enable for second layer

 The (width 8) tile on the left edge of a layer cannot have its offset
  changed. It will always use standard H/V scroll.

 The offset change map is used for the remaining width of the screen.
  The maximum number of displayed tiles is 33, and the leftmost tile is
  excluded, hence there is data in the table for 32 tiles.

 There are one or two sets of data for the scanline. Each set is 32 words
  (one word per tile). In BG modes 2 and 6 there are two: one for
  horizontal, followed by one for vertical. In BG mode 4, there is one,
  shared between horizontal and vertical.

 Mode 4 stores only one word of offset change data per tile - bit 15
  of a word entry determines if it is used for changing horizontal or
  vertical offset (set for vertical).

 When offset change is enabled for a tile, it replaces the standard offset
  (BG#HOFS, BG#VOFS) value for that tile (horizontal offset replaces
  BG#HOFS, vertical offset + 1 replaces BG#VOFS).

 The BG3 scroll registers move the offset change map. The scrolling is
  limited to increments of 8.

 ; word offset in offset change map of first offset change entry
 OffsetChangeMap_X = BG3HOFS >> 3;
 ; word offset in row in offset change map to use
 OffsetChangeMap_Y = (BG3VOFS >> 3) << 5;

 Note that the offset change map does wrap rows back to themselves like
  any other layer.

%endif

;Sets up VLMapAddress and VRMapAddress

;Uses mosaic setting, horizontal/vertical offsets, screen map size and
;current scanline
;eax = C_LABEL(Current_Line_Render)
ALIGNC
EXPORT Sort_Screen_Height_Mosaic
 Get_Current_Line
EXPORT Sort_Screen_Height
 ; Corrupts eax,ebx,ecx,esi
 mov bl,[HScroll+1+edx]
 mov ecx,TLMapAddress
 mov bh,[TileWidth+edx]     ; 1 = 8x8, 2 = 16x8, 16x16
 mov esi,TRMapAddress
 test bl,bh
 jz .first_tile_in_left_screen_map
 add ecx,byte (TRMapAddress-TLMapAddress)
 add esi,byte (TLMapAddress-TRMapAddress)
.first_tile_in_left_screen_map:
 mov bl,[TileHeight+edx]    ; 1 = 8x8, 16x8, 2 = 16x16
 add eax,[VScroll+edx]
 test ah,bl
 jz .line_in_top_screen_map

 mov eax,[edx+ecx+(BLMapAddress-TLMapAddress)]
 mov ebx,[edx+esi+(BLMapAddress-TLMapAddress)]
 mov [VRMapAddress+edx],ebx
 mov [VLMapAddress+edx],eax
 ret

ALIGNC
.line_in_top_screen_map:
 mov eax,[edx+ecx]
 mov ebx,[edx+esi]
 mov [VRMapAddress+edx],ebx
 mov [VLMapAddress+edx],eax
 ret

;%1 = planenum, 2 = priority
%macro RENDER_LINE 2
 LOAD_BG_TABLE %1

%if %2 == 0
 xor eax,eax
 mov [Tile_Priority_Used],ax
%else
 mov al,[Priority_Unused+edx]
 test al,al
 jz %%no_plot

 mov al,[Priority_Used+edx]
 cmp al,1
 sbb al,al
%endif

 ; set up depth
 mov byte [Tile_priority_bit],(1 - (%2)) << (13 - 8)

 ; tile size and depth selected in BGMODE write handler
 call dword [LineRender+edx]
%%no_plot:
%endmacro

;%1 = planenum
%macro RENDER_LINE_NP 1
 LOAD_BG_TABLE %1

 mov al,1
 ; tile size and depth selected in BGMODE write handler
 call dword [LineRender+edx]
%endmacro

%if 0
 Mode 0 - 4 background layers, 8x8 and 16x16 tile sizes
  2bpl tile depth in all layers
  special: each background layer has its own set of palettes

 Mode 1 - 3 background layers, 8x8 and 16x16 tile sizes
  4bpl tile depth in layers 1 and 2, 2bpl tile depth in layer 3
  special: BG3 high priority selection
%endif

%define SM01_Local_Bytes 20
%define SM01_Layers_Copy esp+16
%define SM01_Current_Line esp+12
%define SM01_BaseDestPtr esp+8
%define SM01_Lines esp+4
%define SM01_Layers esp

%macro Check_Present_Layer 2
 test byte %2,1 << ((%1)-1)
%endmacro

%macro Jump_Present_Layer 3
 Check_Present_Layer (%1),%2
 jnz (%3)
%endmacro

%macro Jump_Not_Present_Layer 3
 Check_Present_Layer (%1),%2
 jz (%3)
%endmacro

⌨️ 快捷键说明

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