|
Echo
#03
31 марта 1997 |
|
Маленькие хитрости-2 - О корректной обработке Retry/Abort/Ignore в TR-DOS.

┌════════════════════════════════════════┐
│░░░░░ О корректной обработке R/I/A ░░░░░│
└════════════════════════════════════════┘
VfNG/NEW
В многих программах людям бывает необ-
ходимо перехватить стандартное сообщение
DOS об ошибке чтения/записи сектора чтобы
открыть свое красивенькое окошко, сделать
запрос Retry/Abort/Ignore, получить ответ
и правильно продолжить или закончить вы-
полнение программы. Далеко не все умеют
это делать. Я попробую эту проблему осве-
тить.
По адресу #3F0A ДОС находится процеду-
ра, обеспечивающая запись сектора, а по
#3F0E-чтение. Как раз именно этими проце-
дурами и осуществляется чтение/запись
стандартными функциями. Рассмотрим эти
процедуры внимательно:
#3F0A LD A,#A0 ;Код команды записи
;сектора
JR #3F10
#3F0E LD A,#80 ;Код команды чтения
;сектора
#3F10 LD (#5CFE),A
LD D,#0A ;число попыток
;чтение/записи
#3F15 PUSH DE
DI
LD A,(#5CFF)
INC A
OUT (#5F),A ;номер сектора
LD HL,(#5D00) ;буфер
LD C,#7F ;порт данных
LD A,(#5CFE) ;код команды
OUT (#1F),A ;вызов команды
CP #A0 ;запись?
PUSH AF
CALL Z,#3FBA ;вызов записи
;сектора
POP AF
CALL NZ,#3FD5 ;вызов чтения
;сектора
POP DE
EI
IN A,(#1F) ;чтение регистра
;состояния
LD B,A
AND #7F
RET Z ;выход, если нет
;ошибки
LD HL,#29D8 ;адрес надписи
;"Read Only"
AND #40 ;защита от записи?
JR NZ,#3F4B ;да
LD A,B
AND 4 ;потеря данных?
JR Z,#3FA0 ;нет. повторная
;попытка чтения.
DEC D ;последняя попытка?
JR NZ,#3F15 ;нет, еще одна
LD HL,#29E2 ;адрес надписи
;"Disk error"
LD A,#D0
OUT #1F,A ;прекращение ко-
;манды, если она
;продолжает выполнятся
LD A,B
AND 1
JP NZ,#3EE7 ;обработка
;"No disk"
IN A,#3F ;чтение регистра
;дорожки
OR A ;нулевая?
JR NZ,#3F5F ;да
IN A,#5F ;чтение регистра
;сектора
CP #0A ;десятый?
RET Z ;выход, если да
#3F5F PUSH HL
#3F60 CALL #1D97 ;вызов очистки
;экрана
POP HL
RST #18
LD HL,#2A13 ;адрес надписи
;"Trk."
RST #18 ;вывод
IN A,#3F ;чтение регистра
;дорожки
CALL #1DA3 ;вывод номера
;дорожки
LD HL,#2A18 ;адрес надписи
;"Sec."
RST #18 ;вывод
IN A,#5F ;чтение регистра
;сектора
CALL #1DA3 ;вывод номера
;сектора
LD HL,#29FE ;адрес надписи
;"Retry/Abort/Ignore?"
RST #18 ;вывод надписи
#3F7B CALL #1052 ;процедура #1052
;возвращает в A ASCII-код нажатой на кла-
виатуре клавиши
#3F7E CP "I" ;Ignore?
RET Z ;возврат, если
;да
CP "R" ;Retry?
JR Z,#3F94 ;да, выход в
;очередной цикл
;попыток
CP "A" ;Abort?
JR NZ,#3F7B ;нет, переход на
;чтение клавиа-
;туры
#3F89 ;Abort
Главное, что можно выделить из нарисо-
ванного выше, это то, что в результате
ошибки мы попадаем либо в #3F60, либо в
#3EE7. Попрубуем рассмотреть #3F60 повни-
мательнее.
#3F60 CALL #1D97
#1D97 RST #20
DEFB #6B
DEFB #0D
#0020 JP #2F72
#2F72 LD (#5D02),HL
LD (#5D04),DE
POP HL
LD E,(HL)
INC HL
LD D,(HL)
INC HL
PUSH HL
LD HL,#3D2F
PUSH HL
PUSH DE
LD HL,#5CC2
PUSH HL
LD HL,(#5D02)
LD DE,(#5D04)
RET
Таким образом, при дисковой ошибке, от-
личной от "No disk", мы вылетаем в #5CC2.
В #5CC2 стандартно торчит RET. Эта точка
используется для вызова подпрограмм ПЗУ
Бейсика. Два байта в #5CC3 и #5CC4 не ис-
пользуются, значит мы законно можем впи-
сать в #5CC2 команду из 3-х байт: JP куда-
нибудь, например на драйвер обработки.
Заметим, что после этого самого JP на
стеке будет торчать число #0D6B. Значит,
сделаем следующую вещичку:
DRIVER EX (SP),HL
PUSH AF
LD A,H
CP #0D
JR Z,ERROR
POP AF
EX (SP),HL
RET
Догадайтесь сами, что тут произошло. Ну
а теперь
ERROR POP HL
POP HL
POP HL
POP HL
POP HL
CALL PROC ;вызов собственной
;процедуры RIA возврат-в A "R","I","A"
;соответственно.
LD HL,#3F7E
EX (SP),HL
JP #3D2F ;возврат в ДОС
;ответа!
В простейшем случае CALL PROC заменяет-
ся на LD A,"R"/"I"/"A", если ответ на
ошибку определен одназначно.
Аналогично, хотя и несколько сложнее,
обстоит дело с обработкой "No disk"
(#3EE7). В этом, а также куда вылетаем по
"Abort", разбирайтесь сами, это не сложно
сделать.
Другие статьи номера:
Похожие статьи:
В этот день... 17 ноября