TR-DOS для программистов.
music by DNK
(C) Макс Петров.
________________________________
Я не буду в этой статье повто-
рять описания tr-dos различных
изданий, показывать пример ис-
пользования её из basica и пере-
числять номера подпрограмм пзу
'#3d13'. Моя цель состоит в опи-
сании тонкостей и сложностей, с
которыми я сам встретился, пыта-
ясь раскрутить мотор дисковода,
написать свой загрузчик и нако-
нец свой командера. Я попытаюсь
доходчиво объяснить 'как' рабо-
тать с ВГ 93 и дисководом и при-
веду примеры полезных процеду-
рок.
ВГ 93.
Как Вам должно быть известно,
общение с ВГ происходит через
порты, обращаться к которым мож-
но _только_ из пзу tr-dos (от-
дельные экземпляры speccy позво-
ляют выводить/читать из портов
хоть из озу, но то является
только нежеланием разработчика
привести контроллер дисковода к
стандарту).
Порты (регистры) ВГ 93:
чтение:
#1f - содержит информацию о
состоянии микросхемы в процессе
выполнения команды или о наличии
ошибок исполнения команды.
#3f - содержит номер дорожки
(физический), на которой, по
мнению ВГ, стоит головка диско-
вода. Если сдвинуть головку
вручную, значение регистра не
изменится!
#5f - содержит номер сектора.
#7f - информация, передаваемая
микросхемой в процессе выполне-
ния команды (очередной считанный
с диска байт).
#ff - бит 7 =1 означает конец
выполнения команды, бит 6 =1 оз-
начает просьбу ВГ передать ей
следующий байт, например, при
записи сектора, или взять прочи-
танный ею с диска байт, который
она поместила в регистр #7f.
Практического применения чтение
из портов #3f и #5f не имеет, да
из них и невозможно прочитать
(см. 'чтение из портов').
запись:
#1f - код команды.
#3f и #5f - тоже, что чтение.
#7f - сюда следует записывать
очередной байт после просьбы ВГ
для записи его на диск, или но-
мер дорожки для команды позицио-
нирования.
#ff - бит 6 - плотность записи
(fm/mfm). В некоторых контролле-
рах (а может и во всех) этот бит
не подключен, поэтому не стоит
пытаться им воспользоваться. бит
3 отвечает за остановку мотора.
Если он =1, то мотор через неко-
торое время после выполнения ко-
манды остановится, иначе будет
крутиться вечно (по-моему так).
Бит 2 (небезизвестная книга Лар-
ченко и Родионова даёт о нём не-
верную информацию) - сбросив его
в 0 Вы добьётесь мгновенного
прекращения выполнения команды и
остановки мотора. Порт #ff имеет
ещё три бита, но внимание! ВГ об
их существовании не знает! Они
управляют непосредственно диско-
водом и контроллером (в частнос-
ти, ВГ не имеет понятия, с каким
дисководом (a,b...) она работа-
ет). Бит 4 - номер стороны дис-
кеты (1 - нижняя), биты 1,0 -
номер дисковода. Некоторые
контроллеры (а может почти все)
работают только с битом 0 и поз-
воляют выбрать только 2 дисково-
да.
Как программировать ВГ 93.
Как я уже сказал, в наших прог-
раммах нельзя непосредственно
обратиться к регистрам ВГ - для
чтения/записи в порты контролле-
ра необходимо использовать соот-
ветствующие участки пзу DOS, ко-
торые удобно искать с помощью
sts 4.1 (следует заметить, что
sts 4.1 неверно трассирует опе-
рации ld r,(hl) в пзу tr-dos,
где r<>a и 0<=hl<=#3fff). К най-
денным участкам затем можно об-
ращаться такой последова-
тельностью команд (adr - адрес
участка):
ld hl,l01
push hl
ld hl,adr
push hl
jp #3d2f
l01 ...
Удобнее так:
ld ix,adr
call dos
...
dos push ix
jp #3d2f
Не следует вместо #3d2f ставить
#3d30, т.к. существуют особо
тормозные контроллеры (?), кото-
рые не успевают подключить пзу
tr-dos и требуют для этого нес-
кольких тактов процессора.
Полезные подпрограммы пзу DOS:
запись в любой порт:
#2a53 out (c),a
ret
запись на диск до конца опера-
ции из hl:
#3fca in a,(#ff)
and #c0
jr z,#3fca
ret m; bit 7,a=1 - конец
outi
jr #3fca
чтение в hl с диска до конца
операции:
#3fe5 тоже, только ini вместо outi.
ожидание выполнения команды
(используется при позиционирова-
нии):
#3ef5 in a,(#ff)
and #c0
jr z,#3ef5
ei
ret m
di
in a,(#7f)
jr #3ef5
Везде в статье адреса даны для
tr-dos 5.03/04t. Для 5.01 адреса
другие.
Теперь у нас есть всё для того
чтобы заставить ВГ выполнить ко-
манду. Однако надо бы ещё прове-
рить успешность этого выполне-
ния, т.е. прочитать значение ре-
гистра #1f. Разработчики tr-dos
видимо не предполагали, что воз-
можности их системы могут не
удовлетворять программеров, от-
части поэтому такой последова-
тельности как in a,(#1f) или in
r,(c): ret в пзу нет, поэтому
прочитать значения регистров #3f
и #5f невозможно (хотя и не нуж-
но), а #1f - затруднительно.
Есть несколько способов (2 или
3). На мой взгляд самый удобный
и надёжный такой: сразу после
выполнения команды необходимо
выполнить следующие дейстия:
ld d,номер дорожки, на кото-
рой стоит головка дисковода (его
надо знать)
ld (#5cd8),не 0
ld ix,#2740
call dos
ld a,(#5ccd)
здесь a будет содержать значение
регистра #1f. Следует учесть,
что во время отработки процедуры
#2740 осуществляется опрос кла-
виши break, поэтому во избежание
недоразумений следует перехваты-
вать попытку выхода в пзу basic
(см. ниже).
Теперь средство есть, объясню
наконец, как дать ВГ команду
прочитать, например, группу сек-
торов. Замечу, что команды чте-
ния/записи не раскручивают мо-
тор!, это делают команды позици-
онирования. Команду можно пода-
вать только когда микросхема не
занята выполнением предыдущей
команды.
Позиционирование:
(Объясню понятия физической и
логической дорожек: физ. показы-
вает только положение обеих го-
ловок, вне зависимости от сторо-
ны. Можно привести в соот-
ветствие:
номер !физ:0 0 1 1 ... 80 80
дорожки !лог:0 1 2 3 ... 160 161
Зачем это надо? дело в том, что
ВГ 93 работает с физ. номерами
дорожек, ведь она не знает номер
стороны (см. порт #ff), а мы
привыкли к лог. номеру. Т.о.
лог=физ*2+номер стороны (0 -
нижняя)
di
ld a,d ;d - логический но-
;мер дорожки
srl a ; вычисляем физич.
; номер (a/2)
ld c,#7f; сюда надо помес-
; тить номер до-
; рожки,на которую
; я хочу отьехать.
call outc
ld a,#3c; выбор стороны
bit 0,d
jr z,l01
ld a,#2c
l01 ld c,#ff
call outc; устанавливаем
; нужные для
; нормальной ра-
;боты биты порта #ff и номер
;стороны регистр #3f устанавли-
;вать не надо, он должен сам по
;себе содержать номер текущей
;дорожки
ld a,#18; код команды пози-
;цион.
call out1
ld ix,#3ef5
call dos; ожидание выполне-
;ния
di ; команды.
jp cont
...
out1 ld c,#1f
outc ld ix,#2a53
dos push ix
jp #3d2f
Что делает ВГ 93: при получении
в регистр #1f кода #18, она дает
сигнал на раскрутку диска. Затем
сравнивает значения регистров
#3f и #7f, определяет направле-
ние и количество шагов головки и
шагает, изменяя значение рег.
#3f. При этом значение регистра
#3f может и не совпадать с ре-
альным положением головок. Но об
этом поговорим потом. Когда зна-
чения #7f и #3f совпали, ВГ ус-
танавливает bit 7 порта #ff =1 и
готова к приёму следующей коман-
ды.
За время позиционирования мо-
тор, вращающий диск, мог не ус-
петь раскрутиться до требуемой
скорости 5 об/сек, поэтому тео-
ретически следует после выдачи
команды позиционирования и перед
чтением/записью сделать паузу
(паспортное время раскрутки мо-
тора 0.7 сек.). Задержка также
нужна на время успокоения голо-
вок после позиционирования (по
паспорту 15 мс). Однако опыт по-
казывает, что перед чтением за-
держку можно не делать вообще,
перед записью же - тут Вам ре-
шать, скажу лишь, что в уже два
года существующем командере fpm
задержка перед записью делается
только при первом позиционирова-
нии перед записью первого секто-
ра из всей группы.
Итак, ездить по диску мы уже
умеем и мотор уже крутится. Те-
перь можно читать сектора:
- даём команду "чтение сектора"
- читаем сектор
- проверяем наличие ошибки
затем повторяем для остальных
секторов на данной дорожке. При
переходе на следующую дорожку
надо опять дать команду позицио-
нирования. Надо сказать, что оп-
ределение наличия ошибки по
#2740 нерационально при работе с
группой секторов. Существует
другой способ. Процедура #2090
позволяет прочитать сектор, про-
верив затем, была ли ошибка. Для
её вызова необходимо:
поместить в стек:
1) адрес возврата.
2) адрес,указывающий на байт #01
3) bc=#17f
4) в (#5cd6) записать число n
(любое)
5) поместить в регистр #5f номер
сектора
6) войти в пзу по адресу #2090
В hl должен быть адрес, куда
читать или откуда писать сектор.
cont ld bc,exit
push hl
push bc
ld bc,cont; адрес, указыва-
;ющий на 1
push bc
xor a
ld (#5cd6),a
ld a,номер сектора
ld c,#5f
call outc
ld bc,#2090
push bc
ld bc,#17f
jp #3d2f
exit di ; процедура #2090 разре-
; шает прерывания
pop hl
ld a,(#5cd6)
Здесь a будет равно записанному
ранее в (#5cd6) числу, если
ошибки не было, или на 1 больше,
если была. Если ошибка была, то
следует либо повторить операцию,
либо, если действия Вашей прог-
раммы зависят от конкретной
ошибки, то воспользоваться #2740
для определения кода ошибки. Ес-
ли ошибок не было, то следует
перерассчитать значения hl и
'номера сектора' для следующего
сектора и повторить операцию.
Подпрограмма для записи сектора
выглядит несколько иначе:
cont ld bc,exit
push hl
push bc
ld bc,cont;адрес,указываю-
;щий на 1
push bc
xor a
ld (#5cd6),a
ld a,номер сектора
ld bc,#15f
call outc
push bc; в стек надо запи-
;сать #01xx
ld bc,#2099
push bc
ld bc,#3fca
push bc
ld a,#a0; команда 'запись
;сектора'
call out1
ld bc,#17f
jp #3d2f
exit di ; процедура #2090 разре-
; шает прерывания
pop hl
ld a,(#5cd6)
Дальше аналогично загрузке.
Какие могут быть ошибки? (коды
из #1f)
При чтении:
bit 7 =1 дисковод не готов (не
крутится мотор.
bit 5 =1 не обращайте на него
внимания. На всех 'нормальных'
дисках он =0.
'& bit 4 =1 нет сектора. Обычно
что-то где-то не читается.
bit 3 =1 сектор читается с
ошибкой.
bit 0 =1 Вы дали ВГ команду в
тот момент, когда она уже выпол-
няла что-то
(?). Вероятность такой ошибки
практически равна нулю.
При записи:
bit 7 - аналогично чтению.
bit 6 =1 на дискете заклеена
прорезь 'защита записи'.
bit 5 =1 ошибка записи. Не
знаю, что сие означает.
bit 4 и 0 - аналогично чтению.
При корректном обращении к
контроллеру вероятность появле-
ния ошибок bit 2 и 1 также равна
нулю.
Ну вот, на сегодня всё.
Ждите продолжения...