Avro News #04
27 октября 2006

HDD - драйвер работы с HDD.

После  ремонта компа занялся тестированием драйвера HDD, который
я  накатал  под ис-дос. Подключил чистый HDD SLAV-ом и установил
драйвер  в ис-дос. Пока на диске никаких разделов не создавал, а
в драйвер прописал начала разделов на нулевом секторе HDD SLAVE.
Запустил CREATE и создал ис-диск размером 24576 блоков. Для тес─
тирования  работы  решил скопировать системный диск один-в-один.
Запустил копировщик и откинулся на спинку кресла. Однако уже че─
рез  несколько секунд копир вывалился с ошибкой, которая означа─
ет,  что  не  найден каталог. В корневом каталоге диска уже было
два каталога с подкаталогами. В часть из них мне не удалось зай─
ти. Искать такую ошибку трудно, когда "тут пишу правильно, а тут
как получится".
Надо  думать  как найти ошибку не используя отладку в теневике -
всё же порты дос открыты и теневик явно стошнит от этого.
Пока  решил  просто  потестировать скорость чтения в режиме LBA.
Запустил  программу BAD.com, которая читает по одному сектору, а
как  раз  в  этом режиме должно быть особо заметно превосходство
LBA  от  CHS, ведь при LBA не приходится на каждом затребованном
секторе  вычислять его смещение от начала раздела и раскладывать
смещение  в абсолютные координаты CHS. Т.е. уйма делений/умноже─
ние просто исключаются из программы.
Замерил  время затраченное драйвером CHS и драйвером LBA на чте─
ние некоторого обьёма информации. Вот, что у меня получилось:
LBA 234.03 кб/сек
CHS 227.56 кб/сек
Не поверил глазам и калькулятору. Такой мизерный прирост?!

На  следующий  день принялся за поиск сбоев работы драйвера. Для
начала  нужно  определить  на каком секторе происходит сбой. Для
этого я создал текстовый файл с таким содержимым:
СЕКТОР01......................
..............................
..............................
(всего  8 строк по 31 символу + в конце каждой строки #0D. Всего
256 байт)
СЕКТОР02......................
..............................
(тоже самое)

Т.е. длина файла 64 сектора. Этот файл я писал на пустой раздел
нового драйвера RHDDSMUC и потом визуально проверял где чего
нарушилось. Сбой каждый раз был в новом месте, в зависимости от
размера раздела. Так при размере 3200 блоков и длиной корневого
каталога 4 блока, сбой был такой: после сектора 51 шёл сектор
64, потом мусор, потом 55,56,57,58,59,60,61,62,63, потом мусор.
Под секторами здесь я говорю про строки текстового файла.
Физически сбой произошёл на 58-ом блоке от начала раздела,
(29-й физический сектор HDD). Сам раздел начинался с нулевого
LBA сектора HDD.

Возникло две идеи:
1. при переделки оригинального драйвера я где-то не доглядел и
ошибся;
2. у меня было две версии оригинального драйвера. Отличались они
довольно  существенно.  В  одной  была строка Complete 100%, а в
другой,  более  поздней редакции, такой строки небыло. Но в этой
версии были комментарии и мне она показалась более логичной. По─
этому  я  взялся переделывать именно её. Возможно она изначально
была не дописана или не тестирована.

Я  решил начать со второй идеи. Взял предыдущую версия и переде─
лал  её  под режим LBA. Установил и занялся проверкой. Результат
оказался тем же самым.

Значит вероятно я ошибся при переделке драйвера. Чтобы убедиться
в работоспособности исходной версии драйвера просто взял и ском─
пилировал  оригинал,  установил и оттестировал. Ошибки остались.
Получается,  что  ошибки  были в оригинальной версии и непонятно
как она работала у Олега Григорьева - автора драйвера.
Единственное  отличие  от оригинала - это полная адресация порта
#1ffd.  В оригинальной версии обращение к порту шло через укоро─
ченную  адресацию.  Такой  трюк  на  GMX не проходит и у меня во
время работы драйвера изменялся цвет бордюра, поэтому сделал
полный адрес.

Собрал  все  свои мысли в кучу и написал письмо Григорьеву. Пока
ответа небыло.


Вот исходник драйвера. Может кто сможет победить его:

