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

📄 sprites.asm

📁 NES game Emulator in Linux.c and asm codes.
💻 ASM
📖 第 1 页 / 共 3 页
字号:
 cmp ebp,256*8
 mov edi,[C_LABEL(OBNAME)]
 jae .name
 mov edi,[C_LABEL(OBBASE)]
.name:
 and eax,0x3FFFF
 add ebp,edi
 shl ebp,18
 or eax,ebp

 pop ebp
 ;eax = prepared tile descriptor

 mov [edx],eax
 sub al,byte 8
 sub ebp,byte 8
 add edx,byte 4

 dec ch
 jnz .next_tile

 sub edx,34*4
 add ch,cl
 mov cl,0
 jnz .next_tile

 ret

ALIGNC
;ebp -= (count - 1) * 8; al += (count - 1) * 8;
EXPORT_C Add_Sprite_X_Positive_Flip_X
 xor ebx,ebx
 mov bl,ch
 add bl,cl
 dec bl
 shl ebx,3
 add al,bl
;sub ebp,ebx
.next_tile:
 ; compute tile line #'s and store line descriptors
 push ebp
 and ebp,511*8+7
 cmp ebp,256*8
 mov edi,[C_LABEL(OBNAME)]
 jae .name
 mov edi,[C_LABEL(OBBASE)]
.name:
 and eax,0x3FFFF
 add ebp,edi
 shl ebp,18
 or eax,ebp

 pop ebp
 ;eax = prepared tile descriptor

 mov [edx],eax
 sub al,byte 8
 add ebp,byte 8
 add edx,byte 4

 dec ch
 jnz .next_tile

 sub edx,34*4
 add ch,cl
 mov cl,0
 jnz .next_tile

 ret

ALIGNC
;ebp += (count - 1) * 8; al += (count - 1) * 8;
;if al < ((count - 1) * 8) ah ^= 1;
EXPORT_C Add_Sprite_X_Negative_Flip_None
.next_tile:
 ; compute tile line #'s and store line descriptors
 push ebp
 and ebp,511*8+7
 cmp ebp,256*8
 mov edi,[C_LABEL(OBNAME)]
 jae .name
 mov edi,[C_LABEL(OBBASE)]
.name:
 and eax,0x3FFFF
 add ebp,edi
 shl ebp,18
 or eax,ebp

 pop ebp
 ;eax = prepared tile descriptor

 mov [edx],eax
 sub al,byte 8
 jnc .no_carry
 xor ah,1

.no_carry:
 sub ebp,byte 8
 add edx,byte 4

 dec ch
 jnz .next_tile

 sub edx,34*4
 add ch,cl
 mov cl,0
 jnz .next_tile

 ret

ALIGNC
;ebp -= (count - 1) * 8; al += (count - 1) * 8;
;if al < ((count - 1) * 8) ah ^= 1;
EXPORT_C Add_Sprite_X_Negative_Flip_X
.next_tile:
 ; compute tile line #'s and store line descriptors
 push ebp
 and ebp,511*8+7
 cmp ebp,256*8
 mov edi,[C_LABEL(OBNAME)]
 jae .name
 mov edi,[C_LABEL(OBBASE)]
.name:
 and eax,0x3FFFF
 add ebp,edi
 shl ebp,18
 or eax,ebp

 pop ebp
 ;eax = prepared tile descriptor

 mov [edx],eax
 sub al,byte 8
 jnc .no_carry
 xor ah,1

.no_carry:
 add ebp,byte 8
 add edx,byte 4

 dec ch
 jnz .next_tile

 sub edx,34*4
 add ch,cl
 mov cl,0
 jnz .next_tile

 ret

ALIGNC
EXPORT_C Check_OAM_Recache
 ;if priority rotation is off, treat OAM address as 0
 xor eax,eax
 mov al,[SPRLatch]
 mov ebx,[C_LABEL(OAMAddress)]
 sar al,7
 and ebx,eax

 ;convert address to OBJ #
 shr ebx,byte 1
 cmp [C_LABEL(HiSprite)],bl
 jne .priority_update

 mov al,[Redo_OAM]
 test al,al
 jnz C_LABEL(Recache_OAM)

 ret

.priority_update:
 mov [C_LABEL(HiSprite)],bl
 shl ebx,2
