КРАТКИЙ КУРС ПРОГРАММИРОВАНИЯ В СРЕДЕ IS-DOS.
(под общей редакцией Елисеева В. А.)
1. РАСПРЕДЕЛЕНИЕ ПАМЯТИ В iS-DOS:
Операционная система iS-DOS изначально писалась с расчетом ее работоспособности в старом стандарте ZX с 48 KB памяти и хотя бы одним дисководом. Посему в iS-DOS Classic младшие 16 KB памяти компьютера практически не используются (там находится ПЗУ BASIC). Выше, с адреса #4000, находится экран.
Поскольку связь с флоппи-диском осуществляется через TR-DOS, то сохранены некоторые переменные BASIC и TR-DOS. Т.о. нам остается память от 23900(#5D5C) по 65535(#FFFF).
Буфер принтера (#5B00.. ..#5BFF) используется для командного файла exebat.com, необходимого для работы bat-файлов. Область с 23900(#5D5C) по 23999(#5DBF) резервируется под программы mon.com и menu.com, которые также как и exebat.com вызывают другие com-файлы.
Область выше 24000 обычно используется для загрузки системных или пользовательских com-файлов. "Командники" грузятся по адресу загрузки (12-ый, 13-ый байты описателя файла). В ту же точку передается управление. 95% всех com-файлов имеет адрес загрузки 24000.
Сверху область com-файлов ограничена кэшем блочных устройств.
Кэш блочных устройств содержит прочитанные с помощью некоторых рестартов блоки. Он необходим для работы почти всех рестартов уровня файловой службы (с #20 по #38 и с #3B по #3F), многих рестартов уровня командной строки, работающих с файлами и каталогами, и некоторых рестартов верхнего уровня: $shsubr(#8E), $shpanl(#90).
При запуске com-файлов с помощью рестартов $run(#48) или $exebat(#44) система сама следит за неприкосновенностью кэша. Если com-файл не влезает под кэш, генерируется ошибка 130. Адрес кэша и его размер можно узнать у системы с помощью системного рестарта $g_cnfg(#10):
LD C,#10 ;$g_cnfg
RST #10
EXX ;в HL - адрес вектора конфигурации системы
LD BC,5 ;смещение +5
ADD HL,BC
LD E,(HL) ;адрес кэша
INC HL ;помещаем в DE
LD D,(HL)
INC HL ;смещение +7
LD A,(HL) ;размер кэша в блоках
Теперь будет не сложно проверить, хватает ли памяти, и, если нет, пересоздать кэш (если он нужен для работы программы) размером поменьше с помощью рестарта $creat(#00).
Если кэш временно не нужен, этой памятью можно воспользоваться, но затем обязательно пересоздать кэш рестартом $creat(#00).
Выше кэша находится область каналов. Адрес, размер и указатель области каналов достаются через уже знакомый рестарт $g_cnfg(#10) со смещениями +32, +34 и +36 соответственно. В каналах хранится самая необходимая системная информация, такая как каналы драйверов и устройств, каналы панелей и резидентов, а посему начиная от адреса области каналов и до #FFFF лучше ничего не трогать!
Над областью каналов находятся вперемешку (в порядке загрузки) драйверы и резиденты. Нижним будет резидент (драйвер) загруженный последним. Адрес нижнего резидента равен адресу конца области каналов (см. выше).
Резиденты и драйверы доступны по именам с помощью рестартов $fndev(#51) и $run(#48) или по номерам каналов драйверов или устройств.
Так любой драйвер или резидент Вы можете достать, зная номер его канала:
; в A помещаем номер канала
LD C,#16 ;$stchn
RST #10
RET C ;выход по ошибке - нет канала и т. п.
EXX ;в HL - адрес тела канала
INC HL
INC HL
INC HL
INC HL
LD E,(HL)
INC HL
LD D,(HL) ;в DE - адрес тела драйвера
.. и т.д.
(описание $stchn и каналов см. ниже)
Резидентную задачу можно запустить, зная номер ее канала, рестартом $exeres(#53).
Еще выше расположены 5 уровней системы. Сидят они сверху вниз, т. е. самый нижний уровень "DOS" (работа с устройствами, кэшем, каналами и прерываниями) располагается на самом верху. Далее идут "DUD" (файловая служба), "COM" (интерпретатор командной строки), "WIN" (рестарты работы с окнами, печати строк и т. п.) и в самом низу "SHELL" (файловая оболочка, работа с панелями, меню).
Два верхних уровня ("оконная технология" и "работа с панелями") могут быть временно сняты программой set.com с ключом /L, но используется это крайне редко.
Увидеть, чего где сколько, можно с помощью программы Q:UTILshow.com. Она позволяет увидеть все основные адреса системы, адреса загрузки уровней, резидентов и драйверов, адрес и размер кэша и многое другое.
ПРИМЕР РАСПРЕДЕЛЕНИЯ ПАМЯТИ
iS-DOS Classic
|
0 |
ПЗУ BASIC-48 |
|
16384 |
экран |
|
24000 |
область com-файлов |
|
35903 |
кэш |
|
43443 |
каналы |
|
44143 |
резиденты и драйверы |
|
50304 |
уровень 4 SHELL |
|
54800 |
уровень 3 WIN |
|
58472 |
уровень 2 COM |
|
60726 |
уровень 1 DUD |
|
63296 |
уровень 0 DOS |
Вся дополнительная память ZX (128, 256 и т.д.) используется или для виртуального электронного диска, к которому обращаются через специальный драйвер как к обычному устройству (лучше всего его назначить устройством Q:, тогда работа в системе резко ускоряется), или под буферы (например, копировщиками).
В январе 1995 года создан еще один вариант iS-DOSa: "iS-DOS Chic" (исдос шик), использующий нижние 16 KB для размещения неизменяемой части ядра системы. Это оказалось возможным на компьютерах KAY-256, Scorpion ZS-256, Profi и др. им подобным.
Данные модификации Спектрума позволяют в нижней странице памяти разместить 0-ой банк памяти. Вместо него в верхней странице открывается 8-ой банк.
В нижнюю страницу помещаются как правило неизменяемые части системных программ (для возможности прошить эту страницу в ПЗУ), знакогенераторы t42 и t64 (2KB+1KB), благодаря чему транзитная область расширяется почти вдвое (до 30 KB вместо 15 при минимальном количестве резидентов и 29-блочном кэше).
ПРИМЕР РАСПРЕДЕЛЕНИЯ ПАМЯТИ
iS-DOS Chic
|
#0010 |
RST #10 |
|
|
#003B |
подпрограмма драйвера электронного диска |
|
|
#0047 |
признак типа системы/компьютера |
|
|
#0067 |
таблица для драйвера электронного диска |
|
|
#0101 |
буфер для драйвера электронного диска |
|
|
#0201 |
знакогенератор t64 (1K) |
|
|
#0601 |
не используется |
|
|
#093A |
ядро системы (неизменяемая часть) |
|
|
#3800 |
знакогенератор t42 (2K) |
|
|
#4000 |
экран |
|
|
#5DC0 |
область com-файлов |
|
|
#A5A2 |
кэш (49 блоков) |
|
|
#D6F0 |
каналы |
|
|
#DAD8 |
резиденты и драйверы |
|
|
#F365 |
уровень 4: SHELL |
изменяемая часть |
|
#F78C |
уровень 3: WIN |
|
|
#FA88 |
уровень 3: COM |
|
|
#FC0C |
уровень 1: DUD |
|
|
#FDE6 |
уровень 0: DOS |
|
2. НЕСКОЛЬКО ОБЩИХ СЛОВ:
В системе iS-DOS вызов системных подпрограмм осуществляется с помощью команды RST 16 (или RST #10, если кто любит шестнадцатеричные). При этом в iS-DOS Classic должен быть открыт 4-ый канал бейсика (после загрузки так оно и есть, если Вы только не вызывали сами процедуру #1601 или не запускали в исдосе скажем MONS-4).
Код функции подается в регистре C. Его старшие 3 разряда определяют уровень системы. Обычно их (уровней) 5 (с 0 по 4). Дополнительный временный уровень с номером 7 ставит текстовый редактор. Отладчик устанавливает уровень номер 5. Дополнительные уровни устанавливают также базы данных.
Такой способ связи с системой или с собственным ядром пакета из оверлеев чрезвычайно удобен, так как ядро и оверлеи полностью развязываются адресно и после перетрансляции ядра не нужно перелинковывать все оверлеи. В противном случае после изменения системы пришлось бы перетранслировать все командные и резидентные файлы, многие драйверы и т. д. и т. п.
При работе большинства рестартов система сохраняет регистры BC, DE, HL, IX и IY. У многих рестартов выходное значение регистровой пары AF сигнализирует об успехе операции. При этом поднятый в "1" флаг C означает ошибку и регистр A в этом случае содержит её код. В большинстве случаев при ошибках рекомендуем просто отваливать по флагу C:
Например:
LD C,#02 ;flush
RST #10 ;вызов рестарта
RET C ;выход при ошибке
...
Некоторые рестарты, как, например рестарты оконной технологии $wt, $adrwt, $box и др. могут вернуться с любым флагом, т.е. ни флаг C, ни какой другой не являются здесь признаком ошибки, и обрабатывать их после вызова рестарта не только не полезно, но и ошибочно. В дальнейшем, при более подробном рассмотрении рестартов для каждого из них будут указаны возможные ошибки. Для некоторых рестартов важен не только флаг C на выходе, но и флаг Z, а также содержимое регистров. Такие случаи оговариваются особо.
Большинство рестартов, как уже было сказано, сохраняют регистровые пары BC, DE, HL, IX. Исключение: рестарты $exebat и $run. Ими передается управление командным файлам или резидентным программам. При выходе по RET'у из вызывавшихся программ мы попадаем прямо в основную программу минуя процедуру восстановления регистров.
ВНИМАНИЕ! АЛЬТЕРНАТИВНЫЕ РЕГИСТРЫ
ПРИ RST 16 НЕ СОХРАНЯЮТСЯ!
Более того, именно ими многие рестарты возвращают в программу такую полезную информацию, как адреса системных векторов (массивов), адреса или номера блоков устройств, адреса каналов, драйверов и т. д. и т. п. Входные же данные можно передать лишь через основные регистры.
ВАША ПЕРВАЯ ПРОГРАММА
Программы в iS-DOS'ее могут быть двух основных типов: командные файлы и резиденты.
Командные файлы (о резидентах мы поговорим позднее) имеют расширение *.com и загружаются по адресу, указанному в 12-м и 13-м байтах описателя файла, иначе говоря, со смещением 12 (#0C) в описателе файла и запускаются с адреса загрузки. Вызывать их можно из других программ по командной строке рестартом $run. Например:
LD HL,LINE ;адрес командной строки помещаем в HL
LD C,#48 ;$run
RST #10
RET C
;описание командной строки, завершается кодом ENTER (#0D)
...
LINE DEFM "Q:RESset user.res"
DEFB #0D
Из оболочки iS-DOS'а командный файл можно запустить подведя к нему файловый курсор и нажав Enter, либо описав его в текстовом файле Q:SHELLextkey.txt, или из монитора командных строк mon.res (mon+.res, mon.com), а так же из bat-файла (подробнее см. книгу В. Елисеева "IS-DOS - Первое знакомство").
Создать свой командный файл не просто, а очень просто. Сперва при помощи текстового редактора создайте исходный текстовый файл в стандарте любимого Вами ассемблера. Рекомендуем наш as2.com. Файл должен иметь расширение *.as (некоторые любят *.asm). В начале программы установите адрес загрузки директивой ORG (желательно не ниже 24000):
ORG 24000
Затем разместите тело вашей программы.
Выходить в iS-DOS советуем по команде:
RET
При нормальном выходе флаг C должен быть сброшен, флаг Z установлен, в регистре A помещаем код выходной операции:
#00 - ничего не делать
#F0 - перепечатать одну текущую панель, при этом на ней сохраняется открытым текущий каталог, который был на панели до этого, сохраняется позиция курсора, отметка файлов сбрасывается.
#F1 - то же самое, но курсор устанавливается в начало панели.
#F2 - перепечатать обе панели, сохранив в текущей панели ранее открытый каталог и позицию курсора. Перепечатывается также и верхняя строка подсказки, однако, окно монитора командной строки не очищается.
#F3 - то же, но курсор устанавливается в начало панели.
#F4 - полностью очищает экран и перепечатывает обе панели и строку подсказки. На текущей панели сохраняется ранее открытый каталог и позиция курсора.
#F5 - то же, но курсор устанавливается в начало панели.
#F6 - полное обновление экрана, перепечатка обеих панелей и подсказки (как и при F4), кроме того заново пересоздается кэш. Размер кэша берется из вектроа g_cnfg со смещением -6. Позиция курсора и каталог в текущей панели сохраняются.
#F7 - то же, но курсор устанавливается в начало панели.
#F8 - перепечатка текущей панели с сохранением открытого каталога, позиции курсора и отметки файлов.
#17 - (в старых версиях - #FB) - перепечатка текущей панели, при этом текущее устройство на ней открывается заново (перечитывается его корневой каталог).
При ошибке флаг C должен быть установлен, в регистре A помещается код ошибки.
Оттранслируйте программу ассемблером, отлинкуйте полученный объектный файл программой link.com. Для их вызова можно написать bat-файл, а можно просто нажимать Enter, наведя курсор сперва на asm-файл, затем на obj (В файле Q:extent.txt должны быть такие строки:
asm:Q:ASas /auto
obj:Q:ASlink /old /sym S:ASrst
Пользуйтесь при написании стандартными названиями рестартов, тогда Вам пригодится файл глобальных меток rst.obj, а программа будет более читабельной. Обязательно сосчитайте контрольную сумму com-файла программой ch.com. Для этого установите курсор на Ваш com-файл и вызовите из командной строки программу ch.com. В случае bat-файла опишите вызов ch.com прямо в нем.
4. РЕЗИДЕНТНЫЕ ПРОГРАММЫ
Резидентной программой в системе IS-DOS называется программа, постоянно находящаяся в специальной области памяти и, поэтому, доступная для работы в любое время без подгрузки ее с диска.
Работа с резидентной программой подразделяется на три этапа:
1. Установка (загрузка) в память с диска, настройка на адрес и инициализация.
2. Основная работа
3. Удаление программы из памяти
1-й и 3-й этапы осуществляются командой set.com. Она же создает 18-байтовый канал, описывающий резидентную программу.
Установленные (загруженные) резидентные программы можно увидеть при помощи программ show.com и eliminat.com. Обращаться к резидентным программам можно по именам из командной строки, используя встроенную команду DOS "@", например:
@date+3 или @scan ch+ *.*
Последнее выражение содержит сразу 2 имени резидентов. Это вызвано тем, что некоторые резидентные программы предназначены для работы в паре со специальными служебными резидентами - scan.res и univ.res. Эти служебные резиденты осуществляют подбор файлов (по маске, отметке и т. п.) и передачу их в качестве параметра резиденту, запускаемому в паре с ними.
Т. о. Вы запускаете служебную резидентную программу, указав в качестве первого параметра имя рабочего резидента, а в качестве второго - ключ или маску для подбора файлов. Служебный резидент по имени определяет номер канала рабочего резидента, запоминает его и многократно запускает по номеру, предварительно открывая следующий файл, подходящий под указанную маску или ключ.
Резиденты, работающие в паре с резидентами scan.res и univ.res обычно имеют специальную защиту от прямого обращения к ним через команду "@".
Структура резидентной программы:
|
Смещение |
Длина |
Комментарий |
|
0 |
2 |
Адрес процедуры инициализации. Она вызывается при перемещении (при этом в регистре A подается FF) или удалении (в рег. A подается FE) программой SET.com. Если этот адрес равен 0, то процедура не вызывается. Эта программа должна подключать, если это необходимо, резидента к цепочке прерываний или к другой программе, перехватывать рестарты и восстанавливать их. |
|
2 |
2 |
Адрес главного входа, т.е. процедуры запуска по имени рестартами $exebat(#44) и $run(#48) или по номеру канала рестартом $exeres(#53) Если адрес равен 0, то запускается с 4-го байта. |
|
4 |
R |
Тело программы - собственно машинный код |
|
R+4 |
2 |
#FFFF - отделяет тело программы от последующей служебной информации |
|
R+6 |
2n |
таблица настраиваемых адресов - 1. Смещения от начала вычисляются по LSA. Единица вычитается для пущей простоты настройки таких команд как: CALL, JP, LD HL, LD A,(nn), наиболее часто встречающихся в программе. |
С появлением программ ассемблера и сборщика (as.com и link.com) все заботы о разделителе и таблице настраиваемых адресов у программиста отпали. Чтобы собрать резидентную задачу надо лишь зарезервировать в начале файла 4 байта (2 слова) для адресов точек входа (см. только что приведенную структуру) и отлинковать объектный файл(ы) с ключом /res. Не забудьте лишь установить ORG отличный от нуля, чтобы адрес #FFFF не спутался с разделителем!
5. ДРАЙВЕРЫ УСТРОЙСТВ
Драйвер - это резидентная программа специального назначения. Он обслуживает физическое или логическое устройство одного из трех типов:
1. Блочные устройства: файлы типа *.blk, номера каналов драйверов F8..FF, номера каналов устройств - #00..#07
2. Символьные устройства вывода: файлы типа *.typ и *.lpr, номера каналов драйверов F0..F7, номера каналов устройств - #08..#0F
3. Cимвольные устройства ввода: файлы типа *.key номера каналов драйверов E8..EF, номера каналов устройств - #10..#1F
Установленный в систему драйвер имеет только 8-буквенное имя (тип в канале не хранится). typ от lpr можно отличить по 0-му биту в 13-ом байте драйвера (5-ый байт в векторе g_typ(#12)). В начале каждого драйвера располагается вектор стандартной структуры:
|
Смещение |
Длина |
Имя |
Комментарий |
|
0 |
2 |
INST |
Программа, инициализации вызываемая как и для всех резидентов программой SET.com, а также при каждом переключении устройства, обслуживаемого драйвером. При этом в регистре A подается номер устройства |
|
2 |
2 |
ENTRY1 |
1-ая точка входа |
|
4 |
2 |
ENTRY2 |
2-ая точка входа |
|
6 |
2 |
ENTRY3 |
3-я точка входа |
|
8 |
8 |
|
служебная информация, хранящаяся также в описании канала устройства и в векторе устройства - регистры состояния, адреса буферов и т. п. |
|
16 |
... |
|
тело драйвера |
Точка входа INST может использоваться для переключения драйвера на соответствующее устройство (задействовано в sys_driv.blk и в драйверах винчестеров), а также информирует драйвер (и резидент) о том, что его передвинули или отключают. Вся информация подается в регистре A:
A=0..7 - номер устройства, на которое переключается драйвер
A=FE - драйвер (резидент) отключается, т.е. будет снят или просто текущее устройство скоро будет сменено. Делается это на тот случай если драйвер в рабочем состоянии перехватывает обращения к какому-либо рестарту или другому драйверу.
A=FF - драйвер (резидент) только что передвинут.
Входы ENTRY1, 2, 3 соответствуют группам системных рестартов IS-DOS:
|
Драйвер |
ENTRY1 |
ENTRY2 |
ENTRY3 |
|
blk |
$read |
$write |
$binit |
|
typ |
$type |
$tycpl |
$typos |
|
key |
$key |
$kwait |
$ktest |