2764
Комментарий:
|
7026
|
Удаления помечены так. | Добавления помечены так. |
Строка 16: | Строка 16: |
* некоторые регистры более специальные, чем другие: * '''$0''' всегда равен 0, '''$31''' используется для подпрограмм и т. п. |
|
Строка 19: | Строка 21: |
* 3 базовых типа команд (с 26-битной частью адреса, с 16-битной и безадресные) | * 3 базовых типа команд || |||||||||||| биты слова|| || || 31…26 || 25…21 || 20…16 || 15…11 || 10…6 || 5…0 || || || 6 || 5 || 5 || 5 || 5 || 6 || || R-Тип (Register) || op || rs || rt || rd || sa || funct || || I-Тип (Immediate) || op || rs || rt |||||| immediate || || J-Тип (Jump) || op |||||||||||| target || * '''op''' — код операции (6 битов) * '''rs''' — № регистра-источника (5 битов) * '''rt''' — № регистра-опреанда (для команд типа I — регистра-назначения) (5 битов) * '''immediate''' — непосредственный знаковый операнд (16 битов), используется для логических операндов, арифметических знаковых операндов, для смещений в адресе загрузки/сохранения, для команд условного ветвления («близкого» перехода) * '''target''' — адрес перехода (26 битов); в действительности это 28 бттов без последних 2, т. к. адрес перехода всегда кратен 4 (то же верно и для «близкого» перехода, 18 битов вместо 16) * '''rd''' — № регистра-назначения (5 битов) * '''sa''' — величина сдвига для команд побитового сдвига регистра (5 битов достаточно :) ) * '''funct''' — поле функции (6 битов), используется для команд, у которых код операции равен (например, для op=0) |
Строка 21: | Строка 38: |
* Для некоторых операций (например, сложения) «знаковость» означает, что при переполнении будет возникать исключение, а «беззнаковость» — что не будет. | |
Строка 22: | Строка 40: |
* сравнение только с 0 или = / ≠, сравнение на > / < двух регистров потребовало бы ''двух'' арифметических операций! | |
Строка 23: | Строка 42: |
* Суть понятия псевдоинструкции: | * Суть понятия псевдоинструкции на примере `li регистр, число`: |
Строка 25: | Строка 44: |
* ... | * Нет никакой ''инструкции'' «положить I-число в регистр», зато есть инструкция «сложить I-число с `$0` (с нестрираемым нулём) и положить результат в регистр» * Если число в `li` больше 16 битов, псевдоинструкция раскладывается в две: 1. записать старшую половину большого числа (это I-число) в старшую половину регистра (младшая при этом обнуляется), 1. побитово добавить (OR) младшую половину большого числа в регистр * Обратите внимание на использование '''$1''' для хранения промежуточных данных |
Строка 29: | Строка 52: |
* | * Ввести два числа, вывести результат: {{{ li $v0 5 # Системный вызов №5 — ввести десятичное число syscall # Результат — в регистр $v0 (он же $2) move $t0 $v0 # Сохраняем результат в $t0 (он же $8) li $v0 5 # $v0 нам нужен для ввода ещё одного числа syscall add $a0 $v0 $t0 # Складываем ввод с сохранённым, записываем в $a0 (он же $4) li $v0 1 # Системный вызов №1 — вывести число из регистра $a0 syscall li $v0 10 # Системный вызов №10 — останов программы syscall }}} |
Общая структура системы команд MIPS
- Принципы RISC:
- отсутствие вычислительно сложных инструкций,
- фиксированная длина инструкции,
- большое количество регистров общего назначения,
- ограничения на работу непосредственно с оперативной памятью как с медленным устройством
- …и их реализация в MIPS:
- + отсутствие дублирующих инструкций, псевдоинструкции
- + трёхадресность,
- + разделение памяти данных и команд,
- + оптимизация под конвейер (см. далее)
- …
удобство чтения/написания инструкций ассемблера и неудобство чтения машинного кода человеком (упаковка битов, псевдоинструкции и т. п.)
- т. н. исключения — нормальное состояние программы, а не ошибка
- некоторые регистры более специальные, чем другие:
$0 всегда равен 0, $31 используется для подпрограмм и т. п.
- Организация системы команд MIPS32:
(на лекции не перечисляются все команды, даются только примеры, подбор команд по таблице — это ДЗ)
32 регистра общего назначения, доступа к специализированных регистрами нет (в т. ч. нет регистра флагов!)
- 3 базовых типа команд
биты слова
31…26
25…21
20…16
15…11
10…6
5…0
6
5
5
5
5
6
R-Тип (Register)
op
rs
rt
rd
sa
funct
I-Тип (Immediate)
op
rs
rt
immediate
J-Тип (Jump)
op
target
op — код операции (6 битов)
rs — № регистра-источника (5 битов)
rt — № регистра-опреанда (для команд типа I — регистра-назначения) (5 битов)
immediate — непосредственный знаковый операнд (16 битов), используется для логических операндов, арифметических знаковых операндов, для смещений в адресе загрузки/сохранения, для команд условного ветвления («близкого» перехода)
target — адрес перехода (26 битов); в действительности это 28 бттов без последних 2, т. к. адрес перехода всегда кратен 4 (то же верно и для «близкого» перехода, 18 битов вместо 16)
rd — № регистра-назначения (5 битов)
sa — величина сдвига для команд побитового сдвига регистра (5 битов достаточно )
funct — поле функции (6 битов), используется для команд, у которых код операции равен (например, для op=0)
- знаковая и беззнаковая арифметика; регистры LO/HI для умножения/деления; побитовые операции
- Для некоторых операций (например, сложения) «знаковость» означает, что при переполнении будет возникать исключение, а «беззнаковость» — что не будет.
- условная пересылка и сравнение
сравнение только с 0 или = / ≠, сравнение на > / < двух регистров потребовало бы двух арифметических операций!
работа с памятью (в т. ч. псевдоинструкции типа li)
Суть понятия псевдоинструкции на примере li регистр, число:
Нет никакой инструкции «положить I-число в регистр», зато есть инструкция «сложить I-число с $0 (с нестрираемым нулём) и положить результат в регистр»
Если число в li больше 16 битов, псевдоинструкция раскладывается в две:
- записать старшую половину большого числа (это I-число) в старшую половину регистра (младшая при этом обнуляется),
- побитово добавить (OR) младшую половину большого числа в регистр
Обратите внимание на использование $1 для хранения промежуточных данных
- переходы
- Пример программы для Mars
- будем использовать пока что магические системные вызовы ввода и вывода десятичных чисел, находящихся в регистре
- Ввести два числа, вывести результат:
li $v0 5 # Системный вызов №5 — ввести десятичное число syscall # Результат — в регистр $v0 (он же $2) move $t0 $v0 # Сохраняем результат в $t0 (он же $8) li $v0 5 # $v0 нам нужен для ввода ещё одного числа syscall add $a0 $v0 $t0 # Складываем ввод с сохранённым, записываем в $a0 (он же $4) li $v0 1 # Системный вызов №1 — вывести число из регистра $a0 syscall li $v0 10 # Системный вызов №10 — останов программы syscall
Д/З
TODO
- Зарегистрироваться в EJudge
- Решить простейшую задачу