NES 2.0 Mapper 292: Difference between revisions

From NESdev Wiki
Jump to navigationJump to search
(Created page with "Category:MMC3-like mappersNES 2.0 Mapper 292 is used for the unlicensed game ''Dragon Fighter''. Its PCB name is "BMW8544", its UNIF board name is '''UNL-DRAGONFIGHTER'''....")
 
(Rewrite for clarity and accuracy. Use a current FCEUX source code link.)
Line 1: Line 1:
[[Category:MMC3-like mappers]]NES 2.0 Mapper 292 is used for the unlicensed game ''Dragon Fighter''. Its PCB name is "BMW8544", its UNIF board name is '''UNL-DRAGONFIGHTER'''. It's an [[MMC3]] clone with some extremely odd bankswitching that is poorly understood. The description below is based on the [https://github.com/asfdfdfd/fceux/blob/master/src/boards/BMW8544.cpp FCEUX source code], which sort-of runs the game, albeit with occasional graphical glitches.
{{DEFAULTSORT:292}}[[Category:MMC3-like mappers]][[Category:Mappers triggering on reads]]
'''NES 2.0 Mapper 292''' is used for the unlicensed game ''Dragon Fighter'' from "Flying Star", not to be confused with the licensed game from Natsume of the same name. Its PCB name is "BMW8544", its UNIF board name is '''UNL-DRAGONFIGHTER'''. It's an [[MMC3]] clone with custom CHR banking both for protection purposes and to access 512 KiB of CHR-ROM. PRG banking, mirroring and scanline IRQ work as on a normal MMC3.


=Banks=
=Banks=
* CPU $8000-$9FFF: 8 KiB switchable PRG-ROM bank selected by writing to $6000.
* CPU $8000-$9FFF: 8 KiB switchable/fixed PRG-ROM window
* CPU $A000-$BFFF: 8 KiB switchable PRG-ROM bank selected by MMC3 register $07, or fixed to last bank if PRG A14 inversion is active
* CPU $A000-$BFFF: 8 KiB switchable PRG-ROM window
* CPU $C000-$DFFF: 8 KiB PRG-ROM bank, fixed to the second-last bank, or switchable PRG-ROM bank selected by MMC3 register $06 if PRG A14 inversion is active
* CPU $C000-$DFFF: 8 KiB switchable/fixed PRG-ROM window
* CPU $E000-$FFFF: 8 KiB PRG-ROM bank, fixed to the last bank, or switchable PRG-ROM bank selected by MMC3 register $07 if PRG A14 inversion is active
* CPU $E000-$FFFF: 8 KiB fixed PRG-ROM window
* PPU $0000-$07FF: 2 KiB switchable CHR-ROM bank selected by (MMC3 register 0 SHR 1) XOR the low CHR bank.
* PPU $0000-$07FF: 2 KiB switchable CHR-ROM bank
* PPU $0800-$0FFF: 2 KiB switchable CHR-ROM bank selected by (MMC3 register 2 SHR 1) ORed with (bit 6 of the high CHR bank SHR 1).
* PPU $0800-$0FFF: 2 KiB switchable CHR-ROM bank
* PPU $1000-$1FFF: 4 KiB switchable CHR-ROM bank selected by bits 0-5 of the high CHR bank.
* PPU $1000-$1FFF: 4 KiB switchable CHR-ROM bank


MMC3 CHR A12 inversion ($8000 bit 7) is not supported.
=Extra Registers=
There are four extra registers that are filled by writing or reading (!) from the CPU $6000-$7FFF address range when PRG-RAM is enabled in the MMC3's A001 register.


=Registers=
==Extra Index Register ($6000-$7FFF, write)==
==PRG Bank Register ($6000, write)==
D~[ABR. ....]
Mask: Probably $E001
    ||+-------- Select Extra Data Register #0 or #1 on next $6000-$7FFF read
    ++--------- Always 1
It's hypothesized that clearing the A and B bits may switch the two CHR pattern table halves to normal MMC3 CHR banking, but this has not yet been verified on real hardware. The game keeps both bits enabled at all times.


Selects the 8 KiB PRG-ROM bank at CPU $8000-$9FFF.
==Extra Data Register #0 ($6000-$7FFF, read)==
D~[XXXX XXXX]
    ++++-++++- XOR value for 2 KiB CHR-ROM bank at PPU $0000-$07FF
This register is filled by ''reading'' from $6000-$7FFF when the Extra Index Register's R bit is 0. It is filled with the value that had been latched during the last CPU write CPU to any address.


==CHR Bank Register ($6000, read)==
==Extra Data Register #1 ($6000-$7FFF, read)==
Mask: Probably $E001
D~[.BAA AAAA]
    |++-++++- 4 KiB CHR-ROM bank at PPU $1000-$1FFF (CHR A17..A12)
    +-------- Upper bit of 2 KiB CHR-ROM bank at PPU $0800-$0FFF (CHR A18)
