Продвинутые приёмы программирования микропроцессора

## Доступ к устройствам через регистр

Вы можете использовать регистр для доступа к устройствам d0-d5. Полезно для записи одинаковых параметров в несколько устройств.

````
move r0 0
next:
s dr0 Horizontal 0
s dr0 Vertical 0
s dr0 On 0
add r0 r0 1
blt r0 6 next

````

## Функции

Пример использования функции:

````
main:
jal MyFunction
j main

MyFunction:
... тело функции ...
j ra

````

Функция - это просто метка, на которую мы переходим с использованием *-al* версии инструкций ветвления (*jal*, *beqzal*). Но поскольку они сохраняют адрес возврата в специальном регистре *ra*, при вызове функции из другой функции (или из самой себя, рекурсивно), *ra* будет перезаписан, поэтому мы должны сохранить ее в стеке(*push*) и восстановить(*pop*), когда функция завершится:

````
main:
jal _MyFunction
j main

_MyFunction:
... тело функции ...
push ra
jal _MySecondFunction
pop ra
... тело функции ...
j ra

_MySecondFunction:
... тело функции ...
j ra

````
Если бы мы не использовали стек, переход в конце *\_MyFunction* переместил бы нас к вызову *\_MySecondFunction* вместо возврата в *main*.

## Циклы

Пример использования цикла:

````
alias rIterator r0
main:
move rIterator 0
Loop:
... тело цикла ...
add rIterator rIterator 1
bgt rIterator 3 Loop_End
j Loop
Loop_End:
j main

````

## Индексация с относительным переходом (switch)

````
alias rIndex r0
alias rTemp r1
alias rValue r2
main:
move rIndex 1
mul rTemp rIndex 2
add rTemp rTemp 1
jr rTemp
move rValue 123 #Index 0
j Select_end
move rValue 456 #Index 1
j Select_end
move rValue 789 #Index 2
j Select_end
...
Select_end:
j main

````
Используется, чтобы установить один или несколько параметров или вызвать функции используя некоторый вычисленный вами индексный номер (или считанный из другого устройства). Умножаем его на 2, потому что каждое условие в примере занимает две строки, а добавляем единицу потому, что для индекса ноль *jr 0* заблокирует нашу IC создав бесконечный цикл.

## Переопределение alias

Допустим, у вас есть сложная функция, которая управляет устройством (считывает/записывает несколько параметров, контролирует время и т. п.), И вы хотите повторно использовать ее для нескольких устройств. Вы можете скопипастить всю функцию поменяв *alias* или переопределить используемый в ней *alias* и указать его на другое устройство, например:

````
main:
alias dCurrent d0
jal _MyFunction
alias dCurrent d1
jal _MyFunction
j main

````

## Вычислимый переход

D0 - множественное чтение SUM(battery.Charge)

D1 - множественное чтение SUM(battery.Maximum)

D2 - LED-лампа

````
# aliases section
alias BatteryChargeSum d0
alias BatteryMaximumSum d1
alias LED d2
alias charge r15
alias maxCharge r14
alias rate r13
# preparation section
s LED On 1                  # Включаем и блокируем лампу
s LED Lock 1
# main loop
main:
yield
l charge BatteryChargeSum Setting
l maxCharge BatteryMaximumSum Setting
div rate charge maxCharge   # Вычисляем зону заряда
mul rate rate 5             # как floor(charge/maxCharge*5)
floor rate rate             # получим число от 0 до 5
bgtz rate biggerThan0       # Если число больше 0 - показываем постоянные цвета
s LED Color 4               # При нуле (< 20%) моргаем красным (4 - красный, 7 - чёрный)
yield
s LED Color 7
j main
biggerThan0:
mul rate rate 2             # Умножаем на длину каждого блока (2 инструкции)
sub rate rate 1             # Добавляем смещение первого блока (-1 строка)
jr rate                     # Переходим на вычисленное смещение
s LED Color 4               # < 40% - красный (4)
j main
s LED Color 3               # < 60% - оранжевый (3)
j main
s LED Color 5               # < 80% - жёлтый (5)
j main
s LED Color 2               # < 100% - зелёный (2)
j main
s LED Color 0               # = 100% - синий (0)
j main

````

## Триггер Шмидта на косвенной адресации регистров

D0 - регулятор, задающий температуру

D1 - газовый сенсор

D2 - маленький трансформатор, питающий настенные обогреватели

D3 - маленький трансформатор, питающий настенные охладители

