Compare commits

..

51 Commits

Author SHA1 Message Date
92c69f3e57 Отчёт 2025-11-18 14:12:03 +03:00
62be1dc854 Скорость поворота отдельно от velocity 2025-11-18 11:00:54 +03:00
d21460b8e4 Более красивые настройки 2025-11-18 01:24:01 +03:00
51a0a6a2eb Доки 2025-11-18 01:22:01 +03:00
d04c04f028 Подсказка при запуске 2025-11-18 00:21:46 +03:00
33285bbf1c Прекрасное вращение 2025-11-18 00:14:03 +03:00
83a6640b2e Обалденное вращение 2025-11-17 23:51:31 +03:00
7de923d0b6 Почти красота 2025-11-17 23:02:16 +03:00
f48bc757ea Рабочий прототип 2025-11-17 22:46:36 +03:00
494686a203 Расстановка точек на окружности 2025-11-17 20:43:01 +03:00
58eb3695f1 Размер не зависит от ширины 2025-11-17 16:13:47 +03:00
2c383b20e9 первое движение 2025-11-17 15:58:18 +03:00
92f4632803 Первый движок анимации 2025-11-17 15:43:33 +03:00
5ac43bb236 Скелет функции анимации 2025-11-17 15:04:05 +03:00
743b8336a3 Структура для анимации 2025-11-17 14:42:42 +03:00
8dd2aa19ad отдельный поток для физики и изменение цвета 2025-11-17 14:38:03 +03:00
de18bd8252 Подготовлены файлы фигуры 2025-11-17 14:05:42 +03:00
c21df94757 Запуск окон wayland на Return 2025-11-17 13:45:23 +03:00
b8ebf31762 Файл для обработки ввода 2025-11-17 13:41:46 +03:00
bc5bf92fee Игнор билд директории 2025-11-17 11:47:01 +03:00
908d539abe Мелкие правки 2025-11-17 01:38:16 +03:00
e0ac79bae1 Превосходное состояние проекта 2025-11-17 01:31:00 +03:00
0d3efeda49 Логи закрытия 2025-11-16 20:57:46 +03:00
6880efafab Поддержка многопоточности 2025-11-16 20:50:02 +03:00
eeb632ed0e Реструктуризация проекта 2025-11-16 17:52:09 +03:00
1f700295ff Проект разнесён по файлам 2025-11-16 17:02:39 +03:00
b11a56ad06 Полная работа с клавитурой 2025-11-16 16:43:21 +03:00
9cdc529918 Переделано окно согласно видеоуроку
https://www.youtube.com/watch?v=iIVIu7YRdY0
2025-11-15 21:10:42 +03:00
Пытков Роман
2332be6293 Простое окно 2025-09-25 23:50:14 +03:00
Пытков Роман
1698b43da6 Начало проекта wayland 2025-09-24 02:05:38 +03:00
Пытков Роман
17096efe0f Сумма цифр 2025-09-23 21:16:00 +03:00
Пытков Роман
0716753b1f Подсчёт слов 2025-09-23 21:12:41 +03:00
Пытков Роман
4e111c6148 Перевод в бинарь 2025-09-23 20:28:48 +03:00
Пытков Роман
885f62867e более менее 10 2025-09-23 18:33:50 +03:00
Пытков Роман
1f40ef4467 Больше или меньше 10 2025-09-23 18:00:44 +03:00
Пытков Роман
184eeb8525 Перенос stepik в подпапку 2025-09-23 17:48:53 +03:00
Пытков Роман
6a90ff02c8 id_digit и min 2025-09-23 17:16:48 +03:00
Пытков Роман
00273bf803 repeat_str 2025-09-23 14:26:36 +03:00
Пытков Роман
01c7a248ad even_odd 2025-09-23 01:24:01 +03:00
Пытков Роман
8d019a59d7 minimal -> sum 2025-09-22 00:58:48 +03:00
Пытков Роман
444a2da5a8 Сложение двух чисел 2025-09-22 00:53:15 +03:00
Пытков Роман
6ef051900a всякое 2025-09-21 19:25:45 +03:00
Пытков Роман
62bcc7f9cd Обновлён git ignore 2025-09-21 12:05:40 +03:00
Пытков Роман
a6d997f61d притянут C++ 2025-09-20 22:12:40 +03:00
Пытков Роман
241f5acf71 использование безопасного sscanf 2025-09-20 21:52:53 +03:00
Пытков Роман
4cff9ad987 Release config 2025-09-20 21:46:56 +03:00
Пытков Роман
c8c5518597 release-gcc build preset 2025-09-20 21:11:08 +03:00
Пытков Роман
d7cb83d869 Сложение двух чисел в консоли 2025-09-20 20:32:39 +03:00
Пытков Роман
98877d6100 Окружение стало сильно удобнее, lldb заработал 2025-09-20 20:17:31 +03:00
Пытков Роман
13cbb905ec Переезд на .code-workspace 2025-09-20 19:39:56 +03:00
Пытков Роман
8f705bb7b8 Всякое 2025-09-20 18:48:55 +03:00
89 changed files with 8956 additions and 66 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
**/build/
**/out/

30
.vscode/launch.json vendored
View File

@@ -1,30 +0,0 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "<file>: lldb debug x64",
"program": "${fileDirname}/build/${fileBasenameNoExtension}",
"cwd": "${fileDirname}/build",
"preLaunchTask": "asm64"
},
{
"type": "lldb",
"request": "launch",
"name": "<file>: lldb+GCC debug x64",
"program": "${fileDirname}/build/${fileBasenameNoExtension}",
"cwd": "${fileDirname}/build",
"preLaunchTask": "asm64+gcc"
},
{
"type": "lldb",
"request": "launch",
"name": "minimal: lldb debug x64",
"program": "${workspaceFolder}/minimal/build/minimal",
"cwd": "${workspaceFolder}/minimal/build"
// TODO тут требуется ещё указать задачу сборки minimal, но её ещё нет
},
]
}

View File

@@ -1,3 +0,0 @@
{
"debug.allowBreakpointsEverywhere": true
}

37
casm/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"PATH": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
}
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
},
],
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
]
}
]
}

10
casm/CMakeLists.txt Normal file
View File

@@ -0,0 +1,10 @@
cmake_minimum_required(VERSION 3.14)
project(casm)
enable_language(ASM_NASM)
set(CMAKE_ASM_NASM_FLAGS "-f elf64")
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
add_executable(casm asm.asm c.c)

25
casm/CMakePresets.json Normal file
View File

