Архитектура игровой приставки Dendy

Этот документ описывает работу видеоприставки Nintendo, также известной как Famicom (Корея, Япония), Dendy (в России). Описание не основано на официальной документации Nintendo и может быть неполной или неверной в некоторых случаях. "Nintendo Entertainment System" и "Famicom" - зарегестрированные торговые марки фирмы Nintendo.

Данная версия описания не содержит некоторую информацию (в частности о звуке). Автор надеется дополнить описание в следующих версиях. Если вы имеете дополнительную информацию о NES (Nintendo Entertainment System) пишите на fms@freeflight.com (а еще лучше мне, на slep@tvsystem.ru :->).

Содержание

1. Основная архитектура
2. Прерывания
3. Порты ввода-вывода
4. Память PPU
5. VBlank память
6. Джойстики
7. Спрайты
8. Карта памяти
a) Sequential
b) Konami
c) VROM Switch
d) 5202 Chip
e) Другая

Основная архитектура
NES разработана на базе процессора 6502. Видеоконтроллер данной системы принято называть PPU (Picture Processing Unit). Память PPU отделена от основной и доступна для записи/чтения с помощью специальных портов. Картридж может содержать и ROM (загружаемую по главным адресам процессора $8000-$FFFF), и VROM (VRAM) (загружаемую в память PPU по адресам $0000-$1FFF и содержащую таблицы палитр). В малых картриджах, которые имеют только 16kB ROM, она занимает промежуток $C000-$FFFF ($8000-$BFFF остается неиспользованной). Внутренняя память VRAM располагается по адресам $2000-$3FFF в памяти PPU. В некоторых картриджах есть также и RAM ($6000-$7FFF) (может быть сохранена с помощью батареек :->).

Адресное пространство процессора:
--------------------------------------- $10000
Верхний банк картриджа
--------------------------------------- $C000
Нижний банк картриджа
--------------------------------------- $8000
Оперативная память картриджа
--------------------------------------- $6000
Расширяющие модули
--------------------------------------- $5000
Ввод/вывод
--------------------------------------- $2000
2kB внутренняя память
--------------------------------------- $0000

Прерывания
NES использует немаскируемые прерывания (NMI), генерируемые PPU в конце каждого фрейма (так называемые VBlank прерывания). Маскируемые прерывания, или IRQ, также могут быть сгенерированы схемами картриджа, но большинство не делают этого. VBlank прерывания могут быть разрешены/запрещены записью 1/0 в седьмой бит байта $2000. Когда возникает прерывание, процессор запоминает адрес возврата и статус регистра в стеке, и переходит к адресу, хранимому по адресу $FFFA (ПЗУ NES). Обработчик прерывания завершает его исполнение RTI командой, которая возвращает процессор к выполнению главной программы.

Дополнительную информацию об обработчиках прерываний можно найти в описании процессора 6502.

