Skip to content

Commit

Permalink
reverted mmc3 improvements, they'll have to come in a future release …
Browse files Browse the repository at this point in the history
…when I fox the significant amount of broken games.

It's not worth it for 3 passed tests and one Beam Software game.
  • Loading branch information
andrew-hoffman committed Jul 24, 2014
1 parent 1bba97e commit 771b7f7
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 97 deletions.
97 changes: 39 additions & 58 deletions src/com/grapeshot/halfnes/PPU.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ public class PPU {
private int loopyV = 0x0;//ppu memory pointer
private int loopyT = 0x0;//temp pointer
private int loopyX = 0;//fine x scroll
public int scanline = 0;
public int cycles = 0;
private int scanline = 0;
private int cycles = 0;
private int framecount = 0;
private int div = 2;
private final int[] OAM = new int[256], spriteshiftregH = new int[8],
Expand Down Expand Up @@ -184,15 +184,9 @@ public final void write(final int regnum, final int data) {
} else {
loopyT &= 0xff00;
loopyT += data;

//HACK ALERT
//handle the case of MMC3 mapper watching A12 toggle
//even when read or write aren't asserted on the bus
//needed to pass Blargg's mmc3 tests
mapper.ppuRead(loopyV);

loopyV = loopyT;
even = true;

}
break;
case 7:
Expand Down Expand Up @@ -274,20 +268,12 @@ public final void clock() {
//clear the oam address from pxls 257-341 continuously
ppuregs[3] = 0;
}
if ((cycles == 340)) {
//read the same nametable byte twice
//this signals the MMC5 to increment the scanline counter
fetchNTByte();
fetchNTByte();
}
if (cycles == 260 && ppuIsOn()) {
//evaluate sprites for NEXT scanline (as long as either background or sprites are enabled)
//this does in fact happen on scanine 261 but it doesn't do anything useful
//it's cycle 260 because that's when the first important sprite byte is read
//actually sprite overflow should be set by sprite eval somewhat before
//so this needs to be split into 2 parts, the eval and the data fetches
evalSprites();
}
// if ((cycles == 340)) {
// //read the same nametable byte twice
// //this signals the MMC5 to increment the scanline counter
// fetchNTByte();
// fetchNTByte();
// }
if (scanline == 261) {
if (cycles == 0) {// turn off vblank, sprite 0, sprite overflow flags
setvblankflag(false);
Expand All @@ -308,8 +294,9 @@ public final void clock() {
if (getbit(ppuregs[1], 3)) { //if background is on, draw a line of that
final boolean isBG = drawBGPixel(bufferoffset);
//sprite drawing
drawSprites(scanline << 8, cycles - 1, isBG);

if (found > 0) {
drawSprites(scanline << 8, cycles - 1, isBG);
}
} else {
//rendering is off, so draw either the background color OR
//if the PPU address points to the palette, draw that color instead.
Expand All @@ -324,6 +311,12 @@ public final void clock() {
final int emph = (ppuregs[1] & 0xe0) << 1;
bitmap[bufferoffset] = bitmap[bufferoffset] & 0x3f | emph;

} else if (cycles == 257) {
//evaluate sprites for NEXT scanline (as long as either background or sprites are enabled)
//this does not happen on scanine 261
if (ppuIsOn()) {
evalSprites();
}
}
}
//handle nmi
Expand Down Expand Up @@ -359,7 +352,10 @@ private void bgFetch() {
//background fetches
switch ((cycles - 1) & 7) {
case 1:
fetchNTByte();
//fetch nt byte
tileAddr = mapper.ppuRead(
((loopyV & 0xc00) | 0x2000) + (loopyV & 0x3ff)) * 16
+ (bgpattern ? 0x1000 : 0);
break;
case 3:
//fetch attribute (FIX MATH)
Expand Down Expand Up @@ -416,13 +412,6 @@ private void bgFetch() {
}
}

private void fetchNTByte() {
//fetch nt byte
tileAddr = mapper.ppuRead(
((loopyV & 0xc00) | 0x2000) + (loopyV & 0x3ff)) * 16
+ (bgpattern ? 0x1000 : 0);
}

private boolean drawBGPixel(int bufferoffset) {
//background drawing
//loopyX picks bits
Expand Down Expand Up @@ -504,38 +493,30 @@ private void evalSprites() {
}
//get tile address (8x16 sprites can use both pattern tbl pages but only the even tiles)
final int tilenum = OAM[spritestart + 1];
spriteFetch(spritesize, tilenum, offset, oamextra);
if (spritesize) {
tilefetched = ((tilenum & 1) * 0x1000)
+ (tilenum & 0xfe) * 16;
} else {
tilefetched = tilenum * 16
+ ((sprpattern) ? 0x1000 : 0);
}
tilefetched += offset;
//now load up the shift registers for said sprite
final boolean hflip = getbit(oamextra, 6);
if (!hflip) {
spriteshiftregL[found] = reverseByte(mapper.ppuRead(tilefetched));
spriteshiftregH[found] = reverseByte(mapper.ppuRead(tilefetched + 8));
} else {
spriteshiftregL[found] = mapper.ppuRead(tilefetched);
spriteshiftregH[found] = mapper.ppuRead(tilefetched + 8);
}
++found;
}
}
for (int i = found; i < 8; ++i) {
//fill unused sprite registers with zeros
spriteshiftregL[found] = 0;
spriteshiftregH[found] = 0;
//also, we need to do 8 reads no matter how many sprites we found
//dummy reads are to sprite 0xff
spriteFetch(spritesize, 0xff, 0, 0);
}
}

private void spriteFetch(final boolean spritesize, final int tilenum, int offset, final int oamextra) {
int tilefetched;
if (spritesize) {
tilefetched = ((tilenum & 1) * 0x1000)
+ (tilenum & 0xfe) * 16;
} else {
tilefetched = tilenum * 16
+ ((sprpattern) ? 0x1000 : 0);
}
tilefetched += offset;
//now load up the shift registers for said sprite
final boolean hflip = getbit(oamextra, 6);
if (!hflip) {
spriteshiftregL[found] = reverseByte(mapper.ppuRead(tilefetched));
spriteshiftregH[found] = reverseByte(mapper.ppuRead(tilefetched + 8));
} else {
spriteshiftregL[found] = mapper.ppuRead(tilefetched);
spriteshiftregH[found] = mapper.ppuRead(tilefetched + 8);
}
}

Expand Down
64 changes: 25 additions & 39 deletions src/com/grapeshot/halfnes/mappers/MMC3Mapper.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ public final void cartWrite(int addr, int data) {
} else if ((addr >= 0xc000) && (addr <= 0xdfff)) {
//any value here reloads irq counter
irqreload = true;

} else if ((addr >= 0xe000) && (addr <= 0xffff)) {
//iany value here enables interrupts
irqenable = true;
Expand All @@ -94,16 +95,15 @@ public final void cartWrite(int addr, int data) {
} else if ((addr >= 0xc000) && (addr <= 0xdfff)) {
//value written here used to reload irq counter _@ end of scanline_
irqctrreload = data;
//irqreload = true;
//mega man 3 is changing the reload value right after the irq
//and it works, somehow...
irqreload = true;
} else if ((addr >= 0xe000) && (addr <= 0xffff)) {
//any value here disables IRQ and acknowledges
if (interrupted) {
--cpu.interrupt;
}
interrupted = false;
irqenable = false;
irqctr = irqctrreload;
}
}
}
Expand Down Expand Up @@ -146,49 +146,35 @@ private void setbank6() {
}
}

private boolean lastA12 = false;

@Override
public int ppuRead(int addr) {
checkA12(addr);
return super.ppuRead(addr);
}

@Override
public void ppuWrite(int addr, int data) {
checkA12(addr);
super.ppuWrite(addr, data);
}

int a12timer = 3;

private void checkA12(int addr) {
boolean a12 = utils.getbit(addr, 12);
if (a12 && (!lastA12) && a12timer <= 0) {
//System.err.println("clock at ppu line " + ppu.scanline + " " + addr);
clockScanCounter();
a12timer = 3;
public void notifyscanline(int scanline) {
//Scanline counter
if (scanline > 239 && scanline != 261) {
//clocked on LAST line of vblank and all lines of frame. Not on 240.
return;
}
if (!ppu.mmc3CounterClocking()) {
return;
}
--a12timer;
lastA12 = a12;
}

private void clockScanCounter() {
if (irqreload || (irqctr == 0)) {
//System.err.println("reloading");
irqctr = irqctrreload;
if (irqreload) {
irqreload = false;
} else {
--irqctr;
irqctr = irqctrreload;
}
if ((irqctr == 0) && irqenable) {
if (!interrupted) {
++cpu.interrupt;
interrupted = true;
System.err.println("interrupt line " + ppu.scanline + " reload " + irqctrreload);

if (irqctr-- <= 0) {
if (irqctrreload == 0) {
return;
//irqs stop being generated if reload set to zero
}
if (irqenable) {
if (!interrupted) {
++cpu.interrupt;
interrupted = true;
}
}
irqctr = irqctrreload;
}

}

private void setppubank(int banksize, int bankpos, int banknum) {
Expand Down

0 comments on commit 771b7f7

Please sign in to comment.