Среди множества команд микропроцессора 1801 есть несколько команд, действие которых состоит в следующем: вызывается прерывание по фиксированному адресу (адрес вектора прерываний - а.в.п.). Вот эти команды:
Таблица 4.0. Команды-прерывания.
Команда |
Код |
А.В.П. |
BPT | 000003 | 14 |
IOT | 000004 | 20 |
EMT | 104xYZ | 30 |
TRAP | 104XYZ | 34 |
Пример 11. Упражнение с командами-прерываниями IOT и EMT.
Команда IOT (Input-Output Trap) вызывает прерывание с адресом 20. В Системе этот а.в.п. никак не используется. Восполним же этот пробел. Работаем в ОЗУ ПП:
20: 000240
240: 104044 EMT 44
163573 "* ЗАГРУЗКА ИЗ СЕТИ
*"
000002 RTI
Теперь в любую свободную ячейку запишите число 4 (код IOT) и запустите с этого адреса. Ну, а если Вам наскучит играться с этой надписью, в приложении найдите другую, и адрес ее запишите после кода EMT 44. А еще лучше - читайте дальше.
Первые две команды (
BPT и IOT) нам неинтересны, хотя при желании и их можно пустить в дело. Две остальные - EMT и TRAP - представляют некоторый интерес.Старший байт этих команд содержит код команды (по нему процессор опознает их), а младший может быть любым. Такая организация команд позволяет нести в себе полезную информацию. Чтобы реализовать эту информацию, надо к каждому прерыванию подвесить свои программы обработки прерываний, которые называются диспетчерами.
Это название связано с тем, что в зависимости от кода в младшем байте, эти программы передают управление разным подпрограммам, выполняющим каждая свое действие. Это позволяет использовать команды EMT и TRAP как однословные команды вызова подпрограмм.
Рассмотрим реализацию обоих диспетчеров в Системе.
По адресу 30 записан вектор прерывания EMT-дипетчера:30: 174270
32: 000000
Первое слово - адрес диспетчера. Второе - слово, которое загружается в слово состояния процессора (PS) при входе в программу обработки прерываний. 0 означает, что разрешены все прерывания во время работы EMT-диспетчера.
Ниже приведена блок-схема EMT-диспетчера с пояснениями:
Из схемы видно, что диспетчер вызывает подпрограмму, адрес которой определяется по следующей формуле:
Адр=(160000+XXX), где XXX - младший байт EMT.
Иными словами, с адреса 160000 хранится таблица, в которой содержатся адреса искомых подпрограмм. Разумеется, младший байт EMT должен быть четным, во избежание недоразумений в процессоре.
В адресах ПЗУ с 160000 по 160012 хранятся некоторые вектора прерываний, поэтому используются EMT с младшими байтами, начиная с 14. Полезных подпрограмм, вызываемых EMT-диспетчером, всего 10. Перечень их приведен в приложении. Остальные подпрограммы состоят из одной команды - RETURN.
Вектор TRAP-диспетчера записан по адресу 34:
34: 174344
36: 000200
Второе слово говорит о том, что во время работы TRAP-диспетчера будут запрещены прерывания от сетевого и программируемого таймеров, от клавиатуры, от команды RESET в ЦП, от прерываний каналов.
Блок-схема TRAP-диспетчера выглядит так:
Адрес подпрограммы вычисляется так:
Адр=(160160+XXX), где XXX - младший байт TRAP.
Т.е. адреса подпрограмм хранятся с адреса 160160. Этих подпрограмм всего 3, т.е. имеют смысл лишь три команды TRAP:
TRAP 0,
TRAP 2,
TRAP 4.
Отличие их от EMT-подпрограмм в том, заканчиваться они должны на RTI, а не на RETURN.
Информация на экран отправляется побайтно. Каждый процессор
может иметь доступ к выводу символьной и графической информации на терминал. Для этого у каждого процессора свой путь.ЦП посылает информацию через К0. ПП отправляет ее через команды EMT. Но в любом случае эти байты записываются в особую область ОЗУ ПП, называемую буфером. Он находится в адресах с 2000 по 2177 (200 байт).
Буфер позволяет не ждать, пока отправленный байт выведется на экран (тем или иным способом), и представляет собой "очередь" байтов, готовых к обработке (выводу).
Переменная в ОЗУ ПП (22544) является указателем на "хвост" этой очереди. То есть она содержит адрес ячейки, куда будет записана очередная поступившая посылка (от ЦП или ПП).
При записи из ЦП в канал К0 при разрешенном прерывании от приемника в ПП выполняется прерывание с а.в.п. 320. Если прерывания запрещены, тогда есть другой способ считать информацию из К0 в буфер - это команда TRAP 4. Тогда, если посылка действительно была (установлен бит готовности в приемнике), информация считывается в буфер из соответствующего регистра данных.
И п.о.п от К0, и TRAP 4 - это, по сути, одна и та же программа, но с разными точками входа (схема 5.1).
Здесь используется еще
несколько переменных. Смысл их в следующем:
Таблица 5.1
Адрес | Назначение |
7042 | Разрешает
либо запрещает связь с ЦП через К0: 0 - связь
запрещена, |
7064 | Счетчик байт, подлежащих обработке. Может содержать от 0 до 177. |
22546 | Признак переполнения буфера. Если (7064)=177, и поступает новый байт, запись его в буфер не производится, а (22546) присваивается 2 (переполнение). Сбрасывается через TRAP 4. |
Буфер может пополняться также из ПП. Для этого могут использоваться три команды: EMT 42, EMT 44 и EMT 46.
EMT 42 записывает в буфер младший байт R0, EMT 44 - строку, адрес которой содержится в слове, следующем за командой, а EMT 46 - строку с адресом в R1.
На схемах
5.2 и 5.3 показано выполнение этих команд. Поскольку EMT - подпрограммы можно вызывать и через CALL, на схеме показаны и адреса дополнительных точек входа.Если выполнить, к примеру, такой отрывок программы:
JSR R5,@#117204
.WORD A
.
.
A: ASCIZ /*** ЗАЧЕМ ВАМ EMT 44? ***/
то в буфер загрузится строка, начальный адрес которой - A. Это будет несколько быстрее, чем с помощью фрагмента:
EMT 44
.WORD A
.
.
A: ASCIZ /*** ЧТО БЫ ВЫ БЕЗ EMT 44 ДЕЛАЛИ?
***/
поскольку минуется вызов EMT-диспетчера.
Заметим, что с указателем буфера после увеличения выполняется команда &~200, что предотвращает выход его за значение 2177.
Таблица 5.2
Что пишем и откуда |
Способы достижения |
|
С немедленным выводом |
Без такового |
|
1 байт из R0 | EMT 42 | CALL @#117136 |
Строка, адрес которой в R1 | EMT 46 | JSR R5, @#117206 |
Строка, адрес которой - A | EMT 44 WORD A |
JSR R5, @#117204 .WORD A |
Способы с немедленным выводом на экран отличаются выполнением TRAP 0 в конце подпрограммы.
6.0 Схема Диспетчера процессов.
Из всех процедур, выполняемых ПП, TRAP 0 - самая, пожалуй, необходимая и незаменимая. Кроме вывода на экран, она отвечает за множество других функций ввода-вывода, а также некоторых внутренних функций.
TRAP 0 можно назвать также и диспетчером процессов, который координирует работу внешних устройств, подстраивая под их нужды (и под нужды пользователя, в конце концов) все ресурсы, зашитые в ПЗУ.
Сама подпрограмма TRAP 0 немногословна. Она просто коротка (можете взглянуть на схему 6.0). Однако разобраться в ее работе сразу будет довольно трудно. Поэтому упрощенно рассмотрим "стратегию управления" в ОЗУ ПП.
Проследим, что происходит в УК при включении питания.
Далее вся работа ПП идет через диспетчер процессов. Как это происходит?
6.2 Запросы. Таблицы запросов и процессов.
Есть в ОЗУ ПП таблица по адресам с 7060 по 7102. Назовем ее таблицей запросов и попробуем объяснить это название.
Каждому слову в таблице соответствует своя задача:
7060 - обработка информации, поступающей от
клавиатуры,
7062 - загрузка с ВУ,
7064 - экранный вывод,
7066 - управление курсором,
7070 - меню "Установка режимов",
7072 - меня "Загрузка",
7074 - работа с принтером,
7076 - запуск подпрограммы пользователя,
7100 - тестирование,
7102 - выход в диспетчер процессов (обратно).
Нормальное состояние их - нулевое. Если необходимо выполнить какой-либо процесс из вышеперечисленных, к содержимому соответствующей ячейки прибавляется 1.
Диспетчер процессов работает по принципу цикла и в своей работе сканирует таблицу запросов. Найдя ненулевой какую-либо ячейку из таблицы (а просматривает он их по порядку), диспетчер вызывает соответствующую подпрограмму, т.е. сам процесс. Адреса таких подпрограмм составляют свою табличку - таблицу адресов процессов.
Эта таблица расположена в ПЗУ по адресам 174232...174252, т.е. содержит 9 адресов. Последней ячейке таблицы запросов 7102 не соответствует адреса в таблице адресов процессов.
Как и когда изменяется содержимое таблицы запросов? Мы уже встречались с ячейкой 7064 - каждый раз при записи в буфер байта она инкрементируется. Как видно из таблицы, эта ячейка действительно отвечает за экранный вывод. Если она установлена (не равна 0), диспетчер запускает подпрограмму экранного вывода, и та уже обрабатывает записанную в буфер информацию, вычитая из
(7064) единицу после каждого обработанного байта .Это повторяется до тех пор, пока ячейка не обнулится. Тогда происходит возврат в диспетчер процессов и сканирование продолжается.Аналогичным образом обходятся со своими ячейками запросов и другие процессы, причем одни декрементируют, а другие сразу обнуляют их.
Увеличение или установка запросов ведется "со стороны", в основном, по прерываниям: от клавиатуры, от каналов, от сетевого таймера.
Ячейка с адресом 7102 - последняя из таблицы запросов - не меняет своего значения - 1, и служит для возобновления цикла диспетчера процессов.
6.3 Таблица векторов. Вызов процессов через TRAP 0.
Сразу за таблицей запросов в ОЗУ следует еще одна таблица - таблица векторов. Если идет выполнение одного из процессов, и из него надо выполнить другой процесс, не завершая текущего, то вызывается TRAP 0 (как это делается из EMT 44, например). Вектор прерванного процесса, а точнее, текущий адрес переписывается в таблицу векторов. В ней каждой ячейке также соответствует процесс. Разница адресов "одноименных" ячеек таблицы запросов и таблицы векторов составляет 24.
Выполнив процесс, для которого он был вызван, TRAP 0 находит установленную ячейку в таблице запросов. В зависимости от содержания таблицы векторов (а точнее, той ее ячейки, которой соответствует установленный запрос) TRAP 0 либо возвращается в прерванный старый процесс через JMP (в таблице векторов - ненулевой вектор), либо запускает процесс через CALL (в таблице векторов - 0).
Небольшая тонкость: TRAP 0 не может выполнить процесс, стоящий "ниже" того, из которого он был вызван. То есть вызванный из программы вывода на экран (адрес запроса - 7064), он не дойдет до запросов, адреса которых больше 7064 и может обработать только клавиатуру и внешние устройства. Поэтому процессы расположены в порядке убывания важности.
Пример 12. Перехват запросов.
Таблица векторов - самая удобная лазейка для перехвата обработки запросов на процессы. Попробуем перехватить обработку запросов на процесс отслеживания курсора.
В мониторе ПП запишите следующее:
41000: 042737 BIC #200, @#177716
000200
177716
052737 BIS #200, @#177716
000200
177716
004737 CALL @#176056
176056
012737 MOV #41000, @#7112
041000
007112
000137 JMP @#174222
174222
7112: 041000
При каждом обращении к процессу отслеживания курсора теперь прозвучит щелчок пьезодинамика.
6.4 Внутренние и внешние процедуры.
Все процедуры, исполняемые ПП, можно разделить на внутренние и внешние относительно диспетчера процессов. Внутренние - процессы, контролируемые диспетчером. Внешние - это подпрограммы, не подконтрольные диспетчеру (программы обработки прерываний).
Внешние процедуры не имеют права вызывать TRAP 0, это приведет к тому, что диспетчер процессов "вылетит" из цикла и машина подвиснет.
Адреса таблиц запросов векторов, а также содержимое таблицы задач приведены в таблице 6.0:
Таблица 6.0.
N | Процесс | Адрес запроса | Адрес вектора | Адрес процесса |
1 | Терминальный ввод | 7060 | 7104 | 104306 |
2 | Загрузка с ВУ | 7062 | 7106 | 125030 |
3 | Терминальный вывод | 7064 | 7110 | 111144 |
4 | Управление курсором | 7066 | 7112 | 176056 |
5 | Меню "Установка режимов" | 7070 | 7114 | 100040 |
6 | Меню "Загрузка" | 7072 | 7116 | 100742 |
7 | Работа с принтером | 7074 | 7120 | 176076 |
8 | Подпрограмма пользователя | 7076 | 7122 | 176116 |
9 | Тестирование | 7100 | 7124 | 176460 |
10 | Цикл диспетчера процессов | 7102 | 7126 | - |
Пример 13. Перехват цикла диспетчера процессов. Способ 1.
Последнее слово таблицы векторов 7126 содержит число 174222 (адрес рестарта диспетчера процессов). В принципе, ничто не мешает записать туда другой адрес, а по нему сделать что-нибудь типа продолжения диспетчера процессов.
Наш процесс останется тем же - щелчок:
41100: 042737 BIC #200, @#177716
000200
177716
052737 BIS #200, @#177716
000200
177716
000137 JMP @#174230
174230
7112: 000000
7126: 041100
Не удивляйтесь, однако, что после внесенных изменений все останется как бы по-прежнему - тишь да гладь. Монитор ПП тому причина - он является часть процесса меню "Установка", и покуда Вы в находитесь в нем, диспетчер процессов на дойдет до конца таблицы запросов, а значит, и до запроса рестарта. Выйдите из этого меню, и, если Вы не попадете сразу после этого в меню "Загрузка", являющееся, кстати, одним из процессов, то услышите звук с частотой около 10 Кгц.
Пример 14. Перехват цикла диспетчера процессов. Способ 2.
Посмотрим, что произойдет , если обнулить вектор рестарта диспетчера процессов: (7126)=0. Тогда диспетчер станет обрабатывать процесс рестарта через CALL, взяв адрес из таблицы адресов процессов в ПЗУ. Но такого адреса для процесса рестарта на предусмотрено, и диспетчер возьмет первую ячейку после таблицы. Ее содержимое - 13700, а значит, произойдет вызов подпрограммы по адресу 13700. Это и есть второй способ вывести цикл диспетчера на свою концовку. Выход из этой концовки должен осуществляться через RETURN.
13700: 000137 JMP @#41200
041200
41200: 042737 BIC #200, @#177716
000200
177716
052737 BIS #200, @#177716
000200
177716
000207 RETURN
7126: 000000
Набив этот примерчик и выйдя из всех меню, Вы услышите звук. Итак, мы научили диспетчер процессов свистеть.
Все, что входит в пункт 4, вызывается диспетчером процессов.
1) внутренние по отношению к диспетчеру процессов (сами процессы),
2) внешние по отношению к нему (программа начального запуска, подпрограммы обработки прерываний).