Программисты, которые пытаются писать программы высокого качества для работы на компьютерах, совместимых с ZX Spectrum, сталкиваются с некоторыми проблемами мето- дического и практического плана. Одна из них, пожалуй, наиболее неп- риятная, состоит в том, что при выполнении любых операций чтения/записи диска система TR-DOS может очистить экран и выдать сооб- щение о том, что произошла дисковая ошибка или что на дискете установлен маркер защи- ты от записи. После этого она спрашивает, нужно ли попытаться повторить операцию, прервать её или проигнорировать. Для прог- раммиста проблема в том, что появляется необходимость восстанавливать экран после обращения к DOS. Кроме того, система изме- няет номер текущего потока. И вообще, про- грамма, работающая, скажем, в оконном ин- терфейсе, должна полностью обрабатывать свои ошибки в рамках этого интерфейса. Далее я покажу, как перехватить опи- санную функцию TR-DOS лучшим, на мой взгляд, методом. К сожалению, в данном случае нельзя выделить некоторый охваты- вающий все возможные ситуации алгоритм, потому будет приведен конкретный пример, взятый из оконного интерфейса прикладных программ, разработанного автором. Но сна- чала несколько слов о том, как TR-DOS об- ращается к основному ПЗУ компьютера. Как известно, теневое ПЗУ системы TR-DOS подключается на место основного ПЗУ компьютера при обращении процессора к оп- ределенным адресам памяти с целью считыва- ния кода операции. Одним из таких адресов является адрес #3D13 - точка входа для ис- полнения функций TR-DOS. При таком подклю- чении устанавливается специальный триггер в Beta Disk Interface, и дополнительное ПЗУ остается подключенным до обращения процессора за кодом операции вне этого ПЗУ. Тогда триггер сбрасывается. Если же TR-DOS зачем либо нужно обра- титься к основному ПЗУ (например, для очи- стки экрана, вывода символов и т. п.), то она делает это следующим образом: 1) на стек кладется адрес возврата к те- кущей части или модулю TR-DOS; 2) на стек кладется адрес требуемой под- программы из основного ПЗУ; 3) выполняется переход по адресу 23746; 4) поскольку это адрес в области ОЗУ, теневое ПЗУ отключается (триггер сбрасы- вается аппаратно); 5) по этому адресу расположена инструк- ция RET, поэтому со стека берется адрес подпрограммы в основном ПЗУ и она запус- кается; 6) инструкция RET в конце запущенной подпрограммы вызовет переход назад, в те- невое ПЗУ системы TR-DOS. Предлагаемый пример показывает, как можно обратиться к TR-DOS так, чтобы не позволить ей очистить экран и выдать свое сообшение в нижнем окне экрана. Вместо этого сообшение TR-DOS выдается в окне "Сообщение системы" применяемого оконного интерфейса. В примере есть обращения к неописанным здесь процедурам оконного ин- терфейса. Проектируя свою подпрограмму аналогичного назначения, Вы можете встави- ть на место вызовов этих процедур свои специфические вызовы с аналогичными фун- кциями. В данном случае вызов TR-DOS разделен на 3 этапа: 1) подготовительные операции: установка перехватчиков; 2) непосредственно вызов TR-DOS по адре- су #3D13 (с возможной работой перехватчи- ков); 3) завершающие операции: снятие перех- ватчиков. Программа записана в мнемонике ассем- блера HiSoft GEN Assembler Version 4.1. Итак, первый этап - установка перехватчи- ков. DOSPRE SUB A LD (RSTFLG),A ;сообщение DOS ещё ;не выдавалось LD HL,$$DOSW LD (RSTPTR),HL ;указатель в текс- ;те окна - куда заносить символы CALL CLKON ;показать курсор в ;форме песочных часов - "длительная опера- ;ция" CALL IM1 ;перевести систему ;в режим прерываний 1 ;далее следуют действия по установке пе- ;рехватчиков DOSSWP LD HL,DOS_ST ;первая область ;для обмена LD DE,23746 ;вторая область LD BC,3 ;длина области SWAP2 LD A,(DE) ;обмен содержимого ;областей памяти LDI DEC HL LD (HL),A INC HL JP PE,SWAP2 ;таким образом, команда RET по адресу ;23746 заменена на команду JP DOSEMT LD HL,(23633) ;это системная пе- ;ременная CURCHL LD C,(HL) INC HL LD B,(HL) ;это адрес обра- ;ботчика вывода текущего канала LD DE,(DOS_CH) ;в DOS_CH адрес ;нашего обработчика LD (DOS_CH),BC ;меняем их местами LD (HL),D DEC HL LD (HL),E ;таким образом, процедура вывода текущего ;канала подменена на специальную. Установ- ;ка перехватчиков закончена. RET ;непосредственно вызов DOS ;после однократного запуска DOSPRE, можно ;много раз запускать DOS; после всего нуж- ;но запустить DOSEND DOS PUSH AF LD (IY),-1 ;"не было ошибки" SUB A ;начальное значе- ;ние кода возврата TR-DOS LD (23823),A LD (23824),A POP AF CALL #3D13 ;запуск TR-DOS LD A,(23823) ;установка флага ;CY по коду возврата TR-DOS AND A RET Z ;если код = 0, то ;CY = 0 SCF RET ;область временного хранения команды перехода DOS_ST JP DOSEMT ;временное хранение регистров DOS_HL DEFW 0 DOS_BC DEFW 0 ;адрес процедуры вывода в канал DOS_CH DEFW DOSRST ;перехватчик доступа к основному ПЗУ; ;если этот модуль запущен, значит, TR-DOS ;вызывает подпрограмму основного ПЗУ DOSEMT LD (DOS_HL),HL ;сохраняем регист- ;ры LD (DOS_BC),BC POP BC ;это адрес в ос- ;новном ПЗУ PUSH AF AND A LD HL,#D6B SBC HL,BC ;адрес = #D6B ? ;(подпрограмма очистки экрана) JR Z,DOSCLS ;если да, запуска- ;ем новый модуль очистки AND A LD HL,#1601 ;адрес = #1601 ? ;(подпрограмма установки текущего потока) SBC HL,BC JR Z,DOSIGN ;если да, игнори- ;руем вызов, поток не изменяется ;вызываемая подпрограмма не есть одна из ;перехватываемых, значит, иполняем ее POP AF PUSH BC ;возврашение адреса на ;место LD HL,(DOS_HL) ;возвращение ре- ;гистров LD BC,(DOS_BC) RET ; исполнение заказанной ;подпрограммы основного ПЗУ DOSIGN POP AF RET ;ненулевое значение этого флага говорит о ;том, что окно сообщения TR-DOS уже откры- ;то RSTFLG DEFB 0 ;адрес помещения очередного символа в ;текст окна RSTPTR DEFW $$DOSW ;подпрограмма очистки окна, заменяющая ;подпрограмму очистки экрана DOSCLS POP AF ;конкретные дейст- ;вия непринципиальны LD HL,$$DOSW LD DE,$$DOSW+1 LD BC,5*21-1 LD (HL),255 LDIR LD HL,$$DOSW LD (RSTPTR),HL LD A,(RSTFLG) ;если окно не от- ;крыто AND A LD A,28 CALL Z,OPEN ;то открыть его LD A,-1 LD (RSTFLG),A ;изменить флаг JP REDRAW ;перерисовать ок- ;но ;подпрограмма вывода символа в окно, заме- ;няющая собой вывод символа в область "K" ;экрана DOSRST PUSH BC PUSH DE PUSH HL LD HL,(RSTPTR) LD (HL),A INC HL LD (RSTPTR),HL CALL TEXTON ;обновить текст в ;окне POP HL POP DE POP BC RET ;завершающие операции после серии вызовов ;DOS DOSEND LD (IY),-1 ;"ошибки не было" CALL IM2 ;вернуть режим ;прерываний 2 CALL CLKOFF ;убрать курсор в ;форме песочных часов CALL DOSSWP ;вернуть назад все ;вектора переходов и указатели LD A,(RSTFLG) ;если окно сообще- ;ния TR-DOS открывалось AND A CALL NZ,CLOSE ;то закрыть его RET Таким образом, если TR-DOS захочет в процессе работы выдать сообщение Disk error или Read only, то она первым делом попытается очистить экран. Эта попытка бу- дет обнаружена в DOSEMT и вместо очистки экрана будет выполнен вывод окна сообщения TR-DOS и его очистка. Далее, TR-DOS попытается открыть ка- кой-либо поток, связанный с каналом "K" для выдачи сообщения. Эта попытка также будет перехвачена и проигнорирована. После этого переходом по адресу #10 система будет печатать свое сообщение. Казалось бы, можно в той же подпрограмме DOSEMT "поймать" и эту ситуацию и не пере- хватывать вывод в текущий канал. Как пока- зали эксперименты, это срабатывает, но для вывода чисел TR-DOS использует процедуру OUT_NUM, которую приходится в таком случае также перехватывать и эмулировать, что неудобно и неэлегантно. Гораздо проще пе- рехватить вывод в канал на уровне ракорда канала, как и сделано в DOSSWP. В результате сообщение TR-DOS появ- ляется в красивом многоцветном окне посре- ди экрана, а не внизу. Пользователь может ответить на запрос точно так же, как всег- да. Кроме того, экран не нарушается, что очень удобно для программиста. По заверше- нии последовательности вызовов TR-DOS окно закрывается (в процедуре DOSEND). Проконсультироваться у автора Вы можете, написав по адресу: 257010 Украина, Черкассы-10, а/я 1529 Курицыну Б. А.