Hello all! Posting here because I don't want to be annoying in the emuDev forums. I believe I almost have my PPU working properly enough to start actually rendering backgrounds. One small problem, it doesn't! I have been following Disch's examples, and I have to say his explanations for things make a /lot/ of sense to me. And as you'll see in the following code, I follow very closely
I assume I'll be needing to post the Fetch methods as well, so here they are:
I'm not too worried about the attribute fetch at the present time, I mainly want to focus on name table and pattern tables.
Code:
public static void Execute(long runTo)
{
if (NesPPU.Stamp < (341 * 20 * 5))
{
NesPPU.Stamp = (341 * 20 * 5);
NesPPU.Scanline = -1;
NesPPU.ScanlineCycle = 0;
}
if (NesPPU.Stamp >= runTo)
return;
if (NesPPU.Scanline == -1)
{
while (NesPPU.ScanlineCycle < 341)
{
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
RenderFrame();
scroll.AddrV = scroll.AddrT;
pixelX = 0;
pixelY = 0;
NesPPU.Scanline = 0;
NesPPU.ScanlineCycle = 0;
}
while (NesPPU.Scanline < 240)
{
while (NesPPU.ScanlineCycle < 256)
{
if (NesPPU.ScanlineCycle % 8 == 0)
{
// Fetch Data
FetchNameByte();
FetchAttrByte();
FetchPtrnByte();
scroll.ClockX();
}
// Render a single pixel
RenderPixel();
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
while (NesPPU.ScanlineCycle < 341)
{
if (NesPPU.ScanlineCycle % 8 == 0)
{
// Fetch Data
FetchNameByte();
FetchAttrByte();
FetchPtrnByte();
scroll.ClockX();
}
// Do nothing? :/
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
pixelX = (0);
pixelY = (pixelY + 1);
scroll.ResetX();
scroll.ClockY();
NesPPU.Scanline += 1;
NesPPU.ScanlineCycle = 0;
}
if (NesPPU.Scanline == 240)
{
NesPPU.vBlank = true;
if (NesPPU.nmiFire)
{
NesPPU.nmiFire = false;
NesCPU.NMIPending = true;
NesCPU.NMITime = NesCPU.Stamp;
}
}
while (NesPPU.Scanline < 262)
{
while (NesPPU.ScanlineCycle < 341)
{
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
NesPPU.Scanline += 1;
NesPPU.ScanlineCycle = 0;
}
// Pretty sure this is wrong.
NesCPU.Stamp = 0;
NesPPU.Stamp = 0;
}
{
if (NesPPU.Stamp < (341 * 20 * 5))
{
NesPPU.Stamp = (341 * 20 * 5);
NesPPU.Scanline = -1;
NesPPU.ScanlineCycle = 0;
}
if (NesPPU.Stamp >= runTo)
return;
if (NesPPU.Scanline == -1)
{
while (NesPPU.ScanlineCycle < 341)
{
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
RenderFrame();
scroll.AddrV = scroll.AddrT;
pixelX = 0;
pixelY = 0;
NesPPU.Scanline = 0;
NesPPU.ScanlineCycle = 0;
}
while (NesPPU.Scanline < 240)
{
while (NesPPU.ScanlineCycle < 256)
{
if (NesPPU.ScanlineCycle % 8 == 0)
{
// Fetch Data
FetchNameByte();
FetchAttrByte();
FetchPtrnByte();
scroll.ClockX();
}
// Render a single pixel
RenderPixel();
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
while (NesPPU.ScanlineCycle < 341)
{
if (NesPPU.ScanlineCycle % 8 == 0)
{
// Fetch Data
FetchNameByte();
FetchAttrByte();
FetchPtrnByte();
scroll.ClockX();
}
// Do nothing? :/
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
pixelX = (0);
pixelY = (pixelY + 1);
scroll.ResetX();
scroll.ClockY();
NesPPU.Scanline += 1;
NesPPU.ScanlineCycle = 0;
}
if (NesPPU.Scanline == 240)
{
NesPPU.vBlank = true;
if (NesPPU.nmiFire)
{
NesPPU.nmiFire = false;
NesCPU.NMIPending = true;
NesCPU.NMITime = NesCPU.Stamp;
}
}
while (NesPPU.Scanline < 262)
{
while (NesPPU.ScanlineCycle < 341)
{
NesPPU.ConsumeCycles(1);
if (NesPPU.Stamp >= runTo)
return;
}
NesPPU.Scanline += 1;
NesPPU.ScanlineCycle = 0;
}
// Pretty sure this is wrong.
NesCPU.Stamp = 0;
NesPPU.Stamp = 0;
}
I assume I'll be needing to post the Fetch methods as well, so here they are:
Code:
private static void FetchAttrByte()
{
int addr = attrTable[scroll.AddrV & 0x3FF];
attrData = NmtRam[addr >> 10][addr & 0x03FF];
attrData = ((attrData >> attrIndex[scroll.AddrV & 0x03FF]) & 0x03) << 2;
}
private static void FetchNameByte()
{
int addr = (scroll.AddrV & 0x0FFF);
nameData = NmtRam[addr >> 10][addr & 0x03FF];
}
private static void FetchPtrnByte()
{
int addr = bkgAddr | (nameData << 4) | (scroll.AddrV >> 0x0C);
ptr0Data = ChrRom[addr >> 10][(addr + 0) & 0x03FF];
ptr1Data = ChrRom[addr >> 10][(addr + 8) & 0x03FF];
}
{
int addr = attrTable[scroll.AddrV & 0x3FF];
attrData = NmtRam[addr >> 10][addr & 0x03FF];
attrData = ((attrData >> attrIndex[scroll.AddrV & 0x03FF]) & 0x03) << 2;
}
private static void FetchNameByte()
{
int addr = (scroll.AddrV & 0x0FFF);
nameData = NmtRam[addr >> 10][addr & 0x03FF];
}
private static void FetchPtrnByte()
{
int addr = bkgAddr | (nameData << 4) | (scroll.AddrV >> 0x0C);
ptr0Data = ChrRom[addr >> 10][(addr + 0) & 0x03FF];
ptr1Data = ChrRom[addr >> 10][(addr + 8) & 0x03FF];
}
I'm not too worried about the attribute fetch at the present time, I mainly want to focus on name table and pattern tables.