Дело в том, что и для Famicom, и для NES выходили самые разные аксессуары: 3D очки, клавиатуры, роботы, считыватели штрих-кодов, всякие игровые контроллеры и очень многое другое. До нас же дошёл только световой пистолет. Передо мной стояла задача собрать устройство, которое совмещало бы в себе разветвитель на четыре игрока (да, были такие игры) и Arkanoid-контроллер.
Порты ввода-вывода
Прежде всего стоит рассказать, как же работают с
С точки зрения игр порты ввода-вывода представляют из себя два регистра с адресами $4016 и $4017, которые ассоциированы соответственно с двумя портами, куда всё и подключается. Но на стандартных контроллерах для чтения данных используется только один провод — D0, данные с которого соответственно доступны через младший (нулевой) бит в каждом из регистров: $4016.0 и $4017.0. Аналогично используется один провод на запись, его обычно называют STROBE (или LATCH), который сбрасывает счётчик внутри геймпада, и который доступен через запись в $4016.0 (да, для обоих контроллеров он общий).
Проще говоря, чтобы получить состояние кнопок на первом контроллере надо сначала записать 1 в $4016.0, сразу же записать туда же 0, сбросив таким образом счётчик, а потом прочитать $4016 и $4017 восемь раз (для каждой из кнопок), получая данные о кнопках из младшего бита. Но для чего же остальные биты в этих регистрах, куда идут эти линии? Рассмотрим порт контроллера у NES:
Да, на него на самом деле идут D3 и D4! Именно они и доступны через $4016.3, $4016.4 у первого порта и $4017.3, $4017.4 у второго, и именно они используются для нестандартных контроллеров.
Что же касается его японского собрата — Famicom, там нет этих портов, да и сами игровые контроллеры не отсоединяются от консоли, но у него есть порт расширения, который представляет из себя разъём DB-15.
Знакомо выглядит, правда? Да, когда китайцы проектировали нашу Денди (я сомневаюсь, что её проектировали у нас), и им нужно было сделать отсоединяющиеся контроллеры, они решили взять за основу именно порт расширения, ведь в нём есть контакты для второго контроллера, и он на Famicom расположен чуть правее центра. Им тут даже распиновку менять не пришлось. Что же касается первого контроллера, они взяли тот же DB-15, расположили его слева и поменять распиновку так, чтобы можно было подключать первый контроллер. И только его.
Сравните сами передние порты у Famicom и у нашей Денди:
Вот такая вот странная история этих пятнадцатипиновых разъёмов у геймпадов, которые используются в нашей стране.
Но давайте посмотрим, что же выведено на этот порт расширения у Famicom?
(скриншот с сайта wiki.nesdev.com)
Да, на него идут ещё $4016.1 (на ввод), $4017.0-4 (на ввод), $4017.0-2 (на вывод), внешнее прерывание и даже звук! Я был очень приятно удивлён, когда разобрал Денди и увидел, что всё это есть и там:
Правда, не во всех моделях, как выяснилось позже. Но если это есть, значит есть и полная совместимость с аксессуарами для Famicom, и их могут использовать соответствующие японские игры. Но напомню, что Денди — это очень странная смесь NES и Famicom, PAL и NTSC. Пираты выпускали для неё и японские, и американские игры, которые по сути на 100% совместимы, если не брать в рассчёт эти аксессуары и разный формат картриджей.
Итого: в некоторых Денди есть все те же выводы, что и на Фамикоме, которые при этом включают в себя часть выводов доступных на NES. Отсутствует доступ к $4016.3 и $4016.4, но они используются крайне редко. В виде таблички для наглядности:
Принцип работы аксессуаров
Американский разветвитель на четыре игрока для NES называется Four Score представляет из себя простой набор сдвиговых регистров. Т.е. первые восемь чтений из $4016.0 дают данные из первого контроллера, а вторые восемь — из третьего. Аналогично $4017.0 даёт данные о втором и четвёртом контроллерах. Помимо этого при продолжении чтения устройство выдаёт свою сигнатуру, с помощью которой игра определяет, что подключен именно Four Score, а не что-то ещё. Получается, что такое устройство можно собрать из шести сдвиговых регистров (4021 или 74165), и оно будет работать на любой Денди, ведь для него не требуются дополнительные линии данных. Само собой, только с американскими играми, которые выходили для NES.
Японский аналог для Famicom устроен гораздо проще. Третий и четвёртый контроллеры подключаются напрямую в порт расширения и доступны через $4016.1 и $4017.1. Соответственно для такого переходника нам уже нужен полноценный порт расширения у Денди, иначе поиграть вчетвером в японские игры не получится.
Arkanoid-контроллер, как ясно из названия, используется для игры Arkanoid и представляет из себя ручку-крутилку и одну кнопку. Внутри же это аналого-цифровой преобразователь и сдвиговый регистр, который так же последовательно выдаёт положение ручки. Разница между японской и американской версией только в способе подключения. Японская версия игры читает положение ручки и состояние кнопки из $4016.1 и $4017.1, а американская версия из $4016.3 и $4016.4 соответственно. Получается, что для японского Арканоида нужен полноценный порт расширения, а для американского подойдёт любая денди, где работает световой пистолет (он использует те же выводы).
Создание своего аксессуара
Хотя сами по себе вышеперечисленные устройства имеют простую схему и собираются из простейших логических компонентов, для сердца устройства типа «всё в одном» я решил использовать ПЛИС. Тем более мне было высказано пожелание сделать там ещё и простейший переключатель-свитч, а мне хотелось сделать возможность менять местами кнопки A и B. Сначала я выбрал Altera EPM3064ATC100, но вскоре выяснилось, что 64 макроячейки мне не хватит, и выбор пал на EPM3128ATC100, где уже 128 макроячеек.
Если уж на то пошло, я решил совсем не мелочиться и поставить в устройство ещё и какой-то экран, на котором показывались бы текущий режим и меню с настройками, к тому же у меня давно валялся без дела один знакосинтезирующий «16x2» дисплей. Вот для работы с ним уже нужен микроконтроллер, и я выбрал ATMEGA16.
Мне всегда было сложнее всего придать устройству приятный внешний вид. Всё-таки я программист, а не дизайнер, но именно при изготовлении устройства в подарок хотелось сделать его максимально красивым и удобным. Тем более это чуть ли не единственный способ как-то показать другим своё произведение искусства: фотографии и видео — это не то, по готовым схемам и 3D моделькам такие вещи воссоздают единицы, серийное производство наладить тяжело, а вот подарок — самое то.
Итак, требования к внешнему виду были такие: четыре порта для стандартных DB-15 контроллеров от Денди, четыре кнопки для их выбора и настройки, кнопка «режим», кнопка «настройки», удобная ручка для Arkanoid и кнопка для него же, которые должны располагаться достаточно удобно и не мешаться. Помимо этого хотелось сделать, чтобы активные порты подсвечивались светодиодами и как-то интуитивно связывались с соответствующими кнопками, логичнее всего при этом расположить разъёмы в ряд, но эти дурацкие DB-15 слишком огромные для этого. Помимо всего устройство должно удобно лежать в руках, ведь оно само по себе игровой контроллер для Arkanoid. В итоге я пришёл примерно к такому виду:
Кнопки в ряд, порты друг над другом, ручка сбоку, кнопка для Arkanoid сзади слева.
Получается, что места внутри достаточно много. Поэтому ПЛИС с разъёмами под провода и гнёзда я решил вынести на одну плату, а микроконтроллер с экраном и кнопками — на другую. Соединяются они при этом простейшим последовательным интерфейсом.
Плата с ПЛИС (первая версия):
Вторая плата:
Код для ПЛИС я писал на Verilog. Для каждого режима он получается достаточно простым. В первую очередь для многих из них нам надо считать обращения к каждому из портов, т.е. импульсы на проводе clock:
reg [4:0] counter1;
reg [4:0] counter2;
always @ (posedge strobe_in, posedge clock1_in)
begin
if (strobe_in)
counter1 <= 1;
else if (counter1 < 31)
counter1 <= counter1 + 1;
end
always @ (posedge strobe_in, posedge clock2_in)
begin
if (strobe_in)
counter2 <= 1;
else if (counter2 < 31)
counter2 <= counter2 + 1;
end
(простите, хабр не умеет подсвечивать Verilog)
Где strobe_in — это strobe (один на оба порта), а clock1_in и clock2_in — это соответственно clock на каждом из портов. Внутри консоли стоит логика: clock = R/W nand (адрес == $4016/$4017), т.е. на clock логический ноль, когда консоль читает данные по соответствующему адресу.
Режим имитации американского разветвителя на четверых игроков выглядит так:
always @ (*)
begin
// Strobe соединяем напрямую - входы с выходами
assign strobe_out[0] = strobe_in;
assign strobe_out[1] = strobe_in;
assign strobe_out[2] = strobe_in;
assign strobe_out[3] = strobe_in;
// Дёргаем clock у каждого геймпада в зависимости от того, в который раз читает данные консоль
clock_out[0] <= (counter1 <= 8) ? clock1_in : 1;
clock_out[1] <= (counter2 <= 8) ? clock2_in : 1;
clock_out[2] <= (counter1 > 8 && counter1 <= 16) ? clock1_in : 1;
clock_out[3] <= (counter2 > 8 && counter2 <= 16) ? clock2_in : 1;
if (counter1 <= 8)
// Первый контроллер
joy1_data_out[0] <= joy_data[0];
else if (counter1 <= 16)
// Третий контроллер
joy1_data_out[0] <= joy_data[2];
// Сигнатура
else if (counter1 == 20)
joy1_data_out[0] <= 0;
else
joy1_data_out[0] <= 1;
// Второй контроллер
if (counter2 <= 8)
joy2_data_out[0] <= joy_data[1];
// Четвёртый контроллер
else if (counter2 <= 16)
joy2_data_out[0] <= joy_data[3];
// Сигнатура
else if (counter2 == 19)
joy2_data_out[0] <= 0;
else
joy2_data_out[0] <= 1;
// Неиспользуемые выводы оставляем в высокоимпедансном состоянии, они подтягиваются к VCC внутри самой консоли
joy1_data_out[1] <= 1'bZ;
joy2_data_out[4:1] <= 4'bZZZZ;
end
В режиме японского же развитвителя на четверых нужно просто соединить входы с выходами напрямую:
always @ (*)
begin
clock_out[0] <= clock1_in;
clock_out[1] <= clock2_in;
clock_out[2] <= clock1_in;
clock_out[3] <= clock2_in;
joy1_data_out[0] <= joy_data[0];
joy2_data_out[0] <= joy_data[1];
joy1_data_out[1] <= joy_data[2];
joy2_data_out[1] <= joy_data[3];
// Неиспользуемые выводы оставляем в высокоимпедансном состоянии, они подтягиваются к VCC внутри самой консоли
joy2_data_out[4:2] <= 3'bZZZ;
end
Самым сложным оказалось сделать возможность менять местами кнопки A и B, ведь считываются они последовательно, т.е. нужно заранее знать значение B, когда консоль запрашивает A, но оно выдаётся как раз только после A. Сначала я думал как-то ускоренно считывать данные с контроллера, используя какой-то внешний тактовый генератор, но в итоге решил просто брать значение от предыдущего считывания. Это даёт задержку, но она абсолютно незаметна. Тем более игры обычно читают состояние кнопок по несколько раз подряд.
Само собой, все эти режимы и настройки надо как-то задавать. Для этого я определил 12-битный регистр control, данные в который записываются через последовательное соединение, с дополнительным битом для проверки чётности:
reg [11:0] control;
reg control_parity;
reg [11:0] control_receiver;
reg [3:0] control_counter;
always @ (posedge control_strobe, posedge control_clock)
begin
if (control_strobe)
begin
control_counter = 0;
control_parity = 0;
end else begin
if (control_counter <= 11)
begin
control_receiver[control_counter] = control_data;
control_parity = control_parity ^ control_data;
end;
if (control_counter < 12)
control_counter = control_counter + 1;
end
end
always @ (posedge strobe_in)
begin
if (control_counter == 12 && !control_parity)
control = control_receiver;
end
Соответственно со стороны микроконтроллера код (весьма грязный) выглядит вот так:
void control_send(uint16_t data)
{
set_bit(CTRL_PORT, CTRL_STROBE_PIN); // Strobe
_delay_us(10);
unset_bit(CTRL_PORT, CTRL_STROBE_PIN); // Strobe
_delay_us(10);
int b;
char parity = 0;
for (b = 0; b < 11; b++)
{
if (data & (1<<b))
{
set_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
parity ^= 1;
} else {
unset_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
}
unset_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
_delay_us(10);
set_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
_delay_us(10);
}
if (parity)
{
set_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
} else {
unset_bit(CTRL_PORT, CTRL_DATA_PIN); // Data
}
unset_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
_delay_us(10);
set_bit(CTRL_PORT, CTRL_CLOCK_PIN); // Clock
_delay_us(10);
}
В остальном в коде микроконтроллера нет ничего особенного: работа с дисплеем на контроллере HD44780, кнопки, светодиоды, простенькая менюшка и работа с аналого-цифровой преобразователем для определения угла поворота ручки.
Я всё отладил, убедился в работоспособности и уже начал упихивать компоненты в корпус…
Но перед закрытием крышки решил проверить на оригинальном Famicom, ведь с ним устройство тоже будет использоваться. Увы, режимы, где нужно было считать импульсы clock, работали неправильно. С помощью логического анализатора выяснилось, что с линии данных идут наводки на линию clock:
Это помеха длительностью всего в несколько десятков наносекунд всё портит. Я решил посмотреть своим простеньким осциллографом, что же происходит на линии clock у Денди:
А вот что там же у Фамикома:
Видно, что эта линия подтянута к VCC, при чём очень сильно у Денди и весьма слабо у оригинального Фамикома. Я начал экспериментировать с обвеской. Вскоре стало ясно, что на результат лучше смотреть не логическим анализатором, а самой консолью. Пришлось вспоминать ассемблер для 6502 процессора, писать простенькую программу для тестирования и записать её на картридж:
На ней сразу стало всё наглядно видно, а заодно можно было протестировать сразу все режимы, не меняя игры. ROM можно скачать тут.
В итоге проблема была решена подтяжкой линий clock к VCC через резистор в 1кОм, конденсатором между clock и землёй в 22нФ и резисторами на 200 Ом в разрыв всех линий данных. Увы, пришлось травить новую плату (не фотографировал), но зато после этого сразу же всё заработало.
Итоговый вид устройства:
Во времена СССР я мог бы быть хорошим промдизайнером.
Многие наверное захотят увидеть видео, но на данный момент подарок уже в руках нашей почты, а я снял только небольшую видеоинструкцию для конечного пользователя. Посмотреть её можно тут: www.youtube.com/watch?v=39beci7nE8w
И если вас заинтересовала тематика работы разных игровых контроллеров и создания самодельных, мы как раз на эту тему сняли вторую серию нашего шоу «Пока все играют», где многое очень просто и наглядно объясняется для тех, кто совсем не в теме:
Информация по архитектуре этих консолей и аксессуаров бралась с сайта wiki.nesdev.com
Полный код для ПЛИС на Verilog: pastebin.com/nt39ZGvH
Комментарии (31)
Mixim333
21.06.2015 18:58+1Спасибо, вспомнил детство. У самого Dendy не было, лет в 6 за какие-то за слуги на ДР мне подарили SegaMegaDrive2 (SMG2), который через неделю после истечения гарантии сдох. Через пару лет, после моих слез, привезли из Китая новую SMG2, который, по-моему, до сей поры жив. До сей поры помню игру Dune 2 — даже на ПК ни одна игра меня так не цепляла!
ClusterM, ни могли бы подсказать, в те годы у однокашника была Dendy-совместимая приставка, которая по форм-фактору представляла из себя «клавиатуру», вместе с приставкой шла «касета» с различными программами, вроде текстового редактора и прочих, что это за чудо могло быть?docker1
21.06.2015 19:49У меня есть такая — киборд 003 называется. Правда она начала сбоить лет 10 назад, насколько помню, что-то с блоком питания случилось плюс постоянно отходил контакт там, где картридж вставлялся. А картридж, идущий в комплекте, был по-своему интересен. Там были текстовый редактор аля Word, электронная таблица аля Excel, обучение вычислениям в столбик, клавиатурные тренажеры, игра «Архитектор», где можно было строить дома, пасьянс «Косынка», и т. д. Ну и, разумеется, можно было играть во всякие Super Mario Bros и Battletoads, был бы картридж.
Mixim333
21.06.2015 20:40Очень напоминает и картридж был с примерно таким же набором программ, но все равно не то, хотя за 15 лет я мог уже забыть, как в точности выглядела приставка. Помню лишь, что была черного цвета и что привозили ее, также как и мою вторую SMD2, из Китая
shpaker
22.06.2015 07:03А в какие игры вчетвером можно было играть?
ClusterM
22.06.2015 07:21+2Тут полный список: en.wikipedia.org/wiki/NES_Four_Score
Самые интересные: «R.C. Pro-Am II», «Bomberman 2», «Gauntlet II». Есть ещё хак «Battle City» на четверых.
datacompboy
21.06.2015 18:33+1Кстати, а нету ли (случайно) способа заставить световой пистолет работать на ЖКхах?
ClusterM Автор
21.06.2015 19:01+1Есть, но это весьма сложно — надо как-то отслеживать положение пистолета в пространстве и обрабатывать видеосигнал в реальном времени.
datacompboy
21.06.2015 19:07+1Насколько помню, оригинальный пистолет просто ловил момент, когда от начала кадра «видел» квадрат (если видел).
Современные 4нс грей-грей мониторы вполне могут выдать картинку так же быстро, но надо корректировать задержку.
Вопрос — можно ли откалибровать его (например, выстрелом в центр пару раз) под монитор, после чего пользовать?ClusterM Автор
21.06.2015 19:11+1Да, он просто реагирует на свет от экрана. Проблема в том, что игра требует мгновенного получения ответа, тут задержку если только каким-то хитрым хаком игры делать. Более того, некоторые игры вроде как учитывают текущее положение луча на кинескопе, т.е. какая строка выводится на экран в данный момент.
datacompboy
22.06.2015 10:39цитирую Андрея:
Сейчас есть аналоги пистолетов для же дисплеев.
Если интересно, то посмотрите как работает guncon 3 для PS3.
Там в комплекте два инфракрасных диодных фонарика, которые нужно закрепить в углах телевизора, а пистолет их отслеживает.
И вот аналогичный проект сразу для pc www.arcadeguns.com/index.php?main_page=indexClusterM Автор
22.06.2015 15:46Мы с ним уже списались. Описанную выше задачу это не решает, для трекинга можно использовать обычный виимоут.
HardWrMan
23.06.2015 15:57Для получения координат «стрельбы» используйте вимоут (со всеми калибровками и прочим). Для передачи этой «координаты» берите выходной видеосигнал, прогоняйте ее через плисину, и по нажатию на триггер формируйте компаратор «освещенности» в видеосигнале на требуемых строке/ах в капчурным видеосигнале. Данный метод будет работать 100% во всех случаях, даже в VGA дендике, который я купил и потрошу: forums.nesdev.com/viewtopic.php?f=9&t=12578#p149155
PS Этот же метод легко адаптируем под Сегу.ClusterM Автор
23.06.2015 17:54Я ещё не умею работать с выходным сигналом :) Но похоже, что скоро придётся (для других целей).
Mixim333
21.06.2015 18:58+1Спасибо, вспомнил детство. У самого Dendy не было, лет в 6 за какие-то за слуги на ДР мне подарили SegaMegaDrive2 (SMG2), который через неделю после истечения гарантии сдох. Через пару лет, после моих слез, привезли из Китая новую SMG2, который, по-моему, до сей поры жив. До сей поры помню игру Dune 2 — даже на ПК ни одна игра меня так не цепляла!
ClusterM, ни могли бы подсказать, в те годы у однокашника была Dendy-совместимая приставка, которая по форм-фактору представляла из себя «клавиатуру», вместе с приставкой шла «касета» с различными программами, вроде текстового редактора и прочих, что это за чудо могло быть?docker1
21.06.2015 19:49У меня есть такая — киборд 003 называется. Правда она начала сбоить лет 10 назад, насколько помню, что-то с блоком питания случилось плюс постоянно отходил контакт там, где картридж вставлялся. А картридж, идущий в комплекте, был по-своему интересен. Там были текстовый редактор аля Word, электронная таблица аля Excel, обучение вычислениям в столбик, клавиатурные тренажеры, игра «Архитектор», где можно было строить дома, пасьянс «Косынка», и т. д. Ну и, разумеется, можно было играть во всякие Super Mario Bros и Battletoads, был бы картридж.
Mixim333
21.06.2015 20:40Очень напоминает и картридж был с примерно таким же набором программ, но все равно не то, хотя за 15 лет я мог уже забыть, как в точности выглядела приставка. Помню лишь, что была черного цвета и что привозили ее, также как и мою вторую SMD2, из Китая
shpaker
22.06.2015 07:03А в какие игры вчетвером можно было играть?
ClusterM Автор
22.06.2015 07:21+2Тут полный список: en.wikipedia.org/wiki/NES_Four_Score
Самые интересные: «R.C. Pro-Am II», «Bomberman 2», «Gauntlet II». Есть ещё хак «Battle City» на четверых.
ncix
23.06.2015 11:17+1У меня был клон в виде летающей тарелки, вроде этой:
Только пистолет был немного иной, и, самое любопытное, один из гемпадов был беспроводной инфракрасный! Правда, работал он похуже проводного, подглючивал.HardWrMan
23.06.2015 16:00+1Был у меня именно такой клон, и эти джойстики рука еще помнит, но они, к сожалению, 90е не пережили. Но крестовину пришлось продублировать на 4 кнопки для прохождения Clinger Winger в Battletoads.
darkfrei
23.06.2015 20:04Тоже была летающая тарелка, в детстве сильно впечатляла уникальность внешнего вида. В комплекте был черный картдридж похожего дизайна с 99 (999?) играми.
Knakl
23.06.2015 12:06супер челенжем было бы подключение беспроводных джойстиков ( blutooth например) к фамикому \ снесику. Или того же пада от вии\вию.
esher
23.06.2015 14:14Насколько помню, в начале 90х сам подключал 3 и 4 джойстики для японских игр, и возни было гораздо меньше — вывел на корпус два DIN-5, и распаял два джойстика на DIN-5. А распиновка была такой-же как и на 1-2 джойстики за исключением замены одной линии, адресной, как теперь понятно по схеме, тогда же я наткнулся на это случайно, замкнув пару выводов при поиске пропавшего контакта в джойстике.
ClusterM Автор
23.06.2015 17:53Так я же в статье и написал, что они подключаются напрямую, без всякой схемы. У меня ПЛИС их напрямую коммутирует, просто нужно же ещё режимы выбирать.
datacompboy
Кстати, а нету ли (случайно) способа заставить световой пистолет работать на ЖКхах?
ClusterM
Есть, но это весьма сложно — надо как-то отслеживать положение пистолета в пространстве и обрабатывать видеосигнал в реальном времени.
datacompboy
Насколько помню, оригинальный пистолет просто ловил момент, когда от начала кадра «видел» квадрат (если видел).
Современные 4нс грей-грей мониторы вполне могут выдать картинку так же быстро, но надо корректировать задержку.
Вопрос — можно ли откалибровать его (например, выстрелом в центр пару раз) под монитор, после чего пользовать?
ClusterM
Да, он просто реагирует на свет от экрана. Проблема в том, что игра требует мгновенного получения ответа, тут задержку если только каким-то хитрым хаком игры делать. Более того, некоторые игры вроде как учитывают текущее положение луча на кинескопе, т.е. какая строка выводится на экран в данный момент.
datacompboy
цитирую Андрея:
Сейчас есть аналоги пистолетов для же дисплеев.
Если интересно, то посмотрите как работает guncon 3 для PS3.
Там в комплекте два инфракрасных диодных фонарика, которые нужно закрепить в углах телевизора, а пистолет их отслеживает.
И вот аналогичный проект сразу для pc www.arcadeguns.com/index.php?main_page=index