Лекции.ИНФО


Арифметические операции Ассемблер. Команды Ассемблера



Введение в язык Ассемблер

 

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

Программа MASM_v9.0 или MASM_v10.0
Отладчик, например: OLLYDBG.EXE
В установленном месте, где находится программа MASM, создаете файл: aaa.bat

Я выбрал такое название (aaa.bat) для того, чтобы она была в самом верху. И вы могли всегда его видеть. В этом aaa.bat вносите такую информацию:

ml /c /coff "work.asm"
link /SUBSYSTEM:CONSOLE "work.obj"

work.asm - это имя программы, которую нужно компилировать. После ввода этой информации и сохранения можно приступать к программированию.

Ассемблер имеет:

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

В языке Ассемблер есть переменые разных типов: знаковые и беззнаковые форматытипов Shortlnt (signed char), Byte (unsigned char), Integer (int), Word (unsigned int) и т. д.

Напишем программу вычисления выражения: a – e/b – de, где:

a = 5;
b = 27;
c = 86;
е = 1986;
d = 1112;

и сохраним ее там же, где и aaa.bat: work.asm. Если мы хотил откомпилировать другую программу, то нужно в aaa.bat изменить имя файлов, т. е. вместо workзаменить на ... имя. И сохранить его. Если программа не содержит синтаксические ошибки, то должен получиться файл с расширением exe.


Программа:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows

.data ; директива определения данных
_a dw 5 ; запись в 16-разрядный амбарчик памяти с именем _а числа 5
_b dw 27 ; запись _b = 16h
_c dw 86 ; запись _c = 56h
_e dw 1986 ; запись _e = 7c2h
_d dw 1112 ; запись _d = 458
res dw 0 ; резервирование памяти для сохранения переменной res

.code ; директива начала сегмента команд
start:
mov edx,0 ; очистка регистров
mov ebx,0
mov ecx,0
mov ах,_e ; в регистр ах заносим число _e = 7c2h
mul _d ; умножаем _e на _d
SHL edx,16 ; делаем здвиг на 16
mov dx,ax
push edx ; бросаем значение в стек
mov edx,0
mov ах,_e
mov cx,_b
div cx ; делим ах на cx
pop ecx ; достаем из стека значене
sub ecx,eax ; отнимает
mov ах,_a
sub eax,ecx
mov res, eax
ret ; возвращение управления ОС
end start ; окончание программы с именем _start

Результат работы программы:

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

mov куда, откуда - это команда перевылки

mul _d - это команда умнжения регистра ax на _d. Результат попадает в ax

shl edx,16 - команда здвига на 16 разрядов

div cx - команда деления ах на cx. Результат попадает в ax

pop ecx - команда достает из стека значене

sub ecx,eax - команда отнимает значение ecx - eax. Результат попадает в ecx

Арифметические операции Ассемблер. Команды Ассемблера

 

Программирование арифметических выражений в языке Ассемблер происходит через некоторые команды такие, как: mul, div, sub, add. Эти команды называются командами арифметических операций.


Mul – команда умножения. Она умножает регистр ax на то, что стоит после нее. Результат заносится в ax.
Div – команда деления. Она делит регистр axна то, что стоит после нее. Результат заносится в ax.
Add – команда сложения. Слаживает два числа. Результат заносится в первый регистр.
Sub – команда вычитания. Вычитает два числа. Результат заносится в первый регистр.

Пример: Написать программу на ассемблере вычисления выражения: а – e/b – de;
где а =5;
b =27;
c = 86;
е =1986;
d =1112;
Результат вычисления выражения сохранить в памяти. Навести значение и порядок размещения данные в памяти.

Текст программы

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows

.data ; директива определения данные
_a dw 5 ; запись в 16-разрядный амбарчик памяти с именем _а числа 5
_b dw 27 ; запись _b = 16h
_c dw 86 ; запись _c = 56h
_e dw 1986 ; запись _e = 7C2h
_d dw 1112 ; запись _d = 458
res dw 0 ; резервирование памяти для сохранения переменной res

.code ; директива начала сегмента команд
start:
mov edx,0 ; очистка регистров
mov ebx,0 ; очистка регистров
mov ecx,0 ; очистка регистров
mov ах,_e ; в регистр ах заносим число _e = 7C2h
mul _d ; множим _e и _d
SHL edx,16 ; делаем здвиг на 16
mov dx,ax
push edx ; бросаем значение в стек
mov edx,0
mov ах,_e
mov cx,_b
div cx ; делим ах с cx
pop ecx ; достаем из стеку значения
sub ecx,eax ; отнимаем
mov ах,_a
sub eax,ecx
mov res, eax
ret ; возвращение управление ОС
end start ; окончание программы с именем _start

Результат работы программы


Двумерные массивы на Ассемблере. Ассемблер двумерными массивами примеры

 

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

