┌──────────────────────────────┐ │ │ │ TR-DOS ДЛЯ НАЧИНАЮЩИХ │ │ │ └──────────────────────────────┘ В.Сироткин. Продолжение. Начало см. в ZX РЕВЮ 1996 NN 1-2, 4-5, 6, 7-8, ZX РЕВЮ 1997 NN 1-2. ПРОГРАММИРОВАНИЕ КОНТРОЛЛЕРА. ───────────────────────────── Из предыдущего материала мы узнали, что компьютер общается с контроллером дисковода через специально выделенные порты. Так как с этими портами нам и пред- стоит в дальнейшем работать, здесь еще раз приводится крат- кая табличка назначения портов ввода/вывода/управления контрол- лера ТРДОС. ┌─────────────────────────────────────────────────┐ │ ПОРТ #1F - Регистр Состояния - ЧТЕНИЕ │ │ ПОРТ #1F - Регистр Команд - ЗАПИСЬ │ │ ПОРТ #3F - Регистр Дорожки - ЗАПИСЬ / ЧТЕНИЕ │ │ ПОРТ #5F - Регистр Сектора - ЗАПИСЬ / ЧТЕНИЕ │ │ ПОРТ #7F - Регистр Данных - ЗАПИСЬ / ЧТЕНИЕ │ │ │ │ ПОРТ #FF - Регистр Управления -ЗАПИСЬ │ │ │ │ - 0,1 биты - номер дисковода ('A'= 0,0) │ │ - 2 бит - сброс ВГ93 (при=0) │ │ - 3 бит - подготовиться (при=1) │ │ │ │ - 4 бит - сторона диска (при=1 верх) │ │ - 5 -//--------------------//--------- │ │ - 6 бит - плотность (при=0 двойная) │ │ - 7 -//--------------------//--------- │ │ │ │ ПОРТ #FF - Регистр Управления - ЧТЕНИЕ │ │ │ │ - 6 бит - строб байта данных (при =1 есть │ │ данные) │ │ - 7 бит - готовность (при =1 готов) │ └─────────────────────────────────────────────────┘ Как нам уже известно, прямым путем записать или считать ин- формацию по этим портам команда- ми OUT или IN нам не удастся, так как эти порты подключаются к компьютеру только тогда, когда включена ПЗУ ТРДОС и, соответ- ственно, блокированы все порты компютера. Возникает закономерный воп- рос: "А что же делать ?". Дело в том, что в адресном простран- стве ПЗУ ТРДОС, которое совпа- дает с адресами, задействованны- ми на перехват и включение ТРДОС контроллера (а как мы помним из первой главы - это промежуток адресов с #3D00 по #3DFF), есть точка входа, как раз предназна- ченная для таких случаев. (Спа- сибо программистам - хоть ее предусмотрели !) * * * ЭТО ТОЧКА С АДРЕСОМ #3D2F или #3D30. * * * А выглядит эта точка в ПЗУ ТРДОС вот так:140. #3D2F NOP #3D30 RET2 "Ну и что? Как она может нам помочь? Как за то время включе- ния ПЗУ ТРДОС нам дать команду портам?" - воскликните вы! Очень просто! Перед вызовом этой точ- ки командой 'JP' мы занесем в стек сначала адрес возврата, за- тем адрес подпрограммы ПЗУ ДОС, где есть нужная нам подпрограм- ма. По команде 'RET' в точке #3D30 процессор возьмет из стека адрес и исполнит подпрограмму ПЗУ ТРДОС, т.к. в этот момент она будет подключена. Единственное условие: эта подпрограмма в ПЗУ должна окан- чиваться командой 'RET' для то- го, чтобы все вернулось на тот адрес возврата, который мы за- несли в стек первым. Короче говоря, если нам надо исполнить какую-нибудь подпрог- рамму в ПЗУ ТРДОС, то наши дей- ствия: 1) Занести в стек адрес, куда вернется программа после выхода из ПЗУ ДОС. 2) Занести в стек адрес нуж- ной подпрограммы ПЗУ ДОС. 3) Дать команду JP #3D2F (или #3D30). Такой способ вызова называет- ся "Косвенная адресация через стек". Если нам необходимо, чтобы в ПЗУ исполнились две - три под- программы, то в стек загружают- ся (после адреса возврата) два - три адреса подпрограмм. Послед- ним в стек должен быть помещен адрес подпрограммы, которая бу- дет выполняться первой! Вроде бы ничего сложного, но вот тут-то и начинаются неприят- ности... Дело в том, что если содержи- мое точки вызова #3D30 для всех версий ТР ДОС одинаково, то АД- РЕСА ПОДПРОГРАММ-УТИЛИТ ТРДОС ДЛЯ РАЗЛИЧНЫХ ВЕРСИЙ РАЗЛИЧНЫ ! Для версии 5.01 это одни адреса, а для 5.03 это другие адреса. И вот, если Вы составите свою программу, основываясь на адре- сах версии, которая зашита в ПЗУ Вашего контроллера, то это не значит, что программа будет ра- ботать с контроллером приятеля, у которого другая версия ТР ДОС. Может статься, что в 50% слу- чаев Ваша программа просто за- виснет или, того хуже, - запор- тит Вашему приятелю данные на диске. Пример из практики: автору этой книги попалась адаптирован- ная под диск программа 'WORD'- текстовый редактор, которая была рассчитана на версию ТРДОС-5.03. (Загрузка самого редактора тоже производилась через подпрограммы ПЗУ ТРДОС). Запущенная с контроллером версии 5.01, эта программа уже в процессе загрузки "успешно" фор- матировала нулевую и первую до- рожки диска. После чего так же успешно за- висала. Представьте себе: Вы бе- рете диск с целым пакетом прог- рамм, запускаете редактор, а по- том...диск приходится форматиро- вать заново. И самое главное, что никаких надписей, с какой версией ТРДОС этот редактор работает... Хоро- шая адаптация - нечего сказать ! При ближайшем рассмотрении оказалось, что адреса в ПЗУ 5.03 подпрограммы "чтения секто- ра" в версии 5.01 лежат по дру- гим адресам, а по этим адресам в версии 5.01 расположена подпрог- рамма "форматирование". Так вот правило НОМЕР ОДИН: Если Вы программируете на са- мом низком уровне, т.е. с выхо- дом на подпрограммы ТРДОС, то Ваша программа должна опреде- лять (или запрашивать) версию ТРДОС и затем корректировать адреса вызовов подпрограмм ПЗУ. В крайнем случае Ваша програм- ма должна выводить на экран НОМЕР ВЕРСИИ ТРДОС, на какую программа адаптирована. Это правило хорошего тона !!! Далее в примерах будут при- сутствовать адреса и версии ТР ДОС 5.01, и версии 5.03. За основу приняты адреса вер- сии 5.01 !!! А адреса версии 5.03 будут даваться рядом, в угловых скобках: < адрес >. Итак, точка входа у нас есть, остались только адреса подпрог- рамм, которые бы работали с нуж- ными портами. Таких подпрограмм в ПЗУ мно- жество. Но они так тесно увяза- ны друг с другом, что если выде- лить только те, которые после команд 'IN' или 'OUT' сразу имеют команду 'RET', то таких подпрограмм окажется совсем нем- ного...140. 1. Запись в порт #1F (регистр команд). Адреса в ПЗУ Мнемоника ────────────────────────────────────────────── #2F79 < #2FC3 > OUT (#1F),A ; подать команду RET ; вернуться 2. Запись в порт #1F (регистр команд). #3ED5 < #3EDF> OUT (#1F),A ; подать команду LD A,(#5CD1) ; опросить ОЗУ CP #FF ; вернуться, если RET Z ; там байт #FF 3. Запись в порт #3F (регистр дорожки). #1DFE < #1E3A > OUT (#3F),A RET 4. Запись в порт #3F (регистр дорожки). #3E8B < #3E95 > OUT (#3F),A ; номер дорожки LD A,(#5CCD) ; опросить ОЗУ OR A ; венуться, если RET Z ; там байт 00 5. Запись в порт #FF (управление). #1FB7 < #1FF3 > OUT (#FF),A RET 6. Запись в порт #FF (управление). #2EC2 < #2F0C > OUT (#FF),A RET 7. Запись в любой порт по регистру 'C'. #2A09 < #2A53 > OUT (C),A ; номер порта в 'C' RET2 Вы, наверное, заметили, что многих портов в этих подпрограм- мах не хватает, а чтения из пор- тов нет вообще! Чтобы заставить контроллер что-то делать, необ- ходимо выполнить ряд действий в совокупности. Одной командой, в большинстве случаев, не обой- тись. Весь процесс обмена ДИСК <-> ПРОЦЕССОР состоит из 2,3,4 под- программ ПЗУ, которые выполняют ряд взаимосвязанных действий сразу с несколькими портами. Но даже с теми подпрограммами, ко- торые у нас уже есть, можно вы- полнить определенные действия. Например: воздействовать на порт управления (#FF) и дать ко- манду первого типа (адреса в примерах - для версии 5.01).147. 1. Сброс микросхемы ВГ93 и переход на 0 дорожку. START LD IX,ENDE ; адрес возврата -> в стек PUSH IX LD IX,#1FB7 ; адрес п/п ДОС ; (запись в порт #FF) PUSH IX ; занести в стек LD A,0 ; управляющая команда СБРОС JP #3D2F ; исполнить п/п в ПЗУ ENDE RET ; выйти вообще 2 !!! Кстати, если дать такую ко- манду, то потом, при нажатии на 'МАГИК' кнопку, вместо 'магик' файла Вы получите испорченный диск, т.к. микросхема будет пос- тоянно НЕ ГОТОВА по порту #FF и, чтобы вывести ее из этого сос- тояния, необходимо не только по- дать в порт #FF 'готовность', но и подать команду ПРЕРЫВАНИЕ, ко- торая начисто отсутствует в под- программе обработки 'МАГИК' кнопки !!!147. 2. Выбор номера диска, плотности, подача готовности и выбор верхней стороны диска... START LD IX,ENDE ; адрес возврата - в стек PUSH IX LD IX,#1FB7 ; адрес п/п ДОС (запись в ; порт #FF) PUSH IX ; в стек LD A,%00111100 ; управляющая команда: ; диск 'A', и т.д JP #3D2F ; исполнить п/п в ПЗУ ENDE RET ; выйти вообще 3. Поиск нужного цилиндра на диске. START LD C,#FF ; порт #FF в регистр 'C' LD A,#3C ; готовность , диск A и тд. CALL TRDOS ; записать в порт #FF LD C,#7F ; регистр данных LD A,5 ; команда - найти 5-й цилиндр CALL TRDOS ; записать в регистр данных LD C,#1F ; регистр команд LD A,#1C ; команда ПОИСК ЦИЛИНДРА с ; опущенными головками, с провер- ; кой и с минимальной задержкой CALL TRDOS ; дать команду на поиск ENDE RET ; выход из программы ;- - - - - подпрограмма записи данных в порт - - - TRDOS LD IX,#2A09 ; адрес п/п в ПЗУ 'запись в ; порт по регистру 'C' байта ; из регистра 'A' PUSH IX JP #3D2F ; исполнить и вернуться потом, ; как из подпрограммы2 Таким методом можно записы- вать данные в управляющий порт #FF, в регистры ДОРОЖКИ, СЕКТО- РА и подавать команды для ВГ93, но организовать диалог (т.е. об- мен данными и проверку) процес- сор <-> контроллер очень затруд- нительно. Вообще, обмен данными между контроллером и процессором дол- жен идти по следующему алгорит- му: 1. Даем байт управления в порт #FF. Так как этот порт под- ключен к триггеру с защелкой, то эта информация сохраняется до прихода следующего байта в этот порт (выбираем дисковод, даем подготовительную готовность, сторону диска и плотность). 2. Даем в РЕГИСТР команд, порт #1F, байт КОМАНДЫ и обяза- тельно самая первая команда пе- ред командами ЧТЕНИЕ - ЗАПИСЬ должна быть команда ПЕРВОГО ТИПА, с модификатором 'опустить головку на диск' (это связано со схемотехническими особенностями всего контроллера ТРДОС). 3. Начинаем опрашивать порт #FF на 7-й бит (бит готовности микросхемы ВГ93) до тех пор, по- ка там не установится ЕДИНИЦА, т.е. наша команда выполнена. 4. Если команда была связа- на с ЧТЕНИЕМ или ЗАПИСЬЮ, т.е. команды типа 2 и типа 3, то сов- местно с опросом бита 7 порта #FF необходимо перед каждым бай- том ДАННЫХ, идущим с диска или на диск, опрашивать 6-й бит пор- та #FF (строб данных). И если бит 6 установился в ЕДИНИЦУ, то принять или передать байт в порт #7F (регистр данных). 5. Как только бит 7 порта #FF установится в ЕДИНИЦУ, можно приступать к записи следующей команды (перед подачей следующей команды можно дать небольшую за- держку пустым циклом). 6. Опросить регистр СОСТОЯ- НИЯ ВГ93 (порт #1F) и определить правильность выполненной коман- ды. Если команда выполнена без ошибок, и все в норме, то из ре- гистра СОСТОЯНИЯ считается байт #80. 7. Если в регистре СОСТОЯНИЯ устанавливаются биты, то в зави- симости от того, какой бит уста- новился, принимаются соответ- ствующие действия. Например: при команде 'за- пись': - Если установлен бит 6, то придется прервать операции пода- чей команды 'ПРЕРЫВАНИЕ' и вы- вести надпись на экран: "ДИСК ЗАЩИЩЕН". - Если выставился бит 2 (поте- ря данных), то придется или пов- торить операцию заново, или вый- ти с надписью на экране "ошибка записи". - Если бит 0 установлен в еди- ницу, то это значит, что диско- вод занят и придется ждать, пока он не освободится. Поначалу данная последова- тельность кажется длинной и очень сложной, но так как в ПЗУ ТРДОС эти подпрограммы уже есть в совокупности, то весь процесс выльется в вызов 2-х или 3-х соответствующих подпрограмм че- рез стек из ПЗУ. Необходимо запомнить еще од- но правило: правило последова- тельности подачи команд. ПРАВИЛО НОМЕР ДВА: Из-за схемотехнической осо- бенности контроллера ТРДОС вклю- чение двигателя дисковода и при- жатие головки к диску произво- дится только командами ПЕРВОГО ТИПА, с модификатором МАГНИТНАЯ ГОЛОВКА В РАБОТЕ (т.е. когда го- ловка прижата к диску и диск раскручен). Третий бит кода команды дол- жен быть равен 1. Так как диско- вод является медленнодействующим устройством, то после выполне- ния команды первого типа остает- ся достаточно времени для подачи следующих команд ЧТЕНИЯ ИЛИ ЗА- ПИСИ. Давайте рассмотрим несколько примеров дисковых процедур из ПЗУ. ПРИМЕР 1. Подпрограмма ЧТЕНИЯ из порта. Номер порта в регистре 'C'. Перед вызовом данной процеду- ры НЕОБХОДИМО: если считывание производится из регистра данных (т.е. считывание с диска), то в регистр КОМАНД (порт #1F) нужно записать команду, а в порт #FF - записать готовность. Естественно, головки диска должны быть установлены на нуж- ную дорожку и прижаты к диску. (Адреса в примерах для ТРДОС 5.01). В регистр 'HL' поместить адрес ОЗУ, куда будем считывать информацию. В регистр 'C' - но- мер порта.140. #3FDB < #3FE5 > IN A,(#FF) ; опрос выполнения и ; строба данных AND #C0 JR Z,#3FDB ; если не выполнено и нет ; строба, то опять читаем ; порт #FF RET M ; выполнено - выход INI ; чтение байта из порта ; в адрес M (HL) JR #3FDB ; повторим, если групповая ; операция 2 Вообще-то эта процедура пред- назначена для чтения массива данных с диска (из СЕКТОРа или ДОРОЖКИ), но ее можно использо- вать и для чтения из регистров ДОРОЖКИ, УПРАВЛЕНИЯ и СЕКТОРА, если в регистр 'C' занести соот- ветствующий порт. В этом случае подпрограмма сработает ОДИН раз, и у Вас в адресе M (HL) окажется считанный байт. ВНИМАНИЕ! РЕГИСТР СОСТОЯНИЯ (ПОРТ #1F) ЭТОЙ ПРОЦЕДУРОЙ ОПРА- ШИВАТЬ НЕЛЬЗЯ. Так как при его опросе бит ГОТОВНОСТЬ порта #FF сбросится в 0 и все зациклится ! ПРИМЕР 2. Подпрограмма ЗАПИСЬ В ПОРТ. Но- мер порта в регистре 'C'. Эта процедура является обрат- ной копией предыдущей процедуры. Перед вызовом данной процедуры НЕОБХОДИМО: Если запись производится в регистр данных (т.е. запись на диск), то в регистр КОМАНД (порт #1F) нужно записать команду, а в порт #FF - записать готовность. Естественно, головки диска дол- жны быть установлены на нужную дорожку и прижаты к диску. В ре- гистр 'HL' поместить адрес ОЗУ, ОТКУДА будем записывать информа- цию. В регистр 'C'- номер порта.140. #3FC0 < #3FCA > IN A,(#FF) ; опрос выполнения и ; строба данных AND #C0 JR Z,#3FC0 ; если не выполнено и ; нет строба,то опять ; читаем порт #FF RET M ; выполнено - выход OUTI ; запись байта в порт ; из адреса M (HL) JR #3FDB ; повторим, если группо- ; вая операция 2 Этой процедурой, конечно, можно записать байт в любой порт, но для этого есть другие, менее длинные процедуры (смотри выше). Сразу же возникает законный вопрос: "А как все же опросить порт #1F, т.е. Регистр Состоя- ния ?" Дело в том, что программисты, которые писали ТРДОС, не предус- мотрели возможности без помех опросить этот регистр из прог- рамм пользователя. Все опросы порта #1F в ПЗУ тесно увязаны с другими подпрограммами чтения- записи. Есть, правда, точка по адресу #3F28 < #3F32 >, вызвав которую, можно опросить Регистр Состоя- ния. Но там сразу же происходит и проверка битов с переходом на адреса печати сообщений об ошиб- ках и сбоях диска. Эту точку входа можно исполь- зовать в программах, в которых не нарушена системная область BASIC'а и TRDOS, так как при возникновении каких-либо ошибок система будет вызывать программу печати сообщений на экран. А если область системных пе- ременных нарушена ??? Есть два способа выйти из этого положе- ния. Первый - если в программе про- исходит ЧТЕНИЕ с диска, то после прочтения сектора (секторов) произвести подсчет контрольной суммы считанного блока и срав- нить с той суммой, которая из- вестна (заранее просчитана). Если же происходит ЗАПИСЬ на диск, то тут придется или запи- сывать 2 раза один и тот же сек- тор (для уверенности), или тут же считать этот сектор обратно в какое-нибудь свободное место в ОЗУ и сравнить считанный блок с тем, который пытались записать. И если они не идентичны, то про- бовать записать еще раз. Как Вы понимаете, это не лучший выход из положения ! Второй способ - довольно эк- зотический, но очень эффективный и позволяет опросить Регистр Состояния в любое время из прог- раммы пользователя. Этот способ основан на методе ВТОРОГО ПРЕРЫ- ВАНИЯ! ("Вот так-так" - восклик- нет внимательный читатель и нач- нет искать те страницы книги, где написано, что ТРДОС не любит прерывания ДВА. Все верно, не ищите и не торопитесь с выводами и руганью в адрес автора. Дело в том, что действительно, большин- ство подпрограмм ТРДОС "боятся" второго прерывания. Это те под- программы, которые ответственны за чтение/запись информации на диск. Мы же не будем обращаться к диску, а опросим всего лишь порт Состояния ВГ93). Итак... В ПЗУ ТРДОС по адресу #2D3D < #2D87 > есть следующая последователь- ность команд.140. ;--подпрограмма 'опрос порта #1F' #2D3D < #2D87 > #2D3D < #2D87 > IN A,(#1F) ; прочитать порт #1F AND #7F ; выделим все уста- ; новленные биты RET Z ; вернемся, если НЕТ ; ошибок DEC D ; уменьшить регистр D PUSH HL ; HL в стек PUSH DE ; DE в стек JR NZ,#2D31 ; если регистр ; 'D' <> 0 ,то ; перейти выше, ; а нам это не надобно HALT ; Ждать прихода преры- ; вающих импульсов INT ... ; Далее ; нас не интересует.. 2 Воспользуемся тем, что в этой процедуре есть команда HALT. Если вспомнить, то, встретив эту команду, процессор как бы приос- танавливается и ждет прихода сигнала прерывания на вход INT, а потом уходит на исполнение программы прерывания. В СПЕКТРУ- МЕ импульсы прерывания следуют с частотой 50 Герц, и 50 раз в се- кунду опрашивается клавиатура по прерыванию 1. Мы же, установив ПРЕРЫВАНИЕ 2, перехватим выход из этой процедуры на свою прог- рамму. Единственное, не забудем пе- ред вызовом процедуры из ПЗУ за- нести в регистр 'D' ЕДИНИЦУ, а на выходе, в прерывающей проце- дуре, продвинуть указатель СТЕКА вверх по ОЗУ на 3 СЛОВА (напри- мер, три раза дать команду 'POP AF'). 140. ; Программа вызова процедуры опроса порта #1F... START LD A,#FD ; занесем вектор прерывания, ; равный, LD I,A ; например, #FD (полный адрес ; равен #FDFF) LD HL,VARIABLE ; адрес прерывающей процедуры LD (#FDFF),HL ; занесем в адрес вектора ; прерывания адрес программы LD D,1 ; регистр должен=1 для того, ; чтобы программа в ПЗУ отра- ; ботала ОДИН раз LD IX,#2D3D ; адрес подпрограммы ТРДОС ; (для версии ТРДОС 5.01 !) EI ; прерывания разрешить HALT ; приостановить процессор и IM 2 ; включить прерывание ДВА CALL TRDOS ; вызвать программу из ТРДОС с ; последующей отработкой прог- ; раммы прерывания DI ; запрет прерываниям IM 1 ; прерывание ОДИН EI ; разрешить прерывания RET ; выйти из программы ;- - - - - - - прерывающая программа - - - - - VARIABLE DI ; запретим прерывание POP HL ; извлечем из стека адрес ; возврата на POP HL ; программу в ПЗУ после HALT, POP HL ; а также еще два слова IM 1 ; прерывание в 1 RET ; вернуться ;- - - - - - - - - - - - TRDOS PUSH IX ; вызов программы из ПЗУ ТРДОС JP #3D2F ; ;- - - - - - - - - - - - 2 После запуска программы с метки START она отработает, и мы получим на выходе в регистре 'A' НОЛЬ - если все в порядке (пре- рывающая процедура не включит- ся). Если же Регистр Состояния со- держал установленные биты, то в этом случае включится наша пре- рывающая программа, и в регис- тре 'A' мы получим байт, кото- рый можно в дальнейшем проанали- зировать любым способом. Единственным недостатком та- кого метода является резервиро- вание ячеек ОЗУ под вектор - где содержится адрес прерывающей программы (в нашем случае это ячейки ОЗУ с адресами #FDFF и #FE00), а также требование сох- ранять 'старый' регистр 'I', ес- ли переделываемая программа ра- ботала с прерыванием 2. Так как младший байт вектора прерывания всегда равен #FF, то таких адресов в адресном прос- транстве компьютера насчитывает- ся всего 255. Если исключить ад- реса, падающие на ПЗУ (а их 63), то нам останется 255 минус 63, всего 192 произвольных адреса. А это достаточно много. В ПЗУ ТРДОС есть еще несколь- ко подпрограмм опроса порта #1F, которые можно вызвать таким же способом. Одна из них находится по адресу #3DAB < #3DB5 >.140. #3DAB < #3DB5 > IN A,(#1F) ; прочитаем порт AND 02 ; выделим бит 'ЗАПРОС ; ДАННЫХ' ; при операциях чтения ; -записи ; или бит 'ИНДЕКС' ; при остальных опера- ; циях LD B,A ; спрячем полученное ; значение LOOP1 IN A,(#1F) ; еще раз прочитаем ; порт AND 02 ; выделим бит CP B ; сравним с прежним RET NZ ; если бит установлен ; - выйдем INC DE ; увеличим значение LD A,E ; если попытки не ; кончились, OR A ; JR NZ,LOOP1 ; то повторить чтение ; порта 2 Эту подпрограмму удобно вызы- вать в случаях: - когда надо засинхронизировать выполнение программы на прохож- дение Индексного отверстия, т.е. на новый оборот диска, или уз- нать, вставлен ли диск и готов ли он? - при операциях чтения/записи - ожидая сигнала ЗАПРОС ДАННЫХ. Как мы видим, в этой подпрог- рамме отсутствует команда HALT, по которой ВТОРЫМ прерыванием точно перехватывается управле- ние на программу пользователя. Но в любом случае при появлении прерывающего импульса INT про- цессор будет отрабатывать цикл LOOP1, и перехват все равно сос- тоится, а в регистре 'B' или в 'A' будет нужный нам байт с вы- деленным ВТОРЫМ битом. Как и в предыдущем случае, сначала надо установить Вектор прерывания, а в прерывающей про- грамме передвинуть Указатель стека на ДВА байта вверх (чтобы вернуться не в ПЗУ, а в програм- му пользователя). Перед вызовом подпрограммы ПЗУ в регистры 'DE' необходимо занести 00 для макси- мального цикла опроса. Ну, и ес- тественно, дать команды EI и IM2. 140. ; Программа вызова процедуры #3DAB < #3DB5 > start LD A,VECTOR ; установим вектор ; прерывания LD I,A LD HL,VARIABLE ; занесем по адресу ; вектора LD (VECTOR *256+255),HL ; адрес прерывающей ; программы EI HALT LD DE,00 ; число попыток LD IX,#3DAB ; программа в ПЗУ (для v.5.01) IM 2 ; второе прерывание CALL TRDOS ; исполнить программу В ПЗУ и ; прерывающую подпрограмму IM 1 ; RET ; вернуться, в регистре 'A' и ; 'B' будет значение из ; порта #1F ;- - - - - - - - - - TRDOS PUSH IX JP #3D2F ;- - - - - - - - - - VARIABLE DI POP HL RET ;- - - - - - - - - - 2 Для полноты изложения можно еще привести адрес подпрограммы опроса порта #1F с выделением ЧЕТВЕРТОГО бита "ПОТЕРЯ ДАННЫХ", если была операция ЧТЕНИЯ/ЗАПИ- СИ. При остальных операциях - бит "ГОЛОВКА в ИСХОДНОМ СОСТОЯ- НИИ". Вызывают эту подпрограмму ОБЫЧНЫМ способом, без всяких ухищрений. Единственное, в ре- гистр 'C' перед вызовом надо за- нести число 1 - для отработки подпрограммы всего один раз. 140. ;... процедура чтения порта #1F с выделением бита 4 ;... перед вызовом дать комманду LD C,1 #3E30 < #3E3A > IN A,(#1F) ; опросить порт AND 04 ; выделить бит 4 RET NZ ; если он установлен ; - выйти INC B ; увеличить 'B' DEC C ; уменьшить 'C' RET Z ; если 'C'=0, то выйти ... 2 Теперь, когда мы научились опрашивать порт Состояния, нам надо решить, что же должна де- лать программа пользователя в случае установки какого-либо би- та в этом порту, т.е. при ошиб- ке операций. При операциях ЧТЕНИЯ/ЗАПИСИ: - Установлен 2-й бит - 'ПОТЕРЯ ДАННЫХ' и/или 3-й бит - 'ОШИБКА КОНТРОЛЬНОГО КОДА' и/или 4-й бит - 'МАССИВ НЕ НАЙДЕН' и/или 5-й бит - 'ОШИБКА ЗАПИСИ' В этом случае Вам необходимо повторить операцию определенное количество раз, и если бит все так же будет установлен, то это значит, что у Вас сбойный диск. Обрываете операцию командой 'ПРИНУДИТЕЛЬНОЕ ПРЕРЫВАНИЕ', а дальше поступаете так, как счи- таете нужным. - Установлен 6-й бит - 'ЗАЩИТА ЗАПИСИ' (т.е. диск защищен). В этом случае также прерывае- те операцию подачей команды 'ПРЕРЫВАНИЕ' и любезно просите снять защиту с диска, или не просите... - Сброшен 7-й бит - 'ГОТОВНОСТЬ ДИСКОВОДА' А в этом случае Ваша програм- ма должна просто подождать го- товности дисковода пустым цик- лом. А теперь давайте продолжим и посмотрим, что же еще полезно- го есть в ПЗУ ТРДОС. Процедура определения НОМЕРА ЦИЛИНДРА под головками. ~~~~~~~~~~~~~~~~~~~~~~~ Адрес #1DFA < #1E36 >. После вызова этой подпрограм- мы в регистре 'A' возвращается НОМЕР ЦИЛИНДРА; этот же номер сразу заносится в Регистр Дорож- ки контроллера. Также при своей работе подпрограмма опрашивает клавишу 'BREAK' = C/SH+SPACE и печатает сообщение, если клавиша нажата. Эта подпрограмма является за- конченной, т.е. не нуждается в подготовительных действиях. К сожалению, при ее работе затра- гивается ряд адресов в ОЗУ Сис- темных переменных. Условия вызова: - в регистр IY занести значение #5C3A; - в регистре 'B' должен быть НОЛЬ; - в адресе ОЗУ #5C3A должно быть значение #FF. Купируются, т.е. изменяются в процессе работы подпрограммы адреса ОЗУ #5D16 и #5CCD. Процедура 'Поиск нужной ДОРОЖКИ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #3E59 <#3E63>. При работе подпрограмма нахо- дит на диске нужную ДОРОЖКУ (вы- ходит на нужный ЦИЛИНДР и прижи- мает ВЕРХНЮЮ или НИЖНЮЮ головку исходя из заданного номера ДОРОЖКИ). Также опрашивает кла- вишу 'BREAK' = C/SH+SPACE. Под- программа является законченной и работает даже на неформатирован- ном диске. Условия вызова: - в регистр IY занести значение #5C3A; - в регистре 'A' должен быть НОМЕР требуемой ДОРОЖКИ. (Если номер 0 или четный, то дорожка верхняя, если нечетный - ниж- няя); - в адресе ОЗУ #5C3A должен быть байт #FF; - в адресах #5CF6 И #5CF7 должны быть НУЛИ; - в адресе #5CC8 должно быть значение #83; - в адрес #5CFA занести 08 или 00. Купируется, т.е. уничтожается содержимое ячеек памяти по ад- ресам #5D16 и #5CCD. Процедура 'ПОИСК нужной ДОРОЖКИ' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес вызова #2EF0 < #2F3A > Это вторая процедура ПОИСКА. Она более приемлема в програм- мах с дефицитом места в памяти. Во время своей работы процедура портит всего лишь одну ячейку памяти по адресу #5C00. При ра- боте подпрограмма находит на диске нужную ДОРОЖКУ (выходит на нужный ЦИЛИНДР и прижимает ВЕР- ХНЮЮ или НИЖНЮЮ головку, исходя из заданного номера ДОРОЖКИ). Подпрограмма является закончен- ной и работает даже на неотфор- матированном диске. Условия вызова: - в адресе ОЗУ #5C00 должен быть НОЛЬ; - в регистр 'C' заносится номер ДОРОЖКИ. В эту программу можно войти еще по адресу: #2EFB < #2F45 > В этом случае ячейка ОЗУ #5C00 не затрагивается, но перед вызо- вом подпрограммы необходимо в порт #FF подать БАЙТ 'ГОТОВ- НОСТЬ, ВЕРХНЯЯ СТОРОНА ДИСКА и т.д.', а в регистр 'C' перед вы- зовом занести Номер ДОРОЖКИ. Если кого-то не устраивают данные методы поиска ДОРОЖКИ на диске, то можно написать проце- дуру 'ПОИСК ДОРОЖКИ', основыва- ясь на команде микросхемы 'ШАГ'. Правда, это будет занимать больше места в ОЗУ, и по быстро- действию она будет намного мед- леннее всех подпрограмм ПОИСКА в ПЗУ ТРДОС. А выглядит это приблизительно так: - подать команду 'ВОСТАНОВЛЕНИЕ' - подать в порт #FF биты ГОТОВ- НОСТИ и ВЕРХНЕЙ ПОВЕРХНОСТИ (и др.); - занести в регистр (например, в 'C') НОМЕР ДОРОЖКИ; - скорректировать номер дорожки в НОМЕР ЦИЛИНДРА И в повер- хность диска и давать команду контроллеру 'ШАГ ВПЕРЕД' (с установленными модификаторами 'головку прижать, изменять ре- гистр дорожки') полученное число раз... 140. ; Подпрограмма поиска дорожки командой 'ШАГ'. ld c,#20 ; номер ДОРОЖКИ ld a,0 ; КОМАНДА ВОССТАНОВЛЕНИЕ call trdos ; ЗАНЕСТИ В ПОРТ #1F ld a,#3C ; готовность, ВЕРХ call trdos ; занести в регистр #FF ld a,c ; сдублировать номер дорожки or a ; сбросить регистр флагов rra ; разделить Номер дорожки на 2 ; в 'A' теперь номер ЦИЛИНДРА ld b,a ; поместить в счетчик цикла jr nc ,STEP ; число 'Номер Дорожки' было ; четное ? Если да - переход. ld a,#2C ; нет - значит поверхность НИЗ call trdos ; занести в порт #FF STEP ld a,#5b ; команда 'ШАГ ВПЕРЕД' call trdos ; исполнить команду djnz STEP ; повторять 'B' чило раз. .......... ; Метка "trdos" в этом случае является подпрограммой ; вызова процедур ТРДОС, которые напрямую работают с ; портами через точку #3D2F. 2 Как мы видим из примера, та- кой метод довольмо неудобен и громоздок... Процедура'ЗАПИСЬ ОДНОГО СЕКТОРА' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #3F00 < #3F0A> Процедура записывает один сек- тор на текущую ДОРОЖКУ (на кото- рой стоят головки дисковода) и выбранную поверхность. Условия вызова: - головка дисковода должна быть выведена на нужную дорожку и прижата к диску; - в адресах #5D00/#5D01 должен быть помещен адрес ОЗУ, из ко- торого будут записываться 256 байтов в сектор; - в адрес #5CFF должен быть по- мещен ЛОГИЧЕСКИЙ НОМЕР СЕКТО- РА, (т.е. нумерация секторов начинается с 0, подпрограмма потом скорректирует этот номер до физического). - сохранить данные из адреса #5CFE, так как этот адрес при работе купируется, т.е. ис- пользуется при работе. !!! Самым, пожалуй, сложным в условии вызова процедуры являет- ся условие ПРИЖАТЬ ГОЛОВКИ К ДИСКУ. Решается это простыми ме- тодами. Так как запись сектора является как бы продолжением действия программы пользователя в цепочке действий, то данная процедура должна следовать за процедурой ПОИСК НУЖНОЙ ДОРОЖКИ. А так как 'ПОИСК' является командой, которая и прижимает головки к диску, вызвав програм- му 'ЗАПИСЬ' сразу же после окон- чания действия 'ПОИСКА', мы без труда выполним нужное условие. Если же в программе пользова- теля вызов процедуры 'ПОИСК' от- стоит от вызова 'ЗАПИСИ' далеко по времени, и программа не успе- вает подать команду 'ЗАПИСЬ' на прижатые головки, то, вызвав повторно подпрограмму 'ПОИСК' с теми же параметрами, мы загрузим (прижмем) головки. Можно также дать команду дисководу 'ШАГ НА- ЗАД' и следом 'ШАГ ВПЕРЕД' с мо- дификаторами кода 'ПРИЖАТЬ ГО- ЛОВКИ'. Процедура'ЧТЕНИЕ одного СЕКТОРА' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #2ED1 <#2F1B> Условия вызова: - в регистре HL должен быть ад- рес ОЗУ, куда будет считы- ваться сектор; - в регистре 'E' должен быть но- мер СЕКТОРА (номер ЛОГИЧЕСКИЙ, т.е. нумерация с НУЛЯ). Подпрограмма вызывается пос- ле вывода головок на нужный ци- линдр и после прижатия головок к нужной поверхности. Подпрограмма в своей работе опрашивает порт СОСТОЯНИЯ (#1F) и повторяет свои действия, если был сбой в чтении. Процедура'ЧТЕНИЕ ОДНОГО СЕКТОРА' ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #3F04 <#3F0E> Это вторая подпрограмма чте- ния сектора. Условия вызова: - головка дисковода должна быть выведена на нужную дорожку и прижата к диску; - в адресах #5D00/#5D01 должен быть помещен адрес ОЗУ, в ко- торый будут считываться 256 байтов из сектора; - в адрес #5CFF должен быть по- мещен ЛОГИЧЕСКИЙ НОМЕР СЕКТОРА (т.е. нумерация секторов начи- нается с 0, подпрограмма по- том скорректирует этот номер до физического); - Сохранить данные из адреса #5CFE, так как этот адрес при работе купируется, т.е. ис- пользуется при работе. Процедура 'Подача команд ПЕРВОГО типа с ожиданием их исполнения'. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #2F0D <#2F57 > Эту подпрограмму удобно вызы- вать, когда требуется исполнить команды 'ВОСТАНОВЛЕНИЕ', 'ШАГ', 'ПОИСК'. Подпрограмма при своей рабо- те записывает код команды в порт #1F и затем, опрашивая порт #FF, ждет, когда эта команда испол- нится. Условия вызова: - в регистре 'A' должен быть код команды. Процедура 'ЦИКЛИЧЕСКАЯ ЗАПИСЬ В ПОРТ'. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #2075 <#20B1> Обычно эта подпрограмма ис- пользуется в процессе ФОРМАТИРО- ВАНИЯ ДОРОЖКИ. Но ее можно ис- пользовать для нестандартной за- писи информации на дорожку (на- пример, создание юстировочной дорожки, или для полного уничто- жения информации на дорожке). А если исхитриться, то можно запи- сывать информацию и в СЕКТОР. Условия вызова: - головки должны быть выведены на нужный цилиндр и прижаты к нужной поверхности диска; - Подать команду 'ЗАПИСЬ' (до- рожки или сектора). Если запи- сывается СЕКТОР, то в регистр СЕКТОРА поместить номер секто- ра; - В регистре 'D' должен быть байт для записи" - В регистре 'B' должно быть число: сколько раз записать байт из регистра 'D'; - В регистре 'C' должно быть #7F (порт данных). Процедура "ФОРМАТИРОВАНИЕ ОДНОЙ ДОРОЖКИ". ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес #1FC1 <#1FFD> Подпрограмма форматирует одну дорожку стандартным способом. Опрашивает порт состояния (#1F) и выдает надпись на экран, если диск защищен от записи. Условия вызова: - головки должны быть выведены на нужный цилиндр и прижаты к нужной стороне; - В ЯЧЕЙКЕ ОЗУ с адресом #5CD8 должно быть значение, отличное от НУЛЯ; - В регистр 'E' необходимо по- местить номер ЦИЛИНДРА (от 0 до 79), на котором стоят го- ловки. Если у Вас позволяет дисковод, то, выведя головки на цилиндр, больший чем 79, Вы можете разметить 80, и 81,и 82 и т.д. цилиндры до тех пор, пока у Вас головки не упрутся в ограничитель. Если же Вы хотите отформати- ровать нестандартно - пожалуй- ста. Вы можете, например, 1-й трек отформатировать с систем- ным номером 255, но работать с таким диском в ТРДОС СТАНДАРТНЫ- МИ командами будет трудновато!!! Для форматирования дорожки нестандартным образом можно ис- пользовать точку входа этой под- программы: #1FC9 <#2005 > В этом случае, кроме всех предыдущих условий, необходимо: - в регистре 'HL' должен быть помещен адрес дампа данных, где последовательно размещены номера СЕКТОРОВ диска (для нормального выхода ПОСЛЕДНИМ НОМЕРОМ в дампе должен быть номер #10!). ТРДОС использует адрес дампа данных в ПЗУ по адресу #1F7D <#1FB9>; - в порт КОМАНД (#1F) должна быть занесена команда ФОРМАТИ- РОВАНИЕ (например, байт #F4). Подробнее о процессе ФОРМАТИ- РОВАНИЯ будет рассказано чуть позднее. Процедуры 'ЦИКЛ ЗАДЕРЖКИ'. ~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес 1. #3DF3 <#3DFE> Адрес 2. #3E96 <#3EA0> Это подпрограмма задержки для ожидания исполнения команд дис- ководом. Иногда ее полезно вызы- вать, чтобы быть уверенным в том, что последующая команда дисководу поступит на него тог- да, когда он свободен. Первая подпрограмма: задер- жка составляет приблизительно 0.3 секунды, а вторая задержка - приблизительно 1.2 секунды. Процедура 'ПЕРЕСЫЛКА ДАМПА'. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Адрес 1. #17DD <#180D> Адрес 2. #28A5 <#2FEB> По этому адресу в ПЗУ ТРДОС находятся команды: LDIR RET Вызов этой подпрограммы бы- вает полезен тогда, когда надо заморочить голову хаккерам или для перекачки информации из ПЗУ ТРДОС в ОЗУ: например, части ка- кой-либо процедуры. Условия вызова такие же, как и обыкновенной команды 'LDIR'. Можно было бы привести еще множество полезных подпрограмм из ПЗУ. Но все вышеизложенное доста- точно для того, чтобы написать какую угодно программу работы с диском, и мы ограничимся этими подпрограммами, которые являют- ся главенствующими. В процессе написания своих программ или при разборе других аналогичных программ Вы можете обнаружить, что необязательно вызывать подпрограммы ТРДОС по указанным выше адресам. В конце этой главы, в приложении, будут приведены листинги наиболее важ- ных подпрограмм ПЗУ ТРДОС с ука- занием адресов, и вам самим ре- шать, по какому адресу вызывать ту или иную процедуру. (продолжение следует...)