`
黑色杰克史密斯
  • 浏览: 15133 次
社区版块
存档分类
最新评论

NES PPU 杂

    博客分类:
  • n/a
 
阅读更多
      .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
分享到:
评论
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];
}

相关推荐

    ppu.zip_PPU_nes_任天堂

    任天堂nes系统,顶层模块代码,希望大家能用得着

    基于FPGA的NES游戏机系统,附带超级玛丽,坦克大战,吃豆等11个游戏

    首先先大致解释一下NES游戏机(即我们俗称的“小霸王”)的构成以,NES使用6502的CPU以及一块专门负责显示的PPU,两者均可寻址16K的内存,但实际内存没有这么多。CPU能访问的两块内存分别为程序段ROM,以及运行时所...

    基于java语言实现任天堂红白机模拟器,包括CPU、 PPU和APU三部分组成,已实现卡带Mapper

    nes4j是使用java语言实现任天堂红白机模拟器,主要包括CPU、 PPU和APU三部分组成.其中PPU是红白机 实现难度最大的一个模块,理解起来有点困难. 项目结构 nes4j ├── app UI模块(javafx) ├── bin 模拟器核心模块...

    nes document

    任天堂游戏机软硬件英文资料,cpu、ppu资料

    使用java模拟nes(小霸王模拟器).zip

    用java 模拟 nes模拟器(小霸王模拟器) 模拟6502cpu,ppu,apu 实现了mapper4映射 内附魂斗罗rom,代码可能有部分bug,优化没有制作,仅供参考

    NES_FPGA:Cyclone IV FPGA 上的 NES 仿真器

    NES-FPGA 概述 这是我们在 DE2i-150 板上创建 NES 仿真器的尝试,该板由具有 VGA、SD 卡和 GPIO 支持的 Altera Cyclone IV FPGA 组成。 现状与发展 用于 ROM 的 SD 卡控制器完全正常工作。 ROM 解析和获取完全正常...

    nests:用TypeScriptReact编写的NES模拟器

    NesTs任天堂娱乐系统(NES)模拟器 ... PPU 虚拟RAM 背景 精灵 NTSC电视伪像效果 强调RGB /灰度 APU 脉冲通道 三角通道 噪音通道 三角洲模拟通道 输入项 记忆 弹药筒 电池供电的保存R

    nes:Javascript NES模拟器

    这是我对NES控制台的实现,它同时模拟了原始CPU和PPU。 这个git repo没有前端,因为我希望它尽可能裸露。 我开始使用React.js实现UI,您可以在找到源代码。入门正在安装纱yarn install nes-emulatorNPM npm install...

    theJSnes:JS NES模拟器(进行中)

    詹纳斯JS NES模拟器(进行中) 技术说明: 核心系统架构: CPU PPU-图片处理单元pAPU-伪音频处理单元RAM游戏ROM控制器一些开发人员注意: -内存是小端字节-8位数据总线,8位控制总线,16位寻址总线地址范围:$ 0000-...

    nescafe:用C#编写的NES模拟器

    映射器支持支持以下iNES映射器: -超级马里奥兄弟,大金刚,间谍与间谍 -塞尔达传说,恶魔城2,俄罗斯方块 -恶魔城,洛克人,魂斗罗 -超级马里奥兄弟2,超级马里奥兄弟3,洛克人3准确性NES CPU和PPU已在相当精确的...

    macifom:用 Objective-C 编写的用于 OS X 的高精度 NES 模拟器

    扫描线精确 PPU (2C02) 仿真 Blagg 的 Nes_snd_emu 库的出色声音再现护理 窗口和全屏显示模式 支持 USB 游戏手柄和操纵杆控制 支持为 NROM、UxROM、CNROM、AxROM、SNROM、SUROM、TxROM、VRC1、VRC2a、VRC2b 和 iNES ...

    EmbeddedNES:用于嵌入式处理器的便携式NES模拟器

    嵌入式NES 用于嵌入式处理器的便携式NES模拟器。更新日志18-05-2018 PPU性能提升为单个精灵添加缓冲区清除代码,删除未使用的宏开关,即JEG_USE_DIRTY_MATRIX 16-05-2018添加更多默认ROM 添加两个默认ROM ROM1:城市...

    nes-emulator:任天堂娱乐系统模拟器

    NES仿真器 学习项目以构建Nintendo Entertainment System模拟器。 控制项 Arrow keys -D-pad S开始A选择Z按钮B X按钮A R重置Esc退出 去做 中央处理器 在终端中显示RAM和CPU状态以进行调试 ROM读取器和映射器 ...

    rust-nes-emulator:Rust NES模拟器

    Rust NES模拟器 请以获得可播放的演示。 不使用任何花哨的ppu技巧的游戏,包括Donkey Kong和Super MarioBros。仅支持mapper 0。 不支持声音。 超级马里奥兄弟关卡 仿真器可以从文件中读取超级马里奥兄弟的关卡并将...

    rustnes:用Rust编写的[WIP] NES模拟器

    鲁斯内斯用Rust编写的NES模拟器要求Rust 1.48.0以后去做 中央处理器 只读存储器 嵌套运行 PPU PPU 渲染图 APU执照作者

    NesJs:JavaScript中的另一个NES模拟器

    内斯浏览器中的javascript中的另一个NES模拟器。 CPU几乎模拟了所有指令,但是它不是周期精确的(并且不模拟“不稳定”的未记录指令)。 PPU具有完整的背景和精灵渲染,但它也不精确。 APU模拟所有5个通道,但是仍然...

    My-X-Nes:XNA框架4上My Nes项目的端口

    我的X NES My X Nes是可移植的开源NES / FAMICOM模拟器,它使用C#编写,使用Windows和Xbox 360平台的XNA Framework。 我的X Nes是“我的Nes”模拟器的端口,请参阅 请注意,这是一个过时的项目,不再在开发...PPU:

    NEmuS:JAVA NES仿真器

    用Java编写的实验性NES模拟器 目录 产品特点 核心 使用基本反编译器的6502 CPU仿真 2C02 PPU仿真 具有2个脉冲通道,一个三角形通道,一个噪声通道和一个DMC(或PCM)通道的2A03 APU仿真 模拟支持它的游戏的节省(每...

    macifomlite:用 Objective-C 编写的适用于 iOS 的高精度 NES 模拟器

    扫描线精确 PPU (2C02) 仿真 Blagg 的 Nes_snd_emu 库的出色声音再现护理 支持在电视上播放的外部视频(需要 HDMI 适配器) 支持触摸和 iCade 控件 支持为 NROM、UxROM、CNROM、AxROM、SNROM、SUROM、TxROM、VRC1、...

    eyl-nes-emulator:进行中的NES模拟器

    eyl NES仿真器为Wayland编写的在进行中的NES模拟器,用C编写。执照所有代码均已获得GPLv3许可。 所有文档均根据CC BY-SA 4.0许可。测验当前,仿真器通过了所有nestest CPU测试。 大多数PPU测试通过(NMI计时和Sprite...

Global site tag (gtag.js) - Google Analytics