;sub ebx,byte 4
;and ebx,0x1FC
 mov [C_LABEL(HiSpriteAddr)],ebx
 shr ebx,4
 add ebx,0x200
 mov [C_LABEL(HiSpriteBits)],ebx
 mov bl,[C_LABEL(HiSprite)]
 mov bh,128
 mov [C_LABEL(HiSpriteCnt2)+1],bl   ;
 sub bh,bl
 mov [C_LABEL(HiSpriteCnt1)+1],bh   ;
 mov bh,7
 add bl,bl
 sub bh,bl
 and bh,7
 mov [C_LABEL(HiSpriteCnt1)],bh ;

 mov ebx,C_LABEL(OAM)
 add [C_LABEL(HiSpriteAddr)],ebx
 add [C_LABEL(HiSpriteBits)],ebx
 jmp C_LABEL(Recache_OAM)

ALIGNC
EXPORT_C Recache_OAM

%ifdef Profile_Recache_OAM
 inc dword [C_LABEL(Calls_Recache_OAM)]
%endif

; Clear count tables
 mov edi,C_LABEL(OAM_Count_Priority)
 xor eax,eax
 mov ecx,240*4/32
 call Do_Clear

 mov edi,C_LABEL(OAM_Count)
 mov ecx,240*2/32
 call Do_Clear
        
 mov edi,OAM_Tail
 mov ecx,224/32
 call Do_Clear

 mov bl,[edi]
 mov [edi],eax
 mov [edi+4],eax
 mov [edi+8],eax
 mov [edi+12],eax

 mov edi,C_LABEL(OAM_TimeRange)
 mov ecx,224/32
 call Do_Clear

 mov bl,[edi]
 mov [edi],eax
 mov [edi+4],eax
 mov [edi+8],eax
 mov [edi+12],eax

 mov edi,C_LABEL(OAM_Low_Before_High)
 mov ecx,224/32
 call Do_Clear

 mov bl,[edi]
 mov [edi],eax
 mov [edi+4],eax
 mov [edi+8],eax
 mov [edi+12],eax

 mov edi,C_LABEL(OAM_Lowest_Priority)
 mov ecx,224/32
 dec eax
 call Do_Clear

 mov bl,[edi]
 mov [edi],eax
 mov [edi+4],eax
 mov [edi+8],eax
 mov [edi+12],eax

;mov al,[C_LABEL(OBSEL)]
;cmp al,0xC0    ; If invalid size selected, no sprites to plot
;jnb .done

 mov ecx,[C_LABEL(HiSpriteCnt1)]    ; Size of first set and bit offset
 mov eax,[C_LABEL(HiSpriteCnt2)]
 mov esi,[C_LABEL(HiSpriteAddr)]
 test ah,ah
 mov edi,[C_LABEL(HiSpriteBits)]
 jz .is_zero
 push byte 0
.is_zero:
 push eax
 jmp .next_sprite

; Tile attribute word: YXPP CCCT TTTT TTTT
;  Where:
;   Y, X are vertical/horizontal flip
;   P is priority
;   C is color palette selector
;   T is tile number
;

; AAAA AAAA AAAA AAAA YXPP CCCX XXXX XXXX
;  A - OAM sprite line-in-tile address
;  YXPP CCC  - bits 1-7 of OAM attribute word
;  X - X position
ALIGNC
.next_sprite:
;esi = OAM 512 byte subtable address OAM+(0-511)
;edi = OAM 32 byte subtable address OAM+(512-543)
;cl = variable shift count for OAM subtable (1, 3, 5, 7)
;ch = count left in current decode pass (1-128)

;Perform clipping & determine visible range
;Get size
 mov ah,[edi]
 mov edx,[Sprite_Size_Current_X]
 mov ebx,[Sprite_Size_Current_Y]

 ;Shift size bit into carry
 shl ah,cl
 jnc .do_small

 ;dl = sprite size in tiles
 ;dh = lower limit for negative X position
 shr edx,16 ;X
 shr ebx,16 ;Y

.do_small:

 cmp dl,bl  ;rectangular OBJ?
 jne .rect_obj
 mov al,0
.have_vflip_fixup:
 mov [OBJ_vflip_fixup],al

 ;dl = sprite size in tiles
 ;dh = lower limit for negative X position
 mov al,[esi]  ; ax = X

 ;Get X sign bit
 shr ah,8
 jnc .do_positive

 ;Determine if sprite is entirely offscreen
 cmp al,dh
 jb .off_screen

