Безусловный переход ассемблер: Учебный курс. Часть 16. Условные и безусловные переходы

Содержание

Учебный курс. Часть 16. Условные и безусловные переходы

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

Безусловные переходы

Безусловный переход – это переход, который выполняется всегда. Безусловный переход осуществляется с помощью команды JMP. У этой команды один операнд, который может быть непосредственным адресом (меткой), регистром или ячейкой памяти, содержащей адрес. Существуют также “дальние” переходы – между сегментами, однако здесь мы их рассматривать не будем. Примеры безусловных переходов:

    jmp metka    ;Переход на метку
    jmp bx       ;Переход по адресу в BX
    jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX

jmp metka ;Переход на метку jmp bx ;Переход по адресу в BX jmp word[bx] ;Переход по адресу, содержащемуся в памяти по адресу в BX

Условные переходы

Условный переход осуществляется, если выполняется определённое условие, заданное флагами процессора (кроме одной команды, которая проверяет CX на равенство нулю). Как вы помните, состояние флагов изменяется после выполнения арифметических, логических и некоторых других команд. Если условие не выполняется, то управление переходит к следующей команде.

Существует много команд для различных условных переходов. Также для некоторых команд есть синонимы (например, JZ и JE – это одно и то же). Для наглядности все команды условных переходов приведены в таблице:

Команда Переход, если Условие перехода
JZ/JE нуль или равно ZF=1
JNZ/JNE не нуль или не равно ZF=0
JC/JNAE/JB есть переполнение/не выше и не равно/ниже CF=1
JNC/JAE/JNB нет переполнения/выше или равно/не ниже CF=0
JP число единичных бит чётное PF=1
JNP число единичных бит нечётное PF=0
JS знак равен 1 SF=1
JNS знак равен 0 SF=0
JO есть переполнение OF=1
JNO нет переполнения OF=0
JA/JNBE выше/не ниже и не равно CF=0 и ZF=0
JNA/JBE не выше/ниже или равно CF=1 или ZF=1
JG/JNLE больше/не меньше и не равно ZF=0 и SF=OF
JGE/JNL больше или равно/не меньше SF=OF
JL/JNGE меньше/не больше и не равно SF≠OF
JLE/JNG меньше или равно/не больше ZF=1 или SF≠OF
JCXZ содержимое CX равно нулю CX=0

У всех этих команд один операнд – имя метки для перехода. Обратите внимание, что некоторые команды применяются для беззнаковых чисел, а другие – для чисел со знаком. Сравнения “выше” и “ниже” относятся к беззнаковым числам, а “больше” и “меньше” – к числам со знаком. Для беззнаковых чисел признаком переполнения будет флаг CF, а соответствующими командами перехода JC и JNC. Для чисел со знаком о переполнении можно судить по состоянию флага OF, поэтому им соответствуют команды перехода JO и JNO. Команды переходов не изменяют значения флагов.

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
use16                   ;Генерировать 16-битный код
org 100h                ;Программа начинается с адреса 100h
 
    mov al,[x]          ;AL = x
    add al,[y]          ;AL = x + y
    jo error            ;Переход, если переполнение
    mov ah,09h          ;\
    mov dx,ok_msg       ; > Вывод строки 'OK'
    int 21h             ;/
exit:
    mov ah,09h          ;\
    mov dx,pak          ; > Вывод строки 'Press any key. ..'
    int 21h             ;/
 
    mov ah,08h          ;\
    int 21h             ;/ Ввод символа
 
    mov ax,4C00h        ;\
    int 21h             ;/ Завершение программы
error:
    mov ah,09h          ;\
    mov dx,err_msg      ; > Вывод сообщения об ошибке
    int 21h             ;/
    jmp exit            ;Переход на метку exit
;----------------------------------------------------------
x         db -89
y         db -55
err_msg   db 'Error: overflow detected.',13,10,'$'
ok_msg    db 'OK',13,10,'$'
pak       db 'Press any key...$'

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov al,[x] ;AL = x add al,[y] ;AL = x + y jo error ;Переход, если переполнение mov ah,09h ;\ mov dx,ok_msg ; > Вывод строки ‘OK’ int 21h ;/ exit: mov ah,09h ;\ mov dx,pak ; > Вывод строки ‘Press any key. ..’ int 21h ;/ mov ah,08h ;\ int 21h ;/ Ввод символа mov ax,4C00h ;\ int 21h ;/ Завершение программы error: mov ah,09h ;\ mov dx,err_msg ; > Вывод сообщения об ошибке int 21h ;/ jmp exit ;Переход на метку exit ;———————————————————- x db -89 y db -55 err_msg db ‘Error: overflow detected.’,13,10,’$’ ok_msg db ‘OK’,13,10,’$’ pak db ‘Press any key…$’

Команды CMP и TEST

Часто для формирования условий переходов используются команды CMP и TEST. Команда CMP предназначена для сравнения чисел. Она выполняется аналогично команде SUB: из первого операнда вычитается второй, но результат не записывается на место первого операнда, изменяются только значения флагов. Например:

    cmp al,5     ;Сравнение AL и 5
    jl c1        ;Переход, если AL < 5 (числа со знаком)

cmp al,5 ;Сравнение AL и 5 jl c1 ;Переход, если AL < 5 (числа со знаком)

    cmp al,5     ;Сравнение AL и 5
    jb c1        ;Переход, если AL < 5 (числа без знака)

cmp al,5 ;Сравнение AL и 5 jb c1 ;Переход, если AL < 5 (числа без знака)

Команда TEST работает аналогично команде AND, но также результат не сохраняется, изменяются только флаги. С помощью этой команды можно проверить состояние различных битов операнда. Например:

    test bl,00000100b ;Проверить состояние 2-го бита BL
    jz c2             ;Переход, если 2-й бит равен 0

test bl,00000100b ;Проверить состояние 2-го бита BL jz c2 ;Переход, если 2-й бит равен 0

Пример программы

Простая программка, которая выводит меню и предлагает пользователю сделать выбор. Для ввода символа используется функция DOS 01h (при вводе символ отображается на экране). В зависимости от введённого символа осуществляется переход на нужный кусок кода. Для разнообразия, я поместил данные в начале программы, а не в конце (кстати, обычно так и делают). Чтобы данные не выполнились как код, перед ними стоит команда безусловного перехода.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
use16                   ;Генерировать 16-битный код
org 100h                ;Программа начинается с адреса 100h
    jmp start           ;Безусловный переход на метку start
;----------------------------------------------------------
menu    db '1 - Print hello',13,10
        db '2 - Print go away',13,10
        db '0 - Exit',13,10,'$'
select  db 13,10,'Select>$'
hello   db 13,10,'Hello!',13,10,13,10,'$'
go_away db 13,10,'Go away!',13,10,13,10,'$'
;----------------------------------------------------------
start:
    mov ah,09h          ;\
    mov dx,menu         ; > Вывод меню
    int 21h             ;/
 
