|
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
Другие статьи номера:
Похожие статьи:
В этот день... 15 ноября