This register is filled by ''reading'' from $6000-$7FFF when the Extra Index Register's R bit is 1. It is filled with the value that had been latched during the last CPU write CPU to any address.


* When this register is '''read''' ''and'' the PRG Bank AND $E0 is ==$C0, then the low CHR bank is replaced with the value previously written to CPU RAM at $006A.
==Latch Register (Write)==
* When this register is '''read''' ''and'' the PRG Bank AND $E0 is !=$C0, then the high CHR bank is replaced with the value previously written to CPU RAM at $00FF.
All CPU writes, including writes to zero page memory, are visible on the cartridge connector. The mapper keeps the data of the last CPU write to any address in a temporary latch register, so it can store that data in one of its two Extra Data registers when so requested by ''reading'' from $6000-$7FFF.


==MMC3-compatible registers ($8000-$FFFF)==
=Effective CHR banks=
Mask: $E001
The address lines of CHR-ROM are effectively determined as follows:
===PPU $0000-$07FF===
CHR A10: PPU A10
CHR A11: Extra Register 0 Bit 0 XOR MMC3 A11 (MMC3 register 0, bit 1)
CHR A12: Extra Register 0 Bit 1 XOR MMC3 A12 (MMC3 register 0, bit 2)
CHR A13: Extra Register 0 Bit 2 XOR MMC3 A13 (MMC3 register 0, bit 3)
CHR A14: Extra Register 0 Bit 3 XOR MMC3 A14 (MMC3 register 0, bit 4)
CHR A15: Extra Register 0 Bit 4 XOR MMC3 A15 (MMC3 register 0, bit 5)
CHR A16: Extra Register 0 Bit 5 XOR MMC3 A16 (MMC3 register 0, bit 6)
CHR A17: Extra Register 0 Bit 6 XOR MMC3 A17 (MMC3 register 0, bit 7)
CHR A18: Extra Register 0 Bit 7
Or in C code: chrBank2K =extraRegister[0] ^ (mmc3Register[0] >> 1);
Note that when Bit 7 in the MMC3's index register is set, MMC3 registers 2/3 instead of register 0 apply.
===PPU $0800-$0FFF===
CHR A10: PPU A10
CHR A11: MMC3 A11 (i.e. MMC3 register 1 bit 1)
CHR A12: MMC3 A12 (i.e. MMC3 register 1 bit 2)
CHR A13: MMC3 A13 (i.e. MMC3 register 1 bit 3)
CHR A14: MMC3 A14 (i.e. MMC3 register 1 bit 4)
CHR A15: MMC3 A15 (i.e. MMC3 register 1 bit 5)
CHR A16: MMC3 A16 (i.e. MMC3 register 1 bit 6)
CHR A17: MMC3 A17 (i.e. MMC3 register 1 bit 7)
CHR A18: Extra Register 1 Bit 6
Or in C code: chrBank2K =((extraRegister[1] << 1) & 0x80) ^ (mmc3Register[1] >> 1);
Note that when Bit 7 in the MMC3's index register is set, MMC3 registers 4/5 instead of register 1 apply.
===PPU $1000-$1FFF===
CHR A10: PPU A10
CHR A11: PPU A11
CHR A12: Extra Register 1 Bit 0
CHR A13: Extra Register 1 Bit 1
CHR A14: Extra Register 1 Bit 2
CHR A15: Extra Register 1 Bit 3
CHR A16: Extra Register 1 Bit 4
CHR A17: Extra Register 1 Bit 5
CHR A18: Always 0, i.e. restricted to the first 256 KiB CHR-ROM half.
Or in C code: chrBank4K =extraRegister[1] & 0x3F;


Same as regular [[MMC3]] except where noted.
=Errata=
* Contrary to original thought, the PRG-ROM bank at CPU $8000-$9FFF is not determined by any extra register.
* The game has single-frame graphical glitches on real hardware when a metasprite is changed to a different animation cel. The reason is that OAM data is updated one frame later than the CHR bank registers.
 
