i'm loosing all my faith on this thing about the PPU, so please Tepples, Disch, MottZilla and all the NESDEV crew have mercy with me and help me
Graphics routine
Moderator: Moderators
Graphics routine
so here i'm again reading all the documents i have about PPU,VBlank, NMI, IRQ, etc... and still doesn't understand how the NES shows graphics, so i think i'm get drunk and then hang my neck on a rope... ok i'm joking, not gonna suicide... but there's too many things and speaking english can be so complicated sometimes (remember i'm from Argentina... yeah yeah, Maradona's place XD)
i'm loosing all my faith on this thing about the PPU, so please Tepples, Disch, MottZilla and all the NESDEV crew have mercy with me and help me
i'm loosing all my faith on this thing about the PPU, so please Tepples, Disch, MottZilla and all the NESDEV crew have mercy with me and help me
Just to be clear, I'm not asking for code or anything like that. All I'm asking for is the algorithm which NES uses to show its graphics.
[Spelling Fairy was here]
[Spelling Fairy was here]
Last edited by ehguacho on Fri Mar 12, 2010 2:45 pm, edited 1 time in total.
Well there is no one way to emulate the graphics for NES. You can achieve graphics emulation on a basic level pretty easily. The very first thing you need to do is implement the PPU's registers ($2000 - $2007). You will need to keep track of the CPU and PPU to figure out when certain important events happen which early on the main one is $2002 will need to know when VBlank occurs. This will also be in relation to when to trigger NMI interrupts. Based on register $2000 the game can choose if NMI interrupts occur on VBLANK, which happens after the last scanline is rendered.
You'll probably write and rewrite your graphics emulation code in the future so for now if you just want quick results here is a basic idea. Have a counter that counts the amount of CPU cycles executed. Each time a CPU opcode is executed you add the cycle time to this counter. When the counter exceeds 27280 (thats 113.6 the amount of cpu cycles per scanline for NTSC) you've had 240 scanlines drawn. You should mark a flag for this loop related to a check that checks after each opcode if 240 lines have passed by. If the flag isn't set, then you set it and set the VBLANK flag in $2002 as well as check $2000 if you need to trigger a NMI interrupt. Then when 262 lines have passed by, you reset that flag, and subtract 29780 from the counter which is approx 262 scanlines. This will have you setup on a loop to trigger VBLANK flags, NMIs, and games will execute more of their program code than before.
Then you could add some video emulation just by drawing the NameTable to the screen at the same time you are setting the VBL flag and checking to see if you need to trigger a NMI. After drawing the NameTable to the screen you could add drawing the sprites, add drawing the nametables with scrolling in effect.
Now if you have a specific sticking point on what you don't understand I'm sure you can get an answer.
You'll probably write and rewrite your graphics emulation code in the future so for now if you just want quick results here is a basic idea. Have a counter that counts the amount of CPU cycles executed. Each time a CPU opcode is executed you add the cycle time to this counter. When the counter exceeds 27280 (thats 113.6 the amount of cpu cycles per scanline for NTSC) you've had 240 scanlines drawn. You should mark a flag for this loop related to a check that checks after each opcode if 240 lines have passed by. If the flag isn't set, then you set it and set the VBLANK flag in $2002 as well as check $2000 if you need to trigger a NMI interrupt. Then when 262 lines have passed by, you reset that flag, and subtract 29780 from the counter which is approx 262 scanlines. This will have you setup on a loop to trigger VBLANK flags, NMIs, and games will execute more of their program code than before.
Then you could add some video emulation just by drawing the NameTable to the screen at the same time you are setting the VBL flag and checking to see if you need to trigger a NMI. After drawing the NameTable to the screen you could add drawing the sprites, add drawing the nametables with scrolling in effect.
Now if you have a specific sticking point on what you don't understand I'm sure you can get an answer.
There is no algorithm or magic piece of code that does it. I can explain how graphics rendering works on NES but there are enough documents on it already. Again, if you have a specific question, we can help. But it's not possible to just post graphics code you can snap into your emulator. If you want to see complete NES graphics emulation code you could download the source to many open source NES emulators. But I don't think that will help you much. It's better to understand it and write your own code than to try to plug in someone else's code.ehguacho wrote:just to be clear, all i'm asking for is the algorithm wich NES uses to shows their graphics. i'm [not] asking for code!
To draw each scanline of a background, do this 33 times:
- Fetch a nametable entry.
- Fetch the corresponding attribute table entry.
- Fetch the low-order byte of the pattern table sliver.
- Fetch the high-order byte of the pattern table sliver.
- Turn the attribute data and the pattern table data into palette indices, and store them in an array for combination with sprite data.
ok, i think this algorithm you wrote may be helpful.tepples wrote:To draw each scanline of a background, do this 33 times:Which one of the five steps do you want explained in detail first?
- Fetch a nametable entry.
- Fetch the corresponding attribute table entry.
- Fetch the low-order byte of the pattern table sliver.
- Fetch the high-order byte of the pattern table sliver.
- Turn the attribute data and the pattern table data into palette indices, and store them in an array for combination with sprite data.
let's start with step 1: fetch a name table entry.
first of all, i have to read wich is written in $2000 to fetch the information about the address of the name table wich is gonna be used (bits 0 and 1) and the sprite pattern table and background pattern table wich are gonna be used (bits 3 and 4, respectively). that's easy. but what do you mean with "name table entry"? is it a write to $2004 or $2006 or any write to an address between the name table space?
also i have another question about this. as i read, $2003 is used to write the 8-bit address in SPR-RAM to access via $2004. i.e.:
(extracted from GbaGuy demo)
lda #$00 ; these lines tell $2003
sta $2003 ; to tell
lda #$00 ; $2004 to start
sta $2003 ; at $0000.
when i'm handling a routine like that, do i have to store the first write to $2003 (the first "sta $2003") in some variable in order to later assemble it with the value written in the second write? because if i don't, at the second write i'll miss the value written in first time. in that case, why its says it's a 8-bit address if it's a 16-bits address (2 bytes written to $2003 = 16-bits address)?
does all the addresses in a name table work like this? (i.e.: $2014 -> the address register, $2015 -> I/O register)
At this point, please read Loopy's document "The skinny on NES scrolling" available from the main page.ehguacho wrote:let's start with step 1: fetch a name table entry.
first of all, i have to read wich is written in $2000 to fetch the information about the address of the name table wich is gonna be used (bits 0 and 1)
A byte in PPU $2000-$23BF, $2400-$27BF, $2800-$2BBF, or $2C00-$2FBF.but what do you mean with "name table entry"?
GbaGuy's demos have severe defects. Don't use them when developing your emulator.also i have another question about this. as i read, $2003 is used to write the 8-bit address in SPR-RAM to access via $2004. i.e.:
(extracted from GbaGuy demo)
The first write to $2003 is IGNORED because it's only an 8-bit register. It DOES NOT use the latch that $2005 and $2006 use.lda #$00 ; these lines tell $2003
sta $2003 ; to tell
lda #$00 ; $2004 to start
sta $2003 ; at $0000.
look at this simply code:tepples wrote:To draw each scanline of a background, do this 33 times:Which one of the five steps do you want explained in detail first?
- Fetch a nametable entry.
- Fetch the corresponding attribute table entry.
- Fetch the low-order byte of the pattern table sliver.
- Fetch the high-order byte of the pattern table sliver.
- Turn the attribute data and the pattern table data into palette indices, and store them in an array for combination with sprite data.
Code: Select all
static inline void RefreshScreen(void)
{
static unsigned char NameTableEntry,AttributeTableEntry;
NameTableEntry = VRAM[Reg2000_NameTable];
AttributeTableEntry = VRAM[Reg2000_NameTable + 0x3c0];
return;
}thanks for your answer tepples, but what that "Y" stands for?tepples wrote:PatternBits0 = VRAM[Reg2000_PatternTableBase * 4096 + NameTableEntry * 16 + (Y % 8)];
PatternBits1 = VRAM[Reg2000_PatternTableBase * 4096 + NameTableEntry * 16 + (Y % 8) + 8];
i'm assuming that "Reg2000_PatternTableBase" holds the value of the bit of Register 2000 wich indicates the pattern table address (sprite or background). is that right?
Every tile has eight lines in it. For background tiles, the line number is bits 14 through 12 of the VRAM address.ehguacho wrote:what that "Y" stands for?
Yes.i'm assuming that "Reg2000_PatternTableBase" holds the value of the bit of Register 2000 wich indicates the pattern table address (sprite or background). is that right?