I tried other ROM's but a similar thing happens. I moreso wanted to know if there was a plausible or easy-to-spot explanation for why this is happening. Here is a screenshot from Donkey Kong.tokumaru wrote:I believe it has been pointed out that SMB isn't a good test subject for a barebones PPU implementation. It relies on raster effects (status bar), pallette mirroring, VRAM/ROM readback, scrolling... Better start with something simpler, like Donkey Kong or Mario Bros., which have already been suggested.
It doesn't mean you will get nothing out of SMB, as even the simple approach to PPU rendering should show something discernible for SMB, it's just that it may be harder to debug the initial PPU implementation using a game that relies on more advanced PPU features. There certainly is something wrong there, but the problem may be easier to catch if you try a less demanding game.
EDIT: Those patterns do resemble the pattern tables of SMB, but I don't think there's any reason for them to show up like that in the final emulated picture.
Making a basic PPU (Fully working CPU)
Moderator: Moderators
Re: Making a basic PPU (Fully working CPU)
Re: Making a basic PPU (Fully working CPU)
Are drawing the nametable? It looks more like you are drawing the pattern table, although corrupted. It looks like they are not properly aligned.
Also the second pattern table is usually used as background tiles, not the first one. Both Donkey Kong and Mario Bros are doing that.
Also the second pattern table is usually used as background tiles, not the first one. Both Donkey Kong and Mario Bros are doing that.
Re: Making a basic PPU (Fully working CPU)
Better honor the $2000 setting for this than hardcode it. A lot of games do it the other way.Pokun wrote:Also the second pattern table is usually used as background tiles, not the first one. Both Donkey Kong and Mario Bros are doing that.
Re: Making a basic PPU (Fully working CPU)
Yes of course, eventually you'll need to do that. But if you just want to get Donkey Kong to display for now, it sounds like you got them backwards.
Re: Making a basic PPU (Fully working CPU)
Thanks for the suggestion. It is very possible I have either made an arithmetic mistake or misunderstood something. Here is what I am doing in pseudocode:Pokun wrote:Are drawing the nametable? It looks more like you are drawing the pattern table, although corrupted. It looks like they are not properly aligned.
Also the second pattern table is usually used as background tiles, not the first one. Both Donkey Kong and Mario Bros are doing that.
Code: Select all
//Go through each row and column of nametable
for(row<30) {
for(col<32) {
//Fetch nametable, attrTable, and pattern
nameTable = read(0x2000+col+(32*row));
attrTable = read(0x2C30+(col/4)+(row*8));
patternTableAddr = 16*nameTable + (((ctrl>>4)&1)*0x1000);
//Draw pattern Table entry
for(i<8) {
for(bit<8) {
currentPixel = extractCurrentBitFromPatternTable(patternTableAddr,bit);
// only draw background pixels
if(currentPixel ==0) {
pixelColor = palette[ram[0x3F00]];
screen[8*row+i][8*col+bit] = pixelColor;
}
}
}
}
}
Re: Making a basic PPU (Fully working CPU)
What writes to screen if currentPixel is not 0?
How does extractCurrentBitFromPatternTable work?
How does extractCurrentBitFromPatternTable work?
Re: Making a basic PPU (Fully working CPU)
Right now i am only drawing background pixels in order to just see if the ppu works at all. That way i dont have to worry about sprites or different palettes other than the background color. Therefore it is just white where i dont write and grey where i do write.lidnariq wrote:What writes to screen if currentPixel is not 0?
How does extractCurrentBitFromPatternTable work?
Sorry, i was too lazy to write out extractCurrentBits. It just gets one bit from pattern table address and the second from that address + 8 and combines them
Re: Making a basic PPU (Fully working CPU)
Well, anyway, row*8 is not equal to floor(row/4)*8.
Re: Making a basic PPU (Fully working CPU)
I didn't catch anything that would result in the output you showed us, but I did notice a few problems:
- The attribute table base address is wrong;
- The attribute data is not used at all;
- extractCurrentBitFromPatternTable doesn't use i;
I rewrote a few formulas and completed some things that were missing (attributes, mostly), hopefully I didn't make any horrible mistakes:
There's another thing I'd like to get out of the way: Are you separating CPU RAM from PPU RAM? People are sometimes confused by the fact that there are 2 separate buses, and if you don't emulate this correctly there's no way that the various tables will be populated and read correctly. I'm particularly worried about your read() function... is it reading from VRAM?
- The attribute table base address is wrong;
- The attribute data is not used at all;
- extractCurrentBitFromPatternTable doesn't use i;
I rewrote a few formulas and completed some things that were missing (attributes, mostly), hopefully I didn't make any horrible mistakes:
Code: Select all
for (row < 30) {
for (col < 32) {
nameTable = read(0x2000 + (row << 5) + col);
attrTable = read(0x23c0 + ((row >> 2) << 3) + (col >> 2));
attribute = (attrTable >> (((row & 0x02) << 1) + (col & 0x02))) & 0x03;
patternTableAddr = (nameTable << 4) + ((ctrl & 0x10) << 8);
for (i < 8) {
for (bit < 8) {
currentPixel = ((pattern[patternTableAddr + i] >> (7 - bit)) & 0x01) + (((pattern[patternTableAddr + i + 8] >> (7 - bit)) & 0x01) << 1);
pixelColor = palette[(attribute << 2) + currentPixel];
screen[(row << 3) + i][(col << 3) + bit] = pixelColor;
}
}
}
}
Re: Making a basic PPU (Fully working CPU)
Sorry about that. I made it pseudocode and left a few things out. (I am using i in my real calculation for the pixel).tokumaru wrote:I didn't catch anything that would result in the output you showed us, but I did notice a few problems:
- The attribute table base address is wrong;
- The attribute data is not used at all;
- extractCurrentBitFromPatternTable doesn't use i;
I rewrote a few formulas and completed some things that were missing (attributes, mostly), hopefully I didn't make any horrible mistakes:There's another thing I'd like to get out of the way: Are you separating CPU RAM from PPU RAM? People are sometimes confused by the fact that there are 2 separate buses, and if you don't emulate this correctly there's no way that the various tables will be populated and read correctly. I'm particularly worried about your read() function... is it reading from VRAM?Code: Select all
for (row < 30) { for (col < 32) { nameTable = read(0x2000 + (row << 5) + col); attrTable = read(0x23c0 + ((row >> 2) << 3) + (col >> 2)); attribute = (attrTable >> (((row & 0x02) << 1) + (col & 0x02))) & 0x03; patternTableAddr = (nameTable << 4) + ((ctrl & 0x10) << 8); for (i < 8) { for (bit < 8) { currentPixel = ((pattern[patternTableAddr + i] >> (7 - bit)) & 0x01) + (((pattern[patternTableAddr + i + 8] >> (7 - bit)) & 0x01) << 1); pixelColor = palette[(attribute << 2) + currentPixel]; screen[(row << 3) + i][(col << 3) + bit] = pixelColor; } } } }
Also, I am seperating PPU and CPU ram, so that isn't an issue. If you don't mind helping I can PM you the repo where my code is located.
edit: By examining your code i realized I was rendering each pattern mirrored and fixed that. Now the letters are in the correct direction and I have color. However, it is still the same jumbled pattern and still turns to grey after only a few frames of this jumble.