Ассемблер - взгляд издалека
Продолжение.
Начало в || 20, 21, 24, 25, 28-30, 32, 33
{}Инфарх, 2000
Привет, энтузиасты! Что, небось заскуча-
ли на каникулах? Ничего, сейчас продолжим.
На этот раз мы с вами поговорим о работе
с прерываниями. Для начала уясним, что это
такое. Итак...
Прерывания
Вы, может, и не подозреваете, что 50 раз
в секунду процессор отвлекается от обра-
ботки вашей программы и занимается неиз-
вестно чем... Например, опрашивает клавиа-
туру, изменяет значение системной перемен-
ной FRAMES и т.д. Причём, делает это так,
что вы об этом и не догадываетесь. В эти
моменты происходит следующее: процессор
обращается к подпрограме по адресу 56, как
будто выполняет команду RST 56 или
CALL 56. Отличие в том, что переход осу-
ществляется не программно, а аппаратно.
Завершив выполнение вызванной процедуры,
процессор продолжает выполнять основную
программу.
На первый взгляд может показаться, что
от такой "фишки" проку никакого, ведь
программно в ПЗУ ничего не изменишь. К
счастью, программист имеет возможность по-
менять адрес, по которому расположена про-
цедура обработки прерываний. Для этого ис-
пользуется упомянутый ранее регистр I.
Прежде всего, надо запомнить, что имеет-
ся три режима обработки прерываний. Они
обозначаются соответственно цифрами от 0
до 2. Стандартный режим - 1. Именно его
эксплуатирует операционная систама. Нуле-
вой режим нам не особенно интересен: на
практике он ничем не отличается от перво-
го. Заметьте, именно на практике! Разли-
чия, конечно, есть, да только в Спектруме
они не реализованы. Таким образом, самым
интересным для нас является режим 2.
Для начала пару слов о том, как он рабо-
тает и что в этот момент в компьютере тво-
рится. Когда приходит сигнал прерывания,
процессор, для начала, определяет адрес
указателя на процедуру обработки прерыва-
ний. Оный состоит из двух байт: младшего,
считанного с шины данных (его также имену-
ют "вектор прерываний"), и старшего, счи-
танного с регистра I. Полученное значение
помещается на шину адреса, а предыдущее её
содержимое сохраняется на стеке. Всё это,
в сущности, является вариантом вызова
подпрограммы.
"Но что означает этот термин - "вектор
прерываний"?" - спросите вы. Дело в том,
что термин этот связан с работой компьюте-
ров, в которых предусмотрена возможность
поступления нескольких запросов на преры-
вание ОДНОВРЕМЕННО. Естественно, в этой
ситуации необходимо определиться, какое из
прерываний имеет приоритет. А это значит,
что запрос на прерывание следует рассмат-
ривать как "вектор", который, как и всякий
порядочный вектор, характеризется, как ми-
нимум, двумя значениями (в данной ситуации
- источником и приоритетом). При поступле-
нии запроса на прерывание оно обрабатыва-
ется или игнорируется в зависимости от
приоритета над выполняемым в данный момент
прерыванием.
Ну, а для Спектрума, хоть в нём и ис-
пользуется только одно прерывание, термин
этот, тем не менее, сохранён. Вот и вся
недолга.
Как правило, значение вектора прерываний
у Speccy равно 255, поэтому для определе-
ния адреса указателя достаточно содержимое
регистра I умножить на 256 и прибавить
255. Итак, попробуем вообразить те дейс-
твия, которые необходимо произвести для
применения собственной процедуры обработки
прерывания:
1) Запретить прерывания. Это необходимо
во избежание запуска новой процедуры пре-
рывания во время работы текущей, что чре-
вато...
2) Записать по адресу, рассчитанному за-
ранее, указатель на процедуру обработки
прерываний, а именно её адрес.
3) Задать в регистре I старший байт ад-
реса указателя на процедуру обработки.
4) Установить второй режим обработки
прерываний.
5) Вновь разрешить прерывания.
Естественно, процедура обработки преры-
ваний на данный момент уже должна нахо-
диться в памяти.
Вот вкратце и всё. Теперь - пару слов о
средствах реализации. Точнее, о командах.
Итак:
DI запрещение прерываний
EI разрешение прерываний
IM 0
IM 1
IM 2 Установка одного из трёх режимов
прерываний
Теперь у вас есть и команды. Однако пе-
ред установкой своей процедуры обработки
подумайте о том, должна ли она отключаться
и возвращать управление стандартной проце-
дуре. Для отключения же необходимо:
1) Запретить прерывания.
2) Восстановить значение I, записав в
него 63.
3) Назначить командой IM 1 первый режим
прерываний.
4) Разрешить прерывания.
Но и это ещё не всё. Необходимо помнить,
что некоторые внешние устройства могут из-
менять значение вектора прерываний. Кроме
того, если ваш Speccy собран на коленях
"кривыми ручками" по заляпанной пивом схе-
ме, вектор прерывания может скакать самым
непредсказуемым образом. Естественно, в
таком случае вероятность вызова процедуры
обработки равняется 1/256. Во избежание
глюков и головной боли программисты прибе-
гают к следующему приёму: вместо записи
двух байт по определённому адресу выстраи-
вается таблица размером не менее 257 байт
с таким расчётом, чтобы в любом случае
считывался один адрес. Естественно, для
этого все элементы таблицы должны быть
одинаковы.
Наиболее удачным значением для заполне-
ния этой таблицы является 255. Не пугай-
тесь, что адрес процедуры будет равен
#FFFF. Этого одного байта как раз хватит
для размещения кода 24 (команда JR). За
ней последует адрес #0000, по которому в
ПЗУ находится значение #F3. Таким образом
получается JR 65524. По этому адресу уже
можно разместить комаду JP с самым произ-
вольным адресом перехода.
Рассмотрим пример установки своей про-
цедуры обработки прерываний:
LD A,24 ;код команды JR
LD (65535),A
LD A,195 ;код команды JP
LD (65524),A
LD HL,ISR ;адрес обработчика
LD (65525),HL
LD HL,#FE00
LD DE,#FE01
LD BC,#0100
LD (HL),#FF
LD A,H
LDIR
DI
LD I,A
IM 2
EI
Вот мы и подключили процедуру обработки
прерываний. Рассмотрим теперь обратный
процесс, а именно возврат к режиму IM 1.
DI
LD A,63
LD I,A
IM 1
EI
И напоследок - пример. Допустим, вы хо-
тите воспроизводить музыку во время работы
вашей программы. Если вы используете мело-
дию, откомпилированную в одном из музы-
кальных редакторов и оснащённую стан-
дартным плеером, проблем у вас не возник-
нет. Для проигрывания необходимо каждые
1/50 секудны вызывать плеер, а значит,
частота прерываний вам идеально подходит.
Перед тем, как начать воспроизведение, не-
обходимо проинициализировать плеер, сделав
CALL по сответствующему адресу. Адрес ини-
циализации, равно как и проигрывания, за-
висит от конкретного редактора и условий
компиляции. Однако часто бывает, что ини-
циализация расположена в самом начале ме-
лодии, а проигрывание ноты ещё на шесть
байт дальше. Если допустить, что мелодия
компилирована под адрес #C000, то инициа-
лизация будет расположена по адресу #C000,
а воспроизведение ноты - по адресу #C006.
Теперь подкорректируем наши примеры. В
процедуру установки второго режима преры-
ваний добавьте CALL #C000 для инициализа-
ции. Это следует проделать и с процедурой
восстановления прежнего режима прерываний.
Для чего? Чтобы после того, как вы отклю-
чили музыку, AY не продолжал тянуть пос-
леднюю ноту. Инициализация позволит вам
быстро "заткнуть глотку" динамику.
А теперь посмотрм на саму процедуру:
ISR DI
PUSH AF ;сохраняем все регистры
PUSH BC ;для нормального возврата
PUSH DE ;в основную программу
PUSH HL
CALL #C006;вызываем плеер
POP HL ;восстанавливаем
POP DE ;сохраненные значения
POP BC
POP AF
EI ;разрешение прерываний
RET ;и возврат
Если вы всё сделали правильно и опреде-
лили адреса инициализации и проигрывания,
музыка должна зазвучать.
Упомянём ещё одну команду для облегчения
жизни - HALT. Когда процессор набредает на
неё, он приостанавливает работу и ждёт
сигнала прерывания. После его поступления
управление передаётся процедуре обработки
прерывания. А после её завершения основная
программа продолжает свою работу с коман-
ды, следующей за HALT. Это позволяет ис-
пользовать HALT для синхронизации вашей
программы с прерываниями.
Ну, вроде всё пока с теорией. Осталось
только, как водится, изложить кое-что о
флагах и вариантах команд. Взгляните:
╔═══════════╤═══════════════╗
║ Мнемоника │ Флаги ║
║ операции ├───────────────╢
║ │ C Z P/V S N H ║
╟───────────┼───────────────╢
║ DI │ . . . . . . ║
║ EI │ . . . . . . ║
║ IM 0 │ . . . . . . ║
║ IM 1 │ . . . . . . ║
║ IM 2 │ . . . . . . ║
║ LD A,I │ . x x x 0 0 ║
║ LD I,A │ . . . . . . ║
║ HALT │ . . . . . . ║
╚═══════════╧═══════════════╝
Вот и все флаги. Теперь можете смело
приступать к озвучиванию своих программ.
Не забывайте только, что некоторые плееры
имеют привычку разрешать прерывания. Также
непосредственно после перехода на процеду-
ру обработки прерываня по HALT прерывания
оказываются запрещёнными.
Продолжение следует...
──══════════──