It is currently Mon Dec 11, 2017 7:45 pm

All times are UTC - 7 hours





Post new topic Reply to topic  [ 5 posts ] 
Author Message
PostPosted: Wed Oct 05, 2016 2:35 pm 
Offline

Joined: Wed Sep 14, 2016 1:21 pm
Posts: 13
Hi people.

You have been help-me a lot to write my own nes emu. It's just a dummy emulator with an educational purpose. Thank you. Yesterday I got an amazing milestone for me: PPU is working! When I finished to implement the cpu; I feel like: it's alive! But now I can really see that IT'S ALIVE :P

Look how it's going on:
Image

There are some bugs; it's true. Now I'm working comparing the debug trace of Nitendulator and the mine; it's working well. What I want to ask to you is; can you identify something stupidly wrong in the way that I implemented the PPU registers?

I'm not asking for code or a deep analysis, just for a fast check and "Oh my god; You need to re-read everything about XYZ.

Here the functions that Write in PPU REGISTERS:

Code:
func WRITE_PPUCTRL(IO *IOPorts, value byte) {

   if Bit0(value) == 0 && Bit1(value) == 0 {
      IO.PPUCTRL.BASE_NAMETABLE_ADDR = 0x2000
   }
   if Bit0(value) == 1 && Bit1(value) == 0 {
      IO.PPUCTRL.BASE_NAMETABLE_ADDR = 0x2400
   }
   if Bit0(value) == 0 && Bit1(value) == 1 {   
      IO.PPUCTRL.BASE_NAMETABLE_ADDR = 0x2800
   }
   if Bit0(value) == 1 && Bit1(value) == 1 {
      IO.PPUCTRL.BASE_NAMETABLE_ADDR = 0x2C00
   }
   
   if Bit2(value) == 0 {
      IO.PPUCTRL.VRAM_INCREMENT = 1
   } else {
      IO.PPUCTRL.VRAM_INCREMENT = 32
   }
   
   if Bit3(value) == 0 {
      IO.PPUCTRL.SPRITE_8_ADDR = 0x0000
   } else {
      IO.PPUCTRL.SPRITE_8_ADDR = 0x1000
   }
   
   if Bit4(value) == 0 {
      IO.PPUCTRL.BACKGROUND_ADDR = 0x0000
   } else {
      IO.PPUCTRL.BACKGROUND_ADDR = 0x1000
   }
   
   if Bit5(value) == 0 {
      IO.PPUCTRL.SPRITE_SIZE = 8
   } else {
      IO.PPUCTRL.SPRITE_SIZE = 16
   }
   
   if Bit6(value) == 0 {
      IO.PPUCTRL.MASTER_SLAVE_SWITCH = 0
   } else {
      IO.PPUCTRL.MASTER_SLAVE_SWITCH = 1
   }
   
   if Bit7(value) == 0 {
      IO.PPUCTRL.GEN_NMI = false
   } else {
   IO.PPUCTRL.GEN_NMI = true
   }
}

func WRITE_PPUMASK(IO *IOPorts, value byte) {

   if Bit0(value) == 0 {
      IO.PPUMASK.GREYSCALE = false
   } else {
      IO.PPUMASK.GREYSCALE = true
   }
   
   if Bit1(value) == 0 {
      IO.PPUMASK.SHOW_LEFTMOST_8_BACKGROUND = false
   } else {
      IO.PPUMASK.SHOW_LEFTMOST_8_BACKGROUND = true
   }
   
   if Bit2(value) == 0 {
      IO.PPUMASK.SHOW_LEFTMOST_8_SPRITE = false
   } else {
      IO.PPUMASK.SHOW_LEFTMOST_8_SPRITE = true
   }
   
   if Bit3(value) == 0 {
      IO.PPUMASK.SHOW_BACKGROUND = false
   } else {
      IO.PPUMASK.SHOW_BACKGROUND = true
   }
   
   if Bit4(value) == 0 {
      IO.PPUMASK.SHOW_SPRITE = false
   } else {
      IO.PPUMASK.SHOW_SPRITE = true
   }
   
   if Bit5(value) == 0 {
      IO.PPUMASK.RED_BOOST = false
   } else {
      IO.PPUMASK.RED_BOOST = true
   }
   
   if Bit6(value) == 0 {
      IO.PPUMASK.GREEN_BOOST = false
   } else {
      IO.PPUMASK.GREEN_BOOST = true
   }
   
   if Bit7(value) == 0 {
      IO.PPUMASK.BLUE_BOOST = false
   } else {
      IO.PPUMASK.BLUE_BOOST = true
   }
}

func WRITE_OAMADDR(IO *IOPorts, value byte) {
   IO.PPU_OAM_ADDRESS = value
}

func WRITE_OAMDATA(IO *IOPorts, value byte) {
      IO.PPU_OAM[IO.PPU_OAM_ADDRESS] = value
      IO.PPU_OAM_ADDRESS++
}

func WRITE_PPUSCROLL(IO *IOPorts, value byte) {

   if IO.PPUSCROLL.NEXT_WRITES_Y == true {
      IO.PPUSCROLL.Y = value      
   } else {
      IO.PPUSCROLL.X = value      
   }
   IO.PPUSCROLL.NEXT_WRITES_Y = !IO.PPUSCROLL.NEXT_WRITES_Y
}

