|
Читатель - читателю - multicolor - эффекты на бордюре и кое-что еще.
|
ЧИТАТЕЛЬ - ЧИТАТЕЛЮ
© Сергей Кучкин, г. Москва
MULTICOLOR - ЭФФЕКТЫ НА БОРДЮРЕ И КОЕ-ЧТО ЕЩЕ.
Как ни странно, эта тема на страницах журнала почти всегда обходилась стороной. Между тем, в последнее время MULTICOLOR встречается все чаще, а уж без бордюрных эффектов не обходится ни одна музыкальная демонстрация. Определимся с сутью вопроса:
Multicolor - расположение в одном знакоместе (8x8) более чем двух цветов (статическое либо динамическое);
Эффекты на бордюре - статические либо динамические изображения на бордюре.
Принцип, положенный в основу этих эффектов, довольно прост. Дело в том, что изменения в экранной памяти отображаются не мгновенно, а только при очередной прорисовке кадра (каждые 20 мс). Поэтому, быстро варьируя значениями атрибутов, можно добиться желаемого результата. Но тут начинаются проблемы.
1. Аппаратная несовместимость и проблемы синхронизации.
Чтобы хоть как-то компенсировать свою некомпетентность в аппаратных вопросах, я проштудировал все публикации ZX-РЕВЮ на тему ВДТа, порта #FF и тому подобных вещей. Оставшиеся вопросы были проверены программно, но с одним ограничением: под рукой у меня есть ТОЛЬКО ПЕНТАГОН-128, и тестировал я ТОЛЬКО его.
1.1. Сплошные и раздельные поля памяти: конфликт Z80 и ULA. (Историческая справка).
При работе процессора, в блоке экранной памяти может возникнуть ситуация, когда запрос Z80 произойдет одновременно с запросом ULA (которая автоматически обновляет экран). В самых первых моделях Спектрума этот вопрос разрешался в пользу ULA. При этом на процессор переставали подаваться тактовые импульсы (другой метод состоял в подаче сигнала WAIT). Чем лучше была синхронизирована схема компьютера, тем реже возникали конфликты, и тем быстрее работал процессор.
Но, в любом случае, время исполнения одной и той же команды могло быть непостоянным, так что ни о какой полноценной синхронизации для создания тонких цветовых эффектов не могло быть и речи.
Если память компьютера организовывалась на одной микросхеме в 64К (речь пока идет о 48-ых Спек-трумах), то конфликт возникал во всем адресном пространстве ("Москва - 48"). Если же память организовывалась на трех микросхемах по 16К, то конфликт возникал только в экранном блоке #4000-#8000 ("Пентагон-48?").
Известно, также, что в фирменных 128-ых моделях Спектрума страницы памяти 0-3 были бесконфликтными (не состязательными), а 4-7 конфликтными (состязательными).
Позднее появились машины с раздельными полями памяти ("Пентагон-128"). В них для ULA отвели отдельное Видео-ОЗУ, и она перестала тормозить процессор. Программы одинаково быстро заработали во всем адресном пространстве, что гораздо упростило синхронизацию при работе с экраном.
1.2. Экран: 312 против 320. Синхронизация по INT'y.
Сигнал на перерисовку экрана - кадровый синхроимпульс вырабатывается каждые 20 миллисекунд. По его заднему фронту идет INT (сигнал прерывания) (тут я сошлюсь на Кирилла Громова, ZX-РЕВЮ 95/3).
Длительность INT'a по классическим меркам должна составлять 8-9 мкс, то есть 28-32 такта. Но это теория. На практике же начало INT'a может и не совпадать с концом синхроимпульса, а длительность кое-где достигает 15 мкс (52-53 такта). Главное для нас сейчас только чтобы эти величины были постоянными.
кс
КС
INT
Прорисовка экрана начинается с самого верха бордюра и заканчивается в самом его низу. В моем Пентагоне экран состоит из 320 строк по 224 такта на каждую строку. Таким образом, всего получается 320x224=71680 тактов/экран (очевидно, столько же тактов/INT). Однако, существует другой вариант, считающийся более правильным (?). Он реализован, например, в "ПРОФИ". Это 312 строк в экране. Если сделать логичное предположение, что одна строка прорисовывается также за 224 такта, то получим 312x224=69888 тактов/INT. Если Вы захотите проверить число строк на экране своего компьютера, то можете воспользоваться предложенной ниже программой LINETEST. После вызова из Бейсика PRINT USR ... она вернет количество строк в паре BC (исходя из 224 тактов в строке). У меня этот тест дал, как и ожидалось, 320. Проверить его на "Профи", к сожалению, не было возможности.
; LINETEST 312/320/...?
ORG |
#8000 |
|
ENT |
$ |
|
DI |
; |
3апрещаем прерывания. |
LD |
HL,INT |
Останавливаем адрес программы обработки |
LD |
(#80FF),HL |
прерываний на процедуру INT. |
LD |
A, #80 |
|
LD |
I, A |
|
IM |
2 |
|
LD |
DE,0 ; |
Обнуляем счетчик строк. |
EI |
|
Разрешаем прерывания. |
HALT |
|
Ждем очередного синхроимпульса. |
LD |
HL,INT2 |
Переопределяем обработку прерываний |
LD |
(#80FF),HL |
на процедуру INT2, которая остановит выполнение после прихода следующего синхроимпульса. |
INC |
DE ; |
Увеличиваем счетчик строк. |
LD |
в,15 ; |
Пропускаем необходимые такты. |
DJNZ |
Ml |
|
LD |
A, R |
!!! команда для пропуска еще 9 тактов! |
JR |
М0 ; |
Цикл замкнулся. |
EI |
|
|
RET |
|
|
POP |
HL ; |
Снимаем со стека адрес возврата. |
LD |
С, E |
Полученное число строк |
LD |
B,D ; |
пересылаем в вС. |
IM |
0 |
возвращаемся |
EI |
|
в |
RET |
|
Бейсик. |
Обратите внимание! Здесь и далее комментарием «!!!» у меня обозначены команды, выполняемые вхолостую (только ради тактов).
Стоит заметить, что при выполнении процедуры INT, прерывание может захватываться повторно (даже при нормальной длине сигнала INT), но это не страшно, так как лишние 30-40 тактов не способны повлиять на результат теста. (Потенциально возможны ситуации, когда в экране умещается нецелое число строк, например, 312.5; в подобных случаях тест ошибется, если, конечно, не произвести в нем соответствующих изменений).
Теперь я приведу тактовый "портрет" экрана моего Пентагона.
224 такта
Бордюр
192 строки
48 строк
I 128 I
тактов ■ '
Отсюда видно, например, что каждая строка "маленького" экрана (256x192) прорисовывается отдельно. А вот пиксели в строке рисуются по два за такт (256 пикселов за 128 тактов).
Можно заметить, что верхнему левому углу "малого" экрана соответствует 69-й такт 80 строки. Эти величины как раз и характеризуют положение INT^ относительно кадрового синхроимпульса. Не исключено, что они колеблются даже у компьютеров одного типа (однако это не факт). Кстати, эти 69 тактов долго не давали мне покоя (число ведь не круглое!). Я перемерял так и сяк, но результат был один и тот же. В конце концов, я решил, что это связано с длиной кадрового синхроимпульса (ведь INT идет позже начала перерисовки экрана как раз на этот интервал времени, а я отсчитывал такты, разумеется, от INT'a).
Как же синхронизировать программу с перерисовкой экрана? Например, просто HALT'ом:
27 1 тактов
; INT - адрес программы обработки
LD LD LD IM EI
HALT INT ...
Вот и все, программа придет на INT почти сразу после начала перерисовки экрана. Теперь выводите, например, в порт #FE каждые 71680 (69888) тактов что-нибудь, и у Вас готова картинка на бордюре. Вставив небольшую первоначальную задержку легко разместить бордюрную картинку там, где нужно. При желании, можно даже заставить ее двигаться (варьируя число тактов между перерисовками). В «Приложении Б» приведен пример программы CURSOR, которая делает нечто подобное плюс еще кое-что.
1.3. Синхронизация с помощью порта #FF: пара цитат.
Порт #FF! По своей популярности он давно уже побил все рекорды. Корреспонденты приходили и уходили, а порт #FF успешно просуществовал на страницах ZX-РЕВЮ аж с 1991 года и до наших дней! Причем редкий номер не обходился без нового "окончательного и бесповоротного" решения проблемы. Так в чем же суть?
В фирменном Спектруме при чтении из порта #FF (как впрочем, и из любого другого несуществующего порта) считываются атрибуты, выводимые в данный момент на экран, попеременно с кодом #FF. Почему это происходит, объяснили уже давно (ZX-РЕВЮ за 1991 год).
Многие отечественные компьютеры (если не сказать, подавляющее большинство) не имеют порта #FF (то есть, из него ВСЕГДА читается код #FF). И не было бы много печали, если бы некоторые программы не использовали метод синхронизации с помощью этого порта. Его суть вот в чем: WAIT IN A,(#FF) ; Этот цикл выполняется до тех пор,
INC А ; пока в порту не появится байт атрибутов
JR Z,WAIT ; (то есть началась перерисовка экрана).
Очевидно, что при отсутствии порта #FF программа просто повиснет.
Существуют тесты, позволяющие проверить наличие этого порта у Вас (у меня, например, порта нет, что и заставляет меня прекратить рассказ, не подтвержденный экспериментами).
1.4. INT и его повадки: важные мелочи.
До тех пор, пока Вы работаете отдельно с экраном, отдельно с бордюром, всего вышесказанного должно быть достаточно. Но если Вы захотите синхронизировать экранное изображение с бордюрным, то тут появится проблема.
Запустив мою программу CURSOR, Вы должны были заметить, что "бордюрная" часть курсора постоянно либо "убегает", либо отстает от "экранной" (поэтому и была введена клавиша '0'). Такое поведение курсора объясняется не просчетом в программе, а свойством системы прерываний.
Дело в том, что когда приходит сигнал INT, процессор может быть занят выполнением команды. В таком случае он сначала завершит команду, а только потом перейдет по прерыванию. Задержка может составлять от 1 до 20-26 (?) тактов в зависимости от выполняемой команды. Между тем, прорисовка экрана уже идет полным ходом, то есть переход по INT запаздывает. В случае с HALT'ом (который кто-то назвал NOP'ом без увеличения PC), задержка может составлять 0, 1, 2 или 3 такта. Если вспомнить, что за один такт прорисовываются два пикселя экрана, то за 3 такта: 2x3=6 - почти целое знакоместо!
Возникает вопрос, можно ли избавиться от этого эффекта программно? Ответ: можно. Идея реализована в приведенной ниже программе FILTER. Она использует ячейки #81FF, #8200, изменяет I и некоторые другие регистры. После вызова CALL FILTER сигнал INT соответствует началу следующей команды (но прерывания запрещены).
;INT FILTER ONLY FOR PENTAGON-12 8
(#XXFF),HL ; прерываний. A, #XX I,A 2
ORG |
#8000 |
|
ENT |
$ |
|
DI |
|
|
LD |
HL,INT |
; Останавливаем процедуру обработки |
LD |
(#81FF),HL |
; прерываний INT. |
LD |
A,0 |
; Очищаем дно буфера. |
LD |
(BUFF+4),A |
|
LD |
E, l |
; Счетчик установлен в 1. |
LD |
HL,BUFF |
; HL - указатель на первый свободный |
LD |
A, #81 |
; байт в буфере. |
LD |
I,A |
|
IM |
2 |
|
Ждем прерывание. Теперь у нас задержка INTa 0, 1, 2 или 3 такта, а в (HL)=1 в любом случае. 3адержкана71677тактов. Таким образом перед прерыванием успеет начать выполняться INC E для задержек 0, 1 и 2, а для 3 уже нет. В результате: (HL)=2 для случаев 0, 1 и 2 и (HL)=1 для случая 3. 2
Аналогичный "отсев" по одному.
3
4
3апрещаем прерывания. Теперь расклад такой (см. далее таблицу):
Случай |
BUFF+0 |
BUFF+1 |
BUFF+2 |
BUFF+3 |
0 |
1 |
2 |
3 |
4 |
1 |
1 |
2 |
3 |
3 |
2 |
1 |
2 |
2 |
3 |
3 |
1 |
1 |
2 |
3 |
|
|
|
Осталось проверить ячейки и сделать |
|
|
|
соответствующие задержки. |
|
LD |
BC,2749 |
В BC - число повторений в цикле задержки ((ВС-1)х26+21 тактов). |
|
LD |
HL,(BUFF+1) |
|
|
EX |
DE, HL |
|
|
LD |
HL,(BUFF+3) |
|
|
LD |
A, H |
|
|
OR |
A |
|
|
JR |
NZ, F2 |
Если в (BUFF+4) не ноль, то произошел гипотетический случай: прерывание" вклинилось" между EI и HALT. (См. начало программы). Это приведет лишь только к сдвигу данных на один байт, что и устраняем). |
F0 |
LD CP |
A, L 4 |
|
|
JR |
Z,DISP3 ; |
Начальное смещение 0! |
|
LD |
A, D |
|
|
CP |
L |
|
|
JR |
Z,DISP2 ; |
Начальное смещение 1! |
|
LD |
А, E |
|
|
CP |
D |
|
|
JR |
Z,DISP1 ; |
Начальное смещение 2! |
DISP0 |
NOP
LD
LD |
R, A R, A |
!!! Обработка смещения 3. ! ! ! ! ! ! |
Fl |
DEC |
BC |
Ждем рассчитанное число тактов до |
|
LD |
А, В ; |
следующего INT'a |
|
OR |
C |
|
|
JR |
NZ, F1 |
|
|
RET |
|
Возврат. |
F2 |
LD |
E,D |
B случае, если прерывание "вклинилось" между |
|
LD |
D, L |
EI и HALT (в начале), |
|
LD |
L,H |
надо сдвинуть все на 1 байт. |
|
DEC |
BC |
Уменьшаем счетчик задержки, компенсируя время, |
|
DEC |
BC |
потраченное на перезагрузки |
|
LD |
A, (HL) |
! ! ! |
|
NOP |
|
! ! ! |
|
JR |
F0 |
|
DISP1 |
DEC |
BC |
Обработка смещения 2. |
|
NOP |
|
! ! ! |
|
JR |
DISP0 |
|
DISP2 |
JR |
DISP0 ; |
Обработка смещения 1. |
DISP3 |
LD |
R, A |
; |
!!! Обработка смещения 0. |
|
LD |
A, (HL) |
; |
! ! ! |
|
JR |
DISP0 |
|
|
WAIT |
LD |
BC,2753 |
; |
Задержка на 71617 тактов |
Wl |
DEC |
BC |
; |
(включая время на вызов CALL WAIT) |
|
LD |
A, B |
|
|
|
OR |
C |
|
|
|
JR |
NZ,W1 |
|
|
|
LD |
B, (HL) |
; |
!!! |
|
RET |
|
|
|
INT |
LD |
(HL),E |
|
|
|
INC |
HL |
|
|
|
LD |
D,(HL) |
; |
!!! |
|
LD |
D,(HL) |
; |
!!! |
|
EI |
|
|
|
|
RET |
|
|
|
BUFF |
DEFS |
5 |
; |
Буфер для хранения результатов. |
Процедура довольно "сырая" (как, впрочем, и все программки в этой статье).
В принципе, ее несложно переработать и для "Профи" (69888 тактов/INT), но я не стал этого делать из-за невозможности отладки на "Пентагоне".
Напомню, что комментариями отмечались команды, не несущие смысловой нагрузки, а только забивающие время.
Программу CURSOR, модернизированную с помощью "фильтра", Вы найдете в «Приложении Б» под названием SCURS. Теперь ничто ни от чего не отстаёт, все в порядке (за исключением мелочи: бордюрное изображение у меня всегда отстает от экранного примерно на 1 пиксель, то есть 0.5 такта, что, очевидно, программно исправить - невозможно).
Правда, у FILTER'a есть недостаток - он долго работает (несколько прерываний). Таким образом, с его помощью возможна только первоначальная синхронизация, а когда кадры пропускать нельзя, Вам придется выкручиваться без него.
2. MULTICOLOR.
Может сложиться впечатление, что multicolor - вещь редкостная, и, ввиду своей сложности, является уделом музыкальных демонстраций и заставок. Я попытаюсь доказать, что это не так.
Что же нужно для multicolor'a?
a) Синхронизироваться с началом перерисовки экрана;
b) Дождаться перерисовки атрибутов (то есть пропустить, как минимум, первые 80 строк);
c) Дать компьютеру прорисовать первую "полоску" атрибутов, но прежде, чем он доберется до второй, заменить атрибуты на другие.
Таким образом, в одном знакоместе можно разместить до 2x8=16 цветов, то есть, все цвета Спектрума! Цвет задается отдельно для каждого байта знакоместа. Осталось только повторять подобный трюк в каждом кадре, и у Вас на экране полноценный multicolor!
Кстати, для обладателей "старого доброго" RESET'a могу порекомендовать надежный тест. Если Вы сомневаетесь: multicolor перед Вами или обман, то жмите RESET, но не отпускайте его некоторое время. При этом multicolor "рассыплется", а обычная картинка будет преспокойно висеть на экране.
Возможно, у Вас возникнет желание перерисовывать атрибуты настолько быстро, чтобы получился multicolor в пределах одного байта знакоместа. Но хочу Вас огорчить - этот трюк не удастся. Горизонтальный multicolor невозможен, и вот почему.
Байт из экранной памяти вместе со своим атрибутом перед выводом на экран попадает в специальный сдвиговый регистр, недоступный программно. Между считыванием байта из памяти и засылкой его на экран -интервал в 3 такта. Таким образом, первый байт экрана считывается на 66-м такте 80-й строки (нумеруя с 0). Причем любые изменения памяти в промежутке между считыванием и изображением станут заметны только в следующем кадре.
Но вернемся к multicolor'y вертикальному. Тут не все так мрачно, хотя есть и свои проблемы. Небольшой расчет: прорисовка строки экрана занимает 224 такта; переброска 1 байта с помощью LDI (LDD) занимает 16 тактов; 224/16=14, то есть, максимум 14 знакомест с multicolor'oM в строке (это даже без учета установок для LDI, а с ними и того меньше). Что же делать?
Как всегда, выручает стек. Придется, также, отбросить очень медленные команды перехода, то есть развернуть все циклы. У нас получится "рыхлый" код размером в несколько килобайт, но игра стоит свеч.
Есть две проблемы: каким способом брать атрибуты из памяти и каким класть их на экран (трудно нагрузить и то и другое на один стек). Однозначного ответа быть не может. Если Вас устраивает жесткая фиксация области multicolor'a на экране, то Вы немного выигрываете в скорости:
LD SP,#XXXX ; #XXXX - адрес в памяти
POP HL
LD (#YYYY),HL
POP HL
LD (#ZZZZ),HL ; #YYYY, #ZZZZ адреса на экране
и так далее для всей области. Замечу, что POP быстрее, чем PUSH на 1 такт; а LD (#ADDR),HL быстрее LD (#ADDR),DE на 4 такта. При такой процедуре вывода достаточно изменить атрибут в памяти, и при следующей прорисовке он изобразится на экране. Теперь подсчет: "POP HL" + "LD (#YYYY),HL" = 26 тактов; 224=8x26+16. To есть, получаем 2x8=16 знакомест (каждый "POP HL" даёт два), плюс еще 16 холостых тактов. Следующий метод позволяет более гибко менять положение области тикисо1ог'а на экране: LD SP,#ADDR ; #ADDR - адрес на экране
LD HL,(#XXXX)
PUSH HL
LD HL,(#YYYY) ; #XXXX, #YYYY адреса в памяти
PUSH HL
и так далее для всей области. Обратите внимание, что в отличие от предыдущего случая, где могла быть только одна команда загрузки SP, здесь такая команда нужна при выводе каждой строчки (из-за причудливости спек-трумовского экрана). Зато для изменения местоположения multicolor'a достаточно изменить "только" все #ADDR. Это немало, но сравните с предыдущим случаем. Теперь расчет: "LD HL,(#XXXX)" + "PUSH HL" = 27тактов и еще 10 тактов выполняется "LD SP,#ADDR", итого: 224-10=214=7x27+25. То есть, получаем 2x7=14 знакомест в строке и 25 холостых тактов (право, обидно!).
Может возникнуть резонный вопрос: "А нельзя ли косвенно адресовать экран, то есть, вместо LD SP,#ADDR написать LD SP,(#ADDR)?" Ответ: «Нельзя». То есть, конечно, можно, но придется пожертвовать еще парой знакомест. Дело в том, что направление прорисовки экрана и направление заполнения стека противоположны. Вследствие этого, во избежание простоя, мы должны перегружать SP не один, а два раза за строку.
Подводя итог вышесказанному, осталось заметить, что алгоритмы, аналогичные вышерассмотренным реализованы в программах MAXSCM и 16Х16МС. Первая представляет собой реализацию multicolor'a для любого рисунка размером 18x14 знакомест. С моей точки, зрения это максимально широкий по X multicolor, реализуемый для произвольных атрибутов (в специфических случаях, безусловно, его можно расширить). По Y размер картинки некритичен, и может, в принципе, достигать' всего экрана. 16Х16МС реализует multicolor в квадрате 16x16 по первому из рассмотренных алгоритмов. Обе программы сначала создают сам работающий блок, а потом его запускают. При этом на экране может быть любое изображение, а файл атрибутов multicolor'a должен находиться по адресу 49152. Чуть подробнее программы описаны в «Приложении Б».
После прочтения предыдущих абзацев у Вас, должно быть, сложилось впечатление, что все свое время процессор должен посвятить multicolor'y, забросив остальные дела. Но это не так! Рассмотрим, например, multicolor 16x16 (по площади 1/3 экрана). На каждый кадр приходится 42956 тактов "безделья", что ни много, ни мало, а почти 3/5 всего времени процессора. Его можно занять, например, полным вертикальным scro11'ом этого самого квадрата 16x16 с точностью до точки, пустить текст нестандартным шрифтом со скоростью 5 строк в секунду (больше, чем достаточно), и еще время останется!
Как видно из всего вышесказанного, multicolor открывает поистине необозримые возможности для создания мелкой цветной графики. Остается только удивляться, что они не использованы до сих пор. Кстати, второй экран 128 компьютера мне так и не удалось задействовать для улучшения работы multicolor'a. Вот если бы разрешалось фиксировать экран на любой из 8 страниц... Тогда ПОЛНОЭКРАННЫЙ multicolor сводился бы к простой цепочке OUT^ в порт #FD (несмотря на то, что этот OUT делает очень многое, он выполняется не дольше обычного).
Быть может, широкому распространению multicolor'a мешает аппаратная несовместимость? Но этот момент преодолим. Сейчас я разрабатываю систему multicolor'a, автоматически распознающую компьютер, и подстраивающуюся под него. Но тут катастрофически не хватает информации по распространенным синхросисте-мам. Если кто-нибудь заинтересуется подробным вопросом, то мой адрес и телефон даны ниже. Пишите, звоните!
3. Вместо послесловия.
Кучкин Сергей
121096, г. Москва, ул. Минская, д.14, кв.102; тел. 144-26-00
Приложение А.
Программируя multicolor, я столкнулся с одной проблемой: все имеющиеся у меня готовые процедуры теперь не годились, поскольку время их выполнения зависело от начальных условий. Так, например, при написании scroller'a под тиШсо1ог'ом мне пришлось заново переписывать вывод нестандартным шрифтом, опрос клавиатуры и все подобные мелочи.
Необходимость точно согласовывать время выполнения программы при любых условиях, порождает особый стиль программирования. Погоня за скоростью и малым размером отступает на второй план.
Приходится минимизировать число условных переходов и вызовов, которые сильно осложняют ситуацию.
Ниже я рассмотрю несколько способов, позволяющих сделать время выполнения программы независящим от начальных условий.
Способ 1: прямая коррекция времени.
Каждый условный переход должен превратиться в подобную конструкцию:
! ! ! Тут NOP и ... обозначают команды, выполняемые для выравнивания
времени в случае соблюдения условия !!! и в случае его несоблюдения.
Этот способ хорош при небольшом числе необходимых переходов. Но вот с САЬЬ'ами он справиться уже не может. Тут применим способ 2.
Способ 2: косвенная коррекция времени.
Один из регистров (регистровых пар) или ячейка памяти отводится под счетчик задержки в конце программы. Вначале в этот счетчик заносится время задержки, характерное для самой быстрой работы (не происходило условных переходов и заходов в CALL'bi). При вызове каждая из подпрограмм корректирует этот счетчик в зависимости от времени, необходимого для ее выполнения. Поскольку единица счетчика, скорее всего, соответствует нескольким десяткам тактов, то тут не обойтись, также, без прямой коррекции. Но хватит слов. Вот пример:
LD |
BC,#300 |
; Инициализируем счетчик. |
CALL |
NC,M1 |
|
CALL |
Z,M2 |
|
DEC |
BC |
; Задержка в соответствии со счётчиком |
LD |
A, B |
; (единица счетчика равна 2 6 тактам). |
OR |
C |
|
JR |
NZ,M3 |
|
RET |
|
|
DEC |
BC |
; "Занимаем" у счетчика 52 такта, |
DEC |
BC |
; необходимые для работы. |
NOP |
|
; !!! "Возвращаем" 4 лишних. |
........................; Продолжаем
Однако, бывают случаи (особенно при адаптации готовых процедур), когда вносить изменения в структуру программы крайне нежелательно. Тогда применим самый трудоемкий способ:
Способ3: способ "супервизора". Когда нам необходимо вызвать процедуру, которая не заботится о времени своего выполнения, мы вызываем не ее, а специально приготовленную программу-супервизор. Эта программа анализирует переданные параметры, делает соответствующие задержки, и только потом вызывает процедуру.
Метод плох тем, что необходимо для каждого случая рассчитать число тактов выполнения, заложить эту информацию в "супервизор". И не удивительно, если он после этого получится больше самой программы. Что поделаешь, издержки неизбежны!
А теперь небольшой списочек команд, которыми можно забивать время в несколько тактов, если в этом возникнет необходимость:_
4 такта |
NOP; LD reg8,reg8 |
5 тактов |
RET <условие> (если условие заведомо ложно!) |
6 тактов |
INC reg16; DEC reg 16 |
7 тактов |
LD reg8,(HL); CP #00; ADD A,#00 |
8 тактов |
NEG; IM 0/1/2 |
9 тактов |
LD R,A |
10 тактов |
LD reg16,#NNNN; INC IX; DEC IX |
11 тактов |
INC (HL); ADD HL,reg16; OUT (#NN),A |
12 тактов |
IN reg8,(C); OUT (C),reg8 |
13 тактов |
LD A,(#NNNN) |
14 тактов |
LD IX,#NNNN |
15 тактов |
PUSH IX; ADD IX,reg16; ADC HL,reg16 |
16 тактов |
CPI; CPD; LD HL,(#NNNN) |
17 тактов |
CALL #NNNN |
18 тактов |
RLD; RRD |
19 тактов |
LD reg8,(IX+d); CP (IX+d) |
20 тактов |
LD reg16,(#NNNN) |
21 такт |
Некоторые команды при специфических условиях |
23 такта |
RLC (IX+d); SET 0,(IX+d); EX (SP),IX |
Обозначения:
reg8 - A,B,C,D,E,H,L (для IN, F);
regie - BC, DE, HL и AF либо SP (что допустимо);
#NN -байт;
#NNNN - слово;
d - смещение в командах с индексными регистрами. IX везде свободно заменяется на IY.
Это, разумеется, далеко не полный список Некоторые команды из приведенных выше предпочтительнее по размеру, другие - по влиянию на флаги.
Отдельно следует заметить, что переход по маскируемому прерыванию занимает 19 тактов (без учета возможной задержки, то есть в случае, когда прерывание пришло перед началом выполнения команды). Приложение Б.
Первая программа LINETEST - возвращает в регистровой паре ВС число строк в экранном кадре компьютера (если в строке по 224 такта). Возможен вызов из Бейсика по PRINT USR
;LINETEST
312/320/...? |
ORG |
#8000 |
ENT |
$ |
DI |
|
LD |
HL,INT |
LD |
(#80FF),HL |
LD |
A, #80 |
LD |
I,A |
IM |
2 |
LD |
DE,0 |
EI |
|
HALT |
|
LD |
HL,INT2 |
LD |
(#80FF),HL |
INC |
DE |
LD |
B, 15 |
DJNZ |
M1 |
LD |
A, R |
JR |
M0 |
EI |
|
RET |
|
POP |
HL |
LD |
C, E |
LD |
B, D |
IM |
0 |
EI |
|
RET |
|
ВСЕ ОСТАЛЬНЫЕ ПРОГРАММЫ СИНХРОНИЗИРОВАНЫ ТОЛЬКО ПОД "ПЕТАГОН"!
Программа CURSOR позволяет перемещать курсор 3x3 знакоместа, как по экрану, так и по бордюру. В силу изложенных ранее причин курсор на бордюре может отставать от экранного. Ситуацию можно исправить, нажимая клавишу '0'. Управление синклер-джостиком, выход SPACE.
;CURSOR
|
ORG |
#8000 |
|
ENT |
$ |
|
DI |
|
|
EXX |
|
|
PUSH |
HL |
|
LD |
HL,INT |
|
LD |
(#81FF),HL |
|
LD |
HL,#0509 |
|
LD |
(X),HL |
|
LD |
BC,#2FF |
|
LD |
DE,#5801 |
|
LD |
HL,#5800 |
|
LD |
(HL),#0F |
|
LDIR |
|
|
LD |
A, #81 |
|
LD |
I,A |
|
IM |
2 |
|
EI |
|
|
HALT |
|
|
DI |
|
|
LD |
BC,473 |
M0 |
DEC |
BC |
|
LD |
A, B |
|
OR |
C |
|
JR |
NZ,M0 |
|
INC |
BC |
|
INC |
BC |
|
LD |
R, A |
Ml |
LD |
C, #FE |
|
LD |
HL,#0107 |
|
CALL |
DRAW |
|
LD |
BC,2334 |
|
CALL |
INKEY |
|
CALL |
WAIT |
|
LD |
DE,0 |
|
LD |
DE,0 |
|
LD |
D,0 |
|
LD |
BC,#7FFE |
|
IN |
D, (C) |
|
RR |
D |
|
JR |
C,M1 |
|
LD |
BC,#2FF |
|
LD |
DE,#5801 |
|
LD |
HL,#5800 |
|
LD |
(HL),#0F |
|
LDIR |
|
|
POP |
HL |
|
EXX |
|
|
IM |
0 |
|
EI |
|
|
RET |
|
INT |
EI RET |
|
X |
DEFB |
#09 |
Y |
DEFB |
#05 |
DRAW |
LD |
E,#18 |
D1 |
LD |
B, 14 |
D2 |
DJNZ |
D2 |
|
OUT |
(C),L |
OUT |
(C),H |
DEC |
E |
JR |
NZ, Dl |
RET |
|
DEC |
BC |
LD |
A, B |
OR |
С |
JR |
NZ,WAITRET |
LD |
A, #0F |
CALL |
DRAW2 |
LD |
A, #EF |
IN |
A,(#FE) |
RRA |
|
CALL |
NC,FIRE |
RRA |
|
CALL |
NC, UP |
RRA |
|
CALL |
NC,DOWN |
RRA |
|
CALL |
N,RIGHT |
RRA |
|
CALL |
N,LEFT |
LD |
A, #38 |
CALL |
DRAW2 |
RET |
|
LD |
HL, -2 |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
D,0 |
RET |
|
LD |
HL,-74 |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (Y) |
DEC |
A |
CP |
l |
LD |
(Y) , A |
LD |
A, E |
CALL |
Z,DOWN |
LD |
DE,0 |
LD |
DE,0 |
LD |
D,0 |
NOP |
|
RET |
|
LD |
HL, 64 |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (Y) |
INC |
A |
CP |
#24 |
LD |
(Y) , A |
LD |
A, E |
CALL |
Z,UP |
LD |
R, A |
LD |
R, A |
LD |
R, A |
RET |
|
LD |
HL,#FFFC |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (X) |
INC |
A |
CP |
#2F |
LD |
(X) , A |
LD |
A, E |
CALL |
Z,LEFT |
LD |
E, 0 |
RET |
|
LD |
HL,#FFFB |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (X) |
DEC |
A |
CP |
6 |
LD |
(X) , A |
LD |
A, E |
CALL |
Z,RIGHT |
LD |
R, A |
LD |
R, A |
LD |
D,0 |
RET |
|
EX |
AF,AF |
PUSH |
BC |
LD |
DE,(X) |
LD |
C, 3 |
LD |
B, 3 |
LD |
h, 0 |
LD |
A, E |
CP |
12 |
RL |
H |
CP |
44 |
CCF |
|
RL |
H |
LD |
A, D |
LD |
1,0 |
CP |
8 |
RL |
L |
CP |
32 |
CCF |
|
RL |
L |
EXX |
|
LD |
C,A |
EX |
AF,AF |
LD |
B,A |
LD |
A, C |
SUB |
8 |
LD |
L,A |
LD |
H, 0 |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
EXX |
|
LD |
A, E |
EXX |
|
SUB |
12 |
LD |
E,A |
LD |
D,0 |
ADD |
HL, DE |
LD |
DE,#58 |
ADD |
HL, DE |
EXX |
|
LD |
A, H |
OR |
L |
EXX |
|
JR |
NZ, R4 |
LD |
DE,0 |
LD |
(HL),B |
LD |
A, B |
EX |
AF,AF' |
EXX |
|
INC A |
|
DJNZ |
R2 |
INC |
E |
DEC |
С |
JR |
NZ, R1 |
POP |
BC |
RET |
|
JR |
R3 |
R4
Программа - FILTER. Компенсирует непроизвольную задержку INT'a при ожидании исполнения команды. После ее вызова прерывания запрещены, а сигнал INT соответствует началу следующей команды. Портится содержимое I, и других регистров.
;INT FILTER
ORG |
#8000 |
|
ENT |
$ |
|
DI |
|
|
LD |
HL,INT |
|
LD |
(#81FF),HL |
|
LD |
A,0 |
|
LD |
(BUFF+4),A |
|
LD |
E, l |
|
LD |
HL,BUFF |
|
LD |
A, #81 |
|
LD |
I,A |
|
IM |
2 |
|
EI |
|
|
HALT |
|
|
CALL |
WAIT |
|
INC |
E |
;2 |
CALL |
WAIT |
|
INC |
E |
;3 |
CALL |
WAIT |
|
INC |
E |
;4 |
DI |
|
|
LD |
BC,2749 |
|
LD |
Hl,(BUFF+1) |
|
EX |
DE, HL |
|
LD |
HL,(BUFF+3) |
|
LD |
A, H |
|
OR |
A |
|
JR |
NZ, F2 |
|
LD |
A, L |
|
CP |
4 |
|
JR |
Z,DISP3 |
|
LD |
A, D |
|
CP |
L |
|
JR |
Z,DISP2 |
|
LD |
A, E |
|
CP |
D |
|
JR |
Z,DISP1 |
|
NOP |
|
; |
|
LD |
R, A |
• ! ! ! ! ... |
|
LD |
R, A |
• ! ! ! ! ... |
F1 |
DEC |
BC |
|
|
LD |
A, B |
|
|
OR |
С |
|
|
JR |
NZ,F1 |
|
|
RET |
|
|
F2 |
LD |
E, D |
|
|
LD |
D, L |
|
|
LD |
L, H |
|
|
DEC |
BC |
|
|
DEC |
BC |
|
|
LD |
A, (HL) |
• ! ! ! ! ... |
|
NOP |
|
• ! ! ! ! ... |
|
JR |
F0 |
|
DISP1 |
DEC |
BC |
|
|
NOP |
|
• ! ! ! ! ... |
|
JR |
DISP0 |
|
DISP2 |
JR |
DISP0 |
|
DISP3 |
LD |
R, A |
• ! ! ! ! ... |
|
LD |
A, (HL) |
• ! ! ! ! ... |
|
JR |
DISP0 |
|
WAIT |
LD |
BC,2753 |
|
W1 |
DEC |
BC |
|
|
LD |
A, B |
|
|
OR |
С |
|
JR |
NZ,W1 |
|
|
|
LD |
B, (HL) |
• ! ! ! ! ... |
|
RET |
|
|
INT |
LD |
(HL),E |
|
|
INC |
HL |
|
|
LD |
D,(HL) |
• ! ! ! ! ... |
|
LD |
D,(HL) |
• ! ! ! ! ... |
|
EI |
|
|
|
RET |
|
|
BUFF |
DEFS |
5 |
|
|
Программа |
CURSOR, оснащенная фильтром INT'a. Управление синклер-джостиком, |
Возможно отставание бордюрного курсора на один пиксель (что неустранимо программно). |
;SCURS |
|
|
|
|
ORG |
#8000 |
|
|
ENT |
$ |
|
|
JP |
CURSOR |
|
FILTER |
DI |
|
|
|
LD |
HL,INT |
|
|
LD |
(#81FF),HL |
|
|
LD |
A,0 |
|
|
LD |
(BUFF+4),A |
|
|
LD |
E, l |
|
|
LD |
HL,BUFF |
|
|
LD |
A, #81 |
|
|
LD |
I,A |
|
|
IM |
2 |
|
|
EI |
|
|
|
HALT |
|
|
|
CALL |
WAIT |
|
|
INC |
E |
;2 |
|
CALL |
WAIT |
|
|
INC |
E |
;3 |
|
CALL |
WAIT |
|
|
INC |
E |
;4 |
|
DI |
|
|
|
LD |
B, 2749 |
|
|
LD |
HL,(BUFF+1) |
|
|
EX |
DE, HL |
|
|
LD |
HL,(BUFF+3) |
|
LD |
A, H |
|
OR |
A |
|
JR |
NZ, F2 |
F0 |
LD |
A, L |
|
CP |
4 |
|
JR |
Z,DISP3 |
|
LD |
A, D |
|
CP |
L |
|
JR |
Z,DISP2 |
|
LD |
A, E |
|
CP |
D |
|
JR |
Z,DISP1 |
DISP0 |
NOP |
|
|
LD |
R, A |
|
LD |
R, A |
F1 |
DEC |
BC |
|
LD |
A, B |
|
OR |
С |
|
JR |
NZ, F1 |
|
RET |
|
F2 |
LD |
E, D |
|
LD |
D, L |
|
LD |
L, H |
|
DEC |
BC |
|
DEC |
BC |
|
LD |
A, (HL) |
|
NOP |
|
|
JR |
FO |
DISP1 |
DEC |
BC |
|
NOP |
|
|
JR |
DISP0 |
DISP2 |
JR |
DISP0 |
DISP3 |
LD |
R, A |
|
LD |
A, (HL) |
|
JR |
DISP0 |
WAIT |
LD |
BC,2753 |
W1 |
DEC |
BC |
|
LD |
A, B |
|
OR |
С |
|
JR |
NZ, W1 |
|
LD |
B, (HL) |
|
RET |
|
INT |
LD |
(HL),E |
|
INC |
HL |
|
LD |
D,(HL) |
|
LD |
D,(HL) |
|
EI |
|
|
RET |
|
BUFF |
DEFS |
5 |
CURSOR |
DI |
|
|
EXX |
|
|
PUSH |
HL |
|
LD |
HL,#0509 |
|
LD |
(X),HL |
|
LD |
BC,#2FF |
|
LD |
DE,#5801 |
|
LD |
HL,#5800 |
|
LD |
(HL),#0F |
|
LDIR |
|
|
CALL |
FILTER |
|
LD |
BC,475 |
mo |
DEC |
BC |
|
LD |
A, B |
|
OR |
С |
|
JR |
NZ,M0 |
|
LD |
R, A |
Ml |
LD |
C, #FE |
|
LD |
HL,#0107 |
|
CALL |
DRAW |
|
LD |
BC,2334 |
|
CALL |
INKEY |
|
CALL |
WAIT2 |
|
LD |
DE,0 |
|
LD |
DE,0 |
|
LD |
D,0 |
|
LD |
BC,#7FFE |
|
IN |
D, (C) |
|
RR |
D |
|
JR |
C,M1 |
|
LD |
BC,#2FF |
|
LD |
DE,#5801 |
|
LD |
HL,#5800 |
|
LD |
(HL),#0F |
|
LDIR |
|
|
POP |
HL |
|
EXX |
|
|
IM |
0 |
|
EI |
|
|
RET |
|
X |
DEFB |
#09 |
Y |
DEFB |
#05 |
DRAW |
LD |
E,#18 |
D1 |
LD |
B, 14 |
D2 |
DJNZ |
D2 |
|
OUT |
(C),L |
|
OUT |
(C),H |
|
DEC |
E |
|
JR |
NZ,D1 |
|
RET |
|
WAIT2 |
DEC |
BC |
|
LD |
A, B |
|
OR |
С |
|
JR |
NZ,WAIT2 |
|
RET |
|
INKEY |
LD |
A, #0F |
|
CALL |
DRAW2 |
|
LD |
A, #EF |
|
IN |
A,(#FE) |
|
RRA |
|
|
CALL |
NC,FIRE |
|
RRA |
|
|
CALL |
NC, UP |
|
RRA |
|
|
CALL |
NC,DOWN |
|
RRA |
|
|
CALL |
NC,RIGHT |
|
RRA |
|
|
CALL |
NC,LEFT |
|
LD |
A, #38 |
|
CALL |
DRAW2 |
|
RET |
|
FIRE |
LD |
HL, -2 |
|
ADD |
HL, BC |
|
LD |
C, L |
|
LD |
B, H |
|
LD |
D,0 |
|
RET |
|
LD |
HL,-74 |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (Y) |
DEC |
A |
CP |
1 |
LD |
(Y) , A |
LD |
A, E |
CALL |
Z,DOWN |
LD |
DE, 0 |
LD |
DE, 0 |
LD |
D,0 |
NOP |
|
RET |
|
LD |
HL, 64 |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (Y) |
INC |
A |
CP |
#24 |
LD |
(Y) , A |
LD |
A, E |
CALL |
Z,UP |
LD |
R, A |
LD |
R, A |
LD |
R, A |
RET |
|
LD |
HL,#FFFC |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (X) |
INC |
A |
CP |
#2F |
LD |
(X) , A |
LD |
A, E |
CALL |
Z,LEFT |
LD |
E, 0 |
RET |
|
LD |
HL,#FFFB |
ADD |
HL, BC |
LD |
C, L |
LD |
B, H |
LD |
E,A |
LD |
A, (X) |
DEC |
A |
CP |
6 |
LD |
(X) , A |
LD |
A, E |
CALL |
Z,RIGHT |
LD |
R, A |
LD |
R, A |
LD |
D,0 |
RET |
|
EX |
AF,AF |
PUSH |
BC |
LD |
DE,(X) |
LD |
C, 3 |
LD |
B, 3 |
LD |
H, 0 |
LD |
A, E |
CP |
12 |
RL |
H |
CP |
44 |
CCF |
|
RL |
H |
LD |
A, D |
LD |
L,0 |
CP |
8 |
RL |
L |
CP |
32 |
CCF |
|
RL |
L |
EXX |
|
LD |
C,A |
EX |
AF,AF' |
LD |
B,A |
LD |
A, C |
SUB |
8 |
LD |
L,A |
LD |
H, 0 |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
ADD |
HL, HL |
EXX |
|
LD |
A, E |
EXX |
|
SUB |
12 |
LD |
E,A |
LD |
D,0 |
ADD |
HL, DE |
LD |
DE,#5800 |
ADD |
HL, DE |
EXX |
|
LD |
A, H |
OR |
L |
EXX |
|
JR |
NZ, R4 |
LD |
DE,0 |
LD |
(HL),B |
LD |
A, B |
EX |
AF,AF |
EXX |
|
INC |
A |
DJNZ |
R2 |
INC |
E |
DEC |
С |
JR |
NZ, R1 |
POP |
BC |
RET |
|
JR |
R3 |
Программа для создания статического multicolor'a в отцентрованном прямоугольнике 18x14 знакомест. Изображение должно уже находиться на экране, а атрибуты - с адреса SCR=#C000 в формате 18 байт на каждую строку х 112 строк (по порядку).
;MAXIMUM STATIC MULTICOLOR (X)
ORG #8000 SCR EQU #C000
ENT $
LD DE,L4
LD IX,SCR
EXX |
|
PUSH |
HL |
LD |
HL,#58B1 |
LD |
C,14 |
LD |
(L1+1),HL |
LD |
DE,#0008 |
ADD |
HL, DE |
LD |
(L2+1),HL |
LD |
DE,#0018 |
ADD |
HL, DE |
LD |
B, 8 |
EXX |
|
LD |
HL,L2-3 |
LD |
B, 5 |
LD |
A, (IX+0) |
INC |
IX |
LD |
(HL),A |
INC |
HL |
LD |
A, (IX+0) |
INC |
IX |
LD |
(HL),A |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DJNZ |
K1 |
LD |
BC, L2-L1 |
LD |
HL, L1 |
LDIR |
|
LD |
B, 4 |
LD |
HL,L3-5 |
LD |
A, (IX+0) |
INC |
IX |
LD |
(HL),A |
INC |
HL |
LD |
A, (IX+0) |
INC |
IX |
LD |
(HL),A |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DEC |
HL |
DJNZ |
K2 |
LD |
BC, L3-L2 |
LD |
HL, L2 |
LDIR |
|
EXX |
|
DJNZ |
к0 |
DEC |
С |
JR |
NZ,K_1 |
EXX |
|
LD |
B,L4-L3 |
LD |
HL,L3LDIR |
LD |
HL,INT |
LD |
(#94FF),HL |
LD |
(FOR_SP),SP |
LD |
A, #94 |
LD |
I,A |
IM |
2 |
EI |
|
HALT |
|
LD |
BC,1026 |
END
угольник multicolor'a отцентрирован и занимает 16x16 знакомест. Атрибуты (2048 байт) должны располагаться с адреса SCR по 16 байт на строку.
;16X16 MULTICOLOR
ORG #8000 SCR EQU #C000
ENT $
FOR_SP L1
DEC |
BC |
LD |
A, B |
OR |
C |
JR |
NZ, K3 |
LD |
bc,(0) |
NOP |
|
NOP |
|
CALL |
L4 |
POP |
HL |
EXX |
|
IM |
0 |
EI |
|
RET |
|
LD |
bc,(0) |
LD |
bc,(0) |
RET |
|
DEFW |
0 |
LD |
SP,#0000 |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
SP,#0000 |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
LD |
DE,#0000 |
PUSH |
DE |
ADD |
HL, HL |
NOP |
|
LD |
B, 1790 |
DEC |
BC |
LD |
A, B |
OR |
C |
JR |
NZ,L31 |
LD |
R, A |
INC |
DE |
LD |
A, #7F |
IN |
A,(#FE) |
RRCA |
|
JP |
C, L4 |
LD |
SP,(FOR_SP) |
DEC |
SP |
DEC |
SP |
RET |
|
DEFS |
4954 |
NOP |
|
Программа аналогична пре |
EXX |
|
PUSH |
HL |
LD |
HL,#5888 |
LD |
IX, L4 |
LD |
A,16 |
LD |
C,8 |
LD |
DE,#0004 |
LD |
B, 8 |
PUSH |
HL |
LD |
(IX+0),#E1 |
LD |
(IX+1),#22 |
LD |
(IX+2),L |
LD |
(IX+3),H |
ADD |
IX, DE |
INC |
HL |
INC |
HL |
DJNZ |
K2 |
LD |
B, E |
LD |
(IX+0),D |
INC |
IX |
DJNZ |
K3 |
POP |
HL |
DEC |
С |
JR |
NZ, K1 |
LD |
BC,#0020 |
ADD |
HL, BC |
DEC |
A |
JR |
NZ, KO |
PUSH |
IX |
POP |
DE |
LD |
BQL3-L1 |
LD |
HL, L1 |
LDIR |
|
LD |
HL,INT |
LD |
(#92FF),HL |
LD |
(FOR_SP),SP |
LD |
A, #92 |
LD |
I,A |
IM |
2 |
EI |
|
HALT |
|
LD |
BC,956 |
DEC |
BC |
LD |
A, B |
OR |
С |
JR |
NZ, K4 |
LD |
BC,(0) |
NOP |
|
CALL |
L3 |
POP |
HL |
EXX |
|
IM |
1 |
EI |
|
RET |
|
RET |
|
DEFW |
0 |
LD |
BC, 1652 |
DEC |
BC |
LD |
A, B |
OR |
С |
JR |
NZ, L2 |
LD |
R, A |
LD |
A, #7F |
IN |
A,(#FE) |
|
RRCA |
|
|
JP |
C, L3 |
|
LD |
SP,(FOR_SP) |
|
DEC |
SP |
|
DEC |
SP |
|
RET |
|
L3 |
LD |
SP,SCR |
L4 |
DEFS |
4633 |
END |
NOP |
|
P.S. Буквально на днях посмотрел "INSULT MEGADEMO" Code Busters. Полноэкранный скроллер в "секретной" части megademo не явился для меня откровением.
Ввиду всего вышеизложенного, теоретически вопрос ясен (хотя от теории до практики всегда далеко). Следует только заметить, что размеры scroИer'а по горизонтали нельзя существенно улучшить, поскольку быстрейшая команда вывода на бордюр OUT (#FE),A длится 11 тактов, а реально применимая OUT (C),reg8 -12 тактов, что представляет собой 12x24 точки экрана, то есть 3 знакоместа (что, похоже, и реализовано в megademo).
СОДЕРЖАНИЕ:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Форум-Игры - рассмотрены следующие игры: Venturama, The sceptre, Carrier command, Elite, Sim city, Robin of the wood, Think, Hacker 2, Rampage, Звёздное наследие, "A.T.F.", Colony.
-
Перекресток - рассмотрены следующие адвентюры: He-man, Hampstead, Звёздное наследие, Rebel planet, The famous five, Terrormolinos, Sam spoon, Spiderman, Kentilla, Heavy on the magic, Magnetic moon.
-
-
-
-
-
-
-
-
-
-
-
-
-
|
|