@@ -0,0 +1,25 @@
{
"version": 8,
"configurePresets": [
{
"name": "debug-gcc",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release-gcc",
"binaryDir": "${sourceDir}/out/build/${presetName}",
"cacheVariables": {
"CMAKE_INSTALL_PREFIX": "${sourceDir}/out/install/${presetName}",
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

23
casm/asm.asm Normal file
View File

@@ -0,0 +1,23 @@
global main
extern sum, print, scan
extern a
section .text
main:
push rbx
call scan ; прочитать первое число
mov rbx, rax ; сохранить первое число
call scan ; прочитать второе число
mov rdi, rbx ; a
mov rsi, rax ; b
call sum ; сумма
mov rdi, rax ; результат
push rax
call print ; напечатать
pop rax
pop rbx
mov dword [rel a], eax ; записать значение 42 в переменную a
mov rax, 0
ret

24
casm/c.c Normal file
View File

@@ -0,0 +1,24 @@
#include <stdio.h>
#include <stdlib.h>
int a;
int sum(int a, int b) {
return a+b;
}
void print(int num) {
printf("%d\n", num);
fflush(stdout);
}
int scan() {
char buffer[100];
int res;
if (fgets(buffer, sizeof(buffer), stdin) != NULL) {
if (sscanf(buffer, "%d", &res) == 1) {
return res;
}
}
return 0; // or handle error
}

2
casm/input.txt Normal file
View File

@@ -0,0 +1,2 @@
10
20

BIN
docs/Intel manual.pdf Normal file

Binary file not shown.

36
docs/cdecl.md Normal file
View File

@@ -0,0 +1,36 @@
## System V AMD64 ABI (cdecl): шпаргалка
Кратко о соглашении вызова для x86-64 в Unix-подобных ОС (Linux, macOS, BSD) по ABI System V.
### Быстрые правила
- Аргументы (целые/указатели): RDI, RSI, RDX, RCX, R8, R9; остальные — на стек (справа налево).
- Аргументы с плавающей точкой/векторы: XMM0XMM7; остальные — на стек.
- Возврат значения: целые/указатели — RAX (до 128 бит: RAX/RDX); float/double — XMM0 (до двух — XMM0/XMM1).
- Перед call: RSP должен быть выровнен по 16 байт. Внутри функции на входе RSP % 16 == 8 (из-за return address).
- Red zone: 128 байт под RSP доступны leaf-функциям; не трогается ОС и обработчиками сигналов.
- Нет «shadow space» (он есть только в Windows x64 ABI).
### Сохранность регистров
- Caller-saved (clobbered): RAX, RCX, RDX, RSI, RDI, R8R11, XMM0XMM15, флаги RFLAGS.
- Callee-saved (надо сохранять и восстанавливать в функции): RBX, RSP, RBP, R12R15.
### Порядок передачи аргументов
#### Для call
- 16-й целочисленные/указательные: RDI, RSI, RDX, RCX, R8, R9.
- Вещественные/векторные: XMM0XMM7 (независимо от целочисленных).
- 7-й и далее, а также переполнение по типам — через стек. Компиляторы обычно размещают их с выравниванием по 8/16.
### Вариативные функции (printf и т.п.)
- Перед вызовом variadic-функции младший байт RAX (AL) содержит число использованных XMM-регистров для передачи аргументов с плавающей точкой (0, если их нет).
### Структуры и большие значения
- Небольшие структуры (до 16 байт) могут возвращаться через регистры (классы INTEGER/SSE распределяются по RAX/RDX или XMM0/XMM1).
- Большие структуры возвращаются через скрытый указатель: вызывающий передаёт адрес буфера (sret), а функция заполняет его.
### Памятка при написании кода
- До call: выровняй стек (RSP%16==0), подготовь регистры аргументов, AL для varargs.
- После call: результат смотри в RAX/XMM0; считай, что caller-saved испорчены — сохрани важное заранее.
- В своей функции сохраняй/восстанавливай RBX, RSP, RBP, R12R15.

BIN
docs/nasmdoc.pdf Normal file

Binary file not shown.

142
docs/syscall.md Normal file
View File

@@ -0,0 +1,142 @@
## Linux x86-64 syscall: шпаргалка
Кратко о низкоуровневых системных вызовах в Linux на x86-64 через инструкцию `syscall` (без libc/glibc-обёрток).
### Быстрые правила
- Номер системного вызова: в RAX.
- Аргументы (целые/указатели): RDI, RSI, RDX, R10, R8, R9
- Возврат: RAX (неотрицательно при успехе; при ошибке — отрицательное значение `-errno` в диапазоне [-4095..-1]).
- Порченные регистры инструкцией `syscall`: RCX, R11 (всегда). RAX меняется на код возврата.
- Остальные GPR обычно возвращаются неизменёнными ядром, но в пользовательском коде всё равно соблюдай ABI: после syscalls/функций не полагайся на caller-saved (RAX, RCX, RDX, RSI, RDI, R8R11).
- Выравнивание стека: сама инструкция `syscall` не требует 16-байтового выравнивания RSP, но если ты в функции, которая также вызывает обычные функции по ABI System V, держи RSP кратным 16 перед `call`.
- Red zone (128 байт под RSP) по ABI доступна и не трогается ядром/обработчиками сигналов — её можно использовать в leaf-коде. Если есть сомнения/нестандартное окружение — не полагайся на неё.
### Возврат и обработка ошибок
- При успехе RAX содержит неотрицательный результат (часто количество байт, файловый дескриптор и т.п.).
- При ошибке RAX содержит отрицательное число `-errno` (в диапазоне [-4095..-1]). Никаких флагов (CF/ZF) для ошибки не используется — проверяй знак RAX.
- Обёртки libc (например, `write(2)`) конвертируют `-errno` в `-1` и устанавливают `errno`. В чистом `syscall` этого нет — обрабатывай сам.
### Где взять номера системных вызовов
- Заголовки ядра: `/usr/include/x86_64-linux-gnu/asm/unistd_64.h` (или `/usr/include/asm/unistd_64.h` в зависимости от дистрибутива).
- `man 2 syscall`, `man 2 <имя>` (например, `man 2 write`). Часто используется `openat` вместо устаревающего `open`.
### Примеры (NASM)
#### write(1, msg, len)
```nasm
; ssize_t write(int fd, const void *buf, size_t count)
; x86-64: rax=1 (SYS_write), rdi=fd, rsi=buf, rdx=count
mov rax, 1 ; SYS_write
mov rdi, 1 ; fd = stdout
lea rsi, [rel msg] ; buf
mov rdx, msg_end - msg ; count
syscall
; при успехе: rax = число записанных байт (>=0)
; при ошибке: rax < 0 ( = -errno )
msg: db "Hello, syscall!\n", 0x0A
msg_end:
```
#### exit(status)
```nasm
; void _exit(int status) — завершает текущий поток/процесс (exit_group завершит все потоки процесса)
mov rax, 60 ; SYS_exit
xor rdi, rdi ; status = 0
syscall ; не возвращается
```
#### openat(AT_FDCWD, path, flags, mode)
```nasm
; long openat(int dirfd, const char *pathname, int flags, mode_t mode)
; x86-64: rax=257 (SYS_openat), rdi=dirfd, rsi=pathname, rdx=flags, r10=mode
mov rax, 257 ; SYS_openat
mov rdi, -100 ; AT_FDCWD
lea rsi, [rel path]
mov rdx, 0x0002 ; O_RDWR (пример)
mov r10, 0o644 ; mode
syscall
; rax >= 0 => fd, rax < 0 => -errno
path: db "./file.txt", 0
```
#### mmap(addr, length, prot, flags, fd, offset) — пример с 6 аргументами
```nasm
; void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset)
; x86-64: rax=9, rdi=addr, rsi=length, rdx=prot, r10=flags, r8=fd, r9=offset
mov rax, 9 ; SYS_mmap
xor rdi, rdi ; addr = NULL (hint)
mov rsi, 4096 ; length
mov rdx, 3 ; PROT_READ|PROT_WRITE
mov r10, 0x22 ; MAP_PRIVATE|MAP_ANONYMOUS (пример)
mov r8, -1 ; fd = -1 (анонимно)
xor r9, r9 ; offset = 0
syscall
; при успехе: rax = адрес (неотрицательный с точки зрения знака)
; при ошибке: rax < 0 => -errno
```
### Часто используемые номера (x86-64)
- 0 — read
- 1 — write
- 2 — open (лучше использовать 257 — openat)
- 3 — close
- 9 — mmap
- 11 — munmap
- 12 — brk
- 60 — exit
- 61 — wait4
- 62 — kill
- 63 — uname
- 78 — gettimeofday (устар.; лучше clock_gettime: 228)
- 202 — futex
- 231 — exit_group (завершает все потоки процесса)
- 257 — openat
Подробный список — в заголовках ядра и `man 2`.
### Замечания и подводные камни
- Не путай ABI функций и ABI `syscall`. У `syscall` 4-й аргумент — R10 (не RCX), и `syscall` портит RCX/R11.
- Не используй `int 0x80` на x86-64: это 32-битный интерфейс, он не совместим и может вести к неверной работе.
- Проверка ошибок только по знаку RAX, флаги процессора неинформативны.
- Если смешиваешь `syscall` и обычные вызовы функций, следи за выравниванием стека (RSP%16==0 перед `call`).
- В многопоточных программах предпочитай `exit_group(231)` для завершения целого процесса; `exit(60)` завершает только текущий поток.
### Мини-макрос для NASM (опционально)
```nasm
; Использование: SYS SYS_write, fd, buf, len
%define SYS_read 0
%define SYS_write 1
%define SYS_openat 257
%define SYS_exit 60
%macro SYS 1-7
mov rax, %1
%if %0 > 1
mov rdi, %2
%endif
%if %0 > 2
mov rsi, %3
%endif
%if %0 > 3
mov rdx, %4
%endif
%if %0 > 4
mov r10, %5
%endif
%if %0 > 5
mov r8, %6
%endif
%if %0 > 6
mov r9, %7
%endif
syscall
%endmacro
```
### Памятка при написании кода
- Положи номер вызова в RAX, аргументы — в RDI, RSI, RDX, R10, R8, R9.
- Вызови `syscall`; помни, что RCX и R11 будут испорчены.
- Проверяй RAX: `rax < 0` — ошибка (`-errno`), `rax >= 0` — успех.
- Соблюдай сохранность регистров по ABI System V для своего кода (RBX/RBP/R12R15 — сохраняй, если меняешь).

BIN
docs/x86-64_Registers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

569
docs/x86-64_asm_sheet.md Normal file
View File

@@ -0,0 +1,569 @@
# x86-64 ASM sheet
## Addressing
* No segmentation (except for `fs` and `gs` for special purposes like threading)
* Relative to base register
* used for **data on the stack**, **arrays**, **structs** and **class members**
* [`base` + `index` * `scale` + `immediate_offset`]
* `base` is mandatory, can be any 64-bit register
* `index` can be any 64-bit register except `rsp`
* `scale` can be 1, 2, 4, or 8
* `immediate_offset` (called displacement with Gas) relative to the base register
* Gas syntax is `immediate_offset(base, index, scale)`
* RIP-relative (a.k.a. PC-relative)
* used for **static data**
* contains a 32-bit sign-extended offset relative to the instruction pointer
* explicitely specified using `mov eax [rel label]` or `default rel` / `default abs` commands with NASM (uses 32-bit absolute addressing otherwise)
* explicitely specified using `mov eax label(%rip)` with Gas
* 32-bit absolute
* 32 bits constant address sign-extended to 64 bits
* works for addresses below 2^31
* don't use for simple memory operands since RIP-relative addressing is shorter, faster (no need for relocations) and works everywhere
* used to access **static arrays with an index register** like `mov ebx, [intarray + rsi*4]` though it doesn't work for Windows and Linux DLLs and for MacOSX exes and DLLs because addresses are above 2^32 (it is used by gcc and clang for Linux exes, an image base relative addressing is used on Windows exes by MASM)
* an alternative that works everywhere is first loading the static array address into `rbx` using `lea` with a RIP-relative address and then address relatively from this base register (`lea rbx, [array]` then `mov eax, [rbx + rcx*4]`), other static arrays can then be accessed relatively (`mov [(array2-array1) + rbx + rcx*4], eax`)
* 64-bit absolute
* `mov eax, dword [qword a]`
* can only be used with `mov` and registers `al`, `ax`, `eax` or `rax` (src or dst)
* can't contain a segment, base or index register
## Position-Independent Code (PIC)
* Easier and faster than the 32-bit Global Offset Table (GOT) technique since RIP-relative is position independent (note that the technique to access static arrays with an index register described earlier is position independent too)
## General purpose registers
bit 0 - 63 | bit 0 - 31 | bit 0 - 15 | bit 8 - 15 | bit 0 - 7
:----------:|:----------:|:----------:|:----------:|:---------:
`rax` | `eax` | `ax` | `ah` | `al`
`rbx` | `ebx` | `bx` | `bh` | `bl`
`rcx` | `ecx` | `cx` | `ch` | `cl`
`rdx` | `edx` | `dx` | `dh` | `dl`
`rsi` | `esi` | `si` | | `sil`
`rdi` | `edi` | `di` | | `dil`
`rbp` | `ebp` | `bp` | | `bpl`
`rsp` | `esp` | `sp` | | `spl`
`r8` | `r8d` | `r8w` | | `r8b`
`r9` | `r9d` | `r9w` | | `r9b`
`r10` | `r10d` | `r10w` | | `r10b`
`r11` | `r11d` | `r11w` | | `r11b`
`r12` | `r12d` | `r12w` | | `r12b`
`r13` | `r13d` | `r13w` | | `r13b`
`r14` | `r14d` | `r14w` | | `r14b`
`r15` | `r15d` | `r15w` | | `r15b`
`rflags` | | `flags` | |
`rip` | | | |
## `rflags` register
* **CF (Carry Flag, bit 0)** — Set if an arithmetic operation generates a carry or a borrow out of the most-significant bit of the result; cleared otherwise. This flag indicates an overflow condition for unsigned-integer arithmetic. It is also used in multiple-precision arithmetic.
* **PF (Parity Flag, bit 2)** — Set if the least-significant byte of the result contains an even number of 1 bits; cleared otherwise.
* **AF (Auxiliary carry Flag, bit 4)** — Set if an arithmetic operation generates a carry or a borrow out of bit 3 of the result; cleared otherwise. This flag is used in binary-coded decimal (BCD) arithmetic.
* **ZF (Zero Flag, bit 6)** — Set if the result is zero; cleared otherwise.
* **SF (Sign Flag, bit 7)** — Set equal to the most-significant bit of the result, which is the sign bit of a signed integer. (0 indicates a positive value and 1 indicates a negative value.)
* **OF (Overflow Flag, bit 11)** — Set if the integer result is too large a positive number or too small a negative number (excluding the sign-bit) to fit in the destination operand; cleared otherwise. This flag indicates an overflow condition for signed-integer (twos complement) arithmetic.
## Saturation and wraparound modes (of the instruction set)
* **Wraparound arithmetic** — With wraparound arithmetic, a true out-of-range result is truncated (that is, the carry or overflow bit is ignored and only the least significant bits of the result are returned to the destination). Wraparound arithmetic is suitable for applications that control the range of operands to prevent out-of-range results. If the range of operands is not controlled, however, wraparound arithmetic can lead to large errors. For example, adding two large signed numbers can cause positive overflow and produce a negative result.
* **Signed saturation arithmetic** — With signed saturation arithmetic, out-of-range results are limited to the representable range of signed integers for the integer size being operated on. For example, if positive overflow occurs when operating on signed word integers, the result is saturated to 7FFFH, which is the largest positive integer that can be represented in 16 bits; if negative overflow occurs, the result is saturated to 8000H.
* **Unsigned saturation arithmetic** — With unsigned saturation arithmetic, out-of-range results are limited to the representable range of unsigned integers for the integer size. So, positive overflow when operating on unsigned byte integers results in FFH being returned and negative overflow results in 00H being returned.
## Stack frames
## Data transfer instructions
* [**MOV**](http://www.felixcloutier.com/x86/MOV.html) — Move data between general-purpose registers; move data between memory and general-purpose or segment registers; move immediates to general-purpose registers.
* [**CMOVcc**](http://www.felixcloutier.com/x86/CMOVcc.html) — Conditional move.
* [**XCHG**](http://www.felixcloutier.com/x86/XCHG.html) — Exchange.
* [**BSWAP**](http://www.felixcloutier.com/x86/BSWAP.html) — Byte swap.
* [**XADD**](http://www.felixcloutier.com/x86/XADD.html) — Exchange and add.
* [**CMPXCHG**](http://www.felixcloutier.com/x86/CMPXCHG.html) — Compare and exchange.
* [**CMPXCHG8B / CMPXCHG16B**](http://www.felixcloutier.com/x86/CMPXCHG8B:CMPXCHG16B.html) — Compare and exchange 8/16 bytes.
* [**PUSH**](http://www.felixcloutier.com/x86/PUSH.html) — Push onto stack.
* [**POP**](http://www.felixcloutier.com/x86/POP.html) — Pop off of stack.
* [**PUSHA / PUSHAD**](http://www.felixcloutier.com/x86/PUSHA:PUSHAD.html) — Push general-purpose registers onto stack.
* [**POPA / POPAD**](http://www.felixcloutier.com/x86/POPA:POPAD.html) — Pop general-purpose registers from stack.
* [**CWD / CDQ / CQO**](http://www.felixcloutier.com/x86/CWD:CDQ:CQO.html) — Convert word to doubleword/Convert doubleword to quadword.
* [**CBW / CWDE / CDQE**](http://www.felixcloutier.com/x86/CBW:CWDE:CDQE.html) — Convert byte to word/Convert word to doubleword in `rax` register.
* [**MOVSX / MOVSXD**](http://www.felixcloutier.com/x86/MOVSX:MOVSXD.html) — Move and sign extend.
* [**MOVZX**](http://www.felixcloutier.com/x86/MOVZX.html) — Move and zero extend.
## Binary arithmetic instructions
* [**ADCX**](http://www.felixcloutier.com/x86/ADCX.html) — Unsigned integer add with carry.
* [**ADOX**](http://www.felixcloutier.com/x86/ADOX.html) — Unsigned integer add with overflow.
* [**ADD**](http://www.felixcloutier.com/x86/ADD.html) — Integer add.
* [**ADC**](http://www.felixcloutier.com/x86/ADC.html) — Add with carry.
* [**SUB**](http://www.felixcloutier.com/x86/SUB.html) — Subtract.
* [**SBB**](http://www.felixcloutier.com/x86/SBB.html) — Subtract with borrow.
* [**IMUL**](http://www.felixcloutier.com/x86/IMUL.html) — Signed multiply.
* [**MUL**](http://www.felixcloutier.com/x86/MUL.html) — Unsigned multiply.
* [**IDIV**](http://www.felixcloutier.com/x86/IDIV.html) — Signed divide.
* [**DIV**](http://www.felixcloutier.com/x86/DIV.html) — Unsigned divide.
* [**INC**](http://www.felixcloutier.com/x86/INC.html) — Increment.
* [**DEC**](http://www.felixcloutier.com/x86/DEC.html) — Decrement.
* [**NEG**](http://www.felixcloutier.com/x86/NEG.html) — Negate.
* [**CMP**](http://www.felixcloutier.com/x86/CMP.html) — Compare.
## Logical instructions
* [**AND**](http://www.felixcloutier.com/x86/AND.html) — Perform bitwise logical AND.
* [**OR**](http://www.felixcloutier.com/x86/OR.html) — Perform bitwise logical OR.
* [**XOR**](http://www.felixcloutier.com/x86/XOR.html) — Perform bitwise logical exclusive OR.
* [**NOT**](http://www.felixcloutier.com/x86/NOT.html) — Perform bitwise logical NOT.
## Shift and rotate instructions
* [**SAL / SAR / SHL / SHR**](http://www.felixcloutier.com/x86/SAL:SAR:SHL:SHR.html) — Shift arithmetic/logical left/right.
* [**SHLD**](http://www.felixcloutier.com/x86/SHLD.html) — Shift left double.
* [**SHRD**](http://www.felixcloutier.com/x86/SHRD.html) — Shift right double.
* [**RCL / RCR / ROL / ROR**](http://www.felixcloutier.com/x86/RCL:RCR:ROL:ROR.html) — Rotate left/right and rotate left/right through carry.
## Bit and byte instructions
* [**BT**](http://www.felixcloutier.com/x86/BT.html) — Bit test.
* [**BTS**](http://www.felixcloutier.com/x86/BTS.html) — Bit test and set.
* [**BTR**](http://www.felixcloutier.com/x86/BTR.html) — Bit test and reset.
* [**BTC**](http://www.felixcloutier.com/x86/BTC.html) — Bit test and complement.
* [**BSF**](http://www.felixcloutier.com/x86/BSF.html) — Bit scan forward.
* [**BSR**](http://www.felixcloutier.com/x86/BSR.html) — Bit scan reverse.
* [**SETcc**](http://www.felixcloutier.com/x86/SETcc.html) — Set byte on condition.
* [**TEST**](http://www.felixcloutier.com/x86/TEST.html) — Logical compare.
* [**CRC32**](http://www.felixcloutier.com/x86/CRC32.html) — Provides hardware acceleration to calculate cyclic redundancy checks for fast and efficient implementation of data integrity protocols.
* [**POPCNT**](http://www.felixcloutier.com/x86/POPCNT.html) — This instruction calculates the number of bits set to 1 in the second operand (source) and returns the count in the first operand (a destination register).
## Control transfer instructions
* [**JMP**](http://www.felixcloutier.com/x86/JMP.html) — Jump.
* [**Jcc**](http://www.felixcloutier.com/x86/Jcc.html) — Jump if condition is met (RIP-relative operand).
* [**LOOP / LOOPcc**](http://www.felixcloutier.com/x86/LOOP:LOOPcc.html) — Loop with `rcx` counter.
* [**CALL**](http://www.felixcloutier.com/x86/CALL.html) — Call procedure.
* [**RET**](http://www.felixcloutier.com/x86/RET.html) — Return.
* [**IRET / IRETD / IRETQ**](http://www.felixcloutier.com/x86/IRET:IRETD.html) — Return from interrupt.
* [**INT n / INTO / INTO 3**](http://www.felixcloutier.com/x86/INTn:INTO:INT3.html) — Call to interrupt procedure.
* [**ENTER**](http://www.felixcloutier.com/x86/ENTER.html) — High-level procedure entry.
* [**LEAVE**](http://www.felixcloutier.com/x86/LEAVE.html) — High-level procedure exit.
## String instructions
* [**MOVS / MOVSB / MOVSW / MOVSD / MOVSQ**](http://www.felixcloutier.com/x86/MOVS:MOVSB:MOVSW:MOVSD:MOVSQ.html) — Move data from string to string.
* [**CMPS / CMPSB / CMPSW / CMPSD / CMPSQ**](http://www.felixcloutier.com/x86/CMPS:CMPSB:CMPSW:CMPSD:CMPSQ.html) — Compare string operands.
* [**SCAS / SCASB / SCASW / SCASD**](http://www.felixcloutier.com/x86/SCAS:SCASB:SCASW:SCASD.html) — Scan string.
* [**LODS / LODSB / LODSW / LODSD / LODSQ**](http://www.felixcloutier.com/x86/LODS:LODSB:LODSW:LODSD:LODSQ.html) — Load string.
* [**STOS / STOSB / STOSW / STOSD / STOSQ**](http://www.felixcloutier.com/x86/STOS:STOSB:STOSW:STOSD:STOSQ.html) — Store string.
* [**REP / REPE / REPZ / REPNE / REPNZ**](http://www.felixcloutier.com/x86/REP:REPE:REPZ:REPNE:REPNZ.html) — Repeat string operation prefix.
## `rflags` control instructions
* [**STC**](http://www.felixcloutier.com/x86/STC.html) — Set carry flag.
* [**CLC**](http://www.felixcloutier.com/x86/CLC.html) — Clear the carry flag.
* [**CMC**](http://www.felixcloutier.com/x86/CMC.html) — Complement the carry flag.
* [**CLD**](http://www.felixcloutier.com/x86/CLD.html) — Clear the direction flag.
* [**STD**](http://www.felixcloutier.com/x86/STD.html) — Set direction flag.
* [**LAHF**](http://www.felixcloutier.com/x86/LAHF.html) — Load flags into `ah` register.
* [**SAHF**](http://www.felixcloutier.com/x86/SAHF.html) — Store `ah` register into flags.
* [**PUSHF / PUSHFQ**](http://www.felixcloutier.com/x86/PUSHF:PUSHFD:PUSHFQ.html) — Push `rflags` onto stack.
* [**POPF / POPFQ**](http://www.felixcloutier.com/x86/POPF:POPFD:POPFQ.html) — Pop `rflags` from stack.
* [**STI**](http://www.felixcloutier.com/x86/STI.html) — Set interrupt flag.
* [**CLI**](http://www.felixcloutier.com/x86/CLI.html) — Clear the interrupt flag.
## Miscellaneous instructions
* [**LEA**](http://www.felixcloutier.com/x86/LEA.html) — Load effective address.
* [**NOP**](http://www.felixcloutier.com/x86/NOP.html) — No operation.
* [**UD**](http://www.felixcloutier.com/x86/UD.html) — Undefined instruction.
* [**XLAT / XLATB**](http://www.felixcloutier.com/x86/XLAT:XLATB.html) — Table lookup translation.
* [**CPUID**](http://www.felixcloutier.com/x86/CPUID.html) — Processor identification.
* [**MOVBE**](http://www.felixcloutier.com/x86/MOVBE.html) — Move data after swapping data bytes.
* [**PREFETCHW**](http://www.felixcloutier.com/x86/PREFETCHW.html) — Prefetch data into cache in anticipation of write.
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Flushes and invalidates a memory operand and its associated cache line from all levels of the processors cache hierarchy.
* [**CLFLUSHOPT**](http://www.felixcloutier.com/x86/CLFLUSHOPT.html) — Flushes and invalidates a memory operand and its associated cache line from all levels of the processors cache hierarchy with optimized memory system throughput.
* [**RDRAND**](http://www.felixcloutier.com/x86/RDRAND.html) — Retrieves a random number generated from hardware.
* [**RDSEED**](http://www.felixcloutier.com/x86/RDSEED.html) — Seed the random number generator from hardware.
## User-mode extended states save/restore instructions
* [**XSAVE**](http://www.felixcloutier.com/x86/XSAVE.html) — Save processor extended states to memory.
* [**XSAVEC**](http://www.felixcloutier.com/x86/XSAVEC.html) — Save processor extended states with compaction to memory.
* [**XSAVEOPT**](http://www.felixcloutier.com/x86/XSAVEOPT.html) — Save processor extended states to memory, optimized.
* [**XRSTOR**](http://www.felixcloutier.com/x86/XRSTOR.html) — Restore processor extended states from memory.
* [**XGETBV**](http://www.felixcloutier.com/x86/XGETBV.html) — Reads the state of an extended control register.
## Bit manipulation instructions (BMI1, BMI2)
* [**ANDN**](http://www.felixcloutier.com/x86/ANDN.html) — Bitwise AND of first source with inverted 2nd source operands.
* [**BEXTR**](http://www.felixcloutier.com/x86/BEXTR.html) — Contiguous bitwise extract.
* [**BLSI**](http://www.felixcloutier.com/x86/BLSI.html) — Extract lowest set bit.
* [**BLSMSK**](http://www.felixcloutier.com/x86/BLSMSK.html) — Set all lower bits below first set bit to 1.
* [**BLSR**](http://www.felixcloutier.com/x86/BLSR.html) — Reset lowest set bit.
* [**BZHI**](http://www.felixcloutier.com/x86/BZHI.html) — Zero high bits starting from specified bit position.
* [**LZCNT**](http://www.felixcloutier.com/x86/LZCNT.html) — Count the number leading zero bits.
* [**MULX**](http://www.felixcloutier.com/x86/MULX.html) — Unsigned multiply without affecting arithmetic flags.
* [**PDEP**](http://www.felixcloutier.com/x86/PDEP.html) — Parallel deposit of bits using a mask.
* [**PEXT**](http://www.felixcloutier.com/x86/PEXT.html) — Parallel extraction of bits using a mask.
* [**RORX**](http://www.felixcloutier.com/x86/RORX.html) — Rotate right without affecting arithmetic flags.
* [**SARX / SHLX / SHRX**](http://www.felixcloutier.com/x86/SARX:SHLX:SHRX.html) — Shift arithmetic/logic left/right without affecting flags.
* [**TZCNT**](http://www.felixcloutier.com/x86/TZCNT.html) — Count the number trailing zero bits.
## x87 FPU overview
* x87 FPU state is aliased to the MMX state, care must be taken when making transitions to MMX instructions to prevent incoherent or unexpected results.
## x87 FPU data transfer instructions
* [**FLD**](http://www.felixcloutier.com/x86/FLD.html) — Load floating-point value.
* [**FST / FSTP**](http://www.felixcloutier.com/x86/FST:FSTP.html) — Store floating-point value without/with pop.
* [**FILD**](http://www.felixcloutier.com/x86/FILD.html) — Load integer.
* [**FIST / FISTP**](http://www.felixcloutier.com/x86/FIST:FISTP.html) — Store integer with/without pop.
* [**FBLD**](http://www.felixcloutier.com/x86/FBLD.html) — Load BCD.
* [**FBSTP**](http://www.felixcloutier.com/x86/FBSTP.html) — Store BCD and pop.
* [**FXCH**](http://www.felixcloutier.com/x86/FXCH.html) — Exchange registers.
* [**FCMOVcc**](http://www.felixcloutier.com/x86/FCMOVcc.html) — Floating-point conditional move.
## x87 FPU basic arithmetic instructions
* [**FADD / FADDP / FIADD**](http://www.felixcloutier.com/x86/FADD:FADDP:FIADD.html) — Add floating-point.
* [**FSUB / FSUBP / FISUB**](http://www.felixcloutier.com/x86/FSUB:FSUBP:FISUB.html) — Subtract floating-point.
* [**FSUBR / FSUBRP / FISUBR**](http://www.felixcloutier.com/x86/FSUBR:FSUBRP:FISUBR.html) — Subtract floating-point reverse.
* [**FMUL / FMULP / FIMUL**](http://www.felixcloutier.com/x86/FMUL:FMULP:FIMUL.html) — Multiply floating-point.
* [**FDIV / FDIVP / FIDIV**](http://www.felixcloutier.com/x86/FDIV:FDIVP:FIDIV.html) — Divide floating-point.
* [**FDIVR / FDIVRP / FIDIVR**](http://www.felixcloutier.com/x86/FDIVR:FDIVRP:FIDIVR.html) — Divide floating-point reverse.
* [**FPREM**](http://www.felixcloutier.com/x86/FPREM.html) — Partial remainder.
* [**FPREM1**](http://www.felixcloutier.com/x86/FPREM1.html) — IEEE Partial remainder.
* [**FABS**](http://www.felixcloutier.com/x86/FABS.html) — Absolute value.
* [**FCHS**](http://www.felixcloutier.com/x86/FCHS.html) — Change sign.
* [**FRNDINT**](http://www.felixcloutier.com/x86/FRNDINT.html) — Round to integer.
* [**FSCALE**](http://www.felixcloutier.com/x86/FSCALE.html) — Scale by power of two.
* [**FSQRT**](http://www.felixcloutier.com/x86/FSQRT.html) — Square root.
* [**FXTRACT**](http://www.felixcloutier.com/x86/FXTRACT.html) — Extract exponent and significand.
## x87 FPU comparison instructions
* [**FCOM / FCOMP / FCOMPP**](http://www.felixcloutier.com/x86/FCOM:FCOMP:FCOMPP.html) — Compare floating-point.
* [**FUCOM / FUCOMP / FUCOMPP**](http://www.felixcloutier.com/x86/FUCOM:FUCOMP:FUCOMPP.html) — Unordered compare floating-point.
* [**FICOM / FICOMP**](http://www.felixcloutier.com/x86/FICOM:FICOMP.html) — Compare integer.
* [**FCOMI / FCOMIP / FUCOMI / FUCOMIP**](http://www.felixcloutier.com/x86/FCOMI:FCOMIP:FUCOMI:FUCOMIP.html) — Compare floating-point and set `rflags`.
* [**FTST**](http://www.felixcloutier.com/x86/FTST.html) — Test floating-point (compare with 0.0).
* [**FXAM**](http://www.felixcloutier.com/x86/FXAM.html) — Examine floating-point.
## x87 FPU transcendental instructions
* [**FSIN**](http://www.felixcloutier.com/x86/FSIN.html) — Sine.
* [**FCOS**](http://www.felixcloutier.com/x86/FCOS.html) — Cosine.
* [**FSINCOS**](http://www.felixcloutier.com/x86/FSINCOS.html) — Sine and cosine.
* [**FPTAN**](http://www.felixcloutier.com/x86/FPTAN.html) — Partial tangent.
* [**FPATAN**](http://www.felixcloutier.com/x86/FPATAN.html) — Partial arctangent.
* [**F2XM1**](http://www.felixcloutier.com/x86/F2XM1.html) — 2x 1.
* [**FYL2X**](http://www.felixcloutier.com/x86/FYL2X.html) — y log2x.
* [**FYL2XP1**](http://www.felixcloutier.com/x86/FYL2XP1.html) — y log2(x + 1).
## x87 FPU load constants instructions
* [**FLD1 / FLDL2T / FLDL2E / FLDPI / FLDLG2 / FLDLN2 / FLDZ**](http://www.felixcloutier.com/x86/FLD1:FLDL2T:FLDL2E:FLDPI:FLDLG2:FLDLN2:FLDZ.html) — Load constants.
## x87 FPU control instructions
* [**FINCSTP**](http://www.felixcloutier.com/x86/FINCSTP.html) — Increment FPU register stack pointer.
* [**FDECSTP**](http://www.felixcloutier.com/x86/FDECSTP.html) — Decrement FPU register stack pointer.
* [**FFREE**](http://www.felixcloutier.com/x86/FFREE.html) — Free floating-point register.
* [**FINIT / FNINIT**](http://www.felixcloutier.com/x86/FINIT:FNINIT.html) — Initialize FPU.
* [**FCLEX / FNCLEX**](http://www.felixcloutier.com/x86/FCLEX:FNCLEX.html) — Clear floating-point exception flags.
* [**FSTCW / FNSTCW**](http://www.felixcloutier.com/x86/FSTCW:FNSTCW.html) — Store FPU control word.
* [**FLDCW**](http://www.felixcloutier.com/x86/FLDCW.html) — Load FPU control word.
* [**FSTENV / FNSTENV**](http://www.felixcloutier.com/x86/FSTENV:FNSTENV.html) — Store FPU environment.
* [**FLDENV**](http://www.felixcloutier.com/x86/FLDENV.html) — Load FPU environment.
* [**FSAVE / FNSAVE**](http://www.felixcloutier.com/x86/FSAVE:FNSAVE.html) — Save FPU state.
* [**FRSTOR**](http://www.felixcloutier.com/x86/FRSTOR.html) — Restore FPU state.
* [**FSTSW / FNSTSW**](http://www.felixcloutier.com/x86/FSTSW:FNSTSW.html) — Store FPU status word.
* [**WAIT / FWAIT**](http://www.felixcloutier.com/x86/WAIT:FWAIT.html) — Wait for FPU.
* [**FNOP**](http://www.felixcloutier.com/x86/FNOP.html) — FPU no operation.
## x87 FPU and SIMD state management instructions
* [**FXSAVE**](http://www.felixcloutier.com/x86/FXSAVE.html) — Save x87 FPU and SIMD state.
* [**FXRSTOR**](http://www.felixcloutier.com/x86/FXRSTOR.html) — Restore x87 FPU and SIMD state.
## MMX overview
* SIMD execution model to handle 64-bit packed integer data.
* Eight new 64-bit data registers, called MMX registers.
* Three new packed data types:
* 64-bit packed byte integers (signed and unsigned)
* 64-bit packed word integers (signed and unsigned)
* 64-bit packed doubleword integers (signed and unsigned)
* MMX state is aliased to the x87 FPU state, care must be taken when making transitions to x87 FPU instructions to prevent incoherent or unexpected results.
## MMX data transfer instructions
* [**MOVD / MOVQ**](http://www.felixcloutier.com/x86/MOVD:MOVQ.html) — Move doubleword/quadword from/to MMX registers.
## MMX conversion instructions
* [**PACKSSWB / PACKSSDW**](http://www.felixcloutier.com/x86/PACKSSWB:PACKSSDW.html) — Pack words/doublewords into bytes with signed saturation.
* [**PACKUSWB**](http://www.felixcloutier.com/x86/PACKUSWB.html) — Pack words into bytes with unsigned saturation.
* [**PUNPCKHBW / PUNPCKHWD / PUNPCKHDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Unpack high-order bytes/words/doublewords.
* [**PUNPCKLBW / PUNPCKLWD / PUNPCKLDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Unpack low-order bytes/words/doublewords.
## MMX packed arithmetic instructions
* [**PADDB / PADDW / PADDD**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Add packed byte/word/doubleword integers.
* [**PADDSB / PADDSW**](http://www.felixcloutier.com/x86/PADDSB:PADDSW.html) — Add packed signed byte/word integers with signed saturation.
* [**PADDUSB / PADDUSW**](http://www.felixcloutier.com/x86/PADDUSB:PADDUSW.html) — Add packed unsigned byte/word integers with unsigned saturation.
* [**PSUBB / PSUBW / PSUBD**](http://www.felixcloutier.com/x86/PSUBB:PSUBW:PSUBD.html) — Subtract packed byte/word/doubleword integers.
* [**PSUBSB / PSUBSW**](http://www.felixcloutier.com/x86/PSUBSB:PSUBSW.html) — Subtract packed signed byte/word integers with signed saturation.
* [**PSUBUSB / PSUBUSW**](http://www.felixcloutier.com/x86/PSUBUSB:PSUBUSW.html) — Subtract packed unsigned byte/word integers with unsigned saturation.
* [**PMULHW**](http://www.felixcloutier.com/x86/PMULHW.html) — Multiply packed signed word integers and store high result.
* [**PMULLW**](http://www.felixcloutier.com/x86/PMULLW.html) — Multiply packed signed word integers and store low result.
* [**PMADDWD**](http://www.felixcloutier.com/x86/PMADDWD.html) — Multiply and add packed word integers.
## MMX comparison instructions
* [**PCMPEQB / PCMPEQW / PCMPEQD**](http://www.felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html) — Compare packed bytes/words/doublewords for equal.
* [**PCMPGTB / PCMPGTW / PCMPGTD**](http://www.felixcloutier.com/x86/PCMPGTB:PCMPGTW:PCMPGTD.html) — Compare packed signed byte/word/doubleword integers for greater than.
## MMX logical instructions
* [**PAND**](http://www.felixcloutier.com/x86/PAND.html) — Bitwise logical AND.
* [**PANDN**](http://www.felixcloutier.com/x86/PANDN.html) — Bitwise logical AND NOT.
* [**POR**](http://www.felixcloutier.com/x86/POR.html) — Bitwise logical OR.
* [**PXOR**](http://www.felixcloutier.com/x86/PXOR.html) — Bitwise logical exclusive OR.
## MMX shift and rotate instructions
* [**PSLLW / PSLLD / PSLLQ**](http://www.felixcloutier.com/x86/PSLLW:PSLLD:PSLLQ.html) — Shift packed words/doublewords/quadwoards left logical.
* [**PSRLW / PSRLD / PSRLQ**](http://www.felixcloutier.com/x86/PSRLW:PSRLD:PSRLQ.html) — Shift packed words/doublewords/quadwords right logical.
* [**PSRAW / PSRAD**](http://www.felixcloutier.com/x86/PSRAW:PSRAD:PSRAQ.html) — Shift packed words/doublewords right arithmetic.
## MMX state management instructions
* [**EMMS**](http://www.felixcloutier.com/x86/EMMS.html) — Empty MMX state.
## SSE overview
* Expand the SIMD execution model by adding facilities for handling packed and scalar single-precision floating-point values contained in 128-bit registers.
* Sixteen (eight for 32-bit mode) new 128-bit packed single-precision floating-point XMM registers available.
* 128-bit packed and scalar single-precision floating-point instructions.
* Enhancements to MMX instruction set with new operations on packed integer operands located in MMX registers.
* Explicit prefetching of data, control of the cacheability of data, control of the
ordering of store operations.
## SSE data transfer instructions
* [**MOVAPS**](http://www.felixcloutier.com/x86/MOVAPS.html) — Move four aligned packed single-precision floating-point values between XMM registers or between XMM register and memory.
* [**MOVUPS**](http://www.felixcloutier.com/x86/MOVUPS.html) — Move four unaligned packed single-precision floating-point values between XMM registers or between XMM register and memory.
* [**MOVHPS**](http://www.felixcloutier.com/x86/MOVHPS.html) — Move two packed single-precision floating-point values to an from the high quadword of an XMM register and memory.
* [**MOVHLPS**](http://www.felixcloutier.com/x86/MOVHLPS.html) — Move two packed single-precision floating-point values from the high quadword of an XMM register to the low quadword of another XMM register.
* [**MOVLPS**](http://www.felixcloutier.com/x86/MOVLPS.html) — Move two packed single-precision floating-point values to an from the low quadword of an XMM register and memory.
* [**MOVLHPS**](http://www.felixcloutier.com/x86/MOVLHPS.html) — Move two packed single-precision floating-point values from the low quadword of an XMM register to the high quadword of another XMM register.
* [**MOVMSKPS**](http://www.felixcloutier.com/x86/MOVMSKPS.html) — Extract sign mask from four packed single-precision floating-point values.
* [**MOVSS**](http://www.felixcloutier.com/x86/MOVSS.html) — Move scalar single-precision floating-point value between XMM registers or between an XMM register and memory.
## SSE packed arithmetic instructions
* [**ADDPS**](http://www.felixcloutier.com/x86/ADDPS.html) — Add packed single-precision floating-point values.
* [**ADDSS**](http://www.felixcloutier.com/x86/ADDSS.html) — Add scalar single-precision floating-point values.
* [**SUBPS**](http://www.felixcloutier.com/x86/SUBPS.html) — Subtract packed single-precision floating-point values.
* [**SUBSS**](http://www.felixcloutier.com/x86/SUBSS.html) — Subtract scalar single-precision floating-point values.
* [**MULPS**](http://www.felixcloutier.com/x86/MULPS.html) — Multiply packed single-precision floating-point values.
* [**MULSS**](http://www.felixcloutier.com/x86/MULSS.html) — Multiply scalar single-precision floating-point values.
* [**DIVPS**](http://www.felixcloutier.com/x86/DIVPS.html) — Divide packed single-precision floating-point values.
* [**DIVSS**](http://www.felixcloutier.com/x86/DIVSS.html) — Divide scalar single-precision floating-point values.
* [**RCPPS**](http://www.felixcloutier.com/x86/RCPPS.html) — Compute reciprocals of packed single-precision floating-point values.
* [**RCPSS**](http://www.felixcloutier.com/x86/RCPSS.html) — Compute reciprocal of scalar single-precision floating-point values.
* [**SQRTPS**](http://www.felixcloutier.com/x86/SQRTPS.html) — Compute square roots of packed single-precision floating-point values.
* [**SQRTSS**](http://www.felixcloutier.com/x86/SQRTSS.html) — Compute square root of scalar single-precision floating-point values.
* [**RSQRTPS**](http://www.felixcloutier.com/x86/RSQRTPS.html) — Compute reciprocals of square roots of packed single-precision floating-point values.
* [**RSQRTSS**](http://www.felixcloutier.com/x86/RSQRTSS.html) — Compute reciprocal of square root of scalar single-precision floating-point values.
* [**MAXPS**](http://www.felixcloutier.com/x86/MAXPS.html) — Return maximum packed single-precision floating-point values.
* [**MAXSS**](http://www.felixcloutier.com/x86/MAXSS.html) — Return maximum scalar single-precision floating-point values.
* [**MINPS**](http://www.felixcloutier.com/x86/MINPS.html) — Return minimum packed single-precision floating-point values.
* [**MINSS**](http://www.felixcloutier.com/x86/MINSS.html) — Return minimum scalar single-precision floating-point values.
## SSE comparison instructions
* [**CMPPS**](http://www.felixcloutier.com/x86/CMPPS.html) — Compare packed single-precision floating-point values.
* [**CMPSS**](http://www.felixcloutier.com/x86/CMPSS.html) — Compare scalar single-precision floating-point values.
* [**COMISS**](http://www.felixcloutier.com/x86/COMISS.html) — Perform ordered comparison of scalar single-precision floating-point values and set flags in `rflags` register.
* [**UCOMISS**](http://www.felixcloutier.com/x86/UCOMISS.html) — Perform unordered comparison of scalar single-precision floating-point values and set flags in `rflags` register.
## SSE logical instructions
* [**ANDPS**](http://www.felixcloutier.com/x86/ANDPS.html) — Perform bitwise logical AND of packed single-precision floating-point values.
* [**ANDNPS**](http://www.felixcloutier.com/x86/ANDNPS.html) — Perform bitwise logical AND NOT of packed single-precision floating-point values.
* [**ORPS**](http://www.felixcloutier.com/x86/ORPS.html) — Perform bitwise logical OR of packed single-precision floating-point values.
* [**XORPS**](http://www.felixcloutier.com/x86/XORPS.html) — Perform bitwise logical XOR of packed single-precision floating-point values.
## SSE shuffle and unpack instructions
* [**SHUFPS**](http://www.felixcloutier.com/x86/SHUFPS.html) — Shuffles values in packed single-precision floating-point operands.
* [**UNPCKHPS**](http://www.felixcloutier.com/x86/UNPCKHPS.html) — Unpacks and interleaves the two high-order values from two single-precision floating-point operands.
* [**UNPCKLPS**](http://www.felixcloutier.com/x86/UNPCKLPS.html) — Unpacks and interleaves the two low-order values from two single-precision floating-point operands.
## SSE conversion instructions
* [**CVTPI2PS**](http://www.felixcloutier.com/x86/CVTPI2PS.html) — Convert packed doubleword integers to packed single-precision floating-point values.
* [**CVTSI2SS**](http://www.felixcloutier.com/x86/CVTSI2SS.html) — Convert doubleword integer to scalar single-precision floating-point value.
* [**CVTPS2PI**](http://www.felixcloutier.com/x86/CVTPS2PI.html) — Convert packed single-precision floating-point values to packed doubleword integers.
* [**CVTTPS2PI**](http://www.felixcloutier.com/x86/CVTTPS2PI.html) — Convert with truncation packed single-precision floating-point values to packed doubleword integers.
* [**CVTSS2SI**](http://www.felixcloutier.com/x86/CVTSS2SI.html) — Convert a scalar single-precision floating-point value to a doubleword integer.
* [**CVTTSS2SI**](http://www.felixcloutier.com/x86/CVTTSS2SI.html) — Convert with truncation a scalar single-precision floating-point value to a scalar doubleword integer.
## SSE MXCSR management instructions
* [**LDMXCSR**](http://www.felixcloutier.com/x86/LDMXCSR.html) — Load MXCSR register.
* [**STMXCSR**](http://www.felixcloutier.com/x86/STMXCSR.html) — Save MXCSR register state.
## SSE 64-bit integer instructions (MMX enhancements)
* [**PAVGB / PAVGW**](http://www.felixcloutier.com/x86/PAVGB:PAVGW.html) — Compute average of packed unsigned byte integers.
* [**PEXTRW**](http://www.felixcloutier.com/x86/PEXTRW.html) — Extract word.
* [**PINSRW**](http://www.felixcloutier.com/x86/PINSRW.html) — Insert word.
* [**PMAXUB**](http://www.felixcloutier.com/x86/PMAXUB:PMAXUW.html) — Maximum of packed unsigned byte integers.
* [**PMAXSW**](http://www.felixcloutier.com/x86/PMAXSB:PMAXSW:PMAXSD:PMAXSQ.html) — Maximum of packed signed word integers.
* [**PMINUB**](http://www.felixcloutier.com/x86/PMINUB:PMINUW.html) — Minimum of packed unsigned byte integers.
* [**PMINSW**](http://www.felixcloutier.com/x86/PMINSB:PMINSW.html) — Minimum of packed signed word integers.
* [**PMOVMSKB**](http://www.felixcloutier.com/x86/PMOVMSKB.html) — Move byte mask.
* [**PMULHUW**](http://www.felixcloutier.com/x86/PMULHUW.html) — Multiply packed unsigned integers and store high result.
* [**PSADBW**](http://www.felixcloutier.com/x86/MPSADBW.html) — Compute sum of absolute differences.
* [**PSHUFW**](http://www.felixcloutier.com/x86/PSHUFW.html) — Shuffle packed integer word in MMX register.
## SSE cacheability control, prefetch and ordering instructions
* [**MASKMOVQ**](http://www.felixcloutier.com/x86/MASKMOVQ.html) — Non-temporal store of selected bytes from an MMX register into memory.
* [**MOVNTQ**](http://www.felixcloutier.com/x86/MOVNTQ.html) — Non-temporal store of quadword from an MMX register into memory.
* [**MOVNTPS**](http://www.felixcloutier.com/x86/MOVNTPS.html) — Non-temporal store of four packed single-precision floating-point values from an XMM register into memory.
* [**PREFETCHh**](http://www.felixcloutier.com/x86/PREFETCHh.html) — Load 32 or more of bytes from memory to a selected level of the processors cache hierarchy.
* [**SFENCE**](http://www.felixcloutier.com/x86/SFENCE.html) — Serializes store operations.
## SSE2 overview
* Packed and scalar 128-bit double-precision floating-point instructions.
* Additional 64-bit and 128-bit packed byte/word/doubleword/quadword integers instructions.
* 128-bit versions of integer instructions introduced with MMX and SSE.
* Additional cacheability-control and instruction-ordering instructions.
## SSE2 FP64 data movement instructions
* [**MOVAPD**](http://www.felixcloutier.com/x86/MOVAPD.html) — Move two aligned packed double-precision floating-point values between XMM registers or between and XMM register and memory.
* [**MOVUPD**](http://www.felixcloutier.com/x86/MOVUPD.html) — Move two unaligned packed double-precision floating-point values between XMM registers or between and XMM register and memory.
* [**MOVHPD**](http://www.felixcloutier.com/x86/MOVHPD.html) — Move high packed double-precision floating-point value to an from the high quadword of an XMM register and memory.
* [**MOVLPD**](http://www.felixcloutier.com/x86/MOVLPD.html) — Move low packed single-precision floating-point value to an from the low quadword of an XMM register and memory.
* [**MOVMSKPD**](http://www.felixcloutier.com/x86/MOVMSKPD.html) — Extract sign mask from two packed double-precision floating-point values.
* [**MOVSD**](http://www.felixcloutier.com/x86/MOVSD.html) — Move scalar double-precision floating-point value between XMM registers or between an XMM register and memory.
## SSE2 FP64 packed arithmetic instructions
* [**ADDPD**](http://www.felixcloutier.com/x86/ADDPD.html) — Add packed double-precision floating-point values.
* [**ADDSD**](http://www.felixcloutier.com/x86/ADDSD.html) — Add scalar double precision floating-point values.
* [**SUBPD**](http://www.felixcloutier.com/x86/SUBPD.html) — Subtract packed double-precision floating-point values.
* [**SUBSD**](http://www.felixcloutier.com/x86/SUBSD.html) — Subtract scalar double-precision floating-point values.
* [**MULPD**](http://www.felixcloutier.com/x86/MULPD.html) — Multiply packed double-precision floating-point values.
* [**MULSD**](http://www.felixcloutier.com/x86/MULSD.html) — Multiply scalar double-precision floating-point values.
* [**DIVPD**](http://www.felixcloutier.com/x86/DIVPD.html) — Divide packed double-precision floating-point values.
* [**DIVSD**](http://www.felixcloutier.com/x86/DIVSD.html) — Divide scalar double-precision floating-point values.
* [**SQRTPD**](http://www.felixcloutier.com/x86/SQRTPD.html) — Compute packed square roots of packed double-precision floating-point values.
* [**SQRTSD**](http://www.felixcloutier.com/x86/SQRTSD.html) — Compute scalar square root of scalar double-precision floating-point values.
* [**MAXPD**](http://www.felixcloutier.com/x86/MAXPD.html) — Return maximum packed double-precision floating-point values.
* [**MAXSD**](http://www.felixcloutier.com/x86/MAXSD.html) — Return maximum scalar double-precision floating-point values.
* [**MINPD**](http://www.felixcloutier.com/x86/MINPD.html) — Return minimum packed double-precision floating-point values.
* [**MINSD**](http://www.felixcloutier.com/x86/MINSD.html) — Return minimum scalar double-precision floating-point values.
## SSE2 FP64 logical instructions
* [**ANDPD**](http://www.felixcloutier.com/x86/ANDPD.html) — Perform bitwise logical AND of packed double-precision floating-point values.
* [**ANDNPD**](http://www.felixcloutier.com/x86/ANDNPD.html) — Perform bitwise logical AND NOT of packed double-precision floating-point values.
* [**ORPD**](http://www.felixcloutier.com/x86/ORPD.html) — Perform bitwise logical OR of packed double-precision floating-point values.
* [**XORPD**](http://www.felixcloutier.com/x86/XORPD.html) — Perform bitwise logical XOR of packed double-precision floating-point values.
## SSE2 FP64 compare instructions
* [**CMPPD**](http://www.felixcloutier.com/x86/CMPPD.html) — Compare packed double-precision floating-point values.
* [**CMPSD**](http://www.felixcloutier.com/x86/CMPSD.html) — Compare scalar double-precision floating-point values.
* [**COMISD**](http://www.felixcloutier.com/x86/COMISD.html) — Perform ordered comparison of scalar double-precision floating-point values and set flags in `rflags` register.
* [**UCOMISD**](http://www.felixcloutier.com/x86/UCOMISD.html) — Perform unordered comparison of scalar double-precision floating-point values and set flags in `rflags` register.
## SSE2 FP64 shuffle and unpack instructions
* [**SHUFPD**](http://www.felixcloutier.com/x86/SHUFPD.html) — Shuffles values in packed double-precision floating-point operands.
* [**UNPCKHPD**](http://www.felixcloutier.com/x86/UNPCKHPD.html) — Unpacks and interleaves the high values from two packed double-precision floating-point operands.
* [**UNPCKLPD**](http://www.felixcloutier.com/x86/UNPCKLPD.html) — Unpacks and interleaves the low values from two packed double-precision floating-point operands.
## SSE2 FP64 conversion instructions
* [**CVTPD2PI**](http://www.felixcloutier.com/x86/CVTPD2PI.html) — Convert packed double-precision floating-point values to packed doubleword integers.
* [**CVTTPD2PI**](http://www.felixcloutier.com/x86/CVTTPD2PI.html) — Convert with truncation packed double-precision floating-point values to packed doubleword integers.
* [**CVTPI2PD**](http://www.felixcloutier.com/x86/CVTPI2PD.html) — Convert packed doubleword integers to packed double-precision floating-point values.
* [**CVTPD2DQ**](http://www.felixcloutier.com/x86/CVTPD2DQ.html) — Convert packed double-precision floating-point values to packed doubleword integers.
* [**CVTTPD2DQ**](http://www.felixcloutier.com/x86/CVTTPD2DQ.html) — Convert with truncation packed double-precision floating-point values to packed doubleword integers.
* [**CVTDQ2PD**](http://www.felixcloutier.com/x86/CVTDQ2PD.html) — Convert packed doubleword integers to packed double-precision floating-point values.
* [**CVTPS2PD**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Convert packed single-precision floating-point values to packed double-precision floating-point values.
* [**CVTPD2PS**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Convert packed double-precision floating-point values to packed single-precision floating-point values.
* [**CVTSS2SD**](http://www.felixcloutier.com/x86/CVTSS2SD.html) — Convert scalar single-precision floating-point values to scalar double-precision floating-point values.
* [**CVTSD2SS**](http://www.felixcloutier.com/x86/CVTSD2SS.html) — Convert scalar double-precision floating-point values to scalar single-precision floating-point values.
* [**CVTSD2SI**](http://www.felixcloutier.com/x86/CVTSD2SI.html) — Convert scalar double-precision floating-point values to a doubleword integer.
* [**CVTTSD2SI**](http://www.felixcloutier.com/x86/CVTTSD2SI.html) — Convert with truncation scalar double-precision floating-point values to scalar doubleword integers.
* [**CVTSI2SD**](http://www.felixcloutier.com/x86/CVTSI2SD.html) — Convert doubleword integer to scalar double-precision floating-point value.
## SSE2 FP32 instructions (SSE enhancements)
* [**CVTDQ2PS**](http://www.felixcloutier.com/x86/CVTDQ2PS.html) — Convert packed doubleword integers to packed single-precision floating-point values.
* [**CVTPS2DQ**](http://www.felixcloutier.com/x86/CVTPS2DQ.html) — Convert packed single-precision floating-point values to packed doubleword integers.
* [**CVTTPS2DQ**](http://www.felixcloutier.com/x86/CVTTPS2DQ.html) — Convert with truncation packed single-precision floating-point values to packed doubleword integers.
## SSE2 integer instructions
* [**MOVDQA**](http://www.felixcloutier.com/x86/MOVDQA:VMOVDQA32:VMOVDQA64.html) — Move aligned double quadword.
* [**MOVDQU**](http://www.felixcloutier.com/x86/MOVDQU:VMOVDQU8:VMOVDQU16:VMOVDQU32:VMOVDQU64.html) — Move unaligned double quadword.
* [**MOVQ2DQ**](http://www.felixcloutier.com/x86/MOVQ2DQ.html) — Move quadword integer from MMX to XMM registers.
* [**MOVDQ2Q**](http://www.felixcloutier.com/x86/MOVDQ2Q.html) — Move quadword integer from XMM to MMX registers.
* [**PMULUDQ**](http://www.felixcloutier.com/x86/PMULUDQ.html) — Multiply packed unsigned doubleword integers.
* [**PADDQ**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Add packed quadword integers.
* [**PSUBQ**](http://www.felixcloutier.com/x86/PSUBQ.html) — Subtract packed quadword integers.
* [**PSHUFLW**](http://www.felixcloutier.com/x86/PSHUFLW.html) — Shuffle packed low words.
* [**PSHUFHW**](http://www.felixcloutier.com/x86/PSHUFHW.html) — Shuffle packed high words.
* [**PSHUFD**](http://www.felixcloutier.com/x86/PSHUFD.html) — Shuffle packed doublewords.
* [**PSLLDQ**](http://www.felixcloutier.com/x86/PSLLDQ.html) — Shift double quadword left logical.
* [**PSRLDQ**](http://www.felixcloutier.com/x86/PSRLDQ.html) — Shift double quadword right logical.
* [**PUNPCKHQDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Unpack high quadwords.
* [**PUNPCKLQDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Unpack low quadwords.
## SSE2 cacheability control and ordering instructions
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Flush cacheline.
* [**LFENCE**](http://www.felixcloutier.com/x86/LFENCE.html) — Serializes load operations.
* [**MFENCE**](http://www.felixcloutier.com/x86/MFENCE.html) — Serializes load and store operations.
* [**PAUSE**](http://www.felixcloutier.com/x86/PAUSE.html) — Improves the performance of “spin-wait loops”.
* [**MASKMOVDQU**](http://www.felixcloutier.com/x86/MASKMOVDQU.html) — Non-temporal store of selected bytes from an XMM register into memory.
* [**MOVNTPD**](http://www.felixcloutier.com/x86/MOVNTPD.html) — Non-temporal store of two packed double-precision floating-point values from an XMM register into memory.
* [**MOVNTDQ**](http://www.felixcloutier.com/x86/MOVNTDQ.html) — Non-temporal store of double quadword from an XMM register into memory.
* [**MOVNTI**](http://www.felixcloutier.com/x86/MOVNTI.html) — Non-temporal store of a doubleword from a general-purpose register into memory.
## References
* https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
* http://www.agner.org/optimize/optimizing_assembly.pdf
* https://www.nasm.us/xdoc/2.13.03/nasmdoc.pdf
* https://godbolt.org/
* https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
* https://0xax.github.io/categories/assembler/
## Instruction tables
* http://www.agner.org/optimize/instruction_tables.pdf
## Examples
* https://github.com/torvalds/linux/tree/master/arch/x86
* https://gist.github.com/rygorous/bf1659bf6cd1752ed114367d4b87b302
* https://www.csee.umbc.edu/portal/help/nasm/sample_64.shtml
## Utils
* https://software.intel.com/sites/landingpage/IntrinsicsGuide/
* https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavutil/x86/x86inc.asm
* https://gist.github.com/rygorous/f729919ff64526a46e591d8f8b52058e

568
docs/x86-64_asm_sheet.ru.md Normal file
View File

@@ -0,0 +1,568 @@
# Шпаргалка по x8664 ASM
## Адресация
* Без сегментации (кроме `fs` и `gs` для специальных целей, например, потоков)
* Относительно базового регистра
* используется для **данных в стеке**, **массивов**, **структур** и **членов классов**
* [`base` + `index` * `scale` + `immediate_offset`]
* `base` обязателен, может быть любым 64битным регистром
* `index` может быть любым 64битным регистром, кроме `rsp`
* `scale` может быть 1, 2, 4 или 8
* `immediate_offset` (в GAS называется displacement) — смещение относительно базового регистра
* Синтаксис GAS: `immediate_offset(base, index, scale)`
* Относительно RIP (также PCrelative)
* используется для **статических данных**
* содержит 32битное знаково расширяемое смещение относительно указателя команд
* явно задаётся в NASM через `mov eax [rel label]` или директивы `default rel` / `default abs` (в противном случае используется 32битная абсолютная адресация)
* явно задаётся в GAS через `mov eax label(%rip)`
* 32битная абсолютная адресация
* 32битный константный адрес, знаково расширяемый до 64 бит
* работает для адресов ниже 2^31
* не используйте для простых операндов памяти: RIPrelative короче, быстрее (не нужны релокации) и работает везде
* используется для доступа к **статическим массивам с индексным регистром**, например `mov ebx, [intarray + rsi*4]`, однако это не работает для DLL в Windows и Linux, а также для исполняемых файлов и DLL в macOS, потому что адреса выше 2^32 (gcc и clang используют это для Linuxисполняемых файлов; для Windowsисполняемых MASM использует адресацию относительно базы образа)
* альтернативный, работающий везде вариант: сначала загрузить адрес статического массива в `rbx` через `lea` с RIPrelative адресом, а затем адресовать относительно этого базового регистра (`lea rbx, [array]`, затем `mov eax, [rbx + rcx*4]`); другие статические массивы затем можно адресовать относительно (`mov [(array2-array1) + rbx + rcx*4], eax`)
* 64битная абсолютная адресация
* `mov eax, dword [qword a]`
* применима только с `mov` и регистрами `al`, `ax`, `eax` или `rax` (источник или приёмник)
* не может содержать сегмент, базовый или индексный регистр
## Позиционно‑независимый код (PIC)
* Проще и быстрее, чем 32битная техника GOT (Global Offset Table), поскольку RIPrelative уже позиционно‑независим (заметьте, что описанная выше техника доступа к статическим массивам с индексным регистром также позиционно‑независима)
## Регистры общего назначения
bit 0 - 63 | bit 0 - 31 | bit 0 - 15 | bit 8 - 15 | bit 0 - 7
:----------:|:----------:|:----------:|:----------:|:---------:
`rax` | `eax` | `ax` | `ah` | `al`
`rbx` | `ebx` | `bx` | `bh` | `bl`
`rcx` | `ecx` | `cx` | `ch` | `cl`
`rdx` | `edx` | `dx` | `dh` | `dl`
`rsi` | `esi` | `si` | | `sil`
`rdi` | `edi` | `di` | | `dil`
`rbp` | `ebp` | `bp` | | `bpl`
`rsp` | `esp` | `sp` | | `spl`
`r8` | `r8d` | `r8w` | | `r8b`
`r9` | `r9d` | `r9w` | | `r9b`
`r10` | `r10d` | `r10w` | | `r10b`
`r11` | `r11d` | `r11w` | | `r11b`
`r12` | `r12d` | `r12w` | | `r12b`
`r13` | `r13d` | `r13w` | | `r13b`
`r14` | `r14d` | `r14w` | | `r14b`
`r15` | `r15d` | `r15w` | | `r15b`
`rflags` | | `flags` | |
`rip` | | | |
## Регистр `rflags`
* CF (Carry Flag, бит 0) — устанавливается, если арифметическая операция генерирует перенос или заём из старшего бита результата; очищается иначе. Флаг показывает переполнение для беззнаковой арифметики. Также применяется в многоточечной (многословной) арифметике.
* PF (Parity Flag, бит 2) — устанавливается, если младший байт результата содержит чётное число единиц; очищается иначе.
* AF (Auxiliary carry Flag, бит 4) — устанавливается, если операция вызывает перенос или заём из бита 3 результата; очищается иначе. Используется в двоично‑десятичной (BCD) арифметике.
* ZF (Zero Flag, бит 6) — устанавливается, если результат равен нулю; очищается иначе.
* SF (Sign Flag, бит 7) — устанавливается равным старшему биту результата, то есть знаковому биту знакового целого (0 — положительное, 1 — отрицательное).
* OF (Overflow Flag, бит 11) — устанавливается, если целочисленный результат слишком велик (без учёта знакового бита), чтобы поместиться в операнд назначения: слишком большой положительный или слишком маленький отрицательный; очищается иначе. Показывает переполнение для знаковой (дополнительный код) арифметики.
## Режимы насыщения и циклического переполнения (набора инструкций)
* Циклическая арифметика (wraparound) — истинный выход за диапазон усечётся (перенос/переполнение игнорируется, возвращаются только младшие биты результата). Подходит, когда диапазон операндов контролируется. Иначе возможны большие ошибки. Пример: сложение двух больших знаковых чисел может вызвать положительное переполнение и дать отрицательный результат.
* Арифметика со знаковым насыщением — выход за диапазон ограничивается представимым диапазоном знаковых целых для данного размера. Например, при положительном переполнении для знаковых слов результат насыщается до 7FFFH (наибольшее положительное 16битное); при отрицательном — до 8000H.
* Арифметика с беззнаковым насыщением — выход за диапазон ограничивается представимым диапазоном беззнаковых целых данного размера. Положительное переполнение для беззнаковых байтов даёт FFH, отрицательное — 00H.
## Стековые кадры
## Инструкции передачи данных
* [**MOV**](http://www.felixcloutier.com/x86/MOV.html) — Перемещение данных между регистрами общего назначения; между памятью и регистрами общего назначения или сегментными; загрузка непосредственных значений в регистры общего назначения.
* [**CMOVcc**](http://www.felixcloutier.com/x86/CMOVcc.html) — Условное перемещение.
* [**XCHG**](http://www.felixcloutier.com/x86/XCHG.html) — Обмен значениями.
* [**BSWAP**](http://www.felixcloutier.com/x86/BSWAP.html) — Перестановка байтов.
* [**XADD**](http://www.felixcloutier.com/x86/XADD.html) — Обмен с добавлением.
* [**CMPXCHG**](http://www.felixcloutier.com/x86/CMPXCHG.html) — Сравнить и обменять.
* [**CMPXCHG8B / CMPXCHG16B**](http://www.felixcloutier.com/x86/CMPXCHG8B:CMPXCHG16B.html) — Сравнить и обменять 8/16 байт.
* [**PUSH**](http://www.felixcloutier.com/x86/PUSH.html) — Поместить на стек.
* [**POP**](http://www.felixcloutier.com/x86/POP.html) — Снять со стека.
* [**PUSHA / PUSHAD**](http://www.felixcloutier.com/x86/PUSHA:PUSHAD.html) — Поместить все регистры общего назначения на стек.
* [**POPA / POPAD**](http://www.felixcloutier.com/x86/POPA:POPAD.html) — Снять все регистры общего назначения со стека.
* [**CWD / CDQ / CQO**](http://www.felixcloutier.com/x86/CWD:CDQ:CQO.html) — Расширить слово до двойного слова / двойное слово до квадрослова.
* [**CBW / CWDE / CDQE**](http://www.felixcloutier.com/x86/CBW:CWDE:CDQE.html) — Расширить байт до слова / слово до двойного слова в регистре `rax`.
* [**MOVSX / MOVSXD**](http://www.felixcloutier.com/x86/MOVSX:MOVSXD.html) — Перемещение с знаковым расширением.
* [**MOVZX**](http://www.felixcloutier.com/x86/MOVZX.html) — Перемещение с нулевым расширением.
## Инструкции целочисленной арифметики
* [**ADCX**](http://www.felixcloutier.com/x86/ADCX.html) — Беззнаковое сложение с переносом.
* [**ADOX**](http://www.felixcloutier.com/x86/ADOX.html) — Беззнаковое сложение с переполнением.
* [**ADD**](http://www.felixcloutier.com/x86/ADD.html) — Сложение целых.
* [**ADC**](http://www.felixcloutier.com/x86/ADC.html) — Сложение с переносом.
* [**SUB**](http://www.felixcloutier.com/x86/SUB.html) — Вычитание.
* [**SBB**](http://www.felixcloutier.com/x86/SBB.html) — Вычитание с заёмом.
* [**IMUL**](http://www.felixcloutier.com/x86/IMUL.html) — Умножение со знаком.
* [**MUL**](http://www.felixcloutier.com/x86/MUL.html) — Умножение без знака.
* [**IDIV**](http://www.felixcloutier.com/x86/IDIV.html) — Деление со знаком.
* [**DIV**](http://www.felixcloutier.com/x86/DIV.html) — Деление без знака.
* [**INC**](http://www.felixcloutier.com/x86/INC.html) — Инкремент.
* [**DEC**](http://www.felixcloutier.com/x86/DEC.html) — Декремент.
* [**NEG**](http://www.felixcloutier.com/x86/NEG.html) — Изменить знак (двойка‑дополнение).
* [**CMP**](http://www.felixcloutier.com/x86/CMP.html) — Сравнение.
## Логические инструкции
* [**AND**](http://www.felixcloutier.com/x86/AND.html) — Побитовое И.
* [**OR**](http://www.felixcloutier.com/x86/OR.html) — Побитовое ИЛИ.
* [**XOR**](http://www.felixcloutier.com/x86/XOR.html) — Побитовое исключающее ИЛИ.
* [**NOT**](http://www.felixcloutier.com/x86/NOT.html) — Побитовое НЕ.
## Сдвиги и ротации
* [**SAL / SAR / SHL / SHR**](http://www.felixcloutier.com/x86/SAL:SAR:SHL:SHR.html) — Арифметический/логический сдвиг влево/вправо.
* [**SHLD**](http://www.felixcloutier.com/x86/SHLD.html) — Двойной сдвиг влево.
* [**SHRD**](http://www.felixcloutier.com/x86/SHRD.html) — Двойной сдвиг вправо.
* [**RCL / RCR / ROL / ROR**](http://www.felixcloutier.com/x86/RCL:RCR:ROL:ROR.html) — Ротация влево/вправо и через перенос.
## Битовые и байтовые инструкции
* [**BT**](http://www.felixcloutier.com/x86/BT.html) — Тест бита.
* [**BTS**](http://www.felixcloutier.com/x86/BTS.html) — Тест и установка бита.
* [**BTR**](http://www.felixcloutier.com/x86/BTR.html) — Тест и сброс бита.
* [**BTC**](http://www.felixcloutier.com/x86/BTC.html) — Тест и инверсия бита.
* [**BSF**](http://www.felixcloutier.com/x86/BSF.html) — Поиск первого (младшего) установленного бита.
* [**BSR**](http://www.felixcloutier.com/x86/BSR.html) — Поиск последнего (старшего) установленного бита.
* [**SETcc**](http://www.felixcloutier.com/x86/SETcc.html) — Установить байт по условию.
* [**TEST**](http://www.felixcloutier.com/x86/TEST.html) — Логическое сравнение (AND, флаги).
* [**CRC32**](http://www.felixcloutier.com/x86/CRC32.html) — Аппаратное ускорение вычисления CRC для быстрого контроля целостности данных.
* [**POPCNT**](http://www.felixcloutier.com/x86/POPCNT.html) — Подсчёт количества единичных битов во втором операнде с возвратом счётчика в первый (регистр назначения).
## Инструкции передачи управления
* [**JMP**](http://www.felixcloutier.com/x86/JMP.html) — Безусловный переход.
* [**Jcc**](http://www.felixcloutier.com/x86/Jcc.html) — Переход при выполнении условия (операнд RIPrelative).
* [**LOOP / LOOPcc**](http://www.felixcloutier.com/x86/LOOP:LOOPcc.html) — Цикл с счётчиком в `rcx`.
* [**CALL**](http://www.felixcloutier.com/x86/CALL.html) — Вызов процедуры.
* [**RET**](http://www.felixcloutier.com/x86/RET.html) — Возврат из процедуры.
* [**IRET / IRETD / IRETQ**](http://www.felixcloutier.com/x86/IRET:IRETD.html) — Возврат из прерывания.
* [**INT n / INTO / INT 3**](http://www.felixcloutier.com/x86/INTn:INTO:INT3.html) — Вызов обработчика прерывания.
* [**ENTER**](http://www.felixcloutier.com/x86/ENTER.html) — Высокоуровневый вход в процедуру.
* [**LEAVE**](http://www.felixcloutier.com/x86/LEAVE.html) — Высокоуровневый выход из процедуры.
## Строковые инструкции
* [**MOVS / MOVSB / MOVSW / MOVSD / MOVSQ**](http://www.felixcloutier.com/x86/MOVS:MOVSB:MOVSW:MOVSD:MOVSQ.html) — Копирование данных из строки в строку.
* [**CMPS / CMPSB / CMPSW / CMPSD / CMPSQ**](http://www.felixcloutier.com/x86/CMPS:CMPSB:CMPSW:CMPSD:CMPSQ.html) — Сравнение строковых операндов.
* [**SCAS / SCASB / SCASW / SCASD**](http://www.felixcloutier.com/x86/SCAS:SCASB:SCASW:SCASD.html) — Сканирование строки.
* [**LODS / LODSB / LODSW / LODSD / LODSQ**](http://www.felixcloutier.com/x86/LODS:LODSB:LODSW:LODSD:LODSQ.html) — Загрузка из строки.
* [**STOS / STOSB / STOSW / STOSD / STOSQ**](http://www.felixcloutier.com/x86/STOS:STOSB:STOSW:STOSD:STOSQ.html) — Запись в строку.
* [**REP / REPE / REPZ / REPNE / REPNZ**](http://www.felixcloutier.com/x86/REP:REPE:REPZ:REPNE:REPNZ.html) — Префиксы повторения строковых операций.
## Инструкции управления `rflags`
* [**STC**](http://www.felixcloutier.com/x86/STC.html) — Установить флаг переноса.
* [**CLC**](http://www.felixcloutier.com/x86/CLC.html) — Очистить флаг переноса.
* [**CMC**](http://www.felixcloutier.com/x86/CMC.html) — Инвертировать флаг переноса.
* [**CLD**](http://www.felixcloutier.com/x86/CLD.html) — Очистить флаг направления.
* [**STD**](http://www.felixcloutier.com/x86/STD.html) — Установить флаг направления.
* [**LAHF**](http://www.felixcloutier.com/x86/LAHF.html) — Загрузить флаги в регистр `ah`.
* [**SAHF**](http://www.felixcloutier.com/x86/SAHF.html) — Сохранить регистр `ah` в флаги.
* [**PUSHF / PUSHFQ**](http://www.felixcloutier.com/x86/PUSHF:PUSHFD:PUSHFQ.html) — Поместить `rflags` на стек.
* [**POPF / POPFQ**](http://www.felixcloutier.com/x86/POPF:POPFD:POPFQ.html) — Снять `rflags` со стека.
* [**STI**](http://www.felixcloutier.com/x86/STI.html) — Установить флаг прерываний.
* [**CLI**](http://www.felixcloutier.com/x86/CLI.html) — Очистить флаг прерываний.
## Прочие инструкции
* [**LEA**](http://www.felixcloutier.com/x86/LEA.html) — Загрузка эффективного адреса.
* [**NOP**](http://www.felixcloutier.com/x86/NOP.html) — Пустая операция.
* [**UD**](http://www.felixcloutier.com/x86/UD.html) — Неопределённая инструкция.
* [**XLAT / XLATB**](http://www.felixcloutier.com/x86/XLAT:XLATB.html) — Табличное преобразование байта.
* [**CPUID**](http://www.felixcloutier.com/x86/CPUID.html) — Идентификация процессора.
* [**MOVBE**](http://www.felixcloutier.com/x86/MOVBE.html) — Перемещение данных с перестановкой байтов.
* [**PREFETCHW**](http://www.felixcloutier.com/x86/PREFETCHW.html) — Предвыборка данных в кэш с ожиданием записи.
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Сброс и инвалидация операнда памяти и связанной линии кэша на всех уровнях иерархии кэшей процессора.
* [**CLFLUSHOPT**](http://www.felixcloutier.com/x86/CLFLUSHOPT.html) — То же, с оптимизацией пропускной способности памяти.
* [**RDRAND**](http://www.felixcloutier.com/x86/RDRAND.html) — Получение случайного числа, сгенерированного аппаратно.
* [**RDSEED**](http://www.felixcloutier.com/x86/RDSEED.html) — Получение зерна (seed) для ГСЧ из аппаратного источника.
## Сохранение/восстановление расширенных состояний в пользовательском режиме
* [**XSAVE**](http://www.felixcloutier.com/x86/XSAVE.html) — Сохранить расширенные состояния процессора в память.
* [**XSAVEC**](http://www.felixcloutier.com/x86/XSAVEC.html) — Сохранить расширенные состояния с уплотнением.
* [**XSAVEOPT**](http://www.felixcloutier.com/x86/XSAVEOPT.html) — Оптимизированное сохранение расширенных состояний.
* [**XRSTOR**](http://www.felixcloutier.com/x86/XRSTOR.html) — Восстановить расширенные состояния из памяти.
* [**XGETBV**](http://www.felixcloutier.com/x86/XGETBV.html) — Прочитать состояние расширенного управляющего регистра.
## Манипуляции битами (BMI1, BMI2)
* [**ANDN**](http://www.felixcloutier.com/x86/ANDN.html) — Побитовое AND первого операнда с инвертированным вторым.
* [**BEXTR**](http://www.felixcloutier.com/x86/BEXTR.html) — Извлечение непрерывного диапазона битов.
* [**BLSI**](http://www.felixcloutier.com/x86/BLSI.html) — Извлечь младший установленный бит.
* [**BLSMSK**](http://www.felixcloutier.com/x86/BLSMSK.html) — Установить в 1 все младшие биты ниже первого установленного.
* [**BLSR**](http://www.felixcloutier.com/x86/BLSR.html) — Сбросить младший установленный бит.
* [**BZHI**](http://www.felixcloutier.com/x86/BZHI.html) — Обнулить старшие биты, начиная с указанной позиции.
* [**LZCNT**](http://www.felixcloutier.com/x86/LZCNT.html) — Подсчёт ведущих нулей.
* [**MULX**](http://www.felixcloutier.com/x86/MULX.html) — Беззнаковое умножение без изменения флагов.
* [**PDEP**](http://www.felixcloutier.com/x86/PDEP.html) — Параллельная «загрузка» битов по маске.
* [**PEXT**](http://www.felixcloutier.com/x86/PEXT.html) — Параллельное «извлечение» битов по маске.
* [**RORX**](http://www.felixcloutier.com/x86/RORX.html) — Ротация вправо без изменения флагов.
* [**SARX / SHLX / SHRX**](http://www.felixcloutier.com/x86/SARX:SHLX:SHRX.html) — Арифметический/логический сдвиг без изменения флагов.
* [**TZCNT**](http://www.felixcloutier.com/x86/TZCNT.html) — Подсчёт замыкающих нулей (с конца).
## Обзор x87 FPU
* Состояние x87 FPU отображается на состояние MMX; при переходах к MMXинструкциям нужно соблюдать осторожность, чтобы избежать неконсистентности результатов.
## Инструкции передачи данных x87 FPU
* [**FLD**](http://www.felixcloutier.com/x86/FLD.html) — Загрузка числа с плавающей точкой.
* [**FST / FSTP**](http://www.felixcloutier.com/x86/FST:FSTP.html) — Сохранить число с/без извлечения из стека FPU.
* [**FILD**](http://www.felixcloutier.com/x86/FILD.html) — Загрузка целого.
* [**FIST / FISTP**](http://www.felixcloutier.com/x86/FIST:FISTP.html) — Сохранить целое с/без извлечения.
* [**FBLD**](http://www.felixcloutier.com/x86/FBLD.html) — Загрузка BCD.
* [**FBSTP**](http://www.felixcloutier.com/x86/FBSTP.html) — Сохранение BCD и извлечение.
* [**FXCH**](http://www.felixcloutier.com/x86/FXCH.html) — Обмен регистров.
* [**FCMOVcc**](http://www.felixcloutier.com/x86/FCMOVcc.html) — Условное перемещение (FPU).
## Базовая арифметика x87 FPU
* [**FADD / FADDP / FIADD**](http://www.felixcloutier.com/x86/FADD:FADDP:FIADD.html) — Сложение с плавающей точкой.
* [**FSUB / FSUBP / FISUB**](http://www.felixcloutier.com/x86/FSUB:FSUBP:FISUB.html) — Вычитание с плавающей точкой.
* [**FSUBR / FSUBRP / FISUBR**](http://www.felixcloutier.com/x86/FSUBR:FSUBRP:FISUBR.html) — Вычитание в обратном порядке.
* [**FMUL / FMULP / FIMUL**](http://www.felixcloutier.com/x86/FMUL:FMULP:FIMUL.html) — Умножение с плавающей точкой.
* [**FDIV / FDIVP / FIDIV**](http://www.felixcloutier.com/x86/FDIV:FDIVP:FIDIV.html) — Деление с плавающей точкой.
* [**FDIVR / FDIVRP / FIDIVR**](http://www.felixcloutier.com/x86/FDIVR:FDIVRP:FIDIVR.html) — Деление в обратном порядке.
* [**FPREM**](http://www.felixcloutier.com/x86/FPREM.html) — Частный остаток.
* [**FPREM1**](http://www.felixcloutier.com/x86/FPREM1.html) — Частный остаток (IEEE).
* [**FABS**](http://www.felixcloutier.com/x86/FABS.html) — Модуль.
* [**FCHS**](http://www.felixcloutier.com/x86/FCHS.html) — Смена знака.
* [**FRNDINT**](http://www.felixcloutier.com/x86/FRNDINT.html) — Округление до целого.
* [**FSCALE**](http://www.felixcloutier.com/x86/FSCALE.html) — Масштабирование по степени двойки.
* [**FSQRT**](http://www.felixcloutier.com/x86/FSQRT.html) — Квадратный корень.
* [**FXTRACT**](http://www.felixcloutier.com/x86/FXTRACT.html) — Извлечение показателя и мантиссы.
## Сравнения x87 FPU
* [**FCOM / FCOMP / FCOMPP**](http://www.felixcloutier.com/x86/FCOM:FCOMP:FCOMPP.html) — Сравнение чисел с плавающей точкой.
* [**FUCOM / FUCOMP / FUCOMPP**](http://www.felixcloutier.com/x86/FUCOM:FUCOMP:FUCOMPP.html) — Неупорядоченное сравнение чисел с плавающей точкой.
* [**FICOM / FICOMP**](http://www.felixcloutier.com/x86/FICOM:FICOMP.html) — Сравнение целых.
* [**FCOMI / FCOMIP / FUCOMI / FUCOMIP**](http://www.felixcloutier.com/x86/FCOMI:FCOMIP:FUCOMI:FUCOMIP.html) — Сравнение чисел с плавающей точкой с установкой флагов `rflags`.
* [**FTST**](http://www.felixcloutier.com/x86/FTST.html) — Тест (сравнение с 0.0).
* [**FXAM**](http://www.felixcloutier.com/x86/FXAM.html) — Анализ (exam) числа с плавающей точкой.
## Трансцендентные функции x87 FPU
* [**FSIN**](http://www.felixcloutier.com/x86/FSIN.html) — Синус.
* [**FCOS**](http://www.felixcloutier.com/x86/FCOS.html) — Косинус.
* [**FSINCOS**](http://www.felixcloutier.com/x86/FSINCOS.html) — Синус и косинус.
* [**FPTAN**](http://www.felixcloutier.com/x86/FPTAN.html) — Частичная тангенс‑функция.
* [**FPATAN**](http://www.felixcloutier.com/x86/FPATAN.html) — Частичная арктангенс‑функция.
* [**F2XM1**](http://www.felixcloutier.com/x86/F2XM1.html) — 2^x 1.
* [**FYL2X**](http://www.felixcloutier.com/x86/FYL2X.html) — y log2(x).
* [**FYL2XP1**](http://www.felixcloutier.com/x86/FYL2XP1.html) — y log2(x + 1).
## Загрузка констант x87 FPU
* [**FLD1 / FLDL2T / FLDL2E / FLDPI / FLDLG2 / FLDLN2 / FLDZ**](http://www.felixcloutier.com/x86/FLD1:FLDL2T:FLDL2E:FLDPI:FLDLG2:FLDLN2:FLDZ.html) — Загрузка констант.
## Управление x87 FPU
* [**FINCSTP**](http://www.felixcloutier.com/x86/FINCSTP.html) — Инкремент указателя стека FPU.
* [**FDECSTP**](http://www.felixcloutier.com/x86/FDECSTP.html) — Декремент указателя стека FPU.
* [**FFREE**](http://www.felixcloutier.com/x86/FFREE.html) — Освободить регистр FPU.
* [**FINIT / FNINIT**](http://www.felixcloutier.com/x86/FINIT:FNINIT.html) — Инициализация FPU.
* [**FCLEX / FNCLEX**](http://www.felixcloutier.com/x86/FCLEX:FNCLEX.html) — Очистка флагов исключений FPU.
* [**FSTCW / FNSTCW**](http://www.felixcloutier.com/x86/FSTCW:FNSTCW.html) — Сохранить управляющее слово FPU.
* [**FLDCW**](http://www.felixcloutier.com/x86/FLDCW.html) — Загрузить управляющее слово FPU.
* [**FSTENV / FNSTENV**](http://www.felixcloutier.com/x86/FSTENV:FNSTENV.html) — Сохранить окружение FPU.
* [**FLDENV**](http://www.felixcloutier.com/x86/FLDENV.html) — Загрузить окружение FPU.
* [**FSAVE / FNSAVE**](http://www.felixcloutier.com/x86/FSAVE:FNSAVE.html) — Сохранить состояние FPU.
* [**FRSTOR**](http://www.felixcloutier.com/x86/FRSTOR.html) — Восстановить состояние FPU.
* [**FSTSW / FNSTSW**](http://www.felixcloutier.com/x86/FSTSW:FNSTSW.html) — Сохранить статусное слово FPU.
* [**WAIT / FWAIT**](http://www.felixcloutier.com/x86/WAIT:FWAIT.html) — Ожидание готовности FPU.
* [**FNOP**](http://www.felixcloutier.com/x86/FNOP.html) — Пустая операция FPU.
## Управление состоянием x87 FPU и SIMD
* [**FXSAVE**](http://www.felixcloutier.com/x86/FXSAVE.html) — Сохранить состояние x87 FPU и SIMD.
* [**FXRSTOR**](http://www.felixcloutier.com/x86/FXRSTOR.html) — Восстановить состояние x87 FPU и SIMD.
## Обзор MMX
* SIMDмодель вычислений для 64битных упакованных целых.
* Восемь 64битных регистров данных MMX.
* Три новых типа упакованных данных:
* 64битные упакованные байтовые целые (со знаком и без)
* 64битные упакованные словные целые (со знаком и без)
* 64битные упакованные двойные слова (со знаком и без)
* Состояние MMX отображается на состояние x87 FPU; при переходах к инструкциям x87 FPU требуется осторожность во избежание неконсистентности результатов.
## Передача данных MMX
* [**MOVD / MOVQ**](http://www.felixcloutier.com/x86/MOVD:MOVQ.html) — Перемещение двойного/квадрослова между MMX и памятью/регистрами.
## Преобразования MMX
* [**PACKSSWB / PACKSSDW**](http://www.felixcloutier.com/x86/PACKSSWB:PACKSSDW.html) — Упаковка слов/двойных слов в байты со знаковым насыщением.
* [**PACKUSWB**](http://www.felixcloutier.com/x86/PACKUSWB.html) — Упаковка слов в байты с беззнаковым насыщением.
* [**PUNPCKHBW / PUNPCKHWD / PUNPCKHDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Распаковка старших байтов/слов/двойных слов.
* [**PUNPCKLBW / PUNPCKLWD / PUNPCKLDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Распаковка младших байтов/слов/двойных слов.
## Упакованная арифметика MMX
* [**PADDB / PADDW / PADDD**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Сложение упакованных байтов/слов/двойных слов.
* [**PADDSB / PADDSW**](http://www.felixcloutier.com/x86/PADDSB:PADDSW.html) — Сложение упакованных знаковых байтов/слов со знаковым насыщением.
* [**PADDUSB / PADDUSW**](http://www.felixcloutier.com/x86/PADDUSB:PADDUSW.html) — Сложение упакованных беззнаковых байтов/слов с беззнаковым насыщением.
* [**PSUBB / PSUBW / PSUBD**](http://www.felixcloutier.com/x86/PSUBB:PSUBW:PSUBD.html) — Вычитание упакованных байтов/слов/двойных слов.
* [**PSUBSB / PSUBSW**](http://www.felixcloutier.com/x86/PSUBSB:PSUBSW.html) — Вычитание упакованных знаковых байтов/слов со знаковым насыщением.
* [**PSUBUSB / PSUBUSW**](http://www.felixcloutier.com/x86/PSUBUSB:PSUBUSW.html) — Вычитание упакованных беззнаковых байтов/слов с беззнаковым насыщением.
* [**PMULHW**](http://www.felixcloutier.com/x86/PMULHW.html) — Умножение упакованных знаковых слов с сохранением старшей части результата.
* [**PMULLW**](http://www.felixcloutier.com/x86/PMULLW.html) — Умножение упакованных знаковых слов с сохранением младшей части.
* [**PMADDWD**](http://www.felixcloutier.com/x86/PMADDWD.html) — Умножение и сложение упакованных слов.
## Сравнения MMX
* [**PCMPEQB / PCMPEQW / PCMPEQD**](http://www.felixcloutier.com/x86/PCMPEQB:PCMPEQW:PCMPEQD.html) — Сравнение упакованных байтов/слов/двойных слов на равенство.
* [**PCMPGTB / PCMPGTW / PCMPGTD**](http://www.felixcloutier.com/x86/PCMPGTB:PCMPGTW:PCMPGTD.html) — Сравнение упакованных знаковых байтов/слов/двойных слов «больше чем».
## Логика MMX
* [**PAND**](http://www.felixcloutier.com/x86/PAND.html) — Побитовое И.
* [**PANDN**](http://www.felixcloutier.com/x86/PANDN.html) — Побитовое И‑НЕ.
* [**POR**](http://www.felixcloutier.com/x86/POR.html) — Побитовое ИЛИ.
* [**PXOR**](http://www.felixcloutier.com/x86/PXOR.html) — Побитовое исключающее ИЛИ.
## Сдвиги и ротации MMX
* [**PSLLW / PSLLD / PSLLQ**](http://www.felixcloutier.com/x86/PSLLW:PSLLD:PSLLQ.html) — Логический сдвиг упакованных слов/двойных слов/квадрослов влево.
* [**PSRLW / PSRLD / PSRLQ**](http://www.felixcloutier.com/x86/PSRLW:PSRLD:PSRLQ.html) — Логический сдвиг упакованных слов/двойных слов/квадрослов вправо.
* [**PSRAW / PSRAD**](http://www.felixcloutier.com/x86/PSRAW:PSRAD:PSRAQ.html) — Арифметический сдвиг упакованных слов/двойных слов вправо.
## Управление состоянием MMX
* [**EMMS**](http://www.felixcloutier.com/x86/EMMS.html) — Очистить состояние MMX.
## Обзор SSE
* Расширяет SIMDмодель, добавляя операции над упакованными и скалярными числами одиночной точности в 128битных регистрах.
* Шестнадцать (в 32битном режиме — восемь) 128битных регистров XMM.
* 128битные инструкции для упакованных и скалярных чисел одиночной точности.
* Расширения MMXинструкций новыми операциями над упакованными целыми в регистрах MMX.
* Явная предвыборка данных, управление кэшируемостью данных и упорядочиванием операций записи.
## Передача данных SSE
* [**MOVAPS**](http://www.felixcloutier.com/x86/MOVAPS.html) — Перемещение четырёх выровненных упакованных чисел одиночной точности между XMM и памятью.
* [**MOVUPS**](http://www.felixcloutier.com/x86/MOVUPS.html) — Перемещение четырёх невыровненных упакованных чисел одиночной точности между XMM и памятью.
* [**MOVHPS**](http://www.felixcloutier.com/x86/MOVHPS.html) — Перемещение двух чисел одиночной точности из/в старшую квадрословную часть XMM и память.
* [**MOVHLPS**](http://www.felixcloutier.com/x86/MOVHLPS.html) — Перемещение двух чисел из старшей части одного XMM в младшую часть другого XMM.
* [**MOVLPS**](http://www.felixcloutier.com/x86/MOVLPS.html) — Перемещение двух чисел одиночной точности из/в младшую квадрословную часть XMM и память.
* [**MOVLHPS**](http://www.felixcloutier.com/x86/MOVLHPS.html) — Перемещение двух чисел из младшей части одного XMM в старшую часть другого XMM.
* [**MOVMSKPS**](http://www.felixcloutier.com/x86/MOVMSKPS.html) — Извлечь маску знаков из четырёх упакованных чисел одиночной точности.
* [**MOVSS**](http://www.felixcloutier.com/x86/MOVSS.html) — Перемещение скалярного числа одиночной точности между XMM и памятью.
## Арифметика SSE (FP32)
* [**ADDPS**](http://www.felixcloutier.com/x86/ADDPS.html) — Сложение упакованных чисел одиночной точности.
* [**ADDSS**](http://www.felixcloutier.com/x86/ADDSS.html) — Сложение скалярных чисел одиночной точности.
* [**SUBPS**](http://www.felixcloutier.com/x86/SUBPS.html) — Вычитание упакованных чисел одиночной точности.
* [**SUBSS**](http://www.felixcloutier.com/x86/SUBSS.html) — Вычитание скалярных чисел одиночной точности.
* [**MULPS**](http://www.felixcloutier.com/x86/MULPS.html) — Умножение упакованных чисел одиночной точности.
* [**MULSS**](http://www.felixcloutier.com/x86/MULSS.html) — Умножение скалярных чисел одиночной точности.
* [**DIVPS**](http://www.felixcloutier.com/x86/DIVPS.html) — Деление упакованных чисел одиночной точности.
* [**DIVSS**](http://www.felixcloutier.com/x86/DIVSS.html) — Деление скалярных чисел одиночной точности.
* [**RCPPS**](http://www.felixcloutier.com/x86/RCPPS.html) — Обратные значения (1/x) для упакованных чисел.
* [**RCPSS**](http://www.felixcloutier.com/x86/RCPSS.html) — Обратное значение для скаляра.
* [**SQRTPS**](http://www.felixcloutier.com/x86/SQRTPS.html) — Квадратные корни упакованных чисел.
* [**SQRTSS**](http://www.felixcloutier.com/x86/SQRTSS.html) — Квадратный корень скалярного числа.
* [**RSQRTPS**](http://www.felixcloutier.com/x86/RSQRTPS.html) — Обратные квадратные корни упакованных чисел.
* [**RSQRTSS**](http://www.felixcloutier.com/x86/RSQRTSS.html) — Обратный квадратный корень скаляра.
* [**MAXPS**](http://www.felixcloutier.com/x86/MAXPS.html) — Максимумы упакованных чисел одиночной точности.
* [**MAXSS**](http://www.felixcloutier.com/x86/MAXSS.html) — Максимум скаляра одиночной точности.
* [**MINPS**](http://www.felixcloutier.com/x86/MINPS.html) — Минимумы упакованных чисел одиночной точности.
* [**MINSS**](http://www.felixcloutier.com/x86/MINSS.html) — Минимум скаляра одиночной точности.
## Сравнения SSE
* [**CMPPS**](http://www.felixcloutier.com/x86/CMPPS.html) — Сравнение упакованных чисел одиночной точности.
* [**CMPSS**](http://www.felixcloutier.com/x86/CMPSS.html) — Сравнение скалярных чисел одиночной точности.
* [**COMISS**](http://www.felixcloutier.com/x86/COMISS.html) — Упорядоченное сравнение скаляров и установка флагов `rflags`.
* [**UCOMISS**](http://www.felixcloutier.com/x86/UCOMISS.html) — Неупорядоченное сравнение скаляров и установка флагов `rflags`.
## Логика SSE
* [**ANDPS**](http://www.felixcloutier.com/x86/ANDPS.html) — Побитовое И упакованных чисел одиночной точности.
* [**ANDNPS**](http://www.felixcloutier.com/x86/ANDNPS.html) — Побитовое И‑НЕ упакованных чисел.
* [**ORPS**](http://www.felixcloutier.com/x86/ORPS.html) — Побитовое ИЛИ упакованных чисел.
* [**XORPS**](http://www.felixcloutier.com/x86/XORPS.html) — Побитовое XOR упакованных чисел.
## Перестановки и распаковка SSE
* [**SHUFPS**](http://www.felixcloutier.com/x86/SHUFPS.html) — Перестановка значений в упакованных операндах.
* [**UNPCKHPS**](http://www.felixcloutier.com/x86/UNPCKHPS.html) — Распаковка и чередование двух старших значений из двух операндов.
* [**UNPCKLPS**](http://www.felixcloutier.com/x86/UNPCKLPS.html) — Распаковка и чередование двух младших значений из двух операндов.
## Преобразования SSE
* [**CVTPI2PS**](http://www.felixcloutier.com/x86/CVTPI2PS.html) — Преобразование упакованных двойных слов в упакованные числа одиночной точности.
* [**CVTSI2SS**](http://www.felixcloutier.com/x86/CVTSI2SS.html) — Преобразование двойного слова в скаляр одиночной точности.
* [**CVTPS2PI**](http://www.felixcloutier.com/x86/CVTPS2PI.html) — Преобразование упакованных чисел одиночной точности в упакованные двойные слова.
* [**CVTTPS2PI**](http://www.felixcloutier.com/x86/CVTTPS2PI.html) — То же с усечением.
* [**CVTSS2SI**](http://www.felixcloutier.com/x86/CVTSS2SI.html) — Преобразование скаляра одиночной точности в двойное слово.
* [**CVTTSS2SI**](http://www.felixcloutier.com/x86/CVTTSS2SI.html) — То же с усечением.
## Управление MXCSR (SSE)
* [**LDMXCSR**](http://www.felixcloutier.com/x86/LDMXCSR.html) — Загрузка регистра MXCSR.
* [**STMXCSR**](http://www.felixcloutier.com/x86/STMXCSR.html) — Сохранение состояния MXCSR.
## SSE: 64битные целые (расширения MMX)
* [**PAVGB / PAVGW**](http://www.felixcloutier.com/x86/PAVGB:PAVGW.html) — Среднее значение упакованных беззнаковых байтов.
* [**PEXTRW**](http://www.felixcloutier.com/x86/PEXTRW.html) — Извлечь слово.
* [**PINSRW**](http://www.felixcloutier.com/x86/PINSRW.html) — Вставить слово.
* [**PMAXUB**](http://www.felixcloutier.com/x86/PMAXUB:PMAXUW.html) — Максимум упакованных беззнаковых байтов.
* [**PMAXSW**](http://www.felixcloutier.com/x86/PMAXSB:PMAXSW:PMAXSD:PMAXSQ.html) — Максимум упакованных знаковых слов.
* [**PMINUB**](http://www.felixcloutier.com/x86/PMINUB:PMINUW.html) — Минимум упакованных беззнаковых байтов.
* [**PMINSW**](http://www.felixcloutier.com/x86/PMINSB:PMINSW.html) — Минимум упакованных знаковых слов.
* [**PMOVMSKB**](http://www.felixcloutier.com/x86/PMOVMSKB.html) — Маска байтов (перенос знаков в маску).
* [**PMULHUW**](http://www.felixcloutier.com/x86/PMULHUW.html) — Умножение упакованных беззнаковых слов, сохранение старшей части.
* [**PSADBW**](http://www.felixcloutier.com/x86/MPSADBW.html) — Сумма абсолютных разностей.
* [**PSHUFW**](http://www.felixcloutier.com/x86/PSHUFW.html) — Перестановка слов в регистре MMX.
## SSE: кэшируемость, предвыборка и упорядочивание
* [**MASKMOVQ**](http://www.felixcloutier.com/x86/MASKMOVQ.html) — Нетемпоральная запись выбранных байтов из MMX в память.
* [**MOVNTQ**](http://www.felixcloutier.com/x86/MOVNTQ.html) — Нетемпоральная запись квадрослова из MMX в память.
* [**MOVNTPS**](http://www.felixcloutier.com/x86/MOVNTPS.html) — Нетемпоральная запись четырёх упакованных чисел одиночной точности из XMM в память.
* [**PREFETCHh**](http://www.felixcloutier.com/x86/PREFETCHh.html) — Загрузка 32 и более байт из памяти в выбранный уровень кэша.
* [**SFENCE**](http://www.felixcloutier.com/x86/SFENCE.html) — Сериализация операций записи.
## Обзор SSE2
* Упакованные и скалярные 128битные числа двойной точности.
* Дополнительные инструкции для 64 и 128битных упакованных байтов/слов/двойных слов/квадрослов.
* 128битные версии целочисленных инструкций из MMX и SSE.
* Дополнительные инструкции управления кэшируемостью и упорядочиванием инструкций.
## SSE2: перемещение данных FP64
* [**MOVAPD**](http://www.felixcloutier.com/x86/MOVAPD.html) — Перемещение двух выровненных упакованных чисел двойной точности между XMM и памятью.
* [**MOVUPD**](http://www.felixcloutier.com/x86/MOVUPD.html) — Перемещение двух невыровненных упакованных чисел двойной точности между XMM и памятью.
* [**MOVHPD**](http://www.felixcloutier.com/x86/MOVHPD.html) — Перемещение старшего элемента двойной точности из/в старшую часть XMM и память.
* [**MOVLPD**](http://www.felixcloutier.com/x86/MOVLPD.html) — Перемещение младшего элемента двойной точности из/в младшую часть XMM и память.
* [**MOVMSKPD**](http://www.felixcloutier.com/x86/MOVMSKPD.html) — Извлечь маску знаков из двух упакованных чисел двойной точности.
* [**MOVSD**](http://www.felixcloutier.com/x86/MOVSD.html) — Перемещение скалярного числа двойной точности между XMM и памятью.
## SSE2: арифметика FP64
* [**ADDPD**](http://www.felixcloutier.com/x86/ADDPD.html) — Сложение упакованных чисел двойной точности.
* [**ADDSD**](http://www.felixcloutier.com/x86/ADDSD.html) — Сложение скалярных чисел двойной точности.
* [**SUBPD**](http://www.felixcloutier.com/x86/SUBPD.html) — Вычитание упакованных чисел двойной точности.
* [**SUBSD**](http://www.felixcloutier.com/x86/SUBSD.html) — Вычитание скалярных чисел двойной точности.
* [**MULPD**](http://www.felixcloutier.com/x86/MULPD.html) — Умножение упакованных чисел двойной точности.
* [**MULSD**](http://www.felixcloutier.com/x86/MULSD.html) — Умножение скалярных чисел двойной точности.
* [**DIVPD**](http://www.felixcloutier.com/x86/DIVPD.html) — Деление упакованных чисел двойной точности.
* [**DIVSD**](http://www.felixcloutier.com/x86/DIVSD.html) — Деление скалярных чисел двойной точности.
* [**SQRTPD**](http://www.felixcloutier.com/x86/SQRTPD.html) — Квадратные корни упакованных чисел двойной точности.
* [**SQRTSD**](http://www.felixcloutier.com/x86/SQRTSD.html) — Квадратный корень скалярного числа двойной точности.
* [**MAXPD**](http://www.felixcloutier.com/x86/MAXPD.html) — Максимумы упакованных чисел двойной точности.
* [**MAXSD**](http://www.felixcloutier.com/x86/MAXSD.html) — Максимум скаляра двойной точности.
* [**MINPD**](http://www.felixcloutier.com/x86/MINPD.html) — Минимумы упакованных чисел двойной точности.
* [**MINSD**](http://www.felixcloutier.com/x86/MINSD.html) — Минимум скаляра двойной точности.
## SSE2: логические операции FP64
* [**ANDPD**](http://www.felixcloutier.com/x86/ANDPD.html) — Побитовое И упакованных чисел двойной точности.
* [**ANDNPD**](http://www.felixcloutier.com/x86/ANDNPD.html) — Побитовое И‑НЕ упакованных чисел двойной точности.
* [**ORPD**](http://www.felixcloutier.com/x86/ORPD.html) — Побитовое ИЛИ упакованных чисел двойной точности.
* [**XORPD**](http://www.felixcloutier.com/x86/XORPD.html) — Побитовое XOR упакованных чисел двойной точности.
## SSE2: сравнения FP64
* [**CMPPD**](http://www.felixcloutier.com/x86/CMPPD.html) — Сравнение упакованных чисел двойной точности.
* [**CMPSD**](http://www.felixcloutier.com/x86/CMPSD.html) — Сравнение скаляров двойной точности.
* [**COMISD**](http://www.felixcloutier.com/x86/COMISD.html) — Упорядоченное сравнение скаляров двойной точности с установкой `rflags`.
* [**UCOMISD**](http://www.felixcloutier.com/x86/UCOMISD.html) — Неупорядоченное сравнение скаляров двойной точности с установкой `rflags`.
## SSE2: перестановки и распаковка FP64
* [**SHUFPD**](http://www.felixcloutier.com/x86/SHUFPD.html) — Перестановка значений в упакованных операндах двойной точности.
* [**UNPCKHPD**](http://www.felixcloutier.com/x86/UNPCKHPD.html) — Распаковка и чередование старших значений из двух операндов.
* [**UNPCKLPD**](http://www.felixcloutier.com/x86/UNPCKLPD.html) — Распаковка и чередование младших значений из двух операндов.
## SSE2: преобразования
* [**CVTPD2PI**](http://www.felixcloutier.com/x86/CVTPD2PI.html) — Преобразование упакованных чисел двойной точности в упакованные двойные слова.
* [**CVTTPD2PI**](http://www.felixcloutier.com/x86/CVTTPD2PI.html) — То же с усечением.
* [**CVTPI2PD**](http://www.felixcloutier.com/x86/CVTPI2PD.html) — Преобразование упакованных двойных слов в упакованные числа двойной точности.
* [**CVTPD2DQ**](http://www.felixcloutier.com/x86/CVTPD2DQ.html) — Преобразование упакованных чисел двойной точности в упакованные двойные слова.
* [**CVTTPD2DQ**](http://www.felixcloutier.com/x86/CVTTPD2DQ.html) — То же с усечением.
* [**CVTDQ2PD**](http://www.felixcloutier.com/x86/CVTDQ2PD.html) — Преобразование упакованных двойных слов в упакованные числа двойной точности.
* [**CVTPS2PD**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Преобразование упакованных чисел одиночной в двойную точность.
* [**CVTPD2PS**](http://www.felixcloutier.com/x86/CVTPS2PD.html) — Преобразование упакованных чисел двойной в одиночную точность.
* [**CVTSS2SD**](http://www.felixcloutier.com/x86/CVTSS2SD.html) — Преобразование скаляра одиночной в двойную точность.
* [**CVTSD2SS**](http://www.felixcloutier.com/x86/CVTSD2SS.html) — Преобразование скаляра двойной в одиночную точность.
* [**CVTSD2SI**](http://www.felixcloutier.com/x86/CVTSD2SI.html) — Преобразование скаляра двойной точности в двойное слово.
* [**CVTTSD2SI**](http://www.felixcloutier.com/x86/CVTTSD2SI.html) — То же с усечением.
* [**CVTSI2SD**](http://www.felixcloutier.com/x86/CVTSI2SD.html) — Преобразование двойного слова в скаляр двойной точности.
## SSE2: FP32 (расширения SSE)
* [**CVTDQ2PS**](http://www.felixcloutier.com/x86/CVTDQ2PS.html) — Преобразование упакованных двойных слов в упакованные числа одиночной точности.
* [**CVTPS2DQ**](http://www.felixcloutier.com/x86/CVTPS2DQ.html) — Преобразование упакованных чисел одиночной точности в упакованные двойные слова.
* [**CVTTPS2DQ**](http://www.felixcloutier.com/x86/CVTTPS2DQ.html) — То же с усечением.
## SSE2: целочисленные инструкции
* [**MOVDQA**](http://www.felixcloutier.com/x86/MOVDQA:VMOVDQA32:VMOVDQA64.html) — Перемещение выровненного двойного квадрослова.
* [**MOVDQU**](http://www.felixcloutier.com/x86/MOVDQU:VMOVDQU8:VMOVDQU16:VMOVDQU32:VMOVDQU64.html) — Перемещение невыровненного двойного квадрослова.
* [**MOVQ2DQ**](http://www.felixcloutier.com/x86/MOVQ2DQ.html) — Перемещение квадрослова из MMX в XMM.
* [**MOVDQ2Q**](http://www.felixcloutier.com/x86/MOVDQ2Q.html) — Перемещение квадрослова из XMM в MMX.
* [**PMULUDQ**](http://www.felixcloutier.com/x86/PMULUDQ.html) — Умножение упакованных беззнаковых двойных слов.
* [**PADDQ**](http://www.felixcloutier.com/x86/PADDB:PADDW:PADDD:PADDQ.html) — Сложение упакованных квадрослов.
* [**PSUBQ**](http://www.felixcloutier.com/x86/PSUBQ.html) — Вычитание упакованных квадрослов.
* [**PSHUFLW**](http://www.felixcloutier.com/x86/PSHUFLW.html) — Перестановка младших слов.
* [**PSHUFHW**](http://www.felixcloutier.com/x86/PSHUFHW.html) — Перестановка старших слов.
* [**PSHUFD**](http://www.felixcloutier.com/x86/PSHUFD.html) — Перестановка двойных слов.
* [**PSLLDQ**](http://www.felixcloutier.com/x86/PSLLDQ.html) — Логический сдвиг двойного квадрослова влево.
* [**PSRLDQ**](http://www.felixcloutier.com/x86/PSRLDQ.html) — Логический сдвиг двойного квадрослова вправо.
* [**PUNPCKHQDQ**](http://www.felixcloutier.com/x86/PUNPCKHBW:PUNPCKHWD:PUNPCKHDQ:PUNPCKHQDQ.html) — Распаковка старших квадрослов.
* [**PUNPCKLQDQ**](http://www.felixcloutier.com/x86/PUNPCKLBW:PUNPCKLWD:PUNPCKLDQ:PUNPCKLQDQ.html) — Распаковка младших квадрослов.
## SSE2: кэшируемость и упорядочивание
* [**CLFLUSH**](http://www.felixcloutier.com/x86/CLFLUSH.html) — Сброс линии кэша.
* [**LFENCE**](http://www.felixcloutier.com/x86/LFENCE.html) — Сериализация операций чтения.
* [**MFENCE**](http://www.felixcloutier.com/x86/MFENCE.html) — Сериализация операций чтения и записи.
* [**PAUSE**](http://www.felixcloutier.com/x86/PAUSE.html) — Улучшает производительность «циклов активного ожидания» (spinwait).
* [**MASKMOVDQU**](http://www.felixcloutier.com/x86/MASKMOVDQU.html) — Нетемпоральная запись выбранных байтов из XMM в память.
* [**MOVNTPD**](http://www.felixcloutier.com/x86/MOVNTPD.html) — Нетемпоральная запись двух упакованных чисел двойной точности из XMM в память.
* [**MOVNTDQ**](http://www.felixcloutier.com/x86/MOVNTDQ.html) — Нетемпоральная запись двойного квадрослова из XMM в память.
* [**MOVNTI**](http://www.felixcloutier.com/x86/MOVNTI.html) — Нетемпоральная запись двойного слова из регистра общего назначения в память.
## Ссылки
* https://software.intel.com/sites/default/files/managed/39/c5/325462-sdm-vol-1-2abcd-3abcd.pdf
* http://www.agner.org/optimize/optimizing_assembly.pdf
* https://www.nasm.us/xdoc/2.13.03/nasmdoc.pdf
* https://godbolt.org/
* https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
* https://0xax.github.io/categories/assembler/
## Таблицы инструкций
* http://www.agner.org/optimize/instruction_tables.pdf
## Примеры
* https://github.com/torvalds/linux/tree/master/arch/x86
* https://gist.github.com/rygorous/bf1659bf6cd1752ed114367d4b87b302
* https://www.csee.umbc.edu/portal/help/nasm/sample_64.shtml
## Утилиты
* https://software.intel.com/sites/landingpage/IntrinsicsGuide/
* https://git.ffmpeg.org/gitweb/ffmpeg.git/blob_plain/HEAD:/libavutil/x86/x86inc.asm
* https://gist.github.com/rygorous/f729919ff64526a46e591d8f8b52058e

View File

@@ -1,16 +0,0 @@
global _start
section .data
text_message: db "Welcome to NASM!", 0xA
section .text
_start:
mov rax, 1 ; write
mov rdi, 1 ; stdout
mov rsi, text_message
mov rdx, 17 ; длина строки в байтах
syscall
mov rax, 60 ; exit
mov rdi, 1 ; код возврата = 0
syscall

31
nasm.code-workspace Normal file
View File

@@ -0,0 +1,31 @@
{
"folders": [
{
"path": "casm"
},
{
"path": "wayland"
},
{
"path": "docs"
},
],
"settings": {
"debug.allowBreakpointsEverywhere": true,
"debug.inlineValues": "on",
"editor.codeLens": false,
"files.associations": {
"flake.lock": "json",
"ios": "c",
"cstdint": "c",
"array": "c",
"string": "c",
"string_view": "c",
"ranges": "c",
"span": "c",
"vector": "c",
"regex": "c",
"__node_handle": "c"
},
}
}

29
stepik_base/10_to_2/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/10_to_2",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -5,11 +5,11 @@
"label": "asm64",
"type": "shell",
"command": [
"builddir=${fileDirname}/build;",
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/${fileBasenameNoExtension};",
"nasm -F dwarf -g -f elf64 -i ${fileDirname} -o $rawfilename.o ${file};",
"ld -m elf_x86_64 -o $rawfilename $rawfilename.o;"
"rawfilename=$builddir/10_to_2;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/10_to_2.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
@@ -27,16 +27,15 @@
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${fileDirname}/build;",
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/${fileBasenameNoExtension};",
"nasm -F dwarf -g -f elf64 -i ${fileDirname} -o $rawfilename.o ${file};",
"gcc -m64 -o $rawfilename $rawfilename.o;"
"rawfilename=$builddir/10_to_2;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/10_to_2.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
@@ -49,9 +48,6 @@
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build"
}
}
]
}

View File

@@ -0,0 +1,147 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция складывает два значения
; In: RDI, RSI
; Out: RAX
calculate_sum:
lea rax, [rdi + rsi]
ret
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
.while:
xor rdx, rdx
test rax, rax
jz .break
mov dl, al
and dl, 1
or dl, 0x30
mov [rsi], dl
dec rsi
shr rax, 1
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/even_odd",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/even_odd/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/even_odd;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/even_odd.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/even_odd;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/even_odd.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,80 @@
global _start
section .data
buff times 32 db 0
count dq 0
even db "Even"
evenCount dq $-even
odd db "Odd"
oddCount dq $-odd
section .text
default rel
_start:
call read_text
lea rsi, [buff]
add rsi, qword [count]
sub rsi, 2
mov rax, [rsi]
test rax, 0x1
jnz .even
.odd:
lea rsi, [even]
mov rdx, [evenCount]
jmp .write
.even:
lea rsi, [odd]
mov rdx, [oddCount]
.write:
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/is_digit",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/is_digit/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/is_digit;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/is_digit.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/is_digit;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/is_digit.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,79 @@
global _start
section .data
g_buff times 10 db 0
g_buffLen dq 0
g_digit db "Digit"
g_digitLen dq $-g_digit
g_notDigit db "Not a digit"
g_notDigitLen dq $-g_notDigit
section .text
default rel
_start:
call read_text
movzx rax, byte [g_buff] ; первый символ
cmp rax, '0'
jl .notDigit
cmp rax, '9'
jg .notDigit
.digit:
lea rsi, [g_digit]
mov rdx, [g_digitLen]
jmp .write
.notDigit:
lea rsi, [g_notDigit]
mov rdx, [g_notDigitLen]
.write:
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_buffLen], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [g_buffLen], rax
pop rdx
pop rsi
pop rdi
pop rax
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,108 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rsi, %1
mov rdx, %2
mov rdi, 1 ; stdout
mov rax, 1 ; sys_write
syscall
%endmacro
global _start
section .data
g_buff times 32 db 0
g_buff_end:
g_len dq 0
g_less_or_equal db "Less than or equal to 10"
g_less_or_equal_len dq $-g_less_or_equal
g_greater db "Greater than 10"
g_greater_len dq $-g_greater
section .text
default rel
_start:
call read_text
lea rsi, [rel g_buff] ; поставить указатель на начало буфера
call read_num
cmp rax, 10
jle .le
.g:
lea rdi, [g_greater]
mov rdx, [g_greater_len]
jmp .print
.le:
lea rdi, [g_less_or_equal]
mov rdx, [g_less_or_equal_len]
.print:
PRINT_MSG rdi, rdx
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_len], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [g_buff] ; rdi - конец данных
add rdi, [g_len]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/less_greater_10_neg",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10_neg;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10_neg.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/less_greater_10_neg;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/less_greater_10_neg.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,119 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rsi, %1
mov rdx, %2
mov rdi, 1 ; stdout
mov rax, 1 ; sys_write
syscall
%endmacro
global _start
section .data
g_buff times 32 db 0
g_buff_end:
g_len dq 0
g_less_or_equal db "B"
g_less_or_equal_len dq $-g_less_or_equal
g_greater db "A"
g_greater_len dq $-g_greater
section .text
default rel
_start:
call read_text
lea rsi, [rel g_buff] ; поставить указатель на начало буфера
call read_num
cmp rax, 10
jle .le
.g:
lea rdi, [g_greater]
mov rdx, [g_greater_len]
jmp .print
.le:
lea rdi, [g_less_or_equal]
mov rdx, [g_less_or_equal_len]
.print:
PRINT_MSG rdi, rdx
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel g_buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [g_len], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor r8, 1 ; r8 - флаг знака
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [g_buff] ; rdi - конец данных
add rdi, [g_len]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
cmp bl, '-'
jne .add
.neg:
neg r8
jmp .continue
.add:
mul rcx
and bl, 0x0F
add rax, rbx
.continue:
inc rsi
jmp .while
.return:
mul r8
pop rcx
pop rbx
ret

29
stepik_base/macro/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/macro",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/macro/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/macro;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/macro.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/macro;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/macro.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,27 @@
; Макрос для вывода сообщения
; In:
; - %1 - указатель на буффер с сообщением
; - %2 - длина сообщения
%macro PRINT_MSG 2
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
mov rsi, %1
mov rdx, %2
syscall
%endmacro
global _start
section .data
g_msg db "Hello, Stepic!"
g_msg_len dq $-g_msg
section .text
default rel
_start:
PRINT_MSG g_msg, [g_msg_len]
mov rax, 60
mov rdi, 0
syscall

29
stepik_base/min/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/min",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/min/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/min;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/min.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/min;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/min.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

94
stepik_base/min/min.asm Normal file
View File

@@ -0,0 +1,94 @@
global _start
section .data
arr db 5, 7, 3, 1, 2
arrEnd:
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
mov al, 0xFF
lea rsi, [arr]
lea rdi, [arrEnd]
.while:
movzx rbx, byte [rsi] ; текущее число
cmp rbx, rax
cmovl rax, rbx
inc rsi
cmp rsi, rdi
jne .while
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/repeat_str",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/repeat_str;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/repeat_str.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/repeat_str;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/repeat_str.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,130 @@
global _start
section .data
buff times 256 db 0
buffSize dq $-buff
count dq 0
section .text
default rel
_start:
lea rsi, [buff]
lea rdi, [count]
mov rdx, [buffSize]
call read_text
mov al, 0xA
lea rdi, [buff]
mov rcx, [count]
repne scasb
; Теперь rdi указывает на символ после \n
; Вычисляем длину строки: rdi - buff
lea rax, [buff]
sub rdi, rax
mov [count], rdi ; Сохраняем длину строки в count
; rsi уже установлен на buff + длина строки, т.е. на числе
mov rsi, rax
add rsi, rdi
mov rdx, 256
call read_num
mov rcx, rax
jrcxz .return
.while:
lea rsi, [buff]
mov rdx, [count]
call write_text
loop .while
.return:
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; In:
; - RSI - указатель на буффер
; - RDI - указатель на адрес для сохранения длины
; - RDX - длина буффера
; Регистры не изменяет
read_text:
push rax
push rdi
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
syscall
pop rdi
mov [rdi], rax
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rcx
push rax
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
pop rdx
pop rsi
pop rax
pop rcx
ret
; Функция читает число из буфера
; In:
; - RSI - указатель на буффер
; - RDX - длина буффера
; Out:
; - RAX - число
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
mov rdi, rsi
add rdi, rdx
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0x0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret

View File

@@ -0,0 +1,45 @@
{
"folders": [
{
"path": "sum"
},
{
"path": "even_odd"
},
{
"path": "repeat_str"
},
{
"path": "min"
},
{
"path": "is_digit"
},
{
"path": "macro"
},
{
"path": "less_greater_10"
},
{
"path": "less_greater_10_neg"
},
{
"path": "10_to_2"
},
{
"path": "word_count"
},
{
"path": "sum_digits"
},
{
"path": "../docs"
},
],
"settings": {
"debug.allowBreakpointsEverywhere": true,
"debug.inlineValues": "on",
"editor.codeLens": false,
}
}

21
stepik_base/sum/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/sum",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/sum",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

53
stepik_base/sum/.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

154
stepik_base/sum/sum.asm Normal file
View File

@@ -0,0 +1,154 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
mov rbx, rax
inc rsi
call read_num
mov rdi, rax
mov rsi, rbx
call calculate_sum
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция складывает два значения
; In: RDI, RSI
; Out: RAX
calculate_sum:
lea rax, [rdi + rsi]
ret
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
mul rcx
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,21 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/sum_digits",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/sum_digits",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum_digits;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum_digits.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/sum_digits;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/sum_digits.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,140 @@
global _start
section .data
buff times 32 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
lea rsi, [rel buff] ; поставить указатель на начало буфера
call read_num
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция читает число из stdin
; Out: RAX
read_num:
push rbx
push rcx
xor rbx, rbx ; обнулить регистр для символов
xor rax, rax ; обнулить аккумулирующий регистр
mov rcx, 10 ; множитель для сдвига
lea rdi, [rel buff] ; rdi - конец данных
add rdi, [count]
.while:
cmp rsi, rdi ; сначала проверяем границы, чтобы не читать за пределами
jge .return
mov bl, [rsi] ; прочитать текущий символ
cmp bl, 0xA ; если конец строки (\n) - закончить
je .return
cmp bl, 0 ; если null (\0) - закончить
jz .return
cmp bl, ' ' ; если пробел - закончить
jz .return
and bl, 0x0F
add rax, rbx
inc rsi
jmp .while
.return:
pop rcx
pop rbx
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

View File

@@ -0,0 +1,29 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch x64",
"type": "lldb",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64",
},
{
"name": "(gdb) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64"
},
{
"name": "(gdb+gcc) Launch x64",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/build/word_count",
"cwd": "${workspaceFolder}/build",
"preLaunchTask": "asm64+gcc"
}
]
}

View File

@@ -0,0 +1,53 @@
{
"version": "2.0.0",
"tasks": [
{
"label": "asm64",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/word_count;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/word_count.asm;",
"ld -g -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
"group": {
"kind": "build",
"isDefault": true
}
},
{
"label": "asm64+gcc",
"type": "shell",
"command": [
"builddir=${workspaceFolder}/build;",
"mkdir -p $builddir;",
"rawfilename=$builddir/word_count;",
"nasm -gdwarf -f elf64 -o $rawfilename.o ${workspaceFolder}/word_count.asm;",
"gcc -o $rawfilename $rawfilename.o;"
],
"problemMatcher": {
"pattern": {
"regexp": "error"
}
},
"presentation": {
"focus": true,
"panel": "dedicated",
"reveal": "silent",
"clear": true
},
}
]
}

View File

@@ -0,0 +1,129 @@
global _start
section .data
buff times 350 db 0
buffend:
count dq 0
section .text
default rel
_start:
call read_text
xor rax, rax
mov rcx, [count]
dec rcx
lea rsi, [buff]
mov r10, 1 ; просто единица
mov r8, 0 ; прошлый символ - не пробел
.loop:
mov dl, [rsi]
cmp dl, ' '
jne .continue ; если сейчас не пробел - выйти
test r8, r8
jz .continue ; если прошлое пробел - выйти
.space_after_word:
inc rax
.continue:
mov r8, 0
cmp dl, ' '
cmovne r8, r10
inc rsi
loop .loop
test r8, r8
jz .print ; если прошлое пробел - выйти
inc rax
.print:
call print_num_to_buf
mov rdx, [count]
call write_text
mov rax, 60
mov rdi, 0
syscall
; Функция читает текст в буффер
; Регистры не изменяет
read_text:
push rax
push rdi
push rsi
push rdx
mov rax, 0 ; sys_read
mov rdi, 0 ; stdin
lea rsi, [rel buff] ; адрес буфера
mov rdx, 256 ; количество байт
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит buff
; In:
; - RSI - начало буфера
; - RDX - размер буфера
; Регистры не изменяет
write_text:
push rax
push rdi
push rsi
push rdx
mov rax, 1 ; sys_write
mov rdi, 1 ; stdout
syscall
mov [count], rax
pop rdx
pop rsi
pop rdi
pop rax
ret
; Функция выводит число в buff
; In: RAX
; Out: RSI - указатель на начало строки
print_num_to_buf:
lea rsi, [buffend]
dec rsi
mov rdi, rsi ; сохранить последний адрес
mov byte [rsi], 0 ; вписать нуль
dec rsi
mov byte [rsi], 0xA ; вписать перенос строки
dec rsi
mov byte [rsi], '0'
test rax, rax
jz .return
mov rcx, 10 ; десятичный делитель
.while:
xor rdx, rdx
test rax, rax
jz .break
div rcx
or dl, 0x30
mov [rsi], dl
dec rsi
jmp .while
.break:
inc rsi
.return:
sub rdi, rsi
inc rdi
mov [count], rdi
ret

2
wayland/.ignore Normal file
View File

@@ -0,0 +1,2 @@
**/build/
**/out/

37
wayland/.vscode/launch.json vendored Normal file
View File

@@ -0,0 +1,37 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "(lldb) Launch",
"type": "lldb",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"args": [],
"cwd": "${workspaceFolder}",
"env": {
"PATH": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
}
},
{
"name": "(gdb) Launch",
"type": "cppdbg",
"request": "launch",
"program": "${command:cmake.launchTargetPath}",
"cwd": "${workspaceFolder}",
"environment": [
{
"name": "PATH",
"value": "${env:PATH}:${command:cmake.getLaunchTargetDirectory}"
},
],
"MIMode": "gdb",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
},
]
}
]
}

91
wayland/CMakeLists.txt Normal file
View File

@@ -0,0 +1,91 @@
cmake_minimum_required(VERSION 3.14)
project(wayland)
enable_language(ASM_NASM)
set(CMAKE_ASM_NASM_FLAGS "-f elf64 -I${CMAKE_CURRENT_BINARY_DIR}")
set(CMAKE_ASM_NASM_FLAGS_DEBUG "-gdwarf")
find_package(PkgConfig REQUIRED)
# Находим программу wayland-scanner
find_program(WAYLAND_SCANNER wayland-scanner REQUIRED)
# Ищем директорию с протоколами Wayland
find_path(WAYLAND_PROTOCOLS_DIR
NAMES stable/xdg-shell/xdg-shell.xml
PATHS /usr/share/wayland-protocols /usr/local/share/wayland-protocols
REQUIRED
)
# Путь к протоколу xdg-shell
set(PROTOCOL_XML ${WAYLAND_PROTOCOLS_DIR}/stable/xdg-shell/xdg-shell.xml)
# Генерируем заголовочный файл протокола
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h
COMMAND ${WAYLAND_SCANNER} client-header ${PROTOCOL_XML} ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h
DEPENDS ${PROTOCOL_XML}
)
# Генерируем исходный файл протокола
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c
COMMAND ${WAYLAND_SCANNER} private-code ${PROTOCOL_XML} ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c
DEPENDS ${PROTOCOL_XML}
)
# Цель для генерации протокола
add_custom_target(generate-xdg-shell DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.h ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c)
# Генерируем offsets.inc
add_executable(generate-offsets ${CMAKE_CURRENT_SOURCE_DIR}/generate-offsets.c)
target_include_directories(generate-offsets PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
add_custom_command(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc
COMMAND generate-offsets > ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc
DEPENDS generate-offsets
COMMENT "Generating offsets.inc"
)
add_custom_target(generate-offsets-file DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/offsets.inc)
# Создаем исполняемый файл из ассемблерного, C и сгенерированного кода
file(GLOB_RECURSE WAYLAND_SOURCES CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.c"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.asm"
)
# Append the generated XDG C source (will be created in the binary dir)
list(APPEND WAYLAND_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/xdg-shell-client-protocol.c)
# Create executable from collected sources
add_executable(wayland ${WAYLAND_SOURCES})
# Ensure generated files are produced before building the target
add_dependencies(wayland generate-xdg-shell generate-offsets-file)
# Include headers and binary dir where generated headers are written
target_include_directories(wayland PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/include
${CMAKE_CURRENT_BINARY_DIR}
${WAYLAND_CLIENT_INCLUDE_DIRS}
${XKBCOMMON_INCLUDE_DIRS}
)
pkg_check_modules(WAYLAND_CLIENT REQUIRED wayland-client)
set(WAYLAND_CLIENT_LIBRARIES ${WAYLAND_CLIENT_LIBRARIES})
set(WAYLAND_CLIENT_INCLUDE_DIRS ${WAYLAND_CLIENT_INCLUDE_DIRS})
# xkbcommon for keyboard layout handling
pkg_check_modules(XKBCOMMON REQUIRED xkbcommon)
set(XKBCOMMON_LIBRARIES ${XKBCOMMON_LIBRARIES})
set(XKBCOMMON_INCLUDE_DIRS ${XKBCOMMON_INCLUDE_DIRS})
find_package(Threads REQUIRED)
# Link to system libraries
target_link_libraries(wayland PRIVATE ${WAYLAND_CLIENT_LIBRARIES} ${XKBCOMMON_LIBRARIES} Threads::Threads)

23
wayland/CMakePresets.json Normal file
View File

@@ -0,0 +1,23 @@
{
"version": 8,
"configurePresets": [
{
"name": "debug-gcc",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Debug"
}
},
{
"name": "release-gcc",
"binaryDir": "${sourceDir}/build/${presetName}",
"cacheVariables": {
"CMAKE_C_COMPILER": "/usr/bin/gcc",
"CMAKE_CXX_COMPILER": "/usr/bin/g++",
"CMAKE_BUILD_TYPE": "Release"
}
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -0,0 +1,51 @@
@startuml
title Цикл анимации фигуры (aux_thread)
start
:aux_thread запущен;
while (окно не закрыто?) is (да)
:Залочить figure_mutex;
:figure_animation_step(draw_info);
partition "figure_animation_step (ASM)" {
:Обработка коллизий;
note right
figure_handle_collision():
- Расчёт точек фигуры на окружности
- Проверка выхода за границы
- Инверсия velocity при коллизии
- Обновление angular_velocity
end note
:Обновить позицию;
note right
position += (velocity * speed) / height
end note
:Обновить угол поворота;
note right
angle += angular_velocity * speed
end note
:Применить трение к вращению;
note right
angular_velocity *= 0.95
end note
}
:Разлочить figure_mutex;
:usleep(33 ms);
note right: ~30 FPS обновление физики
endwhile (нет)
:Завершение потока;
stop
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

View File

@@ -0,0 +1,76 @@
@startuml
title Цикл отрисовки окна (window_thread)
start
:window_thread запущен;
:Создать event queue;
:window_init();
:Запустить aux_thread для анимации;
while (окно не закрыто?) is (да)
:wl_display_dispatch_queue();
note right: Ожидание событий Wayland
if (событие произошло?) then (да)
if (xdg_surface_configure?) then (да)
:xdg_surface_ack_configure();
if (буфер не создан?) then (да)
:resize_canvas();
endif
:draw();
endif
if (xdg_toplevel_configure?) then (да)
if (размер изменился?) then (да)
:resize_new(w, h);
note right
- Освободить старый буфер
- Создать новый буфер
- Обновить размеры draw_info
end note
endif
endif
if (xdg_toplevel_close?) then (да)
:Установить need_close = 1;
endif
if (frame_callback?) then (да)
:Уничтожить старый callback;
:Создать новый callback;
partition "draw()" {
:Залочить figure_mutex;
:Очистить фон (черный);
:figure_draw();
note right
- Получить текущую фигуру
- Нарисовать границу и заливку
- Цвет зависит от типа фигуры
end note
:Разлочить figure_mutex;
:wl_surface_attach(buffer);
:wl_surface_damage_buffer();
:wl_surface_commit();
}
endif
endif
endwhile (нет)
:window_destroy();
:Уничтожить event queue;
:signal_thread_exit();
stop
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

View File

@@ -0,0 +1,127 @@
@startuml
title Структура классов проекта Wayland
class wayland_runtime {
+ init_wayland() : int32_t
+ run_window() : int32_t
+ wait_for_windows() : void
+ destroy_wayland() : void
+ get_window_by_surface(surf) : wayland_window*
--
- g_display : wl_display*
- g_slots[MAX_WINDOW_THREADS] : window_thread_slot
- g_thread_lock : pthread_mutex_t
- g_active_threads : atomic_int
- g_shutdown : atomic_bool
}
class window_thread_slot {
+ thread : pthread_t
+ aux_thread : pthread_t
+ active : int
+ queue : wl_event_queue*
+ window : wayland_window
}
class wayland_window {
+ id : int
+ wl_surface : wl_surface*
+ xdg_surface : xdg_surface*
+ xdg_toplevel : xdg_toplevel*
+ buffer : wl_buffer*
+ frame_callback : wl_callback*
+ queue : wl_event_queue*
+ need_close : int
+ draw_info : window_draw_info
--
+ window_init(display, queue) : int
+ window_destroy() : void
+ window_should_close() : int
}
class window_draw_info {
+ width : uint32_t
+ height : uint32_t
+ data : void*
+ figure : figure_animation_info
+ figure_mutex : pthread_mutex_t
}
class figure_animation_info {
+ type : figure_type
+ position : vec2
+ velocity : vec2
+ angle : float
+ angular_velocity : float
+ speed : float
+ radius : float
}
enum figure_type {
FIGURE_CIRCLE = 0
FIGURE_TRIANGLE = 1
FIGURE_SQUARE = 2
}
class registry {
+ registry_global_bind(display) : int
+ registry_global_unbind() : void
+ registry_get_compositor() : wl_compositor*
+ registry_get_shm() : wl_shm*
+ registry_get_xdg_wm_base() : xdg_wm_base*
--
- global_compositor : wl_compositor*
- global_shm : wl_shm*
- global_wm_base : xdg_wm_base*
- global_registry : wl_registry*
- global_thread : pthread_t
- global_thread_running : atomic_int
}
class input {
+ input_register_seat(seat) : void
+ input_cleanup() : void
--
- seat : wl_seat*
- keyboard : wl_keyboard*
- xkb_ctx : xkb_context*
- xkb_keymap : xkb_keymap*
- xkb_state : xkb_state*
- focused_window : wayland_window*
}
class input_handle {
+ keyboard_key_handle(kc, ks, state, window) : void
}
class figure_animate <<ASM>> {
+ figure_animation_step(draw_info) : void
+ place_points_on_circle(...) : void
--
- figure_handle_collision(draw_info) : void
- check_collision_mask(...) : uint64_t
- sincos_f32_rbp(angle) : (sin, cos)
}
class figure_draw {
+ figure_draw(draw_info, thickness, border_color, fill_color) : void
}
wayland_runtime "1" *-- "0..128" window_thread_slot
window_thread_slot "1" *-- "1" wayland_window
wayland_window "1" *-- "1" window_draw_info
window_draw_info "1" *-- "1" figure_animation_info
figure_animation_info --> figure_type
wayland_runtime ..> registry : uses
wayland_runtime ..> input : uses
wayland_window ..> registry : uses
wayland_window ..> figure_draw : uses
input ..> input_handle : uses
input --> wayland_window : focuses
window_thread_slot ..> figure_animate : uses (aux_thread)
figure_draw ..> figure_animate : uses
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

View File

@@ -0,0 +1,74 @@
@startuml
title Компоненты проекта Wayland
package "Wayland Application" {
[wayland-runtime] as Runtime
[registry] as Registry
[input] as Input
[input-handle] as InputHandle
[window] as Window
package "Rendering & Animation" {
[figure-draw] as FigureDraw
[figure-animate (ASM)] as FigureAnimate
}
Runtime --> Registry : использует глобальные объекты
Runtime --> Input : инициализирует
Runtime --> Window : создаёт и управляет
Input --> InputHandle : делегирует обработку
InputHandle --> Runtime : вызывает run_window()
InputHandle --> Window : изменяет параметры фигуры
Window --> Registry : получает compositor, shm, wm_base
Window --> FigureDraw : отрисовка фигуры
Window --> FigureAnimate : aux_thread для анимации
FigureDraw --> FigureAnimate : использует place_points_on_circle
}
package "System Libraries" {
[wayland-client] as WaylandLib
[xdg-shell-protocol] as XDGShell
[xkbcommon] as XKB
}
Registry --> WaylandLib
Registry --> XDGShell
Window --> WaylandLib
Window --> XDGShell
Input --> WaylandLib
Input --> XKB
cloud "Wayland Compositor" as Compositor
Runtime --> Compositor : wl_display_connect()
Registry --> Compositor : получение глобальных объектов
Window --> Compositor : создание окон и буферов
Input --> Compositor : получение событий клавиатуры
note right of Runtime
Центральный компонент:
- Управление жизненным циклом
- Многопоточность (окна + анимация)
- Синхронизация через mutex
end note
note right of FigureAnimate
Реализация на NASM:
- Физика движения
- Обработка коллизий
- Математика (sin/cos)
- SSE инструкции
end note
note right of Window
Каждое окно в отдельном потоке:
- window_thread: отрисовка
- aux_thread: анимация
- Event queue для изоляции событий
end note
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

View File

@@ -0,0 +1,78 @@
@startuml
title Последовательность инициализации Wayland приложения
actor Main
participant "wayland-runtime" as Runtime
participant "registry" as Registry
participant "input" as Input
participant "window" as Window
Main -> Runtime: init_wayland()
activate Runtime
Runtime -> Runtime: wl_display_connect()
note right: Подключение к Wayland серверу
Runtime -> Registry: registry_global_bind(display)
activate Registry
Registry -> Registry: wl_display_get_registry()
Registry -> Registry: wl_registry_add_listener()
Registry -> Registry: wl_display_roundtrip()
note right: Получение глобальных объектов:\n- wl_compositor\n- wl_shm\n- xdg_wm_base\n- wl_seat
Registry -> Input: input_register_seat(seat)
activate Input
Input -> Input: wl_seat_add_listener()
Input -> Input: wl_seat_get_keyboard()
Input -> Input: xkb_context_new()
note right: Инициализация обработки клавиатуры
deactivate Input
Registry -> Registry: pthread_create(global_thread)
note right: Запуск потока обработки\nглобальных событий
deactivate Registry
Runtime -> Runtime: Инициализация слотов окон
Runtime -> Runtime: atomic_store(g_shutdown, 0)
deactivate Runtime
Main -> Runtime: run_window()
activate Runtime
Runtime -> Runtime: Найти свободный слот
Runtime -> Runtime: pthread_create(window_thread)
note right: Создание потока окна
Runtime --> Main: slot_index
== Поток окна ==
Runtime -> Runtime: wl_display_create_queue()
Runtime -> Window: window_init(display, queue)
activate Window
Window -> Registry: registry_get_compositor()
Window -> Registry: registry_get_shm()
Window -> Registry: registry_get_xdg_wm_base()
Window -> Window: wl_compositor_create_surface()
Window -> Window: xdg_wm_base_get_xdg_surface()
Window -> Window: xdg_surface_get_toplevel()
Window -> Window: Инициализация listeners
Window -> Window: Инициализация figure_animation_info
note right: Параметры анимации:\n- position, velocity\n- angle, angular_velocity\n- speed, radius
deactivate Window
Runtime -> Runtime: pthread_create(aux_thread)
note right: Вспомогательный поток\nдля анимации
Runtime -> Runtime: wl_display_dispatch_queue()
note right: Цикл обработки событий окна
deactivate Runtime
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@@ -0,0 +1,61 @@
@startuml
title Обработка клавиатурного ввода
actor User
participant "Wayland Server" as Server
participant "input" as Input
participant "input-handle" as Handler
participant "wayland-runtime" as Runtime
participant "window" as Window
User -> Server: Нажатие клавиши
Server -> Input: keyboard_key(key, state)
activate Input
Input -> Input: xkb_state_key_get_one_sym()
note right: Преобразование keycode в keysym
Input -> Handler: keyboard_key_handle(kc, ks, state, window)
activate Handler
alt Клавиша Enter
Handler -> Runtime: run_window()
note right: Создание нового окна
else Клавиша '1'
Handler -> Window: figure.type = CIRCLE
else Клавиша '2'
Handler -> Window: figure.type = TRIANGLE
else Клавиша '3'
Handler -> Window: figure.type = SQUARE
else Клавиша '-'
Handler -> Handler: pthread_mutex_lock()
Handler -> Window: figure.speed -= 0.5
Handler -> Handler: Ограничить [1, 30]
Handler -> Handler: pthread_mutex_unlock()
else Клавиша '+' или '='
Handler -> Handler: pthread_mutex_lock()
Handler -> Window: figure.speed += 0.5
Handler -> Handler: Ограничить [1, 30]
Handler -> Handler: pthread_mutex_unlock()
else Клавиша Up
Handler -> Handler: pthread_mutex_lock()
Handler -> Window: figure.radius += 2.0
Handler -> Handler: Ограничить [1, max]
Handler -> Handler: pthread_mutex_unlock()
else Клавиша Down
Handler -> Handler: pthread_mutex_lock()
Handler -> Window: figure.radius -= 2.0
Handler -> Handler: Ограничить [1, max]
Handler -> Handler: pthread_mutex_unlock()
end
deactivate Handler
deactivate Input
note over Window
Изменения параметров фигуры
влияют на следующий frame
анимации и отрисовки
end note
@enduml

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View File

@@ -0,0 +1,62 @@
@startuml
title Диаграмма состояний фигуры
[*] --> Circle : init (по умолчанию)
Circle : Красный цвет (0xFFFF0000)
Circle : radius точек = 16
Triangle : Зелёный цвет (0xFF00FF00)
Triangle : radius точек = 3
Square : Синий цвет (0xFF0000FF)
Square : radius точек = 4
Circle --> Triangle : Клавиша '2'
Circle --> Square : Клавиша '3'
Triangle --> Circle : Клавиша '1'
Triangle --> Square : Клавиша '3'
Square --> Circle : Клавиша '1'
Square --> Triangle : Клавиша '2'
Circle : velocity движет позицию
Circle : angular_velocity вращает
Triangle : velocity движет позицию
Triangle : angular_velocity вращает
Square : velocity движет позицию
Square : angular_velocity вращает
note right of Circle
Общие свойства для всех состояний:
- position (x, y)
- velocity (vx, vy)
- angle (угол поворота)
- angular_velocity (скорость вращения)
- speed (множитель скорости: 1-30)
- radius (радиус в пикселях)
Управление:
- '+'/'-': изменение speed
- Up/Down: изменение radius
- Enter: создать новое окно
end note
state "Коллизия с границей" as Collision {
[*] --> CheckCollision
CheckCollision --> InvertVelocity : точка вышла за границу
InvertVelocity --> UpdateAngularVel : инверсия компоненты velocity
UpdateAngularVel --> CheckCollision : обновление angular_velocity
CheckCollision : проверка всех точек фигуры
InvertVelocity : vel = -vel (по оси коллизии)
UpdateAngularVel : зависит от направления движения
}
Circle --> Collision : каждый frame
Triangle --> Collision : каждый frame
Square --> Collision : каждый frame
Collision --> Circle
Collision --> Triangle
Collision --> Square
@enduml

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,30 @@
/* generate-offsets.c
* Генерирует offsets.inc с смещениями полей структур
*/
#include <stdio.h>
#include <stddef.h>
#include "window.h"
int main(void) {
printf("; offsets.inc — generated automatically\n");
// window_draw_info offsets
printf("WDI_DATA equ %zu\n", offsetof(struct window_draw_info, data));
printf("WDI_WIDTH equ %zu\n", offsetof(struct window_draw_info, width));
printf("WDI_HEIGHT equ %zu\n", offsetof(struct window_draw_info, height));
printf("WDI_FIGURE equ %zu\n", offsetof(struct window_draw_info, figure));
printf("WDI_FIGURE_MUTEX equ %zu\n", offsetof(struct window_draw_info, figure_mutex));
printf("\n");
// figure_animation_info offsets
printf("FIG_TYPE equ %zu\n", offsetof(struct figure_animation_info, type));
printf("FIG_POSITION equ %zu\n", offsetof(struct figure_animation_info, position));
printf("FIG_VELOCITY equ %zu\n", offsetof(struct figure_animation_info, velocity));
printf("FIG_ANGLE equ %zu\n", offsetof(struct figure_animation_info, angle));
printf("FIG_ANG_VEL equ %zu\n", offsetof(struct figure_animation_info, angular_velocity));
printf("FIG_SPEED equ %zu\n", offsetof(struct figure_animation_info, speed));
printf("FIG_RADIUS equ %zu\n", offsetof(struct figure_animation_info, radius));
return 0;
}

View File

@@ -0,0 +1,9 @@
#ifndef FIGURE_ANIMATE_H
#define FIGURE_ANIMATE_H
#include "window.h"
/* Провести один шаг анимации на окне */
void figure_animation_step(struct window_draw_info* draw_info);
#endif

View File

@@ -0,0 +1,9 @@
#ifndef FIGURE_DRAW_H
#define FIGURE_DRAW_H
#include "window.h"
/* Нарисовать фигуру на холсте */
void figure_draw(struct window_draw_info* draw_info, float border_thikness, uint32_t border_color, uint32_t fill_color);
#endif

26
wayland/include/figure.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef FIGURE_H
#define FIGURE_H
#include "geomerty.h"
enum figure_type
{
FIGURE_CIRCLE = 0,
FIGURE_TRIANGLE = 1,
FIGURE_SQUARE = 2
};
struct figure_animation_info {
enum figure_type type;
struct vec2 position;
struct vec2 velocity;
float angle;
float angular_velocity;
float speed;
float radius;
};
#endif

View File

@@ -0,0 +1,9 @@
#ifndef GEOMETRY_H
#define GEOMETRY_H
struct vec2 {
float x;
float y;
};
#endif

View File

@@ -0,0 +1,10 @@
#ifndef INPUT_HANDLE_H
#define INPUT_HANDLE_H
#include <xkbcommon/xkbcommon.h>
#include "window.h"
#include "input.h"
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window* window);
#endif

26
wayland/include/input.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef WAYLAND_INPUT_H
#define WAYLAND_INPUT_H
#include <wayland-client.h>
/* Вызывается при привязке wl_seat регистром */
void input_register_seat(struct wl_seat *seat);
/* Очистка input (разрушить keyboard и xkb state) */
void input_cleanup(void);
enum keyboard_key_state {
/**
* key is not pressed
*/
KEYBOARD_KEY_STATE_RELEASED = 0,
/**
* key is pressed
*/
KEYBOARD_KEY_STATE_PRESSED = 1,
/**
* key was repeated
*/
KEYBOARD_KEY_STATE_REPEATED = 2,
};
#endif

View File

@@ -0,0 +1,14 @@
#ifndef WAYLAND_REGISTRY_H
#define WAYLAND_REGISTRY_H
#include <wayland-client.h>
int registry_global_bind(struct wl_display *display);
void registry_global_unbind(void);
/* Доступ к привязанным глобальным объектам */
struct wl_compositor *registry_get_compositor(void);
struct wl_shm *registry_get_shm(void);
struct xdg_wm_base *registry_get_xdg_wm_base(void);
#endif

View File

@@ -0,0 +1,21 @@
#ifndef WAYLAND_RUNTIME_H
#define WAYLAND_RUNTIME_H
#include <stdint.h>
/* Инициализация общего соединения Wayland и подготовка глобальных данных */
int32_t init_wayland(void);
/* Создать поток для окна; вернуть индекс слота или отрицательное при ошибке */
int32_t run_window(void);
/* Блокировать до завершения всех оконных потоков */
void wait_for_windows(void);
/* Остановить оконные потоки, очистить input и закрыть соединение Wayland */
void destroy_wayland(void);
/* Поиск окна по wl_surface */
struct wayland_window* get_window_by_surface(struct wl_surface* surf);
#endif

39
wayland/include/window.h Normal file
View File

@@ -0,0 +1,39 @@
#ifndef WAYLAND_WINDOW_H
#define WAYLAND_WINDOW_H
#include <pthread.h>
#include <wayland-client.h>
#include "figure.h"
struct window_draw_info {
uint8_t *data;
int32_t width;
int32_t height;
struct figure_animation_info figure;
pthread_mutex_t figure_mutex;
};
/* Данные одного Wayland-окна (одна поверхность) */
struct wayland_window {
int id;
struct wl_surface *wl_surface;
struct wl_buffer *buffer;
struct wl_callback *frame_callback;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_event_queue *queue; /* очередь событий для окна */
struct window_draw_info draw_info;
int need_close;
};
/* Инициализация окна; структура предоставляется вызывающим */
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win);
/* Нечётное значение — окно запросило закрытие */
int window_should_close(struct wayland_window *win);
/* Уничтожить окно и связанные ресурсы */
void window_destroy(struct wayland_window *win);
#endif

23
wayland/src/asm.asm Normal file
View File

@@ -0,0 +1,23 @@
global main
extern init_wayland
extern run_window
extern wait_for_windows
extern destroy_wayland
section .text
main:
enter 0, 0
call init_wayland
cmp eax, 0
jl .shutdown
; Launch the first window thread (duplicate calls for more windows)
call run_window
call wait_for_windows
.shutdown:
call destroy_wayland
leave
ret

View File

@@ -0,0 +1,616 @@
; Макрос для локальных переменных
%macro local 2
%assign __local_offset __local_offset - %2
%define %1 (__local_offset)
%endmacro
; Подключаем автоматически сгенерированные offsets из C структур
%include "offsets.inc"
section .rodata
PI: dd 3.1415926
TWO_PI: dd 6.2831852
NEG_ONE_CONST: dd -1.0
ONE_CONST: dd 1.0
ZERO_CONST: dd 0.0
ABS_MASK: dd 0x7fffffff, 0x7fffffff, 0x7fffffff, 0x7fffffff
ANG_COLLIDE_COEF: dd 0.2
ANG_BOOST_FACTOR: dd 0.01
; Скорость углового обновления (можно регулировать независимо от FIG_SPEED)
ANG_SPEED: dd 15.0
ANG_MAX: dd 0.03
ANG_SWITCH_FACTOR: dd 0.2
ANG_MAX_DELTA: dd 0.006
ANG_FRICTION: dd 0.94
section .text
; void figure_animation_step(struct window_draw_info* draw_info);
; Параметры:
; rdi - указатель на struct window_draw_info
%assign __local_offset 0
global figure_animation_step
figure_animation_step:
enter 0, 0
; Отработка коллизий
push rdi
call figure_handle_collision
pop rdi
; Вычислить нормализующий коэффициент: 1.0 / height_pixels
cvtsi2ss xmm4, dword [rdi + WDI_HEIGHT]
movss xmm5, [rel ONE_CONST]
divss xmm5, xmm4 ; xmm5 = 1.0 / height
; Обновить позицию: position += (velocity * speed) / height_pixels
; pos_x += (vel_x * speed) / height
movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY]
mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
mulss xmm0, xmm5 ; нормализовать скорость
addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION]
movss [rdi + WDI_FIGURE + FIG_POSITION], xmm0
; pos_y += (vel_y * speed) / height
movss xmm0, [rdi + WDI_FIGURE + FIG_VELOCITY + 4]
mulss xmm0, [rdi + WDI_FIGURE + FIG_SPEED]
mulss xmm0, xmm5 ; нормализовать скорость
addss xmm0, [rdi + WDI_FIGURE + FIG_POSITION + 4]
movss [rdi + WDI_FIGURE + FIG_POSITION + 4], xmm0
; Обновить угол: angle += angular_velocity * ANG_SPEED (локальная константа)
movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
mulss xmm0, [rel ANG_SPEED]
addss xmm0, [rdi + WDI_FIGURE + FIG_ANGLE]
movss [rdi + WDI_FIGURE + FIG_ANGLE], xmm0
; Apply angular friction to slow down rotation over time
movss xmm0, [rdi + WDI_FIGURE + FIG_ANG_VEL]
mulss xmm0, [rel ANG_FRICTION]
movss [rdi + WDI_FIGURE + FIG_ANG_VEL], xmm0
leave
ret
; Функция для обработки коллизии, изменяет velocity при обнаружении коллизии с границами
; Параметры:
; rdi - указатель на struct window_draw_info
%assign __local_offset 0
figure_handle_collision:
enter 128,0
local point_buffer, 128
; Сохранить регистры
push r12
push r13
push r14
push r15
mov r12, rdi
; Нормализовать радиус: radius_normalized = radius_pixels / height_pixels
movss xmm3, [r12 + WDI_FIGURE + FIG_RADIUS]
cvtsi2ss xmm4, dword [r12 + WDI_HEIGHT]
divss xmm3, xmm4
; Вызов place_points_on_circle
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
movss xmm1, [r12 + WDI_FIGURE + FIG_POSITION + 4]
movss xmm2, [r12 + WDI_FIGURE + FIG_ANGLE] ; смещение угла = 0
mulss xmm2, [rel NEG_ONE_CONST]
; Установка правильного количества точек
mov eax, dword [r12 + WDI_FIGURE + FIG_TYPE]
cmp eax, 1 ; FIGURE_TRIANGLE
je .figure_triangle
cmp eax, 2 ; FIGURE_SQUARE
je .figure_square
; default (FIGURE_CIRCLE and others): 16 points
mov rsi, 16
jmp .figure_points_done
.figure_triangle:
mov rsi, 3
jmp .figure_points_done
.figure_square:
mov rsi, 4
.figure_points_done:
lea rdi, [rbp + point_buffer]
call place_points_on_circle
; Вычислить canvas_width = width_pixels / height_pixels
cvtsi2ss xmm0, dword [r12 + WDI_WIDTH]
cvtsi2ss xmm1, dword [r12 + WDI_HEIGHT]
divss xmm0, xmm1
movss xmm14, xmm0 ; сохраняем canvas_width в xmm14
movss xmm13, [rel ONE_CONST] ; canvas_height = 1.0 в xmm13
; Инициализация: r14 = маска коллизий (OR всех точек), r15 = указатель на текущую точку
xor r14, r14
lea r15, [rbp + point_buffer]
mov rcx, rsi
.point_check:
; Загрузить координаты точки
movss xmm2, [r15] ; x
movss xmm3, [r15 + 4] ; y
; Вызвать check_collision_mask(canvas_width, canvas_height, x, y)
movss xmm0, xmm14 ; width
movss xmm1, xmm13 ; height = 1.0
push rcx
call check_collision_mask
pop rcx
; Объединить маску коллизий
or r14, rax
; Перейти к следующей точке
add r15, 8
loop .point_check
; Проверить, были ли коллизии
test r14, r14
jz .no_collision
; -----------------------
; Обновить угловую скорость при коллизии
; Формула: delta = |relevant_velocity| * speed * ANG_COLLIDE_COEF
; Знак delta зависит от границы и направления движения.
; Если итоговое направление совпадает с текущим - даём небольшой буст.
; -----------------------
; Сохраняем старую угловую скорость и обнуляем суммарный эффект
movss xmm6, [r12 + WDI_FIGURE + FIG_ANG_VEL] ; old ang vel
xorps xmm7, xmm7 ; total delta
; LEFT (bit 0): use vertical motion (vel_y)
test r14, 0x1
jz .skip_left_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4] ; vel_y
movss xmm1, xmm0
; Broadcast ABS_MASK (0x7fffffff) into xmm2 and AND to get abs
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; abs(vel_y)
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
jb .left_up_ang ; vel_y < 0 -> moving UP
; moving DOWN -> clockwise (+)
addss xmm7, xmm1
jmp .skip_left_ang
.left_up_ang:
; moving UP -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
.skip_left_ang:
; RIGHT (bit 2): use vertical motion (vel_y)
test r14, 0x4
jz .skip_right_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4] ; vel_y
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
jb .right_up_ang ; vel_y < 0 -> moving UP
; moving DOWN -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
jmp .skip_right_ang
.right_up_ang:
; moving UP -> clockwise (+)
addss xmm7, xmm1
.skip_right_ang:
; TOP (bit 1): use horizontal motion (vel_x)
test r14, 0x2
jz .skip_top_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY] ; vel_x
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
ja .top_right_ang ; vel_x > 0 -> moving RIGHT
; moving LEFT -> clockwise (+)
addss xmm7, xmm1
jmp .skip_top_ang
.top_right_ang:
; moving RIGHT -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
.skip_top_ang:
; BOTTOM (bit 3): use horizontal motion (vel_x)
test r14, 0x8
jz .skip_bottom_ang
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY] ; vel_x
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2
mulss xmm1, [r12 + WDI_FIGURE + FIG_SPEED]
mulss xmm1, [rel ANG_COLLIDE_COEF]
ucomiss xmm0, [rel ZERO_CONST]
ja .bottom_right_ang ; vel_x > 0 -> moving RIGHT
; moving LEFT -> anticlockwise (-)
movss xmm2, [rel NEG_ONE_CONST]
mulss xmm1, xmm2
addss xmm7, xmm1
jmp .skip_bottom_ang
.bottom_right_ang:
; moving RIGHT -> clockwise (+)
addss xmm7, xmm1
.skip_bottom_ang:
; Если суммарный эффект нулевой - ничего не делаем
ucomiss xmm7, [rel ZERO_CONST]
je .ang_no_change
; Invert direction rules to match drawing coordinate system
; (User requested flip — so we reverse sign of computed delta)
movss xmm0, [rel NEG_ONE_CONST]
mulss xmm7, xmm0
; Decide: same direction or switch sign
ucomiss xmm6, [rel ZERO_CONST]
jb .old_neg_dir
; old >= 0
ucomiss xmm7, [rel ZERO_CONST]
jae .same_dir
jmp .switch_dir
.old_neg_dir:
; old < 0
ucomiss xmm7, [rel ZERO_CONST]
jb .same_dir
jmp .switch_dir
; If same direction -> boost and add
.same_dir:
mulss xmm7, [rel ANG_BOOST_FACTOR]
; Clamp delta magnitude to ANG_MAX_DELTA
movss xmm0, xmm7
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs(delta)
movss xmm3, [rel ANG_MAX_DELTA]
ucomiss xmm1, xmm3
ja .cap_delta_same
jmp .after_cap_same
.cap_delta_same:
; Set abs(delta) = ANG_MAX_DELTA, preserve sign
movss xmm1, [rel ANG_MAX_DELTA]
ucomiss xmm0, [rel ZERO_CONST]
jae .cap_delta_same_pos
movss xmm4, [rel NEG_ONE_CONST]
mulss xmm1, xmm4
.cap_delta_same_pos:
movss xmm7, xmm1
.after_cap_same:
addss xmm6, xmm7
jmp .finish_dir_logic
; Switch sign -> compute new magnitude using old magnitude and delta
.switch_dir:
; xmm6 = old, xmm7 = delta
; abs_old = abs(xmm6)
movss xmm0, xmm6
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs_old
; abs_delta = abs(xmm7)
movss xmm3, xmm7
movss xmm4, xmm3
andps xmm4, xmm2 ; xmm4 = abs_delta
; Clamp abs_delta
movss xmm5, [rel ANG_MAX_DELTA]
ucomiss xmm4, xmm5
ja .cap_delta_switch
jmp .delta_not_capped
.cap_delta_switch:
movss xmm4, xmm5
.delta_not_capped:
; abs_old *= ANG_SWITCH_FACTOR
movss xmm5, [rel ANG_SWITCH_FACTOR]
mulss xmm1, xmm5
; new_mag = abs_old + abs_delta
addss xmm1, xmm4
; apply sign of delta (xmm7)
ucomiss xmm7, [rel ZERO_CONST]
jae .switch_positive
; negative
movss xmm5, [rel NEG_ONE_CONST]
mulss xmm1, xmm5
movss xmm6, xmm1
jmp .finish_dir_logic
.switch_positive:
movss xmm6, xmm1
.finish_dir_logic:
; Clamp angular velocity: |xmm6| <= ANG_MAX
movss xmm0, xmm6
movss xmm1, xmm0
mov eax, dword [rel ABS_MASK]
movd xmm2, eax
pshufd xmm2, xmm2, 0x0
andps xmm1, xmm2 ; xmm1 = abs(xmm0)
movss xmm2, [rel ANG_MAX]
ucomiss xmm1, xmm2
ja .ang_clamp_needed
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
jmp .ang_no_change2
.ang_clamp_needed:
; If xmm0 >= 0 -> set +ANG_MAX else set -ANG_MAX
ucomiss xmm0, [rel ZERO_CONST]
jae .ang_positive_clamp
; negative
movss xmm3, [rel ANG_MAX]
movss xmm4, [rel NEG_ONE_CONST]
mulss xmm3, xmm4
movss xmm6, xmm3
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
jmp .ang_no_change2
.ang_positive_clamp:
movss xmm3, [rel ANG_MAX]
movss xmm6, xmm3
movss [r12 + WDI_FIGURE + FIG_ANG_VEL], xmm6
.ang_no_change2:
.ang_no_change:
; Обработка коллизий: инвертировать velocity только если движемся к границе
; Обработка velocity
; Проверка left (bit 0): инвертировать velocity.x только если vel.x < 0
test r14, 0x1
jz .check_right
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_right ; если vel.x >= 0, пропускаем
; vel.x < 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY], xmm0
.check_right:
; Проверка right (bit 2): инвертировать velocity.x только если vel.x > 0
test r14, 0x4
jz .check_top
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jbe .check_top ; если vel.x <= 0, пропускаем
; vel.x > 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY], xmm0
.check_top:
; Проверка top (bit 1): инвертировать velocity.y только если vel.y < 0
test r14, 0x2
jz .check_bottom
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_bottom ; если vel.y >= 0, пропускаем
; vel.y < 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY + 4], xmm0
.check_bottom:
; Проверка bottom (bit 3): инвертировать velocity.y только если vel.y > 0
test r14, 0x8
jz .no_collision
movss xmm0, [r12 + WDI_FIGURE + FIG_VELOCITY + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jbe .no_collision ; если vel.y <= 0, пропускаем
; vel.y > 0, инвертируем
movss xmm1, [rel NEG_ONE_CONST]
mulss xmm0, xmm1
movss [r12 + WDI_FIGURE + FIG_VELOCITY + 4], xmm0
.no_collision:
; Костыль: если центр фигуры вышел за границу, вернуть его на границу
; Проверка pos_x < 0
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_pos_x_max
movss [r12 + WDI_FIGURE + FIG_POSITION], xmm1 ; pos_x = 0
.check_pos_x_max:
; Проверка pos_x > canvas_width
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION]
ucomiss xmm0, xmm14
jbe .check_pos_y_min
movss [r12 + WDI_FIGURE + FIG_POSITION], xmm14 ; pos_x = canvas_width
.check_pos_y_min:
; Проверка pos_y < 0
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION + 4]
movss xmm1, [rel ZERO_CONST]
ucomiss xmm0, xmm1
jae .check_pos_y_max
movss [r12 + WDI_FIGURE + FIG_POSITION + 4], xmm1 ; pos_y = 0
.check_pos_y_max:
; Проверка pos_y > canvas_height (1.0)
movss xmm0, [r12 + WDI_FIGURE + FIG_POSITION + 4]
ucomiss xmm0, xmm13
jbe .position_clamped
movss [r12 + WDI_FIGURE + FIG_POSITION + 4], xmm13 ; pos_y = 1.0
.position_clamped:
; Восстановить регистры
pop r15
pop r14
pop r13
pop r12
leave
ret
; Функция для расположения точек на окружности
; Вход:
; xmm0 - pos_x
; xmm1 - pos_y
; xmm2 - смещение точек на окружности в радианах
; xmm3 - радиус
; rdi - адрес буфера для точек
; rsi - количество точек
; Уничтожает: rax, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7
global place_points_on_circle
place_points_on_circle:
enter 0, 0
; Сохранить координаты центра
movss xmm6, xmm0
movss xmm7, xmm1
; Рассчитать TWO_PI / rsi и сохранить в xmm4
movss xmm4, [rel TWO_PI]
cvtsi2ss xmm5, rsi
divss xmm4, xmm5
movss xmm5, [rel ZERO_CONST] ; счётчик
mov rcx, rsi
.loop:
movss xmm0, xmm5
mulss xmm0, xmm4 ; Счётчик*шаг
addss xmm0, xmm2 ; Прибавить смещение
call sincos_f32_rbp ; Посчитать sincos
mulss xmm0, xmm3 ; sin *= radius
mulss xmm1, xmm3 ; cos *= radius
addss xmm1, xmm6 ; x = center_x + cos*radius
addss xmm0, xmm7 ; y = center_y + sin*radius
movss [rdi], xmm1
movss [rdi + 4], xmm0
add rdi, 8
addss xmm5, [rel ONE_CONST]
loop .loop
leave
ret
; Функция для рассчёта sin и cos
; Вход:
; xmm0 - угол в радианах (float)
; Выход:
; xmm0 - sin(angle)
; xmm1 - cos(angle)
; Уничтожает: rax, flags
sincos_f32_rbp:
enter 24, 0 ; 24 байта локального места:
; [rbp-8] — временно угол (для fld)
; [rbp-16] — sin
; [rbp-24] — cos
; (выравнивание по 16 будет соблюдено за счёт enter)
; Сохраняем входной угол как float32 в стек для загрузки в x87
movss [rbp-8], xmm0
fld dword [rbp-8] ; ST(0) = angle (в extended precision)
fsincos ; ST(0) = cos, ST(1) = sin
; Сохраняем результаты обратно в память как float32
fstp dword [rbp-24] ; pop cos → [rbp-24]
fstp dword [rbp-16] ; pop sin → [rbp-16]
; Загружаем результаты в xmm0 и xmm1
movss xmm0, [rbp-16] ; xmm0 = sin
movss xmm1, [rbp-24] ; xmm1 = cos
leave ; эквивалент: mov rsp, rbp / pop rbp
ret
; Функция проверки выхода за границы с маской
; Вход:
; xmm0 - width
; xmm1 - height
; xmm2 - x
; xmm3 - y
; Выход:
; rax - битовая маска границ (left=1, top=2, right=4, bottom=8)
check_collision_mask:
xor rax, rax ; очистим rax (маска)
movss xmm4, [rel ZERO_CONST]
; left: x < 0
ucomiss xmm2, xmm4
jb .set_left
.next_left:
; right: x > width
ucomiss xmm2, xmm0
ja .set_right
.next_right:
; top: y < 0
ucomiss xmm3, xmm4
jb .set_top
.next_top:
; bottom: y > height
ucomiss xmm3, xmm1
ja .set_bottom
ret
.set_left:
or rax, 1
jmp .next_left
.set_top:
or rax, 2
jmp .next_top
.set_right:
or rax, 4
jmp .next_right
.set_bottom:
or rax, 8
ret

239
wayland/src/figure-draw.c Normal file
View File

@@ -0,0 +1,239 @@
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "figure-draw.h"
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
/* Вспомогательная функция для установки пикселя */
static inline void set_pixel(uint8_t *data, int32_t width, int32_t height, int x, int y, uint32_t color)
{
if (x < 0 || x >= width || y < 0 || y >= height)
return;
uint32_t *pixel = (uint32_t *)(data + (y * width + x) * 4);
*pixel = color;
}
/* Проверка, находится ли точка внутри треугольника (барицентрические координаты) */
static int point_in_triangle(float px, float py, float x1, float y1, float x2, float y2, float x3, float y3)
{
float d1 = (px - x2) * (y1 - y2) - (x1 - x2) * (py - y2);
float d2 = (px - x3) * (y2 - y3) - (x2 - x3) * (py - y3);
float d3 = (px - x1) * (y3 - y1) - (x3 - x1) * (py - y1);
int has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0);
int has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0);
return !(has_neg && has_pos);
}
/* Расстояние от точки до отрезка */
static float point_to_segment_distance(float px, float py, float x1, float y1, float x2, float y2)
{
float dx = x2 - x1;
float dy = y2 - y1;
float len_sq = dx * dx + dy * dy;
if (len_sq < 0.0001f) {
dx = px - x1;
dy = py - y1;
return sqrtf(dx * dx + dy * dy);
}
float t = ((px - x1) * dx + (py - y1) * dy) / len_sq;
t = fmaxf(0.0f, fminf(1.0f, t));
float proj_x = x1 + t * dx;
float proj_y = y1 + t * dy;
dx = px - proj_x;
dy = py - proj_y;
return sqrtf(dx * dx + dy * dy);
}
/* Рисование круга */
static void draw_circle(struct window_draw_info* draw_info, float cx, float cy, float radius,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
int x_min = (int)fmaxf(0, cx - radius - border_thickness);
int x_max = (int)fminf(draw_info->width - 1, cx + radius + border_thickness);
int y_min = (int)fmaxf(0, cy - radius - border_thickness);
int y_max = (int)fminf(draw_info->height - 1, cy + radius + border_thickness);
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
float dx = x - cx;
float dy = y - cy;
float dist = sqrtf(dx * dx + dy * dy);
if (dist <= radius) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else if (dist <= radius + border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
}
}
}
}
/* Рисование треугольника */
static void draw_triangle(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
/* Вычисляем координаты вершин равностороннего треугольника */
/* Угол 0 означает, что одна вершина справа от центра */
float vertices[3][2];
for (int i = 0; i < 3; i++) {
float vertex_angle = angle + i * (2.0f * M_PI / 3.0f);
vertices[i][0] = cx + radius * cosf(vertex_angle);
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
}
/* Находим ограничивающий прямоугольник */
float min_x = fminf(vertices[0][0], fminf(vertices[1][0], vertices[2][0])) - border_thickness;
float max_x = fmaxf(vertices[0][0], fmaxf(vertices[1][0], vertices[2][0])) + border_thickness;
float min_y = fminf(vertices[0][1], fminf(vertices[1][1], vertices[2][1])) - border_thickness;
float max_y = fmaxf(vertices[0][1], fmaxf(vertices[1][1], vertices[2][1])) + border_thickness;
int x_min = (int)fmaxf(0, min_x);
int x_max = (int)fminf(draw_info->width - 1, max_x);
int y_min = (int)fmaxf(0, min_y);
int y_max = (int)fminf(draw_info->height - 1, max_y);
/* Рисуем треугольник */
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
int inside = point_in_triangle((float)x, (float)y,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]);
if (inside) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else {
/* Проверяем расстояние до границ */
float dist1 = point_to_segment_distance((float)x, (float)y,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1]);
float dist2 = point_to_segment_distance((float)x, (float)y,
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]);
float dist3 = point_to_segment_distance((float)x, (float)y,
vertices[2][0], vertices[2][1],
vertices[0][0], vertices[0][1]);
float min_dist = fminf(dist1, fminf(dist2, dist3));
if (min_dist <= border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
}
}
}
}
}
/* Рисование квадрата */
static void draw_square(struct window_draw_info* draw_info, float cx, float cy, float radius, float angle,
float border_thickness, uint32_t border_color, uint32_t fill_color)
{
/* Вычисляем координаты вершин квадрата */
/* Угол 0 означает, что одна вершина справа от центра */
float vertices[4][2];
for (int i = 0; i < 4; i++) {
float vertex_angle = angle + i * (M_PI / 2.0f);
vertices[i][0] = cx + radius * cosf(vertex_angle);
vertices[i][1] = cy - radius * sinf(vertex_angle); /* Инвертируем Y для экранных координат */
}
/* Находим ограничивающий прямоугольник */
float min_x = vertices[0][0], max_x = vertices[0][0];
float min_y = vertices[0][1], max_y = vertices[0][1];
for (int i = 1; i < 4; i++) {
min_x = fminf(min_x, vertices[i][0]);
max_x = fmaxf(max_x, vertices[i][0]);
min_y = fminf(min_y, vertices[i][1]);
max_y = fmaxf(max_y, vertices[i][1]);
}
min_x -= border_thickness;
max_x += border_thickness;
min_y -= border_thickness;
max_y += border_thickness;
int x_min = (int)fmaxf(0, min_x);
int x_max = (int)fminf(draw_info->width - 1, max_x);
int y_min = (int)fmaxf(0, min_y);
int y_max = (int)fminf(draw_info->height - 1, max_y);
/* Рисуем квадрат */
for (int y = y_min; y <= y_max; y++) {
for (int x = x_min; x <= x_max; x++) {
float px = (float)x;
float py = (float)y;
/* Проверяем, находится ли точка внутри квадрата */
/* Используем два треугольника */
int inside = point_in_triangle(px, py,
vertices[0][0], vertices[0][1],
vertices[1][0], vertices[1][1],
vertices[2][0], vertices[2][1]) ||
point_in_triangle(px, py,
vertices[0][0], vertices[0][1],
vertices[2][0], vertices[2][1],
vertices[3][0], vertices[3][1]);
if (inside) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, fill_color);
} else {
/* Проверяем расстояние до границ */
float min_dist = INFINITY;
for (int i = 0; i < 4; i++) {
int next = (i + 1) % 4;
float dist = point_to_segment_distance(px, py,
vertices[i][0], vertices[i][1],
vertices[next][0], vertices[next][1]);
min_dist = fminf(min_dist, dist);
}
if (min_dist <= border_thickness) {
set_pixel(draw_info->data, draw_info->width, draw_info->height, x, y, border_color);
}
}
}
}
}
void figure_draw(struct window_draw_info* draw_info, float border_thickness, uint32_t border_color, uint32_t fill_color)
{
if (!draw_info || !draw_info->data)
return;
/* Координаты приходят в относительных единицах
* Y: [0..1] -> умножаем на высоту
* X: нормализован относительно высоты -> умножаем на высоту же
*/
float cx = draw_info->figure.position.x * draw_info->height;
float cy = draw_info->figure.position.y * draw_info->height;
float radius = draw_info->figure.radius;
float angle = draw_info->figure.angle;
enum figure_type type = draw_info->figure.type;
switch (type) {
case FIGURE_CIRCLE:
draw_circle(draw_info, cx, cy, radius, border_thickness, border_color, fill_color);
break;
case FIGURE_TRIANGLE:
draw_triangle(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
break;
case FIGURE_SQUARE:
draw_square(draw_info, cx, cy, radius, angle, border_thickness, border_color, fill_color);
break;
}
}

View File

@@ -0,0 +1,81 @@
#include "input-handle.h"
#include "wayland-runtime.h"
#include <math.h>
void keyboard_key_handle(xkb_keycode_t kc, xkb_keysym_t ks, enum keyboard_key_state state, struct wayland_window *window)
{
if (ks != XKB_KEY_NoSymbol)
{
char buf[64];
int n = xkb_keysym_to_utf8(ks, buf, sizeof(buf));
// if (n > 0)
// printf("keyboard: symbol '%s' (keysym 0x%x) on surface:%p\n", buf, ks, window);
// else
// printf("keyboard: keysym 0x%x (no UTF-8 representation)\n", ks);
if(state != KEYBOARD_KEY_STATE_RELEASED)
{
switch (ks)
{
case XKB_KEY_Return:
run_window();
break;
case '1':
window->draw_info.figure.type = FIGURE_CIRCLE;
break;
case '2':
window->draw_info.figure.type = FIGURE_TRIANGLE;
break;
case '3':
window->draw_info.figure.type = FIGURE_SQUARE;
break;
case '-':
/* decrease animation speed (multiplicative delta, clamped) */
pthread_mutex_lock(&window->draw_info.figure_mutex);
window->draw_info.figure.speed -= 1;
if (window->draw_info.figure.speed < 1)
window->draw_info.figure.speed = 1;
printf("keyboard: speed decreased to %.2f\n", window->draw_info.figure.speed);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case '+':
case '=': /* some layouts may emit '=' for unshifted, handle + via keysym */
/* increase animation speed (multiplicative delta, clamped) */
pthread_mutex_lock(&window->draw_info.figure_mutex);
window->draw_info.figure.speed += 1;
if (window->draw_info.figure.speed > 50.0f)
window->draw_info.figure.speed = 50.0f;
printf("keyboard: speed increased to %.2f\n", window->draw_info.figure.speed);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case XKB_KEY_Up:
/* increase figure radius */
pthread_mutex_lock(&window->draw_info.figure_mutex);
{
float maxr = fminf(window->draw_info.width, window->draw_info.height) / 2.0f - 1.0f;
window->draw_info.figure.radius += 2.0f;
if (window->draw_info.figure.radius > maxr)
window->draw_info.figure.radius = maxr;
}
printf("keyboard: radius increased to %.2f\n", window->draw_info.figure.radius);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
case XKB_KEY_Down:
/* decrease figure radius */
pthread_mutex_lock(&window->draw_info.figure_mutex);
{
window->draw_info.figure.radius -= 2.0f;
if (window->draw_info.figure.radius < 1.0f)
window->draw_info.figure.radius = 1.0f;
}
printf("keyboard: radius decreased to %.2f\n", window->draw_info.figure.radius);
pthread_mutex_unlock(&window->draw_info.figure_mutex);
break;
default:
break;
}
}
}
}

200
wayland/src/input.c Normal file
View File

@@ -0,0 +1,200 @@
#include <stdio.h>
#include <xkbcommon/xkbcommon.h>
#include <wayland-client.h>
#include <sys/mman.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include "input.h"
#include "input-handle.h"
#include "wayland-runtime.h"
#include "window.h"
static struct wl_seat *seat = NULL;
static struct wl_keyboard *keyboard = NULL;
static struct xkb_context *xkb_ctx = NULL;
static struct xkb_keymap *xkb_keymap = NULL;
static struct xkb_state *xkb_state = NULL;
static struct wayland_window* focused_window = NULL;
/* Обработчики клавиатуры */
static void keyboard_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format, int fd, uint32_t size)
{
printf("keyboard: keymap format=%u size=%u\n", format, size);
if (fd < 0)
return;
if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1)
{
close(fd);
return;
}
char *map = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
perror("mmap");
close(fd);
return;
}
if (!xkb_ctx)
xkb_ctx = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
if (xkb_state)
{
xkb_state_unref(xkb_state);
xkb_state = NULL;
}
if (xkb_keymap)
{
xkb_keymap_unref(xkb_keymap);
xkb_keymap = NULL;
}
xkb_keymap = xkb_keymap_new_from_string(xkb_ctx, map, XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!xkb_keymap)
{
fprintf(stderr, "Unable to compile xkb keymap\n");
munmap(map, size);
close(fd);
return;
}
xkb_state = xkb_state_new(xkb_keymap);
munmap(map, size);
close(fd);
}
static void keyboard_enter(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface, struct wl_array *keys)
{
/* Сохраняем поверхность, которая получила фокус клавиатуры */
focused_window = get_window_by_surface(surface);
}
static void keyboard_leave(void *data, struct wl_keyboard *keyboard, uint32_t serial, struct wl_surface *surface)
{
/* Если уходим с фокусной поверхности — сбросить фокус */
if (focused_window && focused_window->wl_surface == surface)
focused_window = NULL;
}
static void keyboard_key(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
enum keyboard_key_state key_state = (state == WL_KEYBOARD_KEY_STATE_PRESSED) ? KEYBOARD_KEY_STATE_PRESSED
: (state == WL_KEYBOARD_KEY_STATE_REPEATED) ? KEYBOARD_KEY_STATE_REPEATED
: KEYBOARD_KEY_STATE_RELEASED;
if (xkb_state && focused_window)
{
xkb_keycode_t kc = (xkb_keycode_t)key + 8;
xkb_keysym_t ks = xkb_state_key_get_one_sym(xkb_state, kc);
keyboard_key_handle(kc, ks, key_state, focused_window);
}
}
static void keyboard_modifiers(void *data, struct wl_keyboard *keyboard, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
{
if (xkb_state)
{
xkb_state_update_mask(xkb_state, mods_depressed, mods_latched, mods_locked, group, 0, 0);
}
}
static void keyboard_repeat_info(void *data, struct wl_keyboard *keyboard, int32_t rate, int32_t delay)
{
}
static const struct wl_keyboard_listener keyboard_listener = {
.keymap = keyboard_keymap,
.enter = keyboard_enter,
.leave = keyboard_leave,
.key = keyboard_key,
.modifiers = keyboard_modifiers,
.repeat_info = keyboard_repeat_info};
/* Обработчики wl_seat */
static void seat_capabilities(void *data, struct wl_seat *seat_local, uint32_t caps)
{
if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !keyboard)
{
keyboard = wl_seat_get_keyboard(seat_local);
wl_keyboard_add_listener(keyboard, &keyboard_listener, NULL);
printf("Seat reports keyboard capability - keyboard bound\n");
}
else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && keyboard)
{
wl_keyboard_destroy(keyboard);
keyboard = NULL;
if (xkb_state)
{
xkb_state_unref(xkb_state);
xkb_state = NULL;
}
if (xkb_keymap)
{
xkb_keymap_unref(xkb_keymap);
xkb_keymap = NULL;
}
}
}
static void seat_name(void *data, struct wl_seat *seat, const char *name)
{
printf("Seat name: %s\n", name);
}
static const struct wl_seat_listener seat_listener = {
.capabilities = seat_capabilities,
.name = seat_name};
void input_register_seat(struct wl_seat *s)
{
if (!s)
return;
if (seat)
{
if (keyboard)
{
wl_keyboard_destroy(keyboard);
keyboard = NULL;
}
wl_seat_destroy(seat);
seat = NULL;
}
seat = s;
wl_seat_add_listener(seat, &seat_listener, NULL);
}
void input_cleanup(void)
{
if (keyboard)
{
wl_keyboard_destroy(keyboard);
keyboard = NULL;
}
if (seat)
{
wl_seat_destroy(seat);
seat = NULL;
}
if (xkb_state)
{
xkb_state_unref(xkb_state);
xkb_state = NULL;
}
if (xkb_keymap)
{
xkb_keymap_unref(xkb_keymap);
xkb_keymap = NULL;
}
if (xkb_ctx)
{
xkb_context_unref(xkb_ctx);
xkb_ctx = NULL;
}
focused_window = NULL;
}

221
wayland/src/registry.c Normal file
View File

@@ -0,0 +1,221 @@
#include "registry.h"
#include "input.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <stdatomic.h>
#include <poll.h>
#include <errno.h>
#include <wayland-client.h>
#include "xdg-shell-client-protocol.h"
static void wm_base_ping(void *data, struct xdg_wm_base *wm_base, uint32_t serial)
{
(void)data;
xdg_wm_base_pong(wm_base, serial);
}
static struct xdg_wm_base_listener wm_base_listener = {
.ping = wm_base_ping
};
/* Глобальные объекты, привязанные к единому registry-потоку (общие для процесса) */
static struct wl_compositor *global_compositor;
static struct wl_shm *global_shm;
static struct xdg_wm_base *global_wm_base;
/* Глобальный реестр живёт на весь срок программы (удаляется при сбросе) */
static struct wl_registry *global_registry = NULL;
/* Поток обработки глобальных событий: использует дефолтную очередь */
static pthread_t global_thread;
static _Atomic int global_thread_running = 0;
static struct wl_display *global_display = NULL;
static uint32_t clamp_version(uint32_t announced, uint32_t supported)
{
return (announced < supported) ? announced : supported;
}
static void registry_global(void *data, struct wl_registry *reg, uint32_t name, const char *intf, uint32_t version)
{
printf("%u\t%s\tv:%u\n", name, intf, version);
if (!strcmp(intf, wl_compositor_interface.name))
{
uint32_t ver = clamp_version(version, wl_compositor_interface.version);
/* Привязать compositor на дефолтной очереди сразу */
if (!global_compositor)
global_compositor = wl_registry_bind(reg, name, &wl_compositor_interface, ver);
}
else if (!strcmp(intf, wl_shm_interface.name))
{
uint32_t ver = clamp_version(version, wl_shm_interface.version);
if (!global_shm)
global_shm = wl_registry_bind(reg, name, &wl_shm_interface, ver);
}
else if (!strcmp(intf, xdg_wm_base_interface.name))
{
uint32_t ver = clamp_version(version, xdg_wm_base_interface.version);
if (!global_wm_base)
global_wm_base = wl_registry_bind(reg, name, &xdg_wm_base_interface, ver);
if (global_wm_base)
xdg_wm_base_add_listener(global_wm_base, &wm_base_listener, NULL);
}
else if (!strcmp(intf, wl_seat_interface.name))
{
uint32_t ver = clamp_version(version, wl_seat_interface.version);
/* Привязать seat на дефолтной очереди */
struct wl_seat *seat = wl_registry_bind(reg, name, &wl_seat_interface, ver);
if (seat)
input_register_seat(seat);
}
}
static void registry_global_remove(void *data, struct wl_registry *reg, uint32_t name)
{
(void)data;
(void)reg;
(void)name;
}
static const struct wl_registry_listener registry_listener = {
.global = registry_global,
.global_remove = registry_global_remove
};
static void destroy_global_objects(void)
{
if (global_compositor)
{
wl_compositor_destroy(global_compositor);
global_compositor = NULL;
}
if (global_shm)
{
wl_shm_destroy(global_shm);
global_shm = NULL;
}
if (global_wm_base)
{
xdg_wm_base_destroy(global_wm_base);
global_wm_base = NULL;
}
if (global_registry)
{
wl_registry_destroy(global_registry);
global_registry = NULL;
}
}
/* Привязка глобального реестра — привязать compositor/shm/xdg_wm_base и
* запустить поток обработки глобальной очереди. Возвращает 0 при успехе,
* -1 при ошибке.
*/
static void *registry_global_thread(void *arg)
{
struct wl_display *display = arg;
int fd = wl_display_get_fd(display);
while (global_thread_running)
{
struct pollfd pfd;
pfd.fd = fd;
pfd.events = POLLIN;
pfd.revents = 0;
int ret = poll(&pfd, 1, 100); /* таймаут 100 ms для проверки флага запуска */
if (ret == -1)
{
if (errno == EINTR)
continue;
break;
}
if (ret == 0)
continue;
if (pfd.revents & POLLIN)
{
int r = wl_display_dispatch(display);
if (r < 0)
break;
}
}
return NULL;
}
int registry_global_bind(struct wl_display *display)
{
if (!display)
return -1;
if (global_thread_running)
return 0; /* уже привязан */
/* Используем дефолтную очередь для глобальных объектов.
* Добавим listener и сделаем roundtrip, чтобы вызывающий код
* мог не делать этого заранее. Реестр привяжет глобалы сразу
* при получении событий. */
struct wl_registry *registry = wl_display_get_registry(display);
if (!registry)
{
return -1;
}
wl_registry_add_listener(registry, &registry_listener, NULL);
if (wl_display_roundtrip(display) < 0)
{
/* произошла ошибка — уничтожить registry и вернуть ошибку */
wl_registry_destroy(registry);
return -1;
}
global_registry = registry;
if (!global_compositor || !global_shm || !global_wm_base)
{
destroy_global_objects();
return -1;
}
/* Запустить поток обработки событий дефолтной очереди */
global_thread_running = 1;
global_display = display;
int thr_res = pthread_create(&global_thread, NULL, registry_global_thread, display);
if (thr_res != 0)
{
global_thread_running = 0;
destroy_global_objects();
return -1;
}
return 0;
}
void registry_global_unbind(void)
{
if (!global_thread_running)
return;
/* Корректно остановить поток */
global_thread_running = 0;
pthread_join(global_thread, NULL);
global_display = NULL;
destroy_global_objects();
return;
}
struct wl_compositor *registry_get_compositor(void)
{
return global_compositor;
}
struct wl_shm *registry_get_shm(void)
{
return global_shm;
}
struct xdg_wm_base *registry_get_xdg_wm_base(void)
{
return global_wm_base;
}

View File

@@ -0,0 +1,272 @@
#include <errno.h>
#include <pthread.h>
#include <stdatomic.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <wayland-client.h>
#include <unistd.h>
#include "input.h"
#include "registry.h"
#include "wayland-runtime.h"
#include "window.h"
#include "figure-animate.h"
#define MAX_WINDOW_THREADS 128
struct window_thread_slot
{
pthread_t thread;
pthread_t aux_thread;
int active;
struct wl_event_queue *queue;
struct wayland_window window;
};
static struct wl_display *g_display = NULL;
static struct window_thread_slot g_slots[MAX_WINDOW_THREADS];
static pthread_mutex_t g_thread_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_thread_cond = PTHREAD_COND_INITIALIZER;
static atomic_int g_active_threads = 0;
static atomic_bool g_shutdown = 0;
static int g_initialized = 0;
static void signal_thread_exit(struct window_thread_slot *slot)
{
pthread_mutex_lock(&g_thread_lock);
slot->active = 0;
atomic_fetch_sub(&g_active_threads, 1);
pthread_cond_broadcast(&g_thread_cond);
pthread_mutex_unlock(&g_thread_lock);
}
#include <stdio.h>
#include <math.h>
#include <stdint.h>
#include <stdlib.h>
// Прототип ASM-функции
void place_points_on_circle(
float pos_x,
float pos_y,
float offset_rad,
float radius,
float *points,
size_t count);
struct Point
{
float x;
float y;
};
static void *window_aux_loop(void *arg)
{
struct window_thread_slot *slot = arg;
struct window_draw_info *draw_info = &slot->window.draw_info;
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
{
/* На время обновления позиции фигуры локаем мутекс */
pthread_mutex_lock(&draw_info->figure_mutex);
figure_animation_step(draw_info);
// const size_t n = 8;
// struct vec2 *pts = malloc(sizeof(struct vec2) * n);
// if (!pts)
// {
// printf("malloc failed\n");
// }
// float center_x = 0.0f;
// float center_y = 0.0f;
// float offset = 0.78f;
// float radius = 1.0f;
// // Вызов ASM-функции
// place_points_on_circle(
// center_x,
// center_y,
// offset,
// radius,
// (float *)pts, // адрес выходного массива
// n);
// // Вывод для проверки (и удобной точки останова)
// for (size_t i = 0; i < n; i++)
// {
// printf("%zu: x = %f, y = %f\n", i, pts[i].x, pts[i].y);
// }
// free(pts);
pthread_mutex_unlock(&draw_info->figure_mutex);
usleep(15 * 1000);
}
return NULL;
}
static void *window_thread_main(void *arg)
{
struct window_thread_slot *slot = arg;
memset(&slot->window, 0, sizeof(slot->window));
slot->queue = wl_display_create_queue(g_display);
if (!slot->queue)
{
signal_thread_exit(slot);
return NULL;
}
if (window_init(g_display, slot->queue, &slot->window) < 0)
{
wl_event_queue_destroy(slot->queue);
slot->queue = NULL;
signal_thread_exit(slot);
return NULL;
}
/* Запуск вспомогательного потока, который пока просто крутится с паузой 100 ms.
* Поток завершится, как только окно будет помечено как закрыто. */
int aux_res = pthread_create(&slot->aux_thread, NULL, window_aux_loop, slot);
if (aux_res == 0)
pthread_detach(slot->aux_thread);
while (!atomic_load(&g_shutdown) && !window_should_close(&slot->window))
{
int dispatch = wl_display_dispatch_queue(g_display, slot->queue);
if (dispatch < 0)
{
if (errno == EINTR)
continue;
atomic_store(&g_shutdown, 1);
break;
}
}
printf("Window #%d closed\n", slot->window.id);
window_destroy(&slot->window);
if (slot->queue)
{
wl_event_queue_destroy(slot->queue);
slot->queue = NULL;
}
signal_thread_exit(slot);
return NULL;
}
int32_t init_wayland(void)
{
if (g_initialized)
return 0;
g_display = wl_display_connect(NULL);
if (!g_display)
return -1;
/* Привязать глобальные объекты и запустить поток обработки (дефолтная очередь).
* `registry_global_bind` добавляет listener и делает roundtrip. */
if (registry_global_bind(g_display) < 0)
{
wl_display_disconnect(g_display);
g_display = NULL;
return -1;
}
atomic_store(&g_shutdown, 0);
atomic_store(&g_active_threads, 0);
g_initialized = 1;
/* Print keyboard help to the console so users know available shortcuts and
* behaviors. This mirrors the handling implemented in
* `input-handle.c` and acts as a quick usage hint. */
printf("\nKeyboard shortcuts and behavior:\n");
printf(" - Enter: open a new window\n");
printf(" - 1: switch to circle figure\n");
printf(" - 2: switch to triangle figure\n");
printf(" - 3: switch to square figure\n");
printf(" - - : decrease animation speed (clamped, multiplicative)\n");
printf(" - + or = : increase animation speed (clamped, multiplicative)\n");
printf(" - Up arrow: increase figure radius (clamped to window bounds)\n");
printf(" - Down arrow: decrease figure radius (minimum 1.0)\n");
printf(" Note: actions are triggered on key press (not on release).\n\n");
return 0;
}
int32_t run_window(void)
{
if (!g_initialized || !g_display)
return -1;
int slot_index = -1;
pthread_mutex_lock(&g_thread_lock);
for (int i = 0; i < MAX_WINDOW_THREADS; ++i)
{
if (!g_slots[i].active)
{
slot_index = i;
g_slots[i].active = 1;
atomic_fetch_add(&g_active_threads, 1);
break;
}
}
pthread_mutex_unlock(&g_thread_lock);
if (slot_index < 0)
return -1;
int create_res = pthread_create(&g_slots[slot_index].thread, NULL, window_thread_main, &g_slots[slot_index]);
if (create_res != 0)
{
pthread_mutex_lock(&g_thread_lock);
g_slots[slot_index].active = 0;
atomic_fetch_sub(&g_active_threads, 1);
pthread_mutex_unlock(&g_thread_lock);
return -1;
}
pthread_detach(g_slots[slot_index].thread);
return slot_index;
}
void wait_for_windows(void)
{
pthread_mutex_lock(&g_thread_lock);
while (atomic_load(&g_active_threads) > 0)
pthread_cond_wait(&g_thread_cond, &g_thread_lock);
pthread_mutex_unlock(&g_thread_lock);
}
void destroy_wayland(void)
{
if (!g_initialized)
return;
wait_for_windows();
input_cleanup();
/* Остановить поток глобального реестра и сбросить глобальные данные */
registry_global_unbind();
if (g_display)
{
wl_display_disconnect(g_display);
g_display = NULL;
}
memset(g_slots, 0, sizeof(g_slots));
g_initialized = 0;
atomic_store(&g_shutdown, 0);
}
struct wayland_window *get_window_by_surface(struct wl_surface *surf)
{
for (int i = 0; i < MAX_WINDOW_THREADS; i++)
if (g_slots[i].window.wl_surface == surf)
return &g_slots[i].window;
return NULL;
}

299
wayland/src/window.c Normal file
View File

@@ -0,0 +1,299 @@
#include "window.h"
#include "registry.h"
#include "figure-draw.h"
#include "xdg-shell-client-protocol.h"
#include <wayland-client.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <stdatomic.h>
#include "registry.h"
static atomic_uint_fast64_t shm_counter = 0;
static int32_t alloc_shm(size_t size)
{
char name[64];
uint64_t id = atomic_fetch_add(&shm_counter, 1);
snprintf(name, sizeof(name), "/wayland-shm-%d-%llu", getpid(), (unsigned long long)id);
int32_t fd = shm_open(name, O_RDWR | O_CREAT, 0600);
if (fd == -1)
return fd;
shm_unlink(name);
if (ftruncate(fd, size) == -1)
{
close(fd);
return -1;
}
return fd;
}
static void destroy_frame_callback(struct wayland_window *win)
{
if (win->frame_callback)
{
wl_callback_destroy(win->frame_callback);
win->frame_callback = NULL;
}
}
static void resize_canvas(struct wayland_window *win)
{
struct window_draw_info *draw_info = &win->draw_info;
size_t stride = draw_info->width * 4;
size_t size = stride * draw_info->height;
int32_t fd = alloc_shm(size);
if (fd == -1)
return;
if (win->buffer)
{
wl_buffer_destroy(win->buffer);
win->buffer = NULL;
}
void *map = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
if (map == MAP_FAILED)
{
close(fd);
return;
}
struct wl_shm *shm = registry_get_shm();
struct wl_shm_pool *pool = wl_shm_create_pool(shm, fd, size);
win->buffer = wl_shm_pool_create_buffer(pool, 0, draw_info->width, draw_info->height, stride, WL_SHM_FORMAT_ARGB8888);
wl_shm_pool_destroy(pool);
close(fd);
draw_info->data = map;
}
static void resize_new(struct wayland_window *win, int32_t w, int32_t h)
{
if (!w || !h)
return;
struct window_draw_info *draw_info = &win->draw_info;
if (draw_info->width != w || draw_info->height != h)
{
if (draw_info->data)
{
munmap(draw_info->data, draw_info->width * draw_info->height * 4);
draw_info->data = NULL;
}
draw_info->width = w;
draw_info->height = h;
resize_canvas(win);
}
}
static void draw(struct wayland_window *win)
{
struct window_draw_info *draw_info = &win->draw_info;
size_t stride = draw_info->width * 4;
size_t size = stride * draw_info->height;
if (!draw_info->data || !win->buffer)
return;
// Залочиться, чтобы операции обновления позиции фигуры происходили атомарно
pthread_mutex_lock(&draw_info->figure_mutex);
struct figure_animation_info figure = draw_info->figure;
uint32_t color;
switch (figure.type)
{
case FIGURE_CIRCLE:
color = 0xFFFF0000;
break;
case FIGURE_TRIANGLE:
color = 0xFF00FF00;
break;
case FIGURE_SQUARE:
color = 0xFF0000FF;
break;
default:
break;
}
uint8_t *bytes = (uint8_t *)draw_info->data;
for (int32_t y = 0; y < (int32_t)draw_info->height; ++y)
{
uint32_t *row = (uint32_t *)(bytes + y * stride);
for (int32_t x = 0; x < (int32_t)draw_info->width; ++x)
row[x] = 0xAA5F5F5F; /* background black */
}
/* Draw figure into buffer. border thickness in pixels = 3.0f */
figure_draw(&win->draw_info, 3.0f, 0xFF000000, color);
pthread_mutex_unlock(&draw_info->figure_mutex);
wl_surface_attach(win->wl_surface, win->buffer, 0, 0);
wl_surface_damage_buffer(win->wl_surface, 0, 0, draw_info->width, draw_info->height);
wl_surface_commit(win->wl_surface);
}
static void xdg_surface_conf(void *data, struct xdg_surface *xdg_surface_local, uint32_t serial)
{
xdg_surface_ack_configure(xdg_surface_local, serial);
struct wayland_window *win = data;
if (!win->draw_info.data)
resize_canvas(win);
draw(win);
}
static void xdg_toplevel_conf(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h, struct wl_array *states)
{
(void)states;
struct wayland_window *win = data;
resize_new(win, w, h);
}
static void xdg_toplevel_cls(void *data, struct xdg_toplevel *xdg_top)
{
struct wayland_window *win = data;
(void)xdg_top;
win->need_close = 1;
}
static void xdg_toplevel_bounds(void *data, struct xdg_toplevel *xdg_top, int32_t w, int32_t h)
{
(void)data;
(void)xdg_top;
(void)w;
(void)h;
}
static void xdg_toplevel_wm_caps(void *data, struct xdg_toplevel *xdg_top, struct wl_array *caps)
{
(void)data;
(void)xdg_top;
(void)caps;
}
static struct wl_callback_listener callback_listener;
static void setup_frame_callback(struct wayland_window *win, struct wl_event_queue *queue)
{
struct wl_callback *cb = wl_surface_frame(win->wl_surface);
win->frame_callback = cb;
if (cb && queue)
wl_proxy_set_queue((struct wl_proxy *)cb, queue);
wl_callback_add_listener(cb, &callback_listener, win);
}
static void frame_new(void *data, struct wl_callback *cb, uint32_t _)
{
struct wayland_window *win = data;
if (win->frame_callback == cb)
win->frame_callback = NULL;
wl_callback_destroy(cb);
setup_frame_callback(win, win->queue);
draw(win);
}
static struct wl_callback_listener callback_listener = {
.done = frame_new};
static struct xdg_surface_listener surface_listener = {
.configure = xdg_surface_conf};
static struct xdg_toplevel_listener top_listener = {
.configure = xdg_toplevel_conf,
.close = xdg_toplevel_cls,
.configure_bounds = xdg_toplevel_bounds,
.wm_capabilities = xdg_toplevel_wm_caps};
int window_init(struct wl_display *display, struct wl_event_queue *queue, struct wayland_window *win)
{
static int id = 0;
(void)display;
struct wl_compositor *compositor = registry_get_compositor();
struct wl_shm *shm = registry_get_shm();
struct xdg_wm_base *wm = registry_get_xdg_wm_base();
if (!compositor || !shm || !wm)
return -1;
win->wl_surface = wl_compositor_create_surface(compositor);
win->queue = queue;
if (win->wl_surface && queue)
wl_proxy_set_queue((struct wl_proxy *)win->wl_surface, queue);
setup_frame_callback(win, queue);
win->xdg_surface = xdg_wm_base_get_xdg_surface(wm, win->wl_surface);
if (win->xdg_surface && queue)
wl_proxy_set_queue((struct wl_proxy *)win->xdg_surface, queue);
xdg_surface_add_listener(win->xdg_surface, &surface_listener, win);
win->xdg_toplevel = xdg_surface_get_toplevel(win->xdg_surface);
if (win->xdg_toplevel && queue)
wl_proxy_set_queue((struct wl_proxy *)win->xdg_toplevel, queue);
xdg_toplevel_add_listener(win->xdg_toplevel, &top_listener, win);
wl_surface_commit(win->wl_surface);
struct window_draw_info *draw_info = &win->draw_info;
/* Инициализация состояния */
win->id = id++;
draw_info->width = 400;
draw_info->height = 250;
draw_info->data = NULL;
/* Default animation state */
draw_info->figure.type = FIGURE_CIRCLE;
draw_info->figure.position.x = 0.5f;
draw_info->figure.position.y = 0.5f;
draw_info->figure.velocity.x = 0.5f;
draw_info->figure.velocity.y = 0.5f;
draw_info->figure.angle = 0.0f;
draw_info->figure.angular_velocity = 0.01; /* radians per frame */
draw_info->figure.speed = 10; /* speed multiplier */
draw_info->figure.radius = 25.0f; /* radius in pixels */
win->buffer = NULL;
win->frame_callback = NULL;
win->need_close = 0;
/* Мьютекс нужен для атомарного обращения к структуре фигуры */
if (pthread_mutex_init(&win->draw_info.figure_mutex, NULL) != 0)
{
/* if mutex init failed — cleanup and return error */
window_destroy(win);
return -1;
}
xdg_toplevel_set_app_id(win->xdg_toplevel, "my-wayland-window");
xdg_toplevel_set_title(win->xdg_toplevel, "Custom Title");
return 0;
}
int window_should_close(struct wayland_window *win)
{
return win->need_close;
}
void window_destroy(struct wayland_window *win)
{
destroy_frame_callback(win);
if (win->buffer)
wl_buffer_destroy(win->buffer);
if (win->xdg_toplevel)
xdg_toplevel_destroy(win->xdg_toplevel);
if (win->xdg_surface)
xdg_surface_destroy(win->xdg_surface);
if (win->wl_surface)
wl_surface_destroy(win->wl_surface);
if (win->draw_info.data)
munmap(win->draw_info.data, win->draw_info.width * win->draw_info.height * 4);
/* destroy mutex if initialized */
pthread_mutex_destroy(&win->draw_info.figure_mutex);
}