Cmp
Содержание:
Как запускается программа на Arduino

Начав выполнение программы, Arduino выполняет ряд рутинных операций по инициализации и настройке среды окружения и только затем приступает к выполнению того самого кода, который содержится в наших с вами скетчах. Таким образом, ардуино избавляет нас от необходимости помнить все детали архитектуры микропроцессора и сконцентрироваться на стоящей перед нами задаче (это не значит, что мы не должны понимать, что же происходит за кадром, но об этом поговорим в отдельной статье).
Для иллюстрации сказанного приведем фрагмент исходников Arduino, в которых и производится вызов наших функций (файл main.cpp):
int main(void)
{
init();
initVariant();
#if defined(USBCON)
USBDevice.attach();
#endif
setup();
for (;;) {
loop();
if (serialEventRun) serialEventRun();
}
return 0;
}
Функция main() – это настоящая точка входа в программу, именно она вызывается первой. Как мы видим, в ней вызываются методы инициализации параметров и среды окружения, а затем и наши void setup() и, уже в цикле – void loop();
По идее, мы можем реализовать другую логику запуска и сделать внутри основного метода несколько функций loop, реализуя многопоточность. Но в данной статье мы не будем этого делать. Более подробно о возможности реализации многопоточности можно прочитать в этой замечательной статье.
Команды сравнения данных
Команды данной группы выполняют сравнение значений числа в вершине стека и операнда, указанного в команде.Команды сравнения данных вещественного типа
| Команда | Операнды | Пояснение | Описание |
| FCOM FUCOM | src | ST(0) — src | Вещественное сравнение |
| FCOMP FUCOMP | src | ST(0) — src; TOPSWR+=1; | Вещественное сравнение с выталкиванием |
| FCOMPP FUCOMPP | — | ST(0) — ST(1); TOPSWR+=2; | Вещественное сравнение с двойным выталкиванием |
| FCOMI FUCOMI | ST, ST(i) | ST(0) — ST(i) | Вещественное сравнение c модификацией EFLAGS |
| FCOMIP FUCOMIP | ST, ST(i) | ST(0) — ST(i); TOPSWR+=1; | Вещественное сравнение c выталкиванием с модификацией EFLAGS |
| FXAM | — | Анализ ST(0) |
Команды сравнения сравнивают значение в вершине стека с операндом. По умолчанию (если операнд не задан) происходит сравнение регистров ST(0) и ST(1). В качестве операнда может быть задана ячейка памяти или регистр. Команда устанавливает биты C0, C2, C3 регистра swr в соответствии с таблицей. Сбрасывает в 0 признак C1 при пустом стеке после выполнения команды.
| Условие | С3 | С2 | C0 |
| ST(0) > src | |||
| ST(0) < src | 1 | ||
| ST(0) = src | 1 | ||
| Недопустимая операция (#IA) | 1 | 1 | 1 |
Особый интерес представляет команда FCOMI (FUCOMI). Она сравнивает содержимое регистра ST(0) со значением операнда ST(i) и устанавливает биты ZF, PF, CF регистра в соответствии с таблицей. Анализ выполнения сравнения осуществляет последующая команда условного перехода (команда центрального процессора).
| Условие | ZF | PF | CF | Переход |
| ST(0) > ST(i) | ja | |||
| ST(0) < ST(i) | 1 | jb | ||
| ST(0) = ST(i) | 1 | je | ||
| ST(0) >= ST(i) | * | jae | ||
| ST(0) <= ST(i) | * | * | jbe | |
| Недопустимая операция (#IA) | 1 | 1 | 1 |
Команда FXAM проверяет содержимое регистра ST(0) и устанавливает биты C0, C2, C3 регистра swr в соответствии с таблицей. Бит C1 устанавливается равным знаковому биту ST(0).
| Класс | С3 | С2 | C0 |
| Неподдерживаемый формат | |||
| Нечисло (NaN) | 1 | ||
| Конечное число | 1 | ||
| Бесконечность | 1 | 1 | |
| Ноль | 1 | ||
| Пустой регистр | 1 | 1 | |
| Ненормированное число | 1 | 1 |
Команды сравнения данных целого типа
| Команда | Операнды | Пояснение | Описание |
| FICOM | src | ST(0) — src | Cравнение с целым числом src |
| FICOMP | src | ST(0) — src; TOPSWR+=1; | Cравнение с целым числом src с выталкиванием |
| FTST | — | ST(0)-0; | Анализ ST(0) (сравнение с нулем) |
Синтаксис void setup()
Синтаксис функции setup очень прост:
void setup(){
// тут располагаются команды подпрограммы
}
В этом примере слово setup – это название функции. Нужно писать именно так, именно в таком регистре. Слово перед названием описывает тип возвращаемых данных. В данном случае никаких данных подпрограмма не возвращает, поэтому мы должны указать слово void. Все команды должны размещаться внутри фигурных скобок {}.
Не забывайте ставить фигурные скобки! Потеря хотя бы одной скобки сразу сделает всю программу непонятной для ардуино. Но и лишние скобки тоже не ставьте – это так же приведет к ошибке.
Использование команд перехода
Этот способ вы наверняка уже использовали, сами того не подозревая.
Суть его проста — почти все команды проверяют какие-то флаги. Соответственно, с их помощью можно узнать состояние этих флагов. Правда, некоторые команды перехода проверяют не один, а несколько флагов. Такие команды для нас не подойдут. А вот те, которые проверяют только один флаг — это то, что нам нужно. Вот они:
Таблица 1. Команды, которые можно использовать для проверки флагов.
| Команда | Условие перехода |
| JZ, JE | ZF = 1 |
| JC, JB, JNAE | CF = 1 |
| JS | SF = 1 |
| JO | OF = 1 |
| JPE, JP | PF = 1 |
| JNZ, JNE | ZF = 0 |
| JNC, JNB, JAE | CF = 0 |
| JNS | SF = 0 |
| JNO | OF = 0 |
| JPO, JNP | PF = 0 |
Как видно из таблицы, с помощью команд перехода можно проверить почти все основные флаги.
А теперь о том, как это использовать. Поясню на примере:
.model tiny .code ORG 100h start: MOV AH, 7 CMP AH, 7 ;ZF = 1 JZ ZF_1 JMP ZF_0 ZF_1: ;Если ZF = 1, то MOV AH, 1 ;в AH запишем 1 ZF_0: ;Если ZF = 0, то MOV AH, 0 ;в AH запишем 0 RET END start
Если флаг ZF = 1, то мы переходим к метке ZF_1 и записываем в регистр АН число 1. Если флаг ZF = 0, то мы переходим к метке ZF_0 и записываем в регистр АН число 0. Таким образом мы узнаём состояние флага ZF и записываем его в регистр AH.
Цикл в Python с пользовательским начальных и конечных чисел
Если вы не хотите, чтобы последовательность чисел начиналась с 0, вы можете также указать начальное число и конечное значения в функции range, как показано в примере ниже.
# cat for4.py for i in range(1,6): print(i)
В приведенном выше примере:
- Диапазон (1,6) – Мы определили начальную и конечную величину в функции range.
- Одна важная вещь, здесь является тот факт, что функция будет начинаться с цифрой «1». Но, кол-во значений будет печататься 5 (а не 6).
- Если вы хотите, последовательность 1 .. п, то ваш диапазон должен быть: диапазон (1, п + 1).
- Таким образом, в этом примере, мы хотели последовательность от 1 .. 5 и мы дали диапазон, range(1,6). т.е. конечное значение равно п + 1.
Ниже приведен вывод программы выше
Опять же, обратите внимание, что она начинается с 1 и заканчивается через 5 (а не 6)
# python for4.py 1 2 3 4 5
Рассмотрим команды ассемблера на практическом примере.
С использованием среды разработки TASMED или любого текстового редактора набираем код. Программа, задаст вопрос на английском языке о половой принадлежности (имеется ввиду ваш биологический пол при рождении). Если вы нажмете m (Man), будет выведено приветствие с мужчиной, если w (Woman), то с женщиной, после этого программа прекратит работу. Если будет нажата любая другая клавиша, то программа предположит, что имеет дело с гоблином, не поверит и будет задавать вам вопросы о половой принадлежности, пока вы не ответите верно.
;goblin.asm
.model tiny ; for СОМ
.code ; code segment start
org 100h ; offset in memory = 100h (for COM)
start: main proc
begin:
mov ah,09h
mov dx,offset prompt
int 21h
inpt:
mov ah,01h
int 21h
cmp al,’m’
je mode_man
cmp al,’w’
je mode_woman
call goblin
jmp begin
mode_man:
mov addrs,offset man; указатель на процедуру в addrs
jmp cont
mode_woman:
mov addrs,offset woman; указатель на процедуру в addrs
cont:
call word ptr addrs; косвенный вызов процедуры
mov ax,4c00h
int 21h
main endp
man proc
mov ah,09h
mov dx,offset mes_man
int 21h
ret
man endp
woman proc
mov ah,09h
mov dx,offset mes_womn
int 21h
ret
woman endp
goblin proc
mov ah,09h
mov dx,offset mes_gobl
int 21h
ret
goblin endp
;DATA
addrs dw 0;for procedure adress
prompt db ‘Are you Man or Woman [m/w]? : $’
mes_man db 0Dh,0Ah,»Hello, Strong Man!»,0Dh,0Ah,’$’ ; строка для вывода. Вместо ASCII смвола ‘$’ можно написать машинный код 24h
mes_womn db 0Dh,0Ah,»Hello, Beautyful Woman!»,0Dh,0Ah,’$’ ; строка для вывода
mes_gobl db 0Dh,0Ah,»Hello, Strong and Beautyful GOBLIN!»,0Dh,0Ah,24h ; строка для вывода. 24h = ‘$’ .
len = $ — mes_gobl
end start
|
1 |
;goblin.asm .modeltiny; for СОМ .code; code segment start org100h; offset in memory = 100h (for COM) startmainproc begin movah,09h movdx,offsetprompt int21h inpt movah,01h int21h cmpal,’m’ jemode_man cmpal,’w’ jemode_woman callgoblin jmpbegin mode_man movaddrs,offsetman; указатель на процедуру в addrs jmpcont mode_woman movaddrs,offsetwoman; указатель на процедуру в addrs cont callwordptraddrs; косвенный вызов процедуры movax,4c00h int21h mainendp manproc movah,09h movdx,offsetmes_man int21h ret manendp womanproc movah,09h movdx,offsetmes_womn int21h ret womanendp goblinproc movah,09h movdx,offsetmes_gobl int21h ret goblinendp addrsdw;for procedure adress promptdb’Are you Man or Woman [m/w]? : $’ mes_mandb0Dh,0Ah,»Hello, Strong Man!»,0Dh,0Ah,’$’; строка для вывода. Вместо ASCII смвола ‘$’ можно написать машинный код 24h mes_womndb0Dh,0Ah,»Hello, Beautyful Woman!»,0Dh,0Ah,’$’; строка для вывода mes_gobldb0Dh,0Ah,»Hello, Strong and Beautyful GOBLIN!»,0Dh,0Ah,24h; строка для вывода. 24h = ‘$’ . len=$-mes_gobl endstart |
Прыжок без условия
Как мы уже говорили, безусловный прыжок выполняется инструкцией , которая включает в себя имя метки, куда следует перебросить точку выполнения программы:
В следующем примере мы рассмотрим использование инструкции :
MOV AX, 00 ; инициализируем регистр AX значением 0
MOV BX, 00 ; инициализируем регистр BX значением 0
MOV CX, 01 ; инициализируем регистр CX значением 1
L20:
ADD AX, 01 ; выполняем инкремент регистра AX
ADD BX, AX ; добавляем AX к BX
SHL CX, 1 ; сдвиг влево регистра CX, что, в свою очередь, удваивает значение регистра CX
JMP L20 ; повторно выполняем стейтменты
|
1 |
MOV AX,00;инициализируемрегистрAXзначением MOV BX,00;инициализируемрегистрBXзначением MOV CX,01;инициализируемрегистрCXзначением1 L20 ADD AX,01;выполняеминкрементрегистраAX ADD BX,AX;добавляемAXкBX SHL CX,1;сдвигвлеворегистраCX,что,всвоюочередь,удваиваетзначениерегистраCX JMP L20;повторновыполняемстейтменты |
Команда Loop – просто продолжает цикл
Первая – это сама команда Loop. Все, что она делает, это то, что он продолжает бесконечный цикл.
Как вы видите ниже, следующий пример базовой команды Loop, будет многократно печатать материал между блоком «do» и «end», пока вы не нажмете Ctrl-C
# cat loop1.rb loop do puts "The AndreyEx Blogs" puts "Press Ctrl-C to Exit!" end
Выполните вышеуказанную программу, чтобы проверить ее. Убедитесь, что вы нажимаете Ctrl-C, чтобы выйти из цикла
# ruby loop1.rb
The AndreyEx Blogs
^CPress Ctrl-C to Exit!
loop1.rb:2: Interrupt
from loop1.rb:1:in `loop'
from loop1.rb:1
Кроме того, имейте в виду, что для почти любых команд цикла в Ruby вместо «do» и «end» вы также можете указать тело цикла в фигурных скобках {}, как показано ниже.
Следующий пример точно такой же, как и выше, но с использованием фигурных скобок.
# cat loop2.rb
loop {
puts "The AndreyEx Blogs"
puts "Press Ctrl-C to Exit!"
}
Предупреждение
Не делайте { на отдельной строке! Если вы это сделаете, вы получите сообщение об ошибке. Следующее неверно, так как { находится на следующей строке после цикла. Он должен быть в той же строке, что и команда loop.
# cat loop2.rb
loop
{
puts "The AndreyEx Blogs"
puts "Press Ctrl-C to Exit!"
}
В приведенном выше примере будет выведено следующее сообщение об ошибке.
# ruby loop2.rb
loop2.rb:3: syntax error, unexpected tSTRING_BEG, expecting kDO or '{' or '('
puts "The AndreyEx Blogs"
^
loop2.rb:5: syntax error, unexpected '}', expecting $end