select_loop:
    mov ah,09h          ;\
    mov dx,select       ; > Вывод строки 'Select>'
    int 21h             ;/
 
    mov ah,01h          ;Функция DOS 01h - ввод символа
    int 21h             ;Введённый символ помещается в AL
 
    cmp al,'1'          ;Сравнение введённого символа с '1'
    je c1               ;Переход, если равно
    cmp al,'2'          ;Сравнение введённого символа с '2'
    je c2               ;Переход, если равно
    cmp al,'0'          ;Сравнение введённого символа с '0'
    je exit             ;Переход, если равно
    jmp select_loop     ;Безусловный переход
c1:
    mov ah,09h          ;\
    mov dx,hello        ; > Вывод строки 'Hello'
    int 21h             ;/
    jmp start           ;Безусловный переход
c2:
    mov ah,09h          ;\
    mov dx,go_away      ; > Вывод строки 'Go away'
    int 21h             ;/
    jmp start           ;Безусловный переход
exit:
    mov ax,4C00h        ;\
    int 21h             ;/ Завершение программы

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h jmp start ;Безусловный переход на метку start ;———————————————————- menu db ‘1 — Print hello’,13,10 db ‘2 — Print go away’,13,10 db ‘0 — Exit’,13,10,’$’ select db 13,10,’Select>$’ hello db 13,10,’Hello!’,13,10,13,10,’$’ go_away db 13,10,’Go away!’,13,10,13,10,’$’ ;———————————————————- start: mov ah,09h ;\ mov dx,menu ; > Вывод меню int 21h ;/ select_loop: mov ah,09h ;\ mov dx,select ; > Вывод строки ‘Select>’ int 21h ;/ mov ah,01h ;Функция DOS 01h — ввод символа int 21h ;Введённый символ помещается в AL cmp al,’1’ ;Сравнение введённого символа с ‘1’ je c1 ;Переход, если равно cmp al,’2′ ;Сравнение введённого символа с ‘2’ je c2 ;Переход, если равно cmp al,’0′ ;Сравнение введённого символа с ‘0’ je exit ;Переход, если равно jmp select_loop ;Безусловный переход c1: mov ah,09h ;\ mov dx,hello ; > Вывод строки ‘Hello’ int 21h ;/ jmp start ;Безусловный переход c2: mov ah,09h ;\ mov dx,go_away ; > Вывод строки ‘Go away’ int 21h ;/ jmp start ;Безусловный переход exit: mov ax,4C00h ;\ int 21h ;/ Завершение программы

Скриншот работы программы:

Упражнение

Упражнение простое. Напишите программу для сравнения двух переменных со знаком a и b. В зависимости от результатов сравнения выведите “a < b”, “a > b” или “a = b”. Проверьте работу программы в отладчике. Результаты можете выкладывать в комментариях.

Следующая часть »

Учебный курс. Часть 13. Циклы и команда LOOP

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

Синтаксис объявления меток

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

Теперь вместо имени m1 компилятор везде будет подставлять адрес комады mov ax,4C00h. Можно объявлять метку на пустой строке перед командой:

exit_app:
    mov ax,4C00h
    int 21h

exit_app: mov ax,4C00h int 21h

Имя метки может состоять из латинских букв, цифр и символов подчёркивания, но должно начинаться с буквы. Имя метки должно быть уникальным. В качестве имени метки нельзя использовать директивы и ключевые слова компилятора, названия команд и регистров (в этом случае FASM покажет сообщение об ошибке). FASM различает регистр символов в именах меток. Можно также объявлять несколько меток на один адрес. Например:

no_error:
exit_app:
m1: mov ax,4C00h

no_error: exit_app: m1: mov ax,4C00h

Подробнее о синтаксисе объявления меток рассказывается в части 27.

Команда LOOP

Для организации цикла предназначена команда LOOP. У этой команды один операнд – имя метки, на которую осуществляется переход. В качестве счётчика цикла используется регистр CX. Команда LOOP выполняет декремент CX, а затем проверяет его значение. Если содержимое CX не равно нулю, то осуществляется переход на метку, иначе управление переходит к следующей после LOOP команде.

Содержимое CX интерпретируется командой как число без знака. В CX нужно помещать число, равное требуемому количеству повторений цикла. Понятно, что максимально может быть 65535 повторений. Ещё одно ограничение связано с дальность перехода. Метка должна находиться в диапазоне -127…+128 байт от команды LOOP (если это не так, FASM сообщит об ошибке).

Пример цикла

В качестве примера я приведу простую программу, которая будет печатать все буквы английского алфавита. ASCII-коды этих символов расположены последовательно, поэтому можно выводить их в цикле. Для вывода символа на экран используется функция DOS 02h (выводимый байт должен находиться в регистре DL).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
use16                 ;Генерировать 16-битный код
org 100h              ;Программа начинается с адреса 100h
 
    mov ah,02h        ;Для вызова функции DOS 02h - вывод символа
    mov dl,'A'        ;Первый выводимый символ
    mov cx,26         ;Счётчик повторений цикла
metka:
    int 21h           ;Обращение к функции DOS
    inc dl            ;Следующий символ
    loop metka        ;Команда цикла
 
    mov ah,09h        ;Функция DOS 09h - вывод строки
    mov dx,press      ;В DX адрес строки
    int 21h           ;Обращение к функции DOS
 
    mov ah,08h        ;Функция DOS 08h - ввод символа без эха
    int 21h           ;Обращение к функции DOS
 
    mov ax,4C00h      ;\
    int 21h           ;/ Завершение программы
;-------------------------------------------------------
press:
    db 13,10,'Press any key. ..$'

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov ah,02h ;Для вызова функции DOS 02h — вывод символа mov dl,’A’ ;Первый выводимый символ mov cx,26 ;Счётчик повторений цикла metka: int 21h ;Обращение к функции DOS inc dl ;Следующий символ loop metka ;Команда цикла mov ah,09h ;Функция DOS 09h — вывод строки mov dx,press ;В DX адрес строки int 21h ;Обращение к функции DOS mov ah,08h ;Функция DOS 08h — ввод символа без эха int 21h ;Обращение к функции DOS mov ax,4C00h ;\ int 21h ;/ Завершение программы ;——————————————————- press: db 13,10,’Press any key…$’

Команды “int 21h” и “inc dl” (строки 8 и 9) будут выполняться в цикле 26 раз. Для того, чтобы программа не закрылась сразу, используется функция DOS 08h – ввод символа с клавиатуры без эха, то есть вводимый символ не отображается. Перед этим выводится предложение нажать любую кнопку (но Reset лучше не нажимать). Для примера адрес строки объявлен с помощью метки. Символы с кодами 13 и 10 обозначают переход на следующую строку (символ 13(0Dh) называется CR – Carriage Return – возврат каретки, а символ 10(0Ah) LF – Line Feed – перевод строки . Эти символы унаследованы со времён древних телетайпов, когда текст печатался, как на печатной машинке). Так выглядит результат работы программы:

