Сегодня этот раздел мы хотим начать с критического письма в адрес ЭТЮДОВ, поступившего от Сергея Колотова из г. Шадринск Курганской обл. Он пишет:
Раздел ЭТЮДЫ является одним из любимейших для меня в вашем журнале. Хотя я и не беру из него все программы целиком, но некоторые из них привлекают к себе хорошей идеей, и я пишу свои аналогичные, но более эффективные процедурки.
Все, вроде, в ЭТЮДАХ хорошо, но где же главная цель этого раздела? Вспомним, о чем писал в 3 номере РЕВЮ за прошлый год основоположник раздела А.А.Иванов. Цель рубрики должна состоять не в публикации кучи различных процедур, а в совершенствовании техники программирования, создании "алмазов". Конкурсы, задачи и их элегантные решения - вот чему должно уделяться внимание на страницах ЭТЮДОВ. Тот раздел, который существует сейчас, можно назвать не "ЭТЮДЫ", а "НА СВАЛКЕ".
Ну это, пожалуй уже через край. Хотя мы и согласны с началом письма, но уверены, что с последним замечанием не согласятся и наши читатели. Мы бы назвали не НА СВАЛКЕ, а В МАГАЗИНЕ. На свалку выбрасывают никому не нужные вещи, а в магазин идут, когда хотят приобрести что-то полезное. Именно так считает большинство наших читателей, судя по их письмам. Что до отсутствия конкурсов, так это дело времени. Выдумывать, "высасывая из пальца"различные задания для читателей, мы считаем малополезным занятием. Задачи должна ставить жизнь. Ну а пока идеи не сформулировались в четкую задачу, публикуются готовые процедуры. Ведь что происходит, когда читатель посылает нам свою (или не свою, а вытащенную из другой программы) процедуру? Он делится с нами тем, что его заинтересовало, или тем, с чем ему пришлось столкнуться, будь то эффект с экраном или что-то другое. И пусть даже его способ не оптимален. Публикуя его вариант, мы надеемся, что кто-нибудь тоже решил эту задачу, и сделал это иначе. На самом деле так и есть, читатели пишут нам и делятся более эффективными вариантами. Пробегитесь внимательно по предыдущим выпускам ЭТЮДОВ - Вы найдете не одно подтверждение этому. Разве не в этом смысл раздела ЭТЮДЫ? Да и сегодняшний выпуск не будет исключением. Сейчас к нам поступают письма с идеями, касающимися именно техники программирования.
Однако возвращаемся к письму Сергея Колотова:
Предлагаю читателям подумать над некоторыми задачками. Победителем будет считаться тот, чьи решения будут наиболее компактными и короткими. И еще одно замечание. Все решения должны быть оформлены как подпрограммы и не должны использовать процедуры ПЗУ. Итак, вот конкретные задачи:
1. Вычислить HL=B*C
2. Отсортировать по возрастанию массив, начинающийся в памяти с адреса, указываемого HL, длина массива задана в BC.
3. Календарь. В регистре DE год. В регистре С - месяц. Надо получить в регистре А число дней в месяце.
4. Увеличить изображение в центральной части экрана в два раза так, чтобы оно занимало весь экран (графика + атрибуты).
5. Закрасить экран атрибутом, заданным в А, закручивающейся по часовой стрелке спиралью, с задержкой, величина которой может быть регулируемой и задана в ВС или одном из регистров этой регистровой пары (манипуляция только с файлом атрибутов).
6. Напечатать символ, код которого задан в аккумуляторе, размером во весь экран, атрибутом, заданным в С (манипуляция только с файлом атрибутов).
А теперь я вношу свой вклад в раздел ЭТЮДЫ. Речь пойдет все о той же "гасилке" экрана. Предлагаю такую процедуру, написанную специально для побития рекорда. Она занимает 23 (!) байта и при этом имеет возможность полноценной регулировки скорости.
1 |
; © SerzhSoft'95 |
|
|
|
|
|
10 |
|
|
DEC |
|
HL |
2 |
PAUSE |
EQU |
|
|
5 |
|
|
11 |
|
|
BIT |
|
3,H |
3 |
|
ORG |
|
50000 |
|
|
12 |
|
|
JR |
|
NZ, L2 |
4 |
|
ENT |
|
$ |
|
|
13 |
|
|
LD |
|
B,PAUSE |
5 |
CLRSCR |
LD |
|
C,127 |
|
|
14 |
L3 |
|
HALT |
|
6 |
L1 |
LD |
|
HL,23295 |
|
|
15 |
|
|
DJNZ |
|
L3 |
7 |
L2 |
LD |
|
A,(HL) |
|
|
16 |
|
|
RRC |
|
C |
8 |
|
AND |
|
C |
|
|
17 |
|
|
JR |
|
C, L1 |
9 |
|
LD |
|
|
(HL),A |
|
|
18 |
|
|
RET |
|
|
|
|
|
C350 |
|
0E 7F |
21 |
FF |
5A |
7E |
A1 |
77 |
B0 |
|
|
|
|
C358 |
|
2B CB |
5C |
20 |
F8 |
06 |
05 |
76 |
06 |
|
|
|
|
C360 |
|
10 FD |
CB |
09 |
38 |
EC |
C9 |
00 |
F1 |
|
Присмотримся внимательнее к его процедуре. Начало - традиционное. А вот и оригинальная идея. Адреса в файле атрибутов изменяются не от начала, используя инкремент, а от конца, используя декремент. Что это дает? Число 23295 в двоичном представлении выглядит так: 01011010 11111111 а 22528 так: 01011000 00000000 а 22527 так: 01010111 11111111
Вы уже поняли: третий бит старшего регистра (он подчеркнут) равен единице при уменьшении адреса в файле атрибутов, и становится равным нулю при переходе в дисплейный файл. Его-то и контролирует команда в строке 10. Благодаря этому приему удалось выгадать "победный" байт.
Логично выглядит и использование регистра В и команды DJNZ в цикле задержки вместо JR NZ.
И еще о строке 16. Совсем не важно, используется ли в ней команда сдвига или ротации - в последнем случае единственный "ноль" в маске, перемещаясь от старших разрядов к младшим, поочередно гасит их. Так как старшие разряды атрибутов уже обнулены, то при сравнении по ИЛИ в строке 8, там нули и останутся.
Да, друзья, всего два месяца продержался предыдущий рекорд, и вот новый рекордсмен - Сергей Колотов из Шадринска! Скажет ли кто-нибудь следующее слово?
К другим работам Сергея мы вернемся чуть ниже. А пока поговорим о конкурсе. Со своей стороны можем добавить к вышеперечисленным еще одну конкурсную задачу, которая, как мы уже говорили, подсказана самой жизнью.
Речь идет о дистрибуции программного обеспечения. Дело в том, что мы получаем сейчас очень много программ, в которых управление (опрос клавиатуры, джойстиков) выполнено, мягко говоря, некорректно. Из-за этого многие из них не хотят работать на других моделях Спектрум-совместимых компьютерах несмотря на то, что благополучно работают на компьютере автора. В других программах никак не удается "попасть" в нужный пункт меню из-за отсутствия задержки перед автоповтором (это, наверняка замечали все). Иные "виснут" на компьютерах без порта KEMPSTON-джойстика. В других не предусмотрено элементарное REDEFINE KEYS. В общем, для многих программистов это стало настоящей проблемой из-за того, что они не знают всех особенностей компьютерного парка нашей страны. В то же время существует множество программ, которые имеют удобное управление и прекрасно работают на любых компьютерах.
Сдвиги в решении этой проблемы можно получить только благодаря коллективным усилиям. Идея такая. Вы присылаете нам процедуры опроса (условно назовем их KEY-INPUT), которые считаете наиболее удачными. Мы публикуем их после собственного тестирования и предлагаем читателям сделать то же самое. Вы опробуете их, и у кого эти процедуры не захотят себя хорошо вести, сообщают нам (вместе с подробностями о Вашем компьютере и ПЗУ) или добиваются от них "примерного поведения" и тоже сообщают нам. Мы же, по результатам такого "всеобщего" тестирования сможем предложить всем наиболее удачные варианты и рекомендовать их для использования в своих авторских программах. Кстати, это очень хорошо согласуется и с мнением о создании рынка процедур, высказываемым во многих письмах.
Второй момент. Мы не собираемся оговаривать заранее какие-то условия, связанные с работой процедур KEY-INPUT. Пусть условия будут свободными. Это может быть процедура, гоняющая стрелку по экрану в четырех направлениях, или выбирающая пункт в меню на экране (вверх-вниз), или выдающая результат в системной ячейке, или что-то еще. Ценными остаются общие требования: минимальная длина, максимальная эффективность.
В качестве примера, приводим одно письмо.
© Алексей Артамонов, г. Москва, 1995.
Перед тем, как вам написать, я долго мучился с программами (прикладными, игровыми и системными) в которых программистом не предусмотрен выбор управления. Жестко заданное управление не всегда для всех приемлемо. У меня в таких случаях очень быстро пропадает интерес к программе. Чтобы этого не случалось с программами, которые создают читатели, я предлагаю дать возможность пользователю выбрать удобное ему управление. Обычно используют следующие виды управления: KEMPSTON, SINCLAIR (левый и правый), CURSOR, KEYBOARD. С джойстиками, то есть с программой, которая их будет опрашивать, у Вас вряд ли будет какая-нибудь проблема (практика показывает, что проблемы есть и с этим вопросом - прим. ИФК), а вот при написании программы для обслуживания клавиатуры желательно предоставить пользователю возможность переназначить клавиши по его желанию. Для этого неплохо бы написать универсальную программу, которая подходила бы к любым заданным клавишам. Кстати, если Вы дадите в своей программе выбирать и джойстики, то SINCLAIR 1 и 2 и CURSOR тоже может обслуживать эта программа, так как все эти джойстики "являются" клавишами клавиатуры. Исходя из всего вышесказанного, давайте напишем программу, которая бы обслуживала одновременно и KEMPSTON-джойстик и любые выбранные Вами клавиши:
LD |
D, 0 |
;Процедура, ко |
IN |
A,(31) |
;торая обслужи |
AND |
31 |
;вает KEMPSTON |
LD |
D, A |
;джойстик. |
RET |
NZ |
; |
LD |
B, 5 |
; Процедура, |
LD |
HL,TABL; |
|
LD |
A, (HL) |
; которая |
IN |
A, (254) ; |
|
INC |
HL |
; обслуживает |
AND |
(HL) |
; |
CPL |
|
;клавиши, |
CP |
255 |
; |
RL |
D |
;заданные |
INC |
HL |
; |
DJNZ |
LOOP |
;в таблице |
LD |
A, 31 |
; |
XOR |
D |
;TABL. |
LD |
D, A |
; |
RET |
; |
|
Теперь о таблице TABL. Ее формат должен быть следующий: 1-й байт - старший байт порта, который отвечает за полуряд на клавиатуре, 2-й байт - установленный бит соответствует нажатой клавише. Например, эти два байта указывают на клавишу SPACE: 127, 1. На выходе из программы в регистре D будут установлены те биты, которые соответствуют нажатым клавишам. То есть, если Вы в таблице поместили два байта, указывающие на клавишу "S", и если в регистре D установлен 0-й бит, то эта клавиша нажата. Команда XOR нужна для того, чтобы нажатая клавиша соответствовала установленному биту, а не сброшенному.
И еще. В данной процедуре большим приоритетом обладает KEMPSTON-джойстик. Так что если он находится не в нейтральном положении или нажата кнопка "огонь", то программа будет игнорировать клавиатуру.
Последнее замечание явно не удовлетворяет требованиям, предъявляемым к такого рода процедуре, хотя
сама идея интересна. Ну что же, будем ждать, что скажете Вы, уважаемые читатели.
* * *
Пара "классических" этюдов поступила практически одновременно из разных мест. Оба они содержались в письме Павла Старкова из Красноярска и в письме Эдуарда К. и Андрея Власова из Ростова-на-Дону.
Пара подпрограмм, которые могут оказаться полезными, например, при создании процедур вывода на экран спрайта с точностью до пикселя. На входе - в HL адрес в дисплейном файле. На выходе - в HL адрес, соответствующий ячейке на один пиксел ниже:
DOWN INC H
LD A, H
AND 7
RET NZ
LD A, L
ADD A,32
LD L, A
RET C
LD A, H
SUB 8
LD H, A RET
Длина процедуры: 15 байтов.
Вторая процедура с тем же параметром на входе, выдает в регистре HL адрес ячейки, соответствующий соседней сверху пиксельной линии:
DEC |
H |
LD |
A, H |
AND |
7 |
CP |
7 |
RET |
NZ |
LD |
A, L |
SUB |
32 |
LD |
L, A |
RET |
C |
LD |
A, H |
ADD |
A, 8 |
LD |
H, A |
RET |
|
Длина процедуры: 17 байтов.
А вот "маленькая хитрость ", которой поделился Максим Локтюхин из Саратова.
Что сделает обыкновенный начинающий программист, если ему понадобится удвоить содержимое регистровой пары BC?
PUSH |
HL |
|
PUSH |
HL |
LD |
H, B |
|
PUSH |
HL |
LD |
L, C |
|
POP |
BC |
ADD |
HL, BC |
или: |
ADD |
HL, HL |
LD |
B, H |
|
PUSH |
HL |
LD |
C, L |
|
POP |
BC |
POP |
HL |
|
POP |
HL |
Но если бы он был охотником, то мог бы считать, что у него убежало сразу три зайца: быстрота, размер, простота конструкции (использование дополнительного регистра HL). А убить их можно всего двумя "выстрелами" -командами SLA и RL:
SLA C (4 байта,
RL B 16 тактов)
Поясняю: SLA сдвигает младший байт влево, то есть увеличивает его вдвое, а если 7-й бит был включен, то выставится флаг С. RL - абсолютно то же самое, но если в предыдущей команде включился флаг С, то сейчас он запишется в младший бит старшего разряда регистровой пары. В общем получается то же, что и в приведенных выше программках, даже флаг С выставится, если значение регистровой пары было больше 32768.
Если дело касается регистра DE, то заслуживает внимания традиционный вариант. Он более короткий, однако менее быстрый:
EX DE,HL
ADD HL,HL (3 байта, EX DE,HL 19 тактов) Здесь нет необходимости сохранять на стеке содержимое регистровой пары HL (оно и так сохраняется в регистре DE), а вот для регистра BC или для ячейки памяти, адресуемой регистром HL, такой прием действительно пригодится:
SLA (HL) (4 байта, RL (HL) 30 тактов)
* * *
Пару "загадок" прислал Дмитрий Крапивин из Арзамаса:
1. DI
LD SP,767 (адрес в ПЗУ значения
M1 JR M1 не имеет).
Если запустить эту программу и нажать кнопку "MAGIC", то Speccy сбросится. Почему?
2. LD HL,PROG
LD (32767),HL
DI
LD A,127
LD I,A
IM 2
EI
L1 JR L1
PROG RET
А эта программа вообще "не умеет себя вести". Почему?
Начинающие программисты могут подумать над этими "загадками", но ответы посылать нам не надо
(кто не сумеет отгадать - узнает ответы в следующем номере).
* * *
И опять в нашей почте много писем, посвященных уменьшению длины процедуры гашения экрана. Но практически все - повторения уже придуманных ранее вариантов. Упомянем только письмо Дмитрия Блохина (BIT & BEAT) из Новомосковска, в котором использовался прием, похожий на предложенный Сергеем Колотовым:
6 L1 |
LD |
HL,23552 |
7 L2 |
LD |
A,(HL) |
8 |
AND |
C |
9 |
LD |
(HL),A |
10 |
I NC |
HL |
11 |
LD |
A, H |
12 |
AND |
4 |
13 |
JR |
Z, L2 |
Как видим, здесь следует инкремент регистра HL, и контроль 2-го бита регистра H: 22528 = #5800 = 01011000 00000000 23296 = #5B00 = 01011011 00000000
23551 = #5BFF = 01011011 11111111
23552 = #5C00 = 01011111 00000000
но есть побочный эффект: кроме файла атрибутов "обрабатывается" и область буфера принтера, так что "обнулится" любая информация, находящаяся там. В целом же процедура Дмитрия не побила рекорд, хотя осталось-то "додумать" совсем чуть-чуть.
Кстати, раз уж разговор коснулся процедуры гашения экрана, то можем сообщить еще один интересный факт. Несмотря на обилие писем и вариантов с решением проблемы, только один (!) человек (Вячеслав © SBM из Владивостока) заметил, что сравнивать процедуру из TERMINATOR с процедурой Шишкина и другими, алгоритм которых приводился в прошлом номере, - некорректно, так как в TERMINATOR'е гашение происходит одновременным гашением PAPER и INK, а в приводимых более простых вариантах - сначала гашение битов PAPER, затем - INK.
Как сказал один из наших корреспондентов: "Читая - думайте"! К чему приводит упрощение алгоритма, мы уже знаем из прошлого выпуска ЭТЮДОВ (вспомните хотя бы ну очень короткую процедуру).
Посмотрите, что произойдет, скажем с белым цветом в процедуре из TERMINATOR'а? Сначала он станет желтым, потом голубым, зеленым... и т.д. до черного. Вне зависимости от того, PAPER это или INK плюс полноценные 8 градаций вот что придает процедуре из TERMINATOR'а такое приятное на взгляд ощущение. Все-таки западных программистов "голыми руками не возьмешь " - у них есть, чему поучиться! Но резервы по упрощению процедуры все-же есть. Для этого надо вспомнить все оригинальные идеи, предложенные нашими корреспондентами во время "мозгового штурма".
Вячеслав предлагает процедуру зажигания экрана, для работы в паре с "гасилкой" (работающую, однако, все-таки по упрощенному алгоритму, а не как в TERMINATOR'е). Примечательность её в том, что она является полным "антиподом" процедуры гашения. В "гасилке" маска сдвигалась вправо, заполняя старшие разряды нулями. В "зажигалке" - маска сдвигается влево, а младшие разряды заполняются "единицами".
"Стоп! Разве есть команда такого сдвига?" - спросит читатель, внимательно изучив наш ТРЕХТОМНИК по машинным кодам.
Такая команда существует, хотя и является недокументированной. Это SLI Сравните:
Коды команд SLI:
SLI B - CB 30 SLI C - CB 31
SLI D - CB 32 SLI E - CB 33
SLI H - CB 34 SLI L - CB 35
SLI (HL) - CB 36 SLI A - CB 37
Набирать же эти команды в ассемблере придется не иначе, как при помощи пары DEFB. Для корректной работы процедуру пришлось дополнить очисткой экрана, включая 2 нижних строки (обнулением атрибутов) перед переброской дисплейного файла из буфера. Кроме того, мы немного "оптимизировали" процедуру Вячеслава, используя "последние достижения" технической мысли Сергея Колотова, и в таком виде предлагаем её читателям:
1 BUFF |
EQU |
51000 |
18 |
|
LD |
DE,BUFF+6911 |
2 PAUSE |
EQU |
5 |
19 |
L2 |
LD |
A, (DE) |
3 |
ORG |
50000 |
20 |
|
AND |
C |
4 |
ENT |
$ |
21 |
|
LD |
(HL),A |
5 |
LD |
HL,#5800 |
22 |
|
DEC |
HL |
6 |
LD |
(HL),L |
23 |
|
DEC |
DE |
7 |
LD |
D, H |
24 |
|
BIT |
3,H |
8 |
LD |
E, L |
25 |
|
JR |
NZ, L2 |
9 |
INC |
DE |
26 |
|
LD |
B,PAUSE |
10 |
LD |
BC, #02FF |
27 |
L3 |
HALT |
|
11 |
LDIR |
|
28 |
|
DJNZ |
L3 |
12 |
LD |
HL,BUFF |
29 |
|
DEFB |
#CB |
13 |
LD |
DE,#4000 |
30 |
|
DEFB |
#31 |
14 |
LD |
BC,#1800 |
31 |
|
JR |
NC, L1 |
15 |
LDIR |
|
32 |
|
POP |
HL |
16 |
LD |
C, 0 |
33 |
|
RET |
|
17 L1 |
LD |
HL,23295 |
|
|
|
|
Длина процедуры = 51 байт:
C350 |
21 |
00 |
58 |
75 |
54 |
5D |
13 |
01 |
C6 |
C358 |
FF |
02 |
ED |
B0 |
21 |
38 |
C7 |
11 |
EA |
C360 |
00 |
40 |
01 |
00 |
18 |
ED |
B0 |
0E |
27 |
C368 |
00 |
21 |
FF |
5A |
11 |
37 |
E2 |
1A |
E9 |
C370 |
A1 |
77 |
2B |
1B |
CB |
5C |
20 |
F7 |
CF |
C378 |
06 |
05 |
76 |
10 |
FD |
CB |
31 |
30 |
F5 |
C380 |
E8 |
E1 |
C9 |
00 |
00 |
00 |
00 |
00 |
D5 |
Кстати, в процедуре можно было обойтись и документированными командами:
29 CCF
30 RL C однако такая конструкция имеет длину три байта, так что использование SLI оправдано тем, что экономит один байт.
* * *
А теперь возвращаемся к письму, с которого мы начали сегодняшний раздел ЭТЮДЫ.
RES |
5,(IY+1) |
LD |
HL,#4000 |
PUSH |
HL |
CALL |
RND 2 |
POP |
HL |
LD |
A,(SEED) |
OR |
(HL) |
LD |
(HL),A |
INC |
HL |
BIT |
5,(IY+1) |
RET |
NZ |
LD |
A, H |
CP |
#58 |
JR |
NZ,LOOP |
JR |
BEGIN |
Измерялось время полного заполнения экрана цветом INK. В приведенной Сергеем процедуре оно составило 12 секунд против 18 секунд у прототипа. Увеличение быстродействия в полтора раза при сокращении длины почти вдвое (с 85 до 45 байт) - это очень неплохой результат!
Но и на этом не заканчивается письмо Сергея.
И, напоследок, предлагаю довольно-таки интересную процедуру прорисовки предварительно загруженной в буфер картинки с возрастающим шумовым эффектом. Она называется SHOWER. Ручаюсь - такой Вы ещё не встречали.
© Сергей Колотов, г. Шадринск, 1995.
В ZX-РЕВЮ^, № 6, на стр.5 был опубликован генератор случайных чисел. Мне удалось существенно сократить программу, причем и время выполнения уменьшилось. Вот в этом-то и состоит смысл раздела ЭТЮДЫ (да кто же с этим спорит-то - прим. ИФК), ведь программистам нужны самые эффективные и быстроработающие процедуры. А в конечном итоге пользователям программ станет удобнее работать с ними и меньше времени тратить на ожидание, например, пока компьютер перетасует колоду карт. Пожалуйста, опубликуйте эту процедуру.
Охотно делаем это:
1 ; © SerzhSoft'95 |
|
20 |
SBC |
HL, BC |
2 |
ORG |
50000 |
21 |
SBC |
A, E |
3 |
ENT |
$ |
22 |
LD |
B, H |
4 RND 2 |
LD |
HL,(SEED) |
23 |
LD |
C, L |
5 |
LD |
DE, 1 |
24 |
LD |
E, A |
6 |
XOR |
A |
25 |
ADD |
HL, HL |
7 |
ADD |
HL, DE |
26 |
RLA |
|
8 |
ADC |
A, D |
27 |
ADD |
HL, HL |
9 |
LD |
B, H |
28 |
RLA |
|
10 |
LD |
C, L |
29 |
ADD |
HL, BC |
11 |
LD |
E, A |
30 |
ADC |
A, E |
12 |
ADD |
HL, HL |
31 |
LD |
E, A |
13 |
RLA |
|
32 |
SBC |
HL, DE |
14 |
ADD |
HL, HL |
33 |
LD |
E, D |
15 |
RLA |
|
34 |
CCF |
|
16 |
ADD |
HL, HL |
35 |
SBC |
HL, DE |
17 |
RLA |
|
36 |
LD |
(SEED),HL |
18 |
ADD |
HL, HL |
37 |
RET |
|
19 |
RLA |
|
38 SEED |
DEFW |
0 |
Длина процедуры = 45 байтов:
C350 |
2A |
7B |
C3 |
11 |
01 |
00 |
AF |
19 |
55 |
C358 |
8A |
44 |
4D |
5F |
29 |
17 |
29 |
17 |
15 |
C360 |
29 |
17 |
29 |
17 |
ED |
42 |
9B |
44 |
B1 |
C368 |
4D |
5F |
29 |
17 |
29 |
17 |
09 |
8B |
EB |
C370 |
5F |
ED |
52 |
5A |
3F |
ED |
52 |
22 |
CB |
C378 |
7B |
C3 |
C9 |
00 |
00 |
00 |
00 |
00 |
42 |
Проверку сравнительного быстродействия процедуры мы провели следующим образом:
1 ; © SerzhSoft'95 |
|
24 |
OR |
BORDER |
2 |
ORG |
50000 |
25 |
OUT |
(254),A |
3 |
ENT |
$ |
26 |
LD |
A, C |
4 BUFF |
EQU |
51000 |
27 |
RRCA |
|
5 TYPE |
EQU |
24 |
28 |
RRCA |
|
6 PAUSE |
EQU |
3 |
29 |
RRCA |
|
7 BORDER |
EQU |
0 |
30 |
DEC |
HL |
8 SHOWER |
LD |
HL,BUFF+6911 |
31 |
DEC |
DE |
9 |
LD |
DE,23295 |
32 |
DJNZ |
LP3 |
10 |
LD |
BC,768 |
33 |
RRCA |
|
11 |
LDDR |
|
34 |
BIT |
6,H |
12 |
EX |
DE, HL |
35 |
JR |
NZ,LP2 |
13 |
LD |
A, 128 |
36 |
POP |
HL |
14 LP1 |
PUSH |
DE |
37 |
POP |
DE |
15 |
PUSH |
HL |
38 |
LD |
B,PAUSE |
16 LP2 |
LD |
B,TYPE |
39 LP4 |
HALT |
|
17 LP3 |
LD |
C,A |
40 |
DJNZ |
LP4 |
18 |
EX |
DE, HL |
41 |
RRCA |
|
19 |
AND |
(HL) |
42 |
RRCA |
|
20 |
EX |
DE, HL |
43 |
RRCA |
|
21 |
OR |
(HL) |
44 |
JR |
NC,LP1 |
22 |
LD |
(HL),A |
45 |
RET |
|
23 |
AND |
248 |
|
|
|
Длина процедуры = 56 байтов:
C350 |
21 |
87 |
DE |
11 |
FF |
5A |
01 |
00 |
04 |
C358 |
03 |
ED |
B8 |
EB |
3E |
80 |
D5 |
E5 |
26 |
C360 |
06 |
18 |
4F |
EB |
A6 |
EB |
B6 |
77 |
39 |
C368 |
E6 |
F8 |
F6 |
00 |
D3 |
FE |
79 |
0F |
58 |
C370 |
0F |
0F |
2B |
1B |
10 |
EC |
0F |
CB |
6D |
C378 |
74 |
20 |
E5 |
E1 |
D1 |
06 |
03 |
76 |
E5 |
C380 |
10 |
FD |
0F |
0F |
0F |
30 |
D7 |
C9 |
4D |
Интересен параметр TYPE. От него зависит режим вывода картинки на экран. Допустимо большинство значений от 0 до 255, за исключением некоторых.
Во время вызова процедуры прерывания должны быть разрешены.
Прошу опубликовать мой адрес. Читатели, желающие написать мне, найдут единомышленника в следующих вопросах: ЭТЮДЫ, вирусы на ZX-Spectrum, адаптация программ под TR-DOS, Adventure games:
641812, Курганская обл.,
г. Шадринск, ул. Либкнехта,
д. 27, кв. 1. Колотову Сергею.
* * *
© Николай Губин, г. Новгород, 1995.
Предлагаю процедуру, выполняющую красивый эффект при помощи манипуляции с атрибутами. Цветовая волна как-бы расходится от центра к краям.
1 |
ORG |
50000 |
20 |
|
LD |
A, B |
2 |
ENT |
$ |
21 |
|
LD |
(POKE2+1),A |
3 START |
EI |
|
22 |
|
ADD |
A, A |
4 |
HALT |
|
23 |
|
LD |
(POKE3+1),A |
5 |
LD |
IX,TABL |
24 |
LOOP |
LD |
B,#10 |
6 |
LD |
HL,#5800 |
25 |
LOOP1 |
INC |
E |
7 |
LD |
BC,#0105 |
26 |
|
LD |
A, E |
8 |
CALL |
ATR |
27 |
|
AND |
#1F |
9 |
CALL |
I NTAB |
28 |
|
LD |
(NUM+2),A |
10 |
LD |
A, #7F |
29 |
NUM |
LD |
A,(IX+0) |
11 |
IN |
A,(#FE) |
30 |
|
LD |
(HL),A |
12 |
RRA |
|
31 |
|
INC |
HL |
13 |
JR |
C,START |
32 |
|
DJNZ |
LOOP1 |
14 |
RET |
|
33 |
|
LD |
B,#10 |
15 ATR |
LD |
E,0 |
34 |
LOOP2 |
DEC |
E |
16 |
LD |
A, C |
35 |
|
LD |
A, E |
17 |
SRL |
A |
36 |
|
AND |
#1F |
18 |
INC |
A |
37 |
|
LD |
(NUM1+2),A |
19 |
LD |
(POKE1+1),A |
38 |
NUM1 |
LD |
A,(IX+0) |
39 |
|
LD |
(HL),A |
56 |
|
RET |
|
40 |
|
INC |
HL |
57 |
INTAB |
LD |
HL,TABL+1 |
41 |
|
DJNZ |
LOOP2 |
58 |
|
LD |
DE,TABL |
42 |
|
LD |
A, C |
59 |
|
LD |
BC,#20 |
43 |
POKE1 |
CP |
4 |
60 |
|
LD |
A, (DE) |
44 |
|
JR |
Z,CONT |
61 |
|
LDIR |
|
45 |
|
PUSH |
AF |
62 |
|
LD |
(DE) , A |
46 |
|
LD |
A, E |
63 |
|
RET |
|
47 |
POKE2 |
ADD |
A,4 |
64 |
TABL |
DEFB |
0,#40,1,#41 |
48 |
|
LD |
E, A |
65 |
|
DEFB |
2,#42,3,#43 |
49 |
|
POP |
AF |
66 |
|
DEFB |
4,#44,5,#45 |
50 |
|
JR |
NC,CONT |
67 |
|
DEFB |
6,#46,7,#47 |
51 |
|
LD |
A, E |
68 |
|
DEFB |
#47,#47,7 |
52 |
POKE3 |
SUB |
4 |
69 |
|
DEFB |
#46,6,#45,5 |
53 |
|
LD |
E, A |
70 |
|
DEFB |
#44,4,#43,3 |
54 |
CONT |
DEC |
C |
71 |
|
DEFB |
#42,2,#41,1 |
55 |
|
JR |
NZ,LOOP |
72 |
|
DEFB |
#40,0 |
Длина процедуры = 143 байта: |
|
|
|
|
|
|
|
|
C350 |
FB |
76 |
DD |
21 |
BE |
C3 |
21 |
00 |
24 |
C358 |
58 |
01 |
05 |
01 |
CD |
6A |
C3 |
CD |
41 |
C360 |
B0 |
C3 |
3E |
7F |
DB |
FE |
1F |
38 |
83 |
C368 |
E7 |
C9 |
1E |
00 |
79 |
CB |
3F |
3C |
B8 |
C370 |
32 |
9D |
C3 |
78 |
32 |
A3 |
C3 |
87 |
5C |
C378 |
32 |
AA |
C3 |
06 |
10 |
1C |
7B |
E6 |
6D |
C380 |
1F |
32 |
86 |
C3 |
DD |
7E |
00 |
77 |
AF |
C388 |
23 |
10 |
F2 |
06 |
10 |
1D |
7B |
E6 |
04 |
C390 |
1F |
32 |
96 |
C3 |
DD |
7E |
00 |
77 |
CF |
C398 |
23 |
10 |
F2 |
79 |
FE |
04 |
28 |
0C |
2F |
C3A0 |
F5 |
7B |
C6 |
04 |
5F |
F1 |
30 |
04 |
21 |
C3A8 |
7B |
D6 |
04 |
5F |
0D |
20 |
CC |
C9 |
E1 |
C3B0 |
21 |
BF |
C3 |
11 |
BE |
C3 |
01 |
20 |
C9 |
C3B8 |
00 |
1A |
ED |
B0 |
12 |
C9 |
00 |
40 |
4D |
C3C0 |
01 |
41 |
02 |
42 |
03 |
43 |
04 |
44 |
97 |
C3C8 |
05 |
45 |
06 |
46 |
07 |
47 |
47 |
47 |
FD |
C3D0 |
07 |
46 |
06 |
45 |
05 |
44 |
04 |
43 |
BB |
C3D8 |
03 |
42 |
02 |
41 |
01 |
40 |
00 |
00 |
64 |
Для большей видимости эффекта можно набрать программу на Бейсике типа:
1 BORDER 0: PAPER 0: CLS
2 FOR F=0 TO 5: PRINT AT F,0;"3 2 л ю б ы х с и м в о л а ": NEXT F
3 RANDOMIZE USR 5E4
В блоке кодов установка сделана на 5 верхних строк, но можно сделать больше или меньше. Также можно изменить смещение: в строке 6 в листинге на ассемблере задается адрес в дисплейном файле, соответствующий началу области, охватываемой эффектом. В строке 7 в регистре С - количество строк, охватываемое эффектом. Для большей наглядности можете сделать следующие изменения:
7 LD BC,#0118
тогда эффект будет распространяться на весь экран (для видимости эффекта можете перед стартом процедуры загрузить на экран какую-нибудь картинку).
Интересен параметр, задаваемый в 7 строке в регистре В. Попробуйте задавать значения 0, 1, 2, 4, 10, 30 и увидите, как будет видоизменяться эффект.
© Евгений Любимов, Виталий Сердюк, г. Новокузнецк, 1995. Эту процедуру мы "вытащили" из Ьой'а, который называется "ZYX". Она дополнена предварительной установкой атрибутов для завершенности эффекта:
1 |
ORG |
50000 |
13 |
|
LD |
HL,16384 |
2 |
ENT |
$ |
14 |
L3 |
LD |
B, C |
3 |
LD |
HL,#5800 |
15 |
L1 |
XOR |
A |
4 |
LD |
D, H |
16 |
|
RR |
(HL) |
5 |
LD |
E, L |
17 |
|
INC |
HL |
6 |
INC |
DE |
18 |
|
XOR |
A |
7 |
LD |
(HL),7 |
19 |
|
RL |
(HL) |
8 |
LD |
BC,#02FF |
20 |
|
INC |
HL |
9 |
LDIR |
|
21 |
|
DJNZ |
L1 |
10 ; |
|
|
22 |
|
LD |
B, C |
11 |
LD |
D, 8 |
23 |
L2 |
XOR |
A |
12 L4 |
LD |
C,16 |
24 |
|
RL |
(HL) |
25 INC HL 31 CP 88
26 XOR A 32 JR NZ, L3
27 RR (HL) 33 DEC D
28 INC HL 34 JR NZ,L4 2 9 DJNZ L2 35 RET
30 LD A, H
Длина процедуры = 51 байт:
C350 |
21 |
00 |
58 |
54 |
5D |
13 |
36 |
07 |
8D |
C358 |
01 |
FF |
02 |
ED |
B0 |
16 |
08 |
0E |
E6 |
C360 |
10 |
21 |
00 |
40 |
41 |
AF |
CB |
1E |
6D |
C368 |
23 |
AF |
CB |
16 |
23 |
10 |
F6 |
41 |
48 |
C370 |
AF |
CB |
16 |
23 |
AF |
CB |
1E |
23 |
A1 |
C378 |
10 |
F6 |
7C |
FE |
58 |
20 |
E5 |
15 |
2D |
C380 |
20 |
DD |
C9 |
00 |
00 |
00 |
00 |
00 |
09 |
Следующая программа включает в себя две процедуры. Первая плавно "заливает" бордюр экрана, а вторая -так же плавно очищает его. Процедуры для удобства объединены в один блок.
1 ORG |
50000 |
|
24 |
|
OR |
L |
2 |
ENT |
$ |
25 |
|
JR |
NZ, L4 |
3 PROG1 |
LD |
HL,1 |
26 |
|
LD |
A,(L10) |
4 |
LD |
B, 160 |
27 |
|
OUT |
(254),A |
5 L2 |
PUSH |
BC |
28 |
|
RET |
|
6 |
PUSH |
HL |
29 |
L9 |
DEFB |
0 |
7 |
CALL |
L1 |
30 |
L10 |
DEFB |
1 |
8 |
POP |
HL |
31 |
; |
|
|
9 |
LD |
DE,10 |
32 |
PROG2 |
LD |
HL,1600 |
10 |
ADD |
HL, DE |
33 |
|
LD |
B, 160 |
11 |
POP |
BC |
34 |
L5 |
PUSH |
BC |
12 |
DJNZ |
L2 |
35 |
|
PUSH |
HL |
13 |
LD |
A, (L9) |
36 |
|
CALL |
L1 |
14 |
AND |
7 |
37 |
|
POP |
HL |
15 |
OUT |
(254),A |
38 |
|
LD |
DE,10 |
16 |
RET |
|
39 |
|
AND |
A |
17 L1 |
HALT |
|
40 |
|
SBC |
HL, DE |
18 |
LD |
A, (L9) |
41 |
|
POP |
BC |
19 |
OUT |
(254),A |
42 |
|
DJNZ |
L5 |
20 L4 |
DEC |
HL |
43 |
|
LD |
A,(L10) |
21 |
LD |
B,1 |
44 |
|
AND |
7 |
22 L3 |
DJNZ |
L3 |
45 |
|
OUT |
(254),A |
23 |
LD |
A, H |
46 |
|
RET |
|
Если первая процедура будет расположена с адреса 50000, то вторая окажется в 50049. Суммарная длина = 77 байтов:
C350 |
21 |
01 |
00 |
06 |
A0 |
C5 |
E5 |
CD |
52 |
C358 |
6A |
C3 |
E1 |
11 |
0A |
00 |
19 |
C1 |
1E |
C360 |
10 |
F3 |
3A |
7F |
C3 |
E6 |
07 |
D3 |
62 |
C368 |
FE |
C9 |
76 |
3A |
7F |
C3 |
D3 |
FE |
B5 |
C370 |
2B |
06 |
01 |
10 |
FE |
7C |
B5 |
20 |
C4 |
C378 |
F7 |
3A |
80 |
C3 |
D3 |
FE |
C9 |
00 |
49 |
C380 |
01 |
21 |
40 |
06 |
06 |
A0 |
C5 |
E5 |
FB |
C388 |
CD |
6A |
C3 |
E1 |
11 |
0A |
00 |
A7 |
E8 |
C390 |
ED |
52 |
C1 |
10 |
F1 |
3A |
80 |
C3 |
D1 |
C398 |
E6 |
07 |
D3 |
FE |
C9 |
00 |
00 |
00 |
E2 |
Использование программы:
10 RANDOMIZE USR 50049: RANDOMIZE USR 50000: GO TO 10
* * *
Мы рады сообщить, что читатели не забывают и про музыкальный процессор: начали поступать программки и по нему.
(C) Рустам Гайнутдинов, г. Зеленодольск, 1995.
Предлагаю программу-индикатор для музыкального сопроцессора. В результате её работы, по экрану будут "бегать" три разноцветные полосы, показывая текущий уровень сигнала в каждом канале.
1 ORG 50000 5 LD (NN+1),A
2 ENT $ 6 LD A, 8
3 LD IX,22855 7 CALL ANAL
4 LD A,32 8 LD IX,22887
9 |
LD |
A, 16 |
25 |
DEL1 |
LD |
A,(BUF) |
10 |
LD |
(NN+1),A |
26 |
|
AND |
A |
11 |
LD |
A, 9 |
27 |
|
JR |
Z, LEB |
12 |
CALL |
ANAL |
28 |
|
PUSH |
IX |
13 |
LD |
IX,22919 |
29 |
|
POP |
HL |
14 |
LD |
A,24 |
30 |
NN |
LD |
(HL),0 |
15 |
LD |
(NN+1),A |
31 |
|
LD |
HL,BUF |
16 |
LD |
A, 10 |
32 |
|
DEC |
(HL) |
17 |
CALL |
ANAL |
33 |
|
JR |
NEXT |
18 |
RET |
|
34 |
LEB |
PUSH |
IX |
19 ANAL |
LD |
BC,65533 |
35 |
|
POP |
HL |
20 |
OUT |
(C) , A |
36 |
|
LD |
(HL),00 |
21 |
IN |
A, (C) |
37 |
NEXT |
INC |
IX |
22 |
AND |
15 |
38 |
|
DJNZ |
DEL1 |
23 |
LD |
(BUF),A |
39 |
|
RET |
|
24 |
LD |
B, 15 |
40 |
BUF |
DEFB |
0 |
Длина процедуры = 85 байтов:
C350 |
DD |
21 |
47 |
59 |
3E |
20 |
32 |
93 |
D4 |
C358 |
C3 |
3E |
08 |
CD |
7B |
C3 |
DD |
21 |
2D |
C360 |
67 |
59 |
3E |
10 |
32 |
93 |
C3 |
3E |
F7 |
C368 |
09 |
CD |
7B |
C3 |
DD |
21 |
87 |
59 |
1D |
C370 |
3E |
18 |
32 |
93 |
C3 |
3E |
0A |
CD |
26 |
C378 |
7B |
C3 |
C9 |
01 |
FD |
FF |
ED |
79 |
A5 |
C380 |
ED |
78 |
E6 |
0F |
32 |
A4 |
C3 |
06 |
3C |
C388 |
0F |
3A |
A4 |
C3 |
A7 |
28 |
0B |
DD |
B2 |
C390 |
E5 |
E1 |
36 |
00 |
21 |
A4 |
C3 |
35 |
0C |
C398 |
18 |
05 |
DD |
E5 |
E1 |
36 |
00 |
DD |
2E |
C3A0 |
23 |
10 |
E6 |
C9 |
00 |
00 |
00 |
00 |
45 |
Теперь о применении полученного блока кодов "mus"CODE 50000,85.
Предположим, у Вас имеется подготовленный и скомпилированный в адрес 51000 пакетом SOUND TRACKER, музыкальный фрагмент "SONG".
Тогда для проигрывания музыки и индикации потребуется Бейсик-программа (с автостартом со 2-й строки):
1 GO TO 100
2 BORDER 0: PAPER 0: INK 7: CLEAR 49999: RANDOMIZE USR 15619: REM : LOAD "SONG"
CODE
3 RANDOMIZE USR 15619: REM : LOAD "mus" CODE
4 FOR a=USR "a" TO USR "a"+7: READ b: POKE a,b: NEXT a: RUN : DATA 0,119,119,119,119,119,119,0
10 RANDOMIZE USR 51000: FOR i=10 TO 12: PRINT INVERSE 1;AT i,6;CHR$ (55+i); INK 0;"AAAAAAAAAAAAAAAA": NEXT i: RETURN: REM UDG 100 GO SUB 10
110 RANDOMIZE USR 51006: RANDOMIZE USR 50000: PAUSE 1: IF INKEY$="" THEN GO TO
110
120 GO SUB 10
Строка 4 формирует UDG-символ "А ", при помощи которого изображаются очень симпатичные сегменты
индикатора. В строке 10 происходит инициализация звукового модуля и печать сегментов индикатора цветом
PAPER. А наложение атрибутов выполняет предложенная программа в кодах. Это происходит в строке 110 после
проигрывания очередного такта.
Строка 120 прекращает музыку при нажатии на любую клавишу.