MoarNES 0.11.12.12 alpha

Discuss emulation of the Nintendo Entertainment System and Famicom.

Moderator: Moderators

User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

Post by miker00lz »

i'm now modifying the nametable and scroll registers on writes to $2006, which fixes some bugs in games but seems to break things in other games that worked properly before, like the cutscenes in ninja gaiden.

Image

they look correct if i dont change the scroll registers on $2006 writes. am i parsing the values correctly here?

Code: Select all

void writePPUregs(uint16_t addr, uint8_t value) {
     PPU->regs[addr & 7] = value;
	 lastwritten = value;
     switch (addr) {
       case 0x2000:
            if (value&128) PPU->nmivblank = 1; else PPU->nmivblank = 0;
            if (value&32) PPU->sprsize = 16; else PPU->sprsize = 8;
            if (value&16) PPU->bgtable = 0x1000; else PPU->bgtable = 0x0000;
            if (value&8) PPU->sprtable = 0x1000; else PPU->sprtable = 0x0000;
            if (value&4) PPU->addrinc = 32; else PPU->addrinc = 1;
            PPU->nametable = value&3;
            break;
       case 0x2001:
            if (value&16) PPU->sprvisible = 1; else PPU->sprvisible = 0;
            if (value&8) PPU->bgvisible = 1; else PPU->bgvisible = 0;
            if (value&4) PPU->sprclip = 0; else PPU->sprclip = 1;
            if (value&2) PPU->bgclip = 0; else PPU->bgclip = 1;
            break;
       case 0x2003:
            OAM->addr = value;
            break;
       case 0x2004:
            OAM->RAM[OAM->addr++] = value;
            break;
       case 0x2005:
            if (PPU->addrlatch == 0) {
              PPU->xscroll = value;
              PPU->addrlatch = 1;
            } else {
              PPU->yscroll = value;
              PPU->addrlatch = 0;
            }
			break;
       case 0x2006:
            if (PPU->addrlatch == 0) {
              PPU->r2006[1] = value;
			  PPU->nametable = ((value >> 2) & 3);
			  PPU->xscroll = (PPU->xscroll & 0x3F) | (((uint16_t)value & 3) << 6);
			  PPU->xscroll = (PPU->xscroll & 0xF8) | (((uint16_t)value >> 4) & 7);
              PPU->addrlatch = 1;
            } else {
              PPU->r2006[0] = value;
			  PPU->yscroll = (PPU->yscroll & 7) | ((uint16_t)value << 3);
			  PPU->xscroll = (PPU->xscroll & 0xC7) | (((uint16_t)value >> 2) & 0x38);
			  PPU->addr = ((uint16_t)PPU->r2006[1] << 8) | (uint16_t)PPU->r2006[0];
              PPU->addrlatch = 0;
            }
			break;
       case 0x2007:
            writePPU(PPU->addr, value);
            PPU->addr = (PPU->addr + PPU->addrinc) & 0x3FFF;
            break;
     }
}
User avatar
Zepper
Formerly Fx3
Posts: 3262
Joined: Fri Nov 12, 2004 4:59 pm
Location: Brazil
Contact:

Post by Zepper »

Aren't you using loopy's logic?
Grapeshot
Posts: 85
Joined: Thu Apr 14, 2011 9:27 pm
Contact:

Post by Grapeshot »

I'm not entirely sure how to explain what you're doing wrong here (since you didn't post your rendering code as well), but the most obvious thing is that you are still storing a separate x scroll and y scroll values as well as the PPU memory address. Writes to $2005 and $2006 should both change different bits of the same counter, as described in loopy's famous documentation.
Last edited by Grapeshot on Sat Dec 24, 2011 6:09 pm, edited 1 time in total.
User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

Post by miker00lz »

yeah, thanks guys. i had read it before, quite a few times but it never totally made sense to me the way explained it. in the last day or so, it finally clicked in my head so i'm working on changing my code right now actually.

i felt a bit dumb for asking about it even though loopy's doc is there.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

Loopy's document is also formatted badly...

Code: Select all

           Fine Y
              Nametable Y,X
                Coarse Y
                     Coarse X
          
          .yyyNNYYYYYXXXXX
2000 write:
        t:....xx..........=d:......xx
2005 first write:
        t:...........xxxxx=d:xxxxx...
        x=d:.....xxx
2005 second write:
        t:......xxxxx.....=d:xxxxx...
        t:.xxx............=d:.....xxx
2006 first write:
        t:..xxxxxx........=d:..xxxxxx
        t:xx..............=0
2006 second write:
        t:........xxxxxxxx=d:xxxxxxxx
        v=t
scanline start (if background and sprites are enabled):  (ppu clock 257)
        v:.....x.....xxxxx=t:.....x.....xxxxx
frame start (prerender line, ppu clock 304) (if background and sprites are enabled):
        v=t

Others:
PPU clock 251, if screen is on: Y scroll bits of V are incremented.  If it wraps from 239 to 240, toggle the Y nametable, and set Y to 0.  If it wraps from 255 to 0, DO NOT toggle the Y nametable bit.

User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

Post by miker00lz »

HOLY SHIT i never thought i'd see the day. MoarNES now runs battletoads perfectly now that i got the loopy scrolling stuff figured out correctly.

Image

still can't believe my eyes. thanks for the help, everybody. i will upload a new version of this probably tomorrow if anybody wants to give it a try again. :twisted:

i've only tried the first level of battletoads, so maybe something screws up later. i've only ever gotten to level 3 before, i suck at battletoads. :x

EDIT: just tried levels 2 and 3, they both work perfectly too.

i think battletoads and ninja gaiden 1 are the hardest video games ever created. i can get to the final jaquio battle in ninja gaiden, but i owned the cart when i was a kid. i never played battletoads before about a year ago.

also, i still don't have APU sweeps working. i can't seem to understand quite how that messes with the period values. once i figure that out, and add movie and AVI recording support, i might just have a respectable emulator here.
User avatar
miker00lz
Posts: 235
Joined: Thu Sep 23, 2010 7:28 pm

Post by miker00lz »

oh, and this wasn't related to the scrolling thing but i've also fixed the PPU-CPU timing so it's accurate enough to do the marble madness mid-scanline nametable switching on the textboxes. it looks absolutely flawless. i'm now accurate down to the pixel. :)

Image

i've only used a small handful of NES emus that actually showed that part of marble madness correctly.
User avatar
Dwedit
Posts: 4924
Joined: Fri Nov 19, 2004 7:35 pm
Contact:

Post by Dwedit »

If you need help with the APU sweeps, read the code to Blargg's NES APU. It's very easy to follow.

Most relevant portion:

Code: Select all

void Nes_Square::clock_sweep( int negative_adjust )
{
	int sweep = regs [1];
	
	if ( --sweep_delay < 0 )
	{
		reg_written [1] = true;
		
		int period = this->period();
		int shift = sweep & shift_mask;
		if ( shift && (sweep & 0x80) && period >= 8 )
		{
			int offset = period >> shift;
			
			if ( sweep & negate_flag )
				offset = negative_adjust - offset;
			
			if ( period + offset < 0x800 )
			{
				period += offset;
				// rewrite period
				regs [2] = period & 0xff;
				regs [3] = (regs [3] & ~7) | ((period >> 8) & 7);
			}
		}
	}
	
	if ( reg_written [1] ) {
		reg_written [1] = false;
		sweep_delay = (sweep >> 4) & 7;
	}
}
Sweep is clocked about twice each frame.

BTW, the "negative_adjust" parameter is -1 for Square #1, and 0 for Square #2.

Note that part of the sweep feature is always running no matter what, namely the part which silences the channel when adding the shifted period would make the period become out of range.
Here come the fortune cookies! Here come the fortune cookies! They're wearing paper hats!
beannaich
Posts: 207
Joined: Wed Mar 31, 2010 12:40 pm

Post by beannaich »

- MMC3 IRQ is broken.
- SMB1 title screen is broken, suggesting improper $2007 read buffering behavior.
- Batman refuses to boot
- Bee 52 crashes the emulator

Those are the only 4 things I tested (MMC3 with Mega Man 3 boss select screen)
Post Reply