````
# aliases section
alias Dial d0
alias GasSensor d1
alias HeatersControl d2
alias CoolersControl d3
alias targetCelsius r0
alias currentTemp r1
alias heaterStart r10
alias heaterStop r11
alias coolerStart r12
alias coolerStop r13
alias heaterTrigger r14
alias coolerTrigger r15
# preparation section
move heaterTrigger 10                  # Устанавливаем начальные номера регистров
move coolerTrigger 12                  # для обоих триггеров
s HeatersControl On 0                  # Выключаем и блокируем управление
s HeatersControl Lock 1                # обогревателями и охладителями
s CoolersControl On 0
s CoolersControl Lock 1
# main loop
main:
yield
l targetCelsius Dial Setting           # Получаем заданную температуру
add heaterStart targetCelsius 267.15   # Обогреватель включается, когда температура на 5 градусов ниже заданной
add heaterStop targetCelsius 272.15    # и выключается, когда она на 1 градус ниже заданной
add coolerStart targetCelsius 278.15   # Охладитель включается, когда температура на 5 градусов выше заданной
add coolerStop targetCelsius 274.15    # и выключается, когда она на 1 градус выше заданной
l currentTemp GasSensor Temperature    # Получаем текущую температуру
slt heaterTrigger currentTemp rr14     # Сравниваем её с текущим порогом обогревателя
s HeatersControl On heaterTrigger      # Включаем или выключаем обогреватель
add heaterTrigger heaterTrigger 10     # Добавляем номер первого регистра триггера для следующего цикла
slt coolerTrigger rr15 currentTemp     # Сравниваем температуру с текущим порогом охладителя
s CoolersControl On coolerTrigger      # Включаем или выключаем охладитель
add coolerTrigger coolerTrigger 12     # Добавляем номер первого регистра триггера для следующего цикла
j main

````

## Стек как массив и переход с сохранением адреса как индекс при поиске

На примере программы, проверяющей состояние склада с растениями и выставляющей в db двоичный код для заказа недостающих. Каждый бит этого кода соответствует недостатку определённого растения на складе (1 - пшеница, 2 - соевые бобы, 4 - Кукуруза, 8 - Картофель, 16 - Помидор и т.д.). Прочитав код, контроллер гидропоники может операцией AND определить, надо ли ему запускать цикл выращивания этого растения.

````
alias Vending d0
alias Slot r0
alias ItemHash r1
alias ItemNumber r2
alias ItemCount r3
alias RequestCode r4
main:
yield
# Очищаем первые 15 ячеек стека, это будет массив со счётчиками
move sp 0
clear:
push 0
blt sp 15 clear
move Slot 2                          # Начинаем перебор слотов со 2 по 101
slotloop:
ls ItemHash Vending Slot PrefabHash  # Получаем хэш предмета в очередном слоте
search:                              # Опорная метка для счётчика
beqz ItemHash empty                  # Слот пуст - идём в конец цикла
beqal ItemHash -1057658015 found     # Пшеница
beqal ItemHash 1924673028 found      # Соевые бобы
beqal ItemHash 258339687 found       # Кукуруза
beqal ItemHash 1929046963 found      # Картофель
beqal ItemHash -998592080 found      # Помидор
beqal ItemHash 1277828144 found      # Тыква
beqal ItemHash 658916791 found       # Рис
beqal ItemHash 2044798572 found      # Гриб
beqal ItemHash 892110467 found       # Папоротник
beqal ItemHash -81376085 found       # Красный цветок
beqal ItemHash -1411986716 found     # Оранжевый цветок
beqal ItemHash 1712822019 found      # Жёлтый цветок
beqal ItemHash -1513337058 found     # Зелёный цветок
beqal ItemHash -1573623434 found     # Синий цветок
beqal ItemHash 176446172 found       # Инопланетный гриб
s Vending RequestHash ItemHash       # Попался непонятный предмет, выбрасываем
j main                               # Сбились со счёта, начинаем заново
found:                               # Что-то нашли
sub ItemNumber ra search             # Вычисляем позицию строки относительно опорной метки
sub sp ItemNumber 2                  # Вычитаем дополнительное смещение для нужного индекса в стеке
pop ItemCount                        # Берём значение из стека по индексу
add ItemCount ItemCount 1            # Увеличиваем на 1
push ItemCount                       # И записываем обратно в стек
empty:
add Slot Slot 1
blt Slot 102 slotloop                # Переходим к следующему слоту
move sp 15                           # Перебираем массив в стеке, начиная с конца
move RequestCode 0                   # И формируем двоичный код
makecode:
pop ItemCount
slt ItemCount ItemCount 7            # Если число растений на складе меньше 7
add RequestCode RequestCode RequestCode
add RequestCode RequestCode ItemCount # То соответствующий бит кода будет равен 1
bnez sp makecode
s db Setting RequestCode             # Записываем этот код в db для контроллеров гидропоники
j main

````