11 580 байт добавлено
, 12:48, 22 октября 2023
{{Заготовка}}
= Nano-RISC =
Nano-RISC - архитектура процессора, используемая в интегральных платах.
Процессоры на этой архитектуре в среднем имеют:
* 16 регистров общего назначения '''R'''.
* Регистр счётчика инструкции '''PC'''.
* Регистр указателя на стек '''SP'''.
* 8 пинов внешних устройств '''D'''.
* 512 байт стека.
* 16384 байт оперативной памяти
Существует [https://igorsaux.github.io/nano-risc/ Web-IDE], в которой эмулируется работа процессора, можно писать и компилировать код, а также построчно наблюдать за его работой.
= Ассемблер =
Язык ассемблера довольно прост - каждая строчка может начинаться с комментария, инструкции или метки.
Пример комментария:
# Здесь можно написать любой текст, он будет убран из программы
Пример инструкции:
mov $r0 10
Пример метки:
loop:
Пример рабочей программы:
<nowiki>dbgs "Factorial of 5"
# N
mov $r0 5
# Result
mov $r1 1
loop:
# If $r0 <= 1 then jump to 'end'
ble $r0 1 end
# $r1 = $r1 * $r0
mul $r1 $r1 $r0
# $r0 = $r0 - 1
sub $r0 $r0 1
# Jump back to 'loop'
jmp loop
end:
dbgs "Result:"
dbg $r1</nowiki>
== Инструкция ==
Любая инструкция состоит из одной операции и от нуля до нескольких аргументов, в зависимости от операции может требоваться разное количество аргументов.
Аргумент представляет из себя либо число, либо регистр, ничего другого операция принимать не может, но язык ассемблера позволяет указывать строчки и метки, превращая их в числа во время компиляции.
== Метка ==
Метка - некая именная точка в коде, при компиляции метки превращаются в номера инструкции.
Некоторые операции могут заставлять процессор переходить к инструкциям, находящимся в другой части программы, - для этого необходимо изменить регистр счётчика инструкции на номер инструкции относительно начала программы (в счёт идут только строчки с инструкциями). Во время написания программы или дальнейших изменениях номера инструкции могут меняться, для этого и существуют метки - они автоматически рассчитают своё положение во время компиляции, избавляя программиста от ручного подсчёта при каждом изменении.
== Комментарии ==
Комментарии никак не влияют на код, их можно использовать для пояснения кода и т.д.
== Строки ==
Строки - особый вид аргумента, во время компиляции они помещаются в отдельную секцию программы, которая затем загружается в оперативную память сразу после кода программы. На место строчки подставляется адрес начала строки в памяти, конец строки обозначается нулевым байтом.
= Регистры =
Каждый процессор имеет 32-х битные регистры общего назначения, в коде обозначаются как '''rN''', где N - индекс регистра (начиная с 0). Они могут хранить в себе как вещественное так и целое число.
Обращаться к регистрам в коде можно двумя способами (где x - название регистра):
* Прямой доступ - '''$xN''', при таком обращении из регистра берётся содержащееся в нём число.
* Косвенный доступ - '''%xN''', в этом случае из регистра берётся число, которое используется как индекс другого регистра, из которого уже будет взято итоговое число.
'''Косвенный доступ доступен только регистрам общего назначения!'''
Существует регистр счётчика инструкции - в коде обозначается как '''pc''', он указывает на следующую инструкцию, при её изменении можно изменять порядок выполнения инструкции.
Регистр указателя на стэк - '''sp''', указывает на свободную ячейку в памяти. Важным отличием от других регистров является то - что его нельзя изменять напрямую, только специальными операциями - '''push''' и '''pop'''!
= Операции =
Существует несколько десятков различных операции, запоминание порядка аргументов может показаться сложным - но в основном действуют такие правила:
* С тремя аргументами: '''c = a X b''' - производится некоторая операция '''X''' над значениями '''a''' и '''b''', результат записывается в '''c'''. Примеры:
<nowiki>
# $r0 = 2 + 4
add $r0 2 4
# $r1 = 5 * 10
mul $r1 5 10</nowiki>
* С двумя аргументами: '''c = f(a)''' - выполняется некоторое преобразование '''f''' над значением '''a''', результат записывается в '''c'''. Примеры:
<nowiki>
# Преобразования нет, просто сокращённая запись "add $r0 $r0 0"
# $r0 = 5
mov $r0 5
# $r1 = sqrt(5)
sqrt $r1 5</nowiki>
== Список операции ==
{| class="wikitable" style="margin:auto"
|+ Математические операции
|-
! Обозначение !! Описание
|-
| '''add''' ''c'' ''a'' ''b'' || Сложение: ''a'' + ''b''.
|-
| '''sub''' ''c'' ''a'' ''b'' || Вычитание: ''a'' - b''.
|-
| '''mul''' ''c'' ''a'' ''b'' || Умножение: ''a'' * ''b''.
|-
| '''div''' ''c'' ''a'' ''b'' || Деление: ''a'' / ''b''.
|-
| '''mod''' ''c'' ''a'' ''b'' || Деление с остатком: ''a'' % ''b''.
|-
| '''sqrt''' ''c'' ''a'' || Квадратный корень.
|-
| '''trunc''' ''c'' ''a'' || Отбрасывание части после запятой.
|-
| '''ceil''' ''c'' ''a'' || Округление вверх.
|-
| '''floor''' ''c'' ''a'' || Округление вниз.
|-
| '''abs''' ''c'' ''a'' || Получение модуля числа.
|-
| '''exp''' ''c'' ''a'' || Получение экспоненты.
|-
| '''log''' ''c'' ''a'' ''b'' || Логарифм: log''b''(''a'')
|-
| '''max''' ''c'' ''a'' ''b'' || Записывает в ''c'' максимальное значение из ''a'' и ''b''.
|-
| '''min''' ''c'' a ''b'' || Записывает в ''c'' минимальное значение из ''a'' и ''b''.
|}
{| class="wikitable" style="margin:auto"
|+ Логические операции
|-
! Обозначение !! Описание
|-
| '''and''' ''c'' ''a'' ''b'' || Записывает в ''c'' 1 если ''a'' и ''b'' имеют ненулевое значение.
|-
| '''or''' ''c'' ''a'' ''b'' || Записывает в ''c'' 1 если ''a'' или ''b'' имеет ненулевое значение.
|-
| '''xor''' ''c'' ''a'' ''b'' || Записывает в ''c'' 1 если один из аргументов имеет ненулевое значение, а другой нулевое.
|-
| '''nor''' ''c'' ''a'' ''b'' || Записывает в ''c'' 1 если оба аргумента имеют нулевое значение.
|-
| '''inf''' ''c'' ''a'' || Записывает в ''c'' 1 если ''a'' - бесконечность.
|-
| '''nan''' ''c'' ''a'' || Записывает в ''c'' 1 если ''a'' - не число.
|}
{| class="wikitable" style="margin:auto"
|+ Битовые операции
|-
! Обозначение !! Описание
|-
| '''andi''' ''c'' ''a'' ''b'' || Битовое И.
|-
| '''ori''' ''c'' ''a'' ''b'' || Битовое ИЛИ.
|-
| '''xori''' ''c'' ''a'' ''b'' || Битовое исключающее ИЛИ.
|-
| '''shr''' ''c'' ''a'' ''b'' || Сдвиг ''a'' на ''b'' вправо (''a'' >> ''b'').
|-
| '''shl''' ''c'' ''a'' ''b'' || Сдвиг ''a'' на ''b'' влево (''a'' << ''b'').
|-
| '''ror''' ''c'' ''a'' ''b'' || Круговой сдвиг ''a'' на ''b'' вправо.
|-
| '''rol''' ''c'' ''a'' ''b'' || Круговой сдвиг ''a'' на ''b'' влево.
|}
{| class="wikitable" style="margin:auto"
|+ Операции с памятью
|-
! Обозначение !! Описание
|-
| '''lb''' ''c'' ''a'' || Чтение байта из адреса ''a'' в ''c''.
|-
| '''lh''' ''c'' ''a'' || Чтение двух байтов из адреса ''a'' в ''c''.
|-
| '''lw''' ''c'' ''a'' || Чтение четырёх байтов из адреса ''a'' в ''c''.
|-
| '''sb''' ''c'' ''a'' || Запись байта из ''a'' в адрес ''c''.
|-
| '''sh''' ''c'' ''a'' || Запись двух байтов из ''a'' в адрес ''c''.
|-
| '''sw''' ''c'' ''a'' || Запись четырёх байтов из ''a'' в адрес ''c''.
|}
{| class="wikitable" style="margin:auto"
|+ Операции со стэком
|-
! Обозначение !! Описание
|-
| '''push''' ''a'' || Записывает в стэк ''a'' и увеличивает счётчик стэка.
|-
| '''pop''' ''c'' || Записывает в ''c'' значение из стэка и уменьшает счётчик стэка.
|-
| '''peek''' ''c'' || Записывает в ''c'' значение из стэка но не уменьшает счётчик стэка.
|-
| '''call''' ''a'' || Записывает текущее значение счётчика инструкции в стек и перемещает выполнение программы на указанное значение.
|-
| '''ret''' || Считывает значение из стека как номер инструкции и перемещает выполнение программы на него.
|}