Стек CP/M и приложения ставят в любое место от ~60H до BDOS (CP/M ставит стек на 80H и он опускается до ~60H). Но драйверы загруженные на входы CP/M-BIOS могут переставлять стек на некоммутируемую область ОЗУ и затем переключать банку. Если прерывания организовать за счёт чтения с шины байта FF (т.е без контроллера прерываний), то удобнее всего, если в области 38H находится ПЗУ (как в Синклере). Если во всех банках в области 38H расположить один и тот же код, то не вижу никаких проблем со стеком из-за прерываний (если не допускать рекурсивности прерываний), тем более если есть некоммутируемое ОЗУ выше FE00.Сообщение от Xrust
По прерыванию сохраняем стек программы в некоммутируемой области, ставим стек на некоммутируемую область, считываем и сохраняем всю конфигурацию. Если коммутация цельно банковая, то это один байт в порту коммутации банок, а если многооконная, то считываем и сохраняем содержимое тех окон, которые использует код обработчика прерываний. Затем включаем банку или окно (окна) в которых расположен код обработчика прерываний и уходим на вход процедуры обработки прерываний. Если надо разрешить рекурсивность прерываний (т.е вызов очередного прерывания в момент пока обслуживание предыдущего прерывания ещё не закончено), то код усложнится, но это тоже решаемо.
Но встречный вопрос, а зачем Вам нужны прерывания?
Чтобы считать время по импульсам 50 Гц? - Для этого предназначена 512ВИ1. Или периодически проверять неактивную клавиатуру? Или по прерываниям мгновенно реагировать на клавиши, как в IBM PC, если клавиатура активная (т.е сама даёт сигнал и символ или скан-коды)? Но как раз в CP/M без этого прекрасно обходятся, т.к не волнуют затраты ресурса на опрос клавиатуры и нет процедур настолько надолго прерывающих опрос клавиатуры, что символы теряются. Некоторые программы CP/M, если они вынуждены надолго прервать опрос клавиатуры, сами берут на себя периодический опрос клавиш, так например редакторы, делая вывод (ролик экрана) после вывода каждой строки контроллируют STATUS (и делают ввод, если что-то нажато), и по окончании долгой процедуры, код клавиши нажатой в это время будет взят из буфера (хотя в отличие от MSDOS буфер только на 1 символ).
Поэтому, единственная вещь, ради чего стоит трахаться с прерываниями, это многозадачность, о чём я и упомянул, когда прочитал о TSR обслуживаемых по прерываниям. Вы отмахнулись, что многозадачность не нужна. Это и ежу понятно (если нет межпрограммного обмена или хотя-бы клип-боарда), но как ещё ранее я упоминал, имеется ввиду не многозадачность с равноправными задачами, а однозадачность, но с одновременно выполняемыми маленькими резидентными процессами, в основном предназначенными для контроля флагов, датчиков, событий и обслуживания периодических явлений, типа счёта времени, иными словами для обслуживания периферии в реальном времени.
Процесс это маленькая, короткая по времени прогона подпрограмма, которая должна прогоняться периодически (неважно, раз в 20 МСЕК или раз в 10 минут). Для обслуживания периферии достаточно одного прерывания. Резидентные процессы организованы в цепочку. По апп.прерыванию программа смотрит в таблицу загруженных процессов. В таблице зафиксированы адреса обслуживания загруженных процессов или 0000, если это последний процесс в цепочке. По очереди каждый из загруженных процессов получает управление. Ясно, что для однозадачности с процессами, рекурсивность прерываний абсолютно не нужна. Если надо (т.е процессы ресурсоёмкие или их очень много), можно за одно прерывание обслуживать только один процесс, а в следующем прерывании следующий.
Резидентный процесс может, например, регенерировать динамическую память, выводить текущее время в правом верхнем углу экрана, печатать на принтере в фоновом режиме (в CP/M есть программа для такой задачи, но там апп.прерывания эмулируются за счёт перехвата функций BIOS работающих с клавиатурой), обслуживать клавиатуру (не важно активную ли пассивную матричную), контроллировать запрос на начало передачи по линии, в общем обслуживать любую периферию, что работает в реальном времени. В любом случае, все процессы, вместе взятые, не должны занимать более 50% времени периода апп.прерываний. Если процессу нужно больше времени, он должен разделить задачу на куски и выполнять за одно прерывание только часть своей задачи.
Вот такую многозадачность я имел ввиду. Не стоит думать, что это сложно, объём кода вряд-ли превысит 256 байт. А практически это эквивалентно, как многоядерная ЭВМ, где есть основной процессор и несколько одновременно работающих очень медленных процессоров прогоняющих TSR-программы, обслуживающие периферию и не мешая при этом прогону основной программы.
Впрочем, как показала практика, удобно встроить в ДОС на машине с несколькими банками ещё одну основную задачу. А именно, так называемый Супервизор, (являющийся расширением драйвера клавиатуры). Это программа, которая всегда хранится в ОЗУ какой-либо банки, никому не мешая. Затем, по нажатию сочетания клавиш, прикладная программа прерывается, в центре экрана очищается окно и в нём стартует Супервизор. В простейшем случае это отладчик или многобанковый RAM-монитор. Я делал такое для ДОС ОРИОНА, оказалось очень удобно. Конечно не так, как в ПК11/16, где в процессоре есть второй набор регистров, что более просто позволяет реализовать отладку. Но и для Z80 это лучше, чем CP/M-отладчик, т.к не требует в TPA ОЗУ для него. У меня в Супервизоре был RAM-монитор и HELP по функциям ROM-BIOS, CP/M, упр.кодам консольного драйвера и кодам для рисования рамок, т.е вся та справочная информация, что постоянно нужна при разработке ПО. Супервизор просто запускался, как обычная программа, после чего становились доступны его функции.
В системе с TSR на прерываниях управлять ими удобно с помощью такого же Супервизора.




Ответить с цитированием