Абзац
:: Поиск
:: Поддержка проекта
Webmoney:
  • Z610389805629
  • R427996570517
  • E023541002978
  • :: №15 (26.02.2003) Просмотров: 10382

    Автор: Александр Юдин.

    Рубрика: В помощь разработчику.

    Номер: №15 (26.02.2003).



    Укрощение TR-DOS

    Почему я решил написать эту статью? Во-первых, я знаю, что для многих программирование под TR-DOS до сих пор остается тайной за семью печатями. Во-вторых, практически нет нормальной документации по программированию TR-DOS. В-третьих, хочу поделится с вами той информацией, теми знаниями, которые у меня накоплены. Я постараюсь представить их в виде некоего пособия с простым и понятным содержанием для людей, которые практически не разбираются в работе дисковых устройств. Впрочем, здесь будет много интересного и для разбирающихся в этом деле... Кстати, моя гордость, это процедура программного определения типа дисковода 3.5” или 5.25” (правда в этом описании ее нет). А теперь, пожалуй, самое время перейти к самому интересному.


    TR-DOS


    TR-DOS - дисковая операционная система разработанная в Англии. До нашей страны «докатились» две версии: 5.01 и 5.03 - датированные 1986 годом. Очевидно Technology Research Ltd было необходимо как можно быстрее «выкинуть» в свет свое творение, поскольку я не могу найти другого объяснения тoму факту, что TR-DOS написана так ужасно, напичкана всевозможными ляпами, которые не были исправлены даже в третьей редакции пятой версии! Охарактеризовывая TR-DOS, лично я нахожу лишь один плюс (как для программиста), - это последовательное хранение информации на диске, что дало возможность написания процедур дающих максимальную скорость.

    Пожалуй далее идут одни недостатки. Например, по-моему, непомерно «раздута» область системных переменных, тяп-ляп написаны подпрограммы в ПЗУ, и самое главное, совершенно не предусмотрено возможности для самостоятельного низкого программирования микроконтроллера. Так же, слишком уж перестрахованные задержки в процедурах обмена данными между микроконтроллером и дисководом. Но, тем не менее, не все так уж и плохо. Используя обрывки подпрограмм в ПЗУ (ROM) TR-DOS, можно получить доступ к портам микроконтроллера.


    Порты


    Для управления интерфейсом BETA DISC используются следующие порты: #1f, #3f, #5f, #7f, #ff.

    регистр состояния #1f [in]

    регистр команд #1f [out]

    in a,(#1f) - выдает состояние контроллера, где A:

    http://abzac.retropc.ru/images/i15_10.gif

    out (#1f),a - выполнение команды, где A - код команды (см. раздел команды).

    Регистр дорожки #3f - in/out

    in a,(#3f) - выдает номер текущего физического трека.

    out (#3f),a - задание нового физического трека.

    Регистр сектора #5f - in/out

    in a,(#5f) - выдает номер текущего сектора.

    out (#5f),a - задание нового сектора (нумерация с 1!).

    Регистр данных #7f - in/out

    in a,(#7f) - чтение байта

    out (#7f),a - задание номера логического трека, для команды позиционирования или запись байта если была какая-либо команда на запись.

    ini - последовательное считывание данных.

    outi - последовательная запись данных.

    Регистр #ff состояния сигналов intrq и drq - [in]

    Системный регистр #ff - [out]

    in a,(#ff) - отражает состояние сигналов intrq (d7), drq (d6) контроллера, где A:

    bit

    7 - intrq (сигнал окончания выполнения команды)

    6 - drq (запрос данных микроконтроллером)

    5 - x

    4 - x

    3 - x

    2 - x

    1 - x

    out (#ff),a - вспомогательные функции, где A:

    bit

    7 - x

    6 - метод записи (1 - fm, 0 - mfm)

    5 - x

    4 - выбор магнитной головки (0 - верх, 1 - низ)

    3 - загрузка головки (всегда должен быть в 1)

    2 - аппаратный сброс микроконтроллера (если 0)

    1 - номер дисковода (00 - a, 01 - b, 10 - c, 11 - d)

    0 - -/-

    Порты TR-DOS доступны только тогда, когда включено ПЗУ TR-DOS! Включить ПЗУ TR-DOS можно через специальные точки входа.


    Точки входа


    Аппаратное включение дискового интерфейса происходит в момент выполнения какой-либо команды, записаной по адресу в диапазоне #3d00 - #3dff. Проще говоря, чтобы попасть в ПЗУ TR-DOS нужно запомнить на стеке адрес подпрограммы в ПЗУ TR-DOS, куда вы хотите передать управление и выполнить команду RET, расположенную в этом диапазоне. Либо, если адрес подпрограммы лежит непосредственно в пределах #3d00 - #3dff, можно просто передать на нее управление, например, обычным CALL NN.

    Чаще всего в качестве точки входа используют две:

    самая распространенная точка входа:


     #3d2f nop
           ret

    Редко используемая точка входа (не «переваривается» некоторыми отечественными версиями интерфейса: GRM Pentagon и т.п.):


    #3d30 ret

    Но если хорошенько «покопаться» в ПЗУ TR-DOS, то можно найти еще несколько (недокументированных): #3d2c, #3d4b, #3d7f, #3d93, #3d96, #3d97, #3dac. По всем этим адресам находится команда ret, за исключением точки 3.


    Недокументированная точка входа и кроме меня никем неиспользуемая:


    #3d96 nop
          ret

    По идее, возможно использование любого адреса в качестве точки входа из выше перечисленных, но гарантию работоспособности на всяких «левых» интерфейсах я не даю! Поэтому я настоятельно рекомендую использовать либо первую, либо третью точку входа.

    Используя эти точки входа можно добраться до подпрограмм расположенных в ПЗУ TR-DOS.


    Подпрограммы


    С помощью обрывок подпрограмм TR-DOS можно писать свои собственные процедуры работы с диском. Для начала приведу адреса доступа к портам ввода данных:


    #2fc3 out (#1f),a ;регистр команд
          ret
    .....
    #1e3a out (#3f),a ; регистр дорожки
          ret
    .....
    #1ff3 out (#ff),a ; системный регистр
          ret
    .....
    #2f0c out (#ff),a ; системный регистр
          ret         ; (практически не используется)
    .....
    #2a53 out (c),a   ; универсальный адрес
          ret

    Тот же самый эффект можно получить воспользовавшись процедурой по адресу #20b8:


    #20b8 out (c),d
          djnz #20b1
          ret

    Или процедурой по адресу #3fd1:


    #3fca in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#3fca    ; для drq условие заведомо не выполнится
          ret m         ; выход по intrq
    #3fd1 outi          ; запись байта
          jr #3fca

    Как видите с вводом данных все просто и понятно, чего не скажешь об их получении. К сожалению в ПЗУ TR-DOS не предусмотрено такой возможности. Я не говорю о том, чтобы была такая же возможность считывать состояние каждого регистра в отдельности. В принципе, хватило бы одной простой команды типа in a,(c), но т.к. таковой нет, приходится прибегать к различного рода ухищрениям:

    Так, например, чтобы прочитать значения регистров можно воспользоваться следующей процедурой по адресу #3ef3:


    #3ef3 in h,(c)
    #3ef5 in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#3ef5    ; для drq условие заведомо не выполняется
          ei            ; !
          ret m         ; выход по intrq

    На выходе в H будет значение состояния нужного вам регистра. Единственный недостаток в том, что на выходе разрешаются прерывания, что в некоторых случаях совсем не нужно.

    Можно воспользоваться другой процедурой по адресу #3fec:


    #3fe5 in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#3fe5    ; для drq условие заведомо не выполняется
          ret m         ; выход по intrq
    #3fec ini           ; чтение байта
          jr #3fe5

    На выходе в (HL) будет значение состояния нужного вам регистра.

    Таким образом можно считать состояние всех регистров кроме регистра состояния #1f, т.к. произойдет зацикливание при чтении #ff. Поэтому чтобы все же заполучить значение регистра состояния, нужно выполнить следующие действия:


    ;(c) Andrew MOA Larchenko
    in_1f out (#3f),0
          out (#5f),#a
          ld d,#01
          jp #3f33

    На выходе в B будет находиться значение регистра состояний #1f, т.е. таким способом мы проэмулировали команду in b,(#1f). Однако при выполнении данной процедуры были запорчены регистры дорожки и сектора, поэтому, при необходимости, следует восстановить в них исходные значения.


    Команды


    Прежде чем перейти непосредственно к командам, необходимо сказать, что выполнение каждой последующей команды возможно только тогда, когда завершена предыдущая, т.е. поступит сигнал intrq. Отследить этот сигнал можно воспользовавшись процедурой:


    #3fe5 in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#3fe5    ; для drq условие заведомо не выполнится
          ret m         ; выход по intrq

    Или любой другой аналогичной процедурой по другим адресам...

    Также надо отметить, что выбор дисковода и др. для выполнения команд осуществляется с помощью инструкции out (#ff),a (см. раздел порты).

    Микроконтроллер может выполнять 11 команд:


    1. Восстановление               - %0000hvrr - +
    2. Поиск/Позиционирование       - %0001hvrr |
    3. Шаг в предыдущем направлении - %001thvrr + - 
    4. Шаг вперед                   - %010thvrr |
    5. Шаг назад                    - %011thvrr - +
    6. Чтение сектора               - %100mseca
    7. Запись сектора               - %101msec0
    8. Чтение адреса                - %11000e00
    9. Чтение дорожки               - %11100e00
    10. Запись дорожки/форматир-е   - %11110e00
    11. Принудительное прерывание   - %1101iiii

    где rr - скорость позиционирования головки: 00 - 6мс, 01 - 12мс, 10 - 20мс, 11 - 30мс (1Mhz).

    v - проверка номера дорожки после позиционирования.

    h - загрузка головки (всегда должен быть в 1!).

    t - изменение номера дорожки в регистре дорожки после каждого шага.

    a - тип адресной метки (0 - #fb, стирание сектора запрещено 1 - #F8, стирание сектора разрешено).

    c - проверка номера стороны диска при идентификации индексной области.

    e - задержка после загрузки головки на 30мс (1Mhz).

    s - сторона диска (0 - верх/1 - низ).

    m - мультисекторная операция.

    i - условие прерывания:

    i0 - после перехода сигнала cprdy из 0 в 1 (готов);

    i1 - после перехода сигнала cprdy из 1 в 0 (не готов);

    i2 - при поступлении индексного импульса;

    i3 - немедленное прерывание команды, при:

    i=0 - intrq не выдается

    i=1 - intrq выдается.

    Восстановление - осуществляет позиционирование головки на дорожку 0. Если через 256 импульсов сигнал tr00 не появится, то команда прекращает работу. Выполняется независимо от готовности дисковода.


    to_tr0 out (#1f),#8 ; %00001000

    Поиск/позиционирование - перемещает головку на нужный трек. Перемещение происходит до тех пор, пока не совпадут номера физической дорожки в #3f и логической дорожки в #7f. Номер трека указывается без учета стороны (/2)!


    jump out (#7f),trk/2 ; номер нужного трека/2
         out (#1f),#18   ; %00011000
         jp #3fe5         ; ожидание выполнения команды

    Шаг (пункт 3) - двигает головку на один шаг в предыдущем направлении.


    step out (#1f),#38 ;%00111000
         jp #3fe5      ; ожидание выполнения команды

    Шаг вперед - двигает головку на один шаг вперед.


    step_f out (#1f),#58 ; %01011000
           jp #3fe5      ; ожидание выполнения команды

    Шаг назад - двигает головку на один шаг назад.


    step_b out (#1f),#78 ; %01111000
           jp #3fe5      ; ожидание выполнения команды

    Чтение сектора - чтение сектора с текущей дорожки. При мультисекторной операции читаются все сектора с заданного до конца трека.


    load_s out (#5f),sec ; номер считанного сектора (нумерация с 1)
           out (#1f),#80 ; %10000000
           ld hl,address ; адрес загрузки
           ld c,#7f
           jp #3fe5      ; чтение сектора

    Запись сектора - запись сектора на текущую дорожку. При мультисекторной операции записываются все сектора с заданного до конца трека.


    save_s out (#5f),sec ; номер записываемого сектора (нумерация с 1)
           out (#1f),#a0 ; %10100000
           ld hl,address ; адрес записи
           ld c,#7f
           jp #3fca      ; запись сектора

    Чтение адреса - считывает 6 байтов идентификатора сектора, включая crc (контрольная сумма).


    l_addr ld hl,buffer  ; адрес загрузки идентификатора
           out (#1f),#c0 ; %11000000
           jp #3fe5      ; чтение идентификатора сектора

    На выходе в (HL) по смещению:

    +0 - номер трека (0 - 128)

    +1 - номер стороны (0-верх, 1-низ)

    +2 - номер сектора (0 - 128)

    +3 - длина сектора (0-128b, 1-256b, 2-512b, 3-1024b)

    +4 - контрольная сумма (?)

    +5 - -/-

    Чтение дорожки - считывает всю дорожку целиком. Синхронизация отсутствует (crc не проверяются), т.е. нельзя отследить правильность считанной информации.


    load_t ld hl,address ; адрес загрузки трека
           out (#1f),#e0 ; %11100000
           jp #3fe5      ; чтение трека (>6Kb)

    Запись дорожки/форматирование - форматирование дорожки.


    format ld hl,address ; адрес расположения данных дорожки
           out (#1f),#f0 ; %11110000

    Принудительное прерывание - завершение выполняемой на данный момент команды. В отличие от других команд она может выдаваться в любой момент.


    inter out (#1f),i ; %1101iiii (значение i см. выше)

    Вот еще две подпрограммки из ПЗУ TR-DOS.



    #20af ld b,#01
    #20b1 in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#20b1
          ret m         ; выход если intrq
    #20b8 out (c),d     ; запись байта если drq
          djnz #20b1    ; повтор пока b<>0
          ret

    #3ef3 in h,(c)
    #3ef5 in a,(#ff)    ; ожидание intrq или drq
          and %11000000 ; bit7 - intrq/bit6 - drq
          jr z,#3ef5
          ei            ; !
          ret m         ; выход если intrq
    #3efd di            ; !
    #3efe in a,(#7f)    ; чтение байта если drq
          jr #3ef5      ; повтор пока не поступит intrq

    Вот, собственно и все.

    Адрес для связи: Юдин Александр Владимирович (faster), 432044, г. Ульяновск, ул. Героев Свири 16а-24.

    © 2004-2013 Perspective group