Файл: jourdain_spravochnik_programmista.docx

ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 04.07.2020

Просмотров: 3059

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.

необходимо. Если программа начинает выполнять критичекую часть

кода, когда нельзя использовать процедуру ON PEN GOSUB, напишите

PEN STOP. В этом случае будет продолжаться проверка статуса пера,

и если перо будет включено, то этот факт будет запомнен. Однако

пока не будет встречен оператор PEN ON, управление не будет пере-



даваться процедуре ON PEN GOSUB.

Данный пример вызывает остановку программы, когда нажата кноп-

ка на световом пере. Точка в позиции светового пера включается

процедурой, обрабатывающей включение

ERROR ;на обработку ошибки

INC BX ;увеличиваем указатель

LOOP NEXT_CHAR ;выводим следующий символ


Стандартное прерывание MS DOS для вывода на принтер это функ-

ция 5 прерывания 21H. Просто поместите символ в DL и выполните

прерывание. Эта функция всегда выводит на LPT1 и у нее нет возв-

ращаемых регистров.


;---вывод данных на LPT1

MOV AH,5 ;номер функции

MOV DL,CHAR ;готовим печатаемый символ

INT 21H ;посылаем его на пр

;N,1)*2^(N-1)

2040 NEXT

2050 RETURN


Приложение В. Основные сведения об языке ассемблера.


Читатель этой книги, не знакомый с языком ассемблера, скоро

поймет, что многие программистские трюки не могут быть достигнуты

другими средствами. Хотя изучение языка ассемблера требует от-

дельной книги, в этом приложении приводятся основные понятия,

которые помогут новичкам разобраться в примерах на этом языке.

Внимательный просмотр разделов, посвященных среднему и низкому

уровням, даст Вам возможность получить представление о том, как

работает ассемблер, после чего намного легче изучить разные част-

ные вопросы. Здесь обсуждаются не все ассемблерные инструкции,

встречающиеся в программах, но Вы обнаружите, что около 95 %

инструкций, встреченных Вами в программах, описаны здесь, а зна-

чение остальных может быть понято благодаря комментариям к прог-

раммам.

Микропроцессор 8088 имеет 13 16-разрядных регистров, каждый из

которых имеет свои функции. В то время как в языках высокого

уровня Вы можете поместить два числа в переменные, а затем сло-

жить эти переменные, то в языке ассемблера эти числа помещаются в

регистры микропроцессора, а затем складываются значения, содержа-

щиеся в регистрах. Все операции в языке ассемблера состоят в

обмене данных с регистрами, а затем выполнении операций на ре-

гистрах, таких как изменение отдельных битов, выполнение арифме-

тических операций и т.д. Одной из причин высокой эффективности

языка ассемблера является хранение данных в регистрах микропро-

цессора; компиляторы имеют тенденцию возвращать все значения в

память после выполнения операции, а доступ к памяти требует боль-

шого времени. На рис. В-1 показаны 13 регистров микропроцессоров

8088 и 80286 (последний имеет дополнительные средства для много-

задачной работы, которые мы не будем рассматривать здесь).


Регистры AX, BX, CX и DX являются регистрами общего назначе-

ния. Их особенность состоит в том, что операции могут произво-

диться не только над содержимым всего регистра, но также и над

половиной. Каждый из четырех регистров делится на старшую и млад-

шую части, например, AH обозначает старшую половину регистра AX,

а AL - младшую. Точно так же ассемблерная программа может иметь

доступ к BH, BL, CH, CL, DH и DL. Это свойство очень полезно,

поскольку часто программе приходится работать с байтными величи-

нами. Регистры BP, SI и DI также достаточно удобны, хотя они

могут принимать только 16-битные значения. Каждый бит регистра

флагов сообщает о соответствующем статусе процессора, например, о

том, что при выполнении арифметической операции был перенос за

разрядную сетку.

В общем случае значения помещаются в регистры с помощью инст-

рукции MOV. MOV AX,BX пересылает содержимое регистра BX в AX,

затирая ранее содержащееся в AX значение. MOV AH,BL приводит к

пересылке байта из регистра в регистр, но MOV AX,BL - недопусти-

мая инструкция, так как значения должны иметь одинаковый размер.

Инструкция MOV можеть также передавать значения из памяти, напри-

мер, MOV AX,ACCT_NUMBER. Здесь ACCT_NUMBER - имя переменной,

которую создал программист, совсем как в языке высокого уровня.

Переменная создается оператором вида ACCT_NUMBER DW 0. Этот опе-

ратор оставляет место для слова (двух байтов), присваивая им

значение 0. Другие допустимые символы в этом операторе это DD -

для двойного слова и DB - для байта или строк. Ассемблер следит



за адресами переменных, поэтому при ассемблировании оператора MOV

AX,ACCT_NUMBER имя переменной заменяется на ее адрес.