.do_negative:
;# tiles -= 32 - ((X + 7) & FF) / 8 for -X
 add eax,byte 7
 mov dh,dl
 shr eax,3
 xor al,0xFF
 add al,33
 sub dh,al
;visible width count in dh, total count in dl
;esi = OAM 512 byte subtable address
;edi = OAM 32 byte subtable address
;ecx, esi, edi must be preserved!
 call C_LABEL(Add_Sprite_X_Negative)
 jmp .off_screen

.do_positive:
;# tiles <= 32 - (X & 0xFF) / 8 for +X
 shr al,3
 mov dh,dl
 xor al,0xFF
 add al,33
;max visible count in al

;dl = min(max count(al), total count(dl))
 push ebx
 sub al,dl
 sbb bl,bl
 and bl,al
 add dh,bl
 pop ebx
;visible width count in dh, total count in dl
;esi = OAM 512 byte subtable address
;edi = OAM 32 byte subtable address
;ecx, esi, edi must be preserved!
 call C_LABEL(Add_Sprite_X_Positive)
 jmp .off_screen

.rect_obj:
 mov al,dl
 shl al,3
 jmp .have_vflip_fixup

ALIGNC
.off_screen:
 sub cl,2   ; Adjust variable shift count
 jnc .bits_left
 and cl,7
 inc edi    ; Goto next sprite X-MSB/size byte