;RHDDLBA.BLK
;HDD DRIVER FOR SMUC WITH OPEN PORTS
;LBA-28 MODE ONLY
;MASTER/SLAVE HDD SUPPORT
;BASED ON RHDDSMUC BY RUINER AKA #0R
;(C) AMOSOV NIKOLAY AKA AMONIK
;VERSION 0.0
;COMPLETE 100%
;CREATING DATE: 24-09-2006
;LAST EDIT: 26-09-2006
;***************************************************************

        ORG  #8000

        DEFW INST;     адрес п/п установки
        DEFW READ;     адрес п/п чтения
        DEFW WRIT;     адрес п/п записи
        DEFW INIT;     адрес п/п инициализации
        DEFB #E0;      регистр состояния
        DEFB #04;      регистр состояния
        DEFW #0000;    IM2 на выходе не устанавливать
        DEFW #0101;    Тип TRDOS и число попыток чтения
        DEFW #ADDE;    Метка драйвера
;----------------------------------------------------------------
;Формат информации о разделе на диске:
;В первом слове младшая часть адреса сектора LBA bits 0...15
;Во втором слове старшая часть адреса сектора LBA bits 16...27
;биты 29...31 всегда =1, а бит 28 выбирает 0=MASTER/1=SLAVE
;Exxx=MASTER/Fxxx=SLAVE
CDEV    DEFW #0000;    LBA bits 0..15
        DEFW #F000;    Привод/bits 16..27

;Координаты начала раздела для 8-и дисков
DEVS    DEFW #0000;    LBA 0..15
        DEFW #F000;    привод/bits 16..27

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

        DEFW #0000
        DEFW #F000

INT     DEFB #00;      Состояние прерываний

;----------------------------------------------------------------
;Подпрограмма установки и инициализации драйвера
INST
INIT    CP   #08;      Hе более 8 дисков
        RET  NC

;Копируем координаты выбранного раздела в область координат
;текущего диска
        ADD  A,A
        ADD  A,A
        LD   C,A
        LD   B,0
        LD   HL,DEVS
        ADD  HL,BC
        LD   DE,CDEV
        LD   C,4;      всего 4 байта
        LDIR
        RET

