# ВСЕ ЗДЕСЬ
## TODO
:::danger
:watch: - над этим я в процессе работы или нашел какие-то вещи, которые не объяснены
:sunglasses: - то, что расписано прям от души, уверен как в своем имени
:::
- [x] Вопрос 1 :sunglasses:
- [x] Вопрос 2
- [x] Вопрос 3 :sunglasses:
- [x] Вопрос 4 :sunglasses:
- [x] Вопрос 5
- [X] Вопрос 6 :sunglasses:
- [X] Вопрос 7 :sunglasses:
- [X] Вопрос 8
- [X] Вопрос 9
- [X] Вопрос 10 :sunglasses:
- [x] Вопрос 11
- [ ] Вопрос 12
- [x] Вопрос 13
- [x] Вопрос 14 :sunglasses:
- [x] Вопрос 15 :sunglasses:
- [x] Вопрос 16
- [x] Вопрос 17 :sunglasses:
- [x] Вопрос 18 :sunglasses:
- [x] Вопрос 19
- [x] Вопрос 20
- [X] Синтаксис
- [x] Задачки
## Полезные ссылки
[Учебник по atmega (Скинул Денис) (Недоступен)](https://vk.com/doc347637358_637042757?hash=07LYzGNQwBTHv2FEJynQEz4IQ4qgfYwBJwQPJa83aCL&dl=ldKec3nBjQj6G9MmJL13ysTyGHOEMBeI9vkYlZloTRT)
[Даташит на инглише](http://ww1.microchip.com/downloads/en/devicedoc/doc2466.pdf)
[Крайне урезанный даташит](http://www.gaw.ru/pdf/Atmel/AVR/atmega16p.pdf)
[Сайтик с полезной инфой по avr](http://www.gaw.ru/html.cgi/txt/doc/micros/avr/asm/start.htm)
## Вопросы
### Регистры
[1) Регистр признаков SREG](/BhJ3OyD_RIi3lcawKRJbyg)
[2) Указатель стека SP + память](/osDeyRaFQwyY3-htFL90LA)
[3) Сторожевой регистр WDTCR](/cRBOAvEYSNePy-OvUSFnhw)
[4) Регистры ввода вывода DDRX](/NnhJgnTqQDSuP2VcD7nbjw)
[5) Регистр таймера/счетчика](/W7htxoJPS_K9EVAzmr4acw)
[6) Регистры для последовательного интерфейса SPI](/qTVdGkiDQ9qWkxGaCVK6UQ)
[7) Регистры для последовательного интерфейса USART](/gJ3L7hAJQneWndP3Bnl0xQ)
[8) Регистр для последовательного интерфейса I2C](/wKSafybVQCaiiVRDRKogkQ)
[9) Регистр для работы с АЦП](/wI9ru-dATGuVGcjSfNZvmw)
[10) Регистр управления](/o4lQB_CoTcaqSDBL6orfWA)
### Изобразите и опишите архитектуру:
:::info
:bulb: Ссылки на эти страницы так же есть в вопросах регистров, к которым они относятся
:::
[11. Atmega16](/0LisffV8QMmBkLGKOIdvgw)
[12. микропроцессора AVR архитектуры](/LErY7GMCTtapTDVOeb962g)
[13. системного генератора тактовых частот](/iCv6VxMlTcuQE7yzy0ov6A)
[14. Системное управление и сброс](/_gfEPK4JQ_qo_DJhNp7SGg)
[15. порта ВВ](/mOXnuCxYSP-OA_Vh5FU9Uw)
[16. Таймер и счетчик со сторожевым регистром](/QEqiBwRDTyKwdVh2CG5uog)
[17. SPI](/c3KELy6fRWyH9_UnxYCX9g)
[18. USART](/BwlGJ88fTHG0MM5dZCP3fg)
[19. I2C](/PzkW7zlbSQy_4qCo_F_EyQ)
[20. АЦП](/HzYWPqA4QVyVa8iLTkDjWQ)
### Напрямую в вопросах нет, но есть шансы, что спросят
:::info
:bulb: Ссылки на эти страницы так же есть в вопросах
:::
[Прерывания](/Tun8u1j-QJSgYGSeV2K34Q)
[Дополнение до 1,2](/Njy2wYD-RpOOpWbiyx16yQ)
[Сдвиговые регистры](/_wUCCs6xS3yl7_u7_Ce1tw)
[Дуплексная связь](/onA8_sLUSYWhMZUIMEkoZQ)
[Prescaller](/xRRZwK1LR42uuuzX0FBAog)
[support: Устройство таймера](/ttfdHMD3Rrabf2KNMRe74A)
[support: pull-up resistor (подтягивающий резистор)](/YXQMaYXhTwKJK58rGkExlg)
## Код
:::info
:bulb: тут потом будет инфа по общим командам, по каким-то задачкам. Команды для какого-то конкретного фукнционала есть в вопросах и тут не дублируются
:::
### Алгоритмы
Краткие вырезки алгоритмов, которые могут понадобиться везде
[Алгоритмы](/TIhoWFWYSXO9AWgway3pkw)
### Задачки
##### Пример задачи №1: Арифметические действия, поиск наименьшего
вводится 5 чисел в ROM
N = 27
1 + N = 28
3 * N = 81
7 - N = -20 (subi neg)
(10 * N) + 2 = 272 (mul adiw)
-N + 15 = -12
N - любое число
найти наименьшее число любым доступным образом
программа должна обнулить данные ROM. После очищения ROMa программа повторяет алгоритм пока все 5 чисел не обнуляться, программа продолжает работать
по завершению работы программа выполняет инициализацию
```cp=
clr r16 ; очищаем нашу константу, в ней мы будем хранить номер группы = N
ldi r16, N ; N = свой номер по порядку, ОБЯЗАТЕЛЬНО ВСТАВИТЬ ВМЕСТО N ЧИСЛО
clr r17 ; с r17 по r21 будет работа с числами
clr r18
clr r19
clr r20
clr r21
; число 1 (r17)
mov r17, r16 ; R17 = N
inc r17 ; R17 = N + 1
; число 2 (r18)
clr r22 ; число счётчик
mulR18:
add r18, r16
inc r22
cpi r22, 3
brmi mulR18
clr r22
; число 3 (r19)
mov r19, r16 ; R19 = N
subi r19, 7 ; R19 = N - 7
neg r19 ; R19 = - N + 7
; число 4 (r20)
mov r20, r16 ; R20 = N
adiw r24, 10 ; R24 = 10
muls R20, R24 ; R1:R0 = N * 10
inc r0 inc r0
; число 5 (r21)
mov r21, r16 ; R21 = N
subi r21, 15 ; R21 = N - 15
neg r21 ; R21 = -N + 15
compare:
; R17 compare start
cp r17, r3 ; Смотрим r17=0 если да переходим к r18
breq M1R18
cp r17, r18 ; ну сравниваем два числа r17 - r18
brpl M1R18 ; если + , то прыгаем к сравнению регистра 18, так как он больше, если нет, идём дальше
jmp M2R17
M2R17:
cp r19, r3 ; Смотрим r19=0 если да переходим дальше сравнения r17
breq M3R17
cp r17, r19
brpl M1R19
jmp M3R17
M3R17:
cp r1, r3
breq r20M4null
jmp mxr20bridge
r20M4null: ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
cp r0, r3
brpl m4r17
cp r17, r0
brpl M1R20bridge
jmp M4R17
M4R17:
cp r21, r3 ; если r21=0 то r17 большее и обнуляем его
breq mxR17bridge
cp r17, r21
brpl mxr21bridge
jmp mxR17bridge
; R17 compare end
; R18 compare start
M1R18:
cp r18, r3
breq M1R19
cp r19, r3
breq M2R18
cp r18, r19
brpl M2R19
jmp M2R18
M2R18:
cp r1, r3
breq r20M5null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxr20bridge
r20M5null:
cp r0, r3
brpl m3r18
cp r18, r0
brpl M2R20
jmp M3R18
M3R18:
cp r21, r3
brpl mxR18bridge
cp r18, r21
brpl mxR21bridge ;; перекидываем на построенный Мишей(гением) мост
jmp mxR18bridge
; R18 compare end
; R19 compare start
M1R19:
cp r19, r3
breq M1R20
cp r19, r18
brpl M2R18
jmp M2R19
M2R19:
cp r1, r3
breq r20M8null
jmp mxr20bridge
r20M8null: ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
cp r0, r3
breq M3R19
cp r19, r0
brpl M3R20
jmp M3R19
M3R19:
cp r21, r0
breq mxR19
cp r19, r21
brpl mxR21bridge
jmp mxR19
; R19 compare end
;; bridges start
;; пояснение, мосты это разработка Гаврилова М.С Кандидат Клоунских Наук.
;; Компилятор иногда не может дотянуться от одной метки до другой, поэтому ему необходим "мост"
;; Так он может дотянуться до "моста", после чего отправиться на необходимую метку
M1R18bridge: jmp M1R18
M1R20bridge: jmp M1R20
mxR18bridge: jmp mxr18 ;; это мост, потому-что бранач не мог дотянуться до необходимого места разработка Михаила Гаврилова (гений)
mxR17bridge: jmp mxr17 ;; это мост, потому-что бранач не мог дотянуться до необходимого места разработка Михаила Гаврилова (гений)
mxr21bridge: jmp mxr21 ;; это мост, потому-что бранач не мог дотянуться до необходимого места разработка Михаила Гаврилова (гений)
mxr20bridge: jmp mxr20 ;; это мост, потому-что бранач не мог дотянуться до необходимого места разработка Михаила Гаврилова (гений)
;; bridges end
; R20 compare start
M1R20:
cp r1, r3
breq R20M1null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxR20 ;;если, старший разряд не нуль, это число самое большое и на похуичах сразу его чистим
R20M1null:
cp r0, r3
breq M1R21
cp r18, r3
breq M2R20
cp r0, r18
brpl M1R18bridge
jmp M2R20
M2R20:
cp r1, r3
breq R20M2null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxR20bridge ;;если, старший разряд не нуль, это число самое большое и на похуичах сразу его чистим
R20M2null:
cp r0, r3
breq M1R21
cp r19, r3
breq M3R20
cp r0, r19
brpl M3R19
jmp M3R20
M3R20:
cp r1, r3
breq R20M3null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxR20bridge ;;если, старший разряд не нуль, это число самое большое и на похуичах сразу его чистим
R20M3null:
cp r0, r3
breq M1R21
cp r21, r3
breq mxr20
cp r0, r21
brpl mxR21
jmp mxR20
; R20 compare end
; R21 compare start
; регистр 21 всегда сравнивался последним, следовательно, если хоть где-то он оказался больше, то сразу бы обнулился. Сравнивать его необязательно
M1R21:
cp r21, r3
;breq cycle
jmp mxR21
; R21 compare end
mxR17: clr r17 ; регистр 17 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся на сравнение
mxR18: clr r18 ; регистр 18 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся на сравнение
mxR19: clr r19 ; регистр 19 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся в сравнении
mxR20: ; в падлу писать, тоже самое, только 20 и 21 регистры
clr r20 clr r1 clr r0
jmp compare
mxr21: clr r21
jmp compare
; AssemblerApplication1.asm
;
; Created: 2/25/2022 8:18:58 AM
; Author : loxdogs
;
; Replace with your application code
```
##### Пример задачи №2: Деление до сотых
вводиться 2 числа в ROM, программа должна уметь делить эти числа, точность деления определяется до сотых.
После получения ответа, программа должна зациклиться сама на себя
N = 27
ЧР = 2
НЧР = 1
N + Чр / N + НЧР
```cp=
; очищаем регистры r16-r21 для работы с ними
clr r16 ; r16 - делимое
clr r17 ; r17 - делитель
clr r18 ; r18 - частное(целая часть)
clr r19 ; r19 - частное(десятичная часть)
clr r20 ; r20 - частное(сотая часть)
clr r21 ; r21 - остаток
clr r22 ; r22 = 0, константа, которая будет равна 10
ldi r22, 10
ldi r16, N ; загружаем номер по списку, вписать свой вместо N
ldi r17, N ; сюда тоже загружаем свой номер по списку
inc r16 inc r16 ; добавляем "любое" чётное
inc r17 ; добавляем "любое" нечётное
div: ; начало деления для целого значения
cp r16, r3
breq is00
cp r16, r17
brmi div10mul
sub r16, r17
inc r18
jmp div
div10mul: ;; нам надо один раз умноижть остаток на 10, поэтому создаём переход
mul r16, r22 ;; остаток умноженный на 10 записывается в r0
div10:
cp r0, r3
breq isX0
cp r0, r17
brmi div100mul
sub r0, r17
inc r19
jmp div10
div100mul:
mul r0, r22
div100:
cp r0, r3
breq isX0
cp r0, r17
brmi end
sub r0, r17
inc r20
jmp div100
end: jmp end
is00: ;; если остаток 0, тогда дробная часть тоже нуль, загружаем два нуля
ldi r19, 0
ldi r20, 0
jmp end
isX0: ;; если остаток после десятичной нуль, тогда дальше будут нули...
ldi r20, 0
jmp end
```
#### Пример задачи №3: Сортировка
при инициализации контролера в роне присутствует массив, отсортировать в порядке возрастания
```cp=
; использую сортировку пузырьком
; как она работает - сначала первый элемент сравниваем со вторым - если второй меньше, то меняем местами
; дальше второй меняем с третьим - и так далее
; вот тут понятнее как работает https://academy.yandex.ru/posts/osnovnye-vidy-sortirovok-i-primery-ikh-realizatsii
ldi r16, 12 ; 1
; тут аналогично закидываем данные в регистры между ними
ldi r23, 50 ; 8
; проверяем, что массив отсортирован
isSorted:
; проверяем каждое правое с соседним левым. Если какое-то меньше, то идем сортировать
cp r23, r22
brmi checkAndSwap67 ; вызывается 67, а не 78 потому что relative breach out of reach
; тут аналогично сравниваем соседние элементы и вызываем checkAndSwap56|45...
cp r17, r16
brmi checkAndSwap12
jmp isSorted ; если отсортировано - зациклить
; checkAndSwapXY меняет местами значения на двух регистрах, если левое больше правого
checkAndswap12:
cp r17, r16
brmi swap12 ; если правое меньше левого, меняем местами
jmp checkAndSwap23 ;
swap12:
mov r0, r16
mov r16, r17
mov r17, r0
jmp checkAndSwap23
; тут аналогичные ветки для сравнения 12, 34, 45, 56, 67...
; ------- 78
checkAndswap78:
cp r23, r22
brmi swap78
jmp isSorted
swap78:
mov r0, r22
mov r22, r23
mov r23, r0
jmp isSorted
```
#### Пример задачи №4: Задержка
Реализовать программу задержки в 15 циклов, после чего программа переходит в режим ожидания (M1: nop jmp M1)
```cp=
clr r18 ; cycle param
start:
; cycle body
inc r18
cpi r18, N ; do while r18(++) < N
brmi start
; do after cycle
repeat: jmp repeat
```
#### Пример задачи №5
> [name=Дарья Воронская] А нам точно нужно объяснение для 2 аналогичных задач (типа, 1 найти наименьшее, а это наибольшее)?
> Да и мне кажется, что весь поиск наименьшего в 1 задании можно убрать, потому что у нас есть задание на сортировку, которое делает буквально то же самое
>
> [name=Boyarkin Alexandr] Как минимум одну задачку надо оставить. Вдруг по уловию нельзя будет использовать сортировку
>
Найти наибольшее число любым доступным образом (аналогично условию первого примера)
1 + N = 28
3 * N = 81
(10 * N) + 2 = 272
```cp=
clr r16 ; очищаем нашу константу, в ней мы будем хранить номер группы = N
ldi r16, N ; N = свой номер по порядку,
clr r17 ; с r17, r18, r20 будет работа с числами
clr r18
clr r20
; число 1 (r17)
mov r17, r16 ; R17 = N
inc r17 ; R17 = N + 1
; число 2 (r18)
clr r22 ; число счётчик
mulR18: ; не понял, как сравнивать числа состоящие из двух регистров
add r18, r16
inc r22
cpi r22, 3
brmi mulR18
clr r22
; число 3 (r20)
mov r20, r16 ; R20 = N
adiw r24, 10 ; R24 = 10
muls R20, R24 ; R1:R0 = N * 10
inc r0 inc r0 ; передайте селезнёву, что он хороший челочек
compare:
; R17 compare start
cp r17, r3 ; Смотрим r17=0 если да переходим к r18
breq M1R18
cp r17, r18 ; ну сравниваем два числа r17 - r18
brpl M2R17 ; если + , то идем по коду, так как r17 больше
jmp M1R18
M2R17:
cp r1, r3
breq r20M1null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxr20
r20M1null:
cp r0, r3
breq mxr17
cp r17, r0
brpl mxr17
jmp mxr20
; R17 compare end
; kakaya je eto huyeta
; R18 compare start
M1R18:
cp r18, r3
breq mxr20
cp r1, r3
breq r20M2null ;; если, старший разряд нуль, тогда сравниваем его как обычное число по метке R20null
jmp mxr20
r20M2null:
cp r0, r3
breq mxr18
cp r18, r0
brpl mxr18
jmp mxr20
; R18 compare end
; R19 compare start
mxR17: clr r17 ; регистр 17 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся на сравнение
mxR18: clr r18 ; регистр 18 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся на сравнение
mxR20: clr r20 clr r1 clr r0 ; регистр 20 оказался наименьшим, обнуляем его
jmp compare ; перемещаемся в сравнении
```
#### Пример задачи №6: Чтение из порта ввода, вызов команд
При инициализации в ROM находится 3 числа. Программа должна считывать порт в зависимости от значения на порту выполнять след. действия:
P/N - номер порта/номер по списку
расчитаться по 3
1 - B
2 - C
3 - D
0000 0000 - ничего не происходит
0000 0001 - посчитать сумму
0000 0010 - посчитать произведение
0000 0100 - поиск максимума
0000 1000 - поиск минимума
0001 0000 - рассчитать среднее арифмитическое
0010 0000 - найти среднее
0100 0000 - установить все единицы в регистре
1000 0000 - сбросить регистр
примечание: Детектирование логической единицы на каждом пине должно происходить один раз
```cp=
;; created by group of indusi and eskimo
;; start 03.15.22 - mm/dd/yy
;; end 03.29.22 - mm/dd/yy
;; (не)цензурная версия
;; ¯\_(ツ)_/¯ - не знаем, уточнить у Виктора Сергеевича
;; .equ - задаём список констант
;.include "m16def.inc" ; НИХУЯ НЕ РАБОТАЕТ БИБЛИОТЕКА БЛЯТЬ, НАЕБАЛИ ¯\_(ツ)_/¯
;; уговорите блять селезнёва объяснить людям стек, заебал "relative branch is out of reach" уже
.cseg ; ну, он просил оформлять так, мы добавили...
;; задаём port, ddr, pin
.equ port = portb ; вместо буквы N надо указать букву своего порта (1 - B / 2 - C / 3 - D)
.equ ddr = ddrb ; тоже самое, что и с портом, определяет какие пины на чтение, какие на запись
.equ pin = pinb ; тоже самое, что и с портом, только не знаем, зачем он нужен¯\_(ツ)_/¯
;; commands start
.equ void = 0b00000000 ;(0 ) при отсутствии сигналов на пин, мы ничего не делаем
.equ plus = 0b00000001 ;(1 ) при сигнале на пин 1, мы складываем все числа
.equ mult = 0b00000010 ;(2 ) при сигнале на пин 2, мы умножаем все числа(придумать способ умножения)
.equ maxi = 0b00000100 ;(4 ) при сигнале на пин 3, мы находим максимальное число
.equ mini = 0b00001000 ;(8 ) при сигнале на пин 4, мы находим минимальное число
.equ aver = 0b00010000 ;(16 ) при сигнале на пин 5, мы находим среднее арифмитическое
.equ midl = 0b00100000 ;(32 ) при сигнале на пин 6, мы находим среднее число
.equ onee = 0b01000000 ;(64 ) при сигнале на пин 7, мы устанавливаем все единицы в регистре
.equ drop = 0b10000000 ;(128) при сигнале на пин 8, мы сбрасываем регистр
;; commands end
;; variables definition start
.def zero = r3 ; zero - регистр, который мы определили для сравнения с 0
.def cmnd = r16 ; cmnd - регистр, который отвечает за команду
.def temp = r17 ; temp - регистр, который отвечает за всякую хуйню
.def num1 = r18 ; num1 - регистр, в который мы записываем "случайное" число
.def num2 = r19 ; num2 - регистр, в который мы записываем "случайное" число
.def num3 = r20 ; num3 - регистр, в который мы записываем "случайное" число
.def res1 = r21 ; res1 - регистр, в который мы записываем результат вычислений. При сложнии это нижний байт. При умножении - это нижний байт. При сравнении чисел это самое маленькое число.
.def res2 = r22 ; res2 - регистр, в который мы записываем результат вычислений. При сложнии это старший байт байт. При умножении - это средний байт. При сравнении чисел это среднее число.
.def res3 = r23 ; res3 - регистр, в который мы записываем результат вычислений. При сложнии не учавствует. При умножении - это средний байт. При сравнении чисел это среднее число.
;; variables definition end
; out ddr, 0b00000000 - задаём везде 0, так как все пины
; подача сигнала
ldi cmnd, void ; загружаем в регистр команд команду 0b00000000, так как нам надо, чтобы все пины в ddr были на чтение
;; port reading
out ddr, cmnd ; ddrb - 00000000 - работает на чтение
;; command set start
ldi cmnd, maxi ; тут мы выбираем, какая команда будет дальше по коду(якобы пришло напряжение на пин.)
out port, cmnd ; загружаем в порт эту команду
;; comand set end
;; nums
;; загружаем числа в регистры в 16 системе
ldi num1, 0x05 ; загружаем в num1 число
ldi num2, 0x02 ; загружаем в num2 число
ldi num3, 0x04 ; загружаем в num3 число
;; code starts
;; plus
sbis port, 0 ; если на пине 0 есть 1, тогда пропускаем jmp M1
jmp M1 ; прыгаем на следующую команду, если на пине 0 есть 0
M0:
add res1, num1 ; складываем в res1(нижний байт) num1 -> res1 = num1
add res1, num2 ; добавляем к res1(нижний байт) num2 -> res1 = num1 + num2(остаток от их сложения)
brcs carry ; проверяем, случилось ли переполнение, если да, то прыгаем на carry
jmp stp
carry: ; попадаем сюда, если случилось переполнение (num1+num2>255)
clc ; очищаем флаг переполнения
inc res2 ; повышаем старший байт на 1
add res1, num3 ; добавляем к res1(нижний байт) num3 = res1 = остаток от (num1 + num2) + num3
brcs carry2 ; проверяем на переполнение, если это так, от прыгаем на carry2
jmp stp ; если переполнения нет, то идём к следующему шагу(step)
carry2: ; попадаем сюда, если произошло последнее возможное переполнение
clc ; очищаем флаг переполнения
inc res2 ; повышаем старший байт
stp: ; вычисления закончены, отправляемся на задержку
cpi cmnd, aver
breq M2
jmp timeDelay
;; mult команда работает, но если после первого умножения число будет храниться в двух регистрах, то считает неправильно... (неисправимо на данный момент)
M1: sbis port, 1 ; если на пине 1 есть 1, тогда пропускаем jmp M2
jmp M2 ; прыгаем на следующую команду, если на пине 1 есть 0
mult1: ; умножение первого числа
; brvs poshelN ; на случай, если произойдёт УЛЬТРА переполнение, тогда отправляемся в poshelN
cp num2, zero ; сравниваем, осталось ли во втором множителе ещё чего умножать
breq mult2 ; если во втором множителе уже 0, тогда идём умножать последнее число
add res1, num1 ; если не так, тогда складываем в нижний байт число num1
brcs carry1m ; если у нас переполнение, отправляемся в carry1m
dec num2 ; так как умножение это цикл, то уменьшаем счётчик(множитель)
jmp mult1 ; повторяем цикл
carry1m: ; если переполнение в нижнем байте
cp num2, zero ; сравниваем, есть ли что-то во множителе или надо идти по второму множителю
brne num2cp ; если это множитель не равен нулю, тогда идём в num2cp
jmp num3cp ; если равен, тогда идём в num3cp
num2cp: ; цикл в котором мы решаем переполнение с младшим байтом
dec num2
clc
inc res2
brcs carry2m
jmp mult1
num3cp: ; цикл, в котором решаем переполнение со средним байтом
dec num3
clc
inc res2
brcs carry2m
jmp mult3
mult2: ; умножение второго множителя, промежуточная стадия
; brvs poshelN ; на случай, если произойдёт УЛЬТРА переполнение, тогда отправляемся в poshelN
mov num1, res1 ; так как после умножения, у нас новый множитель(уже какой-то по счёту), надо его назначить
dec num3 ; так как это цикл в цикле, надо число циклов снизить на один... вроде, иначе ответ ровно на цикл больше лол)))
mult3: ; умножение второго множителя
cp num3, zero ; короче, тоже самое, только с другим множителем, нечего тут дописывать уже...
breq M5 ; ЕБУЧИЙ "RELATIVE BRANCH IS OUT OF REACH", короче, оно должно перемещать на TimeDelay, но ты пососёшь, если будешь делать так. Правильно timedelay, неправильно, это отправлять на ближайшую возможную метку, чтобы код просто сам дошёл до timeDelay, но это только в теории. Код надо либо перелопатить, либо пойти нахуй, я выбираю второе
add res1, num1
brcs carry1m
dec num3
jmp mult3
carry2m: ; переполнение среднего байта, решение
clc
inc res3
jmp mult1
;; maxi - нахождение максимального числа
;; ради экономии рабочего времени нахождение максимума, минимума и среднего это один и тот же алгоритм сортировки,
;; все числа записываются в res, где и происходит сортировка (как по массиву)
M2: sbis port, 2
jmp M3
sort: ;; инициализация чисел в res и переход на основной цикл сортировки
mov res1, num1 ;; переписываем значения из переменных num в переменные res до начала сортировки
mov res2, num2
mov res3, num3
jmp isSorted
isSorted: ;; проверка, что числа отсортированы. Если какие-то два не отсортированы, меняет их местами и снова проверяет всё по новой
cp res3, res2 ;; сравниваем правое число со средним
brmi swap23 ;; среднее больше - меняем
cp res2, res1 ;; сравниваем левое число с правым
brmi swap12 ;; левое больше - меняем
jmp timeDelay ;; правое больше или равно среднего, а среднее больше или равно левого. Отсортировано, на задержку
swap23: ;; меняем местами правое и среднее числа
mov temp, res3 ;; я надеюсь не нужно комментировать перекид из одной переменной в другую, ну типа, этож очевидно
mov res3, res2
mov res2, temp
jmp isSorted
swap12: ;; меняем местами среднее и левое числа
mov temp, res1
mov res1, res2
mov res2, temp
jmp isSorted
;; mini - нахождение минимального числа
M3: sbis port, 3
jmp M4
jmp sort
;; aver - нахождение среднего арифмитического
M4: sbis port, 4
jmp M5
jmp M0
stpA: ; вычисления закончены, идём считать среднее арифмитическое(где temp - примерное целое значение)
cpi res1, 3 ; смотрим, можем ли мы ещё из суммы(меньшего байта) вычесть 3(так как всегда ищем ср.Ар. трёх чисел)
brpl bigger ; если можем, то прыгаем на bigger
jmp smaller ; если не можем, то отправляемся в smaller
bigger: ; тут вычитаем из суммы(меньшего байта) три
subi res1, 3
inc temp ; повышем кол-во целых на 1
jmp stpA ; идём на повтор
smaller: ; если мы не можем вычесть из меньшего байта, тогда смотрим, есть ли ещё что-то в старшем байте
cp res2, zero
breq End; если ничего нет, тогда заканчиваем алгоритм, ответ в temp
jmp notEnd; если есть, тогда занимаем один и продолжаем алгоритм
notEnd:
dec res2; занимаем один
ldi res1, 0x7f; выгружаем значение 127(потому что 0xff не работает и считается как -127)
jmp stpA; идем на повторение
end:
jmp poshelN
;; midl - нахождение среднего числа
M5: sbis port, 5
jmp M6
jmp sort
;; onee - установка единиц на регистрах результата(я не совсем понял, что Селезнёв имел ввиду, но думаю напишет, если что-то неправильно)
M6: sbis port, 6
jmp M7
ldi res1, 0b11111111
ldi res2, 0b11111111
ldi res3, 0b11111111
;; drop - сбросить значение на регистре
M7: sbis port, 7
jmp timeDelay
;; очищение основных регистров
clr res1
clr res2
clr res3
jmp timeDelay
poshelN: ;; poshelN - обозначние ошибки(fatalError)
jmp poshelN
;; code ends
timeDelay: ;; задержка в развитии на 3 секунды
clr r29
clr r30
clr r31
ldi r31, 12
M8: inc r29
brne M8
inc r30
brne M8
dec r31
slp: jmp slp ;; режим ожидания, после задержки
```
#### Пример задачи №7
Считывается порт. Такой же как и в задании 6
с 0 по 4 пин задаётся число которое надо записать в регистр общего назначения
после чего 5, 6, 7 пином выполняются след. действия:
5 - увеличение разряда числа
6 - уменьшение разряда числа
7 - записать значение в свободный RON
5,6,7 пин выполняются после 5 секундной задержки
```cp=
;; created by group of indusi
;; start 04.03.22 - mm/dd/yy
;; end 04.03.22 - mm/dd/yy
;; (не)цензурная версия
;; ¯\_(ツ)_/¯ - не знаем, уточнить у Виктора Сергеевича
;; .equ - задаём список констант
;.include "m16def.inc" ; НИХУЯ НЕ РАБОТАЕТ БИБЛИОТЕКА БЛЯТЬ, НАЕБАЛИ ¯\_(ツ)_/¯
;; lsr - logical shift right (смещение битов вправо) (уменьшить число в 2 раза)
;; lsl - logical shift left (смещение битов влево) (увеличить число в 2 раза)
.cseg ; ну, он просил оформлять так, мы добавили...
;; задаём port, ddr, pin
.equ port = portb ; вместо буквы N надо указать букву своего порта (1 - B / 2 - C / 3 - D)
.equ ddr = ddrb ; тоже самое, что и с портом, определяет какие пины на чтение, какие на запись
.equ pin = pinb ; тоже самое, что и с портом, только не знаем, зачем он нужен¯\_(ツ)_/¯
;; variables definition start
.def cmnd = r16 ; cmnd - регистр, который отвечает за команду
.def temp = r17 ; temp - регистр, который отвечает за всякую хуйню
.def res1 = r18 ; res1 - регистр, в который мы записываем результат работы программы.
;; variables definition end
; подача сигнала
ldi cmnd, 0b00000000 ; загружаем в регистр команд команду 0b00000000, так как нам надо, чтобы все пины в ddr были на чтение
;; port reading
out ddr, cmnd ; ddrb - 00000000 - работает на чтение
;; command set start
ldi cmnd, 0b11001111
out port, cmnd ; загружаем в порт эту команду
;; comand set end
;; задержка в развитии на 3 секунды(лень делать на пять)
clr r29
clr r30
clr r31
ldi r31, 12
M18: inc r29
brne M18
inc r30
brne M18
dec r31
;; загружаем в temp задание из порта
in temp, port
cbr temp, 0b11100000;; очищаем 5-7 биты, чтобы осталось только число, которое задавали через порт
m1: sbis port, 5 ;; увеличиваем разряд числа (не сказано, чтобы число осталось тем же самым)
jmp m2
lsl temp
lsl temp
M2: sbis port, 6 ;; уменьшаем разряд числа (не сказано, чтобы число осталось тем же самым)
jmp M3
lsr temp
lsr temp
M3: sbis port, 7 ;; записываем число в регистр
jmp timeDelay
mov res1, temp
timeDelay: ;; задержка в развитии на 3 секунды(лень делать на пять)
clr r29
clr r30
clr r31
ldi r31, 12
M8: inc r29
brne M8
inc r30
brne M8
dec r31
slp: jmp slp ;; режим ожидания, после задержки
```
### Команды
:::info
Описанных ниже команд достаточно, чтобы решать задачки на любые манипуляции с РОН (арифметические действия, массивы, сортировка). А всякого рода задачки из последних месяцев мы не решим :crying_cat_face:
:::
:::warning
:-1: Всратости :scream:
1. Команда inc не изменяет флаг C. Значения остальных флагов: Z = 1, S = 0, V = 0, N = 0
2. команда sub Rd, Rx изменяет флаги так: C = 1 если |Rx| > |Rd|
3. Я не записывал любые косвенные команды, не понимаю их, да и вроде не просили
:::
всратые команды, которые скорее всего не пригодятся, и которые я так и не понял:
> [name=Дарья Воронская] Ля, adiw походу все же нужен
```cp=
; сложить 10 с парой регистров [rx, rx+1]
adiw rx, 10
; сравнить значение регистров с учетом переноса.
cpc Rd, Rx
; дробное умножение
fmul, fmuls, fmulsu
lpm
```
#### Прерывания
```cp=
.org <Вставь номер вектора прерывания>
jmp <Вставь ветку для обработчика прерываний>
; Пример для ацп
.org 0x01C
jmp calculate
calculate: ; получили результат
reti
```
#### Директивы
Грубо говоря, названия для переменных
```cp=
.equ name = const; завести константу
.def name Rx; обозвать регистр
```
#### Загрузка данных
```cp=
; загрузить значение. Не во все регистры можно загрузить значение таким образом
ldi Rx, Rd
; Загрузить в РОН значение по адресу SRAM
lds Rx, $ff00
; загрузить в адрес SRAM значение из РОН
sts $ff00, Rx
; поместить в регистр Rd значение регистра Rx. Иногда это единственный способ поместить в некоторые регистры значение
mov Rd, Rx
; считать значение с порта в РОН
in Rx, P
; закинуть значение в порт с РОН
out P, rx
; очистить бит const в регистре ввода/вывода
cbi P, const
; очистить бит const в РОН
cbr Rx, const
; установить бит const в регистре ввода/вывода
sbi P, const
; установить бит const в РОН
sbr Rx, const
; очистить РОН
clr Rx
```
#### Арифметика
```cp=
; Rd = Rd + Rx. После этой команды sreg меняется
add Rd, Rx
; Сложение с переносом (add with carry); Rd = Rd + Rx + SREG:C.
; Например, если Rd = 2, Rx = 4, C = 1, то Rd = 2+4+1=7
adc Rd, Rx
; вычесть. Значение в Rd. Читай всратости
sub Rd, Rx
subi Rd, const
; вычесть с переносом. Rd = Rd - Rx - C
sbc Rd, Rx
sbci Rd, const
; увеличить значение в РОН на 1. Читай всратости
inc Rx
; уменьшить значение в РОН на 1. SREG меняется адекватно
dec Rx
; беззнаковое умножение.
; из умножения 2 восьмибитных чисел получится 16 битное, которое будет храниться в регистрах R1 (старший байт), R0 (младший байт). SREG:C Устанавливается если установлен бит 15 результата, в ином случае очищается
mul Rd, Rx
; знаковое умножение
muls Rd, Rx
; умножение беззнакового со знаковым
mulsu Rd, Rx
```
#### Битовые операции
```cp=
; очистить бит const в регистре ввода/вывода
cbi P, const
; очистить бит const в РОН
cbr Rx, const
; сдвиг всех битов регистра вправо; 7 бит не изменяется. 0 заносится в SREG:C.
; например 10011001. C = 0 -> 10001100. C = 1 -> 10000110. C = 0.
; Эта команда эффективно делит значение дополнения до двух (число записанное с указанием знака) на два, без изменения знака
asr Rx
; битовые сдвиг влево; Бит 7 сдвигается в C, Бит 0 = 0
; Другими словами является умножением беззнакового числа на два
lsl Rx
; битовые сдвиг вправо; Бит 0 сдвигается в C, Бит 7 = 0
; Другими словами является делением беззнакового числа на два
lsr Rx
; сдвинуть влево через перенос. В бит 0 идет С. Бит 7 сдвигается в С
rol Rx
; сдвинуть вправо через перенос. В бит 7 идет С. Бит 0 сдвигается в С
ror Rx
; поменять местами ниблы (полубайты)
swap Rx
```
#### Дополнения
```cp=
; выполнить дополнение до еденицы
; Другими словами - меняет все 0 на 1 и все 1 на 0.
; C = 1, V = 0; N = 7 бит
com Rx
; выполнить дополнение до 2 (выделяет бит для отрицательности)
; Число 80 (1010000) не меняется
neg Rx
```
#### Сравнения
```cp=
; сравнить значение Rd с регистром/константой. Эквивалентно sub только никуда не записывается результат.
cp Rd, Rx
сpi Rd, const
; сравнить значения двух регистров, и пропустить следующую команду, если они равны
cpse Rd, Rx
; пропустить следующую команду, если бит в регистре IO очищен
sbic P, const
; пропустить следующую команду, если бит в регистре IO установлен
sbis P, const
; пропустить следующую команду, если бит в РОН очищен
sbrc P, const
; пропустить следующую команду, если бит в РОН установлен
sbrs P, const
; подразрядное умножение. Rd = Rd&Rx (коньюкция) = И
and Rd, Rx
; подрязрядное умножение с константой; Rd = Rd&const
andi Rd, 10
; подразрядное сложение. Rd = Rd + Rx (дезьюкция) = ИЛИ
or Rd, Rx
; подразрядное сложение с константой; Rd = Rd + const (дезьюкция) = ИЛИ
ori Rd, 10
; выполнить xor на каждом бите Rd, Rx. Записать в Rd
; например eor 1001, 1010 = 0011
eor Rd, Rx
; Проверить на 0 или минус. Аналогичен and Rx, Rx
tst Rx
```
#### Переходы
**jmp br_name** - безусловный переход на ветку
**br<XY>** - условный переход на ветку. [Читай тут](/BhJ3OyD_RIi3lcawKRJbyg)
#### Функции
**call func_name** - вызвать функцию
**ret** - окончание фукнции
**reti** - вернуться из прерывания
```cp=
mov r16, r0 ; Копировать r0 в r16
call check ; Вызвать подпрограмму
nop ; Продолжать (пустая операция)
. . .
check: cpi r16, $42 ; Проверить содержит ли r16 заданное значение
breq error ; Перейти если содержит
ret ; Вернуться из подпрограммы
```