Работа с файлами в ОС CP/M на компьютере «Profi».
Приложение к статье в журнале ZaRulem #28
В ходе реализации заданий будем использовать уже знакомые по предыдущим статьям макросы, не буду повторно приводить их код, только коротко опишу. Сам код можно посмотреть в файле «BIOSK.INC» на прилагаемом образе диска.
.writed “значение”, [параметр] – выводит по текущем координатам на экран в десятичном формате 16 битное число 0…65535 или содержимое регистров A, SP, HL, DE, BC, IX, IY. Если выводиться 16 битное число, то в качестве «параметра» необходимо указать «1», противном случае его можно опускать или указывать «0».
Say “текст”, [регистр] – выводить «текст» по текущим координатам на экран, если указан один из следующих регистров A, SP, HL, DE, BC, IX, IY, то его значение в десятичной форме будет непечатно сразу за «текстом».
pause - ждет нажатия любой клавиши, если нажата «Esc», то производит холодный рестарт системы (то есть выход из текущей программы), а по любой другой продолжает выполнение программы.
.push <регистровые пары>/.pop <регистровые пары> - позволяют одной командой занести или снять со стека сразу несколько регистровых пар. Передаваемый список регистровых пар, должен быть в угловых кавычках и разделяться запятой. Пример: .push <hl, de> ….pop <de, hl>
.bdos “операция”, [параметр] – вызов «операции» БДОС, с передачей «параметра».
Для визуализации действий будем выводить на экран ту информацию, которую загружаем из файла. Для этого будем работать с текстовым файлом. Так как в одном секторе 128 байт, в него помещаться 2 строки текста по 64 символов строке. Создадим текстовый файл «TEST.TXT» и пропишем в каждых 2 строках номер сектора, в котором находится эти строки.
Рисунок 1.
Пример содержимого файла «TEST.TXT»
Теперь всё готово к решению практических задач.
Задание 1. Подготовка БУФ средствами БДОС
И в два этапа последовательно прочитать три сектора.
Заголовок всех листингов будет состоять из трех строчек.
.Z80; Указываем, что будем работать в мнемониках процессора z80
org 100h
INCLUDE BIOSK.INC; Загружаем описание макросов
;----------------------------------------------------------------
Теперь создадим БУФ для работы с файлом. Для чего воспользуемся операцией БДОС 152 (bdBUFCreate). «Подготовка БУФ». Она готовит БУФ из имени файла. При её вызове в регистровой паре DE должен передаваться адрес блока подготовки имени файла (PFCB), имеющего следующий формат
PFCB: DW STRING;адрес имени файла
DW AFCB;адрес подготавливаемого БУФ
Имя файла должно задаваться в следующем виде:
[D:]Имя файла[.тип файла]
где поля в квадратных скобках необязательны.
Соответственно в конце листинга добавляем строки с массивами исходных данных:
;======================================================================
; Информационные сообщения
err01: db '<!> File not found! <!>', '$'
info01: db '<.> Read 1 sector', 0dh, 0ah, '$'
info02: db '<.> Read 2-3 sectors', 0dh, 0ah, '$'
;======================================================================
FileName: db 'TEST.TXT', 0; Имя рабочего файла
PFCB: dw FileName; Ссылка на имя рабочего файла
dw FCB_file; Ссылка на БУФ рабочего файла
FCB_file: ds 36; Блок управления файлом.
PDP_file: ds 128*2; Буфер файла для загрузки данных с диска.
Теперь продолжим решение поставленной задачи.
.bdos bdBUFCreate,PFCB; Создаем БУФ для рабочего файла.
.bdos bdPDPInst, PDP_file; Устанавливаем адрес буфера файла.
.bdos bdOpen, FCB_file; Открываем файл.
inc a; if a=255 Если на диске нет такого файла.
jp z, err.nofile; then Процедуру обработки ошибки рассматривать не будем.
По умолчанию в CP/M маркером конца текста для вывода на экран является знак «$». Ставим его за буфером файла.
ld a, '$'; Маркер конце текста.
ld (PDP_file+128+1), a; Маркируем конец буфера файла.
Выводим информационную строку о том, какие сектора читаем.
.bdos bdWrite, info01
Выполняем чтение первого сектора и выводим на экран то, что прочитали.
.bdos bdReadCon, FCB_file; Последовательное чтение 1 сектор.
.bdos bdWrite, PDP_file; Вывод прочитанного на экран.
pause
Так как на следующем этапе нужно будет читать два сектор за обращение, переносим маркер конца текста.
ld a, '$'; Маркер конце текста.
ld (PDP_file+128*2+1), a; Переносим маркер конца буфера файла.
Завершаем выполнение задачи.
.bdos bdWrite, info02
.bdos bdMultCount, 2; Мультисекторный счетчик =2
.bdos bdReadCon, FCB_file; Последовательное чтение 2-3 секторов
.bdos bdWrite, PDP_file; Вывод прочитанного на экран.
pause
После компиляции и запуска полученного кода на экране мы увидим следующее:
Рисунок 2
Выполнение задание 1
Задание 2. Подготовка БУФ вручную и в два этапа произвольно прочитать пять секторов.
Как видно из предыдущей задачи подготовить БУФ средствами БДОС не сложно. Но вручную это сделать иногда ещё проще. Для решения задачи 2, в конце листинга, в блоке данных, размещаем ручное описание БУФ:
; Блок управления файлом.
FCB_file: db 0; ДС Код диска 0-16. 0- текущий диск
;12346578
db 'TEST '; И1-И8 Имя файла
db 'TXT'; Ф1-Ф8 Расширение файла
db 0; ЗК Номер экстента 0-31
db 0; C1 Счётчик байтов
ds 18; <!> Не менять
db 0; ТЗ Текущая запись
ds 3; R0-R2 Номер произвольной записи
Теперь просто опускаем вызов операции БДОС 152 (bdBUFCreate). «Подготовка БУФ», так как БУФ уже подготовили, остальное без изменений.
.bdos bdPDPInst, PDP_file; Устанавливаем адрес буфера файла.
.bdos bdOpen, FCB_file; Открываем файл.
inc a; if a=255 Если на диске нет такого файла.
jp z, err.nofile; then
Начнём выполнение задания с чтения трёх секторов. Предварительно устанавливаем маркер конца данных:
ld a, '$'; Маркер конце текста.
ld (PDP_file+128*3+1), a; Маркируем конец буфера файла.
Для включения произвольного доступа к файлу вызываем операций БДОС 36 (bdRecRnd) «Установка номера произвольной записи». В результате выполнения, которой в полях R0...R2 БУФ файла будет записан номер произвольной записи, следующий за записью, доступ к которой осуществляется в последний раз. Эта же операция переводит файл в режим произвольного чтения.
.bdos bdRecRnd, FCB_file; Включаем произвольный режим доступа к файлу.
Теперь в поля R0..R1 заносим номер сектора с которого хотим начать чтение. Пусть, в нашем случае, это будет 7 сектор.
ld hl, 7; Устанавливаем сектор для произвольного чтения.
ld (FCB_file+33), hl;
Далее действуем по схеме из задания 1, только вместо операции БДОС 20 (bdReadCon) «Последовательное чтение» используем операцию 33 (bdReadRnd) «Произвольное чтение».
.bdos bdMultCount, 3; Мультисекторный счетчик =3
.bdos bdWrite, info01
.bdos bdReadRnd, FCB_file; Произвольное чтение 3-х секторов.
.bdos bdWrite, PDP_file; Вывод прочитанного на экран.
pause
Читаем и выведем 3 и 4 сектора.
ld a, '$'; Маркер конце текста.
ld (PDP_file+128*2+1), a; Переносим маркер конца буфера файла.
ld hl, 3; Устанавливаем сектор для произвольного чтения.
ld (FCB_file+33), hl;
.bdos bdWrite, info02
.bdos bdMultCount, 2; Мультисекторный счетчик =2
.bdos bdReadRnd, FCB_file; Произвольное чтение 2-х секторов
.bdos bdWrite, PDP_file; Вывод прочитанного на экран.
pause
Скомпилировав и запустив программу, получим на экране следующий результат.
Рисунок 3
Выполнение задание 2