Function PPUread(ByVal addr As UInteger) As UByte
	addr = addr And &h3FFF
	If (addr >= &h3F00) Then addr = (addr And &h1F) + &h3F00
	If (addr > &h2FFF) And (addr < &h3F00) Then addr = (addr And &hEFF) + &h3000
	If (addr = &h3F04) Or (addr = &h3F08) Or _
		(addr = &h3F0C) Or (addr = &h3F14) Or (addr = &h3F18) Then addr = &h3F00
	If addr = &h3F10 Then addr = &h3F00
	If (ROM.chrcount > 0) And (addr < &h2000) Then
'	If addr < &h2000 Then
		PPUread = CHRMEM(CHRbank(addr Shr 10) + (addr Mod 1024))
	Else
		PPUread = VRAM(addr)
	End If
End Function

Sub PPUwrite(ByVal addr As UInteger, ByVal value As UByte)
	addr = addr And &h3FFF
	If (addr >= &h3F00) Then addr = (addr And &h1F) + &h3F00
	If (addr > &h2FFF) And (addr < &h3F00) Then addr = (addr And &hEFF) + &h3000
	If addr = &h3F10 Then addr = &h3F00
	Select Case addr
		Case Is < &h2000
			If ROM.chrcount = 0 Then
				CHRMEM(CHRbank(addr Shr 10) + (addr Mod 1024)) = value
			End If
		Case &h2000 To &h23FF: addr = (addr - &h2000) + ntmap(0)
		Case &h2400 To &h27FF: addr = (addr - &h2400) + ntmap(1)
		Case &h2800 To &h2BFF: addr = (addr - &h2800) + ntmap(2)
		Case &h2C00 To &h2FFF: addr = (addr - &h2C00) + ntmap(3)
		Case &h3F00: VRAM(&h3F10) = value
		Case &h3F10: VRAM(&h3F00) = value
	End Select
	VRAM(addr) = value
End Sub

Function PPUreadreg(ByVal addr As UInteger) As UByte
	addr = addr And 7
	Select Case As Const addr
		Case 2
			PPUreadreg = PPU.vblank*128 + PPU.spr0hit*64 + PPU.sprcount*32 + (PPUregs(2) And &h1F)
			PPU.vblank = 0
			PPU.latch = 0
			PPU.scrolllatch = 0
		Case 4
			PPUreadreg = spriteRAM(spriteaddr)
			'If PPU.vblank = 0 Then spriteaddr = spriteaddr + 1
		Case 7
			PPUreadreg = PPUread(VRAMaddr)
			VRAMaddr = (VRAMaddr + PPU.addrinc) Mod 16384
		Case Else
			PPUreadreg = PPUregs(addr)
	End Select
End Function

Sub PPUwritereg(ByVal addr As UInteger, ByVal value As UInteger)
	addr = addr And 7
	PPUregs(addr) = value
	Select Case As Const addr
		Case 0
			PPU.nmivblank = value Shr 7
			If (value And 32) = 32 Then PPU.sprsize = 16 Else PPU.sprsize = 8
			PPU.bgtable = ((value Shr 4) And 1) * &h1000
			PPU.sprtable = ((value Shr 3) And 1) * &h1000
			If (value And 4) = 4 Then PPU.addrinc = 32 Else PPU.addrinc = 1
			PPU.nametable = value And 3
		Case 1
			PPU.sprvisible = (value Shr 4) And 1
			PPU.bgvisible = (value Shr 3) And 1
			PPU.sprclip = (value Shr 2) And 1
			PPU.bgclip = (value Shr 1) And 1
		Case 3
			spriteaddr = value
		Case 4
			spriteRAM(spriteaddr) = value
			spriteaddr = (spriteaddr + 1) Mod 256
		Case 5
			If PPU.latch = 0 Then
				PPU.hscroll = value
				PPU.latch = 1
			Else
				PPU.vscroll = value
				PPU.latch = 0
			End If
		Case 6
			If PPU.latch = 0 Then
				VRAMaddr = (VRAMaddr And &hFF) Or (value Shl 8)
				PPU.latch = 1
			Else
				VRAMaddr = (VRAMaddr And &hFF00) Or value
				PPU.latch = 0
			End If
		Case 7
			PPUwrite(VRAMaddr, value)
			VRAMaddr = (VRAMaddr + PPU.addrinc) Mod 16384
	End Select
End Sub

