#import "@docs/bmstu:1.0.0":*
#show: student_work.with(
  caf_name: "Компьютерные системы и сети",
  faculty_name: "Информатика и системы управления",
  work_type: "лабораторной работе",
  work_num: "3",
  discipline_name: "Программирование ветвлений и итерационных циклов ",
  theme: "Программирование целочисленных вычислений",
  author: (group: "ИУ6-42Б", nwa: "<NAME>"),
  adviser: (nwa: "<NAME>"),
  city: "Москва",
  table_of_contents: true,
)

= Выполнение лабораторной работы

== Цель

Изучение средств и приемов программирования ветвлений и итерационных циклов на языке ассемблера.

== Задание

Разработать программу на языке ассемблера, вычисляющую:

$ f = cases(
  (a+b)/m "если" m < 0,
  m^2 + b^3 "иначе",
) $

== Выполнение

В предыдущей лабораторной работе подробно описан процесс ввод-вывода чисел с помощью процедур ```asm geti``` и ```asm outi```. В данной лабораторной работе я буду использовать эту библеотеку без изменений. 

=== Схема алгоритма

Перед началом разработки программы составим примерную схему алгоритма. Тут я не буде разделять ее по меткам, а создам полностью от начала выполнения программы до ее окаанчания. 

#img(image("flow.svg", width:29%), [Схема алгоритма])

=== Инициализация и выделенние памяти

И так алгоритм выполения готов, осталось только, придерживаясь его, сформировать программу. Для начала проинициализируем данные и выделим память. Как и в предыдущих лабораторных за это будут отвечать ```asm section .data``` и ```asm section .bss```. 

#let lab3 = parserasm(read("lab3.asm"))
#code(funcstr(lab3, "section .data") + funcstr(lab3, "section .bss"), "asm", [Инициализируем данные и выделяем память])

=== Ввод условная и безусловная передача управления

В данных инициализируем строки приглашения на вход и сопутствующий ответу вывод. Память выделяем для ввода цифр пользователю. 

После работы с памятью необходимо запросить ввод пользователя, после ввода проверить $m < 0$. 

#code(funcstr(lab3, "_start:"), "asm", [Начало программы])

После ввода пользователя мы перемещаем в ```asm ebx``` $b$, ```asm ecx``` $m$, экономим 2 такта: при условии если $m > 0$ мы вообще не будем перемещать из памяти $a$, так как эта переменная не используется в арифмитических вычислениях.

Команда ```asm cmp``` сравнивает два числа и поднимает некоторые флаги в регистре ```asm flags```. Эти флаги в последствии использует ```asm jl```, оперделяя необходимоть переходить к метке ```asm f1```, если переход просиходит, то в отличии от ```asm call``` место перехода не сохраняется в стеке и мы не сможем вернуться в ```asm _start``` с помощью ```asm ret```. по завершении метки процессор просто перейдет к следующей метке, лежащей в памяти, что может привести к многочисленным ошибкам. Такое как раз может произойти если ```asm ecx``` будет больше нуля, проэтому после ```asm jl``` написан безусловный (не проверяющий значения флагов) переход к метке ```asm jmp```.

=== Ветвление: $m < 0$

Для начала разберем ситуацию когда $m < 0$.

#code(funcstr(lab3, "f1:"), "asm", [Считаем значение функции при $m < 0$])

В этом случае для вычислений нам все-таки пригодится значение $a$, поэтому переместим его в ```asm eax```. Сразу после этого прибавим ```asm ebx``` и разделим на ```asm ecx``` (подробнее об арифметических операциях я написал в лабораторной №2).

После этого ответ будет в регистрe ```asm eax```. Переходим к выводу и завершению программы.

=== Ветвление: $m>=0$

Но для начала разберем другой случай: если $m >= 0$. Для этого напишем другую метку под названием ```asm f2```.

#code(funcstr(lab3, "f2:"), "asm", [Считаем значение функции при $m >= 0$])

Тут так же будем использовать ```asm eax``` для арифметических вычислений. Переместим значение $b$ в него. Умножим 2 раза ```asm eax``` на $b$, таким образом получим куб $b$, который сохраним в ```asm ebx```. Переместим в ```asm eax``` $m$, умножим регистр на $m$ и получим $m^2$. Остается только сложить ```asm eax```, ```asm ebx``` и снова получить ответ в регистре ```asm eax```, после чего переходим к той же метке вывода и выхода.