Вложенные циклы

Иногда требуется организовать вложенный цикл, то есть цикл внутри другого цикла. В этом случае необходимо сохранить значение CX перед началом вложенного цикла и восстановить после его завершения (перед командой LOOP внешнего цикла). Сохранить значение можно в другой регистр, во временную переменную или в стек. Следующая программа выводит все доступные ASCII-символы в виде таблицы 16×16. Значение счётчика внешнего цикла сохраняется в регистре BX.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use16                 ;Генерировать 16-битный код
org 100h              ;Программа начинается с адреса 100h
 
    mov ah,02h        ;Для вызова функции DOS 02h - вывод символа
    sub dl,dl         ;Первый выводимый символ
    mov cx,16         ;Счётчик внешнего цикла (по строкам)
lp1:
    mov bx,cx         ;Сохраняем счётчик в BX
    mov cx,16         ;Счётчик внутреннего цикла (по столбцам)
lp2:
    int 21h           ;Обращение к функции DOS
    inc dl            ;Следующий символ
    loop lp2          ;Команда внутреннего цикла
 
    mov dh,dl         ;Сохраняем значение DL в DH
    mov dl,13         ;\
    int 21h           ; \
    mov dl,10         ; / Переход на следующую строку
    int 21h           ;/
    mov dl,dh         ;Восстанавливаем значение DL
 
    mov cx,bx         ;Восстанавливаем значение счётчика
    loop lp1          ;Команда внешнего цикла
 
    mov ah,09h        ;Функция DOS 09h - вывод строки
    mov dx,press      ;В DX адрес строки
    int 21h           ;Обращение к функции DOS
 
    mov ah,08h        ;Функция DOS 08h - ввод символа без эха
    int 21h           ;Обращение к функции DOS
 
    mov ax,4C00h      ;\
    int 21h           ;/ Завершение программы
;-------------------------------------------------------
press db 13,10,'Press any key. ..$'

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h mov ah,02h ;Для вызова функции DOS 02h — вывод символа sub dl,dl ;Первый выводимый символ mov cx,16 ;Счётчик внешнего цикла (по строкам) lp1: mov bx,cx ;Сохраняем счётчик в BX mov cx,16 ;Счётчик внутреннего цикла (по столбцам) lp2: int 21h ;Обращение к функции DOS inc dl ;Следующий символ loop lp2 ;Команда внутреннего цикла mov dh,dl ;Сохраняем значение DL в DH mov dl,13 ;\ int 21h ; \ mov dl,10 ; / Переход на следующую строку int 21h ;/ mov dl,dh ;Восстанавливаем значение DL mov cx,bx ;Восстанавливаем значение счётчика loop lp1 ;Команда внешнего цикла mov ah,09h ;Функция DOS 09h — вывод строки mov dx,press ;В DX адрес строки int 21h ;Обращение к функции DOS mov ah,08h ;Функция DOS 08h — ввод символа без эха int 21h ;Обращение к функции DOS mov ax,4C00h ;\ int 21h ;/ Завершение программы ;——————————————————- press db 13,10,’Press any key. ..$’

Как видите, всё довольно просто 🙂 Результат работы программы выглядит вот так:

Упражнение

Напишите программу для вычисления степени числа 3 по формуле a = 3n. Число a – 16-битное целое без знака, число n – 8-битное целое без знака (используйте n<11, чтобы избежать переполнения). Проверьте работу программы в отладчике (нажимайте F7 на команде LOOP, чтобы осуществить переход). Результаты можете выкладывать в комментариях.

Следующая часть »

Учебный курс. Часть 14. Режимы адресации

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

1. Неявная адресация

Местоположение операнда фиксировано и определяется кодом операции. Примеры:

Команда CBW всегда работает с регистрами AX и AL, а у команды MUL фиксировано положение первого множителя и результата. Такой режим адресации делает машинную команду короткой, так как в ней отсутствует указание одного или нескольких операндов.

2. Непосредственная адресация

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

    mov al,5
    add bx,1234h
    mov dx,a

mov al,5 add bx,1234h mov dx,a

Обратите внимание, что в третьей строке в DX помещается адрес метки или переменной a, а вовсе не значение по этому адресу. Это особенность синтаксиса FASM. По сути адрес метки тоже является числовой константой.

3. Абсолютная прямая адресация

В машинной команде содержится адрес операнда, находящегося в памяти. Пример:

Вот тут уже в DX помещается значение из памяти по адресу a. Сравните с предыдущим пунктом. Квадратные скобки обозначают обращение по адресу, указанному внутри этих скобок.

4. Относительная прямая адресация

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

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

5. Регистровая адресация

Операнд находится в регистре. Пример:

6. Косвенная регистровая (базовая) адресация

Адрес операнда находится в одном из регистров BX, SI или DI. Примеры:

Размер операнда в памяти здесь определяется размером первого операнда. Так как AX – 16-разрядный регистр, то из памяти берётся слово по адресу в BX. Так как DL – 8-разрядный регистр, то из памяти берётся байт по адресу в SI. Это правило верно и для других режимов адресации.

7. Косвенная регистровая (базовая) адресация со смещением

Адрес операнда вычисляется как сумма содержимого регистра BX, BP, SI или DI и 8- или 16-разрядного смещения. Примеры:

    add ax,[bx+2]
    mov dx,[array1+si]

add ax,[bx+2] mov dx,[array1+si]

В качестве смещения можно указать число или адрес метки. О размере смещения не беспокойтесь – компилятор сам его определяет и использует нужный формат машинной команды.

8. Косвенная базовая индексная адресация

Адрес операнда вычисляется как сумма содержимого одного из базовых регистров BX или BP и одного из индексных регистров SI или DI. Примеры:

    mov ax,[bp+si]
    add ax,[bx+di]

mov ax,[bp+si] add ax,[bx+di]

Например, в одном из регистров может находиться адрес начала массива в памяти, а в другом – смещение какого-то элемента относительно начала. А вообще, всё зависит от вашей фантазии 🙂

9. Косвенная базовая индексная адресация со смещением

Адрес операнда вычисляется как сумма содержимого одного из базовых регистров BX или BP, одного из индексных регистров SI или DI и 8- или 16-разрядного смещения. Примеры:

    mov al,[bp+di+5]
    mov bl,[array2+bx+si]

mov al,[bp+di+5] mov bl,[array2+bx+si]

Пример программы

Допустим, имеется массив 32-битных целых чисел со знаком. Количество элементов массива хранится в 16-битной переменной без знака. Требуется вычислить среднее арифметическое элементов массива и сохранить его в 32-битной переменной со знаком. Я намеренно использовал разные режимы адресации, хотя тоже самое можно написать проще.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
use16                   ;Генерировать 16-битный код
org 100h                ;Программа начинается с адреса 100h
 
      sub ax,ax         ;AX = 0
      cwd               ;DX = 0
      mov si,ax         ;SI = 0 - смещение элемента от начала массива
      mov bx,array      ;Помещаем в BX адрес начала массива
      mov di,n          ;Помещаем в DI адрес n
      mov cx,[di]       ;CX = n
