= Элементы архитектуры ПК и ассемблер для IBM PC
Ассемблер может обрабатывать целые десятичные, шестнадцатеричные, действительные с плавающей точкой, строковые и символьные константы.
- Двоичные целые --- последовательность нулей и единиц, заканчивающихся символом b
- Десятичные --- обычные положительные и отрицательные или заканчивающиеся символом d числа
- Шестнадцатеричные заканчиваются символом h или, если константа начинается с цифр ABCDEF, перед ней можно записать нолик.
- Действительные с плавающей точкой представляются в виде мантиссы и порядка, где буква e --- основание системы, умноженное в соответствующую степень (0.547e-2, 34.751e+02)
- Символьные данные
/ Строки: --- последовательности символов, заключённые в апострофы или кавычки

В ассемблере есть именованные константы, определяемые директивой equ:
```nasm
m equ 27
```

Переменные в ассемблере определяются с помощью директив определения данных и памяти или с помощью директивы равенства
```nasm
v1 db ?
v2 dw 34
v3 = 100
v3 = v3 + 1
```
Константы в основном используются как операнды в выражениях или в директивах определения данных и памяти.

Выражения строятся из операндов, операторов и скобок. Операнды --- это константы и переменные, операторы --- это знаки операций (арифметические, логические, операции отношений, специальные _военные_ операции).

- Арифметические операции: `+`, `-`, `\*`, /, mod
- Логические операции: and, or, xor
- Операции отношений записываются с помощью символов `lt` ($<$), `le` ($<=$), `ne` ($eq.not$), `eq` ($=$), `gt` ($>$), `ge` ($>=$)
- Спецоперации: `offset`, `ptr`
 - `offset имя`, где `имя` --- имя переменной или метка, --- смещение относительно начала сегмента
 - `[размер] ptr имя`
 - `near` --- ближний тип вызова
 - `far` --- дальний тип вызова

== Директива определения
Директива определения данных и памяти имеет вид, соответствующий общему виду директив.

Вот они, слева направо: `db, dw, dd, de, dq, dt`.

Операнды --- это одна или несколько констант, разделённых запятыми. Директива выделяет в памяти определённое количество полей памяти, присваивая имени адрес первого байта в выделенной области памяти.

Если операндом в этой директиве является символическое имя, которому уже поставлен в соответствие какой-то адрес, а это мы могли делать с помощью другой такой же директивы (например)


Если мы хотим выделить 100 полей определённого размера и заполнить их одним и тем же значением, то для этого можно использовать специальный повторитель `dup`.

С помощью этой же директивы мы можем определить одномерный массив, прописав элементы через запятую.

```nasm
m dd im1                ; двойное слово --- адрес im1
d db 100 dup(1)         ; 100 байт 0x01
mas dw 1, 7, 35, 75, 84 ; одномерный массив слов
```

Определим двумерный массив:
```nasm
arr db 7, 14, 11, -5
    db 5, 0, 1, 2
    db -5, 0, 15, 24
```

Строковые константы можно определить с длиной вплоть до 255 символов. Команда определения слова определит широкосимвольную строку.

Команда `int` прерывает работу процессора.

Чтобы вывести на экран '!', необходимо:
```nasm
mov ah, 6
mov di, '!'
int 21h
```

== Команды работы со стеком
Адрес начала сегмента стека загружается в регистр `ss` операционной системой автоматически. На вершину стека указывает регистр `sp` (`esp`, `rsp`). Добавить элемент в стек --- команда `push операнд`, где операнд --- регистр или переменная. Для взятия из стека используется `pop операнд`.

Чтобы работать со всеми регистрами, существуют команды `push a` и `pop a`. Они позволяют положить в стек и считать из стека регистры общего назначения в следующей последовательности: `ax`, `bx`, `cx`, `as`, `bs`, `cs`, `si`, `di`.

Для 32-разрядных регистров существуют `push ad` и `pop ad`, работающие с `eax, ebx, ecx, edx, esp, ebp, esi, edi`.

Чтобы не удалять данные из стека, используют регистр `bp`:
```nasm
mov bp, sp      ; (sp) -> bp
mov ax, [bp+6]  ; (ss:(bp - 6)) -> ax
```


Пересылаем 4 байта из одной области памяти в другую в обратной последовательности и выводим их на экран:
```nasm
title print.asm ; определяет заголовок листинга программы, там может быть до 60 символов
page ,120 ; определяет количество строк на странице листинга и количество символов в строке (количество строк по умолчанию, символов до 120, в теории максимум 132), может использоваться без параметров, тогда она осуществляет переход на следующую страницу листинга
Sseg Segment Para stack 'stack'
    db 100h dup (?)
sseg ends
DSeg Segment Para Public 'data'
    dan db '1', '3', '5', '7'
    rez db 4 dup (?)
dseg ends

CSeg Segment Para Public 'code'
    assume ss:SSeg, ds:DSeg, cs:CSeg
Start proc far
    push ds
    xor ax, ax
    push ax ; положили пустое слово
    mov ax, dsex
    mov ds, ax
    mov ah, 6
    mov dl, dan + 3
    mov rez, dl
    int 21h
    mov dl, dan + 2
    mov rez + 1, dl
    int 21h
    mov dl, dan + 1
    mov rez + 2, dl
    int 21h
    mov dl, dan
    mov rez, dl
    int 21h
Start endp
CSeg ends
end Start
```


== Директива сегмента
```nasm
<имя> Segment <ReadOnly> <выравнивание> <тип> <размер> <'класс'>
```

== Точечные директивы
```nasm
.model small
.data
st1     db 'Line1', '$'
st2     db 'Line2', '$'
st3     db 'Line3', '$'
.code
begin: mov ax, @data ; заносим в сегментный регистр ds
       mov ds, ax    ; физический адрес сегмента данных
mov ah, 9 ; номер функции вывода строки на экран
mov dx, offset st1 ; адрес st1 должен содержаться в регистре dx
int 21h
mov dx, offset st2
int 21h
...........
mov ax, 4c00h
int 21h
end begin
```

`$` --- конец строки, которую необходимо вывести на экран.

В результате выполнения программы:
```
Line1 Line2 Line3
```
Если необходимо построчно, нельзя забывать про байты 13, 10 (они же 0dh, 0ah).


