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

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_任天堂

    标题中的"ppu.zip_PPU_nes_任天堂"表明这是一个与任天堂NES(Nintendo Entertainment System)游戏机的PPU(Picture Processing Unit,图像处理单元)相关的文件集合。PPU是NES硬件的核心部分,负责处理游戏画面的...

    基于STM32F103的NES(FC)模拟器

    1. **理解NES硬件**:包括CPU(6502)、APU(音频处理器)、PPU(图像处理器)的工作原理,以及它们之间的交互。 2. **实现CPU模拟**:根据6502指令集编写代码,使得STM32F103能够正确执行NES游戏的指令。 3. **图形...

    STM32_NES游戏.rar_STM32_NES_nes_stm32 小 游戏_stm32nes_stm32nes文件

    在STM32_NES项目中,开发者需要编写一个NES模拟器,该模拟器能准确地重现NES硬件的逻辑,包括CPU、音频处理器(APU)、图形处理器(PPU)以及输入/输出(I/O)系统。 STM32_NES游戏项目的实现可能包括以下几个关键...

    nes模拟器.rar

    这涉及到对NES的PPU(Picture Processing Unit)的模拟,包括模式表、颜色表、背景层、精灵层的处理,以及扫描线和帧同步的管理。 4. **声音播放**:NES的音频由APU(Audio Processing Unit)负责,模拟器需要模拟...

    33个机型的原机PPU下载

    例如,早期的PPU如NES的PPU在色彩和图形处理能力上相对有限,而后来的如PS2的PPU则能支持更复杂的3D图形和更高的分辨率。 其次,"万能PPU"可能是指一个通用的PPU模拟器或库,它可以兼容多种游戏机的PPU功能,使得...

    NES资料说明含程序讲义

    NES的内存包括ROM、RAM和PPU内存,其中ROM存储游戏程序和数据,RAM用于运行时的数据存储,而PPU内存则用于存储图像和颜色信息。开发者需要学习如何有效地管理这些有限的内存资源,以实现高效的游戏逻辑和视觉效果。 ...

    NES模拟器开发入门

    - 在硬件层面,NES中的CPU和PPU是同时运行的,这意味着游戏可以在特定时间写入PPU寄存器,从而在屏幕上的特定位置产生效果。 - 初始想法是,在每个NES时钟周期交替执行CPU和PPU引擎,这样可以获得非常精确的模拟...

    电子-STM32NESppugba.rar

    STM32 NES PPU GBA 是一个基于STM32微控制器的项目,旨在实现经典游戏机任天堂(Nintendo)的图形处理单元(PPU)功能,并可能与Game Boy Advance(GBA)的游戏兼容。这个项目涉及到嵌入式系统设计、微控制器编程...

    nes document

    除了CPU,NES还配备了定制的PPU(Picture Processing Unit)图形处理单元,负责图像的生成和显示。PPU能够处理256×240像素的分辨率,支持多达64种颜色,其中屏幕可同时显示56种。PPU的性能虽然在当时看来并不算顶尖...

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

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

    nes模拟器mrp格式

    nes ROM文件通常以NES为扩展名,其中包含了6502微处理器的机器语言代码,以及PPU(Picture Processing Unit,图像处理单元)的数据。模拟器需要解码这些指令,并模拟CPU的执行过程,同时还要模拟PPU来渲染游戏画面。...

    nes系统概述

    - **图形处理器(PPU)**:NES的图像处理部分由PPU完成,它能够显示最高64种颜色,支持8x8像素和8x16像素的图块(tile)显示,屏幕分辨率最高为256x240像素。 - **音频处理器(pAPU)**:NES的音频处理由pAPU负责,它提供...

    【(首发)基于stm32H750 NES模拟器,支持重装机兵吞食天地2等游戏 】

    NES模拟器的核心是实现CPU、PPU(Picture Processing Unit)、APU(Audio Processing Unit)以及I/O设备的精确模拟。 4. FC模拟器:FC是NES在中国的别称,全称为Family Computer,因此FC模拟器和NES模拟器是同一...

    FC/NES模拟器0.01版本

    通过查看和分析代码,他们可以了解到如何处理CPU指令、APU(Audio Processing Unit)音频处理、PPU(Picture Processing Unit)图形渲染以及与游戏ROM的交互等核心功能。 在压缩包内的文件中,我们看到了如"APU.h...

    STM32F103VET6移植NES模拟器内置游戏资源---使用SPI屏 无声音无文件系统

    NES模拟器本身是软件层面的重点,它需要实现对原始NES游戏机的CPU、PPU(Picture Processing Unit,图像处理单元)和APU(Audio Processing Unit,音频处理单元)的精确模拟。这个过程涉及对原始NES硬件指令集的理解...

    NES模拟器nintengo.zip

    【描述】nintengo的核心功能是通过软件模拟nes硬件,包括CPU、图形处理器PPU、音频处理单元APU以及输入设备等,从而实现nes游戏在非nes硬件上的运行。这个项目是开源的,意味着它的源代码对公众开放,开发者可以查看...

    NES转JAR工具nescube12_package

    nescube12_package通过模拟NES的硬件架构,如CPU、PPU(图像处理器)、APU(音频处理器)以及输入控制器等,来实现游戏的仿真运行。 转换过程非常简单,只需要将你的NES游戏文件放入一个名为"nes"的文件夹中,然后...

    nes模拟器的代码

    2. PPU模块:处理图形渲染,包括屏幕更新、颜色映射和精灵处理。 3. APU模块:生成音频输出,模拟原版的声音效果。 4. 输入模块:处理用户输入,如键盘、鼠标或游戏控制器,以匹配NES的控制布局。 5. 文件I/O模块:...

    nes学习资料

    2. 图形处理器:NES有一个定制的图形处理单元(PPU),能处理色彩、背景、精灵等图像元素,最大显示色彩数为256色,屏幕分辨率通常为256x240像素。 3. 音频:内置一颗音频芯片,能够产生多种音效,是NES游戏独特...

    正点原子探索者之实验59 综合测试实验(含NES模拟器)

    2. **内存管理**:模拟NES的内存布局,包括RAM、ROM和PPU(Picture Processing Unit)内存。 3. **图形处理**:重现PPU的工作机制,包括扫描线、颜色、模式表和背景图层的管理。 4. **声音合成**:模拟APU(Audio ...

Global site tag (gtag.js) - Google Analytics