--- language: "MIPS Assembly" filename: MIPS.asm contributors: - ["Stanley Lim", "https://github.com/Spiderpig86"] translators: - ["AstiaSun", "https://github.com/AstiaSun"] lang: uk-ua --- Мова асемблера MIPS (англ. Microprocessor without Interlocked Pipeline Stages) була написана для роботи з мікропорцесорами MIPS, парадигма яких була описана в 1981 році [Джоном Геннессі](https://uk.wikipedia.org/wiki/Джон_Лерой_Геннессі). Ці RISC процесори використовуються у таких вбудованих системах, як маршрутизатори та мережеві шлюзи. [Read More](https://en.wikipedia.org/wiki/MIPS_architecture) ```asm # Коментарі позначені як'#' # Всі символи після '#' ігноруються лексичним аналізатором асемблера. # Зазвичай програми поділяються на .data та .text частини .data # У цьому розділі дані зберігаються у пам'яті, виділеній в RAM, подібно до змінних # в мовах програмування вищого рівня # Змінна оголошується наступним чином: [назва]: .[тип] [значенння] # Наприклад: hello_world: .asciiz "Hello World\n" # Оголосити текстову змінну num1: .word 42 # word - це чисельний тип 32-бітного розряду arr1: .word 1, 2, 3, 4, 5 # Масив чисел arr2: .byte 'a', 'b' # Масив буквених символів (розмір кожного - 1 байт) buffer: .space 60 # Виділити місце в RAM # (не очищується, тобто не заповнюється 0) # Розміри типів даних _byte: .byte 'a' # 1 байт _halfword: .half 53 # 2 байти _word: .word 3 # 4 байти _float: .float 3.14 # 4 байти _double: .double 7.0 # 8 байтів .align 2 # Вирівнення пам'яті даних, де число # показує кількість байтів, вирівнених # у степені 2. (.align 2 означає # чисельне (word) вирівнювання оскільки # 2^2 = 4 байти) .text # Розділ, що містить інструкції та # логіку програми .globl _main # Оголошує назву інструкції як # глобальну, тобто, яка є доступною для # всіх інших файлів _main: # програми MIPS виконують інструкції # послідовно, тобто першочергово код # буде виконуватись після цієї позначки # Виведемо на екран "hello world" la $a0, hello_world # Завантажує адресу тексту у пам'яті li $v0, 4 # Завантажує значення системної # команди (вказуючи тип функціоналу) syscall # Виконує зазначену системну команду # з обраним аргументом ($a0) # Регісти (використовуються, щоб тримати дані протягом виконання програми) # $t0 - $t9 # Тимчасові регістри використовуються # для проміжних обчислень всередині # підпрограм (не зберігаються між # викликами функцій) # $s0 - $s7 # Збережені регісти, у яких значення # збегіраються між викликами підпрограм. # Зазвичай збегрігаються у стеку. # $a0 - $a3 # Регістри для передачі аргументів для # підпрограм # $v0 - $v1 # Регістри для значень, що повертаються # від викликаної функції # Типи інструкції завантаження / збереження la $t0, label # Скопіювати адресу в пам'яті, де # зберігається значення змінної label # в регістр $t0 lw $t0, label # Скопівати чисельне значення з пам'яті lw $t1, 4($s0) # Скопівати чисельне значення з адреси # пам'яті ресгіста зі зміщенням в # 4 байти (адреса + 4) lb $t2, label # Скопіювати буквений символ в частину # нижчого порядку регістра $t2 lb $t2, 0($s0) # Скопіювати буквений символ з адреси # в $s0 із зсувом 0 # Подіне використання і 'lh' для halfwords sw $t0, label # Збегігти чисельне значення в адресу в # пам'яті, що відповідає змінній label sw $t0, 8($s0) # Збегігти чисельне значення в адресу, # зазначеній у $s0, та зі зсувом у 8 байтів # Така ж ідея використання 'sb' та 'sh' для буквених символів та halfwords. # 'sa' не існує ### Математичні операції ### _math: # Пам'ятаємо, що попередньо потрібно завантажити данні в пам'ять lw $t0, num # Із розділа з данними li $t0, 5 # Або безпосередньо з константи li $t1, 6 add $t2, $t0, $t1 # $t2 = $t0 + $t1 sub $t2, $t0, $t1 # $t2 = $t0 - $t1 mul $t2, $t0, $t1 # $t2 = $t0 * $t1 div $t2, $t0, $t1 # $t2 = $t0 / $t1 (Може не підтримуватись # деякими версіями MARS) div $t0, $t1 # Виконує $t0 / $t1. Отримати частку можна # за допомогою команди 'mflo', остаток - 'mfhi' # Bitwise Shifting sll $t0, $t0, 2 # Побітовий здвиг вліво з безпосереднім # значенням (константою) 2 sllv $t0, $t1, $t2 # Здвиг вліво зі змінною кількістю у # регістрі srl $t0, $t0, 5 # Побітовий здвиг вправо (не збегігає # знак, знак розширюється 0) srlv $t0, $t1, $t2 # Здвиг вправо зі змінною кількістю у # регістрі sra $t0, $t0, 7 # Побітовий арифметичний збвиг вправо # (зберігає знак) srav $t0, $t1, $t2 # Здвиг вправо зі змінною кількістю у # регістрі # Bitwise operators and $t0, $t1, $t2 # Побітове І (AND) andi $t0, $t1, 0xFFF # Побітове І з беспосереднім значенням or $t0, $t1, $t2 # Побітове АЛЕ (OR) ori $t0, $t1, 0xFFF # Побітове АЛЕ з беспосереднім значенням xor $t0, $t1, $t2 # Побітова виключна диз'юнкція (XOR) xori $t0, $t1, 0xFFF # Побітове XOR з беспосереднім значенням nor $t0, $t1, $t2 # Побітова стрілка Пірса (NOR) ## Розгалуження ## _branching: # В овсновному інструкції розгалуження мають наступну форму: #