Пример: Ввести двумерный массив размером 7 х 4. Найти наибольший элемент двумерного массива. Удалить строку с максимальным элементом.


Текст программы:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
include \masm32\include\msvcrt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные
_c dd 28
sum dd 0
max dd 0 ; переменная для максимального числа

frmt db "%d",0
buf db 30 dup(?)
stdout DWORD ?
stdin DWORD ?
cRead dd ?
temp dd ?
mas1 dd 28 dup(0)
nomer dd 0
st1 db "Vvesty masiv: "
st2 db "Вывод результата удаления", 0
st3 db 10 dup(0)
ifmt db "Удалена %d строка. Внимание!!! Проверьте правильность ввода, чтобы результат был правильным",0

.code ; директива начала кода программы
_start:
lea esi, mas1 ; загрузка адреса начала массива
mov ecx,_c
m1:
mov ebx,ecx
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin,eax
invoke WriteConsoleA,stdout,ADDR st1,14,NULL,NULL ; VIVOD ST1
invoke ReadConsole,stdin,ADDR buf,20,ADDR cRead,NULL ; чтения числа как символ
invoke crt_atoi,ADDR buf ; преобразовать символ в число
mov [esi],eax
add esi,4
mov ecx,ebx
loop m1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m3:
.IF(eax>max) ; условие
mov max,eax
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3

.ELSE ; иначе
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3 ; перейти, если ecx не равен 0

.ENDIF ; окончание директивы высокого уровня

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m4:

.IF(eax == max) ; условие
inc nomer
add esi,4 ; расчет адреса нового числа
mov eax[esi]
jmp m5
loop m4

.ELSE ; иначе
inc nomer
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m4 ; перейти, если ecx не равен 0

.ENDIF ; окончание директивы высокого уровня

m5:
.IF(nomer <= 7) ; условие
mov ecx,7
x1: lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
mov eax,0
add esi,4
loop x1
mov nomer,1
jmp end_prog
.ENDIF

.IF(nomer <=14) ; условие
mov ecx,7
lea esi, mas1 ; загрузка адреса начала массива
xx: add esi,4
loop xx
mov ecx,7
x2: mov eax [esi] ; загрузка числа
mov eax,0
add esi,4
loop x2
mov nomer,2
jmp end_prog
.ENDIF

.IF(nomer <=21) ; условие
mov ecx,7
lea esi, mas1 ; загрузка адреса начала массива
xx2: add esi,4
loop xx2
mov ecx,7
xx3: add esi,4
loop xx3
mov ecx,7
x3: mov eax [esi] ; загрузка числа
mov eax,0
add esi,4
loop x3
mov nomer,3
jmp end_prog
.ENDIF

.IF(nomer <=28) ; условие
mov ecx,7
lea esi, mas1 ; загрузка адреса начала массива
xxx2: add esi,4
loop xxx2
mov ecx,7
xxx3: add esi,4
loop xxx3
mov ecx,7
xxx4: add esi,4
loop xxx4
mov ecx,7
x4: mov eax [esi] ; загрузка числа
mov eax,0
add esi,4
loop x4
mov nomer,4
jmp end_prog
.ENDIF

end_prog:

mov ebx,nomer

invoke wsprintf \
ADDR st3 \
ADDR ifmt \
ebx
invoke MessageBox \
NULL \
addr st3 \
addr st2 \
MB_OK
invoke ExitProcess,0
ret
end _start ; конец программы

Результат работы программы:



Ассемблер структуры. Примеры задач

 

Пример: Задана матрица 3 X 4. Определить максимальный элемент каждой строки. Результат выполнения программы вывести в окно консоли.

Текст программы:

.386 ; директива определения типа микропроцессора
.model flat, stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
ExitProcess proto: dword ; прототип API-функции

DATE1 STRUCT ; тип данных СТРУКТУРА с именем DATE1
elem1 db ? ; имя первого поля структуры
elem2 db ? ; имя второго поля структуры
elem3 db ? ; имя третьего поля структуры
elem4 db ? ; имя четвертого поля структуры
DATE1 ENDS
.data ; директива определения данные
max db 0
nomer db 1
str1 DATE1 <20,9,2,15> ; структура с именем str1
str2 DATE1 <6,31,1,3> ; структура с именем str2
str3 DATE1 <4,6,155,2> ; структура с именем str2
st1 db " Вывод максимальных чисел ",0
st2 db 180 dup(?),0
stemp db 0
stemp2 db 3 dup(?),0
st4 db " Нажмите Ок",0
st3 db "-й ряд имеет максимальное число = "
kol3 = $ - st3
kol4 = $ - st4
ifmt db "%d ",0
.code ; директива начала сегмента-данных
start: ; метка начала программы с именем start
xor edx,edx ; заполнение нулями
mov ebx,3 ; загрузка количества строк
lea esi, str1 ; загрузка адреса первой строки структуры
lea edi,st2
m1: mov ecx,4 ; количество элементов в строке
mov max,0
m2: mov al[esi] ; загрузка элемента из строки структуры
.IF (al > max)
mov max,al
.ENDIF
jmp m4 ; безусловный переход, если наоборот
m3: add edx,eax ; добавление негативных элементов строки структуры
m4: inc esi ; подготовка адреса нового элемента
loop m2 ; есх := ecx – 1 и переход на m3, если не нуль