Работа с именами переменных - самый простой способ идентифика-

ции данных в программах на языке ассемблера. Но имеются различные

способы хитрой адресации, которые позволяют программе хранить

массивы или использовать указатели. Например, MOV AX,[BX][SI]

посылает в AX значение, которое содержится по смещению, равному

сумме значений регистров BX и SI. Но от чего отсчитывать смеще-

ние? Ответ заключается в том, что все данные собраны в одну часть

программы, а весь исполняемый код - в другую. Часть, отведенная

под данные, называется сегментом данных, а под программу - кодо-

вым сегментом. Все переменные, отведенные для хранения данных,

адресуются через смещение относительно начала сегмента данных.

Позиция в памяти, с которой начинается сегмент данных, хранит-

ся в регистре DS, одном из четырех сегментных регистров. Как и

все остальные регистры микропроцессора он 16-разрядный, поэтому

он не может содержать числа, большие чем 65535. Каким же образом

сегмент даных может указывать на ячейки памяти, расположенные в

верхней части мегабайтного адресного пространства? Ответ состоит

в том, что сегментные регистры автоматически умножаются на 16, а

результат указывает на место в памяти, с которого начинается


сегмент. Таким образом, сегменты всегда выравнены на 16-байтную

границу. После того как сегмент установлен, все остальные регист-

ры могут содержать смещения, указывающие на любой из следующих

65535 байтов. Регистр дополнительного сегмента (ES) также исполь-

зуется для указания на данные, хранящиеся в памяти.

Среди ассемблерных инструкций, которые Вы часто будете встре-

чать в этой книге, есть инструкции загрузки сегментных и относи-

тельных адресов переменных. MOV AX,SEG ACCT_NUMBER помещает зна-

чение сегментного регистра, в котором расположен ACCT_NUMBER в

AX, а впоследствии это значение будет переслано в DS. MOV BX,OFF-

SET ACCT_NUMBER помещает в BX смещение переменной ACCT_NUMBER в

сегменте данных. После выполнения этих операций DS:BX будут ука-

зывать на ACCT_NUMBER. Если ACCT_NUMBER является одномерным мас-

сивом, то для указания на определенный элемент массива может

использоваться добавочное смещение. Вы часто будете встречать

также инструкцию LEA, предоставляющую другой способ загрузки

смещения.

Кодовый сегмент содержит последовательность машинных инструк-

ций, составляющих программу. Например, инструкция MOV существует

в виде нескольких байтов машинного кода, значение байтов которого

определяет в какой регистр идет пересылка и откуда. Регистр IP

(счетчик команд) содержит величину смещения, которая указывает на

ту инструкцию в кодовом сегменте, которая сейчас должна выпол-

няться. После выполнения инструкции IP увеличивается таким обра-

зом, чтобы он указывал на следующую инструкцию. В простейшей

программе счетчик команд будет передвигаться от первого байта

кодового сегмента к последнему, где программа и завершится. Но,

как и другие программы, программа на языке ассемблера может быть

разбита на процедуры (подпрограммы), поэтому счетчик команд может

прыгать из одного места кодового сегмента в другое.

Когда счетчик команд прыгает в другое место кодового сегмента,

то его старое значение должно быть запомнено, с тем чтобы можно

было вернуться в нужное место, так как это делает оператор RETURN



в Бейсике, возвращая управление в то место, откуда была вызвана

процедура. В языке ассемблера процедуре присваивается имя, напр-

имер, COMBINE_DATA, и оператор CALL COMBINE_DATA передает управ-

ление в процедуру. Процедура завершается инструкцией RET (возв-

рат). При вызове процедуры процессор запоминает текущее значение

счетчика команд, заталкивая его на стек.

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

После завершения процедуры старое значение счетчика команд берет-

ся из стека и выполнение программы продолжается. Стек также со-

держится в отдельном сегменте, который, совершенно естественно,

называется сегментом стека. Ему соответствует сегментный регистр

SS. В регистре SP хранится указатель стека, который всегда указы-

вает на вершину стека и изменяется при засылке на стек и выборке


из стека.

На первый взгляд стек кажется достаточно неуклюжим способом

хранения информации, но у него есть два преимущества. Во-первых,

доступ к его содержимому намного быстрее, чем к переменным, хра-

нящимся в памяти, а, во-вторых, стек может использоваться для

многих целей. Он может хранить адреса возврата из процедуры,

вложенной в другую процедуру. Впоследствии, то же самое прост-

ранство может использоваться программистом для хранения данных,

которые должны сейчас обрабатываться, но для которых не хватает

места в регистрах микропроцессора. Программа выталкивает содержи-

мое регистра на стек командой PUSH, а позднее забирает его оттуда

командой POP. В ассемблерных программах, приведенных в этой кни-

ге, Вы не раз встретитесь с инструкциями типа PUSH BX и POP DX.

