Из журнала Deja Vu #09, Кемерово, 1999 (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_Wopep1 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. До новых встреч!!! ------------------------------------------