┌──────────────────────────────┐
│ │
│ 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'.
Можно было бы привести еще
множество полезных подпрограмм
из ПЗУ.
Но все вышеизложенное доста-
точно для того, чтобы написать
какую угодно программу работы с
диском, и мы ограничимся этими
подпрограммами, которые являют-
ся главенствующими.
В процессе написания своих
программ или при разборе других
аналогичных программ Вы можете
обнаружить, что необязательно
вызывать подпрограммы ТРДОС по
указанным выше адресам. В конце
этой главы, в приложении, будут
приведены листинги наиболее важ-
ных подпрограмм ПЗУ ТРДОС с ука-
занием адресов, и вам самим ре-
шать, по какому адресу вызывать
ту или иную процедуру.
(продолжение следует...)