Пишем эмулятор приставки ч2, или немного о CHIP16

    В предыдущей своей небольшой заметке я описывал принцип построения эмулятора старой игровой платформы CHIP-8 из далеких 70-х. Здесь же речь пойдет о своего рода наследнице – CHIP16. Итак, что же такое CHIP16?

    CHIP16 – “вымышленная” игровая приставка, которой никогда не существовало в “железе”. Всю спецификацию на нее разрабатывали (-ют) энтузиасты с одного англоязычного форума. Смысл в том, чтобы максимально упростить написание эмулятора, иметь хорошую документацию и поддержку комьюнити. Тем самым позволяя даже новичкам в программировании создать полностью рабочий эмулятор с нуля на фактически любом языке программирования. Сразу оговорюсь, что здесь я не буду приводить примеры кода эмулятора, цель – просто рассказать об этой платформе. И да, конечно все Just for fun!


    Предыстория


    А все началось где-то в 2010 году, с тех пор спецификация приобрела номер версии 1.1, основные недочёты были устранены, были написаны основные инструменты для создания игр и других программ под эту платформу (ассемблер, отладчик, конвертер изображений и прочее). Основное отличие от той-же CHIP-8 это наличие большего разрешения экрана, большего количества цветов, большего количества арифметических и других инструкций, улучшенной поддержки звукового сопровождения и отсутствие недокументированных фич.

    Приставка имеет 16-ти разрядный процессор, память, два устройства ввода (джойстики типа Dendy), звуковую и видео подсистему. Рассмотрим всю эту кучу подробнее.

    Процессор

    Процессор включает:
    • Один 16-разрядный счетчик команд (PC)
    • Один 16-разрядный указатель стека (SP)
    • Шестнадцать 16-разрядных регистра общего назначения (R0 – RF)
    • Один 8-разрядный регистр флагов

    Выполнение каждого опкода (команды процессора) занимает ровно один цикл, процессор работает на частоте 1 Mhz. Здесь я оговорюсь, что на самом деле, пока частота не ясна до конца, и каждый выполняет на эмуляторе команды быстрее, чем 1 Mhz. Иногда с максимальной скоростью эмуляции. В общем пока можно не заморачиваться по этому поводу.

    Память

    Всего 64Kb (65536 байт). Память распределяется следующим образом:
    0x0000 – Начало бинарных данных
    0xFDF0 – Начало стека (512 байт).
    0xFFF0 – Порты ввода/вывода (I/O, для отслеживания состояния джойстиков).

    Видео

    Разрешение экрана 320x240 пикселей. Одновременное количество отображаемых цветов – 16 из стандартной палитры.
    Индекс в палитре Шестнадцат. значение Цвет
    0x0 0x000000 Черный, прозрачный на слое фона
    0x1 0x000000 Черный
    0x2 0x888888 Серый
    0x3 0xBF3932 Красный
    0x4 0xDE7AAE Розовый
    0x5 0x4C3D21 Темно-коричневый
    0x6 0x905F25 Коричневый
    0x7 0xE49452 Оранжевый
    0x8 0xEAD979 Желтый
    0x9 0x537A3B Зеленый
    0xA 0xABD54A Светло-зеленый
    0xB 0x252E38 Темно-синий
    0xC 0x00467F Синий
    0xD 0x68ABCC Светло-синий
    0xE 0xBCDEE4 Sky blue
    0xF 0xFFFFFF Белый

    Есть возможность устанавливать собственную цветовую палитру. Частота обновления экрана 60 кадров в секунду, при этом каждый кадр выставляется внутренний флаг Vblank (через каждые ~16ms). Процессор имеет возможность ожидать завершения отрисовки кадра с помощью инструкции VBLNK. Изображение формируется из спрайтов, прямого доступа к видеопамяти нет. Помимо основного слоя, где рисуются спрайты, присутствует слой фона, который заполняет весь экран одним из 16-ти цветов.

    Экран зеркально не отображается, таким образом все, что не влезло в физические координаты – остается за экраном и не отображается. Из этого следует, что спрайты могут иметь отрицательные координаты (либо превышающие 320x200). Если взять спрайт 4x4 пикселя и, к примеру, отдать команду нарисовать его по координатам (-2,-2), то в верхнем левом углу экрана отобразиться часть спрайта размером 2x2 пикселя.

    Так, как всего возможных цветов в палитре 16, то чтобы закодировать одну точку на экране необходимо 4 бита. Один байт является блоком из двух точек. Минимальный спрайт состоит из одного байта – это спрайт размером 2x1 (две точки). Давайте для примера посмотрим как закодировать спрайт размером 8x5 пикселей, если учесть что белый цвет в стандартной палитре это цвет с индексом 0xFh, а черный — с индексом 0x1h

    Итого, 20 байт. То есть (8 x 5) / 2 = 20

    Если новый спрайт перекрывает любые уже существующие пиксели на экране (за исключением пикселей с нулевым цветом – они прозрачны), то устанавливается флаг переполнения (carry flag). Таким образом, можно отслеживать столкновения и коллизии объектов на экране в играх.
    Для назначения собственной цветовой палитры вместо стандартной существует специальная команда процессора PAL. Каждый цвет палитры состоит из 3-х байт, в формате RGB. Так как используется всего 16 цветов, то команда PAL прочитает из памяти массив в 48 байт и назначит RGB компоненты цветам с индексами 0x0, 0x1,..,0xF. Палитра сменяется после получения процессором команды VBLNK.

    Звук

    В начальных версиях присутствовала возможность проигрывать только три фиксированных тона (500Hz, 1000Hz, 1500Hz) определенное количество миллисекунд, но затем добавилась возможность использовать звуковой генератор типа ADSR

    Устройства ввода (джойстики)

    Доступ к информации с джойстиков осуществляется посредством отображаемых в памяти портов ввода-вывода. Первый джойстик по адресу 0xFFF0, второй – 0xFFF2.
    Bit[0] – Up (Вверх)
    Bit[1] — Down (Вниз)
    Bit[2] — Left (Влево)
    Bit[3] — Right (Вправо)
    Bit[4] — Select (Выбор)
    Bit[5] — Start (Старт)
    Bit[6] — A
    Bit[7] — B
    Bit[8 — 15] — Не используются, всегда равны нулю.

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

    Формат файлов-образов (ROM-файлов)

    ROM файл (стандартное расширение .c16) содержит в себе заголовок и бинарные данные сразу после заголовка. Информация из заголовка может быть использована для определения версии спецификации и пр. Заголовок имеет постоянный размер 16 байт. Его формат:
    Смещение Назначение
    0x00 Магическое число 'CH16'
    0x04 Зарезервированно
    0x05 Версия спецификации (первые 4 бита=главная версия, вторые 4 бита=подверсия, т.е 0.7 = 0x07 и 1.0 = 0x10)
    0x06 Размер ROM-файла (не включая заголовок, в байтах)
    0x0A Начальный адрес (Значение счетчика команд PC)
    0x0C CRC32 контрольная сумма (не включая заголовок, полином = 0x04c11db7)

    Сразу за ним начинаются бинарные данные, которые всегда должны быть прочитаны в память начиная с адреса 0x0000. Счетчик команд должен быть установлен в соответствии со значением в заголовке. Как правило это 0x0000.

    ROM-файлы могут и не иметь заголовка вовсе, так как он был введен в спецификацию сравнительно недавно.

    Регистр флагов

    Bit[0] Зарезервирован
    Bit[1] c — carry flag (беззнаковое переполнение)
    Bit[2] z — zero flag
    Bit[3] Зарезервирован
    Bit[4] Зарезервирован
    Bit[5] Зарезервирован
    Bit[6] o — Overflow (переполнение чисел со знаком)
    Bit[7] n — negative (флаг отрицательного знака)


    Типы условий для команд условного перехода

    Условия используются для команд условного перехода (прыжков) или команд условного вызова подпрограмм. К примеру: «jle метка» или «cno some_label2». В квадратных скобках приводится состояние флагов, когда условие срабатывает.
    Z 0x0 [z==1] Equal (Zero)
    NZ 0x1 [z==0] Not Equal (Non-Zero)
    N 0x2 [n==1] Negative
    NN 0x3 [n==0] Not-Negative (Positive or Zero)
    P 0x4 [n==0 && z==0] Positive
    O 0x5 [o==1] Overflow
    NO 0x6 [o==0] No Overflow
    A 0x7 [c==0 && z==0] Above (Unsigned Greater Than)
    AE 0x8 [c==0] Above Equal (Unsigned Greater Than or Equal)
    B 0x9 [c==1] Below (Unsigned Less Than)
    BE 0xA [c==1 || z==1] Below Equal (Unsigned Less Than or Equal)
    G 0xB [o==n && z==0] Signed Greater Than
    GE 0xC [o==n] Signed Greater Than or Equal
    L 0xD [o!=n] Signed Less Than
    LE 0xE [o!=n || z==1] Signed Less Than or Equal


    Так же можно использовать альтернативные мнемоники:
    NC 0x8 [c==0] Not Carry (Same as AE)
    C 0x9 [c==1] Carry (Same as B)


    Команды процессора

    Любой опкод CHIP16 занимает ровно 4 байта (32 бита).
    HH — старший байт.
    LL — младший файт.
    N — nibble (4х-битное значение).
    X, Y, Z — 4х-битный идентификатор регистра.

    Опкод Мнемоника Использование
    00 00 00 00 NOP Нет операции, просто один цикл процессора
    01 00 00 00 CLS Очистка экрана (основной слой очищается, цвет фона устанавливается в цвет с индексом 0)
    02 00 00 00 VBLNK Ожидать вертикальной синхронизации. Если кадр не успел отрисоваться, то PC-=4
    03 00 0N 00 BGC N Установить цвет фона с индексом N. Если индекс равен 0, то цвет фона — черный
    04 00 LL HH SPR HHLL Установить размер спрайта: ширину (LL) и высоту (HH)
    05 YX LL HH DRW RX, RY, HHLL Нарисовать спрайт из адреса в памяти HHLL по координатам, заданным в регистрах X и Y. Результат влияет на carry flag
    06 YX 0Z 00 DRW RX, RY, RZ Нарисовать спрайт из адреса в памяти, на который указывает регистр Z по координатам, заданным в регистрах X и Y. Результат влияет на carry flag
    07 0X LL HH RND RX, HHLL Поместить случайное число в регистр X. Максимальное значение задается HHLL
    08 00 00 00 FLIP 0, 0 Задать ориентацию отображения спрайта. Горизонтальный переворот = НЕТ, вертикальный переворот = НЕТ
    08 00 00 01 FLIP 0, 1 Задать ориентацию отображения спрайта. Горизонтальный переворот = НЕТ, вертикальный переворот = ДА
    08 00 00 02 FLIP 1, 0 Задать ориентацию отображения спрайта. Горизонтальный переворот = ДА, вертикальный переворот = НЕТ
    08 00 00 03 FLIP 1, 1 Задать ориентацию отображения спрайта. Горизонтальный переворот = ДА, вертикальный переворот = ДА
    09 00 00 00 SND0 Остановить воспроизведение звука
    0A 00 LL HH SND1 HHLL Воспроизводить 500Hz тон HHLL миллисекунд
    0B 00 LL HH SND2 HHLL Воспроизводить 1000Hz тон HHLL миллисекунд
    0C 00 LL HH SND3 HHLL Воспроизводить 1500Hz тон HHLL миллисекунд
    0D 0X LL HH SNP RX, HHLL Воспроизводить звуковой тон в течении HHLL миллисекунд, в соответствии с текущим звуковым генератором, заданным по адресу HHLL
    0E AD SR VT SNG AD, VTSR Звуковой генератор ADSR
    A = attack (0..15)
    D = decay (0..15)
    S = sustain (0..15, volume)
    R = release (0..15)
    V = volume (0..15)
    T = type of sound:
    • 00 = triangle wave
    • 01 = sawtooth wave
    • 02 = pulse wave (is just square for now)
    • 03 = noise
    • При неправильных значениях звук не воспроизводится


    10 00 LL HH JMP HHLL Перейти на указанный адрес HHLL
    12 0x LL HH Jx HHLL Перейти на указанный адрес HHLL с учетом условия 'x'. (см. Типы условий)
    13 YX LL HH JME RX, RY, HHLL Перейти на указанный адрес HHLL если регистр X равен регистру Y
    16 0X 00 00 JMP RX Перейти на адрес, заданный в регистре X
    14 00 LL HH CALL HHLL Вызвать подпрограмму по адресу HHLL. Сохраняет PC в [SP], увеличивает SP на 2
    15 00 00 00 RET Возврат из подпрограммы. Уменьшает SP на 2 и восстанавливает PC из [SP]
    17 0x LL HH Cx HHLL Если выполняется условие 'x', тогда вызов подпрограммы. (см. Типы условий)
    18 0X 00 00 CALL RX Вызвать подпрограмму по адресу, находящемуся в регистре X. Сохраняет PC в [SP], увеличивает SP на 2
    20 0X LL HH LDI RX, HHLL Поместить в регистр X непосредственное значение HHLL
    21 00 LL HH LDI SP, HHLL Установить указатель стека на адрес HHLL. Не перемещает старые значения в стеке на новый адрес
    22 0X LL HH LDM RX, HHLL Поместить в регистр X 16-битное значение из памяти по адресу HHLL
    22 YX 00 00 LDM RX, RY Поместить в регистр X 16-битное значение из памяти по адресу, на который указывает регистр Y
    24 YX 00 00 MOV RX, RY Скопировать значение регистра Y в регистр X
    30 0X LL HH STM RX, HHLL Сохранить значение регистра X в памяти по адресу HHLL
    31 YX 00 00 STM RX, RY Сохранить значение регистра X в памяти по адресу, находящемуся в регистре Y
    40 0X LL HH ADDI RX, HHLL Добавить непосредственное значение HHLL к регистру X. Влияет на флаги [c,z,o,n]
    41 YX 00 00 ADD RX, RY Добавить значение регистра Y к регистру X. Результат помещается в регистр X. Влияет на флаги [c,z,o,n]
    42 YX 0Z 00 ADD RX, RY, RZ Добавить значение регистра Y к регистру X. Результат помещается в регистр Z. Влияет на флаги [c,z,o,n]
    50 0X LL HH SUBI RX, HHLL Вычесть непосредственное значение HHLL из регистра X. Результат в регистре X. Влияет на флаги [c,z,o,n]
    51 YX 00 00 SUB RX, RY Вычесть значение регистра Y из регистра X. Результат помещается в регистр X. Влияет на флаги [c,z,o,n]
    52 YX 0Z 00 SUB RX, RY, RZ Вычесть значение регистра Y из регистра X. Результат помещается в регистр Z. Влияет на флаги [c,z,o,n]
    53 0X LL HH CMPI RX, HHLL Вычесть непосредственное значение HHLL из регистра X. Результат не сохраняется. Влияет на флаги [c,z,o,n]
    54 YX 00 00 CMP RX, RY Вычесть значение регистра Y из регистра X. Результат не сохраняется. Влияет на флаги [c,z,o,n]
    60 0X LL HH ANDI RX, HHLL Логическая операция 'И' непосредственного значения HHLL к регистру X. Результат в регистре X. Влияет на флаги [z,n]
    61 YX 00 00 AND RX, RY Логическая операция 'И' значения в регистре Y к регистру X. Результат помещается в регистр X. Влияет на флаги [z,n]
    62 YX 0Z 00 AND RX, RY, RZ Логическая операция 'И' значения в регистре Y к регистру X. Результат помещается в регистр Z. Влияет на флаги [z,n]
    63 0X LL HH TSTI RX, HHLL Логическая операция 'И' непосредственного значения HHLL к регистру X. Результат не сохраняется. Влияет на флаги [z,n]
    64 YX 00 00 TST RX, RY Логическая операция 'И' значения в регистре Y к регистру X. Результат не сохраняется. Влияет на флаги [z,n]
    70 0X LL HH ORI RX, HHLL Логическая операция 'ИЛИ' непосредственного значения HHLL к регистру X. Результат в регистре X. Влияет на флаги [z,n]
    71 YX 00 00 OR RX, RY Логическая операция 'ИЛИ' значения в регистре Y к регистру X. Результат помещается в регистр X. Влияет на флаги [z,n]
    72 YX 0Z 00 OR RX, RY, RZ Логическая операция 'ИЛИ' значения в регистре Y к регистру X. Результат помещается в регистр Z. Влияет на флаги [z,n]
    80 0X LL HH XORI RX, HHLL Логическая операция 'XOR' непосредственного значения HHLL к регистру X. Результат в регистре X. Влияет на флаги [z,n]
    81 YX 00 00 XOR RX, RY Логическая операция 'XOR' значения в регистре Y к регистру X. Результат помещается в регистр X. Влияет на флаги [z,n]
    82 YX 0Z 00 XOR RX, RY, RZ Логическая операция 'XOR' значения в регистре Y к регистру X. Результат помещается в регистр Z. Влияет на флаги [z,n]
    90 0X LL HH MULI RX, HHLL Умножение непосредственного значения HHLL на регистр X. Результат в регистре X. Влияет на флаги [c,z,n]
    91 YX 00 00 MUL RX, RY Умножение значения в регистре Y на регистр X. Результат помещается в регистр X. Влияет на флаги [c,z,n]
    92 YX 0Z 00 MUL RX, RY, RZ Умножение значения в регистре Y на регистр X. Результат помещается в регистр Z. Влияет на флаги [c,z,n]
    A0 0X LL HH DIVI RX, HHLL Деление регистра X на непосредственное значение HHLL. Результат в регистре X. Влияет на флаги [c,z,n]
    A1 YX 00 00 DIV RX, RY Деление регистра X на значение в регистре Y. Результат помещается в регистр X. Влияет на флаги [c,z,n]
    A2 YX 0Z 00 DIV RX, RY, RZ Деление регистра X на значение в регистре Y. Результат помещается в регистр X. Влияет на флаги [c,z,n]
    B0 0X 0N 00 SHL RX, N Логический сдвиг значения в регистре X влево N-раз. Влияет на флаги [z,n]
    B1 0X 0N 00 SHR RX, N Логический сдвиг значения в регистре X вправо N-раз. Влияет на флаги [z,n]
    B0 0X 0N 00 SAL RX, N Арифметический сдвиг значения в регистре X влево N-раз. Влияет на флаги [z,n]. Аналогична команде SHL
    B2 0X 0N 00 SAR RX, N Арифметический сдвиг значения в регистре X вправо N-раз. Влияет на флаги [z,n]
    B3 YX 00 00 SHL RX, RY Логический сдвиг значения в регистре X влево на значение, находящееся в регистре Y. Влияет на флаги [z,n]
    B4 YX 00 00 SHR RX, RY Логический сдвиг значения в регистре X вправо на значение, находящееся в регистре Y. Влияет на флаги [z,n]
    B3 YX 00 00 SAL RX, RY Арифметический сдвиг значения в регистре X влево на значение, находящееся в регистре Y. Влияет на флаги [z,n]. Аналогична команде SHL
    B5 YX 00 00 SAR RX, RY Арифметический сдвиг значения в регистре X вправо на значение, находящееся в регистре Y. Влияет на флаги [z,n]
    C0 0X 00 00 PUSH RX Поместить значение регистра X в стек. Увеличивает SP на 2
    C1 0X 00 00 POP RX Уменьшает SP на 2. Восстановить значение регистра X из стека.
    C2 00 00 00 PUSHALL Сохранить значения всех регистров общего назначения (r0-rf) в стеке. Увеличивает SP на 32
    C3 00 00 00 POPALL Уменьшает SP на 32. Восстановить значения всех регистров общего назначения (r0-rf) из стека.
    C4 00 00 00 PUSHF Сохранить состояние регистра флагов в стеке. Биты 0-7 основные флаги, биты 8-15 пусты (всегда ноль). Увеличивает SP на 2
    C5 00 00 00 PUSHF Уменьшает SP на 2. Восстановить состояние регистра флагов из стека
    D0 00 LL HH PAL HHLL Загрузить палитру находящуюся по адресу HHLL, 16*3 байт, RGB-формат; начнет действовать сразу после последнего VBlank
    D1 0x 00 00 PAL Rx Загрузить палитру находящуюся по адресу в регистре X, 16*3 байт, RGB-формат; начнет действовать сразу после последнего VBlank


    Где почитать подробнее, как «пощупать»?

    Почитать подробнее можно, как я уже говорил, на англоязычном форуме.
    Первая (и уже устаревшая и закрытая) тема с обсуждением CHIP16
    Вторая тема с обсуждением (основная). Здесь вся информация собирается в первом посте темы. Там спецификация, инструменты, примеры программ. Нужна регистрация, что бы что-то скачивать с форума.

    Хороший эмулятор RefCHIP16: code.google.com/p/refchip16/downloads/list Исходники на Си++, имеется возможность как простой интерпретации, так и AOT (Ahead Of Time) компиляции, что несомненно доставляет. Пожалуй единственный нормальный эмулятор, который корректно обрабатывает спецификацию 1.1 (в особенности ADSR звук).

    Немного устаревший набор игр, демок и тестовых образов для CHIP16. Там же исходники на ассемблере для большинства программ: rghost.ru/38862474 Новые игры и программы выкладываются в теме на форуме.

    Разработка

    Программы и игры для CHIP16 пока в подавляющем большинстве пишутся на ассемблере. Скачать его можно здесь: code.google.com/p/tchip16/downloads/list Для примера, возьмем наш спрайт из этого топика (стрелочку) и выведем его на экран. Для этого открываем любой текстовый редактор, создаем пустой файл habr.asm и пишем туда команды:

         spr #0504       ; установим размер спрайта 8x5
         ldi r0,10       ; в регистр r0 - X координата
         ldi r1,10       ; в регистр r1 - Y координата
         drw r0,r1,arrow ; выведем спрайт на экран по координатам (10,10)
    
    end: jmp end         ; бесконечный цикл
    
    ; Спрайт
    arrow: db #f1, #11, #11, #ff
           db #f1, #1f, #ff, #ff
           db #f1, #f1, #ff, #ff
           db #f1, #ff, #1f, #ff
           db #f1, #ff, #f1, #ff


    После чего компилируем программу с помощью данной команды:
    tchip16.exe habr.asm -o habr.c16
    Затем открываем получившийся файл habr.c16 в эмуляторе и наслаждаемся видом черной стрелочки на белом фоне :)

    Для отладки сложных алгоритмов можно использовать мой отладчик — chip16debugger: code.google.com/p/chip16debugger/downloads/list
    image
    Пока альфа версия, говнокод, наверняка с багами, но лучше чем ничего. Иногда реально помогает словить баг.

    Эмулятор… А что еще прикольного можно замутить?

    Ну, например какой-нибудь компилятор (или транслятор) с языка высокого уровня. Я, например, пытался написать транслятор с паскале-подобного языка. Кое-что конечно получилось, но до полноценного языка явно не дотягивает. Вот такие программки можно было на нем писать:
    var
       xPixels, yPixels, xStart, yStart, Xsize, YSize, maxiter : integer;
       xStep, yStep : integer;
       ix,iy,x,y,x0,y0,iteration,xtemp : integer;
       dist : byte;
       temp : byte;
       xx,yy : byte;
    
    begin
      XPixels := 160;
      YPixels := 100;
      XStart := $FF9c;
      YStart := $FFce;
      XSize := 160;
      YSize := 100;
      MaxIter := 16;
    
      XStep := XSize div XPixels;
      YStep := YSize div YPixels;
    
      yy := 20;
      For iy := 0 to yPixels do
        begin
              xx := 0;
              For ix := 0 to xPixels do
                begin
                   x := xStart + ix * xStep;
                   y := yStart + iy * yStep;
                   x0 := x;
                   y0 := y;
                   iteration := 0;
                   Repeat
                         xtemp := ((x*x) div 48) - ((y*y) div 48) + x0;
                         y := 2*((x*y) div 48) + y0;
                         x := xtemp;
                         iteration := iteration + 1;
                         dist := ((x*x) div 48) + ((y*y) div 48);
                         If iteration = maxiter then dist := 4000;
                   Until dist > 192;
    
                   If iteration <> maxiter then
                    If iteration > 1 then
                    begin
                     temp := ((iteration shl 4) or iteration) shl 8;
                     temp := temp or ((iteration shl 4) or iteration);
                     DrawSprite(xx,yy,$0201,^temp);
                    end;
                   xx := xx + 2;
                end;
              yy := yy + 2;
        end;
    end.
    


    На выходе получалась тонна ассемблерного говнокода, который компилился вышеуказанным ассемблером tchip16. В итоге это как-то работало и давало такую картинку:


    К сожалению забросил, не хватило скила довести все до релиза или хотя бы беты.

    Что еще… Ах да, был случай интересный — хотели замутить CHIP16 демо-компо, типа написание демок под сабж. Ну а что, олдскульно, ресурсы ограниченны, это вам не шойдеры с гигами оперативы. В теории можно вполне крутить старые эффекты, так, как хоть тут нет фрейм-буффера, зато есть 32Kb оперативы под спрайт размером с весь экран. И 32Kb на код остается. Будет даже без морганий экрана. Моя небольшая демка sinedots (такие точки крутятся в пространстве, получается как-бы трехмерные). Правда я тут ступил, и выводил точки именно точками (спрайтами в один байт) из-за чего получается моргание.

    Еще можно создать всю платформу аппаратно (для любителей ПЛИС и прочих транзисторов). А я быть может напишу свой эмулятор под эту железяку:

    И пускай не совсем аппаратно с точки зрения аппаратности (там обычный MIPS процессор), зато все равно интересно.

    Всем удачи!
    Share post

    Comments 19

      0
      Я только с этой статьи наконец-то понял как работают эмуляторы =)
      Спасибо!
        0
        Рекомендую прочитать статью по теме http://emulate-su.livejournal.com/663058.html. Очень интересно.
          0
          Если я правильно понял статью, то это нормально, что у меня тормозят эмуляторы NES, когда много спрайтов, в игре Blaster Master. Пробовал разные дампы и эмуляторы — всё равно, другие игры идут нормально. Жаль, недавно только играл.
            0
            Тормозят не эмуляторы, а игры в эмуляторах.
              0
              Если вы просто придрались к тому, что так обычно не говорят, то по мне, нет большой разницы как говорить.

              А вообще, написал это, потому что думаю по этому поводу так: Если бы эмулятор был лучше и железо, то игра уже не тормозит? Но она ведь ничего не сделала, чтобы стать лучше. Для каждой игры есть системные требования, если у тебя система хуже, то нечего говорить, что игра тормозит. В конечном счёте, тормоза могут быть вызваны как игрой, так и тем, что её запускает. Так как Blaster Master написали для NES и там она не тормозила, значит или кому-то захочется отредактировать игру, или надо написать нормальный эмулятор, ну или сделать ещё что-то.
                0
                Я не придираюсь, а просто проясняю ситуацию. Тормозит именно игра, а не эмулятор. При том так же, как тормозила бы в этой же ситуации на реальной приставке.
                +1
                Странно, что вас минусуют. Люди, наверное, не играли в ту же contra force на NES на реальной консоли и в эмуляторе.
          0
          Как-то мне не очень понятно — зачем придумывать ещё одну аппаратную платформу, когда существующих девайсов и так пруд пруди — можно брать спеку на них и эмулировать. В том числе есть реальные устройства для которых пока нет эмуляторов или существующие эмуляторы неточны/несвободны итп.
            +2
            Потому что, как правило, у существующих девайсов есть: маскируемые/немаскируемые прерывания, тайминги, таймеры, различная длинна опкодов, различные мепперы памяти (как например в NES), биосы (прошивки), не говоря уже о перефирии типа дисковода или, не дай боже, жесткого диска на пару с видюхой. Поэтому вот так просто взять и эмульнуть x64, чтоб семерка грузилась в эмуляторе я думаю не получится. Начинают с простого обычно.
              +1
              Во-первых, есть более старые а значит и более простые девайсы, есть девайсы специализированные а значит тоже более простые. Не надо просто сразу браться за что-то сложное.
              Во-вторых, эмулятор можно писать шаг за шагом — процессор зашагал, потом один из режимов памяти допилить, затем видео. Ну и так постепенно можно сэмулировать довольно сложную систему, и каждый шаг даёт положительный фидбек.
              Трудности обычно не в сложности самой системы, а в том что спецификации недостаточно полные и многие вещи приходится додумывать.
              Ну и допустим если писать в MESS — там уже общие вещи все сделаны, фреймворк эмуляции давно готов, остаётся только части системы описывать — тоже получается намного проще.
                –1
                Да знаю я про это все. Еще раз — эта статья не для сотрудников VMWARE/MESS/VirtualBox/DosBox. Это статья для _начинающих_
            +2
            Еще можно создать всю платформу аппаратно (для любителей ПЛИС и прочих транзисторов). А я быть может напишу свой эмулятор под эту железяку:

            Аппаратно на ПЛИС это как? Есть исходный код (Verilog, VHDL), схема? Если есть, то ссылку можно, пожалуйста? И какая именно «железяка» имеется в виду?
              +1
              Конечно ничего нет. Ни схемы, ни исходников Это теоретические размышления были. А железка на фото — это видео-вкладыш из журнала, www.vogeeky.co.cc/
                +1
                Апдейтов для miniOS для девайса не предвидится?)
                  +1
                  Видимо нет, поскольку ничего нового для данного проца Ingenic не выкладывал. Походу они уже давно забили на него.
                    +1
                    Видимо они сейчас очень заняты новыми мипсами для андроида.
              +2
              tronix286, а я смотрю — ник знакомый. Теперь по последней фотке вспомнил — vogeek :)
                +1
                А прямого доступа к памяти экрана нет?
                  –1
                  Увы, нет. Но повторюсь — есть место для формирования полного изображения в памяти — 32 килобайта, который затем можно отрисовать как спрайт размером 320x240. Еще около 32Kb остается для кода.

                Only users with full accounts can post comments. Log in, please.