=See also=
[https://github.com/TASEmulators/fceux/blob/master/src/boards/BMW8544.cpp FCEUX emulation source code]

Revision as of 03:32, 2 January 2025

NES 2.0 Mapper 292 is used for the unlicensed game Dragon Fighter from "Flying Star", not to be confused with the licensed game from Natsume of the same name. Its PCB name is "BMW8544", its UNIF board name is UNL-DRAGONFIGHTER. It's an MMC3 clone with custom CHR banking both for protection purposes and to access 512 KiB of CHR-ROM. PRG banking, mirroring and scanline IRQ work as on a normal MMC3.

Banks

  • CPU $8000-$9FFF: 8 KiB switchable/fixed PRG-ROM window
  • CPU $A000-$BFFF: 8 KiB switchable PRG-ROM window
  • CPU $C000-$DFFF: 8 KiB switchable/fixed PRG-ROM window
  • CPU $E000-$FFFF: 8 KiB fixed PRG-ROM window
  • PPU $0000-$07FF: 2 KiB switchable CHR-ROM bank
  • PPU $0800-$0FFF: 2 KiB switchable CHR-ROM bank
  • PPU $1000-$1FFF: 4 KiB switchable CHR-ROM bank

Extra Registers

There are four extra registers that are filled by writing or reading (!) from the CPU $6000-$7FFF address range when PRG-RAM is enabled in the MMC3's A001 register.

Extra Index Register ($6000-$7FFF, write)

D~[ABR. ....]
   ||+-------- Select Extra Data Register #0 or #1 on next $6000-$7FFF read
   ++--------- Always 1

It's hypothesized that clearing the A and B bits may switch the two CHR pattern table halves to normal MMC3 CHR banking, but this has not yet been verified on real hardware. The game keeps both bits enabled at all times.

Extra Data Register #0 ($6000-$7FFF, read)

D~[XXXX XXXX]
   ++++-++++- XOR value for 2 KiB CHR-ROM bank at PPU $0000-$07FF

This register is filled by reading from $6000-$7FFF when the Extra Index Register's R bit is 0. It is filled with the value that had been latched during the last CPU write CPU to any address.

Extra Data Register #1 ($6000-$7FFF, read)

D~[.BAA AAAA]
    |++-++++- 4 KiB CHR-ROM bank at PPU $1000-$1FFF (CHR A17..A12)
    +-------- Upper bit of 2 KiB CHR-ROM bank at PPU $0800-$0FFF (CHR A18)

This register is filled by reading from $6000-$7FFF when the Extra Index Register's R bit is 1. It is filled with the value that had been latched during the last CPU write CPU to any address.

Latch Register (Write)

All CPU writes, including writes to zero page memory, are visible on the cartridge connector. The mapper keeps the data of the last CPU write to any address in a temporary latch register, so it can store that data in one of its two Extra Data registers when so requested by reading from $6000-$7FFF.

Effective CHR banks

The address lines of CHR-ROM are effectively determined as follows:

PPU $0000-$07FF

CHR A10: PPU A10
CHR A11: Extra Register 0 Bit 0 XOR MMC3 A11 (MMC3 register 0, bit 1)
CHR A12: Extra Register 0 Bit 1 XOR MMC3 A12 (MMC3 register 0, bit 2)
CHR A13: Extra Register 0 Bit 2 XOR MMC3 A13 (MMC3 register 0, bit 3)
CHR A14: Extra Register 0 Bit 3 XOR MMC3 A14 (MMC3 register 0, bit 4)
CHR A15: Extra Register 0 Bit 4 XOR MMC3 A15 (MMC3 register 0, bit 5)
CHR A16: Extra Register 0 Bit 5 XOR MMC3 A16 (MMC3 register 0, bit 6)
CHR A17: Extra Register 0 Bit 6 XOR MMC3 A17 (MMC3 register 0, bit 7)
CHR A18: Extra Register 0 Bit 7
Or in C code: chrBank2K =extraRegister[0] ^ (mmc3Register[0] >> 1);

Note that when Bit 7 in the MMC3's index register is set, MMC3 registers 2/3 instead of register 0 apply.

PPU $0800-$0FFF

CHR A10: PPU A10
CHR A11: MMC3 A11 (i.e. MMC3 register 1 bit 1)
CHR A12: MMC3 A12 (i.e. MMC3 register 1 bit 2)
CHR A13: MMC3 A13 (i.e. MMC3 register 1 bit 3)
CHR A14: MMC3 A14 (i.e. MMC3 register 1 bit 4)
CHR A15: MMC3 A15 (i.e. MMC3 register 1 bit 5)
CHR A16: MMC3 A16 (i.e. MMC3 register 1 bit 6)
CHR A17: MMC3 A17 (i.e. MMC3 register 1 bit 7)
CHR A18: Extra Register 1 Bit 6
Or in C code: chrBank2K =((extraRegister[1] << 1) & 0x80) ^ (mmc3Register[1] >> 1);

Note that when Bit 7 in the MMC3's index register is set, MMC3 registers 4/5 instead of register 1 apply.

PPU $1000-$1FFF

CHR A10: PPU A10
CHR A11: PPU A11
CHR A12: Extra Register 1 Bit 0
CHR A13: Extra Register 1 Bit 1
CHR A14: Extra Register 1 Bit 2
CHR A15: Extra Register 1 Bit 3
CHR A16: Extra Register 1 Bit 4
CHR A17: Extra Register 1 Bit 5
CHR A18: Always 0, i.e. restricted to the first 256 KiB CHR-ROM half.
Or in C code: chrBank4K =extraRegister[1] & 0x3F;

Errata

  • Contrary to original thought, the PRG-ROM bank at CPU $8000-$9FFF is not determined by any extra register.
  • The game has single-frame graphical glitches on real hardware when a metasprite is changed to a different animation cel. The reason is that OAM data is updated one frame later than the CHR bank registers.

See also

FCEUX emulation source code