mov eax,0
mov al,nomer
invoke wsprintf \ ; API-ФУНКЦИЯ превращения числа
ADDR stemp \ ; адрес буфф., куда будет записан помет. символов
ADDR ifmt \ ; адрес строки превращения формата
eax ; регистр, содержание которого превращается
mov al,stemp
mov [edi],al
inc edi

lea esi, st3
mov ecx,kol3

_m1:
mov al[esi]
mov [edi],al
inc esi
inc edi
loop _m1
mov eax,0
mov al,max

invoke wsprintf \ ; API-ФУНКЦИЯ превращения числа
ADDR stemp2 \ ; адрес буфф., куда будет записан помет. символов
ADDR ifmt \ ; адрес строки превращения формата
eax ; регистр, содержание которого превращается
lea esi, stemp2
mov ecx,3
z1:
mov al[esi]
mov [edi],al
inc edi
inc esi
loop z1

mov al,10
mov [edi],al
inc edi
inc nomer

dec ebx ; ebx := ebx – 1
.IF ebx == 2
lea esi,str2 ; загрузка адреса новой строки
jmp m1 ; переход на новый цикл
.ELSEIF ebx == 1
lea esi,str3 ; загрузка адреса новой строки
jmp m1 ; переход на новый цикл
.ENDIF

mov al,10
mov [edi],al
inc edi
lea esi, st4
mov ecx,kol4
inc esi
_z1:
mov al[esi]
mov [edi],al
inc esi
inc edi
loop _z1

invoke MessageBox \ ; API-ФУНКЦИЯ выведения окна консоли
NULL \ ; hwnd – идентификатор окна
addr st2 \ ; адрес строки, который содержит текст сообщения
addr st1 \ ; адрес строки, который содержит заглавие сообщения
MB_OK ; вид диалогового окна

invoke ExitProcess, 0 ; возвращение управления ОС Windows
end start ; директива окончания программы с именем start


Результат работы программы:


Текст процедуры программы

.686 ; директива определения типа микропроцессора
.model flat ; задание линейной модели памяти
option casemap:none
public _abcd
extern _a:dword, _b:dword, _c:dword,_d:dword
.code ; директива начала программы
_abcd proc ; ab - c/d
mov eax,_a ; пересылка из памяти с именем _а в eax
mov ebx,_b ; пересылка из памяти с именем _b в ebx
mul ebx ; edx, eax := eax ? ebx
mov esi,eax
mov edi,edx
mov eax,_c
mov ebx,_d
xor edx,edx ; подготовление к делению
div ebx
mov ecx,0
sub ecx,edx ; вычитание мелкой части из целого числа
sbb esi,eax ; вычитание целой младшей части
sbb edi,0 ; вычитание позычки, если она есть
ret
_abcd endp
end ; директива окончания программы


Результат работы программы


Массивы в Ассемблере. Программа на Ассемблере. Пример массив элементов

 

Пример задачи с использованием массива на ассемблере: Заданы массивы Aи Виз N= 8 элементов. Сформировать новый массивСпо правилу: если у элементов Aiи Bi биты 0, 1 и 2 совпадают, то Ci= Аi + Вi.

Текст прогаммы

.686 ; директива определения типа микропроцессора
.model flat, stdcall ; задание линейной модели памяти
; но соглашения ОС Windows
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib
ExitProcess proto:DWORD

.data ; директива определения данные
st1 db "Вывод массива! С", 0
st2 db 10 dup(?),0
ifmt db "%d",0
masivA db 7,34,34,45,2,6,2-6
masivB db 54,2,7,43,13-7,65,9
masivC db 8 dup(0)
work1 db 0
work2 db 0
prom dd 0

.code ; директива начала кода программы
_start:
mov eax,0
mov ebx,0
mov ecx,8
mov edx,0

 

lea esi, masivA
lea edi, masivB
lea edx, masivC

M1:
mov prom,ebx
mov al, byte ptr[esi+ebx]
mov bl, byte ptr[edi+ebx]
mov work1, al
mov work2, bl
and eax,07h
and ebx,07h
sub eax,ebx
jz M3

M2:
mov ebx, prom
inc ebx
loop M1
jmp M4

M3:
mov al, work1
mov bl, work2
add al,bl
mov [edx+ebx],al
jmp M2

