ся символом ASCII 0. В AL надо поместить код доступа, причем 0 открывает файл для чтения, 1 - для записи, а 2 - для чтения/записи. При возврате AX будет содер- жать 16-битный номер файла, по которому файл впоследствии иденти- фицируется. Файловый указатель устанавливается на начало файла. Размер записи устанавливается равным 1 байту - это связано с тем, что операции прямого доступа при использовании метода дескриптора файла не имеют специальных буферов: на самом деле файлы с прямым доступом рассматриваются как последовательные и с ними работают одни и те же функции. Эта функция позволяет открывать как обыч- ные, так и спрятанные файлы. При возврате флаг переноса равен 0, если файл открыт успешно. В противном случае флаг переноса уста- навливается, а AX содержит 2 - если файл не найден, 4 - если программа хочет открыть слишком много файлов, 6 - при ошибке на диске и 12 - если неправильно указан код доступа в AL. Вот при- мер: ;---в сегменте данных PATH DB 'A:LEVEL1\FILENAME.EXT',0 ;---открываем файл для чтения/записи MOV AH,3DH ;номер функции MOV AL,2 ;открываем для чтения/записи LEA DX,PATH ;DS:DX указывают на путь INT 21H ;открываем файл JC OPEN_ERROR ;уход на обработку ошибок MOV HANDLE,AX ;сохраняем номер файла Функция 3EH прерывания 21H закрывает файл, открытый методом дескриптора файла. Надо просто поместить номер файла в BX и вы- полнить функцию. При возврате флаг переноса равен 0, если все в порядке, иначе он равен 1, а AX = 6, если указан неверный номер файла. ;---закрытие файла MOV AH,3EH ;номер функции MOV BX,HANDLE ;номер файла INT 21H ;закрываем файл JC CLOSE_ERROR ;уход на обработку ошибки Функция 45H прерывания 21H создает второй дескриптор файла из существующего открытого дескриптора. В BX должен быть указан существующий номер, а в AX будет возвращен новый. Функция 46H прерывания 21H связывает второй дескриптор (помещаемый в CX) с открытым файлом (номер которого в BX) таким образом, что первый будет относиться к тому же файлу и устройству, что и последний. 5.3.4 Переименование файла; изменение позиции файла в каталоге. Переименование файла может заключаться лишь в изменении первых 11-ти символов элемента каталога. Однако в древовидном каталоге весь элемент каталога может быть перенесен в другой подкаталог, переопределяя тем самым путь к файлу. Одна команда может как переименовать файл, так и перенести его в другой каталог. Высокий уровень. В Бейсике файл переименовывается командой NAME. С помощью этой команды он может быть также перенесен в другой каталог. Напишите сначала существующее имя, а затем новое имя файла, оба заключен- ные в кавычки, например NAME "OLDFILE.EXT" AS "NEWFILE.EXT". В этом случае будет переименован файл в корневом каталоге. Для изменения имен файлов, расположенных в подкаталогах, могут быть использованы пути к файлу. Например, NAME "B:LEVEL1\OLDFILE.EXT" AS "B:LEVEL1\NEWFILE.EXT" изменяет имя файла в подкаталоге LE- VEL1. Отметим, что для нового имени файла должен быть указан полный путь. Если Вы запишете NAME "B:LEVEL1\OLDFILE.EXT" AS "NEWFI- LE.EXT", то файл будет не только переименован, но и перенесен в корневой каталог. Для переноса файла из одного подкаталога в другой без изменения его имени напишите команду NAME "A:SUBDIR1- \OLDFILE.EXT" AS "A:SUBDIR2\OLDFILE.EXT". Таким методом нельзя перенести файл с диска на диск. Поскольку файлы, расположенные в разных каталогах могут иметь одно и то же имя, то возможна ошибка при попытке переноса файлов с одинаковыми именами. В этом случае будет возвращен код ошибки 58 [5.4.8]. Средний уровень. MS DOS может переименовывать файлы, используя как метод управ- ляющего блока файла, так и метод дескриптора файла. Первый из них может применяться только к файлам, расположенным в текущем ката- логе. Метод FCB: Используйте функцию 17H прерывания 21H. DS:DX должны указывать на открытый управляющий блок файла. Поместите новое имя файла в FCB, начиная со смещения 11H (это "резервная" область блока). Новое имя может использовать символ "?", в этом случае символы, находящиеся в этих позициях, не будут изменяться. При возврате, если новое имя уже существовало в каталоге, то AL будет равно FF, иначе AL = 0. В примере имя файла ACCOUNTS.DAT меняется на DEBTS.DAT. ;---в сегменте данных FCB DB 'FILENAMEEXT',25 DUP(0) NEWNAME DB 'NEWNAME EXT', ;11 символов нового имени ;---помещаем новое имя файла в переменную NEWNAME MOV SI,OFFSET NEWNAME ;DS:SI указывают на новое имя MOV AX,SEG FCB ;ES:DI указывают на FCB MOV ES,AX ; MOV DI,OFFSET FCB ; ADD DI,11H ;начинаем со смещения 11H MOV CX,11 ;имя файла содержит 11 символов REP MOVSB ;переносим 11 байтов LEA DX,FCB ;DS:DX указывают на FCB MOV AH,17H ;функция изменения имени INT 21H ;изменяем имя CMP AL,0FFH ;проверка на ошибку JE RENAME_ERROR ;уход на обработку ошибки Метод дескриптора файла: Функция 56H прерывания 21H переименовывает и перемещает файлы. DS:DX должны указывать на строку, дающую путь и имя переименуемо- го файла (до 63-х символов) и завершающуюся символом ASCII 0. ES:DI должны указывать на вторую строку, которая дает новые имя и путь файла. Имена накопителей, если они присутствуют, должны совпадать. Если пути различны, то файл переноносится в другой подкаталог. Чтобы перенести файл без переименования надо во вто- рой строке указать то же самое имя, но другой путь. При возврате, если произошла ошибка, то устанавливается флаг переноса, а AX будет содержать 3 - если один из путей не найден, 5 - при ошибке на диске и 17 - при попытке переноса между разными накопителями. В примере файл ACCOUNTS.DAT переносится из подкаталога GAINS в подкаталог LOSSES. ;---в сегменте данных OLDPATH DB 'A:GAINS\ACCOUNTS.DAT',0 NEWPATH DB 'A:LOSSES\ACCOUNTS.DAT',0 ;---изменение пути файла LEA DX,OLDPATH ;DS:DX указывают на старый путь MOV AX,SEG NEWPATH ;ES:DI указывают на новый путь MOV ES,AX ; MOV DI,OFFSET NEWPATH ; MOV AH,56H ;номер функции INT 21H ;переносим файл JC ERROR_ROUTINE ;уход на обработку ошибки 5.3.5 Подготовка к файловым операциям. Языки высокого уровня, такие как Бейсик, выполняют подготови- тельную работу для файловых операций автоматически. Однако прог- раммы на языке ассемблера имеют достаточно работы перед тем как создать или открыть файл. Требования отличаются, в зависимости от того используется ли для доступа к файлу метод управляющего блока файла или метод дескриптора файла. Для обоих методов Вам необхо- димо строку или блок параметров, указывающих на файл и буфер для переноса данных. MS DOS предоставляет различные наборы функций чтения/записи для двух методов. Средний уровень. Метод управляющего блока файла: Этот метод доступа к файлам требует, чтобы Вы создали блок параметров, котрый первоначально должен содержать такую информа- цию, которая позволяет найти файл в каталоге. Хотя FCB имеет много полей, вообще говоря, только некоторые из них должны быть заполнены; MS DOS заполняет большинство остальных полей информа- цией после того, как файл открывается. Отметим, что к началу FCB может добавляться специальное поле для создания расширенного FCB, который объяняется ниже. Вот структура FCB: Накопитель (DB) Число, определяющее на каком накопителе будет искаться файл, 1 = A, 2 = B и т.д. Если указан 0, то берется накопитель по умолчанию, а затем система заменяет 0 на код этого накопителя. Имя и расширение Восьмибайтное имя файла, выравненное по (11 байтов) левому краю должно быть дополнено пробелами (ASCII 32), если оно меньше 8 байтов. То же относится и к трехбайтному расширению. Между ними не должна стоять точка. Текущий блок (DW) DOS организует файлы блоками по 128 записей, пронумерованных от 0 до 127. Например, сис- тема рассматривает запись #129 файла прямого доступа, как запись #0 блока #1 (отсчет как для записей, так и для блоков ведется с 0). В файлах нет специальных ограничителей ни для блоков ни для записей. Вместо этого смещение для блоков и записей вычисляется исходя из длины записи, которая устанавли- вается следующим полем FCB. Размер записи (DW) Все функции MS DOS, связанные с чтением или записью в файл, работают в терминах записи. Для файлов прямого доступа важно, чтобы размер записи был установлен равным размеру записей, помещенных в файл. Для последова- тельных файлов размер записи не столь важен, однако маленький размер записи будет замед- лять дисковые операции. Поскольку размер сектора 512 байтов, то оптимальным является размер записи 512 байтов. Система автомати- чески помещает значение по умолчанию 80H (128) в поле длины записи при открытии фай- ла. Поэтому не забудьте установить это поле после открытия файла. Размер файла (DD) Размер указывается с точностью до байта. Это поле заполняется системой при открытии фай- ла. Дата файла (DW) Дата записывается системой при открытии FCB. Ее формат приведен в [5.2.5]. Текущая запись (DB) Текущая запись используется совместно с полем текущего блока. Записи нумеруются от 0 до 127. Запись прямого доступа #200, распо- ложенная в блоке 1, имеет номер текущей записи равный 71 ((200 - 128) - 1). Номер записи пря- Вместо того, чтобы требовать от программы, мого доступа (DD) чтобы она вычисляла текущие значения блока и записи для файла прямого доступа, MS DOS делает эту работу сама. При операциях с файлами прямого доступа просто поместите номер записи в это 4-хбайтное поле. При выполнении операции с файлом прямого доступа MS DOS поместит нужные значения в поля теку- щего блока и текущей записи. Помните, что старший байт расположен в старшей ячейке. Связь между полями текущей записи, текущего блока и номер записи прямого доступа показана на рис. 5-3. Простейший путь создать FCB как переменную в сегменте данных программы. Если имя открываемого файла не меняется, то это имя может быть прямо записано в это поле. Остаток блока инициализи- руйте байтами ASCII 0. Только после того как FCB будет открыт (с помощью функции 0FH прерывания 21H, как показано в [5.3.3]) Вы должны записать в блок остальную информацию. Отметим, что FCB для работы с простым последовательным файлом с длиной записи 128 байтов не требует дальнейших приготовлений. После создания FCB дальнейшие операции требуют, чтобы DS:DX указывали на него. Прос- тейшая форма его такая: FCB DB 1,'FILENAMEEXT',25 DUP(0) Можно также создать FCB как структуру: FCB STRUC DRIVE_NUM DB 0 FILE_NAME DB 8 DUP(?) FILE_EXT DB 3 DUP(?) BLOCK_NUM DW 0 RECORD_SIZE DW 0 FILE_SIZE DD 0 FILE_DATE DW 0 RESERVED DB 10 DUP(0) CURRENT_REC DB 0 RANDOM_REC DD 0 FCB ENDS При таком подходе программе проще помещать данные в FCB, посколь- ку метки существуют для каждого поля. В зависимости от типа фай- ловых операций на поля могут накладываться следующие ограничения: 1. Для файлов прямого доступа Вы должны установить размер записи и номер записи в поле записи прямого доступа. 2. Для доступа к последовательным файлам с начала Вы должны установить только размер записи, при условии, что Вы инициализи- ровали поля текущего блока и текущей записи в 0 (просто обнулите весь FCB, за исключением имен накопителя и файла). При открытии поле размера записи будет установлено равным 128, если это значе- ние устаривает Вас, то дальнейшая подготовка не нужна. 3. Для доступа к последовательному файлу с середины или с конца Вы должны установить поля текущего блока и текущей записи (в этом случае Ваша программа должна будет производить вычисления сама). Префикс программного сегмента [1.3.0] имеет достаточно большое поле, чтобы содержать управляющий блок файла. Это пространство предоставляется для каждой программы, поэтому экономно использо- вать его, особенно в программах типа .COM. Поле FCB расположено со смещением 5CH в префиксе программного сегмента. В программах COM используйте ORG для создания FCB следующим образом (здесь помечен также используемый по умолчанию DTA, который будет обсуж- даться ниже): ;---в начале кодового сегмента ORG 5CH FCB LABEL BYTE DRIVE_NUM DB 0 FILE_NAME DB 8 DUP(?) FILE_EXT DB 3 DUP(?) BLOCK_NUM DW 0 RECORD_SIZE DW 0 FILE_SIZE DD 0 FILE_DATE DW 0 RESERVED DB 10 DUP(0) CURRENT_REC DB 0 RANDOM_REC DD 0 ORG 80H DTA LABEL BYTE ORG 100H ASSUME CS:CSEG, DS:DSEG, SS:SSEG ... Расширенный FCB используется для создания или доступа к файлу, имеющему специальные атрибуты, например, к спрятанному файлу или файлу только для чтения. Различные атрибуты объяснены в [5.2.6]. Расширенный FCB на 7 байтов длиннее, причем эти 7 байтов пред- шетсвуют обычному блоку. Первый байт равен FF, что указывает на специальный статус. За ним следуют 5 байтов ASCII 0, а затем байт атрибутов. При открытии файла с использованием расширенного FCB DS:DX должны указывать на первый из дополнительных семи байтов, а не на имя накопителя, как для обычного FCB. Вот обычная форма, где 2 - значение байта атрибутов, а 1 - указывает на накопитель: FCB DB 0FFH, 5 DUP(0),2,1,'FILENAMEEXT',25 DUP(0) Метод дескриптора файла: Этот метод требует меньшей подготовки чем метод FCB. Для него Вы должны только создать строку, указывающую путь к файлу, такую как в стандартных командах DOS. Например B:COMPILE\UTILITY\PASCAL указывает на файл PASCAL в подкаталоге UTILITY. Строка ограничена длиной в 63 символа, включая имя накопителя. При открытии файла (с использованием функции 3DH прерывания 21H - см. [5.3.3]), DS:DX должны указывать на первый байт этой строки. Система выпол- няет всю работу по анализу строки и нахождению файла, а после того как файл открыт она возвращает 16-битный идентификационный номер файла в AX. Его называют номером файла и он используется во всех последующих операциях с этим файлом. Буфера данных: Программа должна указать место в памяти, куда должны помещать- ся принимаемые данные или откуда должны браться выводимые. Это пространство в памяти может быть временным буфером, который будет использоваться данными как промежуточная станция. Или это прост- ранство может быть именно тем местом, где данные реально обраба- тываются. Обычно временный буфер устанавливается размером в одну запись и бывает удобно описать его как строковую переменную в сегменте данных, как это сделано в нижеприведенном примере. С другой стороны, большие рабочие области данных должны распреде- ляться с помощью методов распределения памяти, предоставляемых операционной системой [1.3.1]. Ведь создание, например, области данных размером в 10000 байт в сегменте данных сделает программу на диске на 10000 байт длиннее, что совершенно ненужно. Буфер используемый методом FCB доступа к файлам называется областью обмена с диском или DTA. На этот буфер указывает словный указатель, который хранится операционной системой и который может быть изменен Вашей программой. В фирменной документации этот указатель на DTA часто сам называют DTA. Поскольку указано только начало буфера, то ничто не мешает данным занять область прилегаю- щую к DTA, поэтому Вы сами должны следить, чтобы этого не прои- зошло. Указатель на DTA устанавливается специальной функцией DOS и после того как он установлен все функции чтения/записи автома- тически обращаются к нему. Это означает, что сами функции не должны содержать адрес временного буфера. Когда DTA совпадает с областью данных, в которой обрабатывают- ся данные, то необходимо постоянно менять DTA, с тем чтобы файло- вые операции могли получать доступ к различным фрагментам данных. При простой операции последовательного чтения или при операции чтения одного блока с прямым доступом система автоматически поме- щает в DTA одну запись за другой. Необходимо отвести пространст- во, достаточное для числа записей, которые будут затребованы программой. DTA не может иметь размеры больше одного сегмента (64K). Для установки указателя на DTA используйте функцию 1AH преры- вания 21H. DS:DX должны указывать на первый байт DTA, а затем надо выполнить функцию. Это все что нужно. Вот пример: ;---в сегменте данных DTA 256 DUP (?) ;---установка DTA LEA DX,DTA ;DS:DX указывают на DTA MOV AH,1AH ;функция установки DTA INT 21H ;установка DTA Функция 2FH прерывания 21H сообщает текущую установку указате- ля DTA. У нее нет входных регистров. При возврате ES:BX содержат сегмент и смещение DTA. Префикс программного сегмента [1.3.0] обеспечивает каждую программу 128-байтным встроенным DTA, начиная со смещения 80H и до 9FH. Вы можете использовать его при нехватке памяти. Первона- чально указатель на DTA указывает именно на этот буфер, поэтому если Вы будете использовать его, то нет нужды устанавливать ука- затель. Этот буфер по умолчанию особенно удобно использовать с COM файлами, где DS указывает на начало префикса программного сегмента. Для файлов EXE может потребоваться небольшой добавочный код, чтобы использовать DTA по умолчанию. Отметим, что для опре- деления текущей установки указателя на DTA Вы должны использовать функцию 2FH прерывания 21H. У нее нет входных регистров, а при выходе ES:BX указывают на DTA. Указатель на DTA не используется при доступе к файлу методом дескриптора файла. Функции чтения или записи данных всегда содер- жат адрес, по которому расположен буфер данных. Целиком на Вашей совести лежит определение того, будут ли данные передаваться через временный буфер или непосредственно в то место, где они будут использоваться. 5.3.6 Анализ информации командной строки. При запуске многие программы позволяют пользователю поместить добавлчную информацию в командной строке, обычно указывающую имя файла, с которым программа будет работать. Эта информация записы- вается в 128-байтную область, начинающуюся со смещения 80H в префиксе программного сегмента [1.3.0]. (Эта же область исполь- зуется как DTA по умолчанию, как обсуждалось в [5.3.5].) Первый байт содержит длину строки, а затем идет сама строка. Для программ, использующих метод дескриптора файла для работы с файлами, имя файла, вводимое в командной строке, должно иметь адекватную форму. Требуется, чтобы пользователь программы исполь- зовал стандартный протокол MS DOS для строки пути. С другой сто- роны, управляющий блок файла требует, чтобы строка вида 'A:ACCT.- BAK' была преобразована к виду 1,'ACCT BAK'. MS DOS имеет специальную функцию, которая выполняет такое преобразование над первой порцией информации, следующей за именем программы в ко- мандной строке. Эта процедура называется разбором строки (par- sing). Средний уровень. Имя файла должно быть первой информацией, следующей за именем загружаемой программы. Оно должно быть отделено от имени програм- мы одним из следующих символов : . ; , = + табуляцией или пробе- лом. Конец имени файла должен быть указан одним из символов : . ; , = + \ < > | / " [ ] табуляцией, пробелом или одним из управляю- щих символов (коды ASCII от 1 до 31). Функция 29H прерывания 21H производит разбор имени файла. DS:SI должны указывать на смещение 81H в PSP. Помните, что при загрузке программы как DS, так и ES указывают на начало PSP. ES:DI должны указывать на область памяти, которая будет служить управляющим блоком для нового файла. Установка битов в AL опреде- ляет как будет выполняться разборка. Имеют значение только биты 0-3: бит 0 1 = начальный ограничитель игнорируется 1 1 = байт, идентифицирующий накопитель, устанавливается в FCB, только если он указан в командной строке 2 1 = имя файла в FCB меняется только если командная строка содержит имя файла 3 1 = расширение файла в FCB меняется только если коман- ная строка содержит расширение файла После того как эта информация установлена, программа может вызы- вать функцию. Если в командной строке не указан накопитель, то берется накопитель по умолчанию. Если отсутствует расширение файла, то предполагается, что оно пробельное (ASCII 32). Если в имени файла указана звездочка, то она заменяется на нужное число вопросительных знаков в поле имени файла FCB. AL возвращает 1, если имя файла содержит * или ? и FF, если указан неверный нако- питель. При возврате DS:SI указывают на первый символ, следующий за именем файла, которое начинается со смещения 81H. Дальнейшая информация, содержащаяся в командной строке должна расшифровы- ваться Вашей программой. ES:DI указывают на первый байт вновь сформированного FCB. Если в FCB не создано допустимого имени файла, то содержимое ES:[DI]+1 равно пробелу. Вот пример, который помещает код в область FCB в PSP, начиная со смещения 5CH: ;---разбираем командную строку, создавая FCB со смещением 5CH ;---в PSP MOV AH,29H ; MOV SI,81H ; MOV DI,5CH ; MOV AL,1111B ; INT 21H ; MOV AL,ES:[DI]+1 ; CMP AL,32 ; JE ERROR_ROUTINE ; Раздел 4. Чтение и запись файла. Имеются два основных метода доступа к файлу - последовательный и прямой. Хотя в вычислительной литературе часто используют тер- мины "последовательный" файл и файл "прямого доступа", сами по себе файлы хранятся на диске одинаково: как непрерывная последо- вательность байтов. Ни в каталоге ни в каком-либо другом месте нет индикатора, указывающего, что данный файл является последова- тельным или файлом прямого доступа. Реально эти два типа файлов различаются по расположению данных в них и по методу доступа к ним. К любому файлу прямого доступа можно получить последователь- ный доступ, а к любому последовательному файлу - прямой доступ, хотя редко имеются причины делать это, особенно во втором случае. Последовательные файлы помещают элементы данных один за дру- гим, независимо от их длины, разделяя эти элементы парой симво- лов, сначала возвратом каретки (ASCII 13), а затем переводом строки (ASCII 10). Языки высокого уровня, такие как Бейсик, вставляют эти символы автоматически, в то время как программы на ассемблере должны сами заботиться о вставке этих символов после записи каждой переменной в файл. В последовательных файлах могут храниться как числа, так и строки. Строки требуют по одному байту на каждый символ строки. Числа по соглашению записываются в стро- ковом виде, хотя они могут писаться и в числовом виде. Таким образом Бейсик записывает значение "128" в виде строки из трех цифр, хотя программа на ассемблере может записать это число в виде двухбайтного целого или даже однобайтного кода - все опреде- ляется тем, что при повторном чтении файла программа должна пони- мать используемый формат. Для соместимости рекомендуется записы- вать числа в виде строк. Необязательно, чтобы каждое число строки было отделено парой возврат каретки/перевод строки, однако если эта пара опущена, то программа должна обеспечить способ отделения данных. Например, 10 целых чисел могут быть записаны как 20-байтный элемент данных. С другой стороны, очень большие элементы данных, такие как парагра- фы текста, могут быть разделены на несколько элементов данных (стандартный текстовый файл представляет из себя документ, разби- тый на строки удобного размера, записанные последовательно). Поскольку элементы данных имеют переменную длину, то невозможно узнать где в файле расположен определенный элемент. Поэтому для того чтобы найти нужный элемент программа должна читать файл, начиная с начала и отсчитывая нужное число пар возврат карет- ки/перевод строки. По этой причине файлы такого формата называют последовательными. Как правило с диска в память передается весь такой файл. Файлы прямого доступа заранее отводят фиксированное место под каждый элемент данных. Если какой-то элемент данных не занимает все отведенное пространство, то остаток заполняется пробелами. Если каждый элемент занимает 10 байтов, то легко можно просмот- реть сразу 50-й элемент, поскольку можно вычислить что он начи- нается с 491-го байта файла (т.е. с байта #490, поскольку отсчет начинается с 0). Как правило связанный набор элементов группи- руется в запись. Каждая запись содержит несколько полей, которые создают набор номеров байтов, начиная с которых пишутся данные элементы. Например, запись может иметь поля возраст, вес и рост. Соответствующие поля могут занимать 2, 3 и 5 байтов. Вместе они образуют запись длиной в 10 байтов. Файл прямого доступа может состоять из тысяч таких записей. Каждая запись следует непос- редственно за предшествующей без всяких ограничителей, таких как пары возврат каретки/перевод строки, используемые в последова- тельных файлах. При этом записи могут писаться в любом порядке и можно записать запись 74, хотя запись 73 еще не была записана (при этом записи 73 отведено дисковое пространство и она будет содержать те данные, которые случайно оказались в том секторе, в котором отведено место для этой записи). В отличии от последова- тельных файлов файлы прямого доступа остаются на диске. В памяти присутствуют только определенные записи, с которыми идет работа в данный момент времени. Когда для прямого доступа к файлу используется управляющий блок файла, то системе сообщается размер записи файла (все записи данного файла должны иметь одинаковую длину). Это позволяет прог- рамме запросить любую запись по номеру, а MS DOS точно вычислит где эта запись расположена на диске. При работе с файлами прямого доступа методом дескриптора файла программа должна сама вычислять положение требуемой записи. Система хранит файловый указатель для каждого буфера файла. Он указывает на n-ный байт файла, определяя место в файле, с которо- го будет начинаться следующая операция чтения или записи. При последовательной операции перезаписи файловый указатель первона- чально устанавливается на начало файла и постоянно сдвигается по мере того, как все новые и новые данные записываются в файл. Когда данные добавляются к последовательному файлу, то файловый указатель первоначально устанавливается на конец файла. При дос- тупе к одной записи в файле прямого доступа положение записи вычисляется в виде смещения относительно начала файла и указатель устанавливается равным этому значению; затем нужная запись чи- тается или пишется. Обычно за файловым указателем следит система, однако программа может сама управлять им и манипулировать указа- телем для своих специальных нужд. Единственным примером низкого уровня в данном разделе является чтение/запись одного сектора. Чтение или запись целых файлов состоит в последовательности таких чтений или записей одного сектора, программируя микросхему контроллера НГМД заново для каждого сектора. Полномасштабные файловые операции очень сложны на этом уровне, что следует хотя бы из больших размеров файла COMMAND.COM. Однако, изучив обсуждение операций низкого уровня, а также имея информацию о таблице размещения файлов [5.1.1] и дис- ковых каталогах [5.2.1] Вы можете представить как работает дис- ковая операционная система. 5.4.1 Программирование контроллера НГМД 765 и микросхемы прямого доступа к памяти 8237. Микросхема контроллера НГМД 765 фирмы NEC управляет мотором и головками накопителя на дискетах и обрабатывает потоки данных, направляемые в или из дисковых секторов. Один контроллер, уста- новленный на плате адаптора дисков, может обслуживать до четырех НГМД. За исключением случаев, связанных с защитой от копирования, программистам не приходится программировать микросхему контролле- ра НГМД прямо. Процедуры работы с дисками, предоставляемые DOS и BIOS эффективны и удобны, кроме того, очень рисковано писать свои собственные процедуры, поскольку ошибки в них могут разрушить дисковый каталог или таблицу размещения файлов, что вызовет пол- ное разрушение информации на диске. Нижеследующее обсуждение служит цели дать Вам только общее представление. Листинг ROM-BIOS, приведенный в конце каждого технического руководства по MS DOS, содержит код тщательно разра- ботанных процедур для форматирования дискет, чтения и записи секторов, а также сброса и получения статуса накопителей. После того, как Вы усвоите приведенный здесь материал, изучите процеду- ры ROM-BIOS для продолжения Вашего образования в области операций с дисками на низком уровне. Вам потребуется также документация по микросхеме контроллера НГМД 8272A фирмы Intel, которая аналогична микросхеме фирмы NEC. В данной документации перечислены прерыва- ния, генерируемые контроллером НГМД, в то время как в документа- ции по IBM PC этого списка нет. Информация о микросхеме 8272A может быть найдена во втором томе Справочника по компонентам микросистем (Microsystem Components Handbook). Контроллер НГМД может выполнять 15 операций, из которых здесь будут обсуждаться только три: операции поиска и чтения или записи одного сектора. Понимание того как они работают позволит Вам выполнить любую из оставшихся двенадцати, при условии, что у Вас будет вышеупомянутая информация. Чтение файла состоит в поиске его в каталоге [5.2.1], определении его положения на диске с помощью таблицы размещения файлов [5.1.1] и затем наборе операций чтения одного сектора. Эта процедура включает 6 шагов: 1. Включение мотора и короткое ожидание, пока он наберет обороты. 2. Выполнение операции поиска и ожидание прерывания, указывающего на завершение этой операции. 3. Инициализация микросхемы DMA для пересылки данных в память. 4. Посылка команды чтения контроллеру НГМД и ожидание прерывания, указывающего, что пересылка данных завершена. 5. Получение информации о статусе контроллера НГМД. 6. Выключение мотора. Контроллер НГМД работает через три порта ввода/вывода. На самом деле микросхема имеет больше, чем три регистра, но доступ к большинству из них осуществляется через один порт. Эти три порта такие: 3F2H регистр цифрового вывода 3F4H регистр статуса 3F5H регистр данных Первый шаг состоит в доступе к регистру цифрового вывода. Значение его битов следующее: биты 1-0 выбор накопителя, где 00 = A 01 = B 10 = C 11 = D 2 0 = сброс контроллера НГМД 3 1 = разрешение прерывания FDC и доступа DMA 7-4 1 = включение мотора накопителя D-A (бит 4 = A) Это регистр только для записи, поэтому необходимо заботиться обо всех его битах. В нижеприведенном примере используется накопитель A, поэтому цепочка битов должна выглядеть 00011100. Такая уста- новка битов выбирает накопитель A, сохраняет установленным бит 2, разрешающий работу с НГМД и включает мотор накопителя A. Не сбра- сывайте бит 2 в ноль, так как в этом случае Вам придется произво- дить перекалибровку накопителя, действие, которое необходимо очень редко. "Перекалибровка" накопителя подразумевает возврат его головки на нулевую дорожку. Эта операция осуществляется посылкой простой последовательности команд контроллеру НГМД. Контроллер НГМД уп- равляет текущей позицией головки, за счет запоминания всех изме- нений позиции головки после ее начальной установки на нулевую дорожку. Когда контроллер НГМД сбрасывается, за счет изменения бита 2 регистра цифрового вывода, то значение текущей позиции головки устанавливается в ноль, независимо от того, на какой дорожке находится головка на самом деле, что делает необходимым перекалибровку. Обычно сброс контроллера НГМД производится только в случае такой серьезной ошибки накопителя, после которой неиз- вестно текущее состояние контроллера НГМД и накопителя. Отметим, что выбор накопителя и включение его мотора - это отдельные действия. Контроллер НГМД может иметь доступ только к одному накопителю в данный момент времени, но мотры могут быть включены у нескольких. Моторы могут оставаться включенными еще несколько секунд после завершения обмена данными, в ожидании следующего доступа к накопителю. Такая стратегия позволяет избе- жать потери времени на повторное ожидание пока мотор наберет скорость. Напротив, мотор нельзя оставлять постоянно включенным, так как это приведет к преждевременному износу дискет. Работа микросхемы контроллера НГМД разделяется на три фазы: командная фаза, фаза выполнения и фаза результата. В командной фазе один или более байтов посылаются в регистр данных. Последо- вательность байтов строго фиксирована и она меняется от команды к команде. Затем контроллер НГМД выполняет команду и в это время он находится в фазе выполнения. Наконец, во время фазы результата, ряд байтов статуса считываются из регистра данных. При этом обя- зательно, чтобы не было ошибки в числе передаваемых или считывае- мых данных в регистр данных в фазах командной и результата. Число байтов команды и результата меняется в зависимости от выполняемой контроллером дисковой операции. В техническом руко- водстве по IBM PC приведены данные для всех 15 операций. Первый байт команды является кодом, определяющим требуемую операцию. Номер кода содержится в младших 5-ти битах байта и в некоторых случаях в старших трех битах закодирована добавочная информация. В большинстве случаев второй байт команды содержит номер накопи- теля (0-3) в младших двух битах и номер головки (0 или 1) в бите 2, все остальные биты игнорируются контроллером НГМД. При опера- ции поиска требуется дополнительно еще только один байт, в кото- ром должен содержаться номер новой дорожки. Чтение или запись сектора требует семи дополнительных командных байтов, которые идентичны в этих двух случаях. Байты с третьего по пятый содержат текущий номер дорожки, номер головки и номер сектора. За ними следуют четыре байта, содержащие техническую информацию, необхо- димую для контроллера НГМД. Первый байт этой технической информации относится к числу байтов в секторе, которое кодируется как 0 для 128, 1 для 256, 2 для 512 и 3 для 1024. Конечно дискеты, созданные в MS DOS имеют сектора размером 512 байт. Затем идут данные конца дорожки (EOT), которые дают максимальный номер сектора для цилиндра; это значе- ние равно 9 для дискет емкостью 360K. Наконец, идет байт дающий длину сдвига (GPL, равный 2AH) и длину данных (DTL, равный FFH). Техническое руководство по IBM PC содержит таблицу, в которой объясняются другие вхожные параметры, например те, которые ис- пользуются при форматировании диска. MS DOS хранит четыре техни- ческих параметра в памяти, в специальной таблице параметров, называемой базой диска (disk base). Вектор прерывания 1EH указы- вает на эту таблицу. Четыре значения хранятся в том порядке, в котором они должны быть переданы контроллеру НГМД, начиная со смещения 3. В следующей таблице показана командная последователь- ность для трех операций, используемых в нижеприведенном примере. В цепочках битов черех X обозначены биты, значение которых несу- щественно, через H - номер головки, а через DD - номер накопите- ля. Операция # байта Функция Установка для головки 0 дорожки 15, сектора 1 Поиск 1 номер кода 00001111 1FH 2 головка и накопитель 00H XXXXXHDD Чтение 1 номер кода 01100110 66H сектора 2 головка и накопитель 00H XXXXXHDD 3 номер дорожки 0FH 4 номер головки 00H 5 номер сектора 01H 6 байтов в секторе 02H 7 конец дорожки 09H 8 длина сдвига 1AH 9 длина данных FFH Запись 1 номер кода 01000101 45H сектора 2-9 те же, что и для чтения сектора Вы должны быть уверены, что контроллер НГМД готов прежде чем Вы пошлете или прочитаете байт из регистра данных. Биты 7 и 6 регистра статуса предоставляют эту информацию. Вот значение битов этого регистра: биты 3-0 1 = накопитель D-A в режиме поиска 4 1 = контроллер НГМД выполняет команду чтения/записи 5 1 = контроллер НГМД не в режиме DMA 6 1 = регистр данных контроллер НГМД готов к приему данных 0 = готов к посылке данных 7 1 = контроллер НГМД готов к посылке или приему данных Перед началом дисковых операций неплохо проверить, что бит 6 равен нулю, индицируя что контроллер НГМД ожидает команду. Если он ожидает посылки данных, то произошла ошибка. Когда байт данных посылается в регистр данных, то бит 7 регистра статуса становится равным нулю; продолжайте чтение регистра до тех пор, пока бит не изменится обратно на 1, а затем посылайте следующий байт команды. Аналогично, проверяйте этот бит статуса перед чтением байта ста- туса в фазе результата. Нижеприведенный пример кончается двумя процедурами, которые выполняют эти функции. Когда операция поиска завершена, то контроллер НГМД инициирует прерывание 6, прерывание от НГМД. Хотя так же просто можно узнать об окончании операции поиска проверяя регистр статуса, в примере это делается за счет обработки прерывания. Когда происходит пре- рывание, то обработчик прерывания BIOS устанавливает бит 7 байта статуса поиска в области данных BIOS, расположенного по адресу 0040:003E. Это единственный результат обработки прерывания. Можно проверять этот байт до тех пор, пока бит 7 не будет установлен, а затем переходить к следующему шагу операции чтения сектора. Следующий шаг состоит в инициализации микросхеиы прямого дос- тупа к памяти 8237. Эта микросхема занимается обменом данных между периферийными устройствами и памятью, работой, которой может заниматься также процессор. На самом деле, в PCjr, где нет микросхемы DMA, контроллер НГМД посылает данные прямо в процес- сор, который в свою очередь пересылает их в память. Тактовая частота процессора адекватна этой задаче, однако при пересылке данных все прерывания должны быть запрещены, с тем чтобы не происходило потери данных. Это означает, что в PCjr при передаче данных ввод с клавиатуры или из модема запрещен. Прерывания тай- мера также игнорируются, однако впоследствии счетчик времени суток обновляется специальной процедурой, использующей канал 1 микросхемы таймера 8253 для подсчета импульсов, прошедших за время дисковых операций. Все остальные модели IBM PC имеют мик- росхему DMA, поэтому процессор свободен при передаче данных. IBM PC и XT используют 4-хканальную микросхему DMA 8237. Канал 0 предназначен для "освежения" памяти (memory refresh); он пос- тоянно восстанавливает заряд ячеек оперативной памяти. Если Вы будете работать по этому каналу, то это приведет скорее всего к краху машины. Канал 2 предназначен для дисковых операций, а два дру