lp1:
      add ax,[bx+si]    ;Прибавление младшего слова
      adc dx,[bx+si+2]  ;Прибавление старшего слова
      add si,4          ;Увеличиваем смещение в SI на 4
      loop lp1          ;Команда цикла
 
      idiv word[di]     ;Делим сумму на количество элемнтов
      cwd               ;DX:AX = AX
      mov word[m],ax    ;\ Сохраняем
      mov word[m+2],dx  ;/ результат
 
      mov ax,4C00h      ;\
      int 21h           ;/ Завершение программы
;-------------------------------------------------------
n     dw 10
array dd 10500,-7500,-15000,10000,-8000
      dd 6500,11500,-5000,10500,-20000
m     dd ?

use16 ;Генерировать 16-битный код org 100h ;Программа начинается с адреса 100h sub ax,ax ;AX = 0 cwd ;DX = 0 mov si,ax ;SI = 0 — смещение элемента от начала массива mov bx,array ;Помещаем в BX адрес начала массива mov di,n ;Помещаем в DI адрес n mov cx,[di] ;CX = n lp1: add ax,[bx+si] ;Прибавление младшего слова adc dx,[bx+si+2] ;Прибавление старшего слова add si,4 ;Увеличиваем смещение в SI на 4 loop lp1 ;Команда цикла idiv word[di] ;Делим сумму на количество элемнтов cwd ;DX:AX = AX mov word[m],ax ;\ Сохраняем mov word[m+2],dx ;/ результат mov ax,4C00h ;\ int 21h ;/ Завершение программы ;——————————————————- n dw 10 array dd 10500,-7500,-15000,10000,-8000 dd 6500,11500,-5000,10500,-20000 m dd ?

Упражнение

Объявите в программе два массива 16-битных целых со знаком. Количество элементов массивов должно быть одинаковым и храниться в 8-битной переменной без знака. Требуется из последнего элемента второго массива вычесть первый элемент первого, из предпоследнего – вычесть второй элемент и т.д. Результаты можете выкладывать в комментариях.

Следующая часть »

Команда JMP


Что такое JavaScript

Если вы интересуетесь программированием вообще, и сайтостроением в частности, то вы наверняка слышали слово JavaScript. И, если вы до сих пор не узнали толком, что же это такое, то пришло время сделать это. Подробнее…

Команда JMP — это команда безусловного перехода в Ассемблере. Выполняет, соответственно, безусловный переход в указанное место.

Синтаксис команды JMP такой:

JMP МЕТКА

МЕТКОЙ может быть один из следующих:

  • Идентификатор метки в исходном коде
  • Адрес в формате СЕГМЕНТ:СМЕЩЕНИЕ

Безусловный переход в Ассемблере выполняется всегда и в любом случае, если в исходном коде имеется инструкция JMP.

Никакие флаги при выполнении этой инструкции не изменяются.

Что такое безусловный переход

Как следует из названия, это переход без условий. Это значит, что если в исходном коде встречается команда JMP, то эта команда выполняет переход на указанный в МЕТКЕ адрес без каких либо условий — в любом случае.

Что такое метка в Ассемблере

Теперь немного поговорим о том, что такое метка в Ассемблере.

Метка — это идентификатор, после которого следует двоеточие. Идентификатор должен быть составлен по правилам составления идентификаторов для конкретного языка программирования

Пример метки в Ассемблере:


--- Здесь инструкции Ассемблера ---

MyLabel:		; Это МЕТКА

--- И здесь инструкции Ассемблера ---

Для чего нужны метки?

Для того, чтобы управлять ходом выполнения программы.

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

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

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

В языках высокого уровня подобные действия называются ветвлением, и реализуются с помощью соответствующих конструкций языка (таких как if…then…else или case в Паскале).

Пример безусловного перехода

Сначала давайте подумаем, зачем нужен безусловный переход.

Логичный вопрос: если мы всегда и во всех случаях пропускаем участок кода, то зачем нам тогда вообще этот участок?

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

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


JMP Label_2
Label_1:
--- Участок кода 1 ---
Label_2:		; Это МЕТКА
--- Участок кода 2 ---
JMP Label_1

Здесь при первом проходе программы мы пропускаем участок кода 1 и сразу переходим к метке Label_2 (то есть ко второму участку). Но во втором участке мы возвращаемся к участку 1 (к метке Label_1) и выполняем его.

Пример второй: может быть так, что какой-то участок кода требуется только для отладки. Тогда можно сделать так:


;JMP Label_2
--- Участок кода ТОЛЬКО для отладки ---
Label_2:		; Это МЕТКА
--- Участок кода 2 ---

Обратите внимание, что инструкция JMP закомментирована, то есть не выполняется. Так что пока вы отлаживаете свою программу, участок кода для отладки выполняется.

Когда отладка программы закончена, мы убираем точку с запятой перед инструкцией JMP и отладочный код выполняться не будет, так как будет выполняться безусловный переход на метку Label_2.

А почему бы просто не убрать отладочный код?

Можно, конечно, и убрать. Но вы уверены, что он вам больше не пригодится?

В конце как обычно расскажу, почему эта команда ассемблера называется JMP. Это сокращение от английского слова JUMP, которое можно перевести как “прыжок, переход”.



Первые шаги в программирование

Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее…


Инструкция JB


Что такое JavaScript

Если вы интересуетесь программированием вообще, и сайтостроением в частности, то вы наверняка слышали слово JavaScript. И, если вы до сих пор не узнали толком, что же это такое, то пришло время сделать это. Подробнее…

Инструкция JB выполняет короткий переход, если первый операнд МЕНЬШЕ второго операнда при выполнении операции сравнения с помощью команды CMP.

Синтаксис команды JB:

JB МЕТКА

О метках я рассказывал в статье о команде JMP. Повторяться не буду.

Инструкция JB проверяет флаг CF. Если этот флаг равен 1, то выполняется переход к МЕТКЕ.

Сама же инструкция JB при работе никакие флаги не изменяет.

Условный переход в Ассемблере

В упомянутой выше статье о команде JMP рассказано о безусловном переходе. Условный переход в Ассемблере можно выполнить с помощью нескольких инструкций, в том числе с помощью команды JB.

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

Итак, условный переход в Ассемблере выполняется примерно по такому алгоритму:

  • Если УСЛОВИЕ ВЫПОЛНЯЕТСЯ, то перейти к МЕТКЕ
  • Если УСЛОВИЕ НЕ ВЫПОЛНЯЕТСЯ, то выполнить следующую инструкцию

