ES:BX, с тем чтобы они указывали на заго- ловок запроса, а затем читает кодовый номер команды. По этому коду процедура обработки прерывания вызывает нужную процедуру, которая выполнит требуемую функцию. Процедура ищется с помощью 13-словной таблицы, содержащей смещения для 13 типов функций. Функции всегда перечисляются в следующем порядке: 1. INITIALIZE (инициализация) 2. CHECK_MEDIA (проверка носителя) 3. MAKE_BPB 4. IOCTL_IN 5. INPUT_DATA (ввод данных) 6. NONDESTRUCT_IN 7. INPUT_STATUS (статус ввода) 8. CLEAR_INPUT (очистка ввода) 9. OUTPUT_DATA (вывод данных) 10. OUTPUT_VERIFY (проверка вывода) 11. OUTPUT_STATUS (статус вывода) 12. CLEAR_OUTPUT (очистка вывода) 13. IOCTL_OUT После завершения процедуры, процедура обработки прерывания завершается инструкцией RET и управление возвращается в вызываю- щую программу. Драйвер устройства может включать код для обработ- ки только некоторых функций, в зависимости от устройства и тре- буемой степени контроля ошибок и управления устройством. Номера функций, для которых не написаны процедуры, должны завершаться выходом из драйвера без выполнения чего-либо. В этом случае надо только перед выходом установить биты 15, 8, 1 и 0 в заголовке запроса, чтобы информировать вызывающую задачу, что была затребо- вана несуществующая функция (бит 15 индицирует ошибку, бит 8 показывает, что драйвер работает нормально, а биты 0 и 1 дают код ошибки 3, что соответствует "неизвестной команде"). Но одна функция должна присутствовать во всех драйверах уст- ройств, и это функция номер 1 - инициализация. Эта функция авто- матически выполняется при загрузке драйвера, а затем нет. Одна из важных задач, выполняемая этой процедурой, состоит установке адреса конца драйвера в четырех байтах, начинающихся со смещения 14 в заголовке запроса. В нижеприведенном примере конец программы отмечен меткой eop:. Кроме этой задачи, процедура инициализации должна также выполнить всю необходимую для данного устройства инициализацию. На рис. 7-4 показана структура драйвера устройст- ва. Какие из оставшихся 12-ти функций будут включены в драйвер устройства зависит от того, что драйвер должен делать. Некоторые, такие как CHECK_MEDIA и MAKE_BPB, относятся только к блочным устройствам (они устанавливают тип диска, размер секторов и т.д.). Для символьных устройств наиболее важными являются две функции: INPUT_DATA и OUTPUT_DATA (отметим, что эти имена несу- щественны - важна позиция в таблице функций, которая неизменна). В обоих случаях заголовок запроса имеет следующую структуру: 13 байтов стандартный формат заголовка запроса 1 байт байт описания среды (только для блочных устройств) 4 байта смещение/сегмент буфера обмена данных 2 байта число байтов, которое надо передать 2 байта стартовый номер сектора (только для блочных) В нижеприведенном примере используется функция вывода. Процедура, выполняющая вывод получает из заголовка запроса адрес буфера, в котором находятся выводимые данные (смещение 14). Она также счи- тывает число байтов, которое надо вывести (смещение 18). Когда процедура завершит вывод данных, то она установит слово статуса в заголовке запроса (смещение 3) и возвратит управление. Если опе- рация успешна, то надо установить бит 8 слова статуса. Другие возможности будут обсуждены позднее. Низкий уровень. В данном примере приведена общая форма процедуры обработки прерывания, не включая реального кода, управляющего устройством. ;---инициализация обработчика прерывания устройства DEV_INTERRUPT: PUSH ES ;сохраняем регистры PUSH DS PUSH AX PUSH BX PUSH CX PUSH DX PUSH SI PUSH DI PUSH BP MOV AX,CS:KEEP_ES ;ES:BX указывают на заголовок запроса MOV ES,AX ; MOV BX,CS:KEEP_BX ; MOV AL,ES:[BX]+2 ;получаем код команды из заголовка SHL AL,1 ;умножаем на 2 (т.к. таблица словная) SUB AH,AH ;обнуляем AH LEA DI,FUNCTIONS ;DI указывает на смещение до таблицы ADD DI,AX ;добавляем смещение в таблице JMP WORD PTR [DI] ;переходим на адрес из таблицы FUNCTIONS LABEL WORD ;это таблица функций DW INITIALIZE DW CHECK_MEDIA DW MAKE_BPB DW IOCTL_IN DW INPUT_DATA DW NONDESTRUCT_IN DW INPUT_STATUS DW CLEAR_INPUT DW OUTPUT_DATA DW OUTPUT_VERIFY DW OUTPUT_STATUS DW CLEAR_OUTPUT DW IOCTL_OUT ;---выход из драйвера, если функция не поддерживается CHECK_MEDIA: MAKE_BPB: IOCTL_IN: INPUT_DATA: NONDESTRUCT_IN: INPUT_STATUS: CLEAR_INPUT: OUTPUT_VERIFY: OUTPUT_STATUS: CLEAR_OUTPUT: IOCTL_OUT: OR ES:WORD PTR [BX]+3,8103H ;модифицируем статус JMP QUIT ;---процедуры для двух поддерживаемых кодов INITIALIZE: LEA AX,E_O_P ;смещение конца программы в AX MOV ES:WORD PTR [BX]+14,AX ;помещаем его в заголовок MOV ES:WORD PTR [BX]+16,CS ; . (здесь идет инициализация устройства) . JMP QUIT OUTPUT_DATA: MOV CL,ES:[BX]+18 ;получаем число символов CBW CX ;CX используем как счетчик MOV AX,ES:[BX]+16 ;получаем адрес буфера данных MOV DS,AX ; MOV DX,ES:[BX]+14 ; . (здесь идут операции по выводу) . JMP QUIT ;---выходим, модифицируя байт статуса в заголовке запроса QUIT: OR ES:WORD PTR [BX]+3,100H ;устанавливаем бит 8 POP BP ;восстанавливаем регистры POP DI ; POP SI ; POP DX ; POP CX ; POP BX ; POP AX ; POP DS ; POP ES ; RET E_O_P: ;метка конца программы DEVICE12 ENDP CSEG ENDS END DEVICE12 Перед возвратом драйвер устанавливает слово статуса в заголов- ке запроса. В данном примере это делается в двух местах, в зави- симости от того вызывалась функция обеспечиваемая драйвером или нет. Эти строки выглядят так: OR ES:WORD PTR [BX]+3,XXXXH. Значе- ние битов XXXX следующее: биты 0-7 код ошибки (если бит 15 = 1) бит 8 устанавливается в 1, когда функция завершена бит 9 устанавливается в 1, когда драйвер занят биты 10-14 зарезервированы MS DOS бит 15 устанавливается при возникновении ошибки Младший байт этого слова содержит следующие коды ошибок, если установлен бит 15, индицирующий ошибку: 0 попытка записи на защищенное от записи устройство 1 неизвестное устройство 2 устройство не готово 3 неизвестная команда 4 ошибка проверки по контрольной сумме 5 неверная длина запроса к устройству 6 ошибка поиска 7 неизвестный носитель 8 сектор не найден 9 нет бумаги в принтере A ошибка записи B ошибка чтения C общая ошибка 7.2.4 Доступ к драйверу устройства. Драйвер устройства устанавливается путем включения имени гото- вой программы в файл конфигурации системы. Для установки пробной программы поместите в файл CONFIG.SYS строку DEVICE = DEVI- CE12.COM. Затем перезагрузите систему для установки драйвера. Если машина не будет загружаться, то скорее всего имеется ошибка в коде инициализации драйвера. После того как драйвер установлен, для доступа к нему пользуй- тесь обычными функциями MS DOS прерывания 21H. Какие функции можно использовать зависит от того, заменяет ли устройство стан- дартное устройство DOS (как в приведенном примере) или оно добав- ляется как совершенно новое устройство. Для замены стандартного последовательного устройства, назовите драйвер AUX, после чего функции 3 [7.1.7] и 4 [7.1.6] прерывания 21H будут осуществлять соответственно ввод и вывод. Если устройство параллельное, то назовите его PRN, после чего функция 5 [6.3.1] будет выводить данные на принтер. Другой возможностью является использование функции 3FH [5.4.4] для ввода и [5.4.3] для вывода. В этом случае используйте номер файла 3 - для последовательного устройства и 4 - для параллельного. Напоминаем, что при использовании предопре- деленных номеров файла нет необходимости открывать устройство. Если устройство не заменяет одно из стандартных устройств MS DOS (т.е. если оно не названо одним из резервных слов, таким как PRN, AUX и т.д.), то Вы можете открыть устройство с помощью одной из функций для открытия файла. Вы можете использовать как метод доступа с помощью управляющего блока файла, так и метод дескрип- тора файла, хотя последний предпочтительнее. Чтобы быть уверен- ным, что Вы по ошибке не откроете дисковый файл, поместите номер файла в BX, 0 - в AL, посде чего выполните функцию 44H прерывания 21H. Это функция IOCTL и если бит 7 значения, возвращаемого в DL установлен, то драйвер устройства загружен. IOCTL требует, чтобы в байте атрибутов драйвера была соот- ветствующая установка битов и чтобы по крайней мере основы проце- дуры обработки IOCTL имелись в процедуре обработчика прерывания драйвера. Функция IOCTL имеет 8 подфункций, пронумерованных от 0 до 7, при этом соответствующий кодовый номер помещается в AL при вызове функции: 0 Возвратить информацию об устройстве в DX 1 Установить информацию об устройстве, используя DL (DH=0) 2 Считать CX байтов от драйвера устройства через управля- щий канал и поместить их начиная с DS:DX 3 Записать CX байтов в драйвер устройства через управляющий канал, взяв их начиная с DS:DX 4 То же, что и 2, но использовать номер накопителя в BL, где 0 = накопитель по умолчанию, 1 = A и т.д. 5 То же, что и 3, но использовать номер накопителя как в 5 6 Получить статус ввода 7 Получить статус вывода В ответ возвращается различная информация, в зависимости от того, какая функция вызвана. Для подфункций 0 и 1 значение битов регистра DX следующее (при условии, что бит 7 = 1, что означает, что доступ получен к устройству, а не к файлу): 0 1 = устройство консольного ввода 1 1 = устройство консольного вывода 2 1 = нулевое устройство 3 1 = устройство часы 4 резерв 5 1 = нет проверки на Ctrl-Z, 0 = есть проверка на Ctrl-Z 6 1 = не конец файла, 0 = конец файла 7 1 = устройство, 0 = дисковый файл 8-13 резерв 14 1 = если можно использовать подфункции 2 и 3, 0 = нельзя 15 резерв Подфункции 2-5 позволяют программе и устройству обмениваться произвольными управляющими строками. Это позволяет передавать управляющие сообщения отдельно от основного потока данных, что существенно упрощает дело. При возврате AX будет содержать число переданных байтов. Подфункции 6-7 позволяют программе проверить, готово ли устройство для ввода или вывода. Для устройств в AL возвращается FF, если устройство готово и 0, если нет. При ис- пользовании с открытым файлом (бит 7 = 0) в AL возвращается FF до тех пор, пока не будет доститгнут конец файла. Отметим, что в Бейсике 3.0 добавлены операторы IOCTL и IOCTL$. Они позволяют бейсиковской программе, соответственно, посылать и принимать управляющие строки от драйвера устройства, которое было предварительно открыто оператором OPEN. Выходная строка должна быть заключена в кавычки, как в IOCTL #3,"...". Подобным образом, A$ = IOCTL$(3) принимает информацию о статусе через IOCTL. 7.2.5 Обнаружение и анализ ошибок устройства. Устройства могут ошибаться по одной из трех причин. Устройство может быть физически повреждено или находиться не в том состоя- нии. Может быть плохим программное обеспечение, управляющее уст- ройством. И, наконец, программа может послать устройству недопус- тимый запрос (например, попытка писать на накопитель, где нахо- дится дискета защищенная от записи). MS DOS обнаруживает и анали- зирует большинство таких ошибок и обеспечивает возможности для восстановления. Высокий уровень. Интерпретатор Бейсика обнаруживает многие ошибки, включая ошибки драйверов устройств. При обнаружении ошибки возвращается код ошибки и если не предусмотрена программа восстановления при ошибках, то программа останавливается. Однако можно установить обработку ошибок, с тем чтобы когда происходит критическая ошибка Бейсик автоматически переходил на процедуру восстановления при сбоях, которую Вы создали. Процедура может проанализировать код и определить в какой строке программы произошла ошибка. После того как это сделано, программа может принять меры по устранению ошиб- ки, либо с помощью пользователя, либо выполняя другую часть прог- раммы. После того, как эта процедура завершена, программа может продолжить выполнение с любого места, с которого Вы захотите (с некоторыми ограничениями). Код для тщательного анализа ошибочных ситуаций может существенно увеличить размер программы. Отметим, что компилятора Бейсика даже минимальные проверки на ошибки пот- ребуют дополнительно по не менее чем 4 байта на каждую строку программы. Чтобы разрешить обработку ошибок в Бейсике поместите в начале программы строку ON ERROR GOSUB n, где n это номер строки прог- раммы, в которой начинается процедура обработки ошибок. При воз- никновении критической ошибки управление будет передано на эту строку. В начале процедуры поместите ряд строк вида IF ERR = n THEN номерстроки, где n - номер ошибки, взятый из приложения к руководству по Бейсику, содержащему сообщения об ошибках. Номера строк в этих операторах соответствуют началу кода, обрабатывающе- го данную конкретную ошибку. Эти части могут быть в свою очередь разбиты на куски рядом операторов IF ERL = n THEN номерстроки. ERL возвращает номер строки, в которой произошла ошибка, позволяя процедуре восстановления точно определить ошибочное место. После того как процедура восстановления завершила свою работу надо использовать оператор RESUME для возврата управления в ту строку, где произошла ошибка. За этим оператором может следовать номер, в этом случае управление будет передано на строку с ука- занным номером. Однако, имейте ввиду, что нельзя использовать RESUME для перехода в точку программы, которая находится за пре- делами процедуры, в которой произошла ошибка. Если восстановление после ошибки невозможно, но необходимо, чтобы программа продолжи- ла свою работу, то напишите RESUME NEXT и управление будет пере- дано на строку, следующую за той, в которой произошла ошибка. Вот общая структура процедуры восстановления в Бейсике: 100 ON ERROR GOSUB 5000 'разрешаем обработку ошибок . . 5000 IF ERR = 61 THEN 5100 'диск полон 5010 IF ERR = 71 THEN 5200 'диск не готов . . 5100 IF ERL = 2080 THEN 5120 'где произошла ошибка? 5110 BEEP: PRINT "Disk in drive B: is full": RESUME 5120 BEEP: PRINT "Disk in drive A: is full": RESUME . 5200 BEEP: PRINT "A disk drive is not ready" 5210 PRINT "Strike any key when corrected" 5220 IF INKEY$ = "" THEN 5220 'ожидаем нажатия клавиши 5230 RESUME ERL - 10 'пытаемся повторить операцию В Бейсике 3.0 введены инструкции ERDEV и ERDEV$. Обе они поз- воляют получить переменные только для чтения от прерывания 24H, обрабатывающего критичекие ошибки. Z% = ERDEV возвращает в Z% слово статуса, в котором старший байт содержит 13-15 биты атрибу- та заголовка устройства, а младший байт - код ошибки прерывания 24H. Z$ = ERDEV$ помещает в Z$ 8-байтное имя устройства для сим- вольных устройств и 2-байтный указатель накопителя для блочных устройств. Низкий уровень. Иногда драйверы устройств содержат такие серьезные ошибки, что программа просто не может продолжаться, пока они не будут исправ- лены. Когда такие ошибки происходят, то система вызывает обработ- чик критических ошибок. Он может вступать в действие как для стандартных устройств, так и для установленных драйверов. Пользо- ватель наиболее часто сталкивается с ним, когда пытается произ- вести дисковую операцию с дисководом, у которого открыта дверца. В этом случае появляется сообщение: "Not ready error reading drive A - Abort, Retry, Ignore?" Обработчик критических ошибок может быть переписан, чтобы он лучше обрабатывал устройства, для которых Вы создали устанавли- ваемые драйверы. Вектор прерывания 24H указывает на стандартную процедуру MS DOS, но Вы можете перенаправить вектор на свою про- цедуру. При вызове этой процедуры старший бит AH содержит 0 если ошибка произошла на блочном устройстве и 1, если на символьном. BP:SI указывают на заголовок драйвера виновного устройства, кото- рый может дать дополнительную информацию. Восемь байтов, начиная со смещения AH в заголовке содержат имя устройства, а обработчик критичеких ошибок помещает код ошибки длиной в слово в DI. Вот кодовые номера (они не представляют битовых позиций): Код Проблема 0 попытка писать на диск, защищенный от записи 1 неизвестное устройство 2 накопитель не готов 3 неизвестная команда 4 ошибка обмена данными 5 неверная длина запроса 6 ошибка поиска 7 неизвестный тип носителя 8 сектор не найден 9 нет бумаги в принтере A ошибка при записи B ошибка при чтении C общая ошибка В случае дисковой ошибки AL содержит номер накопителя, на котором произошла ошибка (0 = A, 1 = B и т.д.), а биты 2-0 AH индицируют тип ошибки. Бит 0 устанавливается, если ошибка произошла во время операции записи, и сбрасывается - если при чтении. Биты 2-1 со- держат информацию о том, в каком месте диска произошла ошибка, давая 00 - для начальных секторов DOS, 01 - для FAT, 10 - для каталога и 11 - для всего остального диска. Имеется три способа, которыми программа может восстановиться после критической ошибки: 1. Можно попросить пользователя устранить причину ошибки (напри- мер, закрыть дверцу накопителя), после чего система предоставит устройству возможность повторить операцию. 2. Управление может быть возвращено инструкции, следующей за INT 21H, которая сделала попытку обратиться к драйверу. 3. Программа может завершиться и вернуть управление системе. Ваша процедура обработки ошибок может восстановить ситуацию, выдав инструкцию IRET, после того, как она поместила 0 в AL, чтобы игнорировать ошибку, 1 - чтобы повторить операцию и 2 - чтобы завершить программу. Если Вы хотите, чтобы Ваша процедура провела восстановление сама, то она должна восстановить регистры выполняемой программы из стека, а затем удалить со стека все, кроме последних трех слов. После этого инструкция IRET возвратит управление программе, хотя сама система останется в нестабильном состоянии до тех пор, пока она не сделает вызов функции с номером большим, чем 12. Вот конфигурация стека (начиная сверху до низа) когда вызывается обработчик критических ошибок: Адрес возврата обработчика ошибок: IP, CS, флаги Пользовательские регистры задачи, AX, BX, CX, DX, SI, DI, BP, из которой был вызван драйвер: DS, ES, IP, CS, флаги MS DOS обрабатывает также многие некритические ошибки. Сюда включаются коды ошибок, которые могут возвращаться в регистрах, когда вызывалась функция DOS. Эти коды обсуждаются в данной книге в тех местах, в которых описываются соответствующие функции. Однако имейте ввиду, что начиная с версии 3.0 MS DOS возвращает расширенные коды ошибок для функций, использующих FCB или деск- рипторы файлов. Когда при выполнении одной из этих функций уста- навливается флаг переноса, то в AX возвращается обычный код ошиб- ки. Дополнительный расширенный код доступен через прерывание 59H, если в BX поместить 0. Эта функция сообщает также о критических ошибках и она может быть использована из обработчика критических ошибок, вызываемого через прерывание 24H. Функция помещает в AX код ошибки, взятый из обычного списка знакомых кодов ошибок (например, "недостаточно памяти") или один из новых кодов (например, "ограничение доступа" для многопользо- вательской системы). BH возвращает код класса ошибки, указывая какого типа ошибка произошла. Например, код 1 указывает, что исчерпаны ресурсы, т.е. что память, файловые буфера или что-то еще израсходовано. Другие классы могут указывать на программные ошибки, проблемы с носителями, форматированием и т.д. BL содержит код, предполагающий действие для восстановления, такое как "пов- торить", "прекратить" или "запросить у пользователя". Наконец, CH возвращает число, определяющее место где возникли проблемы: на блочном устройстве, на символьном, в памяти? Данные для этих кодов ошибок весьма обширны. Полную информацию о них см. в Техническом руководстве по MS DOS 3.0. Поскольку предполагается, что MS DOS 3.0 не будет использоваться на маши- нах, более ранних, чем AT, то использование этих кодов ограничи- вает совместимость Ваших программ. Тем не менее, набор процедур, предназначенный только для MS DOS 3.0 может дополняться поверх обычных процедур обработки ошибок. В [1.1.3] показано как прог- рамма может определить версию MS DOS, в которой она работает. Наконец, имейте ввиду, что процесс может передавать код завер- шения вызвавшему его процессу. Термин процесс относится к взаимо- действующим программам. Например, когда одна программа загружает и запускает другую с помощью функции EXEC, то запускаемая прог- рамма называется потомком, а запускающая программа - родителем. Родителю может потребоваться информация о том, как завершился потомок. Чтобы использовать эту возможность, поместите желаемый код завершения в AL и выполните функцию 4CH прерывания 21H для завершения программы. Когда управление будет возвращено родителю, то он выполнит функцию 4DH прерывания 21H (без входных регистров) и в AL будет получен код завершения, который может затем быть проанализирован. Кроме того, AH будет содержать информацию о том, как завершился потомок: 0 - для нормального завершения, 1 - по Ctrl-Break, 2 - по критической ошибке устройства и 3 - с помощью функции 31H, оставляющей задачу резидентной. Если программа завершилась с помощью этой функции (а не 20H - см. обсуждение в [1.3.4]), то MS DOS получает код выхода и он может быть включен в обработку командным файлом с помощью подко- манды IF. Эта подкоманда позволяет условное исключение других команд из командного файла. Код выхода рассматривается как номер ERRORLEVEL и условные операции выполняются в зависимости от того, больше он или нет определенного числа. С помощью этой возможности командные файлы могут прекращать обработку и выводить сообющение о возникновении ошибки в одной из запущенных программ. Более подробная информация приведена в разделе "Команды пакетной обра- ботки" руководства по операционной системе. Раздел 3. Использование специальных устройств ввода/вывода. Имеется огромное количество устройств ввода/вывода, которые могут быть присоединены к IBM PC, включая мышь, джойстик, графо- построители и т.д. В данном разделе обсуждаются только те уст- ройства, которые специально поддерживаются оборудованием IBM PC. Сюда относятся кассетные магнитофоны, световое перо и другие устройства, которые могут быть присоединены через игровой порт. Адреса портов, относящиеся к другим устройствам, обсуждаются в других разделах этой книги, относящихся именно к данным устройст- вам. Распределение адресов портов в основном одно и то же для всех типов IBM PC: Адрес порта Функция 00-0F микросхема DMA 8237 (не для PCjr) 20-2F микросхема прерываний 8259 (AT контроллер #1: 20-3F) 40-4F микросхема таймера 8253/8254 60-6F микросхема PPI 8255 (AT использует только адреса клавиатуры 70-7F часы реального времени (только AT) 80-83 регистры страниц DMA (не для PCjr) A0-BF микросхема прерываний #2 (только AT) C0-C7 микросхема звука SN76496 (только PCjr) F0-FF PCjr - контроллер НГМД, AT - управление математиче- ским сопроцессором 1F0-1F8 фиксированный диск AT 200-20F игровой адаптер 278-27F AT коммуникационный порт #2 2F8-2FF коммуникационный порт COM2 (COM1 для PCjr) 320-32F фиксированный диск XT 378-37F адаптер параллельного принтера для PC, XT, AT 3B0-3BF монохромный/параллельный адаптеры (не для PCjr) 3D0-3DF цветной графический адаптер 3F0-3F7 контроллер НГМД 3F8-3FF коммуникационный адаптер COM1 (модем PCjr) 7.3.1 Чтение/запись с кассетного магнитофона. Только очень немногие IBM PC и PCjr используют кассетный маг- нитофон, а XT и AT не поддерживают его вообще. Помимо того, что он очень ненадежен, обмен с кассетным магнитофоном возможен толь- ко последовательный, но не с прямым доступом. Тем не менее, могут быть причины для программирования кассетного магнитофона на PCjr. Имейте ввиду, что кассетные операции используют канал 2 микросхе- мы таймера 8253 [2.1.1], поэтому не пытайтесь одновременно ис- пользовать этот канал для других целей. Отметим также, что при операции чтения с кассеты, запрещено прерывание времени суток, поэтому счетчик времени суток BIOS будет давать неверное значе- ние. Высокий уровень. Хотя кассетные файлы обрабатываются совершенно по-другому чем дисковые файлы, однако команды доступа к ним совершенно аналогич- ны. На кассету могут записываться только программные файлы и пос- ледовательные файлы данных. Последние могут включать файлы изоб- ражения памяти. Отметим, что данные не могут добавляться к после- довательным файлам. При создании, именам файлов даются следующие однобайтные расширения: .B программа на Бейсике .P защищенная программа на Бейсике .A программа на Бейсике в формате ASCII .M файл изображения памяти .D последовательный файл данных Для сохранения файла на кассете напишите SAVE "CAS1:имяфайла". Для загрузки программы - LOAD "CAS1:имяфайла". В последнем случае лента прогоняется до тех пор, пока нужный файл не будет найден, при этом имя каждого встреченного файла будет выводиться на экран (кассеты не используют каталоги). Если запросить несуществующий файл, то будет выведен полный список файлов на кассете. Средний уровень. BIOS работает с кассетной лентой порциями в 256-байтные блоки. Набору блоков предшествует "лидер", который состоит из 256 байтов ASCII 1. Лидер завершается нулевым битом синхронизации. Затем следует байт синхронизации со значением 16H, а затем 256 байтов данных. После этого идут 2 байта контроля ошибок, а затем новый блок данных, сопровождающийся парой байт проверки ошибок и т.д. Вся последовательность завершается четырехбайтным "хвостом", содержащим коды ASCII 1. Для чтения данных с кассеты на до использовать функцию 2 пре- рывания 15H. Нет необходимости открывать файл, как это делается при дисковых операциях. ES:BX указывают на буфер в памяти, куда будут посылаться данные, а CX - число байтов, которые надо счи- тать. При возврате DX сообщит сколько байтов прочитано на самом деле, а ES:BX будут указывать на последний считанный байт плюс 1. Флаг переноса будет равен 0, если чтение прошло успешно, а в противном случае AH будет содержать 1, если проблема с контролем ошибки, 2 - при ошибке чтения данных и 3 - при отсутствии данных на ленте. Функция 3 прерывания 15H записывает данные на кассету. ES:BX указывают на первый байт данных, а CX содержит число байтов, которое надо записать. При возврате ES:BX указывают на байт, следующий за последним записанным. Мотор управляется функциями 0 (включение) и 1 (выключение) прерывания 15H. Для этих функций нет выходных регистров. 7.3.2 Чтение позиции светового пера. Хотя очень немногие компьютеры оснащены световым пером, тем не менее это одно из немногих вспомогательных устройств, которое поддерживается как оборудованием, так и операционной системой. Световое перо работает с помощью небольшого оптического детектора на кончике пера. По ходу сканирования экрана электронным лучом инициируется импульс оптического детектора, когда пучок достигает точки экрана, над которой находится перо. Время возникновения этого импульса, относительно сигналов горизонтальной и вертикаль- ной синхронизации, позволяет определить позицию светового пера. Высокий уровень. Бейсик может определять позицию светового пера двумя способа- ми. При первом программа непрерывно определяет статус пера. При втором, когда перо используется, то управление временно передает- ся процедуре, обеспечиваемой Вашей программой. Для непрерывного контроля за пером надо использовать оператор PEN как функцию в форме X = PEN(n), где n - кодовый номер, определяющий какую ин- формацию Вы хотите получить о пере и его позиции. Возможные зна- чения n такие: 0 возвращает -1, если перо было выключено со времени послед- него запроса, 0 - если нет 1 возвращает последнюю координату x (0-319 или 0-639), в ко- торой перо было включено (оно могло быть впоследствии передвинуто, если оставалось включенным) 2 возвращает последнюю координату y (0-199), в которой перо было включено. 3 возвращает -1, если перо включено и 0 - если нет 4 возвращает текущую x координату (0-319 или 0-639) пера 5 возвращает текущую y координату (0-199) пера 6 возвращает позицию - номер строки (1-24), в которой перо было последний раз активизировано 7 возвращает позицию - номер столбца (1-40 или 1-80), в ко- торой перо было последний раз активизировано 8 возвращает текущую позицию - номер строки (1-24) 9 возвращает текущую позицию - номер столбца (1-40 или 1-80) В данном примере определяется включено ли перо, и если это так, то берется текущее его положение: 100 IF NOT PEN(3) THEN 130 'проверяем включено ли перо 110 X = PEN(4) 'получаем координату точки по оси x 120 Y = PEN(5) 'получаем координату точки по оси y 130 ... 'продолжаем программу Более гибкие возможности использования светового пера предос- тавляются оператором ON PEN GOSUB. Этот оператор указывает номер строки, в которой начинается процедура, активизируемая при вклю- чении пера. Бейсик достигает этого проверкой состояния пера после выполнения каждой его инструкции. Процедура может получить пози- цию пера и предпринять требуемые действия. Когда процедура закан- чивается, то программа продолжается с того места, где она была при включении пера. ON PEN GOSUB не работает до тех пор, пока она не активизирова- на оператором PEN ON. PEN OFF отменяет ее работу. Смысл этого состоит в том, что постоянная проверка статуса пера замедляет работу программы, поэтому ее надо осуществлять только когда это необходимо. Если программа начинает выполнять критичекую часть кода, когда нельзя использовать процедуру ON PEN GOSUB, напишите PEN STOP. В этом случае будет продолжаться проверка статуса пера, и если перо будет включено, то этот факт будет запомнен. Однако пока не будет встречен оператор PEN ON, управление не будет пере- даваться процедуре ON PEN GOSUB. Данный пример вызывает остановку программы, когда нажата кноп- ка на световом пере. Точка в позиции светового пера включается процедурой, обрабатывающей включение светового пера. 100 ON PEN GOSUB 5000 'устанавливаем процедуру для светового 110 PEN ON 'пера и включаем режим отслеживания его . . 5000 '''процедура обработки светового пера 5010 X = PEN(4) 'получаем координату X 5020 Y = PEN(5) 'получаем координату Y 5030 PSET(X,Y) 'включить эту точку 5040 RETURN ' Средний уровень. Функция 4 прерывания 10H BIOS сообщает текущую позицию свето- вого пера. У нее нет входных регистров. При возврате AX содержит 0, если перо не включено и 1 - если получены новые значения для его позиции. Возвращается два набора координат, позиции точки и позиции строки и столбца. Позиции символа содержатся в DX, причем DH содержит строку (0-24), а DL - столбец (0-79). Позиция точки содержится в CH и BX, причем CH содержит вертикальную координату (0-199), а BX - горизонтальную (0-319 или 0-639, в зависимости от режима терминала). ;---читаем и запоминаем положение светового пера MOV AH,4 ;номер функции INT 10H ;прерывание BIOS CMP AH,1 ;новая позиция? JE NO_READING ;если нет, то уходим MOV COL,BX ;сохраняем горизонтальную координату MOV CL,CH ;помещаем вертикальную координату MOV CH,0 ;в CX MOV ROW,CX ;сохраняем вертикальную координату Низкий уровень. По своей сути световое перо является расширением видеосистемы и как таковое использует микросхему контроллера CRT 6845. Позиция светового пера дается одним 2-хбайтным значением, хранящимся в регистрах 10H (старший байт) и 11H (младший байт) микросхемы. В [4.1.1] объясняется как читать регистры микросхемы. Посмотрите пример. Порт с адресом 3DCH устанавливает задвижку светового пера, а с номером 3DBH - сбрасывает ее. ;---проверка светового пера и чтение его позиции MOV DX,3DAH ;указываем на регистр статуса IN AL,DX ;получаем информацию TEST AL,4 ;проверяем выключатель JNZ NOT_SET ;на выход TEST AL,2 ;проверяем триггер JZ NOT_SET ;на выход SUB DX,7 ;указываем на регистр адреса 6845 MOV AL,10H ;запрос на старший байт позиции пера OUT DX,AL ;посылаем запрос INC DX ;указываем на регистр данных 6845 IN AL,DX ;получаем значение XCNG AH,AL ;запоминаем его в AH DEC DX ;возвращаемся к адресному регистру MOV AL,11H ;теперь хотим получить младший байт OUT DX,AL ;посылаем запрос INC DX ;назад к регистру данных IN AL,DX ;теперь это значение в AX 7.3.3 Получение аналогового ввода через игровой порт. Игровой порт может поддерживать 2 джойстика или 4 "весла". Для джойстика он сообщает две координаты и статус двух кнопок; для весла он сообщает одну координату и статус одной кнопки. Несколь- ко вспомогательных устройств, таких как графическое табло, также может быть подключено к игровому порту; их работа может осуществ- ляться параллельно с работой джойстика. Данный раздел посвящен чтению координат, а в следующем обсуждается как получить статус кнопок. Высокий уровень. Функция STICK возвращает позиции по осям, указываемую следую- щими кодовыми номерами: 0 ось X джойстика A 1 ось Y джойстика A 2 ось X джойстика B 3 ось Y джойстика B Вам нужно написать, например, X = STICK(0) и в X будет содержать- ся значение координаты X для джойстика A. Но эта функция имеет ловушку, о которой Вам необходимо знать. Только при использовании кода 0 действительно читаются координаты джойстика, при этом читаются все 4 значения. Кодовые номера 1-3 просто сообщают пока- зания, прочитанные кодом 0. Чтобы получить последние 3 координаты Вам необходимо перед этим использовать функцию X = STICK(0), даже если Вам не нужно знать значение, возвращаемое кодом 0. Джойстики отличаются по своим физическим характеристикам, поэтому необходимо настраивать их, чтобы их предельные положения совпадали с границами экрана. В следующем примере показано как это делается. В примере непрерывно рисуется точка, в позиции, указываемой джойстиком, действие, которое требуется, чтобы диапа- зон значений, принимаемых игровым портом, преобразовывался в диапазон позиций экрана. 100 '''получаем предельные показания джойстика 110 STRIG ON 'разрешаем кнопки 120 V= STRIG(0) 'чистим старые показания 130 PRINT "Briefly push button 1 when stick is farthest to left" 140 XLEFT = STICK(0) 'получаем самое левое значение 150 IF STRIG(0) = 0 THEN 140 'ждем нажатия кнопки 160 STRIG OFF: FOR N = 1 TO 1000: NEXT: STRIG ON 170 PRINT "Briefly push button 1 when stick is farthest to right" 180 XRIGHT = STICK(0) 'получаем самое правое значение 190 IF STRIG(0) = 0 THEN 180 'ждем нажатия кнопки 200 STRIG OFF: FOR N = 1 TO 1000: NEXT: STRIG ON 210 PRINT "Briefly push button 1 when stick is farthest to top" 220 V = STICK(0): YTOP = STICK(1) 'самое верхнее значение 230 IF STRIG(0) = 0 THEN 220 'ждем нажатия кнопки 240 STRIG OFF: FOR N = 1 TO 1000: NEXT: STRIG ON 250 PRINT "Briefly push button 1 when stick farthest to bottom" 260 V = STICK(0): YBOTTOM = STICK(1) 'самое нижнее значение 270 IF STRIG(0) = 0 THEN 260 'ждем нажатия кнопки 280 STRIG OFF 'закончили 290 '''получаем множители для установки на размер экрана 300 XRIGHT = XRIGHT - XLEFT 'горизонтальный размер 310 XMULTIPLIER = 320/XRIGHT 'вычисляем число точек на деление 320 YBOTTOM = YBOTTOM - YTOP 'вертикальный размер 330 YMULTIPLIER = 200/B/YBOTTOM 'число точек на деление 340 '''теперь вычисляем координаты в режиме умеренного разрешения 350 X = STICK(0) 'получаем горизонтальную позицию 360 Y = STICK(1) 'получаем вертикальную позицию 370 X = (X - XLEFT)*XMULTIPRIER 'приводим к экрану 380 Y = (Y - YTOP)*YMULTIPRIER ' 390 PSET(X,Y) 'выводим точку в нужной позиции 400 GOTO 350 'повторяем Средний уровень. Только AT предоставляет поддержку джойстика на уровне опера- ционной системы. Это функция 84H прерывания 15H, которая возвра- щает координаты, причем: AX = координата X джойстика A BX = координата Y джойстика A CX = координата X джойстика B DX = координата Y джойстика B При входе поместите в DX 1. Когда в DX содержится 0, то эта функ- ция возвращает состояние кнопок джойстика [7.3.4]. При возврате флаг переноса установлен, когда у машины нет игрового порта. Низкий уровень. Информация о координатах обоих джойстиков или всех четырех весел хранится в одном байте, доступ к которому осуществляется через порт 201H. Вот значение его битов: Бит Джойстик Весло 3 координата Y джойстика B координата весла D 2 координата X джойстика B координата весла C 1 координата Y джойстика A координата весла B 0 координата X джойстика A координата весла A Координата может описываться одним битом за счет измерения временных интервалов. Пошлите в порт байт с произвольным значе- нием. Это приведет к тому, что младшие 4 бита обнулятся. Затем постоянно считывайте значение из порта, замеряя интервал времени, через который интересующий Вас бит станет равным 1. Этот интервал пропорционален позиции джойстика по интересующей Вас оси. Макси- мальны еинтервалы соответствуют нижней позиции по оси Y и правой позиции по оси X. Независимо от позиции, биты меняются от 0 к 1 очень быстро, по сравнению с механической скоростью перемещения джойстика или весла. Поэтому программа может с большой точностью получить сначала позицию координаты Y, а затем позицию координаты X. Нет необходимости тестировать каждую координату отдельно. В данном примере определяется координата X джойстика A. ;---получаем координату X джойстика A MOV DX,201H ;адрес игрового порта OUT DX,AL ;посылаем в порт произвольное значение MOV AH,1 ;проверяем бит 1 MOV SI,0 ;инициализируем счетчик NEXT: IN AL,DX ;читаем значение из порта TEST AL,AH ;проверяем бит 1 JE FINISHED ;выход, когда бит установлен INC SI ;иначе, увеличиваем счетчик LOOP NEXT ;на начало цикла FINISHED: 7.3.4 Получение цифрового ввода из игрового порта. Игровой порт поддерживает два джойстика или четыре "весла", а также ряд графических устройств. При этом может определяться статус до четырех кнопок устройств. Проверка состояния кнопок может быть сложным делом, поскольку программа может не иметь возможности постоянно проверять их, а кнопка может быть нажата и отпущена, пока программа занята другими делами. Может быть созда- на специальная процедура для решения этой проблемы. Статус кнопок автоматически читается несколько раз в секунду, без специального запроса на это программы; когда оказывается, что кнопка нажата, то управдение передается процедуре, которая определяет какая кнопка нажата и предпринимает нужные действия. Высокий уровень. Бейсик использует оператор STRIG для чтения статуса кнопок. Оператор STRIG достаточно хитрый, чтобы обнаружить нажатие кноп- ки, даже если программа в данный момент не занимается статусом кнопки, т.е. программа может запросить: "Было ли нажатие кнопки, со времени моего последнего запроса?" Это свойство очень полезно для видеоигр