Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
М_Арх инф систем.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
194.56 Кб
Скачать

6. Работа со стеком

На вершину стека всегда указывает регистр SP. Для обращения к данным в стеке с использованием режимов адресации памяти, при которых в указателем базы является регистр BP, можно использовать инструкцию MOV. Например, инструкция:

mov ax,[bp+4]

загружает регистр AX содержимым слова в сегменте стека со смещением BP+4.

Однако чаще к стеку обращаются с помощью инструкций PUSH и POP. Инструкция PUSH сохраняет операнд в вершине стека, а инструкция POP извлекает значение из вершины стека и сохраняет его в операнде. Например, инструкции:

mov ax,1

push ax

pop bx

заносят значение (равное 1) в регистре AX в вершину стека, затем извлекают 1 из вершины стека и сохраняют ее в BX.

7. Арифметические операции

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

xchg ax,dx

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

push ax

mov ax,dx

pop dx

Операции ADD и SUB работают с 8- или 16-битовыми операндами. Если нужно сложить или вычесть 32-разрядные операнды, надо разбить операцию на ряд операций со значениями размером в слово и использовать инструкции ADC и SBB.

Когда складываются два операнда, процессор записывает состояние во флаг переноса (бит С в регистре флагов), которое показывает, был ли выполнен перенос из приемника. Младшее слово результата равно нулю, перенос равен 1, поскольку результат (10000h) не вмещается в 16 битов. Инструкция ADC аналогична инструкции ADD, но в ней учитывается флаг переноса (предварительно установленный предыдущим сложением). Всякий раз когда складываются два значения, превышающие по размеру слово, то младшие (менее значащие) слова нужно сложить с помощью инструкции ADD, а остальные слова этих значений - с помощью одной или нескольких инструкций ADC, последними складывая самые значащие слова. Например, следующие инструкции складывают значение в регистрах CX:BX, размером в двойное слово, со значением, записанным в регистрах DX:AX:

add ax,bx

adc dx,cx

а в следующей группе инструкций выполняется сложение четверного слова в переменной DoubleLong1 с четверным словом в переменной DoubleLong2:

mov ax,[DoubleLong1]

add [DoubleLong2],ax

mov ax,[DoubleLong1+2]

adc [DoubleLong2+2],ax

mov ax,[DoubleLong1+4]

adc [DoubleLong1+4],ax

mov ax,[DoubleLong1+6]

adc [DoubleLong2+6],ax

Инструкция SBB работает по тому же принципу, что и инструкция ADC. Когда инструкция SBB выполняет вычитание, в ней учитывается заем, произошедший в предыдущем вычитании. Например, следующие инструкции вычитают значение, записанное в регистрах CX:BX, из значения размеров в двойное слово, записанного в регистрах DX:AX:

sub ax,bx

sbb dx,cx

При работе с инструкциями ADC и SBB нужно убедиться, что флаг переноса не изменился с момента выполнения последнего сложения или вычитания, иначе состояние заема/переноса, хранящееся во флаге переноса, будет потеряно. Например, в следующем фрагменте программы сложение CX:BX с DX:AX выполняется некорректно:

add ax,bx ; сложить младшие слова

sub si,si ; очистить SI (флаг переноса сбрасывается в 0)

adc dx,cx ; сложить старшие слова...

; это будет работать некорректно,

; так как с момента последней

; операции сложения содержимое

; флага переноса потеряно

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

Инструкция MUL перемножает 8- или 16-битовые беззнаковые сомножители, создавая 16- или 32-битовое произведение.

При 8-битовом умножении один из операндов должен храниться в регистре AL, а другой может представлять собой любой 8-битовый общий регистр или переменную памяти соответствующего размера. Инструкция MUL всегда сохраняет 16-битовое произведение в регистре AX. Например, во фрагменте программы:

mov al,25

mov dh,40

mul dh

AL умножается на DH, а результат (1000) помещается в регистр AX.

Инструкция перемножения 16-битовых сомножителей работает аналогично. Один из сомножителей должен храниться в регистре AX, а другой может находиться в 16-разрядном общем регистре или в переменной памяти. 32-битовое произведение инструкция MUL помещает в этом случае в регистры DX:AX, при этом младшие (менее значащие) 16 битов произведения записываются в регистр AX, а старшие (более значащие) 16 битов - в регистр DX. Например, инструкции:

mov ax,1000

mul ax

загружают в регистр AX значение 1000, а затем возводят его в

квадрат, помещая результат (значение 1000000) в регистры DX:AX.

В отличие от сложения и вычитания, в операции умножения не учитывается, являются ли сомножители операндами со знаком или без знака, поэтому имеется вторая инструкция умножения IMUL для умножения 8- и 16-битовых сомножителей со знаком. Если не принимать во внимание, что перемножаются значения со знаком, инструкция IMUL работает аналогично инструкции MUL. Например, при выполнении инструкций:

mov al,-2

mov ah,10

imul ah

в регистре AX будет записано значение -20.

Процессор позволяет с определенными ограничениями разделить 32-битовое значение на 16-битовое, или 16-битовое значение на 8-битовое. Сначала рассмотрим деление 16-битового значения на 8-битовое.

При беззнаковом делении 16-битового значения на 8-битовое делимое должно быть записано в регистре AX. 8-битовый делитель может храниться в любом 8-битовом общем регистре или переменной в памяти соответствующего размера. Инструкция DIV всегда записывает 8-битовое частное в регистр AL, а 8-битовый остаток - в AH. Например, в результате выполнения инструкций:

mov ax,51

mov dl,10

div dl

результат 5 (51/10) будет записан в AL, а остаток 1 (остаток от

деления 51/10) - в AH. Частное представляет собой 8-битовое значение. Это означает, что результат деления 16-битового операнда на 8-битовый операнд должен превышать 255. Если частное слишком велико, то генерируется прерывание 0 (прерывания по делению на 0). Инструкции:

mov ax,0fffh

mov bl,1

div bl

генерируют прерывание по делению на 0 (как можно ожидать, прерывание по делению на 0 генерируется также, если 0 используется в качестве делителя).

При делении 32-битового операнда на 16-битовый операнд делимое должно записываться в регистрах DX:AX. 16-битовый делитель может находиться в любом из 16-битовых регистров общего назначения или в переменной в памяти соответствующего размера. Например, в результате выполнения инструкций:

mov ax,2

mov dx,1 ; загрузить в DX:AX 10002h

mov bx,10h

div bx

частное 1000h (результат деления 10002h на 10h) будет записано в регистре AX, а 2 (остаток от деления) - в регистре DX.

Как и при умножении, при делении имеет значение, используются операнды со знаком или без знака. Для деления беззнаковых операндов используется операция DIV, а для деления операндов со знаком - IDIV. Например, операции:

.DATA

TestDivisor DW 100

.CODE

mov ax,-667

cwd ; установить DX:AX в значение -667

idiv [TestDivisor]

сохраняют значение -6 в регистре AX и значение -67 в регистре DX.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]