> Этот байт нужен, чтобы понять, а не поменял ли пользователь диск в процессе записи.
Немного поясню: речь идёт о доступе к файлам в поблочном режиме: что-то вроде fopen(); fwrite(); fseek(); fclose();.
В агатовских доках этот режим не особо описан (только частный случай доступа к текстовым файлам).
Но общая суть в том, что в этом режиме операции открытия файла, чтения или записи и закрытия разнесены во времени.
Т.е. прога может быть открыла файл, что-то в нём исправила, потом пауза, общение с пользователем, дисковод отключен. Потом вновь вносятся какие-то изменения в файл. Вот когда дисковод остановлен, пользователь может не понять, что операция не закончена, и сменить диск. И операционка сразу же должна распознать этот факт.
Я думаю, тут расчёт был на то, что по умолчанию -то номер тома - 254, но именно если автор разрабатывает прогу, которая таким образом общается с диском, он при инициализации диска как раз и укажет какой нибудь том, отличный от 254. И тогда этот диск будет явно отличаться от других.
Способ не супер удобный и стабильный, но лучше чем ничего.
==
> А есть где-нибудь описание всего того, что он делает? Мне нехватает понимания, что я сделал не так, драйвер работает, а операционка нет.
Он - кто ? ROM драйвер был давно и подробно расписан Игорем Бончаном:
Так как возникает много вопросов по поводу работы контроллера Teac, решил
все-таки ответить всем и сразу. Читайте.
Листинг ПЗУ контроллера дисководов ЕС5323.01(02) (фг3.089.174) с
комментариями (Бончан Игорь)
В листинге все числа шестнадцатиричные
;=================================================================================================================================
C500: A2 20 LDX #20 ;оставлено на случай изменений в подпрограмме
C502: A0 00 LDY #00 ;FFCB (см. ниже) и совместимости между контроллерами, иногда выступает в роли ID
C504: A2 03 LDX #03 ;количество шагов головки внутрь
C506: 86 3C STX 3C ;кладем
C508: 20 CB FF JSR FFCB ;идем на RTS (возврат из подпрограммы) в мониторе
C50B: BA TSX ;помещаем указатель стека в регистр X
C50C: BD 00 01 LDA 0100,X ;в FF+X имеем WORD вектор, который остался после JSR FFCB (FF+X=0A, 100+X=C5 в нашем случае)
C50F: 0A ASL ;делаем это чтобы узнать слот контроллера (старший байт адреса - C0)
C510: 0A ASL ;сдвигаем этот байт в аккумуляторе (С5) влево на 4 бита (ASL)
C511: 0A ASL
C512: 0A ASL ;имеем в аккумуляторе A=50
C513: 85 2B STA 2B ;теперь ячейка равна 2B=SLOTx10
C515: AA TAX ;и индексный регистр X тоже
;=================================================================================================================================
C516: A9 92 LDA #92 ;стартовая комбинация входных сигналов логики 1-го контроллера (чипа) КР580ВВ55А
C518: 9D 83 C0 STA C083,X ;считайте что это "full reset" !!! именно поэтому не надо при работе писать единицу в 7 разряд RK
;конкретно: сброс режима предкомпенсации, сброс номера первого привода, выборка
;неопределенного состояния тракта чтение-запись (2-й чип)
C51B: A9 BD LDA #BD ;стартовая комбинация входных сигналов логики 2-го контроллера (чипа) КР580ВВ55А
C51D: 9D 87 C0 STA C087,X ;также считайте за "full reset" !!! поэтому при работе с контроллером можно изменять лишь
;биты 2 и 4, иначе, не зная конкретной схемотехники, вы получите непредсказуемое состояние
;контроллера
C520: A9 0F LDA #0F ;7 бит RK в "1" - включаем НГМД
C522: 9D 83 C0 STA C083,X ;начал раскручиваться первый привод
C525: A9 09 LDA #09 ;в 4 бит RD пишем 1 - включаем разрешение формирования сигнала готовности чтения для тракта
C527: 9D 87 C0 STA C087,X ;проще говоря - режим чтения
C52A: EA NOP ;
C52B: EA NOP ;оставлено после правок и для совместимости с Волжскими контроллерами
C52C: A9 05 LDA #05 ;устанавливаем бит 2 регистра RK в "1" - направление движения головки "внутрь"
C52E: 2C A9 04 BIT 04A9 ;типичный прием для 6502 когда пойдем на C52F установим бит 2 RK в "0" направление
C531: 9D 83 C0 STA C083,X ;головки "наружу" (т.е. "0" во 2-й бит), устанавливаем RK
C534: 9D 89 C0 STA C089,X ;делаем шаг
C537: A0 08 LDY #08
C539: CA DEX ;задержка на успокоение головки
C53A: E4 2B CPX 2B ;выйдем с X таким же как и вошли
C53C: D0 FB BNE C539 ;N-разъема x 10
C53E: 88 DEY
C53F: D0 F8 BNE C539 ;всего x*y $800 проходов
C541: BD 81 C0 LDA C081,X ;опрашиваем слово состояния (регистр S)
C544: 30 FB BMI C541 ;не готов, ждем (Флаг готовности "0" в 7 бите)
C546: C6 3C DEC 3C ;делаем 3 шага внутрь
C548: 10 EA BPL C534 ;(было по адресу C504:LDX #3,STX 3C)
C54A: 29 40 AND #40 ;а когда их сделаем будем приходить сюда
C54C: D0 E1 BNE C52F ;и ждать сигнала "0-й трек" (бит 6) ведь в 7 бите $3C будет "1" не менее $80
C54E: EA NOP ;раз, а это больше чем дорожек $50
C54F: 85 26 STA 26 ;сюда из аккумулятора "0" XFXXXXXXb AND 40 =0 (где F-сигнал "нулевой трек" регистра S)
C551: EA NOP ;уже говорил выше
C552: EA NOP
C553: EA NOP
C554: 85 41 STA 41 ;
C556: 85 3D STA 3D ;обнуляем все 26,41,3d
C558: A9 08 LDA #08 ;27=8, 26=0 (см.выше), это WORD вектор, по адресу 800 будет считан 0 сектор 0 дорожки
C55A: 85 27 STA 27 ;
;=================================================================================================================================
C55C: 9D 8A C0 STA C08A,X ;сбрасываем состояние синхротриггера (если не поняли ведь пока мы двигали головку и ждали
;диск прошел далеко не один раз и не раз произошел сбой "синхро", секторов 20 прошло по минимуму)
C55F: BD 86 C0 LDA C086,X ;теперь ждем нового взвода синхротриггера
C562: 0A ASL ;выдвигаем на 1 бит влево - проверяем 6-й бит
C563: 30 FA BMI C55F ;если не равен нулю (признак сбоя) то ждем
C565: BD 84 C0 LDA C084,X ;сбрасываем байт-мусора после сбоя (после синхро пишется байт из единиц FF, так как
;нам нужно время после реакции синхротриггера, чтобы не зависеть от согласования схем тракта
C568: BD 86 C0 LDA C086,X ;теперь ждем первый рабочий байт после сбоя "синхро"
C56B: 10 FB BPL C568 ;байт сформирован ? ("1" в старшем 7 разряде - признак готовности байта)
C56D: BD 84 C0 LDA C084,X ;получен первый байт маркера пролога поля адреса (95 6A)
C570: C9 95 CMP #95
C572: D0 E8 BNE C55C ;нет будем идем на C55C, сбросим синхротриггер и все сначала
C574: 9D 8A C0 STA C08A,X ;сбрасываем синхротриггер (он ведь остался взведенным), отсюда и далее при стандартном чтении
;появление сбоя синхронизации следует считать ошибкой в стандартном чтении (не в этом ПЗУ)
;в конце чтения будет проверка сбоя "синхро"
C577: BD 86 C0 LDA C086,X ;следующий байт
C57A: 10 FB BPL C577 ;не готов
C57C: BD 84 C0 LDA C084,X
C57F: C9 6A CMP #6A ;получили 2-й байт маркера пролога адреса
C581: D0 D9 BNE C55C ;нет, другой - ошибка, все сначала
C583: BD 86 C0 LDA C086,X ;1-й информационный байт поля адреса
C586: 10 FB BPL C583 ;не готов
C588: BD 84 C0 LDA C084,X ;это должен быть номер тома, но здесь он нам не важен, поэтому просто очищаем регистр R-данных
C58B: BD 86 C0 LDA C086,X ;2-й информационный байт поля адреса
C58E: 10 FB BPL C58B ;не готов
C590: BD 84 C0 LDA C084,X ;это трек
C593: C5 41 CMP 41 ;в ячейке 41 первый записывали 0 (на C554), что первый раз проверяем нулевой ли трек
;а потом (см. ниже) будем просто проверять на нужный (41) нам трек
C595: D0 C5 BNE C55C ;но если не совпадает: ошибка позиционирования или запись на дискете не верна, то так и
;будем крутиться - перепозиционирования не будет, идем на риторическое C55C, и до упора
C597: BD 86 C0 LDA C086,X ;3-й информационный байт поля адреса
C59A: 10 FB BPL C597 ;не готов
C59C: BD 84 C0 LDA C084,X ;читаем
C59F: C5 3D CMP 3D ;нужный нам сектор? первый раз 3D=0 (см.выше), а потом просто ищем нужный нам
C5A1: D0 B9 BNE C55C ;нет, не тот сектор, идем искать поле адреса следующего
;=================================================================================================================================
C5A3: A0 00 LDY #00
C5A5: 84 3C STY 3C ;там был мусор после поиска 0-й дорожки
C5A7: 9D 8A C0 STA C08A,X ;сбрасываем синхротриггер, так как сбои синхронизации в разделителях GAP1 и GAP2 совершенно
;естественное и множественное дело, ведь когда мы перезаписываем поле данных (запись любого
;файла) информация в GAP'е нарушается и принимает вид, отличный от строки GAPxAAв после
;исходного форматирования, так и появляются в GAP'ах сбои "синхро"
C5AA: BD 86 C0 LDA C086,X ;теперь ждем нового взвода синхротриггера
C5AD: 0A ASL ;выдвигаем на 1 бит влево - проверяем 6-й бит
C5AE: 30 FA BMI C5AA ;если не равен нулю (признак сбоя) то ждем
C5B0: BD 84 C0 LDA C084,X ;сбрасываем байт-мусора после сбоя (после синхро пишется байт из единиц FF, так как
;нам нужно время после реакции синхротриггера, чтобы не зависеть от согласования схем тракта
C5B3: BD 86 C0 LDA C086,X ;теперь ждем первый рабочий байт после сбоя "синхро"
C5B6: 10 FB BPL C5B3 ;не готов
C5B8: BD 84 C0 LDA C084,X ;получен первый байт маркера пролога поля данных (6A 95)
C5BB: C9 6A CMP #6A
C5BD: D0 E8 BNE C5A7 ;нет будем, значит в GAP2 висел мусор (совпадающий с маркером) идем на C5A7,
;сбросим синхротриггер, и все сначала
C5BF: 9D 8A C0 STA C08A,X ;сбрасываем синхротриггер (он ведь остался взведенным), отсюда и далее при стандартном чтении
;появление сбоя синхронизации следует считать ошибкой в стандартном чтении (не в этом ПЗУ)
;в конце чтения будет проверка сбоя "синхро"
C5C2: BD 86 C0 LDA C086,X ;следующий байт
C5C5: 10 FB BPL C5C2 ;не готов
C5C7: BD 84 C0 LDA C084,X ;получили 2-й байт маркера пролога поля данных
C5CA: C9 95 CMP #95
C5CC: D0 D9 BNE C5A7 ;нет, другой - ошибка, все сначала
;=================================================================================================================================
C5CE: 18 CLC ;сбрасываем флажок переноса, для операции сложения при подсчете контрольной суммы (далее CHS)
C5CF: BD 86 C0 LDA C086,X ;начинаем читать собственно байты данных, помним что Y=0 (см. C5A5)
C5D2: 10 FB BPL C5CF ;не готов
C5D4: BD 84 C0 LDA C084,X ;байт
C5D7: 91 26 STA (26),Y ;напомню 26,27 - WORD адрес страницы, сюда читаем 256 байт данных (байт берем по индексу в Y)
C5D9: 65 3C ADC 3C ;добавляем к CHS
C5DB: 85 3C STA 3C ;пишем в ячейку (CHS=CHS+byte)
C5DD: C8 INY ;индекс + 1
C5DE: D0 EF BNE C5CF ;когда пройдем до FF в Y то FF+1=0, а пока Y<>0 читаем дальше
;=================================================================================================================================
C5E0: BD 86 C0 LDA C086,X ;читаем следующий байт
C5E3: 10 FB BPL C5E0 ;не готов
C5E5: BD 84 C0 LDA C084,X ;это байт - контрольной суммы (CHS)
C5E8: C5 3C CMP 3C ;сверяем с посчитанной
C5EA: D0 B5 BNE C5A1 ;не совпадает идем через C5A1 на C55C BNE-BNE и перечитываем весь сектор и поле адреса и данные
C5EC: E6 27 INC 27 ;увеличваем старший байт адреса страницы с данными +1
C5EE: E6 3D INC 3D ;увеличиваем номер сектора +1
C5F0: A5 3D LDA 3D ;сверяем номер сектора с первым байтом прочитанного 0-го сектора 0-й дорожки (читали по адресу
C5F2: CD 00 08 CMP 0800 ;800) - в нем должно быть число секторов, которое должен прочитать контроллер до передачи
;управления на следующий за этим байтом адрес, (т.е. 801)
C5F5: A6 2B LDX 2B ;еще раз в индексный регистр X=слот x 10, и если
C5F7: 90 A8 BCC C5A1 ;номер прочитанного сектора меньше указанного в 800, то через C5A1 на C55C (BNE-BNE)
C5F9: 4C 01 08 JMP 0801 ;прочитали столько секторов, сколько было указано (800), передаем управление программе в
;0-м секторе (смещение 1 байт)
C5FC: 01 02 ORA (02,X) ;ID контроллера (02 - Teac)
C5FE: 34 ???
C5FF: 02 ??? ;контроллер НГМД
Вообще говоря, программа расположенная в ПЗУ является упрощенным вариантом
штатного чтения сектора и не проверяет сбоев синхро, не делает проверку
эпилогов, не учитывает число попыток чтения, не делает перекалибровки в
случае сбоя и т.п. Обычно в первом байте 0-го сектора (загрузчика) указан
байт 01, что подразумевает чтение лишь нулевого сектора. Почему? Это
связано с тем, что редко имеет смысл читать начальный код самозагружающихся
систем линейно, т.е.:
0-й сектор - адрес 800
1-й сектор - адрес 900
2-й сектор - адрес A00
3-й сектор - адрес B00
и т.п.
Обычно загрузчик сам управляет адресами загрузки в ячейке 27 возвращая
управление на C55C и принимая на 801.
Надеюсь, теперь вам все ясно.
Спрашивайте, хотя выходные уже заканчиваются.
Игорь.
Вообще, можно условно говорить о трёх драйверах:
- ROM-драйвер;
- Код, управляющий ROM-драйвером, уже после загрузки сектора 0/0, для чтения остальных секторов (эту штуку почему-то часто называли "автолоадер");
- RWTS (Read/Write Track/Sector) - полноценный, независимый от ROM, драйвер дисковода со всеми плюшками, записью, очередью команд и прочим.
Большинство операционок Агата используют все три вида драйверов.
> Мне нехватает понимания, что я сделал не так, драйвер работает, а операционка нет.
Так выложи свои наработки и поковыряем совместно.
Вообще, драйвер дисковода нынче - с появлением эмуляторов - не сложно отлаживать.
Но заканчивать отладку нужно обязательно на реальном железе.
Эмуляторы слишком предсказуемы, по сравнению с реальным железом.
> Все, больше нам ничего для перепрограммирования недоступно
Всё, что я хорошо запомнил о программировании и режимах ВВ55 - это то, что те константы, которые приводятся в документации и драйверах - это единственная полезная комбинация и именно её используют все драйвера. Единственное, что мне доводилось видеть, расширяющее доки: в драйверах BTK есть такая штука: когда был сбой чтения, драйвер записывает режимные регистры какую-то константу, которая "распрограммирует" микруху (что-то типа состония "после reset"). Вроде бы идея в том, что при последующем старте драйвера он будет заного программировать микруху, тем самым сбрасывая всё, что можно сбросить. Но если ли в этом хоть малейший технический смысл - я не уверен.