(C) Rezonance group
__________________________________________
Обработка ошибок TR-DOS при работе
через #3D13.
Ключевым моментом является изменение
системных переменных TR-DOS по адресу
23749, где обычно располагается команда
RET, используемая для обращения к подпрог-
раммам ПЗУ BASIC 48. После перехвата вызо-
ва определяется, какая именно подпрограмма
потребовалась TR-DOS, и принимается реше-
ние о том, идти ли в BASIC или использо-
вать альтернативную подпрограмму, написан-
ную нами.
При ошибках чтения сектора и защиты от
записи происходит обращение в BASIC по ад-
ресам: #0D6B - очистка экрана и открытие
потока 0; #0010 - печать символа; #028E,
#031Е, #0333 - все это опрос клавиатуры;
#1F54 - опрос BREAK; #1B7B - RST8 (обра-
ботчик ошибок). Именно эти подпрограммы
нам придется подменить своими. Кроме пере-
численных, TR-DOS использует еще несколько
подпрограмм: #1F1A, #1F05, #0030, #19E5 и
т.д. для корректировки памяти, но их лучше
не трогать, пусть работают как работали.
Все остальные ошибки возвращаются в сис-
темной переменной 23823 и обрабатываются
специальной процедурой. Теперь перейдем к
самой программе.
Пример вызова процедуры загрузки файла.
В регистре 'A' - способ загрузки.
ORG #8000,0
DI
LD A,#FF
LD HL,NAME
LD DE,0
CALL Load_file
В случае фатальной ошибки управление пере-
дается вот сюда.
ABORT NOP
NOP
NOP
RET
Имя файла и расширение.
NAME DEFM "screen2 "
DEFM "C"
Переменные: тип загрузки, адрес имени
файла и адрес загрузки, длина файла, адрес
на экране.
DOStyp DEFB 0
DOSnam DEFW 0
DOSadr DEFW 0
DOSlen DEFW 0
DOSscr DEFW 0
;-------------------------------
;| ЗАГРУЗКА ФАЙЛА |
;-------------------------------
;IN :
; A - ТИП ЗАГРУЗКИ
; 0 - адрес и длина из каталога
; 1,2 - адрес из 'DE', длина из
; каталога
; 3 - адрес из 'DE', длина из 'BC'
;HL - АДРЕС ИМЕНИ ФАЙЛА
;DE - АДРЕС ЗАГРУЗКИ
;BC - ДЛИНА ФАЙЛА
Load_file
DI
Сохраним содержимое регистров в памяти.
LD (DOStyp),A
LD (DOSnam),HL
LD (DOSadr),DE
LD (DOSlen),BC
Скопируем имя файла в область переменных
TR-DOS.
CALL DOS_move_name
Эти переменные требуется установить для
нормальной работы.
LD A,0
LD (23801),A
LD (23824),A
Подготовка остальных переменных к работе.
CALL DOS_instal
В случае отсутствия файла или аналогичной
ошибки на экране высветится сообщение и
запрос Retry, Abort. Этот цикл необходим
для повтора операции в случае ответа
Retry.
Lfile01
LD A,(DOStyp)
LD HL,(DOSadr)
LD DE,(DOSlen)
LD BC,14
CALL #3D13
CALL DOS_disk_error
JR NZ,Lfile01
Восстановить исходные значения переменных
и вернуться.
JP DOS_uninstal
;-------------------------------
;| ОТГРУЗКА ФАЙЛА |
;-------------------------------
;IN :
;HL - АДРЕС ИМЕНИ ФАЙЛА
;DE - АДРЕС ФАЙЛА
;BC - ДЛИНА ФАЙЛА
Здесь все аналогично процедуре загрузки
файла.
Save_file
DI
LD (DOSnam),HL
LD (DOSadr),DE
LD (DOSlen),BC
CALL DOS_move_name
LD A,0
LD (23801),A
LD (23824),A
CALL DOS_instal
Sfile01
LD HL,(DOSadr)
LD DE,(DOSlen)
LD BC,11
CALL #3D13
CALL DOS_disk_error
JR NZ,Sfile01
JP DOS_uninstal
;-------------------------------
Установим количество символов, по которым
ищется файл, изменим переменную ERR_SP,
чтобы без проблем вернуться назад, и не
забудем про команду JP.
DOS_instal
LD A,9
LD (23814),A
LD (23613),SP
LD A,#C3
LD HL,DOS_error_intercept
LD (23746),A
LD (23747),HL
RET
;-------------------------------
После того, как процедура отработала, вер-
нем на место RET. Сюда же можно добавить
команды для восстановления ERR_SP.
DOS_uninstal
LD A,#C9
LD HL,#FFFF
LD (23746),A
LD (23747),HL
RET
;-------------------------------
Перенос имени файла в область переменных
TR-DOS.
DOS_move_name
LD DE,23773
LD BC,9
LDIR
RET
;-------------------------------
;ОБРАБОТКА ОШИБОК 'RZ-DOSv1' |
;-------------------------------
Смотрим содержимое 23823: если там 0, то
файл загружен (отгружен) без проблем, ина-
че выясняем, что это за ошибка.
DOS_disk_error
LD A,(23823)
OR A
RET Z
Откроем на экране окно.
CALL DOS_window_open
В 'HL' адрес сообщений об ошибках.
LD HL,DOS_mezage
Не обращайте внимания, просто строка не
умещается на экране. В 'BC' длина всех со-
общений.
LD BC,DOS_mezage_error-DOS_mezage
Поиск нужного нам сообщения по его коду в
регистре 'A'.
DOS_Derror1
CPI
JR Z,DOS_Derror2
JP PE,DOS_Derror1
Если сообщение найдено, то в 'HL' его ад-
рес, если нет, то в 'HL' адрес сообщения
"* Indiscernible error *", т.е. нераспоз-
нанная ошибка.
DOS_Derror2
Печать сообщения в окно
CALL DOS_write_line
Печать Retry, Abort? ( если, например, на
диске нет нужного файла, то вам вежливо
сообщают об этом и спрашивают, поискать
еще раз или хватит? А вы в это время с
наглым видом вставляете другой диск и да-
вите "R"!).
LD HL,DOS_mezage_ask
CALL DOS_write_line
Обнулить ошибку, чтобы при ответе "R" и
удачном завершении работы загадочно не
появлялось сообщение об ошибке.
LD A,0
LD (23823),A
Опрос кнопочек "R" и "A".
DOS_Derror3
CALL DOS_RAI_ask
CP "A"
JR Z,DOS_abort
CP "R"
JR Z,DOS_retry
JR DOS_Derror3
Закроем окно, сбросим флаг Z и повторим
все почти с самого начала.
DOS_retry
CALL DOS_window_close
OR #FF
RET
Закроем окно, отключим все, что нужно и
отправляемся в вызывавшую программу.
DOS_abort
CALL DOS_window_close
CALL DOS_uninstal
JP ABORT
Сообщения об ошибке. Формат: код ошибки,
перевод строки (зачем впереди? так делает
DOS), сообщение, 0 - маркер конца сообще-
ния.
DOS_mezage
DEFB 1,13
DEFM "No file"
DEFB 0,2,13
DEFM "File exists"
DEFB 0,3,13
DEFM "No space"
DEFB 0,4,13
DEFM "Directory full"
DEFB 0,5,13
DEFM "Rec O/F"
DEFM 0,6,13
DEFM "No disc"
DEFB 0,12,13
DEFM "Break into program"
DEFB 0,20,13
DEFM "Break-cont repeats"
DEFB 0
DOS_mezage_error
;НЕРАСПОЗНАНАЯ RZ-DOSом ОШИБКА !!!
DEFB 13
DEFM "*Indiscernible error*"
DEFB 0
DOS_mezage_ask
DEFB 13
DEFM "Retry, Abort?"
DEFB 0
Это просто автограф автора!!!
DEFM "RZ-DOSv1 special for"
DEFM " magazine DEJA VU! "
DEFM "Rezonance multimedia"
DEFM " group "
;-------------------------------
;ПЕРЕХВАТ ОШИБКИ TR-DOS!!! |
;ТОЧНЕЕ ПЕРЕХВАТ ОБРАЩЕНИЯ К |
;ПЗУ БЕЙСИК 48 (BIOS) |
;-------------------------------
;ОБРАБАТЫВАЕТ ОШИБКИ:
;Disc error Trc XX sec XX
;Read only Trc XX sec XX
;Break-cont repeats
Снимем со стека адрес подпрограммы и про-
верим, нужно ли ее подменить.
DOS_error_intercept
POP DE
AND A
LD HL,#0D6B
SBC HL,DE
Открытие канала 0. Вместо канала откроем
окно.
JP Z,DOS_window_open
AND A
LD HL,#0010
SBC HL,DE
Печать символа.
JP Z,DOS_write
AND A
LD HL,#1A1B
SBC HL,DE
Печать цифры из регистра 'BC'.
JP Z,DOS_hex_sumbol
AND A
LD HL,#028E
SBC HL,DE
Просто вернемся в DOS с установленными
флагами.
JP Z,DOS_return
AND A
LD HL,#031E
SBC HL,DE
То же самое, что и предыдущее.
JP Z,DOS_return
AND A
LD HL,#0333
SBC HL,DE
Опрос клавиш "R", "A", "I".
JP Z,DOS_ask_and_close
AND A
LD HL,#1B7B
SBC HL,DE
Вызов подпрограммы RST8
JP Z,DOS_rst8
Восстановим 'HL', 'DE' и вызовем процедуру
из BASIC 48.
PUSH DE
В эти переменные DOS копирует регистры пе-
ред вызовом процедур.
LD HL,(23810)
LD DE,(23812)
RET
;-------------------------------
;ПЕЧАТЬ ЧИСЛА ИЗ РЕГИСТРА 'BC'
;( НОМЕР ТРЕКА И СЕКТОРА )
DOS_hex_sumbol
Печатаем символ '#', т.к. номер сектора
или трека выводится в шестнадцатиричном
формате.
LD A,"#"
CALL DOS_write
Находим и печатаем старший полубайт.
LD HL,DOS_fex_sumbol1
LD D,0
LD E,C
SRL E
SRL E
SRL E
SRL E
ADD HL,DE
LD A,(HL)
CALL DOS_write
Теперь младший полубайт.
LD A,C
AND #0F
LD HL,DOS_fex_sumbol1
LD D,0
LD E,A
ADD HL,DE
LD A,(HL)
CALL DOS_write
RET
DOS_hex_sumbol1
DEFM "0123456789ABCDF"
;-------------------------------
;ОПРОСИТЬ КЛАВИАТУРУ И ЗАКРЫТЬ ОКНО
DOS_ask_and_close
CALL DOS_RAI_ask
CALL DOS_window_close
RET
;-------------------------------
;ВЕРНУТЬСЯ В DOS С ВКЛЮЧЕННЫМ
;ФЛАГОМ Z И C (ВМЕСТО ОПРОСА)
DOS_return
LD A,#01
ADD A,#FF
RET
;-------------------------------
;ОПРОС КЛАВИАТУРЫ
DOS_RAI_ask
LD A,#FB
IN A,(#FE)
BIT 3,A
LD A,"R"
RET Z
LD A,#FD
IN A,(#FE)
BIT 0,A
LD A,"A"
RET Z
LD A,#DF
IN A,(#FE)
BIT 2,A
LD A,"I"
RET Z
JR DOS_RAI_ask
;-------------------------------
;ЕСЛИ НАЖАТ "BREAK", ТО DOS
;ВЫЗЫВАЕТ ПРОЦЕДУРУ RST8
Заменитель подпрограммы RST 8. Восстанав-
ливаем стек, в 'BC' и (23823) код ошибки
"Break-cont repeats"
DOS_rst8
LD SP,(23827)
LD BC,20
LD A,C
LD (23823),A
RET
;-------------------------------
;ОТКРЫТИЕ ОКНА
Окно формируется в средней трети экрана,
высота четыре знакоместа. DOS_window_open
Сохраняем регистры.
PUSH AF
PUSH HL
PUSH DE
PUSH BC
Адрес в экране для процедуры печати.
LD HL,#4802
LD (DOSscr),HL
Копируем содержимое экрана в буфер и очи-
щаем окно.
LD HL,#4820
LD DE,DOS_bufer
DOS_Wopen1
LD BC,32*3
DOS_Wopen2
LD A,(HL)
LD (HL),0
LD (DE),A
INC HL
INC DE
DEC BC
LD A,B
OR C
JR NZ,DOS_Wopen2
INC H
LD A,#20
LD L,A
LD A,7
AND H
JR NZ,DOS_Wopen1
То же самое для области атрибутов.
LD HL,#5920
LD BC,32*3
DOS_Wopen3
LD A,(HL)
LD (HL),#16
LD (DE),A
INC HL
INC DE
DEC BC
LD A,B
OR C
JR NZ,DOS_Wopen3
Восстанавливаем регистры и возвращаемся.
POP BC
POP DE
POP HL
POP AF
RET
;-------------------------------
;ЗАКРЫТИЕ ОКНА
DOS_window_close
Сохраняем регистры
PUSH AF
PUSH HL
PUSH DE
PUSH BC
Восстанавливаем содержимое экрана под ок-
ном.
LD HL,DOS_bufer
LD DE,#4820
DOS_Wclose1
LD BC,32*3
LDIR
INC D
LD A,#20
LD E,A
LD A,7
AND D
JR NZ,DOS_Wclose1
То же самое для области атрибутов.
LD DE,#5920
LD BC,32*3
LDIR
Восстанавливаем регистры и возвращаемся.
POP BC
POP DE
POP HL
POP AF
RET
;-------------------------------
;ПРОЦЕДУРА ПЕЧАТИ СИМВОЛА
;РАЗРАБОТАНА СПЕЦИАЛЬНО ДЛЯ
;RZ-DOSv1, И ПОЗВОЛЯЕТ ПЕЧАТАТЬ
;СИМВОЛЫ ВНУТРИ ТРЕТИ ЭКРАНА!!!
Печать строки текста.
DOS_write_line
LD A,(HL)
INC HL
AND A
RET Z
CALL DOS_write
JR DOS_write_line
Печать символа. Процедура максимально уп-
рощена и поэтому печатает символы только
внутри трети экрана, т.к. если произойдет
переход на следующую треть, то адрес зна-
коместа будет неправильно рассчитан.
DOS_write
Сохраняем регистры.
PUSH HL
PUSH DE
PUSH BC
Код перевода строки?
CP #0D
JR NZ,DOS_write1
Да. Помещаем в 'HL' адрес знакоместа.
LD HL,(DOSscr)
Обнуляем 5 младших регистра.
Теперь текущий самый левый столбец.
LD A,L
AND #E0
Прибавим 32 и тем самым перейдем на сле-
дующую строку.
ADD A,#20
Отступим от края 2 знакоместа.
OR 2
LD L,A
Сохраним в переменной.
LD (DOSscr),HL
JP DOS_write3
DOS_write1
В 'HL' код символа.
LD L,A
LD H,0
Умножим на 8.
ADD HL,HL
ADD HL,HL
ADD HL,HL
Прибавим к адресу знакогенератора в ПЗУ.
LD DE,#3C00
ADD HL,DE
Поместим в 'DE' адрес знакоместа.
LD DE,(DOSscr)
Скопировать в экран из ПЗУ 8 линий.
LD B,8
DOS_write2
LD A,(HL)
LD (DE),A
INC HL
INC D
DJNZ DOS_write2
Переход к следующей позиции печати.
LD DE,(DOSscr)
INC DE
LD (DOSscr),DE
Восстановим регистры и возврат.
DOS_write3
POP BC
POP DE
POP HL
RET
;-------------------------------
;БУФЕР ДЛЯ СОХРАНЕНИЯ ЭКРАНА
DOS_bufer
DEFS 1024,0
Статья написана при информационной под-
держке книги Федина Павла Юрьевича "Полное
описание + полный дизассемблер ПЗУ TR-DOS
5.04T (5.03)". Остается только поблагода-
рить его за проделанную работу и пореко-
мендовать читателям журнала это замеча-
тельное книгу в качестве пособия по изуче-
нию особенностей работы TR-DOS.
До новых встреч!!!
------------------------------------------