.bits_left:
 add esi,byte 4 ; Goto next sprite XYAA dword
 dec ch         ; Check sprite list count
 jnz .next_sprite
 mov ch,[1+esp] ; Get next list count
 sub esi,0x200  ; Adjust pointers to sprite 127 (if we're at end)
 sub edi,byte 0x20
 add esp,byte 4
 test ch,ch     ; Continue if valid list
 jnz .next_sprite

.done:
 mov byte [Redo_OAM],0

 ret

ALIGNC
EXPORT_C Reset_Sprites
 pusha
 ; Set eax to 0, as we're setting most everything to 0...
 xor eax,eax

 ; Reset sprite renderer vars
 mov byte [C_LABEL(HiSprite)],0
 mov dword [C_LABEL(HiSpriteAddr)],C_LABEL(OAM)+0x000
 mov dword [C_LABEL(HiSpriteBits)],C_LABEL(OAM)+0x200
 mov dword [C_LABEL(HiSpriteCnt1)],0x8007
 mov dword [C_LABEL(HiSpriteCnt2)],0x0007
 mov byte [Redo_OAM],-1
 mov ecx,[Sprite_Size_Table]
 mov edx,[Sprite_Size_Table+4]
 mov [Sprite_Size_Current_X],ecx
 mov [Sprite_Size_Current_Y],edx
 mov byte [Pixel_Allocation_Tag],1
 mov [C_LABEL(OBBASE)],eax
 mov [C_LABEL(OBNAME)],eax

 ; Reset sprite port vars
 mov [C_LABEL(OAMAddress)],eax
 mov [C_LABEL(OAMAddress_VBL)],eax
 mov [OAMHigh],al
 mov [OAM_Write_Low],al
 mov [SPRLatch],al
 mov [C_LABEL(OBSEL)],al

; Clear pixel allocation tag table
 mov edi,DisplayZ+8
 xor eax,eax
 mov ecx,256/32
 call Do_Clear

 popa
 ret

ALIGNC
EXPORT SNES_R2138 ; OAMDATAREAD
 mov edx,[C_LABEL(OAMAddress)]
 mov al,[OAMHigh]
 cmp edx,0x100  ; if address >= 0x100...
 jb .no_mirror
 and edx,0x10F   ; ignore disconnected lines

.no_mirror:
 xor al,1
 mov [OAMHigh],al
 jnz .read_low

 mov al,[C_LABEL(OAM)+edx*2+1]

 mov edx,[C_LABEL(OAMAddress)]
 inc edx
 and edx,0x1FF  ; address is 9 bits
 mov [C_LABEL(OAMAddress)],edx
 ret

ALIGNC
.read_low:
 mov al,[C_LABEL(OAM)+edx*2]
 ret

ALIGNC
EXPORT SNES_W2101 ; OBSEL
 cmp [C_LABEL(OBSEL)],al
 je .no_change

 UpdateDisplay  ;*
 push ebx
 mov [C_LABEL(OBSEL)],al    ; Get our copy of this
 mov ebx,eax
 shr eax,5
 and eax,byte 7
 mov edx,[Sprite_Size_Table+eax*8]
 mov eax,[Sprite_Size_Table+eax*8+4]
 mov [Sprite_Size_Current_X],edx
 mov [Sprite_Size_Current_Y],eax
 mov eax,ebx
 mov edx,eax
 and ebx,byte 3<<3  ; Name address 0000 0000 000n n000
 and edx,byte 3     ; Base address 0000 0000 0000 0xbb
;shl ebx,10         ; Name is either 0x0000,0x1000,0x2000,0x3000 words
;shl edx,14         ; Base is either 0x0000,0x2000,0x4000,0x6000 words
 shl ebx,8          ; Name is either 0x0000,0x0800,0x1000,0x1800 lines
 shl edx,12         ; Base is either 0x0000,0x1000,0x2000,0x3000 lines
 add ebx,edx
;and edx,0xFFFF
;and ebx,0xFFFF
 and edx,0x3FFF
 and ebx,0x3FFF
;add edx,edx        ; Convert to offsets into tile cache
;add ebx,ebx
;add edx,C_LABEL(TileCache4)
;add ebx,C_LABEL(TileCache4)
 mov [C_LABEL(OBBASE)],edx
 mov [C_LABEL(OBNAME)],ebx
 pop ebx
 mov byte [Redo_OAM],-1
.no_change:
 ret

ALIGNC
EXPORT SNES_W2102 ; OAMADDL
 UpdateDisplay  ;*
 push ebx
 xor ebx,ebx
 mov [OAMHigh],bh
 mov [C_LABEL(OAMAddress)],al
 mov [C_LABEL(OAMAddress_VBL)],al
 pop ebx
 ret

ALIGNC
EXPORT SNES_W2103 ; OAMADDH
 UpdateDisplay  ;*
 push ebx
 mov ebx,[C_LABEL(OAMAddress_VBL)]
 xor edx,edx
 mov bh,1
 mov [OAMHigh],dl
 and bh,al      ; Only want MSB of address
 mov dl,0x80
 mov [C_LABEL(OAMAddress_VBL)+1],bh
 and dl,al      ; Is priority rotation bit set?
 mov [C_LABEL(OAMAddress)],ebx
 mov [SPRLatch],dl
 pop ebx
 ret

ALIGNC
EXPORT SNES_W2104 ; OAMDATA
 push ebx
 cmp byte [HVBJOY], 0
 js .in_vblank

 cmp byte [C_LABEL(INIDISP)], 0
 jns .no_increment  ;.no_change

.in_vblank:
 xor ebx,ebx
 mov edx,[C_LABEL(OAMAddress)]
 mov bl,[OAMHigh]
 cmp edx,0x100  ; if address >= 0x100, byte access
 jnb .byte_access

 xor ebx,byte 1
 mov [OAMHigh],bl
 jnz .write_low

 mov bl,[OAM_Write_Low]
 mov bh,al
 cmp [C_LABEL(OAM)+edx*2],bx
 je .no_change
 UpdateDisplay  ;*
 mov edx,[C_LABEL(OAMAddress)]
 mov byte [Redo_OAM],-1
 mov [C_LABEL(OAM)+edx*2],bx
.no_change:
 mov edx,[C_LABEL(OAMAddress)]
 inc edx
 and edx,0x1FF  ; address is 9 bits
 mov [C_LABEL(OAMAddress)],edx
.no_increment:
.ignore_write:
 pop ebx
 ret
ALIGNC
.write_low:
 mov [OAM_Write_Low],al
 pop ebx
 ret

ALIGNC
.byte_access:
 and edx,0x10F   ; ignore disconnected lines
 cmp [C_LABEL(OAM)+edx*2+ebx],al
 je .ba_no_change
 push edx
 UpdateDisplay  ;*
 pop edx
 mov byte [Redo_OAM],-1
 mov [C_LABEL(OAM)+edx*2+ebx],al
.ba_no_change:

 xor ebx,byte 1
 mov [OAMHigh],bl
 jnz .no_increment

 mov edx,[C_LABEL(OAMAddress)]
 inc edx
 and edx,0x1FF  ; address is 9 bits
 mov [C_LABEL(OAMAddress)],edx
 pop ebx
 ret

section .text
ALIGNC
section .data
ALIGND
section .bss
ALIGNB

⌨️ 快捷键说明

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