https://www.nesdev.org/w/api.php?action=feedcontributions&user=Zepper&feedformat=atomNESdev Wiki - User contributions [en]2024-03-29T01:23:43ZUser contributionsMediaWiki 1.39.0https://www.nesdev.org/w/index.php?title=Sunsoft_FME-7&diff=11490Sunsoft FME-72021-05-28T14:20:18Z<p>Zepper: /* PRG Bank 0 ($8) */ minor glitch</p>
<hr />
<div>{{Infobox iNES mapper<br />
|name=FME-7<br />
|name2=Sunsoft 5A/5B<br />
|company=Sunsoft<br />
|mapper=69<br />
|nescartdbgames=9<br />
|complexity=ASIC<br />
|boards=JLROM, JSROM,<br />NES-BTR, others<br />
|pinout=Sunsoft 5 pinout<br />
|prgmax=512K (FME-7)<br>256K (5A/5B)<br />
|prgpage=8K×4 + 8K fixed<br />
|wrammax=512K (FME-7)<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=1Kx8<br />
|mirroring=H, V, or 1, switchable<br />
|busconflicts=No<br />
|irq=CPU cycle counter<br />
|audio=[[Sunsoft 5B audio|5B only]]<br />
}}<br />
[[Category:Mappers with large PRG RAM]][[Category:Nintendo licensed mappers]][[Category:Mappers with cycle IRQs]][[Category:Mappers with single-screen mirroring]]<br />
The [[Sunsoft FME-7]] is a mapper IC used by Sunsoft in several of its games. It is nearly identical to the '''Sunsoft 5A''' and '''Sunsoft 5B''' mapper chips used only in Famicom games, with the 5B notably having expansion audio (see [[Sunsoft 5B audio]]).<br />
<br />
The FME-7, 5A and 5B are grouped together as '''iNES Mapper 69'''.<br />
<br />
Both the Sunsoft 5B and FME-7 exist as a 44 pin TQFP chip: [[Sunsoft 5 pinout|diagram]] <br />
<br />
In Europe, boards using the FME-7 were labeled as [[JxROM|JSROM and JLROM]]. The FME-7 mapper was used in only one game released in the US, ''Batman: Return of the Joker''. Many Japanese releases by Sunsoft used the FME-7: ''Gimmick!'', ''Hebereke'', ''Gremlins 2'' (but not in the US version), ''Barcode World'', and others.<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB Bankable PRG ROM or PRG RAM<br />
* CPU $8000-$9FFF: 8 KB Bankable PRG ROM<br />
* CPU $A000-$BFFF: 8 KB Bankable PRG ROM<br />
* CPU $C000-$DFFF: 8 KB Bankable PRG ROM<br />
* CPU $E000-$FFFF: 8 KB PRG ROM, fixed to the last bank of ROM<br />
* PPU $0000-$03FF: 1 KB Bankable CHR ROM<br />
* PPU $0400-$07FF: 1 KB Bankable CHR ROM<br />
* PPU $0800-$0BFF: 1 KB Bankable CHR ROM<br />
* PPU $0C00-$0FFF: 1 KB Bankable CHR ROM<br />
* PPU $1000-$13FF: 1 KB Bankable CHR ROM<br />
* PPU $1400-$17FF: 1 KB Bankable CHR ROM<br />
* PPU $1800-$1BFF: 1 KB Bankable CHR ROM<br />
* PPU $1C00-$1FFF: 1 KB Bankable CHR ROM<br />
<br />
== Registers ==<br />
Configuration of the FME-7 is accomplished by first writing the command number to the Command Register at $8000-9FFF, then writing the command's parameter byte to the Parameter Register at $A000-BFFF.<br />
<br />
There are 16 commands:<br />
* '''$0-7''' control CHR banking<br />
* '''$8-B''' control PRG banking<br />
* '''$C''' controls nametable mirroring<br />
* '''$D-F''' controls IRQ<br />
<br />
On the 5B variant, there are two additional registers at $C000-DFFF and $E000-FFFF that control the audio expansion. See: [[Sunsoft 5B audio]]<br />
<br />
=== Command Register ($8000-$9FFF) ===<br />
7 bit 0<br />
---- ----<br />
.... CCCC<br />
||||<br />
++++- The command number to invoke when writing to the Parameter Register<br />
<br />
=== Parameter Register ($A000-$BFFF) ===<br />
7 bit 0<br />
---- ----<br />
PPPP PPPP<br />
|||| ||||<br />
++++-++++- The parameter to use for this command. Writing to this register invokes the command in the Command Register.<br />
<br />
== Commands ==<br />
<br />
=== CHR Bank 0-7 ($0-7) ===<br />
7 bit 0<br />
---- ----<br />
BBBB BBBB<br />
|||| ||||<br />
++++-++++- The bank number to select for the specified bank.<br />
<br />
Bank $0 - PPU $0000-$03FF<br />
Bank $1 - PPU $0400-$07FF<br />
Bank $2 - PPU $0800-$0BFF<br />
Bank $3 - PPU $0C00-$0FFF<br />
Bank $4 - PPU $1000-$13FF<br />
Bank $5 - PPU $1400-$17FF<br />
Bank $6 - PPU $1800-$1BFF<br />
Bank $7 - PPU $1C00-$1FFF<br />
<br />
=== PRG Bank 0 ($8) ===<br />
7 bit 0<br />
---- ----<br />
ERBB BBBB<br />
|||| ||||<br />
||++-++++- The bank number to select at CPU $6000 - $7FFF<br />
|+------- RAM / ROM Select Bit<br />
| 0 = PRG ROM<br />
| 1 = PRG RAM<br />
+-------- RAM Enable Bit ([[6264]] +CE line)<br />
0 = PRG RAM Disabled<br />
1 = PRG RAM Enabled<br />
<br />
The FME-7 has up to 6 bits for PRG banking (512 KiB), though this was never used in a game. The 5A and 5B, however, support only 5 (256 KiB). The extra address line is instead an audio expansion line, or unused.<br />
<br />
It is [http://forums.nesdev.org/viewtopic.php?f=9&t=12467 confirmed] that the FME-7 outputs the bank number during accesses to $6000-$7FFF even if RAM is enabled.<br />
Though Sunsoft never took advantage of this, it would allow making a cartridge that bank switches up to 256 KiB of PRG RAM.<br />
The FME-7 mapper in Loopy's [[PowerPak]] mappers, for example, supports 32 KiB.<br />
<br />
Open bus occurs if the RAM / ROM Select Bit is 1 (RAM selected), but the RAM Enable Bit is 0 (disabled), i.e. any value in the range $40-$7F. This is a limited form of WRAM write protection on power-up.<br />
<br />
NOTE: the enable bit is NOT functional with 2048×8, 32768×8, and 524288×8 RAMs, because those RAMs don't have a +CE input.<br />
<br />
There is a [http://forums.nesdev.org/viewtopic.php?p=105129#p105129 tentative report] that [http://forums.nesdev.org/viewtopic.php?p=105193#p105193 not all games honor some or any of the bits in this register]. Corroboration is needed before any action is taken.<br />
<br />
=== PRG Bank 1-3 ($9-B) ===<br />
7 bit 0<br />
---- ----<br />
..bB BBBB<br />
|| ||||<br />
++-++++- The bank number to select for the specified bank.<br />
<br />
Bank $9 - CPU $8000-$9FFF<br />
Bank $A - CPU $A000-$BFFF<br />
Bank $B - CPU $C000-$DFFF<br />
<br />
The FME-7 has up to 6 bits for PRG banking, but the 5A and 5B support only 5.<br />
<br />
=== Name Table Mirroring ($C) ===<br />
These values are the same as [[MMC1]] mirroring modes with the MSB inverted.<br />
7 bit 0<br />
---- ----<br />
.... ..MM<br />
||<br />
++- Mirroring Mode<br />
0 = Vertical<br />
1 = Horizontal<br />
2 = One Screen Mirroring from $2000 ("1ScA")<br />
3 = One Screen Mirroring from $2400 ("1ScB")<br />
<br />
=== IRQ Control ($D) ===<br />
7 bit 0<br />
---- ----<br />
C... ...T<br />
| |<br />
| +- IRQ Enable<br />
| 0 = Do not generate IRQs<br />
| 1 = Do generate IRQs<br />
+-------- IRQ Counter Enable<br />
0 = Disable Counter Decrement<br />
1 = Enable Counter Decrement<br />
<br />
All writes to this register acknowledge an active IRQ.<ref>Test performed in 2015 by Oliveira using [http://forums.nesdev.org/viewtopic.php?p=142243#p142243 IRQ acknowledge test ROM on NESdev BBS]</ref> It is not yet known what will happen if this register is written to at the same time as an IRQ would have been generated.<br />
<br />
=== IRQ Counter Low Byte ($E) ===<br />
7 bit 0<br />
---- ----<br />
LLLL LLLL<br />
|||| ||||<br />
++++-++++- The low eight bits of the IRQ counter<br />
<br />
=== IRQ Counter High Byte ($F) ===<br />
7 bit 0<br />
---- ----<br />
HHHH HHHH<br />
|||| ||||<br />
++++-++++- The high eight bits of the IRQ counter<br />
<br />
Writes to the IRQ counter registers directly set the lower or upper eight bits of the counter. Unlike on MMC3, there is no separate reload latch.<br />
<br />
== IRQ Operation ==<br />
The IRQ feature of FME-7 is a CPU cycle counting IRQ generator. When enabled the 16-bit IRQ counter is decremented once per CPU cycle. When the IRQ counter is decremented from $0000 to $FFFF an IRQ is generated. The IRQ line is held low until it is acknowledged.<br />
<br />
=== How to Use the IRQ Generator ===<br />
# Set the counter to the desired number of cycles minus one.<br />
# Enable the IRQ generator by turning on both the IRQ Enable and IRQ Counter Enable flags of the IRQ Control command.<br />
# Within the IRQ handler, write to the IRQ Control command to acknowledge the IRQ.<br />
# Optional: Go back to Step 1 for the next IRQ.<br />
<br />
== References ==<br />
<references/><br />
<br />
== See also ==<br />
* [http://nesdev.org/sunsoft.txt Sunsoft Mapper] by goroh, translated by Sgt. Bowhack.<br />
* [http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_117&diff=4888INES Mapper 1172021-05-28T01:30:15Z<p>Zepper: /* IRQ operation */</p>
<hr />
<div>iNES Mapper 117 is used for ''Crayon Shin-Chan (Ch)'' and ''San Guo Zhi 4 - Chi Bi Feng Yun'' by Future Media.<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KB switchable PRG ROM bank.<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank.<br />
* CPU $C000-$DFFF: 8 KB switchable PRG ROM bank.<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank.<br />
<br />
* PPU $0000-$03FF: 1 KB switchable CHR ROM bank.<br />
* PPU $0400-$07FF: 1 KB switchable CHR ROM bank.<br />
* PPU $0800-$0BFF: 1 KB switchable CHR ROM bank.<br />
* PPU $0C00-$0FFF: 1 KB switchable CHR ROM bank.<br />
* PPU $1000-$13FF: 1 KB switchable CHR ROM bank.<br />
* PPU $1400-$17FF: 1 KB switchable CHR ROM bank.<br />
* PPU $1800-$1BFF: 1 KB switchable CHR ROM bank.<br />
* PPU $1C00-$1FFF: 1 KB switchable CHR ROM bank.<br />
<br />
== Registers ==<br />
<br />
$8000/$8001/$8002<br />
7 bit 0<br />
---- ----<br />
PPPP PPPP<br />
|||| ||||<br />
++++-++++- swaps 8 KB PRG ROM bank at CPU $8000/$A000/$C000.<br />
<br />
$A000/$A001/$A002/$A003/$A004/$A005/$A006/$A007<br />
7 bit 0<br />
---- ----<br />
CCCC CCCC<br />
|||| ||||<br />
++++-++++- swaps 1 KB CHR ROM bank at PPU $400*(address AND 7).<br />
<br />
$A008/$A009/$A00A/$A00B/$A00C/$A00D/$A00E/$A00F<br />
* Unknown, writes should be ignored.<br />
<br />
$C000/$C001/$C002<br />
* Any write to these registers sets the IRQ counter AND latch to the value written.<br />
* IRQs are also acknowledged.<br />
<br />
$E000<br />
7 bit 0<br />
---- ----<br />
xxxx xxxI<br />
|<br />
+-- IRQ enable/disable.<br />
<br />
<br />
== IRQ operation ==<br />
<br />
* The IRQ counter value selects PPU scanline MINUS $14 (?) to trigger an IRQ.<br />
* If the IRQ counter matches the scanline number, and IRQs are enabled, and the latched value isn't zero, an IRQ is triggered. The counter is set to zero.</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_117&diff=4887INES Mapper 1172021-05-28T01:28:48Z<p>Zepper: /* My mapper 117 information (a reliable source of information is lacking). */</p>
<hr />
<div>iNES Mapper 117 is used for ''Crayon Shin-Chan (Ch)'' and ''San Guo Zhi 4 - Chi Bi Feng Yun'' by Future Media.<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KB switchable PRG ROM bank.<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank.<br />
* CPU $C000-$DFFF: 8 KB switchable PRG ROM bank.<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank.<br />
<br />
* PPU $0000-$03FF: 1 KB switchable CHR ROM bank.<br />
* PPU $0400-$07FF: 1 KB switchable CHR ROM bank.<br />
* PPU $0800-$0BFF: 1 KB switchable CHR ROM bank.<br />
* PPU $0C00-$0FFF: 1 KB switchable CHR ROM bank.<br />
* PPU $1000-$13FF: 1 KB switchable CHR ROM bank.<br />
* PPU $1400-$17FF: 1 KB switchable CHR ROM bank.<br />
* PPU $1800-$1BFF: 1 KB switchable CHR ROM bank.<br />
* PPU $1C00-$1FFF: 1 KB switchable CHR ROM bank.<br />
<br />
== Registers ==<br />
<br />
$8000/$8001/$8002<br />
7 bit 0<br />
---- ----<br />
PPPP PPPP<br />
|||| ||||<br />
++++-++++- swaps 8 KB PRG ROM bank at CPU $8000/$A000/$C000.<br />
<br />
$A000/$A001/$A002/$A003/$A004/$A005/$A006/$A007<br />
7 bit 0<br />
---- ----<br />
CCCC CCCC<br />
|||| ||||<br />
++++-++++- swaps 1 KB CHR ROM bank at PPU $400*(address AND 7).<br />
<br />
$A008/$A009/$A00A/$A00B/$A00C/$A00D/$A00E/$A00F<br />
* Unknown, writes should be ignored.<br />
<br />
$C000/$C001/$C002<br />
* Any write to these registers sets the IRQ counter AND latch to the value written.<br />
* IRQs are also acknowledged.<br />
<br />
$E000<br />
7 bit 0<br />
---- ----<br />
xxxx xxxI<br />
|<br />
+-- IRQ enable/disable.<br />
<br />
<br />
== IRQ operation ==<br />
<br />
* The IRQ counter value MINUS $14 (?) selects a PPU scanline to trigger an IRQ.<br />
* If the IRQ counter matches the scanline number, and IRQs are enabled, and the latched value isn't zero, an IRQ is triggered. The counter is set to zero.</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10921RAMBO-12021-03-07T13:48:36Z<p>Zepper: /* IRQ counter operation */ grammar</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|pinout=Tengen RAMBO-1 pinout<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
* ''Rolling Thunder''<br />
* ''Hard Drivin' (prototype)''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0000: R0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000)<br />
||| 0001: R1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800)<br />
||| 0010: R2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF)<br />
||| 0011: R3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF)<br />
||| 0100: R4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF)<br />
||| 0101: R5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF)<br />
||| 0110: R6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF)<br />
||| 0111: R7: Select 8 KiB PRG ROM bank at $A000-$BFFF<br />
||| 1000: R8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400)<br />
||| 1001: R9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00)<br />
||| 1111: RF: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF)<br />
||+------- Full 1 KiB CHR bank mode 0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF)<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF)<br />
|+-------- PRG ROM bank mode 0: $8000-$9FFF uses bank selected with R6<br />
| $A000-$BFFF uses bank selected with R7<br />
| $C000-$DFFF uses bank selected with RF<br />
| 1: $8000-$9FFF uses bank selected with RF<br />
| $A000-$BFFF uses bank selected with R7<br />
| $C000-$DFFF uses bank selected with R6<br />
+--------- CHR A12 inversion 0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF<br />
four 1 KiB banks at $1000-$1FFF<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF<br />
four 1 KiB banks at $0000-$0FFF<br />
<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & $80 !! is $00 !! is $80<br />
|-<br />
! PPU Bank !! colspan=2|Value of RAMBO-1 register<br />
|-<br />
| $0000-$03FF || R0 || R2<br />
|-<br />
| $0400-$07FF || K=0: R0<br/>K=1: R8 || R3<br />
|-<br />
| $0800-$0BFF || R1 || R4<br />
|-<br />
| $0C00-$0FFF || K=0: R1<br/>K=1: R9 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0<br />
|-<br />
| $1400-$17FF || R3 || K=0: R0<br/>K=1: R8 <br />
|-<br />
| $1800-$1BFF || R4 || R1<br />
|-<br />
| $1C00-$1FFF || R5 || K=0: R1<br/>K=1: R9 <br />
|}<br />
With 2KiB banks (where K=0), only even-numbered CHR banks can be selected. The lowest bit in the register is ignored and instead passes PPU A10 directly through to CHR A10.<br />
<br />
==== PRG Banks ====<br />
Because the values in R6, R7, RF, and $8000 are unspecified at power on, the reset vector must point into $E000-$FFFF, and code must initialize these before jumping out of $E000-$FFFF.<br />
<br />
{| class="wikitable"<br />
! When $8000 & $40 !! is $00 !! is $40<br />
|-<br />
! CPU Bank !! colspan=2|Value of RAMBO-1 register<br />
|-<br />
| $8000-$9FFF || R6 || RF<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || RF || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
=== Unknown ($A001-$BFFF, odd) ===<br />
This register is either not implemented or has undiscovered functionality on RAMBO-1. The MMC3/MMC6 equivalent of this register controls external and internal PRG-RAM access. There is not presently any reason to believe that RAMBO-1 has any support for PRG-RAM.<br />
<br />
== IRQ registers ==<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts. Note that writing to this register does not acknowledge the IRQ if already set.<br />
<br />
== IRQ counter operation ==<br />
There are two IRQ modes: PPU A12 mode (also known as ''scanline mode'') and CPU cycle mode.<br />
<br />
In ''scanline mode'', the counter is clocked using a very similar method to that used by the [[MMC3]] and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In ''CPU cycle mode'', the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever IRQ mode is being used, the counter behaves the following way:<br />
<br />
'''When the IRQ is clocked by ''scanline'' or ''CPU cycle'' modes:'''<br />
* '''IF''' $C001 was written to after previous clock:<br />
** reload IRQ counter with IRQ reload value; if non zero, this value is '''ORed with 1''' (see notes).<br />
* '''ELSE IF''' IRQ counter is 0:<br />
** reload IRQ counter with IRQ reload value.<br />
* '''ELSE'''<br />
** Decrement IRQ counter by 1. <br />
* If IRQ counter is now 0 '''AND''' IRQs are enabled:<br />
** trigger IRQ after 4 CPU cycles.<br />
<br />
'''Notes:''' <br />
* It's still unknown how the extra kick works. ''Klax'' still requires '''+1''' to run perfectly.<br />
* Most emulators run ''Skull & Crossbones'' with a glitched scanline on the "Continue" screen OR during the game (score bar). <br />
<br />
Following these rules in scanline counter mode has demonstrated accurate behavior, but this needs to be refined and merged with the description above:<br />
<br />
On M2 falling edge:<br />
If PA12 = 0:<br />
If 4-bit counter < 16: 4-bit counter++.<br />
else keep the same value.<br />
If PA12 = 1:<br />
If 4-bit counter = 16: Clock the 8-bit counter.<br />
Always reset 4-bit counter to 0.<br />
<br />
On 8-bit counter clock:<br />
If value = 0:<br />
If IRQ is enabled, trigger IRQ (wait 1 more cycle before doing that though, regardless of PA12 next cycle...)<br />
Always reload counter with value in $C000.<br />
Else value--.<br />
<br />
On Write to $C001 (reset):<br />
Reload 8-bit counter with value in $C000<br />
Set 4-bit counter to 17.<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Emulators&diff=2361Emulators2020-02-09T22:50:13Z<p>Zepper: /* Popular */ Back to the work!</p>
<hr />
<div>This is a '''list of NES emulators'''.<br />
<br />
__TOC__<br />
<br />
== Commercial ==<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| acNES<br />
| Nintendo<br />
| GameCube, Game Boy Advance<br />
| Used for Animal Crossing, e-Reader, and Classic NES Series. The name "acNES" is unofficial, as Nintendo has not released this emulator as a distinct product. Information from TCRF indicates that it may be called "QFC".<br />
|-<br />
| Virtual Console<br />
| Nintendo<br />
| Wii/Wii U/3DS<br />
| Most games cost 500 Nintendo Points in Wii Shop Channel<br />
|-<br />
| [http://www.dwedit.org/gba/pocketnes.php PocketNES]<br />
| loopy, FluBBa, and Dwedit<br />
| Game Boy Advance, Nintendo DS<br />
| Used commercially for some emulated re-releases by Atlus, Jaleco, Konami<br />
|}<br />
<br />
== Popular ==<br />
These are commonly used or well-established.<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [https://github.com/TASVideos/BizHawk BizHawk] || Multiple authors || Win32, macOS<br />
|-<br />
| [http://wiibrew.org/wiki/FCE_Ultra_GX FCE Ultra GX] || Tantric || Wii, GameCube<br />
|-<br />
| [http://fceux.com/web/home.html FCEUX] || Anthony Giorgio / Mark Doliner || Win32, Linux<br />
|-<br />
| [http://www.the-interweb.com/serendipity/index.php?/categories/9-FCEUXD-SP FCEUXD SP] || sp || Win32<br />
|-<br />
| [https://byuu.org/emulation/higan/ higan] || byuu || Win32, FreeBSD, Linux, macOS || Multi-platform<br />
|-<br />
| [http://fms.komkon.org/iNES/ iNES] || Marat Fayzullin || Win32 and Linux<br />
|-<br />
| [http://jabosoft.com/?categoryid=1 Jnes] || Jabosoft || Win32<br />
|-<br />
| [http://www.mesen.ca/ Mesen] || Sour || Win32/.NET || [http://forums.nesdev.org/viewtopic.php?p=164372#p164372 Announcement] / [https://github.com/SourMesen/Mesen Source], excellent debugger<br />
|-<br />
| [http://www.nemulator.com nemulator] || James Slepicka || Win32 (Vista/7)<br />
|-<br />
| [http://www.nesemu2.com/ nesemu2] || holodnak || Win32, OS X, Linux || [https://github.com/holodnak/nesemu2 github source]<br />
|-<br />
| [http://tnse.zophar.net/NESten.htm NESten] || TNSe || Win32<br />
|-<br />
| [http://nestopia.sourceforge.net/ NEStopia] || Martin Freij || Win32 || [http://rbelmont.mameworld.info/?page_id=200 Linux], [http://www.bannister.org/software/nestopia.htm MacOS]<br />
|-<br />
| [http://0ldsk00l.ca/nestopia/ Nestopia UE] || rdanbrook || Linux, BSD, Win7+ || a.k.a. Nestopia Undead Edition. Contains bugfixes/etc.<br />Windows binaries are available [http://sourceforge.net/projects/nestopiaue/ at Sourceforge] or [http://www.emucr.com/search/label/Nestopia at EmuCR]<br />
|-<br />
| [http://www.qmtpro.com/~nes/nintendulator/ Nintendulator] || Quietust || Win32 || [http://kkfos.aspekt.fi/projects/nes/tools/nintendulatordx/ Nintendulator DX] (by [[User:Thefox|thefox]]) for an even more-improved debugger<br />
|-<br />
| [http://problemkaputt.de/nes.htm NO$NES] || Martin Korth || Win32<br />
|-<br />
| [http://www.dwedit.org/gba/pocketnes.php PocketNES] || loopy, FluBBa, and Dwedit || Game Boy Advance || Updates on [http://www.dwedit.org/dwedit_board/viewtopic.php?id=409 Dwedit's board]<br />
|-<br />
| [http://rocknes.web.fc2.com RockNES] || Zepper (formerly Fx3) || Win32 || Status: under development.<br />
|-<br />
| [http://www.ubernes.com/ UberNES] || M \ K Productions || Win32<br />
|-<br />
| [http://virtuanes.s1.xrea.com/ VirtuaNES] || Norix || Win32 || Has a real-time memory hex-editor<br />
|}<br />
<br />
== Under development ==<br />
<br />
The following is a list of NES emulators that are supposedly under development, who their authors are, relevant home pages/sites, and the source of the announcement (direct or indirect).<br />
<br />
{{mbox<br />
| type = warning<br />
| text = '''Before considering developing your own NES emulator, ask yourself if your efforts may be better spent helping out those who already have emulators in development!'''<br />
}}<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [http://www.nesicide.com/ NESICIDE] || cpow || Win32/64, Linux32/64, macOS ||<br />
|-<br />
| [http://fpganes.blogspot.se/ FPGA NES] || Ludde || FPGA (hardware) ||<br />
|-<br />
| [https://rm-rfroot.net/nes_fpga/ VeriNES] || jwdonal || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=6157 Announcement]<br />
|-<br />
| [http://kevtris.org/Projects/console/sections/index.html FPGA NES] || kevtris || FPGA (hardware) ||<br />
|-<br />
| [http://danstrother.com/fpga-nes/ FPGA NES] || Dan Strother || FPGA (hardware) ||<br />
|-<br />
| [http://code.google.com/p/nesface/ NESFaCE] || 6T4 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7499 Announcement]<br />
|-<br />
| [http://www.crazysmart.net.au/kindred kindred] || Overload || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10429 Announcement]<br />
|-<br />
| ? || allthatremains || Win32 || [http://forums.nesdev.org/viewtopic.php?t=5108 Announcement]<br />
|-<br />
| [http://www.aminlab.cn/app/nes/ ?] || amin2312 || Flash || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ModNES || Petruza || Portable, mainly MacOS & Win32 || [http://forums.nesdev.org/viewtopic.php?t=6159 Announcement]<br />
|-<br />
| [http://www.anes.se/ A/NES] || Morgan Johansson || AmigaOS || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?f=3&t=6928 puNES] || FHorse || Linux32/64, Win32/64 || [http://forums.nesdev.org/viewtopic.php?t=6928 Announcement] / [https://github.com/punesemu/puNES Source]<br />
|-<br />
| [https://github.com/rohtang/famique famique] || sahib || Mac OS X, Win32, Linux || [http://forums.nesdev.org/viewtopic.php?t=5922 Announcement]<br />
|-<br />
| FooNES || aphex || Win32 || [http://forums.nesdev.org/viewtopic.php?p=75152#p75152 Announcement]<br />
|-<br />
| nesemu1 || Bisqwit || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?t=8385 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?t=8400 MoarNES] || miker00lz || Win32 || [http://forums.nesdev.org/viewtopic.php?t=6972 Announcement]<br />
|-<br />
| jaNES || crudelios || Win32 || [http://forums.nesdev.org/viewtopic.php?p=89751 Announcement]<br />
|-<br />
| ? || neet || ? || [http://forums.nesdev.org/viewtopic.php?p=89437#p89437 Announcement]<br />
|-<br />
| ? || foobaz || Java || [http://forums.nesdev.org/viewtopic.php?t=8559 Announcement]<br />
|-<br />
| ? || MottZilla || ? || [http://forums.nesdev.org/viewtopic.php?t=8491 Announcement]<br />
|-<br />
| ? || runaway pancake || ? || [http://forums.nesdev.org/viewtopic.php?p=88478#p88478 Announcement]<br />
|-<br />
| ? || Vegenad || ? || [http://forums.nesdev.org/viewtopic.php?t=3593 Announcement]<br />
|-<br />
| ? || johnathonrh || ? || [http://forums.nesdev.org/viewtopic.php?t=5780 Announcement]<br />
|-<br />
| [http://www.yanese.com/ Yanese] || Anes || Win32 || [http://forums.nesdev.org/viewtopic.php?p=713 Announcement]<br />
|-<br />
| ? || nesemuguy || ? || [http://forums.nesdev.org/viewtopic.php?t=2798 Announcement]<br />
|-<br />
| ? || Coldberg || ? || [http://forums.nesdev.org/viewtopic.php?t=4231 Announcement]<br />
|-<br />
| ? || pops || ? || [http://forums.nesdev.org/viewtopic.php?t=6260 Announcement]<br />
|-<br />
| ? || beannaich || ? || [http://forums.nesdev.org/viewtopic.php?t=6240 Announcement]<br />
|-<br />
| ? || windwakr || ? || [http://forums.nesdev.org/viewtopic.php?t=6294 Announcement]<br />
|-<br />
| ? || JuniorZ || ? || [http://forums.nesdev.org/viewtopic.php?t=896 Announcement]<br />
|-<br />
| ? || NesHackR || ? || [http://forums.nesdev.org/viewtopic.php?t=6102 Announcement]<br />
|-<br />
| AwesomeNES || Snaer || libSDL (portable) || [http://forums.nesdev.org/viewtopic.php?t=6064 Announcement]<br />
|-<br />
| ? || BeTheDuck || ? || [http://forums.nesdev.org/viewtopic.php?t=5869 Announcement]<br />
|-<br />
| ? || Luke || ? || [http://forums.nesdev.org/viewtopic.php?t=5821 Announcement]<br />
|-<br />
| ? || The Lord || ? || [http://forums.nesdev.org/viewtopic.php?t=5795 Announcement]<br />
|-<br />
| ? || essial || ? || [http://forums.nesdev.org/viewtopic.php?t=5791 Announcement]<br />
|-<br />
| ? || JamesK89 || ? || [http://forums.nesdev.org/viewtopic.php?t=5787 Announcement]<br />
|-<br />
| ? || yaazz || OS X || [http://forums.nesdev.org/viewtopic.php?t=5723 Announcement]<br />
|-<br />
| ? || blanham || OS X || [http://forums.nesdev.org/viewtopic.php?t=5312 Announcement]<br />
|-<br />
| ? || magicphenix || ? || [http://forums.nesdev.org/viewtopic.php?t=5703 Announcement]<br />
|-<br />
| ? || happymaomao || ? || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ? || someone_somewhere || ? || [http://forums.nesdev.org/viewtopic.php?t=5638 Announcement]<br />
|-<br />
| ? || Undubbed || ? || [http://forums.nesdev.org/viewtopic.php?t=5482 Announcement]<br />
|-<br />
| ? || Muchaserres || ? || [http://forums.nesdev.org/viewtopic.php?t=3665 Announcement]<br />
|-<br />
| ? || takeda || ? || [http://forums.nesdev.org/viewtopic.php?t=5530 Announcement]<br />
|-<br />
| ? || albailey || ? || [http://forums.nesdev.org/viewtopic.php?t=5512 Announcement]<br />
|-<br />
| ? || CaptainMuscles || ? || [http://forums.nesdev.org/viewtopic.php?t=5419 Announcement]<br />
|-<br />
| ? || hatorijr || ? || [http://forums.nesdev.org/viewtopic.php?t=5408 Announcement]<br />
|-<br />
| ? || tanoatnd || ? || [http://forums.nesdev.org/viewtopic.php?t=5189 Announcement]<br />
|-<br />
| ? || max_sweat || ? || [http://forums.nesdev.org/viewtopic.php?t=5388 Announcement]<br />
|-<br />
| ? || jjpeerless || ? || [http://forums.nesdev.org/viewtopic.php?t=5281 Announcement]<br />
|-<br />
| ? || Cloudy || ? || [http://forums.nesdev.org/viewtopic.php?t=5109 Announcement]<br />
|-<br />
| ? || meatloaf69 || ? || [http://forums.nesdev.org/viewtopic.php?p=62817#p62817 Announcement]<br />
|-<br />
| ? || parth || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=4502 Announcement]<br />
|-<br />
| ? || oRBIT2002 || ? || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| ? || Elessar || ? || [http://forums.nesdev.org/viewtopic.php?t=7862 Announcement]<br />
|-<br />
| ? || cmoh89 || ? || [http://forums.nesdev.org/viewtopic.php?t=7521 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?f=3&t=9935 HDNes] || mkwong98 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7848 Announcement]<br />
|-<br />
| ? || ehguacho || ? || [http://forums.nesdev.org/viewtopic.php?t=7936 Announcement]<br />
|-<br />
| ? || nop || Java || [http://forums.nesdev.org/viewtopic.php?t=8876 Announcement]<br />
|-<br />
| ? || emu_enthusiast || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=5826 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?p=140741#p140741 MahNES] || HLorenzi || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9054 Announcement]<br />
|-<br />
| ? || haydenmuhl || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9101 Announcement]<br />
|-<br />
| ? || urbanspr1nter || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9227 Announcement]<br />
|-<br />
| Fergulator || fergus_maximus || Mac OS X or X Windows || [http://forums.nesdev.org/viewtopic.php?f=3&t=9292 Announcement]<br />
|-<br />
| ? || ermular || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9353 Announcement]<br />
|-<br />
| ? || alexwy || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9608 Announcement]<br />
|-<br />
| ? || caiiio || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9625 Announcement]<br />
|-<br />
| ? || miguelsfp || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9726 Announcement]<br />
|-<br />
| ? || ember || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=3&t=9653 Announcement]<br />
|-<br />
| ? || ninjis || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9829 Announcement]<br />
|-<br />
| [http://www.geocities.jp/submarine600/html/p8/nesemu.html ?] || submarine600 || PC-8801 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9921 Announcement]<br />
|-<br />
| [http://alike.se/yane/ Yane] || roku6185 || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?f=3&t=9969 Announcement]<br />
|-<br />
| [http://vpnes.googlecode.com/ VPNES] || x0000 || Win32 w/ SDL || <br />
|-<br />
| [https://github.com/macifom/macifom macifom] || Auston Stewart || OS X, iOS || [http://forums.nesdev.org/viewtopic.php?f=3&t=9989 Announcement]<br />
|-<br />
| [https://github.com/macifom/macifomlite macifomlite] || Auston Stewart || iOS || <br />
|-<br />
| [https://github.com/eteran/pretendo Pretendo] || proxy || Linux/BeOS/Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10045 Announcement]<br />
|-<br />
| ? || samfoo || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10070 Announcement]<br />
|-<br />
| ? || LightStruk || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10071 Announcement]<br />
|-<br />
| [http://zelex.net/nezulator Nezulator] || Zelex || JavaScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=7704 Announcement]<br />
|-<br />
| [http://www.oriku.com/emuya.html EMUya] || Zelex || Ouya || [http://forums.nesdev.org/viewtopic.php?f=3&t=10002 Announcement]<br />
|-<br />
| ? || dreampeppers99 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10130 Announcement]<br />
|-<br />
| ? || Skypher || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10193 Announcement]<br />
<!--<br />
|-<br />
| ? || Dartht33bagger || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10266 Announcement]<br />
--><br />
|-<br />
| ? || ArsonIzer || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=10297 Announcement]<br />
|-<br />
| ? || SuperFXMaster || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=10&t=10308 Announcement]<br />
|-<br />
| ? || Choz || Win32 w/ SDL || [http://forums.nesdev.org/viewtopic.php?f=3&t=10333 Announcement]<br />
|-<br />
| ? || sronsse || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10348 Announcement]<br />
|-<br />
| ? || Emu6502Writer || ? || [http://forums.nesdev.org/viewtopic.php?p=116397#p116397 Announcement]<br />
|-<br />
| ? || fred || ? || [http://forums.nesdev.org/viewtopic.php?p=117245#p117245 Announcement]<br />
|-<br />
| ? || janzdott || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10558 Announcement]<br />
|-<br />
| ? || d15ea5e || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10569 Announcement]<br />
|-<br />
| ? || mrhyde || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10751 Announcement]<br />
|-<br />
| ? || codeblox || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10781 Announcement]<br />
|-<br />
| [http://return-1.com/FC87/FC87.html FC87] || Boolean || SDL (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=10839 Announcement]<br />
|-<br />
| phibiaNES || nIghtorius || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11201 Announcement]<br />
|-<br />
| ? || Choz || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=11639 Announcement]<br />
|-<br />
| [https://github.com/nwidger/nintengo nintengo] || nwidger || Go w/ libSDL || <br />
|-<br />
| [https://github.com/rockcarry/ffnes ffnes] || rockcarry || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11948 Announcement]<br />
|-<br />
| [https://github.com/peteward44/WebNES WebNES] || peteward44 || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12006 Announcement] / [http://peteward44.github.io/WebNES Live demo]<br />
|-<br />
| O-Nes-Sama || Fumarumota, aLaix || SDL2 (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=11287 Announcement]<br />
|-<br />
| [http://nintaco.com Nintaco] || zeroone || Java (Windows, GNU/Linux, macOS) || [http://forums.nesdev.org/viewtopic.php?f=3&t=12185 Announcement]<br />
|-<br />
| ? || austere || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12222 Announcement]<br />
|-<br />
| [https://github.com/jpikl/cfxnes cfxnes] || jonyzz || Javascript/CoffeeScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12315 Announcement] / [http://cfxnes.herokuapp.com/ Live demo]<br />
|-<br />
| ? || mreiland || ? || [http://forums.nesdev.org/viewtopic.php?p=143522#p143522 Announcement]<br />
|-<br />
| [https://github.com/amaiorano/nes-emu ?] || daroou || Win32 || [http://forums.nesdev.org/viewtopic.php?p=143752#p143752 Announcement]<br />
|-<br />
| [https://github.com/fogleman/nes fogleman/nes] || Michael Fogleman || Go with Go/GL and PortAudio || [https://medium.com/@fogleman/i-made-an-nes-emulator-here-s-what-i-learned-about-the-original-nintendo-2e078c9b28fe Medium article]<br />
|-<br />
| ? || RobertLoggia || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12605 Announcement]<br />
|-<br />
| [https://github.com/ulfalizer/nesalizer nesalizer] || Ulfalizer || libSDL (portable), tested on Linux ||<br />
|-<br />
| ? || NewDietCoke248903 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12725 Announcement]<br />
|-<br />
| [https://github.com/dgrigoriou1/NES-Emu NES-Emu] || imid || C#/.NET || [http://forums.nesdev.org/viewtopic.php?p=222378#p222378 Announcement]<br />
|-<br />
| ? || mreiland || Linux (?) || [http://forums.nesdev.org/viewtopic.php?p=146814#p146814 Announcement]<br />
|-<br />
| nSide || hex_usr || ? || Fork of byuu's higan-nes. [http://forums.nesdev.org/viewtopic.php?f=3&t=12792 Announcement]<br />
|-<br />
| ? || DarylTechNES || ? || [http://forums.nesdev.org/viewtopic.php?p=147242#p147242 Announcement]<br />
|-<br />
| [https://github.com/andrew-hoffman/halfnes HalfNES] || Grapeshot || Java || [https://github.com/andrew-hoffman/halfnes/tree/master/src Github source]<br />
|-<br />
| [https://github.com/ThomsonKernel/EduNes EduNes] || thomson || SDL2 || [http://forums.nesdev.org/viewtopic.php?p=167743#p167743 Announcement]<br />
|-<br />
| ? || Feuerwerk42 || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=3&t=13966&p=166338 Announcement]<br />
|-<br />
| ? || fspinolo || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14231 Announcement]<br />
|-<br />
| ? || DaNES || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=14232 Announcement]<br />
|-<br />
| ? || charrli || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14287 Announcement]<br />
|-<br />
| ? || amhndu || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14359 Announcement]<br />
|-<br />
| SharpNES || colinvella || Win32/.NET || [http://forums.nesdev.org/viewtopic.php?f=3&t=11353&p=172798#p172798 Announcement]<br />
|-<br />
| ? || Alyosha_TAS || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=14411 Announcement]<br />
|-<br />
| NESfusto || DarkMoe || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14705 Announcement]<br />
|-<br />
| ? || Bowie90333212391 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=13143 Announcement]<br />
|-<br />
| ? || RomarioSilva || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=15104 Announcement]<br />
|-<br />
| ? || JSBryan || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15113 Announcement]<br />
|-<br />
| ? || Sarospa || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15138 Announcement]<br />
|-<br />
| ? || Totolasticot42 || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=15268 Announcement]<br />
|-<br />
| ? || been_jamin || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15411 Announcement]<br />
|-<br />
| ? || wbrian || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15537 Announcement]<br />
|-<br />
| ? || lord_Chile || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=17087 Announcement]<br />
|-<br />
| Nintendoish || drewying || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=17103 Announcement] / [https://github.com/drewying/Nintendoish Source]<br />
|-<br />
| ? || tdondich || JavaScript (Vue.js) || [http://forums.nesdev.org/viewtopic.php?f=3&t=17179 Announcement] / [https://github.com/tdondich/vue-2a03-emu Source]<br />
|-<br />
| ? || ace314159 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17267 Announcement]<br />
|-<br />
| ? || iOSBrett || Swift || [http://forums.nesdev.org/viewtopic.php?f=3&t=17272 Announcement]<br />
|-<br />
| ? || relaxok || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17407 Announcement]<br />
|-<br />
| ? || jamieyello || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17415 Announcement]<br />
|-<br />
| ? || JonteP || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17663 Announcement]<br />
|-<br />
| ? || zzzz898 || ? || [http://forums.nesdev.org/viewtopic.php?p=223812#p223812 Announcement]<br />
|-<br />
| ? || ap9 || ? || [http://forums.nesdev.org/viewtopic.php?f=6&t=115&p=198800#p198800 Announcement]<br />
|-<br />
| ? || zeno84 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17699 Announcement]<br />
|-<br />
| ? || HastatusXXI || ? || [http://forums.nesdev.org/viewtopic.php?p=224241#p224241 Announcement]<br />
|-<br />
| ? || andsve || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17748 Announcement]<br />
|-<br />
| ? || stickzman || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17750 Announcement]<br />
|-<br />
| ? || babai || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=16293 Announcement]<br />
|-<br />
| ? || arcnor || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=17895 Announcement]<br />
|-<br />
| ? || cbalen || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18014 Announcement]<br />
|-<br />
| ? || psychopathetica || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18134 Announcement]<br />
|-<br />
| ? || Myself086 || SNES || [http://forums.nesdev.org/viewtopic.php?f=12&t=18021 Announcement]<br />
|-<br />
| ? || nflga || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18505 Announcement]<br />
|-<br />
| ? || rodri042 || ? || [http://forums.nesdev.org/viewtopic.php?p=235687#p235687 Announcement]<br />
|-<br />
| ? || twicetimes || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18583 Announcement]<br />
|-<br />
| ? || dawid9554 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18613 Announcement]<br />
|-<br />
| [https://github.com/kgabis/agnes agnes] || kgabis || C with libSDL examples || [http://forums.nesdev.org/viewtopic.php?f=3&t=18624 Announcement]<br />
|-<br />
| ? || LukasP || ? || [http://forums.nesdev.org/viewtopic.php?p=236630#p236630 Announcement]<br />
|-<br />
| [https://github.com/JorenJoestar/HydraNes HydraNES] || BadFoolPrototype || Win32 (Glew/OpenGL) || [http://forums.nesdev.org/viewtopic.php?f=3&t=18811 Announcement] / [http://forums.nesdev.org/viewtopic.php?f=10&t=3829 First mention]<br />
|-<br />
| ? || mferrantini || JavaScript || [http://forums.nesdev.org/viewtopic.php?f=10&t=18785 Announcement]<br />
|-<br />
| ? || gobblebit || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18939 Announcement]<br />
|-<br />
| ? || AshleyJamesy || Android || First mention on Discord #programming channel<br />
|-<br />
| [https://github.com/lukexor/rustynes RustyNES] || lukexor || Rust/SDL 2 || [http://forums.nesdev.org/viewtopic.php?f=3&t=18972 Announcement]<br />
|-<br />
| ? || radis || ? || First mention on Discord #emulator-development channel<br />
|-<br />
| ? || timl132 || ? || [http://forums.nesdev.org/viewtopic.php?p=241082#p241082 Announcement]<br />
|-<br />
| ? || thejunkjon || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19142 Announcement]<br />
|-<br />
| ? || olivecc || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19191 Announcement]<br />
|-<br />
| [https://github.com/Nax/nin nin] || Nax || C++/Qt/OpenAL/OpenGL || [http://forums.nesdev.org/viewtopic.php?f=3&t=19316 Announcement]<br />
|-<br />
| ? || Seksys || ? || [http://forums.nesdev.org/viewtopic.php?p=242587#p242587 Announcement]<br />
|-<br />
| q00.nes || LilaQ || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19259 Announcement]<br />
|}<br />
<br />
== Discontinued ==<br />
<br />
These are emulators which are known to be officially discontinued, i.e. abandoned or are no longer in development.<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Other details<br />
|-<br />
| [http://fms.komkon.org/iNES/ iNES] || Marat Fayzullin || MS-DOS || Version discontinued; Win32 and Linux still active<br />
|-<br />
| [http://www.kryptonware.com/ Kryptonware] || rubenhbaca || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=9395 Initial development announcement]. Website has reported "under maintenance" for a very long time<br />
|-<br />
| [https://github.com/Alegend45/MSE MSE] || Alegend45 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=8853 Initial development announcement]. GitHub account has been deleted<br />
|-<br />
| [http://eigenbloom.com/projects/nes/nestest.php?version=1 ?] || graham || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=10243 Initial development announcement]. Website returns internal server error<br />
|-<br />
| [https://github.com/jonathandasilvasantos/2014-alphanes-nintendo-emulator Alphanes] || zerojnt || Go || [https://forums.nesdev.org/viewtopic.php?f=3&t=14830 Initial development announcement]<br />
|-<br />
|}</div>Zepperhttps://www.nesdev.org/w/index.php?title=Emulators&diff=2360Emulators2019-10-08T03:07:00Z<p>Zepper: /* Popular */</p>
<hr />
<div>This is a '''list of NES emulators'''.<br />
<br />
__TOC__<br />
<br />
== Commercial ==<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| acNES<br />
| Nintendo<br />
| GameCube, Game Boy Advance<br />
| Used for Animal Crossing, e-Reader, and Classic NES Series. The name "acNES" is unofficial, as Nintendo has not released this emulator as a distinct product. Information from TCRF indicates that it may be called "QFC".<br />
|-<br />
| Virtual Console<br />
| Nintendo<br />
| Wii/Wii U/3DS<br />
| Most games cost 500 Nintendo Points in Wii Shop Channel<br />
|-<br />
| [http://www.dwedit.org/gba/pocketnes.php PocketNES]<br />
| loopy, FluBBa, and Dwedit<br />
| Game Boy Advance, Nintendo DS<br />
| Used commercially for some emulated re-releases by Atlus, Jaleco, Konami<br />
|}<br />
<br />
== Popular ==<br />
These are commonly used or well-established.<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [https://github.com/TASVideos/BizHawk BizHawk] || Multiple authors || Win32, macOS<br />
|-<br />
| [http://wiibrew.org/wiki/FCE_Ultra_GX FCE Ultra GX] || Tantric || Wii, GameCube<br />
|-<br />
| [http://fceux.com/web/home.html FCEUX] || Anthony Giorgio / Mark Doliner || Win32, Linux<br />
|-<br />
| [http://www.the-interweb.com/serendipity/index.php?/categories/9-FCEUXD-SP FCEUXD SP] || sp || Win32<br />
|-<br />
| [https://byuu.org/emulation/higan/ higan] || byuu || Win32, FreeBSD, Linux, macOS || Multi-platform<br />
|-<br />
| [http://fms.komkon.org/iNES/ iNES] || Marat Fayzullin || Win32 and Linux<br />
|-<br />
| [http://jabosoft.com/?categoryid=1 Jnes] || Jabosoft || Win32<br />
|-<br />
| [http://www.mesen.ca/ Mesen] || Sour || Win32/.NET || [http://forums.nesdev.org/viewtopic.php?p=164372#p164372 Announcement] / [https://github.com/SourMesen/Mesen Source], excellent debugger<br />
|-<br />
| [http://www.nemulator.com nemulator] || James Slepicka || Win32 (Vista/7)<br />
|-<br />
| [http://www.nesemu2.com/ nesemu2] || holodnak || Win32, OS X, Linux || [https://github.com/holodnak/nesemu2 github source]<br />
|-<br />
| [http://tnse.zophar.net/NESten.htm NESten] || TNSe || Win32<br />
|-<br />
| [http://nestopia.sourceforge.net/ NEStopia] || Martin Freij || Win32 || [http://rbelmont.mameworld.info/?page_id=200 Linux], [http://www.bannister.org/software/nestopia.htm MacOS]<br />
|-<br />
| [http://0ldsk00l.ca/nestopia/ Nestopia UE] || rdanbrook || Linux, BSD, Win7+ || a.k.a. Nestopia Undead Edition. Contains bugfixes/etc.<br />Windows binaries are available [http://sourceforge.net/projects/nestopiaue/ at Sourceforge] or [http://www.emucr.com/search/label/Nestopia at EmuCR]<br />
|-<br />
| [http://www.qmtpro.com/~nes/nintendulator/ Nintendulator] || Quietust || Win32 || [http://kkfos.aspekt.fi/projects/nes/tools/nintendulatordx/ Nintendulator DX] (by [[User:Thefox|thefox]]) for an even more-improved debugger<br />
|-<br />
| [http://problemkaputt.de/nes.htm NO$NES] || Martin Korth || Win32<br />
|-<br />
| [http://www.dwedit.org/gba/pocketnes.php PocketNES] || loopy, FluBBa, and Dwedit || Game Boy Advance || Updates on [http://www.dwedit.org/dwedit_board/viewtopic.php?id=409 Dwedit's board]<br />
|-<br />
| [http://rocknes.web.fc2.com RockNES] || Zepper (formerly Fx3) || Win32 || Status: on hold.<br />
|-<br />
| [http://www.ubernes.com/ UberNES] || M \ K Productions || Win32<br />
|-<br />
| [http://virtuanes.s1.xrea.com/ VirtuaNES] || Norix || Win32 || Has a real-time memory hex-editor<br />
|}<br />
<br />
== Under development ==<br />
<br />
The following is a list of NES emulators that are supposedly under development, who their authors are, relevant home pages/sites, and the source of the announcement (direct or indirect).<br />
<br />
{{mbox<br />
| type = warning<br />
| text = '''Before considering developing your own NES emulator, ask yourself if your efforts may be better spent helping out those who already have emulators in development!'''<br />
}}<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [http://www.nesicide.com/ NESICIDE] || cpow || Win32/64, Linux32/64, macOS ||<br />
|-<br />
| [http://fpganes.blogspot.se/ FPGA NES] || Ludde || FPGA (hardware) ||<br />
|-<br />
| [https://rm-rfroot.net/nes_fpga/ VeriNES] || jwdonal || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=6157 Announcement]<br />
|-<br />
| [http://kevtris.org/Projects/console/sections/index.html FPGA NES] || kevtris || FPGA (hardware) ||<br />
|-<br />
| [http://danstrother.com/fpga-nes/ FPGA NES] || Dan Strother || FPGA (hardware) ||<br />
|-<br />
| [http://code.google.com/p/nesface/ NESFaCE] || 6T4 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7499 Announcement]<br />
|-<br />
| [http://www.crazysmart.net.au/kindred kindred] || Overload || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10429 Announcement]<br />
|-<br />
| ? || allthatremains || Win32 || [http://forums.nesdev.org/viewtopic.php?t=5108 Announcement]<br />
|-<br />
| [http://www.aminlab.cn/app/nes/ ?] || amin2312 || Flash || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ModNES || Petruza || Portable, mainly MacOS & Win32 || [http://forums.nesdev.org/viewtopic.php?t=6159 Announcement]<br />
|-<br />
| [http://www.anes.se/ A/NES] || Morgan Johansson || AmigaOS || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?f=3&t=6928 puNES] || FHorse || Linux32/64, Win32/64 || [http://forums.nesdev.org/viewtopic.php?t=6928 Announcement] / [https://github.com/punesemu/puNES Source]<br />
|-<br />
| [https://github.com/rohtang/famique famique] || sahib || Mac OS X, Win32, Linux || [http://forums.nesdev.org/viewtopic.php?t=5922 Announcement]<br />
|-<br />
| FooNES || aphex || Win32 || [http://forums.nesdev.org/viewtopic.php?p=75152#p75152 Announcement]<br />
|-<br />
| nesemu1 || Bisqwit || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?t=8385 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?t=8400 MoarNES] || miker00lz || Win32 || [http://forums.nesdev.org/viewtopic.php?t=6972 Announcement]<br />
|-<br />
| jaNES || crudelios || Win32 || [http://forums.nesdev.org/viewtopic.php?p=89751 Announcement]<br />
|-<br />
| ? || neet || ? || [http://forums.nesdev.org/viewtopic.php?p=89437#p89437 Announcement]<br />
|-<br />
| ? || foobaz || Java || [http://forums.nesdev.org/viewtopic.php?t=8559 Announcement]<br />
|-<br />
| ? || MottZilla || ? || [http://forums.nesdev.org/viewtopic.php?t=8491 Announcement]<br />
|-<br />
| ? || runaway pancake || ? || [http://forums.nesdev.org/viewtopic.php?p=88478#p88478 Announcement]<br />
|-<br />
| ? || Vegenad || ? || [http://forums.nesdev.org/viewtopic.php?t=3593 Announcement]<br />
|-<br />
| ? || johnathonrh || ? || [http://forums.nesdev.org/viewtopic.php?t=5780 Announcement]<br />
|-<br />
| [http://www.yanese.com/ Yanese] || Anes || Win32 || [http://forums.nesdev.org/viewtopic.php?p=713 Announcement]<br />
|-<br />
| ? || nesemuguy || ? || [http://forums.nesdev.org/viewtopic.php?t=2798 Announcement]<br />
|-<br />
| ? || Coldberg || ? || [http://forums.nesdev.org/viewtopic.php?t=4231 Announcement]<br />
|-<br />
| ? || pops || ? || [http://forums.nesdev.org/viewtopic.php?t=6260 Announcement]<br />
|-<br />
| ? || beannaich || ? || [http://forums.nesdev.org/viewtopic.php?t=6240 Announcement]<br />
|-<br />
| ? || windwakr || ? || [http://forums.nesdev.org/viewtopic.php?t=6294 Announcement]<br />
|-<br />
| ? || JuniorZ || ? || [http://forums.nesdev.org/viewtopic.php?t=896 Announcement]<br />
|-<br />
| ? || NesHackR || ? || [http://forums.nesdev.org/viewtopic.php?t=6102 Announcement]<br />
|-<br />
| AwesomeNES || Snaer || libSDL (portable) || [http://forums.nesdev.org/viewtopic.php?t=6064 Announcement]<br />
|-<br />
| ? || BeTheDuck || ? || [http://forums.nesdev.org/viewtopic.php?t=5869 Announcement]<br />
|-<br />
| ? || Luke || ? || [http://forums.nesdev.org/viewtopic.php?t=5821 Announcement]<br />
|-<br />
| ? || The Lord || ? || [http://forums.nesdev.org/viewtopic.php?t=5795 Announcement]<br />
|-<br />
| ? || essial || ? || [http://forums.nesdev.org/viewtopic.php?t=5791 Announcement]<br />
|-<br />
| ? || JamesK89 || ? || [http://forums.nesdev.org/viewtopic.php?t=5787 Announcement]<br />
|-<br />
| ? || yaazz || OS X || [http://forums.nesdev.org/viewtopic.php?t=5723 Announcement]<br />
|-<br />
| ? || blanham || OS X || [http://forums.nesdev.org/viewtopic.php?t=5312 Announcement]<br />
|-<br />
| ? || magicphenix || ? || [http://forums.nesdev.org/viewtopic.php?t=5703 Announcement]<br />
|-<br />
| ? || happymaomao || ? || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ? || someone_somewhere || ? || [http://forums.nesdev.org/viewtopic.php?t=5638 Announcement]<br />
|-<br />
| ? || Undubbed || ? || [http://forums.nesdev.org/viewtopic.php?t=5482 Announcement]<br />
|-<br />
| ? || Muchaserres || ? || [http://forums.nesdev.org/viewtopic.php?t=3665 Announcement]<br />
|-<br />
| ? || takeda || ? || [http://forums.nesdev.org/viewtopic.php?t=5530 Announcement]<br />
|-<br />
| ? || albailey || ? || [http://forums.nesdev.org/viewtopic.php?t=5512 Announcement]<br />
|-<br />
| ? || CaptainMuscles || ? || [http://forums.nesdev.org/viewtopic.php?t=5419 Announcement]<br />
|-<br />
| ? || hatorijr || ? || [http://forums.nesdev.org/viewtopic.php?t=5408 Announcement]<br />
|-<br />
| ? || tanoatnd || ? || [http://forums.nesdev.org/viewtopic.php?t=5189 Announcement]<br />
|-<br />
| ? || max_sweat || ? || [http://forums.nesdev.org/viewtopic.php?t=5388 Announcement]<br />
|-<br />
| ? || jjpeerless || ? || [http://forums.nesdev.org/viewtopic.php?t=5281 Announcement]<br />
|-<br />
| ? || Cloudy || ? || [http://forums.nesdev.org/viewtopic.php?t=5109 Announcement]<br />
|-<br />
| ? || meatloaf69 || ? || [http://forums.nesdev.org/viewtopic.php?p=62817#p62817 Announcement]<br />
|-<br />
| ? || parth || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=4502 Announcement]<br />
|-<br />
| ? || oRBIT2002 || ? || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| ? || Elessar || ? || [http://forums.nesdev.org/viewtopic.php?t=7862 Announcement]<br />
|-<br />
| ? || cmoh89 || ? || [http://forums.nesdev.org/viewtopic.php?t=7521 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?f=3&t=9935 HDNes] || mkwong98 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7848 Announcement]<br />
|-<br />
| ? || ehguacho || ? || [http://forums.nesdev.org/viewtopic.php?t=7936 Announcement]<br />
|-<br />
| ? || nop || Java || [http://forums.nesdev.org/viewtopic.php?t=8876 Announcement]<br />
|-<br />
| ? || emu_enthusiast || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=5826 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?p=140741#p140741 MahNES] || HLorenzi || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9054 Announcement]<br />
|-<br />
| ? || haydenmuhl || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9101 Announcement]<br />
|-<br />
| ? || urbanspr1nter || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9227 Announcement]<br />
|-<br />
| Fergulator || fergus_maximus || Mac OS X or X Windows || [http://forums.nesdev.org/viewtopic.php?f=3&t=9292 Announcement]<br />
|-<br />
| ? || ermular || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9353 Announcement]<br />
|-<br />
| ? || alexwy || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9608 Announcement]<br />
|-<br />
| ? || caiiio || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9625 Announcement]<br />
|-<br />
| ? || miguelsfp || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9726 Announcement]<br />
|-<br />
| ? || ember || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=3&t=9653 Announcement]<br />
|-<br />
| ? || ninjis || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9829 Announcement]<br />
|-<br />
| [http://www.geocities.jp/submarine600/html/p8/nesemu.html ?] || submarine600 || PC-8801 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9921 Announcement]<br />
|-<br />
| [http://alike.se/yane/ Yane] || roku6185 || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?f=3&t=9969 Announcement]<br />
|-<br />
| [http://vpnes.googlecode.com/ VPNES] || x0000 || Win32 w/ SDL || <br />
|-<br />
| [https://github.com/macifom/macifom macifom] || Auston Stewart || OS X, iOS || [http://forums.nesdev.org/viewtopic.php?f=3&t=9989 Announcement]<br />
|-<br />
| [https://github.com/macifom/macifomlite macifomlite] || Auston Stewart || iOS || <br />
|-<br />
| [https://github.com/eteran/pretendo Pretendo] || proxy || Linux/BeOS/Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10045 Announcement]<br />
|-<br />
| ? || samfoo || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10070 Announcement]<br />
|-<br />
| ? || LightStruk || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10071 Announcement]<br />
|-<br />
| [http://zelex.net/nezulator Nezulator] || Zelex || JavaScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=7704 Announcement]<br />
|-<br />
| [http://www.oriku.com/emuya.html EMUya] || Zelex || Ouya || [http://forums.nesdev.org/viewtopic.php?f=3&t=10002 Announcement]<br />
|-<br />
| ? || dreampeppers99 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10130 Announcement]<br />
|-<br />
| ? || Skypher || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10193 Announcement]<br />
<!--<br />
|-<br />
| ? || Dartht33bagger || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10266 Announcement]<br />
--><br />
|-<br />
| ? || ArsonIzer || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=10297 Announcement]<br />
|-<br />
| ? || SuperFXMaster || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=10&t=10308 Announcement]<br />
|-<br />
| ? || Choz || Win32 w/ SDL || [http://forums.nesdev.org/viewtopic.php?f=3&t=10333 Announcement]<br />
|-<br />
| ? || sronsse || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10348 Announcement]<br />
|-<br />
| ? || Emu6502Writer || ? || [http://forums.nesdev.org/viewtopic.php?p=116397#p116397 Announcement]<br />
|-<br />
| ? || fred || ? || [http://forums.nesdev.org/viewtopic.php?p=117245#p117245 Announcement]<br />
|-<br />
| ? || janzdott || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10558 Announcement]<br />
|-<br />
| ? || d15ea5e || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10569 Announcement]<br />
|-<br />
| ? || mrhyde || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10751 Announcement]<br />
|-<br />
| ? || codeblox || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10781 Announcement]<br />
|-<br />
| [http://return-1.com/FC87/FC87.html FC87] || Boolean || SDL (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=10839 Announcement]<br />
|-<br />
| phibiaNES || nIghtorius || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11201 Announcement]<br />
|-<br />
| ? || Choz || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=11639 Announcement]<br />
|-<br />
| [https://github.com/nwidger/nintengo nintengo] || nwidger || Go w/ libSDL || <br />
|-<br />
| [https://github.com/rockcarry/ffnes ffnes] || rockcarry || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11948 Announcement]<br />
|-<br />
| [https://github.com/peteward44/WebNES WebNES] || peteward44 || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12006 Announcement] / [http://peteward44.github.io/WebNES Live demo]<br />
|-<br />
| O-Nes-Sama || Fumarumota, aLaix || SDL2 (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=11287 Announcement]<br />
|-<br />
| [http://nintaco.com Nintaco] || zeroone || Java (Windows, GNU/Linux, macOS) || [http://forums.nesdev.org/viewtopic.php?f=3&t=12185 Announcement]<br />
|-<br />
| ? || austere || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12222 Announcement]<br />
|-<br />
| [https://github.com/jpikl/cfxnes cfxnes] || jonyzz || Javascript/CoffeeScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12315 Announcement] / [http://cfxnes.herokuapp.com/ Live demo]<br />
|-<br />
| ? || mreiland || ? || [http://forums.nesdev.org/viewtopic.php?p=143522#p143522 Announcement]<br />
|-<br />
| [https://github.com/amaiorano/nes-emu ?] || daroou || Win32 || [http://forums.nesdev.org/viewtopic.php?p=143752#p143752 Announcement]<br />
|-<br />
| [https://github.com/fogleman/nes fogleman/nes] || Michael Fogleman || Go with Go/GL and PortAudio || [https://medium.com/@fogleman/i-made-an-nes-emulator-here-s-what-i-learned-about-the-original-nintendo-2e078c9b28fe Medium article]<br />
|-<br />
| ? || RobertLoggia || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12605 Announcement]<br />
|-<br />
| [https://github.com/ulfalizer/nesalizer nesalizer] || Ulfalizer || libSDL (portable), tested on Linux ||<br />
|-<br />
| ? || NewDietCoke248903 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12725 Announcement]<br />
|-<br />
| [https://github.com/dgrigoriou1/NES-Emu NES-Emu] || imid || C#/.NET || [http://forums.nesdev.org/viewtopic.php?p=222378#p222378 Announcement]<br />
|-<br />
| ? || mreiland || Linux (?) || [http://forums.nesdev.org/viewtopic.php?p=146814#p146814 Announcement]<br />
|-<br />
| nSide || hex_usr || ? || Fork of byuu's higan-nes. [http://forums.nesdev.org/viewtopic.php?f=3&t=12792 Announcement]<br />
|-<br />
| ? || DarylTechNES || ? || [http://forums.nesdev.org/viewtopic.php?p=147242#p147242 Announcement]<br />
|-<br />
| [https://github.com/andrew-hoffman/halfnes HalfNES] || Grapeshot || Java || [https://github.com/andrew-hoffman/halfnes/tree/master/src Github source]<br />
|-<br />
| [https://github.com/ThomsonKernel/EduNes EduNes] || thomson || SDL2 || [http://forums.nesdev.org/viewtopic.php?p=167743#p167743 Announcement]<br />
|-<br />
| ? || Feuerwerk42 || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=3&t=13966&p=166338 Announcement]<br />
|-<br />
| ? || fspinolo || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14231 Announcement]<br />
|-<br />
| ? || DaNES || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=14232 Announcement]<br />
|-<br />
| ? || charrli || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14287 Announcement]<br />
|-<br />
| ? || amhndu || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14359 Announcement]<br />
|-<br />
| SharpNES || colinvella || Win32/.NET || [http://forums.nesdev.org/viewtopic.php?f=3&t=11353&p=172798#p172798 Announcement]<br />
|-<br />
| ? || Alyosha_TAS || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=14411 Announcement]<br />
|-<br />
| NESfusto || DarkMoe || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=14705 Announcement]<br />
|-<br />
| ? || Bowie90333212391 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=13143 Announcement]<br />
|-<br />
| ? || RomarioSilva || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=15104 Announcement]<br />
|-<br />
| ? || JSBryan || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15113 Announcement]<br />
|-<br />
| ? || Sarospa || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15138 Announcement]<br />
|-<br />
| ? || Totolasticot42 || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=15268 Announcement]<br />
|-<br />
| ? || been_jamin || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15411 Announcement]<br />
|-<br />
| ? || wbrian || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=15537 Announcement]<br />
|-<br />
| ? || lord_Chile || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=17087 Announcement]<br />
|-<br />
| Nintendoish || drewying || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=17103 Announcement] / [https://github.com/drewying/Nintendoish Source]<br />
|-<br />
| ? || tdondich || JavaScript (Vue.js) || [http://forums.nesdev.org/viewtopic.php?f=3&t=17179 Announcement] / [https://github.com/tdondich/vue-2a03-emu Source]<br />
|-<br />
| ? || ace314159 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17267 Announcement]<br />
|-<br />
| ? || iOSBrett || Swift || [http://forums.nesdev.org/viewtopic.php?f=3&t=17272 Announcement]<br />
|-<br />
| ? || relaxok || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17407 Announcement]<br />
|-<br />
| ? || jamieyello || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17415 Announcement]<br />
|-<br />
| ? || JonteP || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17663 Announcement]<br />
|-<br />
| ? || zzzz898 || ? || [http://forums.nesdev.org/viewtopic.php?p=223812#p223812 Announcement]<br />
|-<br />
| ? || ap9 || ? || [http://forums.nesdev.org/viewtopic.php?f=6&t=115&p=198800#p198800 Announcement]<br />
|-<br />
| ? || zeno84 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17699 Announcement]<br />
|-<br />
| ? || HastatusXXI || ? || [http://forums.nesdev.org/viewtopic.php?p=224241#p224241 Announcement]<br />
|-<br />
| ? || andsve || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17748 Announcement]<br />
|-<br />
| ? || stickzman || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=17750 Announcement]<br />
|-<br />
| ? || babai || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=16293 Announcement]<br />
|-<br />
| ? || arcnor || ? || [http://forums.nesdev.org/viewtopic.php?f=10&t=17895 Announcement]<br />
|-<br />
| ? || cbalen || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18014 Announcement]<br />
|-<br />
| ? || psychopathetica || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18134 Announcement]<br />
|-<br />
| ? || Myself086 || SNES || [http://forums.nesdev.org/viewtopic.php?f=12&t=18021 Announcement]<br />
|-<br />
| ? || nflga || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18505 Announcement]<br />
|-<br />
| ? || rodri042 || ? || [http://forums.nesdev.org/viewtopic.php?p=235687#p235687 Announcement]<br />
|-<br />
| ? || twicetimes || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18583 Announcement]<br />
|-<br />
| ? || dawid9554 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18613 Announcement]<br />
|-<br />
| [https://github.com/kgabis/agnes agnes] || kgabis || C with libSDL examples || [http://forums.nesdev.org/viewtopic.php?f=3&t=18624 Announcement]<br />
|-<br />
| ? || LukasP || ? || [http://forums.nesdev.org/viewtopic.php?p=236630#p236630 Announcement]<br />
|-<br />
| [https://github.com/JorenJoestar/HydraNes HydraNES] || BadFoolPrototype || Win32 (Glew/OpenGL) || [http://forums.nesdev.org/viewtopic.php?f=3&t=18811 Announcement] / [http://forums.nesdev.org/viewtopic.php?f=10&t=3829 First mention]<br />
|-<br />
| ? || mferrantini || JavaScript || [http://forums.nesdev.org/viewtopic.php?f=10&t=18785 Announcement]<br />
|-<br />
| ? || gobblebit || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=18939 Announcement]<br />
|-<br />
| ? || AshleyJamesy || Android || First mention on Discord #programming channel<br />
|-<br />
| [https://github.com/lukexor/rustynes RustyNES] || lukexor || Rust/SDL 2 || [http://forums.nesdev.org/viewtopic.php?f=3&t=18972 Announcement]<br />
|-<br />
| ? || radis || ? || First mention on Discord #emulator-development channel<br />
|-<br />
| ? || timl132 || ? || [http://forums.nesdev.org/viewtopic.php?p=241082#p241082 Announcement]<br />
|-<br />
| ? || thejunkjon || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19142 Announcement]<br />
|-<br />
| ? || olivecc || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19191 Announcement]<br />
|-<br />
| [https://github.com/Nax/nin nin] || Nax || C++/Qt/OpenAL/OpenGL || [http://forums.nesdev.org/viewtopic.php?f=3&t=19316 Announcement]<br />
|-<br />
| ? || Seksys || ? || [http://forums.nesdev.org/viewtopic.php?p=242587#p242587 Announcement]<br />
|-<br />
| q00.nes || LilaQ || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=19259 Announcement]<br />
|}<br />
<br />
== Discontinued ==<br />
<br />
These are emulators which are known to be officially discontinued, i.e. abandoned or are no longer in development.<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Other details<br />
|-<br />
| [http://fms.komkon.org/iNES/ iNES] || Marat Fayzullin || MS-DOS || Version discontinued; Win32 and Linux still active<br />
|-<br />
| [http://www.kryptonware.com/ Kryptonware] || rubenhbaca || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=9395 Initial development announcement]. Website has reported "under maintenance" for a very long time<br />
|-<br />
| [https://github.com/Alegend45/MSE MSE] || Alegend45 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=8853 Initial development announcement]. GitHub account has been deleted<br />
|-<br />
| [http://eigenbloom.com/projects/nes/nestest.php?version=1 ?] || graham || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=10243 Initial development announcement]. Website returns internal server error<br />
|-<br />
| [https://github.com/jonathandasilvasantos/2014-alphanes-nintendo-emulator Alphanes] || zerojnt || Go || [https://forums.nesdev.org/viewtopic.php?f=3&t=14830 Initial development announcement]<br />
|-<br />
|}</div>Zepperhttps://www.nesdev.org/w/index.php?title=Emulator_tests&diff=2126Emulator tests2019-03-09T03:01:00Z<p>Zepper: small fix</p>
<hr />
<div>There are many ROMs available that test an emulator for [[accuracy|inaccuracies]].<br />
<br />
== Validation ROMs ==<br />
Note: Most of these test roms can also be found at [https://github.com/christopherpow/nes-test-roms https://github.com/christopherpow/nes-test-roms]<br />
<br />
=== CPU Tests ===<br />
<br />
{| class="wikitable sortable"<br />
|-<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [http://www.slack.net/~ant/nes-tests/branch_timing_tests.zip branch_timing_tests] || blargg || These ROMs test timing of the branch instruction, including edge cases || <br />
|-<br />
| [https://github.com/christopherpow/nes-test-roms/raw/master/cpu_dummy_reads/cpu_dummy_reads.nes cpu_dummy_reads] || blargg || Tests the CPU's dummy reads || [https://forums.nesdev.org/viewtopic.php?p=31629 thread]<br />
|- <br />
| [http://bisqwit.iki.fi/src/nes_tests/cpu_dummy_writes.zip cpu_dummy_writes] || bisqwit || Tests the CPU's dummy writes || [https://forums.nesdev.org/viewtopic.php?t=8738 thread]<br />
|- <br />
| [http://bisqwit.iki.fi/src/nes_tests/cpu_exec_space.zip cpu_exec_space] || bisqwit || Verifies that the CPU can execute code from any possible memory location, even if that is mapped as I/O space || [https://forums.nesdev.org/viewtopic.php?t=8755 thread]<br />
|- <br />
| [http://bisqwit.iki.fi/kala/test1.zip cpu_flag_concurrency] || bisqwit || Unsure what results are meant to be, see thread for more info. || [https://forums.nesdev.org/viewtopic.php?f=3&t=8757 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/cpu_interrupts_v2.zip cpu_interrupts_v2] || blargg || Tests the behavior and timing of CPU in the presence of interrupts, both IRQ and NMI; see CPU interrupts. || [https://forums.nesdev.org/viewtopic.php?f=2&t=6510 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/cpu_reset.zip cpu_reset] || blargg || Tests CPU registers just after power and changes during reset, and that RAM isn't changed during reset. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/cpu_timing_test6.zip cpu_timing_test6] || blargg || This program tests instruction timing for all official and unofficial NES 6502 instructions except the 8 branch instructions (Bxx) and the 12 halt instructions (HLT) || [https://forums.nesdev.org/viewtopic.php?f=3&t=3831 thread]<br />
|-<br />
| [//forums.nesdev.org/viewtopic.php?p=157782#p157782 coredump] || jroatch || Coredump tool for displaying contents of RAM || [http://forums.nesdev.org/viewtopic.php?f=22&t=11520 thread]<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/nes_instr_misc.zip instr_misc] || blargg || Tests some miscellaneous aspects of instructions, including behavior when 16-bit address wraps around, and dummy reads. ||<br />
|- <br />
| [http://blargg.8bitalley.com/nes-tests/instr_test-v5.zip instr_test_v5] || blargg || Tests official and unofficial CPU instructions and lists which ones failed. It will work even if emulator has no PPU and only supports NROM, writing a copy of output to $6000 (see readme). This more thoroughly tests instructions, but can't help you figure out what's wrong beyond what instruction(s) are failing, so it's better for testing mature CPU emulators. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/instr_timing.zip instr_timing] || blargg || Tests timing of all instructions, including unofficial ones, page-crossing, etc. ||<br />
|-<br />
| [http://nickmass.com/images/nestest.nes nestest] ([http://www.qmtpro.com/~nes/misc/nestest.txt doc]) || kevtris || fairly thoroughly tests CPU operation. This is the best test to start with when getting a CPU emulator working for the first time. Start execution at $C000 and compare execution with a [http://www.qmtpro.com/~nes/misc/nestest.log log] from [[Nintendulator]], an emulator whose CPU is known to work correctly (apart from some details of the power-up state). ||<br />
|-<br />
| [//forums.nesdev.org/viewtopic.php?t=13334 ram_retain] || rainwarrior || RAM contents test, for displaying contents of RAM at power-on or after reset || [http://forums.nesdev.org/viewtopic.php?t=13334 thread]<br />
|}<br />
<br />
=== PPU Tests ===<br />
<br />
{| class="wikitable sortable"<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [http://forums.nesdev.org/download/file.php?id=4043 color_test] || rainwarrior || Simple display of any chosen color full-screen || [http://forums.nesdev.org/viewtopic.php?p=155593#p155593 thread]<br />
|-<br />
| [http://www.slack.net/~ant/nes-tests/blargg_ppu_tests.zip blargg_ppu_tests_2005.09.15b] || blargg || Miscellaneous PPU tests (palette ram, sprite ram, etc.) || [https://forums.nesdev.org/viewtopic.php?t=567 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-code/full_palette.zip full_palette] || blargg || Displays the full palette with all emphasis states, demonstrates direct PPU color control || [https://forums.nesdev.org/viewtopic.php?p=10658 thread]<br />
|- <br />
| [http://blargg.parodius.com/nes-code/nmi_sync.zip nmi_sync] || blargg || Verifies NMI timing by creating a specific pattern on the screen (NTSC & PAL versions) || [https://forums.nesdev.org/viewtopic.php?t=6589 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=6939 ntsc_torture] || rainwarrior || NTSC Torture Test displays visual patterns to demonstrate NTSC signal artifacts || [http://forums.nesdev.org/viewtopic.php?f=2&t=15080 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/oam_read.zip oam_read] || blargg || Tests OAM reading ($2004), being sure it reads the byte from OAM at the current address in $2003. || [https://forums.nesdev.org/viewtopic.php?t=6424 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/oam_stress.zip oam_stress] || blargg || Thoroughly tests OAM address ($2003) and read/write ($2004) || [https://forums.nesdev.org/viewtopic.php?t=6424 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=1537 oamtest3] || lidnariq || Utility to upload OAM data via $2003/$2004 - can be used to test for the OAMADDR bug behavior || [http://forums.nesdev.org/viewtopic.php?p=128913#p128913 thread 1] [http://forums.nesdev.org/viewtopic.php?p=128842#p128842 thread 2]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?t=13264 palette] || rainwarrior || Palette display requiring only scanline-based palette changes, intended to demonstrate the full palette even on less advanced emulators || [http://forums.nesdev.org/viewtopic.php?t=13264 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/ppu_open_bus.zip ppu_open_bus] || blargg || Tests behavior when reading from open-bus PPU bits/registers ||<br />
|-<br />
| [http://bisqwit.iki.fi/src/nes_tests/ppu_read_buffer.zip ppu_read_buffer] || bisqwit || Mammoth test pack tests many aspects of the NES system, mostly centering around the PPU $2007 read buffer || [https://forums.nesdev.org/viewtopic.php?f=3&t=8847&start=0 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/ppu_sprite_hit.zip ppu_sprite_hit] || blargg || Tests sprite 0 hit behavior and timing || [https://forums.nesdev.org/viewtopic.php?t=626 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/ppu_sprite_overflow.zip ppu_sprite_overflow] || blargg || Tests sprite overflow behavior and timing || [https://forums.nesdev.org/viewtopic.php?t=1308 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/ppu_vbl_nmi.zip ppu_vbl_nmi] || blargg || Tests the behavior and timing of the NTSC PPU's VBL flag, NMI enable, and NMI interrupt. Timing is tested to an accuracy of one PPU clock. || [https://forums.nesdev.org/viewtopic.php?t=730 thread]<br />
|-<br />
| [http://www.qmtpro.com/~nes/demos/scanline.zip scanline] || Quietust || Displays a test screen that will contain glitches if certain portions of the emulation are not perfect. ||<br />
|- <br />
| [http://www.slack.net/~ant/nes-tests/sprite_hit_tests.zip sprite_hit_tests_2005.10.05] || blargg || Generally the same as ppu_sprite_hit (older revision of the tests - ppu_sprite_hit is most likely better) || [https://forums.nesdev.org/viewtopic.php?t=626 thread]<br />
|-<br />
| [http://www.slack.net/~ant/nes-tests/sprite_overflow_tests.zip sprite_overflow_tests] || blargg || Generally the same as ppu_sprite_overflow (older revision of the tests - ppu_sprite_overflow is most likely better) || [https://forums.nesdev.org/viewtopic.php?t=1308 thread]<br />
|-<br />
| [http://blargg.parodius.com/temp/sprdma_and_dmc_dma.zip sprdma_and_dmc_dma] || blargg || Tests the cycle stealing behavior of the DMC DMA while running Sprite DMAs || [https://forums.nesdev.org/viewtopic.php?f=3&t=6100 thread]<br />
|-<br />
| [http://pics.pineight.com/nes/tvpassfail.zip tvpassfail] || tepples || NTSC color and NTSC/PAL pixel aspect ratio test ROM || [https://forums.nesdev.org/viewtopic.php?t=3393 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/ppu_vbl_nmi.zip vbl_nmi_timing] || blargg || Generally the same as ppu_vbl_nmi (older revision of the tests - ppu_vbl_nmi is most likely better) || [https://forums.nesdev.org/viewtopic.php?f=3&t=3953 thread]<br />
|}<br />
<br />
=== APU Tests ===<br />
<br />
{| class="wikitable sortable"<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/apu_mixer.zip apu_mixer] || blargg || Verifies proper operation of the APU's sound channel mixer, including relative volumes of channels and non-linear mixing. recordings when run on NES are available for comparison, though the tests are made so that you don't really need these. || [https://forums.nesdev.org/viewtopic.php?f=3&t=4911 thread]<br />
|- <br />
| [https://forums.nesdev.org/download/file.php?id=7496 apu_phase_reset] || Rahsennor || Tests the correct square channel behavior when writing to $4003/4007 (reset the duty cycle sequencers but not the clock dividers) || [https://forums.nesdev.org/viewtopic.php?f=2&t=15346 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/apu_reset.zip apu_reset] || blargg || Tests initial APU state at power, and the effect of reset. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/apu_test.zip apu_test] || blargg || Tests many aspects of the APU that are visible to the CPU. Really obscure things are not tested here. ||<br />
|- <br />
| [http://www.slack.net/~ant/nes-tests/blargg_apu_2005.07.30.zip blargg_apu_2005.07.30] || blargg || Tests APU length counters, frame counter, IRQ, etc. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/dmc_dma_during_read4.zip dmc_dma_during_read4] || blargg || Tests register read/write behavior while DMA is running ||<br />
|- <br />
| [https://github.com/christopherpow/nes-test-roms/tree/master/dmc_tests dmc_tests] || ? || ? ||<br />
|- <br />
| [http://pics.pineight.com/nes/dpcmletterbox.zip dpcmletterbox] || tepples || Tests accuracy of the DMC channel's IRQ ||<br />
|- <br />
| [http://www.slack.net/~ant/nes-tests/pal_apu_tests.zip pal_apu_tests] || blargg || PAL version of the blargg_apu_2005.07.30 tests ||<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/older/square_timer_div2.zip square_timer_div2] || blargg || Tests the square timer's period ||<br />
|- <br />
| [https://forums.nesdev.org/download/file.php?id=1494 test_apu_2 (1-10)] [https://forums.nesdev.org/download/file.php?id=5699 (11)] || x0000 || 11 tests that verify a number of behaviors with the APU (including the frame counter) || [https://forums.nesdev.org/viewtopic.php?f=3&t=11174 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/older/test_apu_env.zip test_apu_env] || blargg || Tests the APU envelope for correctness. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/older/test_apu_sweep.zip test_apu_sweep] || blargg || Tests the sweep unit's add, subtract, overflow cutoff, and minimum period behaviors. ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/older/test_apu_timers.zip test_apu_timers] || blargg || Tests frequency timer of all 5 channels ||<br />
|- <br />
| [http://blargg.8bitalley.com/parodius/nes-tests/older/test_tri_lin_ctr.zip test_tri_lin_ctr] || blargg || Tests triangle's linear counter and clocking by the frame counter ||<br />
|-<br />
| [http://pics.pineight.com/nes/volume_tests.zip volume_tests] || tepples || Plays tones on all the APU's channels to show their relative volumes at various settings of $4011. Package includes a recording from an NES's audio output for comparison. ||<br />
|}<br />
<br />
=== Mapper-specific Tests ===<br />
<br />
{| class="wikitable sortable"<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=3772 31_test] || rainwarrior || Tests for mapper 31 (see thread for ROMs in various PRG sizes) || [https://forums.nesdev.org/viewtopic.php?f=3&t=13120 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=2253 BNTest] || tepples || Tests how many PRG banks are reachable in BxROM and AxROM. || [https://forums.nesdev.org/viewtopic.php?p=79826#p79826 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=2247 bxrom_512k_test] || rainwarrior || Similar to the BxROM test in BNTest above. || [https://forums.nesdev.org/viewtopic.php?f=3&t=12085 thread]<br />
|-<br />
| [http://forums.nesdev.org/download/file.php?id=10240 FdsIrqTests (v7)] || Sour || Tests various elements of the FDS' IRQ || [http://forums.nesdev.org/viewtopic.php?f=3&t=16507 thread]<br />
|-<br />
| [http://www.qmtpro.com/~nes/demos/mmc5exram.zip exram] || Quietust || MMC5 exram test ||<br />
|-<br />
| [http://rainwarrior.ca/projects/nes/famicom_audio_swap_tests.zip famicom_audio_swap_tests] || rainwarrior || Hotswap tests for Famicom expansion audio (5B, MMC5, VRC6, VRC7, N163, FDS) || [http://forums.nesdev.org/viewtopic.php?t=8639 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=2759 fme7acktest-r1] || tepples || Checks some IRQ acknowledgment behiaviors of Sunsoft FME-7 that emulators were getting wrong in 2015. || [https://forums.nesdev.org/viewtopic.php?f=2&t=12436 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=2800 fme7ramtest-r1] || tepples || Checks how much work ram the Sunsoft FME-7 can access || [https://forums.nesdev.org/viewtopic.php?f=9&t=12467 thread]<br />
|-<br />
| [https://pineight.com/nes/holydiverbatman-bin-0.01.7z Holy Mapperel] || tepples || Detects over a dozen mappers and verifies that all PRG ROM and CHR ROM banks are reachable, that PRG RAM and CHR RAM can be written and read back without error, and that nametable mirroring, IRQ, and WRAM protection work. (Formerly Holy Diver Batman) || [https://forums.nesdev.org/viewtopic.php?f=22&t=10640 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=5166 mmc3bigchrram] || tepples || MMC3 test for large 32kb CHR RAM with NES 2.0 headers || [https://forums.nesdev.org/viewtopic.php?f=3&t=13890 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-tests/mmc3_test_2.zip mmc3_test] || blargg || MMC3 scanline counter and IRQ generation tests. ||<br />
|-<br />
| [http://forums.nesdev.org/download/file.php?id=8609 mmc5test_v2] || AWJ || MMC5 tests || [http://forums.nesdev.org/viewtopic.php?f=2&t=15788 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=3753 serom] || lidnariq || Tests the constraints of SEROM / SHROM / SH1ROM variations of the MMC1 boards. || [https://forums.nesdev.org/viewtopic.php?f=3&t=9350&start=90#p153298 thread]<br />
|-<br />
| rowspan="4" | NES 2.0 Submapper Tests || rainwarrior || [https://forums.nesdev.org/download/file.php?id=4299 2_test] - Mapper 2, Submappers 0, 1 and 2 || [https://forums.nesdev.org/viewtopic.php?f=3&t=9350&start=90#p157804 thread]<br />
|-<br />
| rainwarrior || [https://forums.nesdev.org/download/file.php?id=4302 3_test] - Mapper 3, Submappers 0, 1 and 2 || [https://forums.nesdev.org/viewtopic.php?f=3&t=9350&start=90#p154555 thread]<br />
|-<br />
| rainwarrior || [https://forums.nesdev.org/download/file.php?id=4301 7_test] - Mapper 7, Submappers 0, 1 and 2 || [https://forums.nesdev.org/viewtopic.php?f=3&t=9350&start=90#p157804 thread]<br />
|-<br />
| rainwarrior || [https://forums.nesdev.org/download/file.php?id=3771 34_test] - Mapper 34, Submappers 1 and 2 || [https://forums.nesdev.org/viewtopic.php?f=3&t=9350&start=90#p153334 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=12185 test28] || tepples || Tests for mapper 28 || [https://forums.nesdev.org/viewtopic.php?p=215345#p215345 thread]<br />
|-<br />
| [http://forums.nesdev.org/download/file.php?id=10017 vrc24test] || AWJ || Detects and tests all VRC 2/4 variants || [http://forums.nesdev.org/viewtopic.php?f=3&t=16009 thread]<br />
|-<br />
| [http://www.mediafire.com/download/6hvuj53omv8y3fn/vrc6test.zip vrc6test] || natt || VRC6 mirroring tests || [https://forums.nesdev.org/viewtopic.php?t=11028 thread]<br />
|}<br />
<br />
=== Input Tests ===<br />
{| class="wikitable sortable"<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [https://github.com/pinobatch/allpads-nes/raw/master/allpads.nes allpads] || tepples || Multiple controller test supporting NES controller, Super NES controller, Famicom microphone, Four Score, Zapper, NES Arkanoid controller, and Super NES Mouse || [https://forums.nesdev.org/viewtopic.php?f=2&t=12549 thread] [https://github.com/pinobatch/allpads-nes GitHub]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=5905 dma_sync_test_v2] || Rahsennor || Tests DMC DMA read corruption || [https://forums.nesdev.org/viewtopic.php?f=2&t=14319 thread]<br />
|-<br />
| [https://github.com/christopherpow/nes-test-roms/raw/master/PaddleTest3/PaddleTest.nes PaddleTest3] || 3gengames || Test for the Arkanoid controller || [https://forums.nesdev.org/viewtopic.php?t=7929 thread]<br />
|-<br />
| [http://blargg.8bitalley.com/parodius/nes-code/read_joy3.zip read_joy3] || blargg || Various NES controllers tests, including read corruption due to DMC DMA || [https://forums.nesdev.org/viewtopic.php?f=2&t=4124&start=0 thread]<br />
|-<br />
| [https://github.com/pinobatch/zap-ruder/raw/master/ruder.nes Zap Ruder] || tepples || Test for the Zapper, including dual wield but not the serial Vs. variant || [https://forums.nesdev.org/viewtopic.php?t=8108 thread] [https://github.com/pinobatch/zap-ruder GitHub]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=5356 spadtest-nes] || tepples || Super Nintendo controller test (when connected to a NES) || [https://forums.nesdev.org/viewtopic.php?p=167288 thread]<br />
|-<br />
| [http://pics.pineight.com/nes/vaus-test-0.02.zip vaus_test] || tepples || Another test for the Arkanoid controller || [https://forums.nesdev.org/viewtopic.php?p=120455 thread]<br />
|-<br />
| [https://forums.nesdev.org/viewtopic.php?p=231608#p231608 mset] || rainwarrior || SNES mouse test || [https://forums.nesdev.org/viewtopic.php?p=231608#p231608 thread]<br />
|-<br />
| [https://forums.nesdev.org/viewtopic.php?f=3&t=18314&p=232358#p232358 mict] || rainwarrior || Famicom microphone test || [https://forums.nesdev.org/viewtopic.php?f=3&t=18314 thread]<br />
|}<br />
<br />
=== Misc Tests ===<br />
{| class="wikitable sortable"<br />
! Name<br />
! Author<br />
! Description<br />
! Resources<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=7745 240pee-0.15] || tepples || 240p test suite (an NES version of the [http://junkerhq.net/xrgb/index.php/240p_test_suite 240p test suite] by Artemio Urbina) || [https://forums.nesdev.org/viewtopic.php?t=13394 thread]<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=1415 characterize-vs] || lidnariq || VS System tests || [https://forums.nesdev.org/viewtopic.php?f=3&t=10276&start=15#p127592 thread]<br />
|-<br />
| [http://nesdev.org/NEStress.zip NEStress] || || Old test - some of the tests are supposed to fail on real hardware. ||<br />
|-<br />
| [https://forums.nesdev.org/download/file.php?id=2826 oc-r1a] || tepples || Detects and displays accurate clock rate of the NES || [https://forums.nesdev.org/viewtopic.php?f=22&t=12499 thread]<br />
|-<br />
| [https://github.com/bbbradsmith/nes-audio-tests nes-audio-tests] || rainwarrior || NSF and NES ROM tests for expansion audio sound, NSF behaviour, and other various audio related things. ||<br />
|}<br />
<br />
== Automated testing ==<br />
<br />
It's best if your emulator can automatically run a suite of tests at the press of a button. This allows you to re-run them every time you make a change, without any effort. Automation can be difficult, because the emulator must be able to determine success/failure without your help.<br />
<br />
The first part of automated testing is support for a "movie" or "demo", or a list of what buttons were pressed when.<br />
An emulator makes a movie by recording presses while the user is playing, and then it plays the movie by feeding the recorded presses back through the input system.<br />
This not only helps automated testing but also makes your emulator attractive to [[wikipedia:Speedrun|speedrunners]].<br />
<br />
To create a test case, record a movie of the player activating all tests in a ROM, take a screenshot of each result screen, and log the time and a [[wikipedia:Hash function|hash]] of each screenshot.<br />
The simplest test ROMs won't require any button presses.<br />
ROMs that test more than one thing are more likely to require them, and an [[Tricky-to-emulate games|actual game]] will require a playthrough.<br />
Then to run a test case, play the movie in fast-forward (no delay between frames) and take screenshots at the same times.<br />
If a screenshot's hash differs from that of the corresponding screenshot from when the test case was created, make a note of this difference in the log.<br />
Then you can compare the emulator's output frame-by-frame to that of the previous release of your emulator running the same test case.</div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=10309PPU sprite evaluation2019-01-22T12:43:58Z<p>Zepper: /* Notes */ Thanks to Mesen source for the important info! It fixes R.C. Pro AM-II (hangs before the race starts).</p>
<hr />
<div>'''PPU sprite evaluation''' is an operation done by the PPU once each scanline. It prepares the set of sprites and fetches their data to be rendered on the next scanline.<br />
<br />
This is a separate step from sprite rendering.<br />
<br />
== Overview ==<br />
Each scanline, the PPU reads the spritelist (that is, Object Attribute Memory) to see which to draw:<br />
# First, it clears the list of sprites to draw.<br />
# Second, it reads through OAM, checking which sprites will be on this scanline. It chooses the first eight it finds that do.<br />
# Third, if eight sprites were found, it checks (in a wrongly-implemented fashion) for further sprites on the scanline to see if the sprite overflow flag should be set.<br />
# Fourth, using the details for the eight (or fewer) sprites chosen, it determines which pixels each has on the scanline and where to draw them.<br />
== Details ==<br />
During all visible scanlines, the PPU scans through OAM to determine which sprites to render on the next scanline. Sprites found to be within range are copied into the secondary OAM, which is then used to initialize eight internal sprite output units.<br />
<br />
''OAM[n][m]'' below refers to the byte at offset ''4*n + m'' within OAM, i.e. OAM byte ''m'' (0-3) of sprite ''n'' (0-63).<br />
<br />
During each pixel clock (341 total per scanline), the PPU accesses OAM in the following pattern:<br />
<br />
# Cycles 1-64: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF. Internally, the clear operation is implemented by reading from the OAM and writing into the secondary OAM as usual, only a signal is active that makes the read always return $FF.<br />
# Cycles 65-256: Sprite evaluation<br />
#* ''On odd cycles, data is read from (primary) OAM''<br />
#* ''On even cycles, data is written to secondary OAM (unless secondary OAM is full, in which case it will read the value in secondary OAM instead)''<br />
#*1. Starting at n = 0, read a sprite's Y-coordinate (OAM[n][0], copying it to the next open slot in secondary OAM (unless 8 sprites have been found, in which case the write is ignored).<br />
#**1a. If Y-coordinate is in range, copy remaining bytes of sprite data (OAM[n][1] thru OAM[n][3]) into secondary OAM.<br />
#*2. Increment n<br />
#**2a. If n has overflowed back to zero (all 64 sprites evaluated), go to 4<br />
#**2b. If less than 8 sprites have been found, go to 1<br />
#**2c. If exactly 8 sprites have been found, disable writes to secondary OAM because it is full. This causes sprites in back to drop out.<br />
#*3. Starting at m = 0, evaluate OAM[n][m] as a Y-coordinate.<br />
#**3a. If the value is in range, set the sprite overflow flag in $2002 and read the next 3 entries of OAM (incrementing 'm' after each byte and incrementing 'n' when 'm' overflows); if m = 3, increment n<br />
#**3b. If the value is not in range, increment n '''and''' m (without carry). If n overflows to 0, go to 4; otherwise go to 3<br />
#***''The m increment is a hardware bug - if only n was incremented, the overflow flag would be set whenever more than 8 sprites were present on the same scanline, as expected.''<br />
#*4. Attempt (and fail) to copy OAM[n][0] into the next free slot in secondary OAM, and increment n (repeat until HBLANK is reached)<br />
# Cycles 257-320: Sprite fetches (8 sprites total, 8 cycles per sprite)<br />
#*1-4: Read the Y-coordinate, tile number, attributes, and X-coordinate of the selected sprite from secondary OAM<br />
#*5-8: Read the X-coordinate of the selected sprite from secondary OAM 4 times (while the PPU fetches the sprite tile data)<br />
#* For the first empty sprite slot, this will consist of sprite #63's Y-coordinate followed by 3 $FF bytes; for subsequent empty sprite slots, this will be four $FF bytes<br />
#Cycles 321-340+0: Background render pipeline initialization<br />
#* Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline)<br />
<br />
This pattern was determined by doing carefully timed reads from $2004 using various sets of sprites, and simulation in Visual 2C02 has subsequently confirmed this behavior.<br />
<br />
== Sprite overflow bug ==<br />
During sprite evaluation, if eight in-range sprites have been found so far, the sprite evaluation logic continues to scan the primary OAM looking for one more in-range sprite to determine whether to set the sprite overflow flag. The first such check correctly checks the y coordinate of the next OAM entry, but after that the logic breaks and starts scanning OAM "diagonally", evaluating the tile number/attributes/X-coordinates of subsequent OAM entries as Y-coordinates (due to incorrectly incrementing m when moving to the next sprite). This results in inconsistent sprite overflow behavior showing both false positives and false negatives.<br />
<br />
=== Cause of the sprite overflow bug ===<br />
After investigation in [[Visual 2C02]], the culprit of the sprite overflow bug appears to be the write disable signal that goes high after eight in-range sprites have been found (to prevent further updates to the secondary OAM), along with an error in the sprite evaluation logic.<br />
<br />
As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it. Once eight in-range sprites have been found, the value being read during write cycles from that point on is the y coordinate of the first sprite copied into the secondary OAM. Due to a logic error, the result of comparing this y coordinate to the current scanline number (which will always yield "in range", since the sprite would have had to be in range to get copied into the secondary OAM) is allowed to influence the sprite address incrementation logic, causing the glitchy updates to the sprite address seen above (due to how the timing works out). Once one more sprite has been found, another signal prevents the comparison from influencing the sprite address incrementation logic, and the bug is no longer in effect.<br />
<br />
=== Examples of usage ===<br />
For some examples of games using this bug/quirk, refer to the [[Sprite overflow games]] page.<br />
<br />
== Notes ==<br />
* Sprite evaluation does not happen on the pre-render scanline. Because evaluation applies to the next line's sprite rendering, no sprites will be rendered on the first scanline, and this is why there is a 1 line offset on a sprite's Y coordinate.<br />
* Sprite evaluation occurs if ''either'' the sprite layer or background layer is enabled via $2001. Unless both layers are disabled, it merely hides sprite rendering.<br />
* Sprite evaluation does not cause sprite 0 hit. This is handled by sprite rendering instead.<br />
* If the sprite address ([[OAMADDR|OAMADDR, $2003]]) is not zero at the beginning of the pre-render scanline, on the 2C02 an [[Errata#OAM_and_Sprites|OAM hardware refresh bug]] will cause the first 8 bytes of OAM to be overwritten by the 8 bytes beginning at OAMADDR & $F8 before sprite evaluation begins.<ref>[http://forums.nesdev.org/viewtopic.php?p=110019#p110019 Forum]: Re: Just how cranky is the PPU OAM? (test notes by quietust)</ref><ref>[http://forums.nesdev.org/viewtopic.php?f=3&t=12407 Forum]: Huge Insect does not fully start</ref> This should only be done if rendering is enabled (otherwise oam_stress test fails immediately).<br />
* [[Visual 2C02]] might be helpful when trying to understand how the algorithm operates and what the precise timings are.<br />
<br />
== External links ==<br />
*[https://gist.github.com/beannaich/7a7ba066d909318debea Visual 2C02 logs of the PPU evaluating 1, 8, and 9 sprites] by beannaich<br />
<br />
== References ==<br />
<references></div>Zepperhttps://www.nesdev.org/w/index.php?title=NES_reference_guide&diff=8545NES reference guide2018-09-19T20:37:48Z<p>Zepper: Why not a link to the NES emulators page?</p>
<hr />
<div>This page lists all major hardware reference divided by categories in their simplest form. From this list, you can drill down to a more specific section of the selected category. <br />
<br />
=== General ===<br />
*[[Glossary]]<br />
*[[Cartridge and mappers' history]]<br />
<br />
=== Hardware reference ===<br />
* [[2A03]]: [[APU]], [[CPU]]<br />
* [[PPU]]<br />
* [[Input devices]]<br />
* [[Mapper]]s<br />
* [[Hardware pinout|Pinout]]<br />
* [[Clock rate]] of various components in different variants of NES<br />
* [[Cartridge_board_reference|Cartridge board]]<br />
* [[:File:neswires.jpg|RF Famicom wiring diagram]] (many parts also applicable to NES)<br />
* [[Errata]]: Hardware bugs and quirks<br />
* Miscellaneous<br />
** [[Vs. System]]<br />
** [[CIC lockout chip]]<br />
** [[Myths]]<br />
** [[PRG RAM circuit]]<br />
** [[Implementing Mappers In Hardware]]<br />
** [[Visual circuit tutorial|Tutorial on reading circuits in Visual 6502/2A03/2C02]]<br />
** [[MOD RF|RF modulator board]]<br />
** [http://console5.com/wiki/Nintendo_NES-001 Nintendo NES-001] on Console5<br />
<br />
=== File format reference ===<br />
* [[iNES]]<br />
** [[NES 2.0]]<br />
* [[UNIF]]<br />
* [[NSF]]<br />
* [[FDS]]<br />
* [http://old.smwiki.net/wiki/IPS IPS]<br />
<br />
=== Emulation reference ===<br />
* List of NES [[emulators]]<br />
* [[Emulator tests]]<br />
* [[Game bugs]] - games that display buggy behavior on the actual hardware<br />
* [[Tricky-to-emulate games]]<br />
* [[Sprite overflow games]] - games which use the [[PPU_sprite_evaluation#Sprite_overflow_bug|sprite overflow bug]] of [[OAM]]<br />
* [[Colour-emphasis games]] - games which make use of the colour emphasis bits of $2001<br />
* [[Colour $0D games]] - games which use the infra-black colour $0D.<br />
* [[Expansion audio games]] - Famicom games that use extra audio hardware.<br />
<br />
=== Notes ===<br />
* All content refer to the NTSC system unless otherwise specified<br />
<br />
=== External links ===<br />
* [http://console5.com/wiki/Nintendo_NES-001 NES-001 (frontloader)] and [http://console5.com/wiki/Nintendo_NES-101 NES-101 (toploader)] Control Deck PCB maps on Console5 TechWiki</div>Zepperhttps://www.nesdev.org/w/index.php?title=Nestech.txt&diff=9323Nestech.txt2018-09-05T00:28:44Z<p>Zepper: /* General Information */</p>
<hr />
<div>This is an updated version of "Nintendo Entertainment System Documentation" by Jeremy Chadwick, aka "koitsu".<br />
It provides a brief overview of the NES hardware and may prove easier to understand, particularly for programmers new to the NES, than some of the other, more technical documentation on this wiki.<br />
<br />
== Introduction ==<br />
<br />
=== Disclaimer ===<br />
I am in no way held responsible for the results of this information.<br />
This is public-domain information.<br />
I am not trying to hinder anyone financially: if you wish to do development on Nintendo's current platforms, contact Nintendo via developer.nintendo.com.<br />
<br />
All titles of cartridges and console systems are trademarks of their respective owners. (I just don't deem it necessary to list every single one by hand.)<br />
<br />
=== Why? ===<br />
At the time this document was created, there was only one piece of literature covering the internals to the NES: Marat Fayzullin's documentation, otherwise known as "NES.DOC".<br />
<br />
While Fayzullin's documentation was lacking in many areas, it provided a strong base for the basics, and in itself truly stated how complex the little grey box was.<br />
<br />
I took the opportunity to expand on "NES.DOC," basing other people's findings, as well as my own, on experience; experience which has helped make this document what it has become today. The beginning stages of this document looked almost like a replica of Fayzullin's documentation, with both minor and severe changes. Marat Fayzullin himself later picked up a copy of my documentation, and later began referring people to it.<br />
<br />
Keep in mind, without Marat's "NES.DOC" document, I would have never had any incentive to write this one.<br />
<br />
=== Mission ===<br />
The goal of this document is simplistic: to continue providing accurate, understandable, and up-to-date information regarding the Nintendo Entertainment System and its Famicom counterpart.<br />
<br />
=== Dedications ===<br />
I'd like to dedicate this document to Alex Krasivsky. Alex has been a great friend, and in my eyes, truly started the ball of emulation rolling. During the good times, and the bad times, Alex was there. Spasibo, Alex; umnyj Russki...<br />
<br />
=== "Thank You"s ===<br />
I'd like to take the time and thank all the people who helped make this document what it is today. I couldn't have done it without all of you.<br />
<br />
<pre><br />
Alex Krasivsky - bcat@lapkin.rosprint.ru<br />
Andrew Davie<br />
Avatar Z - swahlen@nfinity.com<br />
Barubary - barubary@mailexcite.com<br />
Bluefoot - danmcc@injersey.com<br />
CiXeL<br />
Chi-Wen Yang - yangfanw@ms4.hinet.net<br />
Chris Hickman - typhoonz@parodius.com<br />
D - slf05@cc.usu.edu<br />
Dan Boris - dan.boris@coat.com<br />
David de Regt - akilla@earthlink.net<br />
Donald Moore - moore@futureone.com<br />
Fredrik Olsson - flubba@hem2.passagen.se<br />
Icer Addis - bldlust@maelstrom.net<br />
Jon Merkel - jpm5974@omega.uta.edu<br />
Kevin Horton - khorton@iquest.net<br />
Loopy - zxcvzxcv@netzero.net<br />
Marat Fayzullin - fms@cs.umd.edu<br />
Mark Knibbs - mark_k@iname.com<br />
Martin Nielsen - mnielsen@get2net.dk<br />
Matt Conte - itsbroke@classicgaming.com<br />
Matthew Richey - mr6v@andrew.cmu.edu<br />
Memblers - 5010.0951@tcon.net<br />
MiKael Iushin - acc@tulatelecom.ru<br />
Mike Perry - mj-perry@uiuc.edu<br />
Morgan Johansson - morgan.johansson@mbox301.swipnet.se<br />
Neill Corlett - corlett@elwha.nrrc.ncsu.edu<br />
Pat Mccomack - splat@primenet.com<br />
Patrik Alexandersson - patrikus@hem2.passagen.se<br />
Paul Robson - AutismUK@aol.com<br />
Ryan Auge - rauge@hay.net<br />
Stumble - stumble@alpha.pulsar.net<br />
Tennessee Carmel-Veilleux - veilleux@ameth.org<br />
Thomas Steen - Thomas.Steen@no.jotankers.com<br />
Tony Young - KBAAA@aol.com<br />
Vince Indriolo - indriolo@nm.picker.com<br />
\FireBug\ - lavos999@aol.com<br />
</pre><br />
Special thanks goes out to Stumble, for providing a myriad of information over IRC, while avoiding sleep to do so.<br />
<br />
== Acronyms ==<br />
<br />
=== Internals ===<br />
<pre><br />
CPU - Central Processing Unit: Self-explanitory. The NES uses a<br />
standard 6502 (NMOS).<br />
PPU - Picture Processing Unit: Used to control graphics, sprites,<br />
and other video-oriented features.<br />
pAPU - pseuedo-Audio Processing Unit: Native to the CPU; generates<br />
waveforms via (5) audio channels:: four (4) analogue, and<br />
one (1) digital. There is no separate IC for audio process-<br />
ing nor generation inside the NES.<br />
MMC - Multi-Memory Controller or Memory Management Controller:<br />
Integrated circuits used in NES games<br />
to access memory beyond the 6502 64Kbyte boundary. They can<br />
also be used to access extra CHR-ROM, and may be used for<br />
"special effects" such as forcing and IRQ, and other things.<br />
VRAM - Video RAM: The RAM which is internal to the PPU. There is<br />
16kbits of VRAM installed in the NES.<br />
SPR-RAM - Sprite RAM: 256 bytes of RAM which is used for sprites. It is<br />
not part of VRAM nor ROM, though it's local to the PPU.<br />
OAM - Object Attribute Memory: Synonymous with SPR-RAM.<br />
PRG-ROM - Program ROM: The actual program-code area of memory. Also can<br />
be used to describe areas of code which are external to the<br />
actual code area and are swapped in via an MMC.<br />
PRG-RAM - Program RAM: Synonymous with PRG-ROM, except that it's RAM.<br />
CHR-ROM - Character ROM: The VRAM data which is kept external to the PPU,<br />
swapped in and out via an MMC, or "loaded" into VRAM during the<br />
power-on sequence.<br />
VROM - Synonymous with CHR-ROM.<br />
SRAM - Save RAM: RAM which is commonly used in RPGs such as "Cry-<br />
stalis," the Final Fantasy series, and "The Legend of Zelda."<br />
WRAM - Work RAM: Synonymous with SRAM.<br />
DMC - Delta Modulation Channel: The channel of the APU which handles<br />
digital data. Commonly referred to as the PCM (Pulse Code<br />
Modulation) channel.<br />
EX-RAM - Expansion RAM: This is the memory used within Nintendo's MMC5,<br />
allowing games to extend the capabilities of VRAM.<br />
</pre><br />
<br />
=== Hardware ===<br />
<pre><br />
NES - Nintendo Entertainment System: Self-explanitory.<br />
Famicom - Family Computer: Synonymous with the NES, except for also<br />
supporting external audio synthesizers in the cartridge.<br />
FDS - Famicom Disk System: Unit which sits atop the Famicom, support-<br />
ing the use of 3" double-sided floppy disks for games.<br />
Dendy - Third-party clone of the Famicom for PAL TV systems,<br />
distributed in Russia and elsewhere in the East.<br />
</pre><br />
<br />
== CPU ==<br />
<br />
=== General Information ===<br />
<br />
The NES uses a customized NMOS 6502 CPU, engineered and produced by Ricoh. Its primary customization adds audio.<br />
<br />
Different regional variants of the NES run the CPU different clock speeds.<br />
<br />
* The Famicom and NTSC NES runs at 1.789773 MHz.<br />
* The PAL NES runs at 1.662607 MHz.<br />
* The Dendy and other PAL famiclones run at 1.773448 MHz.<br />
<br />
=== Memory Map ===<br />
<pre><br />
+---------+-------+-------+-----------------------+<br />
| Address | Size | Flags | Description |<br />
+---------+-------+-------+-----------------------+<br />
| $0000 | $800 | | RAM |<br />
| $0800 | $800 | M | RAM |<br />
| $1000 | $800 | M | RAM |<br />
| $1800 | $800 | M | RAM |<br />
| $2000 | 8 | | Registers |<br />
| $2008 | $1FF8 | R | Registers |<br />
| $4000 | $20 | | Registers |<br />
| $4020 | $1FE0 | | Expansion I/O |<br />
| $6000 | $2000 | | SRAM |<br />
| $8000 | $4000 | | PRG-ROM |<br />
| $C000 | $4000 | | PRG-ROM |<br />
+---------+-------+-------+-----------------------+<br />
Flag Legend: M = Mirror of $0000<br />
R = Mirror of $2000-2008 every 8 bytes<br />
(e.g. $2008=$2000, $2018=$2000, etc.)<br />
</pre><br />
<br />
=== Interrupts ===<br />
<br />
The 6502 has three (3) interrupts: IRQ/BRK, NMI, and RESET.<br />
<br />
Each interrupt has a vector.<br />
A vector is a 16-bit address which specifies a location to "jump to" when the interrupt is triggered.<br />
<br />
IRQ/BRK is triggered under two circumstances, hence it's split name: when a software IRQ is executed (the BRK instruction), or when a hardware IRQ is executed (via the IRQ line).<br />
<br />
RESET is triggered on power-up.<br />
The ROM is loaded into memory, and the 6502 jumps to the address specified in the RESET vector.<br />
No registers are modified, and no memory is cleared; these only occur during power-up.<br />
<br />
NMI stands for Non-Maskable Interrupt, and is generated by each refresh (VBlank), which occurs at different intervals depending upon the system used (PAL/NTSC).<br />
<br />
NMI is updated 60 times/sec. on NTSC consoles, and 50 times/sec on PAL.<br />
Interrupt latency on the 6502 is seven (7) cycles; this means it takes seven (7) cycles to move in and out of an interrupt.<br />
<br />
Most interrupts should return using the RTI instruction.<br />
Some NES carts do not use this method, such as SquareSoft's ''Final Fantasy'' title.<br />
These carts return from interrupts in a very odd fashion: by manipulating the stack by hand, and then doing an RTS.<br />
This is technically valid, but morally shunned.<br />
<br />
The aforementioned interrupts have the following vector addresses, mapped to areas of ROM:<br />
<br />
* $FFFA = NMI<br />
* $FFFC = RESET<br />
* $FFFE = IRQ/BRK<br />
<br />
Interrupt priorities are as follows:<br />
<br />
* RESET (highest)<br />
* NMI<br />
* IRQ/BRK (lowest)<br />
<br />
=== NES-specific Customizations ===<br />
<br />
The NES's 6502 does not contain support for decimal mode.<br />
Both the CLD and SED opcodes function normally, but the 'd' bit of P is unused in both ADC and SBC.<br />
It is common practice for games to CLD prior to code execution, as the status of 'd' is unknown on power-on and on reset.<br />
<br />
Audio registers are mapped internal to the CPU; all waveform generation is done internal to the CPU as well.<br />
<br />
=== Notes ===<br />
<br />
Please note the two separate 16K PRG-ROM segments; they may be linear, but they play separate roles depending upon the size of the cartridge.<br />
Some games only hold one (1) 16K bank of PRG-ROM, which should be loaded into both $C000 and $8000.<br />
<br />
Most games load themselves into $8000, using 32K of PRG-ROM space.<br />
The first game to use this method is _Super Mario Bros._<br />
However, almost all games with more than one (1) 16K bank of PRG-ROM load themselves into $8000 as well.<br />
These games use Memory Mappers to swap in and out PRG-ROM data, as well as CHR-ROM.<br />
A few Memory Mappers, especially on later games, allow swapping in half of a 16K segment.<br />
<br />
When a BRK is encountered, the NES's 6502 pushes the CPU status flag onto the stack with the 'b' CPU bit set.<br />
On an IRQ or NMI, the CPU pushes the status flag onto the stack with the 'b' bit clear.<br />
This is done because of the fact that a hardware IRQ (IRQ) and a software IRQ (BRK) both share the same vector.<br />
For example, one could use the following code to distinguish the difference between the two:<br />
<pre><br />
C134: PLA ; Copy CPU status flag<br />
C135: PHA ; Return status flag to stack<br />
C136: AND #$10 ; Check D4 ('b' CPU bit)<br />
C138: BNE is_BRK_opcode ; If set then it is a software IRQ (BRK)<br />
</pre><br />
Executing BRK inside of an interrupt handler (IRQ or NMI) will result in the pushed 'b' bit being set.<br />
<br />
The 6502 has a bug in opcode $6C (jump absolute indirect).<br />
The CPU does not correctly calculate the effective address if the low-byte is $FF.<br />
Example:<br />
<pre><br />
C100: EF<br />
C1FF: 00<br />
C200: C3<br />
..<br />
D000: 6C FF C1 - JMP ($C1FF)<br />
</pre><br />
Logically, this will jump to address $C300. However, due to the fact that the high-byte of the calculate address is *NOT* increased on a page-wrap, this will actually jump to $EF00.<br />
<br />
It should be noted that page wrapping does *NOT* occur in indexed-indirect addressing modes. Due to limitations of zero-page, all indexed-indirect read/writes should apply a logical AND #$FF to the effective address after calculation. Example:<br />
<pre><br />
C000: LDX #3 ; Reads indirect address from $0002+$0003,<br />
C002: LDA ($FF,X) ; not $0102+$0103.<br />
</pre><br />
<br />
== PPU ==<br />
<br />
=== General Information ===<br />
Mirroring (also referred to as "shadowing") is the process of mapping particular addresses or address ranges to other addresses/ranges via hardware.<br />
<br />
=== Memory Map ===<br />
Included here are two (2) memory maps.<br />
The first is a "RAM Memory Map," which despite being less verbose describes the actual regions which point to physical memory in the NES Control Deck and most Game Paks.<br />
The second is a "Programmer Memory Map" which is quite verbose and describes the entire memory region of the NES and how it's used/manipulated.<br />
<pre><br />
RAM Memory Map<br />
+---------+-------+----------------+<br />
| Address | Size | Description |<br />
+---------+-------+----------------+<br />
| $0000 | $2000 | Pattern Tables |<br />
| $2000 | $800 | Name Tables |<br />
| $3F00 | $20 | Palettes |<br />
+---------+-------+----------------+<br />
<br />
Programmer Memory Map<br />
+---------+-------+-------+--------------------+<br />
| Address | Size | Flags | Description |<br />
+---------+-------+-------+--------------------+<br />
| $0000 | $1000 | C | Pattern Table #0 |<br />
| $1000 | $1000 | C | Pattern Table #1 |<br />
| $2000 | $3C0 | | Name Table #0 |<br />
| $23C0 | $40 | N | Attribute Table #0 |<br />
| $2400 | $3C0 | N | Name Table #1 |<br />
| $27C0 | $40 | N | Attribute Table #1 |<br />
| $2800 | $3C0 | N | Name Table #2 |<br />
| $2BC0 | $40 | N | Attribute Table #2 |<br />
| $2C00 | $3C0 | N | Name Table #3 |<br />
| $2FC0 | $40 | N | Attribute Table #3 |<br />
| $3000 | $F00 | R | |<br />
| $3F00 | $10 | | Image Palette #1 |<br />
| $3F10 | $10 | | Sprite Palette #1 |<br />
| $3F20 | $E0 | P | |<br />
| $4000 | $C000 | F | |<br />
+---------+-------+-------+--------------------+<br />
C = Either CHR-ROM or CHR-RAM<br />
N = Mirrored (see Subsection G)<br />
P = Mirrored (see Subsection H)<br />
R = Mirror of $2000-2EFF (VRAM)<br />
F = Mirror of $0000-3FFF (VRAM)<br />
</pre><br />
<br />
=== Name Tables ===<br />
The NES displays graphics using a matrix of "tiles"; this grid is called a Name Table. Tiles themselves are 8x8 pixels.<br />
The entire Name Table itself is 32x30 tiles (256x240 pixels).<br />
Keep in mind that the displayed resolution differs between NTSC and PAL units.<br />
<br />
The Name Tables holds the tile number of the data kept in the Pattern Table (continue on).<br />
<br />
=== Pattern Tables ===<br />
The Pattern Table contains the actual 8x8 tiles which the Name Table refers to.<br />
It also holds the lower two (2) bits of the 4-bit colour matrix needed to access all 16 colours of the NES palette. Example:<br />
<pre><br />
VRAM Contents of Colour <br />
Addr Pattern Table Result<br />
------ --------------- --------<br />
$0000: %00010000 = $10 --+ ...1.... Periods are used to<br />
.. %00000000 = $00 | ..2.2... represent colour 0.<br />
.. %01000100 = $44 | .3...3.. Numbers represent<br />
.. %00000000 = $00 +-- Bit 0 2.....2. the actual palette<br />
.. %11111110 = $FE | 1111111. colour #.<br />
.. %00000000 = $00 | 2.....2.<br />
.. %10000010 = $82 | 3.....3.<br />
$0007: %00000000 = $00 --+ ........<br />
<br />
$0008: %00000000 = $00 --+<br />
.. %00101000 = $28 |<br />
.. %01000100 = $44 |<br />
.. %10000010 = $82 +-- Bit 1<br />
.. %00000000 = $00 |<br />
.. %10000010 = $82 |<br />
.. %10000010 = $82 |<br />
$000F: %00000000 = $00 --+<br />
</pre><br />
The result of the above Pattern Table is the glyph for the letter 'A', as shown in the "Colour Result" section in the upper right.<br />
<br />
=== Attribute Tables ===<br />
Each byte in an Attribute Table represents a 4x4 group of tiles on the screen.<br />
There are multiple ways to describe what the function of one (1) byte in the Attribute Table is:<br />
<br />
* Holds the upper two (2) bits of a 32x32 pixel grid, per 16x16 pixels.<br />
* Holds the upper two (2) bits of sixteen (16) 8x8 tiles.<br />
* Holds the upper two (2) bits of four (4) 4x4 tile grids.<br />
<br />
It's quite confusing; two graphical diagrams may help:<br />
<pre><br />
+------------+------------+<br />
| Square 0 | Square 1 | #0-F represents an 8x8 tile<br />
| #0 #1 | #4 #5 |<br />
| #2 #3 | #6 #7 | Square [x] represents four (4) 8x8 tiles<br />
+------------+------------+ (i.e. a 16x16 pixel grid)<br />
| Square 2 | Square 3 |<br />
| #8 #9 | #C #D |<br />
| #A #B | #E #F |<br />
+------------+------------+<br />
</pre><br />
The actual format of the attribute byte is the following (and corres ponds to the above example):<br />
<pre><br />
Attribute Byte<br />
(Square #)<br />
----------------<br />
33221100<br />
||||||++-- Upper two (2) colour bits for Square 0 (Tiles #0,1,2,3)<br />
||||++---- Upper two (2) colour bits for Square 1 (Tiles #4,5,6,7)<br />
||++------ Upper two (2) colour bits for Square 2 (Tiles #8,9,A,B)<br />
++-------- Upper two (2) colour bits for Square 3 (Tiles #C,D,E,F)<br />
</pre><br />
<br />
=== Palettes ===<br />
The NES has two 16-colour "palettes": the Image Palette and the Sprite Palette.<br />
These palettes are more of a "lookup table" than an actual palette, since they do not hold physical RGB values.<br />
They're actually closer to HSV, with lightness in D5-D4 and hue in D3-D0.<br />
<br />
D7-D6 of bytes written to $3F00-3FFF are ignored.<br />
<br />
For details see [[PPU palettes]] and [[NTSC video]].<br />
<br />
=== Name Table Mirroring ===<br />
One should keep in mind that there are many forms of mirroring when understanding the NES.<br />
Some methods even use CHR-ROM-mapped Name Tables (mapper-specific).<br />
<br />
The NES itself only contains 2048 ($800) bytes of RAM used for Name Tables.<br />
However, as shown in Subsection B, the NES has the capability of addressing up to four (4) Name Tables.<br />
<br />
By default, many carts come with "horizontal" and "vertical" mirroring, allowing you to change where the Name Tables point into the NES's PPU RAM. This form of mirroring affects two (2) Name Tables simultaneously; you cannot switch Name Tables independently.<br />
<br />
The following chart should assist in understanding all the types of mirroring encountered on the NES.<br />
Please note that the addresses shown (12-bit in size) refer to VRAM.<br />
Mirroring determines how raw addresses in VRAM are translated into addresses that the PPU sees in the "$2xxx" region.<br />
<pre><br />
Name NT#0 NT#1 NT#2 NT#3 Flags<br />
+--------------------------+------+------+------+------+-------+<br />
| Horizontal | $000 | $000 | $400 | $400 | | <br />
| Vertical | $000 | $400 | $000 | $400 | | <br />
| Four-screen | $000 | $400 | $800 | $C00 | F | <br />
| Single-screen | | | | | S | <br />
| CHR-ROM mirroring | | | | | C |<br />
+--------------------------+------+------+------+------+-------+<br />
F = Four-screen mirroring relies on an extra 2048 ($800) of RAM<br />
(kept on the cart), resulting in four (4) physical independent<br />
Name Tables.<br />
S = Single-screen games have mappers which allow you to select<br />
which PPU RAM area you want to use ($000, $400, $800, or<br />
$C00); all the NTs point to the same PPU RAM address.<br />
C = Mapper #68 (Afterburner 2) allows you to map CHR-ROM to the<br />
Name Table region of the NES's PPU RAM area. Naturally this<br />
makes the Name Table ROM-based, and one cannot write to it.<br />
However, this feature can be controlled via the mapper itself,<br />
allowing you to enable or disable this feature.<br />
</pre><br />
<br />
=== Palette Mirroring ===<br />
Mirroring occurs between the Background Palette and the Sprite Palette on addresses that are multiples of 4.<br />
Any data which is written to $3F00 is mirrored to $3F10. Any data written to $3F04 is mirrored to $3F14, etc. etc...<br />
<br />
Colour #0 in the upper three (3) palettes of both the Image and Sprite palette defines transparency (the actual colour stored there is not drawn on-screen).<br />
<br />
In most cases, the PPU uses the value in $3F00 to define background colour.<br />
<br />
For a more verbose explanation, assume the following:<br />
<br />
* $0D has been written to $3F00 (mirrored to $3F10)<br />
* $03 has been written to $3F08 (mirrored to $3F18)<br />
* $1A has been written to $3F18<br />
* $3F08 is read into the accumulator<br />
<br />
The PPU will use $0D as the background colour, despite $3F08 holding a value of $03 (since colour #0 in all the palette entries defines transparency, it is not drawn).<br />
Finally, the accumulator will hold a value of $1A, which is mirrored from $3F18.<br />
Again, the value of $1A is not drawn, since colour #0 defines transparency.<br />
<br />
The entire Background and Sprite Palettes are both mirrored to other areas of VRAM as well; $3F20-3FFF are mirrors of both palettes, respectively.<br />
<br />
Again, D7-D6 of bytes written to $3F00-3FFF are ignored.<br />
<br />
=== Background Scrolling ===<br />
The NES can scroll the background (pre-rendered Name Table + Pattern Table + Attribute Table) independently of the sprites which are overlaid on top of it. The background can be scrolled horizontally and vertically.<br />
<br />
Scrolling works as follows:<br />
<pre><br />
Horizontal Scrolling Vertical Scrolling<br />
0 512<br />
+-----+-----+ +-----+ 0<br />
| | | | |<br />
| A | B | | A |<br />
| | | | |<br />
+-----+-----+ +-----+<br />
| |<br />
| B |<br />
| |<br />
+-----+ 480<br />
</pre><br />
Name Table "A" is specified via Bits D1-D0 in register $2000, and "B" is the Name Table after (due to mirroring, this is dynamic).<br />
Games which use Horizontal & Vertical scrolling simultaneously need special attention paid to mirroring.<br />
<br />
The background will span across multiple Name Tables, as shown here:<br />
<pre><br />
+---------------+---------------+<br />
| Name Table #0 | Name Table #1 |<br />
| ($2000) | ($2400) |<br />
+---------------+---------------+<br />
| Name Table #2 | Name Table #3 |<br />
| ($2800) | ($2C00) |<br />
+---------------+---------------+<br />
</pre><br />
<br />
But depending on mirroring, some of them will be repeated:<br />
<pre><br />
Horizontal Mirroring<br />
+---------------+---------------+<br />
| Name Table #0 | Duplicate #0 |<br />
| ($2000) | ($2400) |<br />
+---------------+---------------+<br />
| Name Table #2 | Duplicate #2 |<br />
| ($2800) | ($2C00) |<br />
+---------------+---------------+<br />
<br />
<br />
Vertical Mirroring<br />
+---------------+---------------+<br />
| Name Table #0 | Name Table #1 |<br />
| ($2000) | ($2400) |<br />
+---------------+---------------+<br />
| Duplicate #2 | Duplicate #3 |<br />
| ($2800) | ($2C00) |<br />
+---------------+---------------+<br />
</pre><br />
<br />
Writes to the Horizontal Scroll value in $2005 range from 0 to 256.<br />
Writes to the Vertical Scroll value range from 0-239.<br />
Vertical Scroll values above 239 are considered negative (e.g. a write of 248 is really -8).<br />
This is because values above 239 cause the PPU to interpret Attribute Table data as Name Table data.<br />
<br />
=== Screen and Sprite Layering ===<br />
There is a particular order in which the NES draws its contents:<br />
<pre><br />
FRONT BACK<br />
+----+-----------+----+-----------+-----+<br />
| CI | OBJs 0-63 | BG | OBJs 0-63 | EXT |<br />
+----+-----------+----+-----------+-----+<br />
| SPR-RAM | | SPR-RAM |<br />
| BGPRI==0 | | BGPRI==1 |<br />
+-----------+ +-----------+<br />
</pre><br />
CI stands for 'Colour Intensity', which is synonmous with D7-D5 of $2001.<br />
BG is the BackGround, and EXT is for the EXTension port video signal.<br />
<br />
'BGPRI' represents the 'Background Priority' bit in SPR-RAM, on a per-sprite basis (D5, Byte 2).<br />
<br />
OBJ numbers represent actual Sprite numbers, not Tile Index values.<br />
<br />
FRONT is considered what is seen atop all other layers (drawn last), and BACK is deemed what is below most other layers (drawn first).<br />
<br />
If a sprite with BGPRI==1 has a lower index in SPR-RAM than a sprite with BGPRI==0, the front-to-back ordering is more complicated.<br />
See [[PPU sprite priority]] for full details.<br />
<br />
=== Sprites and OAM ===<br />
The NES supports 64 sprites, which can be either 8x8 or 8x16 pixels in size.<br />
The sprite data is kept within the Pattern Table region of VRAM.<br />
<br />
Sprite attributes such as flipping and priority, are stored in SPR-RAM, which is a separate 256 byte area of memory, independent of ROM and VRAM.<br />
The format of SPR-RAM is as follows:<br />
<pre><br />
+-----------+-----------+-----+------------+<br />
| Sprite #0 | Sprite #1 | ... | Sprite #63 |<br />
+-+------+--+-----------+-----+------------+<br />
| | <br />
+------+----------+--------------------------------------+<br />
+ Byte | Bits | Description |<br />
+------+----------+--------------------------------------+<br />
| 0 | YYYYYYYY | Y Coordinate - 1. Consider the coor- |<br />
| | | dinate the upper-left corner of the |<br />
| | | sprite itself. |<br />
| 1 | IIIIIIII | Tile Index # |<br />
| 2 | vhp000cc | Attributes |<br />
| | | v = Vertical Flip (1=Flip) |<br />
| | | h = Horizontal Flip (1=Flip) |<br />
| | | p = Background Priority |<br />
| | | 0 = In front |<br />
| | | 1 = Behind |<br />
| | | c = Upper two (2) bits of colour |<br />
| 3 | XXXXXXXX | X Coordinate (upper-left corner) |<br />
+------+----------+--------------------------------------+<br />
</pre><br />
The Tile Index # is obtained the same way as Name Table data.<br />
<br />
Sprites which are 8x16 in size function a little bit differently.<br />
An 8x16 sprite which has an even-numbered Tile Index # use the Pattern Table at $0000 in VRAM; odd-numbered Tile Index #s use $1000.<br />
*NOTE*: Register $2000 D3 has no effect on 8x16 sprites.<br />
<br />
All 64 sprites contain an internal priority; sprite #0 is of a higher priority than sprites #63 (sprite #0 should be drawn last, etc.).<br />
<br />
Only eight (8) sprites can be displayed per scan-line.<br />
Each entry in SPR-RAM is checked to see if it's in a horizontal range with the other sprites.<br />
Remember, this is done on a per scan-line basis, not on a per sprite basis (e.g. done 256 times, not 256/8 or 256/16 times).<br />
<br />
NOTE: On a real NES unit, if both background and sprites are disabled (D4-D3 of $2001 is 00) for a long period of time, SPR-RAM will gradually degrade.<br />
Photographs of a decapped PPU have confirmed that SPR-RAM is actually DRAM, and rendering controls the DRAM refresh cycle.<br />
<br />
=== Sprite #0 Hit Flag ===<br />
The PPU is capable of figuring out where Sprite #0 is, and stores its findings in D6 of $2002.<br />
The way this works is as follows:<br />
<br />
As the PPU draws each line, it scans for the first actual non-transparent "sprite pixel" and the first non-transparent "background pixel."<br />
A "background pixel" is a tile which is in use by the Name Table.<br />
Remember that colour #0 defines transparency.<br />
<br />
The pixel which causes D6 to be set *IS* drawn.<br />
<br />
The following example should help.<br />
The following are two tiles.<br />
Transparent colours (colour #0) are defined via the underscore ('_') character.<br />
An asterisk ('*') represents when D6 will be set.<br />
<pre><br />
Sprite BG Result<br />
------ -- ------<br />
__1111__ ________ __1111__<br />
_111111_ _______2 _1111112 <br />
11222211 ______21 11222211<br />
112__211 + _____211 = 112__*11 '*' will be drawn as colour #2<br />
112__211 ____2111 112_2211<br />
11222211 ___21111 11222211<br />
_111111_ __211111 _1111111<br />
__1111__ _2111111 _2111111<br />
</pre><br />
This also applies to sprites that are underneath the BG (via the 'Background Priority' SPR-RAM bit), though the above example would be 'BG+Sprite'.<br />
<br />
However, D6 does not get set if the overlap is at the far right of the screen (X==255).<br />
<br />
Also, D6 is cleared (set to 0) at the end of each VBlank.<br />
<br />
=== Horizontal and Vertical Blanking ===<br />
The NES, like every console, has a refresh: where the display device relocates the electron gun to display visible data.<br />
The most common display device is a television set.<br />
The refresh occurs 60 times a second on an NTSC device, and 50 on a PAL device.<br />
<br />
The gun itself draws pixels left to right: this process results in one (1) horizontal scanline being drawn.<br />
After the gun is done drawing the entire scanline, the gun must return to the left side of the display device, becoming ready to draw the next scanline.<br />
The process of the gun returning to the left side of the display is the Horizontal Blank period (HBlank).<br />
<br />
When the gun has completed drawing all of the scanlines, it must return to the top of the display device.<br />
The time it takes for the gun to re-position itself atop the device is called the Vertical Blank period (VBlank).<br />
<br />
As you can see from the below diagram, the gun more or less works in a zig-zag pattern until VBlank is reached, then the process repeats:<br />
<pre><br />
+-----------+<br />
+--->|***********| <-- Scanline 0<br />
| | ___---~~~ | <-- HBlank<br />
V |***********| <-- Scanline 1<br />
B | ___---~~~ | <-- HBlank<br />
l | ... | ...<br />
a | ... | ...<br />
n |***********| <-- Scanline 239<br />
k +-----+-----+<br />
| |<br />
+--VBlank--+<br />
</pre><br />
The screen is 256 pixels wide, and the HBlank time that follows each line adds an additional 85 for a total of 341.<br />
<br />
An NTSC NES has the following refresh and screen layout:<br />
<pre><br />
0 256 340<br />
+--------+ | 0 --+<br />
| | | |<br />
| | H | |<br />
| Screen | B | +-- (0-239) 256x240 on-screen results<br />
| | l | |<br />
| | | |<br />
+--------+ | 239 --+<br />
+--------+ 240 --+-- (240) Post-render<br />
+--------+ 241 --+<br />
| | |<br />
| VBlank | +-- (241-260) VBlank<br />
| | |<br />
+--------+ 260 --+<br />
+--------+ 261 --+-- (261) Pre-render<br />
</pre><br />
<br />
The Vertical Blank (VBlank) flag is contained in D7 of $2002.<br />
It indicates whether PPU is in VBlank or not.<br />
A program can reset D7 by reading $2002.<br />
Reading $2002 at the very start of VBlank will reset $2002 even though D7 appears false.<br />
<br />
=== $2005/$2006 Magic ===<br />
Games can split the screen by changing the video memory address using both the $2005 and $2006 registers.<br />
This is often used to draw a status bar at the top or bottom of the screen.<br />
For detailed information pertaining to splits, refer to Loopy's $2005/2006 document.<br />
His document provides entirely accurate information regarding how these registers work.<br />
See [[PPU scrolling]] for more information<br />
<br />
=== Reading VRAM ===<br />
The first byte read from VRAM is invalid.<br />
Due to this aspect, the NES will returned pseudo-buffered values from VRAM rather than linear as expected.<br />
See the below example:<br />
<br />
* VRAM $2000 contains $AA $BB $CC $DD.<br />
* VRAM incrementation value is 1.<br />
* The result of execution is printed in the comment field. <br />
<pre><br />
LDA #$20<br />
STA $2006<br />
LDA #$00<br />
STA $2006 ; VRAM address now set at $2000<br />
LDA $2007 ; A=?? VRAM Buffer=$AA<br />
LDA $2007 ; A=$AA VRAM Buffer=$BB<br />
LDA $2007 ; A=$BB VRAM Buffer=$CC<br />
LDA #$20<br />
STA $2006<br />
LDA #$00<br />
STA $2006 ; VRAM address now set at $2000<br />
LDA $2007 ; A=$CC VRAM Buffer=$AA<br />
LDA $2007 ; A=$AA VRAM Buffer=$BB<br />
</pre><br />
As shown, the PPU will post-increment it's internal address data after the first read is performed.<br />
This '''only applies''' to VRAM $0000-3EFF (e.g. Palette data and their respective mirrors do not suffer from this phenomenon).<br />
<br />
=== Notes ===<br />
The PPU will auto-increment the VRAM address by 1 or 32 (based on D2 of $2000) after accessing $2007.<br />
<br />
While rendering is off ($2001 D4-D3 set to 00), and the current video memory address is at $3F00-$3FFF, the PPU outputs the palette entry at that address.<br />
To avoid streaks of rainbow colours, make sure to update the palette during VBlank.<br />
<br />
== pAPU ==<br />
This section was not completed in time for Nestech.txt version 2.00.<br />
See [[APU]] for accurate information.<br />
<br />
== Joypads, paddles, expansion ports ==<br />
<br />
=== General Information ===<br />
The NES supports several different input devices, including joypads, Zapper (light guns), and four-player devices.<br />
<br />
Joypad #1 and #2 are read via $4016 and $4017, respectively.<br />
<br />
The joypads are reset via a strobing-method: writing 1, then 0, to $4016.<br />
This address controls the strobe on both joypads.<br />
See "Expansion ports" for information regarding "half-strobing."<br />
<br />
After a full strobe, the joypad's button status will be returned in a single-bit stream (D0).<br />
Multiple reads need to be made to read all the information about the controller.<br />
<br />
The standard controller can be read 8 times, once for each button:<br />
<pre><br />
1 = A<br />
2 = B<br />
3 = SELECT<br />
4 = START<br />
5 = UP<br />
6 = DOWN<br />
7 = LEFT<br />
8 = RIGHT<br />
</pre><br />
Reads after the eighth return a 1 bit on most controllers.<br />
A few return 0 instead.<br />
<br />
=== The Zapper ===<br />
The Zapper (otherwise known as the "Light Gun") uses bits within $4016 and $4017, described in Section 8.<br />
D4 and D3 are connected to the trigger and light sensor respectively.<br />
The light sensor needs to be read throughout the frame, as it returns a light signal for only about 2000 cycles.<br />
<br />
It is possible to have two Zapper units connected to both joypad ports simultaneously.<br />
The unlicensed games ''Chiller'' and ''Zap Ruder'' use this.<br />
<br />
=== Four-player devices ===<br />
Some NES games allow the use of a four-player adapter, extending the number of usable joypads from two (2) to four (4).<br />
Carts which use the NES Four Score or NES Satellite are Mindscape/Tengen's ''Gauntlet II'' and Nintendo/Rare's ''R.C. Pro-Am 2''.<br />
<br />
All four (4) controllers read their status-bits from D0 of $4016 or $4017, as Subsection A states.<br />
<br />
For register $4016, reads #1-8 control joypad #1, reads #9-16 control joypad #3, and reads #17-24 return a signature.<br />
For $4017, it is respective for joypad #2 and #4.<br />
<br />
The following is a list of read #s and their results.<br />
<pre><br />
1 = A 9 = A 17 = +--+<br />
2 = B 10 = B 18 = +-- Signature<br />
3 = SELECT 11 = SELECT 19 = |<br />
4 = START 12 = START 20 = +--+<br />
5 = UP 13 = UP 21 = 0<br />
6 = DOWN 14 = DOWN 22 = 0<br />
7 = LEFT 15 = LEFT 23 = 0<br />
8 = RIGHT 16 = RIGHT 24 = 0<br />
</pre><br />
<br />
The Famicom has a different four-player adapter.<br />
On that system (not the NES), $4016 reads controllers 1 and 3 at the same time, with controller 1 in D0 and controller 3 in D1.<br />
Likewise, $4016 returns controller 2 in D0 and controller 4 in D1.<br />
In Famicom games that do not use four players, the player expects to be able to use controllers 3 and 4 as if they were controllers 1 and 2.<br />
<br />
=== Paddles ===<br />
Taito's ''Arkanoid'' uses a paddle as it's primary controller.<br />
<br />
The paddle position on the Famicom version is read via D1 of $4017; the read data is inverted (0=1, 1=0).<br />
The first value read is the MSB, and the 8th value read is (obviously) the LSB.<br />
The valid value range is about 160 units wide.<br />
One unit was measured with a range 98 to 242, where 98 represents the paddle being turned completely counter-clockwise.<br />
<br />
For example, if %01101011 is read, the value would be NOT'd, making %10010100 which is 146.<br />
<br />
The paddle also contains one button, which is read via D1 of $4016.<br />
A value of 1 specifies that the button is being pressed.<br />
<br />
On the NES version of the Arkanoid, D3 and D4 of $4017 are used instead.<br />
See [[Arkanoid controller]] for full information.<br />
<br />
=== Signatures ===<br />
A signature allows the programmer to detect if a device is connected to one of the four (4) ports or not, and if so, what type of device it is.<br />
<br />
The NES Four Score and NES Satellite have a signature in bits 17-24:<br />
* %0001 0000 = Joypad ($4016 only)<br />
* %0010 0000 = Joypad ($4017 only)<br />
<br />
Other controllers may or may not have a signature.<br />
<br />
=== Expansion ports ===<br />
The joypad strobing process requires dual writes: 1, then 0.<br />
Some specialised controllers, especially for the Famicom's front expansion port, use a non-standard order for the strobing process.<br />
<br />
For example, reading a Super NES Mouse while it is half strobed changes its sensitivity.<br />
A program would execute the following code:<br />
<pre><br />
LDA #%00000001 ; Begin half strobe<br />
STA $4016<br />
LDA $4017 ; Send one clock while half strobed<br />
LDA #%00000000 ; End half strobe<br />
STA $4016<br />
</pre><br />
<br />
== Memory Mapping Hardware ==<br />
Due to the hundreds of different mappers in use, both discrete logic and integrated MMCs, this document cannot describe them all.<br />
See [[Mapper]] for complete information.<br />
<br />
== Registers ==<br />
Programmers communicate with the PPU and pAPU via registers, which are nothing more than pre-set memory locations which allow the coder to make changes to the NES.<br />
Without registers, programs would have no way to communicate with the outside world.<br />
<br />
Each register is a 16-bit address. Each register has a statistics field in parentheses located immediately after its description. The legend:<br />
<br />
R = Readable W = Writable<br />
2 = Double-write register 16 = 16-bit register<br />
<br />
Notes:<br />
<br />
* 16-bit registers actually consist of two linear 8-bit registers, which can (and will be) *INDEPENDENTLY* assigned. The reason for specifying them as 16-bit is for ease of documentation. For instance, "$4002+$4003" would mean that D15-D8 would be in $4003, and D7-D0 would be in $4002.<br />
* Bits not listed are to be considered unused.<br />
<br />
<pre><br />
+---------+----------------------------------------------------------+<br />
| Address | Description |<br />
+---------+----------------------------------------------------------+<br />
| $2000 | PPU Control Register #1 (W) |<br />
| | |<br />
| | D7: Execute NMI on VBlank |<br />
| | 0 = Disabled |<br />
| | 1 = Enabled |<br />
| | D6: PPU Master/Slave Selection --+ Always write 0 |<br />
| | 0 = Receive EXTBG +-- in unmodified |<br />
| | 1 = Send EXTBG --+ Control Deck |<br />
| | D5: Sprite Size |<br />
| | 0 = 8x8 |<br />
| | 1 = 8x16 |<br />
| | D4: Background Pattern Table Address |<br />
| | 0 = $0000 (VRAM) |<br />
| | 1 = $1000 (VRAM) |<br />
| | D3: Sprite Pattern Table Address |<br />
| | 0 = $0000 (VRAM) |<br />
| | 1 = $1000 (VRAM) |<br />
| | D2: PPU Address Increment |<br />
| | 0 = Increment by 1 |<br />
| | 1 = Increment by 32 |<br />
| | D1-D0: Name Table Address |<br />
| | 00 = $2000 (VRAM) |<br />
| | 01 = $2400 (VRAM) |<br />
| | 10 = $2800 (VRAM) |<br />
| | 11 = $2C00 (VRAM) |<br />
+---------+----------------------------------------------------------+<br />
| $2001 | PPU Control Register #2 (W) |<br />
| | |<br />
| | D7-D5: Colour Intensity |<br />
| | 000 = None +--+ NOTE: Some TVs don't |<br />
| | 001 = Intensify red | sync well if more |<br />
| | 010 = Intensify green | than one type used; |<br />
| | 100 = Intensify blue +--+ PAL swaps D6/D5 |<br />
| | D4: Sprite Visibility |<br />
| | 0 = Sprites not displayed |<br />
| | 1 = Sprites visible |<br />
| | D3: Background Visibility |<br />
| | 0 = Background not displayed |<br />
| | 1 = Background visible |<br />
| | D2: Sprite Clipping |<br />
| | 0 = Sprites invisible in left 8-pixel column |<br />
| | 1 = No clipping |<br />
| | D1: Background Clipping |<br />
| | 0 = BG invisible in left 8-pixel column |<br />
| | 1 = No clipping |<br />
| | D0: Display Type |<br />
| | 0 = Colour display |<br />
| | 1 = Monochrome display (all palette values |<br />
| | ANDed with $30) |<br />
+---------+----------------------------------------------------------+<br />
| $2002 | PPU Status Register (R) |<br />
| | |<br />
| | D7: VBlank Occurance |<br />
| | 0 = Not occuring |<br />
| | 1 = In VBlank |<br />
| | D6: Sprite #0 Hit |<br />
| | 0 = Sprite #0 not found |<br />
| | 1 = PPU has hit Sprite #0 since end of VBlank |<br />
| | D5: Scanline Sprite Count |<br />
| | 0 = No scanline with more than eight (8) |<br />
| | sprites |<br />
| | 1 = At least one line with more than 8 sprites |<br />
| | since end of VBlank |<br />
| | |<br />
| | NOTE: D7 is set to 0 after read occurs. |<br />
| | NOTE: After a read occurs, $2005 is reset, hence the |<br />
| | next write to $2005 will be Horizontal. |<br />
| | NOTE: After a read occurs, $2006 is reset, hence the |<br />
| | next write to $2006 will be the high byte portion. |<br />
| | NOTE: D4-D0 return the last value written to any PPU |<br />
| | register. |<br />
| | |<br />
| | For detailed information regarding D6, see Section 4, |<br />
| | Subsection L. |<br />
+---------+----------------------------------------------------------+<br />
| $2003 | SPR-RAM Address Register (W) |<br />
| | |<br />
| | D7-D0: 8-bit address in SPR-RAM to access via $2004. |<br />
| | |<br />
| | NOTE: The SPR-RAM DRAM controller is very touchy. |<br />
| | Write $00 here. |<br />
+---------+----------------------------------------------------------+<br />
| $2004 | SPR-RAM I/O Register (W) |<br />
| | |<br />
| | D7-D0: 8-bit data written to SPR-RAM. |<br />
| | |<br />
| | NOTE: It is strongly recommended to use $4014 instead. |<br />
+---------+----------------------------------------------------------+<br />
| $2005 | VRAM Address Register #1 (W2) |<br />
| | |<br />
| | Commonly used used to "pan/scroll" the screen (sprites |<br />
| | excluded) horizontally and vertically. However, there |<br />
| | is no actual panning hardware inside the NES. This |<br />
| | register controls VRAM addressing lines. |<br />
| | |<br />
| | Refer to Section 4, Subsection N, for more information. |<br />
+---------+----------------------------------------------------------+<br />
| $2006 | VRAM Address Register #2 (W2) |<br />
| | |<br />
| | Commonly used to specify the 16-bit address in VRAM to |<br />
| | access via $2007. However, this register controls VRAM |<br />
| | addressing bits, and therefore should be used with |<br />
| | knowledge of how it works, and when it works. |<br />
| | |<br />
| | Refer to Section 4, Subsection N, for more information. |<br />
+---------+----------------------------------------------------------+<br />
| $2007 | VRAM I/O Register (RW) |<br />
| | |<br />
| | D7-D0: 8-bit data read/written from/to VRAM. |<br />
+---------+----------------------------------------------------------+<br />
| $4000 | pAPU Pulse #1 Control Register (W) |<br />
| $4001 | pAPU Pulse #1 Ramp Control Register (W) |<br />
| $4002 | pAPU Pulse #1 Fine Tune (FT) Register (W) |<br />
| $4003 | pAPU Pulse #1 Coarse Tune (CT)/Length Register (W) |<br />
| $4004 | pAPU Pulse #2 Control Register (W) |<br />
| $4005 | pAPU Pulse #2 Ramp Control Register (W) |<br />
| $4006 | pAPU Pulse #2 Fine Tune Register (W) |<br />
| $4007 | pAPU Pulse #2 Coarse Tune/Length Register (W) |<br />
| $4008 | pAPU Triangle Linear Counter Register #1 (W) |<br />
| $4009 | Unused |<br />
| $400A | pAPU Triangle Fine Tune Register Register #1 (W) |<br />
| $400B | pAPU Triangle Coarse Tune/Length Register #2 (W) |<br />
| $400C | pAPU Noise Control Register #1 (W) |<br />
| $400D | Unused |<br />
| $400E | pAPU Noise Frequency Register (W) |<br />
| $400F | pAPU Noise Length Register (W) |<br />
| $4010 | pAPU Delta Modulation Control Register (W) |<br />
| $4011 | pAPU Delta Modulation D/A Register (W) |<br />
| $4012 | pAPU Delta Modulation Address Register (W) |<br />
| $4013 | pAPU Delta Modulation Data Length Register (W) |<br />
+---------+----------------------------------------------------------+<br />
| $4014 | Sprite DMA Register (W) |<br />
| | |<br />
| | Transfers 256 bytes of memory into SPR-RAM. The address |<br />
| | read from is $100*N, where N is the value written. |<br />
+---------+----------------------------------------------------------+<br />
| $4015 | pAPU Sound/APU Frame Counter Register (R) |<br />
| | |<br />
| | D6: APU Frame IRQ Availability |<br />
| | 0 = One (1) frame occuring, hence IRQ cannot |<br />
| | occur |<br />
| | 1 = One (1) frame is being interrupted via IRQ |<br />
| | D4: Delta Modulation |<br />
| | D3: Noise |<br />
| | D2: Triangle |<br />
| | D1: Pulse #2 |<br />
| | D0: Pulse #1 |<br />
| | 0 = Not in use |<br />
| | 1 = In use |<br />
| +----------------------------------------------------------+<br />
| | pAPU Channel Control (W) |<br />
| | |<br />
| | D4: Delta Modulation |<br />
| | D3: Noise |<br />
| | D2: Triangle |<br />
| | D1: Pulse #2 |<br />
| | D0: Pulse #1 |<br />
| | 0 = Channel disabled |<br />
| | 1 = Channel enabled |<br />
+---------+----------------------------------------------------------+<br />
| $4016 | Joypad #1 (RW) |<br />
| | |<br />
| | READING: |<br />
| | D4: Zapper Trigger |<br />
| | 0 = Pulled or released |<br />
| | 1 = Half pulled |<br />
| | D3: Zapper Light Detection |<br />
| | 0 = Light in front of barrel |<br />
| | 1 = Dark in front of barrel |<br />
| | D1: Famicom Expansion Joypad Data |<br />
| | D0: Joypad Data |<br />
| +----------------------------------------------------------+<br />
| | WRITING: |<br />
| | Joypad Strobe (W) |<br />
| | |<br />
| | D0: Joypad Strobe |<br />
| | 0 = Finish polling both joypads |<br />
| | 1 = Poll both joypads |<br />
+---------+----------------------------------------------------------+<br />
| $4017 | Joypad #2/SOFTCLK (RW) |<br />
| | |<br />
| | READING: |<br />
| | D4: Zapper Trigger |<br />
| | 0 = Pulled or released |<br />
| | 1 = Half pulled |<br />
| | D3: Zapper Light Detection |<br />
| | 0 = Light in front of barrel |<br />
| | 1 = Dark in front of barrel |<br />
| | D1: Famicom Expansion Joypad Data |<br />
| | D0: Joypad Data |<br />
+---------+----------------------------------------------------------+<br />
</pre><br />
<br />
== File Formats ==<br />
<br />
=== iNES Format (.NES) ===<br />
Most common ROMs will be found in this format:<br />
<pre><br />
+--------+------+------------------------------------------+<br />
| Offset | Size | Content(s) |<br />
+--------+------+------------------------------------------+<br />
| 0 | 3 | 'NES' |<br />
| 3 | 1 | $1A |<br />
| 4 | 1 | 16K PRG-ROM page count |<br />
| 5 | 1 | 8K CHR-ROM page count |<br />
| 6 | 1 | ROM Control Byte #1 |<br />
| | | %####vTsM |<br />
| | | | ||||+- 0=Horizontal mirroring |<br />
| | | | |||| 1=Vertical mirroring |<br />
| | | | |||+-- 1=SRAM enabled |<br />
| | | | ||+--- 1=512-byte trainer present |<br />
| | | | |+---- 1=Four-screen mirroring |<br />
| | | | | |<br />
| | | +--+----- Mapper # (lower 4-bits) |<br />
| 7 | 1 | ROM Control Byte #2 |<br />
| | | %####0000 |<br />
| | | | | |<br />
| | | +--+----- Mapper # (upper 4-bits) |<br />
| 8-15 | 8 | $00 |<br />
| 16-.. | | Actual 16K PRG-ROM pages (in linear |<br />
| ... | | order). If a trainer exists, it precedes |<br />
| ... | | the first PRG-ROM page. |<br />
| ..-EOF | | CHR-ROM pages (in ascending order). |<br />
+--------+------+------------------------------------------+<br />
</pre><br />
See [[iNES]] for full details.<br />
<br />
Some ROMs using more obscure mappers require an extension to the iNES format called "NES 2.0", first proposed by Kevin Horton.<br />
See [[NES 2.0]] for full details.<br />
<br />
== Programming the NES ==<br />
<br />
=== General Information ===<br />
None.<br />
<br />
=== CPU Notes ===<br />
None.<br />
See "CPU Notes" in Section 11 "Emulation" for more possible information.<br />
<br />
=== PPU Notes ===<br />
<br />
Reading and writing to VRAM consists of a multi-step process:<br />
<pre><br />
Writing to VRAM Reading from VRAM<br />
--------------- -----------------<br />
1) Wait for VBlank 1) Wait for VBlank<br />
2) Write upper VRAM address 2) Write upper VRAM address<br />
byte into $2006 byte into $2006<br />
3) Write lower VRAM address 3) Write lower VRAM address<br />
byte into $2006 byte into $2006<br />
4) Write one or more bytes 4) Read $2007 (invalid data once)<br />
to $2007 5) Read one or more bytes<br />
from $2007<br />
</pre><br />
NOTE: Step #4 when reading VRAM is only necessary when reading VRAM data not in the $3F00-3FFF range.<br />
<br />
NOTE: Accessing VRAM should only be performed during VBlank, or with rendering turned off ($2001 D4-D3 cleared to 0).<br />
Attempts to access VRAM outside of VBlank will usually result in garbage showing up on the screen.<br />
See Section 4, Subsection N for more information regarding why this occurs.<br />
<br />
Waiting for VBlank is quite simple:<br />
<code><br />
8000: LDA $2002<br />
BPL $8000<br />
</code><br />
Reading $2002 will result in all bits being returned; however, D7 will be reset to 0 after the read is performed.<br />
To ensure the PPU is warmed up, this should be done twice before any access to $2003-$2007.<br />
<br />
Waiting for VBlank during a game should be done by waiting for the NMI handler to change a variable:<br />
<code><br />
8000: INC $FF<br />
RTI<br />
<br />
8003: LDA $FF<br />
8004: CMP $FF<br />
BNE $8003<br />
</code><br />
<br />
The actual on-screen palette used by the NES, as stated prior, is not RGB.<br />
However, a near-exact replica can be found in common NES emulators today.<br />
See [[PPU palettes]] to obtain a valid RGB palette.<br />
<br />
You will often encounter a situation where a palette fade or a VRAM update will cause the screen "to be trashed" (squares on the screen, or what seem to be graphical "glitches").<br />
The reason for this is that your code took longer than a VBlank.<br />
When the VBlank ends, the PPU begins to refresh the screen again, taking whatever value is in the internal VRAM address and uses that as the starting base for Name Table #0.<br />
The solution is to fix your code to take no more than 2273 cycles, which is 20 scanlines times 341 pixels per scanline divided by 3 pixels per cycle.<br />
<br />
In addition, after you update video memory through $2006 and $2007, the scroll position becomes corrupt, and the PPU again begins at the internal VRAM address.<br />
To solve this, make sure to reset the scroll position through $2005 and $2000 before the next frame begins.<br />
Such code would be:<br />
<br />
LDA #$00<br />
STA $2005<br />
STA $2005<br />
LDA #$88<br />
STA $2000<br />
<br />
If your game scrolls, use different values for $2005 and for $2000 D1-D0.<br />
<br />
== Emulation ==<br />
<br />
=== General Information ===<br />
<br />
If you're going to be programming an emulator in C or C++, please be familiar with pointers.<br />
Being familiar with pointers will help you out severely when it comes to handling mirroring and VRAM addressing.<br />
For you assembly buffs out there, obviously pointers are nothing more than indirect addressing -- it's easier to change a 32-bit value than to swap in and out an entire 64K of data.<br />
<br />
When SRAM ($6000-7FFF) is disabled, writes to the memory area should be ignored.<br />
Reads will possibly return data previously left on the bus, and therefore when emulated should return the previous bus value.<br />
This will usually (but not always) be the high byte of the address.<br />
See [[Open bus]] for more details.<br />
<br />
RAM-based memory areas ($0000-07FF) should *NOT* be zeroed on RESET; they should be set to some value on power on.<br />
Please make sure that a cold boot and a warm boot do different things.<br />
(Technically, the RAM is not zeroed on power on either: the RAM will slowly dissipate over time when the unit is off.)<br />
<br />
=== CPU Notes ===<br />
The NES uses the NMOS 6502, not a CMOS 6502 or any other variant.<br />
<br />
There are 154 valid opcodes (out of 256 total) on the NES.<br />
Please support the option of trapping opcodes which are bad.<br />
Sometimes a ROM contains bad opcodes, due to dirty connectors on the cartridge during the extraction process (or other reasons).<br />
But other games out there, such as ''Puzznic'' and ''Super Cars'', contain bad opcodes even in a correct dump.<br />
<br />
=== PPU Notes ===<br />
<br />
The formulae to calculate the base address of a Name Table tile number is:<br />
<br />
(TILENUM * 16) + PATTERNTABLE<br />
<br />
Where TILENUM is the tile number in the Name Table, and PATTERNTABLE is the Pattern Table Address defined via register $2000.<br />
<br />
Most emulators do not limit the number of sprites which can be displayed per scanline, while the actual NES will show flicker as a result of more than eight (8).<br />
One supports 15 sprites per line by changing the order of sprite-related Pattern Table fetches during HBlank.<br />
<br />
Emulators should _NOT_ mask out unused bits within registers; doing so may result in a cart not working.<br />
<br />
== Reference Material ==<br />
Many of these no longer exist:<br />
<br />
=== Mailing Lists ===<br />
There is a NES Development Mailing List in existence.<br />
Contact Mark Knibbs for more information.<br />
This list is for anyone who wishes to discuss technical issues about the NES; it is not a list for picking up the latest and greatest information about NES emulators or what not.<br />
<br />
However, most users have since migrated to a phpBB forum at https://forums.nesdev.org/<br />
<br />
=== WWW Sites ===<br />
The following are a list of WWW sites which contain NES-oriented material.<br />
If you encounter errors, bad links, or other anomalies while visiting these sites, contact the site authors/owners, NOT me. Thanks.<br />
<br />
<br />
; https://nesdev.org/<br />
: Contains a verbose amount of documentation regarding anything NES-oriented, including hard-to-find mapper documentation. Seems to be a decent NES information depository.<br />
; http://www.ameth.org/~veilleux/NES_info.html<br />
: Currently only contains hardware-oriented material, such as overviews of cart and unit ASICs, mappers, and MMCs. Many pinout diagrams for mappers and NES units are available here. Also provides documentation on NES repair, modifying your NES to give fake stereo output, applying stereo mixing to your NES, and much much more.<br />
<br />
=== Hardware Information ===<br />
The following security bits may be purchased from MCM Electronics (http://www.mcmelectronics.com/):<br />
<br />
* For NES, Game Boy, Super NES, and Nintendo 64 Game Paks: 22-1145 (3.8mm security bit)<br />
* For NES, Super NES, and Nintendo 64 Control Deck: 22-1150 (4.5mm security bit)<br />
<br />
Other sellers may offer them under the "Line" or "GameBit".<br />
<br />
An alternate method is to cut a notch in a standard flat head screwdriver that grips two of the six indentations on the screw.<br />
<br />
== See also ==<br />
* [[Nestech.txt errata]] - Errata from version 2.00 used to produce this updated document<br />
<br />
== External links ==<br />
*[https://nesdev.org/ndox200.zip Nestech.txt]</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:INES_Mapper_014&diff=13917Talk:INES Mapper 0142017-08-22T11:53:52Z<p>Zepper: </p>
<hr />
<div>: Reportedly the $800s bit should be ORed into the 2s bit to select which CHR register is updated.<br />
<br />
What does that mean? What is a "$800s bit"? [[User:NewRisingSun|NewRisingSun]] ([[User talk:NewRisingSun|talk]]) 01:39, 19 August 2017 (MDT)<br />
: For my best, "$800s" means the binary "1000 0000 0000". Take the "2s" notation for mirroring bit as binary "10" too. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 05:53, 22 August 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10911RAMBO-12017-08-09T18:25:59Z<p>Zepper: /* IRQ timing */ Let's make it official, since the current spec does NOT work well.</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
* ''Rolling Thunder''<br />
* ''Hard Drivin' (prototype)''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000);<br />
||| 1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800);<br />
||| 2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $A000-$BFFF);<br />
||| 7: Select 8 KiB PRG ROM bank at $A000-$BFFF (or $C000-$DFFF);<br />
||| 8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400);<br />
||| 9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00);<br />
||| F: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF);<br />
||+------- Full 1 KiB CHR bank mode (0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF),<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF))<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF uses bank selected with R:6,<br />
| $A000-$BFFF uses bank selected with R:7,<br />
| $C000-$DFFF uses bank selected with R:F;<br />
| 1: $8000-$9FFF uses bank selected with R:F,<br />
| $A000-$BFFF uses bank selected with R:6, -- NOT 7<br />
| $C000-$DFFF uses bank selected with R:7) -- NOT 6<br />
+--------- CHR A12 inversion (0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF,<br />
four 1 KiB banks at $1000-$1FFF;<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF,<br />
four 1 KiB banks at $0000-$0FFF)<br />
<br />
In PRG ROM bank mode 1, the functions of registers 6 and 7 are ''backward'' compared to the corresponding mode of MMC3.<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
== IRQ registers ==<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ acknowledge / enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
== IRQ counter operation ==<br />
There are two IRQ modes: PPU A12 mode (also known as ''scanline mode'') and CPU cycle mode.<br />
<br />
In ''scanline mode'', the counter is clocked using a very similar method to that used by the [[MMC3]] and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In ''CPU cycle mode'', the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever IRQ mode is being used, the counter behaves the following way:<br />
<br />
'''When the IRQ is clocked by ''scanline'' or ''CPU cycle'' modes:'''<br />
* '''IF''' $C001 was written to after previous clock:<br />
** reload IRQ counter with IRQ reload value; if non zero, this value is '''ORed with 1''' (see notes).<br />
* '''ELSE IF''' IRQ counter is 0:<br />
** reload IRQ counter with IRQ reload value.<br />
* '''ELSE'''<br />
** Decrement IRQ counter by 1. <br />
* If IRQ counter is now 0 '''AND''' IRQs are enabled:<br />
** trigger IRQ after 4 CPU cycles.<br />
<br />
'''Notes:''' <br />
* It's still unknown how the extra kick works. ''Klax'' still requires '''+1''' to run perfectly.<br />
* Most emulators run ''Skull & Crossbones'' with a glitched scanline at the continue screen OR during the gameplay (scorebar).<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15606Talk:RAMBO-12017-08-08T15:46:30Z<p>Zepper: /* Alternate IRQ timing */ roll back :(</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is how to get 4 games working: Klax, Skull&Crossbones, Rolling Thunder and Hard Drivin'.<br />
*Address mask: $E001.<br />
<br />
writes to $C000: irq_latch=data;<br />
writes to $C001: irq_reload=true; irq_mode=data&1;<br />
writes to $E000: irq_enable=false; IRQ acknowledge by CPU.<br />
writes to $E001: irq_enable=true; IRQ acknowledge by CPU.<br />
<br />
* When the IRQ is clocked by CPU or scanline modes:<br />
<br />
If irq_reload == true:<br />
irq_counter = irq_latch;<br />
if irq_latch != 0<br />
irq_counter |= 1;<br />
irq_reload=false;<br />
Else if irq_counter == 0:<br />
irq_counter = irq_latch;<br />
Else<br />
irq_counter--;<br />
If irq_counter == 0 and irq_enable == true<br />
irq_delay=4 (IRQ will be fired 4 CPU cycles later)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15605Talk:RAMBO-12017-08-08T02:12:38Z<p>Zepper: /* Alternate IRQ timing */ Minor update, almost perfect!</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is how to get 4 games working: Klax, Skull&Crossbones, Rolling Thunder and Hard Drivin'.<br />
*Address mask: $E001.<br />
<br />
writes to $C000: irq_flags|=2; irq_latch=data;<br />
writes to $C001: irq_flags|=1; irq_mode=data&1;<br />
writes to $E000: irq_enable=false; IRQ acknowledge by CPU.<br />
writes to $E001: irq_enable=true; IRQ acknowledge by CPU.<br />
<br />
* When the IRQ is clocked by CPU or scanline modes:<br />
<br />
If irq_flags&1:<br />
irq_counter = irq_latch;<br />
if irq_latch != 0<br />
{<br />
if irq_flags&2 irq_counter |= 1;<br />
else irq_counter+=1;<br />
}<br />
irq_flags=0;<br />
Else if irq_counter == 0:<br />
irq_counter = irq_latch;<br />
Else<br />
irq_counter--;<br />
If irq_counter == 0 and irq_enable == true<br />
irq_delay=4 (IRQ will be fired 4 CPU cycles later)<br />
<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 20:12, 7 August 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15604Talk:RAMBO-12017-08-07T03:16:37Z<p>Zepper: Deleted obsoleted IRQ speculation.</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is how to get 4 games working: Klax, Skull&Crossbones, Rolling Thunder and Hard Drivin'.<br />
*Address mask: $E001.<br />
<br />
writes to $C000: irq_latch=data;<br />
writes to $C001: irq_reload=true; irq_mode=data&1;<br />
writes to $E000: irq_enable=false; IRQ acknowledge by CPU.<br />
writes to $E001: irq_enable=true; IRQ acknowledge by CPU.<br />
<br />
* When the IRQ is clocked by CPU or scanline modes:<br />
<br />
If irq_reload == true:<br />
irq_counter = irq_latch;<br />
if(irq_latch != 0) irq_counter |= 1;<br />
irq_reload=false;<br />
Else if irq_counter == 0:<br />
irq_counter = irq_latch;<br />
Else<br />
irq_counter--;<br />
If irq_counter == 0 and irq_enable == true<br />
irq_delay=4 (IRQ will be fired 4 CPU cycles later)<br />
<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 21:16, 6 August 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_235&diff=5809INES Mapper 2352017-07-11T13:33:23Z<p>Zepper: Created page with "235 "Golden Game" 150 in 1 Mapper Info ---------------------------------- 10.29.2000 Mapper info by The Mad Dumper Revised, version 2.0 -..."</p>
<hr />
<div>[[Category:iNES Mappers|235]]<br />
"Golden Game" 150 in 1 Mapper Info<br />
----------------------------------<br />
10.29.2000<br />
Mapper info by The Mad Dumper<br />
Revised, version 2.0<br />
---<br />
<br />
This mapper has been assigned the number 235. (that's 235 decimal)<br />
<br />
It is the weirdest multicart I have ever seen. There are only 60 or so<br />
games which can be expected, however there's an integrated "trainer"<br />
setup, some "demos", and other weird crap. The menu screen has Adventure<br />
Island music and graphics. Instead of a PRG ROM, this cart uses a single<br />
8K VRAM and it loads the graphics into RAM before/during gameplay!<br />
All the games have been hacked, so when they wish to switch out CHR ROM,<br />
it will load in a new set of GFX!<br />
<br />
The mapper hardware itself is very simple, only 4 TTL chips. This particular<br />
board has space for 4 ROM chips, however only 2 are filled.<br />
<br />
---<br />
<br />
There is no CHR ROM, there is only 8K VRAM. This particular cart has space<br />
for up to 4Mbytes of ROMs but only 2Mbytes have been stuffed.<br />
<br />
Reads:<br />
8000-BFFF: Lower 16K ROM bank<br />
C000-FFFF: Upper 16K ROM bank <br />
<br />
Writes:<br />
8000-FFFF: Control register (See below)<br />
<br />
---<br />
<br />
How to work it good:<br />
<br />
Like other multicarts, the address written to is used instead of the<br />
actual data written.<br />
<br />
The bits are set up like so:<br />
<br />
(A15) (A0)<br />
1xMP RNBB xxxA AAAA<br />
<br />
A15 must be 1 (obviously)<br />
x = don't care<br />
R = ROM page size (0=16K, 1=32K)<br />
P = ROM page # (0=lower 16K, 1=upper 16K)<br />
M = Mirroring control (0=H 1=V)<br />
N = Mirroring control (0=2 screens 1=1 screen) (see below)<br />
B = ROM # (A8=bit 0, A9=bit 1) (32K pages)<br />
A = Upper ROM address lines (aka 32K pages. A0=bit 0, A1=bit 1, etc.)<br />
<br />
The Mirroring Control bit (N) is sorta cool. It allows one to make<br />
"single screen" games where there is only 1K of nametable RAM, so all<br />
4 quadrants of the scrollable screen are the same thing.<br />
<br />
The B bits are the ROM enable bits. This cart can have up to 4 1Mbyte<br />
ROM chips, however only 2 are used. So the only valid selections are<br />
ROM 0 and ROM 2. (i.e.: 00b = ROM 0, 10b = ROM 1)<br />
<br />
---<br />
<br />
There is no CHR ROM on this board, so no emulation of it is required.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15601Talk:RAMBO-12017-07-08T01:55:59Z<p>Zepper: /* Alternate IRQ timing */ Minor fixes.</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is how to get 3 games working: Klax, Skull&Crossbones and Hard Drivin'.<br />
*Address mask: $E001.<br />
<br />
*Register $C000: IRQ_latch = value AND $FE (last bit is NOT used), IRQ_clear = '''true'''.<br />
*Register $C001: IRQ_mode = value AND $01, IRQ_clear = '''true'''.<br />
*Register $E000: IRQ_enable = '''false''', acknowledges IRQ.<br />
*Register $E001: IRQ_enable = '''true''', acknowledges IRQ.<br />
<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes:'''<br />
*IF IRQ_counter++ == IRQ_latch:<br />
**IF IRQ_enable == true, wait 4 CPU cycles, then trigger an IRQ '''AND''' clear IRQ_counter.<br />
*ELSE IF IRQ_clear == '''true''':<br />
**Clear IRQ_counter and IRQ_clear = '''false'''.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15600Talk:RAMBO-12017-07-07T22:22:19Z<p>Zepper: /* Alternate IRQ timing */ Figured out the IRQ timing!</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is how to get 3 games working: Klax, Skull&Crossbones and Hard Drivin'.<br />
*Address mask: $E001.<br />
<br />
*Register $C000: IRQ_latch = value AND $FE (last bit is NOT used), IRQ_clear = '''true'''.<br />
*Register $C001: IRQ_mode = value AND $01, IRQ_clear = '''true'''.<br />
*Register $E000: IRQ_enable = '''false''', acknowledges IRQ.<br />
*Register $E001: IRQ_enable = '''true''', acknowledges IRQ.<br />
<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes:'''<br />
*If the IRQ counter++ == IRQ latch:<br />
**If IRQ_enabled == true, wait 4 CPU cycles then trigger an IRQ AND clear IRQ_counter.<br />
*ELSE if the IRQ_clear == '''true''':<br />
**''IRQ counter'' is set to zero.<br />
**''IRQ clear flag'' is set to '''false'''.<br />
<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 16:22, 7 July 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15599Talk:RAMBO-12017-07-03T23:22:17Z<p>Zepper: /* Alternate IRQ timing */ Tweaks.</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is an hack to get 3 games working: Klax, Skull&Crossbones and Hard Drivin'.<br />
*Address mask: $E001.<br />
*Writing to the registers $E000 '''or''' $E001 acknowledges the IRQ.<br />
*Register $C001 sets the ''IRQ clear flag'' to '''true''' (it's cleared at the next IRQ clock).<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes:'''<br />
*If the IRQ counter++ == IRQ latch:<br />
**If IRQs are enabled, trigger an IRQ 2 CPU cycles later.<br />
**Set ''IRQ clear flag'' to '''true'''.<br />
*If the ''IRQ clear flag'' is '''true''':<br />
**''IRQ counter'' is set to zero.<br />
**''IRQ clear flag'' is set to '''false'''.<br />
<br />
''Notice!''<br />
*Skull&Crossbones has a glitched scanlined at the top of the scorebar, but NOT on the continue screen. Plus, the bottom line of the scorebar is NOT missing.<br />
*Hard Drivin' works, but the title screen has 2 glitched scanlines.<br />
*Klax is perfect, no problems.<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:12, 3 July 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15598Talk:RAMBO-12017-07-03T23:12:47Z<p>Zepper: /* Alternate IRQ timing */ $E001 also acknowledges the IRQ.</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is an hack to get 3 games working: Klax, Skull&Crossbones and Hard Drivin'.<br />
<br />
Address mask: $E001.<br />
Writing to the registers $E000 '''or''' $E001 acknowledges the IRQ.<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes'''<br />
*If the IRQ counter++ == IRQ latch:<br />
**If IRQs are enabled, trigger an IRQ 2 CPU cycles later.<br />
**Set IRQ reset flag.<br />
*If the IRQ flag is set (including previous $C001 write):<br />
**IRQ counter is set to zero.<br />
**IRQ reset flag is cleared.<br />
<br />
''Notice!''<br />
*Skull&Crossbones has a glitched scanlined at the top of the scorebar, but NOT on the continue screen. Plus, the bottom line of the scorebar is NOT missing.<br />
*Hard Drivin' works, but the title screen has 2 glitched scanlines.<br />
*Klax is perfect, no problems.<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:12, 3 July 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15597Talk:RAMBO-12017-07-03T01:29:59Z<p>Zepper: oops</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== Alternate IRQ timing ==<br />
<br />
This is an hack to get 3 games working: Klax, Skull&Crossbones and Hard Drvin'.<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes'''<br />
*If the IRQ counter++ == IRQ latch:<br />
**If IRQs are enabled, trigger an IRQ 2 CPU cycles later.<br />
**Set IRQ reset flag.<br />
*If the IRQ flag is set (including previous $C001 write):<br />
**IRQ counter is set to zero.<br />
**IRQ reset flag is cleared.<br />
<br />
''Notice!''<br />
*Skull&Crossbones has a glitched scanlined at the top of the scorebar, but NOT on the continue screen. Plus, the bottom line of the scorebar is NOT missing.<br />
*Hard Drivin' works, but the title screen has 2 glitched scanlines. Upon a cruve, it's glitched with line segments.<br />
*Klax is perfect, no problems.<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:29, 2 July 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:RAMBO-1&diff=15596Talk:RAMBO-12017-07-03T01:29:35Z<p>Zepper: /* lternate IRQ timing */ new section</p>
<hr />
<div>As for the 2mb PRG, I'm not sure if the cart actually supports that much ROM, but the PRG registers apparently are 8 bits, and 8kb * $100 = 2048kb = 2mb. --[[User:Drag|Drag]] 03:05, 9 November 2011 (UTC)<br />
<br />
== IRQ related - Hard Drivin' ==<br />
<br />
Suggested changes for the Mapper64 IRQ. It makes Hard Drivin' to work fine. No other games are affected with this change.<br />
Every cycle on 6502 is either a read or a write cycle. So, you update the IRQ counter in the next CPU cycle:<br />
<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE'''<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
When the IRQ is clocked by the mapper (in scanline or cycle mode):<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ<br />
<br />
Hard Drivin' works. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 17:57, 14 January 2014 (MST)<br />
<br />
== lternate IRQ timing ==<br />
<br />
This is an hack to get 3 games working: Klax, Skull&Crossbones and Hard Drvin'.<br />
<br />
'''When the IRQ is clocked by CPU or scanline modes'''<br />
*If the IRQ counter++ == IRQ latch:<br />
**If IRQs are enabled, trigger an IRQ 2 CPU cycles later.<br />
**Set IRQ reset flag.<br />
*If the IRQ flag is set (including previous $C001 write):<br />
**IRQ counter is set to zero.<br />
**IRQ reset flag is cleared.<br />
<br />
''Notice!''<br />
*Skull&Crossbones has a glitched scanlined at the top of the scorebar, but NOT on the continue screen. Plus, the bottom line of the scorebar is NOT missing.<br />
*Hard Drivin' works, but the title screen has 2 glitched scanlines. Upon a cruve, it's glitched with line segments.<br />
*Klax is perfect, no problems.<br />
--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:29, 2 July 2017 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10910RAMBO-12017-06-28T23:07:04Z<p>Zepper: /* IRQ counter operation */ Minor fixes.</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000);<br />
||| 1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800);<br />
||| 2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $A000-$BFFF);<br />
||| 7: Select 8 KiB PRG ROM bank at $A000-$BFFF (or $C000-$DFFF);<br />
||| 8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400);<br />
||| 9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00);<br />
||| F: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF);<br />
||+------- Full 1 KiB CHR bank mode (0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF),<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF))<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF uses bank selected with R:6,<br />
| $A000-$BFFF uses bank selected with R:7,<br />
| $C000-$DFFF uses bank selected with R:F;<br />
| 1: $8000-$9FFF uses bank selected with R:F,<br />
| $A000-$BFFF uses bank selected with R:6, -- NOT 7<br />
| $C000-$DFFF uses bank selected with R:7) -- NOT 6<br />
+--------- CHR A12 inversion (0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF,<br />
four 1 KiB banks at $1000-$1FFF;<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF,<br />
four 1 KiB banks at $0000-$0FFF)<br />
<br />
In PRG ROM bank mode 1, the functions of registers 6 and 7 are ''backward'' compared to the corresponding mode of MMC3.<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts.<br />
<br />
== IRQ counter operation ==<br />
There are two IRQ modes: PPU A12 mode (also known as ''scanline mode'') or CPU cycle mode.<br />
<br />
In ''scanline mode'', the counter is clocked using a very similar method to that used by the [[MMC3]] and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In ''CPU cycle mode'', the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever IRQ mode is being used, the counter behaves the following way:<br />
<br />
'''When the IRQ is clocked by ''scanline'' or ''CPU cycle'' modes:'''<br />
* '''IF''' $C001 was written to after previous clock:<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE''' (see note).<br />
* '''ELSE IF''' IRQ counter is 0:<br />
** reload IRQ counter with IRQ Reload value, but see below.<br />
* '''ELSE'''<br />
** Decrement IRQ counter by 1. If IRQ counter is now 0 '''AND''' IRQs are enabled:<br />
*** wait one M2 cycle, then trigger IRQ.<br />
<br />
'''Notes:''' <br />
* When $C001 is written to, it's unknown as to whether reload+1 is written to the counter, or if the counter just takes an extra clock to start counting.<br />
* The game Hard Drivin' works only if the IRQ counter never stops, even on reloads.<br />
* No emulators are able to get ''Skull & Crossbones'' running without a glitched scanline at the continue screen OR during the gameplay (scorebar).<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10909RAMBO-12017-06-28T23:00:07Z<p>Zepper: /* IRQ counter operation */ Update. A deep test & better info is required.</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000);<br />
||| 1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800);<br />
||| 2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $A000-$BFFF);<br />
||| 7: Select 8 KiB PRG ROM bank at $A000-$BFFF (or $C000-$DFFF);<br />
||| 8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400);<br />
||| 9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00);<br />
||| F: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF);<br />
||+------- Full 1 KiB CHR bank mode (0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF),<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF))<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF uses bank selected with R:6,<br />
| $A000-$BFFF uses bank selected with R:7,<br />
| $C000-$DFFF uses bank selected with R:F;<br />
| 1: $8000-$9FFF uses bank selected with R:F,<br />
| $A000-$BFFF uses bank selected with R:6, -- NOT 7<br />
| $C000-$DFFF uses bank selected with R:7) -- NOT 6<br />
+--------- CHR A12 inversion (0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF,<br />
four 1 KiB banks at $1000-$1FFF;<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF,<br />
four 1 KiB banks at $0000-$0FFF)<br />
<br />
In PRG ROM bank mode 1, the functions of registers 6 and 7 are ''backward'' compared to the corresponding mode of MMC3.<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts.<br />
<br />
== IRQ counter operation ==<br />
The counter can be set to either scanline mode or cpu cycle mode.<br />
<br />
In scanline mode, the counter is clocked using a very similar method to that used by the [[MMC3]], and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In CPU cycle mode, the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever method is being used, the counter behaves the following way:<br />
<br />
'''When the IRQ is clocked by scanline or CPU cycle modes:'''<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE''' (see note)<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value, but see below.<br />
* '''ELSE'''<br />
** Decrement IRQ counter by 1. If IRQ counter is now 0 '''AND''' IRQs are enabled:<br />
*** wait one M2 cycle, then trigger IRQ.<br />
<br />
'''Notes:''' <br />
* When $C001 is written to, it's unknown as to whether reload+1 is written to the counter, or if the counter just takes an extra clock to start counting.<br />
* The game Hard Drvin' works only if the IRQ counter never stops, even on reload.<br />
* No emulators are able to get Skull&Crossbones running without a glitched scanline at the continue screen OR during the gameplay (scorebar).<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10908RAMBO-12017-06-27T02:01:49Z<p>Zepper: /* IRQ counter operation */ it should be "at every CPU cycle", my bad.</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000);<br />
||| 1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800);<br />
||| 2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $A000-$BFFF);<br />
||| 7: Select 8 KiB PRG ROM bank at $A000-$BFFF (or $C000-$DFFF);<br />
||| 8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400);<br />
||| 9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00);<br />
||| F: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF);<br />
||+------- Full 1 KiB CHR bank mode (0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF),<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF))<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF uses bank selected with R:6,<br />
| $A000-$BFFF uses bank selected with R:7,<br />
| $C000-$DFFF uses bank selected with R:F;<br />
| 1: $8000-$9FFF uses bank selected with R:F,<br />
| $A000-$BFFF uses bank selected with R:6, -- NOT 7<br />
| $C000-$DFFF uses bank selected with R:7) -- NOT 6<br />
+--------- CHR A12 inversion (0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF,<br />
four 1 KiB banks at $1000-$1FFF;<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF,<br />
four 1 KiB banks at $0000-$0FFF)<br />
<br />
In PRG ROM bank mode 1, the functions of registers 6 and 7 are ''backward'' compared to the corresponding mode of MMC3.<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts.<br />
<br />
== IRQ counter operation ==<br />
The counter can be set to either scanline mode or cpu cycle mode.<br />
<br />
In scanline mode, the counter is clocked using a very similar method to that used by the [[MMC3]], and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In CPU cycle mode, the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever method is being used, the counter behaves the following way:<br />
<br />
'''At every CPU cycle:'''<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE''' (see note)<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value, but see below.<br />
<br />
'''When the IRQ is clocked by scanline or CPU cycle modes:'''<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ.<br />
<br />
'''Note:''' When $C001 is written to, it's unknown as to whether reload+1 is written to the counter, or if the counter just takes an extra clock to start counting.<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=RAMBO-1&diff=10907RAMBO-12017-06-16T02:03:56Z<p>Zepper: /* IRQ counter operation */ code update</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=RAMBO-1<br />
|company=Tengen<br />
|mapper=64<br />
|othermappers=[[iNES Mapper 158|158]]<br />
|nescartdbgames=5<br />
|complexity=ASIC<br />
|boards=800032<br />
|prgmax=256K<br />
|prgpage=3×8K + 8K fixed<br />
|chrmax=256K<br />
|chrpage=1Kx8 or 2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|64|iNES 064<br />
|unif|TENGEN-800032|800032<br />
}}:''For the mapper used in the game "Rambo", see [[UxROM]].''<br />
[[Category:MMC3-like mappers]][[Category:Mappers with scanline IRQs]][[Category:Mappers with cycle IRQs]]<br />
The '''Tengen RAMBO-1''' is an [[:Category:ASIC mappers|ASIC]] [[MMC|mapper]], canonically designated as '''mapper 64'''. This mapper is basically Tengen's version of the [[MMC3]], but with some extra features. The RAMBO-1 came as a [[Tengen RAMBO-1 pinout|40-pin PDIP]]. A variant with different mirroring control is [[iNES Mapper 158|mapper 158]].<br />
<br />
Example games:<br />
* ''Klax''<br />
* ''Skull and Crossbones''<br />
* ''Shinobi''<br />
<br />
== Banks ==<br />
* CPU $8000-$9FFF: 8 KiB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $C000-$DFFF: 8 KiB switchable PRG ROM bank<br />
* CPU $E000-$FFFF: 8 KiB PRG ROM bank, fixed to the last bank<br />
* PPU -- Three selectable configurations:<br />
*# 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00, $1000, $1400, $1800, $1C00<br />
*# 2 KiB switchable CHR banks at $0000, $0800; 1 KiB switchable CHR banks at $1000, $1400, $1800, $1C00 <br />
*# 2 KiB switchable CHR banks at $1000, $1800; 1 KiB switchable CHR banks at $0000, $0400, $0800, $0C00<br />
<br />
== Registers ==<br />
<br />
The RAMBO-1 has four pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPKx RRRR<br />
||| ||||<br />
||| ++++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0000 (or $1000);<br />
||| 1: Select 2 (K=0) or 1 (K=1) KiB CHR bank at PPU $0800 (or $1800);<br />
||| 2: Select 1 KiB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KiB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KiB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KiB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KiB PRG ROM bank at $8000-$9FFF (or $A000-$BFFF);<br />
||| 7: Select 8 KiB PRG ROM bank at $A000-$BFFF (or $C000-$DFFF);<br />
||| 8: If K=1, Select 1 KiB CHR bank at PPU $0400 (or $1400);<br />
||| 9: If K=1, Select 1 KiB CHR bank at PPU $0C00 (or $1C00);<br />
||| F: Select 8 KiB PRG ROM bank at $C000-$DFFF (or $8000-$9FFF);<br />
||+------- Full 1 KiB CHR bank mode (0: two 2 KiB banks at $0000-$0FFF (or $1000-$1FFF),<br />
|| 1: four 1 KiB banks at $0000-$0FFF (or $1000-$1FFF))<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF uses bank selected with R:6,<br />
| $A000-$BFFF uses bank selected with R:7,<br />
| $C000-$DFFF uses bank selected with R:F;<br />
| 1: $8000-$9FFF uses bank selected with R:F,<br />
| $A000-$BFFF uses bank selected with R:6, -- NOT 7<br />
| $C000-$DFFF uses bank selected with R:7) -- NOT 6<br />
+--------- CHR A12 inversion (0: two 2 KiB banks (or four 1 KiB banks) at $0000-$0FFF,<br />
four 1 KiB banks at $1000-$1FFF;<br />
1: two 2 KiB banks (or four 1 KiB banks) at $1000-$1FFF,<br />
four 1 KiB banks at $0000-$0FFF)<br />
<br />
In PRG ROM bank mode 1, the functions of registers 6 and 7 are ''backward'' compared to the corresponding mode of MMC3.<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
All eight bits are used for a new value for the bank based on last value written to Bank select register (as mentioned above)<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- [[Mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This applies to '''mapper 64''' only (see [[#Variants|Variants]] below).<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
All eight bits of this register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied into the IRQ counter at the end of the current scanline.<br />
<br />
=== IRQ mode select / reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- IRQ mode select (0: Scanline Mode, 1: CPU Cycle Mode)<br />
<br />
Writing to this register also clears the IRQ counter so that it will be reloaded at next clock, or the next scanline, depending on the selected mode. This also resets the prescaler in cycle mode, so the next clock will occur 4 cycles later.<br />
<br />
=== IRQ acknowledge / disable ($E000-$FFFE, even) ===<br />
Writing any value to this register will disable counter interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
Writing any value to this register will enable counter interrupts.<br />
<br />
== IRQ counter operation ==<br />
The counter can be set to either scanline mode or cpu cycle mode.<br />
<br />
In scanline mode, the counter is clocked using a very similar method to that used by the [[MMC3]], and follows the same restrictions. In comparison to the [[MMC3]], the actual interrupt triggers slightly later. Specifically, it is delayed until [http://forums.nesdev.org/viewtopic.php?p=117323#p117323 M2 falls twice after the PPU A12 rise] that would have triggered the MMC3 interrupt.<br />
<br />
In CPU cycle mode, the counter is clocked every 4 CPU cycles. The actual interrupt triggers [http://forums.nesdev.org/viewtopic.php?p=117461#p117461 one M2 cycle later] than one would naively expect.<br />
<br />
Whichever method is being used, the counter behaves the following way:<br />
<br />
'''At the end of the scanline:'''<br />
* '''IF''' $C001 was written to after previous clock<br />
** reload IRQ counter with IRQ Reload value '''PLUS ONE''' (see note)<br />
* '''ELSE IF''' IRQ counter is 0<br />
** reload IRQ counter with IRQ Reload value<br />
<br />
'''When the IRQ is clocked by scanline or CPU cycle modes:'''<br />
** Decrement IRQ counter by 1<br />
** '''IF''' IRQ counter is now 0 '''AND''' IRQs are enabled<br />
*** wait one M2 cycle, then trigger IRQ.<br />
<br />
'''Note:''' When $C001 is written to, it's unknown as to whether reload+1 is written to the counter, or if the counter just takes an extra clock to start counting.<br />
<br />
== Variants ==<br />
[[iNES Mapper 158|Mapper 158]], used for ''Alien Syndrome'', has mirroring like [[iNES Mapper 118|mapper 118]] ([[TLSROM]]), where CIRAM A10 is connected to CHR A17, and bit 7 of each CHR bank mapped into PPU $0000-$0FFF controls which page of CIRAM is used for the corresponding nametable in $2000-$2FFF.<br />
<br />
== See also ==<br />
*[http://www.romhacking.net/documents/362/ NES Mapper List] by Disch<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\, information about mapper's initial state is inaccurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_206&diff=5596INES Mapper 2062017-02-22T00:57:14Z<p>Zepper: /* References */ Link to the FCEUX source code (map206)</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=Namco 118, Tengen MIMIC-1<br />
|name2=DxROM<br />
|company=Namco, Tengen, others<br />
|mapper=206<br />
|othermappers=[[iNES Mapper 076|76]], [[iNES Mapper 088|88]], [[iNES Mapper 154|154]], [[iNES Mapper 095|95]]<br />
|nescartdbgames=39<br />
|boards=34xx, DxROM<br />
|complexity=ASIC<br />
|prgmax=128K<br />
|prgpage=8K + 8K + 16K fixed<br />
|chrmax=64K<br />
|chrpage=2Kx2 + 1Kx4<br />
|mirroring=Fixed H/V, or 4<br />
|busconflicts=No<br />
}}<br />
{{DEFAULTSORT:206}}[[Category:iNES Mappers]][[Category:MMC3-like mappers]][[Category:in NesCartDB]][[Category:Nintendo licensed mappers]]<br />
[[iNES Mapper 206]] is the simpler predecessor of the [[MMC3]], and was used by Tengen and Namco.<br />
Chips used include "Tengen MIMIC-1" and "[[Namcot 108 family pinout|Namcot 118]]", and the boards made by Nintendo of America that used this mapper are NES-[[DxROM]].<br />
Many ROMS using this mapper are incorrectly listed as using MMC3, but will usually work if emulated with MMC3, and the mirroring is correct, as if they were on a [[TxROM|TEROM or TFROM board]].<br />
<br />
Compared to MMC3:<br />
* There are no IRQs<br />
* There is no WRAM support<br />
* PRG always has the last two 8KiB banks fixed to the end.<br />
* CHR always gives the left pattern table (0000-0FFF) the two 2KiB banks, and the right pattern table (1000-1FFF) the four 1KiB banks.<br />
* Mirroring is hardwired, one game uses 4-screen mirroring (Gauntlet, DRROM).<br />
* CHR size limit is 64KiB, PRG size limit is 128KiB.<br />
* There are no control registers in the $A000-$FFFF range.<br />
** Naruko observed a bug where writes to RAM (i.e. $0000-$1FFF) while executing code from $8000-$9FFF will cause erratic mapper writes. It is not known whether all five ICs (108, 109, 118, 119, MIMIC-1) have this same bug.<br />
<br />
Register mask: $E001<br />
* $8000: 00000xxx - Select which internal register gets written by $8001<br />
* $8001: 00xxxxxx - Value written to the internal register. PRG registers use only 4 bits.<br />
<br />
Internal registers:<br />
* 0, 1: 2k CHR banks at 0000, 0800. Least significant bit is ignored.<br />
* 2, 3, 4, 5: 1k CHR banks at 1000, 1400, 1800, 1C00.<br />
* 6, 7: 8k PRG banks at 8000, A000.<br />
<br />
== Warning ==<br />
The game ''Babel no Tou'', on the PCB '''3401''', is the only game with 32 KiB PRG that allows—and uses!—PRG banking. All other games with 32 KiB PRG connect CPU A13 and CPU A14 directly to the PRG ROM, but fortunately they initialize their PRG registers to work on a normal board. Because all six games can be correctly emulated by respecting the PRG banking registers, it seems no submapper needs to be allocated for this variation.<br />
<br />
== Variants ==<br />
[[INES Mapper 076|Mapper 76]] increases CHR to 128KiB by inflating the 1KiB CHR banks to 2KiB and making the originally-2KiB banks inaccessible.<br />
<br />
Mapper [[INES Mapper 088|88]] increases CHR to 128KiB by connecting PPU's A12 line to the CHR ROM's A16 line, making tiles in $0000 and $1000 come from disjoint sections of ROM.<br />
Because an undersize ROM on a mapper 88 board behaves identically to mapper 206, emulators may treat these mapper numbers as synonymous.<br />
<br />
[[INES Mapper 154|Mapper 154]] has the same as mapper 88, plus mapper-controlled one-screen mirroring.<br />
<br />
[[INES Mapper 095|Mapper 95]] uses the MSB to control mirroring by connecting CHR A15 to CIRAM A10, much as CHR A17 controls CIRAM A10 in [[iNES Mapper 118|TxSROM]].<br />
<br />
== References ==<br />
*[https://github.com/asfdfdfd/fceux/blob/master/src/boards/206.cpp FCEUX source code]<br />
*[http://www43.tok2.com/home/cmpslv/ Enri]'s reverse-engineered schematic of PCBs 3407 and 3416: http://www43.tok2.com/home/cmpslv/Famic/Fcmp206.htm<br />
*[http://forums.nesdev.org/viewtopic.php?t=13297 Naruko's forum thread] about mapper register range</div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_registers&diff=10127PPU registers2017-02-02T12:40:22Z<p>Zepper: /* Color Control */ Updated table.</p>
<hr />
<div>The PPU exposes eight memory-mapped registers to the CPU. These nominally sit at $2000 through $2007 in the CPU's address space, but because they're incompletely decoded, they're [[Mirroring|mirrored]] in every 8 bytes from $2008 through $3FFF, so a write to $3456 is the same as a write to $2006.<br />
<br />
Immediately after powerup, the PPU isn't necessarily in a usable state.<br />
The program needs to do a few things to get it going; see [[PPU power up state]] and [[Init code]]. <br />
<br />
<noinclude><br />
__TOC__<br />
</noinclude><br />
<br />
== Summary ==<br />
<br />
{| class="tabular"<br />
! Common Name<br />
! Address<br />
! Bits<br />
! Notes<br />
|-<br />
! [[#PPUCTRL|PPUCTRL]]<br />
! $2000<br />
| <tt style="white-space: nowrap">VPHB SINN</tt> || NMI enable (V), PPU master/slave (P), sprite height (H), background tile select (B), sprite tile select (S), increment mode (I), nametable select (NN)<br />
|-<br />
! [[#PPUMASK|PPUMASK]]<br />
! $2001<br />
| <tt style="white-space: nowrap">BGRs bMmG</tt> || color emphasis (BGR), sprite enable (s), background enable (b), sprite left column enable (M), background left column enable (m), greyscale (G)<br />
|-<br />
! [[#PPUSTATUS|PPUSTATUS]]<br />
! $2002<br />
| <tt style="white-space: nowrap">VSO- ----</tt> || vblank (V), sprite 0 hit (S), sprite overflow (O), read resets write pair for $2005/2006<br />
|-<br />
! [[#OAMADDR|OAMADDR]]<br />
! $2003<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM read/write address<br />
|-<br />
! [[#OAMDATA|OAMDATA]]<br />
! $2004<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || OAM data read/write<br />
|-<br />
! [[#PPUSCROLL|PPUSCROLL]]<br />
! $2005<br />
| <tt style="white-space: nowrap">xxxx xxxx</tt> || fine scroll position (two writes: X, Y)<br />
|-<br />
! [[#PPUADDR|PPUADDR]]<br />
! $2006<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || PPU read/write address (two writes: MSB, LSB)<br />
|-<br />
! [[#PPUDATA|PPUDATA]]<br />
! $2007<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || PPU data read/write<br />
|-<br />
! [[#OAMDMA|OAMDMA]]<br />
! $4014<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM DMA high address<br />
|}<br />
<br />
== Ports ==<br />
<br />
The PPU has an internal data bus that it uses for communication with the CPU.<br />
This bus, called <code>_io_db</code> in [[Visual 2C02]] and <code>PPUGenLatch</code> in FCEUX,<ref>[http://sourceforge.net/p/fceultra/code/HEAD/tree/fceu/trunk/src/ppu.cpp#l183 ppu.cpp] by Bero and Xodnizel</ref> behaves as an 8-bit dynamic latch due to capacitance of very long traces that run to various parts of the PPU.<br />
Writing any value to any PPU port, even to the nominally read-only PPUSTATUS, will fill this latch.<br />
Reading any readable port (PPUSTATUS, OAMDATA, or PPUDATA) also fills the latch with the bits read.<br />
Reading a nominally "write-only" register returns the latch's current value, as do the unused bits of PPUSTATUS.<br />
This value begins to decay after a frame or so, faster once the PPU has warmed up, and it is likely that values with alternating bit patterns (such as $55 or $AA) will decay faster.<ref>[http://forums.nesdev.org/viewtopic.php?p=143801#p143801 Reply to "Riding the open bus"] by lidnariq</ref><br />
<br />
=== <span id="PPUCTRL"><span id="Reg2000">Controller ($2000) > write</span></span> === <br />
<br />
* Common name: '''PPUCTRL'''<br />
* Description: PPU control register<br />
* Access: write<br />
<br />
Various flags controlling PPU operation<br />
7 bit 0<br />
---- ----<br />
VPHB SINN<br />
|||| ||||<br />
|||| ||++- Base nametable address<br />
|||| || (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)<br />
|||| |+--- VRAM address increment per CPU read/write of PPUDATA<br />
|||| | (0: add 1, going across; 1: add 32, going down)<br />
|||| +---- Sprite pattern table address for 8x8 sprites<br />
|||| (0: $0000; 1: $1000; ignored in 8x16 mode)<br />
|||+------ Background pattern table address (0: $0000; 1: $1000)<br />
||+------- Sprite size (0: 8x8; 1: 8x16)<br />
|+-------- PPU master/slave select<br />
| (0: read backdrop from EXT pins; 1: output color on EXT pins)<br />
+--------- Generate an [[NMI]] at the start of the<br />
[[wikipedia:Vertical blanking interval|vertical blanking interval]] (0: off; 1: on)<br />
<br />
Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates (see [[PPU_nametables|Nametables]] and [[#PPUSCROLL|PPUSCROLL]]):<br />
7 bit 0<br />
---- ----<br />
.... ..YX<br />
||<br />
|+- 1: Add 256 to the X scroll position<br />
+-- 1: Add 240 to the Y scroll position<br />
<br />
Another way of seeing the explanation above is that when you reach the end of a nametable, you must switch to the next one, hence, changing the nametable address.<br />
<br />
[[PPU power up state|After power/reset]], writes to this register are ignored for about 30000 cycles.<br />
<br />
When turning on the NMI flag in bit 7, if the PPU is currently in vertical blank and the [[#PPUSTATUS|PPUSTATUS]] ($2002) vblank flag is set, an NMI will be generated immediately.<br />
This can result in graphical errors (most likely a misplaced scroll) if the NMI routine is executed too late in the blanking period to finish on time.<br />
To avoid this problem it is prudent to read $2002 immediately before writing $2000 to clear the vblank flag.<br />
<br />
==== Master/slave mode and the EXT pins ====<br />
When bit 6 of PPUCTRL is clear (the usual case), the PPU gets the [[PPU_palettes|palette index]] for the background color from the EXT pins. The stock NES grounds these pins, making palette index 0 the background color as expected. A secondary picture generator connected to the EXT pins would be able to replace the background with a different image using colors from the background palette, which could be used e.g. to implement parallax scrolling.<br />
<br />
Setting bit 6 causes the PPU to output the lower four bits of the palette memory index on the EXT pins for each pixel (in addition to normal image drawing) - since only four bits are output, background and sprite pixels can't normally be distinguished this way. As the EXT pins are grounded on an unmodified NES, setting bit 6 is discouraged as it could potentially damage the chip whenever it outputs a non-zero pixel value (due to it effectively shorting Vcc and GND together). Looking at the relevant circuitry in [[Visual 2C02]], it appears that the [[PPU palettes|background palette hack]] would not be functional for output from the EXT pins; they would always output index 0 for the background color.<br />
<br />
==== Bit 0 bus conflict ====<br />
Be very careful when writing to this register outside vertical blanking if you are using vertical mirroring (horizontal arrangement) or 4-screen VRAM.<br />
For specific CPU-PPU alignments, [http://forums.nesdev.org/viewtopic.php?p=112424#p112424 a write near the end of a visible scanline] may cause only the next scanline to be erroneously drawn from the left nametable.<br />
This can cause a visible glitch.<br />
Worse, it can theoretically cause a sprite 0 hit to fail, which may crash a game using a sprite 0 spin loop that's not resilient.<br />
<br />
Only writes at the exact moment between active picture and horizontal blanking cause this glitch; well-timed mid-scanline writes do not, nor do writes that land well within horizontal blanking.<br />
The glitch has no effect in horizontal or one-screen mirroring.<br />
It also does not appear if bit 0 of the written value is 0; this always correctly sets the left nametable.<br />
<br />
This produces an occasionally [[Game bugs|visible glitch]] in ''Super Mario Bros.'' when the program writes to PPUCTRL at the end of game logic.<br />
It appears to be turning NMI off during game logic and then turning NMI back on once the game logic has finished in order to prevent the NMI handler from being called again before the game logic finishes.<br />
To work around this in new productions, have your game logic set a flag that your NMI handler checks.<br />
<br />
=== <span id="PPUMASK"><span id="Reg2001">Mask ($2001) > write</span></span> ===<br />
<br />
* Common name: '''PPUMASK'''<br />
* Description: PPU mask register<br />
* Access: write<br />
<br />
This register controls the rendering of sprites and backgrounds, as well as colour effects.<br />
<br />
7 bit 0<br />
---- ----<br />
BGRs bMmG<br />
|||| ||||<br />
|||| |||+- Greyscale (0: normal color, 1: produce a greyscale display)<br />
|||| ||+-- 1: Show background in leftmost 8 pixels of screen, 0: Hide<br />
|||| |+--- 1: Show sprites in leftmost 8 pixels of screen, 0: Hide<br />
|||| +---- 1: Show background<br />
|||+------ 1: Show sprites<br />
||+------- Emphasize red*<br />
|+-------- Emphasize green*<br />
+--------- Emphasize blue*<br />
<br />
<nowiki>*</nowiki> NTSC colors. PAL and Dendy swaps green and red<ref>PAL PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=131889#p13188</ref><ref>Dendy PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=155513#p155513</ref>.<br />
<br />
==== Render Control ====<br />
<br />
* Bits 3 and 4 enable the rendering of background and sprites, respectively.<br />
<br />
* Bits 1 and 2 enable rendering of the background and sprites in the leftmost 8 pixel columns. Setting these bits to 0 will mask these columns, which is often useful in horizontal scrolling situations where you want partial sprites or tiles to scroll in from the left.<br />
<br />
* A value of $1E enables all rendering, with no color effects. A value of $00 disables all rendering. It is usually best practice to write this register only during vblank, to prevent partial-frame visual artifacts.<br />
<br />
* If either of bits 3 or 4 is enabled, at any time outside of the vblank interval the PPU will be making continual use to the PPU address and data bus to fetch tiles to render, as well as internally fetching sprite data from the OAM. If you wish to make changes to PPU memory outside of vblank (via '''$2007'''), you must set ''both'' of these bits to 0 to disable rendering and prevent conflicts.<br />
<br />
* Disabling rendering (clear both bits 3 and 4) during a visible part of the frame can be problematic. It can cause a corruption of the sprite state, which will display incorrect sprite data on the next frame. (See: [[Errata]]) It is, however, perfectly fine to mask sprites but leave the background on (set bit 3, clear bit 4) at any time in the frame.<br />
<br />
* Sprite 0 hit does not trigger in any area where the background or sprites are hidden.<br />
<br />
==== Color Control ====<br />
<br />
* Bit 0 controls a greyscale mode, which causes the palette to use only the colors from the grey column: $00, $10, $20, $30. This is implemented as a bitwise AND with $30 on any value read from PPU $3F00-$3FFF, both on the display and through [[#PPUDATA|PPUDATA]]. Writes to the palette through [[#PPUDATA|PPUDATA]] are not affected. Also note that black colours like $0F will be replaced by a non-black grey $00.<br />
<br />
* Bits 5,6,7 control a color "emphasis" or "tint" effect. Each bit emphasizes 1 color while darkening the other two. Setting all three emphasis bits will darken all colors.<br />
** Bit 5 emphasizes red on the NTSC PPU, and green on the PAL & Dendy PPUs.<br />
** Bit 6 emphasizes green on the NTSC PPU, and red on the PAL & Dendy PPUs.<br />
** Bit 7 emphasizes blue on the NTSC, PAL, & Dendy PPUs.<br />
** See [[NTSC video]] for a description of how bits 5-7 work on NTSC and PAL PPUs.<br />
** The [[Vs. System|RGB PPU]] used by PlayChoice and some other systems treat the emphasis bits differently. Instead of darkening other RGB components, it forces one component to maximum brightness. [[Colour-emphasis games|A few games]], which set all three tint bits to darken all colors, are unplayable on these PPUs.<br />
<br />
* The emphasis bits are applied independently of greyscale, so they will still tint the color of the grey image.<br />
<br />
* For a RGB color space, these values are used to create the color emphasis effect. Note that emphasis red+green becomes yellow, and so on.<br />
<br />
$2001:$E0 %Red %Green %Blue<br />
000 Black 1.00 1.00 1.00<br />
001 Red 1.00 0.85 0.85<br />
010 Green 0.85 1.00 0.85<br />
011 Yellow 0.85 0.85 0.70<br />
100 Blue 0.85 0.85 1.00<br />
101 Magenta 0.85 0.70 0.85<br />
110 Cyan 0.70 0.85 0.85<br />
111 White 0.70 0.70 0.70<br />
<br />
=== <span id="PPUSTATUS"><span id="Reg2002">Status ($2002) < read</span></span> ===<br />
<br />
* Common name: '''PPUSTATUS'''<br />
* Description: PPU status register<br />
* Access: read<br />
<br />
This register reflects the state of various functions inside the PPU.<br />
It is often used for determining timing.<br />
<span id="Sprite_0">To determine when the PPU has reached a given pixel of the screen, put an opaque pixel of sprite 0 there.</span><br />
<br />
7 bit 0<br />
---- ----<br />
VSO. ....<br />
|||| ||||<br />
|||+-++++- Least significant bits previously written into a PPU register<br />
||| (due to register not being updated for this address)<br />
||+------- Sprite overflow. The intent was for this flag to be set<br />
|| whenever more than eight sprites appear on a scanline, but a<br />
|| hardware bug causes the actual behavior to be more complicated<br />
|| and generate false positives as well as false negatives; see<br />
|| [[PPU sprite evaluation]]. This flag is set during sprite<br />
|| evaluation and cleared at dot 1 (the second dot) of the<br />
|| pre-render line.<br />
|+-------- Sprite 0 Hit. Set when a nonzero pixel of sprite 0 overlaps<br />
| a nonzero background pixel; cleared at dot 1 of the pre-render<br />
| line. Used for raster timing.<br />
+--------- Vertical blank has started (0: not in vblank; 1: in vblank).<br />
Set at dot 1 of line 241 (the line *after* the post-render<br />
line); cleared after reading $2002 and at dot 1 of the<br />
pre-render line.<br />
<br />
==== Notes ====<br />
* Reading the status register will clear D7 mentioned above and also the address latch used by [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]]. It does not clear the sprite 0 hit or overflow bit.<br />
* Once the sprite 0 hit flag is set, it will not be cleared until the end of the next vertical blank. If attempting to use this flag for raster timing, it is important to ensure that the sprite 0 hit check happens outside of vertical blank, otherwise the CPU will "leak" through and the check will fail. The easiest way to do this is to place an earlier check for D6 = 0, which will wait for the pre-render scanline to begin.<br />
* If using sprite 0 hit to make a bottom scroll bar below a vertically scrolling or freely scrolling playfield, be careful to ensure that the tile in the playfield behind sprite 0 is opaque.<br />
* Sprite 0 hit is not detected at x=255, nor is it detected at x=0 through 7 if the background or sprites are hidden in this area.<br />
* See: [[PPU rendering]] for more information on the timing of setting and clearing the flags.<br />
* Some [[Vs. System]] PPUs return a constant value in D4-D0 that the game checks.<br />
* '''Caution:''' Reading PPUSTATUS at the exact start of vertical blank will return 0 in bit 7 but clear the latch anyway, causing the program to miss frames. See [[NMI]] for details.<br />
<br />
=== <span id="OAMADDR"><span id="Reg2003">OAM address ($2003) > write</span></span> === <br />
<br />
* Common name: '''OAMADDR'''<br />
* Description: OAM address port<br />
* Access: write<br />
<br />
Write the address of [[PPU OAM|OAM]] you want to access here. Most games just write $00 here and then use [[#OAMDMA|OAMDMA]]. (DMA is implemented in the 2A03/7 chip and works by repeatedly writing to [[#OAMDATA|OAMDATA]])<br />
<br />
==== Values during rendering ====<br />
<br />
OAMADDR is set to 0 during each of ticks 257-320 (the sprite tile loading interval) of the pre-render and visible scanlines.<br />
<br />
The value of OAMADDR when sprite evaluation starts at tick 65 of the visible scanlines will determine where in OAM sprite evaluation starts, and hence which sprite gets treated as sprite 0. The first OAM entry to be checked during sprite evaluation is the one starting at <tt>OAM[OAMADDR]</tt>. If OAMADDR is unaligned and does not point to the y position (first byte) of an OAM entry, then whatever it points to (tile index, attribute, or x coordinate) will be reinterpreted as a y position, and the following bytes will be similarly reinterpreted. No more sprites will be found once the end of OAM is reached, effectively hiding any sprites before <tt>OAM[OAMADDR]</tt>.<br />
<br />
==== OAMADDR precautions ====<br />
<br />
On the 2C02, writes to OAMADDR reliably corrupt OAM<!--, copying a pair of sprites from the old address value to the open-bus address high-byte of the OAMADDR write-->.<ref name = "OAMglitch">Manual OAM write glitchyness: http://forums.nesdev.org/viewtopic.php?f=2&t=10189</ref> This can then be worked around by writing all 256 bytes of OAM.<br />
<br />
It is also the case that if OAMADDR is not less than eight when rendering starts, the eight bytes starting at <tt>OAMADDR & 0xF8</tt> are copied to the first eight bytes of OAM; it seems likely that this is related. The former bug is known to have been fixed in the 2C07; the latter is suspected to be. On the Dendy, the latter bug is required for 2C02 compatibility.<br />
<br />
=== <span id="OAMDATA"><span id="Reg2004">OAM data ($2004) <> read/write</span></span> ===<br />
<br />
* Common name: '''OAMDATA'''<br />
* Description: OAM data port<br />
* Access: read, write<br />
<br />
Write OAM data here. Writes will increment [[#OAMADDR|OAMADDR]] after the write; reads during vertical or forced blanking return the value from OAM at that address but do not increment.<br />
<br />
Because changes to OAM should normally be made only during vblank, writing through OAMDATA is only effective for partial updates (it is too slow). Most games will use the DMA feature through [[#OAMDMA|OAMDMA]] instead.<br />
<br />
* Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this.<br />
<br />
* Writes to OAMDATA during rendering (on the pre-render line and the visible lines 0-239, provided either sprite or background rendering is enabled) do not modify values in OAM, but do perform a glitchy increment of [[#OAMADDR|OAMADDR]], bumping only the high 6 bits (i.e., it bumps the ''[n]'' value in [[PPU sprite evaluation]] - it's plausible that it could bump the low bits instead depending on the current status of sprite evaluation). This extends to DMA transfers via [[#OAMDMA|OAMDMA]], since that uses writes to $2004. For emulation purposes, it is probably best to completely ignore writes during rendering.<br />
<br />
* It used to be thought that reading from this register wasn't reliable<ref>$2004 reading reliable? http://forums.nesdev.org/viewtopic.php?f=2&t=6424</ref>, however more recent evidence seems to suggest that this is solely due to corruption by [[#OAMADDR|OAMADDR]] writes.<br />
<br />
* In the oldest instantiations of the PPU, as found on earlier Famicoms and NESes, this register is not readable<ref>$2003 not readable on early revisions: http://forums.nesdev.org/viewtopic.php?p=62137#p62137</ref>. The readability was added on the RP2C02G, found on most NESes and later Famicoms.<ref>hardware revisions and $2003 reads: http://forums.nesdev.org/viewtopic.php?f=2&t=12958&start=45#p150926</ref><br />
<br />
* In the 2C07, sprite evaluation can ''never'' be fully disabled, and will always start 20 scanlines after the start of vblank<ref>2C07 PPU sprite evaluation notes: http://forums.nesdev.org/viewtopic.php?f=9&t=11041</ref> (same as when the prerender scanline would have been on the 2C02). As such, you must upload anything to OAM that you intend to within the first 20 scanlines after the 2C07 signals vertical blanking.<br />
<br />
=== <span id="PPUSCROLL"><span id="Reg2005">Scroll ($2005) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUSCROLL'''<br />
* Description: PPU scrolling position register<br />
* Access: write twice<br />
<br />
This register is used to change the [[PPU scrolling|scroll position]], that is, to tell the PPU which pixel of the nametable selected through [[#PPUCTRL|PPUCTRL]] should be at the top left corner of the rendered screen. Typically, this register is written to during vertical blanking, so that the next frame starts rendering from the desired location, but it can also be modified during rendering in order to split the screen. Changes made to the vertical scroll during rendering will only take effect on the next frame.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the horizontal and vertical scroll offsets here just before turning on the screen:<br />
<br />
bit PPUSTATUS<br />
; possibly other code goes here<br />
lda cam_position_x<br />
sta PPUSCROLL<br />
lda cam_position_y<br />
sta PPUSCROLL<br />
<br />
Horizontal offsets range from 0 to 255. "Normal" vertical offsets range from 0 to 239, while values of 240 to 255 are treated as -16 through -1 in a way, but tile data is incorrectly fetched from the attribute table.<br />
<br />
By changing the values here across several frames and writing tiles to newly revealed areas of the nametables, one can achieve the effect of a camera panning over a large background.<br />
<br />
=== <span id="PPUADDR"><span id="Reg2006">Address ($2006) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUADDR'''<br />
* Description: PPU address register<br />
* Access: write twice<br />
<br />
Because the CPU and the PPU are on separate buses, neither has direct access to the other's memory.<br />
The CPU writes to VRAM through a pair of registers on the PPU.<br />
First it loads an address into [[#PPUADDR|PPUADDR]], and then it writes repeatedly to [[#PPUDATA|PPUDATA]] to fill VRAM.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the 16-bit address of VRAM you want to access here, upper byte first.<br />
For example, to set the VRAM address to $2108:<br />
<br />
lda #$21<br />
sta PPUADDR<br />
lda #$08<br />
sta PPUADDR<br />
<br />
Valid addresses are $0000-$3FFF; higher addresses will be [[mirroring|mirrored]] down.<br />
<br />
==== note ====<br />
Access to [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]] during screen refresh produces interesting raster effects; the starting position of each scanline can be set to any pixel position in nametable memory. For more information, see [[PPU scrolling]] and tokumaru's sample code on the BBS.<ref>PPU synchronization from NMI: http://forums.nesdev.org/viewtopic.php?p=64111#p64111</ref><br />
<br />
''' Editor's note:''' Last comment about external page should be re-directed to the getting started section instead.<br />
<br />
=== <span id="PPUDATA"><span id="Reg2007">Data ($2007) <> read/write</span></span> ===<br />
<br />
* Common name: '''PPUDATA'''<br />
* Description: PPU data port<br />
* Access: read, write<br />
<br />
VRAM read/write data register. After access, the video memory address will increment by an amount determined by $2000:2.<br />
<br />
When the screen is turned off by disabling the background/sprite rendering flag with the [[#PPUMASK|PPUMASK]] or during vertical blank, you can read or write data from VRAM through this port. Since accessing this register increments the VRAM address, it should not be accessed outside vertical or forced blanking because it will cause graphical glitches, and if writing, write to an unpredictable address in VRAM. However, two games are known to [[Reading 2007 during rendering|read from PPUDATA during rendering]]: see [[Tricky-to-emulate games]].<br />
<br />
VRAM reading and writing shares the same internal address register that rendering uses. So after loading data into video memory, the program should reload the scroll position afterwards with [[#PPUSCROLL|PPUSCROLL]] writes in order to avoid wrong scrolling.<br />
<br />
==== The PPUDATA read buffer (post-fetch) ====<br />
<br />
When reading while the VRAM address is in the range 0-$3EFF (i.e., before the palettes), the read will return the contents of an internal read buffer. This internal buffer is updated '''only''' when reading [[#PPUDATA|PPUDATA]], and so is preserved across frames. After the CPU reads and gets the contents of the internal buffer, the PPU will immediately update the internal buffer with the byte at the current VRAM address. Thus, after setting the VRAM address, one should first read this register and discard the result.<br />
<br />
Reading palette data from $3F00-$3FFF works differently. The palette data is placed immediately on the data bus, and hence no dummy read is required. Reading the palettes still updates the internal buffer though, but the data placed in it is the mirrored nametable data that would appear "underneath" the palette. (Checking the [[PPU memory map]] should make this clearer.)<br />
<br />
=== <span id="Reg4014"><span id="OAMDMA">OAM DMA ($4014) > write</span></span> ===<br />
<br />
* Common name: '''OAMDMA'''<br />
* Description: OAM DMA register (high byte)<br />
* Access: write<br />
<br />
This port is located on the CPU. Writing $XX will upload 256 bytes of data from CPU page $XX00-$XXFF to the internal PPU OAM. This page is typically located in internal RAM, commonly $0200-$02FF, but cartridge RAM or ROM can be used as well.<br />
<br />
* The CPU is suspended during the transfer, which will take 513 or 514 cycles after the $4014 write tick. (1 dummy read cycle while waiting for writes to complete, +1 if on an odd CPU cycle, then 256 alternating read/write cycles.)<br />
<br />
* The OAM DMA is the only effective method for initializing all 256 bytes of OAM. Because of the decay of OAM's dynamic RAM when rendering is disabled, the initialization should take place within vblank. Writes through [[#OAMDATA|OAMDATA]] are generally too slow for this task.<br />
<br />
* The DMA transfer will begin at the current OAM write address. It is common practice to initialize it to 0 with a write to [[#OAMADDR|OAMADDR]] before the DMA transfer. Different starting addresses can be used for a simple OAM cycling technique, to alleviate sprite priority conflicts by flickering. If using this technique, after the DMA [[#OAMADDR|OAMADDR]] should be set to 0 before the end of vblank to prevent potential OAM corruption (See: [[Errata]]). However, due to OAMADDR writes also having a "corruption" effect<ref name = "OAMglitch" /> this technique is not recommended.<br />
<br />
== References ==<br />
<references /></div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_registers&diff=10126PPU registers2017-01-22T03:18:29Z<p>Zepper: /* Color Control */ typo</p>
<hr />
<div>The PPU exposes eight memory-mapped registers to the CPU. These nominally sit at $2000 through $2007 in the CPU's address space, but because they're incompletely decoded, they're [[Mirroring|mirrored]] in every 8 bytes from $2008 through $3FFF, so a write to $3456 is the same as a write to $2006.<br />
<br />
Immediately after powerup, the PPU isn't necessarily in a usable state.<br />
The program needs to do a few things to get it going; see [[PPU power up state]] and [[Init code]]. <br />
<br />
<noinclude><br />
__TOC__<br />
</noinclude><br />
<br />
== Summary ==<br />
<br />
{| class="tabular"<br />
! Common Name<br />
! Address<br />
! Bits<br />
! Notes<br />
|-<br />
! [[#PPUCTRL|PPUCTRL]]<br />
! $2000<br />
| <tt style="white-space: nowrap">VPHB SINN</tt> || NMI enable (V), PPU master/slave (P), sprite height (H), background tile select (B), sprite tile select (S), increment mode (I), nametable select (NN)<br />
|-<br />
! [[#PPUMASK|PPUMASK]]<br />
! $2001<br />
| <tt style="white-space: nowrap">BGRs bMmG</tt> || color emphasis (BGR), sprite enable (s), background enable (b), sprite left column enable (M), background left column enable (m), greyscale (G)<br />
|-<br />
! [[#PPUSTATUS|PPUSTATUS]]<br />
! $2002<br />
| <tt style="white-space: nowrap">VSO- ----</tt> || vblank (V), sprite 0 hit (S), sprite overflow (O), read resets write pair for $2005/2006<br />
|-<br />
! [[#OAMADDR|OAMADDR]]<br />
! $2003<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM read/write address<br />
|-<br />
! [[#OAMDATA|OAMDATA]]<br />
! $2004<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || OAM data read/write<br />
|-<br />
! [[#PPUSCROLL|PPUSCROLL]]<br />
! $2005<br />
| <tt style="white-space: nowrap">xxxx xxxx</tt> || fine scroll position (two writes: X, Y)<br />
|-<br />
! [[#PPUADDR|PPUADDR]]<br />
! $2006<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || PPU read/write address (two writes: MSB, LSB)<br />
|-<br />
! [[#PPUDATA|PPUDATA]]<br />
! $2007<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || PPU data read/write<br />
|-<br />
! [[#OAMDMA|OAMDMA]]<br />
! $4014<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM DMA high address<br />
|}<br />
<br />
== Ports ==<br />
<br />
The PPU has an internal data bus that it uses for communication with the CPU.<br />
This bus, called <code>_io_db</code> in [[Visual 2C02]] and <code>PPUGenLatch</code> in FCEUX,<ref>[http://sourceforge.net/p/fceultra/code/HEAD/tree/fceu/trunk/src/ppu.cpp#l183 ppu.cpp] by Bero and Xodnizel</ref> behaves as an 8-bit dynamic latch due to capacitance of very long traces that run to various parts of the PPU.<br />
Writing any value to any PPU port, even to the nominally read-only PPUSTATUS, will fill this latch.<br />
Reading any readable port (PPUSTATUS, OAMDATA, or PPUDATA) also fills the latch with the bits read.<br />
Reading a nominally "write-only" register returns the latch's current value, as do the unused bits of PPUSTATUS.<br />
This value begins to decay after a frame or so, faster once the PPU has warmed up, and it is likely that values with alternating bit patterns (such as $55 or $AA) will decay faster.<ref>[http://forums.nesdev.org/viewtopic.php?p=143801#p143801 Reply to "Riding the open bus"] by lidnariq</ref><br />
<br />
=== <span id="PPUCTRL"><span id="Reg2000">Controller ($2000) > write</span></span> === <br />
<br />
* Common name: '''PPUCTRL'''<br />
* Description: PPU control register<br />
* Access: write<br />
<br />
Various flags controlling PPU operation<br />
7 bit 0<br />
---- ----<br />
VPHB SINN<br />
|||| ||||<br />
|||| ||++- Base nametable address<br />
|||| || (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)<br />
|||| |+--- VRAM address increment per CPU read/write of PPUDATA<br />
|||| | (0: add 1, going across; 1: add 32, going down)<br />
|||| +---- Sprite pattern table address for 8x8 sprites<br />
|||| (0: $0000; 1: $1000; ignored in 8x16 mode)<br />
|||+------ Background pattern table address (0: $0000; 1: $1000)<br />
||+------- Sprite size (0: 8x8; 1: 8x16)<br />
|+-------- PPU master/slave select<br />
| (0: read backdrop from EXT pins; 1: output color on EXT pins)<br />
+--------- Generate an [[NMI]] at the start of the<br />
[[wikipedia:Vertical blanking interval|vertical blanking interval]] (0: off; 1: on)<br />
<br />
Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates (see [[PPU_nametables|Nametables]] and [[#PPUSCROLL|PPUSCROLL]]):<br />
7 bit 0<br />
---- ----<br />
.... ..YX<br />
||<br />
|+- 1: Add 256 to the X scroll position<br />
+-- 1: Add 240 to the Y scroll position<br />
<br />
Another way of seeing the explanation above is that when you reach the end of a nametable, you must switch to the next one, hence, changing the nametable address.<br />
<br />
[[PPU power up state|After power/reset]], writes to this register are ignored for about 30000 cycles.<br />
<br />
When turning on the NMI flag in bit 7, if the PPU is currently in vertical blank and the [[#PPUSTATUS|PPUSTATUS]] ($2002) vblank flag is set, an NMI will be generated immediately.<br />
This can result in graphical errors (most likely a misplaced scroll) if the NMI routine is executed too late in the blanking period to finish on time.<br />
To avoid this problem it is prudent to read $2002 immediately before writing $2000 to clear the vblank flag.<br />
<br />
==== Master/slave mode and the EXT pins ====<br />
When bit 6 of PPUCTRL is clear (the usual case), the PPU gets the [[PPU_palettes|palette index]] for the background color from the EXT pins. The stock NES grounds these pins, making palette index 0 the background color as expected. A secondary picture generator connected to the EXT pins would be able to replace the background with a different image using colors from the background palette, which could be used e.g. to implement parallax scrolling.<br />
<br />
Setting bit 6 causes the PPU to output the lower four bits of the palette memory index on the EXT pins for each pixel (in addition to normal image drawing) - since only four bits are output, background and sprite pixels can't normally be distinguished this way. As the EXT pins are grounded on an unmodified NES, setting bit 6 is discouraged as it could potentially damage the chip whenever it outputs a non-zero pixel value (due to it effectively shorting Vcc and GND together). Looking at the relevant circuitry in [[Visual 2C02]], it appears that the [[PPU palettes|background palette hack]] would not be functional for output from the EXT pins; they would always output index 0 for the background color.<br />
<br />
==== Bit 0 bus conflict ====<br />
Be very careful when writing to this register outside vertical blanking if you are using vertical mirroring (horizontal arrangement) or 4-screen VRAM.<br />
For specific CPU-PPU alignments, [http://forums.nesdev.org/viewtopic.php?p=112424#p112424 a write near the end of a visible scanline] may cause only the next scanline to be erroneously drawn from the left nametable.<br />
This can cause a visible glitch.<br />
Worse, it can theoretically cause a sprite 0 hit to fail, which may crash a game using a sprite 0 spin loop that's not resilient.<br />
<br />
Only writes at the exact moment between active picture and horizontal blanking cause this glitch; well-timed mid-scanline writes do not, nor do writes that land well within horizontal blanking.<br />
The glitch has no effect in horizontal or one-screen mirroring.<br />
It also does not appear if bit 0 of the written value is 0; this always correctly sets the left nametable.<br />
<br />
This produces an occasionally [[Game bugs|visible glitch]] in ''Super Mario Bros.'' when the program writes to PPUCTRL at the end of game logic.<br />
It appears to be turning NMI off during game logic and then turning NMI back on once the game logic has finished in order to prevent the NMI handler from being called again before the game logic finishes.<br />
To work around this in new productions, have your game logic set a flag that your NMI handler checks.<br />
<br />
=== <span id="PPUMASK"><span id="Reg2001">Mask ($2001) > write</span></span> ===<br />
<br />
* Common name: '''PPUMASK'''<br />
* Description: PPU mask register<br />
* Access: write<br />
<br />
This register controls the rendering of sprites and backgrounds, as well as colour effects.<br />
<br />
7 bit 0<br />
---- ----<br />
BGRs bMmG<br />
|||| ||||<br />
|||| |||+- Greyscale (0: normal color, 1: produce a greyscale display)<br />
|||| ||+-- 1: Show background in leftmost 8 pixels of screen, 0: Hide<br />
|||| |+--- 1: Show sprites in leftmost 8 pixels of screen, 0: Hide<br />
|||| +---- 1: Show background<br />
|||+------ 1: Show sprites<br />
||+------- Emphasize red*<br />
|+-------- Emphasize green*<br />
+--------- Emphasize blue*<br />
<br />
<nowiki>*</nowiki> NTSC colors. PAL and Dendy swaps green and red<ref>PAL PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=131889#p13188</ref><ref>Dendy PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=155513#p155513</ref>.<br />
<br />
==== Render Control ====<br />
<br />
* Bits 3 and 4 enable the rendering of background and sprites, respectively.<br />
<br />
* Bits 1 and 2 enable rendering of the background and sprites in the leftmost 8 pixel columns. Setting these bits to 0 will mask these columns, which is often useful in horizontal scrolling situations where you want partial sprites or tiles to scroll in from the left.<br />
<br />
* A value of $1E enables all rendering, with no color effects. A value of $00 disables all rendering. It is usually best practice to write this register only during vblank, to prevent partial-frame visual artifacts.<br />
<br />
* If either of bits 3 or 4 is enabled, at any time outside of the vblank interval the PPU will be making continual use to the PPU address and data bus to fetch tiles to render, as well as internally fetching sprite data from the OAM. If you wish to make changes to PPU memory outside of vblank (via '''$2007'''), you must set ''both'' of these bits to 0 to disable rendering and prevent conflicts.<br />
<br />
* Disabling rendering (clear both bits 3 and 4) during a visible part of the frame can be problematic. It can cause a corruption of the sprite state, which will display incorrect sprite data on the next frame. (See: [[Errata]]) It is, however, perfectly fine to mask sprites but leave the background on (set bit 3, clear bit 4) at any time in the frame.<br />
<br />
* Sprite 0 hit does not trigger in any area where the background or sprites are hidden.<br />
<br />
==== Color Control ====<br />
<br />
* Bit 0 controls a greyscale mode, which causes the palette to use only the colors from the grey column: $00, $10, $20, $30. This is implemented as a bitwise AND with $30 on any value read from PPU $3F00-$3FFF, both on the display and through [[#PPUDATA|PPUDATA]]. Writes to the palette through [[#PPUDATA|PPUDATA]] are not affected. Also note that black colours like $0F will be replaced by a non-black grey $00.<br />
<br />
* Bits 5,6,7 control a color "emphasis" or "tint" effect. Each bit emphasizes 1 color while darkening the other two. Setting all three emphasis bits will darken all colors.<br />
** Bit 5 emphasizes red on the NTSC PPU, and green on the PAL & Dendy PPUs.<br />
** Bit 6 emphasizes green on the NTSC PPU, and red on the PAL & Dendy PPUs.<br />
** Bit 7 emphasizes blue on the NTSC, PAL, & Dendy PPUs.<br />
** See [[NTSC video]] for a description of how bits 5-7 work on NTSC and PAL PPUs.<br />
** The [[Vs. System|RGB PPU]] used by PlayChoice and some other systems treat the emphasis bits differently. Instead of darkening other RGB components, it forces one component to maximum brightness. [[Colour-emphasis games|A few games]], which set all three tint bits to darken all colors, are unplayable on these PPUs.<br />
<br />
* The emphasis bits are applied independently of greyscale, so they will still tint the color of the grey image.<br />
<br />
* For a RGB color space, these values are used to create the color emphasis effect. Note that emphasis red+green becomes yellow, and so on.<br />
<br />
$2001:$E0 %Red %Green %Blue<br />
001 Red 1.239 .915 .743<br />
010 Green .794 1.086 .882<br />
011 Yellow 1.019 .980 .653<br />
100 Blue .905 1.026 1.277<br />
101 Magenta 1.023 .908 .979<br />
110 Cyan .741 .987 1.001<br />
111 Black .750 .750 .750<br />
<br />
=== <span id="PPUSTATUS"><span id="Reg2002">Status ($2002) < read</span></span> ===<br />
<br />
* Common name: '''PPUSTATUS'''<br />
* Description: PPU status register<br />
* Access: read<br />
<br />
This register reflects the state of various functions inside the PPU.<br />
It is often used for determining timing.<br />
<span id="Sprite_0">To determine when the PPU has reached a given pixel of the screen, put an opaque pixel of sprite 0 there.</span><br />
<br />
7 bit 0<br />
---- ----<br />
VSO. ....<br />
|||| ||||<br />
|||+-++++- Least significant bits previously written into a PPU register<br />
||| (due to register not being updated for this address)<br />
||+------- Sprite overflow. The intent was for this flag to be set<br />
|| whenever more than eight sprites appear on a scanline, but a<br />
|| hardware bug causes the actual behavior to be more complicated<br />
|| and generate false positives as well as false negatives; see<br />
|| [[PPU sprite evaluation]]. This flag is set during sprite<br />
|| evaluation and cleared at dot 1 (the second dot) of the<br />
|| pre-render line.<br />
|+-------- Sprite 0 Hit. Set when a nonzero pixel of sprite 0 overlaps<br />
| a nonzero background pixel; cleared at dot 1 of the pre-render<br />
| line. Used for raster timing.<br />
+--------- Vertical blank has started (0: not in vblank; 1: in vblank).<br />
Set at dot 1 of line 241 (the line *after* the post-render<br />
line); cleared after reading $2002 and at dot 1 of the<br />
pre-render line.<br />
<br />
==== Notes ====<br />
* Reading the status register will clear D7 mentioned above and also the address latch used by [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]]. It does not clear the sprite 0 hit or overflow bit.<br />
* Once the sprite 0 hit flag is set, it will not be cleared until the end of the next vertical blank. If attempting to use this flag for raster timing, it is important to ensure that the sprite 0 hit check happens outside of vertical blank, otherwise the CPU will "leak" through and the check will fail. The easiest way to do this is to place an earlier check for D6 = 0, which will wait for the pre-render scanline to begin.<br />
* If using sprite 0 hit to make a bottom scroll bar below a vertically scrolling or freely scrolling playfield, be careful to ensure that the tile in the playfield behind sprite 0 is opaque.<br />
* Sprite 0 hit is not detected at x=255, nor is it detected at x=0 through 7 if the background or sprites are hidden in this area.<br />
* See: [[PPU rendering]] for more information on the timing of setting and clearing the flags.<br />
* Some [[Vs. System]] PPUs return a constant value in D4-D0 that the game checks.<br />
* '''Caution:''' Reading PPUSTATUS at the exact start of vertical blank will return 0 in bit 7 but clear the latch anyway, causing the program to miss frames. See [[NMI]] for details.<br />
<br />
=== <span id="OAMADDR"><span id="Reg2003">OAM address ($2003) > write</span></span> === <br />
<br />
* Common name: '''OAMADDR'''<br />
* Description: OAM address port<br />
* Access: write<br />
<br />
Write the address of [[PPU OAM|OAM]] you want to access here. Most games just write $00 here and then use [[#OAMDMA|OAMDMA]]. (DMA is implemented in the 2A03/7 chip and works by repeatedly writing to [[#OAMDATA|OAMDATA]])<br />
<br />
==== Values during rendering ====<br />
<br />
OAMADDR is set to 0 during each of ticks 257-320 (the sprite tile loading interval) of the pre-render and visible scanlines.<br />
<br />
The value of OAMADDR when sprite evaluation starts at tick 65 of the visible scanlines will determine where in OAM sprite evaluation starts, and hence which sprite gets treated as sprite 0. The first OAM entry to be checked during sprite evaluation is the one starting at <tt>OAM[OAMADDR]</tt>. If OAMADDR is unaligned and does not point to the y position (first byte) of an OAM entry, then whatever it points to (tile index, attribute, or x coordinate) will be reinterpreted as a y position, and the following bytes will be similarly reinterpreted. No more sprites will be found once the end of OAM is reached, effectively hiding any sprites before <tt>OAM[OAMADDR]</tt>.<br />
<br />
==== OAMADDR precautions ====<br />
<br />
On the 2C02, writes to OAMADDR reliably corrupt OAM<!--, copying a pair of sprites from the old address value to the open-bus address high-byte of the OAMADDR write-->.<ref name = "OAMglitch">Manual OAM write glitchyness: http://forums.nesdev.org/viewtopic.php?f=2&t=10189</ref> This can then be worked around by writing all 256 bytes of OAM.<br />
<br />
It is also the case that if OAMADDR is not less than eight when rendering starts, the eight bytes starting at <tt>OAMADDR & 0xF8</tt> are copied to the first eight bytes of OAM; it seems likely that this is related. The former bug is known to have been fixed in the 2C07; the latter is suspected to be. On the Dendy, the latter bug is required for 2C02 compatibility.<br />
<br />
=== <span id="OAMDATA"><span id="Reg2004">OAM data ($2004) <> read/write</span></span> ===<br />
<br />
* Common name: '''OAMDATA'''<br />
* Description: OAM data port<br />
* Access: read, write<br />
<br />
Write OAM data here. Writes will increment [[#OAMADDR|OAMADDR]] after the write; reads during vertical or forced blanking return the value from OAM at that address but do not increment.<br />
<br />
Because changes to OAM should normally be made only during vblank, writing through OAMDATA is only effective for partial updates (it is too slow). Most games will use the DMA feature through [[#OAMDMA|OAMDMA]] instead.<br />
<br />
* Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this.<br />
<br />
* Writes to OAMDATA during rendering (on the pre-render line and the visible lines 0-239, provided either sprite or background rendering is enabled) do not modify values in OAM, but do perform a glitchy increment of [[#OAMADDR|OAMADDR]], bumping only the high 6 bits (i.e., it bumps the ''[n]'' value in [[PPU sprite evaluation]] - it's plausible that it could bump the low bits instead depending on the current status of sprite evaluation). This extends to DMA transfers via [[#OAMDMA|OAMDMA]], since that uses writes to $2004. For emulation purposes, it is probably best to completely ignore writes during rendering.<br />
<br />
* It used to be thought that reading from this register wasn't reliable<ref>$2004 reading reliable? http://forums.nesdev.org/viewtopic.php?f=2&t=6424</ref>, however more recent evidence seems to suggest that this is solely due to corruption by [[#OAMADDR|OAMADDR]] writes.<br />
<br />
* In the oldest instantiations of the PPU, as found on earlier Famicoms and NESes, this register is not readable<ref>$2003 not readable on early revisions: http://forums.nesdev.org/viewtopic.php?p=62137#p62137</ref>. The readability was added on the RP2C02G, found on most NESes and later Famicoms.<ref>hardware revisions and $2003 reads: http://forums.nesdev.org/viewtopic.php?f=2&t=12958&start=45#p150926</ref><br />
<br />
* In the 2C07, sprite evaluation can ''never'' be fully disabled, and will always start 20 scanlines after the start of vblank<ref>2C07 PPU sprite evaluation notes: http://forums.nesdev.org/viewtopic.php?f=9&t=11041</ref> (same as when the prerender scanline would have been on the 2C02). As such, you must upload anything to OAM that you intend to within the first 20 scanlines after the 2C07 signals vertical blanking.<br />
<br />
=== <span id="PPUSCROLL"><span id="Reg2005">Scroll ($2005) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUSCROLL'''<br />
* Description: PPU scrolling position register<br />
* Access: write twice<br />
<br />
This register is used to change the [[PPU scrolling|scroll position]], that is, to tell the PPU which pixel of the nametable selected through [[#PPUCTRL|PPUCTRL]] should be at the top left corner of the rendered screen. Typically, this register is written to during vertical blanking, so that the next frame starts rendering from the desired location, but it can also be modified during rendering in order to split the screen. Changes made to the vertical scroll during rendering will only take effect on the next frame.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the horizontal and vertical scroll offsets here just before turning on the screen:<br />
<br />
bit PPUSTATUS<br />
; possibly other code goes here<br />
lda cam_position_x<br />
sta PPUSCROLL<br />
lda cam_position_y<br />
sta PPUSCROLL<br />
<br />
Horizontal offsets range from 0 to 255. "Normal" vertical offsets range from 0 to 239, while values of 240 to 255 are treated as -16 through -1 in a way, but tile data is incorrectly fetched from the attribute table.<br />
<br />
By changing the values here across several frames and writing tiles to newly revealed areas of the nametables, one can achieve the effect of a camera panning over a large background.<br />
<br />
=== <span id="PPUADDR"><span id="Reg2006">Address ($2006) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUADDR'''<br />
* Description: PPU address register<br />
* Access: write twice<br />
<br />
Because the CPU and the PPU are on separate buses, neither has direct access to the other's memory.<br />
The CPU writes to VRAM through a pair of registers on the PPU.<br />
First it loads an address into [[#PPUADDR|PPUADDR]], and then it writes repeatedly to [[#PPUDATA|PPUDATA]] to fill VRAM.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the 16-bit address of VRAM you want to access here, upper byte first.<br />
For example, to set the VRAM address to $2108:<br />
<br />
lda #$21<br />
sta PPUADDR<br />
lda #$08<br />
sta PPUADDR<br />
<br />
Valid addresses are $0000-$3FFF; higher addresses will be [[mirroring|mirrored]] down.<br />
<br />
==== note ====<br />
Access to [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]] during screen refresh produces interesting raster effects; the starting position of each scanline can be set to any pixel position in nametable memory. For more information, see [[PPU scrolling]] and tokumaru's sample code on the BBS.<ref>PPU synchronization from NMI: http://forums.nesdev.org/viewtopic.php?p=64111#p64111</ref><br />
<br />
''' Editor's note:''' Last comment about external page should be re-directed to the getting started section instead.<br />
<br />
=== <span id="PPUDATA"><span id="Reg2007">Data ($2007) <> read/write</span></span> ===<br />
<br />
* Common name: '''PPUDATA'''<br />
* Description: PPU data port<br />
* Access: read, write<br />
<br />
VRAM read/write data register. After access, the video memory address will increment by an amount determined by $2000:2.<br />
<br />
When the screen is turned off by disabling the background/sprite rendering flag with the [[#PPUMASK|PPUMASK]] or during vertical blank, you can read or write data from VRAM through this port. Since accessing this register increments the VRAM address, it should not be accessed outside vertical or forced blanking because it will cause graphical glitches, and if writing, write to an unpredictable address in VRAM. However, two games are known to [[Reading 2007 during rendering|read from PPUDATA during rendering]]: see [[Tricky-to-emulate games]].<br />
<br />
VRAM reading and writing shares the same internal address register that rendering uses. So after loading data into video memory, the program should reload the scroll position afterwards with [[#PPUSCROLL|PPUSCROLL]] writes in order to avoid wrong scrolling.<br />
<br />
==== The PPUDATA read buffer (post-fetch) ====<br />
<br />
When reading while the VRAM address is in the range 0-$3EFF (i.e., before the palettes), the read will return the contents of an internal read buffer. This internal buffer is updated '''only''' when reading [[#PPUDATA|PPUDATA]], and so is preserved across frames. After the CPU reads and gets the contents of the internal buffer, the PPU will immediately update the internal buffer with the byte at the current VRAM address. Thus, after setting the VRAM address, one should first read this register and discard the result.<br />
<br />
Reading palette data from $3F00-$3FFF works differently. The palette data is placed immediately on the data bus, and hence no dummy read is required. Reading the palettes still updates the internal buffer though, but the data placed in it is the mirrored nametable data that would appear "underneath" the palette. (Checking the [[PPU memory map]] should make this clearer.)<br />
<br />
=== <span id="Reg4014"><span id="OAMDMA">OAM DMA ($4014) > write</span></span> ===<br />
<br />
* Common name: '''OAMDMA'''<br />
* Description: OAM DMA register (high byte)<br />
* Access: write<br />
<br />
This port is located on the CPU. Writing $XX will upload 256 bytes of data from CPU page $XX00-$XXFF to the internal PPU OAM. This page is typically located in internal RAM, commonly $0200-$02FF, but cartridge RAM or ROM can be used as well.<br />
<br />
* The CPU is suspended during the transfer, which will take 513 or 514 cycles after the $4014 write tick. (1 dummy read cycle while waiting for writes to complete, +1 if on an odd CPU cycle, then 256 alternating read/write cycles.)<br />
<br />
* The OAM DMA is the only effective method for initializing all 256 bytes of OAM. Because of the decay of OAM's dynamic RAM when rendering is disabled, the initialization should take place within vblank. Writes through [[#OAMDATA|OAMDATA]] are generally too slow for this task.<br />
<br />
* The DMA transfer will begin at the current OAM write address. It is common practice to initialize it to 0 with a write to [[#OAMADDR|OAMADDR]] before the DMA transfer. Different starting addresses can be used for a simple OAM cycling technique, to alleviate sprite priority conflicts by flickering. If using this technique, after the DMA [[#OAMADDR|OAMADDR]] should be set to 0 before the end of vblank to prevent potential OAM corruption (See: [[Errata]]). However, due to OAMADDR writes also having a "corruption" effect<ref name = "OAMglitch" /> this technique is not recommended.<br />
<br />
== References ==<br />
<references /></div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_registers&diff=10125PPU registers2017-01-22T03:18:00Z<p>Zepper: /* Color Control */ Added % for each RGB component for color emphasis in the RGB color space.</p>
<hr />
<div>The PPU exposes eight memory-mapped registers to the CPU. These nominally sit at $2000 through $2007 in the CPU's address space, but because they're incompletely decoded, they're [[Mirroring|mirrored]] in every 8 bytes from $2008 through $3FFF, so a write to $3456 is the same as a write to $2006.<br />
<br />
Immediately after powerup, the PPU isn't necessarily in a usable state.<br />
The program needs to do a few things to get it going; see [[PPU power up state]] and [[Init code]]. <br />
<br />
<noinclude><br />
__TOC__<br />
</noinclude><br />
<br />
== Summary ==<br />
<br />
{| class="tabular"<br />
! Common Name<br />
! Address<br />
! Bits<br />
! Notes<br />
|-<br />
! [[#PPUCTRL|PPUCTRL]]<br />
! $2000<br />
| <tt style="white-space: nowrap">VPHB SINN</tt> || NMI enable (V), PPU master/slave (P), sprite height (H), background tile select (B), sprite tile select (S), increment mode (I), nametable select (NN)<br />
|-<br />
! [[#PPUMASK|PPUMASK]]<br />
! $2001<br />
| <tt style="white-space: nowrap">BGRs bMmG</tt> || color emphasis (BGR), sprite enable (s), background enable (b), sprite left column enable (M), background left column enable (m), greyscale (G)<br />
|-<br />
! [[#PPUSTATUS|PPUSTATUS]]<br />
! $2002<br />
| <tt style="white-space: nowrap">VSO- ----</tt> || vblank (V), sprite 0 hit (S), sprite overflow (O), read resets write pair for $2005/2006<br />
|-<br />
! [[#OAMADDR|OAMADDR]]<br />
! $2003<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM read/write address<br />
|-<br />
! [[#OAMDATA|OAMDATA]]<br />
! $2004<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || OAM data read/write<br />
|-<br />
! [[#PPUSCROLL|PPUSCROLL]]<br />
! $2005<br />
| <tt style="white-space: nowrap">xxxx xxxx</tt> || fine scroll position (two writes: X, Y)<br />
|-<br />
! [[#PPUADDR|PPUADDR]]<br />
! $2006<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || PPU read/write address (two writes: MSB, LSB)<br />
|-<br />
! [[#PPUDATA|PPUDATA]]<br />
! $2007<br />
| <tt style="white-space: nowrap">dddd dddd</tt> || PPU data read/write<br />
|-<br />
! [[#OAMDMA|OAMDMA]]<br />
! $4014<br />
| <tt style="white-space: nowrap">aaaa aaaa</tt> || OAM DMA high address<br />
|}<br />
<br />
== Ports ==<br />
<br />
The PPU has an internal data bus that it uses for communication with the CPU.<br />
This bus, called <code>_io_db</code> in [[Visual 2C02]] and <code>PPUGenLatch</code> in FCEUX,<ref>[http://sourceforge.net/p/fceultra/code/HEAD/tree/fceu/trunk/src/ppu.cpp#l183 ppu.cpp] by Bero and Xodnizel</ref> behaves as an 8-bit dynamic latch due to capacitance of very long traces that run to various parts of the PPU.<br />
Writing any value to any PPU port, even to the nominally read-only PPUSTATUS, will fill this latch.<br />
Reading any readable port (PPUSTATUS, OAMDATA, or PPUDATA) also fills the latch with the bits read.<br />
Reading a nominally "write-only" register returns the latch's current value, as do the unused bits of PPUSTATUS.<br />
This value begins to decay after a frame or so, faster once the PPU has warmed up, and it is likely that values with alternating bit patterns (such as $55 or $AA) will decay faster.<ref>[http://forums.nesdev.org/viewtopic.php?p=143801#p143801 Reply to "Riding the open bus"] by lidnariq</ref><br />
<br />
=== <span id="PPUCTRL"><span id="Reg2000">Controller ($2000) > write</span></span> === <br />
<br />
* Common name: '''PPUCTRL'''<br />
* Description: PPU control register<br />
* Access: write<br />
<br />
Various flags controlling PPU operation<br />
7 bit 0<br />
---- ----<br />
VPHB SINN<br />
|||| ||||<br />
|||| ||++- Base nametable address<br />
|||| || (0 = $2000; 1 = $2400; 2 = $2800; 3 = $2C00)<br />
|||| |+--- VRAM address increment per CPU read/write of PPUDATA<br />
|||| | (0: add 1, going across; 1: add 32, going down)<br />
|||| +---- Sprite pattern table address for 8x8 sprites<br />
|||| (0: $0000; 1: $1000; ignored in 8x16 mode)<br />
|||+------ Background pattern table address (0: $0000; 1: $1000)<br />
||+------- Sprite size (0: 8x8; 1: 8x16)<br />
|+-------- PPU master/slave select<br />
| (0: read backdrop from EXT pins; 1: output color on EXT pins)<br />
+--------- Generate an [[NMI]] at the start of the<br />
[[wikipedia:Vertical blanking interval|vertical blanking interval]] (0: off; 1: on)<br />
<br />
Equivalently, bits 0 and 1 are the most significant bit of the scrolling coordinates (see [[PPU_nametables|Nametables]] and [[#PPUSCROLL|PPUSCROLL]]):<br />
7 bit 0<br />
---- ----<br />
.... ..YX<br />
||<br />
|+- 1: Add 256 to the X scroll position<br />
+-- 1: Add 240 to the Y scroll position<br />
<br />
Another way of seeing the explanation above is that when you reach the end of a nametable, you must switch to the next one, hence, changing the nametable address.<br />
<br />
[[PPU power up state|After power/reset]], writes to this register are ignored for about 30000 cycles.<br />
<br />
When turning on the NMI flag in bit 7, if the PPU is currently in vertical blank and the [[#PPUSTATUS|PPUSTATUS]] ($2002) vblank flag is set, an NMI will be generated immediately.<br />
This can result in graphical errors (most likely a misplaced scroll) if the NMI routine is executed too late in the blanking period to finish on time.<br />
To avoid this problem it is prudent to read $2002 immediately before writing $2000 to clear the vblank flag.<br />
<br />
==== Master/slave mode and the EXT pins ====<br />
When bit 6 of PPUCTRL is clear (the usual case), the PPU gets the [[PPU_palettes|palette index]] for the background color from the EXT pins. The stock NES grounds these pins, making palette index 0 the background color as expected. A secondary picture generator connected to the EXT pins would be able to replace the background with a different image using colors from the background palette, which could be used e.g. to implement parallax scrolling.<br />
<br />
Setting bit 6 causes the PPU to output the lower four bits of the palette memory index on the EXT pins for each pixel (in addition to normal image drawing) - since only four bits are output, background and sprite pixels can't normally be distinguished this way. As the EXT pins are grounded on an unmodified NES, setting bit 6 is discouraged as it could potentially damage the chip whenever it outputs a non-zero pixel value (due to it effectively shorting Vcc and GND together). Looking at the relevant circuitry in [[Visual 2C02]], it appears that the [[PPU palettes|background palette hack]] would not be functional for output from the EXT pins; they would always output index 0 for the background color.<br />
<br />
==== Bit 0 bus conflict ====<br />
Be very careful when writing to this register outside vertical blanking if you are using vertical mirroring (horizontal arrangement) or 4-screen VRAM.<br />
For specific CPU-PPU alignments, [http://forums.nesdev.org/viewtopic.php?p=112424#p112424 a write near the end of a visible scanline] may cause only the next scanline to be erroneously drawn from the left nametable.<br />
This can cause a visible glitch.<br />
Worse, it can theoretically cause a sprite 0 hit to fail, which may crash a game using a sprite 0 spin loop that's not resilient.<br />
<br />
Only writes at the exact moment between active picture and horizontal blanking cause this glitch; well-timed mid-scanline writes do not, nor do writes that land well within horizontal blanking.<br />
The glitch has no effect in horizontal or one-screen mirroring.<br />
It also does not appear if bit 0 of the written value is 0; this always correctly sets the left nametable.<br />
<br />
This produces an occasionally [[Game bugs|visible glitch]] in ''Super Mario Bros.'' when the program writes to PPUCTRL at the end of game logic.<br />
It appears to be turning NMI off during game logic and then turning NMI back on once the game logic has finished in order to prevent the NMI handler from being called again before the game logic finishes.<br />
To work around this in new productions, have your game logic set a flag that your NMI handler checks.<br />
<br />
=== <span id="PPUMASK"><span id="Reg2001">Mask ($2001) > write</span></span> ===<br />
<br />
* Common name: '''PPUMASK'''<br />
* Description: PPU mask register<br />
* Access: write<br />
<br />
This register controls the rendering of sprites and backgrounds, as well as colour effects.<br />
<br />
7 bit 0<br />
---- ----<br />
BGRs bMmG<br />
|||| ||||<br />
|||| |||+- Greyscale (0: normal color, 1: produce a greyscale display)<br />
|||| ||+-- 1: Show background in leftmost 8 pixels of screen, 0: Hide<br />
|||| |+--- 1: Show sprites in leftmost 8 pixels of screen, 0: Hide<br />
|||| +---- 1: Show background<br />
|||+------ 1: Show sprites<br />
||+------- Emphasize red*<br />
|+-------- Emphasize green*<br />
+--------- Emphasize blue*<br />
<br />
<nowiki>*</nowiki> NTSC colors. PAL and Dendy swaps green and red<ref>PAL PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=131889#p13188</ref><ref>Dendy PPU swaps green and red emphasis bits: http://forums.nesdev.org/viewtopic.php?p=155513#p155513</ref>.<br />
<br />
==== Render Control ====<br />
<br />
* Bits 3 and 4 enable the rendering of background and sprites, respectively.<br />
<br />
* Bits 1 and 2 enable rendering of the background and sprites in the leftmost 8 pixel columns. Setting these bits to 0 will mask these columns, which is often useful in horizontal scrolling situations where you want partial sprites or tiles to scroll in from the left.<br />
<br />
* A value of $1E enables all rendering, with no color effects. A value of $00 disables all rendering. It is usually best practice to write this register only during vblank, to prevent partial-frame visual artifacts.<br />
<br />
* If either of bits 3 or 4 is enabled, at any time outside of the vblank interval the PPU will be making continual use to the PPU address and data bus to fetch tiles to render, as well as internally fetching sprite data from the OAM. If you wish to make changes to PPU memory outside of vblank (via '''$2007'''), you must set ''both'' of these bits to 0 to disable rendering and prevent conflicts.<br />
<br />
* Disabling rendering (clear both bits 3 and 4) during a visible part of the frame can be problematic. It can cause a corruption of the sprite state, which will display incorrect sprite data on the next frame. (See: [[Errata]]) It is, however, perfectly fine to mask sprites but leave the background on (set bit 3, clear bit 4) at any time in the frame.<br />
<br />
* Sprite 0 hit does not trigger in any area where the background or sprites are hidden.<br />
<br />
==== Color Control ====<br />
<br />
* Bit 0 controls a greyscale mode, which causes the palette to use only the colors from the grey column: $00, $10, $20, $30. This is implemented as a bitwise AND with $30 on any value read from PPU $3F00-$3FFF, both on the display and through [[#PPUDATA|PPUDATA]]. Writes to the palette through [[#PPUDATA|PPUDATA]] are not affected. Also note that black colours like $0F will be replaced by a non-black grey $00.<br />
<br />
* Bits 5,6,7 control a color "emphasis" or "tint" effect. Each bit emphasizes 1 color while darkening the other two. Setting all three emphasis bits will darken all colors.<br />
** Bit 5 emphasizes red on the NTSC PPU, and green on the PAL & Dendy PPUs.<br />
** Bit 6 emphasizes green on the NTSC PPU, and red on the PAL & Dendy PPUs.<br />
** Bit 7 emphasizes blue on the NTSC, PAL, & Dendy PPUs.<br />
** See [[NTSC video]] for a description of how bits 5-7 work on NTSC and PAL PPUs.<br />
** The [[Vs. System|RGB PPU]] used by PlayChoice and some other systems treat the emphasis bits differently. Instead of darkening other RGB components, it forces one component to maximum brightness. [[Colour-emphasis games|A few games]], which set all three tint bits to darken all colors, are unplayable on these PPUs.<br />
<br />
* The emphasis bits are applied independently of greyscale, so they will still tint the color of the grey image.<br />
<br />
* From a RGB color space, these values are used to create the color emphasis effect. Note that emphasis red+green becomes yellow, and so on.<br />
<br />
$2001:$E0 %Red %Green %Blue<br />
001 Red 1.239 .915 .743<br />
010 Green .794 1.086 .882<br />
011 Yellow 1.019 .980 .653<br />
100 Blue .905 1.026 1.277<br />
101 Magenta 1.023 .908 .979<br />
110 Cyan .741 .987 1.001<br />
111 Black .750 .750 .750<br />
<br />
=== <span id="PPUSTATUS"><span id="Reg2002">Status ($2002) < read</span></span> ===<br />
<br />
* Common name: '''PPUSTATUS'''<br />
* Description: PPU status register<br />
* Access: read<br />
<br />
This register reflects the state of various functions inside the PPU.<br />
It is often used for determining timing.<br />
<span id="Sprite_0">To determine when the PPU has reached a given pixel of the screen, put an opaque pixel of sprite 0 there.</span><br />
<br />
7 bit 0<br />
---- ----<br />
VSO. ....<br />
|||| ||||<br />
|||+-++++- Least significant bits previously written into a PPU register<br />
||| (due to register not being updated for this address)<br />
||+------- Sprite overflow. The intent was for this flag to be set<br />
|| whenever more than eight sprites appear on a scanline, but a<br />
|| hardware bug causes the actual behavior to be more complicated<br />
|| and generate false positives as well as false negatives; see<br />
|| [[PPU sprite evaluation]]. This flag is set during sprite<br />
|| evaluation and cleared at dot 1 (the second dot) of the<br />
|| pre-render line.<br />
|+-------- Sprite 0 Hit. Set when a nonzero pixel of sprite 0 overlaps<br />
| a nonzero background pixel; cleared at dot 1 of the pre-render<br />
| line. Used for raster timing.<br />
+--------- Vertical blank has started (0: not in vblank; 1: in vblank).<br />
Set at dot 1 of line 241 (the line *after* the post-render<br />
line); cleared after reading $2002 and at dot 1 of the<br />
pre-render line.<br />
<br />
==== Notes ====<br />
* Reading the status register will clear D7 mentioned above and also the address latch used by [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]]. It does not clear the sprite 0 hit or overflow bit.<br />
* Once the sprite 0 hit flag is set, it will not be cleared until the end of the next vertical blank. If attempting to use this flag for raster timing, it is important to ensure that the sprite 0 hit check happens outside of vertical blank, otherwise the CPU will "leak" through and the check will fail. The easiest way to do this is to place an earlier check for D6 = 0, which will wait for the pre-render scanline to begin.<br />
* If using sprite 0 hit to make a bottom scroll bar below a vertically scrolling or freely scrolling playfield, be careful to ensure that the tile in the playfield behind sprite 0 is opaque.<br />
* Sprite 0 hit is not detected at x=255, nor is it detected at x=0 through 7 if the background or sprites are hidden in this area.<br />
* See: [[PPU rendering]] for more information on the timing of setting and clearing the flags.<br />
* Some [[Vs. System]] PPUs return a constant value in D4-D0 that the game checks.<br />
* '''Caution:''' Reading PPUSTATUS at the exact start of vertical blank will return 0 in bit 7 but clear the latch anyway, causing the program to miss frames. See [[NMI]] for details.<br />
<br />
=== <span id="OAMADDR"><span id="Reg2003">OAM address ($2003) > write</span></span> === <br />
<br />
* Common name: '''OAMADDR'''<br />
* Description: OAM address port<br />
* Access: write<br />
<br />
Write the address of [[PPU OAM|OAM]] you want to access here. Most games just write $00 here and then use [[#OAMDMA|OAMDMA]]. (DMA is implemented in the 2A03/7 chip and works by repeatedly writing to [[#OAMDATA|OAMDATA]])<br />
<br />
==== Values during rendering ====<br />
<br />
OAMADDR is set to 0 during each of ticks 257-320 (the sprite tile loading interval) of the pre-render and visible scanlines.<br />
<br />
The value of OAMADDR when sprite evaluation starts at tick 65 of the visible scanlines will determine where in OAM sprite evaluation starts, and hence which sprite gets treated as sprite 0. The first OAM entry to be checked during sprite evaluation is the one starting at <tt>OAM[OAMADDR]</tt>. If OAMADDR is unaligned and does not point to the y position (first byte) of an OAM entry, then whatever it points to (tile index, attribute, or x coordinate) will be reinterpreted as a y position, and the following bytes will be similarly reinterpreted. No more sprites will be found once the end of OAM is reached, effectively hiding any sprites before <tt>OAM[OAMADDR]</tt>.<br />
<br />
==== OAMADDR precautions ====<br />
<br />
On the 2C02, writes to OAMADDR reliably corrupt OAM<!--, copying a pair of sprites from the old address value to the open-bus address high-byte of the OAMADDR write-->.<ref name = "OAMglitch">Manual OAM write glitchyness: http://forums.nesdev.org/viewtopic.php?f=2&t=10189</ref> This can then be worked around by writing all 256 bytes of OAM.<br />
<br />
It is also the case that if OAMADDR is not less than eight when rendering starts, the eight bytes starting at <tt>OAMADDR & 0xF8</tt> are copied to the first eight bytes of OAM; it seems likely that this is related. The former bug is known to have been fixed in the 2C07; the latter is suspected to be. On the Dendy, the latter bug is required for 2C02 compatibility.<br />
<br />
=== <span id="OAMDATA"><span id="Reg2004">OAM data ($2004) <> read/write</span></span> ===<br />
<br />
* Common name: '''OAMDATA'''<br />
* Description: OAM data port<br />
* Access: read, write<br />
<br />
Write OAM data here. Writes will increment [[#OAMADDR|OAMADDR]] after the write; reads during vertical or forced blanking return the value from OAM at that address but do not increment.<br />
<br />
Because changes to OAM should normally be made only during vblank, writing through OAMDATA is only effective for partial updates (it is too slow). Most games will use the DMA feature through [[#OAMDMA|OAMDMA]] instead.<br />
<br />
* Reading OAMDATA while the PPU is rendering will expose internal OAM accesses during sprite evaluation and loading; Micro Machines does this.<br />
<br />
* Writes to OAMDATA during rendering (on the pre-render line and the visible lines 0-239, provided either sprite or background rendering is enabled) do not modify values in OAM, but do perform a glitchy increment of [[#OAMADDR|OAMADDR]], bumping only the high 6 bits (i.e., it bumps the ''[n]'' value in [[PPU sprite evaluation]] - it's plausible that it could bump the low bits instead depending on the current status of sprite evaluation). This extends to DMA transfers via [[#OAMDMA|OAMDMA]], since that uses writes to $2004. For emulation purposes, it is probably best to completely ignore writes during rendering.<br />
<br />
* It used to be thought that reading from this register wasn't reliable<ref>$2004 reading reliable? http://forums.nesdev.org/viewtopic.php?f=2&t=6424</ref>, however more recent evidence seems to suggest that this is solely due to corruption by [[#OAMADDR|OAMADDR]] writes.<br />
<br />
* In the oldest instantiations of the PPU, as found on earlier Famicoms and NESes, this register is not readable<ref>$2003 not readable on early revisions: http://forums.nesdev.org/viewtopic.php?p=62137#p62137</ref>. The readability was added on the RP2C02G, found on most NESes and later Famicoms.<ref>hardware revisions and $2003 reads: http://forums.nesdev.org/viewtopic.php?f=2&t=12958&start=45#p150926</ref><br />
<br />
* In the 2C07, sprite evaluation can ''never'' be fully disabled, and will always start 20 scanlines after the start of vblank<ref>2C07 PPU sprite evaluation notes: http://forums.nesdev.org/viewtopic.php?f=9&t=11041</ref> (same as when the prerender scanline would have been on the 2C02). As such, you must upload anything to OAM that you intend to within the first 20 scanlines after the 2C07 signals vertical blanking.<br />
<br />
=== <span id="PPUSCROLL"><span id="Reg2005">Scroll ($2005) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUSCROLL'''<br />
* Description: PPU scrolling position register<br />
* Access: write twice<br />
<br />
This register is used to change the [[PPU scrolling|scroll position]], that is, to tell the PPU which pixel of the nametable selected through [[#PPUCTRL|PPUCTRL]] should be at the top left corner of the rendered screen. Typically, this register is written to during vertical blanking, so that the next frame starts rendering from the desired location, but it can also be modified during rendering in order to split the screen. Changes made to the vertical scroll during rendering will only take effect on the next frame.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the horizontal and vertical scroll offsets here just before turning on the screen:<br />
<br />
bit PPUSTATUS<br />
; possibly other code goes here<br />
lda cam_position_x<br />
sta PPUSCROLL<br />
lda cam_position_y<br />
sta PPUSCROLL<br />
<br />
Horizontal offsets range from 0 to 255. "Normal" vertical offsets range from 0 to 239, while values of 240 to 255 are treated as -16 through -1 in a way, but tile data is incorrectly fetched from the attribute table.<br />
<br />
By changing the values here across several frames and writing tiles to newly revealed areas of the nametables, one can achieve the effect of a camera panning over a large background.<br />
<br />
=== <span id="PPUADDR"><span id="Reg2006">Address ($2006) >> write x2</span></span> ===<br />
<br />
* Common name: '''PPUADDR'''<br />
* Description: PPU address register<br />
* Access: write twice<br />
<br />
Because the CPU and the PPU are on separate buses, neither has direct access to the other's memory.<br />
The CPU writes to VRAM through a pair of registers on the PPU.<br />
First it loads an address into [[#PPUADDR|PPUADDR]], and then it writes repeatedly to [[#PPUDATA|PPUDATA]] to fill VRAM.<br />
<br />
After reading [[#PPUSTATUS|PPUSTATUS]] to reset the address latch, write the 16-bit address of VRAM you want to access here, upper byte first.<br />
For example, to set the VRAM address to $2108:<br />
<br />
lda #$21<br />
sta PPUADDR<br />
lda #$08<br />
sta PPUADDR<br />
<br />
Valid addresses are $0000-$3FFF; higher addresses will be [[mirroring|mirrored]] down.<br />
<br />
==== note ====<br />
Access to [[#PPUSCROLL|PPUSCROLL]] and [[#PPUADDR|PPUADDR]] during screen refresh produces interesting raster effects; the starting position of each scanline can be set to any pixel position in nametable memory. For more information, see [[PPU scrolling]] and tokumaru's sample code on the BBS.<ref>PPU synchronization from NMI: http://forums.nesdev.org/viewtopic.php?p=64111#p64111</ref><br />
<br />
''' Editor's note:''' Last comment about external page should be re-directed to the getting started section instead.<br />
<br />
=== <span id="PPUDATA"><span id="Reg2007">Data ($2007) <> read/write</span></span> ===<br />
<br />
* Common name: '''PPUDATA'''<br />
* Description: PPU data port<br />
* Access: read, write<br />
<br />
VRAM read/write data register. After access, the video memory address will increment by an amount determined by $2000:2.<br />
<br />
When the screen is turned off by disabling the background/sprite rendering flag with the [[#PPUMASK|PPUMASK]] or during vertical blank, you can read or write data from VRAM through this port. Since accessing this register increments the VRAM address, it should not be accessed outside vertical or forced blanking because it will cause graphical glitches, and if writing, write to an unpredictable address in VRAM. However, two games are known to [[Reading 2007 during rendering|read from PPUDATA during rendering]]: see [[Tricky-to-emulate games]].<br />
<br />
VRAM reading and writing shares the same internal address register that rendering uses. So after loading data into video memory, the program should reload the scroll position afterwards with [[#PPUSCROLL|PPUSCROLL]] writes in order to avoid wrong scrolling.<br />
<br />
==== The PPUDATA read buffer (post-fetch) ====<br />
<br />
When reading while the VRAM address is in the range 0-$3EFF (i.e., before the palettes), the read will return the contents of an internal read buffer. This internal buffer is updated '''only''' when reading [[#PPUDATA|PPUDATA]], and so is preserved across frames. After the CPU reads and gets the contents of the internal buffer, the PPU will immediately update the internal buffer with the byte at the current VRAM address. Thus, after setting the VRAM address, one should first read this register and discard the result.<br />
<br />
Reading palette data from $3F00-$3FFF works differently. The palette data is placed immediately on the data bus, and hence no dummy read is required. Reading the palettes still updates the internal buffer though, but the data placed in it is the mirrored nametable data that would appear "underneath" the palette. (Checking the [[PPU memory map]] should make this clearer.)<br />
<br />
=== <span id="Reg4014"><span id="OAMDMA">OAM DMA ($4014) > write</span></span> ===<br />
<br />
* Common name: '''OAMDMA'''<br />
* Description: OAM DMA register (high byte)<br />
* Access: write<br />
<br />
This port is located on the CPU. Writing $XX will upload 256 bytes of data from CPU page $XX00-$XXFF to the internal PPU OAM. This page is typically located in internal RAM, commonly $0200-$02FF, but cartridge RAM or ROM can be used as well.<br />
<br />
* The CPU is suspended during the transfer, which will take 513 or 514 cycles after the $4014 write tick. (1 dummy read cycle while waiting for writes to complete, +1 if on an odd CPU cycle, then 256 alternating read/write cycles.)<br />
<br />
* The OAM DMA is the only effective method for initializing all 256 bytes of OAM. Because of the decay of OAM's dynamic RAM when rendering is disabled, the initialization should take place within vblank. Writes through [[#OAMDATA|OAMDATA]] are generally too slow for this task.<br />
<br />
* The DMA transfer will begin at the current OAM write address. It is common practice to initialize it to 0 with a write to [[#OAMADDR|OAMADDR]] before the DMA transfer. Different starting addresses can be used for a simple OAM cycling technique, to alleviate sprite priority conflicts by flickering. If using this technique, after the DMA [[#OAMADDR|OAMADDR]] should be set to 0 before the end of vblank to prevent potential OAM corruption (See: [[Errata]]). However, due to OAMADDR writes also having a "corruption" effect<ref name = "OAMglitch" /> this technique is not recommended.<br />
<br />
== References ==<br />
<references /></div>Zepperhttps://www.nesdev.org/w/index.php?title=APU_Pulse&diff=543APU Pulse2016-12-28T15:26:07Z<p>Zepper: /* APU */ only cosmetic changes.</p>
<hr />
<div>[[Category:APU]]<br />
Each of the two [[APU|NES APU]] pulse (square) wave channels generate a pulse wave with variable duty.<br />
<br />
Each pulse channel contains the following: [[APU Envelope|envelope generator]], [[APU Sweep|sweep unit]], [[APU Misc|timer]], 8-step [[APU Misc|sequencer]], [[APU Length Counter|length counter]].<br />
'''Note''': the addresses below are write-only''!''<br />
<br />
<pre><br />
Sweep -----> Timer<br />
| |<br />
| |<br />
| v <br />
| Sequencer Length Counter<br />
| | |<br />
| | |<br />
v v v<br />
Envelope -------> Gate -----> Gate -------> Gate --->(to mixer)<br />
</pre><br />
<br />
{| class="tabular"<br />
! Address || Bitfield || Description<br />
|-<br />
| '''$4000''' || <tt>DDlc.vvvv</tt> || '''Pulse 1''' '''D'''uty cycle, [[APU Length Counter|length counter halt]], '''c'''onstant volume/[[APU Envelope|envelope]] flag, and '''v'''olume/envelope divider period<br />
|-<br />
| '''$4004''' || <tt>DDlc.vvvv</tt> || '''Pulse 2''' '''D'''uty cycle, [[APU Length Counter|length counter halt]], '''c'''onstant volume/[[APU Envelope|envelope]] flag, and '''v'''olume/envelope divider period<br />
|-<br />
|colspan=2| Side effects || The duty cycle is changed (see table below), but the sequencer's current position isn't affected.<br />
|-<br />
|colspan=3| &nbsp;<br />
|-<br />
| '''$4002''' || <tt>LLLL.LLLL</tt> || '''Pulse 1''' timer '''L'''ow 8 bits<br />
|-<br />
| '''$4006''' || <tt>LLLL.LLLL</tt> || '''Pulse 2''' timer '''L'''ow 8 bits<br />
|-<br />
|colspan=3| &nbsp;<br />
|-<br />
| '''$4003''' || <tt>llll.lHHH</tt> || '''Pulse 1''' [[APU Length Counter|length counter load]] and timer '''H'''igh 3 bits<br />
|-<br />
| '''$4007''' || <tt>llll.lHHH</tt> || '''Pulse 2''' [[APU Length Counter|length counter load]] and timer '''H'''igh 3 bits<br />
|-<br />
|colspan=2| Side effects || The sequencer is immediately restarted at the first value of the current sequence. The [[APU Envelope|envelope]] is also restarted.<br />
|}<br />
<br />
'''Duty Cycle Sequences'''<br />
{|<br />
! Duty || Waveform sequence<br />
|-<br />
| 0 || <tt>0 1 0 0 0 0 0 0</tt> (12.5%)<br />
|-<br />
| 1 || <tt>0 1 1 0 0 0 0 0</tt> (25%)<br />
|-<br />
| 2 || <tt>0 1 1 1 1 0 0 0</tt> (50%)<br />
|-<br />
| 3 || <tt>1 0 0 1 1 1 1 1</tt> (25% negated)<br />
|}<br />
:The reason for these odd sequences is that the sequence counter is initialized to zero but counts ''downward'' rather than upward<br />
<br />
The sequencer is clocked by an 11-bit [[APU Misc|timer]]. Given the timer value ''t = HHHLLLLLLLL'' formed by timer high and timer low,<br />
this timer is updated every APU cycle (i.e., every second CPU cycle), and counts ''t, t-1, ..., 0, t, t-1, ...'', clocking the waveform<br />
generator when it goes from 0 to t. Since the period of the timer is ''t+1'' APU cycles and the sequencer has 8 steps, the period of the waveform is<br />
''8*(t+1)'' APU cycles, or equivalently ''16*(t+1)'' CPU cycles.<br />
<br />
Hence<br />
<br />
* f<sub>pulse</sub> = f<sub>CPU</sub>/(16*(t+1)) (where f<sub>CPU</sub> is 1.789773 MHz for NTSC, 1.662607 MHz for PAL, and 1.773448 MHz for Dendy)<br />
* t = f<sub>CPU</sub>/(16*f<sub>pulse</sub>) - 1<br />
<br />
A period of ''t < 8'', either set explicitly or via a sweep period update, silences the corresponding pulse channel. The highest frequency a pulse channel can output is hence about 12.4 kHz for NTSC. ('''TODO:''' PAL behavior?)<br />
<br />
The [[APU Mixer|mixer]] receives the current [[APU Envelope|envelope volume]] except when<br />
* The sequencer output is zero, or<br />
* overflow from the [[APU Sweep|sweep]] unit's adder is silencing the channel, or<br />
* the [[APU Length Counter|length counter]] is zero, or<br />
* the timer has a value less than eight.<br />
<br />
The behavior of the two pulse channels differs only in the effect of the negate mode of their [[APU Sweep|sweep units]].<br />
<br />
Notice that a few Famiclone units have swapped APU duty cycles, as 12.5, 50, 25 and 25 negated instead.</div>Zepperhttps://www.nesdev.org/w/index.php?title=APU_Frame_Counter&diff=446APU Frame Counter2016-12-27T12:39:41Z<p>Zepper: Removed duplicated/unnecessary note.</p>
<hr />
<div>[[Category:APU]]<br />
The '''[[APU|NES APU]] frame counter''' (or '''frame sequencer''') generates low-frequency clocks for the channels and an optional 60 Hz interrupt.<br />
The name "frame counter" might be slightly misleading because the clocks have nothing to do with the video signal.<br />
<br />
The frame counter contains the following: [[APU Misc|divider]], looping clock [[APU Misc|sequencer]], frame interrupt flag.<br />
<br />
The sequencer is clocked on every other CPU cycle, so 2 CPU cycles = 1 APU cycle. The sequencer keeps track of how many APU cycles have elapsed in total, and each step of the sequence will occur once that total has reached the indicated amount (with an additional delay of one CPU cycle for the quarter and half frame signals). Once the last step has executed, the count resets to 0 on the next APU cycle.<br />
<br />
{| class="tabular"<br />
| Address || Bitfield || Description<br />
|-<br />
| '''$4017''' || <tt>MI--.----</tt> || '''Set mode and interrupt''' (write)<br />
|-<br />
| Bit 7 || <tt>M--- ----</tt> || Sequencer mode: 0 selects 4-step sequence, 1 selects 5-step sequence<br />
|-<br />
| Bit 6 || <tt>-I-- ----</tt> || Interrupt inhibit flag. If set, the frame interrupt flag is cleared, otherwise it is unaffected.<br />
|-<br />
|colspan=2| Side effects || After 3 or 4 CPU clock cycles*, the timer is reset.<br>If the mode flag is set, then both "quarter frame" and "half frame" signals are also generated.<br />
|}<br />
<nowiki>*</nowiki> If the write occurs ''during'' an APU cycle, the effects occur 3 CPU cycles after the '''$4017''' write cycle, and if the write occurs ''between'' APU cycles, the effects occurs 4 CPU cycles after the write cycle.<br />
<br />
''TODO: describe PAL''<br />
<br />
The frame interrupt flag is connected to the [[CPU]]'s IRQ line. It is set at a particular point in the 4-step sequence (see below) provided the interrupt inhibit flag in $4017 is clear, and can be cleared either by reading $4015 (which also returns its old status) or by setting the interrupt inhibit flag.<br />
<br />
=== Mode 0: 4-Step Sequence (bit 7 of $4017 clear) ===<br />
{| class="tabular"<br />
| Step || APU cycles || [[APU Envelope|Envelopes]] & [[APU Triangle|triangle's linear counter]] (Quarter frame) || [[APU Length Counter|Length counters]] & [[APU Sweep|sweep units]] (Half frame) || Frame interrupt flag<br />
|-<br />
| 1 || 3728.5 || Clock || &nbsp; || &nbsp;<br />
|-<br />
| 2 || 7456.5 || Clock || Clock || &nbsp;<br />
|-<br />
| 3 || 11185.5 || Clock || &nbsp; || &nbsp;<br />
|-<br />
| 4 || 14914 || &nbsp; || &nbsp; || Set if interrupt inhibit is clear<br />
|-<br />
| || 14914.5 || Clock || Clock || Set if interrupt inhibit is clear<br />
|-<br />
| || 0 (14915) || &nbsp; || &nbsp; || Set if interrupt inhibit is clear<br />
|-<br />
| || &nbsp; || ''240 Hz (approx.)'' || ''120 Hz (approx.)'' || ''60 Hz (approx.)''<br />
|}<br />
<br />
In this mode, the interrupt flag is set every 29830 CPU cycles, which is slightly slower than the 29780.5 CPU cycles per NTSC PPU frame.<br />
<br />
Some Nintendo arcade boards, even those not directly based on the NES, use the 2A03 CPU as a sound processor. Examples include ''[[wikipedia:Punch-Out!! (arcade game)|Punch-Out!!]]'' and ''[[wikipedia:Donkey Kong 3|Donkey Kong 3]]''. This IRQ allows the CPU to keep time even if no PPU is connected to the bus.<br />
<br />
=== Mode 1: 5-Step Sequence (bit 7 of $4017 set) ===<br />
{| class="tabular"<br />
| Step || APU cycles || [[APU Envelope|Envelopes]] & [[APU Triangle|triangle's linear counter]] (Quarter frame) || [[APU Length Counter|Length counters]] & [[APU Sweep|sweep units]] (Half frame)<br />
|-<br />
| 1 || 3728.5 || Clock || &nbsp;<br />
|-<br />
| 2 || 7456.5 || Clock || Clock<br />
|-<br />
| 3 || 11185.5 || Clock || &nbsp;<br />
|-<br />
| 4 || 14914.5 || &nbsp; || &nbsp;<br />
|-<br />
| 5 || 18640.5 || Clock || Clock<br />
|-<br />
| || 0 (18641) || &nbsp; || &nbsp;<br />
|-<br />
| || &nbsp; || ''192 Hz (approx.), uneven timing'' || ''96 Hz (approx.), uneven timing''<br />
|}<br />
<br />
In this mode, the frame interrupt flag is never set.<br></div>Zepperhttps://www.nesdev.org/w/index.php?title=APU&diff=337APU2016-12-27T12:38:16Z<p>Zepper: /* Frame Counter ($4017) */ Added more details.</p>
<hr />
<div>[[Category:APU]]<br />
The NES '''APU''' is the '''audio processing unit''' in the NES console which generates sound for games. It is implemented in the RP2A03 (NTSC) and RP2A07 (PAL) chips. Its [[APU registers|registers]] are mapped in the range $4000-$4013, $4015 and $4017.<br />
<br />
== Overview ==<br />
<br />
The APU has five channels: two pulse wave generators, a triangle wave, noise, and a delta modulation channel for playing DPCM samples.<br />
<br />
Each channel has a variable-rate timer clocking a waveform generator, and various modulators driven by low-frequency clocks from the [[#Frame Counter ($4017)|frame counter]]. The [[#DMC ($4010-4013)|DMC]] plays samples while the other channels play waveforms. Each sub-unit of a channel generally runs independently and in parallel to other units, and modification of a channel's parameter usually affects only one sub-unit and doesn't take effect until that unit's next internal cycle begins.<br />
<br />
The read/write [[#Status ($4015)|status register]] allows channels to be enabled and disabled, and their current [[#Length Counter|length counter status]] to be queried.<br />
<br />
The outputs from all the channels are combined using a [[APU Mixer|non-linear mixing]] scheme.<br />
<br />
=== Conditions for channel output ===<br />
<br />
The pulse, triangle, and noise channels will play their corresponding waveforms (at either a constant volume or at a volume controlled by an [[APU Envelope|envelope]]) only when (and in the model given here, ''precisely'' when) their [[#Length Counter|length counters]] are all non-zero (this includes the linear counter for the triangle channel). There are two exceptions for the pulse channels, which can also be silenced either by having a frequency above a certain threshold (see below), or by a [[APU Sweep|sweep]] towards lower frequencies (longer periods) reaching the end of the range.<br />
<br />
The DMC channel always outputs the value of its counter, regardless of the status of the DMC enable bit; the enable bit only controls automatic playback of delta-encoded samples (which is done through counter updates).<br />
<br />
=== Notes ===<br />
<br />
* This reference describes the ''abstract'' operation of the APU. The ''exact'' hardware implementation is not necessarily relevant to an emulator, but the [http://www.qmtpro.com/~nes/chipimages/visual2a03/ Visual 2A03] project can be used to determine detailed information about the hardware implementation.<br />
<br />
* The [[Famicom]] had an audio return loop on its [[cartridge connector]] allowing extra audio from individual cartridges. See [[:Category:Expansion audio|Expansion audio]] for details on the audio produced by various [[Mapper|mappers]].<br />
<br />
* For a basic usage guide to the APU, see [[APU basics]], or [[Nerdy Nights: APU overview]].<br />
<br />
* The APU may have additional diagnostic features if CPU pin 30 is pulled high. See [[:File:Apu_address.jpg|diagram by Quietust]].<br />
<br />
== Specification ==<br />
<br />
=== Registers ===<br />
* See [[APU registers|APU Registers]] for a complete APU register diagram.<br />
<br />
{| class="tabular"<br />
! Registers || Channel || Units<br />
|-<br />
! $4000-$4003<br />
| [[#Pulse ($4000-4007)|Pulse 1]] || Timer, [[#Length Counter|length counter]], [[APU Envelope|envelope]], [[APU Sweep|sweep]]<br />
|-<br />
! $4004-$4007<br />
| [[#Pulse ($4000-4007)|Pulse 2]] || Timer, [[#Length Counter|length counter]], [[APU Envelope|envelope]], [[APU Sweep|sweep]]<br />
|-<br />
! $4008-$400B<br />
| [[#Triangle ($4008-400B)|Triangle]] || Timer, [[#Length Counter|length counter]], linear counter<br />
|-<br />
! $400C-$400F<br />
| [[#Noise ($400C-400F)|Noise]] || Timer, [[#Length Counter|length counter]], [[APU Envelope|envelope]], linear feedback shift register<br />
|-<br />
! $4010-$4013<br />
| [[#DMC ($4010-4013)|DMC]] || Timer, memory reader, sample buffer, output unit<br />
|-<br />
! $4015<br />
| All || [[#Status ($4015)|Channel enable and length counter status]]<br />
|-<br />
! $4017<br />
| All || [[#Frame Counter ($4017)|Frame counter]]<br />
|}<br />
<br />
=== Pulse ($4000-4007) ===<br />
* See [[APU Pulse]]<br />
<br />
The pulse channels produce a variable-width pulse signal, controlled by volume, envelope, length, and sweep units.<br />
<br />
{| class="tabular"<br />
! $4000 / $4004<br />
| <tt>DDLC VVVV</tt> || Duty (D), envelope loop / length counter halt (L), constant volume (C), volume/envelope (V)<br />
|-<br />
! $4001 / $4005<br />
| <tt>EPPP NSSS</tt> || Sweep unit: enabled (E), period (P), negate (N), shift (S)<br />
|-<br />
! $4002 / $4006<br />
| <tt>TTTT TTTT</tt> || Timer low (T)<br />
|-<br />
! $4003 / $4007<br />
| <tt>LLLL LTTT</tt> || Length counter load (L), timer high (T)<br />
|}<br />
<br />
* The frequency of the pulse channels is a division of the [[Clock rate|CPU Clock]] (1.789773MHz NTSC, 1.662607MHz PAL). The output frequency (f) of the generator can be determined by the 11-bit period value (t) written to $4002-4003/$4006-4007. If t < 8, the corresponding pulse channel is silenced.<br />
<br />
f = CPU / (16 * (t + 1))<br />
t = (CPU / (16 * f)) - 1<br />
<br />
* The width of the pulse is controlled by the duty bits in $4000/4004. See [[APU Pulse]] for details.<br />
<br />
* The channel volume is a 4-bit value that is either constant, or controlled by an envelope (chosen by $4000/4004 bit 4). If using the envelope, the 4-bit value in $4000/4004 is the period of the envelope, otherwise it is the direct volume.<br />
<br />
* The length counter and envelope units are clocked by the [[#Frame Counter|frame counter]]. If the envelope is not looped, the length counter must be enabled (making it redundant if longer than the envelope). The length counter simply silences the channel when it counts down to 0. The envelope starts at a volume of 15 and decrements every time the unit is clocked, stopping at 0 if not looped.<br />
<br />
* Writing to $4003/4007 reloads the length counter, restarts the envelope, and resets the phase of the pulse generator. Because it resets phase, vibrato should only write the low timer register to avoid a phase reset click. At some pitches, particularly near A440, wide vibrato should normally be avoided (e.g. this flaw is heard throughout the Mega Man 2 ending).<br />
<br />
* Registers $4001/4005 control the sweep unit. Enabling the sweep causes the pitch to constantly rise or fall. When the frequency reaches the end of the generator's range of output the channel is silenced. See [[APU Sweep]] for details.<br />
<br />
* The two pulse channels are combined in a nonlinear mix (see [[#Mixer|mixer]] below).<br />
<br />
=== Triangle ($4008-400B) ===<br />
* See [[APU Triangle]]<br />
<br />
The triangle channel produces a quantized triangle wave. It has no volume control, but it has a length counter as well as a higher resolution linear counter control (called "linear" since it uses the 7-bit value written to $4008 directly instead of a lookup table like the length counter).<br />
<br />
{| class="tabular"<br />
! $4008<br />
| <tt>CRRR RRRR</tt> || Length counter halt / linear counter control (C), linear counter load (R)<br />
|-<br />
! $4009<br />
| <tt>---- ----</tt> || Unused<br />
|-<br />
! $400A<br />
| <tt>TTTT TTTT</tt> || Timer low (T)<br />
|-<br />
! $400B<br />
| <tt>LLLL LTTT</tt> || Length counter load (L), timer high (T)<br />
|}<br />
<br />
* The triangle wave has 32 steps that output a 4-bit value.<br />
<br />
* The linear counter control will silence the channel after a specified time with a resolution of 240Hz in NTSC (see [[#Frame Counter|frame counter]] below). It shares a control bit with the length counter in $4008, which means that they are always enabled at the same time, and whichever is longer is redundant. See [[APU Triangle]] for more linear counter details.<br />
<br />
* The pitch of the triangle channel is one octave below the pulse channels with an equivalent timer value (i.e. use the formula above but divide the resulting frequency by two).<br />
<br />
* Silencing the triangle channel merely halts it. It will continue to output its last value, rather than 0.<br />
<br />
* There is no way to reset the triangle channel's phase.<br />
<br />
=== Noise ($400C-400F) ===<br />
* See [[APU Noise]]<br />
<br />
The noise channel produces noise with a pseudo-random bit generator.<br />
It has a volume, envelope, and length counter like the pulse channels.<br />
<br />
{| class="tabular"<br />
! $400C<br />
| <tt>--LC VVVV</tt> || Envelope loop / length counter halt (L), constant volume (C), volume/envelope (V)<br />
|-<br />
! $400D<br />
| <tt>---- ----</tt> || Unused<br />
|-<br />
! $400E<br />
| <tt>L--- PPPP</tt> || Loop noise (L), noise period (P)<br />
|-<br />
! $400F<br />
| <tt>LLLL L---</tt> || Length counter load (L)<br />
|}<br />
<br />
* The frequency of the noise is determined by a 4-bit value in $400E, which loads a period from a lookup table (see [[APU Noise]]).<br />
<br />
* If bit 7 of $400E is set, the period of the random bit generation is drastically shortened, producing a buzzing tone (e.g. the metalic ding during Solstice's gameplay). The actual timbre produced depends on whatever bits happen to be in the generator when it is switched to periodic, and is somewhat random.<br />
<br />
=== DMC ($4010-4013) ===<br />
* See [[APU DMC]]<br />
<br />
The delta modulation channel outputs a 7-bit PCM signal from a counter that can be driven by DPCM samples.<br />
<br />
{| class="tabular"<br />
! $4010<br />
| <tt>IL-- RRRR</tt> || IRQ enable (I), loop (L), frequency (R)<br />
|-<br />
! $4011<br />
| <tt>-DDD DDDD</tt> || Load counter (D)<br />
|-<br />
! $4012<br />
| <tt>AAAA AAAA</tt> || Sample address (A)<br />
|-<br />
! $4013<br />
| <tt>LLLL LLLL</tt> || Sample length (L)<br />
|}<br />
<br />
* DPCM samples are stored as a stream of 1-bit deltas that control the 7-bit PCM counter that the channel outputs. A bit of 1 will increment the counter, 0 will decrement, and it will clamp rather than overflow if the 7-bit range is exceeded.<br />
<br />
* DPCM samples may loop if the loop flag in $4010 is set, and the DMC may be used to generate an IRQ when the end of the sample is reached if its IRQ flag is set.<br />
<br />
* The playback rate is controlled by register $4010 with a 4-bit frequency index value (see [[APU DMC]] for frequency lookup tables).<br />
<br />
* DPCM samples must begin in the memory range $C000-FFFF at an address set by register $4012 (address = %11AAAAAA.AA000000).<br />
<br />
* The length of the sample in bytes is set by register $4013 (length = %LLLL.LLLL0001).<br />
<br />
==== Other Uses ====<br />
<br />
* The $4011 register can be used to play PCM samples directly by setting the counter value at a high frequency. Because this requires intensive use of the CPU, when used in games all other gameplay is usually halted to facilitate this.<br />
<br />
* Because of the APU's [[#Mixer|nonlinear mixing]], a high value in the PCM counter reduces the volume of the triangle and noise channels. This is sometimes used to apply limited volume control to the triangle channel (e.g. Super Mario Bros. adjusts the counter between levels to accomplish this).<br />
<br />
* The DMC's IRQ can be used as an IRQ based timer when the [[Mapper|mapper]] used does not have one available.<br />
<br />
=== Status ($4015) ===<br />
The status register is used to enable and disable individual channels, control the DMC, and can<br />
read the status of length counters and APU interrupts.<br />
<br />
{| class="tabular"<br />
! $4015 write<br />
| <tt>---D NT21</tt> || Enable DMC (D), noise (N), triangle (T), and pulse channels (2/1)<br />
|}<br />
<br />
* Writing a zero to any of the channel enable bits will silence that channel and immediately set its length counter to 0.<br />
* If the DMC bit is clear, the DMC bytes remaining will be set to 0 and the DMC will silence when it empties.<br />
* If the DMC bit is set, the DMC sample will be restarted ''only if'' its bytes remaining is 0. If there are bits remaining in the 1-byte sample buffer, these will finish playing before the next sample is fetched.<br />
* Writing to this register clears the DMC interrupt flag.<br />
* [[CPU power up state|Power-up and reset]] have the effect of writing $00, silencing all channels.<br />
<br />
{| class="tabular"<br />
! $4015 read<br />
| <tt>IF-D NT21</tt> || DMC interrupt (I), frame interrupt (F), DMC active (D), length counter > 0 (N/T/2/1)<br />
|}<br />
<br />
* N/T/2/1 will read as 1 if the corresponding length counter is greater than 0. For the triangle channel, the status of the linear counter is irrelevant.<br />
* D will read as 1 if the DMC bytes remaining is more than 0.<br />
* Reading this register clears the frame interrupt flag (but not the DMC interrupt flag).<br />
* If an interrupt flag was set at the same moment of the read, it will read back as 1 but it will ''not'' be cleared.<br />
<br />
=== Frame Counter ($4017) ===<br />
* See [[APU Frame Counter]]<br />
<br />
{| class="tabular"<br />
! $4017<br />
| <tt>MI-- ----</tt> || Mode (M, 0 = 4-step, 1 = 5-step), IRQ inhibit flag (I)<br />
|}<br />
<br />
The frame counter is controlled by register $4017, and it drives the envelope, sweep, and length units on the pulse, triangle and noise channels. It ticks approximately 4 times per frame (240Hz NTSC), and executes either a 4 or 5 step sequence, depending how it is configured. It may optionally issue an [[IRQ]] on the last tick of the 4 step sequence.<br />
<br />
The following diagram illustrates the two modes, selected by bit 7 of $4017:<br />
<br />
mode 0: mode 1: function<br />
--------- ----------- -----------------------------<br />
- - - f - - - - - IRQ (if bit 6 is clear)<br />
- l - l l - l - - Length counter and sweep<br />
e e e e e e e e - Envelope and linear counter<br />
<br />
Both the 4 and 5-step modes operate at the same rate, but because the 5-step mode has an extra step, the effective update rate for individual units is slower in that mode (total update taking ~60Hz vs ~48Hz in NTSC). Writing to $4017 resets the frame counter and the quarter/half frame triggers happen simultaneously, but only on "odd" cycles (and only after the first "even" cycle after the write occurs) - thus, it happens either 2 or 3 cycles after the write (i.e. on the 2nd or 3rd cycle of the next instruction). After 2 or 3 clock cycles (depending on when the write is performed), the timer is reset. Writing to $4017 with bit 7 set ($80) will immediately clock all of its controlled units at the beginning of the 5-step sequence; with bit 7 clear, only the sequence is reset without clocking any of its units.<br />
<br />
Note that the frame counter is not exactly synchronized with the PPU [[NMI]]; it runs independently at a consistent rate which is approximately 240Hz (NTSC). Some games (e.g. Super Mario Bros., Zelda) manually synchronize it by writing $C0 or $FF to $4017 once per frame.<br />
<br />
==== Length Counter ====<br />
* See [[APU Length Counter]]<br />
<br />
The pulse, triangle, and noise channels each have their own length counter unit. It is clocked twice per sequence, and counts down to zero if enabled. When the length counter reaches zero the channel is silenced. It is reloaded by writing a 5-bit value to the appropriate channel's length counter register, which will load a value from a lookup table. (See [[APU Length Counter]] for the table.)<br />
<br />
The triangle channel has an additional '''linear counter''' unit which is clocked four times per sequence (like the envelope of the other channels). It functions independently of the length counter, and will also silence the triangle channel when it reaches zero.<br />
<br />
=== Mixer ===<br />
* See [[APU Mixer]]<br />
<br />
The APU audio output signal comes from two separate components. The pulse channels are output on one pin, and the triangle/noise/DMC are output on another, after which they are combined. Each of these channels has its own nonlinear DAC. For details, see [[APU Mixer]].<br />
<br />
After combining the two output signals, the final signal may go through a lowpass and highpass filter. For instance, RF demodulation in televisions usually results in a strong lowpass. The NES' RCA output circuitry has a more mild lowpass filter.<br />
<br />
== Glossary ==<br />
<br />
* All [[APU]] channels have some form of frequency control. The term '''frequency''' is used where larger register value(s) correspond with higher frequencies, and the term '''period''' is used where smaller register value(s) correspond with higher frequencies.<br />
<br />
* In the block diagrams, a '''gate''' takes the input on the left and outputs it on the right, unless the control input on top tells the gate to ignore the input and always output 0.<br />
<br />
* Some [[APU]] units use one or more of the following building blocks:<br />
<br />
:* A '''divider''' outputs a clock periodically. It contains a period reload value, P, and a counter, that starts at P. When the divider is clocked, if the counter is currently 0, it is reloaded with P and generates an output clock, otherwise the counter is decremented. In other words, the divider's period is P + 1.<br />
<br />
:* A divider can also be forced to reload its counter immediately (counter = P), but this ''does not'' output a clock. Similarly, changing a divider's period reload value ''does not'' affect the counter.<br />
<br />
:* A divider may be implemented as a down counter (5, 4, 3, ...) or as a [[wikipedia:linear feedback shift register|linear feedback shift register]] (LFSR). The dividers in the pulse and triangle channels are linear down-counters. The dividers for noise, DMC, and the APU Frame Counter are implemented as LFSRs to save gates compared to the equivalent down counter.<br />
<br />
:* A '''sequencer''' continuously loops over a sequence of values or events. When clocked, the next item in the sequence is generated.<br />
<br />
:* A '''timer''' is used in each of the five channels to control the sound frequency. It contains a divider which is clocked by the [[CPU]] clock. The triangle channel's timer is clocked on every CPU cycle, but the pulse, noise, and DMC timers are clocked only on every second CPU cycle and thus produce only even periods.<br />
<br />
== References ==<br />
<br />
* [http://nesdev.org/apu_ref.txt Blargg's NES APU Reference].<br />
* [http://nesdev.org/2A03%20technical%20reference.txt Brad Taylor's 2A03 Technical Reference].</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_227&diff=5773INES Mapper 2272016-12-25T04:20:47Z<p>Zepper: /* oops! */</p>
<hr />
<div>[[Category:iNES Mappers|227]][[Category:Multicart mappers|227]]<br />
The Chinese unlicensed game <i>[NJXXX] Xiang Shuai Chuan Qi</i> will fail to load pattern data if the below notes on write protection are employed. Is this feature only on some 227 carts (more likely multicarts)? The write protection has been temporarily disabled in fceux and bizhawk until more evidence is gathered. It should be noted that VirtuaNES doesn't use the write protection.<br />
<br />
In r2750 of fceux this support was rewritten; it should still work. It supposedly works in nestopia as well.<br />
<br />
Here are Disch's original notes.<br />
Menu information added by Zepper, thanks to zxbdragon. <br />
========================<br />
= Mapper 227 =<br />
========================<br />
<br />
<br />
Example Game:<br />
--------------------------<br />
1200-in-1<br />
600-in-1<br />
<br />
<br />
Notes:<br />
---------------------------<br />
This mapper has 8k CHR-RAM, and also has the ability to write protect it's CHR-RAM!<br />
<br />
<br />
Registers:<br />
---------------------------<br />
This mapper uses the address written for its setup. The value is irrelevant.<br />
<br />
$8000-FFFF: A~[.... .mLP OPPP PPMS]<br />
L = Last PRG Page Mode<br />
P = PRG Reg<br />
O = Mode<br />
M = Mirroring (0=Vert, 1=Horz)<br />
S = PRG Size<br />
m = Menu list (see below)<br />
<br />
Setup:<br />
---------------------------<br />
<br />
When 'O' is set, CHR-RAM is write protected (writes have no effect). 'O' also changes the PRG mode.<br />
<br />
Note there is funky ANDs and ORs going on below depending on the modes:<br />
<br />
<br />
$8000 $A000 $C000 $E000 <br />
+---------------+---------------+<br />
O=1, S=0: | P | P |<br />
+-------------------------------+<br />
O=1, S=1: | < P > |<br />
+-------------------------------+<br />
O=0, S=0, L=0: | P | P AND $38 |<br />
+---------------+---------------+<br />
O=0, S=1, L=0: | P AND $3E | P AND $38 |<br />
+---------------+---------------+<br />
O=0, S=0, L=1: | P | P OR $07 |<br />
+---------------+---------------+<br />
O=0, S=1, L=1: | P AND $3E | P OR $07 |<br />
+---------------+---------------+<br />
<br />
Menu list:<br />
---------------------------<br />
The following information does not work for the 1200in1 cartridge!<br />
Bit 11 of the address written activates the menu list selection. When activated, reading anywhere<br />
at $8000-$FFFF returns the menu list type (value x 8) described below; otherwise, returns PRG ROM<br />
data at $8000-$FFFF.<br />
+-------+----------------------------+<br />
| value | number of selectable games |<br />
+-------+----------------------------+<br />
| 0 | 860 in 1 |<br />
| 1 | 460 in 1 |<br />
| 2 | 500 in 1 |<br />
| 3 | 560 in 1 |<br />
| 4 | 600 in 1 |<br />
| 5 | 660 in 1 |<br />
| 6 | 700 in 1 |<br />
| 7 | 860 in 1 |<br />
| 8 | 900 in 1 |<br />
| 9 | 920 in 1 |<br />
| 10 | 940 in 1 |<br />
| 11 | 960 in 1 |<br />
| 12 | 980 in 1 |<br />
| 13 | 400 in 1 |<br />
| 14 | 380 in 1 |<br />
| 15 | 360 in 1 |<br />
+-------+----------------------------+<br />
| 16~19 | blue screen |<br />
| 20 | up to 980, 981+ bugged |<br />
| 21 | same of 21 |<br />
| 22 | 40 in 1, clipped list |<br />
| 23~31 | blue screen |<br />
| 32 | 420 in 1 |<br />
| 33 | 460 in 1 (same of 1) $21 |<br />
| 34 | 500 in 1 (same of 2) $22 |<br />
+-------+----------------------------+</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_227&diff=5772INES Mapper 2272016-12-25T04:19:01Z<p>Zepper: /* added menu list selection */</p>
<hr />
<div>[[Category:iNES Mappers|227]][[Category:Multicart mappers|227]]<br />
The Chinese unlicensed game <i>[NJXXX] Xiang Shuai Chuan Qi</i> will fail to load pattern data if the below notes on write protection are employed. Is this feature only on some 227 carts (more likely multicarts)? The write protection has been temporarily disabled in fceux and bizhawk until more evidence is gathered. It should be noted that VirtuaNES doesn't use the write protection.<br />
<br />
In r2750 of fceux this support was rewritten; it should still work. It supposedly works in nestopia as well.<br />
<br />
Here are Disch's original notes.<br />
Menu information added by Zepper, thanks to zxbdragon. <br />
========================<br />
= Mapper 227 =<br />
========================<br />
<br />
<br />
Example Game:<br />
--------------------------<br />
1200-in-1<br />
600-in-1<br />
<br />
<br />
Notes:<br />
---------------------------<br />
This mapper has 8k CHR-RAM, and also has the ability to write protect it's CHR-RAM!<br />
<br />
<br />
Registers:<br />
---------------------------<br />
This mapper uses the address written for its setup. The value is irrelevant.<br />
<br />
$8000-FFFF: A~[.... .mLP OPPP PPMS]<br />
L = Last PRG Page Mode<br />
P = PRG Reg<br />
O = Mode<br />
M = Mirroring (0=Vert, 1=Horz)<br />
S = PRG Size<br />
m = Menu list (see below)<br />
<br />
Setup:<br />
---------------------------<br />
<br />
When 'O' is set, CHR-RAM is write protected (writes have no effect). 'O' also changes the PRG mode.<br />
<br />
Note there is funky ANDs and ORs going on below depending on the modes:<br />
<br />
<br />
$8000 $A000 $C000 $E000 <br />
+---------------+---------------+<br />
O=1, S=0: | P | P |<br />
+-------------------------------+<br />
O=1, S=1: | < P > |<br />
+-------------------------------+<br />
O=0, S=0, L=0: | P | P AND $38 |<br />
+---------------+---------------+<br />
O=0, S=1, L=0: | P AND $3E | P AND $38 |<br />
+---------------+---------------+<br />
O=0, S=0, L=1: | P | P OR $07 |<br />
+---------------+---------------+<br />
O=0, S=1, L=1: | P AND $3E | P OR $07 |<br />
+---------------+---------------+<br />
<br />
Menu list:<br />
---------------------------<br />
The following information does not work for the 1200in1 cartridge!<br />
Bit 11 of the address written activates the menu list selection. When activated, reading anywhere<br />
at $8000-$FFFF returns the menu list type (value) described below; otherwise, returns PRG ROM<br />
data at $8000-$FFFF.<br />
+-------+----------------------------+<br />
| value | number of selectable games |<br />
+-------+----------------------------+<br />
| 0 | 860 in 1 |<br />
| 1 | 460 in 1 |<br />
| 2 | 500 in 1 |<br />
| 3 | 560 in 1 |<br />
| 4 | 600 in 1 |<br />
| 5 | 660 in 1 |<br />
| 6 | 700 in 1 |<br />
| 7 | 860 in 1 |<br />
| 8 | 900 in 1 |<br />
| 9 | 920 in 1 |<br />
| 10 | 940 in 1 |<br />
| 11 | 960 in 1 |<br />
| 12 | 980 in 1 |<br />
| 13 | 400 in 1 |<br />
| 14 | 380 in 1 |<br />
| 15 | 360 in 1 |<br />
+-------+----------------------------+<br />
| 16~19 | blue screen |<br />
| 20 | up to 980, 981+ bugged |<br />
| 21 | same of 21 |<br />
| 22 | 40 in 1, clipped list |<br />
| 23~31 | blue screen |<br />
| 32 | 420 in 1 |<br />
| 33 | 460 in 1 (same of 1) $21 |<br />
| 34 | 500 in 1 (same of 2) $22 |<br />
+-------+----------------------------+</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:INES_Mapper_227&diff=14151Talk:INES Mapper 2272016-12-25T03:57:02Z<p>Zepper: /* /* update */ */ new section</p>
<hr />
<div>puNES uses (addr >> 3) for the PRG bank. The info says (addr >> 2).<br />
$8000-FFFF: A~[.... ..LP OPPP PPMS]<br />
<br />
What's the correct info after all?<br />
<br />
== /* update */ ==<br />
<br />
I can confirm that Disch' information is correct.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:PPU_sprite_evaluation&diff=15469Talk:PPU sprite evaluation2016-09-07T01:04:49Z<p>Zepper: last round</p>
<hr />
<div>== Sprite zero with sprites disabled ==<br />
The article says: "According to the blargg's sprite zero hit tests, sprites are NOT evaluated in the pre-render scanline. Plus, the evaluation occurs if sprites OR background are enabled."<br />
<br />
I find the second sentence problematic. I took it to mean that the sprite zero flag will still be set even if sprites are disabled in PPUMASK. But in fact it will not. I was pretty annoyed to find that out the hard way! So what is this trying to say, then? - [[User:Furrykef|Furrykef]] ([[User talk:Furrykef|talk]]) 01:10, 30 August 2016 (MDT)<br />
<br />
:I think this is worded very confusingly. Sprite "evaluation" is a vague and unclear term, especially since you've determined that sprite 0 hit won't be caused when sprites are disabled. I think it means that the OAM is accessed and refreshed as long as either the sprites or background are enabled. This is important for OAM decay, at least, but I don't know about other factors. Does sprite overflow still happen is sprites are disabled, but the background is? (Is that what "sprite evaluation" means?) Does sprite 0 hit still happen? (No. Right?) I think the whole sentence is a bit worthless as-is, to be honest. I think I'll delete it. - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 01:36, 30 August 2016 (MDT)<br />
<br />
::Man, you must be kidding now. It's not my fault if "sprite evaluation" is a vague term to you, sorry. Anyway, the sprite zero test FAILS (plain and simple) if the PPU sprite evaluation starts at scanline -1 (pre-render scanline). It should start at scanline 0, the first visible scanline. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:39, 5 September 2016 (MDT)<br />
::http://wiki.nesdev.org/w/index.php/PPU_sprite_evaluation<br />
<br />
Sprite evaluation *is* vague. It could mean fetch OAM data into temporary OAM or fetch data from VRAM based on temporary OAM data, and also the setting of sprite #0 and overflow flags. 3 different things. Also if might be mistaken, but sprite zero hit won't work either if sprites are enabled but not BG. You rally need both enabled for it to work. Disabling only sprites or only BG just replace them by blank patterns insternally, but still fetches the pattern in VRAM and internally replace them with all 0s, I guess. (Bregalad)<br />
[[Special:Contributions/128.178.126.68|128.178.126.68]] 07:21, 6 September 2016 (MDT)<br />
<br />
:I added a brief definition at the top of the page, and I tried to break up the removed sentence into a couple of ideas that I hope are more clear. ([http://wiki.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=12889&oldid=12382 revision 12889]) - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 11:27, 6 September 2016 (MDT)<br />
<br />
::Cool. Again, let me rephrase it. If the emulator (PPU) evaluates sprites at the pre-render scanline (-1), the sprite zero hit test will give an error. Simple. People that don't understand the PPU sprite evaluation proccess should read about it more and more, ever and ever... until it's clear. Crying here isn't good.--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 15:38, 6 September 2016 (MDT)<br />
<br />
:::I reverted [http://wiki.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=12898&oldid=12897 this change] because the difference between sprite 0 hit and sprite evaluation was ''precisely'' what was causing confusion. You removed my statement clarifying that, and then added something that says evaluation will cause sprite 0 test failure. This is not good! Sprite 0 hit does not happen in sprite evaluation! That's the whole problem here! - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 16:13, 6 September 2016 (MDT)<br />
<br />
:::I sort of understand your statement as "I implemented evaluation a line early by mistake, and it caused ''blargg's sprite 0 test ROM'' to fail (whatever that test is, you still need to clarify this), but if you really want to include that information you have to be more explicit about this. I don't really think it's a good idea to try to enumerate all the ways people might get emulation wrong (there are endless ways). The lack of evaluation on line 0 is clearly mentioned, is it not? - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 16:15, 6 September 2016 (MDT)<br />
<br />
::::"I implemented evaluation a line early by mistake, and it caused ''blargg's sprite 0 test ROM'' to fail". '''Correct'''. Actually, it's a hint ''JUST IN CASE'' someone is getting errors in the sprite #0 hit test ROM. Well, the lack of evaluation on line 0 was '''NOT''' clear, I asked a few times in the forum without success... until I got the sprite #0 test error and located the problem in my emulator. You see, it's a hint, not a rule. And I'm sorry for the trouble and language barrier, but I must discuss things at anyway.--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:04, 6 September 2016 (MDT)<br />
<br />
== Note about sprite address not zero ==<br />
<br />
:''If the sprite address ($2003) is not zero (usually, $2003 AND $F8) at the beginning of the pre-render scanline, then copy the contents of its 8-byte page into the first 8 bytes.''<br />
What does this mean? Is there a forum thread where this was discussed? Does this cause sprites to be rendered on scanline 0? - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 16:34, 6 September 2016 (MDT)<br />
<br />
::I found some relevant forum posts explaining it. What was very unclear to me was where these bytes were copied to. It sounded like it was to affect PPU sprite evaluation (because it's on the PPU sprite evaluation page), but it's actually a corruption of OAM that happens before evaluation begins. I rewrote the line hopefully making this clearer, and added links to the forum posts explaining it. - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 16:56, 6 September 2016 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=10304PPU sprite evaluation2016-09-06T21:41:12Z<p>Zepper: /* Notes */ Needless to get related "sprite eval. x sprite zero hits".</p>
<hr />
<div>'''PPU sprite evaluation''' is an operation done by the PPU once each scanline. It prepares the set of sprites and fetches their data to be rendered on the next scanline.<br />
<br />
This is a separate step from sprite rendering.<br />
<br />
== Overview ==<br />
Each scanline, the PPU reads the spritelist (that is, Object Attribute Memory) to see which to draw:<br />
# First, it clears the list of sprites to draw.<br />
# Second, it reads through OAM, checking which sprites will be on this scanline. It chooses the first eight it finds that do.<br />
# Third, if eight sprites were found, it checks (in a wrongly-implemented fashion) for further sprites on the scanline to see if the sprite overflow flag should be set.<br />
# Fourth, using the details for the eight (or fewer) sprites chosen, it determines which pixels each has on the scanline and where to draw them.<br />
== Details ==<br />
During all visible scanlines, the PPU scans through OAM to determine which sprites to render on the next scanline. Sprites found to be within range are copied into the secondary OAM, which is then used to initialize eight internal sprite output units.<br />
<br />
''OAM[n][m]'' below refers to the byte at offset ''4*n + m'' within OAM, i.e. OAM byte ''m'' (0-3) of sprite ''n'' (0-63).<br />
<br />
During each pixel clock (341 total per scanline), the PPU accesses OAM in the following pattern:<br />
<br />
# Cycles 1-64: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF. Internally, the clear operation is implemented by reading from the OAM and writing into the secondary OAM as usual, only a signal is active that makes the read always return $FF.<br />
# Cycles 65-256: Sprite evaluation<br />
#* ''On odd cycles, data is read from (primary) OAM''<br />
#* ''On even cycles, data is written to secondary OAM (unless secondary OAM is full, in which case it will read the value in secondary OAM instead)''<br />
#*1. Starting at n = 0, read a sprite's Y-coordinate (OAM[n][0], copying it to the next open slot in secondary OAM (unless 8 sprites have been found, in which case the write is ignored).<br />
#**1a. If Y-coordinate is in range, copy remaining bytes of sprite data (OAM[n][1] thru OAM[n][3]) into secondary OAM.<br />
#*2. Increment n<br />
#**2a. If n has overflowed back to zero (all 64 sprites evaluated), go to 4<br />
#**2b. If less than 8 sprites have been found, go to 1<br />
#**2c. If exactly 8 sprites have been found, disable writes to secondary OAM because it is full. This causes sprites in back to drop out.<br />
#*3. Starting at m = 0, evaluate OAM[n][m] as a Y-coordinate.<br />
#**3a. If the value is in range, set the sprite overflow flag in $2002 and read the next 3 entries of OAM (incrementing 'm' after each byte and incrementing 'n' when 'm' overflows); if m = 3, increment n<br />
#**3b. If the value is not in range, increment n '''and''' m (without carry). If n overflows to 0, go to 4; otherwise go to 3<br />
#***''The m increment is a hardware bug - if only n was incremented, the overflow flag would be set whenever more than 8 sprites were present on the same scanline, as expected.''<br />
#*4. Attempt (and fail) to copy OAM[n][0] into the next free slot in secondary OAM, and increment n (repeat until HBLANK is reached)<br />
# Cycles 257-320: Sprite fetches (8 sprites total, 8 cycles per sprite)<br />
#*1-4: Read the Y-coordinate, tile number, attributes, and X-coordinate of the selected sprite from secondary OAM<br />
#*5-8: Read the X-coordinate of the selected sprite from secondary OAM 4 times (while the PPU fetches the sprite tile data)<br />
#* For the first empty sprite slot, this will consist of sprite #63's Y-coordinate followed by 3 $FF bytes; for subsequent empty sprite slots, this will be four $FF bytes<br />
#Cycles 321-340+0: Background render pipeline initialization<br />
#* Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline)<br />
<br />
This pattern was determined by doing carefully timed reads from $2004 using various sets of sprites, and simulation in Visual 2C02 has subsequently confirmed this behavior.<br />
<br />
== Sprite overflow bug ==<br />
During sprite evaluation, if eight in-range sprites have been found so far, the sprite evaluation logic continues to scan the primary OAM looking for one more in-range sprite to determine whether to set the sprite overflow flag. The first such check correctly checks the y coordinate of the next OAM entry, but after that the logic breaks and starts scanning OAM "diagonally", evaluating the tile number/attributes/X-coordinates of subsequent OAM entries as Y-coordinates (due to incorrectly incrementing m when moving to the next sprite). This results in inconsistent sprite overflow behavior showing both false positives and false negatives.<br />
<br />
=== Cause of the sprite overflow bug ===<br />
After investigation in [[Visual 2C02]], the culprit of the sprite overflow bug appears to be the write disable signal that goes high after eight in-range sprites have been found (to prevent further updates to the secondary OAM), along with an error in the sprite evaluation logic.<br />
<br />
As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it. Once eight in-range sprites have been found, the value being read during write cycles from that point on is the y coordinate of the first sprite copied into the secondary OAM. Due to a logic error, the result of comparing this y coordinate to the current scanline number (which will always yield "in range", since the sprite would have had to be in range to get copied into the secondary OAM) is allowed to influence the sprite address incrementation logic, causing the glitchy updates to the sprite address seen above (due to how the timing works out). Once one more sprite has been found, another signal prevents the comparison from influencing the sprite address incrementation logic, and the bug is no longer in effect.<br />
<br />
=== Examples of usage ===<br />
For some examples of games using this bug/quirk, refer to the [[Sprite overflow games]] page.<br />
<br />
== Notes ==<br />
* Sprite evaluation does not happen on the pre-render scanline. Because evaluation applies to the next line's sprite rendering, no sprites will be rendered on the first scanline, and this is why there is a 1 line offset on a sprite's Y coordinate. If your emulator do sprite evaluation at the pre-render scanline, the sprite zero hit test will give an error.<br />
* Sprite evaluation occurs if ''either'' the sprite layer or background layer is enabled via $2001. Unless both layers are disabled, it merely hides sprite rendering.<br />
* If the sprite address ($2003) is not zero (usually, $2003 AND $F8) at the beginning of the pre-render scanline, then copy the contents of its 8-byte page into the first 8 bytes.<br />
* [[Visual 2C02]] might be helpful when trying to understand how the algorithm operates and what the precise timings are.<br />
<br />
== External links ==<br />
*[https://gist.github.com/beannaich/7a7ba066d909318debea Visual 2C02 logs of the PPU evaluating 1, 8, and 9 sprites] by beannaich</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:PPU_sprite_evaluation&diff=15464Talk:PPU sprite evaluation2016-09-06T21:38:28Z<p>Zepper: /* Sprite zero X sprite evaluation */</p>
<hr />
<div>== Sprite zero with sprites disabled ==<br />
The article says: "According to the blargg's sprite zero hit tests, sprites are NOT evaluated in the pre-render scanline. Plus, the evaluation occurs if sprites OR background are enabled."<br />
<br />
I find the second sentence problematic. I took it to mean that the sprite zero flag will still be set even if sprites are disabled in PPUMASK. But in fact it will not. I was pretty annoyed to find that out the hard way! So what is this trying to say, then? - [[User:Furrykef|Furrykef]] ([[User talk:Furrykef|talk]]) 01:10, 30 August 2016 (MDT)<br />
<br />
:I think this is worded very confusingly. Sprite "evaluation" is a vague and unclear term, especially since you've determined that sprite 0 hit won't be caused when sprites are disabled. I think it means that the OAM is accessed and refreshed as long as either the sprites or background are enabled. This is important for OAM decay, at least, but I don't know about other factors. Does sprite overflow still happen is sprites are disabled, but the background is? (Is that what "sprite evaluation" means?) Does sprite 0 hit still happen? (No. Right?) I think the whole sentence is a bit worthless as-is, to be honest. I think I'll delete it. - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 01:36, 30 August 2016 (MDT)<br />
<br />
::Man, you must be kidding now. It's not my fault if "sprite evaluation" is a vague term to you, sorry. Anyway, the sprite zero test FAILS (plain and simple) if the PPU sprite evaluation starts at scanline -1 (pre-render scanline). It should start at scanline 0, the first visible scanline. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:39, 5 September 2016 (MDT)<br />
::http://wiki.nesdev.org/w/index.php/PPU_sprite_evaluation<br />
<br />
Sprite evaluation *is* vague. It could mean fetch OAM data into temporary OAM or fetch data from VRAM based on temporary OAM data, and also the setting of sprite #0 and overflow flags. 3 different things. Also if might be mistaken, but sprite zero hit won't work either if sprites are enabled but not BG. You rally need both enabled for it to work. Disabling only sprites or only BG just replace them by blank patterns insternally, but still fetches the pattern in VRAM and internally replace them with all 0s, I guess. (Bregalad)<br />
[[Special:Contributions/128.178.126.68|128.178.126.68]] 07:21, 6 September 2016 (MDT)<br />
<br />
:I added a brief definition at the top of the page, and I tried to break up the removed sentence into a couple of ideas that I hope are more clear. ([http://wiki.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=12889&oldid=12382 revision 12889]) - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 11:27, 6 September 2016 (MDT)<br />
<br />
::Cool. Again, let me rephrase it. If the emulator (PPU) evaluates sprites at the pre-render scanline (-1), the sprite zero hit test will give an error. Simple. People that don't understand the PPU sprite evaluation proccess should read about it more and more, ever and ever... until it's clear. Crying here isn't good.--[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 15:38, 6 September 2016 (MDT)</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:PPU_sprite_evaluation&diff=15460Talk:PPU sprite evaluation2016-09-06T01:40:19Z<p>Zepper: </p>
<hr />
<div>== Sprite zero with sprites disabled ==<br />
The article says: "According to the blargg's sprite zero hit tests, sprites are NOT evaluated in the pre-render scanline. Plus, the evaluation occurs if sprites OR background are enabled."<br />
<br />
I find the second sentence problematic. I took it to mean that the sprite zero flag will still be set even if sprites are disabled in PPUMASK. But in fact it will not. I was pretty annoyed to find that out the hard way! So what is this trying to say, then? - [[User:Furrykef|Furrykef]] ([[User talk:Furrykef|talk]]) 01:10, 30 August 2016 (MDT)<br />
<br />
:I think this is worded very confusingly. Sprite "evaluation" is a vague and unclear term, especially since you've determined that sprite 0 hit won't be caused when sprites are disabled. I think it means that the OAM is accessed and refreshed as long as either the sprites or background are enabled. This is important for OAM decay, at least, but I don't know about other factors. Does sprite overflow still happen is sprites are disabled, but the background is? (Is that what "sprite evaluation" means?) Does sprite 0 hit still happen? (No. Right?) I think the whole sentence is a bit worthless as-is, to be honest. I think I'll delete it. - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 01:36, 30 August 2016 (MDT)<br />
<br />
::Man, you must be kidding now. It's not my fault if "sprite evaluation" is a vague term to you, sorry. Anyway, the sprite zero test FAILS (plain and simple) if the PPU sprite evaluation starts at scanline -1 (pre-render scanline). It should start at scanline 0, the first visible scanline. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:39, 5 September 2016 (MDT)<br />
::http://wiki.nesdev.org/w/index.php/PPU_sprite_evaluation</div>Zepperhttps://www.nesdev.org/w/index.php?title=Talk:PPU_sprite_evaluation&diff=15459Talk:PPU sprite evaluation2016-09-06T01:39:11Z<p>Zepper: /* sprite evaluation start */</p>
<hr />
<div>== Sprite zero with sprites disabled ==<br />
The article says: "According to the blargg's sprite zero hit tests, sprites are NOT evaluated in the pre-render scanline. Plus, the evaluation occurs if sprites OR background are enabled."<br />
<br />
I find the second sentence problematic. I took it to mean that the sprite zero flag will still be set even if sprites are disabled in PPUMASK. But in fact it will not. I was pretty annoyed to find that out the hard way! So what is this trying to say, then? - [[User:Furrykef|Furrykef]] ([[User talk:Furrykef|talk]]) 01:10, 30 August 2016 (MDT)<br />
<br />
:I think this is worded very confusingly. Sprite "evaluation" is a vague and unclear term, especially since you've determined that sprite 0 hit won't be caused when sprites are disabled. I think it means that the OAM is accessed and refreshed as long as either the sprites or background are enabled. This is important for OAM decay, at least, but I don't know about other factors. Does sprite overflow still happen is sprites are disabled, but the background is? (Is that what "sprite evaluation" means?) Does sprite 0 hit still happen? (No. Right?) I think the whole sentence is a bit worthless as-is, to be honest. I think I'll delete it. - [[User:Rainwarrior|Rainwarrior]] ([[User talk:Rainwarrior|talk]]) 01:36, 30 August 2016 (MDT)<br />
<br />
::Man, you must be kidding now. It's not my fault if "sprite evaluation" is a vague term to you, sorry. Anyway, the sprite zero test FAILS (plain and simple) if the sprites evaluation starts at scanline -1 (pre-render scanline). It should start at scanline 0, the first visible scanline. --[[User:Zepper|Zepper]] ([[User talk:Zepper|talk]]) 19:39, 5 September 2016 (MDT)<br />
::http://wiki.nesdev.org/w/index.php/PPU_sprite_evaluation</div>Zepperhttps://www.nesdev.org/w/index.php?title=PPU_sprite_evaluation&diff=10300PPU sprite evaluation2016-05-20T02:06:06Z<p>Zepper: /* Notes */</p>
<hr />
<div>== Overview ==<br />
Each scanline, the PPU reads the spritelist (that is, Object Attribute Memory) to see which to draw:<br />
# First, it clears the list of sprites to draw.<br />
# Second, it reads through OAM, checking which sprites will be on this scanline. It chooses the first eight it finds that do.<br />
# Third, if eight sprites were found, it checks (in a wrongly-implemented fashion) for further sprites on the scanline to see if the sprite overflow flag should be set.<br />
# Fourth, using the details for the eight (or fewer) sprites chosen, it determines which pixels each has on the scanline and where to draw them.<br />
== Details ==<br />
During all visible scanlines, the PPU scans through OAM to determine which sprites to render on the next scanline. Sprites found to be within range are copied into the secondary OAM, which is then used to initialize eight internal sprite output units.<br />
<br />
''OAM[n][m]'' below refers to the byte at offset ''4*n + m'' within OAM, i.e. OAM byte ''m'' (0-3) of sprite ''n'' (0-63).<br />
<br />
During each pixel clock (341 total per scanline), the PPU accesses OAM in the following pattern:<br />
<br />
# Cycles 1-64: Secondary OAM (32-byte buffer for current sprites on scanline) is initialized to $FF - attempting to read $2004 will return $FF. Internally, the clear operation is implemented by reading from the OAM and writing into the secondary OAM as usual, only a signal is active that makes the read always return $FF.<br />
# Cycles 65-256: Sprite evaluation<br />
#* ''On odd cycles, data is read from (primary) OAM''<br />
#* ''On even cycles, data is written to secondary OAM (unless secondary OAM is full, in which case it will read the value in secondary OAM instead)''<br />
#*1. Starting at n = 0, read a sprite's Y-coordinate (OAM[n][0], copying it to the next open slot in secondary OAM (unless 8 sprites have been found, in which case the write is ignored).<br />
#**1a. If Y-coordinate is in range, copy remaining bytes of sprite data (OAM[n][1] thru OAM[n][3]) into secondary OAM.<br />
#*2. Increment n<br />
#**2a. If n has overflowed back to zero (all 64 sprites evaluated), go to 4<br />
#**2b. If less than 8 sprites have been found, go to 1<br />
#**2c. If exactly 8 sprites have been found, disable writes to secondary OAM because it is full. This causes sprites in back to drop out.<br />
#*3. Starting at m = 0, evaluate OAM[n][m] as a Y-coordinate.<br />
#**3a. If the value is in range, set the sprite overflow flag in $2002 and read the next 3 entries of OAM (incrementing 'm' after each byte and incrementing 'n' when 'm' overflows); if m = 3, increment n<br />
#**3b. If the value is not in range, increment n '''and''' m (without carry). If n overflows to 0, go to 4; otherwise go to 3<br />
#***''The m increment is a hardware bug - if only n was incremented, the overflow flag would be set whenever more than 8 sprites were present on the same scanline, as expected.''<br />
#*4. Attempt (and fail) to copy OAM[n][0] into the next free slot in secondary OAM, and increment n (repeat until HBLANK is reached)<br />
# Cycles 257-320: Sprite fetches (8 sprites total, 8 cycles per sprite)<br />
#*1-4: Read the Y-coordinate, tile number, attributes, and X-coordinate of the selected sprite from secondary OAM<br />
#*5-8: Read the X-coordinate of the selected sprite from secondary OAM 4 times (while the PPU fetches the sprite tile data)<br />
#* For the first empty sprite slot, this will consist of sprite #63's Y-coordinate followed by 3 $FF bytes; for subsequent empty sprite slots, this will be four $FF bytes<br />
#Cycles 321-340+0: Background render pipeline initialization<br />
#* Read the first byte in secondary OAM (while the PPU fetches the first two background tiles for the next scanline)<br />
<br />
This pattern was determined by doing carefully timed reads from $2004 using various sets of sprites, and simulation in Visual 2C02 has subsequently confirmed this behavior.<br />
<br />
== Sprite overflow bug ==<br />
During sprite evaluation, if eight in-range sprites have been found so far, the sprite evaluation logic continues to scan the primary OAM looking for one more in-range sprite to determine whether to set the sprite overflow flag. The first such check correctly checks the y coordinate of the next OAM entry, but after that the logic breaks and starts scanning OAM "diagonally", evaluating the tile number/attributes/X-coordinates of subsequent OAM entries as Y-coordinates (due to incorrectly incrementing m when moving to the next sprite). This results in inconsistent sprite overflow behavior showing both false positives and false negatives.<br />
<br />
=== Cause of the sprite overflow bug ===<br />
After investigation in [[Visual 2C02]], the culprit of the sprite overflow bug appears to be the write disable signal that goes high after eight in-range sprites have been found (to prevent further updates to the secondary OAM), along with an error in the sprite evaluation logic.<br />
<br />
As seen above, a side effect of the OAM write disable signal is to turn writes to the secondary OAM into reads from it. Once eight in-range sprites have been found, the value being read during write cycles from that point on is the y coordinate of the first sprite copied into the secondary OAM. Due to a logic error, the result of comparing this y coordinate to the current scanline number (which will always yield "in range", since the sprite would have had to be in range to get copied into the secondary OAM) is allowed to influence the sprite address incrementation logic, causing the glitchy updates to the sprite address seen above (due to how the timing works out). Once one more sprite has been found, another signal prevents the comparison from influencing the sprite address incrementation logic, and the bug is no longer in effect.<br />
<br />
=== Examples of usage ===<br />
For some examples of games using this bug/quirk, refer to the [[Sprite overflow games]] page.<br />
<br />
== Notes ==<br />
*[[Visual 2C02]] might be helpful when trying to understand how the algorithm operates and what the precise timings are.<br />
*The [[PPU sprite priority|sprite priority]] system has a quirk when the background, a front-priority sprite, and a back-priority sprite are in the same area. Games such as Super Mario Bros. 3 take advantage of this.<br />
*If the sprite address ($2003) is not zero (usually, $2003 AND $F8) at the beginning of the pre-render scanline, then copy the contents of its 8-byte page into the first 8 bytes.<br />
*According to the blargg's sprite zero hit tests, sprites are NOT evaluated in the pre-render scanline. Plus, the evaluation occurs if sprites OR background are enabled.<br />
<br />
== External links ==<br />
*[https://gist.github.com/beannaich/7a7ba066d909318debea Visual 2C02 logs of the PPU evaluating 1, 8, and 9 sprites] by beannaich</div>Zepperhttps://www.nesdev.org/w/index.php?title=MMC3&diff=6528MMC32016-04-20T02:13:57Z<p>Zepper: More small tweaks.</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=MMC3<br />
|name2=TxROM<br />
|company=Nintendo, others<br />
|mapper=4<br />
|othermappers=[[iNES Mapper 118|118]], [[iNES Mapper 119|119]]<br />
|nescartdbgames=300<br />
|complexity=ASIC<br />
|boards=TSROM, others<br />
|prgmax=512K<br />
|prgpage=8K + 8K + 16K fixed<br />
|wrammax=8K<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable, or 4 fixed<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|4|iNES 004<br />
|unif_wild|-T%ROM|TxROM<br />
}}<br />
[[Category:MMC3-like mappers]][[Category:Nintendo licensed mappers]][[Category:Mappers with scanline IRQs]]<br />
The '''Nintendo MMC3''' is a [[MMC|mapper]] [[:Category:ASIC mappers|ASIC]] used in Nintendo's [[TxROM]] Game Pak boards. Most common TxROM boards, along with the '''NES-HKROM''' board (which uses the Nintendo [[MMC6]]) are assigned to [[iNES Mapper 004]].<br />
<br />
Some less common MMC3 boards required alternative iNES mapper implementations:<br />
* [[iNES Mapper 118]] - TKSROM and TLSROM<br />
* [[iNES Mapper 119]] - TQROM<br />
<br />
This chip first appeared in the fourth quarter of 1988.<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB PRG RAM bank<br />
* CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank<br />
* CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank<br />
* PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank<br />
* PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank<br />
* PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank<br />
* PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank<br />
* PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank<br />
* PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank<br />
<br />
== Registers ==<br />
<br />
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
These can be broken into two independent functional units: memory mapping ($8000, $8001, $A000, $A001) and scanline counting ($C000, $C001, $E000, $E001).<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPMx xRRR<br />
||| |||<br />
||| +++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);<br />
||| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);<br />
||| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);<br />
||| 7: Select 8 KB PRG ROM bank at $A000-$BFFF<br />
||+------- Nothing on the MMC3, see [[MMC6]]<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,<br />
| $C000-$DFFF fixed to second-last bank;<br />
| 1: $C000-$DFFF swappable,<br />
| $8000-$9FFF fixed to second-last bank)<br />
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,<br />
four 1 KB banks at $1000-$1FFF;<br />
1: two 2 KB banks at $1000-$1FFF,<br />
four 1 KB banks at $0000-$0FFF)<br />
<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$80 !! is 0 !! is #$80<br />
|-<br />
! PPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $0000-$03FF || R0 AND $FE || R2<br />
|-<br />
| $0400-$07FF || R0 OR 1 || R3<br />
|-<br />
| $0800-$0BFF || R1 AND $FE || R4<br />
|-<br />
| $0C00-$0FFF || R1 OR 1 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0 AND $FE<br />
|-<br />
| $1400-$17FF || R3 || R0 OR 1<br />
|-<br />
| $1800-$1BFF || R4 || R1 AND $FE<br />
|-<br />
| $1C00-$1FFF || R5 || R1 OR 1<br />
|}<br />
<br />
==== PRG Banks ====<br />
Because the values in R6, R7, and $8000 are unspecified at power on, the reset vector must point into $E000-$FFFF, and code must initialize these before jumping out of $E000-$FFFF.<br />
<br />
{| class="wikitable"<br />
! When $8000 & #$40 !! is 0 !! is #$40<br />
|-<br />
! CPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $8000-$9FFF || R6 || (-2)<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || (-2) || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank, in a proper MMC3, the 63rd<br />
* (-2) : the penultimate bank; properly the 62nd<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)<br />
<br />
The PRG banks are 8192 bytes in size, half the size of an [[iNES]] PRG bank.<br />
If your emulator or copier handles PRG data in 16384 byte chunks, you can think of the lower bit as selecting the first or second half of the bank:[http://forums.nesdev.org/viewtopic.php?p=38182#p38182]<br />
<br />
7 bit 0 When $8000 AND #$06 == #$06<br />
---- ----<br />
xxBB BBBH<br />
|| ||||<br />
|| |||+- 0: Select first half of this bank;<br />
|| ||| 1: Select second half of this bank<br />
++-+++-- Select 16 KB PRG bank at $8000-$9FFF, $A000-$BFFF, or $C000-$DFFF<br />
<br />
Writes to registers 6 and 7 always ignore bits 6 and 7, as the MMC3 has only 6 PRG ROM address output lines.<br />
<br />
Writes to registers 0 and 1 always ignore bit 0, loading the value AND #$FE into the first half and the value OR #$01 into the second half of the 2 KiB bank.<br />
<br />
Some romhacks rely on an 8-bit extension of registers 6 and 7 for oversized PRG-ROM, but this is deliberately not supported by many emulators. See [[#iNES Mapper 004 and MMC6|iNES Mapper 004]] below.<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- Nametable [[mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This bit has no effect on ''[http://bootgod.dyndns.org:7777/profile.php?id=137 Rad Racer II]'', which uses the TVROM board, because TVROM is hardwired to 4-screen VRAM.<br />
In the iNES and NES 2.0 formats, TVROM can be identified through [[INES#Flags 6|bit 3 of byte $06 of the header]].<br />
<br />
=== PRG RAM protect ($A001-$BFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
RWXX xxxx<br />
||||<br />
||++------ Nothing on the MMC3, see [[MMC6]]<br />
|+-------- Write protection (0: allow writes; 1: deny writes)<br />
+--------- PRG RAM chip enable (0: disable; 1: enable)<br />
<br />
Disabling PRG RAM through bit 7 causes reads from the PRG RAM region to return open bus.<br />
<br />
Though these bits are functional on the MMC3, their main purpose is to write-protect save RAM during power-off. Many emulators choose not to implement them as part of iNES Mapper 4 to avoid an incompatibility with the MMC6.<br />
<br />
See [[#iNES Mapper 004 and MMC6|iNES Mapper 004 and MMC6]] below.<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
<span id="IRQ"></span><br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- IRQ latch value<br />
<br />
This register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied to the IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register reloads the MMC3 IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ disable ($E000-$FFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will disable MMC3 interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will enable MMC3 interrupts.<br />
<br />
== Hardware ==<br />
<br />
The MMC3 most commonly exists in a [[MMC3_pinout|44-pin TQFP package]].<br />
Three revisions are known to exist - MMC3A, MMC3B, and MMC3C. No major behavioral differences are known, except for the IRQ counter.<br />
<br />
The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for two rising edges of M2).<br />
<br />
The counter is based on the following trick: whenever rendering is turned on in the [[PPU]], it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible.<br />
Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame. It may oscillate more if the program uses registers $2006 and $2007 to access PPU $1000-$1FFF during vblank, but this is rare because very few games have MMC3 and CHR RAM (two on TQROM and three on TGROM among NES games, and a couple more Famicom-only games). The scanline counter will also work when the BG uses the right pattern table ($1000) and the sprites use the left pattern table ($0000), but this is less common. The MMC3 IRQ has two revisions that work slightly different [http://forums.nesdev.org/viewtopic.php?p=62546#p62546].<br />
<br />
Counter operation:<br />
* When the IRQ is clocked (PPU A12 0->1), the counter value is checked - if zero '''or''' the ''reload flag'' is true, it's reloaded with the IRQ latched value at $C000; otherwise, it decrements.<br />
* If the IRQ counter is zero ''and'' IRQs are enabled ($E001), an IRQ is triggered. The "alternate revision" checks the IRQ counter transition 1->0, whether from decrementing or reloading.<br />
<br />
Regarding PPU A12:<br />
* If the BG uses $0000, and the sprites use $1000, the IRQ counter should decrement on PPU cycle 260,268,276... ''or'' 315 (as in, a little after the visible part of the target scanline has ended).<br />
* If the BG uses $1000, and the sprites use $0000, the IRQ counter should decrement on PPU cycle 324 ''or'' 332 of the ''previous'' scanline (as in, ''right before'' the target scanline is about to be drawn).<br />
* For 8x16 sprites: if there are less than 8 sprites on a scanline, the PPU makes a dummy fetch to tile $FF (right pattern table $1000) for each leftover sprite. So, games with background and sprites from PPU $0000 watches the sprite tile pattern selection.<br />
<br />
Important points:<br />
* The scanline counter cannot be stopped. It will continue to decrement and reload as long as PPU A12 on the PPU bus toggles.<br />
* There is no direct access to the counter! The best you can do is update the reload value and immediately request a reload.<br />
* Writing to $E000 will only prevent the MMC3 from generating IRQs - the counter will continue to run.<br />
* Writing to $E001 will simply allow the MMC3 to generate IRQs - the counter remains unaffected.<br />
* Writing to $C001 will cause the counter to be cleared, and set ''reload flag'' to '''true'''. It will be reloaded on the NEXT rising edge of the PPU A12.<br />
* Writing to $C000 does not immediately affect the value within the counter - this value is only used when the counter is reloaded, whether from reaching 0 or from writing to $C001.<br />
* The exact number of scanlines between IRQs is N+1, where N is the value written to $C000. 1 (Sharp MMC3B, MMC3C) or 2 (MMC3A, Non-Sharp MMC3B) to 256 scanlines are supported.<br />
* The counter will not work properly unless you use different pattern tables for background and sprite data. The standard configuration is to use PPU $0000-$0FFF for background tiles and $1000-$1FFF for sprite tiles, whether 8x8 or 8x16.<br />
* The counter is clocked on each rising edge of PPU A12, no matter what caused it, so it is possible to (intentionally or not) clock the counter by writing to $2006, regardless of whether PPU is/is not rendering.<br />
<br />
There's a slight discrepancy with what happens when you set $C000 to $00, and so far, two behaviors are known to exist:<br />
* All MMC3A's and non-Sharp MMC3B's will generate only a single IRQ when $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''decremented'' to 0. In addition, writing to $C001 with $C000 still at $00 will result in another single IRQ being generated. In the community, this is known as the "alternate" or "old" behavior.<br />
* All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''equal'' to 0. In the community, this is known as the "normal" or "new" behavior.<br />
<br />
Acclaim's MC-ACC chip is their own variant of the MMC3, that they used for their own boards (for industrial money-saving purposes). It comes in a standard 600 mil 40-pin DIP package. It is not known if it has SRAM support. The only known difference is that the scanline counter triggers on [http://forums.nesdev.org/viewtopic.php?p=116691#p116691 ''falling'' edges] instead of rising edges.<br />
<br />
== iNES Mapper 004 and MMC6 ==<br />
<br />
The unfortunate conflation of MMC3 and [[MMC6]] into the same iNES mapper can be resolved by the use of an [[NES 2.0]] header, but since the new header is not yet well adopted among emulators or ROM sets, an approach that supports both MMC3 and MMC6 may be desired when an NES 2.0 header is not used.<br />
<br />
The MMC6 has a smaller PRG-RAM, and a different register scheme for write protecting it.<br />
<br />
Because write protection is generally only used to guard against corruption during power off, many implementations of iNES Mapper 004 simply omit the write protection. Leaving PRG-RAM always write-enabled removes most of the incompatibility between MMC3 and MMC6, and is sufficient to support the popular MMC6 games StarTropics and StarTropics II. These games do not rely on the smaller PRG-RAM size of the MMC6, so the larger 8k RAM addressed by the MMC3 is not a problem.<br />
<br />
The less well known game ''Low G Man'' is problematic. It used an MMC3 board with no PRG-RAM. Because of a bug in its music code, it relies on open-bus behaviour in the RAM's address range to function correctly. The game does use the MMC3 mechanism to disable RAM, so it may function on an MMC3 board with PRG-RAM, but implementing the MMC3 RAM disable may conflict with the effort to support MMC6 games. Alternatively, NES 2.0 could be used to specify a PRG-RAM size of 0, or the problem can be resolved by patching the Low G Man ROM to work around the conflict: [http://www.romhacking.net/hacks/2512/ patch].<br />
<br />
Some romhacks attempt to increase the available PRG-ROM size beyond the MMC3's hard 512k limit (e.g. [http://www.romhacking.net/translations/1590/ Translation of Final Fantasy III]). Full 8-bit banking registers could theoretically support up to 2048K PRG-ROM, but very few emulators implement this extension.<br />
<br />
== Variants ==<br />
The TKSROM and TLSROM boards, assigned to [[INES Mapper 118]], connect the upper bank select line directly to VRAM A10, allowing more flexible control over nametable mirroring.<br />
<br />
The TQROM board, assigned to [[INES Mapper 119]], uses both CHR ROM and CHR RAM simultaneously, using the 2nd-highest CHR bank select line to choose between them (on a per-bank basis).<br />
<br />
The [[DxROM]] board, assigned to [[iNES Mapper 206]] has a custom mapper developed by Namco before the MMC3 existed. It has no IRQ or mirroring control.<br />
Tengen used it for some of their games under the name MIMIC-1.<br />
It exists both in a [[Namcot 108 family pinout|400 mil 28-pin Shrink-DIP]] (found in licensed [[DxROM]] boards) and in a larger 600 mil 28-pin DIP (found in unlicensed Tengen cartridges).<br />
<br />
The Namco 108/MIMIC-1 does the basic ROM banking exactly like the MMC3, but it only implements the low 3 bits of $8000 and the low 6 bits of $8001. Compared to the MMC3, it lacks mirroring control, SRAM support and an IRQ counter. The TEROM and TFROM boards have been developed with backward compability with [[DxROM]] in mind, featuring solder pads to have hardwired H/V mirroring instead of MMC3 controlled mirroring, and allow the hardware to disable IRQs.<br />
<br />
IRQ behavior when reload is set to 0 differs among different MMC3 chips.<br />
MMC3 chips with the "new behavior" generate an IRQ every scanline.<br />
(These include at least MMC3B chips bearing a bold S before the date code.)<br />
MMC3 chips with the "old behavior" cease to generate IRQs.<br />
(These include MMC3B chips lacking the S and having a date code of the form nnnnPKnnn, and an MMC3A 8940EP chip.)<br />
Some games have been manufactured with both versions, and during the transition, relying on old or new behavior might at first have been one of the things that caused Nintendo lot check to reject a program.<br />
A few later games developed after Nintendo had run out of the old chips, such as ''[http://bootgod.dyndns.org:7777/profile.php?id=249 Star Trek: 25th Anniversary]'', are reported to rely on the new behavior (source: Nestopia 1.30 changelog).<br />
There's an anecdotal report that [http://forums.nesdev.org/viewtopic.php?p=124478#p124478 ''Felix the Cat'' needs MMC3A], but it could also have been a rewiring mistake.<br />
<br />
Nintendo made at least two MMC3-based multicart mappers: mappers [[INES Mapper 037|37]] and [[INES Mapper 047|47]].<br />
<br />
== Pirate variants ==<br />
* [[INES Mapper 245|Mapper 245]] increases PRG to 1024K by losing CHR ROM.<br />
<br />
* Mappers [[INES Mapper 205|205]], [[INES Mapper 052|52]], [[INES Mapper 049|49]], [[INES Mapper 045|45]], and [[INES Mapper 044|44]] force unmodified games together in a multicart. <br />
<br />
* [[INES Mapper 189|Mapper 189]] loses the MMC3's 8+8+16F banking scheme in exchange for 32k-at-a-time banking like [[AxROM]], [[BxROM]], or [[GxROM]]<br />
<br />
* [[INES Mapper 182|Mapper 182]]'s registers are only in a different order.<br />
<br />
* [[INES Mapper 115|Mapper 115]] increases CHR to 512K by losing PRG RAM and contains an [[UxROM]] emulation mode.<br />
<br />
* Mappers [[INES Mapper 194|194]], [[INES Mapper 192|192]], [[INES Mapper 191|191]], and [[INES Mapper 074|74]], are like TQROM in that they combine CHR ROM and CHR RAM by replacing some CHR pages with CHR RAM.<br />
<br />
== See also ==<br />
* [[:Category:MMC3-like mappers|MMC3-like mappers]]<br />
* [http://www.romhacking.net/documents/362/ NES Mapper list] by Disch.<br />
* [http://nesdev.org/mmc3.txt Nintendo MMC3] by goroh.<br />
* [http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\. Information on mapper's initial state is innacurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=MMC3&diff=6527MMC32016-04-18T19:19:38Z<p>Zepper: /* Hardware */ Time to update the IRQ-hell. Your help now, plz?</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=MMC3<br />
|name2=TxROM<br />
|company=Nintendo, others<br />
|mapper=4<br />
|othermappers=[[iNES Mapper 118|118]], [[iNES Mapper 119|119]]<br />
|nescartdbgames=300<br />
|complexity=ASIC<br />
|boards=TSROM, others<br />
|prgmax=512K<br />
|prgpage=8K + 8K + 16K fixed<br />
|wrammax=8K<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=2Kx2 + 1Kx4<br />
|mirroring=H or V, switchable, or 4 fixed<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
{{nesdbbox<br />
|ines|4|iNES 004<br />
|unif_wild|-T%ROM|TxROM<br />
}}<br />
[[Category:MMC3-like mappers]][[Category:Nintendo licensed mappers]][[Category:Mappers with scanline IRQs]]<br />
The '''Nintendo MMC3''' is a [[MMC|mapper]] [[:Category:ASIC mappers|ASIC]] used in Nintendo's [[TxROM]] Game Pak boards. Most common TxROM boards, along with the '''NES-HKROM''' board (which uses the Nintendo [[MMC6]]) are assigned to [[iNES Mapper 004]].<br />
<br />
Some less common MMC3 boards required alternative iNES mapper implementations:<br />
* [[iNES Mapper 118]] - TKSROM and TLSROM<br />
* [[iNES Mapper 119]] - TQROM<br />
<br />
This chip first appeared in the fourth quarter of 1988.<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB PRG RAM bank<br />
* CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank<br />
* CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank<br />
* PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank<br />
* PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank<br />
* PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank<br />
* PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank<br />
* PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank<br />
* PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank<br />
<br />
== Registers ==<br />
<br />
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
These can be broken into two independent functional units: memory mapping ($8000, $8001, $A000, $A001) and scanline counting ($C000, $C001, $E000, $E001).<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPMx xRRR<br />
||| |||<br />
||| +++- Specify which bank register to update on next write to Bank Data register<br />
||| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);<br />
||| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);<br />
||| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
||| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
||| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
||| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
||| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);<br />
||| 7: Select 8 KB PRG ROM bank at $A000-$BFFF<br />
||+------- Nothing on the MMC3, see [[MMC6]]<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,<br />
| $C000-$DFFF fixed to second-last bank;<br />
| 1: $C000-$DFFF swappable,<br />
| $8000-$9FFF fixed to second-last bank)<br />
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,<br />
four 1 KB banks at $1000-$1FFF;<br />
1: two 2 KB banks at $1000-$1FFF,<br />
four 1 KB banks at $0000-$0FFF)<br />
<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$80 !! is 0 !! is #$80<br />
|-<br />
! PPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $0000-$03FF || R0 AND $FE || R2<br />
|-<br />
| $0400-$07FF || R0 OR 1 || R3<br />
|-<br />
| $0800-$0BFF || R1 AND $FE || R4<br />
|-<br />
| $0C00-$0FFF || R1 OR 1 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0 AND $FE<br />
|-<br />
| $1400-$17FF || R3 || R0 OR 1<br />
|-<br />
| $1800-$1BFF || R4 || R1 AND $FE<br />
|-<br />
| $1C00-$1FFF || R5 || R1 OR 1<br />
|}<br />
<br />
==== PRG Banks ====<br />
Because the values in R6, R7, and $8000 are unspecified at power on, the reset vector must point into $E000-$FFFF, and code must initialize these before jumping out of $E000-$FFFF.<br />
<br />
{| class="wikitable"<br />
! When $8000 & #$40 !! is 0 !! is #$40<br />
|-<br />
! CPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $8000-$9FFF || R6 || (-2)<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || (-2) || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank, in a proper MMC3, the 63rd<br />
* (-2) : the penultimate bank; properly the 62nd<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)<br />
<br />
The PRG banks are 8192 bytes in size, half the size of an [[iNES]] PRG bank.<br />
If your emulator or copier handles PRG data in 16384 byte chunks, you can think of the lower bit as selecting the first or second half of the bank:[http://forums.nesdev.org/viewtopic.php?p=38182#p38182]<br />
<br />
7 bit 0 When $8000 AND #$06 == #$06<br />
---- ----<br />
xxBB BBBH<br />
|| ||||<br />
|| |||+- 0: Select first half of this bank;<br />
|| ||| 1: Select second half of this bank<br />
++-+++-- Select 16 KB PRG bank at $8000-$9FFF, $A000-$BFFF, or $C000-$DFFF<br />
<br />
Writes to registers 6 and 7 always ignore bits 6 and 7, as the MMC3 has only 6 PRG ROM address output lines.<br />
<br />
Writes to registers 0 and 1 always ignore bit 0, loading the value AND #$FE into the first half and the value OR #$01 into the second half of the 2 KiB bank.<br />
<br />
Some romhacks rely on an 8-bit extension of registers 6 and 7 for oversized PRG-ROM, but this is deliberately not supported by many emulators. See [[#iNES Mapper 004 and MMC6|iNES Mapper 004]] below.<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- Nametable [[mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This bit has no effect on ''[http://bootgod.dyndns.org:7777/profile.php?id=137 Rad Racer II]'', which uses the TVROM board, because TVROM is hardwired to 4-screen VRAM.<br />
In the iNES and NES 2.0 formats, TVROM can be identified through [[INES#Flags 6|bit 3 of byte $06 of the header]].<br />
<br />
=== PRG RAM protect ($A001-$BFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
RWXX xxxx<br />
||||<br />
||++------ Nothing on the MMC3, see [[MMC6]]<br />
|+-------- Write protection (0: allow writes; 1: deny writes)<br />
+--------- PRG RAM chip enable (0: disable; 1: enable)<br />
<br />
Disabling PRG RAM through bit 7 causes reads from the PRG RAM region to return open bus.<br />
<br />
Though these bits are functional on the MMC3, their main purpose is to write-protect save RAM during power-off. Many emulators choose not to implement them as part of iNES Mapper 4 to avoid an incompatibility with the MMC6.<br />
<br />
See [[#iNES Mapper 004 and MMC6|iNES Mapper 004 and MMC6]] below.<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
<span id="IRQ"></span><br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- IRQ latch value<br />
<br />
This register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied to the IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register reloads the MMC3 IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ disable ($E000-$FFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will disable MMC3 interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will enable MMC3 interrupts.<br />
<br />
== Hardware ==<br />
<br />
The MMC3 most commonly exists in a [[MMC3_pinout|44-pin TQFP package]].<br />
Three revisions are known to exist - MMC3A, MMC3B, and MMC3C. No major behavioral differences are known, except for the IRQ counter.<br />
<br />
The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for two rising edges of M2).<br />
<br />
The counter is based on the following trick: whenever rendering is turned on in the [[PPU]], it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible.<br />
Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame. It may oscillate more if the program uses registers $2006 and $2007 to access PPU $1000-$1FFF during vblank, but this is rare because very few games have MMC3 and CHR RAM (two on TQROM and three on TGROM among NES games, and a couple more Famicom-only games). The scanline counter will also work when the BG uses the right pattern table ($1000) and the sprites use the left pattern table ($0000), but this is less common.<br />
<br />
The MMC3 IRQ has two revisions that work slightly different [http://forums.nesdev.org/viewtopic.php?p=62546#p62546].<br />
* When the IRQ is clocked, the counter is firstly checked. If it's zero '''or''' the ''reload flag'' is true, it's reloaded with the IRQ latched value at $C000; otherwise, it decrements. If the IRQ counter is zero and IRQs are enabled ($E001), an IRQ is triggered. Note that the "alternate version" checks if the IRQ counter came from 1->0, whether from decrementing or reloading.<br />
<br />
Regarding PPU A12 rises:<br />
* If the BG uses $0000, and the sprites use $1000, the IRQ counter should decrement on PPU cycle 260,268,276... ''or'' 315 (as in, a little after the visible part of the target scanline has ended).<br />
* If the BG uses $1000, and the sprites use $0000, the IRQ counter should decrement on PPU cycle 324 ''or'' 332 of the ''previous'' scanline (as in, ''right before'' the target scanline is about to be drawn).<br />
* For 8x16 sprites: if there are less than 8 sprites on a scanline, the PPU makes a dummy fetch to tile $FF (right pattern table $1000) for each leftover sprite.<br />
<br />
Important points:<br />
* The scanline counter cannot be stopped. It will continue to decrement and reload as long as PPU A12 on the PPU bus toggles.<br />
* There is no direct access to the counter! The best you can do is update the reload value and immediately request a reload.<br />
* Writing to $E000 will only prevent the MMC3 from generating IRQs - the counter will continue to run.<br />
* Writing to $E001 will simply allow the MMC3 to generate IRQs - the counter remains unaffected.<br />
* Writing to $C001 will cause the counter to be cleared, and set ''reload flag'' to '''true'''. It will be reloaded on the NEXT rising edge of the PPU A12.<br />
* Writing to $C000 does not immediately affect the value within the counter - this value is only used when the counter is reloaded, whether from reaching 0 or from writing to $C001.<br />
* The exact number of scanlines between IRQs is N+1, where N is the value written to $C000. 1 (Sharp MMC3B, MMC3C) or 2 (MMC3A, Non-Sharp MMC3B) to 256 scanlines are supported.<br />
* The counter will not work properly unless you use different pattern tables for background and sprite data. The standard configuration is to use PPU $0000-$0FFF for background tiles and $1000-$1FFF for sprite tiles, whether 8x8 or 8x16.<br />
* The counter is clocked on each rising edge of PPU A12, no matter what caused it, so it is possible to (intentionally or not) clock the counter by writing to $2006, regardless of whether PPU is/is not rendering.<br />
<br />
There's a slight discrepancy with what happens when you set $C000 to $00, and so far, two behaviors are known to exist:<br />
* All MMC3A's and non-Sharp MMC3B's will generate only a single IRQ when $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''decremented'' to 0. In addition, writing to $C001 with $C000 still at $00 will result in another single IRQ being generated. In the community, this is known as the "alternate" or "old" behavior.<br />
* All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''equal'' to 0. In the community, this is known as the "normal" or "new" behavior.<br />
<br />
Acclaim's MC-ACC chip is their own variant of the MMC3, that they used for their own boards (for industrial money-saving purposes). It comes in a standard 600 mil 40-pin DIP package. It is not known if it has SRAM support. The only known difference is that the scanline counter triggers on [http://forums.nesdev.org/viewtopic.php?p=116691#p116691 ''falling'' edges] instead of rising edges.<br />
<br />
== iNES Mapper 004 and MMC6 ==<br />
<br />
The unfortunate conflation of MMC3 and [[MMC6]] into the same iNES mapper can be resolved by the use of an [[NES 2.0]] header, but since the new header is not yet well adopted among emulators or ROM sets, an approach that supports both MMC3 and MMC6 may be desired when an NES 2.0 header is not used.<br />
<br />
The MMC6 has a smaller PRG-RAM, and a different register scheme for write protecting it.<br />
<br />
Because write protection is generally only used to guard against corruption during power off, many implementations of iNES Mapper 004 simply omit the write protection. Leaving PRG-RAM always write-enabled removes most of the incompatibility between MMC3 and MMC6, and is sufficient to support the popular MMC6 games StarTropics and StarTropics II. These games do not rely on the smaller PRG-RAM size of the MMC6, so the larger 8k RAM addressed by the MMC3 is not a problem.<br />
<br />
The less well known game ''Low G Man'' is problematic. It used an MMC3 board with no PRG-RAM. Because of a bug in its music code, it relies on open-bus behaviour in the RAM's address range to function correctly. The game does use the MMC3 mechanism to disable RAM, so it may function on an MMC3 board with PRG-RAM, but implementing the MMC3 RAM disable may conflict with the effort to support MMC6 games. Alternatively, NES 2.0 could be used to specify a PRG-RAM size of 0, or the problem can be resolved by patching the Low G Man ROM to work around the conflict: [http://www.romhacking.net/hacks/2512/ patch].<br />
<br />
Some romhacks attempt to increase the available PRG-ROM size beyond the MMC3's hard 512k limit (e.g. [http://www.romhacking.net/translations/1590/ Translation of Final Fantasy III]). Full 8-bit banking registers could theoretically support up to 2048K PRG-ROM, but very few emulators implement this extension.<br />
<br />
== Variants ==<br />
The TKSROM and TLSROM boards, assigned to [[INES Mapper 118]], connect the upper bank select line directly to VRAM A10, allowing more flexible control over nametable mirroring.<br />
<br />
The TQROM board, assigned to [[INES Mapper 119]], uses both CHR ROM and CHR RAM simultaneously, using the 2nd-highest CHR bank select line to choose between them (on a per-bank basis).<br />
<br />
The [[DxROM]] board, assigned to [[iNES Mapper 206]] has a custom mapper developed by Namco before the MMC3 existed. It has no IRQ or mirroring control.<br />
Tengen used it for some of their games under the name MIMIC-1.<br />
It exists both in a [[Namcot 108 family pinout|400 mil 28-pin Shrink-DIP]] (found in licensed [[DxROM]] boards) and in a larger 600 mil 28-pin DIP (found in unlicensed Tengen cartridges).<br />
<br />
The Namco 108/MIMIC-1 does the basic ROM banking exactly like the MMC3, but it only implements the low 3 bits of $8000 and the low 6 bits of $8001. Compared to the MMC3, it lacks mirroring control, SRAM support and an IRQ counter. The TEROM and TFROM boards have been developed with backward compability with [[DxROM]] in mind, featuring solder pads to have hardwired H/V mirroring instead of MMC3 controlled mirroring, and allow the hardware to disable IRQs.<br />
<br />
IRQ behavior when reload is set to 0 differs among different MMC3 chips.<br />
MMC3 chips with the "new behavior" generate an IRQ every scanline.<br />
(These include at least MMC3B chips bearing a bold S before the date code.)<br />
MMC3 chips with the "old behavior" cease to generate IRQs.<br />
(These include MMC3B chips lacking the S and having a date code of the form nnnnPKnnn, and an MMC3A 8940EP chip.)<br />
Some games have been manufactured with both versions, and during the transition, relying on old or new behavior might at first have been one of the things that caused Nintendo lot check to reject a program.<br />
A few later games developed after Nintendo had run out of the old chips, such as ''[http://bootgod.dyndns.org:7777/profile.php?id=249 Star Trek: 25th Anniversary]'', are reported to rely on the new behavior (source: Nestopia 1.30 changelog).<br />
There's an anecdotal report that [http://forums.nesdev.org/viewtopic.php?p=124478#p124478 ''Felix the Cat'' needs MMC3A], but it could also have been a rewiring mistake.<br />
<br />
Nintendo made at least two MMC3-based multicart mappers: mappers [[INES Mapper 037|37]] and [[INES Mapper 047|47]].<br />
<br />
== Pirate variants ==<br />
* [[INES Mapper 245|Mapper 245]] increases PRG to 1024K by losing CHR ROM.<br />
<br />
* Mappers [[INES Mapper 205|205]], [[INES Mapper 052|52]], [[INES Mapper 049|49]], [[INES Mapper 045|45]], and [[INES Mapper 044|44]] force unmodified games together in a multicart. <br />
<br />
* [[INES Mapper 189|Mapper 189]] loses the MMC3's 8+8+16F banking scheme in exchange for 32k-at-a-time banking like [[AxROM]], [[BxROM]], or [[GxROM]]<br />
<br />
* [[INES Mapper 182|Mapper 182]]'s registers are only in a different order.<br />
<br />
* [[INES Mapper 115|Mapper 115]] increases CHR to 512K by losing PRG RAM and contains an [[UxROM]] emulation mode.<br />
<br />
* Mappers [[INES Mapper 194|194]], [[INES Mapper 192|192]], [[INES Mapper 191|191]], and [[INES Mapper 074|74]], are like TQROM in that they combine CHR ROM and CHR RAM by replacing some CHR pages with CHR RAM.<br />
<br />
== See also ==<br />
* [[:Category:MMC3-like mappers|MMC3-like mappers]]<br />
* [http://www.romhacking.net/documents/362/ NES Mapper list] by Disch.<br />
* [http://nesdev.org/mmc3.txt Nintendo MMC3] by goroh.<br />
* [http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\. Information on mapper's initial state is innacurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=Emulators&diff=2264Emulators2016-04-17T18:33:03Z<p>Zepper: Formerly Fx3 ^_^;;</p>
<hr />
<div>This is a '''list of NES emulators'''.<br />
<br />
__TOC__<br />
<br />
== Commercial ==<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| acNES<br />
| Nintendo<br />
| GameCube, Game Boy Advance<br />
| Used for Animal Crossing, e-Reader, and Classic NES Series. The name "acNES" is unofficial, as Nintendo has not released this emulator as a distinct product. Information from TCRF indicates that it may be called "QFC".<br />
|-<br />
| Virtual Console<br />
| Nintendo<br />
| Wii/Wii U/3DS<br />
| Most games cost 500 Nintendo Points in Wii Shop Channel<br />
|-<br />
| PocketNES<br />
| Atlus, Jaleco, Konami<br />
| Game Boy Advance, Nintendo DS<br />
| source: [[wikipedia:PocketNES#Commercial_use|Wikipedia]]<br />
|}<br />
<br />
== Popular ==<br />
These are commonly used or well-established.<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [http://code.google.com/p/bizhawk/ BizHawk] || Multiple authors || Win32, MacOS<br />
|-<br />
| [http://wiibrew.org/wiki/FCE_Ultra_GX FCE Ultra GX] || Tantric || Wii, GameCube<br />
|-<br />
| [http://fceux.com/web/home.html FCEUX] || Anthony Giorgio / Mark Doliner || Win32, Linux<br />
|-<br />
| [http://www.the-interweb.com/serendipity/index.php?/categories/9-FCEUXD-SP FCEUXD SP] || sp || Win32<br />
|-<br />
| [http://jabosoft.com/?categoryid=1 Jnes] || Jabosoft || Win32<br />
|-<br />
| [http://www.nemulator.com nemulator] || James Slepicka || Win32 (Vista/7)<br />
|-<br />
| [http://www.nesemu2.com/ nesemu2] || holodnak || Win32, OS X, Linux || [https://github.com/holodnak/nesemu2 github source]<br />
|-<br />
| [http://tnse.zophar.net/NESten.htm NESten] || TNSe || Win32<br />
|-<br />
| [http://nestopia.sourceforge.net/ NEStopia] || Martin Freij || Win32 || [http://rbelmont.mameworld.info/?page_id=200 Linux], [http://www.bannister.org/software/nestopia.htm MacOS]<br />
|-<br />
| [http://0ldsk00l.ca/nestopia/ Nestopia UE] || rdanbrook || Linux, BSD, Win7+ || a.k.a. Nestopia Undead Edition. Contains bugfixes/etc.<br />Windows binaries are available [http://sourceforge.net/projects/nestopiaue/ at Sourceforge] or [http://www.emucr.com/search/label/Nestopia at EmuCR]<br />
|-<br />
| [http://www.qmtpro.com/~nes/nintendulator/ Nintendulator] || Quietust || Win32 || [http://kkfos.aspekt.fi/projects/nes/tools/nintendulatordx/ Nintendulator DX] (by [[User:Thefox|thefox]]) for an even more-improved debugger<br />
|-<br />
| [http://problemkaputt.de/nes.htm NO$NES] || Martin Korth || Win32<br />
|-<br />
| [http://pocketnes.org/ PocketNES] || loopy, FluBBa, and Dwedit || Game Boy Advance || Updates on [http://www.dwedit.org/dwedit_board/viewtopic.php?id=409 Dwedit's board]<br />
|-<br />
| [http://rocknes.web.fc2.com RockNES] || Zepper (formerly Fx3) || Win32<br />
|-<br />
| [http://www.ubernes.com/ UberNES] || M \ K Productions || Win32<br />
|-<br />
| [http://virtuanes.s1.xrea.com/ VirtuaNES] || Norix || Win32<br />
|}<br />
<br />
== Under development ==<br />
<br />
The following is a list of NES emulators that are supposedly under development, who their authors are, relevant home pages/sites, and the source of the announcement (direct or indirect).<br />
<br />
{{mbox<br />
| type = warning<br />
| text = '''Before considering developing your own NES emulator, ask yourself if your efforts may be better spent helping out those who already have emulators in development!'''<br />
}}<br />
<br />
{| class="wikitable sortable"<br />
! Emulator name<br />
! Author<br />
! Platform(s)<br />
! Ports and/or other details<br />
|-<br />
| [http://nesicide1.nesicide.com/ NESICIDE (version 1)] || NESICIDE || Win32<br />
|-<br />
| [http://nesicide2.nesicide.com/ NESICIDE (version 2)] || NESICIDE/essial || Win32/64, Linux32/64, MacOS<br />
|-<br />
| [http://fpganes.blogspot.se/ FPGA NES] || Ludde || FPGA (hardware)<br />
|-<br />
| [https://rm-rfroot.net/nes_fpga/ VeriNES] || jwdonal || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=6157 Announcement]<br />
|-<br />
| [http://kevtris.org/Projects/console/sections/index.html FPGA NES] || kevtris || FPGA (hardware)<br />
|-<br />
| [http://danstrother.com/fpga-nes/ FPGA NES] || Dan Strother || FPGA (hardware)<br />
|-<br />
| [http://code.google.com/p/nesface/ NESFaCE] || 6T4 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7499 Announcement]<br />
|-<br />
| [http://www.crazysmart.net.au/kindred kindred] || Overload || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10429 Announcement]<br />
|-<br />
| ? || allthatremains || Win32 || [http://forums.nesdev.org/viewtopic.php?t=5108 Announcement]<br />
|-<br />
| [http://www.aminlab.cn/app/nes/ ?] || amin2312 || Flash || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ModNES || Petruza || Portable, mainly MacOS & Win32 || [http://forums.nesdev.org/viewtopic.php?t=6159 Announcement]<br />
|-<br />
| [http://www.anes.se/ A/NES] || Morgan Johansson || AmigaOS || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| puNES || FHorse || Linux32/64, Win32/64 || [http://forums.nesdev.org/viewtopic.php?t=6928 Announcement]<br />
|-<br />
| famique || sahib || Mac OS X, Win32, Linux || [http://forums.nesdev.org/viewtopic.php?t=5922 Announcement]<br />
|-<br />
| FooNES || aphex || Win32 || [http://forums.nesdev.org/viewtopic.php?p=75152#p75152 Announcement]<br />
|-<br />
| nesemu1 || Bisqwit || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?t=8385 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?t=8400 MoarNES] || miker00lz || Win32 || [http://forums.nesdev.org/viewtopic.php?t=6972 Announcement]<br />
|-<br />
| jaNES || crudelios || Win32 || [http://forums.nesdev.org/viewtopic.php?p=89751 Announcement]<br />
|-<br />
| ? || neet || ? || [http://forums.nesdev.org/viewtopic.php?p=89437#p89437 Announcement]<br />
|-<br />
| ? || foobaz || Java || [http://forums.nesdev.org/viewtopic.php?t=8559 Announcement]<br />
|-<br />
| ? || MottZilla || ? || [http://forums.nesdev.org/viewtopic.php?t=8491 Announcement]<br />
|-<br />
| ? || runaway pancake || ? || [http://forums.nesdev.org/viewtopic.php?p=88478#p88478 Announcement]<br />
|-<br />
| ? || Vegenad || ? || [http://forums.nesdev.org/viewtopic.php?t=3593 Announcement]<br />
|-<br />
| ? || johnathonrh || ? || [http://forums.nesdev.org/viewtopic.php?t=5780 Announcement]<br />
|-<br />
| [http://www.yanese.com/ Yanese] || Anes || Win32 || [http://forums.nesdev.org/viewtopic.php?p=713 Announcement]<br />
|-<br />
| ? || nesemuguy || ? || [http://forums.nesdev.org/viewtopic.php?t=2798 Announcement]<br />
|-<br />
| ? || Coldberg || ? || [http://forums.nesdev.org/viewtopic.php?t=4231 Announcement]<br />
|-<br />
| ? || pops || ? || [http://forums.nesdev.org/viewtopic.php?t=6260 Announcement]<br />
|-<br />
| ? || beannaich || ? || [http://forums.nesdev.org/viewtopic.php?t=6240 Announcement]<br />
|-<br />
| ? || windwakr || ? || [http://forums.nesdev.org/viewtopic.php?t=6294 Announcement]<br />
|-<br />
| ? || JuniorZ || ? || [http://forums.nesdev.org/viewtopic.php?t=896 Announcement]<br />
|-<br />
| ? || NesHackR || ? || [http://forums.nesdev.org/viewtopic.php?t=6102 Announcement]<br />
|-<br />
| AwesomeNES || Snaer || libSDL (portable) || [http://forums.nesdev.org/viewtopic.php?t=6064 Announcement]<br />
|-<br />
| ? || BeTheDuck || ? || [http://forums.nesdev.org/viewtopic.php?t=5869 Announcement]<br />
|-<br />
| ? || Luke || ? || [http://forums.nesdev.org/viewtopic.php?t=5821 Announcement]<br />
|-<br />
| ? || The Lord || ? || [http://forums.nesdev.org/viewtopic.php?t=5795 Announcement]<br />
|-<br />
| ? || essial || ? || [http://forums.nesdev.org/viewtopic.php?t=5791 Announcement]<br />
|-<br />
| ? || JamesK89 || ? || [http://forums.nesdev.org/viewtopic.php?t=5787 Announcement]<br />
|-<br />
| ? || yaazz || OS X || [http://forums.nesdev.org/viewtopic.php?t=5723 Announcement]<br />
|-<br />
| ? || blanham || OS X || [http://forums.nesdev.org/viewtopic.php?t=5312 Announcement]<br />
|-<br />
| ? || magicphenix || ? || [http://forums.nesdev.org/viewtopic.php?t=5703 Announcement]<br />
|-<br />
| ? || happymaomao || ? || [http://forums.nesdev.org/viewtopic.php?t=5678 Announcement]<br />
|-<br />
| ? || someone_somewhere || ? || [http://forums.nesdev.org/viewtopic.php?t=5638 Announcement]<br />
|-<br />
| ? || Undubbed || ? || [http://forums.nesdev.org/viewtopic.php?t=5482 Announcement]<br />
|-<br />
| ? || Muchaserres || ? || [http://forums.nesdev.org/viewtopic.php?t=3665 Announcement]<br />
|-<br />
| ? || takeda || ? || [http://forums.nesdev.org/viewtopic.php?t=5530 Announcement]<br />
|-<br />
| ? || albailey || ? || [http://forums.nesdev.org/viewtopic.php?t=5512 Announcement]<br />
|-<br />
| ? || CaptainMuscles || ? || [http://forums.nesdev.org/viewtopic.php?t=5419 Announcement]<br />
|-<br />
| ? || hatorijr || ? || [http://forums.nesdev.org/viewtopic.php?t=5408 Announcement]<br />
|-<br />
| ? || tanoatnd || ? || [http://forums.nesdev.org/viewtopic.php?t=5189 Announcement]<br />
|-<br />
| ? || max_sweat || ? || [http://forums.nesdev.org/viewtopic.php?t=5388 Announcement]<br />
|-<br />
| ? || jjpeerless || ? || [http://forums.nesdev.org/viewtopic.php?t=5281 Announcement]<br />
|-<br />
| ? || Cloudy || ? || [http://forums.nesdev.org/viewtopic.php?t=5109 Announcement]<br />
|-<br />
| ? || meatloaf69 || ? || [http://forums.nesdev.org/viewtopic.php?p=62817#p62817 Announcement]<br />
|-<br />
| ? || parth || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?t=4502 Announcement]<br />
|-<br />
| ? || oRBIT2002 || ? || [http://forums.nesdev.org/viewtopic.php?t=1279 Announcement]<br />
|-<br />
| ? || Elessar || ? || [http://forums.nesdev.org/viewtopic.php?t=7862 Announcement]<br />
|-<br />
| ? || cmoh89 || ? || [http://forums.nesdev.org/viewtopic.php?t=7521 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?f=3&t=9935 HDNes] || mkwong98 || Win32 || [http://forums.nesdev.org/viewtopic.php?t=7848 Announcement]<br />
|-<br />
| ? || ehguacho || ? || [http://forums.nesdev.org/viewtopic.php?t=7936 Announcement]<br />
|-<br />
| ? || nop || Java || [http://forums.nesdev.org/viewtopic.php?t=8876 Announcement]<br />
|-<br />
| [https://github.com/Alegend45/MSE MSE] || Alegend45 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=8853 Announcement]<br />
|-<br />
| ? || emu_enthusiast || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=5826 Announcement]<br />
|-<br />
| [http://forums.nesdev.org/viewtopic.php?p=140741#p140741 MahNES] || HLorenzi || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9054 Announcement]<br />
|-<br />
| ? || haydenmuhl || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9101 Announcement]<br />
|-<br />
| ? || urbanspr1nter || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9227 Announcement]<br />
|-<br />
| Fergulator || fergus_maximus || Mac OS X or X Windows || [http://forums.nesdev.org/viewtopic.php?f=3&t=9292 Announcement]<br />
|-<br />
| ? || ermular || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9353 Announcement]<br />
|-<br />
| [http://www.kryptonware.com/ Kryptonware] || rubenhbaca || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=9395 Announcement]<br />
|-<br />
| ? || alexwy || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9608 Announcement]<br />
|-<br />
| ? || caiiio || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9625 Announcement]<br />
|-<br />
| ? || miguelsfp || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9726 Announcement]<br />
|-<br />
| ? || ember || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=3&t=9653 Announcement]<br />
|-<br />
| ? || ninjis || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=9829 Announcement]<br />
|-<br />
| [http://www.geocities.jp/submarine600/html/p8/nesemu.html ?] || submarine600 || PC-8801 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9921 Announcement]<br />
|-<br />
| [http://alike.se/yane/ Yane] || roku6185 || libSDL (portable), testing under Linux || [http://forums.nesdev.org/viewtopic.php?f=3&t=9969 Announcement]<br />
|-<br />
| [http://vpnes.googlecode.com/ VPNES] || x0000 || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=9989 Announcement]<br />
|-<br />
| [https://github.com/eteran/pretendo Pretendo] || proxy || Linux/BeOS/Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=10045 Announcement]<br />
|-<br />
| ? || samfoo || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10070 Announcement]<br />
|-<br />
| ? || LightStruk || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10071 Announcement]<br />
|-<br />
| [http://zelex.net/nezulator Nezulator] || Zelex || JavaScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=7704 Announcement]<br />
|-<br />
| [http://www.oriku.com/emuya.html EMUya] || Zelex || Ouya || [http://forums.nesdev.org/viewtopic.php?f=3&t=10002 Announcement]<br />
|-<br />
| ? || dreampeppers99 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10130 Announcement]<br />
|-<br />
| ? || Skypher || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10193 Announcement]<br />
|-<br />
<!--<br />
|-<br />
| ? || Dartht33bagger || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10266 Announcement]<br />
|-<br />
--><br />
|-<br />
| [http://eigenbloom.com/projects/nes/nestest.php?version=1 ?] || graham || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=10243 Announcement]<br />
|-<br />
| ? || ArsonIzer || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=10297 Announcement]<br />
|-<br />
| ? || SuperFXMaster || FPGA (hardware) || [http://forums.nesdev.org/viewtopic.php?f=10&t=10308 Announcement]<br />
|-<br />
| ? || Choz || Win32 w/ SDL || [http://forums.nesdev.org/viewtopic.php?f=3&t=10333 Announcement]<br />
|-<br />
| ? || sronsse || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10348 Announcement]<br />
|-<br />
| ? || Emu6502Writer || ? || [http://forums.nesdev.org/viewtopic.php?p=116397#p116397 Announcement]<br />
|-<br />
| ? || fred || ? || [http://forums.nesdev.org/viewtopic.php?p=117245#p117245 Announcement]<br />
|-<br />
| ? || janzdott || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10558 Announcement]<br />
|-<br />
| ? || d15ea5e || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10569 Announcement]<br />
|-<br />
| ? || mrhyde || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10751 Announcement]<br />
|-<br />
| ? || codeblox || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=10781 Announcement]<br />
|-<br />
| [http://return-1.com/FC87/FC87.html FC87] || Boolean || SDL (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=10839 Announcement]<br />
|-<br />
| phibiaNES || nIghtorius || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11201 Announcement]<br />
|-<br />
| ? || Choz || ? || [http://forums.nesdev.org/viewtopic.php?f=2&t=11639 Announcement]<br />
|-<br />
| [https://github.com/nwidger/nintengo nintengo] || nwidger || Go w/ libSDL || <br />
|-<br />
| [https://github.com/rockcarry/ffnes ffnes] || rockcarry || Win32 || [http://forums.nesdev.org/viewtopic.php?f=3&t=11948 Announcement]<br />
|-<br />
| [https://github.com/peteward44/WebNES WebNES] || peteward44 || Javascript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12006 Announcement] / [http://peteward44.github.io/WebNES Live demo]<br />
|-<br />
| O-Nes-Sama || Fumarumota, aLaix || SDL2 (Win32, GNU/Linux) || [http://forums.nesdev.org/viewtopic.php?f=3&t=11287 Announcement]<br />
|-<br />
| Nintaco || zeroone || Java || [http://forums.nesdev.org/viewtopic.php?f=3&t=12185 Announcement]<br />
|-<br />
| ? || austere || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12222 Announcement]<br />
|-<br />
| [https://github.com/jpikl/cfxnes cfxnes] || jonyzz || Javascript/CoffeeScript || [http://forums.nesdev.org/viewtopic.php?f=3&t=12315 Announcement] / [http://cfxnes.herokuapp.com/ Live demo]<br />
|-<br />
| ? || mreiland || ? || [http://forums.nesdev.org/viewtopic.php?p=143522#p143522 Announcement]<br />
|-<br />
| [https://github.com/amaiorano/nes-emu ?] || daroou || Win32 || [http://forums.nesdev.org/viewtopic.php?p=143752#p143752 Announcement]<br />
|-<br />
| [https://github.com/fogleman/nes fogleman/nes] || Michael Fogleman || Go with Go/GL and PortAudio || [https://medium.com/@fogleman/i-made-an-nes-emulator-here-s-what-i-learned-about-the-original-nintendo-2e078c9b28fe Medium article]<br />
|-<br />
| ? || RobertLoggia || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12605 Announcement]<br />
|-<br />
| [https://github.com/ulfalizer/nesalizer nesalizer] || Ulfalizer || libSDL (portable), tested on Linux ||<br />
|-<br />
| ? || NewDietCoke248903 || ? || [http://forums.nesdev.org/viewtopic.php?f=3&t=12725 Announcement]<br />
|-<br />
| ? || imid || Win32/.NET || Repeated questions/details on [[NESdev IRC channel]]<br />
|-<br />
| ? || mreiland || Linux (?) || [http://forums.nesdev.org/viewtopic.php?p=146814#p146814 Announcement]<br />
|-<br />
| nSide || hex_usr || ? || Fork of byuu's higan-nes. [http://forums.nesdev.org/viewtopic.php?f=3&t=12792 Announcement]<br />
|-<br />
| ? || DarylTechNES || ? || [http://forums.nesdev.org/viewtopic.php?p=147242#p147242 Announcement]<br />
|-<br />
| [https://github.com/andrew-hoffman/halfnes HalfNES] || Grapeshot || Java || [https://github.com/andrew-hoffman/halfnes/tree/master/src Github source]<br />
|-<br />
| ? || thomson || ? || [http://forums.nesdev.org/viewtopic.php?p=167743#p167743 Announcement]<br />
|}</div>Zepperhttps://www.nesdev.org/w/index.php?title=MMC3&diff=6507MMC32015-04-26T14:12:13Z<p>Zepper: /* IRQ reload ($C001-$DFFF, odd) */</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=MMC3<br />
|name2=TxROM<br />
|company=Nintendo, others<br />
|mapper=4<br />
|nescartdbgames=300<br />
|complexity=ASIC<br />
|boards=TSROM, others<br />
|prgmax=512K<br />
|prgpage=8K + 8K + 16K fixed<br />
|wrammax=8K<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=2Kx2 + 4Kx1<br />
|mirroring=H or V, switchable, or 4 fixed<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
[[Category:MMC3-like mappers]][[Category:Nintendo licensed mappers]]<br />
The '''Nintendo MMC3''' is a [[MMC|mapper]] [[:Category:ASIC mappers|ASIC]] used in Nintendo's [[TxROM]] Game Pak boards. Most common TxROM boards, along with the '''NES-HKROM''' board (which uses the Nintendo [[MMC6]]) are assigned to [[iNES Mapper 004]]; the TKSROM and TLSROM boards are assigned to [[iNES Mapper 118]], and TQROM is assigned to [[iNES Mapper 119]].<br />
This chip first appeared in the fourth quarter of 1988.<br />
<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB PRG RAM bank<br />
* CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank<br />
* CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank<br />
* PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank<br />
* PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank<br />
* PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank<br />
* PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank<br />
* PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank<br />
* PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank<br />
<br />
== Registers ==<br />
<br />
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
These can be broken into two independent functional units: memory mapping ($8000, $8001, $A000, $A001) and scanline counting ($C000, $C001, $E000, $E001).<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPxx xRRR<br />
|| |||<br />
|| +++- Specify which bank register to update on next write to Bank Data register<br />
|| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);<br />
|| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);<br />
|| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
|| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
|| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
|| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
|| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);<br />
|| 7: Select 8 KB PRG ROM bank at $A000-$BFFF<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,<br />
| $C000-$DFFF fixed to second-last bank;<br />
| 1: $C000-$DFFF swappable,<br />
| $8000-$9FFF fixed to second-last bank)<br />
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,<br />
four 1 KB banks at $1000-$1FFF;<br />
1: two 2 KB banks at $1000-$1FFF,<br />
four 1 KB banks at $0000-$0FFF)<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$80 !! is 0 !! is #$80<br />
|-<br />
! PPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $0000-$03FF || R0 AND $FE || R2<br />
|-<br />
| $0400-$07FF || R0 OR 1 || R3<br />
|-<br />
| $0800-$0BFF || R1 AND $FE || R4<br />
|-<br />
| $0C00-$0FFF || R1 OR 1 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0 AND $FE<br />
|-<br />
| $1400-$17FF || R3 || R0 OR 1<br />
|-<br />
| $1800-$1BFF || R4 || R1 AND $FE<br />
|-<br />
| $1C00-$1FFF || R5 || R1 OR 1<br />
|}<br />
<br />
==== PRG Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$40 !! is 0 !! is #$40<br />
|-<br />
! CPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $8000-$9FFF || R6 || (-2)<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || (-2) || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank, in a proper MMC3, the 63rd<br />
* (-2) : the penultimate bank; properly the 62nd<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)<br />
<br />
The PRG banks are 8192 bytes in size, half the size of an [[iNES]] PRG bank.<br />
If your emulator or copier handles PRG data in 16384 byte chunks, you can think of the lower bit as selecting the first or second half of the bank:[http://forums.nesdev.org/viewtopic.php?p=38182#p38182]<br />
<br />
7 bit 0 When $8000 AND #$06 == #$06<br />
---- ----<br />
xxBB BBBH<br />
|| ||||<br />
|| |||+- 0: Select first half of this bank;<br />
|| ||| 1: Select second half of this bank<br />
++-+++-- Select 16 KB PRG bank at $8000-$9FFF, $A000-$BFFF, or $C000-$DFFF<br />
<br />
Writes to registers 6 and 7 always ignore bits 6 and 7, as the MMC3 has only 6 PRG ROM address output lines.<br />
Writes to registers 0 and 1 always ignore bit 0, loading the value AND #$FE into the first half and the value OR #$01 into the second half of the 2 KiB bank.<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- Nametable [[mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This bit has no effect on ''[http://bootgod.dyndns.org:7777/profile.php?id=137 Rad Racer II]'', which uses the TVROM board, because TVROM is hardwired to 4-screen VRAM.<br />
In the iNES and NES 2.0 formats, TVROM can be identified through [[INES#Flags 6|bit 3 of byte $06 of the header]].<br />
<br />
=== PRG RAM protect ($A001-$BFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
RWxx xxxx<br />
||<br />
|+-------- Write protection (0: allow writes; 1: deny writes)<br />
+--------- Chip enable (0: disable chip; 1: enable chip)<br />
These bits work on the MMC3 that blargg tried, even if some emulators do not implement them.<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
<span id="IRQ"></span><br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- IRQ latch value<br />
<br />
This register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied to the IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register reloads the MMC3 IRQ counter at the NEXT rising edge of the PPU address, presumably at PPU cycle 260 of the current scanline.<br />
<br />
=== IRQ disable ($E000-$FFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will disable MMC3 interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will enable MMC3 interrupts.<br />
<br />
== Hardware ==<br />
<br />
The MMC3 most commonly exists in a [[MMC3_pinout|44-pin TQFP package]].<br />
Three revisions are known to exist - MMC3A, MMC3B, and MMC3C. No major behavioral differences are known, except for the IRQ counter.<br />
<br />
The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for two rising edges of M2).<br />
<br />
The counter is based on the following trick: whenever rendering is turned on in the [[PPU]], it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible.<br />
Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame. It may oscillate more if the program uses registers $2006 and $2007 to access PPU $1000-$1FFF during vblank, but this is rare because very few games have MMC3 and CHR RAM (two on TQROM and three on TGROM among NES games, and a couple more Famicom-only games). The scanline counter will also work when the BG uses the right pattern table ($1000) and the sprites use the left pattern table ($0000), but this is less common.<br />
<br />
The MMC3 IRQ has two revisions that work slightly different [http://forums.nesdev.org/viewtopic.php?p=62546#p62546].<br />
* For the alternate version, the ''reload flag'' is set to '''true''' when writing to $C001.<br />
* When the scanline counter is clocked, the value will first be checked. If it is zero '''or''' the ''reload flag'' is set to true, it will be reloaded from the IRQ latch ($C000); otherwise, it will decrement. If the scanline counter is zero, an IRQ will be fired if IRQ generation is enabled (by writing to $E001); also, the alternate version checks if the scanline counter is zero and the previous value is non-zero, whether from decrementing or reloading.<br />
<br />
Regarding PPU A12 rises:<br />
* If the BG uses $0000, and the sprites use $1000, then the IRQ will occur after PPU cycle 260 (as in, a little after the visible part of the target scanline has ended).<br />
* If the BG uses $1000, and the sprites use $0000, then the IRQ will occur after PPU cycle 324 of the ''previous'' scanline (as in, ''right before'' the target scanline is about to be drawn).<br />
* When using 8x16 sprites: When there are less than 8 sprites on a scanline, the PPU makes a dummy fetch to tile $FF for each leftover sprite. In 8x16 sprite mode, tile $FF corresponds to the right pattern table ($1000).<br />
<br />
Important points:<br />
* The scanline counter cannot be stopped. It will continue to decrement and reload as long as PPU A12 on the PPU bus toggles.<br />
* There is no direct access to the counter! The best you can do is update the reload value and immediately request a reload.<br />
* Writing to $E000 will only prevent the MMC3 from generating IRQs - the counter will continue to run.<br />
* Writing to $E001 will simply allow the MMC3 to generate IRQs - the counter remains unaffected.<br />
* Writing to $C001 will cause the counter to be cleared, and set ''reload flag'' to '''true'''. It will be reloaded on the NEXT rising edge of the PPU A12.<br />
* Writing to $C000 does not immediately affect the value within the counter - this value is only used when the counter is reloaded, whether from reaching 0 or from writing to $C001.<br />
* The exact number of scanlines between IRQs is N+1, where N is the value written to $C000. 1 (Sharp MMC3B, MMC3C) or 2 (MMC3A, Non-Sharp MMC3B) to 256 scanlines are supported.<br />
* The counter will not work properly unless you use different pattern tables for background and sprite data. The standard configuration is to use PPU $0000-$0FFF for background tiles and $1000-$1FFF for sprite tiles, whether 8x8 or 8x16.<br />
* The counter is clocked on each rising edge of PPU A12, no matter what caused it, so it is possible to (intentionally or not) clock the counter by writing to $2006.<br />
<br />
There's a slight discrepancy with what happens when you set $C000 to $00, and so far, two behaviors are known to exist:<br />
* All MMC3A's and non-Sharp MMC3B's will generate only a single IRQ when $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''decremented'' to 0. In addition, writing to $C001 with $C000 still at $00 will result in another single IRQ being generated. In the community, this is known as the "alternate" or "old" behavior.<br />
* All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''equal'' to 0. In the community, this is known as the "normal" or "new" behavior.<br />
<br />
Acclaim's MC-ACC chip is their own variant of the MMC3, that they used for their own boards (for industrial money-saving purposes). It comes in a standard 600 mil 40-pin DIP package. It is not known if it has SRAM support. The only known difference is that the scanline counter triggers on [http://forums.nesdev.org/viewtopic.php?p=116691#p116691 ''falling'' edges] instead of rising edges.<br />
<br />
== Variants ==<br />
The TKSROM and TLSROM boards, assigned to [[INES Mapper 118]], connect the upper bank select line directly to VRAM A10, allowing more flexible control over nametable mirroring.<br />
<br />
The TQROM board, assigned to [[INES Mapper 119]], uses both CHR ROM and CHR RAM simultaneously, using the 2nd-highest CHR bank select line to choose between them (on a per-bank basis).<br />
<br />
[[DxROM]] carts have a custom mapper developed by Namco before the MMC3 existed.<br />
Tengen used it for some of their games under the name MIMIC-1.<br />
It exists both in a [[Namcot 108 family pinout|400 mil 28-pin Shrink-DIP]] (found in licensed [[DxROM]] boards) and in a larger 600 mil 28-pin DIP (found in unlicensed Tengen cartridges).<br />
<br />
This chip does the basic PRG ROM switching exactly like the MMC3, but it only implements the low 3 bits of $8000 and the low 6 bits of $8001. Compared to the MMC3, it lacks mirroring control, SRAM support and an IRQ counter. The TEROM and TFROM boards have been developed with backward compability with [[DxROM]] in mind, featuring solder pads to have hardwired H/V mirroring instead of MMC3 controlled mirroring, and allow the hardware to disable IRQs.<br />
<br />
IRQ behavior when reload is set to 0 differs among different MMC3 chips.<br />
MMC3 chips with the "new behavior" generate an IRQ every scanline.<br />
(These include at least MMC3B chips bearing a bold S before the date code.)<br />
MMC3 chips with the "old behavior" cease to generate IRQs.<br />
(These include MMC3B chips lacking the S and having a date code of the form nnnnPKnnn, and an MMC3A 8940EP chip.)<br />
Some games have been manufactured with both versions, and during the transition, relying on old or new behavior might at first have been one of the things that caused Nintendo lot check to reject a program.<br />
A few later games developed after Nintendo had run out of the old chips, such as ''[http://bootgod.dyndns.org:7777/profile.php?id=249 Star Trek: 25th Anniversary]'', are reported to rely on the new behavior (source: Nestopia 1.30 changelog).<br />
There's an anecdotal report that [http://forums.nesdev.org/viewtopic.php?p=124478#p124478 ''Felix the Cat'' needs MMC3A], but it could also have been a rewiring mistake.<br />
<br />
Nintendo made at least two MMC3-based multicart mappers: mappers [[INES Mapper 037|37]] and [[INES Mapper 047|47]].<br />
<br />
== Pirate variants ==<br />
* [[INES Mapper 245|Mapper 245]] increases PRG to 1024K by losing CHR ROM.<br />
<br />
* Mappers [[INES Mapper 205|205]], [[INES Mapper 052|52]], [[INES Mapper 049|49]], [[INES Mapper 045|45]], and [[INES Mapper 044|44]] force unmodified games together in a multicart. <br />
<br />
* [[INES Mapper 189|Mapper 189]] loses the MMC3's 8+8+16F banking scheme in exchange for 32k-at-a-time banking like [[AxROM]], [[BxROM]], or [[GxROM]]<br />
<br />
* [[INES Mapper 182|Mapper 182]]'s registers are only in a different order.<br />
<br />
* [[INES Mapper 115|Mapper 115]] increases CHR to 512K by losing PRG RAM and contains an [[UxROM]] emulation mode.<br />
<br />
* Mappers [[INES Mapper 194|194]], [[INES Mapper 192|192]], [[INES Mapper 191|191]], and [[INES Mapper 074|74]], are like TQROM in that they combine CHR ROM and CHR RAM by replacing some CHR pages with CHR RAM.<br />
<br />
== See also ==<br />
* [http://www.romhacking.net/documents/362/ NES Mapper list] by Disch.<br />
* [http://nesdev.org/mmc3.txt Nintendo MMC3] by goroh.<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\. Information on mapper's initial state is innacurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=MMC3&diff=6505MMC32015-04-26T01:46:49Z<p>Zepper: /* IRQ reload ($C001-$DFFF, odd) */</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=MMC3<br />
|name2=TxROM<br />
|company=Nintendo, others<br />
|mapper=4<br />
|nescartdbgames=300<br />
|complexity=ASIC<br />
|boards=TSROM, others<br />
|prgmax=512K<br />
|prgpage=8K + 8K + 16K fixed<br />
|wrammax=8K<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=2Kx2 + 4Kx1<br />
|mirroring=H or V, switchable, or 4 fixed<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
[[Category:MMC3-like mappers]][[Category:Nintendo licensed mappers]]<br />
The '''Nintendo MMC3''' is a [[MMC|mapper]] [[:Category:ASIC mappers|ASIC]] used in Nintendo's [[TxROM]] Game Pak boards. Most common TxROM boards, along with the '''NES-HKROM''' board (which uses the Nintendo [[MMC6]]) are assigned to [[iNES Mapper 004]]; the TKSROM and TLSROM boards are assigned to [[iNES Mapper 118]], and TQROM is assigned to [[iNES Mapper 119]].<br />
This chip first appeared in the fourth quarter of 1988.<br />
<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB PRG RAM bank<br />
* CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank<br />
* CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank<br />
* PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank<br />
* PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank<br />
* PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank<br />
* PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank<br />
* PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank<br />
* PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank<br />
<br />
== Registers ==<br />
<br />
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
These can be broken into two independent functional units: memory mapping ($8000, $8001, $A000, $A001) and scanline counting ($C000, $C001, $E000, $E001).<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPxx xRRR<br />
|| |||<br />
|| +++- Specify which bank register to update on next write to Bank Data register<br />
|| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);<br />
|| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);<br />
|| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
|| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
|| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
|| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
|| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);<br />
|| 7: Select 8 KB PRG ROM bank at $A000-$BFFF<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,<br />
| $C000-$DFFF fixed to second-last bank;<br />
| 1: $C000-$DFFF swappable,<br />
| $8000-$9FFF fixed to second-last bank)<br />
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,<br />
four 1 KB banks at $1000-$1FFF;<br />
1: two 2 KB banks at $1000-$1FFF,<br />
four 1 KB banks at $0000-$0FFF)<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$80 !! is 0 !! is #$80<br />
|-<br />
! PPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $0000-$03FF || R0 AND $FE || R2<br />
|-<br />
| $0400-$07FF || R0 OR 1 || R3<br />
|-<br />
| $0800-$0BFF || R1 AND $FE || R4<br />
|-<br />
| $0C00-$0FFF || R1 OR 1 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0 AND $FE<br />
|-<br />
| $1400-$17FF || R3 || R0 OR 1<br />
|-<br />
| $1800-$1BFF || R4 || R1 AND $FE<br />
|-<br />
| $1C00-$1FFF || R5 || R1 OR 1<br />
|}<br />
<br />
==== PRG Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$40 !! is 0 !! is #$40<br />
|-<br />
! CPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $8000-$9FFF || R6 || (-2)<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || (-2) || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank, in a proper MMC3, the 63rd<br />
* (-2) : the penultimate bank; properly the 62nd<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)<br />
<br />
The PRG banks are 8192 bytes in size, half the size of an [[iNES]] PRG bank.<br />
If your emulator or copier handles PRG data in 16384 byte chunks, you can think of the lower bit as selecting the first or second half of the bank:[http://forums.nesdev.org/viewtopic.php?p=38182#p38182]<br />
<br />
7 bit 0 When $8000 AND #$06 == #$06<br />
---- ----<br />
xxBB BBBH<br />
|| ||||<br />
|| |||+- 0: Select first half of this bank;<br />
|| ||| 1: Select second half of this bank<br />
++-+++-- Select 16 KB PRG bank at $8000-$9FFF, $A000-$BFFF, or $C000-$DFFF<br />
<br />
Writes to registers 6 and 7 always ignore bits 6 and 7, as the MMC3 has only 6 PRG ROM address output lines.<br />
Writes to registers 0 and 1 always ignore bit 0, loading the value AND #$FE into the first half and the value OR #$01 into the second half of the 2 KiB bank.<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- Nametable [[mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This bit has no effect on ''[http://bootgod.dyndns.org:7777/profile.php?id=137 Rad Racer II]'', which uses the TVROM board, because TVROM is hardwired to 4-screen VRAM.<br />
In the iNES and NES 2.0 formats, TVROM can be identified through [[INES#Flags 6|bit 3 of byte $06 of the header]].<br />
<br />
=== PRG RAM protect ($A001-$BFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
RWxx xxxx<br />
||<br />
|+-------- Write protection (0: allow writes; 1: deny writes)<br />
+--------- Chip enable (0: disable chip; 1: enable chip)<br />
These bits work on the MMC3 that blargg tried, even if some emulators do not implement them.<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
<span id="IRQ"></span><br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- IRQ latch value<br />
<br />
This register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied to the IRQ counter at the NEXT rising edge of the PPU address, presumably at cycle 260th of the current scanline.<br />
<br />
=== IRQ reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register reloads the MMC3 IRQ counter at the NEXT rising edge of the PPU address, presumably at cycle 260th of the current scanline.<br />
<br />
=== IRQ disable ($E000-$FFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will disable MMC3 interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will enable MMC3 interrupts.<br />
<br />
== Hardware ==<br />
<br />
The MMC3 most commonly exists in a [[MMC3_pinout|44-pin TQFP package]].<br />
Three revisions are known to exist - MMC3A, MMC3B, and MMC3C. No major behavioral differences are known, except for the IRQ counter.<br />
<br />
The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for two rising edges of M2).<br />
<br />
The counter is based on the following trick: whenever rendering is turned on in the [[PPU]], it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible.<br />
Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame. It may oscillate more if the program uses registers $2006 and $2007 to access PPU $1000-$1FFF during vblank, but this is rare because very few games have MMC3 and CHR RAM (two on TQROM and three on TGROM among NES games, and a couple more Famicom-only games). The scanline counter will also work when the BG uses the right pattern table ($1000) and the sprites use the left pattern table ($0000), but this is less common.<br />
<br />
The MMC3 IRQ has two revisions that work slightly different [http://forums.nesdev.org/viewtopic.php?p=62546#p62546].<br />
* For the alternate version, the ''reload flag'' is set to '''true''' when writing to $C001.<br />
* When the scanline counter is clocked, the value will first be checked. If it is zero '''or''' the ''reload flag'' is set to true, it will be reloaded from the IRQ latch ($C000); otherwise, it will decrement. If the scanline counter is zero, an IRQ will be fired if IRQ generation is enabled (by writing to $E001); also, the alternate version checks if the scanline counter is zero and the previous value is non-zero, whether from decrementing or reloading.<br />
<br />
Regarding PPU A12 rises:<br />
* If the BG uses $0000, and the sprites use $1000, then the IRQ will occur after PPU cycle 260 (as in, a little after the visible part of the target scanline has ended).<br />
* If the BG uses $1000, and the sprites use $0000, then the IRQ will occur after PPU cycle 324 of the ''previous'' scanline (as in, ''right before'' the target scanline is about to be drawn).<br />
* When using 8x16 sprites: When there are less than 8 sprites on a scanline, the PPU makes a dummy fetch to tile $FF for each leftover sprite. In 8x16 sprite mode, tile $FF corresponds to the right pattern table ($1000).<br />
<br />
Important points:<br />
* The scanline counter cannot be stopped. It will continue to decrement and reload as long as PPU A12 on the PPU bus toggles.<br />
* There is no direct access to the counter! The best you can do is update the reload value and immediately request a reload.<br />
* Writing to $E000 will only prevent the MMC3 from generating IRQs - the counter will continue to run.<br />
* Writing to $E001 will simply allow the MMC3 to generate IRQs - the counter remains unaffected.<br />
* Writing to $C001 will cause the counter to be cleared, and set ''reload flag'' to '''true'''. It will be reloaded on the NEXT rising edge of the PPU A12.<br />
* Writing to $C000 does not immediately affect the value within the counter - this value is only used when the counter is reloaded, whether from reaching 0 or from writing to $C001.<br />
* The exact number of scanlines between IRQs is N+1, where N is the value written to $C000. 1 (Sharp MMC3B, MMC3C) or 2 (MMC3A, Non-Sharp MMC3B) to 256 scanlines are supported.<br />
* The counter will not work properly unless you use different pattern tables for background and sprite data. The standard configuration is to use PPU $0000-$0FFF for background tiles and $1000-$1FFF for sprite tiles, whether 8x8 or 8x16.<br />
* The counter is clocked on each rising edge of PPU A12, no matter what caused it, so it is possible to (intentionally or not) clock the counter by writing to $2006.<br />
<br />
There's a slight discrepancy with what happens when you set $C000 to $00, and so far, two behaviors are known to exist:<br />
* All MMC3A's and non-Sharp MMC3B's will generate only a single IRQ when $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''decremented'' to 0. In addition, writing to $C001 with $C000 still at $00 will result in another single IRQ being generated. In the community, this is known as the "alternate" or "old" behavior.<br />
* All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''equal'' to 0. In the community, this is known as the "normal" or "new" behavior.<br />
<br />
Acclaim's MC-ACC chip is their own variant of the MMC3, that they used for their own boards (for industrial money-saving purposes). It comes in a standard 600 mil 40-pin DIP package. It is not known if it has SRAM support. The only known difference is that the scanline counter triggers on [http://forums.nesdev.org/viewtopic.php?p=116691#p116691 ''falling'' edges] instead of rising edges.<br />
<br />
== Variants ==<br />
The TKSROM and TLSROM boards, assigned to [[INES Mapper 118]], connect the upper bank select line directly to VRAM A10, allowing more flexible control over nametable mirroring.<br />
<br />
The TQROM board, assigned to [[INES Mapper 119]], uses both CHR ROM and CHR RAM simultaneously, using the 2nd-highest CHR bank select line to choose between them (on a per-bank basis).<br />
<br />
[[DxROM]] carts have a custom mapper developed by Namco before the MMC3 existed.<br />
Tengen used it for some of their games under the name MIMIC-1.<br />
It exists both in a [[Namcot 108 family pinout|400 mil 28-pin Shrink-DIP]] (found in licensed [[DxROM]] boards) and in a larger 600 mil 28-pin DIP (found in unlicensed Tengen cartridges).<br />
<br />
This chip does the basic PRG ROM switching exactly like the MMC3, but it only implements the low 3 bits of $8000 and the low 6 bits of $8001. Compared to the MMC3, it lacks mirroring control, SRAM support and an IRQ counter. The TEROM and TFROM boards have been developed with backward compability with [[DxROM]] in mind, featuring solder pads to have hardwired H/V mirroring instead of MMC3 controlled mirroring, and allow the hardware to disable IRQs.<br />
<br />
IRQ behavior when reload is set to 0 differs among different MMC3 chips.<br />
MMC3 chips with the "new behavior" generate an IRQ every scanline.<br />
(These include at least MMC3B chips bearing a bold S before the date code.)<br />
MMC3 chips with the "old behavior" cease to generate IRQs.<br />
(These include MMC3B chips lacking the S and having a date code of the form nnnnPKnnn, and an MMC3A 8940EP chip.)<br />
Some games have been manufactured with both versions, and during the transition, relying on old or new behavior might at first have been one of the things that caused Nintendo lot check to reject a program.<br />
A few later games developed after Nintendo had run out of the old chips, such as ''[http://bootgod.dyndns.org:7777/profile.php?id=249 Star Trek: 25th Anniversary]'', are reported to rely on the new behavior (source: Nestopia 1.30 changelog).<br />
There's an anecdotal report that [http://forums.nesdev.org/viewtopic.php?p=124478#p124478 ''Felix the Cat'' needs MMC3A], but it could also have been a rewiring mistake.<br />
<br />
Nintendo made at least two MMC3-based multicart mappers: mappers [[INES Mapper 037|37]] and [[INES Mapper 047|47]].<br />
<br />
== Pirate variants ==<br />
* [[INES Mapper 245|Mapper 245]] increases PRG to 1024K by losing CHR ROM.<br />
<br />
* Mappers [[INES Mapper 205|205]], [[INES Mapper 052|52]], [[INES Mapper 049|49]], [[INES Mapper 045|45]], and [[INES Mapper 044|44]] force unmodified games together in a multicart. <br />
<br />
* [[INES Mapper 189|Mapper 189]] loses the MMC3's 8+8+16F banking scheme in exchange for 32k-at-a-time banking like [[AxROM]], [[BxROM]], or [[GxROM]]<br />
<br />
* [[INES Mapper 182|Mapper 182]]'s registers are only in a different order.<br />
<br />
* [[INES Mapper 115|Mapper 115]] increases CHR to 512K by losing PRG RAM and contains an [[UxROM]] emulation mode.<br />
<br />
* Mappers [[INES Mapper 194|194]], [[INES Mapper 192|192]], [[INES Mapper 191|191]], and [[INES Mapper 074|74]], are like TQROM in that they combine CHR ROM and CHR RAM by replacing some CHR pages with CHR RAM.<br />
<br />
== See also ==<br />
* [http://www.romhacking.net/documents/362/ NES Mapper list] by Disch.<br />
* [http://nesdev.org/mmc3.txt Nintendo MMC3] by goroh.<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\. Information on mapper's initial state is innacurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=MMC3&diff=6504MMC32015-04-26T01:46:18Z<p>Zepper: /* IRQ latch ($C000-$DFFE, even) */</p>
<hr />
<div>{{Infobox_iNES_mapper<br />
|name=MMC3<br />
|name2=TxROM<br />
|company=Nintendo, others<br />
|mapper=4<br />
|nescartdbgames=300<br />
|complexity=ASIC<br />
|boards=TSROM, others<br />
|prgmax=512K<br />
|prgpage=8K + 8K + 16K fixed<br />
|wrammax=8K<br />
|wrampage=8K<br />
|chrmax=256K<br />
|chrpage=2Kx2 + 4Kx1<br />
|mirroring=H or V, switchable, or 4 fixed<br />
|busconflicts=No<br />
|irq=Yes<br />
}}<br />
[[Category:MMC3-like mappers]][[Category:Nintendo licensed mappers]]<br />
The '''Nintendo MMC3''' is a [[MMC|mapper]] [[:Category:ASIC mappers|ASIC]] used in Nintendo's [[TxROM]] Game Pak boards. Most common TxROM boards, along with the '''NES-HKROM''' board (which uses the Nintendo [[MMC6]]) are assigned to [[iNES Mapper 004]]; the TKSROM and TLSROM boards are assigned to [[iNES Mapper 118]], and TQROM is assigned to [[iNES Mapper 119]].<br />
This chip first appeared in the fourth quarter of 1988.<br />
<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB PRG RAM bank<br />
* CPU $8000-$9FFF (or $C000-$DFFF): 8 KB switchable PRG ROM bank<br />
* CPU $A000-$BFFF: 8 KB switchable PRG ROM bank<br />
* CPU $C000-$DFFF (or $8000-$9FFF): 8 KB PRG ROM bank, fixed to the second-last bank<br />
* CPU $E000-$FFFF: 8 KB PRG ROM bank, fixed to the last bank<br />
* PPU $0000-$07FF (or $1000-$17FF): 2 KB switchable CHR bank<br />
* PPU $0800-$0FFF (or $1800-$1FFF): 2 KB switchable CHR bank<br />
* PPU $1000-$13FF (or $0000-$03FF): 1 KB switchable CHR bank<br />
* PPU $1400-$17FF (or $0400-$07FF): 1 KB switchable CHR bank<br />
* PPU $1800-$1BFF (or $0800-$0BFF): 1 KB switchable CHR bank<br />
* PPU $1C00-$1FFF (or $0C00-$0FFF): 1 KB switchable CHR bank<br />
<br />
== Registers ==<br />
<br />
The MMC3 has 4 pairs of registers at $8000-$9FFF, $A000-$BFFF, $C000-$DFFF, and $E000-$FFFF - even addresses ($8000, $8002, etc.) select the low register and odd addresses ($8001, $8003, etc.) select the high register in each pair.<br />
These can be broken into two independent functional units: memory mapping ($8000, $8001, $A000, $A001) and scanline counting ($C000, $C001, $E000, $E001).<br />
<br />
=== Bank select ($8000-$9FFE, even) ===<br />
7 bit 0<br />
---- ----<br />
CPxx xRRR<br />
|| |||<br />
|| +++- Specify which bank register to update on next write to Bank Data register<br />
|| 0: Select 2 KB CHR bank at PPU $0000-$07FF (or $1000-$17FF);<br />
|| 1: Select 2 KB CHR bank at PPU $0800-$0FFF (or $1800-$1FFF);<br />
|| 2: Select 1 KB CHR bank at PPU $1000-$13FF (or $0000-$03FF);<br />
|| 3: Select 1 KB CHR bank at PPU $1400-$17FF (or $0400-$07FF);<br />
|| 4: Select 1 KB CHR bank at PPU $1800-$1BFF (or $0800-$0BFF);<br />
|| 5: Select 1 KB CHR bank at PPU $1C00-$1FFF (or $0C00-$0FFF);<br />
|| 6: Select 8 KB PRG ROM bank at $8000-$9FFF (or $C000-$DFFF);<br />
|| 7: Select 8 KB PRG ROM bank at $A000-$BFFF<br />
|+-------- PRG ROM bank mode (0: $8000-$9FFF swappable,<br />
| $C000-$DFFF fixed to second-last bank;<br />
| 1: $C000-$DFFF swappable,<br />
| $8000-$9FFF fixed to second-last bank)<br />
+--------- CHR A12 inversion (0: two 2 KB banks at $0000-$0FFF,<br />
four 1 KB banks at $1000-$1FFF;<br />
1: two 2 KB banks at $1000-$1FFF,<br />
four 1 KB banks at $0000-$0FFF)<br />
==== CHR Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$80 !! is 0 !! is #$80<br />
|-<br />
! PPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $0000-$03FF || R0 AND $FE || R2<br />
|-<br />
| $0400-$07FF || R0 OR 1 || R3<br />
|-<br />
| $0800-$0BFF || R1 AND $FE || R4<br />
|-<br />
| $0C00-$0FFF || R1 OR 1 || R5<br />
|-<br />
| $1000-$13FF || R2 || R0 AND $FE<br />
|-<br />
| $1400-$17FF || R3 || R0 OR 1<br />
|-<br />
| $1800-$1BFF || R4 || R1 AND $FE<br />
|-<br />
| $1C00-$1FFF || R5 || R1 OR 1<br />
|}<br />
<br />
==== PRG Banks ====<br />
{| class="wikitable"<br />
! When $8000 & #$40 !! is 0 !! is #$40<br />
|-<br />
! CPU Bank !! colspan=2|Value of MMC3 register<br />
|-<br />
| $8000-$9FFF || R6 || (-2)<br />
|-<br />
| $A000-$BFFF || R7 || R7<br />
|-<br />
| $C000-$DFFF || (-2) || R6<br />
|-<br />
| $E000-$FFFF || (-1) || (-1)<br />
|}<br />
* (-1) : the last bank, in a proper MMC3, the 63rd<br />
* (-2) : the penultimate bank; properly the 62nd<br />
<br />
=== Bank data ($8001-$9FFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- New bank value, based on last value written to Bank select register (mentioned above)<br />
<br />
The PRG banks are 8192 bytes in size, half the size of an [[iNES]] PRG bank.<br />
If your emulator or copier handles PRG data in 16384 byte chunks, you can think of the lower bit as selecting the first or second half of the bank:[http://forums.nesdev.org/viewtopic.php?p=38182#p38182]<br />
<br />
7 bit 0 When $8000 AND #$06 == #$06<br />
---- ----<br />
xxBB BBBH<br />
|| ||||<br />
|| |||+- 0: Select first half of this bank;<br />
|| ||| 1: Select second half of this bank<br />
++-+++-- Select 16 KB PRG bank at $8000-$9FFF, $A000-$BFFF, or $C000-$DFFF<br />
<br />
Writes to registers 6 and 7 always ignore bits 6 and 7, as the MMC3 has only 6 PRG ROM address output lines.<br />
Writes to registers 0 and 1 always ignore bit 0, loading the value AND #$FE into the first half and the value OR #$01 into the second half of the 2 KiB bank.<br />
<br />
=== Mirroring ($A000-$BFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxM<br />
|<br />
+- Nametable [[mirroring]] (0: vertical; 1: horizontal)<br />
<br />
This bit has no effect on ''[http://bootgod.dyndns.org:7777/profile.php?id=137 Rad Racer II]'', which uses the TVROM board, because TVROM is hardwired to 4-screen VRAM.<br />
In the iNES and NES 2.0 formats, TVROM can be identified through [[INES#Flags 6|bit 3 of byte $06 of the header]].<br />
<br />
=== PRG RAM protect ($A001-$BFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
RWxx xxxx<br />
||<br />
|+-------- Write protection (0: allow writes; 1: deny writes)<br />
+--------- Chip enable (0: disable chip; 1: enable chip)<br />
These bits work on the MMC3 that blargg tried, even if some emulators do not implement them.<br />
<br />
=== IRQ latch ($C000-$DFFE, even) ===<br />
<span id="IRQ"></span><br />
7 bit 0<br />
---- ----<br />
DDDD DDDD<br />
|||| ||||<br />
++++-++++- IRQ latch value<br />
<br />
This register specifies the IRQ counter reload value. When the IRQ counter is zero (or a reload is requested through $C001), this value will be copied to the IRQ counter at the NEXT rising edge of the PPU address, presumably at cycle 260th of the current scanline.<br />
<br />
=== IRQ reload ($C001-$DFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register reloads the MMC3 IRQ counter at the NEXT rising edge of the PPU address, presumably at the end of the current scanline.<br />
<br />
=== IRQ disable ($E000-$FFFE, even) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will disable MMC3 interrupts AND acknowledge any pending interrupts.<br />
<br />
=== IRQ enable ($E001-$FFFF, odd) ===<br />
7 bit 0<br />
---- ----<br />
xxxx xxxx<br />
<br />
Writing any value to this register will enable MMC3 interrupts.<br />
<br />
== Hardware ==<br />
<br />
The MMC3 most commonly exists in a [[MMC3_pinout|44-pin TQFP package]].<br />
Three revisions are known to exist - MMC3A, MMC3B, and MMC3C. No major behavioral differences are known, except for the IRQ counter.<br />
<br />
The MMC3 scanline counter is based entirely on PPU A12, triggered on rising edges (after the line remains low for two rising edges of M2).<br />
<br />
The counter is based on the following trick: whenever rendering is turned on in the [[PPU]], it fetches nametable and BG pattern tiles from dots 0-255 and 320-340 of a scanline and fetches sprite patterns from dots 256-319, even if no sprites are visible.<br />
Because of this, if BG uses the left pattern table ($0000), and if sprites always use the right pattern table ($1000), A12 will remain low during all nametable and BG pattern fetches, and high during all sprite pattern fetches, causing it to oscillate exactly one time per scanline and 241 times per frame. It may oscillate more if the program uses registers $2006 and $2007 to access PPU $1000-$1FFF during vblank, but this is rare because very few games have MMC3 and CHR RAM (two on TQROM and three on TGROM among NES games, and a couple more Famicom-only games). The scanline counter will also work when the BG uses the right pattern table ($1000) and the sprites use the left pattern table ($0000), but this is less common.<br />
<br />
The MMC3 IRQ has two revisions that work slightly different [http://forums.nesdev.org/viewtopic.php?p=62546#p62546].<br />
* For the alternate version, the ''reload flag'' is set to '''true''' when writing to $C001.<br />
* When the scanline counter is clocked, the value will first be checked. If it is zero '''or''' the ''reload flag'' is set to true, it will be reloaded from the IRQ latch ($C000); otherwise, it will decrement. If the scanline counter is zero, an IRQ will be fired if IRQ generation is enabled (by writing to $E001); also, the alternate version checks if the scanline counter is zero and the previous value is non-zero, whether from decrementing or reloading.<br />
<br />
Regarding PPU A12 rises:<br />
* If the BG uses $0000, and the sprites use $1000, then the IRQ will occur after PPU cycle 260 (as in, a little after the visible part of the target scanline has ended).<br />
* If the BG uses $1000, and the sprites use $0000, then the IRQ will occur after PPU cycle 324 of the ''previous'' scanline (as in, ''right before'' the target scanline is about to be drawn).<br />
* When using 8x16 sprites: When there are less than 8 sprites on a scanline, the PPU makes a dummy fetch to tile $FF for each leftover sprite. In 8x16 sprite mode, tile $FF corresponds to the right pattern table ($1000).<br />
<br />
Important points:<br />
* The scanline counter cannot be stopped. It will continue to decrement and reload as long as PPU A12 on the PPU bus toggles.<br />
* There is no direct access to the counter! The best you can do is update the reload value and immediately request a reload.<br />
* Writing to $E000 will only prevent the MMC3 from generating IRQs - the counter will continue to run.<br />
* Writing to $E001 will simply allow the MMC3 to generate IRQs - the counter remains unaffected.<br />
* Writing to $C001 will cause the counter to be cleared, and set ''reload flag'' to '''true'''. It will be reloaded on the NEXT rising edge of the PPU A12.<br />
* Writing to $C000 does not immediately affect the value within the counter - this value is only used when the counter is reloaded, whether from reaching 0 or from writing to $C001.<br />
* The exact number of scanlines between IRQs is N+1, where N is the value written to $C000. 1 (Sharp MMC3B, MMC3C) or 2 (MMC3A, Non-Sharp MMC3B) to 256 scanlines are supported.<br />
* The counter will not work properly unless you use different pattern tables for background and sprite data. The standard configuration is to use PPU $0000-$0FFF for background tiles and $1000-$1FFF for sprite tiles, whether 8x8 or 8x16.<br />
* The counter is clocked on each rising edge of PPU A12, no matter what caused it, so it is possible to (intentionally or not) clock the counter by writing to $2006.<br />
<br />
There's a slight discrepancy with what happens when you set $C000 to $00, and so far, two behaviors are known to exist:<br />
* All MMC3A's and non-Sharp MMC3B's will generate only a single IRQ when $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''decremented'' to 0. In addition, writing to $C001 with $C000 still at $00 will result in another single IRQ being generated. In the community, this is known as the "alternate" or "old" behavior.<br />
* All MMC3C's and Sharp MMC3B's will generate an IRQ on each scanline while $C000 is $00. This is because this version of the MMC3 generates IRQs when the scanline counter is ''equal'' to 0. In the community, this is known as the "normal" or "new" behavior.<br />
<br />
Acclaim's MC-ACC chip is their own variant of the MMC3, that they used for their own boards (for industrial money-saving purposes). It comes in a standard 600 mil 40-pin DIP package. It is not known if it has SRAM support. The only known difference is that the scanline counter triggers on [http://forums.nesdev.org/viewtopic.php?p=116691#p116691 ''falling'' edges] instead of rising edges.<br />
<br />
== Variants ==<br />
The TKSROM and TLSROM boards, assigned to [[INES Mapper 118]], connect the upper bank select line directly to VRAM A10, allowing more flexible control over nametable mirroring.<br />
<br />
The TQROM board, assigned to [[INES Mapper 119]], uses both CHR ROM and CHR RAM simultaneously, using the 2nd-highest CHR bank select line to choose between them (on a per-bank basis).<br />
<br />
[[DxROM]] carts have a custom mapper developed by Namco before the MMC3 existed.<br />
Tengen used it for some of their games under the name MIMIC-1.<br />
It exists both in a [[Namcot 108 family pinout|400 mil 28-pin Shrink-DIP]] (found in licensed [[DxROM]] boards) and in a larger 600 mil 28-pin DIP (found in unlicensed Tengen cartridges).<br />
<br />
This chip does the basic PRG ROM switching exactly like the MMC3, but it only implements the low 3 bits of $8000 and the low 6 bits of $8001. Compared to the MMC3, it lacks mirroring control, SRAM support and an IRQ counter. The TEROM and TFROM boards have been developed with backward compability with [[DxROM]] in mind, featuring solder pads to have hardwired H/V mirroring instead of MMC3 controlled mirroring, and allow the hardware to disable IRQs.<br />
<br />
IRQ behavior when reload is set to 0 differs among different MMC3 chips.<br />
MMC3 chips with the "new behavior" generate an IRQ every scanline.<br />
(These include at least MMC3B chips bearing a bold S before the date code.)<br />
MMC3 chips with the "old behavior" cease to generate IRQs.<br />
(These include MMC3B chips lacking the S and having a date code of the form nnnnPKnnn, and an MMC3A 8940EP chip.)<br />
Some games have been manufactured with both versions, and during the transition, relying on old or new behavior might at first have been one of the things that caused Nintendo lot check to reject a program.<br />
A few later games developed after Nintendo had run out of the old chips, such as ''[http://bootgod.dyndns.org:7777/profile.php?id=249 Star Trek: 25th Anniversary]'', are reported to rely on the new behavior (source: Nestopia 1.30 changelog).<br />
There's an anecdotal report that [http://forums.nesdev.org/viewtopic.php?p=124478#p124478 ''Felix the Cat'' needs MMC3A], but it could also have been a rewiring mistake.<br />
<br />
Nintendo made at least two MMC3-based multicart mappers: mappers [[INES Mapper 037|37]] and [[INES Mapper 047|47]].<br />
<br />
== Pirate variants ==<br />
* [[INES Mapper 245|Mapper 245]] increases PRG to 1024K by losing CHR ROM.<br />
<br />
* Mappers [[INES Mapper 205|205]], [[INES Mapper 052|52]], [[INES Mapper 049|49]], [[INES Mapper 045|45]], and [[INES Mapper 044|44]] force unmodified games together in a multicart. <br />
<br />
* [[INES Mapper 189|Mapper 189]] loses the MMC3's 8+8+16F banking scheme in exchange for 32k-at-a-time banking like [[AxROM]], [[BxROM]], or [[GxROM]]<br />
<br />
* [[INES Mapper 182|Mapper 182]]'s registers are only in a different order.<br />
<br />
* [[INES Mapper 115|Mapper 115]] increases CHR to 512K by losing PRG RAM and contains an [[UxROM]] emulation mode.<br />
<br />
* Mappers [[INES Mapper 194|194]], [[INES Mapper 192|192]], [[INES Mapper 191|191]], and [[INES Mapper 074|74]], are like TQROM in that they combine CHR ROM and CHR RAM by replacing some CHR pages with CHR RAM.<br />
<br />
== See also ==<br />
* [http://www.romhacking.net/documents/362/ NES Mapper list] by Disch.<br />
* [http://nesdev.org/mmc3.txt Nintendo MMC3] by goroh.<br />
*[http://nesdev.org/mappers.zip Comprehensive NES Mapper Document] by \Firebug\. Information on mapper's initial state is innacurate.</div>Zepperhttps://www.nesdev.org/w/index.php?title=INES_Mapper_093&diff=4699INES Mapper 0932015-03-26T23:19:47Z<p>Zepper: CHR RAM bit</p>
<hr />
<div>[[Category:iNES Mappers|093]][[Category:Discrete logic mappers|093]][[Category:in NesCartDB|093]]<br />
This is part of a family of Sunsoft mappers used by Japanese games: ([[iNES Mapper 089]], [[iNES Mapper 093]], [[iNES Mapper 184]])<br />
<br />
This mapper represents the [[Sunsoft 2 pinout|Sunsoft-2 IC]] on the Sunsoft-3R board. It is used by [http://bootgod.dyndns.org:7777/profile.php?id=3142 Shanghai], as well as [http://bootgod.dyndns.org:7777/profile.php?id=3858 Fantasy Zone] whose program is compatible with both this board and a different one that used the [[Sunsoft 1 pinout|Sunsoft-1 IC]].<br />
<br />
[[iNES Mapper 089|Mapper 89]] uses the same Sunsoft-2 IC but on the Sunsoft-3 board and so differs in that it has mapper-controlled one-screen mirroring and CHR ROM banking. Note that the CHR bank lines are still hooked up to the RAM, explaining the RAM enable bit. For homebrew and hacks, games with CHR ROM should use 89's banking behavior with fixed mirroring.<br />
<br />
Despite the mapper existing as a single IC, its functionality [[Sunsoft 2 pinout|is describable]] using just a [[74377]] and a [[7432]] and should probably be considered discrete logic.<br />
<br />
This mapper is deprecated for new development. Homebrew projects other than mapper tests should use [[UxROM]] ([[iNES Mapper 002]]) instead.<br />
<br />
Here is the documentation in [[INES_Mapper_DischDocs|disch's original style]]: <br />
<br />
Registers **BUS CONFLICTS**:<br />
--------------------------<br />
<br />
$8000-FFFF: [.PPP ...E]<br />
P = PRG Reg (16k @ $8000)<br />
E = CHR RAM enable:<br />
0 = dummy reads/writes.<br />
1 = normal operation.<br />
<br />
<br />
PRG Setup:<br />
--------------------------<br />
<br />
$8000 $A000 $C000 $E000 <br />
+---------------+---------------+<br />
| $8000 | { -1} |<br />
+---------------+---------------+</div>Zepperhttps://www.nesdev.org/w/index.php?title=Sunsoft_FME-7&diff=11474Sunsoft FME-72015-03-13T12:29:42Z<p>Zepper: /* PRG Bank 0 ($8) */</p>
<hr />
<div>[[Category:Mappers with large PRG RAM]][[Category:ASIC mappers]][[Category:in NesCartDB]]<br />
The [[Sunsoft FME-7]] is a mapper IC used by Sunsoft in several of its games. It is nearly identical to the '''Sunsoft 5A''' and '''Sunsoft 5B''' mapper chips used only in Famicom games, with the 5B notably having expansion audio (see [[Sunsoft 5B audio]]).<br />
<br />
The FME-7, 5A and 5B are grouped together as [[iNES Mapper 069]].<br />
<br />
Both the Sunsoft 5B and FME-7 exist as a 44 pin TQFP chip: [[Sunsoft 5 pinout|diagram]] <br />
<br />
In Europe, boards using the FME-7 were labeled as [[JxROM|JSROM and JLROM]]. The FME-7 mapper was used in only one game released in the US, ''Batman: Return of the Joker''. Many Japanese releases by Sunsoft used the FME-7: ''Gimmick!'', ''Hebereke'', ''Gremlins 2'' (but not in the US version), ''Barcode World'', and others.<br />
<br />
== Overview ==<br />
* Manufacturer: Sunsoft<br />
* PRG ROM Size: Up to 256 KiB on 5B; Up to 512 KiB on FME-7; at least 256 KiB on 5A but unknown.<br />
* PRG ROM Bank Size: 8 KiB<br />
* PRG RAM: Up to 8 KiB, and [[#PRG_Bank_0_.28.248.29|possibly more]]<br />
* CHR capacity: 256 KiB<br />
* CHR Bank Size: 1 KiB<br />
* Nametable [[mirroring]]: Controlled by Mapper: H, V, 1scA, 1scB<br />
* Subject to [[bus conflict]]s: No<br />
<br />
== Banks ==<br />
* CPU $6000-$7FFF: 8 KB Bankable PRG ROM or PRG RAM<br />
* CPU $8000-$9FFF: 8 KB Bankable PRG ROM<br />
* CPU $A000-$BFFF: 8 KB Bankable PRG ROM<br />
* CPU $C000-$DFFF: 8 KB Bankable PRG ROM<br />
* CPU $E000-$FFFF: 8 KB PRG ROM, fixed to the last bank of ROM<br />
* PPU $0000-$03FF: 1 KB Bankable CHR ROM<br />
* PPU $0400-$07FF: 1 KB Bankable CHR ROM<br />
* PPU $0800-$0BFF: 1 KB Bankable CHR ROM<br />
* PPU $0C00-$0FFF: 1 KB Bankable CHR ROM<br />
* PPU $1000-$13FF: 1 KB Bankable CHR ROM<br />
* PPU $1400-$17FF: 1 KB Bankable CHR ROM<br />
* PPU $1800-$1BFF: 1 KB Bankable CHR ROM<br />
* PPU $1C00-$1FFF: 1 KB Bankable CHR ROM<br />
<br />
== Registers ==<br />
Configuration of the FME-7 is accomplished by first writing the command number to the Command Register at $8000-9FFF, then writing the command's parameter byte to the Parameter Register at $A000-BFFF.<br />
<br />
There are 16 commands:<br />
* '''$0-7''' control CHR banking<br />
* '''$8-B''' control PRG banking<br />
* '''$C''' controls nametable mirroring<br />
* '''$D-F''' controls IRQ<br />
<br />
On the 5B variant, there are two additional registers at $C000-DFFF and $E000-FFFF that control the audio expansion. See: [[Sunsoft 5B audio]]<br />
<br />
=== Command Register ($8000-$9FFF) ===<br />
7 bit 0<br />
---- ----<br />
.... CCCC<br />
||||<br />
++++- The command number to invoke when writing to the Parameter Register<br />
<br />
=== Parameter Register ($A000-$BFFF) ===<br />
7 bit 0<br />
---- ----<br />
PPPP PPPP<br />
|||| ||||<br />
++++-++++- The parameter to use for this command. Writing to this register invokes the command in the Command Register.<br />
<br />
== Commands ==<br />
<br />
=== CHR Bank 0-7 ($0-7) ===<br />
7 bit 0<br />
---- ----<br />
BBBB BBBB<br />
|||| ||||<br />
++++-++++- The bank number to select for the specified bank.<br />
<br />
Bank $0 - PPU $0000-$03FF<br />
Bank $1 - PPU $0400-$07FF<br />
Bank $2 - PPU $0800-$0BFF<br />
Bank $3 - PPU $0C00-$0FFF<br />
Bank $4 - PPU $1000-$13FF<br />
Bank $5 - PPU $1400-$17FF<br />
Bank $6 - PPU $1800-$1BFF<br />
Bank $7 - PPU $1C00-$1FFF<br />
<br />
=== PRG Bank 0 ($8) ===<br />
7 bit 0<br />
---- ----<br />
ERbB BBBB<br />
|||| ||||<br />
||++-++++- The bank number to select at CPU $6000 - $7FFF<br />
|+------- RAM / ROM Select Bit<br />
| 0 = PRG ROM<br />
| 1 = PRG RAM<br />
+-------- RAM Enable Bit ([[6264]] +CE line)<br />
0 = PRG RAM Disabled<br />
1 = PRG RAM Enabled<br />
<br />
The FME-7 has up to 6 bits for PRG banking (512 KiB), though this was never used in a game. The 5A and 5B, however, support only 5 (256 KiB). The extra address line is instead an audio expansion line, or unused.<br />
<br />
It is [http://forums.nesdev.org/viewtopic.php?f=9&t=12467 confirmed] that the FME-7 outputs the bank number during accesses to $6000-$7FFF even if RAM is enabled.<br />
Though Sunsoft never took advantage of this, it would allow making a cartridge that bank switches up to 256 KiB of PRG RAM.<br />
The FME-7 mapper in Loopy's PowerPak mappers, for example, supports 32 KiB.<br />
<br />
Open bus occurs if the RAM / ROM Select Bit is 1 (RAM selected), but the RAM Enable Bit is 0 (disabled), i.e. any value in the range $40-$7F. This is a limited form of WRAM write protection on power-up.<br />
<br />
NOTE: the enable bit is NOT functional with 32768×8 and 524288×8 RAMs, because those RAMs don't have a +CE input.<br />
<br />
There is a [http://forums.nesdev.org/viewtopic.php?p=105129#p105129 tentative report] that [http://forums.nesdev.org/viewtopic.php?p=105193#p105193 not all games honor some or any of the bits in this register]. Corroboration is needed before any action is taken.<br />
<br />
=== PRG Bank 1-3 ($9-B) ===<br />
7 bit 0<br />
---- ----<br />
..bB BBBB<br />
|| ||||<br />
++-++++- The bank number to select for the specified bank.<br />
<br />
Bank $9 - CPU $8000-$9FFF<br />
Bank $A - CPU $A000-$BFFF<br />
Bank $B - CPU $C000-$DFFF<br />
<br />
The FME-7 has up to 6 bits for PRG banking, but the 5A and 5B support only 5.<br />
<br />
=== Name Table Mirroring ($C) ===<br />
These values are the same as [[MMC1]] mirroring modes with the MSB inverted.<br />
7 bit 0<br />
---- ----<br />
.... ..MM<br />
||<br />
++- Mirroring Mode<br />
0 = Vertical<br />
1 = Horizontal<br />
2 = One Screen Mirroring from $2000 ("1ScA")<br />
3 = One Screen Mirroring from $2400 ("1ScB")<br />
<br />
=== IRQ Control ($D) ===<br />
7 bit 0<br />
---- ----<br />
C... ...T<br />
| |<br />
| +- IRQ Enable<br />
| 0 = Do not generate IRQs<br />
| 1 = Do generate IRQs<br />
+-------- IRQ Counter Enable<br />
0 = Disable Counter Decrement<br />
1 = Enable Counter Decrement<br />
<br />
All writes to this register acknowledge an active IRQ.<ref>Test performed in 2015 by Oliveira using [http://forums.nesdev.org/viewtopic.php?p=142243#p142243 IRQ acknowledge test ROM on NESdev BBS]</ref> It is not yet known what will happen if this register is written to at the same time as an IRQ would have been generated.<br />
<br />
=== IRQ Counter Low Byte ($E) ===<br />
7 bit 0<br />
---- ----<br />
LLLL LLLL<br />
|||| ||||<br />
++++-++++- The low eight bits of the IRQ counter<br />
<br />
=== IRQ Counter High Byte ($F) ===<br />
7 bit 0<br />
---- ----<br />
HHHH HHHH<br />
|||| ||||<br />
++++-++++- The high eight bits of the IRQ counter<br />
<br />
Writes to the IRQ counter registers directly set the lower or upper eight bits of the counter. Unlike on MMC3, there is no separate reload latch.<br />
<br />
== IRQ Operation ==<br />
The IRQ feature of FME-7 is a CPU cycle counting IRQ generator. When enabled the 16-bit IRQ counter is decremented once per CPU cycle. When the IRQ counter is decremented from $0000 to $FFFF an IRQ is generated. The IRQ line is held low until it is acknowledged.<br />
<br />
=== How to Use the IRQ Generator ===<br />
# Set the counter to the desired number of cycles minus one.<br />
# Enable the IRQ generator by turning on both the IRQ Enable and IRQ Counter Enable flags of the IRQ Control command.<br />
# Within the IRQ handler, write to the IRQ Control command to acknowledge the IRQ.<br />
# Optional: Go back to Step 1 for the next IRQ.<br />
<br />
== References ==<br />
<references/></div>Zepper