* Mapper 90 information ----------------------- Written by Fx3, most of information provided by Nori ("Famtasia Author" ), a Famicom emulator. ---------------------------------------------------------------------------- This mapper is quite complex, and very similar with MMC5. It's used by some pirate titles (Taiwan) such as Super Mario World, Tekken2 and Mortal Kombat. Thanks to Nori for most of these informations. WHAT'S NEW: Version 2.0 [07-17-2000 (MON) - number 002] - Many things were fixed, added source code and lots of comments. ---------------------------------------------------------------------------- * This mapper does not have RAM at $6000-$7FFF space. ---------------------------------------------------------------------------- address desc notes ======= ==== ===== $5000 value1 Reading $5000: (value1*value2) & $ff $5001 value2 $8000 PRG reg1 8k PRG bank at $8000 $8001 PRG reg2 8 or 16k PRG bank at $A000 $8002 PRG reg3 8k PRG bank at $C000 $8003 PRG reg4 8k PRG bank at $E000 $9000-$9007 CHR low regs Low byte of CHR banks $A000-$A007 CHR high regs High byte of CHR banks $B000-$B003 nametable regs Low byte of CHR bank number $B004-$B007 nametable regs High byte of CHR bank number $C000 irq registers Unknown $C001 irq registers Unknown $C006 irq registers Unknown $C007 irq registers Unknown $C002 irq clear irq_flag=0 and INT signal is clear $C003 irq reset if $C005=0, irq_flag=0 else, irq_flag=1 and irq_counter=irq_latch $C004 irq reset It seems same of $C003 $C005 irq counter irq_flag=1, irq_latch = irq_counter = value $D000 bank mode S-NccPpp ('-' (0x40) = unused bit) S: PRG bank at $6000 (1=enabled) P: PRG bank at $E000 (1=enabled) pp: PRG bank size 00 - nothing? 01 - 16k banks 10 - 8k banks 11 - 8k in reverse mode? NOTE- If PRG bank size=2 (10 - 8k banks): * if P=1, page at $6000 does not change; swap 8k PRG bank at $E000. * else (P=0), page at $E000 points to last 8k of PRG (originally set). If S=1, swap 8k of PRG at $6000. cc: CHR bank size select 00 - 8k banks 01 - 4k banks 10 - 2k banks 11 - 1k banks N: Mirroring 0: Normal mirroring (use the $D001 setting) 1: Use CHR banks, instead of VRAM $2000-$2FFF $D001 mirroring ------MM 00: Vertical mirroring 01: Horizontal mirroring 10, 11: All pages mirror from PPU $2000 $D002 unknown Unused? $D003 bank page Only used by larger carts ----------------------------------------------------------------------------- General notes: 1) CHR regs: - The value has 16 bits. However, MASK the final value correctly. - Use this table to help the CHR bankswitching. CHR bank size: bits 4&3 of $D000. =REG= =PPU area= ----------------- size : 1k 2k 4k 8k $9000 $0000-$03ff or $0000-$07ff or $0000-$0fff or $0000-$1fff $9001 $0400-$07ff $9002 $0800-$0bff or $0800-$0fff $9003 $0c00-$0fff $9004 $1000-$13ff or $1000-$17ff or $1000-$1fff $9005 $1400-$17ff $9006 $1800-$1bff or $1800-$1fff $9007 $1c00-$1fff Notice that only writes to $9000/$A000 can swap a 8k bank. Notice that only writes to $9000/$A000(L), $9004/$A004(H) can swap a 4k bank. Notice that only writes to: $9000/$A000 $9002/$A002 $9004/$A004 $9006/$A006 can swap a 2k bank; And... any register can swap 1k bank :-) Usually, you cache all writes to these registers: =================================== case 0x9000: case 0x9001: (...) case 0x9007: chr_low_byte[addr&7] = data sync_chr_banks() case 0xA000: case 0xA001: (...) case 0xA007: chr_high_byte[addr&7] = data sync_chr_banks() =================================== - Bits 4 & 3 of $D000 control the CHR bank size. - Sync CHR banks on $D000 writes too. 2) PRG regs: - On system reset, the LAST 32k of PRG appears at $8000. - They work like the CHR bankswitching: you cache all the writes: =================================== case 0x8000: case 0x8001: case 0x8002: case 0x8003: prg_banks[addr&3] = data sync_prg_banks() =================================== - Sync PRG banks on $D000 writes too. - Bits 1 & 0 of $D000 control the PRG bank size. *NOTES: - When PRG bank size is $0, Nori restores the RESET setting (last 32k of PRG to $8000). - When PRG bank size is $1 (16k), Nori keeps the last 16k of PRG at $C000. - When PRG bank size is $2 (8k) and P=0 (bit 2 of $D000), Nori keeps the last 8k of PRG at $E000. * In short words, he always restores the initial PRG state when that area is unused. 3) Mirroring: - It's not clear (I'm having problems with MK3). - I'll clarify how the mirroring works: 1) On $D001 writes, cache the value written. If bit 5 of $D000 (N) is clear, so mirroring works normally (Horizontal, Vertical or $2000 settings). 2) You usually cache writes to $B00x regs: =================================== case 0xb000: case 0xb001: case 0xb002: case 0xb003: nam_low_byte[addr&3] = data sync_mirrors() case 0xB004: case 0xB005: case 0xB006: case 0xB007: nam_high_byte[addr&3] = data sync_mirrors() =================================== 3) Writes to $D000 sync_mirrors() too. The sync_mirrors() looks like: void sync_mirrors() { u8 i; /* bankmode = last value written to $D000 */ if(bankmode & 0x20) { /* You map CHR data in the nametable area using the $B00x values. But, if (high byte, low byte) != (0,0) or (0,1) or (0,2) or (0,3), so N is cleared, and mirroring does not change. If you ignore it, a lot of crappy gfx might be displayed. */ for(i=0;i<4;i++) { if(!nam_high_byte[i] && (nam_low_byte[i] == i)) { bankmode &= 0xdf; //clear the N bit return; } } /* NOTE: #define NAM_CHR(v) \ (((nam_high_byte[v]<<8) | nam_low_byte[v]) << 10) size=1k ($400) */ PPU_NameTables[0] = &VROM[NAM_CHR(0)]; PPU_NameTables[1] = &VROM[NAM_CHR(1)]; PPU_NameTables[2] = &VROM[NAM_CHR(2)]; PPU_NameTables[3] = &VROM[NAM_CHR(3)]; } else { /* Use the normal mirroring (map90_mirror = last value written to $D001) */ switch(map90_mirror & 3) { case 0: set_vertical_mirroring(); break; case 1: set_horizontal_mirroring(); break; default: set_page(0x2000); } } } 4) Mapper reset: - The LAST 32k appears at $8000. - The 1st 8k of CHR appears at PPU $0000. 5) IRQs: - Not clear, but it works like MMC3 does. * IRQ counter is decremented at every scanline, always while not blanking (scanline < 240), and background or sprites are enabled. When it reaches zero (or a negative value), IRQ is triggered _IF_ the irq_flag is set, clearing the irq_flag and irq_latch. ============================================================================= I have no clue how accurate this stuff might be. Please, tell me if you did any changes to this file. -= Fx3 =- July, 17th 2000 (fx3rnes@hotmail.com) ============================================================================= eof