Улучшенный способ динамического обновления данных плитки на Commodore 64.

Я планирую использовать программные спрайты в многоцветном режиме символов для моего нового проекта C64. Моя идея состоит в том, чтобы использовать наложенные данные спрайта «пуля» для данных плитки.

Я думаю, что у меня могут быть данные набора плиток по адресу «TILESET», данные спрайтов по адресу «SPRITE». И я могу объединить эти два, чтобы подготовить маркер маркера с динамически вычисляемым фоном и сохранить по адресу «SUPERIMPOSED».

Я написал следующий код и количество циклов, чтобы проверить, возможно ли это. И я думаю, что это не так. Цикл съедает 219 циклов. Почти четыре растровых строки. И я не включил другие необходимые вычисления, необходимые перед этим циклом. Вроде расчета целевых адресов.

Когда я хочу иметь 16 маркеров на экране, мне потребуется 64 растра или 8 рядов символов. Поэтому я становлюсь подозрительным. Это правильный путь? Или есть другой более оптимизированный способ сделать ту же работу?

                         cycles
                        ---------
    ldy #$07             4 x1 = 4   
-   LDA TILESET,x       3 x8 = 24
    AND SPRITE,x        4 x8 = 32 
    STA SUPERIMPOSED,x  5 x8 = 40
    dey                 2 x8 = 16
    cpy                 4 x8 = 32
    bne -               3 x8-1 = 71 
                        ----------
                        219 Cycle

Я рассматриваю повторяющийся узор в фоновом режиме. Так что я могу использовать ту же плитку пули без повторного расчета.


person wizofwor    schedule 27.09.2015    source источник
comment
Разверните цикл, чтобы избавиться от накладных расходов за счет некоторого увеличения кода. Также вы, кажется, используете x для индексации, но y для цикла?   -  person Jester    schedule 27.09.2015
comment
Если ваш спрайт имеет размер более одного пикселя и вы хотите иметь возможность позиционировать его в любом пикселе, вам потребуется гораздо больше кода, включая возможность наложения 2 или 4 символов (тайлов). Если спрайт состоит всего из одного пикселя, вы можете немного упростить код.   -  person Ross Ridge    schedule 27.09.2015
comment
@RossRidge Я еще не закончил спрайты. Так что я не уверен в размере, но это будет что-то около 4x4.   -  person wizofwor    schedule 28.09.2015
comment
Если вам нужно пиксельное гранулированное позиционирование спрайтов 4x4, я думаю, вы либо будете использовать растровый режим (который также будет довольно дорогим, поскольку вам все равно придется обновлять столько байтов), либо аппаратные спрайты. Вы можете иметь более 8 спрайтов на экране одновременно, перемещая их по мере сканирования экрана. Вы по-прежнему ограничены 8 спрайтами в данной строке сканирования. Вы также можете чередовать два набора из 8 спрайтов в каждом кадре. Это заставит их мерцать, но эффект может быть не таким уж плохим. (И хорошо, мерцание было чем-то, чем ваш тезка был печально известен.)   -  person Ross Ridge    schedule 28.09.2015


Ответы (1)


Как предлагает Jester, в качестве первой оптимизации просто повторите lda, and, sta и dey восемь раз. Устраните cpy и bne. Это немедленно сэкономит 103 цикла. Даже если вы хотите сохранить формальный цикл, обратите внимание, что dey устанавливает нулевой флаг, поэтому вам не нужен cpy.

В качестве второй оптимизации рассмотрим скомпилированный спрайт. Вместо того, чтобы выполнять чтение из sprite, x, вы бы закодировали эти значения непосредственно в свою подпрограмму, создав отдельную подпрограмму для каждого спрайта. Это сократило бы еще 16 циклов.

При этом ваши lda будут 4 цикла в выровненной таблице, а не 3. Таким образом, есть 8, которые вы не учли. Это означает, что развернутый плюс специализированный для вашего спрайта = 102 цикла (опустив конечный dey).

Не зная архитектуры C64 и/или того, что делает остальная часть вашего кода, если тот, кто принимает SUPERIMPOSED, может сделать это со страницы стека, рассмотрите возможность записи вывода в стек, а не через индексированную адресацию. Просто загрузите s с соответствующим начальным значением и сохраните новые результаты через pha. Это сэкономит два цикла на хранилище за счет 12 дополнительных циклов настройки и восстановления.

Исходя из этой мысли, если у вас была свобода в том, как выглядят эти таблицы, рассмотрите возможность изменения их формата — вместо одной таблицы, которая содержит все восемь байтов TILESET, используйте восемь таблиц, каждая из которых содержит один байт этого числа. Это устранило бы необходимость корректировать y в цикле; просто используйте другую целевую таблицу в каждой развернутой итерации.

Предположим, что и TILESET, и SUPERIMPOSED могут быть восемью таблицами, что приводит вас к:

LDA TILESET1, x
AND #<value>
STA SUPERIMPOSED1, x    ; * 8

[... LDA TILESET2, x ...]

... что составляет в общей сложности 88 циклов. Если SUPERIMPOSED является линейным, но находится на странице стека, то:

TSX
TXA
LDX #newdest
TXS
TAX                ; adds 10

LDA TILESET1, y
AND #<value>
PHA                ; * 8

[... LDA TILESET2, y ...]

TXS                ; adds 2

... что составляет 84 цикла.

Позднее добавление:

Если вы хотите предварительно умножить индекс в x на 8, эффективно уменьшив индексируемый диапазон до 32 плиток, вы можете продолжить заполнение линейного выходного массива без корректировки y, как показано ниже:

LDA TILESET, x
AND #<value1>
STA SUPERIMPOSED, x

LDA TILESET+1, x
AND #<value2>
STA SUPERIMPOSED+1, x

... etc ...

Таким образом, вам потребуется восемь копий этой подпрограммы с разными базовыми адресами таблиц, чтобы получить 256 выходных тайлов. Предположим, у вас есть 20 спрайтов, что составляет в общей сложности 20 * 8 = 160 копий вашей процедуры построения спрайтов, каждая из которых, вероятно, будет иметь размер порядка 100 байт, поэтому вы тратите около 16 КБ.

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

person Tommy    schedule 27.09.2015