This page is a mirror of Tepples' nesdev forum mirror (URL TBD).
Last updated on Oct-18-2019 Download

Reading NES rom in c++

Reading NES rom in c++
by on (#182771)
hi, i'm programing one NES emulator, and i have problems with the rom's read. the content read is strange.
Re: Reading NES rom in c++
by on (#182773)
Looks normal to me.

Maybe you should read about the iNES file format and the NES 2.0 file format.
Re: Reading NES rom in c++
by on (#182774)
In the future, be more specific about what you expect to happen vs what is actually happening.

The first bytes of the rom are probably
4E 45 53 1A 01 01 00

Zero (00, 0x00, however you represent it) is the terminator character for a char string in C.

Your program is printing 6 characters terminated by that zero, so all seems to be in order. If you want to display a printout of all the bytes as hex or something, using cout on the buffer alone is not a great way to accomplish this. You could create a formatted string of each byte as hex, or various other things.
Re: Reading NES rom in c++
by on (#182813)
The first thing you consider is the Memory Map. It's what the NES's CPU sees when it tries to access memory.

0000-07FF = RAM
0800-1FFF = mirrors of RAM
2000-2007 = PPU registers accessable from the CPU
2008-3FFF = mirrors of those same 8 bytes over and over again
4000-401F = sound channels, joypads, and other IO
6000-7FFF = cartridge PRG-RAM (if present), or PRG-ROM depending on mapper
8000-FFFF = cartridge memory, usually ROM.

The cartridge ROM is usually bankswitched in either 32K, 16K, or 8K chunks.

If you're starting out on an emulator, start with something simple, like a mapper 0 game such as Balloon Fight.

Loading a iNES file:
16 bytes header, parse this to get the rom and vrom size, mapper number, and flags.
PRG ROM - size depends on the header (prg size * 16K)
CHR ROM (if present) - size depends on the header (chr size * 8K)

For a simple Mapper 0 (NROM) game, the 32K of ROM appears in memory at 8000-FFFF. If it's 16k in size, it appears in memory at 8000-BFFF and C000-FFFF.
Other mappers arrange the cartridge memory differently, see documentation for more details. Some mappers have the last 16K bank of the ROM fixed into C000-FFFF.

The first instruction executed depends on the Reset Vector, and not the first byte of the PRG ROM. The reset vector is a 16-bit value read from Memory address FFFC, first the low byte then the high byte.
Re: Reading NES rom in c++
by on (#182896)
tanx, guys. :D
Re: Reading NES rom in c++
by on (#182960)
hey guys, i have a question.
that's my example, the two first lines of hex code, when the first is the header. what byte of second line is the opcode ? can you explain ?
4E 45 53 1A 01 01 00 00 00 00 00 00 00 00 00 00
4C F5 C5 60 78 D8 A2 FF 9A AD 02 20 10 FB AD 02
Re: Reading NES rom in c++
by on (#182963)
4C F5 C5 disassembles to JMP $C5F5.

But though you start reading PRG ROM bytes immediately after the end of the header (this ROM has $4C as its first byte), you don't execute at the start of PRG ROM. For that, you have to read through to the end of the PRG ROM and look up the reset vector, which is stored at $FFFC-$FFFD. (The corresponding offset in the ROM image in iNES format depends on the mapper and PRG ROM size. In an NROM-128 game in iNES format, this is stored with its low byte at file offset $400C and its high byte in $400D.) When reset is asserted, the CPU does something very similar to the instruction JMP ($FFFC). This copies the value at $FFFC into the low byte of the program counter and the value at $FFFD into the low byte of the program counter.
Re: Reading NES rom in c++
by on (#182965)
There's nothing specifying which bytes are opcodes, operands, or data... As far as the CPU is concerned, all bytes could be anything. The good news is that you don't need to make this distinction at all. You will simply interpret whatever the program counter points to as an opcode, and depending on the opcode, 0 to 2 bytes that follow it as its operand. The person who programmed the game is the one responsible for making sure that the program counter will never point to something that isn't an instruction, otherwise the program would most likely crash.

The initial value for the program counter is obtained from the reset vector (16-bit value at $FFFC-$FFFD). Just copy the address at that location to the program counter and start executing from there.