Навчальний курс

Стеком називається структура даних, організована за принципом LIFO ( «Last In - First Out» або «останнім прийшов - першим пішов»). Стек є невід'ємною частиною архітектури процесора і підтримується на апаратному рівні: в процесорі є спеціальні регістри (SS, BP, SP) і команди для роботи зі стеком.

Схема організації стека в процесорі 8086 показана на малюнку:

Навчальний курс

Для стека існують лише дві основні операції:

  • додавання елемента на вершину стека (PUSH);
  • витяг елемента з вершини стека (POP);

Додавання елемента в стек

Виконується командою PUSH. У цій команди один операнд, який може бути безпосереднім значенням, 16-бітовим регістром (в тому числі сегмент) або 16-бітної змінної в пам'яті. Команда працює в такий спосіб:

Навчальний курс

Існують ще 2 команди для додавання в стек. Команда PUSHF поміщає в стек вміст регістра прапорів. Команда PUSHA поміщає в стек вміст всіх регістрів загального призначення в наступному порядку: АХ, СХ, DX, ВХ, SP, BP, SI, DI (значення DI буде на вершині стека). Значення SP поміщається то, яке було до виконання команди. Обидві ці команди не мають операндов.

Витяг елемента з стека

Виконується командою POP. У цій команди також один операнд, який може бути 16-бітовим регістром (в тому числі сегмент, але крім CS) або 16-бітної змінної в пам'яті. Команда працює в такий спосіб:

Зверніть увагу, що витягнутий з стека елемент не обнуляється і не затирається в пам'яті, а просто залишається як сміття. Він буде перезаписан при приміщенні нового значення в стек.

Навчальний курс

Відповідно, є ще 2 команди. POPF поміщає значення з вершини стека в регістр прапорів. POPA відновлює з стека все регістри загального призначення (але при цьому значення для SP ігнорується).

Є двовимірний масив - таблиця 16-бітних значень зі знаком розміром n рядків на m стовпців. Програма обчислює суму елементів кожного рядка і зберігає результат в масиві sum. Перший елемент масиву буде містити суму елементів першого рядка, другий елемент - суму елементів другого рядка і так далі.

Як бачите, у програмі два вкладених циклу: зовнішній і внутрішній. Зовнішній цикл - це цикл по рядках таблиці. Внутрішній цикл обчислює суму елементів рядка. Стек тут використовується для тимчасового зберігання лічильника зовнішнього циклу. Перед початком внутрішнього циклу CX зберігається в стеку, а після завершення відновлюється. Такий прийом можна використовувати для програмування і більшої кількості вкладених циклів.

Навчальний курс

; Здається найбільш швидкий варіант застосовний до даного випадку
use16
org 100h
jmp main

; =================================;
main:
; Зберігаємо рядок в стек
mov bx, strReverse
mov ax, [bx]
xchg al, ah
push ax
mov ax, [bx + 2]
xchg al, ah
push ax
mov ax, [bx + 4]
xchg al, ah
push ax
mov ax, [bx + 6]
push ax
; Витягуємо з стека вже перевернуту
pop ax
mov [bx], al
pop ax
mov word [bx + 1], ax
pop ax
mov word [bx + 3], ax
pop ax
mov word [bx + 5], ax
; Відображаємо рядок
mov dx, bx
mov ah, 09h
int 21h

Згоден. Швидше за все такий варіант коду швидше, так як цикл перетворений в лінійний алгоритм. Однак, працювати буде тільки з рядком з 7 символів.

Ще можна ось так зробити:

jmp start
press db 13,10, 'Press any key ... $'
string db '$! olleH'
len db 7

movzx cx, [len]
xor si, si

cyk1:
movzx ax, [string + si]
push ax
inc si
loop cyk1

movzx cx, [len]
xor si, si

cyk2:
pop ax
mov [string + si], al
inc si
loop cyk2

mov ah, 09h
mov dx, string
int 21h
mov ah, 09h
mov dx, press
int 21h
mov ah, 08h
int 21h
mov ax, 4c00h
int 21h

USE16
ORG 0x100
JMP START
; ---
STR1 DB '$! OlleH'
STR1_LENGTH DW 7
; ---
START:

MOV CX, [STR1_LENGTH]
XOR DI, DI

LOOP1:
MOV AL, [STR1 + DI]
PUSH AX
INC DI
LOOP LOOP1

MOV CX, [STR1_LENGTH]
XOR DI, DI

LOOP2:
POP AX
MOV [STR1 + DI], AL
INC DI
LOOP LOOP2

MOV AH, 0x09
MOV DX, STR1
INT 0x21

MOV AH, 0x08
INT 0x21

MOV AX, 0x4C00
INT 0x21

Схожі статті