Ресурсы УКНЦ/Глава 3: различия между версиями
Nzeemin (обсуждение | вклад) |
Xolod (обсуждение | вклад) Нет описания правки |
||
(не показаны 2 промежуточные версии 1 участника) | |||
Строка 138: | Строка 138: | ||
=== § 8. Программа экранного вывода === | === § 8. Программа экранного вывода === | ||
Начнем разбирать самую важную программу экранного вывода. На схеме 8.0 дан ее алгоритм. Начало важных участков помечено метками (M…). | |||
Описание сей программы — пожалуй, самое скучное место в главе, посему прибегать к чтению сей вирши следует только по необходимости. Ежели таковая отсутствует, предлагаем Вам перескочить сразу к резюме, что находится на стр …. | |||
Итак, начали… | |||
M0 ... M1 (адреса 111144-111202): | |||
> Устанавливается ячейка (7066) из таблицы запросов, показывая, что надо высветить курсор. | |||
> R5 загружается из ячейки 23150 начальным адресом текущей экранной карты. | |||
> Регистры кода цвета точки и фона заружаются из экранной карты: | |||
РТ из (R5+34), | |||
РФ из (R5+40). | |||
Заметим, что оба слова РФ загружаются из одной и той же переменной. | |||
> В регистр управления отображением, в 1-й байт пишется цвет курсора из ячейки (R5+70). В этой ячейке, помимо цвета, можно задать и вид курсора (графический или символьный), а также позицию графического курсора в октете. | |||
* Итак, загружены цвета точки и знакоместа. Курсор готов ко включению. | |||
M1 ... M2 (адреса 111204-111230): | |||
> Из буфера в R0 пишется 1 байт. | |||
Ячейка (22542) служит указателем буфера при выводе на экран. Ее отличие от ячейки (22544) в следующем: | |||
(22544) указывает на место в буфере, куда запишется очередной байт (голова буфера). | |||
(22542) указывает, откуда в буфере следует читать новый байт (хвост) (см. рис. 8.0). | |||
< Рис. 8.0 Масенький рисунок-пояснение > | |||
Ясно, что (22542) должен указывать на адрес, не больший того, на котоый указывает (22544) (голова всегда впереди хвоста): | |||
(22542)<=(22544). | |||
> Изменяется указатель-хвост - (22542). Он инкрементируется, а для предотвращения выхода за пределы буфера над ним выполняется команда &~200. | |||
> В стек пишется число 111126. Это сделано для того, чтобы при команде RETURN из любого места управление передавалось на адрес 111126 (а не сразу в Диспетчер). | |||
> Из R0 выделяется младший байт. | |||
* Итак, из буфера в R0 записан байт. Перехвачено управление на выходе по RETURN. | |||
M2 ... (адреса 111232... ): | |||
> В зависимости от значения R0 содержимое интерпретируется либо как управляющий код (меньше 40), либо как символ (больше 40). | |||
1. УПРАВЛЯЮЩИЙ КОД: | |||
> В зависимости от содержимого ячейки (22552) управляющий код либо отображается на экране (режим ИСУ - индикации символов управления), либо идет "исполнение" управляющего кода. | |||
а) (22552)<>0 - "ИСУ": | |||
M21 ... M22 (адреса 111730-112020): | |||
> В угловых скобках печатается трехзначное восьмеричное число, равное управляющему коду. | |||
M22 ... RETURN (адреса 112022 ... 113036): | |||
> Если управляющий код - 12 (ВК), выполняется "возврат каретки" (код 25). | |||
б) (22552)=0 - не "ИСУ": | |||
M20 ... | |||
> Содержимое R0 умножается на 2, к результату прибавляется 13142. Получившееся число - адрес ячейки, в которой содержится адрес соответствующей спецфункции. (О спецфункциях см. ниже). | |||
> Идет переход на адрес спецфункции. | |||
2. СИМВОЛ. | |||
M3 ... M4 (адреса 111260 ... 111314): | |||
> Если R0>=100, к нему по ИЛИ добавляется содержимое ячейки (22556). Эта ячейка используется для переключения между алфавитами (русский/latinsky). | |||
> Содержимое R0 умножается на 2, к результату прибавляется 14142 - начальный адрес таблицы знакогенератора. Слово из ячейки с получившимся адресом пишется в R1. Это - адрес знакогенератора (таблички, содержащей 11 байт). Каждый байт В ЗГ представляет собой сечение символа, т.е октет. | |||
> R0 загружается из (R5+10) шагом в ВОЗУ между видеостроками. | |||
> В R2 пишется 177010 (адрес РА), в R3 - 177024 (адрес РО). В РА пишется текущий адрес ВОЗУ в данном экране (первое слово ЭК). | |||
* Итак, все готово к тому, чтобы нарисовать символ: | |||
R1 указывает на знакогенератор, | |||
R0 содержит шаг в ВОЗУ, | |||
R2, R3 содержат адреса регистров адреса планов и октета. | |||
РА загружен текущим адресом ВОЗУ. | |||
M4 ... M5 (адреса 111316-111420): | |||
> К счетчику команд прибавляется содержимое ячейки (R5+56). Если не включены режимы инверсии или подчеркивания, эта переменная равна 0. При включении соответствующего режима она загружается определенным значением. Тогда управление передается на адрес, вычисляемый так: | |||
А=111322+(R5+56). | |||
> Если это - нормальный режим, то все 11 байт из знакогенератора переписываются в ВОЗУ через РО. При этом установленным разрядам в этих байтах соответствует цвет символа, а сброшенным - цвет знакоместа. Если инверсия - перед записью в октет байты инвертируются. Если подчеркивание - последний байт заменяется на 377. | |||
* Итак, символ нарисован. | |||
M5 ... M9. | |||
> К текущему адресу ВОЗУ (первая ячейка ЭК) прибавляется 1. Из (R5+16) вычитается 1. Ячейка (R5+16) показывает позицию символа в строке, начиная с правого края. Для крайнего правого знакоместа эта ячейка равна 1. Вы все еще читаете? Странно. | |||
> Если получившееся значение (R5+16) отлично от 0 (не достигнут правый край), выполняется RETURN. | |||
* Ну что ж... Изменена текущая позиция знакоместа (по оси X). | |||
> Если (R5+16)=0 (правый край экрана), выполняется переход на новую символьную строку. При этом в (R5+16) копруется содержимое (R5+4), равное количеству знакомест в строке, выводимых в данный экран. Кстати, это количество не обязательно равно числу октетов в данном режиме (80, 40, 20 или 10). | |||
> Текущий адрес в таблице строк - (R5+32) - увеличивается на 54 (разница в адресах элементов через 11 видеострок). | |||
> В текущий адрес ВОЗУ - (R5) - записывается содержимое переменной (R5+22). Эта ячейка содержит номер знакоместа (слева), с которого начинается вывод в строке. | |||
> В случае, если обнаружен конец таблицы строк, т.е. текущий адрес таблицы строк равен конечному: | |||
(R5+32)=(R5+26), | |||
текущим адресом становится начальный: (R5+32):=(R5+24). | |||
> К текущему адресу ВОЗУ - (R5) - прибавляется адрес ВОЗУ, на который указывает текущий элемент таблицы строк. Номер текущей символьной строки уменьшается на 1 (он считается снизу): | |||
DEC 20(R5). | |||
* Изменилась позиция по Y (в случае перехода на новую символьную строку). | |||
> Если это не самая нижняя строка на экране - (R5+20) не равно 0 - выполняется RETURN. | |||
M12 ... | |||
> В противном случае (нижняя строка) - встает выбор - прокручивать рулон на одну символьную строку вверх (рулон включен) или не прокручивать (выключен). За состояние рулона (включен-выключен) отвечает последняя переменная экранной карты - (R5+74). | |||
... M13 - рулон выключен: | |||
> Вывод идет опять с верхнего края экрана. Для этого текущим адресом в таблицЕ строк становится адрес верхней строки, а текущим адресом ВОЗУ - соответствующий адрес ВОЗУ + отступ от левого края. | |||
> Номер текущей символьной строки (отсчитываемой снизу), становится максимальным: | |||
(R5+20):=(R5+12). | |||
Затем - выход по RETURN. | |||
... M14-M15 - рулон включен. | |||
> В этом случае (R5+20) инкрементируется. | |||
> В стек пишется 13. Это - смещение экрана при прокрутке. | |||
> К адресу верхней строки в таблице строк прибавляется 54, показывая, что после прокручивания рулона верхней строкой на экране станетдругая (ниже на 11 видеострок). | |||
> Если адрес верхней строки в таблице строк равен 4670 (конечный адрес), он заменяется на 2500 (начальный адрес). | |||
M15 ... | |||
> Здесь идет установка рулона на прокручивание. Проверяется счетчик рулона - ячейка (23170). Если он пуст (равен 0), гасится курсор, очищается новая символьная строка (которая пока не высвечивается - она внизу, за горизонтом): | |||
CALL 113344, | |||
и к счетчику прибавляется число из стека (13). Если счетчик на момент проверки был больше 14 (по модулю), выполняется TRAP 0. Затем R5 загружается из (23150) и все поторяется с M15. | |||
Прокрутка рулона осуществляется через сетевой таймер. Работа таймерной программы описывается в главе 5. Пока лишь отметим, что ячейка (23170) отвечает за рулон: содержимое ее показывает, на сколько пиксел надо прокрутить экран. Положительные значения соответствуют прокрутке вверх, отрицательные (в дополнительном коде) - вниз. | |||
* Итак, алгоритм работы программы разобран. | |||
Теперь осталось рассмотреть, что происходит при выполнении RETURN из данной программы. | |||
Как уже отмечалось, по RETURN управление передается на адрес 111126. Здесь делается следующее: | |||
> Вычитается 1 из (7064), т.е. снимается 1 запрос. | |||
> Если (7064) стал равен 0 (запросов нет), а также нет переполнения буфера ((22546)=0), выполняется выход из программы в Диспетчер через RETURN. | |||
> Если же (7064) не равно 0, (еще остались запросы на экранный вывод), проверяется ячейка (7060), содержащая запросы от клавиатуры. Если последних нет ((7060)=0), идет возврат на нашу процедуру, к метке M1, и все повторяется. | |||
Если все-таки запрос на клавиатуру есть, выполняется выход в Диспетчер, чтобы этот запрос удовлетворить. | |||
> Найдя буфер переполненным, ((22546)=2), вызывается TRAP 4 (он считывает байт из канала). В (7064) добавляется еще один запрос, и опять - на адрес 111126. | |||
* Таким образом, выход в Диспетчер осуществляется: | |||
1) При наличии запросов на клавиатуру и на экран. 2) При исчерпании запросов на экран, если буфер не переполнен. | |||
Для тех, кому недосуг разбираться в алгоритме, и просто лентяев (то есть практически для всех): | |||
==== Резюме к § 8 ==== | |||
в котором вкратце сказано, как устроен экранный вывод и как он обходится с экранными картами: | |||
• Экранная карта имеет цель сообщить миру, как устроен данный экран и в каком он сейчас состоянии (и в состоянии ли он вообще). | |||
• Те переменные, которые сообщают об устройстве экрана, назовем статическими, поскольку они не изменяются с момента создания экранной карты. | |||
• Те переменные, которые можно поменять (в основном, с помощью спецфункций, которых мы скоро коснемся), назовем полудинамическими. Характерной переменной этой группы является "цвет символа", например. | |||
• И, наконец, переменные, которые меняются практически при каждом выводе символа (например, позиция текущего знакоместа на экране), обзовем динамическими. | |||
Каждую группу переменных мы сведем в таблицы. | |||
< Здесь, по идее, находятся 3 таблицы: 8.1, 8.2, 8.3 > | |||
< А еще здесь - рисунок 8.4 - Активная страница экрана > | |||
• И, кратко, работа самой программы: | |||
1) Из ЭК в видео-регистры загружаются цвета символа и знакоместа, а также курсора. Включается курсор. | |||
2) Из буфера берется байт. Проверяется его характер. Если он меньше 40 (байт, а не характер), то это управляющий код, ему соответствует определенный адрес. На этот адрес передается управление. | |||
Если байт >=40, то это символ. Его надлежит вывести на экран. | |||
3) Вывод на экран осуществляется из знакогенератора (ЗГ). ЗГ - это табличка, в которой каждому коду (символу) соответствует 11 байт. Эти 11 байт составляют один символ на экране (11*8 точек). | |||
Есть 3 режима вывода на экран: | |||
- нормальный, | |||
- инверсия (все байты выводятся на экран инвертированные), | |||
- подчеркивание (самый нижний байт любого символа выводится "закрашенным" - число 377). | |||
4) После вывода символа текущее знакоместо меняет свою позицию (меняются соответствующие переменные в ЭК). | |||
5) Ели необходимо, дается команда "крутануть" рулон на 11 видеострок вверх (экран заполнен). | |||
6) Если в буфере еще есть байты, которые необходимо "обработать", все повторяется с пункта 2. | |||
Однако, если при этом есть запрос с клавиатуры, осуществляется выход в Диспетчер. | |||
Также выход в Диспетчер происходит при исчерпании запросов (буфер пуст). | |||
=== § 9. Спецфункции === | === § 9. Спецфункции === | ||
Строка 145: | Строка 351: | ||
'''''TODO''''' | '''''TODO''''' | ||
, и таблица настроена на него, т.е. указывает на адреса в ПЗУ. | |||
При желании можно сделать свой знакогенератор, и настроить таблицу на него. Для размещения альтернативного знакогенератора выделена память в ОЗУ ПП - это адреса с 15142 по 22540. Здесь Ваш ЗГ никто не потревожит, разве что другой любитель изобретать алфавиты. | |||
Таблица спецфункций (ТСФ) начинается с адреса 13142. В ней тоже хранятся адреса. Но это уже адреса подпрограмм, называемых спецфункциями. Каждому коду соответствует своя СФ. | |||
==== 9.1. Вызов спецфункций. Код 33. ==== | |||
Как вызываются спецфункции с кодами до 40, мы уже видели: программа экранного вывода, обнаружив такой код, тут же отправляется на адрес, который она находит в таблице спецфункций (ТСФ). | |||
А как быть с кодами от 40? Ведь программа экранного вывода проинтерпретирует такой байт как символ. Чтобы показать Системе, что на данный код надо ответить спецфункцией, предназначен управляющий код 33. 33 ставится перед требуемым кодом, и эта парочка интерпретируется как СФ. | |||
Как это происходит? Взгляните на схему 9.0. На ней дана блок-схема СФ-33, а также блок-схема одной незаменимой подпрограммки. | |||
Итак, получив код 33, Система вызвала СФ-33. Работает эта СФ следующим образом. | |||
* Указатель стека сохраняется в ячейке (23152). Ячейка (23174) становится равной 2. Этим показывается, что идет работа "через 33". | |||
* Вызывается подпрограмма с адресом 110762, после которой в R0 оказывается наш байт (следующий за кодом 33). | |||
* Далее идет вызов искомой спецфункции, обнуление ячейки (23174), восстановление указателя стека и возврат. | |||
Здесь все ясно (по крайней мере автору). Теперь посмотрим, что делается в подпрограмме 110762. | |||
* Подобно программе экранного вывода, здесь идет работа с буфером. Обнаружив поступление очередного байта, следующего за 33 ((7064) не равна 0), подпрограмма пишет в R0 искомый код. | |||
* Если он - от 40, происходит возврат из подпрограммы. Иначе (меньше 40) вызывается соответствующая спецфункция (тут же, внутри этой п/п), а по выходе из СФ - опять, на начало п/п. Исключение делается для кода 33 - при его обнаружении идет "выброс" в СФ-33, в точку с адресом 113544. | |||
* Если же код еще не поступил, (7064)=0, идет выход в Диспетчер, чтобы при поступлении его снова войти в эту подпрограмму с адреса 110726. При переполнении буфера вызывается TRAP 4, и снова - начало подпрограммы. | |||
==== 9.2. Действия спецфункций. ==== | |||
'''''TODO''''' | |||
=== §10. EMT 52, 56, 40 === | === §10. EMT 52, 56, 40 === | ||
Строка 232: | Строка 467: | ||
- включение курсора, | - включение курсора, | ||
- начальные установки цветов символа и знакоместа. | - начальные установки цветов символа и знакоместа. | ||
[[Категория:УКНЦ]] |
Текущая версия от 12:21, 20 ноября 2023
Глава 3. Стандартный экранный вывод.
§ 7. Разделение экранов
Итак, мы разобрались с буфером и с Диспетчером. Рассмотрим такую рядовую ситуацию: ПП «кружит» в Диспетчере, сканируя таблицу запросов и с нетерпением ожидая задачи на исполнение.
Пусть теперь ЦП по каналу К0 послал байт (пока неважно какой). Сработает прерывание от приемника К0 со стороны ПП. Наш байт запишется в буфер, указатель буфера изменится.
Также установится ячейка (7064) в таблице запросов. Программа обработки прерывания завершается, и управление возвращается в Диспетчер. Он обнаруживает, что поступил запрос на обслуживания экрана (ячейка (7064) не равна 0) и запускает подпрограмму экранного вывода, адрес которой находит в таблице задач.
Этот адрес — 111144.
Вряд ли стоит спешить сходу описывать эту подпрограмму. Вообще-то она не очень сложная. Просто будет удобнее подойти к ней с другой стороны.
7.0. Принцип разделения экранов
Из множества хитростей, заложенных в УК разработчиками, эта, на первый взгляд, в глаза не бросается. Однако без нее УК — не УК.
Допустим, Вы работаете в Бейсике, или в пультовом отладчике, и понадобилось, например, изменить цвет символа. Что Вы делаете? Нажимаете клавишу «УСТ». Что происходит? Появляется меню «Установка режимов». Выполнив необходимые манипуляции с этим меню, Вы возвращаетесь опять в ту же среду, где находились, нажатием клавиш «ИСП» или «Ввод».
При этом никаких изменений в текущем экране Вы не находите. Даже курсор на том же месте.
Иными словами, работа в меню «Уст» не касалась Вашей программы и Вашего экрана. Эта работа велась в другом экране. Каким образом этот другой экран влез вместо основного, рабочего? Конечно же, с помощью таблицы строк. Она стала указывать на другие адреса в ВОЗУ, и, таким образом, сделала видимой видеоинформацию другой области видеопамяти.
В этом заключается принцип разделения экранов в УК. Вместо того, чтобы копировать массивы видеоинформации, сохраняя старое изображение, просто меняются несколько ячеек в таблице строк, и в результате перед Вами — новый экран.
7.1 Стандартные экраны в УК-НЦ
Поскольку таблица строк указывает на целые строки, а не на их отрезки, экраны в УК представляют собой горизонтальные «полосы» на всю ширину экрана, различной высоты и расположения на экране.
Системой поддерживаются 4 стандартных экрана (см. рис. 7.0).
Два из них можно назвать экранами лишь с натяжкой. Они представляют собой по символьной строке каждая — служебная (вверху) и информационная (внизу). Эти «экранчики» всегда присутствуют на терминале. Каждая из них содержит 40 знакомест.
Служебная строка служит для отображения текущего алфавита (РУС/ЛАТ), индикации режимов инверсии, подчеркивания, дополнительной клавиатуры (ИНВ, ПОДЧ, ДКЛ), режима индикации символов управления (ИСУ), режима «Установка режимов» (УСТ). Разработчиками предусмотрен вывод и кое-каких других надписей в верхнюю строку, но почему-то Система не использует эти возможности.
Нижняя инфо-строка в Системе вообще не используется.
Для вывода в эти строки предназначены ЕМТ 52 и ЕМТ 56. Но о них позже. Пока — на очереди еще 2 экрана.
Они выводятся в «окошко» между служебной строкой и инфо-строкой. Один — назовем его рабочим — самый главный в УК. В нем работают практически все программы пользователя.
Этот экран содержит 26 символьных строк по 80 символов максимум. Из этих 26 строк 24 всегда выводятся на экран, а две оставшиеся можно просмотреть, циклически сдвинув экран вверх или вниз с помощью команд терминала (УПР+R или УПР+V). Лишь в этом экране действует рулон, и меню «Установка режимов» меняет режимы этого экрана (меняет цвета, формат рабочего экрана, тип рулона).
И последний стандартный экран — служебный. Он содержит 20 символьных строк, максимум по 40 символов в каждой. Рулон в этом экране всегда выключен. Служебный экран используется для размещения меню «Установка режимов», а также под монитор ПП.
Входят в этот монитор так: вызывают меню «Установка» нажатием УСТ, а затем нажимают ГРАФ + ИСП или УПР + @. Работа в мониторе ПП аналогична работе в мониторе ЦП. Однако подвесить машину здесь намного легче. Выход из него в меню «Установки» выполняется нажатием УПР + C.
Каждому экрану в таблице строк соответствуют свои регистры управления цветом и отображением. Их адреса даны в таблице 7.1. Напомним, что каждый из этих регистров занимает в таблице строк 2 слова.
TODO: Таблица 7.1. Адреса регистров управления отображением и цветом для стандартных экранов.
Экран Адр. УО Адр. УЦ Рабочий 2460 2470 Служебный 4670 4700 Служебная строка (верхняя) 2370 2400 Инфо-строка (нижняя) 6740 6750
Ячейка с адресом 2476 содержит информцию о том, какой экран - рабочий или служебный - будет отображаться в окне:
1) рабочий экран: (2476)=2500 2) служебный экран: (2476)=4672.
7.2. Экранные карты
Как отображаются экраны и как отобразить, к примеру, служебный экран вместо рабочего, ясно. Но как организуется вывод в каждый экран так, чтобы было полное разделение экранов? И можно ли конструировать свои экраны так, чтобы вывод в них выполнялся с помощью стандартного обеспечения столь же легко и удобно, как и в рабочий экран?
Оказывается, можно.
Вывод на экран требует размещения в ОЗУ некоторых переменных, например, цвета символа, знакоместа, текущего адреса в ВОЗУ и т.д. Чтобы разделение экранов было полным, у каждого из экранов есть своя саО H8jщiующая и т.д. Тогда обращение к переменным будет выглядеть так:
Смещение Ассемблер Блок-схема 10 10(R5) (R5+10) 2 2(R5) (R5+2)
В таблице 7.2 приведены смещения переменных, их смысл, а также характерные значения для каждого из четырех экранов.
< Таблица 7.2 Экранные карты >
Подробное использование переменных из экранных карт будет дано ниже, вместе с алгоритмом экранного вывода.
Пример 15. Вечные строки.
Войдите в монитор ПП. Перед Вами - служебный экран. Давайте украсим его какими-нибудь приличными, но нестираемыми надписями.
Нажав D, Вы окажетесь в режиме терминала. Очистите экран - <СБРОС>, и сделайте какую-нибудь приличную надпись в верхней строке. Затем выйдите из этого режима - <УПР>+C.
Теперь, чтобы зафиксировать сделанную надпись, изменим некоторые переменные экранной карты:
1) (+2): (22756)=155430 (сместим начальный адрес ВОЗУ "вниз"), 2) (+30):(23004)=5104 ("опустим" адрес верхней видеостроки в таблице строк), 3) (+14):(22770)=312 (уменьшим количество стираемых видео-строк на 11):, 4) (+12):(22766)=23 (уменьшим на 1 количество символьных строк).
Этими действиями мы исключили нашу строку из служебного экрана, хотя на экране она останется. Теперь можно быть уверенным, что лишь инициализация экрана или прямое вторжение в видеопамять сумеет стереть сделанную надпись.
Убрать защиту с первой строки можно, приведя измененные ячейки ЭК в их первоначальное состояние (оно дано в приложении).
Резюме к § 7
• Для создания дружественного интерфейса бывает удобно организовать многоэкранный вывод. Принцип разделения экранов позволяет это сделать.
• Таблица строк может указывать на разные экраны. Экран в УК - это горизонтальная полоса на терминале, состоящая из последовательных видео-строк.
• Чтобы отобразить нужный экран, достаточно "направить" маршрут таблицы строк по нужному руслу. Для этого, как правило, нужно изменить содержимое всего одной ячейки в таблице строк.
• Система поддерживает 4 стандартных экрана: Верхняя служебная строка. Рабочий экран. Служебный экран. Нижняя инфо-строка.
• У каждого экрана - своя область ВОЗУ.
• Служебная и информационная строки всегда отображаются на экране (вверху и внизу). Между ними может быть включен либо рабочий, либо служебный экран. Их переключение делается с помощью ячейки (2476). Рабочему экрану соответствует значение 2500 ,служебному - 4672.
• Вывод в каждый экран полностью независим. Это достигается с помощью экранных карт.
• Экранная карта - таблица переменных для экранного вывода. У каждого экрана она своя, и состоит из 31 слова. Начальный адрес текущей ЭК хранится в ячейке (23150).
• Чтобы организовать вывод в нужный экран, надо в ячейку (23150) записать начальный адрес карты требуемого экрана.
• Начальные адреса четырех экранных карт: 22560 - верхняя служебная строка, 22656 - рабочий экран, 22754 - служебный экран, 23052 - нижняя инфо-строка.
§ 8. Программа экранного вывода
Начнем разбирать самую важную программу экранного вывода. На схеме 8.0 дан ее алгоритм. Начало важных участков помечено метками (M…).
Описание сей программы — пожалуй, самое скучное место в главе, посему прибегать к чтению сей вирши следует только по необходимости. Ежели таковая отсутствует, предлагаем Вам перескочить сразу к резюме, что находится на стр ….
Итак, начали…
M0 ... M1 (адреса 111144-111202):
> Устанавливается ячейка (7066) из таблицы запросов, показывая, что надо высветить курсор.
> R5 загружается из ячейки 23150 начальным адресом текущей экранной карты.
> Регистры кода цвета точки и фона заружаются из экранной карты:
РТ из (R5+34), РФ из (R5+40).
Заметим, что оба слова РФ загружаются из одной и той же переменной.
> В регистр управления отображением, в 1-й байт пишется цвет курсора из ячейки (R5+70). В этой ячейке, помимо цвета, можно задать и вид курсора (графический или символьный), а также позицию графического курсора в октете.
- Итак, загружены цвета точки и знакоместа. Курсор готов ко включению.
M1 ... M2 (адреса 111204-111230):
> Из буфера в R0 пишется 1 байт. Ячейка (22542) служит указателем буфера при выводе на экран. Ее отличие от ячейки (22544) в следующем:
(22544) указывает на место в буфере, куда запишется очередной байт (голова буфера). (22542) указывает, откуда в буфере следует читать новый байт (хвост) (см. рис. 8.0).
< Рис. 8.0 Масенький рисунок-пояснение >
Ясно, что (22542) должен указывать на адрес, не больший того, на котоый указывает (22544) (голова всегда впереди хвоста):
(22542)<=(22544).
> Изменяется указатель-хвост - (22542). Он инкрементируется, а для предотвращения выхода за пределы буфера над ним выполняется команда &~200.
> В стек пишется число 111126. Это сделано для того, чтобы при команде RETURN из любого места управление передавалось на адрес 111126 (а не сразу в Диспетчер).
> Из R0 выделяется младший байт.
- Итак, из буфера в R0 записан байт. Перехвачено управление на выходе по RETURN.
M2 ... (адреса 111232... ):
> В зависимости от значения R0 содержимое интерпретируется либо как управляющий код (меньше 40), либо как символ (больше 40).
1. УПРАВЛЯЮЩИЙ КОД:
> В зависимости от содержимого ячейки (22552) управляющий код либо отображается на экране (режим ИСУ - индикации символов управления), либо идет "исполнение" управляющего кода.
а) (22552)<>0 - "ИСУ":
M21 ... M22 (адреса 111730-112020):
> В угловых скобках печатается трехзначное восьмеричное число, равное управляющему коду.
M22 ... RETURN (адреса 112022 ... 113036):
> Если управляющий код - 12 (ВК), выполняется "возврат каретки" (код 25).
б) (22552)=0 - не "ИСУ":
M20 ...
> Содержимое R0 умножается на 2, к результату прибавляется 13142. Получившееся число - адрес ячейки, в которой содержится адрес соответствующей спецфункции. (О спецфункциях см. ниже).
> Идет переход на адрес спецфункции.
2. СИМВОЛ.
M3 ... M4 (адреса 111260 ... 111314):
> Если R0>=100, к нему по ИЛИ добавляется содержимое ячейки (22556). Эта ячейка используется для переключения между алфавитами (русский/latinsky).
> Содержимое R0 умножается на 2, к результату прибавляется 14142 - начальный адрес таблицы знакогенератора. Слово из ячейки с получившимся адресом пишется в R1. Это - адрес знакогенератора (таблички, содержащей 11 байт). Каждый байт В ЗГ представляет собой сечение символа, т.е октет.
> R0 загружается из (R5+10) шагом в ВОЗУ между видеостроками.
> В R2 пишется 177010 (адрес РА), в R3 - 177024 (адрес РО). В РА пишется текущий адрес ВОЗУ в данном экране (первое слово ЭК).
- Итак, все готово к тому, чтобы нарисовать символ:
R1 указывает на знакогенератор, R0 содержит шаг в ВОЗУ, R2, R3 содержат адреса регистров адреса планов и октета. РА загружен текущим адресом ВОЗУ.
M4 ... M5 (адреса 111316-111420):
> К счетчику команд прибавляется содержимое ячейки (R5+56). Если не включены режимы инверсии или подчеркивания, эта переменная равна 0. При включении соответствующего режима она загружается определенным значением. Тогда управление передается на адрес, вычисляемый так:
А=111322+(R5+56).
> Если это - нормальный режим, то все 11 байт из знакогенератора переписываются в ВОЗУ через РО. При этом установленным разрядам в этих байтах соответствует цвет символа, а сброшенным - цвет знакоместа. Если инверсия - перед записью в октет байты инвертируются. Если подчеркивание - последний байт заменяется на 377.
- Итак, символ нарисован.
M5 ... M9.
> К текущему адресу ВОЗУ (первая ячейка ЭК) прибавляется 1. Из (R5+16) вычитается 1. Ячейка (R5+16) показывает позицию символа в строке, начиная с правого края. Для крайнего правого знакоместа эта ячейка равна 1. Вы все еще читаете? Странно.
> Если получившееся значение (R5+16) отлично от 0 (не достигнут правый край), выполняется RETURN.
- Ну что ж... Изменена текущая позиция знакоместа (по оси X).
> Если (R5+16)=0 (правый край экрана), выполняется переход на новую символьную строку. При этом в (R5+16) копруется содержимое (R5+4), равное количеству знакомест в строке, выводимых в данный экран. Кстати, это количество не обязательно равно числу октетов в данном режиме (80, 40, 20 или 10).
> Текущий адрес в таблице строк - (R5+32) - увеличивается на 54 (разница в адресах элементов через 11 видеострок).
> В текущий адрес ВОЗУ - (R5) - записывается содержимое переменной (R5+22). Эта ячейка содержит номер знакоместа (слева), с которого начинается вывод в строке.
> В случае, если обнаружен конец таблицы строк, т.е. текущий адрес таблицы строк равен конечному:
(R5+32)=(R5+26),
текущим адресом становится начальный: (R5+32):=(R5+24).
> К текущему адресу ВОЗУ - (R5) - прибавляется адрес ВОЗУ, на который указывает текущий элемент таблицы строк. Номер текущей символьной строки уменьшается на 1 (он считается снизу):
DEC 20(R5).
- Изменилась позиция по Y (в случае перехода на новую символьную строку).
> Если это не самая нижняя строка на экране - (R5+20) не равно 0 - выполняется RETURN.
M12 ...
> В противном случае (нижняя строка) - встает выбор - прокручивать рулон на одну символьную строку вверх (рулон включен) или не прокручивать (выключен). За состояние рулона (включен-выключен) отвечает последняя переменная экранной карты - (R5+74).
... M13 - рулон выключен:
> Вывод идет опять с верхнего края экрана. Для этого текущим адресом в таблицЕ строк становится адрес верхней строки, а текущим адресом ВОЗУ - соответствующий адрес ВОЗУ + отступ от левого края.
> Номер текущей символьной строки (отсчитываемой снизу), становится максимальным:
(R5+20):=(R5+12).
Затем - выход по RETURN.
... M14-M15 - рулон включен.
> В этом случае (R5+20) инкрементируется.
> В стек пишется 13. Это - смещение экрана при прокрутке.
> К адресу верхней строки в таблице строк прибавляется 54, показывая, что после прокручивания рулона верхней строкой на экране станетдругая (ниже на 11 видеострок).
> Если адрес верхней строки в таблице строк равен 4670 (конечный адрес), он заменяется на 2500 (начальный адрес).
M15 ...
> Здесь идет установка рулона на прокручивание. Проверяется счетчик рулона - ячейка (23170). Если он пуст (равен 0), гасится курсор, очищается новая символьная строка (которая пока не высвечивается - она внизу, за горизонтом):
CALL 113344,
и к счетчику прибавляется число из стека (13). Если счетчик на момент проверки был больше 14 (по модулю), выполняется TRAP 0. Затем R5 загружается из (23150) и все поторяется с M15.
Прокрутка рулона осуществляется через сетевой таймер. Работа таймерной программы описывается в главе 5. Пока лишь отметим, что ячейка (23170) отвечает за рулон: содержимое ее показывает, на сколько пиксел надо прокрутить экран. Положительные значения соответствуют прокрутке вверх, отрицательные (в дополнительном коде) - вниз.
- Итак, алгоритм работы программы разобран.
Теперь осталось рассмотреть, что происходит при выполнении RETURN из данной программы.
Как уже отмечалось, по RETURN управление передается на адрес 111126. Здесь делается следующее:
> Вычитается 1 из (7064), т.е. снимается 1 запрос.
> Если (7064) стал равен 0 (запросов нет), а также нет переполнения буфера ((22546)=0), выполняется выход из программы в Диспетчер через RETURN.
> Если же (7064) не равно 0, (еще остались запросы на экранный вывод), проверяется ячейка (7060), содержащая запросы от клавиатуры. Если последних нет ((7060)=0), идет возврат на нашу процедуру, к метке M1, и все повторяется.
Если все-таки запрос на клавиатуру есть, выполняется выход в Диспетчер, чтобы этот запрос удовлетворить.
> Найдя буфер переполненным, ((22546)=2), вызывается TRAP 4 (он считывает байт из канала). В (7064) добавляется еще один запрос, и опять - на адрес 111126.
- Таким образом, выход в Диспетчер осуществляется:
1) При наличии запросов на клавиатуру и на экран. 2) При исчерпании запросов на экран, если буфер не переполнен.
Для тех, кому недосуг разбираться в алгоритме, и просто лентяев (то есть практически для всех):
Резюме к § 8
в котором вкратце сказано, как устроен экранный вывод и как он обходится с экранными картами:
• Экранная карта имеет цель сообщить миру, как устроен данный экран и в каком он сейчас состоянии (и в состоянии ли он вообще). • Те переменные, которые сообщают об устройстве экрана, назовем статическими, поскольку они не изменяются с момента создания экранной карты. • Те переменные, которые можно поменять (в основном, с помощью спецфункций, которых мы скоро коснемся), назовем полудинамическими. Характерной переменной этой группы является "цвет символа", например. • И, наконец, переменные, которые меняются практически при каждом выводе символа (например, позиция текущего знакоместа на экране), обзовем динамическими.
Каждую группу переменных мы сведем в таблицы.
< Здесь, по идее, находятся 3 таблицы: 8.1, 8.2, 8.3 >
< А еще здесь - рисунок 8.4 - Активная страница экрана >
• И, кратко, работа самой программы:
1) Из ЭК в видео-регистры загружаются цвета символа и знакоместа, а также курсора. Включается курсор.
2) Из буфера берется байт. Проверяется его характер. Если он меньше 40 (байт, а не характер), то это управляющий код, ему соответствует определенный адрес. На этот адрес передается управление. Если байт >=40, то это символ. Его надлежит вывести на экран.
3) Вывод на экран осуществляется из знакогенератора (ЗГ). ЗГ - это табличка, в которой каждому коду (символу) соответствует 11 байт. Эти 11 байт составляют один символ на экране (11*8 точек).
Есть 3 режима вывода на экран: - нормальный, - инверсия (все байты выводятся на экран инвертированные), - подчеркивание (самый нижний байт любого символа выводится "закрашенным" - число 377).
4) После вывода символа текущее знакоместо меняет свою позицию (меняются соответствующие переменные в ЭК).
5) Ели необходимо, дается команда "крутануть" рулон на 11 видеострок вверх (экран заполнен).
6) Если в буфере еще есть байты, которые необходимо "обработать", все повторяется с пункта 2.
Однако, если при этом есть запрос с клавиатуры, осуществляется выход в Диспетчер. Также выход в Диспетчер происходит при исчерпании запросов (буфер пуст).
§ 9. Спецфункции
TODO
, и таблица настроена на него, т.е. указывает на адреса в ПЗУ.
При желании можно сделать свой знакогенератор, и настроить таблицу на него. Для размещения альтернативного знакогенератора выделена память в ОЗУ ПП - это адреса с 15142 по 22540. Здесь Ваш ЗГ никто не потревожит, разве что другой любитель изобретать алфавиты.
Таблица спецфункций (ТСФ) начинается с адреса 13142. В ней тоже хранятся адреса. Но это уже адреса подпрограмм, называемых спецфункциями. Каждому коду соответствует своя СФ.
9.1. Вызов спецфункций. Код 33.
Как вызываются спецфункции с кодами до 40, мы уже видели: программа экранного вывода, обнаружив такой код, тут же отправляется на адрес, который она находит в таблице спецфункций (ТСФ).
А как быть с кодами от 40? Ведь программа экранного вывода проинтерпретирует такой байт как символ. Чтобы показать Системе, что на данный код надо ответить спецфункцией, предназначен управляющий код 33. 33 ставится перед требуемым кодом, и эта парочка интерпретируется как СФ.
Как это происходит? Взгляните на схему 9.0. На ней дана блок-схема СФ-33, а также блок-схема одной незаменимой подпрограммки.
Итак, получив код 33, Система вызвала СФ-33. Работает эта СФ следующим образом.
- Указатель стека сохраняется в ячейке (23152). Ячейка (23174) становится равной 2. Этим показывается, что идет работа "через 33".
- Вызывается подпрограмма с адресом 110762, после которой в R0 оказывается наш байт (следующий за кодом 33).
- Далее идет вызов искомой спецфункции, обнуление ячейки (23174), восстановление указателя стека и возврат.
Здесь все ясно (по крайней мере автору). Теперь посмотрим, что делается в подпрограмме 110762.
- Подобно программе экранного вывода, здесь идет работа с буфером. Обнаружив поступление очередного байта, следующего за 33 ((7064) не равна 0), подпрограмма пишет в R0 искомый код.
- Если он - от 40, происходит возврат из подпрограммы. Иначе (меньше 40) вызывается соответствующая спецфункция (тут же, внутри этой п/п), а по выходе из СФ - опять, на начало п/п. Исключение делается для кода 33 - при его обнаружении идет "выброс" в СФ-33, в точку с адресом 113544.
- Если же код еще не поступил, (7064)=0, идет выход в Диспетчер, чтобы при поступлении его снова войти в эту подпрограмму с адреса 110726. При переполнении буфера вызывается TRAP 4, и снова - начало подпрограммы.
9.2. Действия спецфункций.
TODO
§10. EMT 52, 56, 40
Теперь займемся тремя EMT-подпрограммами.Две из них - EMT 52 и EMT 56 служат для вывода в служебную (верхнюю) и информационную (нижнюю) строки. EMT 40 служит для инициализации экрана.
10.0. Вывод в служебную и информационную строки (EMT 52, 56)
Итак, EMT 52 и 56. Если желаете, то можете взглянуть на схему 10.0. Здесь даны блок-схемы этих подпрограмм. Точнее, подпрограмма-то всего одна, а точки входа разные. EMT 52 началом текущей экранной карты утанавливает адрес 22560 (служебная строка), а EMT 56 - 23052 (информационная). Кроме того, можно "оградить" служебную строку от надписей через EMT 52 - для этого надо установить ячейку (7150) значением 2.
Действие этих подпрограмм не связано с буфером. Байты выводятся сразу из строки, адрес которой помещается за командой EMT. Первый байт в этой строке всегда интерпретируется как позиция X на экране. Строка должна заканчиваться 0.
Еще один маленький нюанс. EMT 52 и 56 использует для вывода символов стандартную программу экранного экранного вывода с адресом точки входа в нее 111272. А это значит, что управляющие коды (0 ... 37) не будут здесь управляющими. Они не будут вызывать спецфункции, а отображаются в виде символов (в знакогенераторе можно записать символы для таких слов).
10.1. Инициализация экрана (EMT 40)
Выполняя программу начального запуска, ПП должен, в числе прочих задач, инициализировать экран. Что это такое? Это последовательность действий, приводящая "с нуля" к нормальной работоспособности экрана. Инициализация включает в себя:
1) очистка ВОЗУ; 2) подготовка K0 к приему байт; 3) построение таблицы строк; 4) построение таблицы знакогенератора; 5) построение таблицы спецфункций; 6) инициализация буфера; 7) некоторые начальные установки (типа включения курсора).
Все эти действия выполняет EMT 40. Его утройство представлено на схеме 10.1. Помимо начальной точки входа, здесь показаны и некоторые дополнительные адреса.
Если, предположим, Вам не надо очищать экран, а просто нужно заново отстроить таблицу строк, ТЗГ, ТСФ и т.д., можно вызвать подпрограмму через CALL со следующих адресов:
Адрес Начальный пункт (из вышепречисленных)
107754 1 110022 2 110044 3 110050 4 110076 5 110114 6 110136 7
Конечно же, предварительно надо сохранить в стеке нужные еще Вам регистры (при вызове через EMT регистры сохранять не нужно).
Теперь опишем некоторые процедуры, вызываемые из EMT 40.
Процедура 110266. Строит таблицу строк. Как уже говорилось, эта таблица состоит из отдельных элементов. Каждый элемент должен содержать адрес ВОЗУ и адрес следующего элемента. Вначале строится "скелет" таблицы - пишутся адреса последовательных элементов. Затем с помощью процедуры 110550 в таблицу записываются адреса ВОЗУ. И уже в последнюю очередь делаются поправки на регистры УО и УЦ. Заметим, что процедура лишь строит таблицу строк, а не включает ее (ячейка 272 не трогается).
Процедура 110550. Используется предыдущей процедурой для построения непрерывного участка таблицы строк. Вызывается через JSR R5 и содержит 4 параметра, располагаемые в 4-х словах после команды.
1-й параметр - начальный адрес в ВОЗУ. 2-й параметр - начальный адрес в таблице строк. 3-й параметр - количество элементов. 4-й параметр - шаг в ВОЗУ.
В результате в ОЗУ ПП будет построена таблица, в которой через слово будут записаны адреса ВОЗУ с постоянным приращением.
Процедура 110656. Эта подпрограмма переписывает из ПЗУ (хотя может и из ОЗУ) в экранные карты их начальые значения, а затем по адресам, указанным в карте, записываются регистры УО и УЦ. Процедура вызывается через JSR R5 и имеет 2 параметра.
1-й параметр - начальный адрес в ПЗУ (ОЗУ). 2-й параметр - начальный адрес экранной карты.
В ПЗУ каждая экранная карта представлена так:
1-е слово - количество переменных в ЭК. Далее идут эти переменные, а затем 4 слова - содержимые УО1, УО2, УЦ1, УЦ2.
Резюме к §10
• EMT 52 выводит строку символов в верхнюю служебную строку.
• EMT 56 - в нижнюю информционную строку.
• Адрес строки указывается в слове, следующем за командой. Первый байт в строке - позиция по X (слева).
• EMT 40 выполняется инициализацию экрана.
• Последовательность инициализации:
1) стирание всех 3-х планов ВОЗУ; 2) разрешени прерываний от приемника К0; 3) построение таблицы строк; 4) переписывание таблицы знакогенератора из ПЗУ; 5) переписывание таблицы спецфункций из ПЗУ; 6) начальная установка указателей буфера; 7) переписывание экранных карт из ПЗУ; 8) начальные установки: - включение таблицы строк, - текущий экран - рабочий, - включение курсора, - начальные установки цветов символа и знакоместа.