Если говорить непосредственно об инструкции JB, то условием перехода к метке является CF=1 (то есть когда первый операнд меньше второго), а алгоритм её использования может быть таким:

  • Сравнить ЧИСЛО1 с ЧИСЛОМ2 с помощью команды CMP
  • УСЛОВИЕ: ЧИСЛО1
  • Выполнить инструкцию JB

Пример использования команды JB приведён ниже:


	. model	tiny
	.code
	ORG 	100h
	
start:	

	MOV AL, 5      ; AL = 5
	MOV AH, 5      ; AH = 5
	CMP AL, AH     ; AL = AH, ZF = 1
	JB  lblLess
	;Так как AL = AH, то УСЛОВИЕ ПЕРЕХОДА НЕ ВЫПОЛНЯЕТСЯ
	;Поэтому будут выполнены следующие инструкции
	MOV AL, 5      ; AL = 5
	MOV AH, 6      ; AH = 6
	CMP AL, AH     ; AL JB  lblLess
	;Так как AL lblLess:	
	MOV AH, 9      ; AH = 9

	END	start

В комментариях всё подробно расписано, поэтому что-то ещё добавлять нет смысла.

В конце попробую предположить, почему эта команда ассемблера называется JB. Честно говоря, точно не знаю. Первая буква — это первая буква английского слова JUMP, которое переводится как “прыжок, переход”. А вот что означает вторая буква — это вопрос. Можно только предположить, что это тоже первая буква какого-то английского слова, например, BOTTOM (низкий). То есть название этой команды можно вольно перевести как “переход, если ниже (меньше)”.



Первые шаги в программирование

Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее…


Команда JLE


Что такое JavaScript

Если вы интересуетесь программированием вообще, и сайтостроением в частности, то вы наверняка слышали слово JavaScript. И, если вы до сих пор не узнали толком, что же это такое, то пришло время сделать это. Подробнее…

Команда JLE выполняет короткий переход, если первый операнд МЕНЬШЕ второго операнда или РАВЕН ему при выполнении операции сравнения с помощью команды CMP.

Синтаксис команды JLE:

JLE МЕТКА

О метках я рассказывал в статье о команде JMP. Повторяться не буду.

Инструкция JLE проверяет флаги SF, OF и ZF. Переход выполняется, если

  • SF не равен OF
  • или ZF = 1

Сама же инструкция JLE при работе никакие флаги не изменяет.

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

Если вы помните, то команда JBE делает то же самое, то есть выполняет переход, если первый операнд меньше или равен второму. Однако команда JBE может работать только с положительными числами, в то время как JLE — как с положительными, так и с отрицательными.

Пример использования команды JLE приведён ниже:


	.model	tiny
	.code
	ORG 	100h
	
start:	

	MOV AL, -5      ; AL = -5
	MOV AH, 0       ; AH = 0
	CMP AL, AH      ; AL JLE lblJLE
	;Так как AL 


Для сравнения здесь также показана инструкция JBE с теми же параметрами. Однако, в случае с JBE не будет перехода к метке, хотя AL

А вот команда JLE выполнит переход к метке, потому что она сможет понять, что в AL находится отрицательное значение, которое, разумеется, меньше нуля (меньше числа в регистре AH).

Всё остальное подробно расписано комментариях, поэтому что-то ещё добавлять нет смысла. Если нужно более подробно, то см. видео выше.

В конце, как всегда, расскажу, почему эта команда ассемблера называется JLE. Буква J - это первая буква слова слова JUMP (прыжок, переход), буква L - это первая буква слова LESS (меньше, менее, ниже). А буква Е - это первая буква слова EQUAL (одинаковый, равный). Таким образом набор слов, от которых взяты первые буквы имени команды JLE, можно перевести как “переход, если меньше или равно”.



Первые шаги в программирование

Главный вопрос начинающего программиста – с чего начать? Вроде бы есть желание, но иногда «не знаешь, как начать думать, чтобы до такого додуматься». У человека, который никогда не имел дело с информационными технологиями, даже простые вопросы могут вызвать большие трудности и отнять много времени на решение. Подробнее...


8086 Учебник по ассемблеру для начинающих (часть 7)

Короткие условные переходы

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

Инструкции перехода, которые проверяют одиночный флаг

Инструкция Описание Состояние Напротив инструкции
JZ, JE Перейти, если ноль (равно). ZF = 1 JNZ, JNE
JC, JB, JNAE Прыгать при переноске (ниже, не выше равно). CF = 1 JNC, JNB, JAE
JS Перейти, если подпись. SF = 1 JNS
JO Перейти при переполнении. OF = 1 JNO
JPE, JP Перейти, если четность четна. PF = 1 JPO
JNZ, JNE Перейти, если не ноль (не равно). ZF = 0 JZ, JE
JNC, JNB, JAE Прыгать, если не переносить (не ниже, выше). CF = 0 JC, JB, JNAE
JNS Перейти, если не подписать. SF = 0 JS
JNO Перейти, если не переполнение. OF = 0 JO
JPO, JNP Перейти, если четность нечетная (без четности). PF = 0 JPE, JP

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

, если вы имитируете этот код, вы увидите, что все инструкции собраны в JNB , рабочий код (код операции) для этой инструкции — 73h эта инструкция имеет фиксированную длину в два байта, второй байт — это количество байтов для добавить в регистр IP , если условие верно.поскольку инструкция имеет только 1 байт для сохранения смещения, она ограничена передачей управления до -128 байтов назад или 127 байтов вперед, это значение всегда подписано.

   jnc a
   jnb a
   чжэ

   mov ax, 4
a: mov ax, 5
   Ret

 

Инструкции перехода для чисел со знаком

Инструкция Описание Состояние Напротив инструкции
JE, JZ Перейти, если равно (=).
Перейти, если ноль.
ZF = 1 JNE, JNZ
JNE, JNZ Перейти, если не равно (<>).
Перейти, если не ноль.
ZF = 0 JE, JZ
JG, JNLE Перейти, если больше (>).
Перейти, если не меньше или равно (не <=).
ZF = 0
и
SF = OF
JNG, JLE
JL, JNGE Перейти, если меньше ().
Перейти, если не больше или равно (не> =).
SF <> OF JNL, JGE
JGE, JNL Перейти, если больше или равно (> =).
Перейти, если не меньше (не <).
SF = OF JNGE, JL
JLE, JNG Перейти, если меньше или равно (<=).
Перейти, если не больше (не>).
ZF = 1
или
SF <> OF
JNLE, JG

<> — знак означает не равно.

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