=== Вывод результата и выход

Так как ответы хранятся в одном и том же месте больше нет никакого значения в условии, поэтому для вывода и выхода буудет достаточно одной метки, которую назовем ```asm exit```

#code(funcstr(lab3, "exit:"), "asm", [Выводим число в ```asm eax``` и завершаем программу])

В предыдущей лабораторной работе описывалось, как работает мой вывод, тут скажу только о том, что число обязательно должно находится в оперативной памяти. Поэтому первым делом перемещаем в оперативную память наш ответ. Адрес числа передаем через регистры, как и адрес сопуствующего сообщения и его длину. Вызываем функцию ```asm outi```, которая организует остальной вывод за нас.

Переместим в ```asm eax``` единицу, как код функции завершения и вызовем систему.

== Компиляция

Название файлов библеотеки ввода-вывода не изменилось, просто изменисля файл, указанный в ```sh $mod```
Вот, что необходимо ввести в терминал, для компиляции и сборки всех 3 файлов:

#code("mod=lab3/lab3 # Название ассемблерного файла без расширения
nasm -f elf -o $mod.o $mod.asm
nasm -f elf -o lab2/input.o lab2/input.asm
nasm -f elf -o lab2/output.o lab2/output.asm
ld -m elf_i386 -o $mod $mod.o lab2/input.o lab2/output.o", "sh", "Команда в терминале")

== Отладка

Ввод-вывод отлажены в предыдущей лабораторной, поэтому посмотрим только результат работы кода в метках ```asm f1``` и ```asm f2```.

=== Отладка ```asm f1```

Для отладки при $m<0$ возьмем числа $a = 10; b = 13; m = -23$

$ f = (10+13)/(-23) = -1 $

#grid(
  columns:2,
  gutter:10pt,
  img(image("img/1.png", width: 88%), "Запуск"),
  img(image("img/2.png", width: 88%), ```asm mov eax, [a]```)
)
#grid(
  columns:2,
  gutter:10pt,
  img(image("img/3.png", width: 88%), ```asm cmp eax, 0```),
  img(image("img/4.png", width: 88%), ```asm add eax, ebx```)
)
#grid(
  columns:2,
  gutter:10pt,
  img(image("img/5.png", width: 88%), ```asm cdq```),
  img(image("img/6.png", width: 88%), ```asm idiv ecx```)
)

#img(image("img/7.png", width: 50%),[Вывод ответа в консоль], f:(i)=>{i.display()})

=== Отладка ```asm f2```

Для отладки при $m>=0$ возьмем числа $a = 0; b = -13; m = 23$

$ f = 23^2 + (-13)^3 = 529 - 2197 = -1668 $

#grid(
  columns:2,
  gutter:10pt,
  img(image("img/8.png", width: 90%), "Запуск"),
  img(image("img/9.png", width: 90%), ```asm mov eax, ebx```)
)
#grid(
  columns:2,
  gutter:10pt,
  img(image("img/10.png", width: 90%), ```asm imul ebx```),
  img(image("img/11.png", width: 90%), ```asm imul ebx```)
)
#grid(
  columns:2,
  gutter:10pt,
  img(image("img/12.png", width: 90%), ```asm mov ebx, eax```),
  img(image("img/13.png", width: 90%), ```asm mov eax, ecx```)
)
#grid(
  columns:2,
  gutter:10pt,
  img(image("img/14.png", width: 90%), ```asm imul ecx```),
  img(image("img/15.png", width: 90%), ```asm add eax, ebx```)
)

#img(image("img/16.png", width: 50%),[Вывод ответа в консоль], f:(i)=>{i.display()})

== Тестирование
Напишем еще 3 теста для каждой метки. 

=== Тестирование ```asm f1```

$ a = 2" "147" "483" "647; b = 0; m = -1\ f = (2147483647+0)/(-1) = -2147483647 $

#img(image("img/17.png", width: 50%),[Тест ```asm f1``` \#1], f:(i)=>{i.display()})

$ a = -2" "147" "483" "647; b = 0; m = -1\ f = (-2147483647+0)/(-1) = 2147483647 $

#img(image("img/18.png", width: 50%),[Тест ```asm f1``` \#2], f:(i)=>{i.display()})

