ZX-News #54
30 декабря 2000

ZX Spectrum и винчестер — статья Влада Сотникова/Vega о работе и программировании жесткого диска (HDD) на Спектруме.

<b>ZX Spectrum и винчестер</b> — статья Влада Сотникова/Vega о работе и программировании жесткого диска (HDD) на Спектруме.
╔═───────────────════════───────────────═╗
│              Старина  Z80              │
╚═──────────══════════════════──────────═╝

   С удовольствием представляем  капиталь-
ную статью Влада Сотникова/Vega (Санкт-Пе-
тербург) о таком явлении, как винчестер на
Спектруме. Тема эта освещена со всех  сто-
рон, т. к. автор - лучший в Питере специа-
лист (если не  считать MOA :) ) по  всему,
что касается SMUC'а, то  бишь  устройства,
позволяющего работать с "прибамбасами"  во
благо Speccy!

   Сейчас Влад работает над вопросом  под-
ключения к Спектруму  CD-ROM, хотя  о  чем
это  мы! Он  же  уже  подключен! Но  чтобы
CD-ROM заработал полноценно, требуется сл.
информация: список команд ATAPI и их  опи-
сание, драйвер CD-ROM'а (на любом  челове-
ческом или машинном языке), а также непло-
хо бы получить документацию по _не_  ATAPI
CD-ROM'ам - принципы их работы, команды.

   Информацию ждут по таким адресам:

   ZXNet: Vlad Sotnikov (500:812/08.9)
    Fido: Vlad Sotnikov (2:5030/885.50)

   Если у вас нет доступа к этим сетям, то
пишите на  адреса  редакции, мы  передадим
все Владу. 
__________________________________________

(C) Влад Сотников/Vega, 2000

        -= Spectrum и винчестер =-

   1. Работа с винчестером на Spectrum'е.
   1.1. Введение.
   1.2. Обращение к винчестеру.
   1.3. Устройство винчестера.
   1.4. Терминология.
   1.5. Обращение к регистрам  на  Scorpi-
on'e.
   1.6. Описание регистров.
   1.7. Чтение данных с винчестера.
   1.8. Позиционирование головок.
   1.9. Запись данных на винчестер.
   1.10. Описание команд винчестера.
   1.11. Определение конфигурации  винчес-
тера.

   2. Структура винчестера на Scorpion.
   2.1. Файловая структура винчестера.
   2.2. Структура описания подразделов.
   2.3. Внутренняя структура подразделов.
   2.4. Как запустить Is-Dos.
   2.5. Структура подраздела TR-DOS.
   2.6. Структура сектора эмуляций.
   2.7. Расчет контрольной суммы.


  1. Работа с винчестером на Spectrum'е

   Все, что  здесь  написано, основано  на
моем личном  опыте, и  поэтому  практичес-
ки вся информация  является  эксклюзивной.
Вследствие этого в описании  могут  встре-
титься неточности или недоработки, за  что
заранее извиняюсь.


              1.1. Введение

   Данная  статья  посвящена  программиро-
ванию  жесткого  диска, называемого  также
"винчестер", на  компьютере  Scorpion.  На
самом деле, если у вас винчестер подключен
через другой контроллер, то  нужно  просто
знать адреса портов вашего  контроллера, и
вы с помощью этой статьи сможете научиться
его программировать.

   Винчестер - это неотъемлемая составляю-
щая любого компьютера, особенно в  настоя-
щее время, когда размер информации в  сот-
ни, а то и в тысячи раз превышает  размеры
оперативной памяти компьютеров. Такие  но-
сители информации, как гибкие диски, теря-
ют свою актуальность. Но, несмотря на это,
Спектрум долгое время обходился  без  вин-
честера, и появился он  только  недавно. К
сожалению, адаптация винчестера к  системе
TR-DOS не позволяет  использовать  большую
часть его  возможностей  и  поэтому, рабо-
тая с ним напрямую, через порты, можно  не
только в несколько раз увеличить  скорость
работы с жестким диском, но  и  превратить
его в аналог оперативной памяти  компьюте-
ра, как, собственно, и  сделано  на  таком
компьютере, как PC.


       1.2. Обращение к винчестеру

   Итак,  к  винчестеру  можно  обращаться
двояко. Первый вариант -  обращение  через
драйвер. На PC это такая программка, кото-
рая позволяет видеть винчестер  как  склад
для размещения файлов в системе MS-DOS. На
Спектруме таким  драйвером  можно  назвать
ПрофПЗУ 4.01, которое представляет винчес-
тер как набор образов TR-DOS дискет. Образ
подключается к диску A, B, C или  D  через
теневой монитор, и далее программа работа-
ет с одним из этих носителей, не  подозре-
вая, что вместо гибкого диска она общается
с винчестером. Такой подход имеет  некото-
рые недостатки. В частности, поддерживает-
ся только обращение к  TR-DOS  через  под-
грограмму  #3D13 (естественно!), а  всяче-
ские обращения типа #3D2F приводят к тому,
что программа на TR-DOS образе  винчестера
не может работать. Но речь не об этом.

   Кроме контакта через #3D13 теневой  мо-
нитор предлагает обращение к жесткому дис-
ку через команду RST 8. Я не буду ее здесь
описывать, принципы ее работы можно  найти
в книге "SMUC, инструкция  по  подключению
и работе, v1.2". Но второй  вариант  всего
лишь увеличивает скорость чтения и  записи
данных, и поэтому полноценным быть  назван
не может.


        1.3. Устройство винчестера

   Винчестер  -  это  устройство,  имеющее
