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

View file

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

View file

@ -154,6 +154,14 @@ void PPU::Tick()
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
if (scanlineType == ScanlineType::Visible || scanlineType == ScanlineType::PreRender)
{
@ -206,14 +214,6 @@ void PPU::Tick()
Color pixel = MultiplexPixel(bgPixel, spritePixel);
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)
@ -512,14 +512,14 @@ void PPU::EvaluateSprites()
// Find free slot
secondaryOAM[freeSecondaryOAMSlot] = spriteYCoord;
Word diff = y - spriteYCoord;
if (diff == 0x6)
volatile int dkjhfdjf = 32;
if (y - spriteYCoord < 8 + ppuctrl.Flag.SpriteSize * 8) // Choose between 8x8 and 8x16 mode
if (diff < 8u + ppuctrl.Flag.SpriteSize * 8u) // Choose between 8x8 and 8x16 mode
{
secondaryOAM[freeSecondaryOAMSlot + 1] = ReadOAM(oamaddr + 4 * n + 1);
secondaryOAM[freeSecondaryOAMSlot + 2] = ReadOAM(oamaddr + 4 * n + 2);
secondaryOAM[freeSecondaryOAMSlot + 3] = ReadOAM(oamaddr + 4 * n + 3);
sprites[freeSecondaryOAMSlot >> 2].OAMPosition = n >> 4;
freeSecondaryOAMSlot += 4;
}
@ -552,6 +552,8 @@ void PPU::EvaluateSprites()
case FetchingPhase::NametableByte: // Fetch garbage
nametableByte = Read(0x2000 | (current.Raw & 0x0FFF));
sprites[currentlyEvaluatedSprite].Counter = secondaryOAM[4 * currentlyEvaluatedSprite + 3];
if (sprites[currentlyEvaluatedSprite].Counter == 0x00)
volatile int djf = 3;
sprites[currentlyEvaluatedSprite].FineX = 0;
fetchPhase = FetchingPhase::AttributeTableByte;
@ -559,7 +561,7 @@ void PPU::EvaluateSprites()
case FetchingPhase::AttributeTableByte: // Fetch garbage
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;
break;
@ -567,6 +569,9 @@ void PPU::EvaluateSprites()
case FetchingPhase::PatternTableLo:
{
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
spriteFineY = 7 - spriteFineY;
Word tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
sprites[currentlyEvaluatedSprite].Lo = Read((((Word)ppuctrl.Flag.SpritePatternTableAddr << 12) | (tileNumber << 4)) + spriteFineY);
@ -577,12 +582,12 @@ void PPU::EvaluateSprites()
case FetchingPhase::PatternTableHi:
{
Word spriteFineY = y - secondaryOAM[4 * currentlyEvaluatedSprite];
if (sprites[currentlyEvaluatedSprite].Latch.FlipVertically)
spriteFineY = 7 - spriteFineY;
Byte tileNumber = secondaryOAM[4 * currentlyEvaluatedSprite + 1] + (spriteFineY >> 3);
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)
{
@ -627,6 +632,51 @@ Pixel PPU::GetBackgroundPixel()
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)
{
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;
}

View file

@ -57,8 +57,21 @@ union ShiftRegister
struct Sprite
{
Byte OAMPosition;
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 FineX;
};

View file

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