Инструкция Описание Состояние Напротив инструкции
JE, JZ Перейти, если равно (=).
Перейти, если ноль.
ZF = 1 JNE, JNZ
JNE, JNZ Перейти, если не равно ().
Перейти, если не ноль.
ZF = 0 JE, JZ
JA, JNBE Перейти, если вверху (>).
Перейти, если не ниже или равно (не <=).
CF = 0
и
ZF = 0
JNA, JBE
JB, JNAE, JC Перейти, если ниже (<).
Перейти, если не выше или равно (not> =).
Перейти, если нести.
CF = 1 JNB, JAE, JNC
JAE, JNB, JNC Перейти, если выше или равно (> =).
Перейти, если не ниже (не <).
Прыгай, если не несешь.
CF = 0 JNAE, JB
JBE, JNA Перейти, если ниже или равно (<=).
Перейти, если не выше (not>).
CF = 1
или
ZF = 1
JNBE, JA

Обычно, когда требуется сравнить числовые значения Инструкция CMP используется (выполняет то же самое, что и инструкция SUB (вычитание), но не сохраняет результат, просто влияет на флаги).

Логика очень простая, например:
нужно сравнить 5 и 2,
5-2 = 3
результат не равен нулю (нулевой флаг установлен на 0).

Другой пример:
требуется сравнить 7 и 7,
7-7 = 0
результат равен нулю! (Нулевой флаг установлен на 1 и JZ или JE выполнит прыжок).

вот пример инструкции CMP и условного перехода:

включить "emu8086. inc"

org 100h

mov al, 25; установите al на 25.mov bl, 10; установите bl на 10.

cmp al, bl; сравнить al - bl.

je равный; перейти, если al = bl (zf = 1).

putc 'n'; если он попадает сюда, то al <> bl,
jmp stop; так что напечатайте 'n' и прыгайте, чтобы остановиться.

равно:; если попадет сюда,
putc 'y'; тогда al = bl, поэтому выведите 'y'.

стоп:

ret; попадает сюда несмотря ни на что.

 

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



петли

инструкция работа и состояние перехода напротив инструкции
LOOP уменьшить cx, перейти к метке, если cx не ноль. DEC CX и JCXZ
LOOPE уменьшить cx, перейти к метке, если cx не равно нулю и равно (zf = 1). ПЕТЛЯ
LOOPNE уменьшить cx, перейти к метке, если cx не равно нулю и не равно (zf = 0). ПЕТЛЯ
LOOPNZ уменьшить cx, перейти к метке, если cx не равно нулю и zf = 0. LOOPZ
LOOPZ уменьшить cx, перейти к метке, если cx не равен нулю и zf = 1. LOOPNZ
JCXZ перейти к метке, если cx равно нулю. ИЛИ CX, CX и JNZ

циклов — это в основном те же прыжки, можно закодировать циклы без использования инструкции цикла, просто используя условные переходы и сравнение, и это именно то, что делает цикл.все инструкции цикла используют регистр CX для подсчета шагов, поскольку вы знаете, что регистр CX имеет 16 бит и максимальное значение, которое он может удерживать, составляет 65535 или FFFF, однако с некоторой гибкостью можно поместить один цикл в другой, а другой — в другой. два, три и т.д … и получите хорошее значение 65535 * 65535 * 65535 …. до бесконечности …. или до конца оперативной памяти или стека. можно сохранить исходное значение регистра cx с помощью инструкции push cx и вернуть его к исходному, когда внутренний цикл завершится с помощью pop cx , например:

org 100h

mov bx, 0; общий счетчик шагов.mov cx, 5
k1: добавить bx, 1
    mov al, '1'
    mov ах, 0эх
    int 10h
    нажать cx
    mov cx, 5
      k2: добавить bx, 1
      mov al, '2'
      mov ах, 0эх
      int 10h
      нажмите cx
         mov cx, 5
         k3: добавить bx, 1
         mov al, '3'
         mov ах, 0эх
         int 10h
         петля k3; внутренний во внутреннем контуре.
      поп cx
      петля k2; внутренний цикл.
    поп cx
петля k1; внешний контур.

Ret

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

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

для более подробного описания и примеров см. полный набор инструкций 8086



Все условные переходы имеют одно большое ограничение, в отличие от инструкции JMP они могут перемещаться только на 127 байта вперед и на 128 байта назад (обратите внимание, что большинство инструкции собираются в 3 или более байта).

Мы можем легко обойти это ограничение, используя симпатичный трюк:

  • Получите противоположную инструкцию условного перехода из таблицы выше, заставьте его перейти на label_x .
  • Используйте команду JMP для перехода в желаемое место.
  • Определите label_x: сразу после инструкции JMP .
label_x: — может быть любое допустимое имя метки, но не должно быть двух или более меток с одинаковым именем.

вот пример:

включить "emu8086.inc"

org 100h

mov al, 5
mov bl, 5

cmp al, bl; сравнить al - bl.


jne not_equal; перейти, если al <> bl (zf = 0).
jmp равно
не равный:

добавить bl, al
sub al, 10
xor al, bl

jmp skip_data
db 256 dup (0); 256 байт
skip_data:

putc 'n'; если он попадает сюда, то al <> bl,
jmp stop; так что напечатайте 'n' и прыгайте, чтобы остановиться.

равно:; если попадет сюда,
putc 'y'; тогда al = bl, поэтому выведите 'y'.стоп:

Ret
 

Примечание: последняя версия встроенного ассемблера 8086 автоматически создает обходной путь, заменяя условный переход на противоположный и добавляя большой безусловный переход. Чтобы проверить, установлена ​​ли у вас последняя версия emu8086, нажмите help-> проверьте наличие обновлений в меню.



Другой, но редко используемый метод — получение немедленного значения. этикетки. Когда немедленное значение начинается с $ относительного скачка выполняется, иначе компилятор вычисляет инструкцию, которая перескакивает напрямую к заданному смещению.Например:
org 100h

; безусловный переход вперед:
; пропустить следующие 3 байта + себя
; машинный код короткой инструкции jmp занимает 2 байта.
jmp $ 3 + 2
db 3; 1 байт.
b db 4; 1 байт.
c db 4; 1 байт.

; условный переход назад на 5 байтов:
mov bl, 9
дек бл; 2 байта.
cmp bl, 0; 3 байта.
jne $ -5; перейти на 5 байтов назад

Ret
 

<<< предыдущая часть <<< >>> Следующая часть >>>

Простой 8-битный ассемблер — Справка по набору команд

Введение

Этот симулятор предоставляет упрощенный синтаксис ассемблера (основанный на NASM) и имитирует x86-подобный процессор.Подробную документацию и введение в ассемблер можно найти на следующих сайтах:

Симулятор состоит из 8-битного процессора и 256 байтов памяти. Все инструкции (код) и переменные (данные) должны уместиться в памяти. Для простоты каждая инструкция (и операнд) имеет размер 1 байт. Следовательно, инструкция MOV будет использовать 3 байта памяти. Симулятор предоставляет консольный вывод, который отображает память от 0xE8 до 0xFF. Отображение памяти означает, что каждое значение, записанное в этот блок памяти, отображается на консоли.

Синтаксис