внутренний контроллер чтения, записи и об-
работки информации. Таким образом, компью-
теру нет необходимости раскручивать диск и
выполнять подобные процедуры - их берет на
себя контроллер. Собственно программирова-
ние жесткого диска - это передача ему  ко-
манд, а также передача/прием от  него  ин-
формации.

   Винчестер  имеет  следующую  логическую
внутреннюю  структуру: на  нем  существует
некоторое количество  цилиндров. В  каждом
цилиндре имеется  определенное  количество
головок. И каждая головка имеет некое  ко-
личество  секторов. Если  перемножить  все
эти значения, то получим общее  количество
секторов (по 512 байт) на  жестком  диске.
Разделив это число  на  2, мы  узнаем  его
объем.

   Само собой  разумеется, что  логическая
структура винчестера не имеет ничего обще-
го с его реальными физическими  параметра-
ми. То есть 16 головок  вовсе  не  значит,
что их в винчестере действительно 16. Обы-
чно физических головок  3-4, а  количество
секторов на  каждой  дорожке  варьируется,
как и на компакт-диске. Тем не  менее, об-
щаться с жестким диском  необходимо  через
его логические  параметры, за  исключением
случая, когда адресация задается в  режиме
LBA (Logical  Block  Addressing), то  есть
винчестеру вместо цилиндра/головки/сектора
сразу указывается относительный  адрес. Но
режим LBA здесь мною описан не  будет, по-
скольку я  не  знаю  точно  регистры, куда
этот 28-разрядный адрес записывается.

   Эти регистры вы можете подобрать  сами.
Насколько я помню, вот  они: регистры  ци-
линдра  (оба), регистр  секторов,  регистр
накопителя/головки и регистр  возможностей
(то же, что и регистр  ошибок, только  при
записи). Сами регистры будут подробно опи-
саны ниже.


            1.4. Терминология

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

   ■ Логический адрес: состоит из 3-х зна-
чений: номера цилиндра, номера  головки  и
номера сектора.

   ■ Относительный адрес: 4-байтный  адрес
относительно н начала  винчестера. Использу-
ется в LBA режиме. В режиме логической ад-
ресации преобразуется в  логический  адрес
подпрограммой SET_. На  Спектруме  в  пре-
делах  1.9  Гигабайт  используются  только
3 байта.

   ■ Сектор: на винчестере  он  равен  512
байтам. Поэтому под любым сектором, упоми-
наемым мною в этой статье, необходимо  по-
нимать 512 байт.


 1.5. Обращение к регистрам на Scorpion'e

   Управление контроллером происходит  по-
средством  регистров. Каждому  регистру  в
контроллере  SMUC  соответствует  порт. Он
будет указываться рядом с названием регис-
тра. К сожалению, обращение к этим  портам
в компьютере Scorpion должно происходить с
включенным ПЗУ TR-DOS. Поэтому запись зна-
чения в порт будет выглядеть следующим об-
разом:

;OUT register A.
;in: [BC] - номер порта
;    [A]  - значение, записываемое в порт.
OUT_A   LD IX,#3FF0
        PUSH IX
        JP #3D2F

   Дело в том, что при  обращении  к  этой
области  памяти  автоматически   включает-
ся  ПЗУ  TR-DOS  и   выполняется   команда
OUT (C),A.

   Соответственно, чтение:

;IN register A.
;in : [BC] - номер порта.
;out: [A]  - значение, считанное из порта.
IN_A    LD IX,#3FF3
        PUSH IX
        JP #3D2F

   Здесь то же  самое, только  выполняется
команда IN A,(C).

   В последующих примерах мы  будем  обра-
