M_Asm2009LS
.pdfвеличину h, тобто даний регістр вказуватиме на наступний елемент ланцюжка. Стан прапорців не змінюється. Як правило, команда з префіксом повторення не використовується, але її зручно використовувати в програмних циклах замість двох команд:
MOV acc,src
INC SI|ESI (або DEC SI|ESI – в залежності від напрямку просування по ланцюжку)
Дозволяються мнемоніки з вказівкою явної довжини (типу)
операндів LODSB, LODSW, LODSD.
Наявність операнда в команді дозволяє застосовувати префікс заміни сегмента, а також використовується транслятором для визначення типу елементів ланцюжка.
Команда збереження вмісту акумулятора в ланцюжку STOS має такий загальний вигляд:
STOS dst; dst=(acc), DI|EDI=(DI|EDI)+h.
Алгоритм роботи: команда передає вміст акумулятора (байт, слово, подвійне слово) в елемент ланцюжка dst і змінює значення регістра DI|EDI так, що це значення вказує на наступний елемент ланцюжка. Цей ланцюжок повинен знаходитися в додатковому сегменті даних, початкова адреса якого визначається вмістом сегментного регістра ES і префікс заміни сегмента заборонено. З префіксом повторення команда зручна для ініціалізації ланцюжка фіксованим значенням.
Припустимі мнемоніки з явною вказівкою довжини елементів ланцюжка: STOSB, STOSW, STOSD.
Приклади розв’язання задач на обробку ланцюжків
Приклад 1. Використання команди MOVS. Написати програму, яка копіює 1024 слів однієї області оперативної пам’яті в іншу.
Data |
Segment para 'Data' |
||
num = 1024 |
|
||
Sector1 |
dd $+4 |
;$ - оператор мови асемблера, який |
|
|
|
|
; повертає поточне зміщення в сегменті. |
Buf1 |
dw num dup('**'),'$' |
||
Sector2 |
dd $+4 |
|
|
Buf2 |
dw num dup('++’),'$' |
||
Data |
Ends |
|
|
Code |
|
Segment |
para 'code' |
Assume cs:Code,ds:Data,es:Data Main proc far
push ds
91
sub ax,ax push ax mov ax,Data mov ds,ax
Call CopySector ;Виклик процедури копіювання секторів
mov ah,09h |
;Вивід на екран слова OK |
|
mov dx,offset Buf2 |
||
int 21h |
|
|
retf |
|
|
Main endp |
|
|
CopySector proc |
|
|
cld |
; Встановити напрямок обробки рядка |
|
|
; “вперед” (df=0). |
|
push DS |
; Зберегти вміст сегментних регістрів |
;DS і ES.
push ES
les DI,Sector2; Завантаження адреси в сегментні
;та індексні регістри
lds SI,Sector1; початків областей ( ES:DI - Sector2, ; DS:SI - Sector1).
mov CX,1024;Кількість елементів, що копіюємо з
; Sector1 у Sector2.
rep movsw ; Копіювання елементів.
pop ES ; Відновлення вмісту сегментних регістрів. pop DS
ret
CopySector endp Code Ends
End Main
Приклад 2. Використання команди MOVS. Написати програму, яка циклічно зсуває на вісім байтів вправо заданий символьний рядок.
Data |
Segment |
para 'Data' |
;.................. |
|
|
Sb |
db ' Цей рядок буде зсунутий на вісім позицій вправо. $' |
|
NumByte |
dw $ - Sb |
|
Temp |
|
db 8 dup('q') |
Data |
Ends |
|
Code |
Segment para 'code' |
Assume cs:Code,ds:Data,es:Data
Main proc far
92
|
push ds |
|
|
|
sub ax,ax |
|
|
|
push ax |
|
|
|
mov ax,Data |
|
|
|
mov ds,ax |
|
|
|
mov AH,09h |
|
;Виведення на екран стрічки Sb |
|
mov DX,offset Sb |
|
|
|
int 21h |
|
|
|
Call ShiftByte |
|
;Виклик процедури ShiftByte |
|
mov AH,09h |
|
|
|
mov DX,offset Sb |
|
|
|
int 21h |
|
|
|
retf |
|
|
Main Endp |
|
|
|
ShiftByte Proc |
;Процедура зсуву. |
||
|
std |
; Встановити напрямок обробки |
|
|
|
; рядка “назад” (df=1). |
|
|
lea SI, NumByte-2 |
; Адреса останнього символу рядка. |
|
|
push DS |
; Ініціалізація регістра ES. |
|
|
pop ES |
|
|
|
push SI |
; Збереження індексування останнього |
|
|
|
; символу. |
|
|
lea DI,Temp+7; Зберігання 8 останніх символів рядка |
||
|
mov CX,8 |
; у тимчасовому(допоміжному) масиві. |
|
rep |
movsb |
|
|
|
pop DI |
; Відновлення індексу останнього символу. |
|
|
mov CX, NumByte |
; Завантажуємо у регістр кількість |
|
|
sub CX,9 |
; символів, які будемо зсувати. |
|
rep |
movsb |
; Зсув символів на 8 байтів. |
|
|
lea SI,Temp+7; Переміщення символів, які тимчасово |
||
|
|
; зберігалися |
|
|
mov CX,8 |
; у допоміжному масив,і на їх нові позиції. |
|
rep |
movsb |
|
|
ret ShiftByte Endp Code Ends End Main
Приклад 3. Використання команди CMPS. Написати підпрограму, яка порівнює два символьні рядки s1 і s2 (що задаються у сегменті даних). Результат порівняння записуємо в регістр AX. Результатом
93
порівняння буде номер більшого символьного рядка (тобто 1 або 2), або значення 0, якщо вони рівні. Рядок вважається більшим, якщо його перша буква, яка не збіглася з буквою іншого рядка, має більше значення ASCII коду.
Подається тільки фрагменти сегмента коду та даних, які стосуються розв’язання задачі.
Data |
Segment |
para 'Data' |
|
;.................. |
|
|
|
StComp1 db 'First string','$' |
|
||
SizeComp1 = $ - StComp1-1 |
|
||
StComp2 db 'First not string','$' |
|
||
SizeComp2 = $ - StComp2-1 |
|
||
Data |
Ends |
|
|
Code |
Segment para 'code' |
|
|
Assume cs:Code,ds:Data,es:Data |
|||
;............... |
|
|
|
CmpString Proc |
|
||
|
mov |
CX,SizeComp1 |
; Довжина першого рядка. |
|
cmp |
CX,SizeComp2 |
; Порівняння довжин рядків. |
|
jl |
mst |
; В регістр CX меншу довжину. |
|
mov |
CX,SizeComp2 ; Довжина другого рядка. |
|
mst: |
cld |
|
; Встановити напрямок обробки |
|
|
|
;рядка “вперед” (df=0). |
|
lea SI,StComp1 |
; Індексування рядка StComp1 |
|
|
|
|
; регістрами DS:SI. |
|
push DS |
; Ініціалізація регістра ES. |
|
|
pop ES |
|
|
|
lea DI, StComp2 |
; Індексування рядка StComp2 |
|
|
|
|
;регістрами ES:DI. |
repe |
cmpsb |
|
; Порівняння символів, поки вони рівні. |
;Аналіз виходу з циклу порівняння. Зробимо гіпотезу , що рядки рівні.
mov AX,0 |
; Тобто AX=0. |
je mquit |
; Вихід, якщо вони рівні. |
mov AX,1 |
; Нехай перший рядок більший ( AX=1). |
ja mquit |
; Вихід, якщо перший рядок більший. |
mov AX,2 |
; Другий рядок більший. |
mquit: ret |
|
CmpString EndP |
|
Code Ends |
|
End |
|
94 |
|
Приклад 4. Використання команди SCAS. Задано масив знакових цілих чисел розмірності N. Написати процедуру, що замінює у масиві входження числа -24495 на 7000.
Data |
Segment |
para 'Data' |
|
NumVec = 10 |
|
|
|
Vec |
dw 0,-24495,-3,-24496,-24495,24495,0,0,-24495,9 |
||
Data |
Ends |
|
|
Code |
Segment |
para 'code' |
|
Assume cs:Code,ds:Data,es:Data |
|||
; … |
|
|
|
ScanNum Proc |
near ;Процедура заміни -24495 на 7000 |
||
|
cld |
|
; Встановити напрямок обробки |
|
|
|
;рядка “вперед” (df=0). |
|
push ds |
|
; Ініціалізація регістра ES. |
|
pop es |
|
|
|
lea di,Vec |
; Адреса першого елемента вектора (ES:DI). |
|
mov cx,NumVec |
;Розмів масиву. |
||
mov ax,-24495 |
;Шукане число. |
||
m: repne scasw |
|
;Сканувати масив, поки не -4495 або |
|
|
|
|
;кінець вектора. |
jne m1 |
|
; Якщо поточне число не -24495 , то вихід. |
|
mov word ptr [di-2],7000 ; Поміняти -24495 на 7000. |
|||
cmp cx,0 |
|
; |
|
jcxz m1 |
|
|
|
jmp m |
|
; Продовжити пошук. |
|
m1: nop |
|
|
|
ret |
|
|
|
ScanNum Endp |
|
|
|
; … |
|
|
|
Code |
Ends |
|
|
|
End Main |
|
|
Приклад 5. Використання команд LODS та STOS. Написати програму кодування символьного рядка. Для кодування кожний байт циклічно зсунути на один біт вправо.
Data Segment para 'Data' NCb1 equ 90
sCb label byte nmax db NCb1 ncb db ?
Cb db NCb1 Dup (?),'$'
95
nLine |
db 10,13,'$' |
|
||
Data |
Ends |
|
|
|
Code |
Segment |
para 'code' |
||
Assume cs:Code,ds:Data,es:Data |
||||
RCodeByte Proc |
|
|
||
|
cld |
|
|
; Встановити напрямок обробки рядка |
|
|
|
|
;“вперед” (df=0). |
|
push DS |
|
; Ініціалізація регістра ES. |
|
|
pop ES |
|
|
|
|
lea |
SI,Cb |
;Завантажити в SI та DI |
|
|
lea |
DI,Cb |
; адресу Cb. |
|
|
mov CL,ncb |
; CL - кількість байтів. |
||
|
xor CH,CH |
|
||
m15: lodsb |
|
; |
|
|
ror AL,1 |
; |
|
||
stosb |
|
|
|
|
loop m15 |
|
|
||
mov AL,'$' |
|
|
||
stosb |
|
|
|
|
ret |
|
|
|
|
RCodeByte Endp |
|
|
||
Main Proc far ;Основна процедура програми |
||||
|
push DS |
|
|
|
|
sub AX,AX |
|
||
|
push AX |
|
|
|
|
mov AX,Data |
|
||
|
mov DS,AX |
|
||
|
lea DX,nLine |
; Перехід на новий рядок |
||
|
mov AH,09h |
|
||
|
int 21h |
|
|
|
|
lea DX,sCb |
;Завантажити в DX адресу sCb |
||
|
mov AH,0ah |
|
||
|
int 21h |
|
;Читання sCb |
|
|
call RCodeByte ;Виклик процедури RcodeByte |
|||
|
lea DX,nLine |
; Перехід на новий рядок |
||
|
mov AH,09h |
|
||
|
int 21h |
|
; |
|
|
lea DX,Cb |
;Вивід на |
||
|
mov AH,09h |
|
||
|
int 21h |
|
;екран рядка Cb |
|
96 |
|
|
|
|
ret Endp
Code Ends End Main
Завдання для самостійної роботи
I.Розробити програму, яка:
1)копіює 1024 байтів з однієї області оперативної пам’яті в іншу;
2)циклічно зсунути на сім байтів вліво символьний рядок;
3)для заданого масиву беззнакових цілих чисел розмірності N, замінити у масиві входження числа - 1000 на 7000;
4)знаходить кількість входжень слова s1 в рядку s2, де в рядоку s1 заходиться слово, а рядок s2 – текстовий;
5)шифрування символьного рядка. Для шифрування кожний байт циклічно зсунути на один біт вправо.
II. Розробити програми для задач обробки символьних рядків з лабораторної роботи № 4 з використанням ланцюжкових команд.
Список літеpатуpи
1.Абель П. Язык Ассемблера для IBM PC и программирования / Пер. с англ. Ю.В. Сальникова.– М.: Высш. шк., 1992.– 447с..
2.Исида Х. Программирование для микрокомпьютеров / Пер. с яп.–
М: Мир, 1988 .– 224 с.
3.Использование Turbo Assembler при разработке программ / Сост. А.А. Чекатков. – К.: “Диалектика”, 1995. – 288 с.
4.Морс С.П., Алберт Д.Д. Архитектура микропроцессора 80286 / Пер. с англ.- М.: Радио и связь, 1990.– 304 с.
5.Григорьев В.Л. Микропроцессор і486. Архитектура и программирование ( в 4-х книгах). Книга 1. Программная архитектура. / М.: ГРАНАЛ, 1993.– 346 с.
6.Григорьев В.Л. Микропроцессор і486. Архитектура и програмирование ( в 4-х книгах). Книга 2. Аппаратная архитектура. Книга 3. Устройство с плавающей точкой. Книга 4. Справочник по системе команд / М.: ГРАНАЛ, 1993.– 382 с.
7.Юров В., Хорошенко С. Assembler: учебный курс. – СПб.: Питер Ком, 1999. – 672 с.
8.Зубков С.В. Assembler. Для DOS, Windows и Unix. – М.: ДМК, 1999. – 640 c.
9.Юров В. Assembler: учебник. – СПб.: Питер, 2001. – 624 с.
10.Юров В. Assembler: практикум. – СПб.: Питер, 2001. – 400 с.
97
11.Юров В. Assembler: специальный справочник. – СПб.: Питер, 2000. – 496с.
12.Корнеев В.В., Кисельов А.В. Современные микропроцессоры. –
М.: Нолидж, 2000. – 320 с.
98
Навчальне видання
Програмування (мова асемблера) методичні рекомендації до лабораторних робіт
Укладачі: Сопронюк Федір Олексійович (відповідальний за випуск), Лазорик Василь Васильович, Сопронюк Євген Федорович.
Літературний редактор Колодій О.В. Технічний редактор
99