Синтаксис аналогичен используемому большинством ассемблеров. Каждая инструкция должна быть на отдельной строке. Ярлыки необязательны и должны начинаться с буквы или точки (.) И заканчиваться двоеточием.

 метка: операнды инструкции; Комментарий 

Допустимые форматы чисел для констант:

Десятичный: 200
Десятичный: 200d
Шестнадцатеричный: 0xA4
Восьмеричный: 0o48
Двоичный: 101b
 

Можно определить число, используя символ или несколько чисел (см. Инструкцию DB ), используя строку.

Характер: «А»
Строка: «Hello World!»
 

Операнды могут быть одним из четырех регистров общего назначения, регистром указателя стека, адресом памяти или константой. Регистр указателя стека может использоваться только как операнд в инструкциях MOV, ADD, SUB, CMP, INC и DEC. Вместо определения адреса как константы или использования регистра вы можете использовать метки. Затем ассемблер заменит метку соответствующей константой.

Регистр общего назначения (GP): A, B, C, D
Регистр указателя стека: SP
Адрес с использованием регистра GP: [A]
Адрес с использованием регистра GP и смещения: [D-3]
Адрес с использованием регистра SP и смещения: [SP + 2]
Адрес с использованием константы: [100]
Адрес с помощью метки: метка
Константа: любое число от 0..255 (8 бит без знака)
Смещение для косвенной адресации: целое число от -16 до +15 (знак обязателен)
 
MOV — скопировать значение

Копирует значение из src в dest . Инструкция MOV — единственная, которая может напрямую изменять память. SP может использоваться как операнд с MOV.

MOV reg, reg
МОВ рег, адрес
MOV reg, постоянная
Адрес МОВ, рег
Адрес MOV, постоянный
 
DB — переменная

Определяет переменную. Переменная может быть одним числом, символом или строкой.

Константа БД
 
Математические операции
Сложение и вычитание

Складывает два числа или вычитает одно число из другого. Эти операции изменят флаг переноса и нуля. SP может использоваться как операнд с ADD и SUB.

ДОБАВИТЬ рег, рег
ДОБАВИТЬ рег, адрес
ADD reg, постоянная
SUB reg, reg
SUB reg, адрес
SUB reg, постоянная
 
Увеличение и уменьшение

Увеличивает или уменьшает регистр на единицу.Эти операции изменят флаг переноса и нуля. SP может использоваться как операнд с INC и DEC.

INC reg
Рег.
 
Умножение и деление

Умножает или делит регистр A на заданное значение. Эти операции изменят флаг переноса и нуля.

MUL reg
Адрес MUL
Константа MUL
DIV reg
DIV адрес
Константа DIV
 
Логические инструкции

Поддерживаются следующие логические инструкции: AND, OR, XOR, NOT. Эти операции изменят флаг переноса и нуля.

И рег, рег
И рег, адрес
И рег, постоянная
ИЛИ рег, рег
ИЛИ рег, адрес
ИЛИ рег, константа
XOR reg, reg
XOR reg, адрес
XOR reg, константа
НЕ рег
 
Инструкции по смене

Поддерживаются следующие инструкции смены: SHL / SAL и SHR / SAR. Поскольку этот симулятор поддерживает только беззнаковые числа, SHR и SAR дают одинаковый результат. Эти операции изменят флаг переноса и нуля.

ШЛ рег, рег
Регистр СХЛ, адрес
SHL reg, постоянная
SHR рег, рег
SHR reg, адрес
Рег. SHR, постоянная
 
CMP — Сравнить

Сравнивает два значения и устанавливает нулевой флаг в истинное значение, если они равны.SP может использоваться как операнд с CMP. Используйте эту инструкцию перед условным переходом.

CMP reg, reg
CMP reg, адрес
Рег. CMP, постоянная
 
Прыжки
JMP — Безусловный прыжок

Разрешить указателю инструкции выполнить безусловный переход к заданному адресу.

Адрес JMP
 
Условные прыжки

Разрешить указателю инструкции выполнить условный переход к заданному адресу. См. Доступные условия в таблице ниже.

Инструкция Описание Состояние Альтернативы
JC Прыгать при переноске Перенести = ИСТИНА JB, JNAE
JNC Перейти, если нет переноски Перенести = ЛОЖЬ JNB, JAE
JZ Перейти, если ноль Ноль = ИСТИНА JB, JE
JNZ Перейти, если нет нуля Ноль = ЛОЖЬ JNE
JA > Carry = FALSE && Zero = FALSE JNBE
JNBE не <= Carry = FALSE && Zero = FALSE JA
JAE > = Перенести = ЛОЖЬ JNC, JNB
JNB не < Перенести = ЛОЖЬ JNC, JAE
JB < Перенести = ИСТИНА JC, JNAE
JNAE не> = Перенести = ИСТИНА JC, JB
JBE <= C = ИСТИНА или Z = ИСТИНА JNA
JNA не> C = ИСТИНА или Z = ИСТИНА JBE
JE = Z = ИСТИНА JZ
JNE ! = Z = ЛОЖЬ JNZ
CALL — вызов функции

Вызов можно использовать для перехода к подпрограмме (функции). Помещает адрес следующей инструкции в стек и переходит к указанному адресу.

ЗВОНИТЕ адрес
 
RET — Выход из подпрограммы

Выходит из подпрограммы, выталкивая адрес возврата, ранее введенный инструкцией CALL. Перед вызовом RET убедитесь, что SP сбалансирован, иначе указатель инструкции будет иметь неоднозначное значение.

RET
 
Инструкции стека
PUSH — Вставить в стек

Помещает значение в стек.Стек растет вниз, и текущая позиция доступна в регистре указателя стека (SP). Эта инструкция уменьшит SP.

PUSH reg
PUSH адрес
PUSH константа
 
POP — Поп из стека

Извлекает значение из стека в регистр. Эта инструкция увеличит SP.

POP reg
 
Прочие инструкции
HLT — Останавливает процессор.

Останавливает работу процессора.Нажмите кнопку «Сброс», чтобы сбросить IP перед перезапуском.

HLT
 

Марко Швайгхаузер (2015) | Лицензия MIT | Блог

Условное выполнение и ветвление (часть 6)

В главе «Набор команд» мы говорили о том, что существуют разные версии Thumb. В частности, версия Thumb, которая допускает условное выполнение (Thumb-2). Некоторые версии процессоров ARM поддерживают инструкцию «IT», которая позволяет условно выполнять до 4 инструкций в состоянии Thumb.

Ссылка: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/BABIJDIC.html

Синтаксис: IT { x { y { z }}} cond

  • cond определяет условие для первой инструкции в блоке IT
  • x определяет переключатель состояния для второй инструкции в блоке IT
  • y определяет переключатель условий для третьей инструкции в блоке IT
  • z определяет переключатель условий для четвертой инструкции в блоке IT