Порты ввода-вывода
Порты ввода-вывода разделены на промежутки $2000-$2007 и $4000-$4017.
Карта портов ввода-вывода:
|------+-----+---------------------------------------------------------------
|$2000 | RW  | PPU Control Register (управляющий регистр PPU)
|      | 0-1 | Имена таблиц:
|      |     |
|      |     |           +-----------+-----------+
|      |     |           | 2 ($2800) | 3 ($2C00) |
|      |     |           +-----------+-----------+
|      |     |           | 0 ($2000) | 1 ($2400) |
|      |     |           +-----------+-----------+
|      |     |
|      |     | Так как используется зеркалирование, то существует всего
|      |     | два реальных имени таблиц (а не 4)
|      |   2 | Запись, 1 = адрес PPU увеличивается на 32:
|      |     |
|      |     | Название таблицы, VW=0    Название таблицы, VW=1
|      |     |   +----------------+        +----------------+
|      |     |   |----> write     |        | | write        |
|      |     |   |                |        | V              |
|      |     |
|      |   3 | Таблица адресов палитры спрайтов, 1 = $1000, 0 = $0000
|      |   4 | Таблица адресов палитры спрайтов, 1 = $1000, 0 = $0000
|      |   5 | Размер спрайтов, 1 = 8x16, 0 = 8x8
|      |   6 | Hit Switch, 1 = генерируется прерывание (или нет ???) (:->)
|      |   7 | VBlank Switch, 1 = генерирует прерывание VBlank
|------+-----+---------------------------------------------------------------
|$2001 | RW  | PPU Control Register 2 (управляющий регистр PPU 2)
|      |   0 | Неизвестно (???) (:-[)
|      |   1 | Маска рисунка, 0 = не показывать левых 8 колонок экрана
|      |   2 | Маска спрайтов, 0 = не показывать спрайт в левых 8 колонках
|      |   3 | Выбор экрана, 1 = показать картинку, 0 = пустой экран
|      |   4 | Выбор спрайтов, 1 = показать спрайт, 0 = спрятать его
|      | 5-7 | Неизвестно (???) (:-<)
|------+-----+---------------------------------------------------------------
|$2002 | R   | PPU Status Register (регистр статуса)
|      | 0-5 | неизвестно (???) (:-))
|      |   6 | Hit Flag, 1 = обновляет состояние спрайта #0
|      |     | Этот флаг скидывается в 0 когда стартует VBlank, или CPU
|      |     | читает адрес $2002.
|      |   7 | VBlank флаг, 1 = PPU генерирует вертикальный импульс (Vertical Blanking Impulse)
|      |     | Этот флаг скидывается в 0, когда VBlank заканчивается, или CPU читает $2002
|      |     | 
|------+-----+---------------------------------------------------------------
|$2004 | W   | Данные памяти спрайтов
|      |     | Используется для чтения/записи памяти спрайтов. Адрес устанавливается
|      |     | начиная с $2003 и увеличивается после каждого обращения. Эта память
|      |     | содержит координаты, цвет и другие атрибуты спрайтов
|------+-----+---------------------------------------------------------------
|$2003 | RW  | Адрес памяти спрайтов
|      |     | Используется для установки адреса в 256-байтной памяти спрайтов
|      |     | для доступа через $2004. Этот адрес будет увеличиваться на 1
|      |     | после каждого обращения.
|------+-----+---------------------------------------------------------------
|$2005 | W   | Background Scroll (скроллинг заднего плана)
|      |     | Существует два скроллирующих регистра: вертикальный и горизонтальный,
|      |     | оба записываются с помощью этого порта. Первое значение записывается
|      |     | в вертикальный (если значение больше 239, то оно игнорируется).
|      |     | второе значение появится в горизонтальном регистре.
|      |     | Horizontal Scroll Register. 
|      |     | Таблица:
|      |     |
|      |     |           +-----------+-----------+
|      |     |           | 2 ($2800) | 3 ($2C00) |
|      |     |           +-----------+-----------+
|      |     |           | 0 ($2000) | 1 ($2400) |
|      |     |           +-----------+-----------+
|      |     |
|      |     | Когда происходит скроллирование, картинка может попасть в диапазон
|      |     | нескольких таблиц. Опять же реально существует всего 2 имени таблиц
|      |     | из за дублирования
|------+-----+---------------------------------------------------------------
|$2006 |     | PPU Memory Address (адрес памяти PPU)
|------+-----+---------------------------------------------------------------
|$2007 |     | PPU Memory Data (данные памяти PPU)
|------+-----+---------------------------------------------------------------
|$4000-$4013 | регистры звука
|------+-----+---------------------------------------------------------------
|$4014 | W   | Прямой доступ к памяти спрайтов
|      |     | Запись значения N в этот порт приводит к преобразованию
|      |     | памяти по адресу $N*100 в память спрайтов
|------+-----+---------------------------------------------------------------
|$4015 | W   | Переключение звука
|      |   0 | Канал 1, 1 = разрешить звук
|      |   1 | Канал 2, 1 = разрешить звук
|      |   2 | Канал 3, 1 = разрешить звук
|      |   3 | Канал 4, 1 = разрешить звук
|      |   4 | Канал 5, 1 = разрешить звук
|      | 5-7 | неиспользуется
|------+-----+---------------------------------------------------------------
|$4016 | RW  | Первый джойстик и строб
|      |   0 | данные джойстика
|      |   1 | наличие первого джойстика (0-присоединен)
|      | 2-5 | неиспользуется
|      | 6-7 | неизвестно
|------+-----+---------------------------------------------------------------
|$4017 | R   | тоже самое для второго джойстика
|------+-----+---------------------------------------------------------------

