added ppu sprite rendering

This commit is contained in:
Lauchmelder 2022-03-08 16:03:19 +01:00
parent a4e4a16eaa
commit 024e439c24
No known key found for this signature in database
GPG key ID: C2403C69D78F011D
5 changed files with 83 additions and 64 deletions

View file

@ -16,7 +16,7 @@ Bus::Bus(Screen* screen) :
palettes = std::vector<Byte>(0x20, 0); palettes = std::vector<Byte>(0x20, 0);
LOG_CORE_INFO("Inserting cartridge"); LOG_CORE_INFO("Inserting cartridge");
cartridge.Load("roms/mario.nes"); cartridge.Load("roms/donkeykong.nes");
LOG_CORE_INFO("Powering up CPU"); LOG_CORE_INFO("Powering up CPU");
cpu.Powerup(); cpu.Powerup();
@ -82,7 +82,7 @@ void Bus::DMATick()
if (DMALatch != 0) if (DMALatch != 0)
{ {
Byte data = ReadCPU(((Word)DMAPage << 8) | (0xFF - DMACyclesLeft)); Byte data = ReadCPU(((Word)DMAPage << 8) | (0x100 - DMACyclesLeft));
ppu.WriteRegister(0x2004, data); ppu.WriteRegister(0x2004, data);
DMACyclesLeft--; DMACyclesLeft--;
@ -214,7 +214,7 @@ void Bus::WriteCPU(Word addr, Byte val)
{ {
case 0x4014: case 0x4014:
DMAPage = val; DMAPage = val;
DMACyclesLeft = 0xFF; DMACyclesLeft = 0x100;
preDMACycles = 1 + (cpu.GetTotalCycles() % 2); preDMACycles = 1 + (cpu.GetTotalCycles() % 2);
return; return;

View file

@ -98,7 +98,7 @@ private:
ControllerPort controllerPort; ControllerPort controllerPort;
Byte preDMACycles = 0; Byte preDMACycles = 0;
Byte DMACyclesLeft = 0; Word DMACyclesLeft = 0;
Byte DMAPage = 0; Byte DMAPage = 0;
Byte DMALatch = 0; Byte DMALatch = 0;

View file

@ -154,6 +154,14 @@ void PPU::Tick()
ppustatus.Flag.SpriteZeroHit = 0; ppustatus.Flag.SpriteZeroHit = 0;
} }
if (cycleType == CycleType::Fetching || cycleType == CycleType::PreFetching)
{
loTile.Raw <<= 1;
hiTile.Raw <<= 1;
loAttribute.Raw <<= 1;
hiAttribute.Raw <<= 1;
}
// Need to render // Need to render
if (scanlineType == ScanlineType::Visible || scanlineType == ScanlineType::PreRender) if (scanlineType == ScanlineType::Visible || scanlineType == ScanlineType::PreRender)
{ {
@ -206,14 +214,6 @@ void PPU::Tick()
Color pixel = MultiplexPixel(bgPixel, spritePixel); Color pixel = MultiplexPixel(bgPixel, spritePixel);
screen->SetPixel(x, y, pixel); screen->SetPixel(x, y, pixel);
} }
if (cycleType == CycleType::Fetching || cycleType == CycleType::PreFetching)
{
loTile.Raw <<= 1;
hiTile.Raw <<= 1;
loAttribute.Raw <<= 1;
hiAttribute.Raw <<= 1;
}
} }
Byte PPU::ReadRegister(Byte id) Byte PPU::ReadRegister(Byte id)
@ -512,14 +512,14 @@ void PPU::EvaluateSprites()
// Find free slot // Find free slot
secondaryOAM[freeSecondaryOAMSlot] = spriteYCoord; secondaryOAM[freeSecondaryOAMSlot] = spriteYCoord;
Word diff = y - spriteYCoord; Word diff = y - spriteYCoord;
if (diff == 0x6) if (diff < 8u + ppuctrl.Flag.SpriteSize * 8u) // Choose between 8x8 and 8x16 mode
volatile int dkjhfdjf = 32;
if (y - spriteYCoord < 8 + ppuctrl.Flag.SpriteSize * 8) // Choose between 8x8 and 8x16 mode
{ {
secondaryOAM[freeSecondaryOAMSlot + 1] = ReadOAM(oamaddr + 4 * n + 1); secondaryOAM[freeSecondaryOAMSlot + 1] = ReadOAM(oamaddr + 4 * n + 1);
secondaryOAM[freeSecondaryOAMSlot + 2] = ReadOAM(oamaddr + 4 * n + 2); secondaryOAM[freeSecondaryOAMSlot + 2] = ReadOAM(oamaddr + 4 * n + 2);
secondaryOAM[freeSecondaryOAMSlot + 3] = ReadOAM(oamaddr + 4 * n + 3); secondaryOAM[freeSecondaryOAMSlot + 3] = ReadOAM(oamaddr + 4 * n + 3);
sprites[freeSecondaryOAMSlot >> 2].OAMPosition = n >> 4;
freeSecondaryOAMSlot += 4; freeSecondaryOAMSlot += 4;
} }
@ -552,6 +552,8 @@ void PPU::EvaluateSprites()
case FetchingPhase::NametableByte: // Fetch garbage case FetchingPhase::NametableByte: // Fetch garbage
nametableByte = Read(0x2000 | (current.Raw & 0x0FFF)); nametableByte = Read(0x2000 | (current.Raw & 0x0FFF));
sprites[currentlyEvaluatedSprite].Counter = secondaryOAM[4 * currentlyEvaluatedSprite + 3]; sprites[currentlyEvaluatedSprite].Counter = secondaryOAM[4 * currentlyEvaluatedSprite + 3];
if (sprites[currentlyEvaluatedSprite].Counter == 0x00)
volatile int djf = 3;
sprites[currentlyEvaluatedSprite].FineX = 0; sprites[currentlyEvaluatedSprite].FineX = 0;
fetchPhase = FetchingPhase::AttributeTableByte; fetchPhase = FetchingPhase::AttributeTableByte;
@ -559,7 +561,7 @@ void PPU::EvaluateSprites()
case FetchingPhase::AttributeTableByte: // Fetch garbage case FetchingPhase::AttributeTableByte: // Fetch garbage
attributeTableByte = Read(0x23C0 | (current.Raw & 0x0C00) | ((current.CoarseY >> 2) << 3) | (current.CoarseX >> 2)); attributeTableByte = Read(0x23C0 | (current.Raw & 0x0C00) | ((current.CoarseY >> 2) << 3) | (current.CoarseX >> 2));
sprites[currentlyEvaluatedSprite].Latch = secondaryOAM[4 * currentlyEvaluatedSprite + 2]; sprites[currentlyEvaluatedSprite].Latch.Raw = secondaryOAM[4 * currentlyEvaluatedSprite + 2];
fetchPhase = FetchingPhase::PatternTableLo; fetchPhase = FetchingPhase::PatternTableLo;
break; break;
@ -567,6 +569,9 @@ void PPU::EvaluateSprites()
case FetchingPhase::PatternTableLo: case FetchingPhase::PatternTableLo:
{ {
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite]; Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
spriteFineY = 7 - spriteFineY;
Word tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3); Word tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
sprites[currentlyEvaluatedSprite].Lo = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + spriteFineY); sprites[currentlyEvaluatedSprite].Lo = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + spriteFineY);
@ -577,12 +582,12 @@ void PPU::EvaluateSprites()
case FetchingPhase::PatternTableHi: case FetchingPhase::PatternTableHi:
{ {
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite]; Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
spriteFineY = 7 - spriteFineY;
Byte tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3); Byte tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
sprites[currentlyEvaluatedSprite].Hi = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + 8 + spriteFineY); sprites[currentlyEvaluatedSprite].Hi = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + 8 + spriteFineY);
if (sprites[currentlyEvaluatedSprite].Hi != 0x00 && sprites[currentlyEvaluatedSprite].Counter == 0x88)
volatile int dkjf = 3;
if (currentlyEvaluatedSprite * 4 >= freeSecondaryOAMSlot) if (currentlyEvaluatedSprite * 4 >= freeSecondaryOAMSlot)
{ {
@ -627,6 +632,51 @@ Pixel PPU::GetBackgroundPixel()
Pixel PPU::GetSpritePixel() Pixel PPU::GetSpritePixel()
{ {
Pixel returnValue{ 0 };
returnValue.color = 0x00;
returnValue.palette = 4;
returnValue.priority = 1;
if (!ppumask.Flag.ShowSprites)
return returnValue;
for (Sprite& sprite : sprites)
{
// Sprite is inacitve
if (sprite.Counter != 0 || sprite.FineX >= 8)
continue;
// If sprite is active, determine the current pixel
Byte mask = 0x00;
if (sprite.Latch.FlipHorizontally)
mask = 0x1 << sprite.FineX;
else
mask = 0x80 >> sprite.FineX;
Byte loBit = ((sprite.Lo & mask) != 0x00);
Byte hiBit = ((sprite.Hi & mask) != 0x00);
uint8_t color = (hiBit << 1) | loBit;
if (color == 0x00)
continue;
uint8_t palette = 4 + sprite.Latch.Palette;
if (color == 0x00)
palette = 0x00;
if (x < 5)
volatile int djfk = 3;
returnValue.color = color;
returnValue.palette = palette;
returnValue.priority = sprite.Latch.Priority;
returnValue.isZeroSprite = (sprite.OAMPosition == 0x00);
break;
}
for (Sprite& sprite : sprites) for (Sprite& sprite : sprites)
{ {
if (sprite.Counter != 0) if (sprite.Counter != 0)
@ -640,47 +690,6 @@ Pixel PPU::GetSpritePixel()
} }
Pixel returnValue{ 0 };
returnValue.color = 0x00;
returnValue.palette = 4;
returnValue.priority = 1;
if (!ppumask.Flag.ShowSprites)
return returnValue;
bool firstIteration = true;
for (Sprite& sprite : sprites)
{
// Sprite is inacitve
if (sprite.Counter != 0 || sprite.FineX >= 8)
continue;
// If sprite is active, determine the current pixel
Byte loBit = (sprite.Lo & 0x80) >> 7;
Byte hiBit = (sprite.Hi & 0x80) >> 7;
uint8_t color = (hiBit << 1) | loBit;
if (color == 0x00)
{
firstIteration = false;
continue;
}
uint8_t palette = 4 + (sprite.Latch & 0x3);
if (color == 0x00)
palette = 0x00;
sprite.Lo <<= 1;
sprite.Hi <<= 1;
returnValue.color = color;
returnValue.palette = palette;
returnValue.priority = (sprite.Latch >> 5) & 0x1;
returnValue.isZeroSprite = firstIteration;
break;
}
return returnValue; return returnValue;
} }

View file

@ -57,8 +57,21 @@ union ShiftRegister
struct Sprite struct Sprite
{ {
Byte OAMPosition;
Byte Lo, Hi; Byte Lo, Hi;
Byte Latch; union
{
struct
{
Byte Palette : 2;
Byte Unimplemented : 3;
Byte Priority : 1;
Byte FlipHorizontally : 1;
Byte FlipVertically : 1;
};
Byte Raw;
} Latch;
Byte Counter; Byte Counter;
Byte FineX; Byte FineX;
}; };

View file

@ -28,9 +28,6 @@ public:
Byte output = outRegister & 1; Byte output = outRegister & 1;
outRegister >>= 1; outRegister >>= 1;
if (output != 0)
volatile int jdfk = 3;
return (output << outPin); return (output << outPin);
} }