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

Рестарты - DUD.SYS (#20...#2F).



ФАЙЛОВАЯ СЛУЖБА (DUD.SYS)

Для начала о структуре блочного устройства в iS-DOS'е. Любое блочное устройство (дискета, электронный диск или винчестер) с точки зрения iS-DOS'а представляет собой набор блоков размером в 256 байт и нумерующихся от 0 до 65535. Заголовок устройства содержится в 0-ом блоке. Подробно структура 0-го блока приводилась ранее при описании рестарта $binit(#0F), сейчас же повторим лишь следующее:

10(3)* "DSK": признак iS-DOS

18(2) Размер устройства в блоках

20(2) Номер первого блока главного каталога

Подробнее см. ПРИЛОЖЕНИЕ 1.

Размер устройства должен быть кратен 8. Связано это с представлением карты занятых и свободных блоков, в которой каждому блоку устройства соответствует 1 бит. Занятому блоку соответствует 1, свободному - 0. Карта начинается с 1-го блока диска и занимает столько блоков подряд, сколько необходимо для устройства соответствующего размера. Структура карты очень проста: по 1 биту на блок (8 блоков в байте, до 2048 блоков устройства на 1 блок карты), 0-му блоку устройства соответствует 7-ой бит 0-го байта карты, 1-му блоку - 6-ой бит и т.д. На обычном флоппи-диске карта занимает 2 блока. Максимально (на винчестере) карта может занимать 32 блока.

На устройстве должен находиться хотя бы один каталог, т.е. главный. Номер 0-го блока главного каталога указан в 0-ом блоке устройства со смещением 20.

Любой каталог в iS-DOS'е представляет собой файл, содержащий в себе 32-байтовые описатели файлов, первый из которых (0-ой) - это описатель самого каталога. Т.о. в iS-DOS'е у каталогов два описателя: внутренний и внешний. Исключение составляет лишь сам главный каталог, не имеющий внешнего описателя. У двух описателей должны быть одинаковые имена, основную же информацию о каталоге хранит внутренний описатель. Внешний же служит лишь для открывания каталога по имени и печати имени каталога в панели.

Любой файл (и каталог) в iS-DOS'е может быть непрерывным или сегментированным. Непрерывный файл (каталог) занимает на устройстве непрерывную последовательность блоков. Номер начального блока файла указывается в описателе файла со смещением 17. У сегментированных файлов здесь указывается номер блока описателя сегментов. Это специальный блок, имеющий следующую структуру:

0-й байт - число сегментов (от 0 до 85),

следующие 2 байта - номер начального блока 1-го сегмента,

3-й байт - размер сегмента в блоках (от 1 до 255).

Следующие 3 байта описывают следующий сегмент и т.д. (см. ПРИЛОЖЕНИЕ 22)

В iS-DOS'е существуют понятия текущего устройства (их может быть 8, они переключаются рестартом $swblk), текущего каталога (открывается рестартом $open1) и текущего файла.

#20 (32) $open

Этот рестарт открывает устройство и его главный каталог. Для этого считывается 0-й блок устройства и проверяется на наличие признака "DSK" со смещением 10 (13 для новой системы) в нём. Проверяется размер устройства на кратность 8 и неравенство 0. Затем рестарт пытается открыть главный каталог по номеру его начального блока, указанного в том же блоке со смещением 20.

Входных параметров нет. Выходных также. Возможные ошибки:

87 - нет признака "DSK" или неверный размер устройства

86 - каталог не открывается: ошибка в описателе каталога плюс все возможные ошибки драйвера

Пример: выход из программы fileshow. Ожидается нажатие клавиши. Если это <Cs/Ent>, то открывается новое устройство:

LD C,$kwait           ;ждем отпуска клавиш

RST 16

DEC C                  ;ждем нажатия клавиши

RST 16

CP #17                  ;Cs/Enter?

JR NZ,3$

LD C,$clear           ;очистить кэш

RST 16

; очистить буфер драйвера и настроить его на новую дискету:

LD C,$binit

RST 16

RET C

LD C,$open           ;открыть устройство

RST 16

RET C

;и, наконец, выход с перерисовкой экрана

3$          XOR A

LD A,#F4

RET

#21 (33) $open1

Открыть каталог. На входе в регистре DE подается номер начального блока каталога. Выходных параметров нет. Возможна ошибка с номером 86 (см. предыдущий рестарт). Считывается 0-й блок каталога и проверяется: байты 8..10 должны быть пробелами, в 11-ом байте 0-ой и 5-ый биты должны быть в 1, 19-й и 20-й байты должны содержать номер 0-го блока. При любом несоответствии получим ошибку 86.

Возможные ошибки:

81 - файл не найден

85 - ломаный блок описателя сегментов (текущего или искомого каталога)

86 - ломаный каталог

В качестве примера рассмотрим как программа coca.com открывает устройство и каталог альтернативной панели:

;достанем системный вектор оболочки (см. ПРИЛОЖЕНИЕ 17)

LD C,$gmpan               ;#87

RST 16

EXX

DEC BC

LD A,(BC)                    ;номер текущей панели

INC BC

OR A

JR NZ,$+3

INC BC

LD A,(BC)                    ;канал альтернативной панели

LD C,$stchn

RST 16

RET C

EXX

;HL=адрес тела канала альтернативной панели (см. ПРИЛОЖЕНИЕ 18)

LD B,(HL)                   ;номер устройства

INC HL

LD E,(HL)

INC HL

LD D,(HL)

; DE= номер 0-го блока каталога

LD C,$swblk

RST 16

RET C

LD C,$open1

RST 16

RET C

#23 (35) $crfil

Создать файл в текущем каталоге на текущем устройстве. В HL - адрес 32-байтового описателя файла. В нем необходимо указать имя, расширение файла, байт состояния (если непрерывный - 6-ой бит =1). Старший байт длины обнуляется, т.о. создать можно файл длиной не более 255 блоков (65280 байт). Если Вам требуется создать файл большей длины, пользуйтесь дополнительно рестартом $fadd(#2F) или $eadd(#31). После создания файл будет открыт. Следует помнить, что сей рестарт, равно как и большинство рестартов этого уровня работает через кэш. Поэтому:

1. Всегда следите за сохранностью кэша;

2. Так как результат действий рестарта будет также в кэше в виде модифицированных блоков, не забудьте по окончании работы программы сохранить эти модифицированные блоки на устройстве с помощью рестарта $flush(#02).

Возможные ошибки:

82 - файл с таким именем и типом уже существует

84 - переполнение каталога (128 файлов)

92 - на диске нет места

105 - каталог непрерывен и заполнен до краев.

А также любые ошибки кэша и драйвера.

Для примера предлагается кусок из программы move.com:

;Открыть выходной каталог:

CALL G_DEST

RET C

SBC HL,HL

LD (FLEN),HL          ;Обнулить длину

LD HL,FSTAT

SET 6,(HL)             ;Непрерывный файл

LD HL,FILE

LD C,$crfil

RST 16

RET C

;Копируем описатель файла:

EXX

EX DE,HL

LD HL,FILE+32

LD BC,32

LDIR

LD C,$putf               ;и сохраняем его

RST 16

RET C

FILE         EQU $

FSTAT    EQU FILE+11

FLEN     EQU FILE+14

#24 (36) $erfil

Найти файл по имени и уничтожить. Если файл не найден, не докладывать. В регистре HL подается адрес 11-байтового описателя: 8 байт имени и 3 байта расширения.

Возможные ошибки:

89 - файл защищен от удаления

85 - неверный блок описателя сегментов

93 - попытка освободить блоки за концом устройства

Пример из программы sv_image.com:

;текущая дата для создаваемого файла:

LD C,$g_com         ;#45

RST 16

EXX

DEC HL

DEC HL

LD D,(HL)

DEC HL

LD E,(HL)

LD (DATE),DE

;в зависимости от ключа: удалять или нет:

LD HL,FILE

OPTION  LD A,0

OR A

LD C,$erfil

CALL NZ,16

RET C

DEC C              ;$crfil

RST 16

RET C

#25 (37) $fopen

Найти и открыть файл по имени и расширению. В HL на входе подается адрес 11-байтового описателя файла. Если найденный файл - каталог, то он открывается.

Выход (если без ошибок, т.е. флаг C сброшен), то в регистре A:

#00 - открыт файл;

#20 - открыт каталог;

HL' - адрес системного 32-байтового описателя файла (этот адрес можно получить с помощью рестарта $bkfcb(#35)).

Возможные ошибки:

81 - файл не найден

85 - ломаный блок описателя сегментов (текущего или искомого каталога)

86 - ломаный каталог

Рассмотрим для примера кусочек программы unicolor.com в той части, где программа ищет подкаталог HELP и в нем файл с расширением .hlp:

;Текущий путь для печати его в окне:

LD HL,PATH+8           ;буфер для пути

PUSH HL

LD B,pathSZ              ;длина буфера

;Заполним буфер пробелами

LD (HL)," "

INC HL

DJNZ $-3

POP HL

XOR A

LD DE,56

LD C,$g_way             ;#47

RST 16

RET C

;Ищем конец пути, т.е. первый пробел:

1$          LD A,(HL)

CP " "

INC HL

JR NZ,1$

DEC HL

PUSH HL

;В системном описателе - текущий файл:

LD C,$bkfcb

RST 16

EXX

POP DE

;Перекодируем имя текущего файла в буфер пути:

LD C,$convr

RST 16

RET C

;Попытаемся найти HELP*.hlp

XOR A

LD (hlpCSR+1),A

;Копируем 8 байт имени текущего файла в буфер имени hlp-файла:

LD DE,hlpNAM

PUSH DE

LD BC,8

LDIR

; …и, наконец, пользуемся нашим рестартом fopen. Сперва откроем каталог:

LD HL,HELP

LD C,$fopen

RST 16

POP HL

JR C,GW_EX             ;уходим по ошибке

;а затем им же и файл:

RST 16

JR C,GW_EX

;не отходя далеко от кассы, достанем длину файла:

EXX

LD BC,14

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

hlpNAM  DEFS 8

DEFM "hlp"

HELP     DEFM "HELP"

#26 (38) $opnum

Открыть файл по номеру в регистре A.

На выходе, если все в порядке: A-сохраняется, HL' - адрес системного 32-байтового описателя файла.

Возможные ошибки:

80 - номер файла слишком велик (больше 21-го байта описателя каталога -1)

Пример из программы calc.com. С помощью рестарта $opnum программа открывает файл, на котором стоит курсор:

ORG 24000

;пытаемся открыть параметр:

LD C,$opcat

RST 16

RET C

JR Z,1$

;параметра в строке нет, следовательно, открываем файл под курсором:

LD C,$mwait          ;"Wait Please!"

RST 16

LD C,$g_cur            ;#8A

RST 16

;A=номер файла, на котором стоит курсор. Открываем файл по его номеру в каталоге:

LD C,$opnum

JR 2$

1$          EXX

;открываем параметр по имени:

LD C,$find

2$          RST 16

RET C

EXX

;каталоги не обслуживаем:

LD DE,11

ADD HL,DE

BIT 5,(HL)

RET NZ

LD DE,26-11

ADD HL,DE

;HL указывает на длину файла в его описателе

#27 (39) $gname

Считать в кэш или найти в кэше соответствующий блок каталога и установить регистровую пару HL' на описатель искомого файла в этом блоке.

Вход: E - номер файла.

Файл не открывается, т.е. сохраняется текущий открытый файл.

Возможные ошибки: см. предыдущий рестарт.

Пример из программы univ.res. Цикл подбора файлов, подходящих под маску:

PODBOR

LD DE,#100

1$          INC E                   ;номер файла

LD C,$gname

RST 16

JR C,2$

PUSH DE

EXX

;HL указывает на описатель файла в кэше

LD DE,TRAF         ;трафарет (11 байт)

;сравнение 11 байт по адресам в HL и DE:

LD C,$cpfil            ;#8F

RST 16

POP DE

JR NZ,1$

PUSH DE

CALL WIBCN         ;работа с файлом

POP DE

RET C

JR 1$

;Ошибка. В регистре A ее код:

2$          CP 80                    ;каталог кончился

RET Z

SCF                      ;иначе: что-то серьезное

RET

#28 (40) $putf

Сохранить в текущем каталоге измененный вектор текущего файла (тот, что доступен через $bkfcb(#35)). Полезно для переименования файла и тому подобных операций. Номер файла лежит по адресу bkfcb-1.

Возможные ошибки: ошибки файловые, ошибки кэша и драйвера:

80 - номер файла слишком велик

85 - неверный блок описателя сегментов (ломаный каталог)

7 - ошибка чтения/записи (драйвер)

62 - несоответствие числа модифицированных блоков (кэш)

Вот так выглядит применение этого рестарта на выходе из программы calc:

;в HL - контрольная сумма открытого файла

;в (ADRKK+1) - адрес контрольной суммы в системном описателе файла (bkfcb+26)

ADRKK    LD (0),HL

LD C,$putf

RST 16

RET C

LD C,$flush

RST 16

RET C

XOR A

RET

#29 (41) $rpart

Прочитать DE байт из текущего открытого файла со смещением AHL байт от начала файла по адресу в IX.

Возможные ошибки:

100 - попытка чтения за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - чтение 0 байт (DE=0)

171 - файл защищен от чтения

7 - ошибка чтения/записи (драйвер)

Пример из программы tree.com. Она открывает главный каталог, находит там файл treecat.txt, проверяет, влезет ли он в буфер под кэш и считывает его:

LD C,$open             ;главный каталог

RST 16

RET C

LD HL,FILE

LD C,$find               ;найти по имени файл

RST 16

RET C

EXX

LD BC,#000F

ADD HL,BC

LD D,(HL)

DEC HL

LD E,(HL)              ;DE=длина файла

LD HL,BUFF

;BUFF - буфер за концом программы

ADD HL,DE

; адрес конца файла в буфере

LD C,$g_cnf            ;#10

RST 16

PUSH DE                ;длина файла

EXX

LD BC,5

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

PUSH DE                ;адрес кэша

EXX

POP DE

EX DE,HL

XOR A

SBC HL,DE

LD A,130

POP DE                  ;длина файла

RET C                   ;не хватает памяти

XOR A

LD L,A

LD H,A                    ;AHL=0

LD IX,BUFF

LD C,$rpart

RST 16

RET C

#2A (42) $wpart

Записать DE байт в текущей открытый файл со смещением AHL байт от начала файла с адреса в IX.

Возможные ошибки:

100 - попытка записи за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - запись 0 байт (DE=0)

172 - файл защищен от записи

7 - ошибка чтения/записи (драйвер)

62 - несоответствие числа модифицированных блоков (кэш)

Для примера рассмотрим сохранение параметров программой date.com на выходе из программы:

;сохранение текущей среды в буфере curID

LD IX,curID

XOR A

LD C,$p_stat

RST 16

;Достать среду последнего запущенного com-файла, т.е. date.com

LD C,$g_com

RST 16

EXX

LD BC,#FFF7

ADD HL,BC

PUSH HL

POP IX

;открыть файл date.com:

XOR A

LD C,$g_stat

RST 16

RET C

;записать в него 1 байт со смещением 2 из WDCSR:

LD IX,WDCSR

LD DE,1

XOR A

LD HL,2

LD C,$wpart

RST 16

RET C

;сосчитать контрольную сумму date.com

LD HL,CALC

LD C,$run

RST 16

JR NC,0$

;ошибка:

CP 37                 ;нет резидентной задачи?

SCF

RET NZ

0$          LD C,$flush

RST 16

RET C


 

CALC     DEFM "@calc"

DEFB 13

#2B (43) $rifle

Прочитать B блоков открытого файла начиная с DE-го по адресу в HL. Чтение осуществляется мимо кэша, однако следует помнить, что если файл сегментированный, то система сама подчитывает в кэш блок описатель сегментов файла. Т.е. следите, чтобы ваша программа не повредила кэш к тому моменту, когда Вы соберетесь воспользоваться этим рестартом, равно как и большинством рестартов этого уровня системы.

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. DE+B больше длины файла в блоках).

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

Пример из жизни копировщиков: начало цикла копирования программы image.com:

COPY

;B=размер буфера копирования

PUSH BC

;переключиться на входное устройство:

FROM    LD BC,$swblk

RST 16

POP BC

RET C

;Считать B блоков в буфер BUFF из открытого файла:

LD HL,BUFF

LD C,$rifle

RST 16

RET C

;переключиться на выходное устройство:

PUSH BC

DEST       LD BC,$swblk

RST 16

POP BC

RET C

;Записать B блоков на текущее устройство

LD C,$write

RST 16

RET C

#2C (44) $wifle

Записать B блоков в открытый файл начиная с DE-го с адреса в HL. Запись осуществляется мимо кэша. Посему после использования данного рестарта может возникнуть ситуация несоответсвия блоков в кэше блокам на устройстве, что чревато боком. Исправить дело можно очистив принудительно кэш рестартом $clear(#01) или пересоздав его рестартом $creat(#00).

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. DE+B больше длины файла в блоках).

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

В качестве примера - кусок программы ibm_is.com:

;Открыть выходной файл:

O_FILE     LD A,0

CALL OPNUM

JR C,0$

EXX

LD BC,15

ADD HL,BC

LD E,(HL)

INC HL

LD D,(HL)

;DE=длина файла в блоках

LD A,(OBUFSZ+2)

LD B,A

;A=B=размер выходного буфера в блоках.

;Добавить в конец файла A блоков:

LD C,$fadd

RST 16

JR C,0$

;Записать B блоков в файл начиная с DE-го блока из буфера O_BUF:

LD C,$wifle

LD HL,O_BUF

RST 16

0$          POP HL

POP DE

POP BC

RET

;Подпрограмма открывает файл по номеру в регистре A.

OPNUM  CP 0

RET Z                   ;файл уже и так открыт

LD (OPNUM+1),A

LD C,$opnum

RST 16

RET

#2D (45) $qrvbl

Прочитать один блок номер DE открытого файла в кэш.

Выход (если все O.K.):

HL' - адрес блока в кэше. (Если блок уже находился в кэше, то считывания с устройства не происходит, рестарт просто находит его и сообщает адрес. Тогда A=1, иначе A=0.)

DE'- адрес описателя блока в кэше. Необходим для рестарта $modo(#2E).

Возможные ошибки:

101 - попытка чтения за концом файла (т.е. AHL+DE больше длины файла).

106 - файл не открыт

170 - чтение 0 байт (DE=0)

171 - файл защищен от чтения

7 - ошибка чтения/записи (драйвер)

Пример: очистка каталога при его создании программой mkdir.com:

LD HL,(FILE+14)

;HL=длина файла-каталога в байтах

LD A,L

OR A

LD A,H

JR NZ,$+3

DEC A

OR A

RET Z

LD B,A

;B=A=число блоков, которые нужно очистить

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

1$          LD C,$qrvbl       ;прочитать блок

RST 16

RET C

EXX

;HL=адрес блока в кэше

XOR A

LD B,A

;256 нулей:

LD (HL),A

INC HL

DJNZ $-2

PUSH DE            ;адрес описателя блока

EXX

POP HL

EX DE,HL

LD C,$modo

RST 16

RET C

EX DE,HL

INC DE               ;номер блока

DJNZ 1$

RET

#2E (46) $modo

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

Вход: DE - адрес описателя блока в кэше. Этот адрес выдается на выходе рестартами $quard(#06) и $qrvbl(#2D). Обычно рестарт $modo используется сразу после этих рестартов. Именно сразу, поскольку блок может сместиться или вообще быть вытеснен из кэша при вызове многих рестартов, считывающих блоки в кэш, например: $open, $open1, $fopen, $find, $rpart, $gname, $opnum, $crfil и др.

Возможные ошибки:

62 - несоответствие числа модифицированных блоков (кэш)

7 - ошибка чтения/записи (драйвер)

Вот что делает программа arzt+.com, когда сдвигает файл is_dos.sys:

;Прочитать 0-ой блок устройства в кэш:

LD DE,0

LD C,$quard

RST 16

RET C

EXX

LD BC,32+17

ADD HL,BC

LD BC,(FR1ST+1)

;BC=номер блока, где после сдвига находится файл is_dos.sys:

LD (HL),C

INC HL

LD (HL),B

;Сосчитаем новую контрольную сумму описателя файла is_dos.sys:

LD BC,31-18

ADD HL,BC

LD B,#20

XOR A

XOR (HL)

DEC HL

DJNZ $-2

;Контрольная сумма также помещается в 0-ом блоке устройства:

DEC HL

DEC HL

DEC HL

DEC HL

LD (HL),A

;И, наконец, модифицируем блок в кэше:

LD C,$modo

RST 16

RET C

#2F (47) $fadd

Добавить A блоков к сегментированному файлу. Добавленные блоки вставляются перед блоком номер DE (первый добавленный блок становится DE-ым). Если DE слишком велик, то добавление все равно производится в конец файла.

Возможные ошибки:

62 - несоответствие числа модифицированных блоков (кэш)

92 - нет места на диске

94 - переполнение блока описателей сегментов (85 сегментов)

102 - непрерывный файл

103 - добавить/удалить 0 блоков (A=0)

106 - файл не открыт

7 - ошибка чтения/записи (драйвер)

Пример из программы wet.com. Добавление специального блока в начало текстового файла и заполнение его вектором:

EXIT       XOR A

LD E,A

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

INC A                  ;A=1: число блоков

LD C,$fadd

RST 16

RET C

LD HL,BUFF     ;буфер блока

;Очистка буфера:

PUSH HL

XOR A

LD B,A

LD (HL),A

INC HL

DJNZ $-2

LD HL,VECTOR              ;вектор редактора

LD C,VECSZ                    ;размер вектора

LD DE,BUFF+#80+edcsr   ;+смещение

LDIR

POP HL                          ;буфер

LD D,B

LD E,B                             ;DE=0

LD C,$wvblk                     ;записать 1 блок

RST 16

RET C




СОДЕРЖАНИЕ:


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

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



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

Похожие статьи:
Вступление - содержание номера.
Почта - Письма читателей: Андрей Яковлев, Денис Токарчук, Алексей Гаркулим, Александр Гордеев, Евгений Шумилов, Ниточкин Вадим, Михаил Ларкин.
Этюды - Спрайтовый скроллер. Процедуры проявления экрана.
Житие Деда мороза - Все мы знаем Деда Мороза с самого детства.
Обзор - обзор игрушек: Space Gun, World Championchip Soccer, Night Breed, Satan 2, Obliterator, Stun Runner, Side Arms, Salamnder, Dark Fusion, Moontorc, Blood Valley, Magicians Land, Magic Fields, Mountain Bike Simulator, Starfox, Heavy Metall Mover.

В этот день...   6 мая