Неправильный порядок обмена данными со стеком - лучший способ

привести ассемблерную программу к краху.

После того как программист на ассемблере установил три сег-

ментных регистра (CS, DS и SS) и загрузил данные в регистры мик-

ропроцессора он имеет широкий набор встроенных средств, которыми

процессор может помочь программисту на ассемблере. Вот наиболее

распространенные из них:


ADD AX,BX Прибавляет BX к AX. Существует также инструкция вычи-

тания (SUB), а также варианты обеих этих инструкций.


MUL BL Умножает BL на AX. Имеется также инструкция деления

(DIV), а также варианты обеих этих инструкций.


INC BL Увеличивает BL на 1. Имеется также инструкция умень-

шения (DEC).


LOOP XXX Возвращает программу назад к строке помеченной XXX,

повторяя процесс столько раз, какое число содержится

в CX (аналогично инструкции FOR .. TO .. NEXT в Бей-

сике).


OR AL,BL Выполняет операцию логического ИЛИ над содержимым

регистров AL и BL, причем результат помещается в AL.

Имеются также инструкции AND, XOR и NOT.



SHL AX,1 Сдвигает все биты, содержащиеся в AX, на одну позицию

влево. Это эквивалентно умножению содержимого AX на

2. Другие инструкции сдвигают биты вправо или осу-

ществляют циклический сдвиг. Все эти инструкции очень

полезны для битовых операций, таких как установка

точек экрана.

IN AL,DX Помещает в AX байт, обнаруженный в порте, адрес кото-

рого указан в DX. Имеется также инструкция OUT.


JMP Передает управление в другое место программы, как

инструкция GOTO в Бейсике. JMP YYY передает управле-

ние на строку программы, имеющую метку YYY.


CMP AL,BL Сравнивает содержимое AL и BL. За инструкцией CMP

обычно следует инструкция условного перехода. Напри-

мер, если за инструкцией CMP следует инструкция JGE,

то переход произойдет только если BL больше или равно

AL. Инструкция CMP достигает того же результата, что

и инструкция IF .. THEN в Бейсике (на самом деле

инструкция IF .. THEN переводится интерпретатором


Бейсика в инструкцию CMP).


TEST AL,BL Проверяет есть ли среди битов, установленных в BL,

такие, которые установлены также и в AL. За этой

инструкцией обычно следует команда условного перехо-

да, так же как за CMP. TEST очень полезен при провер-

ке статусных битов (битовые операции очень просто

реализуются в языке ассемблера).


MOVS Пересылает строку, длина которой содержится в CX, с

места, на которое указывает SI, на место, на которое

указывает DI. Имеется еще несколько других инструк-

ций, связанных с пересылкой и поиском строк.


Язык ассемблера обеспечивает несколько вариантов этих инструкций,

а также ряд других специальных инструкций. Имеется также целый

класс инструкций, называемых псевдооператорами, которые помещают-

ся в текст программы с целью указания ассемблеру как обрабатывать

данную программу. Например, один из типов псевдооператоров авто-

матически вставляет часто используемый кусок кода по всей прог-

рамме. Такая порция кода называется макросом и именно это свойст-

во ассемблера дало ему название "макроассемблер".

И, наконец, ассемблер имеет возможность, которой завидуют

(или, по крайней мере, должны завидовать) все кто программирует

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

мальным образом использовать прерывания операционной системы.

Ведь это ничто иное, как готовые процедуры. Однако вместо того,

чтобы вызывать их по CALL, они вызываются инструкцией INT. INT21H

вызывает прерывание с шестнадцатиричным номером 21. Имеется ряд

таких прерываний, как в базовой системе ввода/вывода ПЗУ, так и в

операционной системе, причем некоторые из этих процедур необычай-

но мощны. На самом деле некоторые из них настолько тесно связаны

с системой, что Вы практически не можете сами написать эквива-

лентную процедуру. Языки высокого уровня позволяют использовать



многие из этих прерываний. Они используют их для вывода на экран,

приема ввода с клавиатуры и доступа к дискам. Но многие действи-

тельно полезные прерывания игнорируются языками высокого уровня,

например такие, которые позволяют запустить из одной программы

другую. Некоторые трансляторы (такие как Lattice C или Turbo

Pascal) позволяют доступ к этим прерываниям, если Вы знаете как

их готовить и Вы можете использовать разделы среднего уровня этой

книги для этой цели.

Перед вызовом прерывания некоторая информация должна быть

помещена в регистры процессора. Например, прерывание, верикально

сдвигающее экран, должно знать размеры сдвигаемого окна, число

строк на которое его надо сдвинуть и т.д. Эти значения часто

называют входными регистрами. Снова и снова Вы будете встречать

слова "при входе BX должен содержать ...", описывающие специфика-

цию входных регистров. Аналогично, при возврате из прерывания