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