#Macro drawsprites(sl)
	sl = sl - 1
	If PPU.sprclip Then st = 8 Else st = 0
	sprnum = 0
	For idx = 63 To 0 Step -1
		tmpidx = idx Shl 2
		spry = spritebuffer(tmpidx)
		sprtile = spritebuffer(tmpidx+1)
		sprpal = spritebuffer(tmpidx+2) And 3
		sprpri = (spritebuffer(tmpidx+2) Shr 5) And 1
		sprflipx = (spritebuffer(tmpidx+2) Shr 6) And 1
		sprflipy = spritebuffer(tmpidx+2) Shr 7
		sprx = spritebuffer(tmpidx+3)
		If PPU.sprsize = 16 Then
			dosprite = 2
			sprtile = sprtile And &hFE
			If sprflipy Then sprtile = sprtile + 1
		Else
			dosprite = 1
		End If
			While dosprite
				If (sl >= spry) And (sl <= (spry+7)) Then
					If sl < 239 Then sprnum = sprnum + 1
					If sprnum > 8 Then PPU.sprcount = 1: Exit For
					boundxr = sprx + 7
					liney = sl - spry
					If sprflipy Then liney = 7 - liney
					plotx = boundxr
					For xval = sprx To boundxr
						patternoffset = PPU.sprtable + (sprtile Shl 4) + liney
						usebank = patternoffset Shr 10
						usebankmod = patternoffset Mod 1024
						tmpx = xval - sprx
						pixel = (CHRMEM(chrbank(usebank) + usebankmod) Shr (7 - tmpx)) And 1
						pixel = pixel + (((CHRMEM(chrbank(usebank) + usebankmod+8) Shr (7 - tmpx)) And 1) Shl 1)
						If pixel > 0 Then
							coloraddr = &h3F10 + pixel + (sprpal Shl 2)
							If sprflipx = 0 Then plotx = xval
							If plotx >= st Then
								If pri = 1 Then sprback(plotx) = VRAM(coloraddr) Else sprfront(plotx) = VRAM(coloraddr)
								If idx = 0 Then PPU.spr0hit = 1
							End If
						End If
						plotx = plotx - 1
					Next xval
				End If
				dosprite = dosprite - 1: spry = spry + 8
				If sprflipy Then sprtile = sprtile - 1 Else sprtile = sprtile + 1
			Wend
	Next idx
	sl = sl + 1
#EndMacro

#Macro drawbackground(dy, dx)
	Select Case As Const PPU.nametable
		Case 0: calcx = dx: calcy = dy
		Case 1: calcx = dx + 256: calcy = dy
		Case 2: calcx = dx: calcy = dy + 240
		Case 3: calcx = dx + 256: calcy = dy + 240
	End Select
	calcx = (calcx + PPU.hscroll) Mod 512
	calcy = (calcy + PPU.vscroll) Mod 480
	If (calcx < 256) And (calcy < 240) Then
		usent = 0
	ElseIf (calcx > 255) And (calcy < 240) Then
		usent = 1
	ElseIf (calcx < 256) And (calcy > 239) Then
		usent = 2
	ElseIf (calcx > 255) And (calcy > 239) Then
		usent = 3
	End If
	calcx = calcx Mod 256
	calcy = calcy Mod 240
	tmpcalcx = calcx Mod 8
	ntaddr = ntmap(usent)
	ntval = VRAM(ntaddr + ((calcy And 248) Shl 2) + (calcx Shr 3))
	patternoffset = PPU.bgtable + (ntval Shl 4) + (calcy Mod 8)
	patternoffset = chrbank(patternoffset Shr 10) + (patternoffset Mod 1024)
	usebank = patternoffset Shr 10
	usebankmod = patternoffset Mod 1024
	pixel = (CHRMEM(patternoffset) Shr (7 - tmpcalcx)) And 1
	patternoffset = patternoffset + 8
	usebank = patternoffset Shr 10
	usebankmod = patternoffset Mod 1024
	pixel = pixel + (((CHRMEM(patternoffset) Shr (7 - tmpcalcx)) And 1) Shl 1)
	'If (pixel And 3) > 0 Then
		attribx = calcx Shr 5: attriby = calcy Shr 5
		attribbyte = VRAM(ntaddr + &h3C0 + (attriby Shl 3) + attribx)
		attribbyte = attribbyte Shr (((calcx And 16) Shr 3) Or ((calcy And 16) Shr 2)) And 3
		pixel = pixel + (attribbyte Shl 2)
	'End If
	backgnd(dx) = VRAM(&h3F00 + pixel)
#EndMacro

Sub TextDraw(ByVal xtext As UInteger, ByVal ytext As UInteger, textdata As String)
	For textpos = 1 To Len(textdata)
		cc = Asc(Mid$(textdata, textpos, 1))
		For dry = 0 To 7
			For drx = 0 To 7
				outputNES((ytext Shl 3)+dry, (xtext Shl 3)+drx) = font((cc Shl 6)+(dry Shl 3)+drx)+64
			Next drx
		Next dry
		xtext = xtext + 1
		If xtext = 32 Then xtext = 0: ytext = ytext + 1
	Next textpos
End Sub