Структура IT-инструкции — «IF-Then- (Else)», а синтаксис представляет собой конструкцию из двух букв T и E:

  • IT относится к If-Then (следующая инструкция является условной)
  • ITT относится к If-Then-Then (следующие 2 инструкции являются условными)
  • ITE относится к If-Then-Else (следующие 2 инструкции являются условными)
  • ITTE относится к If-Then-Then-Else (следующие 3 инструкции являются условными)
  • ITTEE относится к If-Then-Then-Else-Else (следующие 4 инструкции являются условными)

Каждая инструкция внутри IT-блока должна определять суффикс условия, который является либо таким же, либо логическим обратным.Это означает, что если вы используете ITE, первая и вторая инструкция (If-Then) должны иметь одинаковый суффикс условия, а третья (Else) должна иметь логический обратный по отношению к первым двум. Вот несколько примеров из справочного руководства ARM, которые иллюстрируют эту логику:

 ITTE NE; Следующие 3 инструкции условны
ANDNE R0, R0, R1; ANDNE не обновляет флаги условий
ADDSNE R2, R2, # 1; ADDSNE обновляет флаги условий
MOVEQ R2, R3; Условный ход

ITE GT; Следующие 2 инструкции условны
ADDGT R1, R0, # 55; Условное сложение в случае истинности GT
ДОБАВИТЬ R1, R0, # 48; Условное сложение в случае, если GT не соответствует действительности

ITTEE EQ; Следующие 4 инструкции условны
MOVEQ R0, R1; Условный MOV
ADDEQ R2, R2, # 10; Условное добавление
ANDNE R3, R3, # 1; Условное И
BNE.W dloop; Инструкция перехода может использоваться только в последней инструкции IT-блока 

Неправильный синтаксис:

 IT NE; Следующая инструкция условная
ДОБАВИТЬ R0, R0, R1; Синтаксическая ошибка: в блоке IT не используется код условия. 

Вот условные коды и их противоположность:

Код состояния напротив
Код Значение Код Значение
EQ равно NE Не равно
HS
(или CS)
Без знака выше или тот же
(или переносной набор)
LO
(или CC)
Нижний без знака
(или прозрачный)
MI отрицательный PL Положительный или ноль
VS Подписанное переполнение VC Нет подписанного переполнения
Привет Беззнаковое высшее LS Беззнаковый младший или тот же
GE со знаком больше или равно LT Подписано менее
GT Подписано больше LE со знаком меньше или равно
AL
(или опущен)
Всегда выполняется Нет противоположности AL

Давайте попробуем это с помощью следующего примера кода:

.синтаксис унифицирован @ это важно!
.текст
.global _start

_Начало:
    .code 32
    добавить r3, pc, # 1 @ увеличить значение ПК на 1 и добавить его к R3
    bx r3 @ branch + exchange к адресу в R3 -> переключиться в состояние Thumb, потому что LSB = 1

    .code 16 @ Состояние большого пальца
    cmp r0, # 10
    ite eq @, если R0 равно 10 ...
    addeq r1, # 2 @ ... тогда R1 = R1 + 2
    addne r1, # 3 @ ... иначе R1 = R1 + 3
    bkpt 

.код 32

Этот пример кода запускается в состоянии ARM. Первая инструкция добавляет адрес, указанный в PC плюс 1, к R3, а затем переходит к адресу в R3. Это вызовет переключение в состояние Thumb, потому что младший бит (младший значащий бит) равен 1 и, следовательно, не выровнен по 4 байтам. Для этого важно использовать bx (Branch + exchange). После перехода установлен флаг T (Thumb), и мы находимся в состоянии Thumb.

. Код 16

В состоянии Thumb мы сначала сравниваем R0 с # 10, что устанавливает отрицательный флаг (0-10 = -10).Затем мы используем блок If-Then-Else. Этот блок пропустит инструкцию ADDEQ, потому что флаг Z (ноль) не установлен, и выполнит инструкцию ADDNE, потому что результат был NE (не равен) 10.

Пошаговое выполнение этого кода в GDB испортит результат, потому что вы выполните обе инструкции в блоке ITE. Однако выполнение кода в GDB без установки точки останова и пошаговое выполнение каждой инструкции приведет к правильной настройке результата R1 = 3.

Запрограммированное введение в язык ассемблера MIPS

Запрограммированное введение в язык ассемблера MIPS
Государственный университет Центрального Коннектикута
QtSpim Edition, август 2015 г.

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

Акцент в курсе делается на понимание того, как работают компьютеры. Этот обеспечит основу для дальнейшего изучение архитектуры компьютера и компьютерное программное обеспечение.Процессор MIPS, предмет этого курса, имеет хорошо продуманную архитектуру и особенно полезен для изучения. Однако цель курса — не превратить вас в программист MIPS, но дать вам понимание всех компьютерных систем.

Единственное оборудование, которое вам понадобится для этого курса, — это компьютер. Единственное необходимое программное обеспечение — это SPIM-симулятор процессора MIPS32 и текстовый редактор. Симулятор доступен для бесплатного скачивания. (см. приложение А).Представлены примеры программ с использованием MS Windows Операционная система. Однако вы можете использовать любой платформа, на которой работает СПИМ. (Много).

Язык ассемблера обычно берется семестр после курса программирования высокого уровня язык (например, Java или C). Этот курс предполагает, что у вас есть этот опыт хотя специального языка программирования не требуется.

Читайте страницы этого курса активно . Подумайте и ответьте на вопрос на внизу каждой страницы.(Этот стиль обучения называется программированное обучение . Это очень эффективно для технического материала). Большинство вопросов требуют просто небольшая мысль. Некоторые требуют карандаш и бумагу. Держите карандаш и клочок бумаги рядом с клавиатурой. Каждая глава занимает около 15 страниц. Уделите несколько минут на страницу. Вы можете прочитать каждую главу примерно за 30 минут. Однако для получения максимальной выгоды следует запустить некоторые из примеры программ, написать несколько собственных программ, а потом подумай о ваши результаты.Это может занять несколько часов.

Часть 1: Прелюдия к языку ассемблера

Язык ассемблера: что это такое, почему изучается и где используется.

Часть 2: Представление данных

Данные: символы и целые числа. Алгоритм двоичного сложения .

Часть 3: Запуск СПИМ; Побитовая логика

Запуск СПИМ. Программирование MIPS. Побитовые логические операции.

Часть 4: Целочисленная арифметика и доступ к памяти

Целочисленная арифметика.Перенос данных в и по памяти.

Часть 5: Ветви, решения и циклы

Программный поток : инструкции перехода, перехода и установки; петли, и решения.

Часть 6: Расширенный язык ассемблера

Ассемблер расширяется без машинный язык. Регистры имеют мнемонические имена. Псевдоинструкции расширяют голое оборудование.

Часть 7: Связь стека и подпрограммы

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

Часть 8: Данные с плавающей запятой

Битовые шаблоны используются для представления числа с плавающей запятой.

Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован.