I noticed another discrepancy. From the wiki:
Code:
$6000 $8000 $A000 $C000 $E000
+-----------------+-------------------------------+
PRG Mode %000 | ($8003 * 4)+3 | { -1} |
+-----------------+-------------------------------+
PRG Mode %001 | ($8003 * 2)+1 | $8001 | { -1} |
+-----------------+---------------+---------------+
PRG Mode %010 | $8003 | $8000 | $8001 | $8002 | { -1} |
+-----------------+-------+-------+-------+-------+
PRG Mode %011 | $8003 | $8000 | $8001 | $8002 | { -1} | *BIT REVERSE*
+-----------------+-------------------------------+
PRG Mode %100 | ($8003 * 4)+3 | $8003 |
+-----------------+-------------------------------+
PRG Mode %101 | ($8003 * 2)+1 | $8001 | $8003 |
+-----------------+---------------+---------------+
PRG Mode %110 | $8003 | $8000 | $8001 | $8002 | $8003 |
+-----------------+-------+-------+-------+-------+
PRG Mode %111 | $8003 | $8000 | $8001 | $8002 | $8003 | *BIT REVERSE*
+-----------------+-------+-------+-------+-------+
The final bank in program modes 0, 1, 2 and 3 is fixed to -1. But, according to FCEUX's source, it may not be that simple:
Code:
static void tekprom(void)
{
uint32 bankmode=((tkcom[3]&6)<<5);
switch(tkcom[0]&7)
{
case 00: if(tkcom[0]&0x80)
setprg8(0x6000,(((prgb[3]<<2)+3)&0x3F)|bankmode);
setprg32(0x8000,0x0F|((tkcom[3]&6)<<3));
break;
case 01: if(tkcom[0]&0x80)
setprg8(0x6000,(((prgb[3]<<1)+1)&0x3F)|bankmode);
setprg16(0x8000,(prgb[1]&0x1F)|((tkcom[3]&6)<<4));
setprg16(0xC000,0x1F|((tkcom[3]&6)<<4));
break;
case 03: // bit reversion
case 02: if(tkcom[0]&0x80)
setprg8(0x6000,(prgb[3]&0x3F)|bankmode);
setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
setprg8(0xe000,0x3F|bankmode);
break;
case 04: if(tkcom[0]&0x80)
setprg8(0x6000,(((prgb[3]<<2)+3)&0x3F)|bankmode);
setprg32(0x8000,(prgb[3]&0x0F)|((tkcom[3]&6)<<3));
break;
case 05: if(tkcom[0]&0x80)
setprg8(0x6000,(((prgb[3]<<1)+1)&0x3F)|bankmode);
setprg16(0x8000,(prgb[1]&0x1F)|((tkcom[3]&6)<<4));
setprg16(0xC000,(prgb[3]&0x1F)|((tkcom[3]&6)<<4));
break;
case 07: // bit reversion
case 06: if(tkcom[0]&0x80)
setprg8(0x6000,(prgb[3]&0x3F)|bankmode);
setprg8(0x8000,(prgb[0]&0x3F)|bankmode);
setprg8(0xa000,(prgb[1]&0x3F)|bankmode);
setprg8(0xc000,(prgb[2]&0x3F)|bankmode);
setprg8(0xe000,(prgb[3]&0x3F)|bankmode);
break;
}
}
tkcom[3] corresponds to:
Code:
$D003: [M.BH HHHH]
M = Mirror CHR (very strange, see below)
B = CHR Block mode (0=enabled, 1=disabled)
H = CHR Block (when in block mode)
The code seems to suggest that CHR block register affects PRG banking.
Edit: Also, I do not see an indication that FCEUX is doing the bit reversals elsewhere.
Edit 2: Check out the following ROMs:
Multi-Game Pirate Carts.7z <45-in-1 (JY-120A) (Unl) [b1].nes>
Multi-Game Pirate Carts.7z <45-in-1 (JY-120A) (Unl) [U][!].unf>
Both of these are the same in 2 different file formats. It's a mapper 90 multi-game. They work in FCEUX and Nestopia only, but I have yet to figure out how and it might be related to those undocumented registers.
Edit 3:
Code:
Funky Mode:
When 'F' in $C001 is clear, $C007 is ignored. When set, exact operation is unknown. It appears to funkify
the prescaler. $C007 containing any value other than $FF will result in the IRQ counter not being clocked at
all... and $FF will result in the prescaler dividing by strange amounts (sometimes 8? sometimes 12?
sometimes 257?). Details are unknown. Fortunately, no games use this funky mode.
FCEUX implements it:
Code:
case 07: //if(!(IRQMode&8)) FCEU_printf("C001 is clear, no effect applied\n");
// else if(V==0xFF) FCEU_printf("Prescaler is changed for 12bits\n");
// else FCEU_printf("Counter Stopped\n");
IRQPreSize=V;break;