M4:
mov edx,0
mov ecx,08h
Prom:
lea esi,masivC;
mov al[esi+edx]
cmp al,0
jnz _M2
_M1: inc edx
loop Prom
jmp _M3
_M2:
mov ebx,eax
jmp _M1
_M3:
invoke wsprintf \
ADDR st2 \
ADDR ifmt \
ebx
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; окончание программы


Результат работы программы

Макросы в Ассемблере. Примеры задач

 

Пример: Написать программу с использованием макросовдля вычисления одного из выражений без предыдущего математического упрощения операций:
2x – 3 + 8(2x –3);

Текст программы:

.686 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
; но соглашения ОС Windows
option casemap:none ; отличие малых и больших букв
includelib \masm32\lib\kernel32.lib
ExitProcess proto:dword ; прототип API-функції
mSubB macro x,b ; макрос с именем mSubB
mov al,x
shl al,1 ; занос переменной а
sub al,b ; вычитание а – b
mov res1,al ;; сохранение результата в памяти
endm ; окончание макроса
.data ; директива определения данные
x db 6 ; сохранение в амбарчике памяти, размером в байт операнда 6
b db 3
res1 db 0 ; резервирование памяти для результата res1
res2 dw 0 ; резервирование памяти для результата res2
.code ; директива начала программы
_start: ; метка начала программы с именем _start
xor eax,eax
xor ebx,ebx
mSubB [x][b] ; вызов макроса
mov al,8
mov bl,res1
mul bl
mov bl,al
mSubB [x][b] ; вызов макроса
mov al,res1 ; занос с расширением разрядности
add bx,ax
mov res2,bx ; сохранение остаточного результата
invoke ExitProcess, 0 ; возвращение управления ОС Windows
end _start ; директива окончания программы с именем _start

Результат работы программы:


Файл 1dll.asm


.386
.model flat,stdcall
option casemap:none ; отличие строчных и прописных букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc
include \masm32\include\msvcrt.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\fpu.lib

includelib 1.lib
ExitProcess proto :DWORD
Mas_sum proto :DWORD, :DWORD, :DWORD ; прототип процедуры

.data ; директива определения данные
_c dd 40
sum dd 0
op1 dd 6 ; запись в 32-разрядную память op1
op2 dd 22 ; минимальных предел
frmt db "%d",0
buf db 30 dup(?)
stdout DWORD ?
stdin DWORD ?
cRead dd ?
temp dd ?
mas1 dd 40 dup(0)

st1 db "Vvesty masiv: "
st2 db "Вывод количества элементов в пределах (6,22) массива! А, 0
st3 db 10 dup(0)
ifmt db "количество = %d",0
.code ; директива начала кода программы

_start:
lea esi, mas1 ; загрузка адреса начала массива
mov ecx,_c
m1:
mov ebx,ecx
invoke GetStdHandle,STD_OUTPUT_HANDLE
mov stdout,eax
invoke GetStdHandle,STD_INPUT_HANDLE
mov stdin,eax
invoke WriteConsoleA,stdout,ADDR st1,14,NULL,NULL ; VIVOD ST1
invoke ReadConsole,stdin,ADDR buf,20
ADDR cRead,NULL ; чтения числа как символ
invoke crt_atoi,ADDR buf ; преобразовать символ в число
mov [esi],eax
add esi,4
mov ecx,ebx
loop m1
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

mov ecx,_c
lea esi, mas1 ; загрузка адреса начала массива
mov eax [esi] ; загрузка числа
m3:
invoke Mas_sum, op1,op2,eax
add sum,ebx
add esi,4 ; расчет адреса нового числа
mov eax[esi]
loop m3

mov ebx,sum

invoke wsprintf \
ADDR st3 \
ADDR ifmt \
ebx
invoke MessageBox \
NULL \
addr st3 \
addr st2 \
MB_OK
invoke ExitProcess,0
ret
end _start ; конец программы

Результат работы программы:

Ассемблер сопроцессор. Примеры задач

 

Пример 1: Вычислить 6 значений функции:Yn = 4x/(x + 5) (х изменяется от 3 с шагом 1,25). Результат округлить к целому, разместить в памяти и вывести на экран.


1.1 Текст программы


.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 3 ; сохранение в 32-разрядном амбарчике памяти переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 1.25
krok dd 5
_umnoj dd 4 ; умножение на 4
probel dd 09h ; для вывода на экран
res dd 0
ifmt db "Yn = %d",0
st1 db "Yn = 4x/(x + 5) ",0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
finit ; инициирующее сопроцессора
mov ecx,6
fild _x
m1:
fld st(0)
fiadd krok
fld st(1)
fimul _umnoj
fmul st(0),st(1)
fistp dword ptr [edi]
fistp dword ptr [esi]
fadd hod

