Copy Link
Add to Bookmark
Report

Nintendo Entertainment System Documentation v0.53 (english)

Nintendo's profile picture
Published in 
Famicom
 · 21 Jun 2020


  

+------------------------------------------------------+
| Nintendo Entertainment System Documentation v0.53 |
| by Y0SHi (yoshi@parodius.com) |
| |
| http://nesdev.parodius.com/ |
+------------------------------------------------------+

+--------------------+
| Revision History |
+--------------------+

v0.53: [ #3] Updated (Loopy's palette).
[#10] Mapper #34 updated.
[#10] Unknown mapper added:
American Video Entertainment (MB-91J).
[#11] Minor cosmetic changes.
[#14] Updated (Famicom Disk System information).
[#14] Updated (Konami World 2 *DOES* exist).
[#14] Minor cosmetic changes.
v0.52: [ #6] Updated ($4016/$4017: Zapper).
[ #9] Updated (Sprite Priority Bit).
[#10] MMC1 updated (Register #0; Register #1).
v0.51: [---] CHANGES file added.
[---] Section #17 shifted up one (1).
[---] Some cosmetic changes were made.
[ #0] Updated.
[ #5] Updated (No ABORT pin; RESET issues).
[ #6] Updated ($4016/$4017: Zapper).
[ #9] Updated (Sprite Priority Bit).
[#10] MMC1 updated (Register #0: Bit 4).
[#10] 74HC161/74HC32 Mapper updated (more specific).
[#10] VROM Switch updated (more specific).
[#10] MMC3 updated (Function Select Register).
[#10] ROM Switch updated (more specific).
[#10] Bandai Mapper updated.
[#11] Updated.
[#13] Updated.
[#14] Updated.
[#15] Updated.
[#16] Updated.
v0.50: [ #0] Updated.
[ #2] Updated.
[ #5] Updated.
[#10] FFE F4xxx Mapper updated.
[#10] FFE F6xxx Mapper added.
[#10] ROM Switch updated.
[#10] MMC4 updated.
[#10] Bandai Mapper added.
[#10] FFE F8xx Mapper added.
[#10] Jaleco SS8806 Mapper added.
[#10] Namcot 106 Mapper added.
[#10] Famicom Disk System Mapper added.
[#10] Konami VRC4 Mapper added.
[#10] Konami VRC2 Mapper #1 added.
[#10] Konami VRC2 Mapper #2 added.
[#10] Konami VRC6 Mapper added.
[#10] Irem G-101 Mapper added.
[#10] Taito TC0190/TC0350 Mapper added.
[#10] iNES Mapper #34 added.
[#12] Updated.
[#14] Updated.
[#15] Updated.
[#17] Updated.
v0.41: [#17] Section added ("About the Author").
v0.40: [---] Section #15 ("Relative URLs") removed.
[---] Section #11 shifted down one (1) to allow for the
addition of "Sound".
[ #0] Updated.
[ #1] Updated.
[ #4] Updated.
[ #6] PPUCNT1 is now PPUCNT0.
[ #6] PPUCNT2 is now PPUCNT1.
[ #6] BGSCROL ($2005) updated.
[ #6] SNDCNT ($4015) updated.
[ #8] Updated.
[#10] MMC1 updated.
[#10] Mapper #3 updated.
[#10] MMC3 updated.
[#10] MMC5 updated.
[#10] Mapper #6 updated.
[#10] Mapper #11 updated.
[#11] Section added ("Sound").
[#13] Updated.
[#14] Updated.
[#15] Updated.
v0.34: [---] Private release.
v0.33: [ #0] Section added.
[#10] MMC3 layout changed.
[#10] MMC4 added.
[#10] Mapper #6 updated.
[#12] Data block description updated.
[#15] Section added.
v0.32: [---] Private release.
v0.31: [#10] MMC2 added.
[#10] Mapper #11 added.
[#10] Mapper #6 updated.

v0.30: [---] First public release.


+----------------------+
| 0 | Introduction |
+----------------------+

+-----------------------------+
| READ ME READ ME READ ME |
+-----------------------------+

I'd like to dedicate this document to Alex Krasivsky (Landy on IRC) for
all of his help and moral support throughout the past year regarding the
NES, and issues outside of the console realm. During the good times, and
the bad times, Alex was there. Spasibo, Alex; umnyj russki...

+-----------------------------+
| READ ME READ ME READ ME |
+-----------------------------+

There are bound to be contradictory statements in this document. There
are errors, and many problems regarding terminology (VROM vs. CHR-RAM,
etc.). It is *FAR* from perfect. I have not incorporated all the terminology
I would like to incorporate. Give it time and support: it'll get there.

You will notice severe similarities between Marat Fayzullin's NES Docu-
mentation and mine; I originally based my work on his. Without Marat's
document, I would have never had the desire to create this one.

Do not Email me about 6502 specifics, or such issues as "I can't figure
out how to do {xxx}." I'm not interested in Emails like this; I know that
sounds negative and rude, but I'm really sick and tired of getting Email
about 6502 issues. Read a book. Libraries are *FULL* of 6502 books. There
are tons of web pages about the 6502. I will not teach you 6502, nor any
assembly language (nor do I teach UNIX). It's up to you to learn it.

Do not Email me things like "I am writing an emulator, and I need help.
Please send me documents or code on how to write an emulator." I will not
respond (your Email will be deleted). You're the author: if you're going
to tackle such a task, you should know enough about CPUs and systems to
know just how to go about emulating such. I will answer questions or
comments regarding actual system architecture issues, and errors in my
own documentation.

Finally, please, give credit where credit is due. All of the people in
Section #15 helped contribute to this document. Be sure to thank them,
as without their help, this document wouldn't be much more than a waste
of bandwidth.


+---------------------+
| 1 | Description |
+---------------------+

The NES consists of a custom 6502 CPU, and a PPU (Picture Processing
Unit) used for graphics. Programs can communicate with the NES via
registers (I/O ports, so-to-speak), which allow different things to
happen internally to the NES.

There are multiple areas of memory on the NES, and they should not be
confused. Terms marked with an asterisk ('*') will be the terms used
from here on.

+------------------------------------------------------------------------+
| Term. | Description |

+----------+-------------------------------------------------------------|
|* PRG-ROM | Nintendo of Japan's term for the actual program code area. |
| | |
| | It stands for PRoGram ROM. |
+----------+-------------------------------------------------------------|
|* CHR-RAM | Nintendo of Japan's term for the Pattern Table of the PPU's |
| | internal RAM. |
| | |
| | It stands for CHaRacter RAM. |
+----------+-------------------------------------------------------------|
|* VRAM | The RAM internal to the PPU (Picture Processing Unit). |
| | There is 16K of internal VRAM. |
+----------+-------------------------------------------------------------|
|* WRAM | This is the memory which is most commonly used for games |
| | which support saving (usually RPGs), such as Zelda 1 & 2, |
| | Crystalis, the Final Fantasy series, and other games. |
| | |
| | It stands for Writeable RAM. |
+----------+-------------------------------------------------------------|
|* MMC | The microcontrollers used in carts to address memory past |
| | the standard 6502 64K boundary. They can also be used to |
| | address extra VRAM, and may also be used for "special |
| | effects." |
| | |
| | MMC stands for Multi-Memory Controller. |
+----------+-------------------------------------------------------------|
|* EXRAM | This is the memory which is used in MMC5, to support the |
| | extended colour (Attributes) mode. See Section #10 for more |
| | information on this subject. |
| | |
| | It stands for EXternal RAM. |
+----------+-------------------------------------------------------------|
| VROM | The Pattern Table data kept external to the PPU itself; |
| | standard CHR-RAM data, which is swapped in and out of the |
| | PPU via an MMC. |
| | |
| | VROM stands for Video ROM. |
+----------+-------------------------------------------------------------|
| CHR | Synonymous with CHR-RAM. |
+----------+-------------------------------------------------------------|
| PRG | Synonymous with PRG-ROM. |
+----------+-------------------------------------------------------------|
| SRAM | Synonymous with WRAM. |
+------------------------------------------------------------------------+


+------------------------+
| 2 | CPU Memory Map |
+------------------------+

+-------------------------------------------------------------+
| Address | Size | Description |
+---------+-------+-------------------------------------------|
| $0000 | $800 | RAM |
| $0800 | $800 | RAM (mirrored from $0000) |
| $1000 | $800 | RAM (mirrored from $0000) |
| $1800 | $800 | RAM (mirrored from $0000) |
| $2000 | $3000 | Registers |
| $5000 | $1000 | Expansion Modules |
| $6000 | $1000 | WRAM |
| $7000 | $1000 | WRAM or Trainer (RAM) |
| $8000 | $4000 | PRG-ROM (Lower) |
| $C000 | $4000 | PRG-ROM (Upper) |
+-------------------------------------------------------------+

Note the two seperate PRG-ROM sections; they are congruent, but they
also play seperate roles, depending upon the size of the cartridge itself.
Some games only hold one (1) 16K bank of PRG-ROM, which should be loaded
into $C000 (Upper), not $8000 (Lower). Some games which do this are:
Battle City, Mario Brothers, Millipede, Nuts & Milk, and Tennis. There
are others as well.

Most games load themselves into $8000 (Lower PRG-ROM), using 32K of
PRG-ROM space. The first game (to my knowledge) to use the entire PRG-ROM
space is Super Mario Brothers. However, all games with more than one (1)
16K bank of PRG-ROM load themselves into $8000 as well. These games use
MMCs (see Section #10) to address PRG-ROM past the 32K boundary, and
to access more than 8K of CHR-RAM simultaneously.

+---------------------------------+
| 3 | PPU & Sprite Memory Map |
+---------------------------------+

PPU Memory Map
+-------------------------------------------------------------+
| Address | Size | Description |
+---------+-------+-------------------------------------------|
| $0000 | $1000 | Pattern Table #0 (possibly CHR-RAM) |

| $1000 | $1000 | Pattern Table #1 (possibly CHR-RAM) |
| $2000 | $3C0 | Name Table #0 |
| $23C0 | $40 | Attribute Table #0 |
| $2400 | $3C0 | Name Table #1 |
| $27C0 | $40 | Attribute Table #1 |
| $2800 | $3C0 | Name Table #2 (based on mirroring) |
| $2BC0 | $40 | Attribute Table #2 (based on mirroring) |
| $2C00 | $3C0 | Name Table #3 (based on mirroring) |
| $2FC0 | $40 | Attribute Table #3 (based on mirroring) |
| $3000 | $F00 | [---EMPTY---] |
| $3F00 | $10 | Image Palette |
| $3F10 | $10 | Sprite Palette |
| $3F20 | $E0 | [---EMPTY---] |
+-------------------------------------------------------------+

Sprite RAM
+-------------------------------------------------------------+
| Address | Size | Description |
+---------+-------+-------------------------------------------|
| $0000 | $100 | Sprite RAM |
+-------------------------------------------------------------+

For more information about Sprite RAM, see Sections #6 and #9.

VRAM is quite unorganized, as shown above. To my knowledge, VRAM is
addressed via 14-bit address, and therefore should wrap back around to
$0000 if the memory boundary passes the end of memory ($3FFF).

There is only enough VRAM memory to support two (2) Name Tables and
two (2) Attribute Tables. Therefore, Name/Attribute Tables #2 and #3
are mirrors of Name/Attribute Tables #0 and #1. Which Tables are mirrored
depends upon the mirroring bit set inside of the cartridge header (see
Section #12 for more information).

In a real NES, reading/writing VRAM should only be attempted during
VBlank. Many smaller ROMs have CHR-RAM for the Pattern Tables. In this
case, you won't be able to write into this memory.

Writing to VRAM
---------------
1) Write upper address byte into $2006
2) Write lower address byte into $2006
3) Write data into $2007. After each write, the address will auto-
increment by 1, or 32 (if Bit #2 of $2000 is 1).

Reading from VRAM
-----------------
1) Write upper address byte into $2006
2) Write lower address byte into $2006
3) Read data from $2007. The first read from $2007 is invalid, and
therefore should be taken care of before actual data is read.
4) Read data from $2007. From here on, after each read, the address will
auto-increment by 1, or 32 (if Bit #2 of $2000 is 1).

The Name Table holds "tile index values." Tiles themselves are 8x8
pixels. The entire Name Table itself is 32x30 tiles (256x240 pixels).
However, due to NTSC and PAL frequencies, the actual displayed resolution
is different.

For NTSC, the upper and lower 16 pixels are not displayed, therefore the

resolution is 256x224. The Name Table itself keeps a static size of 32x30
tiles (256x240 pixels).

For more information about NES PAL/NTSC issues, feel free to check out
Mark Knibbs' NES PAL/NTSC document at:

http://nesdev.parodius.com/nesfreq.txt

Continuing on...

These values (re: "tile index values") are usually put into the Name
Table via writes to the $2006 register (see Section #6). These values are
used to reference the information stored in the Pattern Table. For you
emulator authors out there, the formulae is quite simple:

(VALUE * 16) + ScreenPatternTableAddress

Where VALUE is the value which is written to register $2006, and
ScreenPatternTableAddress is the Screen Pattern Table Address defined in
Bit #2 in register $2000 (see Section #6).

The NES can only display 16 colours on the screen simultaneously.

The Pattern Table contains tiles in the following format:

Contents of Colour
Pattern Table Result
--------------- --------
%00010000 = $10 --+ ...1.... Periods are used to rep-
%00000000 = $00 | ..2.2... resent colour 0. Numbers
%01000100 = $44 | .3...3.. shown represent colour #.
%00000000 = $00 +-- Bit 0 2.....2.
%11111110 = $FE | 1111111.
%00000000 = $00 | 2.....2.
%10000010 = $82 | 3.....3.
%00000000 = $00 --+ ........

%00000000 = $00 --+
%00101000 = $28 |
%01000100 = $44 |
%10000010 = $82 +-- Bit 1
%00000000 = $00 |
%10000010 = $82 |
%10000010 = $82 |
%00000000 = $00 --+

The result of the above Pattern Table is the character 'A', as shown
in the "Colour Result" section in the upper right.

Only two (2) bits for each pixel of a tile are stored in the Pattern
Table. The other two (2) bits are taken from the Attribute Table. Four (4)
bits make up the entire possible colours on the NES, which therefore shows
that the NES can display 16 colours on the screen simultaneously.

Each byte in an Attribute Table represents a 4x4 group of tiles on the
screen. There's multiple ways to describe what the function of one (1)
byte in the Attribute Table does:

* Holds the upper two (2) bits of a 32x32 pixel grid, per 16x16 pixels.
* Holds the upper two (2) bits of sixteen (16) 8x8 tiles.
* Holds the upper two (2) bits of four (4) 4x4 tile grids.

It's confusing as hell, to be honest. A few graphical diagrams may help
those who are confused:

+-------------------------+
| Square 0 | Square 1 | #0-F represents an 8x8 tile
| #0 #1 | #4 #5 |
| #2 #3 | #6 #7 | Square [x] represents four (4) 8x8 tiles
+------------+------------| (i.e. a 16x16 pixel grid)
| Square 2 | Square 3 |
| #8 #9 | #C #D |
| #A #B | #E #F |
+-------------------------+

Attribute Byte
----------------
%00000000
+|+|+|+-- Upper two (2) colour bits for Square 0 (Tiles #0/1/2/3)
| | +--- Upper two (2) colour bits for Square 1 (Tiles #4/5/6/7)
| +----- Upper two (2) colour bits for Square 2 (Tiles #8/9/A/B)
+------- Upper two (2) colour bits for Square 3 (Tiles #C/D/E/F)

Putting all of this information together is a cinch, assuming you can
overlay bit patterns in your head. A similar method is used in the tweaked
graphics modes known as "MODE-X" modes on the PC. Most DOS-oriented emu-
lators use what's known as "MODE-Q", since it's resolution is 256x256x256.
For more information, research "chained graphics modes."

Two (2) palettes exist; the Image Palette and the Sprite Palette. These
palettes are more of a "lookup table" than an actual palette, since they
do not hold physical RGB values.

The NES itself uses an NTSC composite video signal, but can be "emulated"
by corrisponding RGB values with the colours on a standard TV set. The
actual 256 RGB palette (though 64 are used) can be obtained from the
following URL:

http://nesdev.parodius.com/loopypal.txt

Mirroring also occurs between the Image Palette and the Sprite Palette.
Any data which is written to $3F00 is mirrored to $3F04, $3F08, and $3F0C.
Any data which is written to $3F10 is mirrored to $3F14, $3F18, and $3F1C.
Colour #0 in both Palettes defines transparency.

+------------------------------+
| 4 | Background Scrolling |
+------------------------------+

It seems there's quite a few questions regarding just how to go about
using Register $2005 (see Section #6) to pan the background. I myself am
still having problems understanding just exactly how this register works.
But, thanks to Pat Mccomack, there is a small explanation which I'll
post here so that those who're having problems can hopefully make use of
this information:

Horizontal Scrolling Vertical Scrolling
0 512
+-----------+ +-----+0
| | | | |
| A | B | | A |
| | | | |
+-----------+ +-----|
| |
| B |
| |
+-----+480

Name Table "A" is specified via Bits #0-1 in $2000 (see Section #6),
and "B" is the next to "A", since it's based on mirroring. This doesn't
work for game which use Horizontal & Vertical scrolling at the same time.
Possibly the four-screen VRAM layout fixes this.

"This stuff is used in smb1 (horizontal scrolling) but it's probably the
same way with other games. Scrolling seems to be scanline based, ie during
refresh the game can write different values to the scroll register (usually
they do this when they detect the sprite 0 hit via reg $2002). The scroll-
ing screen layout also can change. With horizontal scrolling, the name
table at the first screen (0-255) is the one specified in reg $2000, and
the name table for the second screen (256-512) is the opposite of the first
one, based on mirroring I guess."

Thanks for providing this information, Pat. :-)

+--------------------+
| 5 | Interrupts |
+--------------------+

The 6502 has three interrupts: IRQ/BRK, NMI, and RESET.

Each interrupt has it's own vector, usually pointing to some code
to be executed. A vector is a 16-bit address which specifies a location
to "jump to" when the interrupt is triggered.

IRQ/BRK is triggered when the 6502 executes the BRK instruction. BRK
can be used for many things, but is *RARELY* used, since it generally
puts the machine into a state of unhappiness. However, for you emulator
authors out there, be sure to emulate BRK correctly, as some games do
use BRK to force the jump at the IRQ/BRK vector. Super Nintendo (SNES)
games do this as well, but that's a different issue alltogether.

NMI stands for Non-Maskable Interrupt, and is generated by each
refresh (VBlank/VBL), which occurs at different intervals depending upon
the system used.

RESET is triggered on power-up. The ROM is loaded into memory, and
the 6502 jumps to the address specified in the RESET vector. No registers
are modified, and no memory is cleared; these only occur during power-up.

Back to the issue of NMI. NMI is only executed 50 times/sec. when
Bit #7 in $2000 (see Section #6) is set to 1. This tells the NES to
generate interrupts (or more specifically, execute NMI) everytime a
refresh occurs. Interrupt latency on the 6502 is seven (7) cycles; this
means it takes seven (7) cycles to move in and out of an interrupt.

Most interrupts should return using the RTI instruction. Some NES carts
do not use this method, such as Final Fantasy 1. These carts return from
interrupts in a very odd fashion: by manipulating the stack by hand, and
then doing an RTS. This is technically valid, but morally is "bad." If
you're an emulator author, just be sure you implement all your opcodes
right and you should be fine. The game code will take care of the rest.

The following interrupts have the following vector-points in ROM:

+--------------------+
| Vector | Interrupt |
+--------+-----------|
| $FFFA | NMI |
| $FFFC | RESET |
| $FFFE | IRQ/BRK |
+--------------------+

Here are the correct interrupt priority orders for the 6502:

+----------------------+
| Priority | Interrupt |
+----------+-----------|
| Highest | RESET |
| | NMI |
| Lowest | IRQ/BRK |
+----------------------+


+-------------------+
| 6 | Registers |
+-------------------+

Address: The 16-bit address of the register (in ROM)

Stats: Each register has different statistics and "aspects" to it.
These stats are defined as follows:
R = Register is readable.
W = Register is writeable.
2 = A "double-write" register.

? = Statistics are unknown, or are possibly wrong.
Bits: Most registers have bits you can toggle on/off which do
different things to the NES itself.
Bits labelled with '-' (hyphen) are not used.
Bits labelled with '?' are unknown.
[Label]: Labels I have assigned to each register (for programmers).

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description [Label] |
+---------+-------+----------+---------------------------------------------|
| $2000 | W | vhzcpwNN | PPU Control Register #1 [PPUCNT0] |
| | | | |

| | | | v = Execute NMI on VBlank |
| | | | 0 = Disabled |
| | | | 1 = Enabled |
| | | | h = Execute NMI on Sprite Hit |
| | | | 0 = Disabled |
| | | | 1 = Enabled |
| | | | z = Sprite Size |
| | | | 0 = 8x8 |
| | | | 1 = 8x16 |
| | | | c = Screen Pattern Table Address |
| | | | 0 = $0000 (VRAM) |
| | | | 1 = $1000 (VRAM) |
| | | | p = Sprite Pattern Table Address |
| | | | 0 = $0000 (VRAM) |
| | | | 1 = $1000 (VRAM) |
| | | | w = PPU Address Read/Write Increment |
| | | | 0 = Increment by 1 |
| | | | 1 = Increment by 32 |
| | | | N = Name Table Select |
| | | | 00 = $2000 (VRAM) |
| | | | 01 = $2400 (VRAM) |
| | | | 10 = $2800 (VRAM) |
| | | | 11 = $2C00 (VRAM) |
+---------+-------+----------+---------------------------------------------|
| $2001 | W | fffpcSIt | PPU Control Register #2 [PPUCNT1] |
| | | | |
| | | | f = Full Background Colour |
| | | | 000 = None \ |
| | | | 001 = Red \ Select one only |
| | | | 010 = Green / |
| | | | 100 = Blue / |
| | | | p = Sprite Display |
| | | | 0 = Hide sprites |
| | | | 1 = Show sprites |
| | | | c = Screen Display |
| | | | 0 = Off (screen off) |
| | | | 1 = On (screen on) |
| | | | S = Sprite Clip |
| | | | 0 = Don't show sprites in the left |
| | | | 8-pixel column |
| | | | 1 = Show sprites everywhere |
| | | | I = Image Clip |
| | | | 0 = Don't show the left 8 pixels of |
| | | | the screen |
| | | | 1 = Show the left 8 pixels |
| | | | t = Colour Display |
| | | | 0 = Mono-tone display |
| | | | 1 = Colour display |
+---------+-------+----------+---------------------------------------------|
| $2002 | R | vhsW---- | PPU Status Register [PPUSTAT] |
| | | | |
| | | | v = VBlank Occurance Flag |
| | | | 0 = No VBlank |
| | | | 1 = VBlank |
| | | | h = Hit Occurance Flag |
| | | | 0 = No hit |
| | | | 1 = Refresh has hit Sprite #0 |
| | | | s = Sprite Count Max |
| | | | 0 = Less than 8 sprites on the |
| | | | current scanline |
| | | | 1 = More than 8 sprites on the |
| | | | current scanline |
| | | | W = PPU Write Status Flag |
| | | | 0 = Writes to VRAM are respected |
| | | | 1 = Writes to VRAM are ignored |
| | | | |
| | | | NOTE: Bit #6 is reset to 0 at the beginning |
| | | | of the next refresh. |
| | | | NOTE: Bit #6 is not set until the first |
| | | | actual pixel (i.e. non-transparent) |
| | | | is drawn. Therefore, if you have a |
| | | | sprite (8x8) which has it's first 4 |
| | | | pixels as transparent, and it's 5th |
| | | | as a non-transparent value, Bit 6 |
| | | | will be set after the 5th pixel is |
| | | | found & drawn. |
+---------+-------+----------+---------------------------------------------|
| $2003 | W | aaaaaaaa | Sprite Memory Address [SPRADDR] |
| | | | |
| | | | Specifies the address in Sprite RAM to |
| | | | access via $2004 (see Section #9). |
+---------+-------+----------+---------------------------------------------|
| $2004 | W | dddddddd | Sprite I/O Register [SPRIO] |
| | | | |
| | | | Used to read/write to the address spec- |
| | | | ified via $2003 in Sprite RAM. |
+---------+-------+----------+---------------------------------------------|
| $2005 | W2 | dddddddd | Background Scroll Register [BGSCROL] |
| | | | |
| | | | Used to scroll the screen vertically and |
| | | | horizontally. This is a double-write |
| | | | register. |
| | | | |
| | | | BYTE 1: Horizontal Scroll |
| | | | BYTE 2: Vertical Scroll |
| | | | |
| | | | The scrolled data will span across multip- |
| | | | le Name Tables. The layout is as follows: |
| | | | |
| | | | +-------------------------+ |
| | | | | #2 ($2800) | #3 ($2C00) | |
| | | | +------------+------------| |
| | | | | #0 ($2000) | #1 ($2400) | |
| | | | +-------------------------+ |
| | | | |
| | | | NOTE: If the Vertical Scroll value is >239, |
| | | | it will be ignored. Some emulators |
| | | | write 0 to the Vertical Scroll if |
| | | | the value is >239. |
| | | | NOTE: Remember, there is only enough VRAM |
| | | | for two (2) Name Tables. |
| | | | NOTE: After a VBL occurs, the next write |
| | | | will control the Horizontal Scroll. |
+---------+-------+----------+---------------------------------------------|
| $2006 | W2 | aaaaaaaa | PPU Memory Address [PPUADDR] |
| | | | |
| | | | Specifies the address in VRAM in which |
| | | | data should be read from or written to. |
| | | | This is a double-write register. The high- |
| | | | byte of the 16-bit address is written |
| | | | first, then the low-byte. |
+---------+-------+----------+---------------------------------------------|
| $2007 | RW | dddddddd | PPU I/O Register [PPUIO] |
| | | | |
| | | | Used to read/write to the address spec- |
| | | | ified via $2006 in VRAM. |
+---------+-------+----------+---------------------------------------------|
| $4000 | RW | CChessss | Square Wave Control Register #1 |
| | | | |
| | | | C = Duty Cycle (Positive vs. Negative) |
| | | | 00 = 87.5% |
| | | | 01 = 75.0% |
| | | | 10 = 58.0% |
| | | | 11 = 25.0% |
| | | | h = Hold Note |
| | | | 0 = Don't hold note |
| | | | 1 = Hold note |
| | | | e = Envelope Select |
| | | | 0 = Envelope Vary |
| | | | 1 = Envelope Fixed |
| | | | s = Playback Rate |
+---------+-------+----------+---------------------------------------------|
| $4001 | RW | fsssHrrr | Square Wave Control Register #2 |
| | | | |
| | | | f = Frequency Fixed/Variable Select |
| | | | 0 = Fixed (bits 0-6 disabled) |
| | | | 1 = Variable (bits 0-6 enabled) |
| | | | s = Frequency Change Speed |
| | | | H = Low/High Frequency Select |
| | | | 0 = Low -> High |
| | | | 1 = High -> Low |
| | | | r = Frequency Range (0=Min, 7=Max) |
+---------+-------+----------+---------------------------------------------|
| $4002 | RW | dddddddd | Square Wave Frequency Value Register #1 |
| | | | |
| | | | d = Frequency Value Data (lower 8-bits) |
+---------+-------+----------+---------------------------------------------|
| $4003 | RW | tttttddd | Square Wave Frequency Value Register #2 |
| | | | |
| | | | d = Frequency Value Data (upper 3-bits) |
| | | | t = Active Time Length |
| | | | |
| | | | NOTE: The Frequency Value is a full 11-bits |
| | | | in size; be aware you will need to |
| | | | write the upper 3-bits to $4003. |
+---------+-------+----------+---------------------------------------------|
| $4004 | RW | CChessss | Square Wave Control Register #1 |
| | | | |
| | | | C = Duty Cycle (Positive vs. Negative) |
| | | | 00 = 87.5% |
| | | | 01 = 75.0% |
| | | | 10 = 58.0% |
| | | | 11 = 25.0% |
| | | | h = Hold Note |
| | | | 0 = Don't hold note |

| | | | 1 = Hold note |
| | | | e = Envelope Select |
| | | | 0 = Envelope Vary |
| | | | 1 = Envelope Fixed |
| | | | s = Playback Rate |
+---------+-------+----------+---------------------------------------------|
| $4005 | RW | fsssHrrr | Square Wave Control Register #2 |
| | | | |
| | | | f = Frequency Fixed/Variable Select |
| | | | 0 = Fixed (bits 0-6 disabled) |
| | | | 1 = Variable (bits 0-6 enabled) |
| | | | s = Frequency Change Speed |
| | | | H = Low/High Frequency Select |
| | | | 0 = Low -> High |
| | | | 1 = High -> Low |
| | | | r = Frequency Range (0=Min, 7=Max) |
+---------+-------+----------+---------------------------------------------|
| $4006 | RW | dddddddd | Square Wave Frequency Value Register #1 |
| | | | |
| | | | d = Frequency Value Data (lower 8-bits) |
+---------+-------+----------+---------------------------------------------|
| $4007 | RW | tttttddd | Square Wave Frequency Value Register #2 |
| | | | |
| | | | d = Frequency Value Data (upper 3-bits) |
| | | | t = Active Time Length |
| | | | |
| | | | NOTE: The Frequency Value is a full 11-bits |
| | | | in size; be aware you will need to |
| | | | write the upper 3-bits to $4007. |
+---------+-------+----------+---------------------------------------------|
| $4008 | RW | CChessss | Triangle Wave Control Register #1 |
| | | | |
| | | | C = Duty Cycle (Positive vs. Negative) |
| | | | 00 = 87.5% |
| | | | 01 = 75.0% |
| | | | 10 = 58.0% |
| | | | 11 = 25.0% |
| | | | h = Hold Note |
| | | | 0 = Don't hold note |
| | | | 1 = Hold note |
| | | | e = Envelope Select |
| | | | 0 = Envelope Vary |
| | | | 1 = Envelope Fixed |
| | | | s = Playback Rate |
+---------+-------+----------+---------------------------------------------|
| $4009 | RW | fsssHrrr | Triangle Wave Control Register #2 |
| | | | |
| | | | f = Frequency Fixed/Variable Select |
| | | | 0 = Fixed (bits 0-6 disabled) |
| | | | 1 = Variable (bits 0-6 enabled) |
| | | | s = Frequency Change Speed |
| | | | H = Low/High Frequency Select |
| | | | 0 = Low -> High |
| | | | 1 = High -> Low |
| | | | r = Frequency Range (0=Min, 7=Max) |
+---------+-------+----------+---------------------------------------------|
| $400A | RW | dddddddd | Triangle Wave Frequency Value Register #1 |
| | | | |
| | | | d = Frequency Value Data (lower 8-bits) |
+---------+-------+----------+---------------------------------------------|
| $400B | RW | tttttddd | Triangle Wave Frequency Value Register #2 |
| | | | |
| | | | d = Frequency Value Data (upper 3-bits) |
| | | | t = Active Time Length |
| | | | |
| | | | NOTE: The Frequency Value is a full 11-bits |
| | | | in size; be aware you will need to |
| | | | write the upper 3-bits to $400B. |
+---------+-------+----------+---------------------------------------------|
| $400C | RW | CChessss | Noise Control Register #1 |
| | | | |
| | | | C = Duty Cycle (Positive vs. Negative) |
| | | | 00 = 87.5% |
| | | | 01 = 75.0% |
| | | | 10 = 58.0% |
| | | | 11 = 25.0% |
| | | | h = Hold Note |
| | | | 0 = Don't hold note |
| | | | 1 = Hold note |
| | | | e = Envelope Select |
| | | | 0 = Envelope Vary |

| | | | 1 = Envelope Fixed |
| | | | s = Playback Rate |
+---------+-------+----------+---------------------------------------------|
| $400D | RW | fsssHrrr | Noise Control Register #2 |
| | | | |
| | | | f = Frequency Fixed/Variable Select |
| | | | 0 = Fixed (bits 0-6 disabled) |
| | | | 1 = Variable (bits 0-6 enabled) |
| | | | s = Frequency Change Speed |
| | | | H = Low/High Frequency Select |
| | | | 0 = Low -> High |
| | | | 1 = High -> Low |
| | | | r = Frequency Range (0=Min, 7=Max) |
+---------+-------+----------+---------------------------------------------|
| $400E | RW | dddddddd | Frequency Value Register #1 |
| | | | |
| | | | d = Frequency Value Data (lower 8-bits) |
+---------+-------+----------+---------------------------------------------|
| $400F | RW | tttttddd | Frequency Value Register #2 |
| | | | |
| | | | d = Frequency Value Data (upper 3-bits) |
| | | | t = Active Time Length |
| | | | |
| | | | NOTE: The Frequency Value is a full 11-bits |
| | | | in size; be aware you will need to |
| | | | write the upper 3-bits to $400F. |
+---------+-------+----------+---------------------------------------------|
| $4010 | RW | CChessss | PCM Control Register #1 |
| | | | |
| | | | C = Duty Cycle (Positive vs. Negative) |
| | | | 00 = 87.5% |
| | | | 01 = 75.0% |
| | | | 10 = 58.0% |
| | | | 11 = 25.0% |
| | | | h = Hold Note |
| | | | 0 = Don't hold note |
| | | | 1 = Hold note |
| | | | e = Envelope Select |
| | | | 0 = Envelope Vary |
| | | | 1 = Envelope Fixed |
| | | | s = Playback Rate |
+---------+-------+----------+---------------------------------------------|
| $4011 | RW | vvvvvvvv | PCM Volume Control Register |
| | | | |
| | | | v = Volume |
+---------+-------+----------+---------------------------------------------|
| $4012 | RW | aaaaaaaa | PCM Address Register |
| | | | |
| | | | a = Address |
+---------+-------+----------+---------------------------------------------|
| $4013 | RW | LLLLLLLL | PCM Data Length Register |
| | | | |
| | | | L = Data Size/Length |
+---------+-------+----------+---------------------------------------------|
| $4014 | W | | Sprite DMA [SPRDMA] |
| | | | |
| | | | Transfers 256 bytes of memory at address |
| | | | $100*N, where N is the value written to |
| | | | this register, into Sprite RAM. |
+---------+-------+----------+---------------------------------------------|
| $4015 | RW | ---abcde | Sound Control Register [SNDCNT] |
| | | | |
| | | | e = Channel 1 (0=Disable, 1=Enable) |
| | | | d = Channel 2 (0=Disable, 1=Enable) |
| | | | c = Channel 3 (0=Disable, 1=Enable) |
| | | | b = Channel 4 (0=Disable, 1=Enable) |
| | | | a = Channel 5 (0=Disable, 1=Enable) |
+---------+-------+----------+---------------------------------------------|
| $4016 | RW | ???STeed | Joypad #1 [SPECIO1] |
| | | | [READING] |
| | | | |
| | | | S = Zapper sprite detection |
| | | | 0 = Sprite not detected |
| | | | 1 = Sprite detected in front of |
| | | | crosshair |
| | | | T = Zapper trigger |
| | | | 0 = Pressed |
| | | | 1 = Not pressed |
| | | | e = Expansion Port Data |
| | | | d = Joypad Data (see Section #8) |
| | | +---------------------------------------------|
| | | ?????eej | [WRITING] |
| | | | |
| | | | j = Joypad Strobe |
| | | | 0 = Clear joypad strobe |
| | | | 1 = Reset joypad strobe |
| | | | e = Expansion Port Data |
+---------+-------+----------+---------------------------------------------|
| $4017 | R | ???STeed | Joypad #2 [SPECIO2] |
| | | | |
| | | | S = Zapper sprite detection |
| | | | 0 = Sprite not detected |
| | | | 1 = Sprite detected in front of |
| | | | crosshair |
| | | | T = Zapper trigger |
| | | | 0 = Pressed |
| | | | 1 = Not pressed |
| | | | e = Expansion Port Data |
| | | | d = Joypad Data (see Section #8) |
+--------------------------------------------------------------------------+

+----------------------+

| 7 | VBL/Hit Bits |
+----------------------+

The VBlank flag is contained in the 7th bit of read-only location $2002.
It indicates whether PPU is scanning the screen, or generating a vertical
blanking impulse. It is set in the end of each frame (scanline 232), and
stays on until the next screen refresh starts from scanline 8. The pro-
gram can reset this bit prematurely by reading $2002.

The Hit Flag is contained in the 6th bit of read-only location $2002.
It goes to 1 when PPU starts refreshing the first scanline where sprite#0
is located. For example, if sprite#0's Y coordinate is 34, the Hit flag
will be set in scanline 34. The Hit flag is reset when vertical blanking
impulse starts. The program can reset this bit prematurely by reading from
$2002.

+-----------------------+
| 8 | Joypad/Zapper |
+-----------------------+

There are two joysticks which are accessed via locations $4016 and
$4017. To reset joysticks, write first 1, then 0 into $4016. This way, you
will generate a strobe in the joysticks' circuitry. Then, read either from
$4016 (for joystick 0) or from $4017 (for joystick 1). Each read will
give you the status of a single button in the 0th bit (1 if pressed, 0
otherwise):

+----------------------------------------------------------------+
| Read # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
+--------+-----+-----+--------+-------+----+------+------+-------|
| A | B | SELECT | START | UP | DOWN | LEFT | RIGHT |
+-------------------------------------------------------+

See Section #6 for details regarding each bit in $4016/$4017.

+-----------------+
| 9 | Sprites |
+-----------------+


There are 64 sprites, which can be either 8x8 or 8x16 pixels. Sprites
patterns are stored in on of the Pattern Tables in the PPU Memory. Sprite
attributes are stored in the Sprite RAM of 256 bytes, which is not a
part of neither CPU nor PPU address space. The entire contents of Sprite
Memory can be written via DMA (see Section #6). Sprite RAM can also be
accessed byte-by-byte by putting the starting address into $2003 and then
writing/reading $2004 (the address will auto-increment). The format of
Sprite RAM is as follows:

+-------------------------------------------------------+
| Sprite #0 | Sprite #1 | ... | Sprite #62 | Sprite #63 |
+-------------------------------------------------------+
| +-------------------------------------------------------------+
+----| Byte # | Bits | Description |
+--------+----------+-----------------------------------------|
| 0 | YYYYYYYY | Sprite Y coordinate - 1. Consider the |
| | | coordinate the upper-left corner of |
| | | the sprite itself. |
| 1 | IIIIIIII | Sprite Tile Index # |
| 2 | vhp000cc | Colour/Attributes |
| | | v = Vertical Flip (1=Flip) |
| | | h = Horizontal Flip (1=Flip) |
| | | p = Sprite Priority Bit |
| | | 0 = Sprite on top of background |
| | | 1 = Sprite behind background |
| | | c = Upper two (2) bits of colour |
| 3 | XXXXXXXX | Sprite X coordinate (upper-left corner) |
+-------------------------------------------------------------+

The Sprite Tile Index # is obtained the same way as Tile Index #s are
in regards to the Name Table (background) picture.

For 8x16 sprites, the Pattern Table is at $0000 in VRAM, containing 256
8x16 tiles. Bit #3 of $2000 (see Section #6) has no effect on 8x16 sprites.
The Sprite Tile Index # in the Sprite Attribute RAM is rotated right
one (1) bit by the PPU, when drawing. Therefore, a Tile Index # $01 will
draw tile #128, $02 would draw tile #1, $03 would draw tile #129, etc..

The Sprite Priority bit works as follows: If a sprite has this bit set,
and has a higher priority than a sprite at the same location, then the
background will be in front of both sprites).

Only eight (8) sprites can be displayed per scan-line. Each Sprite entry
in Sprite RAM is checked to see if it's in a horizontal range with the
other sprites. Remember, this is done on a per scan-line basis, not on a
per sprite basis (e.g. this is done 256 times, not 256/8 or 256/16 times).

+---------------+
| 10 | MMCs |
+---------------+

Each reference number below (e.g. "3)" or "1)") is the iNES Mapper
number. The actual MMC title is printed after, if one is available. Do not
get these confused.


1) Nintendo MMC1

MMC1 is commonly used in 256K and 512K carts. It may be used to switch
PRG-ROM and CHR-RAM. This MMC also supports WRAM.

MMC1 has four (4) 8-bit registers, which are accessed via following
addresses:

+-----------------------------------------------------------------------+
| Reg # | Range | Bits | Description |
+-------+-------+----------+--------------------------------------------|
| 0 | $8000 | ????BKpm | MMC Control Register #1 |
| | ... | | |
| | $9FFF | | B = Base Bootup Select |
| | | | 0 = $8000 (NOTE: This is probably |
| | | | 1 = $C000 incorrect!) |
| | | | K = Bank Size |
| | | | 0 = 16K |
| | | | 1 = 32K |
| | | | p = Panning/Scrolling Enable/Disable |
| | | | 0 = Enabled |
| | | | 1 = Disabled |
| | | | m = Mirror Select |
| | | | 0 = Horizontal Mirroring |
| | | | 1 = Vertical Mirroring |
| | | | |
| | | | NOTE: Bit #1, when set to 1, actually just |
| | | | mirrors Name Table #0 throughout all |
| | | | the other Name Tables. |
+-------+-------+----------+--------------------------------------------|
| 1 | $A000 | ???mCCCC | MMC Control Register #2 |
| | ... | | |
| | $BFFF | | m = Multi Function |
| | | | [Cart w/ VROM] |
| | | | Size Select |
| | | | 0 = Select 8K CHR-RAM at $0000 |
| | | | 1 = Swap 4K at $0000 and $1000 |
| | | | [Cart w/out VROM] |
| | | | PRG-ROM 256K Select |
| | | | 0 = Select lower 256K of PRG-ROM |
| | | | 1 = Select upper 256K of PRG-ROM |
| | | | C = CHR-RAM Page Select at $0000 (VRAM) |
+-------+-------+----------+--------------------------------------------|
| 2 | $C000 | ssssssss | CHR-RAM 4K Page Selection Register |
| | ... | | |
| | $DFFF | | Sets the 4K CHR-RAM page at $1000, but |
| | | | only if 4K CHR-RAM pages are selected via |
| | | | Register #0 (otherwise ignored). |
+-------+-------+----------+--------------------------------------------|
| 3 | $E000 | ssssssss | PRG-ROM 16K Page Selection Register |
| | ... | | |
| | $FFFF | | Sets the 16K ROM page at $8000. The page |
| | | | at $C000 is hardwired to the last ROM |
| | | | page in the cart. Page 0 starts at $8000. |
+-----------------------------------------------------------------------+

Before writing to a mapper register for the first time, you need to reset
it by setting bit #7 in each address range base ($8000, $A000, $C000, and
$E000) before writing data to each address range itself. Once you've
done this, you may write the value bit by bit to the appropriate address
range. For example, the following code will write $0C into register 3:

lda #%10000000
sta $8000 ; Resetting range #0
sta $A000 ; Resetting range #1
sta $C000 ; Resetting range #2
sta $E000 ; Resetting range #3
lda #$0C ; This is our value
sta $EFD9 ; Writing bit 0
lsr a ; Shifting
sta $EFD9 ; Writing bit 1
lsr a ; Shifting
sta $EFD9 ; Writing bit 2
lsr a ; Shifting
sta $EFD9 ; Writing bit 3
lsr a ; Shifting
sta $EFD9 ; Writing bit 4

For "512K" carts (such as Dragon Warrior 3), pay attention to Bit #4 of
Register #0. As these carts don't have anything but PRG-ROM, Bit #4 func-
tions as a 256K selection register.

Finally, for "512K" carts, $C000-$FFFF is hardwired to the last 16K of
the lower 256K PRG-ROM area.


2) 74HC161/74HC32 Mapper

This mapper only switches PRG-ROM banks, 16K in size. All carts with this
mapper contain 8K of CHR-RAM at $0000.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W | PPPPPPPP | PRG-ROM Control Register |
| ... | | | |
| $FFFF | | | P = 16K PRG-ROM Bank |
+--------------------------------------------------------------------------+

NOTE: The last 16K PRG-ROM page is hardwired to $C000.
NOTE: The cart starts with PRG-ROM Bank #0 at $8000.


3) VROM Switch


This mapper only switches CHR-RAM banks, 8K in size. PRG-ROM is 16K
or 32K, and cannot be switched.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W | CCCCCCCC | CHR-RAM Control Register |
| ... | | | |
| $FFFF | | | C = 8K CHR-RAM Bank at $0000 (VRAM) |
+--------------------------------------------------------------------------+

  
4) Nintendo MMC3


This MMC is used in many recent cartridges, such as: Batman Returns,
Super Contra, Vindicators, Silver Surfer, Crystalis, Legacy of the Wizard,
and others. This MMC is able to generate it's own interrupts via the IRQ
line, and has a set of commands to switch PRG-ROM and CHR-RAM. CHR-RAM
pages are 1K, PRG-ROM are 8K.

NOTE: The last two (2) 8K pages of PRG-ROM are hardwired to $C000 and
$E000, when Bit #6 of the Functional Select Register (see below) is 0.
When it is set to 1, the hardwiring affects $8000 and $E000.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W ? | as???ddd | Function Select Register |
| | | | |
| | | | a = CHR-RAM Base Address Select |
| | | | 0 = $0000 |

| | | | 1 = $1000 |
| | | | s = PRG-ROM Page Base Select |
| | | | 0 = Select $8000 and $A000 |
| | | | 1 = Select $A000 and $C000 |
| | | | ddd = CMD # (0-7) |
| | | | |
| | | | NOTE: Bit #6 only affects CMDs 6 & 7. |
| | | | NOTE: Writing to this register resets |
| | | | changes made to the $E000 register. |
+---------+-------+----------+---------------------------------------------|
| $8001 | W | dddddddd | Page Number Select Register |
| | | | |
| | | | This register selects the page # to be |
| | | | read from (or written to). |
| | | | |
| | | | NOTE: When using CMD 0, Bit #0 of this reg- |
| | | | ister is ignored. Therefore, a value |
| | | | of 5 will select pages 4 & 5). |
+---------+-------+----------+---------------------------------------------|
| $A000 | W | ???????m | Shadow Select Register |
| | | | |
| | | | m = Shadowing |
| | | | 0 = Vertical |
| | | | 1 = Horizontal |
+---------+-------+----------+---------------------------------------------|
| $A001 | W ? | p??????? | Pattern Table Control Register |
| | | | |
| | | | p = Pattern Table Enable/Disable |
| | | | 0 = Disable use of $0000-$1FFF in |
| | | | VRAM |
| | | | 1 = Enable use of $0000-$1FFF in |
| | | | VRAM |
| | | | |
| | | | NOTE: Information here could possibly be |
| | | | incorrect. |
+---------+-------+----------+---------------------------------------------|
| $C000 | | dddddddd | IRQ Decrement Register |
| | | | |
| | | | A value (1-255) is written here. The chip |
| | | | auto-decrements this value at every scan- |
| | | | line. Once 0 is hit, IRQ/BRK is executed. |
| | | | If 0 is stored, then this feature is dis- |
| | | | abled. |
+---------+-------+----------+---------------------------------------------|
| $C001 | W | | Temporary Latch Register |
+---------+-------+----------+---------------------------------------------|
| $E000 | W | | IRQ Control Register #1 |
| | | | |
| | | | Any writes which occur to this register |
| | | | will cause the value written to $C001 to |
| | | | be copied into $C000. IRQs are also dis- |
| | | | abled as well. |
+---------+-------+----------+---------------------------------------------|
| $E001 | W | | IRQ Control Register #2 |
| | | | |
| | | | Any writes to this register enable IRQs. |
+--------------------------------------------------------------------------+

In order to make the MMC function, you must first write a Command Number
(CMD #) into $8000, and then a value (Page Number) into $8001. The follow-
ing CMDs exist:

+--------------------------------------------------------------------------+
| CMD # | Address | Description |
+-------+---------+--------------------------------------------------------|
| 0 | $0000 | Selects two (2) 1K CHR-RAM pages at the Address. |
| 1 | $0800 | Selects two (2) 1K CHR-RAM pages at the Address. |
| 2 | $1000 | Selects one (1) 1K CHR-RAM pages at the Address. |
| 3 | $1400 | Selects one (1) 1K CHR-RAM pages at the Address. |
| 4 | $1800 | Selects one (1) 1K CHR-RAM pages at the Address. |
| 5 | $1C00 | Selects one (1) 1K CHR-RAM pages at the Address. |
+-------+---------+--------------------------------------------------------|
| 6 | N/A | Selects one (1) 8K PRG-ROM Page at the CHR-RAM Page |
| | | Base Select. Initial value is 0. |
+-------+---------+--------------------------------------------------------|
| 7 | N/A | Selects one (1) 8K PRG-ROM Page at the CHR-RAM Page |
| | | Base Select. Initial value is 1. |
+--------------------------------------------------------------------------+

NOTE: For CMDs 0-5, see the Page Number Select Register ($8001). For
CMDs 6-7, see the Function Select Register ($8000) above.

NOTE: Address is really "CHR-RAM Base Address XOR (Address)". Therefore,
if the CHR-RAM Base Address is set to $1000, then using CMD #4 would
result in a transfer to $2800 in VRAM.


5) Nintendo MMC5

This mapper is used in Castlevania III. It supports a four-screen Name
Table layout, allowing four (4) physical Name Tables to be used.

This mapper supports a 1K section of external RAM (EXRAM), which is
mapped to $5C00-$5FFF. EXRAM holds one (1) byte corrisponding to each of
the 960 8x8 tiles. The format of an EXRAM byte is:

+------------------------------------------------------------+
| Bits | Description |
+----------+-------------------------------------------------|
| ccIIIIII | c = Colour Expansion |
| | |
| | Used to remove the annoying 4x4 tile |
| | Attribute Bit limitation. Using these |
| | bits is optional. |

| | |
| | I = Index Expansion |
| | |
| | Extends the maximum Index Tile #s from |
| | 256 to 16384 (8-bits to 14-bits), by |
| | using these six (6) in the Name Table, |
| | e.g.: |
| | |
| | IIIIIInnnnnnnn |
| | +----++------+ |
| | | +--- Name Table |
| | +---------- Index Expansion |
+------------------------------------------------------------+

A register at $5104 can control whether the CPU can write to EXRAM or
not, and also controls if the Colour Expansion bits in the EXRAM are used
or not

It also seems MMC5 has a register which can flip between Vertical and
Horizontal mirroring. This register is definitely used in Castlevania III.


6) FFE F4xxx Mapper

This mapper allows swapping of PRG-ROM, and supports four (4) Pattern
Tables. This mapper was invented by FFE (Front Far East) for their NES
backup unit/development system, and seems to only be used on F4xxx-style
games, such as the famous Wai Wai World ("Konami World"), Getsufuu Maden,
and others. It also supports IRQ and counter registers, resembling that of
Nintendo's MMC3.

Two styles of data can be written here, but most of the time, the format
of the more commonly used data (used in "Wai Wai World") is:

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $42FC | W | pppppppp | PRG-ROM Write Enable |

| $42FD | W | mmmmmmmm | Mirroring Write Enable |
| $42FE | W | ???p???? | PRG-ROM Swap |
| $42FF | W | ???m???? | Mirroring Select |
| | | | m = Mirroring Select |
| | | | 0 = Vertical |
| | | | 1 = Horizontal |
| $43FE | W | CCCCCCpp | 4mb PRG-ROM/CHR-RAM Select |
| $4500 | RW | eXssWPPP | Configuration Register |
| | | | e = Disk/Cart Mode |
| | | | 0 = Famicom Disk game |
| | | | 1 = Famicom cart |
| | | | X = Execute Mode |
| | | | 0 = Do nothing |
| | | | 1 = Execute game |
| | | | s = SRAM Availability |
| | | | 0 = Not used |
| | | | 1 = SRAM used |
| | | | W = SW Pin |
| | | | PPP = PPU Mode |
| | | | 010 = 256K |
| | | | 101 = 2M + Extended VRAM |
| | | | 111 = 2M |
| $4501 | W | iiiiiiii | IRQ Disable |
| $4502 | W | iiiiiiii | IRQ Increment Register (low byte) |
| $4503 | W | iiiiiiii | IRQ Enable & Increment Register (high byte) |
| $8000 | RW | --ppppCC | PRG-ROM/CHR-RAM Control Register |
| $A000 | | | |
| $C000 | | | p = 16K PRG-ROM Select |
| $E000 | | | Selects 16K PRG-ROM bank at $8000 |
| | | | CC = Pattern Table Select |
| | | | Selects Pattern Table #0-3 |
+--------------------------------------------------------------------------+

The support of an IRQ counter is very similar to that of MMC3, except
that it is incremented and not decremented. When the value reaches $FFFF,
it will be reset to $0000. To enable the use of the IRQ counter, store
the value $0000 into $4503.

This mapper also supports the use of a trainer. The trainer is loaded at
$7000-71FF. Each described item below is actual 6502 code, and not a
vector (e.g. JMP $xxxx). The address itself *IS* the vector.

+-------------------------------------------------------+
| Address | Description |
+---------+---------------------------------------------|
| $7000 | NMI |
| $7003 | Game Setup code |
| $7006 | Mirroring Switch |
| $7009 | Other trainer routines |
| ... | |
+-------------------------------------------------------+

NOTE: It seems most these images are purely PRG-ROM; i.e. no CHR-RAM. All
the CHR-RAM is kept inside the PRG-ROM, which is swapped in and out during
runtime via the MMC.

The documentation here is still not complete; for a more accurate and
detailed documentation, please check out FanWen's document regarding
Mapper #6 via this URL:

http://nesdev.parodius.com/mapper6.txt


7) ROM Switch

This mapper only switches PRG-ROM banks, 32K in size. It can also spec-
ify which Name Table and Attribute Table to use.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W | ???nPPPP | PRG-ROM Control Register |
| ... | | | |
| $FFFF | | | P = 32K PRG-ROM Bank at $8000 |
| | | | n = Name/Attribute Table Select |
| | | | 0 = $2000 (VRAM) |
| | | | 1 = $2400 (VRAM) |
+--------------------------------------------------------------------------+

NOTE: The remaining Name Tables and Attribute Tables just mirror that of
the one selected via Bit #4.


8) FFE F3xxx Mapper

No information is currently available.


9) Nintendo MMC2

This MMC is used in the American version of the "Mike Tyson's Punch-Out!"
cart. It supports switching of PRG-ROM and CHR-RAM.

PRG-ROM banks are 8K in size, with a base ROM address of $8000. CHR-RAM
banks are 4K in size,

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $A000 | W | dddddddd | PRG-ROM 8K Page Select Register |
| ... | | | |
| $AFFF | | | d = 8K PRG-ROM Select |
| | | | Selects 8K PRG-ROM bank at $8000. |
| | | | |
| $B000 | W | dddddddd | CHR-RAM 4K Page Select Register #1 |
| $C000 | | | |
| | | | d = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $0000. |
| | | | |
| $D000 | W | dddddddd | CHR-RAM 4K Page Select Register #2 |
| $E000 | | | |
| | | | d = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $1000. |
+--------------------------------------------------------------------------+

The last three (3) PRG-ROM banks in the cart itself are hardwired to the
last three (3) 8K sections of ROM. For instance, in the case of "Mike
Tyson's Punch-Out!" which has sixteen (16) 8K PRG-ROM banks, PRG-ROM
bank #13, #14, and #15 would be mapped to $A000, $C000, and $E000, respec-
tively.

NOTE: The CHR-RAM 4K Page Select Register seem to work in congruency;
i.e. when data is written to $B000, $D000 will function, but $E000 will
not (and therefore, the same rules apply to $C000/$E000 where $D000 will
not work).


10) Nintendo MMC4

This MMC is used in the Japanese version of the "Mike Tyson's Punch-Out!"
cart. It supports switching of PRG-ROM and CHR-RAM.

PRG-ROM banks are 16K in size, and CHR-RAM banks are 4K.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $A000 | W | pppppppp | PRG-ROM Page Select Register |
| | | | |
| | | | p = 32K PRG-ROM Select |
| | | | Selects 16K PRG-ROM bank at $8000. |
+---------+-------+----------+---------------------------------------------|
| $B000 | W | CCCCCCCC | CHR-RAM Page Select Register #1 |
| | | | |
| | | | C = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $0000. |
+---------+-------+----------+---------------------------------------------|
| $C000 | W | CCCCCCCC | CHR-RAM Page Select Register #2 |
| | | | |

| | | | C = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $1000. |
+---------+-------+----------+---------------------------------------------|
| $D000 | W | CCCCCCCC | CHR-RAM Page Select Register #3 |
| | | | |
| | | | C = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $0000. |
+---------+-------+----------+---------------------------------------------|
| $E000 | W | CCCCCCCC | CHR-RAM Page Select Register #4 |
| | | | |
| | | | C = 4K CHR-RAM Select |
| | | | Selects 4K CHR-RAM bank at VRAM |
| | | | address $1000. |
+---------+-------+----------+---------------------------------------------|
| $F000 | W | dddddddd | Mirroring Select Register |
| | | | |
| | | | d = Mirroring Select |
| | | | 0 = Horizontal |
| | | | 1 = Vertical |
+--------------------------------------------------------------------------+

This mapper has some very peculiar aspects, especially when it comes to
accessing VRAM. The CHR-RAM Page Select Registers listed above are auto-
matically "enabled" and "disabled" depending upon which address(es) in
VRAM you access.

+------------------------------------------------------------------+
| VRAM Address Range | Description |
+--------------------+---------------------------------------------|
| $0FD8-0FDF | Switches VRAM $0000-0FFF swapping to $C000 |
| $0FE8-0FEF | Switches VRAM $0000-0FFF swapping to $B000 |
| $1FD8-1FDF | Switches VRAM $1000-1FFF swapping to $E000 |
| $1FE8-1FEF | Switches VRAM $1000-1FFF swapping to $D000 |
+------------------------------------------------------------------+


11) Color Dreams Mapper

This mapper is commonly used in Color Dreams games, but not all of
them will function correctly when using this mapper.

PRG-ROM banks are 32K in size, and CHR-RAM banks are 8K.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W | CCCCpppp | PRG-ROM/CHR-RAM Page Select Register |
| ... | | | |
| $FFFF | | | C = 8K CHR-RAM Select |
| | | | Selects 8K CHR-RAM bank at VRAM |
| | | | address $0000. |
| | | | p = 32K PRG-ROM Select |
| | | | Selects 32K PRG-ROM bank at $8000. |
+--------------------------------------------------------------------------+


12) FFE F6xx Mapper

No information is currently available.

13) [Unused]

14) [Unused]

15) 100-in-1 Mapper

NOTE: Assume ROM16k[] is an array of 16K PRG-ROM Banks.
NOTE: Unlike other MMCs, the 16K of PRG-ROM loaded into $C000 on startup
is the second 16K PRG-ROM page, not the last 16K PRG-ROM page.

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W ? | smNNNNNN | PRG-ROM Control Register #1 |
| | | | |
| | | | s = Swap 8K Pages |
| | | | Swaps 8K at $8000 and $A000 |
| | | | Swaps 8K at $C000 and $E000 |
| | | | m = Mirroring Control |
| | | | 0 = Vertical |
| | | | 1 = Horizontal |
| | | | N = PRG-ROM Page Select |
| | | | $8000 now holds ROM16k[N] |
| | | | $C000 now holds ROM16k[N+1] |
+---------+-------+----------+---------------------------------------------|
| $8001 | W | s?NNNNNN | PRG-ROM Control Register #2 |
| | | | |
| | | | s = Swap 8K Pages |
| | | | Swaps 8K at $C000 and $E000 |
| | | | N = PRG-ROM Page Select |
| | | | $C000 now holds ROM16k[N] |
+---------+-------+----------+---------------------------------------------|
| $8002 | W | S?NNNNNN | PRG-ROM Control Register #3 |
| | | | |
| | | | S = Upper/Lower 8K Select |
| | | | 0 = Select Lower 8K of 16K segment |
| | | | 1 = Select Upper 8K of 16K segment |
| | | | N = 8K PRG-ROM Page Select |
| | | | $8000 now holds ROM16k[N] |
| | | | $A000 now holds ROM16k[N] |
| | | | $C000 now holds ROM16k[N] |
| | | | $E000 now holds ROM16k[N] |
| | | | |
| | | | NOTE: Bit 7 handles only Bits 0-5 of this |
| | | | register, and does not affect any |
| | | | other registers. |
| | | | |
| | | | NOTE: Bits 0-5 base their 8K Selection on |
| | | | Bit 7. Keep this in mind. |
+---------+-------+----------+---------------------------------------------|

| $8003 | W | smNNNNNN | PRG-ROM Control Register #4 |
| | | | |
| | | | s = Swap 8K Pages |
| | | | Swaps 8K at $C000 and $E000 |
| | | | m = Mirroring Control |
| | | | 0 = Vertical |
| | | | 1 = Horizontal |
| | | | N = ROM Page Select |
| | | | $C000 now holds ROM16k[N] |
+--------------------------------------------------------------------------+


16) Bandai Mapper

This mapper uses only 32K of PRG-ROM and 8K of CHR-RAM, both which can be
swapped. The actual bank-switching is similar to that of Mapper #2:

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $8000 | W ? | ??PP??CC | PRG-ROM & CHR-RAM Control Register |
| ... | | | |
| $FFFF | | | P = 32K PRG-ROM Page |
| | | | C = 8K CHR-RAM Page |
+--------------------------------------------------------------------------+


17) FFE F8xxx Mapper

No information is currently available.

18) Jaleco SS8806 Mapper

No information is currently available.

19) Namcot 106 Mapper

No information is currently available.

20) Famicom Disk System Mapper

See Section #13 for more information.

21) Konami VRC4 Mapper

No information is currently available.

22) Konami VRC2 Mapper #1

No information is currently available.

23) Konami VRC2 Mapper #2

No information is currently available.

24) Konami VRC6 Mapper

No information is currently available.

25) [Unused]

26) [Unused]

27) [Unused]

28) [Unused]

29) [Unused]

30) [Unused]

31) [Unused]

32) Irem G-101 Mapper

No information is currently available.

33) Taito TC0190/TC0350 Mapper

No information is currently available.

34) iNES Mapper #34

This mapper is used by Mission Impossible 2, Deadly Towers, and 3D
Worldrunner. It can be used to swap 32K of PRG-ROM and 8K of CHR-RAM (in
4K sections):

The actual bank-switching is similar to that of the ROM Switch (#7):

+--------------------------------------------------------------------------+
| Address | Stats | Bits | Description |
+---------+-------+----------+---------------------------------------------|
| $7FFD | W ? | PPPPPPPP | PRG-ROM Page |
| $7FFE | W ? | CCCCCCCC | CHR-RAM Page (lower 4K) |
| $7FFF | W ? | cccccccc | CHR-RAM Page (upper 4K) |
| $8000 | W ? | PPPPPPPP | PRG-ROM Page |
| ... | | | |
| $FFFF | | | NOTE: $7FFE and $7FFF within this range |
| | | | are described above, and do not |
| | | | control PRG-ROM. |
+--------------------------------------------------------------------------+


??) American Video Entertainment (MB-91J)

This mapper has yet to be given an actual number, but most likely will
be as future version of Marat Fayzullin's iNES emulator are updated.

This mapper supports 32K PRG-ROM and 8K CHR-RAM bank-switching. The
actual addresses for switching are strange, and are not linear. From the
information i've been given, it seems the valid addresses for switching
are:

$xy00-$xyFF 'x' can be: $1,4,5
$xy00-$xyFF 'y' can be: $1,3,5,7,9,B,D,E,F
$xy00-$xyFF

The format of the data written is:

+------------------------------------------------------------+
| Bits | Description |
+----------+-------------------------------------------------|
| ----PCCC | P = PRG-ROM Page |
| | C = CHR-RAM Page |
+------------------------------------------------------------+

This mapper pretty insane, and I'm probably wrong about the addresses.
Rumour has it, the 'x' nybble in the address can be $0 as well, but this
seems to kill off zero-page: therefore I'm considering it invalid.

Let's wait and see what Mr. Fayzullin has to say about it.

+----------------+
| 11 | Sound |
+----------------+

One of the most interesting aspects of the NES is it's sound support,
which is very analogue, excluding the PCM register.

The perfect sound constant seems to be:

111860.78 (e.g. 3579545/32)

This was taken from the sound constant used in the TI 76486 PSG sound
processor within the Sega Genesis (interesting, eh).

For the Square Wave and Triangle Wave channels, a formulae can be used
to provide accurate playback of the NES's sound:

P = 111860.78 / (CHx + 1)

Where "P" is the actual played data, and CHx is the channel played.
The channel formulaes are the following:

CH1 = $4002 + ($4003 & 7) * 256 (Square Wave #1)
CH2 = $4006 + ($4007 & 7) * 256 (Square Wave #2)
CH3 = $400A + ($400B & 7) * 256 (Triangle Wave)

Where the $400x values are actual values written to that register.

For the PCM channel, there are two methods of implementation: via DMA,
and via the PCM Volume Port ($4011).

Samples are sent byte-by-byte into $4011, the result being quite

audible. However, only a few games seem to use this method, while most
use the DMA transfer approach.

Any information is appreciated.

+---------------------------+
| 12 | .NES File Format |
+---------------------------+

This is the .NES File Format, created by Marat Fayzullin (author of
iNES). This is the newer format, supporting >16 iNES Mappers.

+----------------------------------------------------------------------+
| Offset | Size | Content(s) |
+--------+------+------------------------------------------------------|
| 0 | 3 | 'NES' |
| 3 | 1 | $1A (Control-Z) |
| 4 | 1 | Number of 16K PRG-ROM banks |
| 5 | 1 | Number of 8K CHR-RAM banks |
| 6 | 1 | ROM Control Byte #1 |
| | | %00000000 |
| | | +--+|||+- 0=Horizontal Mirroring |
| | | | ||| 1=Vertical Mirroring |
| | | | ||+-- 1=WRAM located at $6000-7FFF |
| | | | |+--- 1=512-byte trainer present |
| | | | +---- 1=Four-screen VRAM layout |
| | | | |
| | | +------ iNES Mapper # (lower 4-bits) |
| 7 | 1 | ROM Control Byte #2 |
| | | %00000000 |
| | | +--+ |
| | | +------ iNES Mapper # (upper 4-bits) |
| | | |
| 8-15 | 9 | [Reserved for expansion, should be 0] |
| 16-.. | | PRG-ROM banks (in ascending order). A trainer pre- |
| | | cedes the first bank, if a trainer exists. |
| ..-EOF | | CHR-RAM banks (in ascending order). |
+----------------------------------------------------------------------+

The previously mentioned 512-byte trainer is interesting, since it has
different implementations depending upon which iNES Mapper is used in the
cart. See Section #10 for more information about MMC-dependant trainers.

+------------------------------------------------------+
| 13 | Famicom Disk System Format (.DKA/.DKB/.500) |
+------------------------------------------------------+

This is the file format for Famicom Disk System images; the only
emulator at this time to support them is Pasowing, which is the
emulator which these images are based off of.

The format for the .DKA/.DKB (DisK side-A and DisK side-B) files
is somewhat undocumented (as shown). .DKA and .DKB files are 64K in
size (65536 bytes). The format for the file is as follows:

+----------------------------------------------------------------------+
| Offset | Size | Content(s) |
+----------------------------------------------------------------------|
| [IMAGE HEADER] |
| |
| 0 | 1 | [Unknown] |
| 1 | 3 | Disk ID |
| 6 | 1 | Disk # |
| 38 | 1 | Disk # (???) |
| 63 | 1 | Amount of data blocks |
| |
| [DATA BLOCK HEADER] |
| |
| 64 | 1 | $03 |
| 65 | 1 | Block # |
| 66 | 1 | ??? |
| 67 | 8 | Name |
| 75 | 2 | Destination |
| 77 | 2 | Size of data |
| 79 | 1 | Data Type |
| | | +-------+ |
| | | | |
| | | +------ $00 = PRG-RAM |
| | | $01 = CHR-RAM |
| | | $02 = Name Table Data |
| 79-.. | | Data |
| | | |
| ..-EOF | | Repeat loading DATA BLOCKS HEADERS as shown above; |
| | | continue loading until EOF is reached. |
+----------------------------------------------------------------------+

+------------------------------------+
| 14 | Notes to emulator authors |
+------------------------------------+

The NES is a 6502 (NMOS) CPU. It is not a 65C02 (CMOS) CPU as rumoured.

Ignore opcodes which are "bad" (not in the 6502 instruction set); a lot
of ROMs available are flawed, due to bad backup units or readers. I've
noticed this in the "Twinbee" and "Adventure of Lolo" ROMs floating around.

The Four-screen VRAM layout is used within other mappers, not just iNES
Mapper #5 (MMC5). I have seen it used in iNES Mapper #15 and others.

A reminder: MMC != iNES Mapper.

When the NES screen is turned off, programmers do not have to wait for
the VBL to occur. While the screen is off, code may safely edit VRAM and
manipulate graphics without having to sync to the VBL (if you don't,
while the screen is on, the result is quite disgusting). This applies to
most consoles, like the Super Nintendo.

For more information about NES PAL/NTSC issues, feel free to check out
Mark Knibb's NES PAL/NTSC document at:

http://nesdev.parodius.com/nesfreq.txt

I was wrong; Konami World 2 *DOES* exist, and was made in 1991 by Konami
of Japan. The cart uses the Konami VRC2 Mapper. I am still unsure about
Marat Fayzullin's "Punch Out 2," however.

A quick comment about the Famicom Disk System (for those who care):
Apparently PRG-RAM (that's right, RAM; not ROM) is located in the range
$6000-$DFFF. A bootstrap image is loaded into $E000-$FFFF (this can be
considered "a trainer," but technically, it's different). FDS registers
seem to be in the $E000-$FFFF range. The IRQ/RESET and NMI vectors are
taken from the end of the first PRG-RAM Data Block. Please don't Email
me with questions about the FDS: I don't know much about it (despite
owning one).

+-----------------+
| 15 | Thanks |
+-----------------+

Thanks to the following people for helping make this document what it
has become today. In alphabetical order:

+--------------------------------------------------+
| Name/Pseudo | Email |
+--------------------+-----------------------------|
| Acey | d0p@sofi.ah.dk |
| Alex Krasivsky | bcat@lapkin.rosprint.ru |
| Avatar Z | swahlen@nfinity.com |
| Bloodlust Software | bldlust@parodius.com |
| Bluefoot | danmcc@injersey.com |
| CiXeL | |
| Chris Hickman | typhoonz@parodius.com |
| D | d@animal.blarg.net |
| Dan Boris | dan.boris@coat.com |
| Donald Moore | mindrape@goodnet.com |
| FanWen Yang | yangfanw@ms4.hinet.net |
| Johansson Morgan | MOJ@nerikes.se |
| Jon Merkel | jpm5974@omega.uta.edu |
| Kevin Horton | khorton@iquest.net |
| Loopy | loopy@itsnet.com |
| Marat Fayzullin | fms@freeflight.com |
| Mark Knibbs | markk@netcomuk.co.uk |
| Matthew Richey | mr6v@andrew.cmu.edu |
| Mike Perry | mj-perry@uiuc.edu |
| Neill Corlett | corlett@elwha.nrrc.ncsu.edu |
| Pat Mccomack | splat@primenet.com |
| Paul Robson | AutismUK@aol.com |
| Stumble | stumble@alpha.pulsar.net |
| Tony Young | KBAAA@aol.com |
| Vince Indriolo | indriolo@nm.picker.com |
+--------------------------------------------------+

+---------------------------+
| 16 | About the Author |
+---------------------------+

One of the most common questions I get (usually from newbies) is "Who
are you, and where the HELL did you come from? I hear of your name on a
regular basis, but just who are you?"

My name is Jeremy Chadwick, more commonly known as Y0SHi or Yoshi. I'm
5'10" (175cm), 150-160 pounds, blue-grey eyes, and professionally cut
blonde-brown hair. A picture of me is available on my WWW page.

I'm a UNIX System/Network/Security Administrator located in Corvallis,
Oregon USA (but will be relocating to Mountain View, California during
early 1998). I currently work for Electronic Arts (UK) doing PSX R&D, and
a local engraving shop where I do graphics design and vinyl layout. I'm
also the primary System Administrator for parodius.com, which over the past
year has slowly become the most well-known site on the InterNET for
console-oriented material.

I've been on the 'net since late 1989, and on BBSes around the world
since latee 1988. I've been programming computers since 1987, and consoles
since 1994: all in assembly language. I became interested in console pro-
gramming around July of '94, and released my famous SNES Documentation a
few days after Christmas in 1994.

Since then, I've worked on multiple projects/games, such as:

* qNES * TRaCER (Pascal and ASM)
* SNES Documentation * Hexad (coming soon)

And also helped out on other projects (in one way or another) such as:

* VSMC * ESNES
* SNES96/97 * NESticle
* Genecyst * SNES9x
* A/NES * X-Char & X-Late

One of the greatest rewards in life is when you can help someone else
achieve a goal by giving them information or just by giving them moral
support. It doesn't take money to help someone; sometimes it just takes
a pat on the back and positive feedback. I found that by giving someone
such support, and by being honest with people, you can really feel good
about yourself, while still enjoying what you do.

I get a lot of comments such as "You're god damn smart," "I wish I could
know what you know," and "Hey, can I borrow your resume for a few days?"

What I know isn't important. The fact that I have the desire to learn
as much as I can, is important. Someone who wants to learn and has the
capability to is much more valuable (business-wise) than someone who claims
they know everything, and has a BS (a BS in BS, most likely).

You can contact me via one of the following methods:

Email: yoshi@parodius.com
yoshi@dynamik.com
yoshi@usa.net
WWW: http://yoshi.parodius.com/
IRC: Y0SHi (EFNet)
Mail: Parodius Networking
c/o Jeremy Chadwick
2470 NW Rolling Green Dr. #29
Corvallis, OR 97330
USA

My comments here regarding the emulation "scene" have been removed:
because in my eyes, there is no scene.

*****
_EOF_


← previous
next →
loading
sending ...
New to Neperos ? Sign Up for free
download Neperos App from Google Play
install Neperos as PWA

Let's discover also

Recent Articles

Recent Comments

Neperos cookies
This website uses cookies to store your preferences and improve the service. Cookies authorization will allow me and / or my partners to process personal data such as browsing behaviour.

By pressing OK you agree to the Terms of Service and acknowledge the Privacy Policy

By pressing REJECT you will be able to continue to use Neperos (like read articles or write comments) but some important cookies will not be set. This may affect certain features and functions of the platform.
OK
REJECT