Ассемблер и программирование для IBM PC

         

Арифметические операции II:


------------------------------------------------------------

Арифметические операции II: Обработка данных в форматах ASCII и BCD

Цель: Рассмотреть ASCII и BCD форматы данных и дать сведения о преобразованиях между этими форматами и двоичным форматом.

ВВЕДЕНИЕ ------------------------------------------------------------

Для получения высокой производительности компьютер выполняет aрифметические операции над числами в двоичном формате. Как показано в главе 12, этот формат не вызывает особых трудностей, если данные определены в самой программе. Во многих случаях новые данные вводятся программой с клавиатуры в виде ASCII символов в деcятичном формате. Аналогично вывод информации на экран осуществляется в кодах ASCII. Например, число 23 в двоичном представлении выглядит как 00010111 или шест.17; в коде ASCII на каждый cимвол требуется один байт и число 25 в ASCII-коде имеет внутpеннее представление шест.3235. Назначение данной главы - показать технику преобразования данных из ASCII-формата в двоичный формат для выполнения арифметических операций и обратного преобразования двоичных результатов в ASCII-формат для вывода на экран или принтер. Программа, приведенная в конце главы , демонстрирует большую часть матеpиала от главы 1 до главы 12. При программировании на языках высокого уровня, таких как BASIC или Pascal, для обозначения порядка числа или положе ния десятичной запятой (точки) можно положиться на кампилятор. Однако, компьютер не распознает десятичную запятую (точку) в арифметических полях. Так как двоичные числа не имеют возможности установки десятичной (или двоичной) запятой (точки), то именно программист должен подразумевать и определить порядок обрабатываемых чисел.

ASCII-формат ------------------------------------------------------------

Данные, вводимые с клавиатуры, имеют ASCII-формат, например, буквы SAM имеют в памяти шестнадцатиричное представление 53414D, цифры 1234 - шест. 31323334. Во многих случаях формат алфавитных данных, например, имя человека или описание статьи, не меняется в программе. Но для выполнения арифметических операций над числовыми значениями, такими как шест. 31323334, требуется специальная обработка. С помощью следующих ассемблерных команд можно выполнять арифметические операции непосредственно над числами в ASCII-формате:


Ассемблер для IBM PC. Глава 13 2
AAA (ASCII Adjust for Addition - коррекция для сложения ASCII-кода) AAD (ASCII Adjust for Division - коррекция для деления ASCII-кода) AAM (ASCII Adjust for Multiplication - коррекция для умножения ASCII-кода) AAS (ASCII Adjust for Subtraction - коррекция для вычитания ASCII-кода)
Эти команды кодируются без операндов и выполняют автоматичес кую коррекцию в регистре AX. Коррекция необходима, так как ASCII код представляет так называемый распакованный десятичный формат, в то время, как компьютер выполняет арифметические операции в двоичном формате.
Сложение в ASCII-формате
Рассмотрим процесс сложения чисел 8 и 4 в ASCII-формате:
Шест. 38 34 Шест. 6C
Полученная сумма неправильна ни для ASCII-формата, ни для двоичного формата. Однако, игноригуя левую 6 и прибавив 6 к правой шест.C: шест.C + 6 = шест.12 - получим правильный результат в десятичном формате. Правильный пример слегка упрощен, но он хорошо демонстрирует процесс, который выполня ет команда AAA при коррекции. В качестве примера, предположим, что регистр AX содержит шест. 0038, а регистр BX - шест.0034. Числа 38 и 34 представляют два байта в ASCII формате, которые необходимо сложить. Сложение и коррекция кодируется следующими командами:
ADD AL,BL ;Сложить 34 и 38 AAA ;Коррекция для сложения ASCII кодов
Команда AAA проверяет правую шест. цифру (4 бита) в регистре AL. Если эта цифра находится между A и F или флаг AF равен 1, то к регистру AL прибавляется 6, а к регистру AH прибавляется 1, флаги AF и CF устанавливаются в 1. Во всех случаях команда AAA устанавливает в 0 левую шест. цифру в регистре AL. Результат - в регистре AX:
После команды ADD: 006C После команды AAA: 0102
Для того, чтобы выработать окончательное ASCII-представ ление, достаточно просто поставить тройки на место левых шест. цифр: OR AX,3030H ;Результат 3132
Ассемблер для IBM PC. Глава 13 3


Все показанное выше представляет сложение однобайтовых чисел. Сложение многобайтовых ASCII-чисел требует организа ции цикла, который выполняет обработку справа налево с учетом переноса. Пример , показанный на рис.13.1 складывает два трехбайтовых ASCII-числа в четырехбайтовую сумму. Обратите внимание на следующее:


ъ В программе используется команда ADC, так как любое сложение может вызвать перенос, который должен быть прибавлен к следующему (слева) байту. Команда CLC устанавливает флаг CF в нулевое состояние.
------------------------------------------------------------ ------------------------------------------------------------ Рис. 13.1. Сложение в ASCII-формате.
ъ Команда MOV очищает регистр AH в каждом цикле, так как команда AAA может прибавить к нему единицу. Команда ADC учитывает пеpеносы. Заметьте, что использование команд XOR или SUB для oчистки регистра AH изменяет флаг CF. ъ Когда завершается каждый цикл, происходит пересылка содержимого pегистра AH (00 или 01) в левый байт суммы. ъ В результате получается сумма в виде 01020702. Програм ма не использует команду OR после команды AAA для занесения левой тройки, так как при этом устанавливает ся флаг CF, что изменит pезультат команды ADC. Одним из решений в данном случае является сохранение флагового регистра с помощью команды PUSHF, выполнение команды OR, и, затем, восстановление флагового регистра командой POPF:
ADC AL,[DI] ;Сложение с переносом AAA ;Коррекция для ASCII PUSHF ;Сохранение флагов OR AL,30H ;Запись левой тройки POPF ;Восстановление флагов MOV [BX],AL ;Сохранение суммы
Вместо команд PUSHF и POPF можно использовать команды LAHF (Load AH with Flags - загрузка флагов в регистр AH) и SAHF (Store AH in Flag register - запись флагов из регистра AH во флаговый регистр). Команда LAHF загружает в регистр AH флаги SF, ZF, AF, PF и CF; а команда SAHF записывает содержимое регистра AH в указанные флаги. В приведенном примере, однако, регистр AH уже используется для арифметических переполнений. Другой способ вставки троек для получения ASCII-кодов цифр - организовать обработку суммы командой OR в цикле.
Вычитание в ASCII-формате
Ассемблер для IBM PC. Глава 13 4
Команда AAS (ASCII Adjust for Subtraction - коррекция для вычитания ASCII-кодов) выполняется aналогично команде AAA. Команда AAS проверяет правую шест.цифру (четыре бита) в регистре AL. Если эта цифра лежит между A и F или флаг AF равен 1, то из регистра AL вычитается 6, а из регистра AH вычитается 1, флаги AF и CF устанавливаются в 1. Во всех случаях команда AAS устанавливает в 0 левую шест.цифру в регистpе AL. В следующих двух примерах предполагается, что поле ASC1 содержит шест.38, а поле ASC2 - шест.34:


Пример 1: AX AF MOV AL,ASC1 ;0038 SUB AL,ASC2 ;0034 0 AAS ;0004 0
Пример 2: AX AF MOV AL,ASC2 ;0034 SUB AL,ASC1 ;00FC 1 AAS ;FF06 1
В примере 1 команде AAS не требуется выполнять коррекцию. В примере 2, так как правая цифра в регистре AL равна шест.C, команда AAS вычитает 6 из регистра AL и 1 из регистра AH и устанавливает в 1 флаги AF и CF. Результат (который должен быть равен -4) имеет шест. представление FF06, т.е. десятич ное дополнение числа -4.
Умножение в ASCII-формате
Команда AAM (ASCII Adjust for Multiplication - коррекция для умножения ASCII кодов) выполняет корректировку результата умножения ASCII кодов в регистре AX. Однако, шест. цифры должны быть очищены от троек и полученные данные уже не будут являться действительными ASCII-кодами. (В руководствах фирмы IBM для таких данных используется термин pаспакованный десятичный формат). Например, число в ASCII-формате 31323334 имеет распакованное десятичное представление 01020304. Кроме этого, надо помнить, что коррекция осуществляется только для одного байта за одно выполнение, поэтому можно умножать только oдно-байтовые поля; для более длинных полей необходима организация цикла. Команда AAM делит содержимое регистра AL на 10 (шест. 0A) и записывает частное в регистр AH, а остаток в AL. Предположим, что в регистре AL содержится шест. 35, а в регистре CL - шест.39. Следующие команды умножают содержимое регистра AL на содержимое CL и преобразуют результат в ASCII-формат:
AX: AND CL,0FH ;Преобразовать CL в 09 AND AL,0FH ;Преобразовать AL в 05 0005 MUL CL ;Умножить AL на CL 002D
Ассемблер для IBM PC. Глава 13 5
AAM ;Преобразовать в распак.дес. 0405 OR AX,3030H ;Преобразовать в ASCII-ф-т 3435
Команда MUL генерирует 45 (шест.002D) в регистре AX, после чего команда AAM делит это значение на 10, записывая частное 04 в регистр AH и остаток 05 в регистр AL. Команда OR преоб pазует затем распакованное десятичное число в ASCII-формат. Пример на рис.13.2 демонстрирует умножение четырех- байтового множимого на одно-байтовый множитель. Так как команда AAM может иметь дело только с однобайтовыми числами, то в программе организован цикл, который обрабатывает байты справа налево. Окончательный результат умножения в данном примере - 0108090105. Если множитель больше одного байта, то необходимо обеспечить еще один цикл, который обрабатывает множитель. В этом случае проще будет преобразовать число из ASCII-формата в двоичный формат (см. следующий раздел "Преобразование ASCII-формата в двоичный формат").


------------------------------------------------------------ ------------------------------------------------------------ Рис.13.2. Умножение в ASCII-формате.
Деление в ASCII-формате
Команда AAD (ASCII Adjust for Division - коррекция для деления ASCII-кодов) выполняет корректировку ASCII кода делимого до непосредственного деления. Однако, прежде необходимо очистить левые тройки ASCII-кодов для получения распакованного десятичного формата. Команда AAD может оперировать с двухбайтовыми делимыми в регистре AX. Предположим, что регистр AX содержит делимое 3238 в ASCII- формате и регистр CL содержит делитель 37 также в ASCII- формате. Следующие команды выполняют коррекцию для последую щего деления: AX: AND CL,0FH ;Преобразовать CL в распак.дес. AND AX,0F0FH ;Преобразовать AX в распак.дес. 0208 AAD ;Преобразовать в двоичный 001C DIV CL ;Разделить на 7 0004
Команда AAD умножает содержимое AH на 10 (шест.0A), прибавляет pезультат 20 (шест.14) к регистру AL и очищает регистр AH. Значение 001C есть шест. представление десятич ного числа 28. Делитель может быть только однобайтовый от 01 до 09. Пример на рис. 13.3. выполняет деление четырехбайтового делимого на однобайтовый делитель. В программе организован цикл обработки делимого справа налево. Остатки от деления находятся в регистре AH и команда AAD корректирует их в регистре AL. Окончательный pезультат: частное 00090204 и в регистре AH остаток 02.
Ассемблер для IBM PC. Глава 13 6
Если делитель больше одного байта, то необходимо постро ить другой цикл для обработки делителя, но лучше воспользо ваться следующим разделом "Преобразование ASCII-формата в двоичный формат."
ДВОИЧНО-ДЕСЯТИЧНЫЙ ФОРМАТ (BCD) ------------------------------------------------------------
В предыдущем примере деления в ASCII-формате было получено частное 00090204. Если сжать это значение, сохраняя только правые цифры каждого байта, то получим 0924. Такой формат называется двоично-десятичным (BCD - Binary Coded Decimal) (или упакованным). Он содержит только десятичные цифры от 0 до 9. Длина двоично-десятичного представления в два раза меньше ASCII-представления.


------------------------------------------------------------ ------------------------------------------------------------ Рис.13.3. Деление в ASCII-формате.
Заметим, однако, что десятичное число 0924 имеет основание 10 и, будучи преобразованным в основание 16 (т.е. в шест. представление), даст шест.039C. Можно выполнять сложение и вычитание чисел в двоично-десятичном представлении (BCD-формате). Для этих целей имеются две корректиpующих команды:
DAA (Decimal Adjustment for Addition - десятичная коррекция для сложения) DAS (Decimal Adjustment for Subtraction - десятичная коррекция для вычитания)
Обработка полей также осуществляется по одному байту за одно выполнение. В примере программы, приведенном на рис. 13.4, выполняется преобразование чисел из ASCII-формата в BCD-формат и сложение их. Процедура B10CONV преобразует ASCII в BCD. Обработка чисел может выполняться как справа налево, так и слева направо. Кроме того, обработка слов проще, чем обработка байтов, так как для генерации одного байта BCD-кода требуется два байта ASCII-кода. Ориентация на обработку слов требует четного количества байтов в ASCII- поле. Процедура C10ADD выполняет сложение чисел в BCD-формате. Окончательный результат - 127263.
ПРЕОБРАЗОВАНИЕ ASCII-ФОРМАТА В ДВОИЧНЫЙ ФОРМАТ ------------------------------------------------------------
bыполнение арифметических операций над числами в ASCII или BCD форматах удобно лишь для коротких полей. В боль шинстве случаев для арифметических операций используется преобразование в двоичный формат. Практически проще
Ассемблер для IBM PC. Глава 13 7
преобразование из ASCII-формата непосредственно в двоичный формат, чем преобразование из ASCII- в BCD-формат и, затем, в двоичный формат: Метод преобразования базируется на том, что ASCII-формат имеет основание 10, а компьютер выполняет арифметические операции только над числами с основанием 2. Процедура преобразования заключается в следующем:
1. Начинают с самого правого байта числа в ASCII-формате и обрабатывают справа налево. 2. Удаляют тройки из левых шест.цифр каждого ASCII-байта. 3. Умножают ASCII-цифры на 1, 10, 100 (шест.1, A, 64) и т.д. и складывают результаты.


Для примера рассмотрим преобразование числа 1234 из ASCII-формата в двоичный формат:
Десятичное Шестнадцатиричное
4 х 1 = 4 4 3 х 10 = 30 1E 2 х 100 = 200 C8 1 х 1000 = 1000 3E8 Результат: 04D2
------------------------------------------------------------ ------------------------------------------------------------ Рис. 13.4. BCD-преобразование и арифметика.
Проверьте, что шест.04D2 действительно соответствует десятичному 1234. На рис. 13.5. в процедуре B10ASBI выполняется преобразоние ASCII-числа 1234 в двоичный формат. В примере предполагается, что длина ASCII-числа равна 4 и она записана в поле ASCLEN. Для инициализации адрес ASCII- поля ASCVAL-1 заносится в регистр SI, а длина - в регистр BX. Команда по метке B20 пересылает ASCII-байт в регистр AL:
MOV AL,[SI+BX]
Здесь используется адрес ASCVAL-1 плюс содержимое регистра BX (4), т.е. получается адрес ASCVAL+3 (самый правый байт поля ASCVAL). В каждом цикле содержимое регистра BX уменьшается на 1, что приводит к обращению к следующему слева байту. Для данной адресации можно использовать регистр BX, но не CX, и, следовательно, нельзя применять команду LOOP. В каждом цикле происходит также умножение поля MULT10 на 10, что дает в результате множители 1,10,100 и т.д. Такой прием применен для большей ясности, однако, для большей производительности множитель можно хранить в регистре SI или DI.
ПРЕОБРАЗОВАНИЕ ДВОИЧНОГО ФОРМАТА В ASCII-ФОРМАТ ------------------------------------------------------------
Ассемблер для IBM PC. Глава 13 8
Для того, чтобы напечатать или отобразить на экране арифметический pезультат, необходимо преобразовать его в ASCII-формат. Данная операция включает в себя процесс обратный предыдущему. Вместо умножения используется деление двоичного числа на 10 (шест. 0A) пока результат не будет меньше 10. Остатки, которые лежат в границах от 0 до 9, образуют число в ASCII-формате. В качестве примера рассмотрим преобразование щест.4D2 обратно в десятичный формат: Частное Остаток 4D2 : A 7B 4 7B : A C 3 C : A 1 2


Так как последнее частное 1 меньше, чем шест.A, то операция завершена. Остатки вместе с последним частным образуют результат в ASCII-формате, записываемый справа налево 1234. Все остатки и последнее частное должны записываться в память с тройками, т.е. 31323334. На рис. 13.5. процедура C10BIAS преобразует шест. 4D2 (результат вычисления в процедуре B10ASBI) в ASCII-число 1234. Полезно переписать всю программу (рис.13.5.) в компьютер и выполнить трассиpовку ее выполнения по шагам.
------------------------------------------------------------ ------------------------------------------------------------ Рис.13.5. Преобразование ASCII и двоичного форматов.
СДВИГ И ОКРУГЛЕНИЕ ------------------------------------------------------------
Рассмотрим процесс округления числа до двух десятичных знаков после запятой. Если число равно 12,345, то необходимо прибавить 5 к отбрасываемому разряду и сдвинуть число вправо на один десятичный разряд:
Число: 12,345 Плюс 5: +5 Округленное число: 12,350 = 12,35
Если округляемое число равно 12,3455, то необходимо прибавить 50 и сдвинуть на два десятичных разряда. Для 12,34555 необходимо прибавить 500 и сдвинуть на три десятичных разряда:
12,3455 12,34555 +50 +500 12,3505 = 12,35 12,35055 = 12,35
К числу, имеющему шесть знаков после запятой, необходимо прибавить 5000 и сдвинуть на четыре десятичных разряда и т.д. Поскольку данные представляются в компьютере в двоичном
Ассемблер для IBM PC. Глава 13 9
виде, то 12345 выглядит как шест.3039. Прибавляя 5 к 3039, получим 303E, что соответствует числу 12350 в десятичном представлении. Пока все хорошо. Но вот сдвиг на одну двоич ную цифру дает в результате шест.181F, или 1675 - т.е. сдвиг на одну двоичную цифру просто делит число пополам. Но нам необходим такой сдвиг, который эквивалентен сдвигу вправо на одну десятичную цифру. Такой сдвиг можно осуществить делением на 10 (шест.A):
Шест.303E : Шест.A = 4D3 или дес.1235
Преобразование шест.4D3 в ASCII-формат дает число 1235. Теперь oстается лишь вставить запятую в правильную позицию числа 12,35, и можно выдать на экран округленное и сдвинутое значение. Таким образом можно округлять и сдвигать любые двоичные числа. Для трех знаков после запятой необходимо прибавить 5 и разделить на 10, для четырех знаков после запятой: прибавить 50 и pазделить на 100. Возможно вы заметили модель: фактор округления (5, 50, 500 и т.д.) всегда составляет половину фактора сдвига (10, 100, 1000 и т.д.). Конечно, десятичная запятая в двоичном числе только подpазумевается.


ПРОГРАММА: ПРЕОБРАЗОВАНИЕ ВРЕМЕНИ И РАСЦЕНКИ РАБОТ ДЛЯ РАСЧЕТА ЗАРПЛАТЫ ------------------------------------------------------------
Программа, приведенная на рис.13.6, позволяет вводить с клавиатуры значения продолжительности и расценки работ и отображать на экран pасчитанную величину заработанной платы. Для краткости в программе опущены некоторые проверки на ошибку. Программа содержит следующие процедуры:
B10INPT Вводит значения времени работы на ее расценку с клавиатуры. Эти значения могут содержать десятич ную запятую. D10HOUR Выполняет преобразование значения времени из ASCII в двоичный формат. E10RATE Выполняет преобразование значения расценки из ASCII в двоичный формат. F10MULT Выполняет умножение, округление и сдвиг. Величина зарплаты без дробной части или с одним или двумя знаками после запятой не требует округления и сдви га. Данная процедура ограничена тем, что позволяет обрабатывать величину зарплаты с точностью до шести десятичных знаков, что, конечно, больше, чем требуется. G10WAGE Вставляет десятичную запятую, определяет правую позицию для начала записи ASCII символов и преобразует двоичное значение зарплаты в ASCII-формат.
Ассемблер для IBM PC. Глава 13 10
K10DISP Заменяет лидирующие нули на пробелы и выводит результат на экран. M10ASBI Преобразует ASCII в двоичный формат (общая процедура для времени и расценки) и определяет число цифр после запятой в введенном значении.
------------------------------------------------------------ ------------------------------------------------------------ Рис.13.6. Расчет заработной платы.
Ограничения. Первое ограничение в программе, приведенной на рис.13.6, cостоит в том, что допускает не более шести десятичных знаков после запятой. Другое ограничение - размер самой зарплаты и тот факт, что сдвиг включает деление на число, кратное 10, a преобразование в ASCII-формат включает деление на 10. Если значение времени или расценки содержит больше шести десятичных знаков или зарплата превы шает величину около 655350, то программа выдает нулевой результат. На практике программа может предусмотреть в данном случае вывод предупреждающего сообщения или иметь подпрограммы для исключения таких ограничений.


Контроль ошибок. Программа, разработанная для пользовате лей, не являющихся программистами, должна не только выдавать предупреждающие сообщения, но также проверять корректность вводимых значений. Правильными символами при вводе числовых значений являются цифры от 0 до 9 и символ десятичной запятой. Для любых других символов программа должна выдать предупреждающее сообщение и вновь повторить запрос на ввод. Полезной командой для проверки корректности вводимых символов является XLAT (см. главу 14). Тщательно проверяйте программы для любых возможных состояний: нулевое значение, максимально большие и малые значения, отрицательные значения.
Отрицательные величины
Некоторые применения программ допускают наличие отрицательных величин. Знак минус может устанавливаться после числа, например, 12,34-, или перед числом -12,34. Программа может проверять наличие минуса при преобразовании в двоичный формат. Можно оставить двоичное число положительным, но установить соответствующий индикатор исходной отрицательной величины. После завершения арифметических операций знак минус при необходимости может быть вставлен в ASCII поле. Если необходимо, чтобы двоичное число было также отрицательным, то можно преобразовать, как обычно, ASCII-формат в двоичный, а для изменения знака двоичного числа воспользоваться командами, описанными в главе 12 "Преобразование знака". Будьте внимательны при использовании
Ассемблер для IBM PC. Глава 13 11
команд IMUL и IDIV для обработки знаковых данных. Для округления отрицательных чисел следует не прибавлять, а вычитать фактор 5.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ ASCII-формат требует один байт на каждый символ. Если поле содержит только цифры от 0 до 9, то замена старших троек в каждом байте на нули создает распакованный десятичный формат. Сжатие числа до двух цифр в байте создает упакованный десятичный формат.
ъ После ASCII-сложения необходимо выполнить коррекцию с помощью команды AAA; после ASCII-вычитания - коррекция с помощью команды AAS.


ъ Прежде чем выполнить ASCII-умножение, необходимо преобразовать множимое и множитель в "распакованный десятичный" формат, обнулив в каждом байте левые тройки. После умножения необходимо выполнить коррекцию результата с помощью команды AAM.
ъ Прежде чем выполнить ASCII-деление, необходимо: 1) преобразовать делимое и делитель в "распакованный десятичный" формат, обнулив в каждом байте левые тройки и 2) выполнить коррекцию делимого с помощью команды AAD.
ъ Для большинства арифметических операций используйте преобразование чисел из ASCII-формата в двоичной формат. В процессе такого преобразования проверяйте на корректность ASCII-символы: они должны быть от шест.30 до шест.39, могут содержать десятичную запятую (точку) и, возможно, знак минус.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
13.1. Предположим, что регистр AX содержит 9 в ASCII коде, а регистр BX -7 также в ASCII коде. Объясните и дайте точный результат для следующих несвязанных операций:
а) ADD AX,33H б) ADD AX,BX AAA AAA в) SUB AX,BX г) SUB AX,0DH AAS AAS
13.2. Поле UNPAK содержит шест. 01040705 в распаковочном десятичном формате. Напишите цикл, который преобразует это содержимое в ASCII-формат, т.е. 31343735.
Ассемблер для IBM PC. Глава 13 12
13.3. Поле ASCA содержит значение 313733 в ASCII-формате, а другое поле ASCB содержит 35. Напишите команды для умножения этих чисел в ASCII-формате и записи произведения в поле ASCPRO.
13.4. Используя данные из вопроса 13.3, разделите ASCA на ASCB и запишите частное в поле ASCQUO.
13.5. Выполните следующие вычисления вручную: а) преобразо вать ASCII 46328 в двоичный формат и показать результат в шест.виде; б) преобразовать полученное шест.значение обратно в ASCII-формат.
13.6. Напишите и выполните программу, которая определяет размер памяти компьютера (INT 12H - см.гл.2), преобразует полученное значение в ASCII-формат и выводит результат на экран в следующем виде:
Размер памяти nnn байтов.
Ассемблер для IBM PC. Глава 14 24


Обработка таблиц


------------------------------------------------------------

Обработка таблиц

Цель: Раскрыть требования для определения таблиц, организа ции поиска в таблицах и сортировки элементов таблицы.

ВВЕДЕНИЕ ------------------------------------------------------------

Многие программные применения используют табличную организацию таких данных, как имена, описания, размеры, цены. Определение и использование таблиц включает одну новую команду ассемблера - XLAT. Таким образом, использова ние таблиц - это лишь дело техники и применения знаний, полученных из предыдущих глав. Данная глава начинается определением некоторых общепринятых таблиц. Организация поиска в таблице зависит от способа ее определения. Существует много различных вариантов определения таблиц и алгоритмов поиска.

ОПРЕДЕЛЕНИЕ ТАБЛИЦ ------------------------------------------------------------

Для облегчения табличного поиска большинство таблиц определяются систематично, т.е. элементы таблицы имеют одина ковый формат (символьный или числовой), одинаковую длину и восходящую или нисходящую последовательность элементов. Таблица, которой уже приходилось пользоваться в данной книге - это стек, представляющий собой таблицу из 64-х неинициализированных слов:

STACK DW 64 DUP(?)

Следующие две таблицы инициализированы символьными и числовыми значениями:

MONTAB DB 'JAN','FEB','MAR', ... ,'DEC' COSTAB DB 205,208,209,212,215,224,...

Таблица MONTAB определяет алфавитные аббревиатуры месяцев, а COSTAB - определяет таблицу номеров служащих. Таблица может также содепжать смешанные данные (регулярно чередующиеся числовые и символьные поля). В следующей ассортиментной таблице каждый числовой элемент (инвентарный номер) имеет две цифры (один байт), а каждый символьный элемент (наименование) имеет девять байтов. Точки, показанные в наименовании "Paper" дополняют длину этого поля до 9 байт. Точки показывают, что недостающее пространство должно присутствовать. Вводить точки необязательно.


STOKTBL DB 12,'Computers',14,'Paper....',17,'Diskettes'
Для ясности можно закодировать элементы таблицы вертикально:
STOKTBL DB 12, 'Computers' DB 14, 'Paper....' DB 17, 'Diskettes'
Рассмотрим теперь различные способы использования таблиц в программах.
ПРЯМОЙ ТАБЛИЧНЫЙ ДОСТУП ------------------------------------------------------------
Предположим, что пользователь ввел номер месяца - 03 и программа должна преобразовать этот номер в алфавитное значение March. Программа для выполнения такого преобразова ния включает определение таблицы алфавитных названий месяцев, имеющих одинаковую длину. Так как самое длинное название - September, то таблица имеет следующий вид:
MONTBL DB 'January..' DB 'February.' DB 'March....'
Каждый элемент таблицы имеет длину 9 байт. Адрес элемента 'January' - MONTBL+0, 'February' - MONTBL+9, 'March' - MONTBL+18. Для локализации месяца 03, программа должна выполнить следующее:
1. Преобразовать введенный номер месяца из ASCII 33 в двоичное 03. 2. Вычесть единицу из номера месяца: 03 - 1 = 02 3. Умножить результат на длину элемента (9): 02 х 9 = 18 4. Прибавить произведение (18) к адресу MONTBL; в результате получится адрес требуемого названия месяца: MONTBL+18.
------------------------------------------------------------ ------------------------------------------------------------ Рис. 14.1. Прямая табличная адресация.
На рис.14.1 приведен пример прямого доступа к таблице названий месяцев. Для краткости в программе используются вместо девятисимвольных названий - трехсимвольные. Введенный номер месяца определен в поле MONIN. Предположим, что некоторая подпрограмма формирует запрос на ввод номера месяца в ASCII-формате в поле MONIN. Описанная техника работы с таблицей называется прямым табличным доступом. Поскольку данный алглритм непосредствен но вычисляет адpес необходимого элемента в таблице, то в программе не требуется выполнять операции поиска.
Ассемблер для IBM PC. Глава 14 26
Хотя прямая табличная адресация очень эффективна, она возможна только при последовательной организации. То есть можно использовать такие таблицы, если элементы располагаются в регулярной последовательности: 1, 2, 3,... или 106, 107, 108,... или даже 5, 10, 15. Однако, не всегда таблицы построены таким образом. В следующем разделе рассматриваются таблицы, имеющие нерегулярную организацию.


ТАБЛИЧНЫЙ ПОИСК ------------------------------------------------------------
Некоторые таблицы состоят из чисел, не имеющих видимой закономерности. Характерный пример - таблица инвентарных номеров с последовательными номерами, например, 134, 138, 141, 239 и 245. Другой тип таблиц состоит из распределенных по ранжиру величин, таких как подоходный налог. В следующих разделах рассмотрим эти типы таблиц и организацию табличного поиска.
Таблицы с уникальными элементами
Инвентарные номера большинства фирм часто не имеют последовательного порядка. Номера, обычно, группируются по категориям, первые цифры указывают на мебель или приборы, или номер отдела. Кроме того время от времени номера удаляются, а новые добавляются. В таблице необходимо связать инвентарные номера и их конкретные наименования (и, если требуется, включить стоимость). Инвернтарные номера и наименования могут быть определены в различных таблицах, например:
STOKNOS DB '101','107','109',... STOKDCR DB 'Excavators','Processors','Assemblers',...
или в одной таблице, например:
STOKTAB DB '101','Excavators' DB '107','Processors' DB '109','Assemblers' ...
Программа на рис.14.2 определяет инвентарную таблицу и выполняет табличный поиск. Таблица содержит шесть пар номеров и наименований. Цикл поиска начмнается со сравнения введенного инвентарного номера в поле STOKNIN с первым номером в таблице. Если номера различные, то адрес в таблице увеличивается для сравнения со следующим инвентарным номером. Если номера равны, то программа (A30) выделяет наименование из таблицы и записывает его в поле DESCRN. Поиск выполняет максимум шесть сравнений и если требуемый номер в таблице отсутствует, то происходит переход на программу обработки ошибки, которая выводит на экран соответствующее сообщение.
Ассемблер для IBM PC. Глава 14 27
Обратите внимание, что в начале программы имеется команда, которая пересылает содержимое поля STOKNIN в регистр AX. Хотя STOKNIN определенно как 3233, команда MOV загрузит в регистр AX это значение в обратной последователь ности байтов 3332. Так как элементы таблицы имеют прямую последовательность байтов, то после команды MOV имеется команда XCHG, которая меняет местами байты в регистре AX, возвращая им прямую последовательность, т.е. 3233. Команда CMP, предполагая обратную последовательность, сравнивает сначала правые байты, а затем - левые. Следовательно, проверка на pавенство будет корректной, но проверки на больше или меньше дадут неправильные результаты. Для сравнения на больше или меньше следует опустить команду XCHG, переслать элемент таблицы командой MOV, скажем, в регистр BX и затем сравнить содержимое регистров AX и BX следующим образом:


MOV AX,STOKNIN LEA SI,STOKTAB C20: MOV BX,[SI] CMP AX,BX JA или JB ...
В программе такого типа другая таблица может определять стоимость единицы товара. Программа может локализовать элемент таблицы, вычислить продажную стоимость (количество товара умножить на стоимость единицы товара) и выдать на экран наименование и прадажную стоимость товара. В примере на рис. 14.2 таблица содержит двухбайтовые номера и десятибайтовые наименования. Детальное программиро вание будет oтличаться для различного числа и длины элементов. Например, для сравнения трехбайтовых полей можно использовать команду REPE CMPSB, хотя эта команда также включает использование pегистра CX.
Таблицы с ранжированием
Подохожный налог дает характерный пример таблицы с ранжированными значениями. Представим себе таблицу, содержащую размеры доходов oблагаемых налогами, процент налога и поправочный коэффициент:
Размер дохода Процент налога Поправочный к-нт
0-1000.00 10 0,00 1000,01-2500,00 15 050,00 2500,01-4250,00 18 125,00 4250,01-6000,00 20 260,00 6000,01 и более 23 390,00
Ассемблер для IBM PC. Глава 14 28
В налоговой таблице процент увеличивается в соответствии с увеличением налогооблагаемого дохода. Элементы таблицы доходов содержат максимальные величины для каждого шага:
TAXTBL DD 100000,250000,425000,600000,999999
для организации поиска в такой таблице, программа сравнивает доxод налогоплатильщика с табличным значением дохода:
если меньше или равно, то использовать соответствующий процент и поправку; если больше, то перейти к следующему элементу таблицы.
Величина налога рассчитывается по формуле:
Доход х Процент налога : 100 - поправочный к-нт
Табличный поиск с использованием сравнения строк
Если элемент таблицы превышает длину в два байта, то для операции сравнения можно использовать команду REPE CMPS. Предположим, что таблица инвентарных номеров (рис.14.2) переделана для трехбайтовых номеров. Если STOKNIN является первым полем в области данных, а STOKTAB - вторым, то они могут выглядеть cледующим образом:


Данные: |123|035Excavators|038Lifters |049Presses | ... | | | | | | | Адрес: 00 03 06 16 19 29 32
Программа на рис.14.3 определяет таблицу STOKTAB, включая последний элемент '999' для индикации конца таблицы при поиске. Программа поиска сравнивает содержимое каждого элемента таблицы с содержимым поля STOKNIN:
Элемент таблицы STOKNIN Результат сравнения
035 123 Меньше: проверить след.эл-т 038 123 Меньше: проверить след.эл-т 049 123 Меньше: проверить след.эл-т 102 123 Меньше: проверить след.эл-т 123 123 Равно: элемент найден
Заметим, что команда CMPSB на рис.14.3 сравнивает байт за байтом, пока байты не будут равны и автоматически увеличива ет регистpы SI и DI.
------------------------------------------------------------ ------------------------------------------------------------ Рис.14.3. Табличный поиск с использованием команды CMPSB
Ассемблер для IBM PC. Глава 14 29
Регистр CX инициализируется значением 03, а начальные относительные адреса в регистрах SI и DI устанавливаются равными 03 и 00 соответственно. Сравнение с первым элементом таблицы (035:123) завершается на первом байте, после этого регистр SI содержит 04, DI: 01, CX: 02. Для следующего сравнения регистр SI должен иметь значение 16, а DI: 00. Корректировка регистра DI сводится к простой перезагрузке адреса STOKNIN. Увеличение адреса следующего элемента таблицы, который должен быть в регистре SI, зависит от того, на каком байте (первом, втором или третьем) закончилось предыдущее сравнение. Регистр CX содержит число байт, не участвующих в сравнении, в данном случае - 02. Прибавив к содержимому регистра SI значение в регистре CX и длину наименования, получим относительный адрес следующего элемента:
Адрес в SI после CMPSB 04 Прибавить CX 02 Прибавить длину наименования 10 Относительный адрес след.элемента 16
Так как регистр CX всегда содержит число байт, не участвующих в сравнении (если такие есть), то расчет справедлив для всех случаев: прекращение сравнения после 1, 2 или 3 байта. Если сравниваются одинаковые элементы, то регистр CX получит значение 00, а адрес в pегистре SI укажет на требуемое наименование.


Таблицы с элементами переменной длины
Существуют таблицы, в которых элементы имеют переменную длину. Каждый элемент такой таблицы может завершаться специальным символом ограничителем, например, шест.00; конец таблицы можно обозначить огpаничителем шест.FF. В этом случае необходимо гарантировать, чтобы внутри элементов таблицы не встречались указанные ограничители. Помните, что двоичные числа могут выражаться любыми битовыми комбинация ми. Для поиска можно использовать команду SCAS.
ТРАНСЛИРУЮЩАЯ КОМАНДА XLAT ------------------------------------------------------------
Команда XLAT транслирует содержимое одного байта в другое предопределенное значение. С помощью команды XLAT можно проверить корректность содержимого элементов данных. При передаче данных между персональным компьютером и ЕС ЭВМ (IBM) с помощью команды XLAT можно выполнить перекодировку данных между форматами ASCII и EBCDIC. В следующем примере происходит преобразование цифр от 0 до 9 из кода ASCII в код EBCDIC. Так как представление цифр в ASCII выглядит как шест.30-39, а в EBCDIC - шест.F0-F9, то замену можно выполнить командой OR. Однако, дополнительно преобразуем все остальные коды ASCII в пробел (шест.40) в
Ассемблер для IBM PC. Глава 14 30
коде EBCDIC. Для команды XLAT необходимо определить таблицу перекодировки, которая учитывает все 256 возможных символов, с кодами EBCDIC в ASCII позициях:
XLTBL DB 47 DUP(40H) ;Пробелы в коде EBCDIC DB 0F0H,0F1H,0F2H,0F3H,...,0F9H ;0-9 (EBCDIC) DB 199 DUP(40H) ;Пробелы в коде EBCDIC
Команда XLAT предполагает адрес таблицы в регистре BX, а транслируемый байт (например, поля ASCNO) в регистре AL. Следующие команды выполняют подготовку и трансляцию байта:
LEA BX,XLTBL MOV AL,ASCNO XLAT
Команда XLAT использует значение в регистре AL в качестве относительного aдреса в таблице, т.е. складывает адрес в BX и смещение в AL. Если, например, ASCNO содержит 00, то адрес байта в таблице будет XLTBL+00 и команда XLAT заменит 00 на шест.40 из таблицы. Если поле ASCNO cодержит шест.32, то адрес соответствующего байта в таблице будет XLTBL+50. Этот байт содержит шест.F2 (2 в коде EBCDIC), который команда XLAT загружает в регистр AL.


------------------------------------------------------------ ------------------------------------------------------------ Рис.14.4. Преобразование ASCII в EBCDIC.
В программе на рис.14. 4 добавлено преобразование десятичной точки (2E) и знака минус (2D) из кода ASCII в код EBCDIC (4B и 60 соответственно). В программе организован цикл для обработки шестибайтового поля. Поле ASCNO в начале выполнения программы содержит значение 31.5 с последующим пробелом, или шест.2D33312E3520. В конце выполнения програм мы в поле EBCNO должно быть шест. 60F3F14BF540.
ПРОГРАММА: ОТОБРАЖЕНИЕ ШЕСТ. И ASCII-КОДОВ ------------------------------------------------------------
Программа, приведенная на рис.14.5, отображает на экране почти все ASCII-символы, а также их шест.значения. Например, ASCII-символ для шест.53 - это буква S, эти данные программа выводит в виде 53 S. Полное изображение на экране выглядит в виде матрицы 16х16:
00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
------------------------------------------------------------
Ассемблер для IBM PC. Глава 14 31
------------------------------------------------------------ Рис.14.5. Отображение шест. и ASCII-кодов
Как было показано еще на рис.8.1, отображение ASCII- символов, oсобых проблем не вызывает. Что же касается отображения шест.значений в символах ASCII, то этот процесс более сложный. Например, для вывода на экран в коде ASCII шест. 00, 01 и т.д. необходимо преобразовать шест.00 в шест. 3030, шест.01 в шест.3031 и т.д. В программе начальное значение поля HEXCTR равно 00. Это значение последовательно увеличивается на 1. Процедура C10HEX расщепляет байт HEXCTR на две щест.цифры. Предположим, что байт HEXCTR содержит шест. 4F. Процедура сначала выделяет шест.цифру 4 и использует это значение для перекодировки по таблице XLATAB. В регистре AL устанавливает ся в результате значение шест.34. Затем процедура выделяет вторую шест.цифру F и перекодирует ее в шест.46. В результате oбработки получается шест.3446, что отображается на экране как 4F. Так как функция DOS для вывода на экран (шест.40) рассматривает шест.1A как конец файла, то в программе это значение заменяется на пробел. Программа, использующая для вывода на экран функцию DOS (шест.09), дожна заменять символ ограничитель '$' на пробел. Существует много различных способов преобразования шест.цифр в ASCII-символы. Можно поэкспериментировать с операциями сдвига и сравнения.


ПРОГРАММА: СОРТИРОВКА ЭЛЕМЕНТОВ ТАБЛИЦЫ ------------------------------------------------------------
Часто возникает необходимость сортировки элементов таблицы в восходящем или нисходящем порядке. Например, пользователю может потребоваться список наименований товара в алфавитном порядке или список общих цен в нисходящей последовательности. Обычно, табличные данные не определяются как в предыдущей программе, а загружаются с клавиатуры или с диска. Данный раздел посвящен сортировке элементов таблицы, что касается различных применений, включающих сортировку записей на дисках, то здесь возможны более сложные программы. Существует несколько алгоритмов сортировки таблиц от неэффективных, но понятных, до эффективных и непонятных. Программа сортировки, предлагаемая в данном разделе, весьма эффективна и может применяться для большенства табличных сортировок. Конечно, если не проверить различные алгоритмы сортировок, то даже самая неэффективная программа может показаться работающей со скоростью света. Но цель данной книги - показать технику ассемблера, а не сортировки. Основной подход заключается в сравнении соседних элементов таблицы. Если первый элемент больше второго, то элементы меняются местами. Таким образом выполняется сравнение элементов 1 со 2, 2 с 3 и т.д. до конца таблицы с
Ассемблер для IBM PC. Глава 14 32
перестановкой элементов там, где это необходимо. Если в проходе были сделаны перестановки, то весь процесс повторяет ся с начала таблицы т.е. сравниваются снова элементы 1-2, 2-3 и т.д. Если в проходе не было перестановок, то таблица отсортирована и можно прекратить процесс. Ниже приведен алгоритм, в котором переменная SWAP является индикатором: была перестановка элементов (YES) или нет (NO):
G10: Определить адрес последнего элемента G20: Установить SWAP=NO Определить адрес первого элемента G30: Элемент > следующего элемента? Да: Представить элементы Установить SWAP=YES Перейти к следующему элементу Конец таблицы? Нет: Перейти на G30 Да: SWAP=YES? Да: Перейти на G20 (повторить сорт.) Нет: Конец сортировки


Программа, показанная на рис.14.6, обеспечивает ввод с клавиатуры до 30 имен, сортировку введенных имен в алфавит ном порядке и вывод на экран отсортированного списка имен.
------------------------------------------------------------ ------------------------------------------------------------ Рис.14.6. Сортировка таблицы имен.
ОПЕРАТОРЫ ТИПА, ДЛИНА И РАЗМЕРА ------------------------------------------------------------
Ассемблер содержит ряд специальных операторов, которые могут оказаться полезными при программировании. Например, при изменении длины таблицы придется модифицировать программу (для нового определения таблицы) и процедуры, проверяющие конец таблицы. В этом случае использование операторов TYPE (тип), LENGTH (длина) и SIZE (размер) позволяют уменьшить число модифицируемых команд. Рассмотрим определение следующей таблицы из десяти слов:
TABLEX DW 10 DUP(?) ;Таблица из 10 слов
Программа может использовать оператор TYPE для определения типа (DW в данном случае), оператор LENGTH для определения DUP-фактора (10) и оператор SIZE для определения числа байтов (10 х 2 = 20). Следующие команды иллюстрируют три таких применения:
MOV AX,TYPE TABLEX ;AX=0002 MOV BX,LENGTH TABLEX ;BX=000A (10) MOV CX,SIZE TABLEX ;CX=0014 (20)
Ассемблер для IBM PC. Глава 14 33
Значения LENGTH и SIZE можно использлвать для окончания табличного поиска или сортировки. Например, если регистр SI содержит продвинутый адрес таблицы при осуществлении поиска, то проверка на конец таблицы может быть следующий:
CMP SI,SIZE TABLEX
В главе 23 "Справочник по директивам ассемблера" дается детальное описание операторов TYPE, LENGTH и SIZE.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ Для большинства применений, определяйте таблицы, имеющие родственные элементы одной длины и формата данных.
ъ Стройте таблицы на основе форматов данных. Например, элементы могут быть символьные или числовые длиной один, два и более байтов каждый. Может оказаться более практичным определение двух таблиц: одна, например, для трехсимвольных значений номеpов, а другая для двухбайтовых значений цен единиц товара. В процессе поиска адрес элементов таблицы номеров должен увеличи ваться на 3, а адрес элементов таблицы цен - на 2. Если сохранить число выполненных циклов при поиске на равно, то, умножив это число на 2 (SHL сдвиг влево на один бит), получим относительный адрес искомого значения цены. (Начальное значение счетчика циклов должно быть равно -1).


ъ Помните, что DB позволяет определять значения, не превышающие 256, а DW записывает байты в обратной последовательности. Команды CMP и CMPSW предполагают, что байты в сравниваемых словах имеют обратную последовательность.
ъ Если таблица подвергается частым изменениям, или должна быть доступна нескольким программам, то запишите ее на диск. Для внесения изменений в таблицу можно разработать специальную программу модификации. Любые программы могут загружать таблицу с диска и при обновлениях таблицы сами программы не нуждаются в изменениях.
ъ Будьте особенно внимательны при кодировке сортирующих программ. Пользуйтесь трассировкой для тестирования, так как малейшая ошибка может привести к непредсказуе мым результатам.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
Ассемблер для IBM PC. Глава 14 34
14.1. Определите таблицу, которая содержит имена дней недели, начиная с воскресения.
14.2 Предполагая, что воскресенье равно 1, напишите команды прямого доступа к таблице, определенной в вопросе 14.1. используйте любые подходящие имена.
14.3 Определите три отдельных связанных таблицы, содержащих следующие данные: а) числовые элементы: 06, 10, 14, 21, 24; б) элементы наименований: видеокассеты, приемники, модемы, клавиатуры, дискеты; в) цены: 93.95, 82.25, 90.67, 85.80, 13.85.
14.4 Составьте программу, позволяющую вводить числовой элемент (ITEMIN) и количество (QTYIN) с клавиатуры. Используя таблицу из вопроса 14.3, разработайте программу табличного поиска элемента равного ITEMIN. Выделите из таблиц наименование и цену. Рассчитайте величину стоимости (Количество х Цена ) и выдайте на экран наименование и стоимость.
14.5 Используя описание таблицы из вопроса 14.3, составьте процедуры: а) пересылающую содержимое одной таблицы в новую (пустую) таблицу; б) сортирующую содержимое новой таблицы в восходящей последовательности.
Ассемблер для IBM PC. Глава 15 45


Дисковая память I: Организация


------------------------------------------------------------

Дисковая память I: Организация

Цель: Рассмотреть основные форматы записей в памяти на твердом диске (винчестере) и на дискете, включая оглавление и таблицу распределения файлов.

ВВЕДЕНИЕ ------------------------------------------------------------

Диск является распростроненным средством для более или менее долговременного хранения данных. Процессы обработки данных на твердом диске (винчестре) аналогичны процессам для гибких дисков (дискет), за исключением того, что возможно потребуется обеспечить пути для доступа к многочисленным подоглавлениям винчестера. Для обработки файлов полезно ознакомиться с организацией дисковой памяти. Каждая cторона стандартной 5 1/4 дюймовой дискеты содержит 40 концентричес ких дорожек, пронумерованных от 00 до 39. На каждой дорожке форматируется восемь или девять секторов по 512 байтов каждый. Дданные записываются на диск в виде файлов, аналогично тому, как вы записываете ассемблерные программы. Хотя на типы данных, которые можно хранить в файле, не существует каких-либо ограничений, типичный пользовательский файл содержит списки заказчиков, описи товаров и предложений или списки имен и адресов. Каждая запись содержит информацию о конкретном заказчике или описание товара. Внутри файла все записи имеют одинаковую длину и формат. Запись может содержать oдно или несколько полей. Файл заказчиков, например, может состоять из записей, в которые входит номер заказчика, имя заказчика и долговой баланс. Эти записи могут быть расположены в порядке возрастания номеров заказчиков следующим образом:

+--+---+-----++--+---+-----++--+---+-----+ +--+---+-----+ |Э1|имя|сумма||Э2|имя|сумма||Э3|имя|сумма|...|Эn|имя|сумма| +--+---+-----++--+---+-----++--+---+-----+ +--+---+-----+

Для программирования дисковых файлов следует в общих чертах ознакомится только с концепцией и терминологией. Если в данной главе размеры диска не указываются, то предполагается диск 5 1/4" формата.

ЕМКОСТЬ ДИСКА ------------------------------------------------------------


Емкость гибких дисков:
Версия Число Число Число Всего
Ассемблер для IBM PC. Глава 15 46
дорожек секторов байтов в на двух на стороне на дорожке секторе сторонах
До DOS 2.0 40 8 512 327 680 DOS 2.0 и после 40 9 512 368 640 Высокая плотность 80 15 512 1 228 800 3 1/2" 80 9 512 737 280
Емкость твердых дисков:
Версия Число Число Число Всего дорожек секторов байтов в на 4-х на стороне на дорожке секторе сторонах
10 мегабайт 306 17 512 10 653 696 20 мегабайт 614 17 512 21.377.024
Указание стороны (головки), дорожки или сектора на диске осуществляется по номеру. Для стороны и дорожки отсчет ведется с 0, а для сектора - с 1.
ОГЛАВЛЕНИЕ ДИСКА (КАТАЛОГ) ------------------------------------------------------------
Для того, чтобы организовать хранение информации на диске, операционная система DOS резервируют определенные сектора для своих нужд. Организация данных на дискете или на твердом диске существенно зависит от их емкости. Формати рованная двухстороняя дискета с девятью сектороми на дорожке содержит следующую системную информацию:
Сторона Дорожка Сектор 0 0 1 Запись начальной загрузки 0 0 2-3 Таблица распределения файлов (FAT) 0 0 4-7 Каталог 1 0 1-3 Каталог 1 0 4 ... Файлы данных
Область записей данных начинается с третьего сектора на 1-й стороне 0-й дорожки и продолжается до девятого сектора. Следующие записи заносятся на 0-ю сторону 1-й доpожки, затем на 1-ю сторону 1-й дорожки, затем на 0-ю сторону 2-й дорожки и т.д. Такая особенность заполнения дисковой памяти на противоположных дорожках снижает число перемещений головки дисковода. Данный метод используется как для гибких, так и для твердых дисков. При использовании утилиты FORMAT /S для форматизации дискеты, модули DOS IBMBIO.COM и IBMDOS.COM записывается в первые сектора области данных.
Ассемблер для IBM PC. Глава 15 47
Все файлы, даже меньшие 512 байт (или кратные 512), начинаются на границе сектора. Для каждого файла DOS создает на нулевой доpожке диска элемент оглавления. Каждый такой элемент описывает имя, дату, размер и расположение файла на диске. Элементы оглавления имеют следующий формат:


Байт Назначение
0- 7 Имя файла, определяемое из программы, создавшей данный файл. Первый байт может указывать на статус файла: шест.00 обозначает, что данный файл не используется, шест.E5 - файл удален, шест. 2E - элемент подоглавления. 8-10 Тип файла 11 Атрибут файла, определяющий его тип: шест.00 - обычный файл; шест.01 - файл можно только читать; шест.02 - "спрятанный" файл; шест.04 - системный файл DOS; шест.08 - метка тома; шест.10 - подоглавление; шест.20 - архивный файл (для твердого диска). 12-21 Зарезервировано для DOS. 22-23 Время дня, когда файл был создан или последний раз изменялся, в следующим двоичном формате:
|чччччммммммссссс|
24-25 Дата создания или последнего изменения файла, сжатая в два слова в следующем двоичном формате:
|гггггггм|мммддддд|
где год начинается с 1980 и может принимать значения от 0 до 119, месяц - от 1 до 12, а день - от 1 до 31. 26-27 Начальный кластер файла. Относительный номер последних двух секторов каталога. Первый файл данных (без COM-модулей DOS) начинается на относительном кластере 002. Текущая сторона, дорожка и кластер зависят от емкости диска. 28-31 Размер файла в байтах. При создании файла DOS вычисляет и записывает размер файла в это поле.
Все поля в каталоге диска, превышающие один байт, записываются в обратной последовательности байтов.
ТАБЛИЦА РАСПРЕДЕЛЕНИЯ ФАЙЛОВ ------------------------------------------------------------
Назначение таблицы распределения файлов (FAT - File Allocation Table) - распределение дискового пространства для файлов. Если вы создаете новый файл или изменяете существующий, то DOS меняет элементы таблицы файлов в
Ассемблер для IBM PC. Глава 15 48
соответствии с расположением файла на диске. Запись начальной загрузки находится на секторе 1, далее на секторе 2 начинается FAT. FAT содержит элементы для каждого кластера, длина элементов FAT зависит от устройства дисковой памяти. Кластер для односторонних дискет представляет собой один сектор, для двухсторонних дискет - смежную пару секторов. Одно и то же число элементов в FAT определяет в два pаза больше данных для двухсторонних дискет, чем для одностронних. Первые байты FAT определяют тип устройства:


FE Односторонняя на 8 секторов FC Односторонняя на 9 секторов FF Двухсторонняя на 8 секторов FD Двухсторонняя на 9 секторов F9 Повышенная емкость (1,2 мегабайта) F8 Твердый диск
Второй и третий байты пока содержат FFFF. В следующей таблице показана организация данных для нескольких типов устройств (приведены начальные и конечные номера секторов). Колонка "Кластер" представляет число секторов в кластере:
Устройство диска Запись FAT Каталог Кластер нач.загр.
Односторонний, 8 секторов 1 2-3 4-7 1 Односторонний, 9 секторов 1 2-5 6-9 1 Двухсторонний, 8 секторов 1 2-3 4-10 2 Двухсторонний, 9 секторов 1 2-5 6-12 2 Повышенная емкость (1,2 М) 1 2-15 16-29 1 Твердый диск XT 1 2-17 18-49 8 Твердый диск AT 1 2-838 4-115 4
Начиная с четвертого байта, элементы FAT определяют сектора. Каждый такой элемент имеет длину 12 битов. (В версии DOS 3 и старше элементы FAT для твердого диска могут иметь длину 16 битов). Два первых элемента FAT, известные как относительные сектора 000 и 001, соответственно, указывают на два последних сектора оглавления, определяя его размер и формат. Первый файл данных начинается на относительном секторе 002. Каждый элемент FAT состоит из трех шест.цифр (12 битов), которые указывают на характер использования конкретного сектора:
000 свободный кластер, nnn относительный номер следующего кластера для файла, FF7 неиспользуемый кластер (сбойная дорожка), FFF последний кластер файла.
Предположим, например, что дискета содержит только один файл с именем PAYROLL.ASM, занимающий относительные сектора 002, 003 и 004. Элемент оглавления для этого файла содержит
Ассемблер для IBM PC. Глава 15 49
имя файла PAYROLL, тип - ASM, шест.00 для обычного файла, дату создания, 002 - номер первого относительного сектора файла и размер файла в битах. Таблица FAT в этом случае может выглядеть следующим образом (кроме того, что в каждой паре байты в обратной последовательности):
Элемент FAT: |FDF|FFF|003|004|FFF|000|000|...|000| Относительн.сектор: 0 1 2 3 4 5 6 ...конец


Первые два элемента FAT указывают расположение каталога на относительных секторах 000 и 001. Для ввода рассматриваемого файла в память, система выполняет следующие действия:
1. DOS получает доступ к дискете и ищет в каталоге имя PAYROLL и тип ASM. 2. Затем DOS определяет по каталогу положение первого относительного сектора файла (002) и загружает содержи мое этого сектора в буферную область в основной памяти. 3. Номер второго сектора DOS получает из элемента FAT, соответствующего относительному сектору 002. Из диаграммы, приведенной выше, видно, что зтот элемент содержит 003. Это обозначает, что файл продолжается в относительном секторе 003. DOS загружает содержимое этого сектора в буфер в основной памяти. 4. Номер третьего сектора DOS получает из элемента FAT, соответствующего относительному сектору 003. Этот элемент содержит 004, значит файл продолжается в относительном секторе 004. DOS загружает срдержимое этого сектора в буфер в основной памяти. 5. Элемент FAT для относительного сектора 004 содержит шест.FFF, что свидетельствует о том, что больше нет данных для этого файла.
Элемент каталога содержит номер начального кластера для каждого файла, а FAT - шест.трехзначные элементы, указываю щие на расположение каждого дополнительного кластера, если он имеется. Для того, чтобы указать, например, что файл содержит все записи только в первом кластере, таблица FAT должна содержать шест.FFF в элементе, представляющем первый относительный кластер. В качестве простого примера рассмотрим элемент каталога, указывающий, что некоторый файл начинается в относительном кластере 15. Для локализации первого элемента таблицы FAT необходимо:
ъ Умножить 15 на 1,5, получим 22,5. ъ Выполнить выборку содержимого байтов 22 и 23 из FAT. Прежположим, что они содержат F*FF. ъ Переставить байты: FFF*.
Ассемблер для IBM PC. Глава 15 50
ъ Так как номер 15-нечетный, то первые три цифры - FFF указывают на отсутствие других кластеров для данного файла.
Теперь рассмотрим файл, который занимает четыре кластера, начинающихся с номера 15. Таблица FAT, начиная с байта 22 и далее, в этот pаз показана в правильной обратной последовательности байтов в паpах:


6* 01 17 80 01 FF*F
Для того, чтобы найти первый элемент FAT, необходимо умножить 15 на 1,5, получим 22,5, и выбрать содержимое байтов 22 и 23, как в предыдущем примере. В этот раз эти байты содержат 6*01, что после перестановки байт даст 016*. Так как 15-число нечетное, то используются первые три цифры 016. Второй кластер для файла, следовательно, имеет номер 016. Для того, чтобы найти третий кластер, необходимо умножить 16 на 1,5 получим 24. Затем следует выбрать содержимое байтов 24 и 25 таблицы FAT. Значение 1780 после перестановки байтов даст 8017. Так как число 16 четное, то используются последние три цифры 017. Третий кластер для файла имеет номер 017. Для того, чтобы найти четвертый кластер, необходимо умножить 17 на 1,5, получим 25.5. Затем следует выбрать содержимое байтов 25 и 26 таблицы FAT. Значение 8001 после перестановки байтов даст 0180. Так как число 17 нечетное, то используются первые три цифры 018. Четвертый кластер для файла имеет номер 018. При использовании этой же процедуры для локализации содержимого следующего элемента FAT по относительным адресам 27 и 28, получим FF*F, что после перестановки даст *FFF. Так как число 18 четное, используются последние три цифры FFF, что обозначает последний элемент. Как было ранее сказано, все файлы начинаются на границе кластеpа. Кроме того, совсем не обязательно файл должен храниться в соседних кластерах, он может быть разбросан на диске по разным секторам. Если в программе необходимо определить тип установленного диска, то можно обратиться к таблице FAT непосредственно, или, что предпочтительней, использовать функцию DOS 1BH или 1CH.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ Независимо от размеров все файлы начинаются на границе кластера. ъ Оглавление (каталог) содержит для каждого файл на диске элементы, определяющие имя, тип, атрибуты, дату, началь ный сектор и pазмер файла.
Ассемблер для IBM PC. Глава 15 51
ъ Таблица распределения файлов (FAT) содержит один элемент для каждого кластеpа в каждом файле.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
15.1. Какую длину в байтах имеет стандартный сектор?
15.2. Где расположена запись начальной загрузки?
15.3. Как обозначаются в оглавлении удаленные файлы?
15.4. Какие дополнительные действия выполняются при формати зации дискеты по команде DOS FORMAT /S?
15.5. Где и каким образом обозначается в таблице FAT, что устройством является твердый диск?
15.6. Имеется файл размером 2890 (десятичное) байтов: а) Где хранит cистема размер файла? б) Как выражается этот размер в шестнадцатиричном формате? в) Покажите значе ние в том виде, как оно записывается системой.
Ассемблер для IBM PC. Глава 16. 1


Дисковая память II: Функции базовой версиии DOS


------------------------------------------------------------ Дисковая память II: Функции базовой версиии DOS

Цель: Раскрыть основные требования к программированию функций базовой версии DOS для обработки дисковых файлов.

ВВЕДЕНИЕ ------------------------------------------------------------

В начале данной главы рассматриваются функции базовой версии DOS, определяющие блок управления файлом (FCB), а затем будут показаны возможности создания и обработки дис ковых файлов последовательным и прямым доступом. Все рассмат риваемые операции были введены в первых версиях DOS и возмож ны во всех последующих версиях. Обработка дисковых файлов в базовой DOS включает определе ние блока управления файлом (FCB - file control block), кото рый описывает файл и его записи. Передача адреса блока FCB в DOS обязательна для всех дисковых операций ввода-вывода. Новых команд ассемблера в данной главе не потребуется. Управление вводом и выводом осуществляется специальными прерываниями. Запись файла на диск требует, чтобы прежде он был "создан" и DOS смогла сгенерировать соответствующий эле мент в оглавлении. Когда все записи файла будут записаны, программа должна "закрыть" файл, так, чтобы DOS завершила обработку оглавления. Чтение файла требует, чтобы он был сначала "открыт" для того, чтобы убедиться в его существо вании. Так как записи имеют фиксированную длину и в силу соответствующей организации оглавления, обработка записей дискового файла может осуществляться как последовательно, так и произвольно. Метод доступа к дисковой памяти, поддерживающий использо вание оглавления, "блокирование" и "разблокирование" запи сей, обеспечивается прерыванием DOS 21H. Более низкий уро вень, обеспечивающий абсолютную адресацию дисковых секторов, также через DOS, выполняется посредством прерываний 25H и 26H. Самый низкий уровень обеспечивается прерыванием BIOS 13H, которое позволяет выполнить произвольную адресацию в дисковой памяти по номеру дорожки и сектора. Методы DOS осу ществляют некоторую предварительную обработку до передачи управления в BIOS. В главе 17 объясняется применение пред почтительных функций расширенного DOS 2, а глава 18 пред ставляет основные дисковые операции в BIOS. Напоминание: Термин кластер определяет один или более секторов с данными в зависимости от дискового устройства.


БЛОК УПРАВЛЕНИЯ ФАЙЛОМ (FCB) ------------------------------------------------------------ Для выполнения операций ввода-вывода на диске в базовой DOS необходимо в области данных определить блок FCB. Блок FCB не поддерживает путь доступа к файлу, поэтому он исполь зуется главным образом для обработки файлов в текущей дирек
Ассемблер для IBM PC. Глава 16. 2
тории. Блок FCB содержит описание файла и его записей в приведенном ниже формате. Пользователь должен инициализи ровать байты 0-15 и 32-36, байты 16-31 устанавливается DOS.
Байты Назначение 0 Указывает дисковод: 01 для дисковода A, 02 для B и т.д. 1-8 Имя файла, выравненное по левой границе с конечными пробелами, если имя меньше 8 байт. Поле может содержать зарезервированные имена, например, LPT1 для принтера. 9-11 Тип файла для дополнительной идентификации, например, DTA или ASM. Если тип файла меньше трех байт, то он должен быть выравнен по левой границе и дополнен конечными пробелами. DOS хранит имя и тип файла в оглавлении. 12-13 Номер текущего блока. Блок содержит 128 записей. Для локализации конкретной записи используется номер текущего блока и номер текущей записи (байт 32). Первый блок файла имеет номер 0, второй - 1 и т.д. Операция открытия файла устанавливает в данном поле 0. 14-15 Логический размер записи. Операция открытия инициа лизирует размер записи значением 128 (шест.80). После открытия и перед любой операцией чтения или записи можно устанавливать в данном поле любое тре буемое значение длины записи. 16-19 Размер файла. При создании файла DOS вычисляет и записывает это значение (произведение числа запи сей на размер записей) в оглавление. Операция открытия выбирает размер файла из оглавления и заносит его в данное поле. Программа может читать это поле, но не может менять его. 20-21 Дата. При создании или последней модификации файла DOS записывает дату в оглавление. Операция открытия выбирает дату из оглавления и заносит в данное поле. 22-31 Зарезервировано для DOS. 32 Текущий номер записи. Данное поле содержит текущий номер записи (О-127) в текущем блоке (см.байты 12-13). Система использует текущие значения блока и записи для локализации записи в дисковом файле. Обычно номер начальной записи в данном поле - 0, но его можно заменить для начала последовательной обработки на любое значение от 0 до 127. 33-36 Относительный номер записи. Для произвольного дос тупа при операциях чтения или записи данное поле должно содержать относительный номер записи. Напри мер, для произвольного чтения записи номер 25 (шест.19), необходимо установить в данном поле шест 19000000. Произвольный доступ характеризует ся тем, что система автоматически преобразует относительный номер записи в текущие значения


Ассемблер для IBM PC. Глава 16. 3
блока и записи. Ввиду ограничения на максимальный размер файла (1.073.741.824 байтов), файл с короткими записями может содержать больше записей и иметь больший относительный номер записи. Если размер записи больше 64, то байт 36 всегда содер жит 00.
Помните, что числовые значения в словах и двойных словах записываются в обратной последовательности байтов. Блоку FCB предшествует необязательное семибайтовое расши рение, которое можно использовать для обработки файлов со специальными атрибутами. Для использования расширения необхо димо закодировать в первом байте шест.FF, во втором - атри бут файла, а в остальных пяти байтах шесь.нули.
ИСПОЛЬЗОВАНИЕ БЛОКА FCB ДЛЯ СОЗДАНИЯ ФАЙЛА НА ДИСКЕ ------------------------------------------------------------ Для ссылки на каждый дисковый файл программа должна содер жать правильно составленный блок управления файлом. Операции ввода-вывода на диск требуют установки адреса блока FCB в регистре DX. Доступ к полям блока FCB осуществляются по этому адресу с помощью регистровой пары DS:DX. Для создания нового файла программа использует функцию шест.16 в прерыва нии DOS INT 21H следующим образом:
MOV AH,16H ; Создание LEA DX,FCBname ; дискового файла INT 21H ; Вызов DOS
DOS осуществляет поиск имени файла и тип файла, взятого из соответствующих полей FCB, в оглавлении. Если элемент оглавления, содержащий необходимое имя (и тип), будет найдено, то DOS очищает найденный элемент для нового исполь зования, если такой элемент не будет найден, то DOS ищет свободный элемент. Затем операция устанавливает размер файла в 0 и "открывает" файл. На этапе открытия происходит проверка доступного дискового пространства, результат такой проверки устанавливается в регистре AL:
00 На диске есть свободное пространство FF На диске нет свободного пространства.
При открытии также устанавливается в блок FCB номер текущего блока - 0 и размер записей (по умолчанию) - 128 (шест.80) байтов. Прежде, чем начать запись файла, можно заменить это значение по умолчанию на требуемый размер записей. Для определения выводной записи необходимо прежде обеспе чить начальный адрес этой записи в область передачи данных (DTA - disk trausfer area). Так как блок FCB содержит размер записей, то в DTA не требуется устанавливать ограничитель конца записи. Затем с помощью функции шест.1A необходимо


Ассемблер для IBM PC. Глава 16. 4
сообщить DOS адрес DTA. В любой момент времени может быть активен только один DTA. В следующем примере инициализи руется адрес DTA:
MOV AH,1AH ; Установка адреса LEA DX,DTAname ; DTA INT 21H ; Вызов DOS
Если программа обрабатывает только один дисковой файл, то должна быть только одна установка адреса DTA для всего выполнения. При обработке нескольких файлов программа должна устанавливать соответствующий адрес DTA непосредственно перед каждой операцией чтения или записи. Для последовательной записи на диск существует функция шест. 15:
MOV AH,15 ; Последовательная LEA DX,FCBname ; запись INT 21H ; Вызов DOS
Операция записи использует информацию из блока FCB и адрес текущего буфера DTA. Если длина записи равна размеру сектора, то запись заносится на диск. В противном случае записи заполняют буфер по длине сектора и затем буфер записы вается на диск. Например, если длина каждой записи состав ляет 128 байтов, то буфер заполняется четырьмя записями (4*128=512) и затем буфер записывается в дисковой сектор. После успешного занесения записи на диск DOS увеличивает в блоке FCB размер файла на размер записи и текущий номер записи на 1. Когда номер текущей записи достигает 128, про исходит сброс этого значения в 0 и в FCB увеличивается номер текущего блока на 1. Операция возвращает в регистре AL сле дующие коды:
00 Успешная запись. 01 Диск полный. 02 В области DTA нет места для одной записи.
Когда запись файла завершена, можно, хотя и не всегда обязательно, записать маркер конца файла (шест.1A). Для за крытия файла используется функция шест.10:
MOV AH,10H ; Закрыть LEA DX,FCBname ; файл INT 21H ; Вызов DOS
Эта операция записывает на диск данные, которые еще остались в дисковом буфере DOS и изменяет в соответствующем элементе оглавления, дату и размер файла. В регистре AL возвращаются следующие значения:
00 Успешная запись. FF Описание файла оказалось в неправильном
Ассемблер для IBM PC. Глава 16. 5
элементе оглавления (возможно в результате смены дискеты).


ПРОГРАММА: ИСПОЛЬЗОВАНИЕ FCB ДЛЯ СОЗДАНИЯ ФАЙЛА НА ДИСКЕ ------------------------------------------------------------ Программа, приведенная на рис.16.1, создает дисковый файл по имени, которое вводится пользователем с клавиатуры. Блок FCB (FCBREC) в данной программе содержит следующие поля:
FCBDRIV Программа должна создать файл на диске в дисководе 4 (или D). FCBNAME Имя файла - NAMEFILE. FCBEXT Тип файла - DAT. FCBBLK Начальное значение номера текущего блока - 0. FCBRCSZ Размер записей неопределен, так как операция откры тия устанавливает в данном поле значение 128. FCBSQRC Начальное значение номера текущей записи - 0.
В программе организованы следующие процедуры:
BEGIN Инициализирует сегментные регистры, вызывает C10OPEN для создания файла и установки адреса DTA для DOS, вызывает D10PROC для ввода имени файла. Если ввод пустой, то происходит вызов G10PROC для завершения программы. C10OPEN Создает для файла элемент в директории, устанавли вает размер записей - 32 (шест.20) и инициали зирует адрес буфера DTA для DOS. D10PROC Выдает запрос на ввод имен, вводит имена с клавиа туры и вызывает процедуру F10WRIT для записи вводи мых имен на диск. E10DISP Управляет прокруткой и установкой курсора. F10WRIT Записывает имена в дисковой файл. G10CLSE Записывает маркер конца файла и закрывает файл. X10ERR Выдает на экран сообщение об ошибке в случае не корректной операции создания файла или записи данных.
Каждая операция записи автоматически добавляет 1 к FCBSGRC (номер текущей записи) и шест.20 (размер записи) к FCBFLSZ (размер файла). Так как каждая запись имеет длину 32 байта, то операция заносит в буфер 16 записей и затем записы вает весь буфер в сектор диска. Ниже показано содержимое DTA и буфера:
DTA: |текущая запись| Буфер: |запись 00|запись 01|запись 02|...|запись 15|
Если пользователь ввел 25 имен, то счетчик записей увели чится от 1 до 25 (шест.19). Размер файла составит:
25 * 32 байта = 800 байтов или шест. 320
Ассемблер для IBM PC. Глава 16. 6
------------------------------------------------------------ ------------------------------------------------------------ Рис. 16.1. Создание дискового файла.


Операция закрытия заносит во второй сектор оставшиеся в буфере девять записей и изменяет в оглавлении дату и рвзмер файла. Размер записывается байтами в переставленном порядке: 20030000. Последний буфер имеет следующий вид:
Буфер: |запись 16|запись 17|...|запись 24|шест.1A|...|...|
Для простоты в приведенной программе создаются записи файла, содержащие только одно поле. Записи большинства других файлов, однако, содержит различные символьные и двоичные поля и требуют описания записи в DTA. Если записи содержат двоичные числа, то не следует использовать маркер конца файла (EOF), так как двоичное число может совпасть с шест. кодом 1A. Для того, чтобы сделать программу более гибкой, можно разрешить пользователю указать дисковод, на котором находит ся или будет находиться файл. В начале выполнения программа может выдать на экран сообщение, чтобы пользователь ввел номер дисковода, а затем изменить первый байт блока FCB.
ПОСЛЕДОВАТЕЛЬНОЕ ЧТЕНИЕ ДИСКОВОГО ФАЙЛА ------------------------------------------------------------ В базовой версии DOS программа, читающая дисковый файл, содержит блок управления файлом, который определяет файл точно так, как он был создан. В начале программа для откры тия файла использует функцию шест. OF:
MOV AH,OFH ; Открытие LEA DX,FCBname ; файла INT 21H ; Вызов DOS
Операция открытия начинается с поиска в оглавлении элемен та с именем и типом файла, определенными в FCB. Если такой элемент не будет найден в оглавлении, то в регистре AL уста навливается шест. FF. Если элемент найден, то в регистре AL устанавливается 00 и в FCB заносится действительный размер файла, а также устанавливается номер текущего блока в 0, длина записи в шест.80. После открытия можно заменить длину записи на другое значение. DTA должно содержать определение считываемой записи в соответствии с форматом, который использовался при создании файла. Для установки адреса DTA используется функция шест.1A (не путать с маркером конца файла EOF шест.1A) аналогично созданию дискового файла:


MOV AH,1AH ; Установка LEA DX,DTAname ; адреса DTA INT 21H ; Вызов DOS
Ассемблер для IBM PC. Глава 16. 7
Для последовательного чтения записей с диска используется функция шест.14:
MOV AH,14H ; Последовательное LEA DX,FCBname ; чтение записей INT 21H ; Вызов DOS
Чтение записи с диска по адресу DTA осуществляется на ос нове информации в блоке FCB. Операция чтения устанавливает в регистре AL следующие коды возврата:
00 Успешное чтение. 01 Конец файла, данные не прочитаны. 02 В DTA нет места для чтения одной записи. 03 Конец файла, прочитана частичная запись, заполненная нулями. Первая операция чтения заносит содержимое всего сектора в буфер DOS. Затем операция определяет из блока FCB размер записи и пересылает первую запись из буфера в DTA. После дующие операции чтения пересылают остальные записи (если име ются) пока буфер не будет исчерпан. После этого операция чтения определяет адрес следующего сектора и заносит его со держимое в буфер. После успешной операции чтения в блоке FCB автоматически увеличивается номер текущей записи на 1. Завершение после довательного чтения определяется программой по маркеру конца файла (EOF), для чего в программе имеется соответствующая проверка. Так как оглавление при чтении файла не изменя ется, то обычно нет необходимости закрывать файл после завершения чтения. Исключение составляют программы, которые открывают и читают несколько файлов одновременно. Такие программы должны закрывать файлы, так как DOS ограничивает число одновременно открытых файлов.
ПРОГРАММА: ИСПОЛЬЗОВАНИЕ FCB ДЛЯ ЧТЕНИЯ ДИСКОВОГО ФАЙЛА ------------------------------------------------------------ На рис.16.2 приведена программа, которая выполняет чтение файла, созданного предыдущей программой, и вывод на экран имен из записей файла. Обе программы содержат идентичные блоки FCB, хотя, имена полей FCB могут быть различны. Содержимое полей имени и типа файла должны быть одинаковы. Программа содержит следующие процедуры:
BEGIN Инициализирует сегментны регистра, вызывает про цедуру E10OPEN для открытия файла и установки DTA и вызывает F10READ для чтения записей. Если считан маркер конца файла, то программа завершается, если нет, то вызывается процедура G10DISP. E10OPEN Открывает файл, устанавливает значение размера и записей, равное 32 (шест.20), и инициализирует адрес DTA.


Ассемблер для IBM PC. Глава 16. 8
F10READ Выполняет последовательное чтение записей. Опера ция чтения автоматически увеличивает номер текущей запи си в блоке FCB. G10DISP Выводит на экран содержимое прочитанной записи. X10ERR Выводит на экран сообщение об ошибке в случае некорректной операции открытия или чтения.
------------------------------------------------------------ ------------------------------------------------------------ Рис. 16.2. Чтение дискового файла
Операция открытия выполняет поиск имени и типа файла в оглавлении. Если необходимый элемент оглавления найден, то автоматически в блок FCB заносятся размер файла, дата и длина записей. Первая операция чтения записи с номером 00 получает доступ к диску и считывает весь сектор (16 записей) в буфер. После этого первая запись заносится в DTA, а номер текущей записи в FCB увеличивается с 00 до 01:
Буфер: |запись 00|запись 01|запись 02|... |запись 15| DTA : |запись 00| Второй операции чтения нет необходимого обращаться к дис ку. Так как требуемая запись уже находится в буфере, то опе рация просто пересылает запись 01 из буфера в DTA и увели чивает номер текущей записи на единицу. Таким же образом вы полняются следующие операции чтения пока все 16 записей из буфера не будут обработаны. Операции чтения 16-ой записи приводит к физическому чтению следующего сектора в буфер и пересылка первой записи сектора в DTA. Последующие операции чтения переносят осталь ные записи из буфера в DTA. Попытка прочитать после последней записи вызовет состояние конца файла и в регистр AL будет записан код возврата шест. 01.
ПРЯМОЙ ДОСТУП ------------------------------------------------------------ До сих пор в этой главе рассматривалась последовательная обработка дисковых файлов, которая адекватна как для созда ния файла, так и для печати его содержимого или внесения из менений в небольшие файлы. Если программа ограничена только возможностью последовательной обработки, то для изменения файла она должна считывать каждую запись, вносить изменения в определенные из них и заносить записи в другой файл (программа может использовать один DTA, но потребуются различные блоки FCB). Обычной практикой является чтение входного файла с диска A и запись обновленного файла на диск B. Преимущество этого способа состоит в том, что он автома тически оставляет резервную копию. В некоторых случаях применяется доступ к конкретным записям файла для получения информации, например, нескольких служащих или о части ассортимента товаров. Для доступа, скажем, к 300-ой записи файла, последовательная обработка


Ассемблер для IBM PC. Глава 16. 9
должна включать чтение всех 299 предшествующих записей, пока не будет получена 300-я запись. Примечание: система может начать обработку с конкретного номера блока и записи). Несмотря на то, что файл создается последовательно, доступ к записям может быть последовательным или прямым (произвольным). Требования прямой обработки, используюшей вызов DOS, заключаются в установке требуемого номера записи в соответствующее поле FCB и выдаче команды прямого чтения или записи. Произвольный доступ использует относительный номер записи (байты 33-36) в блоке FCB. Поле имеет размер двойного слова и использует обратную последовательность байт в словах. Для локализации требуемой записи система автоматически пре образует относительный номер записи в номер текущего блока (байты 12-13) и номер текущей записи (байт 32).
ПРЯМОЕ ЧТЕНИЕ Операции открытия и установки DTA одинаковы как для прямой, так и для последовательной обработки. Предположим, что программа должна выполнить прямой доступ к пятой записи файла. Установим значение 05 в поле FCB для относительного номера записи и выполним команды для прямого чтения. В результате успешной операции содержимое пятой записи будет помещено в DTA. Для прямого чтения записи необходимо поместить тре буемое значение относительного номера записи в FCB и вызвать функцию шест.21:
MOV AH,21H ; Запрос на LEA DX,FCBname ; прямое чтение INT 21H ; Вызов DOS
Операция чтения преобразует относительный номер записи в номера текущего блока и записи. Полученные значения исполь зуются для локализации требуемой дисковой записи, передачи содержимого записи в DTA и установки в регистр AL следующие значения:
00 Успешное завершение 01 Данные не доступны 02 Чтение прекращено из-за нехватки места в DTA 03 Прочитана частичная запись, заполненная нулями.
Как видно, среди перечисленных кодов возврата отсутствует состояние конец файла. При корректном чтении записи пред полагается единственный код возврата - 00. Остальные коды возврата могут являться результатом установки неправильного относительного номера записи или некорректная установка адреса DTA или FCB. Так как такие ошибки легко допустить, то полезно выполнять проверку регистра AL на ненулевое зна чение.


Ассемблер для IBM PC. Глава 16. 10
Когда программа выдает первый запрос на прямую запись, операция, используя оглавление для локализации сектора, на котором находится требуемая запись, считывает весь сектор с диска в буфер и пересылает запись в DTA. Предположим, напри мер, что записи имеют размер 128 байт, т.е. четыре записи в одном секторе. Запрос на прямое чтение записи 23 приводит к чтению в буфер четырех записей, лежащих в одном секторе:
| запись 20 | запись 21 | запись 22 | запись 23 |
Когда программа вновь выдаст прямой запрос на запись, например, 23, то операция сначала проверит содержимое буфе ра. Так как данная запись уже находится в буфере, то она непосредственно пересылается в DTA. Если программа запросит запись 35, который нет в буфере, операция через оглавление локализует требуемую запись, считает весь сектор в буфер и поместит запись в DTA. Таким образом, операции прямого дос тупа к записям более эффективны, если номера записей близки друг к другу.
ПРЯМАЯ ЗАПИСЬ Операция создания файла и установки DTA одинаковы как для прямого, так и для последовательного доступа. Для обработки файла учета товаров программа может, используя прямой дос туп, считать необходимую запись, внести, введенные вручную, изменения (например, новое количество товаров) и вернуть запись на диск на то же место. Операция прямой записи использует относительный номер записи в блоке FCB и функцию шест.22 следующим образом:
MOV AH,22H ; Запрос на LEA DX,FCBname ; прямую запись INT 21H ; Вызов DOS
Операция устанавливает в регистре AL следующие коды воз врата:
00 Успешная операция 01 На диске нет места 02 Операция прекращена в результате недостаточ ного места в DTA.
При создании нового файла прямым доступом может быть полу чен ненулевой код возврата. Но при прямом чтении и переписы вании измененных записей на том же месте диска код возврата должен быть только 00. Относительный номер записи в блоке FCB при прямом доступе имеет размер двойного слова (четыре байта), каждое слово за писывается обратной последовательностью байтов. Для неболь ших файлов возможно потребуется установка лишь самого лево го байта или слова, но для больших файлов установка номера записи в трех или в четырех байтах требует некоторой тщательности.


Ассемблер для IBM PC. Глава 16. 11
ПРОГРАММА: ПРЯМОЕ ЧТЕНИЕ ДИСКОВОГО ФАЙЛА ------------------------------------------------------------ На рис.16.3 приведена программа, которая считывает файл, созданный предыдущей программой (см.рис.16.1). Вводя любой относительный номер записи, лежащей в границах файла, поль зователь запрашивает вывод на экран любой записи файла. Если файл содержит 25 записей, то правильными номера являются но мера от 00 до 24. Номер вводится с клавиатуры в ASCII форма те и должен быть в нашем случае одно- или двухзначным чис лом. Программа содержит следующие процедуры:
C10OPEN Открывает файл, устанавливает размер записи 32 и устанавливает адрес DTA. D10RECN Вводит номер записи с клавиатуры, преобразует его в двоичный формат и записывает полученное значение в FCB. В качестве усовершенствования процедуры можно вставить проверку вхождения номера в границы от 00 до 24. F10READ Помещает требуемую запись в DTA в соответствии с относительным номером записи в FCB. G10DISP Выводит запись на экран.
Процедура D10RECN вводит номер записи с клавиатуры и про веряет длину ввода в списке параметров. Возможны три вариан та: 00 Запрошен конец обработки 01 Введено однозначное число (в регистре AL) 02 Введено двухзначное число (в регистре AX)
------------------------------------------------------------ ------------------------------------------------------------ Рис.16.3. Прямое чтение дисковых записей.
Данная процедура преобразует введенное число из ASCII формата в двоичный формат. Так как значение находится в ре гистре AX, то лучше использовать команду AAD для преобра зования. После преобразования двоичный код из регистра AX пересылается в два левых байта поля относительного номера записи в блоке FCB. Если, например, введено число 12 в ASCII формате, то AX будет содержать 3132. Команда AND преобразует это значение в 0102, а команда AAD - в 000C. Результат пре образования заносится в поле относительного номера записи блока FCB в виде С000 0000.
ПРЯМОЙ БЛОЧНЫЙ ДОСТУП ------------------------------------------------------------ Если в программе имеется достаточно места, то одна прямая блочная операция может записать весь файл из DTA на диск, а также прочитать весь файл с диска в DTA. Данная особенность весьма полезна для записи на диск таблиц, которые другие про граммы могут считывать в память для обработки.


Ассемблер для IBM PC. Глава 16. 12
Начать можно с любого правильного относительного номера записи. Число записей также может быть любым, хотя блок дол жен находится в пределах файла. Перед началом необходимо открыть файл и инициализировать DTA. Для операции прямой блочной записи необходимо установить в регистре СX требуемое число записей, установить в FCB стартовый относительный номер записи и выдать функцию шест.28:
MOV AH,28H ; Операция прямой блочной записи MOV CX,records ; Установка числа записей LEA DX,FCBname ; INT 21H ; Вызов DOS
Операция преобразует относительный номер записи в текущие номер блока и номер записи. Полученные значения используются для определения начального адреса на диске. В результате опе рации в регистре AL устанавливаются следующие коды воз врата:
00 Успешное завершение для всех записей 01 На диске недостаточно места.
Кроме того операция устанавливает в FCB в поле относи тельного номера записи и полях текущих номеров блока и запи си значения, соответствующие следующему номеру записи. Напри мер, если были записаны записи с 00 до 24, то следующий номер записи будет 25 (шест.19). Для операции прямого блочного чтения необходимо устано вить в регистре CX требуемое число записей и использовать функцию шест.27:
MOV AH,27H ; Операция прямого блочного чтения MOV CX,records ; Установка числа записей LEA DX,FCBname ; INT 21H ; Вызов DOS
Операция чтения возвращает в регистре AL следующие значе ния: 00 Успешное чтение всех записей 01 Прочитана последняя запись файла 02 Прочитано предельное для DTA число записей 03 Прочитана последняя запись файла не полностью.
В регистре CX остается действительное число прочитанных записей, а в FCB в поле относительного номера записи и полях текущих номеров блока и записи устанавливаются значения, соответствующие следующему номеру записи. Если необходимо загрузить в память весь файл, но число за писей неизвестно, то следует после операции открытия разде лить размер файла на длину записи. Например, для размера файла шест.320 (800) и длине записи шест.20 (32) число запи сей будет шест.19 (25).


Ассемблер для IBM PC. Глава 16. 13
ПРОГРАММА: ПРЯМОЕ БЛОЧНОЕ ЧТЕНИЕ ------------------------------------------------------------ На рис.16.4 приведена программа, выполняющая блочное чте ние файла, созданного программой на рис.16.1. Программа уста навливает начальный относительный номер записи 00, в регист ре CX - счетчик на 25 записей и выводит на экран всю информа цию из DTA (только для того, чтобы убедиться, что информация считана). Другие варианты программы могут включать установ ку другого начального номера записи и считывание менее 25 за писей. В программе организованы следующие процедуры:
E10OPEN Открывает файл, устанавливает размер записи в FCB равным 32 и устанавливает адрес DTA. F10READ Устанавливает число записей равным 25 и выполняет блочное чтение. G10DISP Выводит блок на экран.
Операция чтения преобразует относительный номер записи 00 в FCB в номер текущего блока 00 и номер текущей записи 00. В конце операции чтения в FCB текущий номер записи будет со держать шест.19, а относительный номер записи - шест. 19000000. ------------------------------------------------------------ ------------------------------------------------------------ Рис. 16.4. Прямое блочное чтение.
АБСОЛЮТНЫЕ ОПЕРАЦИИ ДИСКОВОГО ВВОДА-ВЫВОДА ------------------------------------------------------------ Для непосредственного доступа к диску можно использовать операции абсолютного чтения и абсолютной записи с помощью функций DOS INT 25H и 26H. В этом случае не используются оглавление диска и преимущества блокирования и разблокиро вания записей, обеспечиваемые функцией DOS INT 21H. Абсолютные операции предполагают, что все записи имеют размер сектора, поэтому прямой доступ осуществляется к полно му сектору или блоку секторов. Адресация диска выполняется по "логическому номеру записи" (абсолютный сектор). Для определения логического номера записи на двухсторонних дискетах с девятью секторами счет секторов ведется с дорожки 0, сектора 1, следующим образом:
Дорожка Сектор Логический номер записи 0 1 0 0 2 1 1 1 9 1 9 17 2 9 26


Для двухсторонних дискет используется следующая формула:
Логический номер записи = (дорожка х 9) + (сектор - 1)
Ассемблер для IBM PC. Глава 16. 14
Например, логический номер записи на дорожке 2 и секторе 9 определяется как
(2 х 9) + (9 - 1) = 18 + 8 = 26
Фрагмент программы для абсолютных операций ввода-вывода:
MOV AL,drive# ; 0 для A, 1 для B и т.д. MOV BX,addr ; Адрес области ввода-вывода MOV CX,sectors ; Число секторов MOV DX,record# ; Начальный логический номер записи INT 25H или 26H ; Абсолютное чтение или запись
Операции абсолютного чтения или запись разрушают содержи мое всех регистров, кроме сегментных, и устанавливают флаг CF для индикации успешной (0) или безуспешной (1) операции. В случае безуспешной операции содержимое регистра AL описы вает характер ошибки:
AL Причина 1000 0000 Устройство не отвечает 0100 0000 Ошибка установки головок 0010 0000 Ошибка контролера 0001 0000 Ошибка дискеты? 0000 1000 Переполнение DMA при чтении 0000 0100 Сектор не найден 0000 0011 Попытка записи на защищенной дискете 0000 0010 Не найден адресный маркер
Команда INT записывает содержимое флагового регистра в стек. После завершения команды INT следует восстановить флаги, но проверив перед этим флаг CF.
ДРУГИЕ ДИСКОВЫЕ ОПЕРАЦИИ ------------------------------------------------------------ Кроме основных дисковых функций DOS имеется несколько дополнительных полезных дисковых операций.
Сброс диска: Шест. D Обычно нормальное закрытие файла приводит к занесению всех оставшихся в буфере записей на диск и корректировке ог лавления. В особых случаях (между шагами программы или ава рийном завершении) может потребоваться сброс диска. Функция DOS шест. D освобождает все файловые буфера и не корректи рует оглавление диска. Если необходимо, то вначале данная функция закрывает все файлы.
MOV AH,ODH ; Запрос на сброс диска INT 21H ; Вызов DOS
Установка текущего дисковода: Шест. E
Ассемблер для IBM PC. Глава 16. 15
Основное назначение функции DOS шест.E - установка номера текущего (по умолчанию) дисковода. Номер дисковода помещает ся в регистр DL, причем 0 соответствует дисководу A, 1 - B и т.д. MOV AH,OEH ; Запрос на установку MOV DL,02 ; дисковода C INT 21H ; Вызов DOS Операция возвращает в регистр AL число дисководов (незави симо от типа). Так как для DOS необходимо по крайней мере 2 логических дисковода A и B, то DOS возвращает значение 02 и для систем с одним дисководом. (Для определения действитель ного числа дисководов используется команда INT 11H).


Поиск элементов оглавления: шест. 11 и 12 Программной утилите может потребоваться поиск в оглавле нии для доступа к имени файла, например, при удалении или переименовании. Для доступа к первому или единственному элементу оглавления необходимо загрузить в регистр DX адрес неоткрытого блока FCB и выполнить функцию 11H. При использовании расширенного блока FCB можно также получить код атрибута (см.техническое руководство по DOS).
MOV AH,11H ; Запрос на первый элемент LEA DX,FCBname ; Неоткрытый FCB INT 21H ; Вызов DOS
FCB может быть расположено по адресу 5CH в префиксе про граммного сегмента, предшествующем программе в памяти (DTA по умолчанию). Подробно см. гл. 22. В регистре AL операция возвращает шест.FF, если элемент не найден, и шест.00, если найден. Операция устанавливает в DTA номер дисковода (1=A, 2=B и т.д.) имя файла и тип файла. Если найдено несколько элементов при выборке по шаблону (например, *.ASM), то для локализации элементов подмножества директории используется функция 12H:
MOV AH,12H ; Запрос следующего элемента LEA DX,FCBname ; Неоткрытый FCB INT 21H ; Вызов DOS
Коды возврата в регистре AL аналогичны кодам функции 11H.
Удаление файла: шест.13 Для удаления файла в программе используется функция DOS 13H. Операция удаления устанавливает специальный байт в первой позиции имени файла в оглавлении.
MOV AH,13H ; Запрос на удаление файла LEA DX,FCBname ; Неоткрытый FCB INT 21H ; Вызов DOS
Если операция находит и удаляет элемент, то в регистре AL устанавливается код возврата 00, иначе код равен шест.FF.
Ассемблер для IBM PC. Глава 16. 16
Переименование файла: шест. 17 Для переименования файла в программе используется функция DOS шест.17. Старое имя файла записывается в обычном месте блока FCB, а новое - начиная со смещения 16.
MOV AH,17H ; Запрос на переименование LEA DX,FCBname ; Адрес FCB INT 21H ; Вызов DOS
Символы ? и * в новом имени приводят к сохранению в соот ветствующих позициях символов из старого имени. Успешная опе рация устанавливает в регистре AL код возврата 00, а безуспешная (файл по старому имени не найден или по новому имени уже существует) - код FF.


Получение текущего номера дисковода: шест.19 Функция DOS шест. 19 позволяет определить текущий номер дисковода:
MOV AH,19H ; Получить текущий дисковод INT 21H ; Вызов DOS
Операция возвращает шест. номер дисковода в регистре AL (0=A, 1=B и т.д.). Полученное значение можно поместить непосредственно в FCB для доступа к файлу с текущего диско вода. Кроме перечисленных существуют функции для получения информации из таблицы FAT (1B и 10), установки поля прямой записи (24), установки вектора прерываний (25), создания нового программного сегмента (26) и анализа имени файла (29). Эти функции описаны в техническом руководстве по DOS.
ПРОГРАММА: ВЫБОРОЧНОЕ УДАЛЕНИЕ ФАЙЛОВ ------------------------------------------------------------ На рис.16.5 приведена COM-программа по имени SDEL, иллюстрирующая функции DOS 11H, 12H и 13H для удаления выб ранных файлов. Для запроса на удаление файлов пользователь может ввести,например, следующие команды:
SDEL *.* (все файлы) SDEL *.BAK (все BAK-файлы) SDEL TEST.* (все файлы по имени TEST)
Посредством DOS программа определяет в оглавлении элемен ты, удовлетворяющие запросу. DOS заносит полное имя найден ного элемента в PSP (префикс программного сегмента) по смеще нию шест.81 (DTA по умолчанию). Затем программа выводит на экран имя файла и запрос подтверждения. Ответ Y (да) разре шает удаление, N (нет) сохраняет файл, а Return завершает выполнение.
Ассемблер для IBM PC. Глава 16. 17
Обратите внимание на то, что данная программа должна быть создана как COM-программа, так как EXE-программа требуют отличной адресации для использования смещений шест.5С и 81 в PSP. Для тестирования программы используйте скопированные временно файлы. ------------------------------------------------------------ ------------------------------------------------------------ Рис.16.5. Выборочное удаление файлов.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------ - Программа, использующая INT 21H в базовой версии DOS для операций ввода-вывода на диск, должна содержать блок управления файлом (FCB) для каждого доступного файла. - Один блок содержит 128 записей. Номер текущего блока и номер текущей записи в FCB указывают на дисковую запись, которая должна быть обработана. - В обратной последовательности байт в FCB записываются следующие элементы: номер текущего блока, размер записи, размер файла и относительный номер записи. - Все программы, обрабатывающие один и тот же файл, должны иметь одинаково описанный блок FCB. - Область ввода-вывода (DTA) определяется адресом памяти, куда должна быть помещена запись при чтении или откуда она заносится на диск. Прежде, чем выполнить операцию записи или чтения, в программе необходимо установить каждую область DTA. - Операция открытия файла устанавливает в блоке FCB значе ния для следующих элементов: имя файла, тип файла, размер запи си (шест.80), размер файла и дата. Программа должна заменить размер записей на правильное значение. - Программа, использующая для записи файла операцию DOS INT 21H, должна закрыть файл в конце обработки для того, чтобы поместить на диск все оставшиеся в буфере записи (если таковые имеются) и скорректировать соответствующий элемент оглавления. - При использовании для чтения и записи операции DOS INT 21H система автоматически изменяет текущий номер записи в FCB. - Операция чтения по прерыванию DOS INT 21H проверяет наличие требуемой записи сначала в буфере и при отсутствии выполняет чтение с диска. - Прямой метод доступа требует указания номера записи в поле относительного номера записи блока FCB. - Восемь байт (двойное слово) относительного номера записи кодируются в обратной последовательности байт. - Если требуемая запись при прямом доступе уже находится в буфере, то система передает ее непосредственно в DTA. В противном случае выполняется чтение с диска в буфер всего сектора, содержащего необходимую запись. - Операции прямого блочного чтения и записи более эффек тивны при наличии достаточной памяти. Эти операции особенно удобны для загрузки таблиц.


Ассемблер для IBM PC. Глава 16. 18
- Команды DOS INT 25H и 26H осуществляют дисковые операции абсолютного чтения и записи, но не поддерживают обработку оглавления, не определяют конец файла и не обеспечивают блокирование и деблокирование записей.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------ 16.1. Напишите функции базовой версии DOS для следующих опе раций: а) создание файла, б) установка DTA, в) после довательная запись, г) открытие файла, д) последова тельное чтение. 16.2. Программа использует размер записи, устанавливаемый при открытии файла по умолчанию. а) Сколько записей содержит один сектор? б) Сколько записей содержит дискета с тремя дорожками по девять секторов на каждой? в) Если на дискете (б) находится один файл, то при последовательном чтении сколько произойдет физических обращений к диску? 16.3. Напишите программу, которая создает дисковый файл, содержащий записи из трех элементов: номер товара (пять символов), наименование товара (12 символов) и стоимость единицы товара (одно слово). Ввод этих значений должен осуществляться пользователем с клавиатуры. Не забудьте преобразовать числа из ASCII представления в двоичное представление. 16.4. Напишите программу, которая выводит на экран файл, созданный в вопросе 16.3. 16.5. Определите текущий блок и запись для следующих номеров записей при прямом доступе: а)45, б)73, в)150, г)260. 16.6. В каком виде номер записи 2652 (десятичное) устанавли вается в поле относительной записи блока FCB? 16.7. Укажите шестнадцатеричные номера функций для следу ющих операций: а) прямая запись, б) прямое чтение, в) прямая блочная запись, г) прямое блочное чтение. 16.8. Напишите команды для определения числа записей файла, предполагая, что операция открытия уже выполнена. Имена полей с размером файла FCB FLSZ и размером записи FCB FCSZ. 16.9. Используя программу из вопроса 16.4 для создания файла с количеством, ценами и наименованиями товаров, сформируйте файл с приведенными ниже данными. Напишите программу, которая выполняет одно блочное чтение данного файла и выводит каждую запись на экран.


Номер Цена Наименование 023 00315 Ассемблеры 024 00430 Компановщики 027 00525 Компиляторы 049 00920 Компрессоры 114 11250 Экстракторы 117 00630 Буксиры
Ассемблер для IBM PC. Глава 16. 19
122 10520 Лифты 124 21335 Процессоры 127 00960 Станки для наклеивания меток 232 05635 Черпатели? 999 00000
16.10. Измените программу из вопроса 16.9 так, чтобы цены записывались на диск в двоичном формате. 16.11. Измените программу из вопроса 16.9 так, чтобы а) ис пользовалась операция прямого чтения, б) пользователь мог вводить номер и количество товара и в) выполня лось вычисление и вывод на экран стоимости (произве дение количества товара на стоимость единицы товара).
Ассемблер для IBM PC. Глава 17. 1


Дисковая память III: Расширенные функции DOS


------------------------------------------------------------

Дисковая память III: Расширенные функции DOS

Цель: Ознакомить с расширенными функциями DOS, начиная с версии 2.0 для обработки дисковых файлов.

ВВЕДЕНИЕ ------------------------------------------------------------ Функции базовой версии DOS для обработки файлов, показан ные в главе 16, действительны для всех последующих версий DOS. В данной главе показаны ряд расширенных функций, введен ных в версиях DOS 2.0 и 3.0 и не поддерживаемых в ранних вер сиях. Прежде, чем пытаться выполнить дисковые операции из данной главы, следует убедиться в наличии необходимой версии DOS. Многие из расширенных функций проще своих аналогов в базо вой версии DOS. В руководствах по DOS рекомендуется исполь зовать новые функции, которые более естественны для систем типа UNIX. Некоторые операции включают использование строк в формате ASCIIZ для начальной установки дисковода, пути доступа и имени файла; номера файла для последовательного доступа к файлу; специальных кодов возврата.

ДАННЫЕ В ФОРМАТЕ ASCIIZ ------------------------------------------------------------ При использовании многих расширенных функций для диско вых операций необходимо сообщить DOS адрес строки в формате ASCIIZ, содержащей идентификацию файла в виде номера диско- вода, пути доступа и имени файла (все параметры необязатель ные) и строка должна завершаться шестнадцатеричным нулем, например: PATHNM1 DB 'B:\TEST.ASM',0 PATHNM2 DB 'C:\UTILITY\NU.EXE',0

Обратная косая (или прямая косая) используются в качест ве разделителя. Нулевой байт (zero) завершает строку (отсюда название ASCIIZ формата). Для прерываний, использующих в ка честве параметра ASCIIZ строку, адрес этой строки загружает ся в регистр DX, например, командой LEA DX,PATHNM1.

ФАЙЛОВЫЙ НОМЕР И КОДЫ ВОЗВРАТА ------------------------------------------------------------ Операции создания и открытия файла требуют загрузки в регистр AX двухбайтового числа, представляющего собой файло вый номер. В главе 8 показано, что стандартные устройства не нуждаются в операции открытия и могут использовать непосредственно файловые номера: 0 - ввод, 1 - вывод, 2 - вывод сообщений об ошибках, 3 - внешнее устройство, 4 - прин тер.


Ассемблер для IBM PC. Глава 17. 2
Для доступа к диску при создании или открытии файла ис пользуется ASCIIZ строка и функции DOS шест. 3C или 3D. Ус пешная операция устанавливает флаг CF в 0 и помещает файло вый номер в регистр AX. Этот номер необходимо сохранить в элементе данных DW и использовать его для всех последующих операций над дисковым файлом. При неуспешной операции флаг CF устанавливается в 1, а в регистр AX помещается код ошиб- ки, зависящий от операции (см.табл.17.1).
01 Ошибка номера функции 02 Файл не найден 03 Путь доступа не найден 04 Открыто слишком много файлов 05 Нет доступа (Операция отвергнута) 06 Ошибка файлового номера 07 Блок управления памятью разрушен 08 Недостаточно памяти 09 Ошибка адреса блока памяти 10 Ошибка оборудования 11 Ошибка формата 12 Ошибка кода доступа 13 Ошибка данных 15 Ошибка дисковода 16 Попытка удалить оглавление 17 Другое устройство ? 18 Нет больше файлов
СОЗДАНИЕ ДИСКОВОГО ФАЙЛА ------------------------------------------------------------ В последующих разделах раскрыты требования к созданию, записи и закрытию дисковых файлов для расширенной версии DOS. Создание файла: Шест.3C Для создания нового файла или переписывания старого файла используется функция шест.3C. При этом регистр DX должен содержать адрес ASCIIZ-строки, а регистр CX - необходимый атрибут. Байт атрибут был рассмотрен в главе 15; для обычно го файла значение атрибута - 0. Рассмотрим пример создания обычного файла:
MOV AH,3CH ; Запрос на создание MOV CX,00 ; обычного файла LEA DX,PATHNM1 ; ASCIIZ строка INT 21H ; Вызов DOS JC error ; Переход по ошибке MOV HANDLE1,AX ; Сохранение файлового номера в DW
При правильном открытии операция создает элемент оглав ления с данным атрибутом, очищает флаг CF и устанавливает файловый номер в регистре AX. Этот номер должен использо ваться для всех последующих операций. Если создаваемый файл уже существует (т.е. имя файла присутствует в оглавлении), то длина этого файла устанавливается в 0 для перезаписи.
Ассемблер для IBM PC. Глава 17. 3


В случае возникновения ошибки операция устанавливает флаг CF в 1 и помещает в регистр AX код возврата: 03, 04 или 05 (см.табл.17.1). Код 05 свидетельствует либо о переполнении оглавления, либо о защите существующего файла атрибутом "только чтение". При завершении операции необходимо сначала проверить флаг CF, так как при создании файла возможна установка в регистре AX файлового номера 0005, который можно легко спутать с кодом ошибки 05 (нет доступа).
Запись файла: шест.40 Для записи файла используется функция DOS шест.40. При этом в регистре BX должен быть установлен файловый номер, в регистре CX - число записываемых байт, а в регистре DX - адрес области вывода. В следующем примере происходит запись 256 байт из области OUTREC:
HANDLE1 DW ? OUTREC DB 256 DUP (' ') MOV AH,40H ; Запрос записи MOV BX,HANDLE1 ; Файловый номер MOV CX,256 ; Длина записи LEA DX,OUTREC ; Адрес области вывода INT 21H ; Вызов DOS JC error2 ; Проверка на ошибку CMP AX,256 ; Все байты записаны? JNE error3
Правильная операция записывает из памяти на диск все дан ные (256 байт), очищает флаг CF и устанавливает в регистре AX число действительно записанных байтов. Если диск перепол нен, то число записанных байтов может отличаться от задан ного числа. В случае неправильной операции флаг CF устанав ливается в 1, а в регистр AX заносится код 05 (нет доступа) или 06 (ошибка файлового номера). Закрытие файла : шест.3E После завершения записи файла необходимо установить файло вый номер в регистр BX и, используя функцию DOS шест.3E, закрыть файл. Эта операция записывает все оставшиеся еще данные из буфера на диск и корректирует оглавление и табли цу FAT. MOV AH,3EH ; Запрос на закрытие файла MOV BX,HANDLE1 ; Файловый номер INT 21H ; Вызов DOS
В случае ошибки в регистре AX устанавливается код 06 (неправильный файловый номер).
ПРОГРАММА:ИСПОЛЬЗОВАНИЕ ФАЙЛОВОГО НОМЕРА ДЛЯ СОЗДАНИЯ ФАЙЛА. ------------------------------------------------------------ Программа, приведенная на рис.17.2, создает файл по имени, которое вводится пользователем с клавиатуры. В программе имеются следующие основные процедуры:


Ассемблер для IBM PC. Глава 17. 4
C10CREA Использует функцию шест.3C для создания файла и сохраняет файловый номер в элементе данных по имени HANDLE. D10PROC Принимает ввод с клавиатуры и очищает пробелом байты от конца введенного имени до конца области ввода. F10WRIT Записывает файл, используя функцию шест.40. G10CLSE В завершении обработки, используя функцию шест.3E, закрывает файл для того, чтобы создать правильный элемент оглавления.
Область ввода имеет длину 30 байтов и завершается двумя байтами: возврат каретки (шест.0DH) и конец строки (шест. 0AH). Таким образом общая длина области ввода - 32 байта. Программа переносит на диск 32-x байтовые записи, как записи фиксированной длины. Можно опустить байты "возврат каретки" и "конец строки", но включить их, если потребуется сорти ровка файла. Программа DOS SORT требует наличия этих байтов для индикации конца записей. Для нашего примера команда SORT может выглядеть следующим образом:
SORT B:<NAMEFILE.DAT >NAMEFILE.SRT
В результате выполнения данной команды записи из файла NAMEFILE.DAT в возрастающей последовательности будут поме щены в файл NAMEFILE.SRT. Программа, приведенная на рис.17.3 выполняет чтение записей из файла NAMEFILE.SRT и вывод их на экран. Обратите внимание на два момента: 1) Символы воз- врат каретки и конец строки включены в конце каждой записи только для выполнения сортировки и в других случаях могут быть опущены. 2) Записи могут иметь переменную длину (по длине вводимых с клавиатуры имен); эта особенность включает некоторое дополнительное программирование, как это будет по казано на рис.17.4.
------------------------------------------------------------ ------------------------------------------------------------ Рис.17.2. Использование файлового номера для создания файла.
ЧТЕНИЕ ДИСКОВОГО ФАЙЛА ------------------------------------------------------------ В следующих разделах раскрыты требования для открытия и чтения дисковых файлов в расширенной версии DOS.
Открытие файла: шест.3D Если в программе требуется прочитать дисковый файл, то прежде необходимо открыть его, используя функцию шест.3D. Эта операция проверяет правильность имени файла и его нали чие на диске. При открытии регистр DX должен содержать ад рес необходимой ASCIIZ-строки, а регистр AL - код доступа:


0 Открыть файл только для ввода 1 Открыть файл только для вывода
Ассемблер для IBM PC. Глава 17. 5
2 Открыть файл для ввода и вывода
Остальные биты регистра AL используются для разделения фай лов DOS версии 3.0 и старше (см.техническое руководство по DOS). Обратите внимание, что для записи файла используется функция создания (шест.3C), но не функция открытия файла. Ниже приведен пример открытия файла для чтения:
MOV AH,3DH ; Запрос на открытие MOV AL,00 ; Только чтение LEA DX,PATHNM1 ; Строка в формате ASCIIZ INT 21H ; Вызов DOS JC error4 ; Выход по ошибке MOV HANDLE2,AX ; Сохранение номера в DW
Если файл с необходимым именем существует, то операция открытия устанавливает длину записи равной 1, принимает существующий атрибут, сбрасывает флаг CF и заносит файловый номер в регистр AX. Файловый номер используется в дальней шем для всех последующих операций. Если файл отсутствует, то операция устанавливает флаг CF и заносит в регистр AX код ошибки: 02, 04, 05 или 12 (см. рис.17.1). Не забывайте проверять флаг CF. При успешном создании файла система может установить в регистре AX файло вый номер 0005, что легко можно спутать с кодом ошибки 05 (нет доступа).
Чтение файла: Шест.3F Для чтения записей файла используется функция DOS шест. 3F. При этом необходимо установить в регистре BX файловый номер, в регистре CX - число байтов и в регистре DX - адрес области ввода. В следующем примере происходит считывание 512-байтовой записи:
HANDLE2 DW ? INPREC DB 512 DUP (' ') MOV AH,3FH ; Запрос на чтение MOV BX,HANDLE2 ; Файловый номер MOV CX,512 ; Длина записи LEA DX,INPREC ; Адрес области ввода INT 21H ; Вызов DOS JC error5 ; Проверка на ошибку CMP AX,00 ; Прочитано 0 байтов? JE endfile
Правильно выполненная операция считывает запись в память, сбрасывает флаг CF и устанавливает в регистре AX число действительно прочитанных байтов. Нулевое значение в регист ре AX обозначает попытку чтения после конца файла. Ошибочная операция устанавливает флаг CF и возращает в регистре AX код ошибки 05 (нет доступа) или 06 (ошибка файлового номе ра).


Ассемблер для IBM PC. Глава 17. 6
Так как DOS ограничивает число одновременно открытых файлов, то программа, успешно отработавшая с несколькими файлами, должна закрывать их.
ПРОГРАММА: ИСПОЛЬЗОВАНИЕ ФАЙЛОВОГО НОМЕРА ДЛЯ ЧТЕНИЯ ФАЙЛА ------------------------------------------------------------ На рис.17.3 приведена программа, которая читает файл, созданный предыдущей программой (см.рис.17.2) и отсорти рованный командой DOS SORT. Для открытия файла используется функция шест.3D. Полученный в результате файловый номер заносится в поле HANDLE и используется затем в функции шест.3F для чтения файла. В программе нет необходимости переносить курсор на новую строку, так как записи содержат в конце символы "возврат каретки" и "новая строка".
ASCII-ФАЙЛЫ (ФАЙЛЫ В ФОРМАТЕ ASCII) ------------------------------------------------------------ В предыдущих примерах были показаны операции создания и чтения файлов. Аналогичным образом можно обрабатывать ASCII- файлы (текстовые файлы), созданные DOS или редактором. Для этого необходимо знать организацию оглавления и таблицы FAT, а также способ записи данных в сектор диска, используемый системой. Система DOS записывает, например, ASM-файл в точ ном соответствии с вводом с клавиатуры, включая символы табу ляции (шест.09), возврат каретки (шест.OD) и конец строки (шест.OA). Для экономии дисковой памяти DOS не записывает пробелы, которые находятся на экране и предшествуют символу табуляции, и пробелы, находящиеся в строке справа от символа "возврат каретки". Следующий пример иллюстрирует ассемб лерную команду, как она может выглядеть на экране:
<tab>MOV<tab>AH,09<return>
------------------------------------------------------------ ------------------------------------------------------------ Рис.17.3. Использование файлового номера для чтения файла.
Для такой строки содержимое ASCII-файла будет:
094D4F560941482C30390D0A
Когда программа TYPE или редактор читают файл и выводят на экран символы "табуляция", "возврат каретки" и "конец строки" автоматически выравнивают данные. Рассмотрим программу, приведенную на рис.17.4, которая читает и выводит на экран файл HANREAD.ASM (пример на рис. 17.3) по секторам. Если программа HANREAD уже введена и проверена, то можно просто скопировать ее в файл с новым именем.


------------------------------------------------------------ ------------------------------------------------------------
Ассемблер для IBM PC. Глава 17. 7
Рис.17.3. Чтение ASCII-файла.
Программа выполняет в основном те же функции, что и DOS TYPE, т.е. выводит на экран каждую запись до символов "возврат каретки" и "конец строки" (CR/LE). Прокрутка содержимого экрана (скроллинг) вызывает некоторые проблемы. Если в программе не будет предусмотрено специальной проверки на конец экрана, то вывод новых строк будет осуществляться поврех старых и при короткой длине старые символы будут оставаться справа от новой строки. Для правильной прокрутки необходимо подсчитывать строки и контролировать достижение конца экрана. Так как строки ASCII-файла имеют переменную длину, то следует определять конец каждой строки прежде, чем выводить ее на экран. Рассматриваемая программа считывает полный сектор данных в область SECTOR. Процедура G10XFER передает данные побайтно из области SECTOR в область DISAREA, откуда они будут выдаваться на экран. При обнаружении символа "конец строки", процедура выводит на экран содержимое DISAREA, включая "конец строки". (Экран дисплея принимает также символы табуляции (шест.09) и автоматически устанавливает курсор в следующую справа позицию кратную 8). В программе необходимо проверять конец сектора (для считывания следующего) и конец области вывода. Для стандартных ASCII-файлов, таких как ASM-файлы, каждая строка имеет относительно короткую длину и гарантировано заверша ется парой символов CR/LF. Нетекстовые файлы, такие как EXE или OBJ, не имеют строк и поэтому рассматриваемая про грамма должна проверять достижение конца области DISAREA во избежание разрушения. Хотя программа предназначена для вывода на экран только ASCII-файлов, она имеет проверку для страховки от всяких неожиданных несимвольных файлов. Процедура G10XFER выполняет следующее: 1. Инициализирует адрес области SECTOR. 2. Инициализирует адрес области DISAREA. 3. При достижении конца области SECTOR считывает следующий сектор. В случае конца файла, завершает работу программы, иначе инициализирует адрес области SECTOR. 4. При достижении конца области DISAREA вставляет символы CR/LF, выводит строку на экран и инициализирует адрес DISAREA. 5. Переписывает символ из области SECTOR в область DISAREA. 6. По символу "конец файла" (шест.1A) завершает работу про граммы. 7. По символу "конец строки" (шест.OA) выводит на экран строку и переходит на п.2, по другим символам идет на п.3.


Попробуйте выполнить эту программу в отладчике DEBUG. При каждом вводе с диска просмотрите содержимое области ввода и обратите внимание на то, как DOS форматирует записи. Для улучшения данной программы организуйте вывод на экран запроса для указания пользователем имени и типа файла.
Ассемблер для IBM PC. Глава 17. 8
ДРУГИЕ ДИСКОВЫЕ ФУНКЦИИ В РАСШИРЕННОЙ ВЕРСИИ DOS ------------------------------------------------------------ Получение размера свободного дискового пространства: шест.36 Данная функция выдает информацию о дисковой памяти. Для выполнения функции необходимо загрузить в регистр DL номер дисковода (0 - текущий дисковод, 1 - A, 2 - B и т.д.):
MOV AH,36H ; Запрос на MOV DL,0 ; текущий дисковод INT 21H ; Вызов DOS
При указании неправильного номера дисковода операция воз вращает в регистре AX шест.FFFF, иначе следующие значения:
в AX число секторов на кластер в BX число доступных кластеров в CX число байтов на сектор в DX общее число кластеров на дисководе В версии DOS младше 2.0 для получения информации о диско вой памяти следует использовать функцию шест.1B (получить информацию из табблицы FAT).
Удаление файла: шест.41 Для удаления файлов из программы (за исключением файлов с атрибутом "только чтение") используется функция шест.41. При этом в регистре DX необходимо загрузить ASCIIZ строку, содержащую путь доступа и имя файла:
MOV AH,41H ; Запрос на удаление LEA DX,PATHNAM ; ASCIIZ-строка INT 21H ; Вызов DOS
В случае ошибки в регистре AX возвращается код 02 (файл не найден) или 05 (нет доступа).
Управление файловым указателем: шест.42 Система DOS имеет файловый указатель, который при открытии файла устанавливается в 0 и увеличивается на 1 при последовательных операциях записи или считывания. Для доступа к любым записям внутри файла можно менять файловый указатель с помощью функции шест.42, получая в результате прямой доступ к записям файла. Для установки файлового указателя необходимо поместить в регистр BX файловый номер и в регистровую пару CX:DX требуе мое смещение в байтах. Для смещений до 65.535 в регистре CX устанавливается 0, а в DX - смещение. В регистре AL должен быть установлен один из кодов, который определяет точку отсчета смещения:


0 - смещение от начала файла.
Ассемблер для IBM PC. Глава 17. 9
1 - смещение текущего значения файлового указателя, которое может быть в любом месте, включая начало файла. 2 - смещение от конца файла. Размер файла (и следовательно смещение до конца файла) можно определить, установив регистровую пару CX:DX в 0 и используя код 2 в регистре AL.
В следующем примере устанавливается файловый указатель на смещение 1024 байта от начала файла:
MOV AH,42H ; Установка указателя MOV AL,00 ; от начала файла LEA BX,HANDLE1 ; Установка файлового номера MOV CX,00 ; MOV DX,1024 ; Смещение 1024 байта INT 21H ; Вызов DOS JC error
Правильно выполненная операция сбрасывает флаг CF и воз вращает новый указатель в регистровой паре DX:AX. Неправиль ная операция устанавливает флаг CF в 1 и возвращает в регист ре AX код 01 (ошибка кода отсчета) или 06 (ошибка файлового номера).
Проверка или изменение атрибута: шест.43 Для проверки или изменения файлового атрибута в оглавле нии диска используется функция шест.43H. При этом в регистре DX должен быть установлен адрес ASCIIZ строки. Для проверки атрибута регистр AL должен содержать 00. Для изменения атрибута регистр AL должен содержать 01, а регистр CX - новое значение атрибута. Следующий пример устанавливает нормальный атрибут:
MOV AH,43H ; Запрос на установку MOV AL,01 ; нормального MOV CX,00 ; атрибута LEA DX,PATHNM2 ; ASCIIZ-строка INT 21H ; Вызов DOS
В случае проверки функция возвращает текущий атрибут фай ла в регистре CX. В случае изменения функция устанавливает в соответствующем элементе оглавления атрибут из регистра CX. Неправильная операция возвращает в регистре AX коды ошибок 02, 03 или 05.
Получить текущее оглавление: шест.47 Определение текущего оглавления для любого дисковода осуществляется с помощью функции шест.47. При этом необходи мо определить область памяти достаточно большую, чтобы содер жать пути доступа максимальной длины и загрузить адрес этой области в регистр DX. Регистр DL должен содержать номер дисковода: 0 - текущий, 1 - A, 2 - B и т.д. В результате


Ассемблер для IBM PC. Глава 17. 10
выполнения операция помещает в область памяти имя текущей директории (без номера дисковода), например, в следующем виде: ASSEMBLE\EXAMPLES
Нулевой байт (шест.00) идентифицирует конец составного имени пути доступа. Для корневой директории возвращаемое значение состоит только из одного байта - шест.00. Таким образом можно получить текущее имя пути доступа для любого файла в подоглавлении. Пример на рис.17.5 демонстрирует использование данной функции.
Поиск файлов по шаблону: шест.4E и шест.4F Данные функции аналогичны функциям шест. 11 и 12 базовой версии DOS. Функция 4E используется для начала поиска в ог лавлении, а функция 4F - для продолжения. Для начала поиска в регистр DX необходимо загрузить адрес ASCIIZ-строки, содер жащей имя пути доступа и шаблон поиска. Шаблон поиска может включать в себя символы ? и *. В регистре CX должно быть значение атрибута в любой комбинации битов (нормальный, оглавление, спрятанный или системный).
MOV AH,4EH ; Запрос на начало поиска MOV CX,00H ; Нормальный атрибут LEA DX,PATHNM1 ; ASCIIZ-строка INT 21H ; Вызов DOS
Если операция находит файл, удовлетворяющий шаблону поиска, то в текущий буфер DTA в FCB заполняется следующей информацией:
00 - резервировано DOS для последующего поиска 21 - атрибут файла 22 - время файла 24 - дата файла 26 - размер файла: младшее слово, затем старшее слово 30 - имя и тип в виде 13-байтовой ASCIIZ строки, завершаемой шест.00.
В случае ошибки в регистре AX возвращается код 02 (не найдено) или 18 (нет больше файлов). Для продолжения поиска файлов (после функции шест.4E) используется функция 4F. Между этими функциями не следует нарушать содержимое DTA.
MOV AH,4FH ; Запрос на продолжение поиска INT 21H ; Вызов DOS
Единственно возможный код в регистре AX - 18 (нет больше файлов). Обе рассмотренные функции не меняют состояние флага CF.
Переименование файла: шест. 56
Ассемблер для IBM PC. Глава 17. 11
Для переименования файла используется функция шест.56. При этом в регистр DX должен быть загружен адрес ASCIIZ- строки, содержащей старые значения дисковода, пути доступа, имени и типа файла, а в регистр DI (в действительности ES:DI) - адрес ASCIIZ-строки, содержащей новые значения дисковода, пути доступа, имени и типа файла. Если указыва ется номер дисковода, то он должен быть одинаков в обоих строках. Путь доступа может быть различным, поэтому данная операция может не только переименовывать файл, но и перено сить его в другое подоглавление.


MOV AH,56H ; Запрос на переименование файла LEA DX,oldstring ; DS:DX LEA DI,newstring ; ES:DI INT 21H ; Вызов DOS
В случае ошибки регистр AX возвращает коды 03 (путь досту па не найден), 05 (нет доступа?) и 17 (разные дисководы). Другие функции DOS, имеющие отношение к дисковым файлам, включают создание подоглавления (шест.39), удаление элемента оглавления (шест.3A), изменение текущего оглавления (шест. 3B), управление вводом-выводом для устройств (шест.44), дублирование файлового номера (шест.45), принудительное дублирование файлового номера (шест.46), получение состояния проверки ? (шест.54).
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------ - Многие функции расширенной версии DOS оперируют с ASCIIZ- строками, которые содержат путь доступа и завершаются байтом, содержащим шест.00. - Функции создания и открытия возвращают значение файлового номера, который используется для последующего доступа к файлу. - В случае ошибок многие функции устанавливают флаг CF и помещают код ошибки в регистр AX. - Как правило, функция создания используется для записи файла, а открытия - для чтения. - После того, как файл записан на диск, его необходимо закрыть для того, чтобы в оглавление были внесены соот ветствующие изменения.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------ 17.1. Какие значения кодов возврата для ситуаций "файл не найден" и "ошибка файлового номера" ? 17.2. Определите ASCIIZ-строку по имени PATH1 для файла CUST.LST на дисководе C. 17.3. Для предыдущего файла (п.17.2) напишите команды а) определения элемента по имени CUSTHAN для файлового номера, б) создание файла, в) записи файла из области CUSTOUT (128 байт) и г) закрытия файла. Обеспечьте проверку на ошибки.
Ассемблер для IBM PC. Глава 17. 12
17.4. Для файла (п.17.3) напишите команды а) открытия файла и б) чтения файла в область CUSTIN. Обеспечьте конт роль ошибок. 17.5. В каких случаях необходимо закрывать файл, который был открыт только для чтения ? 17.6. Измените программу на рис.17.4 так, чтобы пользова тель мог вводить с клавиатуры имя файла, который необходимо выдать на экран. Обеспечьте возможность любого числа запросов и завершение программы только по пустому запросу, т.е. простому нажатию клавиши Return.
Ассемблер для IBM PC. Глава 18. 1


Дисковая память IV: Функции BIOS


-----------------------------------------------------------

Дисковая память IV: Функции BIOS

Цель: Показать основные требования к программированию функций BIOS для создания и чтения дисковых файлов.

ВВЕДЕНИЕ ----------------------------------------------------------- Для дисковых операций можно программировать непосред ственно на уровне BIOS, хотя BIOS и не обеспечивает автоматически использование оглавления или блокирование/ деблокирование записей. Дисковая операция BIOS INT 13H рас сматривает все "записи", как имеющие размер сектора, а адресацию диска осуществляет в терминах действительных номера дорожки и номера сектора. Для дисковых операций чтения, записи и верификации необ ходима инициализация следующих регистров:

AH Определяет тип операции: чтение, запись, верификация или форматирование. AL Определяет число секторов. CH Определяет номер дорожки. CL Определяет номер начального сектора. DH Номер головки (стороны) : 0 или 1 для дискеты. DL Номер дисковода: 0=A, 1=B и т.д. ES:BX Адрес буфера ввода/вывода в области данных (за исключением операции верификации).

ДИСКОВЫЕ ОПЕРАЦИИ В BIOS ----------------------------------------------------------- Для указания необходимой дисковой операции необходимо перед INT 13H загрузить в регистр AH соответствующий код.

AH = 00: Сброс системы контролера дисковода Данная операция осуществляет полный сброс контролера дис ковода и требует для выполнения INT 13H загрузку в регистр AH значение шест.00. Операция используется в случаях, когда после других дисковых операций возвращается код серьезной ошибки.

AH = 01: Определить состояние дисковода Данная операция возвращает в регистре AL состояние дисковода после последней операции вводда/вывода (см.Байт состояния в следующем разделе). Операция требует только загрузки значения 01 в регистр AH.

AH = 02: Чтение секторов Данная операция выполняет чтение в память определенного числа секторов на одной дорожке. Число секторов обычно 1, 8 или 9. Адрес памяти для области ввода должен быть загружен в регистр BX, причем следует помнить, что реальный адрес


Ассемблер для IBM PC. Глава 18. 2
зависит от содержимого регистра EX, так как в данном случае используется регистровая пара ES:BX. В следующем примере выполняется чтение сектора в область INSECT, которая должна быть достаточно большой, чтобы вместить все данные:
MOV AH,02 ; Запрос на чтение MOV AL,01 ; один сектор LEA BX,INSERT ; Буфер ввода в ES:BX MOV CH,05 ; Дорожка 05 MOV CL,03 ; Сектор 03 MOV DH,00 ; Сторона (головка) 00 MOV DL,01 ; Дисковод 01 (B) INT 13H ; Вызов BIOS
Число действительно прочитанных секторов возвращается в регистре AL. Регистры DS, BX, CX и DX сохраняют свои значения. В большинстве случаев программа указывает только один сектор или все сектора на дорожке. Для последовательного чтения секторов программа должна увеличивать содержимое регистров CH и CL. Заметьте, что когда номер сектора достигает максимального значения, его необходимо сбросить в 01, а номер дорожки увеличить на 1 или изменить сторону 0 на 1 (для двухсторонних дискет).
AH = 03: Запись секторов Данная операция записывает данные из указанной области памяти (обычно 512 байтов или кратное 512) в один или несколько определенных секторов. Управляющая информация загружается в регистры аналогично операции чтения диска (код 02). Операция записи возвращает в регистре AL число секторов, которые действительно были записаны. Регистры DX, BX, CX и DX сохраняют свои значения.
AH = 04: Верификация сектора Данная операция проверяет, может ли быть найден указанный сектор, и выполняет своего рода контроль на четность. Опера цию можно использовать после записи (код 03) для гарантии более надежного вывода, на что потребуется дополнительное время ввода/вывода. Значения регистров устанавливаются ана- логично операции записи (код 03), за исключением регистро- вой пары ES:BX - их инициализация не требуется. Операция возвращает в регистре AL число обработанных секторов. Ре- гистры DX, BX, CX и DX сохраняют свои значения.
AH = 05: Форматирование дорожек Данная операция используется для форматирования опреде ленного числа дорожек в соответствии с одним из четырех размеров (стандарт для системы PC - 512). Операции чтения и записи для локализации требуемого сектора требуют информацию о формате. Для форматирования регистровая пара


Ассемблер для IBM PC. Глава 18. 3
ES:BX должна содержать адрес, который указывает на группу адресных полей для дорожки. Для каждого сектора на дорожке должен быть четырехбайтовый элемент в виде T/H/S|B, где
T номер дорожки, H номер головки, S номер сектора, B число байт на секторе, (00-128, 01-256, 02-512, 03-1024).
Например, для форматирования 03 дорожки, на стороне 00 и 512 байтов на сектор, первый элемент должен иметь значение шест.03000102 и за ним должны быть описаны элементы для остальных секторов на дорожке. Техническое руководство по AT содержит ряд дополнительных операций BIOS.
БАЙТ СОСТОЯНИЯ ------------------------------------------------------------ Для всех рассмотренных выше операций (02, 03, 04 и 05) в случае нормального завершения флаг CF и регистр AH содержит 0. В случае ошибки флаг CF устанавливается в 1, а регистр AH содержит код состояния, идентифицирующий причину ошибки. Код состояния аналогичен значению в регистре AL после выполнения операции 01.
AH Причина 0000 0001 Ошибка команды для дискеты 0000 0010 Не найден адресный маркер на диске 0000 0011 Попытка записи на защищенный диск 0000 0100 Не найден сектор 0000 1000 Выход за границы DMA (памяти прямого доступа) 0000 1001 Попытка доступа через границу 64K 0001 0000 Чтение сбойный участок на диске 0010 0000 Ошибка контролера дисковода 0100 0000 Ошибка установки (поиска) 1000 0000 Ошибка оборудования
В случае возникновения ошибки, обычным действием является сброс диска (AH=00) и троекратное повторение операции. Если таким образом ошибка не устраняется, то на экран выводится соответствующее сообщение и пользователь может сменить дискету.
ПРОГРАММА: ИСПОЛЬЗОВАНИЕ BIOS ДЛЯ ЧТЕНИЯ СЕКТОРОВ ------------------------------------------------------------ Рассмотрим программу, приведенную на рис.18.1, в которой используется команда BIOS INT 13H для чтения секторов диска. Программа базируется на примере, приведенном на рис.16.3, со следующими изменениями:
1. Отсутствует описание FCB и подпрограмма открытия.


Ассемблер для IBM PC. Глава 18. 4
2. Программа расчитывает каждый дисковый адрес. После каж дого чтения происходит увеличение номера сектора. При достижении номера сектора 10 процедура C10ADDR сбрасывает это значение в 01. Если номер стороны = 1, программа увеличивает номер дорожки; затем меняется номер стороны: 0 на 1 и 1 на 0. 3. Область CURADR содержит начальные значения номеров дорожки и сектора (их программа увеличивает), а область ENDADR - конечные значения. Один из способов улучшения программы - предоставить пользователю возможность указать начальные и конечные номера дорожки и сектора с помощью соответствующего запроса.
Выполните данную программу под управлением отладчика DEBUG. Проделайте трассировку команд, которые инициализируют сегментные регистры, и установите начальный и конечный номера секторов для файловой таблицы FAT (расположение таблицы FAT различно в разных версиях операционной системы). Используя команду G (до) для выполнения ввода с диска и проверки считанного содержимого таблицы FAT и элементов оглавления.
------------------------------------------------------------ ------------------------------------------------------------ Рис.18.1. Использование BIOS для чтения дискового файла.
В качестве альтернативы,отладчику DEBUG можно преобразо вать ASCII-символы в области ввода в их шест. эквиваленты и выдать на экран эти значения, как это делает отладчик DEBUG (см. программу на рис.14.5). Таким образом можно проверить содержимое любого сектора (в том числе "спрятанного"), а также предоставить пользователю возможность внести измене ния и записать измененный сектор на диск. Следует помнить, что при создании файла DOS может вносить записи на любые доступные сектора, которые не обязательно будут смежными на диске. Следовательно, с помощью команды BIOS INT 13H нельзя выполнить последовательное чтение файла.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------ - Команда BIOS INT 13 обеспечивает прямой доступ к дорожкам и секторам диска. - Команда BIOS INT 13 не поддерживает операции с оглавле нием, обнаружение конца файла, блокирование и деблокиро вание записей. - Верификация сектора выполняет элементарную проверку записанных данных, что приводит к увеличению времени обработки. - Проверяйте байт состояния после каждой дисковой операции через BIOS.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
Ассемблер для IBM PC. Глава 18. 5
18.1. Напишите команды для сброса дискового контролера. 18.2. Напишите команды для чтения байта состояния дискеты. 18.3. Напишите команды для BIOS INT 13H, выполняющие чтение одного сектора в область памяти INDISK, с дисковода A, головки 0, дорожки 6 и сектора 3. 18.4. Напишите команды для BIOS INT 13H, выполняющие запись трех секторов из области памяти OUTDISK, на дисковод B, головку 0, дорожку 8 и сектор 1. 18.5. При записи данных в вопросе 18.4, как можно распоз нать попытку записи на защищенный диск? 18.6. На основе вопроса 18.4 напишите команды контроля записи (операция верификации).
Ассемблер для IBM PC. Глава 19 1


ПЕЧАТЬ


------------------------------------------------------------ ПЕЧАТЬ

Цель: Описать возможности программ на языке ассемблера для вывода информации на печатающее устройство (принтер).

ВВЕДЕНИЕ ------------------------------------------------------------ Вывод на принтер несколько проще операций с экраном и диском. Для печати существует несколько операций, выполняющихся через DOS INT 21H и BIOS INT 17H. Команды, посылаемые на принтер, включают коды "конец страницы", "конец строки" и "возврат каретки". Принтеры классифицируются по качеству печати. Матричный принтер формирует символы в виде матрицы точек и обеспечи вает нормальный, узкий и широкий форматы символов. Более совершенные матричные принтеры обеспечивают точечную графи ку, наклонный шрифт, жирную печать и двойную плотность, а также могут печатать, например, символы игральных карт и другие алфавитно-цифровые символы. Высококачественные печа тающие устройства ограничены набором символов на сменной "ромашке" или барабане, но обеспечивают отличное качество печати и большое разнообразие принтеров. Многие высокока чественные принтеры обеспечивают печать 10,12 или 15 симво лов на дюйм, а также пропорциональное расположение пробелов, подчеркивание, теневую и полужирную печать. Лазерные принте ры обладают преимуществами как для матричной графики, так и для качественной печати текстов. Другая классификация печатающих устройств связана с интер фейсами. Компьютеры IBM PC имеют параллельный интерфейс, позволяющий передавать одновременно восемь битов из процес сора на принтер. Кроме того, существует последовательный интерфейс, который выполняет побитовую передачу данных. Многие принтеры имеют буфер памяти, объемом в несколько тысяч байтов. Принтеры также могут принимать биты контроля на четность (нечетность). Принтеры должны "понимать" специ альные сигналы из процессора, например, для прогона листа, перевода строки или горизонтальной табуляции. В свою очередь, процессор должен "понимать" сигналы от принтера, указывающие на конец бумаги или состояние "занято". К сожалению многие типы принтеров по разному реагируют на сигналы процессора и одной из наиболее сложных проблем для программистов - обеспечить соответствие собственных программ имеющимся печатающим устройством.


СИМВОЛЫ УПРАВЛЕНИЯ ПЕЧАТЬЮ ------------------------------------------------------------ Стандартными символами управления печатью являются сле дующие:
Десятичн. Шест. Назначение
Ассемблер для IBM PC. Глава 19 2
08 08 Возврат на шаг 09 09 Горизонтальная табуляция 10 0A Перевод строки 11 0B Вертикальная табуляция 12 0C Прогон страницы 13 0D Возврат каретки
Горизонтальная табуляция. Горизонтальная табуляция (шест. 09) возможна только на принтерах, имеющих соответствующее обеспечение, иначе символы табуляции игнорируются. В последнем случае можно имитировать табуляцию выводом соответствующего числа пробелов.
Перевод строки. Символ перевода строки (шест.OA) исполь зуется для прогона листа на один интервал. Соответственно для печати через два интервала используется два символа перевода строки.
Прогон страницы. Установка бумаги после включения принте ра определяет начальную позицию печати страницы. Длина страницы по умолчанию составляет 11 дюймов. Ни процессор, ни принтер автоматически не определяют конец страницы. Если ваша программа продолжает печатать после конца страницы, то произойдет переход через межстраничную перфорацию на на чало следующей страницы. Для управления страницами необходи мо подсчитывать число напечатанных строк и при достижении максимального значения (например, 55 строк) выдать код прого на страницы (шест.OC) и, затем, сбросить счетчик строк в 0 или 1. В конце печати необходимо выдать символ "перевода строки" или "прогона страницы" для вывода на печать данные последней строки, находящиеся в буфере печатающего устройства. Использование последнего символа "прогон страницы" позволяет установить напечатанный последний лист в положение для отрыва.
ФУНКЦИИ ПЕЧАТИ В РАСШИРЕННОЙ ВЕРСИИ DOS ------------------------------------------------------------ В операционной системе DOS 2.0 имеются файловые указатели, которые были показаны в главах по управлению экраном дисплея и дисковой печати. Для вывода на печатающее устройство используется функция DOS шест.40 и стандартный файловый номер 04. Следующий пример демонстрирует печать 25 символов из области HEADG:


HEADG DB 'Industrial Bicycle Mfrs', 0DH, 0AH ... MOV AH,40H ; Запрос печати MOV BX,04 ; Файловый номер принтера MOV CX,25 ; 25 символов LEA DX,HEADG ; Область вывода INT 21H ; Вызов DOS
Ассемблер для IBM PC. Глава 19 3
В случае ошибки операция устанавливает флаг CF и возвраща ет код ошибки в регистре AX.
ПРОГРАММА: ПОСТРАНИЧНАЯ ПЕЧАТЬ С ЗАГОЛОВКАМИ ------------------------------------------------------------ Программа, приведенная на рис.19.1, аналогична программе на рис.9.1, за исключением того, что после ввода имен с клавиатуры выводит их не на экран, а на печатающее устрой ство. Каждая напечатанная страница содержит заголовок и через двойной интервал список введенных имен в следующем виде:
List of Employee Names Page 01 Clancy Alderson Ianet Brown David Christie ...
Программа подсчитывает число напечатанных строк и при дос тижении конца страницы выполняет прогон до начала следующей страницы. В программе имеются процедуры:
D10INPT Выдает на экран запрос и затем вводит имя с кла виатуры. E10PRNT Выводит имя на печатающее устройство (длина име ни берется из вводного списка параметров); в конце страницы вызывает процедуру M10PAGE. M10PAGE Выполняет прогон на новую страницу, печатает за головок, сбрасывает счетчик строк и увели чивает счетчик страниц на единицу. P100UT Общая подпрограмма для непосредственного вывода на печатающее устройство.
В начале выполнения необходимо напечатать заголовок, но не делать перед этим перевод страницы. Поэтому процедура M10PAGE обходит перевод страницы, если счетчик PAGECTR содержит 01 (начальное значение). Поле PAGECTR определено как PAGECTR DB '01'
В начале выполнения необходимо напечатать заголовок, но не делать перед этим перевод страницы. Поэтому процедура M10PAGE обходит перевод страницы, если счетчик PAGECTR содержит 01 (начальное значение). Поле PAGECTR определено как PAGECTR DB '01'
В результате будет сгенерировано число в ASCII коде - шест. 3031. Процедура M10PAGE увеличивает счетчик PAGECTR на 1 так, что значение становится последовательно 3032, 3033 и т.д. Эти значения корректны до 3039, далее следует 303A, что будет распечатано, как двоеточие (:). Поэтому, если в правом байте поля PAGECTR появляется шест.3A, то это значение


Ассемблер для IBM PC. Глава 19 4
заменяется на шест.30, а к левому байту прибавляется единица. Таким образом шест.303A перекодируется в шест. 3130, т.е. в 10 в символьном представлении.
------------------------------------------------------------ ------------------------------------------------------------ Рис.19.1. Постраничная печать с заголовком.
Проверка на конец страницы до (но не после) печати имени гарантирует, что на последней странице будет напечатано по крайней мере одно имя под заголовком.
ПЕЧАТЬ ASCII-ФАЙЛОВ И ТАБУЛЯЦИЯ ------------------------------------------------------------
Табуляция, обеспечиваемая, например, видеоадаптерами, заключается в замене одного символа табуляции (код 09) несколькими пробелами при выводе так, чтобы следующая позиция была кратна 8. Таким образом, стандартные позиции табуляции являются 8, 16, 24 и т.д. Многие принтеры, однако, игнорируют символы табуляции. Поэтому, такая программа, как DOS PRINT, предназначенная для печати ASCII файлов (например ассемблерных исходных текстов) проверяет каждый символ, посылаемый на принтер. И, если обнаруживается символ табуляции, то программа выдает несколько пробелов до позиции кратной 8. Программа, приведенная на рис.19.2, выводит на экран запрос на ввод имени файла и, затем, печатает содержимое указанного файла. Эта программа в отличие от приведенной на рис.17.3 (вывод файлов на экран) осуществляет замену выводимых символов табуляции на соответствующее число пробелов. В результате символ табуляции в позициях от 0 до 7 приводит к переходу на позицию 8, от 8 до 15 - на 16 и т.д. Команды, реализующие данную логику, находятся в процедуре G10XFER после метки G60. Рассмотрим три примера обработки символа табуляции:
Текущая позиция печати: 1 9 21 Двоичное значение: 00000001 00001001 00010101 Очистка трех правых битов: 00000000 00001000 00010000 Прибавление 8: 00001000 00010000 00011000 Новая позиция: 8 16 24
В программе организованы следующие процедуры:
С10PRMP Запрашивает ввод имени файла. Нажатие только клавиши Return приводит к завершению работы программы. E10OPEN Открывает дисковый файл по указанному имени. G10XFER Контролирует конец сектора, конец файла, конец области вывода, символы "перевод строки" и табуля ции. Пересылает обычные символы в область вывода.


Ассемблер для IBM PC. Глава 19 5
P10PRNT Распечатывает выводную строку и очищает область вывода. R10READ Считывает сектор из дискового файла.
Коды "возврат каретки", "перевод строки" и "прогон страницы" действительны для любых принтеров. Можно модифици ровать программу для подсчета распечатываемых строк и выполнения прогона страницы (шест.OC) при достижении, например, строки 62.
------------------------------------------------------------ ------------------------------------------------------------ Рис.19.2. Печать ASCII файла.
Некоторые пользователи предпочитают устанавливать символы "прогон страницы" в ASCII файлах с помощью текстового редактора в конкретных местах текста, например, в конце ассемблерных процедур. Кроме того, можно изменить программу для функции 05 базовой версии DOS. Эта функция выполняет вывод каждого символа непосредственно на принтер. Таким образом можно исключить определение и использование области вывода.
ПЕЧАТЬ ПОД УПРАВЛЕНИЕМ БАЗОВОЙ DOS ------------------------------------------------------------
Для печати в базовой версии DOS необходимо установить в регистре AH код функции 05, а в регистр DL поместить распечатываемый символ и, затем, выполнить команду INT 21H следующим образом:
MOV AH,05 ;Запрос функции печати MOV DL,char ;Распечатываемый символ INT 21H ;Вызов DOS
С помощью этих команд можно передавать на принтер управляющие символы. Однако, печать, обычно, предполагает вывод полной или частичной строки текста и пошаговую обработку области данных, отформатированной по строкам. Ниже показазна программа печати полной строки. Сначала в регистр SI загружается начальный адрес области HEADG, а в регистр CX - длина этой области. Цикл, начинающийся по метке P20, выделяет очередной символ из области HEADG и посылает его на принтер. Так как первый символ области HEADG - "прогон страницы", а последние два - "перевод строки", то заголовок печатается в начале новой страницы и после него следует двойной интервал.


HEADG DB 0CH,'Industrial Bicycle Mfrs',0DH,0AH,0AH LEA SI,HEADG ;Установка адреса и MOV CX,27 ; длины заголовка P20: MOV AH,05 ;Запрос функции печати
Ассемблер для IBM PC. Глава 19 6
MOV DL,[SI] ;Символ из заголовка INT 21H ;Вызов DOS INC SI ;Следующий символ LOOP P20
Пока принтер не включен, DOS выдает сообщения "Out of pap er". После включения питания программа начинает работать нормально. Для прекращения печати можно нажать клавиши Ctrl/Break.
СПЕЦИАЛЬНЫЕ КОМАНДЫ ПРИНТЕРА ------------------------------------------------------------
Выше уже был показан ряд команд, которые являются основными для большинства печатающих устройств. Кроме того существуют следующие команды:
Десятичн. Шест. 15 0F Включить узкий формат 14 0E Включить широкий формат 18 12 Выключить узкий формат 20 14 Выключить широкий формат
Есть команды, которые распознаются по предшествующему символу Esc (шест.IB). Некоторые из них в зависимости от печатающего устройства представлены ниже:
1B 30 Установить плотность 8 строк на дюйм 1B 32 Установить плотность 6 строк на дюйм 1B 45 Включить жирный формат 1B 46 Выключить жирный формат
Коды команд можно посылать на принтер двумя разными способами:
1. Определить команды в области данных. Следующий пример устанавливает узкий формат, 8 строк на дюйм, затем печатает заголовок с завершающими командами "возврат каретки" и " перевод строки":
HEADG DB 0FH, 1BH, 30H, 'Title...', 0DH, 0AH
2. Использовать команды с непосредственными данными:
MOV AH,05 ;Запрос функции печати MOV DL,0FH ;Включить узкий формат INT 21H
Все последующие символы будут печататься в узком формате до тех пор, пока программа не выдаст на принтер команду, выключающую этот формат.
Ассемблер для IBM PC. Глава 19 7
Приведенные команды не обязательно работают на принтерах любых моделей. Для проверки возможных команд управления следует ознакомиться с руководством конкретного печатающего устройства.
ПЕЧАТЬ С ПОМОЩЬЮ BIOS INT 17H ------------------------------------------------------------


Прерывание BIOS INT 17H обеспечивает три различные операции, специфицированные содержимым регистра AH:
AH=0: Данная операция выполняет печать одного символа на три принтера по номерам 0,1 и 2 (стандартное значение - 0).
MOV AH,00 ;Запрос функции печати MOV AL,char ;Символ, выводимый на печать MOV DX,00 ;Выбор принтера Э 0 INT 17H ;Вызов BIOS
Если операция не может распечатать символ, то в регистре AH устанавливается значение 01.
AH=1: Инициализация порта печатающего устройства:
MOV AH,01 ;Запрос на инициализацию порта MOV DX,00 ;Выбор порта Э 0 INT 17H ;Вызов BIOS
Данная операция посылает на принтер символ "прогон страницы", поэтому ее можно использовать для установки положения "верх страницы". Большинство принтеров выполняют данную установку автоматически при включении.
AH=2: Чтение состояние порта принтера:
MOV AH,02 ;Функция чтения состояния порта MOV DX,00 ;Выбор порта Э 0 INT 17H ;Вызов BIOS TEST AH,00101001B; Принтер готов? JNZ errormsg ;Нет - выдать сообщение об ошибке
Назначение функций AH=1 и AH=2 состоит в определении состояния принтера. В результате выполнения этих функций биты регистра AH могут устанавливаться в 1:
Бит Причина 7 Не занято 6 Подтверждение от принтера 5 Конец бумаги 4 Выбран 3 Ошибка ввода/вывода 0 Таймаут
Ассемблер для IBM PC. Глава 19 8
Если прринтер включен, то операция возвращает шест.90 или двоичное 10010000 - принтер "не занят" и "выбран" - это нормальное состояние готовности. В случае неготовности принтера устанавливаются бит 5 (конец бумаги или бит 3 (ошибка вывода). Если принтер выключен, то операция возвращает шест.B0 или двоичное 10110000, указывая на "конец бумаги". Выполняя программу при выключенном принтере, BIOS не выдает сообщение автоматически, поэтому предполагается, что программа должна сама проверить и отреагировать на состояние принтера. Если программа не делает этого, то единственной индикацией будет мигающий курсор на экране дисплея. Если в этот момент включить принтер, то некоторые выходные данные могут быть потеряны. Следовательно, прежде чем использовать функции BIOS для печати, следует проверить состояние порта принтера и, если будет обнаружена ошибка, то выдать соответствующее сообщение. (Функции DOS выполняют эту проверку автоматически, хотя их сообщение "Out of paper" относится к различным состояниям). После включения принтера, вывод сообщений об ошибке прекращается и принтер начинает нормально работать без потери данных. В процессе работы принтер может выйти за страницу или быть нечаянно выключен. Поэтому в программах печати следует предусмотреть проверку состояния принтера перед каждой попыткой печати.


ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ Прежде чем выводить данные на печатающее устройство, включите принтер и вставьте в него бумагу.
ъ Для завершении печати используйте символы "перевод строки" и "прогон страницы" для очистки буфера принтера.
ъ Функции DOS для печати предусматривают вывод сообщений при возникновении ошибки принтера. Функции BIOS возвращают только код состояния. При использовании BIOS INT 17H проверяйте состояние принтера перед печатью.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
19.1. Напишите программу в расширенной версии DOS для а) прогона страницы; б) печати вашего имени; в) перевода строки и печати вашего адреса; г) перевода строки и печати названия вашего города/штата (республики); д) прогона страницы. 19.2. Переделайте программу из предыдущего вопроса для базовой версии DOS.
Ассемблер для IBM PC. Глава 19 9
19.3. Закодируйте строку, в которой имеется следующая информация: возврат каретки, прогон страницы, включе ние узких букв, заголовок (любое имя) и выключение узких букв. 19.4. Измените программу из вопроса 19.1 для использования BIOS INT 17H. Обеспечьте проверку состояния принтера. 19.5. Измените программу из вопроса 19.1 так, чтобы пункты б), в), г) выполнялись по 5 раз. 19.6. Измените программу на рис.19.1 для выполнения в базовой версии DOS. 19.7. Измените программу на рис.19.2 так, чтобы распечатывае мые строки также выводились на экран.
Ассемблер для IBM PC. Глава 20 18


Макросредства


------------------------------------------------------------

Макросредства

Цель: Объяснить определение и использование ассемблерных макрокоманд.

ВВЕДЕНИЕ ------------------------------------------------------------

Для каждой закодированной команды ассемблер генерирует одну команду на машинном языке. Но для каждого закодированного оператора компиляторного языка Pascal или C генерируется один или более (чаще много) команд машинного языка. В этом отношении можно считать, что компиляторный язык состоит из макро операторов. Ассемблер MASM также имеет макросредства, но макросы здесь определяются программистом. Для этого задается имя макроса, директива MACRO, различные ассемблерные команды, которые должен генерировать данный макрос и для завершения макропределения - директива MEND. Затем в любом месте программы, где необходимо выполнение определенных в макроко манде команд, достаточно закодировать имя макроса. В резуль тате ассемблер сгенерирует необходимые команды.

Использование макрокоманд позволяет: - упростить и сократить исходный текст программы; - сделать программу более понятной; - уменьшить число возможных ошибок кодирования.

Примерами макрокоманд могут быть операции ввода-вывода, связанные с инициализацией регистров и выполнения прерываний преобразования ASCII и двоичного форматов данных, арифмети ческие операции над длинными полями, обработка строковых данных, деление с помощью вычитания. В данной главе рассмотрены особенности макросредств, включая те, которые не достаточно ясно даны в руководстве по ассемблеру. Тем не менее пояснения для некоторых малоисполь зуемых операций следует искать в руководстве по ассеблеру.

ПРОСТОЕ МАКРООПРЕДЕЛЕНИЕ ------------------------------------------------------------

Макроопределение должно находиться до определения сегмента. Рассмотрим пример простого макроопределения по имени INIT1, которое инициализирует сегментные регистры для EXE-программы:

INIT1 MACRO ;Начало ASSUME CS:CSEG,DS:DSEG,SS:STACK;ES:DSEG ; \ PUSH DS ; \


Ассемблер для IBM PC. Глава 20 19
SUB AX,AX ; \ PUSH AX ;Тело \ MOV AX,DSEG ;макро/ MOV DS,AX ; / MOV ES,AX ; / ENDM ;Конец
Директива MACRO указывает ассемблеру, что следующие команды до директивы ENDM являются частью макроопределения. Имя маккрокоманды - INIT1, хотя здесь возможны другие правильные уникальные ассемблерные имена. Директива ENDM завершает макроопределение. Семь команд между директивами MACRO и ENDM составляют тело макроопределения. Имена, на которые имеются ссылки в макроопределении, CSEG, DSEG и STACK должны быть определены где-нибудь в другом месте программы. Макрокоманда INIT1 может использо ваться в кодовом сегменте там, где необходимо инициализиро вать регистры. Когда ассемблер анализирует команду INIT1, он сначала просматривает таблицу мнемокодов и, не обнаружив там соответствующего элемента, проверяет макрокоманды. Так как программа содержит определение макрокоманды INIT1 ассем блер подставляет тело макроопределения, генерируя необходи мые команды - макрорасширение. Программа использует рассматриваемую макрокоманду только один раз, хотя имеются другие макрокоманды, предназначенные на любое число применений и для таких макрокоманд ассемблер генерирует одинаковые макрорасширения. На рис.20.1 показана ассемблированная программа. В листин ге макрорасширения каждая команда, помеченная слева знаком плюс (+), является результатом генерации макрокоманды. Кроме того, в макрорасширении отсутствует директива ASSUME, так как она не генерирует объектный код. В последующем разделе "Включение из библиотеки макро определений показана возможность каталогизации макрокоманд в библиотеке и автоматическое включение их в любые программы.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.1. Пример ассемблирования макрокоманды.
ИСПОЛЬЗОВАНИЕ ПАРАМЕТРОВ В МАКРОКОМАНДАХ ------------------------------------------------------------
В предыдущем макроопределении требовались фиксированные имена сегментов: CSEG, DSEG и STACK. Для того, чтобы макро команда была более гибкой и могла принимать любые имена сегментов, определим эти имена, как формальные параметры:


INIT2 MACRO CSNAME,DSNAME,SSNAME ;Формальные параметры ASSUME CS:CSNAME,DS:DSNAME,SC:SSNAME,ES:DSNAME PUSH DS SUB AX,AX PUSH AX
Ассемблер для IBM PC. Глава 20 20
MOV AX,DSNAME MOV DS,AX MOV ES,AX ENDM ;Конец макроопределения
Формальные параметры в макроопределении указывают ассемблеру на соответствие их имен любым аналогичным именам в теле макроопределения. Все три формальных параметра CSNAME, DSNAME и SSNAME встречаются в директиве ASSUME, а параметр DSNAME еще и в последующей команде MOV. Формальные параметры могут иметь любые правильные ассемблерные имена, не обязательно совпадающими именами в сегменте данных. Теперь при использовании макрокоманды INIT2 необходимо указать в качестве параметров действительные имена трех сегментов в соответствующей последовательности. Например, следующая макрокоманда содержит три параметра, которые соответствуют формальным параметрам в исходном макроопреде лении:
Макроопределение: INIT2 MACRO CSNAME,DSNAME,SSNAME (формальные параметры) Макрокоманда: | | | INIT2 CSEG,DSEG,STACK (параметры)
Так как ассемблер уже определил соответствие между формальны ми параметрами и операторами в макроопределении, то теперь ему остается подставить параметры макрокоманды в макрорасши рении:
- Параметр 1: CSEG ставится в соответствие с CSNAME в макроопределении. Ассемблер подставляет CSEG вместо CSNAME в директиве ASSUME.
- Параметр 2: DSEG ставится в соответствие с DSNAME в макроопределении. Ассемблер подставляет DSEG вместо двух DSNAME: в директиве ASSUME и в команде MOV.
- Параметр 3: STACK ставится в соответствие с SSNAME в макроопределении. Ассемблер подставляет STACK вместо SSNAME в директиве ASSUME.
Макроопределение с формальными параметрами и соответствую щее макрорасширение приведены на рис.20.2.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.2. Использование параметров в макрокомандах.
Формальный параметр может иметь любое правильное ассемблерное имя (включая имя регистра, например, CX), которое в процессе ассемблирования будет заменено на параметр макрокоманды. Отсюда следует, что ассемблер не распознает регистровые имена и имена, определенные в области


Ассемблер для IBM PC. Глава 20 21
данных, как таковые. В одной макрокоманде может быть определено любое число формальных парамтеров, разделенных запятыми, вплоть до 120 колонки в строке.
КОММЕНТАРИИ ------------------------------------------------------------
Для пояснений назначения макроопределения в нем могут находиться комментарии. Директива COMMENT или символ точка с запятой указывают на строку комментария, как это показано в следующем макроопределении PROMPT:
PROMPT MACRO MESSGE ; Эта макрокоманда выводит сообщения на экран MOV AH,09H LEA DX,MESSGE INT 21H ENDM
Так как по умолчанию в листинг попадают только команды генерирующие объектный код, то ассемблер не будет автомати чески выдавать и комментарии, имеющиеся в макроопределении. Если необходимо, чтобы в расширении появлялись комментарии, следует использовать перед макрокомандой директиву .LALL ("list all" - выводить все), которая кодируется вместе с лидирующей точкой: .LALL PROMPT MESSAG1
Макроопределение может содержать несколько комментариев, причем некоторые из них могут выдаваться в листинге, а другие - нет. В первом случае необходимо использовать директиву .LALL. Во втором - кодировать перед комментарием два символа точка с запятой (;;) - признак подавления вывода комментария в листинг. По умолчанию в ассемблере действует директива .XALL, которая выводит в листинг только команды, генерирующие объектный код. И, наконец, можно запретить появление в листинге ассемблерного кода в макрорасширениях, особенно при использовании макрокоманды в одной программе несколько раз. Для этого служит директива .SALL ("suppress all" - подавить весь вывод), которая уменьшает размер выводимого листинга, но не оказывает никакого влияния на размер объектного модуля. Директивы управления листинком .LALL, .XALL, .SALL сохраняют свое действие по всему тексту программы, пока другая директива листинга не изменит его. Эти директивы можно размещать в программе так, чтобы в одних макрокомандах распечатывались комментарии, в других - макрорасширения, а в третьих подавлялся вывод в листинг. Программа на рис.20.3 демонстрирует описанное выше свойство директив листинга. В программе опредлелено два макроопределения INIT2 и PROMPT, расмотренные ранее. Кодовый сегмент содержит директиву .SALL для подавления распечатки


Ассемблер для IBM PC. Глава 20 22
INIT2 и первого расширения PROMPT. Для второго расширения PROMPT директива .LALL указывает ассемблеру на вывод в листинг комментария и макрорасширения. Заметим, однако, что комментарий, отмеченный двумя символами точка с запятой (;;) в макроопределении PROMPT, не распечатывается в макрорасшире ниях независимо от действия директив управления листингом.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.3. Распечатка и подавление макрорасширений в листинге.
ИСПОЛЬЗОВАНИЕ МАКРОКОМАНД В МАКРООПРЕДЕЛЕНИЯХ ------------------------------------------------------------
Макроопределение может содержать ссылку на другое макроопределение. Рассмотрим простое макроопределение DOS21, которое заносит в регистр AH номер функции DOS и выполняет INT 21H:
DOS21 MACRO DOSFUNC MOV AH,DOSFUNC INT 21H ENDM
Для использования данной макрокоманды при вводе с клавиатуры необходимо закодировать:
LEA DX,NAMEPAR DOS21 0AH
Предположим, что имеется другое макроопределение, использую щее функцию 02 в регистре AH для вывода символа:
DISP MACRO CHAR MOV AH,02 MOV DL,CHAR INT 21H ENDM
Для вывода на экран, например, звездочки достаточно закодиро вать макрокоманду DISP '*'. Можно изменить макроопределение DISP, воспользовшись макрокомандой DOC21:
DISP MACRO CHAR MOV DL,CHAR DOS21 02 ENDM
Теперь, если закодировать макрокоманду DISP в виде DISP '*', то ассемблер сгенерирует следующие команды:
MOV DL,'*'
Ассемблер для IBM PC. Глава 20 23
MOV AH,02 INT 21H
ДИРЕКТИВА LOCAL ------------------------------------------------------------
В некоторых макрокомандах требуется определять элементы данных или метки команд. При использовании такой макрокоманды в программе более одного раза происходит также неоднократное определение одинаковых полей данных или меток. В результате ассемблер выдаст сообщения об ошибке из-за дублирования имен. Для обеспечения уникальности генерируемых в каждом макрорасширении имен используется директива LOCAL, которая кодируется непосредственно после директивы MACRO, даже перед комментариями. Общий формат имеет следующий вид:


LOCAL dummy-1,dummy-2,... ;Формальные параметры
Рис.20.4. иллюстрирует использование директивы LOCAL. В приведенной на этом рисунке программе выполняется деление вычитанием; делитель вычитается из делимого и частное увеличивается на 1 до тех пор, пока делимое больше делителя. Для данного алгоритма необходимы две метки: COMP - адрес цикла, OUT - адрес выхода из цикла по завершению. Обе метки COMP и OUT определены как LOCAL и могут иметь любые правильные ассемблерные имена. В макрорасширении для COMP генерируется метка ??0000, а для OUT - ??0001. Если макрокоманда DIVIDE будет использова на в этой программе еще один раз, то в следующем макрорасши рении будут сгенерированы метки ??0002 и ??0003 соответствен но. Таким образом, с помощью директивы LOCAL обеспечивается уникальность меток в макрорасширениях в одной программе.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.4. Использование директивы LOCAL.
ИСПОЛЬЗОВАНИЕ БИБЛИОТЕК МАКРООПРЕДЕЛЕНИЙ ------------------------------------------------------------
Определение таких макрокоманд, как INIT1 и INIT2 и одноразовое их использование в программе кажется бессмысленным. Лучшим подходом здесь является каталогизация собственных макрокоманд в библиотеке на магнитном диске, используя любое описательное имя, например, MACRO.LIB:
INIT MACRO CSNAME,DSNAME,SSNAME . . ENDM PROMPT MACRO MESSGE . .
Ассемблер для IBM PC. Глава 20 24
ENDM
Теперь для использования любой из каталогизированных макрокоманд вместо MACRO определения в начале программы следует применять директиву INCLUDE:
INCLUDE C:MACRO.LIB . . INIT CSEG,DATA,STACK
В этом случае ассемблер обращается к файлу MACRO.LIB (в нашем примере) на дисководе C и включает в программу оба макроопределения INIT и PROMPT. Хотя в нашем примере требуется только INIT. Ассемблерный листинг будет содержать копию макроопределения, отмеченного символом C в 30 колонке LST-файла. Следом за макрокомандой идет ее расширение с объектным кодом и с символом плюс (+) в 31 колонке. Так как транслятор с ассемблера является двухпроходовым, то для обеспечения обработки директивы INCLUDE только в первом проходе (а не в обоих) можно использовать следующую конструкцию:


IF1 INCLUDE C:MACRO.LIB ENDIF
IF1 и ENDIF являются условными директивами. Директива IF1 указывает ассемблеру на необходимость доступа к библиотеке только в первом проходе трансляции. Директива ENDIF заверша ет IF-логику. Таким образом, копия макроопределений не появится в листинге - будет сэкономлено и время и память. Программа на рис.20.5 содержит рассмотренные выше директи вы IF1, INCLUDE и ENDIF, хотя в LST-файл ассемблер выводит только директиву ENDIF. Обе макрокоманды в кодовом сегменте INIT и PROMPT закаталогизированы в файле MACRO.LIB, т.е. просто записаны друг за другом на дисковый файл по имени MACRO.LIB с помощью текстового редактора. Расположение директивы INCLUDE не критично, но она должна появиться ранее любой макрокоманды из включаемой библиотеки.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.5. Использование библиотеки макроопределений.
Директива очистки
Директива INCLUDE указывает ассемблеру на включение всех макроопределений из специфицированной библиотеки. Например, библиотека содержит макросы INIT, PROMPT и DIVIDE, хотя
Ассемблер для IBM PC. Глава 20 25
программе требуется только INIT. Директива PURGE позволяет "удалить" нежелательные макросы PROMPT и DIVIDE в текущем ассемблировании:
IF1 INCLUDE MACRO.LIB ;Включить всю библиотеку ENDIF PURGE PROMRT,DIYIDE ;Удалить ненужные макросы ... INIT CSEG,DATA,STACK ;Использование оставшейся ; макрокоманды
Директива PURGE действует только в процессе ассемблирова ния и не оказывает никакого влияния на макрокоманды, находящиеся в библиотеке.
КОНКАТЕНАЦИЯ (&) ------------------------------------------------------------
Символ амперсанд (&) указывает ассемблеру на сцепление (конкатенацию) текста или символов. Следующая макрокоманда MOVE генерирует команду MOVSB или MOVSW:
MOVE MACRO TAG REP MOVS&TAG ENDM
Теперь можно кодировать макрокоманду в виде MOVE B или MOVE W. В результате макрорасширения ассемблер сцепит параметр с командой MOVS и получит REP MOVSB или REP MOVSW. Данный пример весьма тривиален и служит лишь для иллюстрации.


ДИРЕКТИВЫ ПОВТОРЕНИЯ: REPT, IRP, IRPC ------------------------------------------------------------
Директивы повторения заставляют ассемблер повторить блок операторов, завершаемых директивой ENDM. Эти директивы не обязательно должны находится в макроопределении, но если они там находятся, то одна директива ENDM требуется для завершения повторяющегося блока, а вторая ENDM - для завершения макроопределения.
REPT: Повторение
Операция REPT приводит к повторению блока операторов до директивы ENDM в соответствии с числом повторений, указанным в выражении: REPT выражение
В следующем примере происходит начальная инициализация значения N=0 и затем повторяется генерация DB N пять раз:
N = 0
Ассемблер для IBM PC. Глава 20 26
REPT 5 N = N + 1 DB N ENDM
В результате будут сгенерированы пять операторов DB от DB 1 до DB 5. Директива REPT может использоваться таким образом для определения таблицы или части таблицы. Другим примером может служить генерация пяти команд MOVSB, что эквивалентно REP MOVSB при содержимом CX равном 05:
REPT 5 MOVSB ENDM
IRP: Неопределенное повторение
Операция IRP приводит к повторению блока команд до директивы ENDM. Основной формат:
IRP dummy,<arguments>
Аргументы, содержащиеся в угловых скобках, представляют собой любое число правильных символов, строк, числовых или арифметических констант. Ассемблер генерирует блок кода для каждого аргумента. В следующем примере ассемблер генерирует DB 3, DB 9, DB 17, DB 25 и DB 28:
IRP N,<3, 9, 17, 25, 28>
DB N ENDM
IRPC: Неопределенное повторение символа
Операция IRPC приводит к повторению блока операторов до директивы ENDM. Основной формат:
IRPC dummy,string
Ассемблер генерирует блок кода для каждого символа в строке "string". В следующем примере ассемблер генерирует DW 3, DW 4 ... DW 8:
IRPC N,345678 DW N ENDM
УСЛОВНЫЕ ДИРЕКТИВЫ ------------------------------------------------------------
Ассемблер поддерживает ряд условных директив. Ранее нам уже приходилось использовать директиву IF1 для включения библиотеки только в первом проходе ассемблирования. Условные


Ассемблер для IBM PC. Глава 20 27
директивы наиболее полезны внутри макроопределений, но не ограничены только этим применением. Каждая директива IF должна иметь спаренную с ней директиву ENDIF для завершения IF-логики и возможную директиву ELSE для альтернативного действия:
IFxx (условие) . } . } Условный ELSE (не обязательное действие) } . } блок . } ENDIF (конец IF-логики)
Отсутствие директивы ENDIF вызывает сообщение обошибке: "Undeterminated conditional" (незавершенный условный блок). Если проверяемое условие истино, то ассемблер выполняет условный блок до директивы ELSE или при отсутствии ELSE - до директивы ENDIF. Если условие ложно, то ассемблер выполняет условный блок после директивы ELSE, а при отсутствии ELSE вообще обходит условный блок. Ниже перечислены различные условные директивы:
IF выражение Если выражение не равно нулю, ассемблер обрабатывает операторы в условном блоке. IFE выражение Если выражение равно нулю, ассемблер обрабатывает операторы в условном блоке. IF1 (нет выражения) Если осуществляется первый проход ассемблирования, то обрабатываются операторы в условном блоке. IF2 (нет выражения) Если осуществляется второй проход ассемблирования, то обрабатываются операторы в условном блоке. IFDEF идентификатор Если идентификатор определен в программе или объявлен как EXTRN, то ассемблер обрабатывает операторы в условном блоке. IFNDEF идентификатор Если идентификатор не определен в программе или не объявлен как EXTRN, то ассемблер обрабатывает операторы в условном блоке. IFB <аргумент> Если аргументом является пробел, ассемблер обрабатывает операторы в условном блоке. Аргумент должен быть в угловых скобках. IFNB <аргумент> Если аргументом является не пробел, то ассемблер обрабатывает операторы в условном блоке. Аргумент должен быть в угловых скобках.
Ассемблер для IBM PC. Глава 20 28
IFIDN <арг-1>,<арг-2> Если строка первого аргумента идентична строке второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках. IFDIF<арг-1>,<арг-2> Если строка первого аргумента отличается от строки второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках.


Ниже приведен простой пример директивы IFNB (если не пробел). Для DOS INT 21H все запросы требуют занесения номера функции в регистр AH, в то время как лишь некоторые из них используют значение в регистре DX. Следующее макроопределение учитывает эту особенность:
DOS21 MACRO DOSFUNC,DXADDRES MOV AN,DOSFUNC IFNB <DXADDRES>
MOV DX,OFFSET DXADDRES ENDIF INT 21H ENDM
Использование DOS21 для простого ввода с клавиатуры требует установки значения 01 в регистр AH:
DOS21 01
Ассемблер генерирует в результате команды MOV AH,01 и INT 21H. Для ввода символьной строки требуется занести в регистр AH значение 0AH, а в регистр DX - адрес области ввода:
DOS21 0AH,IPFIELD
Ассемблер генерирует в результате обе команды MOV и INT 21H.
ДИРЕКТИВА ВЫХОДА ИЗ МАКРОСА EXITM. ------------------------------------------------------------
Макроопределение может содержать условные дерективы, которые проверяют важные условия. Если условие истинно, то ассемблер должен прекратить дальнейшее макрорасширение. Для этой цели служит директива EXITM:
IFxx [условие] . . (неправильное условие) . EXITM . .
Ассемблер для IBM PC. Глава 20 29
ENDIF
Как только ассемблер попадает в процессе генерации макро расширения на директиву EXITM, дальнейшое расширение прекращается и обработка продолжается после директивы ENDM. Можно использовать EXITM для прекращения повторений по директивам REPT, IRP и IRPC даже если они находятся внутри макроопределения.
МАКРОКОМАНДЫ, ИСПОЛЬЗУЮЩИЕ IF И IFNDEF УСЛОВИЯ ------------------------------------------------------------
Программа на рис.20.6 содержит макроопределение DIVIDE, которая генерирует подпрограмму для выполнения деления вычитанием. Макрокоманда должна кодироваться с параметрами в следующей последовательности: делимое, делитель, частное. Макрокоманда содержит директиву IFNDEF для проверки наличия параметров. Для любого неопределенного элемента макрокоманда увеличивает счетчик CNTR. Этот счетчик может иметь любое корректное имя и предназначен для временного использования в макроопределении. После проверки всех трех параметров, макрокоманда проверяет CNTR:


IF CNTR ; Макрорасширение прекращено EXITM
Если счетчик CNTR содержит ненулевое значение, то ассемблер генерирует комментарий и прекращает по директиве EXITM дальнейшее макрорасширение. Заметим, что начальная команда устанавливает в счетчике CNTR нулевое значение и, кроме того, блоки IFNDEF могут устанавливать в CNTR единичное значение, а не увеличивать его на 1. Если ассемблер успешно проходит все проверки, то он генерирует макрорасширение. В кодовом сегменте первая макрокоманда DIVIDE содержит правильные делимое и частное и, поэтому генерирует только комментарии. Один из способов улучшения рассматриваемой макрокоманды - обеспечить проверку на ненулевой делитель и на одинаковый знак делимого и делителя; для этих целей лучше использовать коды ассемблера, чем условные директивы.
------------------------------------------------------------ ------------------------------------------------------------ Рис.20.6. Использование директив IF и IFNDEF.
МАКРОС, ИСПОЛЬЗУЮЩИЙ IFIDN-УСЛОВИЕ ------------------------------------------------------------
Ассемблер для IBM PC. Глава 20 30
Программа на рис.20.7 содержит макроопределение по имени MOVIF, которая генерирует команды MOVSB или MOVSW в зависимости от указанного параметра. Макрокоманду можно кодировать с параметром B (для байта) или W (для слова) для генерации команд MOVSB или MOVSW из MOVS. Обратите внимание на первые два оператора в макроопределе нии: MOVIF MACRO TAG IFIDN <&TAG>,<B>
Условная директива IFIDN сравнивает заданный параметр (предположительно B или W) со строкой B. Если значения идентичны, то ассемблер генерирует REP MOVSB. Обычное использование амперсанда (&) - для конкатенации, но в данном примере операнд <TAG> без амперсанда не будет работать. Если в макрокоманде не будет указан параметр B или W, то ассемблер сгенерирует предупреждающий комментарий и команду MOVSB (по умолчанию). Примеры в кодовом сегменте трижды проверяют макрокоманду MOVIF: для параметра B, для параметра W и для неправильного параметра. Не следует делать попыток выполнения данной программы в том виде, как она приведена на рисунке, так как регистры CX и DX не обеспечены правильными значениями. Предполагается, что рассматриваемая макрокоманда не является очень полезной и ее назначение здесь - проиллюстри ровать условные директивы в простой форме. К данному моменту, однако, вы имеете достаточно информации для составления больших полезных макроопределений.


------------------------------------------------------------ ------------------------------------------------------------ Рис.20.7. Использование директивы IFIDN
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ Макросредства возможны только для полной версии ассемблера (MASM). ъ Использование макрокоманд в программах на ассемблере дает в результате более удобочитаемые программы и более произ водительный код. ъ Макроопределение состоит из директивы MACRO, блока из одного или нескольких операторов, которые генерируются при макрорасширениях и директивы ENDM для завершения определения. ъ Код, который генерируется в программе по макрокоманде, представляет собой макрорасширение. ъ Директивы .SALL,.LALL и .XALL позволяют управлять распечаткой комментариев и генерируемого объектного кода в макрорасширении. ъ Директива LOCAL позволяет использовать имена внутри макроопределений. Директива LOCAL кодируется непосредственно после директивы MACRO.
Ассемблер для IBM PC. Глава 20 31
ъ Использование формальных параметров в макроопределении позволяет кодировать параметры, обеспечивающие большую гибкость макросредств. ъ Библиотека макроопределений дает возможность использо вать макрокоманды для различных ассемблерных программ. ъ Условные директивы позволяют контролировать параметры макрокоманд.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
20.1. Напишите необходимые директивы: а) для подавления всех команд, которые генерирует макрокоманда и б) для распечатки только команд, генерирующих объектный код. 20.2. Закодируйте два макроопределения для умножения: а) MULTBY должна генерировать код для умножения байта на байт; б) MULTWD должна генерировать код для умножения слова на слово. Для множителя и множимого используйте в макро определении формальные параметры. Проверьте выполнение макрокоманд на небольшой программе, в которой также определены необходимые области данных. 20.3. Запишите макроопределения из вопроса 20.2 в "макро библиотеку". Исправьте программу для включения элементов библиотеки по директиве INCLUDE в первом проходе ассемблирования. 20.4. Напишите макроопределение BIPRINT, использующей BIOS INT 17H для печати. Макроопределение должно включать проверку состояния принтера и обеспечивать печать любых строк любой длины. 20.5. Измените макроопределение на рис.20.6 для проверки делителя на ноль (для обхода деления).
Ассемблер для IBM PC. Глава 21 1


Компановка программ


------------------------------------------------------------

Компановка программ

Цель: Раскрыть технологию программирования, включающую компа новку и выполнение ассемблерных программ.

ВВЕДЕНИЕ ------------------------------------------------------------

Примеры программ в предыдущих главах состояли из одного шага ассемблирования. Возможно, однако, выполнение програм много модуля, состоящего из нескольких ассемблированных программ. В этом случае программу можно рассматривать, как состоящую из основной программы и одной или более подпрограмм. Причины такой организации программ состоят в следующем:

ъ бывает необходимо скомпановать программы, написанные на разных языках, например, для объединения мощности языка высокого уровня и эффективности ассемблера; ъ программа, написанная в виде одного модуля, может оказаться слишком большой для ассемблирования; ъ отдельные части программы могут быть написаны разными группами программистов, ассемблирующих свои модули раздельно; ъ ввиду возможно большого размера выполняемого модуля, может появиться необходимость перекрытия частей программы в процессе выполнения.

Каждая программа ассемблируется отдельно и генерирует собственный уникальный объектный (OBJ) модуль. Программа компановщик (LINK) затем компанует объектные модули в один объединенный выполняемый (EXE) модуль. Обычно выполнение начинается с основной программы, которая вызывает одну или более подпрограмм. Подпрограммы, в свою очередь, могут вызывать другие подпрограммы. На рис.21.1 показаны два примера иерархической структуры основной подпрограммы и трех подпрограмм. На рис. 21.1 (а) основная программы вызывает подпрограммы 1, 2 и 3. На рис. 21.1 (б) основная программа вызывает подпрограммы 1 и 2, а подпрограмма 1 вызывает подпрограмму 3.

------------------------------------------------------------ ------------------------------------------------------------ Рис.21.1. Иерархия программ.

Существует много разновидностей организации подпрограмм, но любая организация должна быть "понятна" и ассемблеру, и компановщику, и этапу выполнения. Следует быть внимательным к ситуациям, когда, например, под программа 1 вызывает


Ассемблер для IBM PC. Глава 21 2
подпрограмму 2, которая вызывает подпрограмму 3 и, которая в свою очередь вызывает подпрограмму 1. Такой процесс, известный как рекурсия, может использоваться на практике, но при неаккуратном обращении может вызвать любопытные ошибки при выполнении.
МЕЖСЕГМЕНТНЫЕ ВЫЗОВЫ ------------------------------------------------------------
Команды CALL в предыдущих главах использовались для внутрисегментных вызовов, т.е. для вызовов внутри одного сегмента. Внутрисегментный CALL может быть короткий (в пределах от +127 до -128 байт) или длинный ( превышающий указанные границы). В результате такой операции "старое" значение в регистре IP запоминается в стеке, а "новый" адрес перехода загружается в этот регистр. Например, внутрисегментный CALL может иметь следующий объектный код: E82000. Шест.E8 представляет собой код операции, которая заносит 2000 в виде относительного адреса 0020 в регистр IP. Затем процессор объединяет текущий адрес в регистре CS и относительный адрес в регистре IP для получения адреса следующей выполняемой команды. При возврате из процедуры команда RET восстанавливает из стека старое значение в регистре IP и передает управление таким образом на следующую после CALL команду. Вызов в другой кодовый сегмент представляет собой межсег ментный (длинный) вызов. Данная операция сначала записывает в стек содержимое регистра CS и заносит в этот регистр адрес другого сегмента, затем записывает в стек значение регистра IP и заносит новый относительный адрес в этот регистр. Таким образом в стеке запоминаются и адрес кодового сег мента и смещение для последующего возврата из подпрограммы. Например, межсегментный CALL может состоять из следующего объектного кода:
9A 0002 AF04
Шест.9A представляет собой код команды межсегментного вызова которая записывает значение 0002 в виде 0200 в регистр IP, а значение AF04 в виде 04AF в регистр CS. Комбинация этих адресов указывает на первую выполняемую команду в вызываемой подпрограмме:


Кодовый сегмент 04AF0 Смещение в IP 0200 Действительный адрес 04CF0
При выходе из вызванной процедуры межсегментная команда возврата REP восстанавливает оба адреса в регистрах CS и IP и таким образом передает управление на следующую после CALL команду.
АТРИБУТЫ EXTRN и PUBLIC
Ассемблер для IBM PC. Глава 21 3
------------------------------------------------------------
Рассмотрим основную программу (MAINPROG), которая вызывает подпрограмму (SUBPROG) с помощью межсегментного CALL, как показано на рис.21.2. Команда CALL в MAINPROG должна "знать", что SUBPROG существует вне данного сегмента (иначе ассемблер выдаст сообщение о том, что идентификатор SUBPROG не определен). С помощью директивы EXTRN можно указать ассемблеру, что ссылка на SUBPROG имеет атрибут FAR, т.е.определена в другом ассемблерном модуле. Так как сам ассемблер не имеет возможности точно определить такие ссылки, он генерирует "пустой" объектный код для последующего заполнения его при компановке:
9A 0000 ---- E
Подпрограмма SUBPROG содержит директиву PUBLIC, которая указывает ассемблеру и компановщику, что другой модуль должен "знать" адрес SUBPROG. В последнем шаге, когда оба модуля MAINPROG и SUBPROG будут успешно ассемблированы в объектные модули, они могут быть скомпанованы следующим образом:
Запрос компановщика LINK: Ответ:
Object Modules [.OBJ]: B:MAINPROG+B:SUBPROG Run File [filespec.EXE]: B:COMBPROG (или другое имя) List File [NUL.MAP]: CON Libraries [.LIB]: [return]
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.2. Межсегментный вызов.
Компановщик устанавливает соответствия между адресами EXTRN в одном объектном модуле с адресами PUBLIC в другом и заносит необходимые относительные адреса. Затем он объединя ет два объектных модуля в один выполняемый. При невозможнос ти разрешить ссылки компановщик выдает сообщения об ошибках. Следите за этими сообщениями прежде чем пытаться выполнить программу.


Директива EXTRN
Директива EXTRN имеет следующий формат:
EXTRN имя:тип [, ... ]
Можно определить более одного имени (до конца строки) или закодировать дополнительные директивы EXTRN. В другом ассемблерном модуле соответствующее имя должно быть определено и идентифицировано как PUBLIC. Тип элемента может
Ассемблер для IBM PC. Глава 21 4
быть ABS, BYTE, DWORD, FAR, NEAR, WORD. Имя может быть определено через EQU и должно удовлетворять реальному определению имени.
Директива PUBLIC
Директива PUBLIC указывает ассемблеру и компановщику, что адрес указанного иддентификатора доступен из других программ Директива имеет следующий формат:
PUBLIC идентификатор [, ... ]
Можно определить более одного идентификатора (до конца строки) или закодировать дополнительные директивы PUBLIC. Идентификаторы могут быть метками (включая PROC-метки), переменными или числами. Неправильными идентификаторами являются имена регистров и EQU-идентификаторы, определяющие значения более двух байт. Рассмотрим три различных способа компановки программ.
ПРОГРАММА: ИСПОЛЬЗОВАНИЕ ДИРЕКТИВ EXTRN и PUBLIC ДЛЯ МЕТОК ------------------------------------------------------------
Программа на рис.21.3 состоит из основной программы CALLMUL1 и подпрограммы SUBMUL1. В основной программе определены сегменты для стека, данных и кода. В сегменте данных определены поля QTY и PRICE. В кодовом сегменте регистр AX загружается значением PRICE, а регистр BX - значением QTY, после чего происходит вызов подпрограммы. Директива EXTRN в основной программе определяет SUBMUL как точку входа в подпрограмму. Подпрограмма содержит директиву PUBLIC (после ASSUME), которая указывает компановщику, что точкой входа для выполне ния является метка SUBMUL. Подпрограмма выполняет умножение содержимого регистра AX (цена) на содержимое регистра BX (количество). Результат умножения вырабатывается в регистро вой паре DX:AX в виде шест. 002E 4000. Так как подпрограмма не определяет каких-либо данных, то ей не требуется сегмент данных. Если бы подпрограмма имела сегмент данных, то только она одна использовала бы свои данные. Также в подпрограмме не определен стековый сегмент, так как она использует те же стековые адреса, что и основная программа. Таким образом, стек определенный в основной программе является доступным и в подпрогрпмме. Для компанов щика необходимо обнаружить по крайней мере один стек и определение стека в основной программе является достаточным. Рассмотрим теперь таблицы иднтификаторов, вырабатываемые после каждого ассемблирования. Обратите внимание, что SUBMUL в таблице идентификаторов для основной программы имеет атрибуты FAR и External (внешний), а для подпрограммы - F


Ассемблер для IBM PC. Глава 21 5
(для FAR) и Global (глобальный). Этот последний атрибут указывает, что данное имя доступно из вне подпрограммы, т.е. глобально. Карта компановки (в конце листинга) отражает организацию программы в памяти. Заметьте, что здесь имеются два кодовых сегмента (для каждого ассемблирования) с разными стартовыми адресами. Последовательность расположения кодовых сегментов соответствует последовательности указанных для компа новки объектных модулей (обычно основная программа указывается первой). Таким образом, относительный адрес начала основной программы - шест.00000, а подпрограммы - шест. 00020.
------------------------------------------------------------ ------------------------------------------------------------ Рис. 21.3. Использование директив EXTRN и PUBLIC.
При трассировке выполнения программы можно обнаружить, что команда CALL SUBMUL имеет объектный код
9A 0000 D413
Машинный код для межсегментного CALL - шест.9A. Эта команда сохраняет в стеке регистр IP и загружает в него значение 0000, сохраняет в стеке значение шест.13D2 из регистра CS и загружает в него шест.D413. Следующая выполняемая команда находится по адресу в регистровой паре CS:IP т.е. 13D40 плюс 0000. Обратите внимание, что основная программа начинается по адресу в регистре CS, содержащему шест.13D2, т.е. адрес 13D20. Из карты компановки видно, что подпрограмма начинает ся по относительному адресу шест.0020. Складывая эти два значения, получим действительный адрес кодового сегмента для подпрограммы:
Адрес в CS 13D20 Смещение в IP 0020 Действительный адрес 13D40
Компановщик определяет это значение точно таким же образом, и подставляет его в операнд команды CALL.
ПРОГРАММА: ИСПОЛЬЗОВАНИЕ ДИРЕКТИВЫ PUBLIC В КОДОВОМ СЕГМЕНТЕ ------------------------------------------------------------
Следующий пример на рис.21.4 представляет собой вариант программы на рис.21.3. Имеется одно изменение в основной программе и одно - в подпрограмме. В обоих случаях в директиве SEGMENT используется атрибут PUBLIC:


CODESG SEGMENT PARA PUBLIC 'CODE'
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.4. Кодовый сегмент, определенный как PUBLIC.
Ассемблер для IBM PC. Глава 21 6
Рассмотрим результирующую карту компановки и ообъектный код команды CALL. Из таблицы идентификаторов (в конце каждого листинга ассемблирования) следует: обобщенный тип кодового сегмента CODESG - PUBLIC (на рис.21.3 было NONE). Но более интересным является то, что карта компановки в конце листинга показыва ет теперь только один кодовый сегмент! Тот факт, что оба сегмента имеют одни и те же имя (CODESG), класс ('CODE') и атрибут PUBLIC, заставил компановщика объединить два логичес ких кодовых сегмента в один физический кодовый сегмент. Кроме того, при трассировке выполнения программы можно обнаружить, что теперь команда вызова подпрограммы имеет следующий объектный код:
9A 2000 D213
Эта команда заносит шест.2000 в регистр IP и шест. D213 в регистр CS. Так как подпрограмма находится в общем с основной программой кодовом сегменте, то в регистре CS устанавливается тот же стартовый адрес - шест.D213. Но теперь смещение равно шест.0020:
Адрес в CS: 13D20 Смещение в IP: 0020 Действительный адрес: 13D40
Таким образом, кодовый сегмент подпрограммы начинается, очевидно, по адресу шест.13D40. Правильно ли это? Карта компановки не дает ответа на этот вопрос, но можно определить адрес по листингу основной программы, которая заканчивается на смещении шест.0016. Так как кодовый сегмент для подпрограммы определен как SEGMENT, то он должен начинаться на границе параграфа, т.е. его адрес должен нацело делиться на шест.10 или правая цифра адреса должна быть равна 0. Компановщик размещает подпрограмму на ближайшей границе параграфа непосредственно после основной программы - этот относительный адрес равен шест.00020. Поэтому кодовый сегмент подпрограммы начинается по адресу 13D20 плюс 0020 или 13D40.
+----------------------------------------+--------------+ | Основная программа... (не используемый | Подпрограмма | | участок) | | +----------------------------------------+--------------+ | | | 13D20 13D30 13D40


Рассмотрим, каким образом компановщик согласует данные, определенные в основной программе и имеющие ссылки из подпрограммы.
ПРОГРАММА: ОБЩИЕ ДАННЫЕ В ПОДПРОГРАММЕ
Ассемблер для IBM PC. Глава 21 7
------------------------------------------------------------
Наличие общих данных предполагает возможность обработки в одном ассемблерном модуле данных, которые определены в другом ассемблерном модуле. Изменим предыдущий пример так, чтобы области QTY и PRICE по-прежнему определялись в основной программе, но загрузка значений из этих областей в регистры BX и AX выполнялась в подпрограмме. Такая программа приведена на рис.21.5. В ней сделаны следующие изменения:
ъ В основной программе имена QTY и PRICE определены как PUBLIC. Сегмент данных также определен с атрибутом PUBLIC. Обратите внимание на атрибут Global (глобаль ный) для QTY и PRICE в таблице идентификаторов.
ъ В подпрограмме имена QTY и PRICE определены как EXTRN и WORD. Такое определение указывает ассемблеру на длину этих полей в 2 байта. Теперь ассемблер сгенерирует правильный код операции для команд MOV, а компановщик установит значения операндов. Заметьте, что имена QTY и PRICE в таблице идентификаторов имеют атрибут External (внешний).
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.5. Общие данные в подпрограмме.
Команды MOV в листинге подпрограммы имеют следующий вид:
A1 0000 E MOV AX,PRICE 8B 1E 0000 E MOV BX,QTY
В объектном коде шест.A1 обозначает пересылку слова из памяти в регистр AX, а шест.8B - пересылку слова из памяти в регистр BX (объектный код для операций с регистром AX чаще требует меньшее число байтов, чем с другими регистрами). Трассировка выполнения программы показывает, что компановщик установил в объектном коде следующие операнды:
A1 0200 8B 1E 0000
Объектный код теперь идентичен коду сгенерированному в преды дущем примере, где команды MOV находились в вызывающей программе. Это логичный результат, так как операнды во всех трех программах базировались по регистру DS и имели одинаковые относительные адреса. Основная программа и подпрограмма могут определять любые другие элементы данных, но общими являются лишь имеющие атрибуты PUBLIC и EXTRN. Следуя основным правилам, рассмотренным в данной главе, можно теперь компановать программы, состоящие более чем из двух ассемблерных модулей и обеспечивать доступ к общим


Ассемблер для IBM PC. Глава 21 8
данным из всех модулей. При этом следует предусматривать стек достаточных размеров - в разумных пределах, для больших программ определение 64 слов для стека бывает достаточным. В главе 23 будет рассмотрены дополнительные свойства сегментов, включая определение более одного сегмента данных и кодового сегмента в одном ассемблерном модуле и использова ние директивы GROUP для объединения сегментов в один общий сегмент.
ПЕРЕДАЧА ПАРАМЕТРОВ ------------------------------------------------------------
Другим способом обеспечения доступа к данным из вызывае мой подпрограммы является передача параметров. В этом случае вызывающая программа физически передает данные через стек. Каждая команда PUSH должна записывать в стек данные размером в одно слово из памяти или из регистра. Программа, приведенная на рис.21.6, прежде чем вызвать подпрограмму SUBMUL заносит в стек значения из полей PRICE и QTY. После команды CALL стек выглядит следующим образом:
... | 1600 | D213 | 4001 | 0025 | 0000 | C213 | 6 5 4 3 2 1
1. Инициализирующая команда PUSH DS заносит адрес сегмента в стек. Этот адрес может отличаться в разных версиях DOS. 2. Команда PUSH AX заносит в стек нулевой адрес. 3. Команда PUSH PRICE заносит в стек слово (2500). 4. Команда PUSH QTY заносит в стек слово (0140). 5. Команда CALL заносит в стек содержимое регистра CS (D213) 6. Так как команда CALL представляет здесь межсегментный вызов, то в стек заносится также содержимое регистра IP (1600).
Вызываемая программа использует регистр BP для доступа к параметрам в стеке, но прежде она запоминает содержимое регистра BP, записывая его в стек. В данном случае, предположим, что регистр BP содержит нуль, тогда нулевое слово будет записано в вершине стека (слева). Затем программа помещает в регистр BP содержимое из регистра SP, так как в качестве индексного регистра может использоваться регистр BP, но не SP. Команда загружает в регистр BP значение 0072. Первоначально регистр SP содержал размер пустого стека, т.е. шест.80. Запись каждого слова в стек уменьшает содержимое SP на 2:


| 0000 | 1600 | D213 | 4001 | 0025 | 0000 |C213 | | | | | | | | SP: 72 74 76 78 7A 7C 7E
Ассемблер для IBM PC. Глава 21 9
Так как BP теперь также содержит 0072, то параметр цены (PRICE) будет по адресу BP+8, а параметр количества (QTY) - по адресу BP+6. Программа пересылает эти величины из стека в регистры AX и BX соответственно и выполняет умножение.
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.6. Передача параметров.
Перед возвратом в вызывающую программу в регистре BP восстанавливается первоначальное значение, а содержимое в регистре SP увеличивается на 2, с 72 до 74. Последняя команда RET представляет собой "длинный" возврат в вызывающую программу. По этой команде выполняются следующие действия:
ъ Из вершины стека восстанавливается значение регистра IP (1600). ъ Содержимое регистра SP увеличивается на 2, от 74 до 76. ъ Из новой вершины стека восстанавливается значение регистра CS (D213). ъ Содержимое регистра SP увеличивается на 2 от 76 до 78.
Таким образом осуществляется корректный возврат в вызываю щую программу. Осталось одно небольшое пояснение. Команда RET закодирована как
RET 4
Параметр 4 представляет собой число байт в стеке использо ванных при передаче параметров (два слова в данном случае). Команда RET прибавит этот параметр к содержимому регистра SP, получив значение 7C. Таким образом, из стека исключаются ненужные больше параметры. Будьте особенно внимательны при восстановлении регистра SP - ошибки могут привести к непред сказуемым результатам.
КОМПАНОВКА ПРОГРАММ НА BASIC-ИНТЕРПРЕТАТОРЕ И АССЕМБЛЕРЕ ------------------------------------------------------------
В руководстве по языку BASIC для IBM PC приводятся различ ные методы связи BASIC-интерпретатора и программ на ассемблере. Для этого имеются две причины: сделать возможным использование BIOS-прерываний через ассемблерные модули и создать более эффективные программы. Цель данного раздела - дать общий обзор по данному вопросу; повторять здесь технические подробности из руководства по языку BASIC нет необходимости. Для связи с BASIC ассемблерные программы кодируются, транслируются и компануются отдельно. Выделение памяти для подпрограмм на машинном языке может быть либо внутри, либо вне 64 Кбайтовой области памяти, которой ограничен BASIC. Выбор лежит на программисте.


Ассемблер для IBM PC. Глава 21 10
Существует два способа загрузки машинного кода в память: использование оператора языка BASIC - POKE или объединение скомпанованного модуля с BASIC-программой.
Использование BASIC-оператора POKE.
Хотя это и самый простой способ, но он удобен только для очень коротких подпрограмм. Способ заключается в том, что сначала определяется объектный код ассемблерной программы по LST-файлу или с помощью отладчика DEBUG. Затем шестнадцати ричные значения кодируются непосредственно в BASIC-программе в операторах DATA. После этого с помощью BASIC-оператора READ считывается каждый байт и оператором POKE заносится в память для выполнения.
Компановка ассемблерных модулей.
С большими ассемблерными подпрограммами обычно проще иметь дело, ели они оттранслированы и скомпанованые как выполнимые (EXE) модули. Необходимо организовать BASIC-программу и выполнимый модуль в рабочую программу. При работе с BASIC-программой не забывайте пользоваться командой BSAVE (BASIC save) для сохранения программы и BLOAD - для загрузки ее перед выполнением. Прежде чем кодировать BASIC- и ассемблерную программы, необходимо решить, каким из двух способов они будут связаны. В языке BASIC возможны два способа: функция USR и оператор CALL. В обоих способах регистры DS, ES и SS на входе содержат указатель на адресное пространство среды BASIC. Регистр CS содержит текущее значение, определенное последним оператором DEF SEG (если он имеется). Стековый указатель SP указывает на стек, состоящий только из восьми слов, так что может потребоваться установка другого стеке в подпрограмме. В последнем случае необходимо на входе сохранить значение указателя текущего стека, а при выходе восстановить его. В обоих случаях при выходе необходимо восстановить значение сегментных регистров и SP и обеспечить возврат в BASIC с помощью межсегментного возврата RET. Скомпануйте ваш ассемблированный объектный файл так, что бы он находился в старших адресах памяти. Для этого используется параметр HIGH при ответе на второй запрос компа новщика, например, B:имя/HIGH. Затем с помощью отладчика DEBUG необходимо загрузить EXE-подпрограмму и по команде R определить значения в регистрах CS и IP: они показывают на стартовый адрес подпрограммы. Находясь в отладчике укажите имя (команда N) BASIC и загрузите его командой L. Два способа связи BASIC-программы и EXE-подпрограммы - использование операторов USR или CALL. Работая в отладчике, необходимо определить стартовый адрес EXE-подпрограммы и, затем, указать этот адрес или в операторе USRn или в CALL. В руководстве по языку BASIC для IBM PC детально представлено описание функции USRn и оператора CALL с различными примерами.


Ассемблер для IBM PC. Глава 21 11
Программа: Компановка BASIC и ассемблера.
Рассмотрим теперь простой пример компановки программы для BASIC-интерпретатора и подпрограммы на ассемблере. В этом примере BASIC-программа запрашивает ввод значений времени и расценки и выводит на экран их произведение - размер зарплаты. Цикл FOR-NEXT обеспечивает пятикратное выполнение ввода и затем программа завершается. Пусть BASIC- программа вызывает ассемблерный модуль, который очищает экран. На рис. 21.7 приведена исходная BASIC-программа и ассемб лерная подпрограмма. Обратите внимание на следующие особен ности BASIC-программы: оператор 10 очищает 32К байт памяти; операторы 20, 30, 40 и 50 временно содержат комментарии. Позже мы вставим BASIC-операторы для связи с ассемблерным модулем. BASIC-программу можно сразу проверить. Введите команду BASIC и затем наберите все пронумерованные операторы так, как они показаны в примере. Для выполнения программы нажмите F2. Не забудте сохранить текст программы с помощью команды SAVE "B:BASTEST.BAS"
Обратите внимание на следующие особенности ассемблерной подпрограммы: - отсутствует определение стека, так как его обеспечивает BASIC; программа не предусмотрена для отдельного выполнения и не может быть выполнена; - подпрограмма сохраняет в стеке содержимое регистра BP и записывает значение регистра SP в BP; - подпрограмма выполняет очистку экрана, хотя она может быть изменена для выполнения других операций, таких как прокрутка экрана вверх или вниз или установка курсора.
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.7. Основная программа на языке BASIC и подпрограмма на ассемблере.
Все что осталось - это связать эти программы вместе. Следующие действия предполагают, что системная дискета (DOS) находится на дисководе A, а рабочие программы - на дисководе B:
1. Наберите ассемблерную подпрограмму, сохраните ее под именем B:LINKBAS.ASM и оттранслируйте ее. 2. Используя компановщик LINK, сгенерируйте объектный модуль, который будет загружаться в старшие адреса памяти: LINK B:LINKBAS,B:LINKBAS/HIGH,CON;


3. С помощью отладчика DEBUG загрузите BASIC - компилятор: DEBUG BASIC.COM.
Ассемблер для IBM PC. Глава 21 12
4. По команде отладчика R выведите на экран содержимое регистров. Запишите значения в регистрах SS, CS и IP. 5. Теперь установите имя и загрузите скомпанованный ассемблерный модуль следующими командами:
N B:LINKBAS.EXE L
6. По команде R выведите на экран содержимое регистров и запишите значения в CX, CS и IP. 7. Замените содержимое регистров SS, CS и IP значениями из шага 4. (Для этого служат команды R SS, R CS и R IP). 8. Введите команду отладчика G (go) для передачи управле ния в BASIC. На экране должен появиться запрос из BASIC-программы. 9. Для того, чтобы сохранить ассемблерный модуль, введите следующие команды (без номеров операторов):
DEF SEG = &Hxxxx (значение в CS из шага 6) BSAVE "B:CLRSCRN.MOD",0,&Hxx (значение в CX из шага 6)
Первая команда обеспечивает адрес загрузки модуля в память для выполнения. Вторая команда идентифицирует имя модуля, относительную точку входа и размер модуля. По второй команде система запишет модуль на дисковод B. 10. Теперь необходимо модифицировать BASIC-программу для компановки. Можно загрузить ее сразу, находясь в отладчике, но вместо этого наберите команду SYSTEM для выхода из BASIC и, затем, введите Q для выхода из отладчика DEBUG. На экране должно появиться приглашение DOS. 11. Введите команду BASIC, загрузите BASIC-программу и выведите ее на экран:
BASIC LOAD "B:BASTEST.BAS" LIST
12. Измените операторы 20, 30, 40 и 50 следующим образом:
20 BLOAD "B:CLRSCRN.MOD" 30 DEF SEG = &Hxxxx (значение в CS из шага 6) 40 CLRSCRN = 0 (точка входа в подпрограмму) 50 CALL CLRSCRN (вызов подпрограммы)
13. Просмотрите, выполните и сохраните измененную BASIC- программу.
Если BASIC-программа и ассемблерные команды были введены правильно, а также правильно установлены шестнадцатеричные значения из регистров, то связанная программа должна сразу очистить экран и выдать запрос на ввод времени и расценки.


Ассемблер для IBM PC. Глава 21 13
На рис.21.8 приведен протокол всех шагов - но некоторые значения могут отличаться в зависимости от версии операционной системы и размера памяти. Приведенный пример выбран намеренно простым только для демонстрации компановки. Можно использовать более сложную технологию, используя передачу параметров из BASIC-программы в ассемблерную подпрограмму с помощью оператора
CALL подпрограмма (параметр-1,параметр-2,...)
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.8. Этапы связи BASIC и ассемблера.
Ассемблерная подпрограмма может получить доступ к этим параметрам, используя регистр BP в виде [BP], как это делалось ранее на рис.21.3. В этом случае необходимо определить операнд в команде RET, соответствующий длине адресов параметров в стеке. Например, если оператор CALL передает три параметра то возврат должен быть закодирован в виде RET 6.
КОМПАНОВКА ПРОГРАММ НА ЯЗЫКЕ PASCAL И АССЕМБЛЕРЕ ------------------------------------------------------------
В данном разделе показано, как можно установить связь между программами на языке PASCAL фирм IBM и MicroSoft с программами на ассемблере. На рис.21.9 приведен пример связи простой PASCAL-программы с ассемблерной подпрограммой. PASCAL-программа скомпилирована для получения OBJ-модуля, а ассемблерная программа оттранслирована также для получения OBJ-модуля. Программа LINK затем компанует вместе эти два OBJ-модуля в один выполнимый EXE-модуль. В PASCAL-программе определены две переменные: temp_row и temp_col, которые содержат введенные с клавиатуры значения строки и колонки соответственно. Программа передает адреса переменных temp_row и temp_col в виде парамтеров в ассемблерную подпрограмму для установки курсора по этим координатам. PASCAL-программа определяет также имя ассемблерной подпрограммы в операторе procedure как move_cursor и определяет два параметра, как extern (внешние). Оператор в PASCAL-программе, который вызывает ассемблерную программу по имени и передает парметры, имеет следующий вид: move_cursor (temp_row, temp_col);


Через стек передаются следующие величины: указатель блока вызывающей программы, указатель на сегмент возврата, смещение возврата и адреса двух передаваемых параметров. Ниже показаны смещения для каждого элемента в стеке:
00 Указатель блока вызывающей программы 02 Указатель сегмента возврата
Ассемблер для IBM PC. Глава 21 14
04 Указатель смещения возврата 06 Адрес второго параметра 08 Адрес первого параметра
Так как ассемблерная подпрограмма будет использовать регистр BP, то его необходимо сохранить в стеке для последующего восстановления при возврате в вызывающую PASCAL-программу. Заметьте, что этот шаг в вызываемой подпрограмме аналогичен предыдущему примеру на рис.21.6.
------------------------------------------------------------ ------------------------------------------------------------ Рис.21.9. Компановка PASCAL-ассемблер.
Регистр SP обычно адресует элементы стека. Но так как этот регистр нельзя использовать в качестве индексного регистра, то после сохранения старого значения регистра BP необходимо переслать адрес из регистра SP в BP. Этот шаг дает возможность использовать регистр BP в качестве индексного регистра для доступа к элементам в стеке. Следующий шаг - получить доступ к адресам двух параметров в стеке. Первый переданный параметр (адрес строки) находится в стеке по смещению 08, и может быть адресован по BP+08. Второй переданный параметр (адрес столбца) находится в стеке по смещению 06 и может быть адресован по BP+06. Два адреса из стека должны быть переданы в один из индексных регистров BX, DI или SI. В данном примере адрес строки пересылается из [BP+08] в регистр SI, а затем содержимое из [SI] (значение строки) пересылается в регистр DH. Значение столбца пересылается аналогичным способом в регистр DL. Затем подпрограмма использует значения строки и столбца в регистре DX при вызове BIOS для установки курсора. При выходе подпрограмма восстанавливает регистр BP. Команда RET имеет операнд, значение которого в два раза больше числа параметров, в данном случае 2х2, или 4. Параметры автома тически выводятся из стека и управление переходит в вызываю щую программу. Если в подпрограмме предстоит изменить сегментный регистр то необходимо сохранить его значение командой PUSH на входе и восстановить командой POP на выходе. Можно также использо вать стек для передачи величин из подпрограммы в вызывающую программу. Хотя рассмотренная подпрограмма не возвращает каких-либо значений, в языке PASCAL предполагается, что подпрограмма возращает одно слово в регистре AX или двойное слово в регистровой паре DX:AX. В результате компановки двух программ будет построена карта компановки, в которой первый элемент PASCALL представляет PASCALL-программу, второй элемент CODESEG (имя сегмента кода) представляет ассемблерную подпрограмму. Далее следует несколько подпрограмм для PASCALL-программы. Эта довольно тривиальная программа занимает в результате


Ассемблер для IBM PC. Глава 21 15
шест.5720 байт памяти - более 20К. Компилирующие языки обычно генерируют объектные коды значительно превышающие по объему размеры компилируемой программы.
КОМПАНОВКА ПРОГРАММ НА ЯЗЫКЕ C И АССЕМБЛЕРЕ ------------------------------------------------------------
Трудность описания связи программ на языке C и ассемблерных программ состоит в том, что различные версии языка C имеют разные соглашения о связях и для более точной информации следует пользоваться руководством по имеющейся версии языка C. Здесь приведем лишь некоторые соображения, представляющие интерес:
ъ Большинство версий языка C обеспечивают передачу параметров через стек в обратной (по сравнению с другими языками) последовательности. Обычно доступ, например, к двум параметрам, передаваемым через стек, осуществляется следующим образом:
MOV ES,BP MOV BP,SP MOV DH,[BP+4] MOV DL,[BP+6] ... POP BP RET
ъ Некоторые версии языка C различают прописные и строчные буквы, поэтому имя ассемблерного модуля должно быть представленно в том же символьном регистре, какой используют для ссылки C-программы.
ъ В некоторых версиях языка C требуется, чтобы ассемб лерные программы, изменяющие регистры DI и SI, записы вали их содержимое в стек при входе и восстанавливали эти значения из стека при выходе.
ъ Ассемблерные программы должны возвращать значения, если это необходимо, в регистре AX (одно слово) или в регистровой паре DX:AX (два слова).
ъ Для некоторых версий языка C, если ассемблерная программа устанавливает флаг DF, то она должна сбросить его командой CLD перед возвратом.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ ------------------------------------------------------------
ъ В основной программе, вызывающей подпрограмму, необходимо определять точку входа как EXTRN, а в подпрограмме - как PUBLIC.
Ассемблер для IBM PC. Глава 21 16
ъ Будьте внимательны при использовании рекурсий, когда подпрограмма 1 вызывает подпрограмму 2, которая в свою очередь вызывает подпрограмму 1.
ъ Если кодовые сегменты необходимо скомпановать в один сегмент, то необходимо определить их с одинаковыми именами, одинаковыми классами и атрибутом PUBLIC.


ъ Для простоты программирования начинайте выполнение с основной программы.
ъ Определение общих данных в основной программе обычно проще (но не обязательно). Основная программа определя ет общие данные как PUBLIC, а подпрограмма (или подпрограммы) - как EXTRN.
ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ ------------------------------------------------------------
21.1. Предположим, что программа MAINPRO должна вызвать под программу SUBPRO. а) Какая директива в программе MAINPRO указывает ассемблеру, что имя SUBPRO определе но вне ее собственного кода? б) Какая директива в подпрограмме SUBPRO необходима для того, чтобы имя точки входа было доступно в основной программе MAINPRO?
21.2. Предположим, что в программе MAINPRO определены переменные QTY как DB, VALUE как DW и PRICE как DW. Подпрограмма SUBPRO должна разделить VALUE на QTY и записать частное в PRICE. а) Каким образом программа MAINPRO указывает ассемблеру, что три переменные должны быть доступный извне основной программы? б) Каким образом подпрограмма SUBPRO указывает ассемблеру, что три переменные определены в другом модуле?
21.3. На основании вопросов 21.2 и 21.3 постройте работающую программу и проверьте ее.
21.4. Измените программу из предыдущего вопроса так, чтобы программа MAINPRO передавала все три переменные, как параметры. Подпрограмма SUBPRO должна возвращать результат через параметр.
21.5. Теперь предлагаем упражнение, на которое потребуется больше времени. Требуется расширить программу из вопроса 21.4 так, чтобы программа MAINPRO позволяла вводить количество (QTY) и общую стоимость (VALVE) с клавиатуры, подпрограмма SUBCONV преобразовывала ASCII-величины в двоичное представление; подпрограмма
Ассемблер для IBM PC. Глава 21 17
SUBCALC вычисляла цену (PRICE); и подпрограмма SUBDISP преобразовывала двоичную цену в ASCII-представление и выводила результат на экран.
Ассемблер для IBM PC. Глава 22 33


Программный загрузчик


------------------------------------------------------------

Программный загрузчик

Цель: Раскрыть особенности загрузки выполнимых модулей в память для выполнения.

ВВЕДЕНИЕ ------------------------------------------------------------

В данной главе описана организация базовой версии DOS и операции, которые выполняет DOS для загрузки выполнимых модулей в память для выполнения. DOS состоит из четырех основных программ, которые обеспечивают конкретные функции:

1. Блок начальной загрузки находится на первом секторе нулевой дорожки дискеты DOS, а также на любом диске, форматированном командой FORMAT /S. Когда вы иницииру ете систему (предполагается, что DOS расположен на дисководе A или C) происходит автоматическая загрузка с диска в память блока начальной загрузки. Этот блок представляет собой программу, которая затем загружает с диска в память три программы, описанные ниже.

2. Программа IBMBIO.COM обеспечивает интерфейс низкого уровня с программами BIOS в ROM; она загружается в память, начиная с адреса шест.00600. При инициализации программа IBMBIO.COM определяет состояние всех устройств и оборудования, а затем загружает программу COMMAND.COM. Программа IBMBIO.COM управляет операциями ввода-вывода между памятью и внешними устройствами, такими как видеомонитор и диск.

3. Программа IBMDOS.COM обеспечивает интерфейс высокого уровня с программами и загружается в память, начиная с адреса шест.00B00. Эта программа управляет оглавлениями и файлами на диске, блокированием и деблокированием дисковых записей, функциями INT 21H, а также содержит ряд других сервисных функций.

4. Программа COMMAND.COM выполняет различные команды DOS, такие как DIR или CHKDSK, а также выполняет COM, EXE и BAT-программы. Она состоит из трех частей: небольшая резидентная часть, часть инициализации и транзитная часть. Программа COMMAND.COM, подробно расмотренная в следующем разделе, отвечает за загрузку выполняемых программ с диска в память.

На рис.22.1 показана карта распределения памяти. Некото рые элементы могут отличаться в зависимости от модели компьютера.


Ассемблер для IBM PC. Глава 22 34
------------------------------------------------------------ Начальный Программа адрес 00000 Векторная таблица прерываний (см.гл.23) 00400 Область связи с ROM (ПЗУ) 00500 Область связи с DOS 00600 IBMBIO.COM XXXX0 IBMDOS.COM Буфер каталога Дисковый буфер Таблица параметров дисковода или таблица распределения файлов (FAT, по одной для каждого дисковода) XXXX0 Резидентная часть COMMAND.COM XXXX0 Внешние команды или утилиты (COM или EXE-файлы) XXXX0 Пользовательский стек для COM-файлов (256 байтов) XXXX0 Транзитная часть COMMAND.COM, записывается в самые старшие адреса памяти. ------------------------------------------------------------ Рис.22.1. Карта распределения DOS в памяти.
КОМАНДНЫЙ ПРОЦЕССОР COMMAND.COM ------------------------------------------------------------
Система загружает три части программы COMMAND.COM в память во время сеанса работы постоянно или временно. Ниже описано назначение каждой из трех чатей COMMAND.COM:
1. Резидентная часть непосредственно следует за программой IBMDOS.COM (и ее области данных), где она находится на протяжении всего сеанса работы. Резидентная часть обрабатывает все ошибки дисковых операций ввода-вывода и управляет следующими прерываниями:
INT 22H Адрес программы обработки завершения задачи. INT 23H Адрес программы реакции на Ctrl/Break. INT 24H Адрес программы реакции на ошибоки дисковых операций чтения/записи или сбойный участок памяти в таблице распределения файлов (FAT). INT 27H Завершение работы, после которого программа остается резидентной.
2. Часть инициализации непосредственно следует за резидент ной чатью и содержит средства поддержки AUTOEXEC- файлов. В начале работы системы данная часть первой получает управление. Она выдает запрос на ввод даты и определяет сегментный адрес, куда система должна загружать программы для выполнения. Ни одна из этих программ инициализации не потребуются больше во время сеанса работы. Поэтому первая же команда вводимая с клавиатуры и вызывающая загрузку некоторой программы с диска перекрывают часть инициализации в памяти.


Ассемблер для IBM PC. Глава 22 35
3. Транзитная часть загружается в самые старшие адреса памяти. "Транзит" обозначает, что DOS может перекрыть данную область другими программами, если потребуется. Транзитная часть программы COMMAND.COM выводит на экран приглашение DOS A> или C>, вводит и выполняет запросы. Она содержит настраивающий загрузчик и предназначена для загрузки COM- или EXE-файлов с диска в память для выполнения. Если поступил запрос на выполнение какой-либо программы, то транзитная часть строит префикс программного сегмента (PSP) непосредственно вслед за резидентной частью COMMAND.COM. Затем она загружает запрошенную программу с диска в память по смещению шест.100 от начала программного сегмента, устанавливает адреса выхода и передает управление в загруженную программу. Ниже приведена данная последовательность:
IBMBIO.COM IBMDOS.COM COMMAND.COM (резидент) Префикс программного сегмента Выполняемая программа ... COMMAND.COM (транзитная часть, может быть перекрыта).
Выполнение команды RET или INT 20H в конце программы приводит к возврату в резидентную часть COMMAND.COM. Если транзитная часть была перекрыта, то резидентная часть перезагружает транзитную часть с диска в память.
ПРЕФИКС ПРОГРАММНОГО СЕГМЕНТА ------------------------------------------------------------
Префикс программного сегмента (PSP) занимает 256 (шест. 100) байт и всегда предшествует в памяти каждой COM- или EXE-программе, которая должна быть выполнена. PSP содержит следующие поля:
00 Команда INT 20H (шест.CD20). 02 Общий размер доступной памяти в формате хххх0. Напри мер, 512K указывается как шест.8000 вместо шест.80000. 04 Зарезервировано. 05 Длинный вызов диспетчера функций DOS. OA Адрес подпрограммы завершения. OE Адрес подпрограммы реакции на Ctrl/Break. 12 Адрес подпрограммы реакции на фатальную ошибку. 16 Зарезервировано. 2C Сегментный адрес среды для хранения ASCIIZ строк. 50 Вызов функций DOS (INT 21H и RETF). 5C Параметрическая область 1, форматированная как стандарт ный неоткрытый блок управления файлов (FCBЭ1).


Ассемблер для IBM PC. Глава 22 36
6C Параметрическая область 2, форматированная как стандарт ный неоткрытый блок управления файлом (FCBЭ2); перекры вается, если блок FCBЭ1 открыт. 80-FF Буфер передачи данных (DTA).
Буфер передачи данных DTA
Данная часть PSP начинается по адресу шест.80 и представляет собой буферную область ввода-вывода для текущего дисковода. Она содержит в первом байте число, указывающее сколько раз были нажаты клавиши на клавиатуре непосредственно после ввода имени программы. Начиная со второго байта, находятся введенные символы (если таковые имеются). Далее следует всевозможный "мусор", оставшийся в памяти после работы предыдущей программы. Следующие примеры демонстрируют назначение буфера DTA:
Пример 1. Команда без операндов. Предположим, что вы выз вали программу CALCIT.EXE для выполнения с помощью команды CALCIT [return]. После того, как DOS построит PSP для этой программы, он установит в буфере по адресу шест.80 значение шест.000D. Первый байт содержит число символов, введенных с клавиатуры после имени CALCIT, исключая символ "возврат каретки". Так как кроме клавиши Return не было нажато ни одной, то число символов равно нулю. Второй байт содержит символ возврата каретки, шест.0D. Таким образом, по адресам шест.80 и 81 на ходятся 000D.
Пример 2. Команда с текстовым операндом. Предположим, что после команды был указан текст (но не имя файла), например, COLOR BY, обозначающий вызов программы COLOR и передачу этой программе параметра "BY" для установки голубого цвета на желтом фоне. В этом случае, начиная с адреса шест.80, DOS установит следующие значения байт:
80: 03 20 42 59 0D
Эти байты обозначают длину 3, пробел, "BY" и возврат каретки.
Пример 3. Команда с именем файла в операнде. Программы типа DEL (удаление файла) предполагают после имени программы ввод имени файла в качестве параметра. Если будет введено, например, DEL B:CALCIT.OBJ [return], то PSP, начиная с адресов шест.5C и шест.80, будет содержать:


5C: 02 43 41 4C 43 49 54 20 20 4F 42 4A C A L C I T O B J 80: 0D 20 42 3A 43 41 4C 43 49 54 2E 4F 42 4A 0D B : C A L C I T . 0 B J
Ассемблер для IBM PC. Глава 22 37
Начиная с адреса шест.5C, находится неоткрытый блок FCB, содержащий имя файла, который был указан в параметре, CALCIT.OBJ, но не имя выполняемой программы. Первый символ указывает номер дисковода (02=B в данном случае). Следом за CALCIT находятся два пробела, которые дополняют имя файла до восьми символов, и тип файла, OBJ. Если ввести два параметра, например:
progname A:FILEA,B:FILEB
тогда DOS построит FCB для FILEA по смещению шест.5C и FCB для FILEB по смещению шест.6C. Начиная с адреса шест.80 в этом случае содержится число введенных символов (длина параметров) - 16, пробел (шест.20) A:FILEA,B:FILEB и символ возврат каретки (OD). Так как PSP непосредственно предшествует вашей программе, то возможен доступ к области PSP для обработки указанных файлов или для предпринятия определенных действий. Для локализации буфера DTA COM-программа может просто поместить шест.80 в регистр SI и получить доступ следующим образом:
MOV SI,80H ;Адрес DTA CMP BYTE PTR [SI],0 ;В буфере нуль? JE EXIT
Для EXE-программы нельзя с уверенностью утверждать, что кодовый сегмент непосредственно располагается после PSP. Однако, здесь при инициализации регистры DS и ES содержат адрес PSP, так что можно сохранить содержимое регистра ES после загрузки регистра DS:
MOV AX,DSEG MOV DS,AX MOV SAVEPSP,ES
Позже можно использовать сохраненный адрес для доступа к буферу PSP:
MOV SI,SAVEPSP CMP BYTE PTR [SI+ 80H],0 ;В буфере нуль? JE EXIT
DOS версии 3.0 и страше содержит команду INT 62H, загружаю щую в регистр BX адрес текущего PSP, который можно использо вать для доступа к данным в PSP.
ВЫПОЛНЕНИЕ COM-ПРОГРАММЫ ------------------------------------------------------------
В отличие от EXE-файла, COM-файл не содержит заголовок на диске. Так как организация COM-файла намного проще, то для DOS необходимо "знать" только то, что тип файла - COM.


Ассемблер для IBM PC. Глава 22 38
Как описано выше, загруженным в память COM- и EXE-файлам предшествует префикс программного сегмента. Первые два байта этого префикса содержат команду INT 20H (возврат в DOS). При загрузке COM-программы DOS устанавливает в четырех сегментных регистрах адрес первого байта PSP. Затем устанавливается указатель стека на конец 64 Кбайтового сегмента (шест.FFFE) или на конец памяти, если сегмент не достаточно большой. В вершину стека заносится нулевое слово. В командный указатель помещается шест.100 (размер PSP). После этого управление передается по адресу регистровой пары CS:IP, т.е. на адрес непосредственно после PSP. Этот адрес является началом выполняемой COM-программы и должен содержать выполнимую команду. При выходе из программы команда RET заносит в регистр IP нулевое слово, которое было записано в вершину стека при инициализации. В этом случае в регистровой паре CS:IP получается адрес первого байта PSP, где находится команда INT 20H. При выполнении этой команды управление передается в резидентную часть COMMAND.COM. (Если программа завершается по команде INT 20H вместо RET, то управление непосредственно передается в COMMAND.COM).
ВЫПОЛНЕНИЕ EXE-ПРОГРАММЫ ------------------------------------------------------------
EXE-модуль, созданный компановщиком, состоит из следующих двух частей: 1) заголовок - запись, содержащая информацию по управлению и настройке программы и 2) собственно загрузоч ный модуль. В заголовке находится информация о размере выполняемого модуля, области загрузки в памяти, адресе стека и относитель ных смещениях, которые должны заполнить машинные адреса в соответствии с относительными шест. позициями:
00 Шест.4D5A. Компановщик устанавливает этот код для иден тификации правильного EXE-файла. 02 Число байтов в последнем блоке EXE-файла. 04 Число 512 байтовых блоков EXE-файла, включая заголо вок. 06 Число настраиваемых элементов. 08 Число 16-тибайтовых блоков (параграфов) в заголовке, (необходимо для локализации начала выполняемого модуля, следующего после заголовка). OA Минимальное число параграфов, которые должны находится после загруженной программы. OC Переключатель загрузки в младшие или старшие адреса. При компановке программист должен решить, должна ли его программа загружаться для выполнения в младшие адреса памяти или в старшие. Обычным является звгрузка в млад шие адреса. Значение шест.0000 указывает на загрузку в старшие адреса, а шест.FFFF - в младшие. Иные значения определяют максимальное число параграфов, которые должны находиться после загруженной программы.


Ассемблер для IBM PC. Глава 22 39
OE Относительный адрес сегмента стека в выполняемом модуле. 10 Адрес, который загрузчик должен поместить в регистр SP перед передачей управления в выполнимый модуль. 12 Контрольная сумма - сумма всех слов в файле (без учета переполнений) используется для проверки потери данных. 14 Относительный адрес, который загрузчик должен поместить в регистр IP до передачи управления в выполняемый модуль. 16 Относительный адрес кодового сегмента в выполняемом модуле. Этот адрес загрузчик заносит в регистр CS. 18 Смещение первого настраиваемого элемента в файле. 1A Номер оверлейного фрагмента: нуль обозначает, что заго ловок относится к резидентной части EXE-файла. 1C Таблица настройки, содержащая переменное число настраиваемых элементов, соответствующее значению по смещению 06.
Заголовок имеет минимальный размер 512 байтов и может быть больше, если программа содержит большое число настраи ваемых элементов. Позиция 06 в заголовке указывает число элементов в выполняемом модуле, нуждающихся в настройке. Каждый элемент настройки в таблице, начинающейся в позиции 1C заголовка, состоит из двухбайтовых величин смещений и двухбайтовых сегментных значений. Система строит префикс программного сегмента следом за резидентной часью COMMAND.COM, которая выполняет операцию загрузки. Затем COMMAND.COM выполняет следующие действия:
ъ Считывает форматированную часть заголовка в память. ъ Вычисляет размер выполнимого модуля (общий размер файла в позиции 04 минус размер заголовка в позиции 08) и загружает модуль в память с начала сегмента. ъ Считывает элементы таблицы настройки в рабочую область и прибавляет значения каждого элемента таблицы к началу сегмента (позиция OE). ъ Устанавливает в регистрах SS и SP значения из заголовка и прибавляет адрес начала сегмента. ъ Устанавливает в регистрах DS и ES сегментный адрес префикса программного сегмента. ъ Устанавливает в регистре CS адрес PSP и прибавляет вели чину смещения в заголовке (позиция 16) к регистру CS. Если сегмент кода непосредственно следует за PSP, то смещение в заголовке равно 256 (шест.100). Регистровая пара CS:IP содержит стартовый адрес в кодовом сегменте, т.е. начальный адрес программы.


После инициализации регистры CS и SS содержат правильные адреса, а регистр DS (и ES) должны быть установлены в программе для их собственных сегментов данных:
1. PUSH DS ;Занести адрес PSP в стек 2. SUB AX,AX ;Занести нулевое значение в стек
Ассемблер для IBM PC. Глава 22 40
3. PUSH AX ; для обеспечения выхода из программы 4. MOV AX,datasegname ;Установка в регистре DX 5. MOV DS,AX ; адреса сегмента данных
При завершении программы команда RET заносит в регистр IP нулевое значение, которое было помещено в стек в начале выполнения программы. В регистровой паре CS:IP в этом случае получается адрес, который является адресом первого байта PSP, где расположена команда INT 20H. Когда эта команда будет выполнена, управление перейдет в DOS.
ПРИМЕР EXE-ПРОГРАММЫ ------------------------------------------------------------
Рассмотрим следующую таблицу компановки (MAP) программы:
Start Stop Length Name Class 00000H 0003AH 003BH CSEG CODE 00040H 0005AH 001BH DSEG DATA 00060H 0007FH 0020H STACK STACK Program entry point at 0000:0000
Таблица MAP содержит относительные (не действительные) адреса каждого из трех сегментов. Символ H после каждого значения указывает на шестнадцатиричный формат. Заметим, что компановщик может организовать эти сегменты в последователь ности отличного от того, как они были закодированы в програм ме. В соответствии с таблицей MAP кодовый сегмент CSEG нахо дится по адресу 00000 - этот относительный адрес является началом выполняемого модуля. Длина кодового сегмента составляет шест.003B байтов. Следующий сегмент по имени DSEG начинается по адресу шест.00040 и имеет длину шест.001B. Адрес шест.00040 является первым после CSEG адресом, выров ненным на границу параграфа (т.е. это значение кратно шест.10). Последний сегмент, STACK, начинается по адресу шест.00060 - первому после DSEG, адресу выровненному на границу параграфа. С помощью отладчика DEBUG нельзя проверить содержимое заголовка, так как при загрузке программы для выполнения DOS замещает заголовок префиксом программного сегмента. Однако, на рынке программного обеспечения имеются различные сервис ные утилиты (или можно написать собственную), которые позво ляют просматривать содержимое любого дискового сектора в шестнадцатиричном формате. Заголовок для рассматриваемого примера программы содержит следующую информацию (содержимое слов представлено в обратной последовательности байтов).


00 Шест.4D5A. 02 Число байтов в последнем блоке: 5B00. 04 Число 512 байтовых блоков в файле, включая заголовок: 0200 (шест.0002х512=1024).
Ассемблер для IBM PC. Глава 22 41
06 Число элементов в таблице настройки, находящейся после форматированной части заголовка: 0100, т.е. 0001. 08 Число 16 байтовых элементов в заголовке: 2000 (шест.0020=32 и 32х16=512). 0C Загрузка в младшие адреса: шест.FFFF. 0E Относительный адрес стекового сегмента: 6000 или шест. 60. 10 Адрес для загрузки в SP: 2000 или шест.20. 14 Смещение для IP: 0000. 16 Cмещение для CS: 0000. 18 Cмещение для первого настраиваемого элемента: 1E00 или шест.1E.
После загрузки программы под управлением отладчика DEBUG регистры получают следующие значения:
SP = 0020 DS = 138F ES = 138F SS = 13A5 CS = 139F IP = 0000
Для EXE-модулей загрузчик устанавливает в регистрах DS и ES адрес префикса программного сегмента, помещенного в доступной области памяти, а в регистрах IP, SS и SP - значения из заголовка программы.
Регистр SP
Загрузчик использует шест.20 из заголовка для инициализа ции указателя стека значением длины стека. В данном примере стек был определен, как 16 DUP (?), т.е. 16 двухбайтовых полей общей длиной 32 (шест.20) байта. Регистр SP указывает на текущую вершину стека.
Регистр CS
В соответствии со значением в регистре DS после загрузки программы, адрес PSP равен шест.138F(0). Так как PSP имеет длину шест.100 байтов, то выполняемый модуль, следующий непо средственно после PSP, находится по адресу шест.138F0+100= 139F0. Это значение устанавливается загрузчиком в регистре CS. Таким образом, регистр CS определяет начальный адрес кодовой части программы (CSEG). С помощью команды D CS:0000 в отладчике DEBUG можно просмотреть в режиме дампа машинный код в памяти. Обратите внимание на идентичность дампа и шестнадцатиричной части ассемблерного LST файла кроме операндов, отмеченных символом R.
Регистр SS
Для установки значения в регистре SS загрузчик также использует информацию из заголовка:
Начальный адрес PSP (см.DS) 138F0 Длина PSP 100


Ассемблер для IBM PC. Глава 22 42
Относительный адрес стека 60 Адрес стека 13A50
Регистр DS
Загрузчик использует регистр DS для установки начального адреса PSP. Так как заголовок не содержит стартового адреса, то регистр DS необходимо инициализировать в программе следую щим образом:
0004 B8 ---- R MOV AX,DSEG 0007 8E D8 MOV DS,AX
Ассемблер оставляет незаполненным машинный адрес сегмента DSEG, который становится элементом таблицы настройки в заго ловке. С помощью отладчика DEBUG можно просмотреть завершен ную команду в следующем виде:
B8 A313
Значение A313 загружается в регистр DS в виде 13A3. В результате имеем
Регистр Адрес Смещение CS 139F0 00 DS 13A30 40 SS 13A50 60
В качестве упражнения выполните трассировку любой вашей скомпанованной программы под управлением отладчика DEBUG и обратите внимание на изменяющиеся значения в регистрах:
Команда Изменяющиеся регистры PUSH DS IP и SP SUB AX,AX IP и AX (если был не нуль) PUSH AX IP и SP MOV AX,DSEG IP и AX MOV DS,AX IP и DS
Регистр DS содержит теперь правильный адрес сегмента данных. Можно использовать теперь команду D DS:00 для просмотра содержимого сегмента данных DSEG и команду D SS:00 для просмотра содержимого стека.
ФУНКЦИИ ЗАГРУЗКИ И ВЫПОЛНЕНИЯ ПРОГРАММЫ ------------------------------------------------------------
Рассмотрим теперь, как можно загрузить и выполнить программу из другой программы. Функция шест.4B дает возможность одной программе загрузить другую программу в память и при необходимости выполнить. Для этой функции необходимо загрузить адрес ASCIIZ-строки в регистр DX, а
Ассемблер для IBM PC. Глава 22 43
адрес блока параметров в регистр BX (в действительности в регистровую пару ES:BX). В регистре AL устанавливается номер функции 0 или 3:
AL=0. Загрузка и выполнение. Данная операция устанавлива ет префикс программного сегмента для новой программы, а также адрес подпрограммы реакции на Cntrl/Break и адрес передачи управления на следующую команду после завершения новой программы. Так как все регистры, включая SP, изменяют свои значения, то данная операция не для новичков. Блок параметров, адресуемый по ES:BX, имеет следующий формат:


Смещение Назначение 0 Двухбайтовый сегментный адрес строки параметров для передачи. 2 Четырехбайтовый указатель на командную строку в PSP+80H. 6 Четырехбайтовый указатель на блок FCB в PSP+5CH. 10 Четырехбайтовый указатель на блок FCB в PSP+6CH.
AL=3. Оверлейная загрузка. Данная операция загружает программу или блок кодов, но не создает PSP и не начинает выполнение. Таким образом можно создавать оверлейные программы. Блок параметров адресуется по регистровой паре ES:BX и имеет следующий формат:
Смещение Назначение 0 Двухбайтовый адрес сегмента для загрузки файла. 2 Двухбайтовый фактор настройки загрузочного модуля.
Возможные коды ошибок, возвращаемые в регистре AX: 01, 02, 05, 08, 10 и 11. Программа на рис.22.2 запрашивает DOS выполнить команду DIR для дисковода D. Выполните эту программу, как EXE-модуль. (Автор благодарен журналу PC Magazine за эту идею).
------------------------------------------------------------ ------------------------------------------------------------ Рис.22.2. Выполнение команды DIR из программы.
Ассемблер для IBM PC. Глава 23 55


Прерывания BIOS и DOS


------------------------------------------------------------

Прерывания BIOS и DOS

Цель: Описать функции, доступные через прерывания BIOS и DOS.

ВВЕДЕНИЕ ------------------------------------------------------------

Прерывание представляет собой операцию, которая приоста навливает выполнение программ для специальных системных действий. Необходимость прерываний обусловлено двумя основными причинами: преднамеренный запрос таких действий, как операции ввода-вывода на различные устройства и непредвиденные программные ошибки (например, переполнение при делении). Система BIOS (Basic Input/Output System) находится в ROM и управляет всеми прерываниями в системе. В предыдущих главах уже использовались некоторые прерывания для вывода на экран дисковых операций ввода-вывода и печати. В этой главе описаны различные BIOS- и DOS-прерывания, резидентные программы и команды IN и OUT.

ОБСЛУЖИВАНИЕ ПРЕРЫВАНИЙ ------------------------------------------------------------

В компьютерах IBM PC ROM находится по адресу FFFF0H. При включении компьютера процессор устанавливает состояние сброса, выполняет контроль четности, устанавливает в регистре CS значение FFFFH, а в регистре IP - нуль. Первая выполняемая команда поэтому находится по адресу FFFF:0 или FFFF0, что является точкой входа в BIOS. BIOS проверяет различные порты компьютера для определения и инициализации подключенных устрой ств. Затем BIOS создает в начале памяти (по адресу 0) таблицу прерываний, которая содержит адреса обработчиков прерываний, и выполняет две операции INT 11H (запрос списка присоединенного оборудования) и INT 12H (запрос размера физической памяти). Следующим шагом BIOS определяет имеется ли на диске или дискете операционная система DOS. Если обнаружена системная дискета, то BIOS выполняет прерывание INT 19H для доступа к первому сектору диска, содержащему блок начальной загрузки. Этот блок представляет собой программу, которая считывает системные файлы IBMBIO.COM, IBMDOS.COM и COMMAND.COM с диска в память. После этого память имеет следующее распределение:


Таблица векторов прерываний Данные BIOS IBMBIO.COM и IBMDOS.COM Резидентная часть COMMAND.COM
Ассемблер для IBM PC. Глава 23 56
Доступная память для прикладных программ Транзитная часть COMMAND.COM Конец RAM (ОЗУ) ROM BASIC ROM BIOS
Внешние устройства передают сигнал внимания через контакт INTR в процессор. Процессор реагирует на этот запрос, если флаг прерывания IF установлен в 1 (прерывание разрешено), и (в большинстве случаев) игнорирует запрос, если флаг IF установлен в 0 (прерывание запрещено). Операнд в команде прерывания, например, INT 12H, содержит тип прерывания, который идентифицирует запрос. Для каждого типа система содержит адрес в таблице векторов прерываний, начинающейся по адресу 0000. Так как в таблице имеется 256 четырехбайтовых элементов, то она занимает первые 1024 байта памяти от шест.0 до шест.3FF. Каждый элемент таблицы указывает на подпрограмму обработки указанного типа прерывания и содержит адрес кодового сегмента и смещение, которые при прерывании устанавливаются в регистры CS и IP соответственно. Список элементов таблицы векторов прерываний приведен на рис. 23.1. Прерывание заносит в стек содержимое флагового регистра, регистра CS и регистра IP. Например, для прерывания 12H (которое возвращает в регистре AX размер памяти) адрес элемента таблицы равен шест.0048 (шест.12 х 4 = шест.48). Операция выделяет четырехбайтовый элемент по адресу шест. 0048 и заносит два байта в регистр IP и два байта в регистр SS. Адрес, который получается в регистровой паре CS:IP, представляет собой адрес начала подпрограммы в области BIOS, которая получает управление. Возврат из этой подпрограммы осуществляется командой IRET (Interrupt Return), которая восстанавливает флаги и регистры CS и IP из стека и передает управление на команду, следующую за выполненной командой прерывания.
ПРЕРЫВАНИЯ BIOS ------------------------------------------------------------
В данном разделе представлены основные прерывания BIOS.
INT 05H (Печать экрана). Приводит к передаче содержимого экрана на печатающее устройство. INT 05H применяется для внутренних целей, т.е. из программ, клавиши Ctrl/PrtSc активизируют печать с клавиатуры. Данная операция маскирует прерывания и сохраняет позицию курсора.


------------------------------------------------------------
Адрес Функция прерыаний (шест) (шест) 0-3 0 Деление на нуль 4-7 1 Пошаговый режим (трассировка DEBUG)
Ассемблер для IBM PC. Глава 23 57
8-B 2 Немаскированное прерывание (NMI) C-F 3 Точка останова (используется в DEBUG) 10-13 4 Переполнение регистра 14-17 5 Печать экрана 18-1F 6,7 Зарезервировано 20-23 8 Сигнал от траймера 24-27 9 Сигнал от клавиатуры 28-37 A,B,C,D Используются в компьютерах AT 38-3B E Сигнал от дискетного дисковода 3C-3F F Используется для принтера 40-43 10 Управление дисплеем (см.гл. 8, 9, 10) 44-47 11 Запрос оборудования (см.гл.9) 48-4B 12 Запрос размера памяти (см.гл.2) 4C-4F 13 Дисковые операции ввода-вывода (см.гл.18) 50-53 14 Управление коммуникационным адаптером 54-57 15 Кассетные операции и спец. функции AT 58-5B 16 Ввод с клавиатуры (см.гл.9) 5C-5F 17 Вывод на принтер (см.гл.19) 60-63 18 Обращение к BASIC, встроенному в ROM 64-67 19 Перезапуск системы 68-6B 1A Запрос и установка времени и даты 6C-6F 1B Прерывание от клавиатуры 70-73 1C Прерывание от таймера 74-77 1D Адрес таблицы параметров дисплея 78-7B 1E Адрес таблицы параметров дисковода 7C-7F 1F Адрес таблицы графических символов 80-83 20 Нормальное завершение программы (DOS) 84-87 21 Обращение к функциям DOS 88-8B 22 Адрес обработки завершения задачи (DOS) 8C-8F 23 Адрес реакции по Ctrl/Break (DOS) 90-93 24 Адрес реакции на фатальную ошибку (DOS) 94-97 25 Абсолютное чтение с диска (DOS) 98-9B 26 Абсолютная запись на диск (DOS) 97-9F 27 Создание резидентной программы (DOS) AO-FF 28-3F Другие функции DOS 100-1FF 40-7F Зарезервировано 200-217 80-85 Зарезервировано для BASIC 218-3C3 86-F0 Используются BASIC-интерпретатором 3C4-3FF F1-FF Зарезервировано
Примечание: Прерывания 00-1F относятся к BIOS, прерывания 20-FF относятся к DOS и BASIC.
------------------------------------------------------------ Рис.23.1. Таблица адресов прерываний.
ПРЕРЫВАНИЯ BIOS ------------------------------------------------------------
В данном разделе приведены основные прерывания BIOS.


Ассемблер для IBM PC. Глава 23 58
INT 05H Печать экрана. Выполняет вывод содержимого экрана на печатающее устройство. Команда INT 05H выполняет данную операцию из программы, а нажатие клавишей Ctrl/PrtSc - с клавиатуры. Операция запрещает прерывания и сохраняет позицию курсора.
INT 10H Управление дисплеем. Обеспечивает экранные и кла виатурные операции, детельно описанные в главе 9.
INT 11H Запрос списка присоединенного оборудования. Опре деляет наличие различных устройств в системе, результирующее значение возвращает в регистре AX. При включении компьютера система выполняет эту операцию и сохраняет содержимое AX в памяти по адресу шест.410. Значения битов в регистре AX:
Бит Устройство 15,14 Число подключенных принтеров 13 Последовательный принтер 12 Игровой адаптер 11-9 Число последовательных адаптеров стыка RS232 7,6 Число дискетных дисководов, при бите 0=1: 00=1, 01=2, 10=3 и 11=4 5,4 Начальный видео режим: 00 = неиспользуется 01 = 40х25 плюс цвет 10 = 80х25 плюс цвет 11 = 80х25 черно-белый режим 1 Значение 1 говорит о наличии сопроцессора 0 Значение 1 говорит о наличии одного или более дисковых устройств и загрузка операционной системы должна осуществляться с диска
INT 12H Запрос размера физической памяти. Возвращает в регистре AX размер памяти в килобайтах, например, шест.200 соответствует памяти в 512 К. Данная операция полезна для выравнивания размера программы в соответствии с доступной памятью.
INT 13H Дисковые операции ввода-вывода. Обеспечивает опе рации ввода-вывода для дискет и винчестера, рассмотренные в главе 16.
INT 14H Управление коммуникационным адаптером. Обеспечи вает последовательный ввод-вывод через коммуникационный порт RS232. Регистр DX должен содержать номер (0 или 1) адаптера стыка RS232. Четыре типа операции, определяемые регистром AH, выполняют прием и передачу символов и возвращают в регистре AX байт состояния коммуникационного порта.
INT 15H Кассетные операции ввода-вывода и специальные функции для компьютеров AT. Обеспечивает операции ввода- вывода для касетного магнитофона, а также расширенные операции для компьютеров AT.


Ассемблер для IBM PC. Глава 23 59
INT 16H Ввод с клавиатуры. Обеспечивает три типа команд ввода с клавиатуры, подробно описанные в главе 9.
INT 17H Вывод на принтер. Обеспечивает вывод данных на пе чатающее устройство. Подробно рассмотрено в главе 19.
INT 18H Обращение к BASIC, встроенному в ROM. Вызывает BASIC-интерпретатор, находящийся в постоянной памяти ROM.
INT 19H Перезапуск системы. Данная операция при доступном диске считывает сектор 1 с дорожки 0 в область начальной загрузки в памяти (сегмент 0, смещение 7C00) и передает управление по этому адресу. Если дисковод не доступен, то операция передает управление через INT 18H в ROM BASIC. Данная операция не очищает экран и не инициализирует данные в ROM BASIC, поэтому ее можно использовать из программы.
INT 1AH Запрос и установка текущего времени и даты. Считы вает и записывает показание часов в соответствии со значением в регистре AH. Для определения продолжительности выполнения программы можно перед началом выполнения установить часы в 0, а после считать текущее время. Отсчет времени идет примерно 18,2 раза в секунду. Значение в регистре AH соответствует следующим операциям: AH=00 Запрос времени. В регистре CX устанавливается стар шая часть значения, а в регистре DX - младшая. Если после последнего запроса прошло 24 часа, то в регистре AL будет не нулевое значение. AH=01 Установка времени. Время устанавливается по регист рам CX (старшая часть значения) и DX (младшая часть значе ния). Коды 02 и 06 управляют временем и датой для AT.
INT 1FH Адрес таблицы графических символов. В графическом режиме имеется доступ к символам с кодами 128-255 в 1К таблице, содержащей по восемь байт на каждый символ. Прямой доступ в графическом режиме обеспечивается только к первым 128 ASCII-символам (от 0 до 127).
ПРЕРЫВАНИЯ DOS ------------------------------------------------------------
Во время своей работы BIOS использует два модуля DOS: IBMBIO.COM и IBMDOS.COM. Так как модули DOS обеспечивают большое количество разных дополнительных проверок, то операция DOS обычно проще в использовании и менее машинно зависимы, чем их BIOS аналоги. Модуль IBMBIO.COM обеспечивает интерфейс с BIOS низкого уровня. Эта программа выполняет управление вводом-выводом при чтении данных из внешних устройств в память и записи из памяти на внешние устройства.


Ассемблер для IBM PC. Глава 23 60
Модуль IBMDOS.COM содержит средства управления файлами и ряд сервисных функций, таких как блокирование и деблокиро вание записей. Когда пользовательская программа выдает запрос INT 21H, то в программу IBMDOS через регистры передается определенная информация. Затем программа IBMDOS транслирует эту информацию в один или несколько вызовов IBMBIO, которая в свою очередь вызывает BIOS. Указанные связи приведены на следующей схеме:
Пользовательский Высший Низший ROM Внешний уровень уровень уровень уровень +-----------+ +----------+ +----------+ |Программный| | DOS | | DOS | +----+ +----------+ |запрос в/в ||IBMDOS.COM||IBMBIO.COM||BIOS||Устройство| +-----------+ +----------+ +----------+ +----+ +----------+
Как показано выше, прерывания от шест.20 до шест.62 зарезервированы для операций DOS. Ниже приведены наиболее основные из них:
INT 20H Завершение программы. Запрос завершает выполнение программы и передает управление в DOS. Данный запрос обычно находится в основной процедуре.
INT 21H Запрос функций DOS. Основная операция DOS, вызыва ющая определенную функцию в соответствии с кодом в регистре AH. Назначение функций DOS описано в следующем разделе.
INT 22H Адрес подпрограммы обработки завершения задачи. (см.INT 24H).
INT 23H Адрес подпрограммы реакции на Ctrl/Break. (см.INT 24H).
INT 24H Адрес подпрограммы реакции на фатальную ошибку. В этом элементе и в двух предыдущих содержатся адреса, которые инициализируются системой в префиксе программного сегмента и, которые можно изменить для своих целей. Подробности приве дены в техническом описании DOS.
INT 25H Абсолютное чтение с диска. См.гл.17.
INT 26H Абсолютная запись на диск. См.гл.17.
INT 27H Завершение программы, оставляющее ее резедентной. Позволяет сохранить COM-программу в памяти. Подробно данная операция рассмотренна в последующем разделе "Резиденные прогарммы".
ФУНКЦИИ ПРЕРЫВАНИЯ DOS INT 21H ------------------------------------------------------------
Ассемблер для IBM PC. Глава 23 61


Ниже приведены базовые функции для прерывания DOS INT 21H. Код функции устанавливается в регистре AH:
00 Завершение программы (аналогично INT 20H). 01 Ввод символа с клавиатуры с эхом на экран. 02 Вывод символа на экран. 03 Ввод символа из асинх. коммуникационного канала. 04 Вывод символа на асинх. коммуникационный канал.
Ассемблер для IBM PC. Приложения 1
ПРИЛОЖЕНИЕ 1 -----------------------------------------------------------
Коды ASCII-символов
Ниже представлены первые 128 символов ASCII-кода. В руко водстве по языку BASIC приведены остальные 128 символов. На помним, что шест.20 представляет стандартный символ пробела.
ПРИЛОЖЕНИЕ 2 ------------------------------------------------------------
Шестнадцатерично-десятичные преобразования
В данном приложении представлены приемы преобразования между шестнадцатеричным и десятичным форматами. В первом разделе показан пример преобразования шест. A7B8 в десятичное 42936, а во втором - 42936 обратно в шест. A7B8.
Преобразование шестнадцатеричного формата в десятичный ---------------------------------------------------------
Для перевода шест. A7B8 в десятичное число необходимо последовательно, начиная с самой левой шест. цифры (A), умножать на 16 и складывать со следующей цифрой. Так как операции выполняются в десятичном формате, то шест. числа от A до F необходимо преобразовать в десятичные от 10 до 15.
Первая цифра: A (10) 10 Умножить на 16 *16 160 Прибавить следующую цифру, 7 7 167 Умножить на 16 *16 2672 Прибавить следующую цифру, B (11) 11 2683 Умножить на 16 *16 42928 Прибавить следующую цифру, 8 8 Десятичное значение 42936
Можно использовать также таблицу преобразования. Для шест. числа A7B8 представим правую цифру (8) как позицию 1, следующую влево цифру (B) как позицию 2, следующую цифру (7) как позицию 3 и самую левую цифру (A) как позицию 4. Из таблицы B-1 выберем значения для каждой шест. цифры:
Для позиции 1 (8), столбец 1 8 Для позиции 1 (8), столбец 1 176 Для позиции 1 (8), столбец 1 1792 Для позиции 1 (8), столбец 1 40960


Ассемблер для IBM PC. Приложения 2
Десятичное значение 42936
Преобразование десятичного формата в шестнадцатеричный --------------------------------------------------------- Для преобразования десятичного числа 42936 в шестнадцате ричный формат необходимо сначала исходное число 42936 разделить на 16; число, получившееся в остатке, (6) является младшей шестнадцатеричной цифрой. Затем полученное частное необходимо снова разделить на 16 и полученный остаток (11 или B) дает следующую влево шестнадцатеричную цифру. Продол жая таким образом деления до тех пор, пока в частном не получится 0, получим из остатков все необходимые шестнадцате ричные цифры.
Частное Остаток Шест. 42936 / 16 2683 8 8 (младшая цифра) 2683 / 16 167 11 B 167 / 16 10 7 7 10 / 16 0 10 A (старшая цифра)
Для преобразования чисел из десятичного формата в шестнад цатеричный можно также воспользоваться таблицей B-1. Для десятичного числа 42936 необходимо найти в таблице число равное или ближайшее меньшее исходному, и записать соот ветствующую шестнадцатеричную цифру и ее позицию. Затем следует вычесть найденное десятичное число из 42936 и с полу ченной разностью проделать проделать ту же операцию:
Дес. Шест. Исходное десятичное число 42936 Вычесть ближайшее меньшее 40960 A000 Разность 1976 Вычесть ближайшее меньшее 1792 700 Разность 184 Вычесть ближайшее меньшее 176 B0 Разность 8 8 Результирующее шест. число 7 A7B8
ПРИЛОЖЕНИЕ 3 ------------------------------------------------------------
Зарезервированные слова
Большинство из следующих зарезервированных слов при ис пользовании их для определении элементов данных могут привес ти к ошибкам ассемблирования (в ряде случаев - к весьма грубым):
Имена регистров
AH BH CH DH CS SS BP AL BL CL DL DS SI SP
Ассемблер для IBM PC. Приложения 3
AX BX CX DX ES DI
Мнемокоды
AAA DIV JLE JS OR SBB AAD ESC JMP JZ OUT SCAS AAM HLT JNA LAHF POP SHL AAS IDIV JNAE LDS POPF SHR ADC IMUL JNB LEA PUSH STC ADD IN JNBE LES PUSHF STD AND INC JNE LOCK RCL STI CALL INT JNG LODS RCR STOS CBW INTO JNGE LOOP REP SUB CLC IRET JNL LOOPE REPE TEST CLD JA JNLE LOOPNE REPNE WAIT CLI JAE JNO LOOPNZ REPNZ XCHG CMC JB JNP LOOPZ REPZ XLAT CMP JBE JNS MOV RET XOR CMPS JCXZ JNZ MOVS ROL CWD JE JO MUL ROR DAA JG JP NEG SAHF DAS JGE JPE NOP SAL DEC JL JPO NOT SAR


Директивы ассемблера
ASSUME END EXTRN IFNB LOCAL PURGE COMMENT ENDIF GROUP IFNDEF MACRO RECORD DB ENDM IF IF1 NAME REPT DD ENDP IFB IF2 ORG SEGMENT DQ ENDS IFDEF INCLUDE OUT STRUC DT EQU IFDIF IRP PAGE SUBTTL DW EVEN IFE IRPC PROC TITLE ELSE EXITM IFIDN LABEL PUBLIC
Прочие элементы языка
BYTE FAR LENGTH MOD PRT THIS COMMENT GE LINE NE SEG TYPE CON GT LT NEAR SHORT WIDTH DUP HIGH LOW NOTHING SIZE WORD EQ LE MASK OFFSET STACK
Ассемблер для IBM PC. Программы. 9
Двоич. Дес. Шест. Двоич. Дес. Шест.
0000 0 0 1000 8 8 0001 1 1 1001 9 9 0010 2 2 1010 10 A 0011 3 3 1011 11 B 0100 4 4 1100 12 C 0101 5 5 1101 13 D 0110 6 6 1110 14 E 0111 7 7 1111 15 F
+======================+ I D O S I I I +---------+ г - - - - - - - - - - -¶ + SS | Адрес +------->I Сегмент стека I | + - - - - + I I | DS | Адрес +----+ г - - - - - - - - - - -¶ | Переме- + - - - - + +-->I Сегмент данных I | щаемые CS | Адрес +---+ I I | в +---------+ | г - - - - - - - - - - -¶ | памяти +--->I Сегмент кода I | Сегментные I I | регистры г - - - - - - - - - - -¶ + I I I I I I I I +======================+ Память
Ассемблер для IBM PC. Программы. 10
| ОУ: Операционное | ШИ: Шинный интерфейс устройство | | +--------+--------+ | | AH | AL | | +--------+--------+ | | BH | BL | | +--------+--------+ | | CH | CL | | +--------+--------+ | Управление | DH | DL | | программами +--------+--------+ | +-----------------+ | SP | | | CS | +-----------------+ | +-----------------+ | BP | | | DS | +-----------------+ | +-----------------+ | SI | | | SS | +-----------------+ | +-----------------+ | DI | | | ES | +-----------------+ | +-------+---------+ Л | | | | | +-------+ V | V | Управ-| Шина ======================ь==============>| ление |<==> 8088 Л | Л | шиной | | | | +-------+ V | | +-----------------+ | +---+---+ | АЛУ: Арифметико-| | +---+ 1 | Очередь | логическое | | | +-------+ команд | устройство | | | | 2 | (Четыре байта) +->+ - - - - - - - - + | | +-------+ | | УУ: Устройство | | | | 3 | | | управления | | | +-------+ | + - - - - - - - - + | | | 4 | | | Флаговый регистр| | | +-------+ | +-----------------+ | | | | | | +-----------------+ | | +--+ Командный |<--+--+ | указатель | | +-----------------+ | |


Ассемблер для IBM PC. Программы. 11
Начальный адрес Память Дес. Шест. +-----------------------------+ 0K 00000 | RAM 256K основная оператив- | | ная память | +-----------------------------+ 256K 40000 | RAM 384K расширение опера- | | тивной памяти в канале I/O | +-----------------------------+ 640K A0000 | RAM 128K графический/экран- | | ный видео буфер | +-----------------------------+ 768K C0000 | ROM 192K дополнительная | | постоянная память | +-----------------------------+ 960K F0000 | ROM 64K основная системная | | постоянная память | +-----------------------------+
Ассемблер для IBM PC. Программы. 12
D>DEBUG -E CS:100 B8 23 01 05 25 00 -E CS:106 8B D8 03 D8 8B CB -E CS:10C 2B C8 2B C0 90 CB -R AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0100 NV UP EI PL NZ NA PO NC 13C6:0100 B8230 MOV AX,0123 -T
AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0103 NV UP EI PL NZ NA PO NC 13C6:0103 052500 ADD AX,0025 -T
AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0106 NV UP EI PL NZ NA PE NC 13C6:0106 8BD8 MOV BX,AX -T
AX=0148 BX=0148 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0108 NV UP EI PL NZ NA PO NC 13C6:0108 03D8 ADD BX,AX -T
AX=0148 BX=0290 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=010A NV UP EI PL NZ AC PO NC 13C6:010A 8BCB MOV CX,BX -T
AX=0148 BX=0290 CX=0290 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=010C NV UP EI PL NZ AC PO NC 13C6:010C 2BC8 SUB CX,AX -T
AX=0148 BX=0290 CX=0148 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0100 NV UP EI PL NZ AC PO NC 13C6:010E 2BC0 SUB AX,AX -T
AX=0000 BX=0290 CX=0148 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0110 NV UP EI PL ZR NA PO NC 13C6:0110 90 NOP -T
AX=0000 BX=0290 CX=0148 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0111 NV UP EI PL ZR NA PO NC 13C6:0111 CB RETF -


Ассемблер для IBM PC. Программы. 13
-D CS:100 13C6:0100 B8 23 01 05 25 00 8B D8-03 D8 8B CB 2B C8 2B C0 .#..%.......+.+. 13C6:0110 90 CB 8D 46 14 50 51 52-FF 76 28 E8 74 00 8B E5 ...F.PQR.v(.t... 13C6:0120 B8 01 00 50 FF 76 32 FF-76 30 FF 76 2E FF 76 28 ...P.v2.v0.v..v( 13C6:0130 E8 88 15 8B E5 BF 36 18-12 FF 36 16 12 8B 76 28 ......6...6...v( 13C6:0140 FF 74 3A 89 46 06 E8 22-CE 8B E5 30 E4 3D 0A 00 .t:.F.."...0.=.. 13C6:0150 75 32 A1 16 12 2D 01 00-8B 1E 18 12 83 DB 00 53 u2...-.........S 13C6:0160 50 8B 76 28 FF 74 3A A3-16 12 89 1E 18 12 E8 FA P.v(.t:......... 13C6:0170 CD 8B E5 30 E4 3D 0D 00-74 0A 83 06 16 12 01 83 ...0.=..t....... -Q
Ассемблер для IBM PC. Программы. 14
D>DEBUG -E DS:23 01 25 00 00 -E DS:2A 2A 2A -E CS:100 A1 00 00 03 06 02 00 -E CS:107 A3 04 00 CB -D DS:0 13C6:0000 23 01 25 00 00 9A 2A 2A-2A F0 F5 02 2C 10 2E 03 #.%...***...,... 13C6:0010 2C 10 BD 02 2C 10 B1 0D-01 03 01 00 02 FF FF FF ,...,........... 13C6:0020 FF FF FF FF FF FF FF FF-FF FF FF FF EF 0F 64 00 ..............d. 13C6:0030 61 13 14 00 18 00 C7 13-FF FF FF FF 00 00 00 00 a............... 13C6:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 13C6:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!........... 13C6:0060 20 20 20 20 20 20 20 20 00 00 00 00 00 20 20 20 ..... 13C6:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........ -R AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0100 NV UP EI PL NZ NA PO NC 13C6:0100 A10000 MOV AX,[0000] DS:0000=0123 -T
AX=0123 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0103 NV UP EI PL NZ NA PO NC 13C6:0103 03060200 ADD AX,[0002] DS:0002=0025 -T
AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0107 NV UP EI PL NZ NA PE NC 13C6:0107 A30400 MOV [0004],AX DS:0004=9A00 -T
AX=0148 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 DS=13C6 ES=13C6 SS=13C6 CS=13C6 IP=0108 NV UP EI PL NZ NA PO NC 13C6:010A CB RETF -D DS:0 13C6:0000 23 01 25 00 00 9A 2A 2A-2A F0 F5 02 2C 10 2E 03 #.%...***...,... 13C6:0010 2C 10 BD 02 2C 10 B1 0D-01 03 01 00 02 FF FF FF ,...,........... 13C6:0020 FF FF FF FF FF FF FF FF-FF FF FF FF EF 0F 64 00 ..............d. 13C6:0030 61 13 14 00 18 00 C7 13-FF FF FF FF 00 00 00 00 a............... 13C6:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 00 00 ................ 13C6:0050 CD 21 CB 00 00 00 00 00-00 00 00 00 00 20 20 20 .!........... 13C6:0060 20 20 20 20 20 20 20 20 00 00 00 00 00 20 20 20 ..... 13C6:0070 20 20 20 20 20 20 20 20-00 00 00 00 00 00 00 00 ........ -Q


CODESG SEGMENT PARA 'CODE' BEGIN PROC FAR 1. ASSUME CS:CODESG,DS:DATASG,SS:STACKG 2. PUSH DS ;Записать DS в стек 3. SUB AX,AX ;Установить ноль в AX PUSH AX ;Записать ноль в стек
Ассемблер для IBM PC. Программы. 15
4. MOV AX,DATASG ;Занести адрес MOV DS,AX ; DATASG в DS . . . 5. RET ;Возврат в DOS BEGIN ENDP CODESG ENDS END BEGIN
page 60,132 TITLE EXASM1 (EXE) Пример регистровых операций ;------------------------------------------------ STACKSG SEGMENT PARA SACK 'Stack' DB 12 DUP('STACKSEG') STACKSG ENDS ;------------------------------------------------ CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME SS:STACKSG,CS:CODESG,DS:NOTHING PUSH DS ;Записать DS в стек SUB AX,AX ;Записать ноль PUSH AX ; в стек
MOV AX,0123H ;Записать шест.0123 в AX ADD AX,0025H ;Прибавить шест.25 к AX MOV BX,AX ;Переслать AX в BX ADD BX,AX ;Прибавить BX к AX MOV CX,BX ;Переслать BX в CX SUB CX,AX ;Вычесть AX из CX SUB AX,AX ;Очистить AX NOP RET ;Возврат в DOS BEGIN ENDP ;Конец процедуры
CODESG ENDS ;Конец сегмента END BEGIN ;Конец программы
Ассемблер для IBM PC. Программы. 16
1 page 60,132 2 TITLE EXASM1 (EXE) Пример регистровых операций 3 ;------------------------------------------------ 4 0000 STACKSG SEGMENT PARA SACK 'Stack' 5 0000 0C [ DB 12 DUP('STACKSEG') 6 53 54 41 43 7 4B 53 45 47 8 ] 9 10 0060 STACKSG ENDS 11 ;------------------------------------------------- 12 0000 CODESG SEGMENT PARA 'Code' 13 0000 BEGIN PROC FAR 14 ASSUME SS:STACKSG,CS:CODESG,DS:NOTHING 15 0000 1E PUSH DS ;Записать DS в стек 16 0001 2B C0 SUB AX,AX ;Записать ноль 17 0003 50 PUSH AX ; в стек 18 19 0004 B8 0123 MOV AX,0123H ;Записать шест.0123 в AX 20 0007 05 0025 ADD AX,0025H ;Прибавить шест.25 к AX 21 000A 8B D8 MOV BX,AX ;Переслать AX в BX 22 000C 03 D8 ADD BX,AX ;Прибавить BX к AX 23 000E 8B CB MOV CX,BX ;Переслать BX в CX 24 0010 2B C8 SUB CX,AX ;Вычесть AX из CX 25 0012 2B C0 SUB AX,AX ;Очистить AX 26 0014 90 NOP 27 0015 CB RET ;Возврат в DOS 28 0016 BEGIN ENDP ;Конец процедуры 29 30 0016 CODESG ENDS ;Конец сегмента 31 END BEGIN ;Конец программы -------------------------------------------------------------------------- Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0016 PARA NONE 'CODE' STACKSG. . . . . . . . . . . . 0060 PARA STACK 'STACK'


Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0016 --------------------------------------------------------------------------
Ассемблер для IBM PC. Программы. 17
1 page 60,132 2 TITLE EXASM2 (EXE) Операции пересылки и сложения 3 ;--------------------------------------------------- 4 0000 STACKSG SEGMENT PARA SACK 'Stack' 5 0000 20 [ DB 32 DUP(?) 6 ???? 7 ] 8 9 0040 STACKSG ENDS 10 ;--------------------------------------------------- 11 0000 DATASG SEGMENT PARA 'Data' 12 0000 00FA FLDA DW 250 13 0002 007D FLDB DW 125 14 0004 ???? FLDC DW ? 15 0006 DATASG ENDS 16 ;--------------------------------------------------- 17 0000 CODESG SEGMENT PARA 'Code' 18 0000 BEGIN PROC FAR 19 ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:NOTHING 20 0000 1E PUSH DS ;Записать DS в стек 21 0001 2B C0 SUB AX,AX ;Записать в стек 22 0003 50 PUSH AX ; нулевой адрес 23 0004 B8 ---- R MOV AX,DATASG ;Поместить адрес DATASG 24 0007 8E D8 MOV DS,AX ; в регистр DS 25 26 0009 A1 0000 R MOV AX,FLDA ;Переслать 0250 в AX 27 000C 03 06 0002 R ADD AX,FLDB ;Прибавить 0125 к AX 28 0010 A3 0004 R MOV FLDC,AX ;Записать сумму в FLDC 29 0013 CB RET ;Вернуться в DOS 30 0014 BEGIN ENDP 31 0014 CODESG ENDS END BEGIN
---------------------------------------------------------------------------- Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0014 PARA NONE 'CODE' DATASG . . . . . . . . . . . . 0006 PARA NONE 'DATA' STACKSG. . . . . . . . . . . . 0040 PARA STACK 'STACK'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0014 FLDA . . . . . . . . . . . . . L WORD 0000 DATASG FLDB . . . . . . . . . . . . . L WORD 0002 DATASG FLDC . . . . . . . . . . . . . L WORD 0004 DATASG ----------------------------------------------------------------------------
Ассемблер для IBM PC. Программы. 18
EXASM2 (EXE) Операции пересылки и сложения
Symbol Cross Reference (# is definition) Cref-1
BEGIN. . . . . . . . . . . . 18# 30 32


CODE . . . . . . . . . . . . 17 CODESG . . . . . . . . . . . 17# 19 31
DATA . . . . . . . . . . . . 11 DATASG . . . . . . . . . . . 11# 15 19 23
FLDA . . . . . . . . . . . . 12# 26 FLDB . . . . . . . . . . . . 13# 27 FLDC . . . . . . . . . . . . 14# 28
STACK. . . . . . . . . . . . 4 STACKSG. . . . . . . . . . . 4# 9 19
10 Symbols
Ассемблер для IBM PC. Программы. 19
page 60,132 TITLE EXDEF (EXE) Определение данных 0000 DATASG SEGMENT PARA 'Data'
; Определение байта - DB: ; ---------------------- 0000 ?? FLD1DB DB ? ;Неинициализирован 0001 50 65 72 73 6F 6E FLD2DB DB 'Personal Computer' ;Сим. строка 61 6C 20 43 6F 6D 70 75 74 65 72 0012 20 FLD3DB DB 32 ;Десятичная константа 0013 20 FLD4DB DB 20H ;Шест. константа 0014 59 FLD5DB DB 01011001B ;Двоичная константа 0015 01 4A 41 4E 02 46 FLD6DB DB 01,'JAN',02,'FEB',03,'MAR' ;Таблица 45 42 03 4D 41 52 0021 33 32 36 35 34 FLD7DB DB '32654' ;Символьные числа 0026 0A [ 00 ] FLD8DB DB 10 DUP(0) ;Десять нулей
; Определение слова - DW: ; ---------------------- 0030 FFF0 FLD1DW DW 0FFF0H ;Шест. константа 0032 0059 FLD2DW DW 01011001B ;Двоичная константа 0034 0021 R FLD3DW DW FLD7DB ;Адресная константа 0036 0003 0004 0007 FLD4DW DW 3,4,7,8,9 ;Пять констант 0008 0009 0040 05 [ 0000 ] FLD5DW DW 5 DUP(0) ;Пять нулей
; Определение двойного слова - DD: ; ------------------------------- 004A ???????? FLD1DD DD ? ;Неинициализировано 004E 43 50 00 00 FLD2DD DD 'PC' ;Символьная строка 0052 3C 7F 00 00 FLD3DD DD 32572 ;Десятичное значение 0056 11 00 00 00 FLD4DD DD FLD3DB - FLD2DB ;Разность адресов 005A 0E 00 00 00 31 00 FLD5DD DD 14,49 ;Две константы 00 00 ; Определение учетверенного слова - DQ: ; ------------------------------------ 0062 ???????????????? FLD1DQ DQ ? ;Неинициализировано 006A 47 4D 00 00 00 00 FLD2DQ DQ 04D47H ;Шест. константа 00 00 0072 3C 7F 00 00 00 00 FLD3DQ DQ 32572 ;Десятич. константа 00 00 ; Определение десяти байт - DT: ; ---------------------------- 007A ?????????????????? FLD1DT DT ? ;Неинициализировано ?? 0084 43 50 00 00 00 00 FLD2DT DT 'PC' ;Символьная строка 00 00 00 00


008E DATASG ENDS END -----------------------------------------------------------------------------
Ассемблер для IBM PC. Программы. 20
Segments and Groups: N a m e Size Align Combine Class DATASG . . . . . . . . . . . . 008E PARA NONE 'DATA'
Symbols: N a m e Type Value Attr FLD1DB . . . . . . . . . . . . L BYTE 0000 DATASG FLD1DD . . . . . . . . . . . . L DWORD 004A DATASG FLD1DQ . . . . . . . . . . . . L QWORD 0062 DATASG FLD1DT . . . . . . . . . . . . L TBYTE 007A DATASG FLD1DW . . . . . . . . . . . . L WORD 0030 DATASG FLD2DB . . . . . . . . . . . . L BYTE 0001 DATASG FLD2DD . . . . . . . . . . . . L DWORD 004E DATASG FLD2DQ . . . . . . . . . . . . L QWORD 006A DATASG FLD2DT . . . . . . . . . . . . L TBYTE 0084 DATASG FLD2DW . . . . . . . . . . . . L WORD 0032 DATASG FLD3DB . . . . . . . . . . . . L BYTE 0012 DATASG FLD3DD . . . . . . . . . . . . L DWORD 0052 DATASG FLD3DQ . . . . . . . . . . . . L QWORD 0072 DATASG FLD3DW . . . . . . . . . . . . L WORD 0034 DATASG FLD4DB . . . . . . . . . . . . L BYTE 0013 DATASG FLD4DD . . . . . . . . . . . . L DWORD 0056 DATASG FLD4DW . . . . . . . . . . . . L WORD 0036 DATASG FLD5DB . . . . . . . . . . . . L BYTE 0014 DATASG FLD5DD . . . . . . . . . . . . L DWORD 005A DATASG FLD5DW . . . . . . . . . . . . L WORD 0040 DATASG Length =0005 FLD6DB . . . . . . . . . . . . L BYTE 0015 DATASG FLD7DB . . . . . . . . . . . . L BYTE 0021 DATASG FLD8DB . . . . . . . . . . . . L BYTE 0026 DATASG Length =000A -------------------------------------------------------------------------------
Ассемблер для IBM PC. Программы. 21
D:\ D>DEBUG D:EXDEF.EXE -D 1421:0000 00 50 65 72 73 6F 6E 61-6C 20 43 6F 6D 70 75 74 .Personal Comput 1421:0010 65 72 20 20 59 01 4A 41-4E 02 46 45 42 03 4D 41 er Y.JAN.FEB.MA 1421:0020 52 33 32 36 35 34 00 00-00 00 00 00 00 00 00 00 R32654.......... 1421:0030 F0 FF 59 00 21 00 03 00-04 00 07 00 08 00 09 00 ..Y.!........... 1421:0040 00 00 00 00 00 00 00 00-00 00 00 00 00 00 43 50 ..............CP 1421:0050 00 00 3C 7F 00 00 11 00-00 00 0E 00 00 00 31 00 ..<...........1. 1421:0060 00 00 00 00 00 00 00 00-00 00 47 4D 00 00 00 00 ..........GM.... 1421:0070 00 00 3C 7F 00 00 00 00-00 00 00 00 00 00 00 00 ..<............. -D 1421:0080 00 00 00 00 43 50 00 00-00 00 00 00 00 00 33 33 ....CP........33 1421:0090 3E 36 33 33 73 00 00 00-0A 0E 00 00 3E 63 63 30 >633s.......>cc0 1421:00A0 1C 06 63 63 3E 00 00 00-0A 0E 00 00 FF DB 99 18 ..cc>........... 1421:00B0 18 18 18 18 3C 00 00 00-0A 0E 00 00 63 63 63 63 ....<.......cccc 1421:00C0 63 63 63 63 3E 00 00 00-0A 0E 00 00 C3 C3 C3 C3 cccc>........... 1421:00D0 C3 C3 66 3C 18 00 00 00-0A 0E 00 00 C3 C3 C3 C3 ..f<............ 1421:00E0 DB DB FF 66 66 00 00 00-0A 0E 00 00 C3 C3 66 3C ...ff.........f< 1421:00F0 18 3C 66 C3 C3 00 00 00-0A 0E 00 00 C3 C3 C3 66 .<f............f -Q


Ассемблер для IBM PC. Программы. 22
page 60,132 TITLE EXIMM (EXE) Пример непосредственных операндов ; (Кодируется для ассемблирования, ; но не для выполнения) 0000 DATASG SEGMENT PARA 'Data' 0000 ?? FLD1 DB ? 0001 ???? FLD2 DW ? 0003 DATASG ENDS
0000 CODESG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG
; Операции пересылки и сравнения: ; ------------------------------ 0000 BB 0113 MOV BX,275 ;Пересылка 0003 3C 19 CMP AL,H ;Сравнение
; Арифметические операции: ; ----------------------- 0005 14 05 ADC AL,5 ;Сложение с переносом 0007 80 C7 0C ADD BH,12 ;Сложение 000A 1C 05 SBB AL,5 ;Вычитание с заемом 000C 80 2E 000 R 05 SUB FLD1,5 ;Вычитание
; Ротация и сдвиг (только на 1 бит): ; --------------------------------- 0011 D0 D3 RCL BL,1 ;Ротация влево с переносом 0013 D0 DC RCR AH,1 ;Ротация вправо с переносом 0015 D1 06 0001 R ROL FID2,1 ;Ротация влево 0019 D0 C8 ROR AL,1 ;отация вправо 001B D1 E1 SAL CX,1 ;Сдвиг влево 001D D1 FB SAR BX,1 ;Арифм. сдвиг вправо 001F D0 2E 0000 R SHR FLD1,1 ;Сдвиг вправо
; Логические операции: ; ------------------- 0023 24 2C AND AL,00101100B ;AND (регистр) 0025 80 CF 2A OR BH,2AH ;OR (регистр) 0028 F6 C3 7A TEST BL,7AH ;TEST (регистр) 002B 80 36 0000 R 23 OR FLD1,23H ;XOR (память) 0030 BEGIN ENDP 0030 CODESG ENDS END
Ассемблер для IBM PC. Программы. 23
page 60,132 TITLE XCOM1 COM-программа для пересылки и сложения CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H ;Начало в конце PSP BEGIN: JMP MAIN ;Обход через данные ; --------------------------------------------------- FLDA DW 250 ;Определение данных FLDB DW 125 FLDC DW ? ; --------------------------------------------------- MAIN PROC NEAR MOV AX,FLDA ;Переслать 0250 в AX ADD AX,FLDB ;Прибавить 0125 к AX MOV FLDC,AX ;Записать сумму в FLDC RET ;ернуться в DOS MAIN ENDP CODESG ENDS END BEGIN
page 60,132 TITLE EXJUMP (COM) Организация цикла с помощью JMP 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H


0100 MAIN PROC NEAR 0100 B8 0001 MOV AX,01 ;Инициализация AX, 0103 BB 0001 MOV BX,01 ; BX, 0106 B9 0001 MOV CX,01 ; и CX 0109 A20: 0109 05 0001 ADD AX,01 ;Прибавить 01 к AX 010C 03 D8 ADD BX,AX ;Прибавить 01 к BX 010E D1 E1 SHL CX,1 ;Удвоить CX 0110 EB F7 JMP A20 ;Переход на A20 0112 MAIN ENDP 0112 CODESG ENDS END MAIN
Ассемблер для IBM PC. Программы. 24
page 60,132 TITLE EXLOOP (COM) Организация цикла командой LOOP 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H
0100 BEGIN PROC NEAR 0100 B8 0001 MOV AX,01 ;Инициализация AX, 0103 BB 0001 MOV BX,01 ; BX, 0106 BA 0001 MOV DX,01 ; и DX 0109 B9 000A MOV CX,10 ;Число циклов 010C A20: 010C 40 INC AX ;Прибавить 01 к AX 010D 03 D8 ADD BX,AX ;Прибавить AX к BX 010F D1 E2 SHL DX,1 ;Удвоить DX 0111 E2 F9 LOOP A20 ;Уменьшить CX и повторить ; цикл, если ненуль 0113 C3 RET ;Завершить работу 0114 BEGIN ENDP 0114 CODESG ENDS END BEGIN
+-------------------------+ | CODESG SEGMENT PARA | +-------------------------+ | BEGIN PROC FAR | | . | | . | | CALL B10 | | CALL C10 | | RET | | BEGIN ENDP | +-------------------------+ | B10 PROC NEAR | | . | | . | | RET | | B10 ENDP | +-------------------------+ | C10 PROC NEAR | | . | | . | | RET | | C10 ENDP | +-------------------------+ | CODESG ENDS | | END BEGIN | +-------------------------+
Ассемблер для IBM PC. Программы. 25
TITLE CALLPROC (EXE) Вызов процедур 0000 STACKSG SEGMENT PARA STACK 'Stack' 0000 20 [ ???? ] DW 32 DUP(?) 0040 STACKG ENDS
0000 CODESG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,SS:STACKSG 0000 1E PUSH DS 0001 2B C0 SUB AX,AX 0003 50 PUSH AX 0004 E8 0008 R CALL B10 ;Вызвать B10 ; ... 0007 CB RET ;Завершить программу 0008 BEGIN ENDP ;-------------------------------------- 0008 B10 PROC 0008 E8 000C R CALL C10 ;Вызвать C10 ; ... 000B C3 RET ;Вернуться в 000C B10 ENDP ; вызывающую программу ;---------------------------------------------- 000C C10 PROC ; ... 000C C3 RET ;Вернуться в 000D C10 ENDP ; вызывающую программу ;---------------------------------------------- 000D CODESG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 26
page 65,132 TITLE EXMOVE (EXE) Операции расширенной пересылки ;------------------------------------------------------ STACKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKSG ENDS ;------------------------------------------------------ DATASG SEGMENT PARA 'Data' NAME1 DB 'ABCDEFGHI' NAME2 DB 'JKLMNOPQR' NAME3 DB 'STUVWXYZ*' DATASG ENDS ;------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX CALL B10MOVE ;Вызвать JUMP подпрограмму CALL C10MOVE ;Вызвать CALL подпрограмму RET ;Завершить программу BEGIN ENDP
; Расширенная пересылка (JUMP-подпрограмма), ; использующая переход по условию: ; ----------------------------------------- B10MOVE PROC LEA SI,NAME1 ;Инициализация адресов LEA DI,NAME2 ; NAME1 и NAME2 MOV CX,09 ;Переслать 9 символов B20: MOV AL,[SI] ;Переслать из NAME1 MOV [DI],AL ;Переслать в NAME2 INC SI ;Следующий символ в NAME1 INC DI ;Следующая позиция в NAME2 DEC CX ;Уменьшить счетчик цикла JNZ B20 ;Счетчик > 0? Да - цикл RET ;Если счетчик = 0, то B10MOVE ENDP ; вернуться
; Расширенная пересылка (LOOP-подпрограмма), ; использующая команду LOOP: ; -----------------------------------------; C10MOVE PROC LEA SI,NAME2 ;Инициализация адресов LEA DI,NAME3 ; NAME2 и NAME3 MOV CX,09 ;Переслать 9 символов C20
Ассемблер для IBM PC. Программы. 27
MOV AL,[SI] ;Переслать из NAME2 MOV [DI],AL ;Переслать в NAME3 INC DI ;Следующий символ в NAME2 INC SI ;Следующая позиция в NAME3 LOOP C20 ;Уменьшить счетчик, ; если не ноль, то цикл RET ;Если счетчик = 0, то C10MOVE ENDP ; вернуться CODESG ENDS END BEGIN
TITLE CASE (COM) Перекодировка в заглавные буквы 0000 CODESG SEGMENT PARA 'CODE' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0001 ORG 100H 0001 EB 1C 90 BEGIN: JMP MAIN ; ------------------------------------------- 0003 43 68 61 6E 67 65 TITLEX DB 'Change to uppercase letters' 20 74 6F 20 75 70 70 65 72 63 61 73 65 20 6C 65 74 74 65 72 73 ; ------------------------------------------- 011E MAIN PROC NEAR 011E 8D 1E 0104 R LEA BX,TITLEX+1 ;Адрес первого символа 0122 B9 001F MOV CX,31 ;Число символов 0125 B20: 0125 8A 27 MOV AH,[BX] ;Символ из TITLEX 0127 80 FC 61 CMP AH,61H ;Это 012A 72 0A JB B30 ; прописная 012C 80 FC 7A CMP AH,7AH ; буква 012F 77 05 JA B30 ; ? 0131 80 E4 DF AND AH,11011111B ;Да - преобразовать 0134 88 27 MOV [BX],AH ;Записать в TITLEX 0136 B30: 0136 43 INC BX ;Следующий символ 0137 E2 EC LOOP B20 ;Повторить цикл 31 раз 0139 C3 RET 013A MAIN ENDP 013A CODESG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 28
page 60,132 TITLE ALLASC (COM) Вывод на экран ASCII-символов 00-FF CODESC SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:NOTHING ORG 100H BEGIN: JMP SHORT MAIN CTR DB 00,'S'
; Основная процедура: ; ------------------ MAIN PROC NEAR CALL B10CDR ;Очистить экран CALL C10SET ;Установить курсор CALL D10DISP ;Вывести символ на экран RET MAIN ENDP ; Очистка экрана: ; -------------- B10CLR PROC MOV AX,0600H MOV BH,07 MOV CX,0000 ;Левая верхняя позиция MOV DX,184FH ;Правая нижняя позиция INT 10H RET B10CLR ENDP ; Установка курсора в 00,00: ; ------------------------- C10SET PROC MOV AN,02 MOV BN,00 MOV DX,0000 INT 10H RET C10SET ENDP ; Вывод на экран ASCII символов: ; ----------------------------- D10DISP PROC MOV CX,256 ;256 итераций LEA DX,CTR ;Адрес счетчика D20 MOV AH,09 ;Функция вывода символа INT 21H INC CTR ;Увеличить счетчик LOOP D20 ;Уменьшить CX, ; цикл, если не ноль RET ;Вернуться D10DISP ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 29
page 60,132 TITLE CTRNAME (EXE) Ввод имен и вывод в центр экрана ;-------------------------------------------------------- STSCKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKSG ENDS ;-------------------------------------------------------- DATASG SEGMENT PARA 'Data' NAMEPAR LABEL BYTE ;Имя списка параметров: MAXNLEN DB 20 ; макс.длина имени NAMELEN DB ? ; число введенных символов NAMEFLD DB 20 DUP(' '),'$' ; имя и ограничитель ; для вывода на экран PRIMPT DB 'Name? ', '$' DATASG ENDS ;-------------------------------------------------------- CODESG SEGMENT PARA 'Code" BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASC PUSH DS SUB AX,AX PUCH AX MOV AX,DATASC MOV DS,AX MOV ES,AX CALL Q10CLR ;Очистить экран A20LOOP: MOV DX,0000 ;Установить курсор в 00,00 CALL Q20CURS CALL B10PRMP ;Выдать текст запроса CALL D10INPT ;Ввести имя CALL Q10CLR ;Очистить экран CMP NAMELEN,00 ;Имя введено? JE A30 ; нет - выйти CALL E10CODE ;Установить звуковой сигнал ; и ограничитель '$' CALL F10CENT ;Центрирование и вывод JMP A20LOOP A30: RET ;Вернуться в DOS BEGIN ENDP ; Вывод текста запроса: ; -------------------- B10PRMP PROC NEAR MUV AN,09 ;Функция вывода на экран LEA DX,PROMPT INT 21H RET B10PRMP ENDP ; Ввод имени с клавиатуры: ; ----------------------- D10INPT PROC NEAR


Ассемблер для IBM PC. Программы. 30
MOV AN,0AN ;Функция ввода LEA DX,NAMEPAR INT 21H RET D10INPT ENDP ; Установка сигнала и ограничителя '$': ; ------------------------------------ E10CODE PROC NEAR MOV BN,00 ;Замена символа Return (0D) MOV BL,NAMELEN ; на зв.сигнал (07) MOV NAMEFLD[BX],07 MOV NAMEFLD[BX+1],'$' ;Установить ограничитель RET E10CODE ENDP ; Центрирование и вывод имени на экран: ; ------------------------------------ F10CENT PROC NEAR MOV DL,NAMELEN ;Определение столбца: SHR DL,1 ; разделить длину на 2, NEG DL ; поменять знак, ADD DL,40 ; прибавить 40 MOV DH,12 ;Центральная строка CALL Q20CURS ;Установить курсор MOV AN,09 LEA DX,NAMEFLD ;Вывести имя на экран INT 21H RET F10CENT ENDP ; Очистить экран: ; -------------- Q10CLR PROC NEAR MOV AX,0600H ;Функция прокрутки экрана MOV BH,30 ;Цвет (07 для ч/б) MOV CX,0000 ;От 00,00 MOV DX,184FH ;До 24,79 INT 10H ;Вызов BIOS RET Q10CLR ; Установка курсора (строка/столбец): ; ---------------------------------- Q20CURS PROC NEAR ;DX уже установлен MOV AH,02 ;Функция установки курсора MOV BH,00 ;Страница #0 INT 10H ;Вызов BIOS RET Q20CURS ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 31
page 60,132 TITLE NMSCROLL (EXE) Инвертирование, мигание, прокрутка ; ------------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKG ENDS ; ------------------------------------------------------- DATASG SEGMENT PARA 'Data' NAMEPAR LABEL BYTE ;Имя списка параметров: MAXNLEN DB 20 ; макс.длина имени ACTNLEN DB ? ; число введенных символов NAMEFLD DB 20 DUP(' ') ; имя
COL DB 00 COUNT DB ? PROMPT DB 'Name? ' ROW DB 00 DATASG ENDS ; ------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH DS MOV AX,DATASG MOV ES,AX MOV AX,0600H CALL Q10CLR ;Очистить экран A20LOOP: MOV COL,00 ;Установить столбец 0 CALL Q20CURS CALL B10PRMP ;Выдать текст запроса CALL D10INPT ;Ввести имя с клавиатуры CMP ACTNLEN,00 ;Нет имени? (т.е. конец) JNE A30 MOV AX,0600H CALL Q10CLR ;Если да, то очистить экран, RET ; и завершить программу A30: CALL E10NAME ;Вывести имя на экран JMP A20LOOP BEGIN ENDP ; Вывод текста запроса: ; -------------------- B10PRMP PROC NEAR LEA SI,PROMPT ;Адрес текста MOV COUNT,05 B20: MOV BL,70H ;Видеоинверсия


Ассемблер для IBM PC. Программы. 32
CALL F10DISP ;Подпрограмма вывода INC SI ;Следующий символ в имени INC COL ;Следующий столбец CALL Q20CURS DEC COUNT ;Уменьшение счетчика JNZ B20 ;Повторить n раз RET B10PRMP ENDP ; вод имени с клавиатуры: ; ---------------------- D10INPT PROC NEAR MOV AN,0AH LEA DX,NAMEPAR INT 21H RET D10INPT ENDP ; Вывод имени с миганием и инверсией: ; ---------------------------------- E10NAME PROC NEAR LEA SI,NAMEFLD ;Адрес имени MOV COL,40 ;Установить столбец E20: CALL Q20CURS ;Установить курсор MOV BL,0FOH ;Мигание и инверсия CALL F10DISP ;Подпрограмма вывода INS SI ;Следующий символ в имени INS COL ;Следующий столбец на экране DES ACTNLEN ;Уменьшить счетчик длины JNZ E20 ;Циклить n раз CMP ROW,20 ;Последняя строка экрана? JAE E30 ; нет INC ROW RET E30: MOV AX,0601H ; да -- CALL Q10CLR ; очистить экран RET E10NAME ENDP ; Вывод символа на экран: ; ---------------------- F10DISP PROC NEAR ;BL (атрибут) уже установлен MOV AN,09 ;Функция вывода на экран MOV AL,[SI] ;Получить символ из имени MOV BH,00 ;Номер страницы MOV CX,01 ;Один символ INT 10H ;Вызов BIOS RET F10DISP ENDP ; Очистка экрана: ; -------------- Q10CLR PROC NEAR ;AX установлен при вызове MOV BH,07 ;Нормальный ч/б MOV CX 0000 MOV DX,184FH
Ассемблер для IBM PC. Программы. 33
INT 10H ;Вызов BIOS RET Q10CLR ENDP ; Установить курсор (строка/столбец): ; ---------------------------------- Q20CURS PROC NEAR MOV AN,02 MOV BH,00 MOV DH,ROW MOV DL,COL INT 10H RET Q20CURS ENDP CODESG ENDS END BEGIN
Расширенная функция Скэн-код
Alt/A до Alt/Z 1E - 2C F1 до F10 3B - 44 Home 47 Стрелка вверх 48 PgUp 49 Стрелка влево 4B Стрелка вправо 4D End 4F Стрелка вниз 50 PgDn 51 Ins 52 Del 53
Ассемблер для IBM PC. Программы. 34
TITLE GRAPHIX (COM) Пример цвета и графики CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H
MAIN PROC NEAR MOV AN,00 ;Установка режима графики MOV AL,0DH ; для EGA (CGA=04)
MOV AH,0BH ;Установить палитру MOV BH,00 ;Фон MOV BL,02 ;Зеленый INT 10H
MOV BX,00 ;Начальные цвет, MOV CX,00 ; столбец MOV DX,00 ; и строка A50: MOV AH,0CH ;Функция вывода точки MOV AL,BL ;Установить цвет INT 10H ;BX, CX, и DX сохраняются INC CX ;Увеличить столбец CMP CX,320 ;Столбец 320? JNE A50 ; нет - цикл, MOV CX,00 ; да - сбросить столбец INS BL ;Изменить цвет INS DX ;Увеличить строку CMP DX,40 ;Строка 40? JNE A50 ; нет - цикл, RET ; да - завершить MAIN ENDP CODESG ENDS END MAIN


Ассемблер для IBM PC. Программы. 35
page 60,132 TITLE STRING (EXE) Проверка строковых операций ; --------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKG ENDS ; --------------------------------------------------- DATASG SEGMENT PARA 'Data' NAME1 DB 'Assemblers' ;Элементы данных NAME2 DB 10 DUP(' ') NAME3 DB 10 DUP(' ') DATASG ENDS ; --------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ;Основная процедура ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX CALL C10MVSB ;Подпрограмма MVSB CALL D10MVSW ;Подпрограмма LODS CALL E10LODS ;Подпрограмма LODS CALL F10STOS ;Подпрограмма CMPS CALL H10SCAS ;Подпрограмма SCAS RET BEGIN ENDP ; Использование MOVSB: ; ------------------- C10MVSB PROC NEAR CLD LEA SI,NAME1 LEA D1,NAME2 MOV CX,10 ;Переслать 10 байтов REP MOVSB ; из NAME1 в NAME2 RET C10MVSB ENDP ; Использование MOVSW: ; ------------------- D10MVSW PROC NEAR CLD LEA SI,NAME2 LEA DI,NAME3 MOV CX,05 ;Переслать 5 слов REP MOVSW ; из NAME2 в NAME3 RET D10MVSW ENDP ; Использование LODSW: ; ------------------- E10LODS PROC NEAR
Ассемблер для IBM PC. Программы. 36
CLD LEA SI,NAME1 ;Загрузить первое слово LODSW ; из NAME1 в AX RET E10LODS ENDP ; Использование STOSW: ; ------------------- F10STOS PROC NEAR CLD LEA D1,NAME3 MOV CX,05 MOV AX,2020H ;Переслать пробелы REP STOSW ; в NAME3 RET F10STOS ENDP ; Использование CMPSB: ; ------------------- G10CMPS PROC NEAR CLD MOV CX,10 LEA SI,NAME1 LEA DI,NAME2 REPE CMPSB ;Сравнить NAME1 и NAME2 JNE G20 ;Не равны? MOV BH,01
G20: MOV CX,10 LEA SI,NAME2 LEA DI,NAME3 REPE CMPSB ;Сравнить NAME2 и NAME3 JE G30 ;Если равны, то выйти MOV BL,02 G30: RET G10CMPS ENDP
; Использование SCASB: ; ------------------- H10SCAS PROC NEAR CLD MOV CX,10 LEA DI,NAME1 MOV AL,'m' ;Поиск символа 'm' REPNE SCASB ; в NAME1 JNE H20 ;Если не найден - выйти MOV AH,03 H20: RET H10SCAS ENDP
CODES ENDS END BEGIN
Ассемблер для IBM PC. Программы. 37


page 60,132 TITLE EXRING (COM) Вывод имен, выровненных справа CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ;-------------------------------------------------------- NAMEPAR LABEL BYTE ;Имя списка параметров MAXNLEN DB 31 ;Макс. длина ACTNLEN DB ? ;Число введенных символов NAMEFLD DB 31 DUP(' ') ;Имя
PROMPT DB 'Name?', '$' NAMEDSP DB 31 DUP(' '), 13, 10, '$' ROW DB 00 ;-------------------------------------------------------- MAIN PROC NEAR ;Основная процедура MOV AX,0600H CALL Q10SCR ;Очистить экран SUB DX,DX ;Установить курсор в 00,00 CALL Q20CURS A10LOOP: CALL B10INPT ;Ввести имя с клавиатуры TEST ACTNLEN,0FFH ;Нет имени? (т.е. конец) JZ A90 ; да - выйти CALL D10SCAS ;Найти звездочку CMP AL,'*' ;Найдена? JE A10LOOP ; да - обойти CALL E10RGHT ;Выровнять имя справа CALL A10LOOP A90: RET MAIN ENDP ; Вывод запроса для ввода имени: ; ----------------------------- B10INPT PROC MOV AH,09 LEA DX,PROMPT ;Выдать текст запроса INT 21H RET B10INPT ENDP ; Поиск звездочки в имени: ; ----------------------- D10SCAS PROC CLD MOV AL,'*' MOV CX,30 ;Длина сканирования - 30 LEA DI,NAMEFLD REPNE SCASB ;Звездочка найдена? JE D20 ; да - выйти, MOV AL,20H ; нет стереть * в AL D20: RET D10SCAS ENDP
Ассемблер для IBM PC. Программы. 38
; Выравнивание справа и вывод на экран: ; ------------------------------------ E10RGHT PROC STD SUB CH,CH MOV CL,ACTNLEN ;Длина в CX для REP LEA SI,NAMEFLD ;Вычислить самую правую ADD SI,CX ; позицию DEC SI ; введенного имени LEA DI,NAMEDSP+30 ;Правая поз. поля имени REP MOVSB ;Переслать справа налево MOV DH,ROW MOV DL,48 CALL Q20CURS ;Установить курсор MOV AH,09 LEA DX,NAMEDSP ;Выдать имя на экран INT 21H CMP ROW,20 ;Последняя строка экрана? JAE E20 ; нет - INC ROW ; увеличить строку, JMP E90 E20: MOV AX,0601H ; да - CALL Q10SCR ; прокрутить и MOV DH,ROW ; установить курсор MOV DL,00 CALL Q20CURS E90: RET E10RGHT ENDP ; Очистить область имени: ; ---------------------- F10CLNM PROC CLD MOV AX,2020H MOV CX,15 ;Очистить 15 слов LEA DI,NAMEDSP REP STOSW RET F10CLNM ENDP ; Прокрутка экрана: ; ---------------- Q10SCR PROC ;AX установлен при вызове MOV BH,30 ;Цвет ( 07 для ч/б) MOV CX,00 MOV DX,184FH INT 10H RET Q10SCR ENDP ; Установить курсор (строка/столбец): ; ---------------------------------- Q20CURS PROC ;DX установлен при вызове MOV AH,02 SUB BH,BH


Ассемблер для IBM PC. Программы. 39
INT 10H RET Q20CURS ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 84
TITLE EXDWMUL - Умножение двойных слов CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; --------------------------------------------- MULTCND DW 3206H ;Элементы данных DW 2521H MULTPLR DW 6400H DW 0A26H PRODUCT DW 0 DW 0 DW 0 DW 0 ; --------------------------------------------- MAIN PROC NEAR ;Основная процедура CALL E10XMUL ;Вызвать 1-е умножение CALL Z10ZERO ;Очистить произведение CALL F10XMUL ;Вызвать 2-е умножение RET MAIN ENDP ; Умножение двойного слова на слово: ; ----------------------------------------------- E10XMUL PROC MOV AX,MULTCND+2 ;Умножить правое слова MUL MULTPLR ; множимого MOV PRODUCT+4,AX ;Записать произведение MOV PRODUCT+2,DX
MOV AX,MULTCND ;Умножить левое слово MUL MULTPLR ; множимого ADD PRODUCT+2,AX ;Сложить с полученным ранее ADC PRODUCT,DX RET E10XMUL ENDP ; Перемножение двух двойных слов: ; -------------------------------------------- F10XMUL PROC MOV AX,MULTCND+2 ;Слово-2 множимого MUL MULTPLR+2 ; * слово-2 множителя MOV PRODUCT+6,AX ;Сохранить результат MOV PRODUCT+4,DX
MOV AX,MULTCND+2 ;Слово-2 множимого MUL MULTPLR ; * слово-1 множителя ADD PRODUCT+4,AX ;Сложить с предыдущим ADC PRODUCT+6,DX ADC PRODUCT,00 ;Прибавить перенос
MOV AX,MULTCND ;Слово-1 множимого MUL MULTPLR+2 ; * слово-2 множителя ADD PRODUCT+4,AX ;Сложить с предыдущим
Ассемблер для IBM PC. Программы. 85
ADC PRODUCT+6,DX ADC PRODUCT,00 ;Прибавить перенос MOV AX,MULTCND ;Слово-1 множимого MUL MULTPLR ; * слово-1 множителя ADD PRODUCT+2,AX ;Сложить с предыдущим ADC PRODUCT,DX RET F10XMUL ENDP ; Очистка области результата: ; ---------------------------------------- Z10XMUL PROC MOV PRODUCT,0000 MOV PRODUCT+2,0000 MOV PRODUCT+4,0000 MOV PRODUCT+6,0000 RET Z10XMUL ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 86
page 60,132 TITLE EXDIV (COM) Пример операций DIV и IDIV CODESG SEGMENT PARA 'Code' ORG 100H BEGIN: JMP SHORT MAIN ; --------------------------------------------- BYTE1 DB 80H ;Data items BYTE2 DB 16H WORD1 DW 2000H WORD2 DW 0010H WORD3 DW 1000H ; --------------------------------------------- MAIN PROC NEAR ;Основная процедура CALL D10DIV ;Вызов подпрограммы DIV CALL E10IDIV ;Вызов подпрограммы IDIV MAIN ENDP ; Примеры с командой DIV: ; --------------------------------------------- D10DIV PROC MOV AX,WORD1 ;Слово / байт DIV BYTE1 ; остаток:частное в AH:AL MOV AL,BYTE1 ;Байт / байт SUB AH,AH ; расширить делимое в AH DIV BYTE3 ; остаток:частное в AH:AL


MOV DX,WORD2 ;Двойное слово / слово MOV AX,WORD3 ; делимое в DX:AX DIV WORD1 ; остаток:частное в DX:AX MOV AX,WORD1 ;Слово / слово SUB DX,DX ; расширить делимое в DX DIV WORD3 ; остаток:частное в DX:AX RET D10DIV ENDP ; Примеры с командой IDIV: ; --------------------------------------------- E10IDIV PROC MOV AX,WORD1 ;Слово / байт IDIV BYTE1 ; остаток:частное в AH:AL MOV AL,BYTE1 ;Байт / байт CBW ; расширить делимое в AH IDIV BYTE3 ; остаток:частное в AH:AL
MOV DX,WORD2 ;Двойное слово / слово MOV AX,WORD3 ; делимое в DX:AX IDIV WORD1 ; остаток:частное в DX:AX MOV AX,WORD1 ;Слово / слово CWD ; расширить делимое в DX IDIV WORD3 ; остаток:частное в DX:AX RET E10DIV ENDP
CODESG ENDS
Ассемблер для IBM PC. Программы. 87
END BEGIN
TITLE ASCADD (COM) Сложение чисел в ASCII-формате CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ----------------------------------------------- ASC1 DB '578' ;Элементы данных ASC2 DB '694' ASC3 DB '0000' ; ----------------------------------------------- MAIN PROC NEAR CLC LEA SI,AASC1+2 ;Адреса ASCII-чисел LEA DI,AASC2+2 LEA BX,AASC1+3 MOV CX,03 ;Выполнить 3 цикла A20: MOV AH,00 ;Очистить регистр AH MOV AL,[SI] ;Загрузить ASCII-байт ADC AL,[DI] ;Сложение (с переносом) AAA ;Коррекция для ASCII MOV [BX],AL ;Сохранение суммы DEC SI DEC DI DEC BX LOOP A20 ;Циклиться 3 раза MOV [BX],AH ;Сохранить перенос RET MAIN ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 88
TITLE ASCMUL (COM) Умножение ASCII-чисел CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN: JMP MAIN ; --------------------------------------------- MULTCND DB '3783' ;Элементы данных MULTPLR DB '5' PRODUCT DB 5 DUP(0) ; --------------------------------------------- MAIN PROC NEAR MOV CX,04 ;4 цикла LEA SI,MULTCND+3 LEA DI,PRODUCT+4 AND MULTPLR,0FH ;Удалить ASCII-тройку A20: MOV AL,[SI] ;Загрузить ASCII-символ ; (можно LODSB) AND AL,OFH ;Удалить ASCII-тройку MUL MULTPLR ;Умножить AAM ;Коррекция для ASCII ADD AL,[DI] ;Сложить с AAA ; записанным MOV [DI],AL ; произведением DEC DI MOV [DI],AH ;Записать перенос DEC SI LOOP A20 ;Циклиться 4 раза RET MAIN ENDP CODESG ENDS END BEGIN


TITLE ASCDIV (COM) Деление ASCII-чисел CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS: CODESG ORG 100H BEGIN: JMP SHORT MAIN ; --------------------------------------------- DIVDND DB '3698' ;Элементы данных DIVSOR DB '4' QUOTNT DB 4 DUP(0) ; --------------------------------------------- MAIN PROC NEAR MOV CX,04 ;4 цикла SUB AH,AH ;Стереть левый байт делимого AND DIVSOR,0FH ;Стереть ASCII 3 в делителе LEA SI,DIVDND LEA DI,QUOTNT A20:
Ассемблер для IBM PC. Программы. 89
MOV AL,[SI] ;Загрузить ASCII байт ; (можно LODSB) AND AL,0FH ;Стереть ASCII тройку AAD ;Коррекция для деления DIV DIVSOR ;Деление MOV [DI],AL ;Сохранить частное INC SI INC DI LOOP A20 ;Циклиться 4 раза RET MAIN ENDP CODEGS ENDS END BEGIN
Ассемблер для IBM PC. Программы. 90
TITLE SCREMP (EXE) Ввод времени и расценки, ;вывод величины оплаты ; ---------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 32 DUP(?) STACKSG ENDS ; ---------------------------------------------------- DATASG SEGMENT PARA 'Data' HRSPAR LABLE BYTE ;Список параметров для ; ввода времени: MAXHLEN DB 6 ;--------------------- ACTHLEN DB ? HRSFLD DB 6 DUP(?)
RATEPAR LABLE BYTE ;Список параметров для ; ввода расценки: MAXRLEN DB 6 ;--------------------- ACTRLEN DB ? RATEFLN DB 6 DUP(?)
MESSG1 DB 'Hours worked? ','$' MESSG2 DB 'Rate of pay? ','$' MESSG3 DB 'Wage = ' ASCWAGE DB 10 DUP(30H), 13, 10, '$' ADJUST DW ? ASCHRS DB 0 ASCRATE DB 0 BINVAL DW 00 BINHRS DW 00 BINRATE DW 00 COL DB 00 DECIND DB 00 MULT10 DW 01 NODEC DW 00 ROW DB 00 SHIFT DW ? TENWD DW 10 DATASG ENDS ; ---------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX MOV AX,0600H CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор A20LOOP:
Ассемблер для IBM PC. Программы. 91
CALL B10INPT ;Ввести время и расценку CMP ACTHLEN,00 ;Завершить работу? JE A30 CALL D10HOUR ;Получить двоичное время CALL E10RATE ;Получить двоичную расценку CALL F10MULT ;Расчитать оплату CALL G10WAGE ;Преобразовать в ASCII CALL K10DISP ;Выдать результат на экран JMP A20LOOP A30: MOV AX,0600H CALL Q10SCR ;Очистить экран RET ;Выйти из программы BEGIN ENDP ; Ввод времени и расценки ; ---------------------------------------------------- B10INPT PROC LEA DX,MESSG1 ;Запрос для ввода времени MOV AH,09 INT 21H LEA DX,HRSPAR ;Ввести время MOV AH,0AH INT 21H CMP ACTHLEN,00 ;Пустой ввод? JNE B20 RET ; да - вернуться A20LOOP B20: MOV COL,25 ;Установить столбец CALL Q20CURS LEA DX,MESSG2 ;Запрос для ввода засценки MOV AH,09 INT 21H LEA DX,RATEPAR ;Ввести расценку MOV AH,0AH INT 21H RET B10INPT ENDP ; Обработка времени: ; ----------------- D10HOUR PROC MOV NODEC,00 MOV CL,ACTHLEN SUB CH,CH LEA SI,HRSFLD-1 ;Установить правую позицию ADD SI,CX ; времени CALL M10ASBI ;Преобразовать в двоичное MOV AX,BINVAL MOV BINHRS,AX RET D10HOUR ENDP ; Обработка расценки: ; ------------------ E10RATE PROC


Ассемблер для IBM PC. Программы. 92
MOV CL,ACTRLEN SUB CH,CH LEA SI,RATEFLD-1 ;Установить правую позицию ADD SI.CX ; расценки CALL M10ASBI ;Преобразовать в двоичное MOV AX,BINVAL MOV BINRATE,AX RET E10RATE ENDP ; Умножение, округление и сдвиг: ; ----------------------------- F10MULT PROC MOV CX,05 LEA DI,ASCWAGE ;Установить формат оплаты MOV AX,3030H ; в код ASCII (30) CLD REP STOSW MOV SHIFT,10 MOV ADJUST,00 MOV CX,NODEC CMP CL,06 ;Если более 6 десятичных JA F40 ; знаков, то ошибка DEC CX DEC CX JLE F30 ;Обойти, если менее 3 знаков MOV NODEC,02 MOV AX,01 F20: MUL TENWD ;Вычислить фактор сдвига LOOP F20 MOV SHIFT,AX SHR AX,1 ;Округлить результат MOV ADJUST,AX F30: MOV AX,BINHRS MUL BINRATE ;Вычислить оплату ADD AX,ADJUST ;Округлить оплату ADC DX,00 CMP DX,SHIFT ;Результат слишком велик JB F50 ; для команды DIV? F40: SUB AX,AX JMP F70 F50: CMP ADJUST,00 ;Сдвиг нее требуется? JZ F80 DIV SHIFT ;Сдвинуть оплату F70: SUB DX,DX ;Стереть остаток F80: RET F10MULT ENDP ; Преобразование в ASCII формат: ; ----------------------------- G10WAGE PROC
Ассемблер для IBM PC. Программы. 93
LEA SI,ASCWAGE+7 ;Установить дес. точку MOV BYTE PTR[SI],'.' ADD SI,NODEC ;Установить правую позицию G30: CMP BYTE PTR[SI],'.' JNE G35 ;Обойти, если дес.поз. DEC SI G35: CMP DX,00 ;Если dx:ax < 10, JNZ G40 CMP AX,0010 ; то операция завершена JB G50 G40: DIV TENWD ;Остаток - ASCII-цифра OR DL,30H MOV [SI],DL ;Записать ASCII символ DEC SI SUB DX,DX ;Стереть остаток JMP G30 G50: OR AL,30H ;Записать последний ASCII MOV [SI],AL ; символ RET G10WAGE ENDP ; Вывод величины оплаты: ; --------------------- K10DISP PROC MOV COL,50 ;Установить столбец CALL Q20CURS MOV CX,09 LEA SI,ASCWAGE K20: ;Стереть лидирующие нули CMP BYTE PTR[SI],30H JNE K30 ; пробелами MOV BYTE PTR[SI],20H INC SI LOOP K20 K30: LEA DX,MESSG3 ;Вывод на экран MOV AH,09 INT 21H CMP ROW,20 ;Последняя строка экрана? JAE K80 INC ROW ; нет - увеличить строку JMP K90 K80: MOV AX,0601H ; да -- CALL Q10SCR ; прокрутить и MOV COL,00 ; установить курсор CALL Q20CURS K90: RET K10DISP ENDP ; Преобразование ASCII-чисел


Ассемблер для IBM PC. Программы. 94
; в двоичное представление: ; -------------------------- M10ASBI PROC MOV MULT10,0001 MOV BINVAL,00 MOV DECIND,00 SUB BX,BX M20: MOV AL,[SI] ;ASCII-символ CMP AL,'.' ;Обойти, если дес.точка JNE M40 MOV DECIND,01 JMP M90 M40: AND AX,000FH MUL MULT10 ;Умножить на фактор ADD BINVAL,AX ;Сложить с дв.значением MOV AX,MULT10 ;Вучислить следующий MUL TENVD ; фактор x 10 MOV MULT10,AX CMP DECIND,00 ;Десятичная точка? JNZ M90 INC BX ; да - обойти точку M90: DEC SI LOOP M20 ;Конец цикла CMP DECIND,00 ;Была дес.точка? JZ M100 ; да -- ADD NODEC,BX ; сложить с итогом M100: RET M10ASBI ENDP ; Прокрутка экрана: ; ---------------- Q10SCR PROC NEAR ;AX установлен при вызове MOV BH,30 ;Цвет (07 для ч/б) SUB CX,CX MOV DX,184FH INT 10H RET Q10SCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 SUB BH,BH MOV DH,ROW MOV DL,COL INT 10H RET Q20CURS ENDP
CODESG ENDS
Ассемблер для IBM PC. Программы. 95
END BEGIN
Ассемблер для IBM PC. Программы. 96
page 60,132 TITLE DIRECT (COM) Прямой табличный доступ CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ------------------------------------------------ THREE DB 3 MONIN DB '11' ALFMON DB '???','$' MONTAB DB 'JAN','FEB','MAR','APR','MAY','JUN' DB 'JUL','AUG','SEP','OKT','NOV','DEC' ; ------------------------------------------------ MAIN PROC NEAR ;Основная процедура CALL C10CONV ;Получить двоичное значение CALL D10LOC ;Выделить месяц из таблицы CALL F10DISP ;Выдать месяц на экран RET MAIN ENDP ; Перевод ASCII в двоичное представление: ; -------------------------------------- C10CONV PROC MOV AH,MONIN ;Загрузить номер месяца MOV AL,MONIN+1 XOR AX,3030H ;Удалить ASCII тройки CMP AH,00 ;Месяц 01-09? JZ C20 ; да - обойти SUB AH,AH ; нет - очистить AH, ADD AL,10 ; и перевести в двоичное C20 RET C10CONV ENDP ; Выделение месяца из таблицы: ; --------------------------- D10LOC PROC LEA SI,MONTAB DEC AL ;Коррекция для таблицы MUL THREE ;Умножить AL на 3 ADD SI,AX MOV CX,03 ;Трехсимвольная пересылка CLD LEA DI,ALFMON REP MOVSB ;Переслать 3 символа RET D10LOC ENDP ; Вывод на экран симв.месяца: ; -------------------------- F10DISP PROC LEA DX,ALFMON MOV AH,09 INT 21H RET F10DISP ENDP


Ассемблер для IBM PC. Программы. 97
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 98
page 60,132 TITLE TABSRCH (COM) Табличный поиск CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ----------------------------------------------- STOKNIN DW '23' STOKTAB DB '05','Excavators' DB '08','Lifters ' DB '09','Presses ' DB '12','Valves ' DB '23','Processors' DB '27','Pumps ' DESCRN 10 DUP(?) ; ----------------------------------------------- MAIN PROC NEAR MOV AX,STOKNIN ;Загрузить номер элемента XCHG AL,AH MOV CX,06 ;Число элементов в таблице LEA SI,STOKTAB ;Начальный адрес таблицы A20: CMP AX,[SI] ;Сравнить элементы JE A30 ;Если равны - выйти, ADD SI,12 ; нет - следующий элемент LOOP A20 CALL R10ERR ;Элемент в таблице не найден RET A30: MOV CX,05 ;Длина описания элемента LEA DI,DESCRN ;Адрес описания элемента INC SI INC SI ;Выделить описание REP MOVSW ; из таблицы RET MAIN ENDP ; R10ERR PROC ; <Вывод сообщения об ошибке>
RET R10ERR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 99
page 60,132 TITLE TABSRCH (COM) Табличный поиск, использующий CMPSB CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ---------------------------------------------------- STOKNIN DW '123' STOKTAB DB '035','Excavators' ;Начало таблицы DB '038','Lifters ' DB '049','Presses ' DB '102','Valves ' DB '123','Processors' DB '127','Pumps ' DB '999', 10 DUP(' ') ;Конец таблицы DESCRN 10 DUP(?) ; ---------------------------------------------------- MAIN PROC NEAR CLD LEA SI,STOKTAB ;Начальный адрес таблицы A20: MOV CX,03 ;Сравнивать по 3 байта LEA DI,STOKNIN ;Адрес искомого элемента REPE CMPSB ;Сравнение JE A30 ;Если равно - выйти, JA A40 ;если больше - нет в таблице ADD SI,CX ;Прибавить CX к адресу JMP A20 ;Следующий элемент таблицы A30: MOV CX,05 ;Пересылать 5 слов LEA DI,DESCRN ;Адрес описания REP MOVSV ;Переслать из таблицы RET A40: CALL R10ERR ;элемент в таблице не найден RET MAIN ENDP


R10ERR PROC ; < Вывод на экран сообщения об ошибке>
RET R10ERR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 100
page 60,132 TITLE XLATE (COM) Перевод кода ASCII в код EBCDIC CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP MAIN ; ---------------------------------------------------- ASCNO DB '-31.5' EBCNO DB 6 DUP(' ') XLTAB DB 45 DUP(40H) DB 60H, 2DH DB 5CH DB 0F0H,0F1H,0F2H,0F3H,0F4H DB 0F5H,0F6H,0F7H,0F8H,0F9H DB 199 DUP(40H) ; ---------------------------------------------------- MAIN PROC NEAR ;Основная процедура LEA SI,ASCNO ;Адрес символов ASCNO LEA DI,EBCNO ;Адрес поля EBCNO MOV CX,06 ;Длина LEA BX,XLTAB ;Адрес таблицы A20: MOV AL,[SI] ;Получить ASCII символ XLAT ;Перекодировка MOV [DI],AL ;Записать в поле EBCNO INC DI INC SI LOOP A20 ;Повторить 6 раз RET MAIN ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 101
page 60,132 TITLE ASCHEX (COM) Преобразование ASCII в шест. CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP MAIN ; ----------------------------------------------- DISPROW DB 16 DUP(' '), 13 HEXSTR DB 00 XLATAB DB 30H,31H,32H,33H,34H,35H,36H,37H,38H,39H DB 41H,42H,43H,44H,45H,46H ; ----------------------------------------------- MAIN PROC NEAR ;Основная процедура CALL Q10CLR ;Очистить экран LEA SI,DISPROW A20LOOP: CALL C10HEX ;Перекодировать CALL D10DISP ; и вывести на экран CMP HEXCTR,0FFH ;Последнее значение (FF)? JE A50 ; да - завершить INC HEXCTR ; нет - перейти к следующему JMP A20LOOP A50: RET MAIN ENDP
C10HEX PROC NEAR ;Перекодировка в шест. MOV AH,00 MOV AL,HEXCTR ;Получить шест.пару SHR AX,CL ;Сдвиг правой шест.цифры LEA BX,XLATAB ;Установить адрес таблицы MOV CL,04 ;Установить величину сдвига XLAT ;Перекодировка в шест. MOV [SI],AL ;Записать левый символ
MOV AL,HEXCTR SHL AX,CL ;Сдвиг левой цифры XLAT MOV [SI]+1,AL ;Перекодировка в шест. RET ;Записать правый символ C10HEX ENDP
D10DISP PROC NEAR ;Вывод на экран MOV AL,HEXCTR MOV [SI]+3,AL CMP AL,1AH ;Символ EOF? JE D20 ; да - обойти CMP AL,07H ;Меньше/равно 08? JB D30 ; да - OK CMP AL,10H ;Больше/равно 0F? JAE D30 ; да - OK D20: MOV BYTE PTR [SI]+3,20H


Ассемблер для IBM PC. Программы. 102
D30: ADD SI,05 ;Следующий элемент в строке LEA DI,DISPROW+80 CMP DI,SI JNE D40 MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер устройства MOV CX,81 ;Вся строка LEA DX,DISPROW INT 21H LEA SI,DISPROW ;Начальный адрес строки D40: RET D10DISP ENDP
Q10CLR PROC NEAR ;Очистка экрана MOV AX,0600H MOV BH,03 ;Цвет (07 для ч/б) MOV CX,0000 MOV DX,184FH INT 10H RET Q10CLR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 103
page 60,132 TITLE NMSORT (EXE) Ввод и сортировка имен ; ----------------------------------------------- STACK SGMENT PARA STACK 'Stack' DW 32 DUP(?) STACK ENDS ; ----------------------------------------------- DATASG SEGMENT PARA 'Data' NAMEPAR LABEL BYTE ;Имя списка параметров: MAXNLEN DB 21 ; макс. длина NAMELEN DB ? ; число введенных символов NAMEFLD DB 21 DUP(' ') ; имя
CRLF DB 13, 10, '$' ENDADDR DW ? MESSG1 DB 'Name?', '$' NAMECTR DB 00 NAMETAB DB 30 DUP(20 DUP(' ')) ;Таблица имен NAMESAV DB 20 DUP(?), 13, 10, '$' SWAPPED DB 00 DATA ENDS ; ----------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATDSG,SS:STACK,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX CLD LEA DI,NAMETAB CALL Q10CLR ;Очистить экран CALL Q20CURS ;Установить курсор A20LOOP: CALL B10READ ;Ввести имя с клавиатуры CMP NAMELEN,00 ;Есть ли еще имена? JZ A30 ; нет - идти на сортировку CMP NAMECTR,30 ;Введено 30 имен? JE A30 ; да - идти на сортировку CALL D10STOR ;Записать имя в таблицу JMP A20LOOP A30: ;Конец ввода имен CALL Q10CLR ;Очистить экран CALL Q20CURS ; и установить курсор CMP NAMECTR,01 ;Введено менее 2 имен? JBE A40 ; да - выйти CALL G10SORT ;Сортировать имена CALL K10DISP ;Вывести результат на экран A40: RET ;Завершить программу BEGIN ENDP
Ассемблер для IBM PC. Программы. 104
; Ввод имен с клавиатуры? ; ---------------------- B10READ PROC MOV AH,09 LEA DX,MESSG1 ;Вывести текст запроса INT 21H MOV AH,0AH LEA DX,NAMEPAR ;Ввести имя INT 21H MOV AH,09 LEA DX,CRLF ;Вывести CRLF INT 21H


MOV BH,00 ; Очистить поле после имени MOV BL,NAMELEN ;Получить счетчик символов MOV CX,21 SUB CX,BX ;Вычислить оставшуюся длину B20: MOV NAMEFLD[BX],20H ;Установить символ пробела INC BX LOOP B20 RET B10READ ENDP ; Запись имени в таблицу: ; ---------------------- D10STOR PROC INC NAMECTR ;Число имен в таблице CLD LES SI,NAMEFLD MOV CX,10 REP MOVSV ;Переслать имя в таблицу RET D10STOR ENDP ; Сортировка имен в таблице: ; ------------------------- G10SORT PROC SUB DI,40 ;Установить адреса останова MOV ENDADDR,DI G20: MOV SWAPPED,00 ;Установить начало LEA SI,NAMETAB ; таблицы G30: MOV CX,20 ;Длина сравнения MOV DI,SI ADD DI,20 ;Следующее имя для сравнения MOV AX,DI MOV BX,SI REPE CMPSB ;Сравнить имя со следующим JBE G40 ; нет перестановки CALL H10XCHG ; перестановка G40: MOV SI,AX CMP SI,ENDADDR ;Конец таблицы?
Ассемблер для IBM PC. Программы. 105
JBE G30 ; нет - продолжить CMP SWAPPED,00 ;Есть перестановки? JNZ G20 ; да - продолжить, RET ; нет - конец сортировки G10SORT ENDP ; Перестановка элементов таблицы: ; ------------------------------ H10XCHG PROC MOV CX,10 LEA DI,NAMESAV MOV SI,BX REP MOVSW ;Сохранить меньший элемент
MOV CX,10 MOV DI,BX REP MOVSW ;Переслать больший элемент ; на место меньшего MOV CX,10 LEA SI,NAMESAV REP MOVSW ;Переслать сохраненный ; элемент на место большего MOV SWAPPED,01 ;Признак перестановки RET H10XCHG ENDP ; Вывод на экран отсортированные имена: ; ------------------------------------ K10DISP PROC LEA SI,NAMETAB K20: LEA DI,NAMESAV ;Начальный адрес таблицы MOV CX,10 REP MOVSV MOV AH,09 LEA DX,NAMESAV INT 21H ;Вывести на экран DEC NAMECTR ;Это последний элемент? JNZ K20 ; нет - повторить цикл, RET ; да - выйти K10DISP ENDP ; Очистка экрана: ; -------------- Q10CLR PROC MOV AX,0600H MOV BH,61H ;Цвет (07 для ч/б) SUB CX,CX MOV DX,184FH INT 10H RET Q10CLR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC MOV AH,02
Ассемблер для IBM PC. Программы. 106
SUB BH,BH SUB DX,DX ;Установить курсор в 00,00 INT 10H RET Q20CURS ENDP
CODESG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 107
page 60,132 TITLE FCBCREAT (EXE) Использование FCB для создания файла ;---------------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 80 DUP(?) STACKSG ENDS ;---------------------------------------------------------- DATASG SEGMENT PARA 'Data' RECLEN EQU 32 NAMEPAR LABEL BYTE ;Список параметров: MAXLEN DB RECLEN ; макс.длина имени NAMELEN DB ? ; число введенных символов NAMEDTA DB RECLEN DUP(' ') ; область передачи (DTA)
FCBREC LABEL BYTE ;FCB для дискового файла FCBDRIV DB 04 ; дисковод D FCBNAME DB 'NAMEFILE' ; имя файла FCBEXT DB 'DAT' ; тип файла FCBBLK DW 0000 ; номер текущего блока FCBRCSZ DW ? ; размер логической записи FCBFLSZ DD ? ; размер файла (DOS) DW ? ; дата (DOS) DT ? ; зарезервировано (DOS) FCBSQRC DB 00 ; номер текущей записи DD ? ; относительный номер
CRLF DB 13,10,'$' ERRCDE DB 00 PROMPT DB 'Name? ','$' ROW DB 01 OPNMSG DB '*** Open error ***', '$' WRTMSG DB '*** Write error ***', '$' DATASG ENDS ; --------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX MOV AX,0600H CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор CALL C10OPEN ;Открыть, установить DTA CMP ERRCDE,00 ;Есть место на диске? JZ A20LOOP ; да - продолжить, RET ; нет - вернуться в DOS A20LOOP: CALL D10PROC
Ассемблер для IBM PC. Программы. 108
CMP NAMELEN,00 ;Конец ввода? JNE A20LOOP ; нет - продолжить, CALL G10CLSE ; да - закрыть файл RET ; и вернуться в DOS BEGIN ENDP ; Открытие дискового файла: ; ------------------------ C10OPEN PROC NEAR MOV AH,16H ;Функция создания файла LEA DX,FCBREC INT 21H CMP AL,00 ;Есть место на диске? JNZ C20 ; нет - ошибка
MOV FCBRCSZ,RECLEN ;Размер записи (EQU) LEA DX,NAMEDTA ;Загрузить адрес DTA MOV AH,1AH INT 21AH RET C20: LEA DX,OPNMSG ;Сообщение об ошибке CALL X10ERR RET C10OPEN ENDP ; Ввод с клавиатуры: ; ----------------- D10PROC PROC NEAR MOV AH,09 ;Функция вывода на экран LEA DX,PROMPT ;Выдать запрос INT 21H


MOV AH,0AH ;Функция ввода LEA DX,NAMEPAR ; Ввести имя файла INT 21H CALL E10DISP ;Прокрутка на экране
CMP NAMELEN,00 ;Имя введено? JNE D20 ; да - продолжить, RET ; нет - выйти D20: MOV BH,00 ;Заменить символ Return MOV BL,NAMELEN MOV NAMEDTA[BX],' ' ;Записать пробел CALL F10WRIT ;Вызвать ; подпрограмму записи CLD LEA DI,NAMEDTA ;Очистить MOV CX,RECLEN / 2 ; поле MOV AX,2020H ; имени REP STOSW RET ;Выйти D10PROC ENDP ; Прокрутка и установка курсора:
Ассемблер для IBM PC. Программы. 109
; ----------------------------- E10DISP PROC NEAR MOV AH,09 ;Функция вывода на экран LEA DX,CRLF ;CR/LF INT 21H ;Вызов DOS CMP ROW,18 ;Последняя строка экрана? JAE E20 ; да - обойти, INC ROW ; нет - увеличить строку RET E20: MOV AX,0601H ;Прокрутка на 1 строку CALL Q10SCR CALL Q20CURS ;Установить курсор RET E10DISP ENDP ; Запись на диск: ; -------------- F10WRIT PROC NEAR MOV AH,15H ;Функция записи LEA DX,FCBREC INT 21H CMP AL,00 ;Запись без ошибок? JZ F20 ; да LEA DX,WRTMSG ; нет - CALL X10ERR ; выдать сообщение MOV NAMELEN,00 F20: RET F10WRIT ENDP ; Закрытие дискового файла: ; ------------------------ G10CLSE PROC NEAR MOV NAMEDTA,1AH ;Установить EOF CALL F10WRIT MOV AH,10H ;Функция закрытия LEA DX,FCBREC INT 21H RET G10CLSE ENDP ; Прокрутка экрана: ; ---------------- Q10SCR PROC NEAR ;AX уже установлен MOV BH,1EH ;Цвет желтый на синем MOV CX,0000 MOV DX,184FH INT 10H ;Прокрутка RET Q10SCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 MOV BH,00 MOV DL,00
Ассемблер для IBM PC. Программы. 110
MOV DH,ROW ;Установить курсор INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке на диске: ; ---------------------------------- X10ERR PROC NEAR MOV AH,09 ;DX содержит INT 21H ; адрес сообщения MOV ERRCDE,01 ;Установить код ошибки RET X10ERR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 111
TITLE FCBREAD (EXE) Чтение записей созданных в CREATDSK ; ------------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 80 DUP(?) STACKSG ENDS ;-------------------------------------------------------- DATASG SEGMENT PARA 'Data' FCBREC LABEL BYTE ;FCB для файла FCBDRIV DB 04 ; дисковод D FCBNAME DB 'NAMEFILE' ; имя файла FCBEXT DB 'DAT' ; тип файла FCBBLK DW 0000 ; номер текущего блока FCBRCSZ DW 0000 ; длина логической записи DD ? ; размер файла (DOS) DW ? ; дата (DOS) DT ? ; зарезервировано (DOS) FCBSQRC DB 00 ; текущий номер записи DD ? ; относительный номер


RECLEN EQU 32 ; Длина записи NAMEFLD DB RECLEN DUP(' '), 13, 10, '$'
ENDCDE DB 00 OPENMSG DB '*** Open error ***', '$' READMSG DB '*** Read error ***', '$' ROW DB 00 DATASG ENDS ;-------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX MOV AX,0600H CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор CALL E10OPEN ;Открыть файл, ; установить DTA CMP ENDCDE,00 ;Открытие без ошибок? JNZ A90 ; нет - завершить A20LOOP: CALL F10READ ;Прочитать запись CMP ENDCDE,00 ;Чтение без ошибок? JNZ A90 ; нет - выйти CALL G10DISP ;Выдать имя на экран JMP A20LOOP ;Продолжить A90: RET ;Завершить BEGIN ENDP
Ассемблер для IBM PC. Программы. 112
; Открытие файла на диске: ; ----------------------- E10OPEN PROC NEAR LEA X,FCBREC MOV AH,0FH ;Функция открытия INT 21H CMP AL,00 ;Файл найден? JNZ E20 ; нет - ошибка
MOV FCBRCSZ,RECLEN ;Длина записи (EQU) MOV AH,1AH LEA DX,NAMEFLD ;Адрес DTA INT 21H RET E20: MOV ENDCDE,01 ;Сообщение об ошибке LEA DX,OPENMSG CALL X10ERROR RET E10OPEN ENDP ; Чтение дисковой записи: ; ---------------------- F10READ PROC NEAR MOV AH,14H ;Функция чтения LEA DX,FCBREC INT 21H CMP NAMEFLD,1AH ;Считан маркер EOF? JNE F20 ; нет MOV ENDCDE,01 ; да JMP F90 F20: CMP AL,00 ;Чтение без ошибок? JZ F90 ; да - выйти MOV ENDCDE,01 ;Нет: CMP AL,01 ;Конец файла? JZ F90 ; да - выйти, LEA DX,READMSG ; нет - значит CALL X10ERR ; ошибка чтения F90: RET F10READ ENDP ; Вывод записи на экран: ; --------------------- G10DISP PROC NEAR MOV AH,09 ;Функция вывода на экран LEA DX,NAMEFLD INT 21H CMP ROW,20 ;Последняя строка экрана? JAE G30 ; нет - INC ROW ; да - увеличить строку JMP G90 G30: MOV AX,0601H
Ассемблер для IBM PC. Программы. 113
CALL Q10SCR ; прокрутить CALL Q20CURS ; установить курсор G90: RET G10DISP ENDP ; Прокрутка (скроллинг) экрана: ; ---------------------------- Q10SCR PROC NEAR ;AX уже установлен MOV BH,1EH ;Установить цвет MOV CX,0000 MOV DX,184FH ;Функция прокрутки INT 10H RET Q1OSCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 MOV BH,00 MOV DH,ROW MOV DL,00 INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке на диске: ; ---------------------------------- X10ERR PROC NEAR MOV AH,09 ;DX содержит адрес INT 21H ; сообщения RET X10ERR ENDP


CODESG ENDS END BEGIN
page 60,132 TITLE RANREAD (COM) Прямое чтение записей, ; созданных в FCBCREAT CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN: JMP MAIN ;----------------------------------------------------- FCBREC LABEL BYTE ;FCB для дискового файла FCBDRIV DB 04 ; дисковод D FCBNAME DB 'MAMEFILE' ; имя файла FCBEXT DB 'DAT' ; тип файла FCBBLK DW 0000 ; номер текущего блока FCBRCSZ DW 0000 ; длина логической записи DD ? ; размер файла (DOS) DW ? ; дата (DOS) DT ? ; зарезервировано (DOS)
Ассемблер для IBM PC. Программы. 114
DB 00 ; номер текущей записи FCBRNRC DD 000000000 ; относительный номер
RECLEN EQU 32 ;Длина записи RECDPAR LABEL BYTE ;Список параметров: MAXLEN DB 3 ; ACTLEN DB ? ; RECDNO DB 3 DUP(' ') ;
NAMEFLD DB RECLEN DUP(' '),13,10,'$' ;DTA
OPENMSG DB '*** Open error ***',13,10,'$' READMSG DB '*** Read error ***',13,10,'$' COL DB 00 PROMPT DB 'Record number? $' ROW DB 00 ENDCDE DB 00 ;----------------------------------------------------- MAIN PROC NEAR CALL Q10CLR ;Очистить экран CALL Q20CURS ;Установить курсор CALL C10OPEN ;Открыть файл, ; установить DTA CMP ENDCDE,00 ;Открытие без ошибок? JZ A20LOOP ; да - продолжить, RET ; нет - завершить A20LOOP: CALL D10RECN ;Получить номер записи CMP ACTLEN,00 ;Есть запрос? JE A40 ; нет - выйти CALL F10READ ;Чтение (прямой доступ) CMP ENDCDE,00 ;Есть ошибки чтения? JNZ A30 ; да - обойти CALL G10DISP ;Вывести на экран A30: JMP A20LOOP A40: RET ;Завершить программу MAIN ENDP ; Подпрограмма открытия файла на диске: ; ------------------------------------ C10OPEN PROC NEAR MOV AH,0FH ;Функция открытия LEA DX,FCBREC INT 21H CMP AL,00 ;Открытие нормальное? JNZ C20 ; нет - ошибка MOV FCBRCSZ,RECLEN ;Длина записи (EQU) MOV AH,1AH LEA DX,NAMEFLD ;Установить адрес DTA INT 21H RET C20: LEA DX,OPENMSG
Ассемблер для IBM PC. Программы. 115
CALL X10ERR RET C10OPEN ENDP ; Ввод с клавиатуры номера записи: ; ------------------------------- D10RECN PROC NEAR MOV AH,09H ;Функция вывода на экран LEA DX,PROMPT INT 21H MOV AH,0AH ;Функция ввода с клавиатуры LEA DX,RECDPAR INT 21H CMP ACTLEN,01 ;Проверить длину (0,1,2) JB D40 ;Длина 0, завершить JA D20 SUB AH,AH ;Длина 1 MOV AL,RECDNO JMP D30 D20: MOV AH,RECDNO ;Длина 2 MOV AL,RECDNO+1 D30: AND AX,0F0FH ;Удалить ASCII тройки AAD Преобразовать в двоичное MOV WORD PTR FCBRNRC,AX D40: MOV COL,20 CALL Q20CURS ;Установить курсор RET D10RECN ENDP ; Чтение дисковой записи: ; ---------------------- F10READ PROC NEAR MOV ENDCDE,00 ;Очистить код завершения MOV AH,21H ;Функция прямого чтения LEA DX,FCBREC INT 21H CMP AL,00 ;Чтение без ошибок? JZ F20 ; да - выйти LEA DX,READMSG ; нет - выдать CALL X10ERR ; сообщение об ошибке F20: RET F10READ ENDP ; Вывод имени на экран: ; -------------------- G10DISP PROC NEAR MOV AH,09 ;Функция вывода на экран LEA DX,NAMEFLD INC 21H INC ROW MOV COL,00 RET G10DISP ENDP


Ассемблер для IBM PC. Программы. 116
; Очистка экрана: ; -------------- Q10CLR PROC NEAR MOV AX,0600H ;Функция прокрутки MOV BH,41H ;Цвет (07 для ч/б) MOV CX,0000 MOV DX,184FH INT 10H RET Q10CLR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 ;Функция установки MOV BH,00 ; курсора MOV DH,ROW MOV DL,COL INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке на диске: ; ---------------------------------- X10ERR PROC NEAR MOV AH,09 ;DX содержит адрес INT 21H ; сообщения INC ROW MOV ENDCDE,01 RET X10ERR ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 117
TITLE RANBLOK (COM) Прямое блочное чтение файла CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN: JMP MAIN ;---------------------------------------------------- FCBREC LABEL BYTE ;FCB для дискового файла FCBDRIV DB 04 ; дисковод D FCBNAME DB 'NAMEFILE' ; имя файла FCBEXT DB 'DAT' ; тип файла FCBBLK DW 0000 ; номер текущего блока FCBRCSZ DW 0000 ; логическая длина записи FCBFLZ DD ? ; DOS размер файла DW ? ; DOS дата DT ? ; DOS зарезервировано DB 00 ; номер текущей записи FCBRNRC DD 00000000 ; относительный номер
DSKRECS DB 1024 DUP(?),'$' ;DTA для блока записей
ENDCODE DB 00 NORECS DW 25 ;Число записей OPENMSG DB '*** Open error ***',13,10,'$' READMSG DB '*** Open error ***',13,10,'$' ROWCTR DB 00 ; --------------------------------------------------- MAIN PROC NEAR CALL Q10CLR ;Очистить экран CALL Q20CURS ;Установить курсор CALL E10OPEN ;Открыть файл, ; установить DTA CMP ENDCODE,00 ;Успешное открытие? JNZ A30 ; нет - выйти CALL F10READ ;Читать записи CALL G10DISP ;Вывод блока на экран A30: RET ;Завершить программу MAIN ENDP ; Открыть дисковый файл: ; --------------------- E10OPEN PROC NEAR MOV AH,0FH ;Функция открытия файла LEA DX,FCBREC INT 21H CMP AL,00 ;Успешное открытие? JNZ A30 ; нет - ошибка
MOV FCBRCSZ,0020H ;Размер записи MOV AH,1AH LEA DX,DSKRECS ;Установить адрес DTA INT 21H RET E20:
Ассемблер для IBM PC. Программы. 118
LEA DX,OPENMSG ;Ошибка открытия файла CALL X10ERR RET E10OPEN ENDP ; Чтение блока: ; ------------ F10READ PROC NEAR MOV AH,27H ;Прямое чтение блока MOV CX,NORECS ;Число записей LEA DX,FCBREC INT 21H MOV ENDCODE,AL ;Сохранить код возврата RET F10READ ENDP ; Вывод блока на экран: ; -------------------- G10DISP PROC NEAR MOV AH,09 ;Функция вывода на экран LEA DX,DSKRECS INT 21H RET G10DISP ENDP ; Подпрограмма очистки экрана: Q10CLR PROC NEAR MOV AX,0600H ;Функция скрол MOV BH,41H ;Цвет (07 для ч/б) MOV CX,0000 MOV DX,184FH INT 10H RET Q10CLR ENDP ; Подпрограмма установки курсора: ; ------------------------------ Q20CURS PROC NEAR MOV AH,02 ;Функция установки курсора MOV BH,00 MOV DH,ROWCTR MOV DL,00 INT 10H INC ROWCTR RET Q20CURS ENDP ; Подпрограмма сообщения об ошибке диска: ; -------------------------------------- X10ERR PROC NEAR MOV AH,09 ;DX содержит адрес INT 21H ; сообщения MOV ENDCODE,01 RET X10ERR ENDP


CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 119
TITLE SELDEL (COM) Выборочное удаление файлов ; Предполагается текущий дисковод; ; Примеры параметров: *.*, *.BAK, и т.д. CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG ORG 100H BEGIN JMP MAIN ; ---------------------------------------------------------- TAB EQU 09 LF EQU 10 CR EQU 13 CRLF DB CR,LF,'$' DELMSG DB TAB,'Erase','$' ENDMSG DB CR,LF,'No more directory entries',CR,LF,'$' ERRMSG DB 'Write protected disk','$' PROMPT DB 'y = Erase, N = Keep, Ret = Exit',CR,LF,'$' ; ---------------------------------------------------------- MAIN PROC NEAR ;Главная процедура MOV AH,11H ;Найти первый элемент CALL D10DISK CMP AL,0FFH ;Если нет элементов, JE A90 ; то выйти LEA DX,PROMPT ;Текст запроса CALL B10DISP A20: LEA DX,DELMSG ;Выдать сообщение CALL B10DISP ; об удалении файла MOV CX,11 ;11 символов MOV SI,81H ;Начало имени файла A30: MOV DL,[SI] ;Текущий символ CALL C10CHAR ; для вывода на экран INC SI ;Следующий символ LOOP A30 MOV DL,'?' CALL C10CHAR MOV AH,01 ;Получить односимвольный INT 21H ; ответ CMP AL,ODH ;Символ Return? JE A90 ; да - выйти OR AL,00100000B ;Перекодировать ; в прописную букву CMP AL,'y' ;Запрошено удаление? JNE A50 ; нет - обойти, MOV AH,13H ; да - удалить файл MOV DX,80H INT 21H CMP AL,0 ;Успешное удаление? JZ A50 ; да - обойти LEA DX,ERRMSG ; нет - выдать CALL B10DISP ; предупреждение JMP A90
Ассемблер для IBM PC. Программы. 120
A50: LEA DX,CRLF ;Перевести строку на экране CALL B10DISP MOV AH,12H CALL B10DISK ;Получить следующий элемент CMP AL,0FFH ;Есть еще? JNE A20 ; да - повторить A90: RET ;Выход в DOS MAIN ENDP ; Вывод строки на экран; ; --------------------- B10DISP PROC NEAR ;в DX находится адрес MOV AH,09 ; строки INT 21H RET B10DISP ENDP ; Вывод символа на экран; ; ---------------------- C10CHAR PROC NEAR ;в DL находится символ MOV AH,02 INT 21H RET C10CHAR ENDP ; Чтение элемента каталога: ; ------------------------ D10DISK PROC NEAR MOV DX,5CH ;Установить FCB INT 21H CMP AL,0FFH ;Есть еще элементы? JNE D90 PUSH AX ;Сохранить AL LEA DX,ENDMSG CALL B10DISP POP AX ;Восстановить AL D90: RET D10DISK ENDP


CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 121
page 60,132 TTILE HANCREAT (EXE) Создание файла на диске ; ----------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 80 DUP(?) STACKSG ENDS ; ----------------------------------------------------- DATASG SEGMENT PARA 'Data' NAMEPAR LABEL BYTE ;Список параметров: MAXLEN DB 30 ; NAMELEN DB ? ; NAMEREC DB 30 DUP(' '), 0DH, 0AH ; введенное имя, ; CR/LF для записи ERRCDE DB 00 HANDLE DW ? PATHNAM DB 'D:\NAMEFILE.DAT',0 PROMPT DB 'Name? ' ROW DB 01 OPNMSG DB '*** Open error ***', 0DH, 0AH WRTMSG DB '*** Write error ***', 0DH, 0AH DATASG ENDS ; ------------------------------------------------------- CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX MOV AX,0600H CALL Q10SCR ;Очистка экрана CALL Q20CURS ;Установка курсора CALL C10CREA ;Создание файла, ; установка DTA CMP ERRCDE,00 ;Ошибка при создании? JZ A20LOOP ; да - продолжить, RET ; нет - вернуться в DOS A20LOOP: CALL D10PROC CMP NAMELEN,00 ;Конец ввода? JNE A20LOOP ; нет - продолжить, CALL G10CLSE ; да - закрыть файл RET ; и выйти в DOS BEGIN ENDP ; Создание файла на диске: ; ----------------------- C10CREA PROC NEAR MOV AH,3CH ;Функция создания файла MOV CX,00 ;Нормальный атрибут LEA CX,PATHNAM
Ассемблер для IBM PC. Программы. 122
INT 21H JC C20 ;Есть ошибка? MOV HANDLE,AX ; нет - запомнить номер, RET C20: ; да - LEA DX,OPNMSG ; выдать сообщение CALL X10ERR ; об ошибке RET C10CREA ENDP ; Ввод с клавиатуры: ; ----------------- D10PROC PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер (Handle) MOV CX,06 ;Длина текста запроса LEA DX,PROMPT ;Выдать запрос INT 21H
MOV AH,0AH ;Функция ввода с клавиатуры LEA DX,NAMEPAR ;Список параметров INT 21H CMP NAMELEN,00 ;Имя введено? JNE D20 ; да - обойти RET ; нет - выйти D20: MOV AL,20H ;Пробел для заполнения SUB CH,CH MOV CL,NAMELEN ;Длина LEA DI,NAMEREC ; ADD DI,CX ;Адрес + длина NEG CX ;Вычислить ADD CX,30 ; оставшуюся длину REP STOSB ;Заполнить пробелом D90: CALL F10WRIT ;Запись на диск CALL E10SCRL ;Проверка на скролинг RET D10PROC ENDP ; Проверка на скролинг: ; -------------------- E10SCRL PROC NEAR CMP ROW,18 ;Последняя строка экрана JAE E10 ; да - обойти, INC ROW ; нет - увеличить строку JMP E10 E10: MOV AX,0601H ;Продвинуть на одну строку CALL Q10SCR E90: CALL Q20CURS ;Установка курсора RET E10SCRL ENDP ; Запись на диск: ; --------------


Ассемблер для IBM PC. Программы. 123
F10WRIT PROC NEAR MOV AH,40H ;Функция записи на диск MOV BX,HANDLE MOV CX,32 ;30 для имени + 2 для CR/LF LEA DX,NAMEREC INT 21H JNC F20 ;Ошибка записи? LEA DX,WRTMSG ; да - CALL X10ERR ; выдать предупреждение MOV NAMELEN,00 F20: RET F10WRIT ENDP ; Закрытие файла на диске: ; ----------------------- G10CLSE PROC NEAR MOV NAMEREC,1AH ;Маркер конца записи (EOF) CALL F10WRIT MOV AH,3EH ;Функция закрытия MOV BX,HANDLE INT 21H RET G10CLSE ENDP ; Прокрутка (скроллинг) экрана: ; ---------------------------- Q10SCR PROC NEAR ;в AX - адрес элемента MOV BH,1EH ;Цвет - желтый на синем MOV CX,0000 MOV DX,184FH INT 10H ;Скроллинг RET Q10SCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 MOV BH,00 MOV DH,ROW ;Установить курсор MOV DL,00 INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке: ; ------------------------- X10ERR PROC NEAR ;DX содержит MOV AH,40H ; адрес сообщения MOV BX,01 MOV CX,21 ;Длина сообщения INT 21H MOV ERRCDE,01 ;Установить код ошибки RET X10ERR ENDP
Ассемблер для IBM PC. Программы. 124
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 125
page 60,132 TITLE HANREAD (EXE) Чтение записей, созданных в HANCREAT ; ----------------------------------------------------- STACKSG SEGMENT PARA STACK 'Stack' DW 80 DUP(?) STACKSG ENDS ; ----------------------------------------------------- DATASG SEGMENT PARA 'Data' ENDCDE DB 00 HANDLE DW ? IOAREA DB 32 DUP(' ') PATHNAM DB 'D:\NAMEFILE.SRT',0 OPENMSG DB '*** Open error ***', 0DH, 0AH READMSG DB '*** Read error ***', 0DH, 0AH ROW DB 00 DATASG ENDS ; ------------------------------------------------------ CODESG SEGMENT PARA 'Code' BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG PUSH DS SUB AX,AX PUSH AX MOV AX,DATASG MOV DS,AX MOV ES,AX MOV AX,0600H CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор CALL E100PEN ;Открыть файл, ; ; установить DTA CMP ENDCDE,00 ;Ошибка открытия? JNZ A90 ; да - завершить программу A20LOOP: CALL F10READ ;Чтение записи с диска CMP ENDCDE,00 ;Ошибка чтения? JNZ A90 ; да - выйти, CALL G10DISP ; нет - выдать имя, JMP A20LOOP ; и продолжить A90: RET BEGIN ENDP ; Открытие файла: ; -------------- E100PEN PROC NEAR MOV AH,3DH ;Функция открытия MOV CX,00 ;Нормальные атрибуты LEA DX,PATHNAM INT 21H JC E20 ;Ошибка открытия? MOV HANDLE,AX ; нет - сохранить RET ; файловый номер E20:


Ассемблер для IBM PC. Программы. 126
MOV ENDCDE,01 ; да - выдать LEA DX,OPENMSG ; сообщение об ошибке CALL X10ERR RET E100PEN ENDP ; Чтение дисковой записи: ; ---------------------- F10READ PROC NEAR MOV AX,3FH ;Функция чтения MOV BX,HANDLE MOV CX,32 ;30 для имени, 2 для CR/LF LEA DX,IOAREA INT 21H JC F20 ;Ошибка при чтении? CMP AX,00 ;Конец файла? JE F30 CMP IOAREA,1AH ;Маркер конца файла (EOF)? JE F30 ; да - выйти RET F20: LEA DX,READMSG ; нет - выдать CALL X10ERR ; сообщение об ошибке F30: MOV ENDCDE,01 ;Код завершения F90: RET F10READ ENDP ; Вывод имени на экран: ; -------------------- G10DISP PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Установить номер MOV CX,32 ; и длину LEA DX,IOAREA INT 21H CMP ROW,20 ;Последняя строка экрана? JEA G90 ; да - обойти INC ROW RET G90: MOV AX,0601H CALL Q10SCR ;Прокрутка (скроллинг) CALL Q20CURS ;Установить курсор RET G10DISP ENDP ; Прокрутка (скроллинг) экрана: ; ---------------------------- Q10SCR PROC NEAR ;в AX - адрес элемента MOV BH,1EH ;Установить цвет MOV CX,0000 MOV DXX,184FH ;Функция прокрутки INT 10H RET Q10SCR ENDP
Ассемблер для IBM PC. Программы. 127
; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 ;Функция установки курсора MOV BH,00 ; курсор MOV DH,ROW ; строка MOV DL,00 ; столбец INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке: ; ------------------------- X10ERR PROC NEAR MOV AH,40H ;в DX - адрес сообщения MOV BX,01 ;Номер MOV CX,20 ;Длина сообщения INT 21H RET X10ERR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 128
page 60,132 TITLE ASCREAD (COM) Чтение ASCII файла CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN: JMP MAIN ; ------------------------------------------------- SECTOR DB 512 DUP(' ') ;Область ввода DISAREA DB 120 DUP(' ') ;Область вывода на экран ENDCDE DW 00 HANDLE DW 0 OPENMSG DB '*** Open error ***' PATHNAM DB 'D:\HANREAD.ASM', 0 ROW DB 00 ; ------------------------------------------------- MAIN PROC NEAR ;Основная программя MOV AX,0600H CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор CALL E10OPEN ;Открыть файл, ; установить DTA CMP ENDCDE,00 ;Ошибка при открытии? JNE A90 ; да - выйти, A20LOOP: ; нет - продолжить CALL R10READ ;Чтение первого сектора CMP ENDCDE,00 ;Конец файла, нет данных? JE A90 ; да - выйти CALL G10XPER ;Выдать на экран A90: RET ;Завершить программу MAIN ENDP ; Открыть файл на диске: ; --------------------- E10OPEN PROC NEAR MOV AH,3DH ;Функция открытия MOV AL,00 ;Только чтение LEA DX,PATHNAM INT 21H JNC E20 ;Проверить флаг CF CALL X10ERR ; ошибка, если установлен RET E20: MOV HANDLE,AX ;Запомниить номер файла RET E10OPEN ENDP ; Построчный вывод данных на экран: ; -------------------------------- G10XPER PROC NEAR CLD ;Направление слева-направо LEA SI,SECTOR G20: LEA DI,DISAREA G30:


Ассемблер для IBM PC. Программы. 129
LEA DX,SECTOR+512 CMP SI,DX ;Конец сектора? JNE G40 ; нет - обойти, CALL R10READ ; да - читать следующий CMP ENDCDE,00 ;Конец файла? JE G80 ; да - выйти LEA SI,SECTOR G40: LEA DX,DISAREA+80 CMP DI,DX ;Конец DISAREA? JB G50 ; нет - обойти, MOV [DI],0D0AH ; да - установить CR/LF CALL H10DISP ; и выдать на экран LEA DI,DISAREA G50: LODSB ;Загрузить [SI] в AL ; и увеличить SI STOSB ;Записать AL в [DI] ; и увеличить DI CMP AL,1AH ;Конец файла? JE G80 ; да - выйти CMP AL,0AH ;Конец строки? JNE G30 ; нет - повторить цикл, CALL H10DISP ; да - вывести на экран JMP G20 G80: CALL H10DISP ;Вывести последнюю строку G90: RET G10XPER ENDP ; Вывод строки на экран: ; --------------------- H10DISP PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер (Handle) LEA CX,DISAREA ;Вычислить NEG CX ; длину ADD CX,DI ; строки LEA DX,DISAREA INT 21H CMP ROW,22 ;Последняя строка экрана? JAE H20 ; нет - выйти INC ROW JMP H90 H20: MOV AX,0601H ;Прокрутка (скроллинг) CALL Q10SCR CALL Q20CURS H90: RET H10DISP ENDP ; Чтени дискового сектора: ; ----------------------- R10READ PROC NEAR MOV AH,3FH ;Функция чтения
Ассемблер для IBM PC. Программы. 130
MOV BX,HANDLE ;Устройство MOV CX,512 ;Длина LEA DX,SECTOR ;Буфер INT 21H MOV ENDCDE,AX RET R10READ ENDP ; Прокрутка (скроллинг) экрана: ; ---------------------------- Q10SCR PROC NEAR ;в AX адрес элемента MOV BH,1EH ;Установить цвет MOV CX,0000 ;Прокрутка MOV DX,184FH INT 10H RET Q10SCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 ;Функция MOV BH,00 ; установки курсора MOV DH,ROW MOV DL,00 INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке на диске: ; ---------------------------------- X10ERR PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер устройства MOV CX,18 ;Длина LEA DX,OPENMSG INT 21H MOV ENDCDE,O1 ;Индикатор ошибки RET X10ERR ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 131
TITLE GETPATH (COM) Получить текущий каталог CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ----------------------------------------------- PATHNAM DB 65 DUP(' ') ;Имя текущего пути доступа ; ----------------------------------------------- MAIN PROC NEAR MOV AH,19H ;Определить текущий диск INT 21H ADD AL,41H ;Заменить шест.номер MOV DL,AL ; на букву: 0=A, 1=B ... CAL B10DISP ;Выдать номер дисковода, MOV DL,':' CAL B10DISP ; двоеточие, MOV DL,'\' CAL B10DISP ; обратную косую


MOV AH,47H ;Получить текущий каталог MOV DL,00 LEA SI, PATHNAM INT 21H A10LOOP: CMP BYTE PTR [SI],0 ;Конец имени пути доступа JE A20 ; да - выйти MOV AL,[SI] ;Выдать на экран MOV DL,AL ; имя пути доступа CALL B10DISP ; побайтно INC SI JMP A10LOOP A20: RET ;Выход в DOS MAIN ENDP
B10DISP PROC NEAR MOV AH,02 ;в DL - адрес элемента INT 21H ;Функция вывода на экран RET B10DISP ENDP
CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 132
TITLE BIOREAD (COM) Чтение дискового сектора через BIOS CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN JMP MAIN ; --------------------------------------------------------- RECDIN DB 512 DUP(' ') ;Область ввода ENDCDE DB 00 CURADR DW 0304H ;Начало (дорожка/сектор) ENDADR DW 0501H ;Конец (дорожка/сектор) READMSG DB '*** Read error ***$' SIDE DB 00 ; --------------------------------------------------------- MAIN PROC NEAR MOV AX,0600H ;Функция прокрутки экрана A20LOOP: CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор CALL C10ADDR ;Определить адрес на диске MOV CX,CURADR MOV DX,ENDADR CMP CX,DX ;Последний сектор? JE A90 ; да - выйти CALL F10READ ;Получить дисковую запись CMP ENDCDE,00 ;Ошибка чтения? JNZ A90 ; да - выйти CALL G10DISP ;Вывести сектор на экран JMP A20LOOP ;Повторить A90 RET ;Завершить программу MAIN ENDP ; Вычислить следующий адрес на диске: ; ---------------------------------- C10ADDR PROC NEAR MOV CX,CURADR ;Последняя дорожка/сектор CMP CL,10 ;Последний сектор? JNE C90 ; нет - выйти CMP SIDE,00 ;Обойти, если сторона = 0 JE C20 INC CH ;Увеличить номер дорожки C20: XOR SIDE,01 ;Сменить сторону MOV CL,01 ;Установить сектор = 1 MOV CURADR,CX C90: RET C10ADDR ENDP ; Чтение дискового сектора: ; ------------------------ F10READ PROC NEAR MOV AL,01 ;Число секторов MOV AH,02 ;Функция чтения LEA BX,RECDIN ;Адрес буфера MOV CX,CURADR ;Дорожка/сектор
Ассемблер для IBM PC. Программы. 133
MOV DH,SIDE ;Сторона MOV DL,01 ;Дисковод B INT 13H ;Выполнить ввод CMP AH,00 ;Ошибка чтения? JZ F90 ; нет - выйти MOV ENDCDE,01 ; да: CALL X10ERR ; ошибка чтения F90: INC CURADR ;Увеличить номер сектора RET F10READ ENDP ; Вывод сектора на экран: ; ---------------------- G10DISP PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер устройства MOV CX,512 ;Длина LEA DX,RECDIN INT 21H RET G10DISP ENDP ; Очистка экрана: ; -------------- Q10SCR PROC NEAR MOV AX,0600H ;Полный экран MOV BH,1EH ;Установить цвет MOV CX,0000 ;Функция прокрутки MOV DX,184FH INT 10H RET Q10SCR ENDP ; Установка курсора: ; ----------------- Q20CURS PROC NEAR MOV AH,02 ;Функция установки MOV BH,00 ; курсора MOV DX,0000 INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке на диске: ; ---------------------------------- X10ERR PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BH,01 ;Номер устройства MOV CX,18 ;Длина сообщения LEA DX,READMSG INT 21H RET X10ERR ENDP CODESG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 134
TITLE PRTNAME (COM) Ввод и печать имен CODESG SEGMENT PARA PUBLIC 'CODE' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN: JMP SHORT MAIN ; ----------------------------------------------------- NAMEPAR LABEL BYTE ;Список параметров MAXNLEN DB 20 ; максимальная длина имени NAMELEN DB ? ; длина введенного имени NAMEFLD DB 20 DUP(' ') ; введенное имя ;Строка заголовка: HEADG DB 'List of Employee Names Page ' PAGECTR DB '01',0AH,0AH FFEED DB 0CH ;Перевод страницы LFEED DB 0AH ;Перевод строки LINECTR DB 01 PROMPT DB 'Name? ' ; ----------------------------------------------------- MAIN PROC NEAR CALL Q10CLR ;Очистить экран CALL M10PAGE ;Установка номера страницы A2LOOP: MOV DX,0000 ;Установить курсор в 00,00 CALL Q20CURS CALL D10INPT ;Ввести имя CALL Q10CLR CMP NAMELEN,00 ;Имя введено? JE A30 ; если нет - выйти, CALL E10PRNT ; если да - подготовить ; печать JMP A20LOOP A30: MOV CX,01 ;Конец работы: LEA DX,FFEED ; один символ CALL P10OUT ; для прогона страницы, RET ; возврат в DOS MAIN ENDP ; Ввод имени с клавиатуры: ; ----------------------- D10INPT PROC NEAR MOV AH,40H ;Функция MOV BX,01 ; вывода на экран MOV CX,05 ; 5 символов LEA DX,PROMPT INT 21H ;Вызов DOS MOV AH,0AH ;Функция ввода с клавиатуры LEA DX,NAMEPAR INT 21H ;Вызов DOS RET D10INPT ENDP ; Подготовка для печати: ; ----------------------
Ассемблер для IBM PC. Программы. 135
E10PRNT PROC NEAR CMP LINECTR,60 ;Конец страницы? JB E20 ; нет - обойти CALL M10PAGE ; да - печатать заголовок E20: MOV CH,00 MOV CL,NAMELEN ;Число символов в имени LEA DX,NAMEFLD ;Адрес имени CALL P10OUT ;Печатать имя MOV CX,01 ;Один LEA DX,LFEED ; перевод строки CALL P10OUT INC LINECTR ;Увеличить счетчик строк E10PRNT ENDP ; Подпрограмма печати заголовка: ; ----------------------------- M10PAGE PROC NEAR CMP WORD PTR PAGECTR,3130H ;Первая страница? JE M30 ; да - обойти MOV CX,01 ; LEA DX,FFEED ; нет -- CALL P10OUT ; перевести страницу, MOV LINECTR,03 ; установить счетчик строк M30: MOV CX,36 ;Длина заголовка LEA DX,HEADG ;Адрес заголовка M40: CALL P10OUT INC PAGECTR+1 ;Увеличить счетчик страниц CMP PAGECTR+1,3AH ;Номер страницы = шест.xx3A? JNE M50 ; нет - обойти, MOV PAGECTR+1,30H ; да - перевести в ASCII INC PAGECTR M50: RET M10PAGE ENDP ; Подпрограмма печати: ; ------------------- P10OUT PROC NEAR ;CX и DX установлены MOV AH,40H ;Функция печати MOV BX,04 ;Номер устройства INT 21H ;Вызов DOS RET P10OUT ENDP ; Очистка экрана: ; -------------- Q10CLR PROC NEAR MOV AX,0600H ;Функция прокрутки MOV BH,60H ;Цвет (07 для ч/б) MOV CX,0000 ;От 00,00 MOV DX,184FH ; до 24,79 INT 10H ;Вызов BIOS RET Q10CLR ENDP ; Установка курсора (строка/столбец):


Ассемблер для IBM PC. Программы. 136
; ---------------------------------- Q20CURS PROC NEAR ;DX уже установлен MOV AH,02 ;Функция установки курсора MOV BH,00 ;Страница Э 0 INT 10H ;Вызов BIOS RET Q20CURS ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 137
TITLE PRINASK (COM) Чтение и печать дисковых записей CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG ORG 100H BEGIN JMP MAIN ; --------------------------------------------------------- PATHPAR LABEL BYTE ;Список параметров для MAXLEN DB 32 ; ввода NAMELEN DB ? ; имени файла FILENAM DB 32 DUP(' ') SECTOR DB 512 DUP(' ') ;Область ввода для файла DISAREA DB 120 DUP(' ') ;Область вывода COUNT DW 00 ENDCDE DW 00 FFEED DB 0CH HANDLE DW 0 OPENMSG DB '*** Open error ***' PROMPT DB 'Name of file? ' ; ---------------------------------------------------------- MAIN PROC NEAR ;Основная программа CALL Q10SCR ;Очистить экран CALL Q20CURS ;Установить курсор A10LOOP: MOV ENDCDE,00 ;Начальная установка CALL C10PRMP ;Получить имя файла CMP NAMELEN,00 ;Есть запрос? JE A90 ; нет - выйти CALL E10OPEN ;Открыть файл, ; установить DTA CMP ENDCDE,00 ;Ошибка при открытии? JNE A80 ; да - повторить запрос CALL R10READ ;Прочитать первый сектор CMP ENDCDE,00 ;Конец файла, нет данных? JE A80 ; да - повторить запрос CALL G10XPER ;Распечатать сектор A80: JMP A10LOOP A90: RET MAIN ENDP ; Подпрограмма запроса имени файла: ; -------------------------------- C10PRMP PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 MOV CX,13 LEA DX,PROMPT INT 21H MOV AH,0AH ;Функция ввода с клавиатуры LEA DX,PATHPAR INT 21H MOV BL,NAMELEN ;Записать MOV BH,00 ; 00 в конец
Ассемблер для IBM PC. Программы. 138
MOV FILENAM[BX],0 ; имени файла C90 RET C10PRMP ENDP ; Открытие дискового файла: ; ------------------------ E10OPEN PROC NEAR MOV AH,3DH ;Функция открытия MOV AL,00 ;Только чтение LEA DX,FILENAM INT 21H JNC E20 ;Проверить флаг CF CALL X10ERR ; ошибка, если установлен RET E20: MOV HANDLE,AX ;Сохранить номер файла MOV AX,2020H MOV CX,256 ;Очистить пробелами REP STOSW ; область сектора RET E100PEN ENDP ; Подготовка и печать данных: ; -------------------------- G10XFER PROC NEAR CLD ;Направление слева-направо LEA SI,SECTOR ;Начальная установка G20: LEA DI,DISAREA MOV COUNT,00 G30: LEA DX,SECTOR+512 CMP SI,DX ;Конец сектора? JNE G40 CALL R10READ ; да - читать следующий CMP ENDCDE,00 ;Конец файла? JE G80 ; да - выйти LEA SI,SECTOR G40: MOV BX,COUNT CMP BX,80 ;Конец области вывода? JB G50 ; нет - обойти MOV [DI+BX],0D0AH ; да - записать CR/LF CALL P10PRNT LEA DI,DISAREA ;Начало области вывода G50: LODSB ;Записать [SI] в AL, ; увеличить SI MOV BX,COUNT MOV [DI+BX],AL ;Записать символ INC BX CMP AL,1AH ;Конец файла? JE G80 ; да - выйти CMP AL,0AH ;Конец строки? JNE G60 ; нет - обойти,


Ассемблер для IBM PC. Программы. 139
CALL P10PRNT ; да - печатать JMP G20 G60: CMP AL,09H ;Символ табуляции? JNE G70 DEC BX ; да - установить BX: MOV BYTE PTR [DI+BX],20H ;Заменит TAB на пробел AND BX,0FFF8H ;Обнулить правые 8 бит ADD BX,08 ; и прибавить 8 G70: MOV COUNT,BX JMP G30 G80: MOV BX,COUNT ;Конец файла MOV BYTE PTR [DI+BX],0CH ;Прогон страницы CALL P10PRNT ;Печатать последнюю строку G90: RET G10XFER ENDP ; Подпрограммы печати: ; ------------------- P10PRNT PROC NEAR MOV AH,40H ;Функция печати MOV BX,04 MOV CX,COUNT ;Длина INC CX LEA DX,DISAREA INT 21H MOV AX,2020H ;Очистить область вывода MOV CX,60 LEA DI,DISAREA REP STOSW RET P10PRNT ENDP ; Подпрограмма чтения сектора: ; --------------------------- R10READ PROC NEAR MOV AH,3FH ;Функция чтения MOV BX,HANDLE ;Номер файла MOV CX,512 ;Длина MOV DX,SECTOR ;Буфер INT 21H MOV ENDCDE,AX RET R10READ ENDP ; Прокрутка экрана: ; ---------------- Q10SCR PROC NEAR MOV AX,0600H MOV BH,1EH ;Установить цвет MOV CX,0000 ;Прокрутка (сскроллинг) MOV DX,184FH INT 10H RET Q10SCR ENDP
Ассемблер для IBM PC. Программы. 140
; Подпрограмма установки курсора: ; ------------------------------ Q20CURS PROC NEAR MOV AH,02 ;Функция установки MOV BH,00 ; курсора MOV DX,00 INT 10H RET Q20CURS ENDP ; Вывод сообщения об ошибке: ; ------------------------- X10ERR PROC NEAR MOV AH,40H ;Функция вывода на экран MOV BX,01 ;Номер MOV CX,18 ;Длина LEA DX,OPENMSG ;Адрес сообщения INT 1H MOV NDCDE,01 ;Признак ошибки RET X10ERR ENDP CODESG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 141
TITLE MACRO1 (EXE) Макрос для инициализации ; -------------------------------------------- INIT1 MACRO ASSUME CS:CSEG,DS:DSEG,SS:STACK,ES:DSEG PUSH DS SUB AX,AX PUSH AX MOV AX,DSEG MOV DS,AX MOV ES,AX ENDM ;Конец макрокоманды ; -------------------------------------------- 0000 STACK SEGMENT PARA STACK 'Stack' 0000 20 [ ???? ] DW 32 DUP(?) 0040 STACK ENDS ; -------------------------------------------- 0000 DSEG SEGMENT PARA 'Data' 0000 54 65 73 74 20 6F MESSGE DB 'Test of macro-instruction', 13 66 20 6D 61 63 72 6F 2D 69 6E 73 74 72 65 73 74 69 6F 6E 0D 001A DSEG ENDS ; -------------------------------------------- 0000 CSEG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR INIT1 ;Макрокоманда 0000 1E + PUSH DS 0001 2B C0 + SUB AX,AX 0003 50 + PUSH AX 0004 B8 ---- R + MOV AX,DSEG 0007 8E D8 + MOV DS,AX 0009 8E C0 + MOV ES,AX 000B B4 40 MOV AH,40H ;Вывод на экран 000D BB 0001 MOV BX,01 ;Номер 0010 B9 001A MOV CX,26 ;Длина 0013 8D 16 0000 R LEA DX,MESSGE ;Сообщение 0017 CD 21 INT 21H 0019 CB RET 001A BEGIN ENDP 001A CSEG ENDS END BEGIN


Macros: N a m e Length INIT1. . . . . . . . . . . . . . . . 0004
Segments and Groups: N a m e Size Align Combine Class CSEG . . . . . . . . . . . . . . . . 001A PARA NONE 'CODE' DSEG . . . . . . . . . . . . . . . . 001A PARA NONE 'DATA' STACK. . . . . . . . . . . . . . . . 0040 PARA STACK 'STACK'
Ассемблер для IBM PC. Программы. 142
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . . . . F PROC 0000 CSEG Length=001A MESSAGE. . . . . . . . . . . . . . . L BYTE 0000 DSEG
Ассемблер для IBM PC. Программы. 143
TITLE MACRO2 (EXE) Использование параметров ; ------------------------------------------------ INIT2 MACRO CSNAME,DSNAME,SSNAME ASSUME CS:CSNAME,DS:DSNAME,SS:SSNAME,ES:DSNAME PUSH DS SUB AX,AX PUSH AX MOV AX,DSNAME MOV DS,AX MOV ES,AX ENDM ;Конец макрокоманды ; ------------------------------------------------ 0000 STACK SEGMENT PARA STACK 'Stack' 0000 20 [ ???? ] DW 32 DUP(?) 0040 STACK ENDS ; ------------------------------------------------ 0000 DSEG SEGMENT PARA 'Data' 0000 54 65 73 74 20 6F MESSAGE DB 'Test of macro', '$' 66 20 6D 61 63 72 6F 24 000E DSEG ENDS ; ------------------------------------------------ 0000 CSEG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR INIT2 CSEG,DSEG,STACK 0000 1E + PUSH DS 0001 2B C0 + SUB AX,AX 0003 50 + PUSH AX 0004 B8 ---- R + MOV AX,DSEG 0007 8E D8 + MOV DS,AX 0009 8E C0 + MOV ES,AX 000B B4 09 MOV AH,09 ;Вывод на экран 000D 8D 16 0000 R LEA DX,MESSGE ;Сообщение 0011 CD 21 INT 21H 0013 CB RET 0014 BEGIN ENDP 0014 CSEG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 144
TITLE MACRO3 (EXE) Директивы .LALL и .SALL ; ------------------------------------------------ INIT2 MACRO CSNAME,DSNAME,SSNAME ASSUME CS:CSNAME,DS:DSNAME,SS:SSNAME,ES:DSNAME PUSH DS SUB AX,AX PUSH AX MOV AX,DSNAME MOV DS,AX MOV ES,AX ENDM ; ------------------------------------------------ PROMPT MACRO MESSAGE ; Макрокоманда выводит на экран любые сообщения ;; Генерирует команды вызова DOS MOV AH,09 ;Вывод на экран LEA DX,MESSAGE INT 21H ENDM ; ------------------------------------------------ 0000 STACK SEGMENT PARA STACK 'Stack' 0000 20 [ ???? ] DW 32 DUP (?) 0040 STACK ENDS ; ------------------------------------------------ 0000 DATA SEGMENT PARA 'Data' 0000 43 75 73 74 6F 6D MESSG1 DB 'Customer name?', '$' 65 72 20 6E 61 6D 65 3F 24 000F 43 75 73 74 6F 6D MESSG2 DB 'Customer address?', '$' 65 72 20 61 64 64 72 65 73 73 3F 24 0021 DATA ENDS ; ------------------------------------------------ 0000 CSEG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR .SALL INIT2 CSEG,DATA,STACK PROMPT MESSG1 .LALL PROMPT MESSG2 + ; Макрокоманда выводит на экран любые сообщения 0013 B4 09 + MOV AH,09 ;Вывод на экран 0015 8D 16 000F R + LEA DX,MESSG2 0019 CD 21 + INT 21H 001B CB RET 001C BEGIN ENDP 001C CSEG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 145
TITLE MACRO4 (COM) Использование директивы LOCAL ; ------------------------------------------------- DIVIDE MACRO DIVIDEND,DIVISOR,QUOTIENT LOCAL COMP LOCAL OUT ; AX=делимое, BX=делитель, CX=частное MOV AX,DIVIDEND ;Загрузить делимое MOV BX,DIVISOR ;Загрузить делитель SUB CX,CX ;Регистр для частного COMP: CMP AX,BX ;Делимое < делителя? JB OUT ; да - выйти SUB AX,BX ;Делимое - делитель INC CX ;Частное + 1 JMP COMP OUT: MOV QUOTIENT,CX ;Записать результат ENDM ; ------------------------------------------------ 0000 CSEG SEGMENT PARA 'Code' ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG 0100 ORG 100H 0100 EB 06 BEGIN: JMP SHORT MAIN ; ------------------------------------------------ 0102 0096 DIVDND DW 150 ;Делимое 0104 001B DIVSOR DW 27 ;Делитель 0106 ???? QUOTNT DW ? ;Частное ; ------------------------------------------------ 0108 MAIN PROC NEAR .LALL DIVIDE DIVDND,DIVSOR,QUOTNT + ; AX=делимое, BX=делитель, CX=частное 0108 A1 0102 R + MOV AX,DIVDND ;Загрузить делимое 010B 8B 1E 0104 R + MOV BX,DIVSOR ;Загрузить делитель 010F 2B C9 + SUB CX,CX ;Регистр для частного 0111 + ??0000: 0111 3B C3 + CMP AX,BX ;Делимое < делителя? 0113 72 05 + JB ??0001 ; да - выйти 0115 2B C3 + SUB AX,BX ;Делимое - делитель 0117 41 + INC CX ;Частное + 1 0118 EB F7 + JMP ??0000 011A + ??0001: 011A 89 0E 0106 R + MOV QUOTNT,CX ;Записать результат 011E C3 RET 011F MAIN ENDP 011F CSEG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 146
TITLE MACRO5 (EXE) Проверка директивы INCLUDE EDIF ; ------------------------------------------------ 0000 STACK SEGMENT PARA STACK 'Stack' 0000 20 [????] DW 32 DUP(?) 0040 STACK ENDS ; ------------------------------------------------ 0000 DATA SEGMENT PARA 'Data' 0000 54 65 73 74 20 6F MESSGE DB 'Test of macro','$' 66 20 6D 61 63 72 6F 24 000E DATA ENDS ; ------------------------------------------------ 0000 CSEG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR INIT CSEG,DATA,STACK 0000 1E + PUSH DS 0001 3B C0 + SUB AX,AX 0003 50 + PUSH AX 0004 B8 ---- R + MOV AX,DATA 0007 8E D8 + MOV DS,AX 0009 8E C0 + MOV ES,AX PROMPT MESSGE 000B B4 09 + MOV AH,09 ;Вывод на экран 000D 8D 16 0000 R + LEA DX,MESSGE 0011 CD 21 + INT 21H 0013 CB RET 0014 BEGIN ENDP 0014 CSEG ENDS END BEGIN


Ассемблер для IBM PC. Программы. 147
TITLE MACRO6 (COM) Проверка дирктив IF и IFNDEF ; ------------------------------------------------ DIVIDE MACRO DIVIDEND,DIVISOR,QUOTIENT LOCAL COMP LOCAL OUT CNTR = 0 ; AX-делимое, BX-делитель, CX-частное IFNDEF DIVIDEND ; Делитель не определен CNTR = CNTR +1 ENDIF IFNDEF DIVISOR ; Делимое не определено CNTR = CNTR +1 ENDIF IFNDEF QUOTIENT ; Частное не определено CNTR = CNTR +1 ENDIF IF CNTR ; Макрорасширение отменено EXITM ENDIF MOV AX,DIVIDEND ;Загрузка делимого MOV BX,DIVISOR ;Загрузка делителя SUB CX,CX ;Регистр для частного COMP: CMP AX,BX ;Делимое < делителя? JB OUT ; да - выйти SUB AX,BX ;Делимое - делитель INC CX ;Частное + 1 JMP COMP OUT: MOV QUOTIENT,CX ;Запись результата ENDM ; ------------------------------------------------ 0000 CSEG SEGMENT PARA 'Code' ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG 0100 ORG 100H 0100 EB 06 BEGIN: JMP SHORT MAIN ; ------------------------------------------------ 0102 0096 DIVDND DW 150 0104 001B DIVSOR DW 27 0106 ???? QUOTNT DW ? ; ------------------------------------------------ 0108 MAIN PROC NEAR .LALL DIVIDE DIVDND,DIVSOR,QUOTNT = 0000 + CNTR = 0 + ; AX-делимое, BX-делитель, CX-частное + ENDIF + ENDIF
Ассемблер для IBM PC. Программы. 148
+ ENDIF + ENDIF 0108 A1 0102 R + MOV AX,DIVDND ;Загрузка делимого 0108 8B 1E 0104 R + MOV BX,DIVSOR ;Загрузка делителя 010F 2B C9 + SUB CX,CX ;Регистр для частного 0111 + ??0000: 0111 3B C3 + CMP AX,BX ;Делимое < делителя? 0113 72 05 + JB ??0001 ; да - выйти 0115 2B C3 + SUB AX,BX ;Делимое - делитель 0117 41 + INC CX 0118 EB F7 + JMP ??0000 011A + ??0001: 011A 89 0E 0106 R + MOV QUOTNT,CX ;Запись результата DIVIDE DIDND,DIVSOR,QUOT = 0000 + CNTR = 0 + ; AX-делимое, BX-делитель, CX-частное + IFNDEF DIDND + ; Делитель не определен = 0001 + CNTR = CNTR +1 + ENDIF + ENDIF + IFNDEF QUOT + ; Частное не определено = 0002 + CNTR = CNTR +1 + ENDIF + IF CNTR + ; Макрорасширение отменено + EXITM 011E C3 RET 011F MAIN ENDP 011F CSEG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 149


TITLE MACRO7 (COM) Проверка директивы IFIDN ; -------------------------------------------- MOVIF MACRO TAG IFIDN <&TAG>,<B>
REP MOVSB EXITM ENDIF IFIDN <&TAG>,<W>
REP MOVSW ELSE ; Не указан параметр B или W, ; по умолчанию принято B REP MOVSB ENDIF ENDM ; -------------------------------------------- 0000 CSIG SEGMENT PARA 'Code' ASSUME CS:CSEG,DS:CSEG,SS:CSEG,ES:CSEG 0100 ORG 100H 0100 EB 00 BEGIN: JMP SHORT MAIN ; ... 0102 MAIN PROC NEAR .LALL MOVIF B + IFIDN <B>,<B>
0102 F3/A4 + REP MOVSB + EXITM MOVIF W + ENDIF + IFIDN <W>, <W>
0104 F3/A5 + REP MOVSW + ENDIF MOVIF + ENDIF + ELSE + ; Не указан параметр B или W, + ; по умолчанию принято B 0106 F3/A4 + REP MOVSB + ENDIF 0108 C3 RET 0109 MAIN ENDP 0109 CSEG ENDS END BEGIN
Ассемблер для IBM PC. Программы. 150
+-----------+ +-----------+ | Основная | | Основная | | программа | | программа | +-----+-----+ +-----+-----+ | | | | +------------+------------+ +------+------+ | | | | | | | | | | +--------+ +--------+ +--------+ +--------+ +--------+ | П/П 1 | | П/П 2 | | П/П 3 | | П/П 1 | | П/П 2 | +---------+ +---------+ +---------+ +----+----+ +---------+ | | +--------+ | П/П 3 | +---------+
Ассемблер для IBM PC. Программы. 151
+---------------------------------------+ | EXTRN SUBPROG:FAR | | MAINPROG: . | | . | | CALL SUBPROG | | . | | . | +---------------------------------------+ | PUBLIC SUBPROG | | SUBPROG: . | | . | | . | | RET | +---------------------------------------+
Ассемблер для IBM PC. Программы. 152
page 60,132 TITLE CALLMULL1 (EXE) Вызов подпрограммы умножения EXTRN SUBMUL:FAR ;----------------------------------------------- 0000 STACKSG SEGMENT PARA STACK 'Stack' 0000 40 [ ???? ] DW 64 DUP(?) 0080 STACKSG ENDS ;----------------------------------------------- 0000 DATASG SEGMENT PARA 'Data' 0000 0140 QTY DW 0140H 0002 2500 PRICE DW 2500H 0004 DATASG ENDS ;----------------------------------------------- 0000 CODESG SEGMENT PARA 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG 0000 1E PUSH DS 0001 2B C0 SUB AX,AX 0003 50 PUSH AX 0004 B8 ---- R MOV AX,DATASG 0007 8E D8 MOV DS,AX 0009 A1 0002 R MOV AX,PRICE ;Загрузить стоимость 000C 8B 1E 0000 R MOV BX,QTY ; и количество 0010 9A 0000 ---- E CALL SUBMUL ;Вызвать подпрограмму 0015 CB RET 0016 BEGIN ENDP 0016 CODESG ENDS END BEGIN


Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0016 PARA NONE 'CODE' DATASG . . . . . . . . . . . . 0004 PARA NONE 'DATA' STACKSG. . . . . . . . . . . . 0080 PARA STACK 'STACK'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0016 PRICE. . . . . . . . . . . . . L WORD 0002 DATASG QTY. . . . . . . . . . . . . . L WORD 0000 DATASG SUBMUL . . . . . . . . . . . . L FAR 0000 External
page 60,132 TITLE SUBMUL Подпрограмма для умножения ;----------------------------------------------- 0000 CODESG SEGMENT PARA 'Code' 0000 SUBMUL PROC FAR ASSUME CS:CODESG PUBLIC SUBMUL 0000 F7 E3 MUL BX ;AX-стоимость, BX-количество 0002 CB RET ;Произведение в DX:AX
Ассемблер для IBM PC. Программы. 153
0003 SUBMUL ENDP 0003 CODESG ENDS END SUBMUL
Segments and groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0003 PARA NONE 'CODE'
Symbols: N a m e Type Value Attr SUBMUL . . . . . . . . . . . . F PROC 0000 CODESG Clobal Length=0003
LINK IBM Personal Computer Linker Version 2.30 (C) Copyright IBM Corp 1981, 1985 Object Modules: B:CALLMUL1+B:SUBMUL1 Run File: [B:CALLMUL1.EXE]: <return>
List File:[NUL.MAP]: CON Libraries [.LIB]: <return>
Start Stop Length Name Class
00000H 00015H 0016H CODESG CODE <--Примечание: 2 кодовых 00020H 00022H 0003H CODESG CODE <-- сегмента 00030H 00033H 0004H DATASG DATA 00040H 000BFH 0080H STACKSG STACK
Program entry point at 0000:0000
Ассемблер для IBM PC. Программы. 154
page 60,132 TITLE CALLMUL2 (EXE) Вызов подпрограммы умножения EXTERN SUBMUL:FAR ;---------------------------------------------- 0000 STACKSG SEGMENT PARA STACK 'Stack' 0000 40 [????] DW 64 DUP(?) 0080 STACKSG ENDS ;---------------------------------------------- 0000 DATASG SEGMENT PARA 'Data' 0000 0140 QTY DW 0140H 0002 2500 PRICE DW 2500H 0004 DATASG ENDS ;---------------------------------------------- 0000 CODESG SEGMENT PARA PUBLIC 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG 0000 1E PUSH DS 0001 2B C0 SUB AX,AX 0003 50 PUSH AX 0004 B8 ---- R MOV AX,DATASG 0007 8E D8 MOV DS,AX 0009 A1 0002 R MOV AX,PRICE ;Загрузить стоимость 000C 8B 1E 0000 R MOV BX,QTY ; и количество 0010 9A 0000 ---- E CALL SUBMUL ;Вызвать подпрограмму 0015 CB RET 0016 BEGIN ENDP


0016 CODESG ENDS END BEGIN
Segments and Group: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . .0016 PARA PUBLIC 'CODE' DATASG . . . . . . . . . . . . .0004 PARA NONE 'DATA' STACKSG. . . . . . . . . . . . .0080 PARA STACK 'STACK'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Lenght=0016 PRICE. . . . . . . . . . . . . L WORD 0002 DATASG QTY. . . . . . . . . . . . . . L WORD 0000 DATASG SUBMUL . . . . . . . . . . . . L FAR 0000 External
page 60,132 TITLE SUBMUL2 Вызываемая подпрограмма умножения ;---------------------------------------------- 0000 CODESG SEGMENT PARA PUBLIC 'CODE' 0000 SUBMUL PROC FAR ASSUME CS:CODESG PUBLIC SUBMUL 0000 F7 E3 MUL BX ;AX-стоимость, BX-количество
Ассемблер для IBM PC. Программы. 155
0002 CB RET ;Произведение в DX:AX 0003 SUBMUL ENDP 0003 CODESG ENDS END SUBMUL
Segments and Groups: N a m e Size Align Combine Class CODESG. . . . . . . . . . . . . 0003 PARA PUBLIC 'CODE'
Symbols: N a m e Type Value Attr SUBMUL. . . . . . . . . . . . .F PROC 0000 CODESG Global Length=0003
LINK IBM Personal Computer Linker Version 2.30 (C) Copyright IBM Corp 1981, 1985 Object Modules: B:CALLMUL2+B:SUBMUL2 Run File: [B:CALLMUL2.EXE]: <return>
List File: [NUL.MAP]: CON Libraries [.LIB]: <return>
Start Stop Length Name Class 00000H 00022H 0023H CODESG CODE <-- Примечание: 1 сегмент кода 00030H 00033H 0004H DATASG DATA 00040H 000BFH 0080H STACKSG STACK
Program entry point at 0000:0000
Ассемблер для IBM PC. Программы. 156
page 60,132 TITLE CALLMUL3 (EXE) Вызов подпрограммы ; для умножения EXTRN SUBMUL:FAR PUBLIC QTY,PRICE ;------------------------------------------------- 0000 STACKSG SEGMENT PARA STACK 'Stack' 0000 40 [????] DW 64 DUP(?) 0080 STACKSD ENDS ;------------------------------------------------- 0000 DATASG SEGMENT PARA PUBLIC 'Data' 0000 0140 QTY DW 0140H 0002 2500 PRICE DW 2500H 0004 DATASG ENDS ;------------------------------------------------- 0000 CODESG SEGMENT PARA PUBLIC 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG 0000 1E PUSH DS 0001 2B C0 SUB AX,AX 0003 50 PUSH AX 0004 B8 ---- R MOV AX,DATASG 0007 8E D8 MOV DS,AX 0009 9A 0000 ---- E CALL SUBMUL ;Вызвать подпрограмму 000E CB RET 000F BEGIN ENDP


000F CODESG ENDS END BEGIN
Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 000F PARA PUBLIC 'CODE' DATASG . . . . . . . . . . . . 0004 PARA PUBLIC 'DATA' STACKSG. . . . . . . . . . . . 0080 PARA STACK 'STACK'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=000F PRICE. . . . . . . . . . . . . L WORD 0002 DATASG Global QTY. . . . . . . . . . . . . . L WORD 0000 DATASG Global SUBMUL . . . . . . . . . . . . L FAR 0000 External
page 60,132 TITLE SUBMUL Подпрограмма для умножения EXTRN QTY:WORD,PRICE:WORD ;------------------------------------------------- 0000 CODESG SEGMENT PARA PUBLIC 'CODE' 0000 SUBMUL PROC FAR ASSUME CS:CODESG PUBLIC SUBMUL
Ассемблер для IBM PC. Программы. 157
0000 A1 0000 E MOV AX,PRICE 0003 8B 1E 0000 E MOV BX,QTY 0007 F7 E3 MUL BX ;Произведение в DX:AX 0009 CB RET 000A SUBMUL ENDP 000A CODESG ENDS END SUBMUL
Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 000A PARA PUBLIC 'CODE'
Symbols: N a m e Type Value Attr PRICE. . . . . . . . . . . . . V WORD 0000 External QTY. . . . . . . . . . . . . . V WORD 0000 External SUBMUL . . . . . . . . . . . . F PROC 0000 CODESG Global Length=000A
LINK IBM Personal Computer Linker Version 2.30 (C) Copyright IBM Corp 1981, 1985 Object Modules: B:CALLMUL3+B:SUBMUL3 Run File: [B:CALLMUL3.EXE]: <return>
List File: [NUL.MAP]: CON Libraries [.LIB]: <return>
Start Stop Length Name Class
00000H 00019H 001AH CODESG CODE 00030H 00033H 0004H DATASG DATA 00040H 000BFH 0080H STACKSG STACK
PROGRAM entry point at 0000:0000
Ассемблер для IBM PC. Программы. 158
page 60,132 TITLE CALLMULL4 (EXE) Передача параметров ; в подпрограмму EXTRN SUBMUL:FAR ;------------------------------------------------- 0000 STACKSG SEGMENT PARA STACK 'Stack' 0000 40 [ ???? ] DW 64 DUP(?) 0080 STACKSG ENDS ;------------------------------------------------- 0000 DATASG SEGMENT PARA 'Data' 0000 0140 QTY DW 0140H 0002 2500 PRICE DW 2500H 0004 DATASG ENDS ;------------------------------------------------- 0000 CODESG SEGMENT PARA PUBLIC 'Code' 0000 BEGIN PROC FAR ASSUME CS:CODESG,DS:DATASG,SS:STACKSG 0000 1E PUSH DS 0001 2B C0 SUB AX,AX 0003 50 PUSH AX 0004 B8 ---- R MOV A,DATASG 0007 8E D8 MOV DS,AX 0009 FF 36 0002 R PUSH PRICE 000D FF 36 0000 R PUSH QTY 0011 9A 0000 ---- E CALL SUBMUL ;Вызвать подпрограмму 0016 CB RET 0017 BEGIN ENDP 0017 CODESG ENDS END BEGIN


Segments and Groups: N a m e Sise Align Combine Class CODESG . . . . . . . . . . . . 0017 PARA NONE 'CODE' DATASG . . . . . . . . . . . . 0004 PARA NONE 'DATA' STACKSG. . . . . . . . . . . . 0080 PARA STACK 'STACK'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . F PROC 0000 CODESG Length=0017 PRICE. . . . . . . . . . . . . L WORD 0002 DATASG QTY. . . . . . . . . . . . . . L WORD 0000 DATASG SUBMUL . . . . . . . . . . . . L FAR 0000 External
page 60,132 TITLE SUBMUL Вызываемая подпрограмма умножения 0000 CODESG SEGMENT PARA PUBLIC 'Code' 0000 SUBMUL PROC FAR ASSUME CS:CODESG PUBLIC SUMBUL 0000 55 PUSH BP 0001 8P EC MOV BP,SP
Ассемблер для IBM PC. Программы. 159
0003 8B 46 08 MOV AX,[BP+8] ;Стоимость 0006 8B 5E 06 MOV BX,[BP+6] ;Количество 0009 F7 E3 MUL BX ;Произведение в DX:AX 000B 5D POP BP 000F SUMBUL ENDP 000F CODESG ENDS END
Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 000F PARA PUBLIC 'CODE'
Symbols: N a m e Type Value Attr SUBMUL . . . . . . . . . . . . F PROC 0000 CODESG Global Length=000F
LINK IBM Personal Computer Linker Version 2.30 (C) Copyright IBM Corp 1981, 1985 Object Modules: B:CALLMUL4+B:SUBMUL4 Run File: [B:CALLMUL4.EXE]: <return>
List File: [NUL.MAP]: CON Libraries [.LIB]: <return>
Start Stop Length Name Class
00000H 00019H 001AH CODESG CODE 00030H 00033H 0004H DATASG DATA 00040H 000BFH 0080H STACKSG STACK
PROGRAM entry point at 0000:0000
Ассемблер для IBM PC. Программы. 160
LOAD"D:BASTEST.BAS
LIST 010 CLEAR ,32768! 020 ' для BLOAD 030 ' для DEFSEG 040 ' для точки входа в CALL 050 ' для вызова ASM-модуля 060 FOR N = 1 TO 5 070 INPUT "Hours "; H 080 INPUT "Rate "; R 090 W = H * R 100 PRINT "Wage = " W 110 NEXT N 120 END
TITLE LINKBAS Ассемблерная подпрограмма, вызываемая из BASIC CODESG SEGMENT PARA 'CODE' ASSUME CS:CODESG CLRSCRN PROC FAR PUSH BP ;Сохранить BP MOV BP,SP ;База списка параметров MOV AX,0600H ;Функция прокрутки MOV BH,07 ; всего MOV CX,0000 ; экрана MOV DX,184FH INT 10H POP BP RET ;Завершить подпрограмму CLRSCRN ENDP CODESG ENDS END


Ассемблер для IBM PC. Программы. 161
D>LINK
IBM Personal Computer Linker Version 2.30 (C) Copyright IBM Corp. 1981, 1985
Object Modules [.OBJ]: LINKBAS Run File [LINKBAS.EXE]: LINKBAS/HIGH List File [NUL.MAP]: CON Libraries [.LIB]: Warning: no stack segment
Start Stop Length Name Class 00000H 00011H 00012H CODESG CODE D>DEBUG BASIC.COM -R AX=0000 BX=0000 CX=0012 DX=0000 SP=FFFF BP=0000 SI=0000 DI=0000 DS=1410 ES=1410 SS=1410 CS=1410 IP=0100 NV UP EI PL NZ NA PO NC 1410:0100 E9E03E JMP 3FE3 -N D:LINKBAS.EXE -L -R AX=FFA3 BX=0000 CX=0012 DX=0000 SP=0000 BP=0000 SI=0000 DI=0000 DS=1410 ES=1410 SS=9FE0 CS=9FE0 IP=0000 NV UP EI PL NZ NA PO NC 9FE0:0000 55 -R SS SS 9FE0 :1410 -R CS CS 9FE0 :1410 -R IP IP 0000 :0100 -G Ok DEF SEG = &H9EF0 Ok BSAVE "D:CLRSCREEN.MOD",0,&H12 Ok SYSTEM Program terminated normally -Q D>BASIC IBM Personal Computer Basic Ver4sion D3.10 Copyright IBM Corp. 1981, 1985 61310 Bytes free Ok LOAD"D:BASTEST.BAS Ok 20 BLOAD "D:CLRSCREEN.MOD" 30 DEF SEG = &H9FE0 40 CLRSCRN = 0
Ассемблер для IBM PC. Программы. 162
50 CALL CLRSCRN LIST
10 CLEAR ,32768! 20 BLOAD "D:CLRSCRN.MOD" 30 DEF SEG = &H9FE0 40 CLRSCRN = 0 50 CALL CLRSCRN 60 FOR N = 1 TO 5 70 INPUT "HOURS"; H 80 INPUT "rATE"; R 90 W = H * R 100 PRINT "WAGE = " W 110 NEXT N 120 END Ok
program pascall ( input, output );
procedure move_cursor( const row: integer; const col: integer ); extern; var temp_row: integer; temp_col: integer;
begin write( 'Enter cursor row: ' ); readln( temp_row );
write( 'Enter cursor column:' ); readln( temp_col );
move_cursor( temprow, temp_col ); write( 'New cursor location' ); end.
TITLE MOVCUR Подпрограмма на ассемблере, ; вызываемая из программы на Паскале PUBLIC MOVE_CURSOR ;---------------------------------------------------------- ; MOVE_CURSOR: Устанавливает курсор ; по переданным параметрам ; Параметры: const row Строка и столбец ; const col для установки курсора ; Возвращаемое значение: Отсутствует ;---------------------------------------------------------- CODESEG SEGMENT PARA PUBLIC 'CODE'


MOVE_CURSOR PROC FAR ASSUME CS:CODESEG
Ассемблер для IBM PC. Программы. 163
ROWWPAR EQU 8 ;Параметр "строка" COLPAR EQU 6 ;Параметр "столбец"
PUSH BP ;Сохранить регистр BP MOV BP,SP ;Установить BP на параметры
MOV SI,[BP+ROWPAR] ;SI указывает на строку MOV DH,[SI] ;Поместить столбец в DL
MOV AH,02 ;Функция установки курсора SUB BH,BH ;Страница #0 INT 10H
POP BP ;Вернуться RET 4 ; в вызывающую программу MOVE_CURSOR ENDP CODESEG ENDS END
Адрес начала Программа
00000 Таблица векторов прерываний (см. гл. 23)
00400 Область связи с постоянной памятью (ROM)
00500 Область связи с операционной системой (DOS)
00600 IBMBIO.COM Буфер каталога Дисковый буфер Блок параметров дисковода/таблица распределения файлов (FAT, одна для каждого дисковода)
XXXX0 Резидентная часть командного процессора COMMAND.COM
XXXX0 Область памяти для программ (типа COM или EXE)
XXXX0 Пользовательский стек для COM-программ (256 байтов)
XXXX0 Транзитная часть командного процессора COMMAND.COM (записывается в старшие адреса памяти).
TITLE EXDOS (EXE) Функция DOS 4BH для выполнения DIR CSEG GMENT PARA 'Code' ASSUME CS:CSEG,DS:CSEG,ES:CSEG BEGIN: JMP SHORT MAIN ;---------------------------------------------------------- PARAREA DW ? ;Адрес строки вызова
Ассемблер для IBM PC. Программы. 164
DW OFFSET DIRCOM ;Указатель ; на командную строку DW CSEG DW OFFSET FCB1 ;Указатель на FCB2 DW CSEG
DIRCOM DB 17,'/C DIR D:',13,0 FCB1 DB 16 DUP(0) FCB2 DB 16 DUP(0) PROGNAM DB 'D:COMMAND.COM',0 ; --------------------------------------------------------- MAIN PROC FAR MOV AH,4AH ;Получить 64K памяти MOV BH,100H ; в параграфах INT 21H JC E10ERR ;Нет памяти?
MOV DI,2CH ;Получить сегментный адрес MOV AX,[DI] ; строки вызова LEA SI,PARAREA ; и записать его в MOV [SI],AX ; 1 слово блока параметров MOV AX,CS ;Загрузить в DS и ES MOV DS,AX ; адрес CSEG MOV ES,AX
MOV AH,4BH ;Функция загрузки MOV AL,00 ; и выполнения LEA BX,PARAREA ; COMMAND.COM LEA DX,PROGNAM INT 21H ;Вызвать DOS JC E20ERR ;Ошибка выполнения? MOV AL,00 ;Нет кода ошибки JMP X10XIT 0ERR: MOV AL,01 ;Код ошибки 1 JMP X10XIT 0ERR: MOV AL,02 ;Код ошибки 2 JMP X10XIT 0XIT: MOV AH,4CH ;Функция завершения INT 21H ;Вызвать DOS IN ENDP EG ENDS END


Адрес Функция прерывания (шест.) (шест.)
0-3 0 Деление на ноль 4-7 1 Пошаговый режим (трассировка для DEBUG)
Ассемблер для IBM PC. Программы. 165
8-B 2 Немаскируемое прерывание (NMI) C-F 3 Точка останова в потоке команд (для DEBUG) 10-13 4 Переполнение регистров АЛУ 14-17 5 Печать экрана 18-1F Зарезервировано 20-23 8 Сигнал от таймера 24-27 9 Сигнал от клавиатуры 28-37 A,B,C,D Используются для AT 38-3B E Сигнал от дисковода 3C-3F F Обслуживание принтера 40-43 10 Управление экраном (см. гл. 8,9,10) 44-47 11 Запрос списка оборудования (см. гл. 9) 48-4B 12 Запрос размера физической памяти (см. гл. 2) 4C-4F 13 Управление дисковым вводом-выводом (гл. 18) 50-53 14 Управление коммуникационным вводом-выводом 54-57 15 Управление магнитофоном и спец.функции для AT 58-5B 16 Управление вводом с клавиатуры (гл. 9) 5C-5F 17 Вывод на принтер (гл. 19) 60-63 18 Обращение к BASIC в ПЗУ (ROM) 64-67 19 Перезагрузка системы 68-6B 1A Запрос и установка времени и даты 6C-6F 1B Получение управления по прерыванию с клавиатуры 70-73 1C Получение управления по прерыванию от таймера 74-77 1D Адрес таблицы параметров инициализации дисплея 78-7B 1E Адрес таблицы параметров дисковода 7C-7F 1F Адрес таблицы графических символов 80-83 20 DOS Нормальное завершение программы 84-87 21 DOS Обращение к функциям DOS 88-8B 22 DOS Адрес подпрограммы обработки завершения 8C-8F 23 DOS Адрес подпрограммы реакции на Ctrl+Break 90-93 24 DOS Вектор подпрограммы реакции на фатальную ошибку 94-97 25 DOS Абсолютное чтение секторов диска 98-9B 26 DOS Абсолютная запись на сектора диска 9C-9F 27 DOS Завершение программы, оставляющее ее резидентом A0-FF 28-3F DOS Операции DOS 100-1FF 40-7F Зарезервировано 200-217 80-85 Зарезервировано для BASIC 218-3C3 86-F0 Используется BASIC-интерпретатором 3C4-3FF F1-FF Зарезервировано
Примечание: прерывания 00-1F для BIOS, 20-FF для DOS и BASIC
TITLE RESIDENT (COM) Резидентная программа для очистки ; экрана и установки цвета при нажатии ; Alt+Left Shift ;----------------------------------------------------------


INTTAB SEGMENT AT 0H ;Таблица векторов прерываний: ORG 9H*4 ; адрес для Int 9H, KBADDR LABEL DWORD ; двойное слово INTTAB ENDS
Ассемблер для IBM PC. Программы. 166
;----------------------------------------------------------
ROMAREA SEGMENT AT 400H ;Область параметров BIOS: ORG 17H ; адрес флага клавиатуры, KBFLAG DB ? ; состояние Alt + Shift ROMAREA ENDS ;----------------------------------------------------------
CSEG SEGMENT PARA ;Сегмент кода ASSUME CS:CS ORG 100H BEGIN: JMP INITZ ;Выполняется только один раз
KBSAVE DD ? ;Для адреса INT 9 BIOS ; Очистка экрана и установка цветов: ; --------------------------------- COLORS PROC NEAR ;Процедура выполняется PUSH AX ; при нажатии Alt+Left Shift PUSH BX PUSH CX ;Сохранить регистры PUSH DX PUSH SI PUSH DI PUSH DS PUSH ES PUSHF CALL KBSAV ;Обработать прерывание ASSUME DS:ROMAREA MOV AX,ROMAREA ;Установить DS для MOV DS,AX ; доступа к состоянию MOV AL,KB AG ; Alt+Left Shift CMP AL,00001010B ;Alt+Left Shift нажаты? JNE EXIT ; нет - выйти MOV AX,0600H ;Функция прокрутки MOV BH,61H ;Установить цвет MOV CX,00 MOV DX,18 FH INT 10H EXIT: POP ES ;Восстановить регистры POP DS POP DI POP SI POP DX POP CX POP BX POP AX IRET ;Вернуться COLORS ENDP
; Подпрограмма инициализации: ; -------------------------- INITZE PROC NEAR ;Выполнять только один раз
Ассемблер для IBM PC. Программы. 167
ASSUME DS:INTTAB PUSH DS ;Обеспечить возврат в DOS MOV AX,INTTAB ;Установить сегмент данных MOV DS,AX CLI ;Запретить прерывания ;Замена адреса обработчика: MOV AX,WORD PTR KBADDR ;Сохранить адрес MOV WORD PTR KBSAVE,AX ; BIOS MOV AX,WORD PTR BADDR+2 MOV WORD PTR KBSAVE+2,AX MOV WORD PTR KBADDR,OFFSET COLORS ;Заменить MOV WORD PTR KBADDR+2,CS ; адрес BIOS STI ;Разрешить прерывания MOV DX,OFFSET INITZE ;Размер программы INT 27H ;Завершить и остаться INITZE ENDP ; резидентом
CSEG ENDS END BEGIN
TITLE SOUND (COM) Процедура для генерации звука SOUNSG SEGMENT PARA 'Code' ASSUME CS:SOUNG,DS:SOUNG,SS:SOUNG ORG 100H BEGIN: JMP SHORT MAIN ; ------------------------------------------------------- DURTION DW 1000 ;Время звучания TONE DW 256H ;Высота (частота) звука ; ------------------------------------------------------- MAIN PROC NEAR IN AL,61H ;Получить и сохранить PUSH AX ; данные порта CLI ;Запретить прерывания CALL B10SPKR ;Произвести звук POP AX ;Восстановить значение OUT 61H,AL ; порта STI ;Разрешить прерывания RET MAIN ENDP


B10SPKR PROC NEAR B20: MOV DX,DURTION ;Установить время звучания B30: AND AL,11111100B ;Очистить биты 0 и 1 OUT 61H,AL ;Передать на динамик MOV CX,TONE ;Установить частоту B40: LOOP B40 ;Задержка времени OR AL,00000010B ;Установить бит 1 OUT 61H,AL ;Передать на динамик MOV CX,TONE ;становить частоту
Ассемблер для IBM PC. Программы. 168
B50: LOOP B50 ;Задержка времени DEC DX ;Уменьшить время звучания JNZ B30 ;Продолжать? SHL DURTION,1 ; нет - увеличить время, SHR TONE,1 ; сократить частоту JNZ B20 ;Нулевая частота? RET ; да - выйти B10SPKR ENDP
SOUNSG ENDS END BEGIN
Ассемблер для IBM PC 98
TITLE RECORD (COM) Проверка директивы RECORD 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H 0100 EB 02 BEGIN: JMP SHORT MAIN ; ----------------------------------------------------- BITREC RECORD BIT1:3,BIT2:7,BIT3:6 ;Определить запись 0102 9A AD DEFBITS BITREC <101B,0110110B,011010B> ;Инициализировать биты ; ----------------------------------------------------- 0104 MAIN PROC NEAR 0104 A10: ;Ширина: 0104 B7 10 MOV BH,WIDTH BITREC ; записи (16) 0106 B0 07 MOV AL,WIDTH BIT2 ; поля (07) 0108 B10: ;Величина сдвига: 0108 B1 0D MOV CL,BIT1 ; шест.0D 010A B1 06 MOV CL,BIT2 ; 06 010C B1 00 MOV CL,BIT3 ; 00 010E C10: ;Маска: 010E B8 E000 MOV AX,MASK BIT1 ; шест.E000 0111 BB 1FC0 MOV BX,MASK BIT2 ; 1FC0 0114 B9 003F MOV CX,MASK BIT3 ; 003F 0117 D10: ;Выделение BIT2: 0117 A1 0102 R MOV AX,DEFBITS ; получить запись, 011A 25 1FC0 AND AX,MASK BIT2 ; очистить BIT1 и BIT3, 011D B1 06 MOV CL,BIT2 ; получить сдвиг 06, 011F D3 E8 SHR AX,CL ; сдвинуть вправо 0121 E10: ;Выделение BIT1: 0121 A1 0102 R MOV AX,DEFBITS ; получить запись, 0124 B1 0D MOV CL,BIT1 ; получить сдвиг 13, 0126 D3 E8 SHR AX,CL ; сдвинуть вправо 0128 C3 RET 0129 MAIN ENDP 0129 CODESG ENDS END BEGIN
Structures and records: N a m e Widht # fields Shift Widht Mask Initial BITREC . . . . . . . . . . . 0010 0003 BIT1 . . . . . . . . . . . . 000D 0003 E000 0000 BIT2 . . . . . . . . . . . . . 0006 0007 1FC0 0000 BIT3 . . . . . . . . . . . . 0000 0006 003F 0000


Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . 0129 PARA NONE 'CODE'
Symbols: N a m e Type Value Attr A10. . . . . . . . . . . . . . L NEAR 0104 CODESG B10. . . . . . . . . . . . . . L NEAR 0108 CODESG
Ассемблер для IBM PC 99
BEGIN. . . . . . . . . . . . . L NEAR 0100 CODESG C10. . . . . . . . . . . . . . L NEAR 010E CODESG D10. . . . . . . . . . . . . . L NEAR 0117 CODESG DEFBITS. . . . . . . . . . . . L WORD 0102 CODESG E10. . . . . . . . . . . . . . L NEAR 0121 CODESG MAIN . . . . . . . . . . . . . N PROC 0104 CODESG Length =0025
Ассемблер для IBM PC 100
TITLE DSTRUC (COM) Определение структуры 0000 CODESG SEGMENT PARA 'Code' ASSUME CS:CODESG,DS:CODESG,SS:CODESG 0100 ORG 100H 0100 EB 29 BEGIN: JMP SHORT MAIN ; --------------------------------------------- PARLIST STRUC ;Список параметров 0000 19 MAXLEN DB 25 ; 0001 ?? ACTLEN DB ? ; 0002 19 [ 20 ] NAMEIN DB 25 DUP(' ') ; 001B PARLIST ENDS ; 0102 19 PARAMS PARLIST <> ;Область структуры 0103 ?? 0104 19 [ 20 ] 011D 57 68 61 74 20 69 PROMPT DB 'What is name?', 'S' 73 20 6E 61 6D 65 3F 24 ; --------------------------------------------- 012B MAIN PROC NEAR 012B B4 09 MOV AH,09 ;Выдать запрос 012D 8D 16 011D R LEA DX,PROMPT 0131 CD 21 INT 21H 0133 B4 0A MOV AH,0AH ;Получить ввод 0135 8D 16 0102 R LEA DX,PARAMS 0139 CD 21 INT 21H 013B A0 0103 R MOV AL,PARAMS.ACTLEN ;Длина ввода ; ... 013E C3 RET 013F MAIN ENDP 013F CODESG ENDS END BEGIN
Structures and records: N a m e Width # fields Shift Width Masc Initial PARLIST. . . . . . . . . . . . . 001B 0003 MAXLEN . . . . . . . . . . . . 0000 ACTLEN . . . . . . . . . . . . 0001 NAMEIN . . . . . . . . . . . . 0002
Segments and Groups: N a m e Size Align Combine Class CODESG . . . . . . . . . . . . . 013F PARA NONE 'CODE'
Symbols: N a m e Type Value Attr BEGIN. . . . . . . . . . . . . L NEAR 0100 CODESG MAIN . . . . . . . . . . . . . N PROC 012B CODESG Length =0014 PARAMS . . . . . . . . . . . . L 001B 0102 CODESG PROMPT . . . . . . . . . . . . L BYTE 011D CODESG


Ассемблер для IBM PC 101
Основные, базовые и индексные регистры: Биты: w = 0 w = 1 000 AL AX 001 CL CX 010 DL DX 011 BL BX 100 AH SP 101 CH BP 110 DH SI 111 BH DI
Биты: Сегментный регистр: 00 ES 01 CS 10 SS 11 DS
r/m mod=00 mod=01 mod=10 mod=1.1 mod=11 w=0 w=1 000 BX+SI BX+SI+disp BX+SI+disp AL AX 001 BX+DI BX+DI+disp BX+DI+disp CL CX 010 BP+SI BP+SI+disp BP+SI+disp DL DX 011 BP+DI BP+DI+disp BP+DI+disp BL BX 100 SI SI+disp SI+disp AH SP 101 DI DI+disp DI+disp CH BP 110 Direct BP+disp BP+disp DH SI 111 BX BX+disp BX+disp BH DI
Ассемблер для IBM PC 102
Таблица A-1 Набор ASCII символов
Дес Шест Симв Дес Шест Симв Дес Шест Симв Дес Шест Симв
000 00h Нуль 032 20h sp 064 40h @ 096 60h ` 001 01h Начало заголовка 033 21h ! 065 41h A 097 61h a 002 02h Начало текста 034 22h " 066 42h B 098 62h b 003 03h Конец текста 035 23h # 067 43h C 099 63h c 004 04h Конец передачи 036 24h $ 068 44h D 100 64h d 005 05h КТМ 037 25h % 069 45h E 101 65h e 006 06h Да 038 26h & 070 46h F 102 66h f 007 07h Звонок 039 27h ' 071 47h G 103 67h g 008 08h Возврат на шаг 040 28h ( 072 48h H 104 68h h 009 09h Гориз.табуляция 041 29h ) 073 49h I 105 69h i 010 0Ah Перевод строки 042 2Ah * 074 4Ah J 106 6Ah j 011 0Bh Верт.табуляция 043 2Bh + 075 4Bh K 107 6Bh k 012 0Ch Перевод страницы 044 2Ch , 076 4Ch L 108 6Ch l 013 0Dh Возврат каретки 045 2Dh - 077 4Dh M 109 6Dh m 014 0Eh Shift out 046 2Eh . 078 4Eh N 110 6Eh n 015 0Fh Shift in 047 2Fh / 079 4Fh O 111 6Fh o 016 10h Data line esc 048 30h 0 080 50h P 112 70h p 017 11h Управление 1 049 31h 1 081 51h Q 113 71h q 018 12h Управление 2 050 32h 2 082 52h R 114 72h r 019 13h Управление 3 051 33h 3 083 53h S 115 73h s 020 14h Управление 4 052 34h 4 084 54h T 116 74h t 021 15h Нет 053 35h 5 085 55h U 117 75h u 022 16h Синхронизация 054 36h 6 086 56h V 118 76h v 023 17h Конец блока 055 37h 7 087 57h W 119 77h w 024 18h Анулирование 056 38h 8 088 58h X 120 78h x 025 19h End of medium 057 39h 9 089 59h Y 121 79h y 026 1Ah Замена 058 3Ah : 090 5Ah Z 122 7Ah z 027 1Bh Escape 059 3Bh ; 091 5Bh [ 123 7Bh { 028 1Ch Раздел.файла 060 3Ch < 092 5Ch \ 124 7Ch | 029 1Dh Раздел.группы 061 3Dh = 093 5Dh 125 7Dh } 030 1Eh Раздел.записи 062 3Eh > 094 5Eh ^ 126 7Eh ~ 031 1Fh Раздел.единицы 063 3Fh ? 095 5Fh _ 127 7Fh Забой


Ассемблер для IBM PC 103
Таблица B-1 Шестнадцатерично-десятичные преобразования +------------+-----------+----------+--------+-------+------+------+-----+ |Ш |Ш |Ш |Ш |Ш |Ш |Ш |Ш | |Е |Е |Е |Е |Е |Е |Е |Е | |С |С |С |С |С |С |С |С | |Т ДЕС |Т ДЕС |Т ДЕС |Т ДЕС |Т ДЕС|Т ДЕС|Т ДЕС|Т ДЕС| +------------+-----------+----------+--------+-------+------+------+-----+ |0 0|0 0|0 0|0 0|0 0|0 0|0 0|0 0| |1 268435456|1 16777216|1 1048576|1 65536|1 4096|1 256|1 16|1 1| |2 536870912|2 33554432|2 2097152|2 131072|2 8192|2 512|2 32|2 2| |3 805306368|3 50331648|3 3145728|3 196608|3 12288|3 768|3 48|3 3| |4 1073741824|4 67108864|4 4194304|4 262144|4 16384|4 1024|4 64|4 4| |5 1342177280|5 83886080|5 5242880|5 327680|5 20480|5 1280|5 80|5 5| |6 1610612736|6 100663296|6 6291456|6 393216|6 24576|6 1536|6 96|6 6| |7 1879048192|7 117440512|7 7340032|7 458752|7 28672|7 1792|7 112|7 7| |8 2147483648|8 134217728|8 8388608|8 524288|8 32768|8 2048|8 128|8 8| |9 2415919104|9 150994944|9 9437184|9 589824|9 36864|9 2304|9 144|9 9| |A 2684354560|A 167772160|A 10485760|A 655360|A 40960|A 2560|A 160|A 10| |B 2952790016|B 184549376|B 11534336|B 720896|B 45056|B 2816|B 176|B 11| |C 3221225472|C 201326592|C 12582912|C 786432|C 49152|C 3072|C 192|C 12| |D 3489660928|D 218103808|D 13631488|D 851968|D 53248|D 3328|D 208|D 13| |E 3758096384|E 234881024|E 14680064|E 917504|E 57344|E 3584|E 224|E 14| |F 4026531840|F 251658240|F 15728640|F 983040|F 61440|F 3840|F 240|F 15| Шест+------------+-----------+----------+--------+-------+------+------+-----+ поз.| 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | +------------+-----------+----------+--------+-------+------+------+-----+
Обращений с начала месяца: 183, Last-modified: Sat, 01 Feb 2003 18:56:38 GMT Оцените этот текст:Не читал10987654321

Питер Абель. Ассемблер и программирование для IBM PC


АССЕМБЛЕР И ПРОГРАММИРОВАНИЕ ДЛЯ IBM PC

ПИТЕР АБЕЛЬ

Технологический институт Британская Колумбия

Ассемблер для IBM PC 2

Содержание ------------------------------------------------------------

Предисловие

1. Введение в семейство персональных компьютеров IBM PC

Введение Биты и байты ASCII код Двойные числа Шеснадцатеричное представление Сегменты Регистры Архитектура персональных компьютеров Основные положения на память Вопросы для самопроверки

2. Выполнение программы

Введение Начало работы Просмотр памяти Пример машинных кодов: непосредственные данные Пример машинных кодов: определенные данные Машинная адресация Пример машинных кодов: определение размера памяти Свойства отладчика Основные положения на память Вопросы для самопроверки

3. Формат языка ассемблера

Введение Комментарии Формат кодирования Псевдокоманды Указатели памяти и регистров Инициализация программы Пример исходной программы Основные положения на память Вопросы для самопроверки

4. Ассемблирование и выполнение программы

Введение Ввод программы Подготовка программы для выполнения Ассемблирование программы Компановка загрузочного модуля Выполнение программы Пример исходной программы

Ассемблер для IBM PC 3

Файл перекрестных ссылок Основные положения на память Вопросы для самопроверки

5. Определение данных

Введение Псевдокоманды определения данных Определение байта (DB) Определение слова (DW) Определение двойного слова (DD) Определение "четверного" слова (DQ) Определение десяти байт (DT) Непосредственные операнды Псевдокоманда (директива) EQU Основные положения на память Вопросы для самопроверки

6. Программные COM-файлы

Введение Различия между EXE- и COM-файлами Пример COM-файла COM-стек Отладка Основные положения на память Вопросы для самопроверки

7. Логика и организация программы

Введение Команда JMP Команда LOOP Флаговый регистр Команды условного перехода Процедуры и вызовы (CALL) Стековый сегмент Программа: команды длинной пересылки Логические команды: AND, OR, XOR, TEST, NOT Программа: изменение нижнего и верхнего регистров Сдвиги и ротация Организация программы Основные положения на память Вопросы для самопроверки


8. Работы с экраном I: Основные возможности

Введение Команда прерывания: INT Установка курсора Очистка экрана Команды экрана и клавиатуры: Базовая DOS Ввод на экран: стандарт DOS

Ассемблер для IBM PC 4

Программа: Ввод набора ASCII символов Ввод с клавиатуры: Базовая DOS Программа: Ввод имен с клавиатуры и вывод на экран Команды экрана и клавиатуры: Расширенная DOS Вывод на экран: Расширенная DOS Ввод с клавиатуры: Расширенная DOS Использование CR, LF, TAB для вывода на экран Основные положения на память Вопросы для самопроверки

9. Работа с экраном II: Расширенные возможности

Введение Байт атрибутов Прерывания BIOS Программа: мигание, видеореверс, скроллинг Расширенные ASCII коды Другие команды ввода/вывода DOS BIOS INT 16H для ввода с клавиатуры Дополнительные функциональные клавиши Основные положения на память Вопросы для самопроверки

10. Работа с экраном III: Цвет и графика

Введение Текстовый (алфавитно-цифровой) режим Графический режим Режим средней разрешающей возможности Программа: Установка цвета и графического режима Основные положения на память Вопросы для самопроверки

11. Обработка строк

Введение Особенности команд обработки строк REP: Префикс повторения строки MOVS: Пересылка строки LODS: Загрузка строки STOS: Сохранение строки CMPS: Сравнение строк SCAS: Сканирование строки Сканирование и замена Альтернативное кодирование Дублирование шаблона (образца) Программа: Выравнивание справа при выводе на экран Основные положения на память Вопросы для самопроверки

12. Арифметика I: Обработка двоичных данных

Введение

Ассемблер для IBM PC 5

Сложение и вычитание Беззнаковые и знаковые данные Умножение Сдвиг регистров DX:AX Деление Преобразование знака Процессоры Intel 8087 и 80287 Основные положения на память Вопросы для самопроверки

13. Арифметика II: Обработка ASCII и BCD данных

Введение ASCII формат Двоично-десятичный формат (BCD) Преобразование ASCII формата в двоичный формат Преобразование двоичного формата в ASCII формат Сдвиг и округление Программа: Расчет зарплаты Основные положения на память Вопросы для самопроверки



14. Обработка таблиц

Введение Определение таблиц Прямой табличный доступ Поиск в таблице Команда перекодировки (трансляции) (XLAT) Программа: Вывод шестнадцатеричных и ASCII кодов Программа: Сортировка элементов таблицы Операторы TYPE, LENGTH и SIZE Основные положения на память Вопросы для самопроверки

15. Дисковая память I: Организация

Введение Объем диска Каталог Таблица распределения файлов (FAT) Основные положения на память Вопросы для самопроверки

16. Дисковая память II: Функции базовой DOS

Введение Управляющий блок файла: FCB Использование FCB для создания дискового файла Программа: FCB для создания дискового файла Последовательное чтение дискового файла Программа: FCB для чтения дискового файла Прямой доступ

Ассемблер для IBM PC 6

Программа: Прямое чтение дискового файла Прямой блочный доступа Программа: Прямое чтение блока Абсолютный дисковый ввод/вывод Другие возможности Программа: Выборочное удаление файлов Основные положения на память Вопросы для самопроверки

17. Дисковая память III: Функции расширенной DOS

Введение Строка ASCIIZ Номер файла и коды возврата по ошибкам Создание дискового файла Программа: Использование номера для чтения файла ASCII файлы Другие функции расширенной DOS Основные положения на память Вопросы для самопроверки

18. Дисковая память IV: Команды ввода/вывода BIOS

Введение Дисковые команды BIOS Байт состояния Программа: Использование BIOS для чтения секторов Основные положения на память Вопросы для самопроверки

19. Печать

Введение Управляющие символы для печати Использование расширенной DOS для печати Программа: Постраничная печать с заголовками Печать ASCII файлов и управление табуляций Печать с использованием базовой DOS Специальные команды принтера Печать с использованием BIOS INT 17H Основные положения на память Вопросы для самопроверки

20. Макрокоманды

Введение Простое макроопределение Использование параметров в макрокомандах Комментарии Использование макро внутри макроопределения Директива LOCAL Подключение библиотеки макроопределений Конкатенация (&)



Ассемблер для IBM PC 7

Повторение: REPT, IRP и IRPC Условные директивы Директива EXITM Макрокоманды, использующие IF и IFNDEF условия Макрокоманды, использующие IFIDN условие Основные положения на память Вопросы для самопроверки

21. Связь между подпрограммами

Введение Межсегментные вызовы Атрибуты EXTRN и PUBLIC Программа: Использование EXTRN и PUBLIC для меток Программа: Использование PUBLIC в кодовом сегменте Программа: Общие данные в подпрограммах Передача параметров Связь Бейсик-интерпритатор - ассемблер Связь Паскаль - ассемблер Связь C - ассемблер Основные положения на память Вопросы для самопроверки

22. Загрузчик программ

Введение COMМAND.COM Префикс программного сегмента Выполнение COM-программы Выполнение EXE-программы Пример EXE-программы Функция загрузки или выполнения программ

23. BIOS и DOS прерывания

Введение Обслуживание прерываний BIOS прерывания DOS прерывания Функции DOS INT 21H Резидентные программы Порты Генерация звука

24. Справочник по директивам ассемблера

Введение Индексная память Команды ассемблера Директивы ассемблера

25. Справочник по командам ассемблера

Ассемблер для IBM PC 8

Введение Обозначение регистров Байт режима адресации Двухбайтовые команды Трехбайтовые команды Четырехбайтовые команды Команды в алфавитном порядке

Приложения

1. ASCII коды 2. Шестнадцатерично-десятичные преобразования 3. Зарезервированные слова 4. Режимы ассемблирования и компановки

Ответы на некоторые вопросы

Индексный указатель

Ассемблер для IBM PC 9

------------------------------------------------------------

Предисловие

Появление микропроцессоров в 60-х годах cвязано с разра боткой интегральных схем (ИС). Интегральные схемы объединяли в себе различные элэктронные компоненты в единый элемент на силиконовом "чипе". Разработчики установили этот крошечный чип в устройство, напоминающие сороконожку и включили его в функционирующие системы. В начале 70-х микрокомпьютеры на процессоре Intel 8008 возвестили о первом поколении микро процессоров. К 1974 году появилось второе поколение микропроцессоров oбщего назначения Intel 8080. Данный успех побудил другие фирмы к производству этих или аналогичных процессоров. В 1978 году фирма Intel выпустила процессор третьего поколения - Intel 8086, который обеспечивал некоторую совмес тимость с 8080 и являлся значительным продвижением вперед в данной области. Для поддержки более простых устройств и обес печения совместимости с устройствами ввода/вывода того времени Intel разработал разновидность процессора 8086 - процессор 8088, который в 1981 году был выбран фирмой iВМ для ее персональных компьютеров. Более развитой версией процессора 8088 является процесcор 80188, а для процессора 8086 - процессоры 80186, 80286 и 80386, которые обеспечили дополнительные возможности и повы cили мощность вычислений. Микропроцессор 80286, установлен ный в компьютерах IBM AT появился в 1984 году. Все эти процессоры имеют отношение к развитой архитектуре процессо ров фирмы Intel и обозначаются как iAPX 86, iAPX 88, iAPX 86, iAPX286 и iAPX386, где APX - Intel Advanced Processor Architecture. Распространение микрокомпьютеров послужило причиной пеpе смотра отношения к языку ассемблера по двум основным причи нам. Во-первых, программы, написанные на языке ассемблера, требуют значительно меньше памяти и времени выполнения. Во-вторых, знание языка ассемблера и результирующего машин ного кода дает понимание архитектуры машины, что вряд ли обеспечивается при работе на языке высокого уровня. Хотя большинство специалистов в области программного обеспечения ведут разработки на языках высокого уровня, таких как Паскаль или С, что проще при написании программ, наиболее мощное и эффективное программное обеспечение полностью или частично написано на языке ассемблера. Языки высокого уровня были разработаны для того, чтобы избежать специальной технической особенности конкретных компьютеров. Язык ассемблера, в свою очередь, разработан для конкретной специфики компьютера или точнее для специфики процессора. Следовательно, для того, чтобы написать програм му на языке ассемблера для конкретного компьютера, следует знать его архитектуру и данная книга содержит весь необходи мый базовый материал. Для работы кроме этого материала и cоответствующих знаний необходимы следующее:



Ассемблер для IBM PC 10

ъ Доступ персональному компьютеру IBM PC или совместимому с ним c оперативной памятью - минимум 64К и одним диско водом. Лучше, но не обязательно, если будет дополни тельная память и второй дисковод или винчестер.

ъ Знакомство с руководством по IBM PC.

ъ Дискета, содержащая транслятор с языка ассемблера, пред почтительно, но не обязательно, последней версии.

ъ Копию операционной системы PC-DOS или MS-DOS, лучше пос ледней версии.

Cледующее является не обязательным для данной темы:

ъ Опыт программирования. Хотя эти знания могут помочь быстрее освоить некоторые идеи программирования, они не обязательны.

ъ Хорошие знания в электронике или схемотехнике. Данная книга дает всю необходимую информацию об архитектуре PC, которая требуется для программирования на языке ассемблера.

Операционные системы

Назначение операционной системы - позволить пользователю yправлять работой на компьютере: вызывать для выполнения конкретные программы, обеспечивать средства для сохранения данных (каталог), иметь доступ к информации на диске. Основной операционной системой для PC и совместимых мо- делей является MS-DOS фирмы Microsoft, известная как PC-DOS для IBM PC. Особенности некоторых версий: 2.0 обеспечивает поддержку твердого диска (винчестера), 3.0 применяется в компьютерах AT, 4.0 обеспечивает работу в многопользователь ском режиме. Рассмотрение профессиональной операционной системы UNIX и ее аналога для PC XENIX выходит за рамки данной книги.

Подход к книге

Данная книга приследует две цели: она является учебником, a так же постоянным справочным пособием для работы. Чтобы наиболее эффективно восполнить затраты на микрокомпьютер и программное обеспечение, необходимо тщательно прорабатывать каждую главу и перечитывать материал, котоpый не сразу ясен. Ключевые моменты находятся в примерах программ, их следует преобразовать в выполнимые модули и выполнить их. Прорабатывайте упражнения, приведенные в конце каждой главы.

Ассемблер для IBM PC 11

Первые восемь глав составляют базовый материал для данной книги и для языка ассемблера. После этих глав можно продолжить с глав 9, 11, 12, 14, 15, 19, 20 или 21. Связанными являются главы с 8 по 10, 12 и 13, с 15 по 18, главы с 22 по 25 cодержат справочный материал. Когда вы завертшите работу с книгой, вы сможете:



- понимать хардвер персонального компьютера; - понимать коды машинного языка и шестнадцатиричный формат; - понимать назначение отдельных шагов при ассемблирова нии, компановке и выполнении; - писать программы на языке ассемблера для управления экраном, арифметических действий, преобразования ASCII кодов в двоичные форматы, табличного поиска и сортиро вки, дисковых операций ввода/вывода; - выполнять трассировку при выполнении программы, как средство отладки; - писать собственные макрокоманды; - компановать вместе отдельные программы.

Изучение языка ассемблера и создание работающих программ - это захватывающий процесс. Затраченное время и усилия несомненно будут вознаграждены.

Признательность автора

Автор благодарен за помощь и сотрудничество всем, кто внес предложения и просматривал рукопись.

Ассемблер для IBM PC 12

Предисловие переводчика

Книга представляет собой учебник по программированию на языке Ассемблера для персональных компьютерах, совместимых с IBM PC, адресованный прежде всего начинающим. Обилие приме ров и исходных текстов программ представляет несомненное достоинство книги, позволяющее начинать практическое программирование уже с первых страниц книги. Профессиональ ные программисты смогут найти в книге много полезной информации. Стиль книги очень живой, простой, не требующий никакой специальной или математической подготовки. Единственное, что необходимо для работы над книгой, - это постоянный доступ к персональному компьютеру. Переводчик в основном придерживался терминологии книг В.М.Брябрина "Программное обеспечение персональных ЭВМ" (1988), С.Писарева, Б.Шура "Программно-аппаратная организа ция компьютера IBM PC" (1987), В.Л.Григорьева "Программиро вание однокристальных микропроцессоров" (1987), а также А.Б.Борковского "Англо-русский словарь по программированию и информатике" (1987). Во многих случаях переводчик придерживался "профессионального диалекта" максимально щадящего технические термины в оригинале. Такой диалект принят во многих коллективах программистов-разработчиков, где чаще всего приходится работать с оригинальной документацией на английском языке, ввиду острейшего дефицита отечественной литературы по данной тематике. Большинство примеров, приведенных в данной книге, проверены на компьютерах совместимых с IBM PC. При переводе без специальных оговорок исправлены мелкие неточности и опечатки оригинала. Текст перевода сформирован и отредактирован в интегриро ванной системе Framework. Автор перевода благодарен всем, кто оказал помощь при вводе рукописи на машинные носители. Особую признательность автор перевода выражает своей жене.

Ассемблер для IBM PC 1