add edi,4

loop m1

lea edi,st2
mov eax[edi+20]

invoke wsprintf \
ADDR st2 \
ADDR ifmt \
eax
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; зак?нчення программы


1.2 Результат работы программы


 

 

Пример 2 : Определить номер (х) элемента функции: xn = + 5, при котором сумма элементов превысит 12 000. Результат разместить в памяти и вывести соответствующие сообщения.


2.1 Текст программы


.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0 ; сохранение переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 1
krok dd 3
plus dd 5
mem dw ?
_MASK equ 0C00h
limit dd 12000
ifmt db "№ = %d",0
st1 db "Вывод номера елемента",0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
mov edx,limit
finit ; инициализация сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,6
m1:
inc _x
fild _x
fild krok
fyl2x
fld st(0)
frndint
fsub st(1),st(0)
frndint
f2xm1
fiadd hod
fldz
fadd st(0),st(2)
f2xm1
fiadd hod
fmul st(0),st(1)
fiadd plus
fistp dword ptr [edi]
fistp dword ptr [esi]
fistp dword ptr [esi]
mov eax[edi]
add ebx,eax
add edi,4
add esi,4
cmp edx,ebx
jns m1

mov eax,_x

invoke wsprintf \
ADDR st2 \
ADDR ifmt \
eax
invoke MessageBox \
NULL \
addr st2 \
addr st1 \
MB_OK
invoke ExitProcess,0
end _start ; зак?нчення программы


2.2 Результат работы программы


 

Пример 3: Вычислить 4 значения функции: Y = 3 * log2(x2+1), x изменяется от 0,2 с шагом 0,3.


3.1 Текст программы


.386 ; директива определения типа микропроцессора
.model flat,stdcall ; задание линейной модели памяти
option casemap:none ; отличие малых и больших букв
include \masm32\include\windows.inc
include \masm32\include\kernel32.inc
include \masm32\include\fpu.inc
include \masm32\include\user32.inc

includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\fpu.lib

.data ; директива определения данные

_x dd 0.2 ; сохранение в 32-разрядном амбарчике памяти переменной х
_y dd 0 ; резервирование 32-х разрядов памяти для переменной в
tmp1 dd ? ; резервирование 32-х разрядов памяти для переменной tmp1
tmp2 dd ? ; резервирование 32-х разрядов памяти для переменной tmp2
hod dd 0.3
umnoj dd 3
const dd 4
mem dw ?
_MASK equ 0C00h
ifmt db "Y = %d",0
st1 db "Вывод функции",0
st2 dd 10 dup(?),0
st3 dd 10 dup(?),0

.code ; директива начала кода программы
_start: ; директива начала кода программы
lea edi,st2
lea esi,st3
xor eax,eax ; обнуление регистров
xor ebx,ebx
xor ecx,ecx
xor edx,edx
finit ; инициализания сопроцессора
fstcw mem
OR mem,_MASK
fldcw mem
mov ecx,4

fld _x
fld _x
m1:
fild umnoj
fld st(1)
fmulp st(2),st(0)
fyl2x
fld hod
fadd st(2),st(0)

fistp dword ptr [edi]
dec const
jz m2
fistp dword ptr [esi]
fld st(0)
mov eax[esi]
add edi,4
add esi,4
loop m1
m2:

 

invoke FpuFLtoA, 0, 10, ADDR st2, SRC1_FPU or SRC2_DIMM
invoke MessageBox, NULL, addr st2, addr st1, MB_OK
invoke ExitProcess, NULL ; возвращение управления ОС Windows
; но освобождение ресурсов

end _start ; директива окончания программы с именем start

Результат работы программы


Общая информация

Здесь представлена информация по ассемблеру всей серии AVR, т.к. все микроконтроллеры этой серии программно совместимы.
Ассемблер – это инструмент, с помощью которого создаётся программа для микроконтроллера. Ассемблер транслирует ассемблируемый исходный код программы в объектный код, который может использоваться в симуляторах или эмуляторах AVR. Также ассемблер генерирует код, который может быть непосредственно введен в программную память микроконтроллера.
При работе с ассемблером нет никакой необходимости в непосредственном соединении с микроконтроллером.

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

Строка программы может быть в одной из четырёх форм:

[ Метка:] директива [операнды] [Комментарий]
[ Метка:] команда [операнды] [Комментарий]
Комментарий
Пустая строка

Комментарий имеет следующую форму:

; [Текст]

Таким образом любой текст после символа “ ; ” игнорируется ассемблером и имеет значение только для пользователя.

Операнды можно задавать в различных форматах:

- десятичный (по умолчанию): 10,255
- шестнадцатеричный (два способа): 0x0а, $0а
- двоичный: 0b00001010, 0b11111111
- восьмеричный (впереди ноль): 010, 077

 

 