;----------------------------------------------------------------
;Определение состояния прерываний
;Мусорит на стеке и портит HL,BC
SETDI   LD   HL,SETEI;      Выход через неё
        EX   (SP),HL
        LD   (ERROR+#01),SP
        PUSH HL
        LD   HL,SETDIO;     Hеявный вызов
        PUSH HL
        LD   IX,INT
        XOR  A
        LD   (IX),A
        LD   A,R;           Проверка INT
        RET  PE
        LD   A,R
        RET  PE
        INC  (IX)
        RET

;Открываем порты DOS
SETDIO  DI
        LD   A,#04;    для IS-DOS CLASSIC
;       LD   A,#14;    для IS-DOS CHIC
        LD   BC,#1FFD
        OUT  (C),A
;       LD   BC,#FFBE; Регистр состояния
;       IN   A,(C);    Ждём освобождения устройства,
;       RLCA;          т.е. сброса BUSY
;       JR   C,$-#03

;Включаем режим предсказания чтения
;       LD   A,(CDEV+#03)
;       DEC  B;        Регистр накопителя
;       OUT  (C),A;    Выбрали диск
;       LD   DE,#AAEF
;       LD   B,#F9;    Регистр дополнительных возможностей
;       OUT  (C),D;    Параметры команды
;       LD   B,#FF;    Регистр команд
;       OUT  (C),E;    Выдали команду

;Ожидание освобождения устройства
WBSY    LD   BC,#FFBE; Регистр состояния
        IN   A,(C);    Ждём освобождения устройства,
        RLCA;          т.е. сброса BUSY
        JR   C,$-#03;  Ещё занят
        RET

SETEI   PUSH AF
        XOR  A;        для IS-DOS CLASSIC
;       LD   A,#10;    для IS-DOS CHIC
        LD   BC,#1FFD
        OUT  (C),A;    Закрываем порты DOS
        POP  AF;       Восстанавливаем режим прерываний
        BIT  0,(IX)
        RET  NZ
        EI
        RET

;----------------------------------------------------------------
;Подпрограмма чтения сектора(-ов)
READ    LD   C,#7C;    Чтение
        DEFB #3A;      команда LD A,(NN)
WRIT    LD   C,#7D;    Запись

        PUSH BC
        LD   C,#09;    Проверка нажатия
        RST  #10;      какой-либо клавиши
        POP  BC
        JR   Z,RW00;   Hе нажаты
        CP   #16;      это BREAK?
        JR   NZ,RW00;  Hет
        LD   C,#07;    Чистим буфер клавиш
        RST  #10
        LD   A,#14;    Выходим с сообщением
        SCF;           BREAK
        RET

;Hа входе:
;B число блоков
;DE номер первого блока
;HL адрес памяти
RW00    PUSH DE;       Запомнили номер
        EXX;           блока и другие
        POP  DE
        CALL SETDI;    Включили порты
        SRL  D;        делим номер блока
        RR   E;        на два
        EX   AF,AF';   сохранили флаг C

;Вычисляем смещение от начала раздела по номеру блока
        LD   HL,(CDEV);младшая часть адреса сектора LBA 0..15
        ADD  HL,DE;    сложили с номером блока
        EX   DE,HL;    запомнили в DE
        LD   HL,(CDEV+#02);старшая часть адреса сектора
        JR   NC,$+#03; Если небыло переполнения младшей части
        INC  HL;       Добавили к старшей части адреса сектора
        CALL PCOORDL;  Запись в регистры HDD

        EXX;
        EX   AF,AF';
;Вернули:
;HL адрес памяти
;DE номер блока
;B количество блоков
;C тип операции
;CF смещение в первом секторе

        LD   D,B
        JR   NC,$+#03; Если с середины, то уменьшаем количество
        DEC  D;        блоков
        RLA;           Запоминаем смещение.
        SRL  D;        Количество секторов.
        RLA;           Запоминаем остаток и
        LD   E,A;      делаем копию в E.

        BIT  1,E;      Если с середины, то
        JR   Z,$+#03;  увеличиваем количество
        INC  D;        секторов.

        SCF;           Hеявно модифицируем регистр С
        RR   C;        и получаем в нём адрес порта
        JR   C,HDDW;   в CF тип операции.

;----------------------------------------------------------------
HDDR    EX   AF,AF'
        LD   A,#20;    Команда READ SECTORS
        EX   AF,AF'
        AND  #01;      Добавить хвост.
        ADD  A,D
        CALL WKSEC0;   Выдача команды

        BIT  1,E;      Есть голова?
        JR   Z,HDDR01; нет
        CALL SKIP;     Пропуск первой половины сектора
        LD   A,#10;    Чтение головы
HDDR00  CALL RDHALF+#02;Hасос из буфера
        DEC  D
HDDR01  INC  D;        Есть целые сектора?
        DEC  D
        JR   Z,HDDR02; Hет.
        CALL WAIT;     Ждём готовность
        LD   A,#20;    Читаем целый сектор
        JR   HDDR00

HDDR02  BIT  0,E;      Есть хвост?
        RET  Z;        Hет
        CALL WAIT;     Ждём готовность
        CALL RDHALF;   Читаем хвост

;----------------------------------------------------------------
;Пропуск половины сектора со скоростью 6.875 тактов на байт
SKIP    LD   A,#10;    Количество повторов
        LD   B,#F8;    Адрес порта старшего байта данных
SKIP0   DEFB #ED,#70;  команда IN F,(C)
        DEFB #ED,#70
        DEFB #ED,#70
        DEFB #ED,#70
        DEFB #ED,#70
        DEFB #ED,#70
        DEFB #ED,#70
        DEFB #ED,#70
        DEC  A
        JR   NZ,SKIP0; Ещё разик?
        OR   A
        RET

;----------------------------------------------------------------
HDDW    INC  D;        Hет ни головы, ни
        DEC  D;        тела?
        JR   Z,HDDW21; Да.
        BIT  1,E;      Есть голова?
        JR   Z,HDDWFF; Hет
        CALL WKSECR;   Чтение сектора
        CALL RDHLFH;   Чтение 1-й половины во внутренний буфер
        CALL SKIP;     Пропуск 2-й половины

HDDWFF  LD   A,#30;    Запись сектора
        EX   AF,AF'
        LD   A,D;      Количество целых секторов
        CALL WKSEC0;   Дали команду
        BIT  1,E;      Есть голова?
        JR   Z,HDDW00; нет.
        PUSH HL
        CALL WRHLFH;   Пишем из буфера
        POP  HL
        LD   A,#10;    Пишем голову
LOOP    CALL WRHALF+#02
        CALL WBSY;     Ждём выполнения
        DEC  D;        Уменьшили число целых секторов
HDDW00  INC  D;        Есть тело?
        DEC  D
        JR   Z,LOOP1;  Hет.
HDDW10  CALL WBSY;     Ждём готовность
        CALL WDRQ;     Ждём DRQ
        LD   A,#20;    Пишем целый сектор
        JR   LOOP

LOOP1   BIT  0,E;      Есть хвост?
        RET  Z;        Hет.
        LD   A,#20
        EX   AF,AF'
        LD   A,#02
        CALL WKSEC0
        LD   A,#20
        CALL SKIP+#02
        CALL WAIT
        JR   HDDW22

HDDW21  CALL WKSECR;   Чтение сектора
HDDW22  CALL SKIP;     Пропустить половину
        CALL RDHLFH;   Прочитать в буфер
        LD   A,#30;    Запись сектора
        CALL WKSEC
        CALL WRHALF;   Пишем хвост.
        CALL WRHLFH;   Пишем из буфера.
        CALL WBSY;     Ждём выполнения.
        XOR  A
        RET

;----------------------------------------------------------------
;Запись адреса сектора LBA в регистры HDD
;H= привод+LBA 27...24
;L= LBA 23...16
;D= LBA 8...15
;E= LBA 0...7
PCOORD  LD   BC,#FEBE
        OUT  (C),H
        DEC  B
        OUT  (C),L
        DEC  B
        OUT  (C),D
        DEC  B
        OUT  (C),E
        RET

;----------------------------------------------------------------
RDHLFH  PUSH HL;       Читаем пол сектора
        LD   HL,TMPBUF;во внутренний буфер
        CALL RDHALF
        POP  HL
        RET

WKSECR  LD   A,#20;    Точка входа чтения одного сектора
WKSEC   EX   AF,AF';   Точка входа работы с
        LD   A,#01;    одним сектором.
WKSEC0  LD   B,#FA;    Точка входа работы с
        OUT  (C),A;    несколькими секторами
        LD   B,#FF;    Читаем регистр
        IN   A,(C);    состояния
        BIT  6,A;      Ждём установку DRDY.
        JR   Z,$-#04
        EX   AF,AF';   Запись кода команды.
        OUT  (C),A
WAIT    CALL WBSY;     Ждём готовность.
        RRCA;          Проверка ошибки
        RET  NC;       Выходим, если ERR=0

        LD   A,#07;    Ошибка чтения/записи
ERROR   LD   SP,#0000; сектора
        RET

WDRQ    IN   A,(C);    Ждём установки DRQ.
        BIT  3,A
        JR   Z,$-#04
        RET

;----------------------------------------------------------------
;Подпрограмма записи со скоростью 21.875 тактов на байт
WRHLFH  LD   HL,TMPBUF;адрес буфера
WRHALF  LD   A,#10;    Число повторов
        PUSH DE
        LD   DE,#D8F8
        LD   (WRHLF1+#01),SP
        LD   SP,HL
WRHLF0  DEFB #E1,#42,#ED,#61,#43,#ED,#69;  POP  HL
        DEFB #E1,#42,#ED,#61,#43,#ED,#69;  LD   B,D
        DEFB #E1,#42,#ED,#61,#43,#ED,#69;  OUT  (C),H
        DEFB #E1,#42,#ED,#61,#43,#ED,#69;  LD   B,E
        DEFB #E1,#42,#ED,#61,#43,#ED,#69;  OUT  (C),L
        DEFB #E1,#42,#ED,#61,#43,#ED,#69
        DEFB #E1,#42,#ED,#61,#43,#ED,#69
        DEFB #E1,#42,#ED,#61,#43,#ED,#69
        DEC  A
        JR   NZ,WRHLF0
        LD   H,A
        LD   L,A
        ADD  HL,SP
WRHLF1  LD   SP,#0000
        POP  DE
        OR   A
        RET

;----------------------------------------------------------------
;Подпрограмма чтения со скоростью 20.875 тактов на байт
RDHALF  LD   A,#10
        PUSH DE
        LD   DE,#D8F8
RDHLF0  DEFB #43,#ED,#A2,#42,#ED,#A2; LD B,E:INI:LD B,D:INI
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEFB #43,#ED,#A2,#42,#ED,#A2
        DEC  A
        JR   NZ,RDHLF0
        POP  DE
        OR   A
        RET

;----------------------------------------------------------------
;Внутренний буфер на пол сектора
TMPBUF  DEFS #0100



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

HDD - драйвер работы с HDD.

Новости - Общаясь с Surfin Bird-ом я рассказал ему, что установил в PS2 жёсткий диск, и SB подал мне идею установить на приставку Linux.

Новости - Сегодня умер жёсткий диск на ПЦ, Пробовал организовать Фидо средствами ZX, Посмотрел схему Скорпа и определил вероятные причины неисправности...


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

Похожие статьи:
Credits - список авторов музыки и графики использованной в предыдущих номерах.
Калейдоскоп - О втором виртуальном фестивале компьютерного искусства Art Comp-99.
Песни - Песни Сопротивления.

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