func WRITE_PPUADDR(IO *IOPorts, value byte) {

   if IO.PPU_MEMORY_STEP == 0 {
      // Records the lower byte
      IO.PPU_MEMORY_HIGHER = value
      IO.PPU_MEMORY_STEP = 1
   } else {
      // Record the Higher Byte
      IO.PPU_MEMORY_LOWER = (value << 2) >> 2
      IO.PPU_MEMORY_STEP = 0
      IO.VRAM_ADDRESS = LE(IO.PPU_MEMORY_LOWER, IO.PPU_MEMORY_HIGHER)
   }
}

func WRITE_PPUDATA(IO *IOPorts, cart *cartridge.Cartridge, value byte) {
   
   
   IO.PPU_RAM[ mapper.PPU(IO.VRAM_ADDRESS) ] = value
   IO.VRAM_ADDRESS += IO.PPUCTRL.VRAM_INCREMENT
}

func WRITE_OAMDMA(IO *IOPorts, cart *cartridge.Cartridge, value byte) {
   
   var cpuaddr uint16 = uint16(value) << 8
   for i:=0; i<256; i++ {
      prgrom, finaladdr := mapper.MemoryMapper(cart, cpuaddr)
      var data byte
      if prgrom == true {
         data = cart.PRG[finaladdr]
      } else {
         data = IO.CPU_RAM[finaladdr]
      }
      
      IO.PPU_OAM[IO.PPU_OAM_ADDRESS] = data
      IO.PPU_OAM_ADDRESS++
      cpuaddr++
   }
}


My functions to READ PPU REGISTERS:

Code:
func READ_PPUSTATUS(IO *IOPorts) byte {

   var result byte = 0
   result = SetBit(result, 0, Bit0(IO.PPUSTATUS.WRITTEN))
   result = SetBit(result, 1, Bit1(IO.PPUSTATUS.WRITTEN))
   result = SetBit(result, 2, Bit2(IO.PPUSTATUS.WRITTEN))
   result = SetBit(result, 3, Bit3(IO.PPUSTATUS.WRITTEN))
   result = SetBit(result, 4, Bit4(IO.PPUSTATUS.WRITTEN))
   
   if IO.PPUSTATUS.SPRITE_OVERFLOW == true {
      result = SetBit(result, 5,1)
   }
   
   if IO.PPUSTATUS.SPRITE_0_BIT == true {
      result = SetBit(result, 6,1)
   }
      
   if IO.PPUSTATUS.NMI_OCCURRED == true {
      result = SetBit(result, 7,1)
   }
   IO.PPUSTATUS.NMI_OCCURRED = false
   
   IO.PPUSCROLL.X = 0
   IO.PPUSTATUS.SPRITE_0_BIT = false
   IO.PPUSCROLL.Y = 0
   IO.VRAM_ADDRESS = 0
   
   return result   
}

func READ_OAMDATA(IO *IOPorts) byte {

      var result byte = IO.PPU_OAM[IO.PPU_OAM_ADDRESS]
      IO.PPU_OAM_ADDRESS++
      return result
}

func READ_PPUDATA(IO *IOPorts, cart *cartridge.Cartridge) byte {

   

   var newaddr uint16 = mapper.PPU (IO.VRAM_ADDRESS)


   var request byte = IO.PPU_RAM[ newaddr ]
   var result byte = IO.PREVIOUS_READ
   
   if newaddr < 0x3F00 {
      IO.PREVIOUS_READ = request
   } else {
      IO.PREVIOUS_READ = IO.PPU_RAM[ newaddr - 0x1000 ]
      result = request
   }
   
   //fmt.Printf("rnd [%x] = %x \n", newaddr, result)   
   IO.VRAM_ADDRESS += IO.PPUCTRL.VRAM_INCREMENT

   return result
}


Is there anything BIZARRE? O_O

(I made a lot of things not optimised; sometimes cause I want to keep it's very readable. Sometimes cause I don't know how to do something better :P

(it's an open source project; Now I'm working on PPU branch: https://github.com/jonathandasilvasanto ... rc/zerojnt )

Thank you!


Top
 Profile  
 
PostPosted: Wed Oct 05, 2016 2:56 pm 
Offline
User avatar

Joined: Fri Nov 19, 2004 7:35 pm
Posts: 3967
The nametable bits of PPUCTRL ($2000) directly affect two bits of loopy_t, there is no actual nametable selection status that you would store into your class.
Likewise, the scroll registers ($2005) also affect Loopy_T only, there's no scroll values or anything to store into your class.

Read this:
http://wiki.nesdev.com/w/index.php/PPU_ ... _registers

_________________
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!


Top
 Profile  
 
PostPosted: Wed Oct 05, 2016 4:32 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 10:59 pm
Posts: 1393
Also, "IO.PPUSCROLL.NEXT_WRITES_Y" and "IO.PPU_MEMORY_STEP" are the same register, and reading from $2002 needs to clear it.

_________________
Quietust, QMT Productions
P.S. If you don't get this note, let me know and I'll write you another.


Top
 Profile  
 
PostPosted: Wed Oct 05, 2016 10:19 pm 
Offline

Joined: Wed Sep 14, 2016 1:21 pm
Posts: 13
Wow! Great! Thank you guys!

This weekend I'm going to re-read everthing that I find about PPU. Now I'm skiping the raster process and I'm showing directly to the screen the background and the sprites according by NAMETABLE and OAM; but I'm looking forward to start to make the things right. :)

Thx!


Top
 Profile  
 
PostPosted: Thu Oct 06, 2016 1:13 pm 
Offline

Joined: Fri Dec 30, 2011 7:15 am
Posts: 43
Location: Sweden
Getting the ppu to finally start cooperating is a great feeling lol. Nice work!


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 5 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 6 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group