Система команд

Система команд микроконтроллеров ATMEL семейства AVR очень большая и в то же время эффективная. Одной из отличительных особенностей микроконтроллеров AVR является то, что почти все команды выполняются за 1 тактовый цикл. Исключение составляют команды перехода. Это существенно увеличивает производительность микроконтроллера даже при относительно невысокой тактовой частоте.

Все команды можно классифицировать на 5 типов:
1. арифметические команды;
2. логические команды;
3. команды перехода;

· команды передачи данных;

· побитовые команды и команды тестирования битов.

 

 

Директивы ассемблера

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

Таблица 1.2.
Директивы ассемблера

Директива Описание
BYTE Зарезервировать байт под переменную
CSEG Сегмент кодов
DB Задать постоянным(и) байт(ы) в памяти
DEF Задать символическое имя регистру
DEVICE Задать для какого типа микроконтроллера компилировать
DSEG Сегмент данных
DW Задать постоянное(ые) слово(а) в памяти
EQU Установите символ равный выражению
ESEG Сегмент EEPROM
EXIT Выход из файла
INCLUDE Включить исходный код из другого файла
LIST Включить генерацию .lst - файла
NOLIST Выключить генерацию .lst - файла
ORG Начальный адрес программы
SET Установите символ равный выражению

Синтаксис всех директив следующий:
.[директива]
То есть перед директивой должна стоять точка. Иначе ассемблер воспринимает это как метку.
Дадим несколько пояснений наиболее важным директивам ассемблера

CSEG - Code segment

Директива CSEG указывает на начало сегмента кодов. Ассемблируемый файл может иметь несколько кодовых сегментов, которые будут объединены в один при ассемблировании.
Синтаксис:

.CSEG
Пример:
.DSEG ; Начало сегмента данных
vartab: .BYTE 4 ; Резервируется 4 байта в СОЗУ
.CSEG ; Начало сегмента кодов
const: .DW 2 ; Записать 0x0002 в программной памяти
mov r1,r0 ; Что-то делать

DSEG - Data Segment

Директива DSEG указывает на начало сегмента данных. Ассемблируемый файл может содержать несколько сегментов данных, которые потом будут собраны в один при ассемблировании. Обычно сегмент данных состоит лишь из директив BYTE и меток.

Синтаксис:

.DSEG
Пример:
.DSEG ; Начало сегмента данных
var1: .BYTE 1 ; Резервировать 1 байт под переменную var1
table: .BYTE tab_size ; Резервировать tab_size байтов.
.CSEG
ldi r30,low(var1)
ldi r31,high(var1)
ld r1,Z

ESEG - EEPROM Segment

Директива ESEG указывает на начало сегмента EEPROM памяти. Ассемблируемый файл может содержать несколько EEPROM сегментов, которые будут собраны в один сегмент при ассемблировании. Обычно сегмент EEPROM состоит из DB и DW директив (и меток). Сегмент EEPROM памяти имеет свой собственный счетчик. Директива ORG может использоваться для размещения переменных в нужной области EEPROM.
Синтаксис:

.ESEG

Пример:

.DSEG ; Начало сегмента данных
var1: .BYTE 1 ; Резервировать 1 байт под переменную var1
table: .BYTE tab_size ; Зарезервировать tab_size байт.
.ESEG
eevar1: .DW 0xffff ; Записать 1 слово в EEPROM

Написание программы

Текст программы можно набирать в любом текстовом редакторе, такие как встроенный редактор Norton Commander, FAR, а также Microsoft Word, WordPad и других. Также можно использовать специально предназначенные для этого программы Wavrasm, AVR Studio
Для создания программы не обязательно использовать ассемблер, программное обеспечение AVR поддерживает также и язык C или С++. Но в лабораторном комплексе этот вариант не рассматривается.
Программа, написанная на ассемблере, должна иметь определенную структуру.
Предлагается следующий шаблон (для AT90S8535)

;*******************************************
; название программы,
; краткое описание, необходимые пояснения
:*******************************************
;******подключаемые дополнительные файлы
.include “8535def.inc” ; файл описания AT90S8535
.include «имя_файла1.расширение» ; включение дополнительных
.include «имя_файла2.расширение» ; файлов
;******глобальные константы
.equ имя1 = xxxx ;
.equ имя2 = nnnn
;******глобальные регистровые переменные
.def имя1= регистр
.def имя2= регистр
;*******сегмент данных
.dseg
.org xxxx ; адрес первого зарезервированного байта
label1: .BYTE 1 ; резервировать 1 байт под переменную label1
label2: .BYTE m ; резервировать m байт под переменную label2
;****** сегментEEPROM(ЭСППЗУ)
.eseg
.org xxxx ; адрес первого зарезервированного байта
.db выражение1,выражение2,… ; записать список байтов в EEPROM.
.dw выражение1,выражение2,… ; записать список слов в EEPROM.
;******сегмент кодов
.cseg
.org $0000 ; адрес начала программы в программной памяти
;****** вектора прерываний (если они используются)
rjmp reset ;прерывание по сбросу
.org $0002
rjmp INT0 ;обработчик прерывания IRQ0
.org $0004
rjmp INT1 ;обработчик прерывания IRQ1
.org adrINTx ;адрес следующего обработчика прерываний
rjmp INTx ;обработчик прерывания x
……. ;далее по порядку располагать обработчики остальных ;прерываний

