WELCOME TO THE ZX-NEWS SITE!

Оригинальная заставка ZX-News #54

От редакции Горячая линия Презентация ZX-Party Старина Z80 Приложение

ZX-News #54
Спектрумовская электронная газета

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

Старина 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)



© Влад Сотников/Vega, 2000

SPECTRUM И ВИНЧЕСТЕР

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

      1.1. Введение.
      1.2. Обращение к винчестеру.
      1.3. Устройство винчестера.
      1.4. Терминология.
      1.5. Обращение к регистрам на Scorpion'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)

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

    Рис.1

    — 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 Parameters.

    Рис.2

    — 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).

    Рис.2

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

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

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

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

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

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

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

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

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

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

    ;читаем сектора, заданные .
    ;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
    
    ;Деление. <>
    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_ и выполнить следующую подпрограмму:

    ;Пишем сектора, заданные .
    ;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 System?). Теневой Монитор будет работать только с ним. Кроме этого подраздела на жестком диске могут находиться подразделы других операционных систем. Таким образом, один винчестер можно использовать как на Спектруме, так и на других компьютерах.

    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
    

    главное меню номера


    Copyright © 2001–2013 The ZX-News Site