щаться к этим подпрограммам. Зная их, мож-
но производить чтение  и  запись  в  порты
(регистры) винчестера. Ниже приводится по-
лное описание  регистров. Обратите  внима-
ние, что младшее значение регистра  всегда
равно #BE. Это можно использовать при  оп-
тимизации  кода  для  увеличения  скорости
программы.


         1.6. Описание регистров

          Регистр Команд (#FFBE)

   Регистр только для записи. Этот регистр
содержит код команды, посылаемой винчесте-
ру. Выполнение  команды  начинается  сразу
после записи этого  регистра. Так, извест-
но, что команда #E6 останавливает  жесткий
диск. Пишем:

        LD A,#E6
        LD BC,#FFBE
        CALL OUT_A
        RET

   Ваш винчестер должен остановиться.

        Регистр Состояния (#FFBE)

   Этот регистр содержит состояние накопи-
теля. Содержимое этого регистра обновляет-
ся после завершения каждой  команды. Соот-
ветственно, биты этого регистра:

      7   6    5   4   3   2    1   0
    ┌───┬────┬───┬───┬───┬────┬───┬───┐
    │BSY│DRDY│DWF│DSC│DRQ│CORR│IDX│ERR│
    └───┴────┴───┴───┴───┴────┴───┴───┘

   - BSY (Занято). Этот бит устанавливает-
ся сразу после передачи команды винчестеру
и сбрасывается только после  того, как  он
эту команду выполнит. То есть  установлен-
ный бит сигнализирует о  том, что  жесткий
диск выполняет команду и вас не "слышит".

   -  DRDY  (Готовность  Накопителя). Этот
бит установлен в том случае, если  винчес-
тер готов принять команду.

   - DWF (Запрет Записи на Диск). Бит ука-
зывает  текущее  состояние  запрета  запи-
си (?).

   - DSC (Установка Дисковода  Завершена).
Бит указывает, что головки  дисковода  ус-
тановлены на дорожку.

   - DRQ (Запрос  Данных). Бит  указывает,
что дисковод готов к  передаче  слова  или
байта данных между ЭВМ и накопителем.

   - CORR (Исправленные Данные). Бит  ука-
зывает, что при  чтении  данных  произошла
коррекция и данные были исправлены.

   - IDX (Индекс). Бит устанавливается при
каждом обороте диска.

   - ERR  (Ошибка). Бит  указывает, что  в
течение выполнения предыдущей команды про-
изошла  ошибка. Дополнительная  информация
относительно причины ошибки  содержится  в
Регистре Ошибки.

   Самыми существенными для  нас  являются
биты BSY, DRQ и ERR. При подаче команды на
винчестер необходима следующая  последова-
тельность действий:

   1. Подается команда (через Регистр  Ко-
манд).
   2. Ждем снятия сигнала BSY.
   3. Смотрим бит  ERR. Если  он  установ-
лен - читаем Регистр ошибок и обрабатываем
ошибку.

   Напишем подпрограмму, которая будет ож-
идать сброса сигнала BSY:

NO_BSY  LD BC,#FFBE
        CALL IN_A
        RLCA
        RET NC
        JR NO_BSY

   Мы крутимся в цикле  до  тех  пор, пока
сигнал BSY не будет  снят. Каждая  команда
должна завершаться обращением к этой  под-
программе.

   Подпрограмма проверки ошибки:

ERR_    LD BC,#FFBE
        CALL IN_A
        RRCA
        RET

   Если на выходе установлен флаг  перено-
са, то команда была выполнена с ошибкой.

   И наш предыдущий  пример, останавливаю-
щий винчестер, будет  выглядеть  следующим
образом:

      LD A,#E6
      LD BC,#FFBE
      CALL OUT_A
      CALL NO_BSY
      CALL ERR_
      JP C,ERROR...
      RET

   Итак, теперь  известно, как  полноценно
послать команду на винчестер. Ниже я  при-
вожу подпрограмму, которая это делает.

;HDd Send Command.
;IN : [A] - код команды.
;OUT: CY  - Операция выполнена с ошибкой.
HDSC  LD BC,#FFBE
      CALL OUT_A  ;послали команду.
      CALL NO_BSY ;ждем выполнения.
      JP ERR_     ;смотрим, нет ли ошибок.


   Следующие регистры указывают номера ци-
линдра, головки и сектора, с которыми про-
исходит операция. Так, при чтении этих ре-
гистров мы узнаем место, где находится го-
ловка. При записи в  эти  регистры  других
значений головка не меняет своего  положе-
ния, но при выполнении команды  чтения/за-
писи она позиционируется в соответствии со
значениями, заданными в этих регистрах.

 Регистр Цилиндра (старшая часть) (#FDBE)

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

 Регистр Цилиндра (младшая часть) (#FCBE)

   Этот регистр содержит младшие 8 бит на-
чального номера цилиндра  для  любой  дис-
ковой операции. После  выполнения  команды
этот регистр модифицируется, и всегда  от-
ражает текущий номер цилиндра.

      Регистр Номера Сектора (#FBBE)

   Этот регистр содержит  начальный  номер
сектора для любой операции с  данными. Но-
мер сектора может быть от 1 до  максималь-
ного числа секторов на дорожку.

    Регистр Накопителя/Головки (#FEBE)

   Этот регистр содержит номер  головки  и
накопителя. Содержимое этого регистра  за-
дает номер накопителя и номер головки  при
выполнении команды  Initialize  Drive  Pa-
rameters.

       7   6   5   4   3   2   1   0
     ┌───┬───┬───┬───┬───┬───┬───┬───┐
     │ 1 │LBA│ 1 │DRV│HS3│HS2│HS1│HS0│
     └───┴───┴───┴───┴───┴───┴───┴───┘

   - DRV  -  бит  выбора  накопителя. Если
DRV=0, то выбран накопитель 0, если DRV=1,
то выбран накопитель 1.

   - LBA - бит указывает, включен или вык-
лючен режим LBA.

   - HS3...HS0 содержат двоичный код номе-
ра головки (начиная с нуля), которая будет
выбрана. Например,  если  HS3...HS0=%0011,
то будет выбрана головка 3. HS3 -  старший
бит. После завершения команды этот регистр
модифицируется и всегда  содержит  текущий
номер выбранной головки.

   Четвертый бит очень интересный. Он  за-
дает  устройство  slave\master, с  которым
должен  работать  компьютер. Так, если  мы
хотим с основного винчестера  переключить-
ся на второй, параллельно подключенный, то
нам необходимо лишь установить этот бит  и
записать число в регистр. И все  последую-
щие команды будут работать с выбранным ус-
тройством.

    Регистр Счетчика Секторов (#FABE)

   Этот регистр содержит число  передавае-
мых секторов данных при операциях  чтения/
записи. Значение  ноль  соответствует  256
секторам.

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

          Регистр Ошибки (#F9BE)

   Этот регистр содержит состояние накопи-
теля после  выполнения  последней  команды
или Диагностический Код.

   После завершения любой команды, за  ис-
ключением Execute  Drive  Diagnostic, этот
регистр содержит код ошибки, если бит  ERR
в Регистре Состояния установлен (ERR=1).

    7   6   5   4    3   2    1     0
  ┌───┬───┬───┬────┬───┬────┬─────┬────┐
  │BBK│UNC│ 0 │IDNF│ 0 │ABRT│TK0NF│AMNF│
  └───┴───┴───┴────┴───┴────┴─────┴────┘

   - BBK (Встречен Плохой Блок). Бит  ука-
зывает, что при  выполнении  операции  был
встречен сектор с неправильной меткой бло-
ка в заголовке сектора.

   - UNC (Неисправимая Ошибка  в  данных).
Бит указывает, что в  ходе  операции  была
встречена неисправимая ошибка в зоне  дан-
ных.

   - IDNF (Сектор не  найден). Бит  указы-
вает, что заголовок указанного сектора  не
найден.

   - ABRT (Прерванная  команда). Бит  ука-
зывает, что  выполнение  заданной  команды
было прервано из-за ошибки состояния  вин-
честера (Не готов, Запрет записи, и т. д.)
или при недопустимом коде команды.

   - TK0NF  (Дорожка  0  не  найдена). Бит
указывает, что при выполнении команды  Re-
calibrate дорожка 0 не найдена.

   - AMNF (Не найден адресный маркер). Бит
указывает, что адресный маркер  не  найден
после нахождения правильного заголовка се-
ктора.

   - Неиспользуемые биты очищаются.

   Регистр данных (Старшая часть) (#D8BE),
Регистр данных (Младшая часть) (#F8BE).


     1.7. Чтение данных с винчестера

   Через Регистр данных осуществляется об-
мен данными между компьютером и  винчесте-
ром. Так, если мы хотим считать  сектор  с
жесткого диска, то мы даем  команду  "чте-
ние". Далее  винчестер  читает  один  512-
байтный сектор в свой буфер и  ждет. Потом
мы читаем младшую часть сектора, кладём  в
память. Затем старшую. И так 256  раз. По-
лучается  512  байт. Интересно, что  между
чтением байт может быть сколь угодно  дол-
гая пауза - винчестер знает, сколько  байт
мы взяли. Затем мы читаем значение Регист-
ра счетчика секторов. Если число не  0, то
повторяем цикл заново. Таким образом  про-
исходит чтение секторов с винчестера. Ниже
приводится эта подпрограмма. В  HL  должно
быть указано место в памяти, куда  читать,
в A - количество 512-байтных секторов.

;читаем сектора, заданные <HDSC>.
;IN: HL-buffer for reading, A-SECTORS
READ    LD B,A
        PUSH BC
        LD BC,#FABE
        CALL OUT_A
        LD (BUF),HL
        LD A,#20
        CALL HDSC;команда читать...
        POP BC
READ1   PUSH BC
        CALL READ_S;читаем сектор
        POP BC
        DJNZ READ1
        RET

;READ Sector.
;читаем сектор...
READ_S  LD HL,(BUF)
        LD BC,#00BE
        LD DE,#D8F8
READ_1  PUSH BC
        LD B,E
        CALL IN_A
        LD (HL),A
        INC HL
        LD B,D
        CALL IN_A
        LD (HL),A
        INC HL
        POP BC
        DJNZ READ_1
        LD (BUF),HL
        RET

BUF     DS 2; Временная переменная для
             хранения адреса в памяти
             для чтения/записи.


      1.8. Позиционирование головок

   Я думаю, вы не забыли, что перед  вызо-
вом команды READ необходимо  указать  вин-
честеру  место, откуда  читать. Это  можно
сделать следующей подпрограммой:

;Write Cylinder, Head, Sector.
;Записать в регистры номера цилиндра/
;головки/сектора.
;IN: DE-цилиндр, H-головка, L-сектор.
W_CHS   LD BC,#FEBE
        LD A,#A0   ;#B0 - slave.
        XOR H
        CALL OUT_A
        DEC B
        LD A,D
        CALL OUT_A
        DEC B
        LD A,E
        CALL OUT_A
        DEC B
        LD A,L
        JP OUT_A

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

;Read Cylinder, Head, Sector.
;Считать текущие цилиндр/головку/сектор.
;OUT: DE-цилиндр, H-головка, L-сектор.
R_CHS   LD BC,#FEBE
        CALL IN_A
        AND #0F
        LD H,A
        DEC B
        CALL IN_A
        LD D,A
        DEC B
        CALL IN_A
        LD E,A
        DEC B
        CALL IN_A
        LD L,A
        RET

   Если же вам нужно  указать  относитель-
ный адрес, то воспользуйтесь подпрограммой
SET_. Для ее  работы  необходимо, чтобы  в
ячейке SECTOR находилось количество секто-
ров на винчестере, а  в  ячейке  SH_SUM  -
произведение головок и секторов.

;установить головку по D,H,L.
;АДРЕС СМЕЩЕНИЯ - CIL/HED/SEC
;IN : D,H,L - 24-разрядный адрес.
;OUT: заданная установка головки.
SET_    LD (SET_3+1),HL
        LD HL,0,E,H
        LD A,D
        OR A
        JR Z,SET_1
        LD D,L
SET_2   PUSH HL
        PUSH DE
        LD HL,#FFFF
        LD DE,(SH_SUM)
        PUSH AF
        CALL DIV
        POP AF,DE
        INC HL
        ADD HL,DE
        EX DE,HL
        POP HL
        ADD HL,BC
        DEC A
        JR NZ,SET_2
SET_1   PUSH HL,DE
SET_3   LD HL,#2121
        LD DE,(SH_SUM)
        CALL DIV
        POP DE
        ADD HL,DE
        EX DE,HL
        POP HL
        ADD HL,BC
        PUSH HL
        EX DE,HL
        LD DE,(SH_SUM)
        CALL DIV
        EX DE,HL
        POP HL
        ADD HL,BC
        PUSH HL
        EX DE,HL
        LD A,(SECTOR)
        LD D,0,E,A
        CALL DIV
        LD H,C
        INC L
        POP DE
        CALL W_CHS
        RET

;Деление. <<BC=HL/DE, HL-остаток.>>
DIV     LD A,E
        OR D
        RET Z
        XOR A
        LD C,A,B,A
        EX DE,HL
DIVW1   INC B
        BIT 7,H
        JR NZ,DIVW2
        ADD HL,HL
        JR DIVW1
DIVW2   EX DE,HL
DIVW3   OR A
        SBC HL,DE
        JR NC,DIVW4
        ADD HL,DE
DIVW4   CCF
        RL C,A
        RR D,E
        DJNZ DIVW3
        LD B,A
        RET

SH_SUM  DB головки * сектора.
SECTOR  DB количество секторов.


     1.9. Запись данных на винчестер

   Чтобы записать информацию на винчестер,
необходимо установить  головку  с  помощью
подпрограммы W_CHS или  SET_  и  выполнить
следующую подпрограмму:

;Пишем сектора, заданные <HDSC>.
;IN: HL-buffer for writing, A-SECTORS
WRITE   LD B,A
        PUSH BC
        LD BC,#FABE
        CALL OUT_A
        LD (BUF),HL
        LD A,#30
        CALL HDSC; команда писать...
        POP BC
WRITE1  PUSH BC
        CALL WRITE_S
        POP BC
        DJNZ WRITE1
        RET

;WRITE Sector.
;пишем сектор...
WRITE_S LD HL,(BUF)
        LD BC,#00BE
        LD DE,#D8F8
WRITE_1 PUSH BC
        LD B,D
        INC HL
        LD A,(HL)
        CALL OUT_A
        LD B,E
        DEC HL
        LD A,(HL)
        CALL OUT_A
        INC HL
        INC HL
        POP BC
        DJNZ WRITE_1
        LD (BUF),HL
        RET


     1.10. Описание команд винчестера

   Ниже я приведу список  команд, актуаль-
ных при работе с винчестером на Спектруме.

            Identify Drive (#EC)
       (Идентифицировать накопитель)

   После команды необходимо дождаться  ус-
тановки сигнала DRQ и  выполнить  подпрог-
рамму  READ_S,  предварительно  записав  в
ячейку (BUF) адрес в  памяти, куда  считы-
вать информацию о винчестере. Вот наиболее
важные значения:

   +2  - количество цилиндров (2 байта);
   +6  - количество головок (2 байта);
   +12 - количество секторов (2 байта);
   +20 - серийный номер (20 символов);
   +40 - тип буфера винчестера (2 байта);
   +42 - размер буфера в секторах (2  бай-
         та);
   +46 - версия прошивки (8 символов);
   +54 - название модели (40 символов).

   Указанные здесь количества головок, се-
кторов и цилиндров в  большинстве  случаев
оказываются ложными. Кроме того, вся текс-
товая информация имеет нестандартный  фор-
мат. Сначала идет старший байт, затем мла-
дший. Для приведения  ее  в  удобочитаемый
вид нужно поменять первый байт со  вторым,
третий с четвертым и т.д.

   Весь текст выровнен по  левому  краю  и
дополнен пробелами. В случае, если  первый
байт текста - 0, то название не  определе-
но.

   Тип буфера винчестера:

    0 - не определено.

    1 - одиночная  буферизация,  винчестер
не может производить одновременные  опера-
ции чтения и записи.

    2 - двойная буферизация. Винчестер мо-
жет одновременно  считывать  и  записывать
информацию.

    3 - двойная  буферизация,  кроме  того
чтение осуществляется с кэшированием.

   Ячейка размера буфера показывает, какой
объем имеет внутренний  буфер  винчестера.
Чем больше объем буфера, тем выше скорость
обмена данными между винчестером и компью-
тером.

        Idle (#97, #E3, #95, #E1)
       (Переход в пассивный режим)

   Происходит остановка винчестера до  вы-
полнения следующей команды.

            Recalibrate  (#1x)
             (Перекалибровка)

   Эта команда перемещает головки  чтения/
записи с любого места диска на цилиндр  0.
Если дисковод не может установить  головку
на  нулевой  цилиндр, генерируется  ошибка
"Дорожка Не Найдена" (Track Not Found).

           Read Sector(s) (#20)
           (Чтение сектора(ов))

          Write  Sector(s) (#30)
           (Запись сектора(ов))

   Работа команд описана выше.

             Sleep (#99, #E6)
               (Остановка)

   Винчестер  полностью   останавливается.
Единственным способом вывести жесткий диск
из режима Остановка без выключения питания
и аппаратного сброса является  программный
сброс.

        Standby (#96, #E2, #94, #E0)
             (Дежурный режим)

   Эта команда переводит винчестер в Дежу-
рный режим. Если Диск  уже  остановлен, то
последовательность остановки диска не  вы-
полняется.


 1.11. Определение конфигурации винчестера

   Также я хочу рассказать о том, как  мне
удалось написать  подпрограмму, определяю-
щую истинную логическую геометрию  винчес-
тера.

   Общеизвестно, и я здесь об этом  писал,
что логическую  геометрию  жесткого  диска
можно  прочитать  из  сектора, вызываемого
командой Identify Drive, и именно так пос-
тупает Теневой Монитор опцией Auto  Detect
Hard Disk. Но в 25% случаев эта информация
оказывается неверной.

   Как же узнать реальные значения  цилин-
дров/головок/секторов  своего  винчестера?
Ведь полагаться на слова продавца, у кото-
рого вы сей винчестер покупаете, очень не-
надежно.

   Моя же идея очень  проста: допустим, вы
даете жесткому диску  команду  читать  256
секторов. Считываете один сектор (подпрог-
раммой READ_S). Теперь в регистрах цилинд-
ра/головки/секторов записаны значения сле-
дующего по порядку относительного сектора.
То есть номер  сектора  увеличился  на  1.
Считываем следующий сектор. И  как  только
сектор принял значение 1 и увеличился  но-
мер  головки, значит, предыдущее  значение
сектора и есть количество секторов на вин-
честере. То же самое с  головками  (ждать,
пока головка не примет  значение  0  и  не
увеличится  номер  сектора). С  цилиндрами
посложнее, но, с другой стороны, если  ра-
ботать в пределах  существующих  подразде-
лов, знать максимальное количество цилинд-
ров вовсе не обязательно - за пределы вин-
честера вы не выйдите. Тем не менее, опре-
делить количество цилиндров можно - напри-
мер, читая 0 головку и  1  сектор  каждого
цилиндра, пока  не  произойдёт  ошибка, то
есть пока сектор будет не найден.

   Приведенная здесь  программа  автомати-
чески определит количество головок и  сек-
торов  на  винчестере. Метка  TABL  должна
указывать на 512-байтный буфер.

;Автоконфигурация винта.
;OUT: [H] - HEADS.
;     [L] - SECTORS.
A_CONF  LD DE,0
        LD H,D
        LD L,E
        CALL W_CHS
        LD A,#EC
        CALL HDSC
        LD BC,#FFBE
        CALL IN_A
        OR A
        RET Z       ;устройства нет
        CALL R_CHS
        OR A
        LD HL,#EB14
        SBC HL,DE
        RET Z       ;это CD-ROM
        CALL NO_BSY
        LD DE,0
        LD HL,#0002
        CALL W_CHS
        LD A,65
        LD BC,#FABE
        CALL OUT_A
        LD A,#20
        CALL HDSC
        CALL NO_BSY
        LD BC,#FBBE
A_CONF2 PUSH BC
        CALL IN_A
        LD D,A
        PUSH DE
        LD BC,#FFBE
A_CONF3 CALL IN_A
        BIT 3,A
        JR Z,A_CONF3
        LD HL,TABL
        LD (BUF),HL
        CALL READ_S
        CALL NO_BSY
        POP DE
        POP BC
        CALL IN_A
        SUB D
        JR NC,A_CONF2
        LD A,D
        PUSH AF
        LD (A_CONFS-1),A
        LD A,1
        LD (A_CONFS),A
A_CONFS EQU $+2
        LD HL,#0100
        LD DE,0
        CALL W_CHS
        LD A,2
        LD BC,#FABE
        CALL OUT_A
        LD A,#40
        CALL HDSC
        CALL NO_BSY
        LD BC,#FEBE
        CALL IN_A
        LD HL,A_CONFS
        AND 15
        OR A
        JR Z,A_CONFH
        INC (HL)
        JR A_CONFS-2
A_CONFH LD A,(HL)
        INC A
        LD H,A
        POP AF
        LD L,A
        RET


     2. Структура разметки винчестера
          на компьютере Scorpion

   В системе MS-DOS программы для Спектру-
ма, разумеется, работать без  определенной
и очень  трудоемкой  адаптации  не  могут.
Требовалось создать на жестком диске  сис-
тему TR-DOS. Авторы Теневого Монитора  по-
дошли к  решению  этой  проблемы  довольно
оригинально: на винчестере  создается  по-
следовательность TR-DOS образов  дисков, и
каждый из этих  образов  можно  "подсоеди-
нить" к носителю A, B, C или D и  операци-
онная система TR-DOS будет работать с этим
образом, не подозревая, что это не  реаль-
ный диск. Отсюда  идет  терминология: диск
физический (гибкий флоппи-диск) и диск эм-
улированный (HDD-образ).


    2.1. Файловая структура винчестера

   Структурная организация  размещения  на
винчестере информации  выглядит  следующим
образом.

   1. Создастся глобальный  подраздел, но-
сящий всегда название MFS (MOA  File  Sys-
tem?).  Теневой  Монитор  будет   работать
только с ним. Кроме  этого  подраздела  на
жестком диске могут находиться  подразделы
других операционных систем. Таким образом,
один винчестер можно использовать  как  на
Спектруме, так и на других компьютерах.

   2. Внутри глобального подраздела созда-
ются так называемые локальные  подразделы.
Они могут быть следующих видов:

   - TR-DOS. Этот подраздел содержит в се-
бе последовательность TR-DOS образов  дис-
ков (от 1 до 51).

   - MicroDos. Как  писал  автор  Теневого
Монитора,  этот  подраздел  зарезервирован
для совместимости с ПК, использующими  эту
ОС, и программная поддержка этого  подраз-
дела планировалась написаться  в  дальней-
шем. Но до настоящего времени  так  ничего
написано и не было.

   - IS-DOS. Подраздел для ОС с  одноимен-
ным названием.

   - BAD. С помощью  этого  подраздела  на
винчестере  покрывается  область,  имеющая
сбойные сектора.

   Способы работы с этой  структурой  вин-
честера через  меню  Теневого  Монитора  и
подпрограмму RST 8 довольно  разнообразны.
Здесь же я приведу описание того, как  эта
структура выглядит "изнутри".


    2.2. Структура описания подразделов

   Список глобальных подразделов  находит-
ся в 0 относительном  секторе (0  цилиндр,
0 головка, 1  сектор) по  адресу  #01BE, и
занимает 16 байт, где:

   +0  - У MOA 0.

   +1  - головка     |
   +2  - сектор      | начала
   +3  - цилиндр (?) | подраздела.

   +4  - у MOA #53 - MFS.

   +5  - ?
   +6  - ?
   +7  - ?

   +8  |
   +9  | относительный адрес
   +10 | подраздела.
   +11 |

   +12 |
   +13 | Длина подраздела
   +14 | (в секторах).
   +15 |

   Всего таких описателей  может  быть  4.
Четвертый байт #53  -  признак  подраздела
MFS. Смысл 5, 6 и 7 байта мне  так  разга-
дать и не удалось. Также я не совсем  уве-
рен в значении 3-го байта. Тем  не  менее,
2-й и 3-й байты  указывают  местоположение
списка локальных подразделов.

   Он занимает  2  сектора  (1024  байта).
Описание каждого  подраздела  занимает  16
байт и выглядит следующим образом.

   +0 - тип подраздела:
        1 - TR-DOS.
        2 - MicroDos.
        3 - Is-DOS.
        4 - BAD.

   +1 |
   +2 | относительный адрес
   +3 | подраздела.
   +4 |

   +6 |
   +7 | Длина подраздела
   +8 | (в секторах).
   +9 |

   +10 - имя подраздела (6 символов).

   С помощью 4-байтного относительного ад-
реса мы можем обратиться к  началу  любого
локального подраздела.


  2.3. Внутренняя структура подразделов

   Подразделы MicroDos  и  BAD  внутренней
структуры не имеют. Подраздел IS-DOS такую
структуру имеет, но определяется она цели-
ком и полностью только  этой  операционной
системой. Здесь я лишь  расскажу, как  за-
пустить IS-DOS, находящийся на винчестере.


        2.4. Как запустить IS-DOS

   Запуск будет происходить с помощью под-
программы RST 8. Для этого необходимо  вы-
полнить следующую подпрограмму:

      LD      DE,имя подраздела *
      LD      A,15; подключаем к диску "D"
      LD      H,A; глюк MOA: SET 4,(HL)
      LD      C,35
      RST     8
      DB      #81
      LD      HL,буфер для 1 сектора.
      PUSH    HL
      LD      BC,#0124; читать 1 сектор.
      LD      DE,1
      RST     8
      DB      #81
      POP     HL
      LD      A,(HL)
      CP      #18; jr $+... ?
      RET     NZ; незапускаемый IS-DOS
      JP      (HL); запустили

   Хочу заметить, что в  некоторых  случа-
ях IS-DOS запускается неполноценно. В  чем
здесь дело: то ли в стеке, то ли в  какой-
либо установленной не так странице - пред-
стоит определить вам самим.


     2.5. Структура подраздела TR-DOS

   Теперь рассмотрим подраздел  TR-DOS. Он
является одним из центральных  подразделов
на винчестере, поскольку большинство прог-
рамм работают именно с  этой  операционной
системой. Поэтому его мы рассмотрим наибо-
лее подробно. Структура подраздела такова:
в первых двух  секторах  находится  описа-
ние TR-DOS образов дисков. Описание  абсо-
лютно аналогично по своей  структуре  опи-
санию локальных дисков. Каждый диск описан
16 байтами, где +0 -  всегда  1  (TR-DOS),
+1 - адрес образа диска плюс 1, +6 -  дли-
на диска (всегда  1, 5, 0, 0  -  поскольку
длина TR-DOS  образа  строго  фиксирована:
1280+1 512-байтных  секторов), +10  -  имя
диска. Стандартное имя -  Disk??, где ?? -
порядковый номер диска, но его можно  без-
болезненно для Теневого Монитора менять.

   Обратите внимание, что к  адресу  диска
на винчестере необходимо прибавлять 1 сек-
тор. Дело в том, что перед  каждым  диском
непонятно зачем существует 512-байтная об-
ласть, заполненная нулями.

   Хочу также обратить внимание на  макси-
мально допустимое количество образов  дис-
ков в  TR-DOS  подразделе. Мне  доводилось
встречать мнение, что их может быть  боль-
ше, чем 51. Объясняю, в чем здесь  заблуж-
дение: дело в том, что Теневой Монитор для
обращения к дискам внутри  подраздела  ис-
пользует 16-разрядный регистр. Относитель-
но начала подраздела адрес 51-го диска бу-
дет #FF33, а  адрес  52-го  диска  был  бы
#010434. Именно поэтому максимальное коли-
чество дисков в подразделе - 51.


     2.6. Структура сектора эмуляций

   Каждый подраздел или образ диска  можно
подключить к драйверу A, B, C  или  D. Ин-
формация об эмуляции находится во 2  отно-
сительном  секторе, если  Теневой  Монитор
работает не в LBA режиме, и  в  3  относи-
тельном секторе, если флаг LBA включен. Ее
длина - 1 сектор. Каждый диск описан 22-мя
байтами:

   +0 - тип подраздела (0 - эмуляции нет).

   +1 |
   +2 | адрес диска/подраздела.
   +3 |
   +4 |

   +5 - тип подраздела.

   +6 |
   +7 | длина диска/подраздела.
   +8 |
   +9 |

   +10 - имя подраздела (6 байт).

   +16 - имя диска/подраздела (6 байт).

   В случае, если мы подключаем образ дис-
ка, то в +10  будет  имя  подраздела, а  в
+16 - имя образа диска (Disk01 и подобное).
Если же подключен не TR-DOS  подраздел, то
в +16 будет имя подраздела (то есть то же,
что и в +10).

   Чтобы полноценно  подключить  диск  или
подраздел, необходимо выполнить  следующие
действия:

   1. Подключить эмуляцию через RST 8. Эм-
уляция пропишется в 8 страницу.

   2. Считать сектор эмуляций с  винчесте-
ра.

   3. Изменить эмуляцию диска.

   4. Записать CRC в сектор эмуляций.

   5. Записать этот сектор на винчестер.

   Очень важно при изменении эмуляции про-
считать контрольную сумму. Если при считы-
вании этого сектора Теневым Монитором кон-
трольная сумма не совпадёт, то  он  снимет
эмуляции со всех четырех дисков.

   Чтобы вычислить верную контрольную сум-
му, надо делать следующее:

        LD  DE,сектор в памяти.
        LD  BC,508
        CALL CRC
        LD  HL,сектор + 508.
        LD  (HL),E
        INC HL
        LD  (HL),D
        RET


       2.7. Расчет контрольной суммы

   Приведенный ниже код расчета CRC любез-
но предоставлен мне MOA и представляет  из
себя, как он мне объяснил, "гибрид" CRC-16
и CRC-32.

;Cyclic Redundancy Check.
;Подсчет контрольной суммы.
;IN : [DE] - START, [BC] - LENGHT
;OUT: [DE] - CRC-SUMM.
CRC     LD HL,#FFFF
        PUSH IX
        PUSH DE
        POP IX
        EX DE,HL
CRC_1   LD HL,CRC_TAB
        LD A,(IX)
        INC IX
        XOR E
        ADD A,L
        LD L,A
        JR NC,CRC_2
        INC H
CRC_2   LD A,D
        XOR (HL)
        LD E,A
        INC HL
        XOR A
        XOR (HL)
        LD D,A
        DEC BC
        LD A,C
        OR B
        JR NZ,CRC_1
        POP IX
        RET

CRC_TAB DW #0000,#1021,#2042,#3063
        DW #4084,#50A5,#60C6,#70E7
        DW #8108,#9129,#A14A,#B16B
        DW #C18C,#D1AD,#E1CE,#F1EF
        DW #1231,#0210,#3273,#2252
        DW #52B5,#4294,#72F7,#62D6
        DW #9339,#8318,#B37B,#A35A
        DW #D3BD,#C39C,#F3FF,#E3DE
        DW #2462,#3443,#0420,#1401
        DW #64E6,#74C7,#44A4,#5485
        DW #A56A,#B54B,#8528,#9509
        DW #E5EE,#F5CF,#C5AC,#D58D
        DW #3653,#2672,#1611,#0630
        DW #76D7,#66F6,#5695,#46B4
        DW #B75B,#A77A,#9719,#8738
        DW #F7DF,#E7FE,#D79D,#C7BC
        DW #48C4,#58E5,#6886,#78A7
        DW #0840,#1861,#2802,#3823
        DW #C9CC,#D9ED,#E98E,#F9AF
        DW #8948,#9969,#A90A,#B92B
        DW #5AF5,#4AD4,#7AB7,#6A96
        DW #1A71,#0A50,#3A33,#2A12
        DW #DBFD,#CBDC,#FBBF,#EB9E
        DW #9B79,#8B58,#BB3B,#AB1A
        DW #6CA6,#7C87,#4CE4,#5CC5
        DW #2C22,#3C03,#0C60,#1C41
        DW #EDAE,#FD8F,#CDEC,#DDCD
        DW #AD2A,#BD0B,#8D68,#9D49
        DW #7E97,#6EB6,#5ED5,#4EF4
        DW #3E13,#2E32,#1E51,#0E70
        DW #FF9F,#EFBE,#DFDD,#CFFC
        DW #BF1B,#AF3A,#9F59,#8F78
        DW #9188,#81A9,#B1CA,#A1EB
        DW #D10C,#C12D,#F14E,#E16F
        DW #1080,#00A1,#30C2,#20E3
        DW #5004,#4025,#7046,#6067
        DW #83B9,#9398,#A3FB,#B3DA
        DW #C33D,#D31C,#E37F,#F35E
        DW #02B1,#1290,#22F3,#32D2
        DW #4235,#5214,#6277,#7256
        DW #B5EA,#A5CB,#95A8,#8589
        DW #F56E,#E54F,#D52C,#C50D
        DW #34E2,#24C3,#14A0,#0481
        DW #7466,#6447,#5424,#4405
        DW #A7DB,#B7FA,#8799,#97B8
        DW #E75F,#F77E,#C71D,#D73C
        DW #26D3,#36F2,#0691,#16B0
        DW #6657,#7676,#4615,#5634
        DW #D94C,#C96D,#F90E,#E92F
        DW #99C8,#89E9,#B98A,#A9AB
        DW #5844,#4865,#7806,#6827
        DW #18C0,#08E1,#3882,#28A3
        DW #CB7D,#DB5C,#EB3F,#FB1E
        DW #8BF9,#9BD8,#ABBB,#BB9A
        DW #4A75,#5A54,#6A37,#7A16
        DW #0AF1,#1AD0,#2AB3,#3A92
        DW #FD2E,#ED0F,#DD6C,#CD4D
        DW #BDAA,#AD8B,#9DE8,#8DC9
        DW #7C26,#6C07,#5C64,#4C45
        DW #3CA2,#2C83,#1CE0,#0CC1
        DW #EF1F,#FF3E,#CF5D,#DF7C
        DW #AF9B,#BFBA,#8FD9,#9FF8
        DW #6E17,#7E36,#4E55,#5E74
        DW #2E93,#3EB2,#0ED1,#1EF0

    __________________________________
         ───══════════════════───



Другие статьи номера:

ZX Spectrum и винчестер — статья Влада Сотникова/Vega о работе и программировании жесткого диска (HDD) на Спектруме.

ZX-Party — итог горячей и скандальной полемики длиною в год.

Горячая линия - Сайт "ZX-News"! Плюс кое-что по SOSG.

От редакции - С Новым годом, веком и тысячелетием!!!

Презентация - Interactive Fiction: новое слово! Новая игра и редактор адвентюр.


Темы: Игры, Программное обеспечение, Пресса, Аппаратное обеспечение, Сеть, Демосцена, Люди, Программирование

Похожие статьи:
News - Новости нашего городка.
Репортаж - Chaos Constructions 2005 глазами Newart
Реклама - Реклама и объявления.
Печатается с продолж. - Как ломаются полуоси (окончание, часть 3).
Железо - Multiviewer. Описание доработочки, позволяющей мерять скорость программ по бордюру без влезания в коды - легким нажатием кнопки.

В этот день...   23 апреля