Пакет документации о рестартах iS-DOS 1969 г.

Рестарты - DOS.SYS (#00...#0F).


0-ой уровень, он же "DOS.SYS"

Нижний уровень системы в iS-DOS (рестарты с #00 по #1F) работает с кэшем, блочными и символьными устройствами каналами и прерываниями. Этот уровень не знает ни о файлах, ни о командных строках, ни об оконной технологии. Всем этим занимаются более высокие уровни. Итак, более подробно о рестартах:

Первые 7 (с #00 по #06) рестарты уровня DOS" работают с так называемой "кэш-памятью", поэтому сперва несколько слов о том, что это собственно такое. Итак, кэш блочных устройств - это системный буфер, используемый исключительно для блоков (по 256 байт), из которых состоят все блочные устройства. Кэш создается рестартом $creat(#00). Система автоматически создает его при загрузке, а также при выходе в систему по рестарту $shel0(#80) или по RET'у со значениями #F6 или #F7 в регистре А процессора. Его пересоздают также некоторые командные файлы: например копировщики. Делают они это в основном, чтобы уменьшить размер кэша и таким образом выиграть несколько килобайт памяти под буферы, а также, чтобы вернуть после этого кэш в прежнее состояние. Как уже говорилось в самом начале книги, система iS-DOS занимает память ZX сверху вниз, и кэш, создаваемый в последнюю очередь, лежит под системой. Сверху он ограничен областью каналов. Верхний адрес области кэш-памяти можно достать из вектора конфигурации системы g_cnf, использовав рестарт $g_cnf(#10) со смещением +32:

LD C,#10        ;$g_cnf возвращает в

RST #10         ;HL' адрес вектора

EXX               ;адрес в HL

LD DE,32       ;прибавляем смещение

ADD HL,DE

LD E,(HL)       ;получаем в DE

INC HL            ;искомый верхний

LD D,(HL)         ;адрес кэша

Нижний адрес кэша, естественно, зависит от верхнего адреса. Если Вам катастрофически не хватает памяти, можно убрать лишние резиденты (в этом Вам поможет set.com с ключом /e). Можно также подсократить область каналов, что умеет делать channel.com. Это вызовет перемещение всей области кэша вверх и, следовательно, поднимет и нижнюю его границу, освободив память для Ваших целей. Однако, из Вашей программы проще всего сократить кэш. Размер кэша, устанавливаемый по умолчанию, лежит в векторе g_cnf со смещением +7

Адрес нижней границы кэша находится в том же векторе со смещением +5 и +6. При необходимости его можно рассчитать по формуле (1):

(1)

где   CACHE - искомый адрес нижней границы кэша

DGCHN адрес начала области каналов

CSIZE размер кэша в блоках.

По этому адресу располагается каталог кэша в виде массива описателей блоков по 4 байта на каждый блок кэша, после которого располагаются сами блоки.

Структура кэша:

Смещение

Размер

Описание

0

EDSIZ*4

каталог кэша состоит из 4-хбайтовых описателей блоков

0

4

описатель 1-го блока

4

4

описатель 2-го бока

8

4

описатель 3-го блока

EDSIZ*4

256

256

256

1-й блок

2-й блок

3-й блок

Это, собственно, тело кэша. Его адрес хранится в векторе g_cnf со смещением -5

где EDSIZ - размер кэша.

Описатель блока имеет следующую структуру:

Смещение

Размер

Описание

0

1

регистр состояния блока, совмещённый с номером устройства. Биты:

7 - блок модифицирован (1)

6 - блок защищён (1)

5 - блок существует (1)

4 - не используется

3..0 - номер устройства, которому принадлежит блок

1

1

счётчик обращений к блоку

2

2

номер блока на устройстве

Минимальный размер кэша равен 6 блокам. Оптимальный в iS-DOS Classic от 20 до 30. В CHIC около 40. Кэш необходим для работы файловой службы. Через него система обращается к устройствам, т.е. читает и пишет описатели файлов, каталогов, карту занятых блоков устройств, заголовки устройств и т.п. При нехватке места в кэше в жертву приносится самый старый считанный блок. Запись также осуществляется через кэш, причем система и не имеет других буферов, поэтому блок просто видоизменяется, то бишь модифицируется прямо в кэше, а в описателе кэша устанавливается в единицу 7-ой бит. По мере накопления модифицированных блоков их записывают на устройство, а бит модификации сбрасывается. Это действие называется "автоматический флаш" или "авто-флаш" flush.

И, наконец, рестарты:

#00 $creat

Создает и пересоздает кэш. Требуемый размер в блоках необходимо подавать в регистре A. Содержимое остальных регистров на работу рестарта не влияют. На выходе проверьте флаг C. В случае ошибки он будет установлен в "1". Единственная возможная ошибка: Error 130 - нехватка памяти, т.е. входное значение регистра A так велико, что кэш не влезает над адресом Utop (User Top). Достать адрес Utop Вы можете, применив рестарт $g_cnf(#10) (смещение +3 в векторе g_cnf). Utop служит, в основном, предохранителем от опускания кэша так низко, что программа set.com в процессе работы убила бы им саму себя. Поэтому обычно Utop=26676. Рестарт $creat(#00) обнуляет блоки размером по 256 байт под нижней границей области каналов ($g_cnf(#10) смещение (+32) в количестве указанном в регистре А и создает каталог кэша (по 4 байта на каждый блок). Работать с кэшем размером менее 4 блоков небезопасно, программа на это просто не рассчитана. Рекомендуемые размеры от 6..10 блоков минимум, если Вы хотите выиграть побольше памяти под буферы для программ или данных до 30 или даже может 70 (в iS-DOS Chic разумеется). Хотя наращивание кэша после 20 блоков почти не дает заметного выигрыша в скорости работы программ. Для восстановления размера кэша по умолчанию советуем такой вот пример:

LD C,#10           ;$g_cnf

RST 16

EXX                  ;в HL адрес вектора

LD BC,-6           ;смещение -6 здесь

ADD HL,BC       ;хранится размер кэша по умолчанию

LD A,(HL)        ;помещаем размер в А

LD C,#10           ;$creat

RST 16            ;пересоздаем кэш

RET C

При расчетах размера создаваемого кэша, если известны верхняя и нижняя границы его, Вы можете пользоваться формулой (2), логически вытекающей из формулы (1):

(2)

где    CSIZE - искомый размер кэша

DGCHN - нижняя граница области каналов она же - верхняя граница кэша

CACHE нижняя граница кэша.

Пример:

LD C,#10            ;$g_cnf

RST 16

EXX                   ;в HL адрес вектора

LD BC,32           ;смещение +32

ADD HL,BC

LD E,(HL)           ;в DE адрес верхней

INC HL               ;границы кэша

LD D,(HL)

LD HL,CACHE    ;это требуемая нижняя граница кэша, ниже которой вся память может

;быть использована Вашей программой

EX DE,HL          ;вычтем CACHE

SBC HL,DE        ;из DGCHN

XOR A

LD DE,260            ;делим результат

1$      SBC HL,DE       ;на 260

INC A

JR NC,1$

DEC A             ;проверяем не стал

CP 6                ;ли CSIZE меньше

JR NC,2$         ;6 блоков

LD A,130          ;Нет места! Выход с

RET                 ;ошибкой 130 код ошибки в регистре А

2$      LD C,#00           ;$creat

RST 16             ;пересоздаем кэш

RET C

#01 $clear

Очистка кэша от блоков текущего устройства. Эта операция необходима при смене дискеты в дисководе или при отказе выгрузки на диск блоков, модифицированных рестартами $modwr(#03), $modo(#2E), $wpart(#2A), когда авто-флаш ещё не случился, а так же при записи на диск мимо кэша блоков, считанных через кэш, дабы диск и кэш соответствовали друг другу. При работе рестарта вся информация, имеющаяся в кэше, теряется. Если в кэше есть модифицированные блоки, и Вы хотите их сохранить, то перед очисткой вызовите рестарт $flush(#02). Ошибок после вызова быть не должно. Входных параметров нет. Пример использования рестарта $clear взят из программы format.com:

Это начало процедуры format. Возможно, перед форматированием был сменен диск. Поэтому кэш должен быть очищен рестартом $clear(#01). Этот пример также будет полезен для лучшего понимания работы рестартов $g_blk(#13), $g_drv(#14), $binit(#0F), которые будут рассмотрены нами далее. Вначале с помощью $g_blk(#13) мы узнаем текущее блочное устройство и достаем адрес тела соответствующего ему драйвера. Далее проверяем является ли этот драйвер драйвером флоппи диска sys_driv.blk т.е. можно ли форматировать это устройство через TRDOS. Затем мы пытаемся открыть это устройство как блочное устройство IS-DOS рестартами $binit(#0F) и $open(#20), дабы предотвратить случайное переформатирование существующего диска:

LD C,#13                  ;$g_blk

RST 16                   ;получаем в А номер текущего блочного устройства

INC C                     ;$g_drv

RST 16                   ;узнаем адрес его

RET C                      ;драйвера

EXX                         ;в HL адрес тела драйвера текущего блочного устройства. Здесь мы проверяем,

;является ли этот драйвер драйвером дисковода

LD BC,9

ADD HL,BC

LD (DRCSR+1),HL

RES 7,(HL)               ;не вызывать $erdrv(#1F) при ошибках на диске

LD C,#01                  ;$clear

RST 16                   ;очищаем кэш

LD C,#0F                  ;$binit

RST 16                   ;инициализируем устройство

JR C,FOR_1             ;переход на процедуру форматирования, если устройство не существует

LD C,#20                  ;$open

RST 16                   ;пытаемся открыть устройство

JR C,FOR_1             ;переход на форматирование, если не открывается

...

FOR_1...                            ;здесь расположена программа форматирования диска

#02 $flush

Рестарт $flush(#02) необходим для фиксации на любом блочном устройстве: диске, винчестере или электронном диске изменений, произведённых в кэше после записи с помощью рестартов $modwr(#03), $modo(#2E), $wpart(#2A), $crfil(#23), $erfil(#24) и др. Все вышеперечисленные рестарты модифицируют блоки в кэше. Естественно, что эти изменения должны в конце концов оказаться на диске. Дело в том, что кэш блочных устройств был создан, во-первых: для ускорения работы нижних уровней системы, дабы дважды и трижды не читать с устройства одни и те же блоки. К тому же системе был нужен некий свой буфер для работы с каталогами и файлами. В связи с этим запись на устройства система в большинстве случаев осуществляет не напрямую и не лезет с каждым новым блоком на диск, а помечает блок в кэше, как "модифицированный", то есть устанавливает в 1 один из разрядов описателя блока в кэше. При достижении определенного количества модифицированных блоков (обычно оно равно размеру кэша, деленному на 2 или размеру кэша минус 3) происходит автоматический флаш. При этом в 1 устанавливается 1-ый бит 1-го байта вектора блочного устройства. Входных параметров у этого рестарта нет. Возможны различные ошибки на выходе, например ошибки кэша:

61 указанный блок не найден

62 реальное кол-во модифицированных блоков не соответствует значению системной переменной ($QNMOD)

63 сектор защищен

64 кэш защищен

65 нет места в кэше

66 чтение запрещено

67 запись запрещена

Ошибки блочного драйвера sys_driv.blk:

6 нет диска

7 ошибка чтения/записи

20 обращение к диску прервано

Если модифицированных блоков в кэше на текущем (!) устройстве нет, то рестарт ничего не делает. Советуем вызывать $flush(#02) в конце вашей программы перед выходом в оболочку, а так же перед запуском из Вашей программы некоторых системных утилит (copy25.com, например) и перед пересозданием кэша при высвобождении памяти. Если Ваша программа писала через кэш на несколько различных блочных устройств, например:

- текущее T:

- системное S:

- быстрое Q:

,то не забудьте сделать flush на каждом из этих устройств, переключаясь на них с помощью рестарта $swblk(#1C) или $g_sta(#37). Вот пример выхода из программы, модифицирующей блоки на нескольких устройствах, сразу скажем на Q S и T:

LD A,"Q"                   ;для устройства "Q"

CALL FLUSH             ;вызов подпрограммы

RET C

LD A,"S"                   ;для устройства "S"

CALL FLUSH             ;вызов подпрограммы

RET C

LD A,"T"                    ;для устройства "T"

CALL FLUSH             ;вызов подпрограммы

RET C                     ;здесь происходит восстановление среды, которая была на момент запуска

LD C,#41                 ;$fmrst

RST #10                    ;вызов рестарта

RET C                     ;выход в оболочку с перепечаткой экрана стандартным способом

XOR A

LD A,#F4

RET

;подпрограмма FLUSH. Сначала преобразуем логическое имя ;устройства ("S","Q","T") в физический номер (0..7)

FLUSH   LD C,#4A               ;$dvtrn

RST #10

LD B,A                    ;номер устройства помещаем в рег B, переключаемся на соответствующее

;устройство

LD C,#1C                ;$swblk

RST #10

RET C

;вот теперь собственно flush

LD C,#02              ;$flush

RST #10

RET                        ;возврат из подпрограммы

#03 $modwr

Запись одного блока (256 байт) с адреса, поданного в HL на текущее блочное устройство под номером блока, поданным в DE. Запись происходит через кэш, т.е. сперва в кэше освобождается место, выкидывается самый старый считанный блок, и на его место переносятся заданные 256 байт.

Новый блок получает свой номер и номер устройства (от 0 до 7) и тут же помечается как модифицированный. Если переполнения модифицированных блоков при этом не произошло, то на этом всё и кончается, иначе происходит автоматический флаш, (т.е. физическая запись модифицированных блоков на текущее устройство посредством обращения к драйверу).

При работе рестарта возможны ошибки, так что после его вызова советуем проверять флаг C. Коды ошибок те же, что и у $flush(#02). Рестарт $modwr(#03) удобен при работе непосредственно с устройством (минуя файл). Не забудьте только вызвать $flush(#02) в конце программы!

Пример из жизни: программа arzt+.com, а точнее ее фрагмент, в котором осуществляется запись на устройство измененной таблицы занятых блоков:

LD HL,$BUFF             ;адрес рабочего буфера помещаем в HL

LD DE,1                     ;номер 1-го блока в DE

LD A,($MLTRD+2)       ;число блоков

LD B,A                    ;помещаем в B это счетчик последующего цикла

LD C,#03                 ;$modwr

3$         RST #10

RET C

INC DE                    ;вызов в цикле

INC H                      ;для всех блоков

DJNZ 3$                  ;по очереди

RET

#04 $unird

Парный к предыдущему рестарт чтения одного блока устройства с кэша. В HL помещаем адрес, в DE - номер блока на устройстве. Если блока в кэше нет, процедура считывает его через драйвер. Флаг C на выходе сообщает о неудачно проведенной операции. Коды ошибок, как и в предыдущих двух случаях. В реальной жизни этот рестарт практически не применяется, поэтому в качестве примера прочитаем 0-й блок устройства в буфер BUFF, очистив перед этим на всякий случай (если была смена диска) кэш.

LD C,#01         ;$clear

RST #10        ;очистка кэша

LD DE,0          ;номер блока = 0

LD HL,BUFF    ;адрес буфера

LD C,#04         ;$unird

RST #10

RET C

#05 $mltrd

Почти тоже самое, но читается сразу несколько блоков. Число блоков задается в регистре B. Сперва эти блоки ищутся в кэше и копируются по означенному адресу, затем прямо туда, куда заказывали, считываются через драйвер недостающие блоки, которые уже затем копируются в кэш. Если число считываемых блоков превосходит размер кэша пополам, то считывание происходит мимо кэша, дабы не выбивать из него такие часто требующиеся блоки как блоки каталогов и заголовок устройства и таким образом не замедлять работу системы с каталогами. Напрямую считываться блоки будут также при наличии в кэше модифицированных блоков. Можно заставить всегда работать этот рестарт напрямую с драйвером, сбросив 7‑ой бит 0‑го байта вектора блочных устройств. Этим рестартом пользуется рестарт чтения части файла $rpart(#29), с помощью которого в свою очередь запускаются все com-файлы системы. На всякий случай анализируйте флаг C на выходе. Коды ошибок те же, что и у $flush(#02). Пример взят опять же из arzt+.com: считывание карты занятых блоков устройства в буфер $BUFF. Байт $MLTRD+2 заранее заполняется размером карты:

LD C,#35                     ;$bkfcb

RST #10                      ;считываем описатель

EXX                            ;диска и находим в

LD BC,-6                     ;нем размер карты

ADD HL,BC

;Округлим его до целых блоков: и поместим по адресу $MLTRD+2

LD A,(HL)

INC HL

OR A

LD A,(HL)

JR Z,$+3

INC A

LD ($MLTRD+2),A

CALL $MLTRD ;вызов подпрограммы

;подпрограмма, использующая $mltrd(#05)

$MLTRD   LD BC,#05                    ;$mltrd

LD HL,$BUFF              ;адрес буфера в HL

LD DE,1

RST #10

RET

$BUFF                                       ;это буфер


 

#06 $quard

Почти тоже, что и $unird(#04), но блок считывается только в кэш (или просто находится в нем). Поэтому регистр HL на входе не используется, зато на выходе в HL' возвращается адрес блока в кэше, DE' - адрес заголовка блока в каталоге кэша (необходим для дальнейшего использования $modo(#2E)). На входе в DE подается номер блока устройства.

Возможны различные ошибки (те же, что и у рестарта $flush(#02)), посему проверяйте флаг C. Удобен для работы резидентов или программ, которым жаль буферов под блок. Пример взят из программы date.com:

;Считаем 0-ой блок устройства. Именно там хранится дата загрузки системы:

LD DE,0                  ;номер блока = 0

LD C,#06               ;$quard

RST #10

RET C

EXX

;Сохраним адрес считанного блока (HL) и адрес описателя этого блока в кэше (DE):

LD (TMPHL+1),HL

LD (TMPDE+1),DE

;печать и изменение даты (эти процедуры пропущены здесь за ненадобностью) выход из программы: в DE подаем новое значение даты. Сравним его с хранящимся в 0-ом блоке устройства и, если они разнятся, положим новую дату в 0-ой блок и сохраним его на устройстве рестартами $modo(#2E) и $flush(#02):

FTMPHL  LD HL,0               ;в этот пустой байт помещается вышеупомянутый адрес считанного блока

LD BC,30

ADD HL,BC

LD C,(HL)

INC HL

LD B,(HL)

;в BC теперь старая дата, считанная с устройства

EX DE,HL

XOR A

PUSH HL            ;новая дата

SBC HL,BC           ;сравнение

POP HL

EX DE,HL

JR Z,SVSTYL        ;даты равны, обход

;Если же даты не равны, то кладем новую поверх старой прямо в кэше:

LD (HL),D

DEC HL

LD (HL),E              ;Промодифицируем блок в кэше:

FTMPDE LD DE,0              ;в пустой байт после DE как Вы помните, мы ранее поместили адрес описателя блока в кэше, полученный из рестарта $quard(6) несколькими строками выше. Этот адрес необходим для $modo.

LD C,#2E            ;$modo

RST #10

RET C

LD C,#02               ;$flush

RST #10

RET C

SVSTYL...

#07 $key

Ввод символа с клавиатуры. Обращается прямо в 1-ую точку входа драйвера клавиатуры. Адрес этой точки входа лежит в драйвере со смещением 2. Если буфер драйвера пуст, тогда драйвер обращается к портам клавиатуры и ждет, пока клавиша не будет нажата.

Выходное значение возвращается в регистре A. Оно зависит от нажатой клавиши и от режима, в котором находится устройство ввода. Режим определяется нулевым байтом вектора символьного устройства ввода g_key, который можно получить обратясь к рестарту $g_key(#11).


0-ой байт вектора. Биты (0/1):

0 строчные/ПРОПИСНЫЕ

1 lat/русские

2 текст/псевдографика

3 не ждать отпускания клавиш при $kwait(#08). Применяется для макросов в редакторе, сбрасывается сам при опустошении буфера драйвера.

Флаг С роли не играет. В качестве примера приводится подпрограмма из текстового редактора edit.com, зажигающая и гасящая курсор в текущих координатах и опрашивающая клавиатуру с ожиданием или без (управляется 5-ым битом в edcsr):

;Переключим клавиатуру в режим маленьких латинских, чтобы получить код управляющей клавиши, не зависящий от текущего состояния. 3-ий бит (макро) маскируется восьмёркой, дабы сохранить его. Биты 0,1,2 обнуляются:

F$KEY      LD C,#11                    ;$g_key

RST #10

EXX

LD A,(HL)

AND 8

LD (HL),A ;lat

;Переключение на текущий драйвер вывода на экран (t42/t64):

CALL $TYCUR

RET C

;Позиционирование Пересчитаем координаты в тексте xc в позицию на экране и положим YX в HL:

LD H,(IX+ys)

LD A,(IX+ys-1)

ADD A,(IX+xc)

SUB (IX+X_skip)

LD L,A

L_F           LD C,#0C                 ;$typos

RST #10                    ;зажжем мигающий курсор в текущей позиции:

LD C,#76                   ;$y

RST #10

LD C,#08                   ;$kwait

;Обход ожидания отпускания клавиши:

BIT 5,(IX+edcsr)

JR Z,$+3

RST #10

DEC C                    ;7=$key ввод

RST #10                  ;клавиши

PUSH AF              ;сохраним код

LD C,#77                 ;$n_

RST #10                  ;погасить курсор

POP AF                  ;восстановим код

RET

#08 $kwait

Ожидание отпускания клавиш. Рестарт необходим в некоторых случаях, когда опасна случайно дважды нажатая (удерживаемая) клавиша, например в самом начале программы, вызываемой клавишей и также опрашивающей клавиатуру с помощью предыдущего рестарта. Это вторая точка входа в драйвер (адрес ее находится в драйвере со смещением 4). Используется в рестартах $smbgt(#6E), $edstr(#7F), $menu(#91). На выходе может быть всё, что угодно. Пример см. предыдущий рестарт. Эта процедура вызывается, скажем, блочным оверлеем ed0+.ovr с ожиданием отпуска клавиши перед рестартом $analy(#7E) после печати нижней строки функций оверлея и при вызове функции <Cs/D>, требующей подтверждения. Такой вызов гарантирует надежность. Однако при отметке блока та же процедура вызывается без ожидания отпускания, что позволяет отмечать большие блоки удерживая клавишу и используя автоповтор. Этот рестарт при вызове опустошает буфер драйвера клавиатуры, т.о. драйвер "забывает" все нажатые до вызова рестарта клавиши. Если бы эта функция драйвера не отключалась бы 3-им битом регистра состояния клавиатуры, макросы работали бы лишь до первого $kwait.


 

#09 $ktest

Этот рестарт - третья точка входа в драйвер клавиатуры. Он определяет, нажата хоть одна клавиша на клавиатуре или нет. Выход во флаге Z:

Z - не нажата,

NZ - нажата.

Как и $key(#07) в первую очередь опрашивает буфер драйвера, где накапливаются быстро нажатые клавиши, и который используется для макросов или эмуляции нажатой клавиши. Этот рестарт удобен для опроса клавиатуры без ожидания, например, для прерывания работы циклов. При нажатии клавиши флаг на выходе - NZ, а код клавиши будет в регистре A, а также в буфере драйвера, откуда его необходимо извлечь рестартом $key(#07), иначе на него наткнется еще кто-нибудь.

Пример:

;Эта подпрограмма вернется с флагом Z, если клавиш нажато не было, и с флагом NZ и кодом клавиши в регистре A в противном случае.

FKTEST       LD C,#09                ;$ktest

RST #10

RET Z

LD C,#07              ;$key

RST #10                ;извлекаем "лишний" код из буфера драйвера клавиатуры

OR A

RET

#0A (10) $type

Печать символа из регистра A на текущем устройстве символьного вывода (экран или принтер). Выбор устройства (экран или принтер) можно осуществить при помощи рестарта $svtyp(#1B).

Флаг на выходе при печати на экране роли не играет, обращаясь к принтеру можно схлопотать следующие ошибки:

150 ошибка или принтер не готов,

151 печать прервана.

Последняя версия программы print.com не пользуется этим рестартом. Печать на экране происходит в текущей позиции, которая хранится в байтах 1..4 вектора символьного устройства вывода. Вектор можно достать с помощью рестарта $g_typ(#12).

Байты:

1 Позиция печати в строке

2 Номер строки на экране

Эти 2 байта подаются в HL на входе рестарта $typos(#0C), который передает их в регистре BC в 3-ю точку входа в драйвер (смещение 6). 3,4 Адрес печати на экране. Это левый верхний байт буквы. Например #40 для 0-ой позиции в 0-ой строке).

Сюда эти байты кладут рестарты $typos(#0C) и $wtpos(#6B). Отсюда берет их для печати следующего символа рестарт $type(#0A). Сюда же он их и возвращает после печати. Рестарт обращается к 1-ой точке входа драйвера (смещение 2 от начала драйвера). При этом адрес печати на экране подается в регистре DE'. Этим рестартом пользуются рестарты более высоких уровней, такие как $str(#6C), $smbgt(#6E) и др.

#0B (11) $tycpl

Устанавливает инверсный/нормальный режимы печати на экране в соответствии с содержимым регистра А:

A<>0 инверсная печать

A=0 нормальный режим

У драйверов принтеров не используется. Флаг C на выходе значения не имеет. Рестарт используется новой версией текстового редактора для блочной отметки, а также программой demon.com. Обращается во 2-ую точку входа в драйвер (адрес по смещению 4).

#0C (12) $typos

Задание позиции печати на экране для последующей печати рестартами $type(#0A), $str(#6C), $lnstr(#6D), $smbgt(#6E), $edstr(#7F). Координаты печати задаются в регистре HL:

H - номер строки,

L - позиция в строке.

Для позиционирования относительно окна также можно пользоваться рестартом $wtpos(#6B). Флаг C на выходе значения не имеет. Этот рестарт использует 3-ю точку входа в драйвер (смещение 6). У старых драйверов принтера эта точка не использовалась. У новых она отвечает за печать символа из регистра A без перекодировки.

Вот как использует рестарты $typos и $type программа exebat.com для печати командной строки из системного буфера:

;Проверка наличия 8-го канала (канал драйвера символьного вывода) т.к. программа должна работать даже тогда, когда печатать нечем:

FPRINT   LD A,8               ;ty42

LD C,#16            ;$stchn

RST #10

RET C

;Позиционирование:

SBC HL,HL         ;HL=0: верхняя строка

LD C,#0C          ;$typos

RST #10

LD C,#45            ;$g_com

RST 16

EXX                 ;HL=адрес системного буфера

LD BC,#2A0A   ;$type B=#2A=42-столько букв помещается в одну строку на экране, #0A - $type

;Печатаем строку до символа #0D:

1$           LD A,(HL)

CP #D

JR Z,2$

RST #10

INC HL

DJNZ 1$

RET

;Допечатка пробелов:

2$           LD A," "

RST 16               ;C=$type (см выше)

DJNZ 2$

RET

#0D (13) $read

Чтение блоков напрямую с драйвера текущего блочного устройства. На входе:

HL - адрес,

DE - номер блока устройства,

B - число блоков.

Флаг C на выходе - признак ошибки. Ошибки только те, что выдает драйвер. Так драйвер электронного диска обычно не выдает ошибок, хотя никто не мешает встроить в него проверку, скажем номера блока на слишком большой номер или число считываемых блоков на 0 или вставить проверку контрольной суммы блока. У драйвера sys_driv.blk возможные ошибки следующие:

6 нет диска

7 сектор не читается

20 чтение прервано.

Обычно драйвер флоппи-диска отрабатывает эти ситуации, обращаясь к рестарту $erdrv(#1F) (см ниже). Рестарт обращается к 1-ой точке входа в драйвер. Пример взят из жизни копировщиков: начало рабочего цикла программы abc.com. В байты INDSK+2 и OUTDSK+2 кладутся номера входного и выходного устройств.

;B=число блоков для чтения/записи

FCOPY   PUSH BC

INDSK       LD BC,#1C        ;$swblk

RST #10

POP BC

RET C

LD HL,BUFF     ;буфер копирования

LD C,#0D            ;$read

RST #10

RET C

PUSH BC

OUTDSK LD BC,#021C       ;$swblk в C

RST #10

POP BC

RET C

LD C,#0E         ;$write

RST #10

RET C

...

#0E (14) $write

Запись B блоков с адреса HL на текущее блочное устройство (флоппи диск, электронный диск или винчестер) начиная с блока номер DE. В IS-DOS любое блочное устройство состоит из логических блоков размером 256 (#100) байт, что очень удобно для расчетов в ассемблере. Пересчётом номера блока в трек, сторону и сектор занимается драйвер. Драйвер флоппи диска настраивается на формат IS-DOS дискеты сам рестартом $binit(#0F). Это 2-ая точка входа в драйвер.

Поскольку это прямое обращение к устройству минуя кэш, то рекомендуется сразу же после вызова этого рестарта вызывать $clear(#01) или $creat(#00) во избежании путаницы блоков в кэше и блоков на устройстве!

Ситуация с возможными ошибками точно такая же, как и у $read(#0D). Пример также см. выше.

#0F (15) $binit

Автонастройка драйвера флоппи диска на формат IS-DOS диска. Считывает 0-й блок диска, проверяет наличие признака "DSK" со смещением 10 (в новых версиях системы по смещению +13 в связи с введением 11-символьного имени устройства). Если признака нет, то выходит с ошибкой 9. Иначе настраивается на параметры диска, лежащие со смещением:

22

число цилиндров

23

тип диска (число сторон)

24

размер сектора (1/2/4:256/512/1024)

25

число секторов на дорожке

64

номера секторов (до 16 штук)

Возможна также ошибка 10 - попытка работы с двусторонним диском на одностороннем дисководе или с 80-дорожечным на 40-трековом. Это 3-ий вход в драйвер. Обычно не используется у драйверов электронного диска и винчестера (там ставятся "заглушки" для совместимости). Этот рестарт полезно вызывать при первом обращении к новому блочному устройству для настройки драйвера на диск и чтоб убедиться в том, что это именно IS-DOS устройство. Кроме ошибок 9 и 10 может выдать ошибки чтения: 6 7 и 20. Драйвер можно настроить и на работу с форматами TR-DOS и MS-DOS, но рестарт здесь уже мало чем поможет. В таких случаях лучше найти драйвер, с помощью рестарта $g_drv(#14), убедиться, что это именно драйвер флоппи-диска и по смещению 34(dec) сменить размер сектора, количество секторов и таблицу секторов. В качестве примера рекомендуем отрывок из format.com, приведенный после описания рестарта $clear(#01).




СОДЕРЖАНИЕ:


  Оставте Ваш отзыв:

  НИК/ИМЯ
  ПОЧТА (шифруется)
  КОД



Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
Начало - Вот ведь, блядь, как плохо на душе!
Разное - Страшилка.
Наш гость - мемуары спектрумиста из Дзержинска - Nuts.
Рассказ - Нетерпение сердца (продолжение).
CREDITZЬ - Здeсь писaно про всeх кто приложылся к fpl-1.

В этот день...   23 ноября