Goal for this week: mapping a NES: Update with PPU probs

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
Goal for this week: mapping a NES: Update with PPU probs
by on (#63012)
Hi guys, long time lurker here.

Semester is over and I've decided I want to attempt to create a NES emulator. This is a serious goal, and I will hopefully blog my exploits.

For this weeks goal, I would like to achieve the reading of a *.nes rom file, and copying the memory addresses so they'll be able to be manipulated later on. I have chosen C# as my language of choice, however this will probably change. My IMMEDIATE aim is to get a stranglehold on the 6502's architecture, it's memory representations and the basics. I'm not attempting any actual CPU emulation yet.

Can anyone give me a few pointers? I realise this isn't a specific question, but I hoped people could just voice their thoughts on anything. Links, tutorials, blogs, other people in my situation are all helpful.

by on (#63021)
http://6502.org/ should get you started.

by on (#63025)
Tepples.. You didn't read is message at all. He just want to know how to take a nes rom file and map it in ram for later use. That site will not help him in that case.

It's quite a vague question actually. Before you can start to map it to memory, you will need to understand more about:

- the nes memory map
- how mapper affect what inside the rom
- how to interpret ines headers

Reading the file for now will not do much good. You need to understand more about the inner workings of the nes and mappers before it will make sense.

My answer maybe vague as well in a way. People that have more experience with making emulator may be able to give you information on the subject.

I would suggest to read the wiki content and understand more about the cpu memory map. This will still not be enough for what you want to do but it will already be a good start.

I will let other more knowledgeable people fill the missing information.

by on (#63028)
Well this afternoon I implemented a quick and dirty Chip8 emulator after following a tutorial. The tut was for C++, and I used python, so it wasn't as much help as I thought it would be.

Learnt a heap (had no prior assembly knowledge, and I feel i have a few of the concepts down pat). I managed to interpret the rom, store the hex data, and begin interpretation of the opcodes. So far I have around 10 opcodes done, but it's enough to display a few graphics on the screen. Python's parsing of hex numbers makes me want to rage.

I realise a 6502 is a big step up from a Chip8, but I'm feeling pretty good atm :D

by on (#63030)
Banshaku wrote:
tepples wrote:
domlebo70 wrote:
My IMMEDIATE aim is to get a stranglehold on the 6502's architecture

http://6502.org/ should get you started.

Tepples.. You didn't read is message at all.

I beg to differ.

Banshaku wrote:
He just want to know how to take a nes rom file and map it in ram for later use. That site will not help him in that case.

Good dumps of NES ROMs consist of a 16-byte header, a PRG ROM (the ROM connected to the CPU bus), and a CHR ROM (the ROM connected to the PPU bus).

The first thing you need to worry about is the header:
  • Byte 0-3 should be 'N','E','S',0x1A
  • Byte 4 is the size of PRG ROM in 16384 byte units
  • Byte 5 is the size of CHR ROM in 8192 byte units; this can be 0
  • Bytes 6 and 7 give more information about the circuit board, which controls (among other things) how the ROM is connected to the CPU

If header bytes 6 and 7 are both less than 16, then the ROM uses mapper 0. This should have 16384 or 32768 bytes of PRG ROM (header[4] = 1 or 2) and 8192 bytes of CHR ROM (header[5] = 1). The first 16384 bytes of PRG ROM appear at $8000-$BFFF in the CPU's address space, and the last 16384 bytes appear at $C000-$FFFF. This means that if the PRG ROM is only 16384 bytes, it will be mirrored into both regions because the ROM chip is ignoring bit 14 of the address bus.

So where do you start the CPU's program counter? It doesn't always start at the start of ROM ($8000 or $C000) as you might expect. When a 6502 is powered on or reset, it executes JMP ($FFFC): read $FFFC and put it in the low 8 bits of the program counter, then read $FFFD and put it in the high 8 bits.
Re: Semester over, realistic goal for this week: mapping a 6
by on (#63031)
Maybe my wording was too strong when I said "you didn't read" and should have been more diplomatic.

This is what I meant:

domlebo70 wrote:
For this weeks goal, I would like to achieve the reading of a *.nes rom file, and copying the memory addresses so they'll be able to be manipulated later on.


If this is what he wants to do this week, he needs to learn more about the nes and files structure. After that, for his immediate goal, he will need to learn more about the 6502.

It just the reply felt dry by just putting a link to 6502.org for the answer. Sorry if my answer felt harsh, no direct attack intended.

by on (#63035)
If this is anything like an emulator, think about PRG banking early, don't bolt it on at the end, and don't even think about memcpy-style bankswitching.
Mappers generally switch PRG in units as small as 8KB.

by on (#63036)
Dwedit wrote:
If this is anything like an emulator, think about PRG banking early, don't bolt it on at the end, and don't even think about memcpy-style bankswitching.
Mappers generally switch PRG in units as small as 8KB.


If you want NSF support, you should even go as small as 4KB

by on (#63725)
Hi guys,

Okay I have rudimentary CPU emulation working so far.

However, like this guys=: http://nesdev.com/bbs/viewtopi ... 91&start=0

I'm a little confused as to how to start PPU emulation.

I'm stuck looping from 800A to 800D (I assume I am waiting for VBLANK. But I don't really know where to go from here :S

Any tips/links

by on (#63729)
Just emulate PPUCTRL ($2000) D7 and PPUSTATUS ($2002) D7, and games will start to boot. (See PPU registers.)

by on (#63981)
Thanks tepples.

Okay, so I have emulated the PPU 2000/2002 registers writing and reading.

Now my execution looks like this:

Code:
8002: LDA #$10    ; read immediate value to set PPU control registers
8004: STA $2000   ; store value
8007: LDX #$FF    ; load immediate value into X register
8009: TXS         ; store X register into stack
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)
00a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)
800a: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
800d: BPL         ; test N flag, branch to 800a if not positive, (N is set)
............... etc etc............
then:

800F: LDA $2002   ; read PPU flags into accumulator (set N flag based on bit 7)
8012: BPL         ; test N flag, branch to 800F if not positive, (N is set)
8014: LDY         ; Loads a byte of memory into the Y register setting the zero and negative flags as appropriate.


Now I was under the impression it's meant to loop from 800F to 8012 for 1 frame, like 800A to 800D. I've clearly missed something basic.

Any ideas?

by on (#63990)
Are you turning off NMI_occurred on reads? See two flags and four operations.

by on (#63995)
Hmm, is that the correct behaviour though? I have the output from another working emulator and it's identical. Here's the output (for Super Mario Bros):

Code:
...etc
.......
.......
.......
800a
800d
800a
800d
800a
800d
800f
8012
8014
8016
8018
801b
801d
801f
8020
8020
8018
801b
801d
801f
8020
8020
8018
801b
etc...