;*******начало основной программы
main: <команда> xxxx
… …

;******* подпрограммы
;*******подпрограмма 1
subr1: <команда> xxxx
…… ………. ……
ret
;*******подпрограмма 2
subr2: <команда> xxxx
…… ………. ……
ret
…………….
;******* программы обработчиков прерываний
INT0: <команда> xxxx
…… ………. ……
reti
INT1: <команда> xxxx
…… ………. ……
reti
INTx: <команда> xxxx
…… ………. ……
reti
………………………
; конец программы никак не обозначается.

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

Как уже указывалось, программа простейшая: вычесть из числа 5 число 3. Если включен тумблер SA1 (рис. 1.2), то на индикацию выдать результат вычитания. Если тумблер SA1отключен – на индикацию вывести цифру ноль.
Алгоритм программы (рис. 1.5) соответствует программе №1, использующей директиву equ ассемблера.
Программа №2 отличается от программы №1 резервированием по одному байту оперативной памяти под семисегментные коды цифр от 0 до 9.

Программа №3 самая короткая. Она использует директиву .dw для определения слов в программной памяти. В программе используется команда LPM ассемблера. По этой команде загружается байт, адресуемый регистром Z в регистр R0. Команда обеспечивает доступ к любому байту памяти программы, организованной как 16 битное слово. Младший бит регистра Z определяет, осуществляется ли доступ к младшему байту слова (0) или к старшему (1).

Рис. 1.5 Алгоритм программы №1

;Программа №1.Использование директивы equ

.include "8535def.inc" ;включить файл – описание для AT90S8535
.dseg ;сегмент данных
.equ cod0=$64 ;присвоение имен ячейкам SRAM
.equ cod1=$65
.equ cod2=$66
.equ cod3=$67
.equ cod4=$68
.equ cod5=$69
.equ cod6=$6a
.equ cod7=$6b
.equ cod8=$6c
.equ cod9=$6d

.cseg
.org 0
rjmp reset
.org $30 ;начало программы

reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16

ldi zl,$64 ;задание адреса начала зарезервированных ячеек
ldi zh,$00

ldi r16,$ff ;настроить порт С на выход
out ddrc,r16
ldi r16,00 ;настроить порт А на вход
out ddra,r16
ldi r16,$c ;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0 ;настроить порт D: биты 0...4 на вход, остальные на выход
out ddrd,r16

sbi portB,3 ;выдать 1 на разряд 3 порта В

 

ldi r17,$3f ;задание семисегментных кодов
sts cod0,r17
ldi r17,$06
sts cod1,r17
ldi r17,$5b
sts cod2,r17
ldi r17,$4f
sts cod3,r17
ldi r17,$66
sts cod4,r17
ldi r17,$6d
sts cod5,r17
ldi r17,$7d
sts cod6,r17
ldi r17,$07
sts cod7,r17
ldi r17,$7f
sts cod8,r17
ldi r17,$6f
sts cod9,r17

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен тумблер SA1,то пропустить
rjmp m2 ;следующую команду

mov r20,r17 ; в r20 поместить уменьшаемое
sub r20,r18 ; вычесть вычитаемое
rjmp vv
m2:
ldi r20,0
vv:
push zl ;сохранить zl в стеке
add zl,r20 ;сложить zl с результатом
ld r0,z ;семисегментный код результата переслать в r20
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

;Программа №2. Использование оперативной памяти под переменные

.include "8535def.inc" ;подключение файла описания AT90S8535

.dseg ;сегмент данных
.org $64 ;адрес первого зарезервированного байта
cod0:.byte 1 ;резервирование по одному байту под переменные
cod1:.byte 1
cod2:.byte 1
cod3:.byte 1
cod4:.byte 1
cod5:.byte 1
cod6:.byte 1
cod7:.byte 1
cod8:.byte 1
cod9:.byte 1

.cseg ;сегмент кодов
.org $0 ;адрес начала программы в программной памяти
rjmp reset ;прерывание по сбросу при подаче питания
;или при нажатии на кнопку "Сброс"
reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16

ldi zl,$64 ;задание адреса начала зарезервированных ячеек
ldi zh,$00

