Написание Эмулятора Gameboy, Часть 2

Привет! В предыдущей части этой серии статей мы рассмотрели процессор и память DMG. Следующим логическим шагом является эмуляция того, как DMG выводит изображение.

Написание эмулятора Gameboy, часть 1 Написание эмулятора Gameboy, часть 2 Написание эмулятора Gameboy, часть 3



Оглавление

Отображать Таймеры Контроль Собираем все это вместе Тестирование Заключение

Отображать

На этом этапе нам нужно эмулировать, как DMG отображает изображение на экране.

Все будет в классе Cookieboy::GPU ( связь к исходному коду Cookieboy).

Задачу можно разделить на две большие части — эмуляция специфики того, как DMG рисует картинку; эмуляция логики, управляющей экраном.



ЖК-контроллер.

Теория

Начнем с логики, поскольку именно она будет определять, когда и что мы будем рисовать.

Как всегда, перед реализацией нам нужно понять, как работает компонент. DMG отображает изображение на экране построчно и эмулирует состояния, характерные для экранов ЭLT. Каждое состояние длится строго определенное количество циклов.

Это необходимо для обеспечения доступа к памяти.

Для рендеринга графики необходим доступ к видеопамяти и ОАМ сразу в двух местах — контроллере ЖК-дисплея, который отображает все на экране; игра (ЦП), которая модифицирует память для вывода нужного ей кадра.

Для решения этой проблемы вся задача вывода графики была разбита на интервалы (каждый соответствует определенному состоянию), определяющие время, в течение которого логика экрана или игра могут обращаться к памяти.

Всего состояний четыре (числа не случайные, а строго определенные для DMG):

  • 0. H-пробел.

    Для экранов ЭLT это означает, что в этот момент сканирующий луч перемещается в начало следующей строки.

    Никаких лучей у ДМГ, естественно, нет. Это состояние означает две вещи.

    Сначала была напечатана одна строка.

    Во-вторых, видеопамять и OAM не используются контроллером ЖК-дисплея и доступны ЦП.

  • 1. V-заготовка.

    Еще одно состояние из мира ЭLT, означающее момент, когда луч достиг конца последней строки и переходит в начало первой строки.

    Для нас это означает две вещи.

    Сначала были напечатаны все 144 видимые строки.

    Во-вторых, видеопамять и OAM не используются контроллером ЖК-дисплея и доступны ЦП.

  • 2. ОАМ.

    Это состояние означает, что контроллер ЖК-дисплея использует память OAM. Она недоступна для ЦП, но видеопамять все еще доступна.

  • 3. ОАМРАМ.

    Это состояние означает, что контроллер ЖК-дисплея использует OAM и видеопамять.

    Они недоступны процессору.

По мере рисования каждой линии ЖК-контроллер проходит состояния в следующем порядке — 2, 3, 0. После рисования последней строки он переходит в состояние 1. Далее все начинается снова с первой строки.

На рисование одной линии уходит ровно 456 тактов.

Это время представляет собой сумму длительности состояний 2, 3, 0 и всегда равно 456 циклам, однако длительность самих состояний может варьироваться.

Поскольку на экране 144 строки, их вывод занимает 65664 такта.

Состояние 1 длится ровно 4560 тактов.

На рисунке видно, что это время равно 10 строкам.

Это действительно так – в состоянии 1 как будто рисуется еще 10 линий.

Счетчик строк (регистр LY) не останавливается на 143, а идет до 153. В результате полное обновление экрана занимает 70224 такта или 154 строки по 456 тактов.

Переход между состояниями сопровождается запросами прерываний, если они разрешены.

Переход в каждое из четырех состояний, кроме третьего, сопровождается запросом прерывания LCDC. Кроме того, это прерывание запрашивается, если LY и LYC равны.

Запрос выполняется только в том случае, если в регистре STAT разрешено прерывание LCDC для этого состояния.

Его структура выглядит следующим образом:

Биты Цель
6 Включить прерывание LCDC, если регистры LY и LYC равны.

5 Включить прерывание LCDC при переходе в состояние 2
4 Включить прерывание LCDC при переходе в состояние 1
3 Включить прерывание LCDC при переходе в состояние 0
2 Бит устанавливается, если LY и LYC равны.

Сбросить в противном случае

0-1 Текущее состояние
Важная деталь заключается в том, что прерывание LCDC может быть запрошено только один раз для каждой строки.

Многое из этого можно было бы почерпнуть из Руководства ЦП, но есть одно обстоятельство — это далеко не все, что нужно знать о работе контроллера ЖК-дисплея для его эмуляции.

Я не стал вдаваться во все детали (фактически я их и не нашел), а просто сосредоточился на том, что позволяет мне корректно отображать графику в тестируемых мной играх и при этом проходить тест ЖК-контроллера.

Чтобы хотя бы грубо эмулировать контроллер, нам придется ввести еще один набор состояний — внутренний, доступный только нашему эмулятору.

Всего их 8:

   

enum InternalLCDModes {

Теги: #эмулятор #gameboy #DMG #C++ #Разработка сайтов #программирование
Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.