- 浏览: 16217 次
.686 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
; 43210
; |||||
; |||++- Pixel value from tile data
; |++--- Palette number from attribute table or OAM
; +----- Background/Sprite select
; As in some second-generation game consoles, values in the NES palette are based on hue and brightness:
; 76543210
; ||||||||
; ||||++++- Hue (phase, determines NTSC/PAL chroma)
; ||++----- Value (voltage, determines NTSC/PAL luma)
; ++------- Unimplemented, reads back as 0
; Hue $0 is light gray, $1-$C are blue to red to green to cyan, $D is dark gray, and $E-$F are mirrors of $1D (black).
; The canonical code for "black" is $0F or $1D. $0D should not be used;
; it results in a "blacker than black" signal that may cause problems for some TVs.
; It works this way because of the way colors are represented in an NTSC or PAL signal,
; with the phase of a color subcarrier controlling the hue. For details, see NTSC video.
; The 2C03 RGB PPU used in the PlayChoice-10 and Famicom Titler renders hue $D as black, not dark gray. The 2C04 PPUs used in many Vs.
; System arcade games have completely different palettes as a copy protection measure.
DisplaySkew struct
dword X ?
dword Y ?
dword ScrLatch ?
DisplaySkew ends
AddressSkew struct
dword LowAddr ?
dword HighAddr ?
dword AddrLatch ?
AddressSkew ends
.data?
align 16
BGPal dd 16 dup (?) ; offset - 160 size : 64
SPPal dd 16 dup (?) ; offset - 96 size : 64
ppuREG dd 8 dup (?) ; offset - 32 size : 32
DisplaySkew ScreenOffset <> ; offset 0
AddressSkew AddressOffset <> ; offset 12
DisplaySkew CurLineOffset <> ; offset 24 size : 24
m_EleGun dd ? ; offset 36 size : 4
m_RollReg dd ? ; offset 40 size : 4
pNameTable dd ? ; offset 44 size : 4
VideoBuffer dd 15360 ?
SRAM dd 256 dup (?) ; offset : N/A unless Sprite RAM
.data
PPU_VBLANK_BIT equ 80h
PPU_SPHIT_BIT equ 40h
PPU_SP16_BIT equ 20h
PPU_BGTBL_BIT equ 10h
PPU_SPTBL_BIT equ 08h
PPU_INC32_BIT equ 04h
PPU_NAMETBL_BIT equ 03h
; 2001 mask
PPU_SHOWCOLOR equ 00h
PPU_NOCOLOR equ 01h
PPU_LEFT8COL equ 02h
PPU_SPRLEFT8COL equ 04h
PPU_SHOWBG equ 08h
PPU_SHOWSPR equ 10h
; 2002 mask
PPU_VBLANK_FLAG equ 80h
PPU_SPHIT_FLAG equ 40h
PPU_SPMAX_FLAG equ 20h
PPU_WENABLE_FLAG equ 10h
SP_VREVERT equ 80h
SP_HREVERT equ 40h
SP_LEVEL equ 20h
SP_HIGHCOLOR equ 03h
_PPU_ReadByte proc C _addr
option prologue:none, epilogue:none
movzx eax, word ptr[esp+4] ; - N
push edx
and eax, 03FFFh ; - decom mirror
mov edx, eax
shr eax, 8
jmp [PLTable+eax*4-08000h] ; -N/V
align 16
GX00:
GX01:
GX02:
GX03:
GX04:
GX05:
GX06:
GX07:
GX08:
GX09:
GX0A:
GX0B:
GX0C:
GX0D:
GX0E:
GX0F:
GX10:
GX11:
GX12:
GX13:
GX14:
GX15:
GX16:
GX17:
GX18:
GX19:
GX1A:
GX1B:
GX1C:
GX1D:
GX1E:
GX1F:
GX20:
GX21:
GX22:
GX23:
GX24:
GX25:
GX26:
GX27:
GX28:
GX29:
GX2A:
GX2B:
GX2C:
GX2D:
GX2E:
GX2F: ; 0x0010 1111
mov eax, edx ; - U
and edx, 03FFh ; - V
shr eax, 10 ; - U
mov eax, [PPU_MEM_BANK_INDEX+eax*4]
movzx eax, [eax+edx]
pop edx
ret
align 16
GX30:
GX31:
GX32:
GX33:
GX34:
GX35:
GX36:
GX37:
GX38:
GX39:
GX3A:
GX3B:
GX3C:
GX3D:
GX3E: ; $2000 - $2EFF's mirror
lea eax, [edx-01000h]
sub edx, 01000h
shr edx, 10 ; - U
and eax, 03FFh ; - V
mov edx, [PPU_MEM_BANK_INDEX+edx*4]
movzx eax, [eax+edx]
pop edx
ret
align 16
GX3F: ; palette/mirror
mov eax, edx ; - U save old frame
and edx, 15 ; - V limit bit for PAL mirror
and eax, 16 ; - U is SPPal ? Y: D5 == 1 : D5 == 0
lea eax, [eax*4] ; - U D5 is 0 ? edx == 0 : edx == 64
mov eax, [BGPal+eax+edx*4] ; N/V set val
pop edx
ret
align 16
PLTable dd GX00, GX01, GX02, GX03, GX04, GX05, GX06, GX07
dd GX08, GX09, GX0A, GX0B, GX0C, GX0D, GX0E, GX0F
dd GX10, GX11, GX12, GX13, GX14, GX15, GX16, GX17
dd GX18, GX19, GX1A, GX1B, GX1C, GX1D, GX1E, GX1F
dd GX20, GX21, GX22, GX23, GX24, GX25, GX26, GX27
dd GX28, GX29, GX2A, GX2B, GX2C, GX2D, GX2E, GX2F
dd GX30, GX31, GX32, GX33, GX34, GX35, GX36, GX37
dd GX38, GX39, GX3A, GX3B, GX3C, GX3D, GX3E, GX3F
_PPU_ReadByte endp
_PPU_WriteByte proc C _addr, _val
option prologue:none, epilogue:none
; push edx
mov eax, [esp+8] ; - U val
push esi ; - V
mov esi, [esp+8] ; - N addr
push edx ; - V
mov edx, esi ; - U
and esi, 03FFFh ; - V decom mirror
shr esi, 8 ; - U
jmp [WLTable+esi*4-08000h] ; -N/V
align 16
ZX00:
ZX01:
ZX02:
ZX03:
ZX04:
ZX05:
ZX06:
ZX07:
ZX08:
ZX09:
ZX0A:
ZX0B:
ZX0C:
ZX0D:
ZX0E:
ZX0F:
ZX10:
ZX11:
ZX12:
ZX13:
ZX14:
ZX15:
ZX16:
ZX17:
ZX18:
ZX19:
ZX1A:
ZX1B:
ZX1C:
ZX1D:
ZX1E:
ZX1F:
ZX20:
ZX21:
ZX22:
ZX23:
ZX24:
ZX25:
ZX26:
ZX27:
ZX28:
ZX29:
ZX2A:
ZX2B:
ZX2C:
ZX2D:
ZX2E:
ZX2F: ; 0x0010 1111
and edx, 03FFFh ; - U
nop ; - V spare
mov esi, edx ; - U
and edx, 03FFh ; - V
shr esi, 10 ; - U
mov esi, [PPU_MEM_BANK_INDEX+esi*4]
mov [esi+edx], al
pop edx
pop esi
ret
align 16
ZX30:
ZX31:
ZX32:
ZX33:
ZX34:
ZX35:
ZX36:
ZX37:
ZX38:
ZX39:
ZX3A:
ZX3B:
ZX3C:
ZX3D:
ZX3E: ; $2000 - $2EFF's mirror
and edx, 03FFFh ; - U
nop ; - V
sub edx, 01000h ; - U
nop ; - V spare
mov esi, edx ; - U
and edx, 03FFh ; - V
shr esi, 10 ; - U
mov esi, [PPU_MEM_BANK_INDEX+esi*4]
mov [esi+edx], al
pop edx
pop esi
ret
align 16
ZX3F: ; palette/mirror
lea esi, [BGPal]
and eax, 63 ; limit PAL index
jmp [PALAddrIndex+edx*4-0FC00h]
align 16
AC00:
AC10:
AC20:
AC30:
AC40:
AC50:
AC60:
AC70:
AC80:
AC90:
ACA0:
ACB0:
ACC0:
ACD0:
ACE0:
ACF0:
mov [esi], eax ; disp 32 .. maybe unaligned pipe ...
mov [esi+64], eax
pop edx
pop esi
ret
align 16
AC01:
AC02:
AC03:
AC04:
AC05:
AC06:
AC07:
AC08:
AC09:
AC0A:
AC0B:
AC0C:
AC0D:
AC0E:
AC0F:
AC21:
AC22:
AC23:
AC24:
AC25:
AC26:
AC27:
AC28:
AC29:
AC2A:
AC2B:
AC2C:
AC2D:
AC2E:
AC2F:
AC41:
AC42:
AC43:
AC44:
AC45:
AC46:
AC47:
AC48:
AC49:
AC4A:
AC4B:
AC4C:
AC4D:
AC4E:
AC4F:
AC61:
AC62:
AC63:
AC64:
AC65:
AC66:
AC67:
AC68:
AC69:
AC6A:
AC6B:
AC6C:
AC6D:
AC6E:
AC6F:
AC81:
AC82:
AC83:
AC84:
AC85:
AC86:
AC87:
AC88:
AC89:
AC8A:
AC8B:
AC8C:
AC8D:
AC8E:
AC8F:
ACA1:
ACA2:
ACA3:
ACA4:
ACA5:
ACA6:
ACA7:
ACA8:
ACA9:
ACAA:
ACAB:
ACAC:
ACAD:
ACAE:
ACAF:
ACC1:
ACC2:
ACC3:
ACC4:
ACC5:
ACC6:
ACC7:
ACC8:
ACC9:
ACCA:
ACCB:
ACCC:
ACCD:
ACCE:
ACCF:
ACE1:
ACE2:
ACE3:
ACE4:
ACE5:
ACE6:
ACE7:
ACE8:
ACE9:
ACEA:
ACEB:
ACEC:
ACED:
ACEE:
ACEF:
and edx, 15
mov [esi+edx*4], eax
pop edx
pop esi
ret
align 16
AC11:
AC12:
AC13:
AC14:
AC15:
AC16:
AC17:
AC18:
AC19:
AC1A:
AC1B:
AC1C:
AC1D:
AC1E:
AC1F:
AC31:
AC32:
AC33:
AC34:
AC35:
AC36:
AC37:
AC38:
AC39:
AC3A:
AC3B:
AC3C:
AC3D:
AC3E:
AC3F:
AC51:
AC52:
AC53:
AC54:
AC55:
AC56:
AC57:
AC58:
AC59:
AC5A:
AC5B:
AC5C:
AC5D:
AC5E:
AC5F:
AC71:
AC72:
AC73:
AC74:
AC75:
AC76:
AC77:
AC78:
AC79:
AC7A:
AC7B:
AC7C:
AC7D:
AC7E:
AC7F:
AC91:
AC92:
AC93:
AC94:
AC95:
AC96:
AC97:
AC98:
AC99:
AC9A:
AC9B:
AC9C:
AC9D:
AC9E:
AC9F:
ACB1:
ACB2:
ACB3:
ACB4:
ACB5:
ACB6:
ACB7:
ACB8:
ACB9:
ACBA:
ACBB:
ACBC:
ACBD:
ACBE:
ACBF:
ACD1:
ACD2:
ACD3:
ACD4:
ACD5:
ACD6:
ACD7:
ACD8:
ACD9:
ACDA:
ACDB:
ACDC:
ACDD:
ACDE:
ACDF:
ACF1:
ACF2:
ACF3:
ACF4:
ACF5:
ACF6:
ACF7:
ACF8:
ACF9:
ACFA:
ACFB:
ACFC:
ACFD:
ACFE:
ACFF:
and edx, 15
mov [esi+edx*4+64], eax
pop edx
pop esi
ret
; $3F00 Universal background color
; $3F01-$3F03 Background palette 0
; $3F05-$3F07 Background palette 1
; $3F09-$3F0B Background palette 2
; $3F0D-$3F0F Background palette 3
; $3F11-$3F13 Sprite palette 0
; $3F15-$3F17 Sprite palette 1
; $3F19-$3F1B Sprite palette 2
; $3F1D-$3F1F Sprite palette 3
; Addresses $3F04/$3F08/$3F0C can contain unique data,
; though these values are not used by the PPU when normally rendering
; They can still be shown using the background palette hack, explained below.
; Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C.
align 16
WLTable dd ZX00, ZX01, ZX02, ZX03, ZX04, ZX05, ZX06, ZX07
dd ZX08, ZX09, ZX0A, ZX0B, ZX0C, ZX0D, ZX0E, ZX0F
dd ZX10, ZX11, ZX12, ZX13, ZX14, ZX15, ZX16, ZX17
dd ZX18, ZX19, ZX1A, ZX1B, ZX1C, ZX1D, ZX1E, ZX1F
dd ZX20, ZX21, ZX22, ZX23, ZX24, ZX25, ZX26, ZX27
dd ZX28, ZX29, ZX2A, ZX2B, ZX2C, ZX2D, ZX2E, ZX2F
dd ZX30, ZX31, ZX32, ZX33, ZX34, ZX35, ZX36, ZX37
dd ZX38, ZX39, ZX3A, ZX3B, ZX3C, ZX3D, ZX3E, ZX3F
PALAddrIndex dd AC00, AC01, AC02, AC03, AC04, AC05, AC06, AC07
dd AC08, AC09, AC0A, AC0B, AC0C, AC0D, AC0E, AC0F
dd AC10, AC11, AC12, AC13, AC14, AC15, AC16, AC17
dd AC18, AC19, AC1A, AC1B, AC1C, AC1D, AC1E, AC1F
dd AC20, AC21, AC22, AC23, AC24, AC25, AC26, AC27
dd AC28, AC29, AC2A, AC2B, AC2C, AC2D, AC2E, AC2F
dd AC30, AC31, AC32, AC33, AC34, AC35, AC36, AC37
dd AC38, AC39, AC3A, AC3B, AC3C, AC3D, AC3E, AC3F
dd AC40, AC41, AC42, AC43, AC44, AC45, AC46, AC47
dd AC48, AC49, AC4A, AC4B, AC4C, AC4D, AC4E, AC4F
dd AC50, AC51, AC52, AC53, AC54, AC55, AC56, AC57
dd AC58, AC59, AC5A, AC5B, AC5C, AC5D, AC5E, AC5F
dd AC60, AC61, AC62, AC63, AC64, AC65, AC66, AC67
dd AC68, AC69, AC6A, AC6B, AC6C, AC6D, AC6E, AC6F
dd AC70, AC71, AC72, AC73, AC74, AC75, AC76, AC77
dd AC78, AC79, AC7A, AC7B, AC7C, AC7D, AC7E, AC7F
dd AC80, AC81, AC82, AC83, AC84, AC85, AC86, AC87
dd AC88, AC89, AC8A, AC8B, AC8C, AC8D, AC8E, AC8F
dd AC90, AC91, AC92, AC93, AC94, AC95, AC96, AC97
dd AC98, AC99, AC9A, AC9B, AC9C, AC9D, AC9E, AC9F
dd ACA0, ACA1, ACA2, ACA3, ACA4, ACA5, ACA6, ACA7
dd ACA8, ACA9, ACAA, ACAB, ACAC, ACAD, ACAE, ACAF
dd ACB0, ACB1, ACB2, ACB3, ACB4, ACB5, ACB6, ACB7
dd ACB8, ACB9, ACBA, ACBB, ACBC, ACBD, ACBE, ACBF
dd ACC0, ACC1, ACC2, ACC3, ACC4, ACC5, ACC6, ACC7
dd ACC8, ACC9, ACCA, ACCB, ACCC, ACCD, ACCE, ACCF
dd ACD0, ACD1, ACD2, ACD3, ACD4, ACD5, ACD6, ACD7
dd ACD8, ACD9, ACDA, ACDB, ACDC, ACDD, ACDE, ACDF
dd ACE0, ACE1, ACE2, ACE3, ACE4, ACE5, ACE6, ACE7
dd ACE8, ACE9, ACEA, ACEB, ACEC, ACED, ACEE, ACEF
dd ACF0, ACF1, ACF2, ACF3, ACF4, ACF5, ACF6, ACF7
dd ACF8, ACF9, ACFA, ACFB, ACFC, ACFD, ACFE, ACFF
; BGPAL[0x04] = BGPAL[0x08] = BGPAL[0x0C] = BGPAL[0x00];
; SPPAL[0x00] = SPPAL[0x04] = SPPAL[0x08] = SPPAL[0x0C] = BGPAL[0x00];
_PPU_WriteByte endp
_ReadPpuPort proc C _addr
` option prologue:none, epilogue:none
movzx eax, word ptr[esp+4] ; - N
jmp [PORT_INDEX_TABLE+eax*4-08000h] ; -N/V
align 16
PORT_INDEX_TABLE dd REG2000, REG2001, REG2002, REG2003
dd REG2004, REG2005, REG2006, REG2007
REG2000:
REG2001:
REG2003:
REG2005:
REG2006:
movzx eax, byte ptr [ppuREG+eax*4-08000h] ; - N
ret ; - N
align 16
REG2002:
push ecx ; - U save old frame
push ebx ; - V save old frame
lea ecx, ScreenOffset ; - U lea base index
nop ; - V spare
mov [ecx+8], 0 ; - U ScrLatch = 0 (<-->)
mov ebx, [ecx-24] ; - V load REG[2]
mov [ecx+20], 1 ; - U AddrLatch = 1 (high bit)
mov eax, ebx ; - V save old frame
and ebx, 07Fh ; - U clr V_BLANK Enable
nop ; - V spare
mov [ecx-24], ebx ; - U write REG[2]
pop ebx ; - V
pop ecx ; - U
ret ; - N
align 16
REG2004:
push ecx ; - U - save old frame
lea ecx, ppuREG ; - V/N - decom reg
mov eax, [ecx+12] ; - U
inc eax ; - U ++ addr
mov [ecx+12], eax ; - N
and eax, 0FFh
pop ecx
movzx eax, byte ptr [SRAM+eax*4-4] ; - N
ret
align 16
REG2007:
push ebx ; - U save old frame
lea ebx, ScreenOffset ; - V/N - decom reg
push ecx ; - U save old frame
mov ecx, [ebx] ; - V load low bit
push edx ; - U save old frame
mov ch, [ebx+4] ; - V load high bit
mov edx, ecx ; - U save old frame VRAM's address
push ecx ; - V call NES_READ_BYTE
call dword ptr [_PPU_ReadByte] ; - N
add esp, 4 ; - U call type __cdcel ++ stack
mov ecx, [ebx-4] ; - V save old frame REG[7]
mov [ebx-4], eax ; - U write REG[7]
and edx, 0FFFFh ; - V
lea eax, [edx-03F00h] ; - U
nop ; - V spare
cmp eax, 0FFh ; - U address >= 0x3F00 && address < 0x4000 ?
ja no_palette ; - V Y: set palette/mirror ... N: next step ...
mov eax, edx ; - U save old frame
mov ecx, edx ; - V save old frame
and eax, 16 ; - U is SPPal ? Y: D5 == 1 : D5 == 0
and ecx, 15 ; - V limit bit for PAL mirror
lea eax, [eax*4] ; - U D5 is 0 ? edx == 0 : edx == 64
mov eax, [BGPal+eax+ecx*4] ; N/V set val
mov ecx, eax ; - U
neg eax ; - N
no_palette:
mov eax, ecx ; - U set return val eax <- REG[7]
mov ecx, [ebx-32] ; - V load REG[0]
shr ecx, 3 ; - U shift PPU_INC32_BIT is setted ? C_flag == 1 : C_flag == 0
mov ebx, 1 ; - V reset 32 to be use
adc ecx, 0 ; - U if C_flag == 1 ? edx == 1 : edx == 0
nop ; - V spare
and ecx, 1 ; - U limit bit
nop ; - V spare
lea ecx, [ecx*2+ecx] ; - U 3 or 0 myabe delay
ror bl, cl ; - N 1 or 32
add edx, ebx ; - U add sum
pop ecx ; - V
lea ebx, ScreenOffset ; - U index base
mov [ebx+4], dl ; - V/N
mov [ebx], dh ; - U
pop edx ; - V
pop ebx ; - U
ret ; - N
_ReadPpuPort endp
_WritePpuPort proc C _addr, _val
` option prologue:none, epilogue:none
mov eax, [esp+4] ; - U load addr
push ebx ; - V save old frame
and eax, 0FFFFh ; - U limit bit
push ecx ; - V
lea ebx, [ppuREG]; - U
mov ecx, [esp+16]; - V load val
jmp [_PORT_INDEX_TABLE+eax*4-08000h] ; -N/V
align 16
_PORT_INDEX_TABLE dd _REG2000, _REG2001, _REG2002, _REG2003
dd _REG2004, _REG2005, _REG2006, _REG2007
_REG2000: ; revise nametable addr
push edx ; - U save old frame
mov edx, ecx ; - V save old frame
shl ecx, 10 ; - U shift opr
mov eax, [ebx+76] ; - V load pNameTable
and ecx, 0C00h ; - U switch nametable index
and eax, 0F3FFh ; - V clear ora nametable index
or eax, ecx ; - U get current nametable index
mov ecx, [ebx] ; - V load REG[0]
mov [ebx+68], eax ; - U write nametable pointer
xor ecx, 080h ; - V neg VBLANK status
mov eax, [ebx+76] ; - U load REG[2]
and ecx, edx ; - V test status
and eax, ecx ; - U test status
mov [ebx], edx ; - V write REG[0]
shr eax, 7 ; - U shift
pop edx ; - V recover old frame
and eax, 1 ; - U clr bit
mov ebx, INT_WARNING ; - V/N
pop ecx ; - U recover old frame
or eax, ebx ; - V test set NMI_FLAG
pop ebx ; - U recover old frame
mov INT_WARNING, eax ; - V write back
ret ; - N child ret
align 16
_REG2001:
mov [ebx+4], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2002:
mov [ebx+8], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2003:
mov [ebx+12], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
align 16
_REG2005:
mov eax, [ebx+40] ; - U load ScrLatch
nop ; - V spare
mov [ebx+32+eax*4], ecx; - U write val to current scr direction
xor eax, 1 ; - V switch now's direction
and ecx, 0FFh ; - U clr bit
mov [ebx+40], eax ; - V write ScrLatch
jmp [_REG2005_SCROLL_DIRECT_TABLE+eax*4]; V/N select table do frame
align 16
_X_HIT:
shr ecx, 3 ; - U get Tile X
mov eax, [ebx+24] ; - V load REG[6]
and ecx, 01Fh ; - U clr bit
and eax, 0FFE0h ; - V clr bit
or eax, ecx ; - U set bit
pop ecx ; - V recover old frame
mov [ebx+24], eax ; - U REG[6]
pop ebx ; - V/N recover old frame
ret ; - return ...
_Y_HIT:
ror ecx, 3 ; - U get Tile Y 0x0000 0111 and Y Tile offset
mov eax, [ebx+24] ; - V load REG[6]
shl cx, 5 ; - U/N ...
and eax, 08C1Fh ; - V clr bit 1000 1100 0001 1111
or eax, ecx ; - U set bit
nop ; - V spare 1110 0000 0000 0000 0NNN 0000 0000 0000
shr ecx, 14 ; - U
nop ; - V spare
or eax, ecx ; - U set bit
pop ecx ; - V recover old frame
mov [ebx+24], eax ; - U write REG[6]
pop ebx ; - V/N recover old frame
ret ; - return ...
align 16
_REG2006:
mov eax, [ebx+52] ; - U load AddrLatch
nop ; - V spare
mov [ebx+44+eax*4], ecx; - U/N write val to current addr
xor eax, 1 ; - V switch now's addr write mode
mov [ebx+52], eax ; - U write AddrLatch
mov [ebx+72+eax], cl ; - V write mem high|low bit (byte)...
mov ecx, [ebx+72+eax] ; - U load m_RollReg
IF 0
and [ebx+73], 03Fh ; - V clr bit load mem-> opr -> write back maybe terribe ..
ELSE
nop ; - V spare
ENDIF
mov [ebx+68+eax*4], ecx; - U/N
pop ecx ; - V/U recover old frame
pop ebx ; - U/V recover old frame
ret ; - return .
align 16
_REG2004:
movzx eax, [ebx+12] ; - N load REG[3]
mov [SRAM+eax*4], ecx ; - U/N write val to spram
inc eax ; - V/N
mov [ebx+12], eax ; - U
pop ecx ; - V
pop ebx ; - U
ret ; - N
align 16
_REG2007:
push ecx ; - U arg1 -> _val
mov al, [ebx+44] ; - V/N get low bit
mov ecx, [ebx] ; - U load REG[0]
mov ah, [ebx+48] ; - V/N get high bit
and ecx, 4 ; - U PPU_INC32_BIT is setted ?
push eax ; - V arg2 -> address
add eax, [_REG2000_INC_TABLE+ecx*4] ; - U PPU_INC32_BIT is setted ?
mov [ebx+44], al
mov [ebx+48], ah
call dword ptr [_WritePpuPort] ; - N
add esp, 8
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2005_SCROLL_DIRECT_TABLE dd _Y_HIT, _X_HIT
_REG2000_INC_TABLE dd 1,1,1,1,32
_WritePpuPort endp
_ResetPPU proc C
option prologue:none, epilogue:none
_ResetPPU endp
_FrameStart proc C
option prologue:none, epilogue:none
test [ppuREG+4], 018h
jne _use_render
ret
_use_render:
mov eax, dword ptr [m_RollReg]
mov dword ptr [m_EleGun], eax
ret
_FrameStart endp
_VBlankStart proc C
option prologue:none, epilogue:none
and [ppuREG+12], 10000000b
test dword ptr [ppuREG], 128
je _NORMAL_P
; NMI PROC
_NORMAL_P:
ret
_VBlankStart endp
_VBlankEnd proc C
option prologue:none, epilogue:none
and [ppuREG+12], 00111111b
ret
_VBlankEnd endp
_StructCopy proc _des, _src, _num
_StructCopy endp
_ScanlineStart proc C
option prologue:none, epilogue:none
lea eax, [ScreenOffset]
nop ; sapre
test dword ptr [eax+28], 24
jne _set_render
ret
_set_render:
push ebx
push ecx
mov ebx, [eax]
mov ecx, [eax+4]
mov [eax+24], ebx
mov [eax+28], ecx
mov ebx, [eax+36]
mov ecx, [eax+40]
and ebx, 0F3E0h
and ecx, 00C1Fh
and ebx, ecx
pop ecx
mov [eax+36], ebx
pop ebx
ret
_ScanlineStart endp
_ScanlineNext proc C
option prologue:none, epilogue:none
test dword ptr [eax+28], 24
jne _set_renderX
ret
align 16
_set_renderX:
mov eax, [m_EleGun] ;
push ebx
mov ebx, eax
and eax, 07000h
cmp eax, 07000h ; cross a Tile's whole Y Offset ? 8 ...
jne _inc_Now_Tile_Offset_Y
and ebx, 08FFFh
mov eax, ebx
and eax, 03E0h
cmp eax, 03A0h ; Tile Y Offset == 29 ?
jne _Not_29
xor ebx, 0800h ; switch vertical nametable
__RET:
and ebx, 0FC1F ; set Tile Y Offset = 0
mov [m_EleGun], ebx
pop ebx
ret
align 16
_Not_29:
cmp eax, 03E0h ; Tile Y Offset == 31 ?
jne _inc_Now_Tile
jmp __RET
_inc_Now_Tile:
lea eax, [ebx+32]
jmp _pXRet
_inc_Now_Tile_Offset_Y: ; ++ Tile's Y Offset
lea eax, [ebx+1000h]
_pXRet:
pop ebx
mov [m_EleGun], eax
ret
_ScanlineNext endp
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
; 43210
; |||||
; |||++- Pixel value from tile data
; |++--- Palette number from attribute table or OAM
; +----- Background/Sprite select
; As in some second-generation game consoles, values in the NES palette are based on hue and brightness:
; 76543210
; ||||||||
; ||||++++- Hue (phase, determines NTSC/PAL chroma)
; ||++----- Value (voltage, determines NTSC/PAL luma)
; ++------- Unimplemented, reads back as 0
; Hue $0 is light gray, $1-$C are blue to red to green to cyan, $D is dark gray, and $E-$F are mirrors of $1D (black).
; The canonical code for "black" is $0F or $1D. $0D should not be used;
; it results in a "blacker than black" signal that may cause problems for some TVs.
; It works this way because of the way colors are represented in an NTSC or PAL signal,
; with the phase of a color subcarrier controlling the hue. For details, see NTSC video.
; The 2C03 RGB PPU used in the PlayChoice-10 and Famicom Titler renders hue $D as black, not dark gray. The 2C04 PPUs used in many Vs.
; System arcade games have completely different palettes as a copy protection measure.
DisplaySkew struct
dword X ?
dword Y ?
dword ScrLatch ?
DisplaySkew ends
AddressSkew struct
dword LowAddr ?
dword HighAddr ?
dword AddrLatch ?
AddressSkew ends
.data?
align 16
BGPal dd 16 dup (?) ; offset - 160 size : 64
SPPal dd 16 dup (?) ; offset - 96 size : 64
ppuREG dd 8 dup (?) ; offset - 32 size : 32
DisplaySkew ScreenOffset <> ; offset 0
AddressSkew AddressOffset <> ; offset 12
DisplaySkew CurLineOffset <> ; offset 24 size : 24
m_EleGun dd ? ; offset 36 size : 4
m_RollReg dd ? ; offset 40 size : 4
pNameTable dd ? ; offset 44 size : 4
VideoBuffer dd 15360 ?
SRAM dd 256 dup (?) ; offset : N/A unless Sprite RAM
.data
PPU_VBLANK_BIT equ 80h
PPU_SPHIT_BIT equ 40h
PPU_SP16_BIT equ 20h
PPU_BGTBL_BIT equ 10h
PPU_SPTBL_BIT equ 08h
PPU_INC32_BIT equ 04h
PPU_NAMETBL_BIT equ 03h
; 2001 mask
PPU_SHOWCOLOR equ 00h
PPU_NOCOLOR equ 01h
PPU_LEFT8COL equ 02h
PPU_SPRLEFT8COL equ 04h
PPU_SHOWBG equ 08h
PPU_SHOWSPR equ 10h
; 2002 mask
PPU_VBLANK_FLAG equ 80h
PPU_SPHIT_FLAG equ 40h
PPU_SPMAX_FLAG equ 20h
PPU_WENABLE_FLAG equ 10h
SP_VREVERT equ 80h
SP_HREVERT equ 40h
SP_LEVEL equ 20h
SP_HIGHCOLOR equ 03h
_PPU_ReadByte proc C _addr
option prologue:none, epilogue:none
movzx eax, word ptr[esp+4] ; - N
push edx
and eax, 03FFFh ; - decom mirror
mov edx, eax
shr eax, 8
jmp [PLTable+eax*4-08000h] ; -N/V
align 16
GX00:
GX01:
GX02:
GX03:
GX04:
GX05:
GX06:
GX07:
GX08:
GX09:
GX0A:
GX0B:
GX0C:
GX0D:
GX0E:
GX0F:
GX10:
GX11:
GX12:
GX13:
GX14:
GX15:
GX16:
GX17:
GX18:
GX19:
GX1A:
GX1B:
GX1C:
GX1D:
GX1E:
GX1F:
GX20:
GX21:
GX22:
GX23:
GX24:
GX25:
GX26:
GX27:
GX28:
GX29:
GX2A:
GX2B:
GX2C:
GX2D:
GX2E:
GX2F: ; 0x0010 1111
mov eax, edx ; - U
and edx, 03FFh ; - V
shr eax, 10 ; - U
mov eax, [PPU_MEM_BANK_INDEX+eax*4]
movzx eax, [eax+edx]
pop edx
ret
align 16
GX30:
GX31:
GX32:
GX33:
GX34:
GX35:
GX36:
GX37:
GX38:
GX39:
GX3A:
GX3B:
GX3C:
GX3D:
GX3E: ; $2000 - $2EFF's mirror
lea eax, [edx-01000h]
sub edx, 01000h
shr edx, 10 ; - U
and eax, 03FFh ; - V
mov edx, [PPU_MEM_BANK_INDEX+edx*4]
movzx eax, [eax+edx]
pop edx
ret
align 16
GX3F: ; palette/mirror
mov eax, edx ; - U save old frame
and edx, 15 ; - V limit bit for PAL mirror
and eax, 16 ; - U is SPPal ? Y: D5 == 1 : D5 == 0
lea eax, [eax*4] ; - U D5 is 0 ? edx == 0 : edx == 64
mov eax, [BGPal+eax+edx*4] ; N/V set val
pop edx
ret
align 16
PLTable dd GX00, GX01, GX02, GX03, GX04, GX05, GX06, GX07
dd GX08, GX09, GX0A, GX0B, GX0C, GX0D, GX0E, GX0F
dd GX10, GX11, GX12, GX13, GX14, GX15, GX16, GX17
dd GX18, GX19, GX1A, GX1B, GX1C, GX1D, GX1E, GX1F
dd GX20, GX21, GX22, GX23, GX24, GX25, GX26, GX27
dd GX28, GX29, GX2A, GX2B, GX2C, GX2D, GX2E, GX2F
dd GX30, GX31, GX32, GX33, GX34, GX35, GX36, GX37
dd GX38, GX39, GX3A, GX3B, GX3C, GX3D, GX3E, GX3F
_PPU_ReadByte endp
_PPU_WriteByte proc C _addr, _val
option prologue:none, epilogue:none
; push edx
mov eax, [esp+8] ; - U val
push esi ; - V
mov esi, [esp+8] ; - N addr
push edx ; - V
mov edx, esi ; - U
and esi, 03FFFh ; - V decom mirror
shr esi, 8 ; - U
jmp [WLTable+esi*4-08000h] ; -N/V
align 16
ZX00:
ZX01:
ZX02:
ZX03:
ZX04:
ZX05:
ZX06:
ZX07:
ZX08:
ZX09:
ZX0A:
ZX0B:
ZX0C:
ZX0D:
ZX0E:
ZX0F:
ZX10:
ZX11:
ZX12:
ZX13:
ZX14:
ZX15:
ZX16:
ZX17:
ZX18:
ZX19:
ZX1A:
ZX1B:
ZX1C:
ZX1D:
ZX1E:
ZX1F:
ZX20:
ZX21:
ZX22:
ZX23:
ZX24:
ZX25:
ZX26:
ZX27:
ZX28:
ZX29:
ZX2A:
ZX2B:
ZX2C:
ZX2D:
ZX2E:
ZX2F: ; 0x0010 1111
and edx, 03FFFh ; - U
nop ; - V spare
mov esi, edx ; - U
and edx, 03FFh ; - V
shr esi, 10 ; - U
mov esi, [PPU_MEM_BANK_INDEX+esi*4]
mov [esi+edx], al
pop edx
pop esi
ret
align 16
ZX30:
ZX31:
ZX32:
ZX33:
ZX34:
ZX35:
ZX36:
ZX37:
ZX38:
ZX39:
ZX3A:
ZX3B:
ZX3C:
ZX3D:
ZX3E: ; $2000 - $2EFF's mirror
and edx, 03FFFh ; - U
nop ; - V
sub edx, 01000h ; - U
nop ; - V spare
mov esi, edx ; - U
and edx, 03FFh ; - V
shr esi, 10 ; - U
mov esi, [PPU_MEM_BANK_INDEX+esi*4]
mov [esi+edx], al
pop edx
pop esi
ret
align 16
ZX3F: ; palette/mirror
lea esi, [BGPal]
and eax, 63 ; limit PAL index
jmp [PALAddrIndex+edx*4-0FC00h]
align 16
AC00:
AC10:
AC20:
AC30:
AC40:
AC50:
AC60:
AC70:
AC80:
AC90:
ACA0:
ACB0:
ACC0:
ACD0:
ACE0:
ACF0:
mov [esi], eax ; disp 32 .. maybe unaligned pipe ...
mov [esi+64], eax
pop edx
pop esi
ret
align 16
AC01:
AC02:
AC03:
AC04:
AC05:
AC06:
AC07:
AC08:
AC09:
AC0A:
AC0B:
AC0C:
AC0D:
AC0E:
AC0F:
AC21:
AC22:
AC23:
AC24:
AC25:
AC26:
AC27:
AC28:
AC29:
AC2A:
AC2B:
AC2C:
AC2D:
AC2E:
AC2F:
AC41:
AC42:
AC43:
AC44:
AC45:
AC46:
AC47:
AC48:
AC49:
AC4A:
AC4B:
AC4C:
AC4D:
AC4E:
AC4F:
AC61:
AC62:
AC63:
AC64:
AC65:
AC66:
AC67:
AC68:
AC69:
AC6A:
AC6B:
AC6C:
AC6D:
AC6E:
AC6F:
AC81:
AC82:
AC83:
AC84:
AC85:
AC86:
AC87:
AC88:
AC89:
AC8A:
AC8B:
AC8C:
AC8D:
AC8E:
AC8F:
ACA1:
ACA2:
ACA3:
ACA4:
ACA5:
ACA6:
ACA7:
ACA8:
ACA9:
ACAA:
ACAB:
ACAC:
ACAD:
ACAE:
ACAF:
ACC1:
ACC2:
ACC3:
ACC4:
ACC5:
ACC6:
ACC7:
ACC8:
ACC9:
ACCA:
ACCB:
ACCC:
ACCD:
ACCE:
ACCF:
ACE1:
ACE2:
ACE3:
ACE4:
ACE5:
ACE6:
ACE7:
ACE8:
ACE9:
ACEA:
ACEB:
ACEC:
ACED:
ACEE:
ACEF:
and edx, 15
mov [esi+edx*4], eax
pop edx
pop esi
ret
align 16
AC11:
AC12:
AC13:
AC14:
AC15:
AC16:
AC17:
AC18:
AC19:
AC1A:
AC1B:
AC1C:
AC1D:
AC1E:
AC1F:
AC31:
AC32:
AC33:
AC34:
AC35:
AC36:
AC37:
AC38:
AC39:
AC3A:
AC3B:
AC3C:
AC3D:
AC3E:
AC3F:
AC51:
AC52:
AC53:
AC54:
AC55:
AC56:
AC57:
AC58:
AC59:
AC5A:
AC5B:
AC5C:
AC5D:
AC5E:
AC5F:
AC71:
AC72:
AC73:
AC74:
AC75:
AC76:
AC77:
AC78:
AC79:
AC7A:
AC7B:
AC7C:
AC7D:
AC7E:
AC7F:
AC91:
AC92:
AC93:
AC94:
AC95:
AC96:
AC97:
AC98:
AC99:
AC9A:
AC9B:
AC9C:
AC9D:
AC9E:
AC9F:
ACB1:
ACB2:
ACB3:
ACB4:
ACB5:
ACB6:
ACB7:
ACB8:
ACB9:
ACBA:
ACBB:
ACBC:
ACBD:
ACBE:
ACBF:
ACD1:
ACD2:
ACD3:
ACD4:
ACD5:
ACD6:
ACD7:
ACD8:
ACD9:
ACDA:
ACDB:
ACDC:
ACDD:
ACDE:
ACDF:
ACF1:
ACF2:
ACF3:
ACF4:
ACF5:
ACF6:
ACF7:
ACF8:
ACF9:
ACFA:
ACFB:
ACFC:
ACFD:
ACFE:
ACFF:
and edx, 15
mov [esi+edx*4+64], eax
pop edx
pop esi
ret
; $3F00 Universal background color
; $3F01-$3F03 Background palette 0
; $3F05-$3F07 Background palette 1
; $3F09-$3F0B Background palette 2
; $3F0D-$3F0F Background palette 3
; $3F11-$3F13 Sprite palette 0
; $3F15-$3F17 Sprite palette 1
; $3F19-$3F1B Sprite palette 2
; $3F1D-$3F1F Sprite palette 3
; Addresses $3F04/$3F08/$3F0C can contain unique data,
; though these values are not used by the PPU when normally rendering
; They can still be shown using the background palette hack, explained below.
; Addresses $3F10/$3F14/$3F18/$3F1C are mirrors of $3F00/$3F04/$3F08/$3F0C.
align 16
WLTable dd ZX00, ZX01, ZX02, ZX03, ZX04, ZX05, ZX06, ZX07
dd ZX08, ZX09, ZX0A, ZX0B, ZX0C, ZX0D, ZX0E, ZX0F
dd ZX10, ZX11, ZX12, ZX13, ZX14, ZX15, ZX16, ZX17
dd ZX18, ZX19, ZX1A, ZX1B, ZX1C, ZX1D, ZX1E, ZX1F
dd ZX20, ZX21, ZX22, ZX23, ZX24, ZX25, ZX26, ZX27
dd ZX28, ZX29, ZX2A, ZX2B, ZX2C, ZX2D, ZX2E, ZX2F
dd ZX30, ZX31, ZX32, ZX33, ZX34, ZX35, ZX36, ZX37
dd ZX38, ZX39, ZX3A, ZX3B, ZX3C, ZX3D, ZX3E, ZX3F
PALAddrIndex dd AC00, AC01, AC02, AC03, AC04, AC05, AC06, AC07
dd AC08, AC09, AC0A, AC0B, AC0C, AC0D, AC0E, AC0F
dd AC10, AC11, AC12, AC13, AC14, AC15, AC16, AC17
dd AC18, AC19, AC1A, AC1B, AC1C, AC1D, AC1E, AC1F
dd AC20, AC21, AC22, AC23, AC24, AC25, AC26, AC27
dd AC28, AC29, AC2A, AC2B, AC2C, AC2D, AC2E, AC2F
dd AC30, AC31, AC32, AC33, AC34, AC35, AC36, AC37
dd AC38, AC39, AC3A, AC3B, AC3C, AC3D, AC3E, AC3F
dd AC40, AC41, AC42, AC43, AC44, AC45, AC46, AC47
dd AC48, AC49, AC4A, AC4B, AC4C, AC4D, AC4E, AC4F
dd AC50, AC51, AC52, AC53, AC54, AC55, AC56, AC57
dd AC58, AC59, AC5A, AC5B, AC5C, AC5D, AC5E, AC5F
dd AC60, AC61, AC62, AC63, AC64, AC65, AC66, AC67
dd AC68, AC69, AC6A, AC6B, AC6C, AC6D, AC6E, AC6F
dd AC70, AC71, AC72, AC73, AC74, AC75, AC76, AC77
dd AC78, AC79, AC7A, AC7B, AC7C, AC7D, AC7E, AC7F
dd AC80, AC81, AC82, AC83, AC84, AC85, AC86, AC87
dd AC88, AC89, AC8A, AC8B, AC8C, AC8D, AC8E, AC8F
dd AC90, AC91, AC92, AC93, AC94, AC95, AC96, AC97
dd AC98, AC99, AC9A, AC9B, AC9C, AC9D, AC9E, AC9F
dd ACA0, ACA1, ACA2, ACA3, ACA4, ACA5, ACA6, ACA7
dd ACA8, ACA9, ACAA, ACAB, ACAC, ACAD, ACAE, ACAF
dd ACB0, ACB1, ACB2, ACB3, ACB4, ACB5, ACB6, ACB7
dd ACB8, ACB9, ACBA, ACBB, ACBC, ACBD, ACBE, ACBF
dd ACC0, ACC1, ACC2, ACC3, ACC4, ACC5, ACC6, ACC7
dd ACC8, ACC9, ACCA, ACCB, ACCC, ACCD, ACCE, ACCF
dd ACD0, ACD1, ACD2, ACD3, ACD4, ACD5, ACD6, ACD7
dd ACD8, ACD9, ACDA, ACDB, ACDC, ACDD, ACDE, ACDF
dd ACE0, ACE1, ACE2, ACE3, ACE4, ACE5, ACE6, ACE7
dd ACE8, ACE9, ACEA, ACEB, ACEC, ACED, ACEE, ACEF
dd ACF0, ACF1, ACF2, ACF3, ACF4, ACF5, ACF6, ACF7
dd ACF8, ACF9, ACFA, ACFB, ACFC, ACFD, ACFE, ACFF
; BGPAL[0x04] = BGPAL[0x08] = BGPAL[0x0C] = BGPAL[0x00];
; SPPAL[0x00] = SPPAL[0x04] = SPPAL[0x08] = SPPAL[0x0C] = BGPAL[0x00];
_PPU_WriteByte endp
_ReadPpuPort proc C _addr
` option prologue:none, epilogue:none
movzx eax, word ptr[esp+4] ; - N
jmp [PORT_INDEX_TABLE+eax*4-08000h] ; -N/V
align 16
PORT_INDEX_TABLE dd REG2000, REG2001, REG2002, REG2003
dd REG2004, REG2005, REG2006, REG2007
REG2000:
REG2001:
REG2003:
REG2005:
REG2006:
movzx eax, byte ptr [ppuREG+eax*4-08000h] ; - N
ret ; - N
align 16
REG2002:
push ecx ; - U save old frame
push ebx ; - V save old frame
lea ecx, ScreenOffset ; - U lea base index
nop ; - V spare
mov [ecx+8], 0 ; - U ScrLatch = 0 (<-->)
mov ebx, [ecx-24] ; - V load REG[2]
mov [ecx+20], 1 ; - U AddrLatch = 1 (high bit)
mov eax, ebx ; - V save old frame
and ebx, 07Fh ; - U clr V_BLANK Enable
nop ; - V spare
mov [ecx-24], ebx ; - U write REG[2]
pop ebx ; - V
pop ecx ; - U
ret ; - N
align 16
REG2004:
push ecx ; - U - save old frame
lea ecx, ppuREG ; - V/N - decom reg
mov eax, [ecx+12] ; - U
inc eax ; - U ++ addr
mov [ecx+12], eax ; - N
and eax, 0FFh
pop ecx
movzx eax, byte ptr [SRAM+eax*4-4] ; - N
ret
align 16
REG2007:
push ebx ; - U save old frame
lea ebx, ScreenOffset ; - V/N - decom reg
push ecx ; - U save old frame
mov ecx, [ebx] ; - V load low bit
push edx ; - U save old frame
mov ch, [ebx+4] ; - V load high bit
mov edx, ecx ; - U save old frame VRAM's address
push ecx ; - V call NES_READ_BYTE
call dword ptr [_PPU_ReadByte] ; - N
add esp, 4 ; - U call type __cdcel ++ stack
mov ecx, [ebx-4] ; - V save old frame REG[7]
mov [ebx-4], eax ; - U write REG[7]
and edx, 0FFFFh ; - V
lea eax, [edx-03F00h] ; - U
nop ; - V spare
cmp eax, 0FFh ; - U address >= 0x3F00 && address < 0x4000 ?
ja no_palette ; - V Y: set palette/mirror ... N: next step ...
mov eax, edx ; - U save old frame
mov ecx, edx ; - V save old frame
and eax, 16 ; - U is SPPal ? Y: D5 == 1 : D5 == 0
and ecx, 15 ; - V limit bit for PAL mirror
lea eax, [eax*4] ; - U D5 is 0 ? edx == 0 : edx == 64
mov eax, [BGPal+eax+ecx*4] ; N/V set val
mov ecx, eax ; - U
neg eax ; - N
no_palette:
mov eax, ecx ; - U set return val eax <- REG[7]
mov ecx, [ebx-32] ; - V load REG[0]
shr ecx, 3 ; - U shift PPU_INC32_BIT is setted ? C_flag == 1 : C_flag == 0
mov ebx, 1 ; - V reset 32 to be use
adc ecx, 0 ; - U if C_flag == 1 ? edx == 1 : edx == 0
nop ; - V spare
and ecx, 1 ; - U limit bit
nop ; - V spare
lea ecx, [ecx*2+ecx] ; - U 3 or 0 myabe delay
ror bl, cl ; - N 1 or 32
add edx, ebx ; - U add sum
pop ecx ; - V
lea ebx, ScreenOffset ; - U index base
mov [ebx+4], dl ; - V/N
mov [ebx], dh ; - U
pop edx ; - V
pop ebx ; - U
ret ; - N
_ReadPpuPort endp
_WritePpuPort proc C _addr, _val
` option prologue:none, epilogue:none
mov eax, [esp+4] ; - U load addr
push ebx ; - V save old frame
and eax, 0FFFFh ; - U limit bit
push ecx ; - V
lea ebx, [ppuREG]; - U
mov ecx, [esp+16]; - V load val
jmp [_PORT_INDEX_TABLE+eax*4-08000h] ; -N/V
align 16
_PORT_INDEX_TABLE dd _REG2000, _REG2001, _REG2002, _REG2003
dd _REG2004, _REG2005, _REG2006, _REG2007
_REG2000: ; revise nametable addr
push edx ; - U save old frame
mov edx, ecx ; - V save old frame
shl ecx, 10 ; - U shift opr
mov eax, [ebx+76] ; - V load pNameTable
and ecx, 0C00h ; - U switch nametable index
and eax, 0F3FFh ; - V clear ora nametable index
or eax, ecx ; - U get current nametable index
mov ecx, [ebx] ; - V load REG[0]
mov [ebx+68], eax ; - U write nametable pointer
xor ecx, 080h ; - V neg VBLANK status
mov eax, [ebx+76] ; - U load REG[2]
and ecx, edx ; - V test status
and eax, ecx ; - U test status
mov [ebx], edx ; - V write REG[0]
shr eax, 7 ; - U shift
pop edx ; - V recover old frame
and eax, 1 ; - U clr bit
mov ebx, INT_WARNING ; - V/N
pop ecx ; - U recover old frame
or eax, ebx ; - V test set NMI_FLAG
pop ebx ; - U recover old frame
mov INT_WARNING, eax ; - V write back
ret ; - N child ret
align 16
_REG2001:
mov [ebx+4], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2002:
mov [ebx+8], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2003:
mov [ebx+12], ecx ; - U write val
pop ecx ; - V
pop ebx ; - U
ret ; - N
align 16
_REG2005:
mov eax, [ebx+40] ; - U load ScrLatch
nop ; - V spare
mov [ebx+32+eax*4], ecx; - U write val to current scr direction
xor eax, 1 ; - V switch now's direction
and ecx, 0FFh ; - U clr bit
mov [ebx+40], eax ; - V write ScrLatch
jmp [_REG2005_SCROLL_DIRECT_TABLE+eax*4]; V/N select table do frame
align 16
_X_HIT:
shr ecx, 3 ; - U get Tile X
mov eax, [ebx+24] ; - V load REG[6]
and ecx, 01Fh ; - U clr bit
and eax, 0FFE0h ; - V clr bit
or eax, ecx ; - U set bit
pop ecx ; - V recover old frame
mov [ebx+24], eax ; - U REG[6]
pop ebx ; - V/N recover old frame
ret ; - return ...
_Y_HIT:
ror ecx, 3 ; - U get Tile Y 0x0000 0111 and Y Tile offset
mov eax, [ebx+24] ; - V load REG[6]
shl cx, 5 ; - U/N ...
and eax, 08C1Fh ; - V clr bit 1000 1100 0001 1111
or eax, ecx ; - U set bit
nop ; - V spare 1110 0000 0000 0000 0NNN 0000 0000 0000
shr ecx, 14 ; - U
nop ; - V spare
or eax, ecx ; - U set bit
pop ecx ; - V recover old frame
mov [ebx+24], eax ; - U write REG[6]
pop ebx ; - V/N recover old frame
ret ; - return ...
align 16
_REG2006:
mov eax, [ebx+52] ; - U load AddrLatch
nop ; - V spare
mov [ebx+44+eax*4], ecx; - U/N write val to current addr
xor eax, 1 ; - V switch now's addr write mode
mov [ebx+52], eax ; - U write AddrLatch
mov [ebx+72+eax], cl ; - V write mem high|low bit (byte)...
mov ecx, [ebx+72+eax] ; - U load m_RollReg
IF 0
and [ebx+73], 03Fh ; - V clr bit load mem-> opr -> write back maybe terribe ..
ELSE
nop ; - V spare
ENDIF
mov [ebx+68+eax*4], ecx; - U/N
pop ecx ; - V/U recover old frame
pop ebx ; - U/V recover old frame
ret ; - return .
align 16
_REG2004:
movzx eax, [ebx+12] ; - N load REG[3]
mov [SRAM+eax*4], ecx ; - U/N write val to spram
inc eax ; - V/N
mov [ebx+12], eax ; - U
pop ecx ; - V
pop ebx ; - U
ret ; - N
align 16
_REG2007:
push ecx ; - U arg1 -> _val
mov al, [ebx+44] ; - V/N get low bit
mov ecx, [ebx] ; - U load REG[0]
mov ah, [ebx+48] ; - V/N get high bit
and ecx, 4 ; - U PPU_INC32_BIT is setted ?
push eax ; - V arg2 -> address
add eax, [_REG2000_INC_TABLE+ecx*4] ; - U PPU_INC32_BIT is setted ?
mov [ebx+44], al
mov [ebx+48], ah
call dword ptr [_WritePpuPort] ; - N
add esp, 8
pop ecx ; - V
pop ebx ; - U
ret ; - N
_REG2005_SCROLL_DIRECT_TABLE dd _Y_HIT, _X_HIT
_REG2000_INC_TABLE dd 1,1,1,1,32
_WritePpuPort endp
_ResetPPU proc C
option prologue:none, epilogue:none
_ResetPPU endp
_FrameStart proc C
option prologue:none, epilogue:none
test [ppuREG+4], 018h
jne _use_render
ret
_use_render:
mov eax, dword ptr [m_RollReg]
mov dword ptr [m_EleGun], eax
ret
_FrameStart endp
_VBlankStart proc C
option prologue:none, epilogue:none
and [ppuREG+12], 10000000b
test dword ptr [ppuREG], 128
je _NORMAL_P
; NMI PROC
_NORMAL_P:
ret
_VBlankStart endp
_VBlankEnd proc C
option prologue:none, epilogue:none
and [ppuREG+12], 00111111b
ret
_VBlankEnd endp
_StructCopy proc _des, _src, _num
_StructCopy endp
_ScanlineStart proc C
option prologue:none, epilogue:none
lea eax, [ScreenOffset]
nop ; sapre
test dword ptr [eax+28], 24
jne _set_render
ret
_set_render:
push ebx
push ecx
mov ebx, [eax]
mov ecx, [eax+4]
mov [eax+24], ebx
mov [eax+28], ecx
mov ebx, [eax+36]
mov ecx, [eax+40]
and ebx, 0F3E0h
and ecx, 00C1Fh
and ebx, ecx
pop ecx
mov [eax+36], ebx
pop ebx
ret
_ScanlineStart endp
_ScanlineNext proc C
option prologue:none, epilogue:none
test dword ptr [eax+28], 24
jne _set_renderX
ret
align 16
_set_renderX:
mov eax, [m_EleGun] ;
push ebx
mov ebx, eax
and eax, 07000h
cmp eax, 07000h ; cross a Tile's whole Y Offset ? 8 ...
jne _inc_Now_Tile_Offset_Y
and ebx, 08FFFh
mov eax, ebx
and eax, 03E0h
cmp eax, 03A0h ; Tile Y Offset == 29 ?
jne _Not_29
xor ebx, 0800h ; switch vertical nametable
__RET:
and ebx, 0FC1F ; set Tile Y Offset = 0
mov [m_EleGun], ebx
pop ebx
ret
align 16
_Not_29:
cmp eax, 03E0h ; Tile Y Offset == 31 ?
jne _inc_Now_Tile
jmp __RET
_inc_Now_Tile:
lea eax, [ebx+32]
jmp _pXRet
_inc_Now_Tile_Offset_Y: ; ++ Tile's Y Offset
lea eax, [ebx+1000h]
_pXRet:
pop ebx
mov [m_EleGun], eax
ret
_ScanlineNext endp
评论
1 楼
黑色杰克史密斯
2015-07-27
/* Programmer Memory Map +---------+-------+-------+--------------------+ | Address | Size | Flags | Description | +---------+-------+-------+--------------------+ | $0000 | $1000 | C | Pattern Table #0 | | $1000 | $1000 | C | Pattern Table #1 | | $2000 | $3C0 | | Name Table #0 | | $23C0 | $40 | N | Attribute Table #0 | | $2400 | $3C0 | N | Name Table #1 | | $27C0 | $40 | N | Attribute Table #1 | | $2800 | $3C0 | N | Name Table #2 | | $2BC0 | $40 | N | Attribute Table #2 | | $2C00 | $3C0 | N | Name Table #3 | | $2FC0 | $40 | N | Attribute Table #3 | | $3000 | $F00 | R | | | $3F00 | $10 | | Image Palette #1 | | $3F10 | $10 | | Sprite Palette #1 | | $3F20 | $E0 | P | | | $4000 | $C000 | F | | +---------+-------+-------+--------------------+ C = Possibly CHR-ROM N = Mirrored (see Subsection G) P = Mirrored (see Subsection H) R = Mirror of $2000-2EFF (VRAM) F = Mirror of $0000-3FFF (VRAM) */ module ppu; class ppu { ubyte vram_pool[4096]; void set_vram_mapper_ptr (uint v0_inx, uint v1_inx, uint v2_inx, uint v3_inx) { v_ptr0 = vram_pool.ptr + (v0_inx << 10); v_ptr1 = vram_pool.ptr + (v1_inx << 10); v_ptr2 = vram_pool.ptr + (v2_inx << 10); v_ptr3 = vram_pool.ptr + (v3_inx << 10); } ubyte fetch_vram_byte(ushort addr) { addr &= 0x3FFF // limit mirror if(addr < 0x1000) // chr1_ptr return *(chr1_ptr + addr); if(addr < 0x2000) // chr2_ptr return *(chr2_ptr + addr); if(addr < 0x2400) // nametable/attribute table 1 return *(v_ptr0 + addr - 0x2000); if(addr < 0x2800) // nametable/attribute table 2 return *(v_ptr1 + addr - 0x2400); if(addr < 0x2C00) // nametable/attribute table 3 return *(v_ptr2 + addr - 0x2800); if(addr < 0x3000) // nametable/attribute table 4 return *(v_ptr3 + addr - 0x2C00); if(addr >= 0x3000) // is it a palette or $2000 - $2EFF 's mirror { if(addr >= 0x3F00) // is bg sp palette or it's mirror ? { if(0x0000 == (addr & 0x0010)) // bg palette { return bg_pal[addr & 0x000F]; } else // sp palette { return sp_pal[addr & 0x000F]; } } else // $2000 - $2EFF 's mirror { return fetch_vram_byte(addr - 0x1000); } } } void set_mirroring(uint mirror_type) { switch(mirror_type) { case FOUR_SCREEN: // four name_table linearly independent // vram layout --------- \ / \ / \ | <-------- / \ v0 | v1 \ _____|_____ \ | \ v2 | v3 \ | { set_vram_mapper_ptr (0, 1, 2, 3); } break; case HORIZ_MIRROR: { set_vram_mapper_ptr (0, 0, 1, 1); } break; case VERT_MIRROR: { set_vram_mapper_ptr (0, 1, 0, 1); } break; default: // error throw ... asm // xl-000-index { ud2; } break; } } ubyte read_ppu_port(ushort addr) // read ppu reg { switch(addr) { case 2: // $2002 { ubyte temp; latch_2005_2006 = 0; // reset latch_2005_2006 temp = ppu_reg[2]; ppu_reg[2] &= 0x7F; // clear v-blank flag return temp; } break; case 7: // $2007 /* * $2007 -> wiki.nesdev.com/w/index.php/PPU_registers#Data_.28.242007.29_.3C.3E_read.2Fwrite * palettes -> wiki.nesdev.com/w/index.php/PPU_palettes */ { ubyte temp; ushort n_vram_addr; real_vram_addr &= 0x3FFF // limit mirror n_vram_addr = real_vram_addr; // save temp val real_vram_addr += (ppu_reg[0] & 4 ? 32 : 1); // vram inc type : HORZ + 32 | VERT + 1 D2 -> ppu_reg[0] if(n_vram_addr >= 0x3000) // is it a palette or $2000 - $2EFF 's mirror { if(n_vram_addr >= 0x3F00) // is bg sp palette or it's mirror ? { if(0x0000 == (n_vram_addr & 0x0010)) // bg palette { return bg_pal[n_vram_addr & 0x000F]; } else // sp palette { return sp_pal[n_vram_addr & 0x000F]; } } else // $2000 - $2EFF 's mirror { n_vram_addr -= 0x1000; } } temp = io_2007_buffer; // switch(n_vram_addr) \ { \ \ } io_2007_buffer = fetch_vram_byte(n_vram_addr); return temp; } return ppu_reg[addr]; } } void write_ppu_port(ushort addr, ubyte val) // write ppu reg { switch(addr) { case 0: // $2000 -> http://wiki.nesdev.com/w/index.php/PPU_registers#Controller_.28.242000.29_.3E_write { bg_pat_pos = (cast(uint)(val & 0x10) << 8); // pointer ppu's $0000 || $1000 depending on ppu_reg[0] 's D4 bit sp_pat_pos = (cast(uint)(val & 0x08) << 9); // pointer ppu's $0000 || $1000 depending on ppu_reg[0] 's D3 bit vram_quadrant = val & 0x03; } break; case 1: // $2001 -> http://wiki.nesdev.com/w/index.php/PPU_registers#Mask_.28.242001.29_.3E_write { /* Color Tint Bits There are three color modulation channels controlled by the top three bits of $2001. Each channel uses one of the color square waves (see above diagram) and enables attenuation of the video signal when the color square wave is high. A single attenuator is shared by all channels. $2001 Active phase Complement Bit 7 Color 8 Color 2 (blue) Bit 6 Color 4 Color A (green) Bit 5 Color C Color 6 (red) When signal attenuation is enabled by one or more of the channels and the current pixel is a color other than $xE/$xF (black), the signal is attenuated as follows (calculations given for both relative and absolute values as shown in the voltage table above): relative = relative * 0.746 normalized = normalized * 0.746 - 0.0912 For example, when $2001 bit 6 is true, the attenuator will be active during the phases of color 4. This means the attenuator is not active during its complement (color A), and the screen appears to have a tint of color A, which is green. Note that on the Dendy and PAL NES, the green and red bits swap meaning. */ } } } ubyte* v_ptr0; ubyte* v_ptr1; ubyte* v_ptr2; ubyte* v_ptr3; ubyte* chr1_ptr; ubyte* chr2_ptr; uint bg_pat_pos; uint sp_pat_pos; uint vram_quadrant; uint cur_line_video_buf[256+8]; uint cur_line_video_buf_attr[256+8]; }
发表评论
-
我发现表达能力也是非常重要的 ...
2015-07-31 11:27 5有些连之乎者也都蹦不利索的人 出的书籍都什么玩意 ? ... ... -
CMOVcc 这条指令真的使用来加速的么 ?
2015-06-04 18:06 783怎么慢的跟狗一样 ... -
Dinput8 杂
2015-05-17 16:53 62310 12 00 00 _c_rgod ... -
很想知道罗云彬老师的近况
2015-05-10 20:23 25磕磕碰碰地读了一点的他写的汇编书 得到不少有益的提示 ... ... -
D语言 bindings库 XAudio2 无法发音 ...
2015-05-07 15:39 606头文件 XAudio2.d 里 interface IXAud ... -
6502 masm
2015-04-24 21:48 87.686 ... -
masm 像素碰撞检测
2015-04-13 22:00 609256 * 240 的 directx surface _ ... -
masm10.0
2015-04-13 21:48 370masm 下载 是从 vs10 里抠出来的 裸程序 ml.e ...
相关推荐
标题中的"ppu.zip_PPU_nes_任天堂"表明这是一个与任天堂NES(Nintendo Entertainment System)游戏机的PPU(Picture Processing Unit,图像处理单元)相关的文件集合。PPU是NES硬件的核心部分,负责处理游戏画面的...
1. **理解NES硬件**:包括CPU(6502)、APU(音频处理器)、PPU(图像处理器)的工作原理,以及它们之间的交互。 2. **实现CPU模拟**:根据6502指令集编写代码,使得STM32F103能够正确执行NES游戏的指令。 3. **图形...
在STM32_NES项目中,开发者需要编写一个NES模拟器,该模拟器能准确地重现NES硬件的逻辑,包括CPU、音频处理器(APU)、图形处理器(PPU)以及输入/输出(I/O)系统。 STM32_NES游戏项目的实现可能包括以下几个关键...
这涉及到对NES的PPU(Picture Processing Unit)的模拟,包括模式表、颜色表、背景层、精灵层的处理,以及扫描线和帧同步的管理。 4. **声音播放**:NES的音频由APU(Audio Processing Unit)负责,模拟器需要模拟...
例如,早期的PPU如NES的PPU在色彩和图形处理能力上相对有限,而后来的如PS2的PPU则能支持更复杂的3D图形和更高的分辨率。 其次,"万能PPU"可能是指一个通用的PPU模拟器或库,它可以兼容多种游戏机的PPU功能,使得...
NES的内存包括ROM、RAM和PPU内存,其中ROM存储游戏程序和数据,RAM用于运行时的数据存储,而PPU内存则用于存储图像和颜色信息。开发者需要学习如何有效地管理这些有限的内存资源,以实现高效的游戏逻辑和视觉效果。 ...
- 在硬件层面,NES中的CPU和PPU是同时运行的,这意味着游戏可以在特定时间写入PPU寄存器,从而在屏幕上的特定位置产生效果。 - 初始想法是,在每个NES时钟周期交替执行CPU和PPU引擎,这样可以获得非常精确的模拟...
STM32 NES PPU GBA 是一个基于STM32微控制器的项目,旨在实现经典游戏机任天堂(Nintendo)的图形处理单元(PPU)功能,并可能与Game Boy Advance(GBA)的游戏兼容。这个项目涉及到嵌入式系统设计、微控制器编程...
除了CPU,NES还配备了定制的PPU(Picture Processing Unit)图形处理单元,负责图像的生成和显示。PPU能够处理256×240像素的分辨率,支持多达64种颜色,其中屏幕可同时显示56种。PPU的性能虽然在当时看来并不算顶尖...
nes4j是使用java语言实现任天堂红白机模拟器,主要包括CPU、 PPU和APU三部分组成.其中PPU是红白机 实现难度最大的一个模块,理解起来有点困难. 项目结构 nes4j ├── app UI模块(javafx) ├── bin 模拟器核心模块...
nes ROM文件通常以NES为扩展名,其中包含了6502微处理器的机器语言代码,以及PPU(Picture Processing Unit,图像处理单元)的数据。模拟器需要解码这些指令,并模拟CPU的执行过程,同时还要模拟PPU来渲染游戏画面。...
- **图形处理器(PPU)**:NES的图像处理部分由PPU完成,它能够显示最高64种颜色,支持8x8像素和8x16像素的图块(tile)显示,屏幕分辨率最高为256x240像素。 - **音频处理器(pAPU)**:NES的音频处理由pAPU负责,它提供...
NES模拟器的核心是实现CPU、PPU(Picture Processing Unit)、APU(Audio Processing Unit)以及I/O设备的精确模拟。 4. FC模拟器:FC是NES在中国的别称,全称为Family Computer,因此FC模拟器和NES模拟器是同一...
通过查看和分析代码,他们可以了解到如何处理CPU指令、APU(Audio Processing Unit)音频处理、PPU(Picture Processing Unit)图形渲染以及与游戏ROM的交互等核心功能。 在压缩包内的文件中,我们看到了如"APU.h...
NES模拟器本身是软件层面的重点,它需要实现对原始NES游戏机的CPU、PPU(Picture Processing Unit,图像处理单元)和APU(Audio Processing Unit,音频处理单元)的精确模拟。这个过程涉及对原始NES硬件指令集的理解...
【描述】nintengo的核心功能是通过软件模拟nes硬件,包括CPU、图形处理器PPU、音频处理单元APU以及输入设备等,从而实现nes游戏在非nes硬件上的运行。这个项目是开源的,意味着它的源代码对公众开放,开发者可以查看...
nescube12_package通过模拟NES的硬件架构,如CPU、PPU(图像处理器)、APU(音频处理器)以及输入控制器等,来实现游戏的仿真运行。 转换过程非常简单,只需要将你的NES游戏文件放入一个名为"nes"的文件夹中,然后...
2. PPU模块:处理图形渲染,包括屏幕更新、颜色映射和精灵处理。 3. APU模块:生成音频输出,模拟原版的声音效果。 4. 输入模块:处理用户输入,如键盘、鼠标或游戏控制器,以匹配NES的控制布局。 5. 文件I/O模块:...
2. **内存管理**:模拟NES的内存布局,包括RAM、ROM和PPU(Picture Processing Unit)内存。 3. **图形处理**:重现PPU的工作机制,包括扫描线、颜色、模式表和背景图层的管理。 4. **声音合成**:模拟APU(Audio ...
1. **硬件仿真**:模拟器需要理解并再现NES的硬件架构,包括CPU( Ricoh 2A03),图形处理器(PPU),音频芯片(2C02 APU),以及内存映射和输入设备接口。这涉及到对8位微处理器的工作原理、图形渲染流程和音频处理...