Память PPU
Чтение/запись памяти PPU может производиться только в периоды VBlank. Многие малые картриджы имеют только ПЗУ для таблиц палитр. В этом случае вы не сможете записать что-то в эту память. $3F00 и $3F10 дублируют друг друга и определяют фоновый цвет рисунка.

Чтение памяти PPU:
А) записывается верхний адрес в $2006
Б) нижний в $2006
В) читаются данные из $2007. Первый байт, считанный из $2007, будет неправильным.
Далее, адрес будет увеличиваться на 1 после каждого чтения.

Таблица имен содержит номера страниц, организованных в 32 ряда по 32 байта каждый. Страницы имеют размер 8х8 точек (получается расширение экрана 256х256). В версии NTSC верхние и нижние 16 точек не показываются (256х224). В PAL версии не показываются верхние и нижние 8 точек (256х240).

Таблица палитр содержит страницы картинок в следующем формате:
Символ Цвета Содержание таблицы
...o.... 00010000 00010000 $10 +-> 00000000 $00
..O.O... 00202000 00000000 $00 | 00101000 $28
.0...0.. 03000300 01000100 $44 | 01000100 $44
O.....O. 20000020 00000000 $00 | 10000010 $82
ooooooo. 11111110 11111110 $FE | 00000000 $00
O.....O. 20000020 00000000 $00 | 10000010 $82
0.....0. 30000030 10000010 $82 | 10000010 $82
........ 00000000 00000000 $00 | 00000000 $00
+---------+

Тоько два бита каждой точки символа хранятся в таблице. Остальные два берутся из таблицы атрибутов. Итак, количество цветов, могущее одновременно отображаться на экране: 16.

Каждый байт в таблице атрибутов представляет 4х4 группу страниц на экране, которые образуют 8х8 таблицы атрибутов. Каждая группа страниц 4х4 делится на четыри квадрата 2х2 как показано ниже:
(0,0) (1,0) 0| (2,0) (3,0) 1
(0,1) (1,1) | (2,1) (3,1)
--------------+----------------
(0,2) (1,2) 2| (2,2) (3,2) 3
(0,3) (1,3) | (2,3) (3,3)

Байт атрибутов содержит два бита номера цвета для каждого квадрата 2х2 (нижние два бита хранятся в таблице палитр):
Биты Функция Страницы
-------------------------------------------------------------------------
7,6 Верхние биты номера цвета для квадрата 3 (2,2),(3,2),(2,3),(3,3)
5,4 2 (0,2),(1,2),(0,3),(1,3)
3,2 1 (2,0),(3,0),(2,1),(3,1)
1,0 0 (0,0),(1,0),(0,1),(1,1)

Имеется две 16-битные таблицы палитр: одна по адресу $3F00, используемая для картинок, вторая от $3F10 и содержит палитру спрайтов. $3F00 и $3F10 в VRAM дублируют друг друга и определяют фон рисунка.

Карта памяти PPU
--------------------------------------- $4000
Пусто
--------------------------------------- $3F20
Палитра спрайтов
--------------------------------------- $3F10
Палитра картинок
--------------------------------------- $3F00
Пусто
--------------------------------------- $3000
Третья таблица атрибутов
--------------------------------------- $2FC0
Третья таблица имен
--------------------------------------- $2C00
Вторая таблица атрибутов
--------------------------------------- $2BC0
Вторая имен
--------------------------------------- $2800
Первая атрибутов
--------------------------------------- $27C0
Первая имен
--------------------------------------- $2400
Нулевая атрибутов
--------------------------------------- $23C0
Нулевая имен
--------------------------------------- $2000
Таблица палитр 1
--------------------------------------- $1000
Таблица палитр 0
--------------------------------------- $0000

VBank Память
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 the scanline 8. The program can reset this bit prematurely by reading from $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.

Joystick
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
-------+---------------------------------------------------------
Button | A B SELECT START UP DOWN LEFT RIGHT

Bit 1 indicates whether joystick is connected to the port or not. It is set to 0 if the joystick is connected, 1 otherwise. Bits 6 and 7 of $4016/$4017 also seem to have some significance, which is not clear yet. The rest of bits is set to zeroes. Some games expect to get *exactly* $41 from $4016/$4017, if a button is pressed, which has to be taken into account.
Спрайты
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 Memory 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 transfer using location $4014 (see above). Sprite Memory can also be accessed byte-by-byte by putting the starting address into $2003 and then writing/reading $2004 (the address will be incremented after each access). The format of sprite attributes is as follows:
Sprite Attribute RAM:
| Sprite#0 | Sprite#1 | ... | Sprite#62 | Sprite#63 |
| |
+---- 4 bytes: 0: Y position of the left-top corner - 1
1: Sprite pattern number
2: Color and attributes:
bits 1,0: two upper bits of color
bits 2,3,4: Unknown (???)
bit 5: if 1, display sprite behind background
bit 6: if 1, flip sprite horizontally
bit 7: if 1, flip sprite vertically
3: X position of the left-top corner
Sprite patterns are fetched in the exactly same way as the tile patterns for the background picture. The only difference occurs in the 16x8 sprites: the top half of the sprite is taken from the Sprite Pattern Table set in the $2000 port, while the bottom part is taken from the same location of the alternative Pattern Table. Therefore, if PPU is displaying a 16x8 sprite, and the Sprite Pattern Table is set to $1000, the bottom half of this sprite will be taken out of the $0000 Pattern Table, and vice versa.
Карта памяти
There are many diffirent memory mappers (aka MMCs) used in the NES cartridges. They are used to switch ROM and VROM pages, and do some other tasks. I will only describe the MMCs I'm familiar with. Any new information on these and other MMCs is highly appreciated. The MMC numbers are given in terms of the .NES file field "Mapper Type".
Sequential

This is a sequential mapper used in many 256kB cartridges, such as Bomberman 2, Destiny Of The Emperor, Megaman 2, Airwolf, Operation Wolf, Castlevania 2, Silk Worm, Yoshi, Break Thru. It may be used to switch ROM and VROM. If there is no VROM, 8kB of VRAM is present at $0000. In some cases (mostly RPG games) such cartridges also contain battery-backed RAM at $6000-$7FFF. The mapper has four 5bit registers, which are accessed via following addresses:
Register Address Range Function
---------------------------------------------------------------------------
0 $8000-$9FFF Mirroring and VROM Page Size select
The 0th bit of this register selects the mirroring type (1 for
horizontal, 0 for vertical). The 4th bit selects the size of
VROM pages. When it is 1, two 4kB VROM pages can be switched
independently at $0000 and $1000. Otherwise, there is a single
8kB VROM page at $0000.
1 $A000-$BFFF VROM page select
This register sets either 8kB or 4kB VROM page at $0000,
depending on the page size selected via register 0.
2 $C000-$DFFF Second VROM page select for 4kB pages
If 4kB VROM pages selected via register 0, this register sets
the VROM page at $1000. Otherwise, its value is ignored.
3 $E000-$FFFF ROM page select
This register sets 16kB ROM page at $8000. The page at $C000 is
always hardwired to the last ROM page in the cartridge. The
cartridge starts with page 0 at $8000.
---------------------------------------------------------------------------
In order to write to a mapper register, write $80 into any of the
locations first. This will reset the mapper. Then write the value bit by
bit into an appropriate address range. For example, the following assembly
code will write $0C into register 3:
lda #$80 ; Resetting mapper
sta $8000 ;
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
Konami
This is a quite simple mapper used in most Konami (Life Force, Castlevania, Metal Gear) and some other cartridges. It only switches the ROM. All cartridges with this mapper have 8kB VRAM at $0000 (i.e. no VROM). The mapper has a single 8bit register which can be written via locations $8000-$FFFF. It contains a number of 16kB ROM page at $8000. The page at $C000 is always hardwired to the last ROM page in the cartridge. The cartridge starts with page 0 at $8000.