$ a = -2" "147" "483" "647; b = " "147" "483" "647; m = -2" "000" "000\ f = (-2147483647+147483647)/(-2000000) = 1000 $

#img(image("img/19.png", width: 50%),[Тест ```asm f1``` \#3], f:(i)=>{i.display()})

=== Тестирование ```asm f2```

$ b = 100; m = 0\ f = 100^3 + 0^2 = 1000000 $

#img(image("img/20.png", width: 50%),[Тест ```asm f2``` \#1], f:(i)=>{i.display()})

$ b = 100; m = 1000\ f = 100^3+1000^2 = 1000000+1000000 = 2000000 $

#img(image("img/21.png", width: 50%),[Тест ```asm f2``` \#2], f:(i)=>{i.display()})

$ b = 0; m = 10000\ f = 0^3 + 10000^2 = 100000000 $

#img(image("img/22.png", width: 50%),[Тест ```asm f2``` \#3], f:(i)=>{i.display()})

=== Сводная таблица

#align(center)[
#table(
  columns: 3,
  inset: 10pt,
  align: horizon,
  [*Исходные\ данные*],[*Ожидаемый\ результат*],[*Полученный\ результат*],
  [$ a = 10; b = 13; m = -23 $], [$-1$], [$-1$],
  [$ a = 2" "147" "483" "647;\ b = 13; m = -1 $], [$-2" "147" "483" "647$], [$-2" "147" "483" "647$],
  [$ a = -2" "147" "483" "647;\ b = 0; m = -1 $], [$2" "147" "483" "647$], [$2" "147" "483" "647$],
  [$ a = -2" "147" "483" "647;\ b = 147" "483" "647;\ m = -2" "000" "000 $], [$1" "000$], [$1" "000$],
  [$ b = -13; m = 23 $], [$-1" "668$], [$-1" "668$],
  [$ b = 100; m = 0 $], [$1" "000" "000$], [$1" "000" "000$],
  [$ b = 100; m = 1" "000 $], [$2" "000" "000$], [$2" "000" "000$],
  [$ b = 0; m = 10" "000 $], [$100" "000" "000$], [$100" "000" "000$],
)]

== Вывод
В процессе выполения лабораторной работы был разобран механизм создания условных операторов в ассемблере, а так же написана и протестирована программа с простейшим ветвлением.

#pagebreak()
== Контрольные вопросы

1. *Какие машинные команды используют при программировании ветвлений и циклов?*
a. Условные переходы (Branching / Conditional Jumps):
- ```asm JE``` (Jump if Equal) - Переход, если равно.
- ```asm JNE``` (Jump if Not Equal) - Переход, если не равно.
- ```asm JZ``` (Jump if Zero) - Переход, если ноль (аналогично ```asm JE```).
- ```asm JNZ``` (Jump if Not Zero) - Переход, если не ноль (аналогично ```asm JNE```).
- ```asm JG``` (Jump if Greater) - Переход, если больше.
- ```asm JGE``` (Jump if Greater or Equal) - Переход, если больше или равно.
- ```asm JL``` (Jump if Less) - Переход, если меньше.
- ```asm JLE``` (Jump if Less or Equal) - Переход, если меньше или равно.

b. Безусловные переходы (Unconditional Jumps):
- ```asm JMP``` (Jump) - Безусловный переход.
c. Циклы (Loops):
- ```asm LOOP``` – Уменьшает счетчик цикла (```asm CX```), и если он не равен нулю, выполняет переход.

2. *Выделите в своей программе фрагмент, реализующий ветвление. Каково назначение каждой машинной команды фрагмента?*

Сравниваем ```asm ecx``` и `0`: 
#code("asm cmp ecx, 0
jl  f1 ; Условный переход, если ecx < 0 (результат отрицателен)
jmp f2 ; Иначе", "asm", "Ветвление")

3. *Чем вызвана необходимость использования команд безусловной передачи управления?*
- ```asm JMP``` используется для эффективного перехода между различными участками кода, такими как циклы или ветвления.
- может быть применен для перехода к обработчику ошибок при возникновении исключительных ситуаций.
- используется для возврата из вызванной функции обратно в вызывающую функцию.

4. *Поясните последовательность команд, выполняющих операции ввода вывода в вашей программе. Чем вызвана сложность преобразований данных при выполнении операций ввода-вывода?*
Рассмотрено в ЛР2
