- 浏览: 15133 次
.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 721怎么慢的跟狗一样 ... -
Dinput8 杂
2015-05-17 16:53 59010 12 00 00 _c_rgod ... -
很想知道罗云彬老师的近况
2015-05-10 20:23 25磕磕碰碰地读了一点的他写的汇编书 得到不少有益的提示 ... ... -
D语言 bindings库 XAudio2 无法发音 ...
2015-05-07 15:39 503头文件 XAudio2.d 里 interface IXAud ... -
6502 masm
2015-04-24 21:48 87.686 ... -
masm 像素碰撞检测
2015-04-13 22:00 571256 * 240 的 directx surface _ ... -
masm10.0
2015-04-13 21:48 327masm 下载 是从 vs10 里抠出来的 裸程序 ml.e ...
相关推荐
任天堂nes系统,顶层模块代码,希望大家能用得着
首先先大致解释一下NES游戏机(即我们俗称的“小霸王”)的构成以,NES使用6502的CPU以及一块专门负责显示的PPU,两者均可寻址16K的内存,但实际内存没有这么多。CPU能访问的两块内存分别为程序段ROM,以及运行时所...
nes4j是使用java语言实现任天堂红白机模拟器,主要包括CPU、 PPU和APU三部分组成.其中PPU是红白机 实现难度最大的一个模块,理解起来有点困难. 项目结构 nes4j ├── app UI模块(javafx) ├── bin 模拟器核心模块...
任天堂游戏机软硬件英文资料,cpu、ppu资料
用java 模拟 nes模拟器(小霸王模拟器) 模拟6502cpu,ppu,apu 实现了mapper4映射 内附魂斗罗rom,代码可能有部分bug,优化没有制作,仅供参考
NES-FPGA 概述 这是我们在 DE2i-150 板上创建 NES 仿真器的尝试,该板由具有 VGA、SD 卡和 GPIO 支持的 Altera Cyclone IV FPGA 组成。 现状与发展 用于 ROM 的 SD 卡控制器完全正常工作。 ROM 解析和获取完全正常...
NesTs任天堂娱乐系统(NES)模拟器 ... PPU 虚拟RAM 背景 精灵 NTSC电视伪像效果 强调RGB /灰度 APU 脉冲通道 三角通道 噪音通道 三角洲模拟通道 输入项 记忆 弹药筒 电池供电的保存R
这是我对NES控制台的实现,它同时模拟了原始CPU和PPU。 这个git repo没有前端,因为我希望它尽可能裸露。 我开始使用React.js实现UI,您可以在找到源代码。入门正在安装纱yarn install nes-emulatorNPM npm install...
詹纳斯JS NES模拟器(进行中) 技术说明: 核心系统架构: CPU PPU-图片处理单元pAPU-伪音频处理单元RAM游戏ROM控制器一些开发人员注意: -内存是小端字节-8位数据总线,8位控制总线,16位寻址总线地址范围:$ 0000-...
映射器支持支持以下iNES映射器: -超级马里奥兄弟,大金刚,间谍与间谍 -塞尔达传说,恶魔城2,俄罗斯方块 -恶魔城,洛克人,魂斗罗 -超级马里奥兄弟2,超级马里奥兄弟3,洛克人3准确性NES CPU和PPU已在相当精确的...
扫描线精确 PPU (2C02) 仿真 Blagg 的 Nes_snd_emu 库的出色声音再现护理 窗口和全屏显示模式 支持 USB 游戏手柄和操纵杆控制 支持为 NROM、UxROM、CNROM、AxROM、SNROM、SUROM、TxROM、VRC1、VRC2a、VRC2b 和 iNES ...
嵌入式NES 用于嵌入式处理器的便携式NES模拟器。更新日志18-05-2018 PPU性能提升为单个精灵添加缓冲区清除代码,删除未使用的宏开关,即JEG_USE_DIRTY_MATRIX 16-05-2018添加更多默认ROM 添加两个默认ROM ROM1:城市...
NES仿真器 学习项目以构建Nintendo Entertainment System模拟器。 控制项 Arrow keys -D-pad S开始A选择Z按钮B X按钮A R重置Esc退出 去做 中央处理器 在终端中显示RAM和CPU状态以进行调试 ROM读取器和映射器 ...
Rust NES模拟器 请以获得可播放的演示。 不使用任何花哨的ppu技巧的游戏,包括Donkey Kong和Super MarioBros。仅支持mapper 0。 不支持声音。 超级马里奥兄弟关卡 仿真器可以从文件中读取超级马里奥兄弟的关卡并将...
鲁斯内斯用Rust编写的NES模拟器要求Rust 1.48.0以后去做 中央处理器 只读存储器 嵌套运行 PPU PPU 渲染图 APU执照作者
内斯浏览器中的javascript中的另一个NES模拟器。 CPU几乎模拟了所有指令,但是它不是周期精确的(并且不模拟“不稳定”的未记录指令)。 PPU具有完整的背景和精灵渲染,但它也不精确。 APU模拟所有5个通道,但是仍然...
我的X NES My X Nes是可移植的开源NES / FAMICOM模拟器,它使用C#编写,使用Windows和Xbox 360平台的XNA Framework。 我的X Nes是“我的Nes”模拟器的端口,请参阅 请注意,这是一个过时的项目,不再在开发...PPU:
用Java编写的实验性NES模拟器 目录 产品特点 核心 使用基本反编译器的6502 CPU仿真 2C02 PPU仿真 具有2个脉冲通道,一个三角形通道,一个噪声通道和一个DMC(或PCM)通道的2A03 APU仿真 模拟支持它的游戏的节省(每...
扫描线精确 PPU (2C02) 仿真 Blagg 的 Nes_snd_emu 库的出色声音再现护理 支持在电视上播放的外部视频(需要 HDMI 适配器) 支持触摸和 iCade 控件 支持为 NROM、UxROM、CNROM、AxROM、SNROM、SUROM、TxROM、VRC1、...
eyl NES仿真器为Wayland编写的在进行中的NES模拟器,用C编写。执照所有代码均已获得GPLv3许可。 所有文档均根据CC BY-SA 4.0许可。测验当前,仿真器通过了所有nestest CPU测试。 大多数PPU测试通过(NMI计时和Sprite...