There is one more thing to note about this mapper: although any address in the $8000-$FFFF range can be used to access the mapper, most games prefer to use the address with the last digit equal to the value they write out. Thus, $07 can be written to $9FF7, $05 to $9FF5, and so forth. The reason for this is unknown.

VRom Switch
Mapper #3, also known as a VROM switch, is used in the Goonies series and many Japanese-only games. It only allows you to switch 8kB pages of VROM. The ROM is either 16kB or 32kB and is not paged. The mapper has a single 8bit register which can be written via locations $8000-$FFFF. It contains a number of 8kB VROM page at $0000.

As with mapper #2, many games use locations with the last digit equal to the value being written. I do not know why.
5202 Chip
This mapper (or should I say 'an expansion chip'?) is used in many recent cartridges, such as Batman Returns, Super Contra, Vindicators, Silver Surfer, etc. It is an extremely complicated device, which is able to generate its own interrupts via IRQ line, and has a set of commands to switch ROM and VROM. VROM pages are 1kB, ROM pages appear to be 8kB. I do not completely understand how this mapper works, so any information is appreciated.

The chip is controlled via following locations:
Address Function
---------------------------------------------------------------------------
$8000 A command number (0-7) is written here. Also, write to this
register appears to reset the change made by a write into $E000.
$8001 An value for command is written here.
$A000 The 0th bit controls mirroring (1 = horizontal mirroring).
$A001 Same as $8001 (???)
$C000 Unknown
$C001 Unknown
$E000 The 5th bit appears to swap memory at $8000-$8FFF and
$A000-$AFFF, when set to 1.
$E001 Unknown
---------------------------------------------------------------------------
In order to use the mapper, you should first write a command number into $8000, and then a value (page number) into $8001. Following commands exist:
Cmd Function
---------------------------------------------------------------------------
0 Select 2 consequent 1kB VROM pages at $0000. The 0th bit of a value written into $8001 does not matter, i.e. 5 will always select pages 4 and 5.
1 Select 2 consequent 1kB VROM pages at $0800. The 0th bit of a value written into $8001 does not matter, i.e. 5 will always select pages 4 and 5.
2 Select a 1kB VROM page at $1000.
3 Select a 1kB VROM page at $1400.
4 Select a 1kB VROM page at $1800.
5 Select a 1kB VROM page at $1C00.
6 Select a 8kB ROM page at $8000. The initial value seems to be 0.
7 Select a 8kB ROM page at $A000. The initial value seems to be 1.
---------------------------------------------------------------------------
Note that the ROM pages at $C000 and $E000 are hardwired to the last pages of the ROM, and can not be switched (they can be swapped via $E000 though).
Другая
There are several other mappers, some of them very sophisticated. iNES partially supports them, but as this support either doesn't work correctly, or the mappers are uncommon (such as 100-in-1 cartridge mapper, I don't cover them here.
Назад