ldi r16,$ff ;настроить порт С на выход
out ddrc,r16
ldi r16,00 ;настроить порт А на вход
out ddra,r16
ldi r16,$c ;настроить порт В: биты 2 и 3 на выход, остальные на вход
out ddrb,r16
ldi r16,$f0 ;настроить порт D: биты 0...4 на вход, остальные на выход
out ddrd,r16

sbi portb,3 ;выдать 1 на разряд 3 порта В

 

ldi r17,$3f ;задание семисегментных кодов
sts cod0,r17
ldi r17,$06
sts cod1,r17
ldi r17,$5b
sts cod2,r17
ldi r17,$4f
sts cod3,r17
ldi r17,$66
sts cod4,r17
ldi r17,$6d
sts cod5,r17
ldi r17,$7d
sts cod6,r17
ldi r17,$07
sts cod7,r17
ldi r17,$7f
sts cod8,r17
ldi r17,$6f
sts cod9,r17

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен тумблер SA1,то пропустить
rjmp m2 ;следующую команду

mov r20,r17 ; в r20 поместить уменьшаемое
sub r20,r18 ; вычесть вычитаемое
rjmp vv
m2:
ldi r20,0
vv: push zl ;сохранить zl в стеке
add zl,r20 ;сложить zl с результатом
ld r0,z ;семисегментный код результата переслать в r20
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

;Программа №3. Использование директивы .dw

.include "8535def.inc" ;подключение файла описания AT90S8535

.cseg
.org 0
rjmp reset
.dw $063f,$4f5b,$6d66,$077d,$6f7f,$7c77,$5e39,$7179 ;семисегментные коды
reset:
ldi r16,$00 ;определение стека с вершиной по адресу $00ff
out sph,r16
ldi r16,$ff
out spl,r16
ldi r16,$ff
out ddrc,r16 ;настроить порт С на выход
ldi r16,00
out ddra,r16 ;настроить порт А на вход
ldi r16,$c
out ddrb,r16 ;настроить порт В: биты 2 и 3 на выход, остальные на вход
ldi r16,$f0
out ddrd,r16 ;настроить порт D: биты 0...4 на вход, остальные на выход

sbi portb,3 ;выдать 1 на разряд 3 порта В

ldi zl,02 ;установить адрес семисегментного кода нуля в регистр Z
ldi zh,00

ldi r17,5 ;задание уменьшаемого
ldi r18,3 ;задание вычитаемого

m1: sbis pina,4 ;если включен SA1, то пропустить следующую команду
rjmp m2
mov r20,r17 ;в r20 поместить уменьшаемое
sub r20,r18 ;вычесть вычитаемое
rjmp vv
m2:
ldi r20,0 ;присвоить результату значение нуль
vv: push zl ;сохранить zl в стеке
add zl,r20 ; сложить zl с результатом
lpm ;загружаем бит, адресуемый регистром Z, в регистр R0
pop zl ;извлечь zl из стека
out portc,r0 ;выдать результат на индикацию
rjmp m1

 

Ввод программы

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

Переключатель режима работы платы ЖКИ рабочего места необходимо поставить в положение “Программирование”. При нажатии на кнопку “Сброс” блока управления на ЖКИ появляется надпись “Место” с соответствующим номером. Этому номеру будет соответствовать окно на экране дисплея ПЭВМ.

Программное обеспечение располагается в каталоге STAND90, в котором есть два подкаталога SERVER и PK&MK. Программное обеспечение работает в среде WINDOWS. Программа SERVER запускается файлом server.bat, программа PK&MK – файлом Pk&mk.exe.
Сразу после запуска программы-сервера на экран выводится меню из трех пунктов: 1 – удалить старые файлы (например, оставшиеся после предыдущей работы), 2 – загрузить старые файлы (для продолжения работы с ними), 3 – любая другая клавиша (например, пробел или Esc) – не удалять и не загружать. После нажатия соответствующей клавиши на экране появляется восемь окон.
Пример содержимого экрана ПЭВМ во время работы программы представлен на рис. 1.6.

Каждое окно имеет надпись “Место” с номером рабочего места и область размером 4х16 знакомест, в которой отображается информация, выводимая на ЖКИ соответствующего рабочего места. Внизу экрана имеется строка, в которой описаны “горячие” клавиши – клавиши и сочетания клавиш, нажатия на которые вызывают определенные действия.

Из “горячих” клавиш студенту доступна только клавиша F6 (просмотр ошибок). Назначение “горячих” клавиш представлено в табл. 1.3.
Узлы набора программ рабочих мест имеют встроенный микроконтроллер AT89C51 для управления ЖКИ и клавиатурой. Микроконтроллер передает клавиатурные коды с рабочих мест в ПЭВМ и отображает принятые от ПЭВМ данные на ЖКИ.

 









Читайте также:

Последнее изменение этой страницы: 2016-03-22; Просмотров: 942;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная