Принципы развития архитектур ЭВМ; система команд RISC-V
Эти лекции —компонент большого курса (или цикла), аналогичного курсу «Архитектура ЭВМ и язык ассемблера» второго семестра.
О чём не будет сказано:
- О подводках к понятию «система команд», «адрес», «память», «регистр» и т. п. — не будет ни модельных машин, ни тем более схемотехники
О различных архитектурах — не позволяет время (в 4 раза меньше, чем вышеупомянутый «АЭиЯА».
- О «верхней» части (поддержка многозадачности и виртуализация) — не только не укладываемся по времени, но и не на чем попробовать
- Об архитектурах не общего назначения (например, GPU)
- О тонкостях программирования на языке Ассемблера (в принципе задача не в этом)
- …
А о чём будет?
RISC-V и его отношение к архитектуре в целом
RARS в качестве базовой платформы
Скачиваем .jar отсюда (на момент лекции это был rars_533d3c0.jar)
- Запускаем:
java -jar rars_533d3c0.jar
- Если шрифты выглядят как кошмар из прошлого века, включаем антиалиасинг вручную:
java -Dawt.useSystemAAFontSettings=on -jar rars_533d3c0.jar
Если шрифт невозможно разглядеть (как в видео этой лекции), всю картинку можно увеличить вдвое (или втрое, но вещественные числа у меня не заработали) одним из двух способов:
GDK_SCALE=2 java -Dawt.useSystemAAFontSettings=on -jar rars_533d3c0.jar
- или
java -Dsun.java2d.uiScale=2 -Dawt.useSystemAAFontSettings=on -jar rars_533d3c0.jar
- Решение задач на языке ассемблера RISC-V и сдача их в EJudge
- Всевозможные рассуждения о том, что является legacy, а что — тенденцией/признаком
Современные и не очень архитектуры
- Принципы фон Неймана как исторический казус:
- появление новой задачи,
- победа одного-двух частных решений этой задачи, актуальных для своего времени
- «канонизация» этих решений (legacy)
- legacy впоследствии (почти) не пересматривается
Общее правило: «так пошла эволюция, переделывать дороже».
Место RISC-V в современных архитектурах
По системе команд:
Ранние ЭВМ: одна инструкция = одна понятная человеку операция (пример — PDP-11)
- CISC: одна инструкция = много последовательных операций
- RISC: одна инструкция = несколько (иногда) операция, ограниченные по времени выполнения
+ расширения для различных задач (плотная упаковка инструкций в микроконтроллерах, искусственный мозг для повышения производительности и т. д.)
- VLIW: одна инструкция = много параллельных операция (или одна большая)
- …
По времени разработки:
- intel 8086 — 1978 (16 bit)
- MIPS (предшественник RISC-V) — 1985 (32 bit)
- intel 80386 — 1985 (32 bit, почти☺)
- ARM2 — 1986 (32-bit, и тут тоже почти☺)
- … (множество архитектур, существовавших в 80-е, 90-е и частично 2000-е)
- AMD64 — 2000 (64 bit)
- RISCV — 2010 (32, 64 и даже 128 bit, хотя на последнюю желающих пока не нашлось, там всё давно захватано GPU)
- В «железе» — намного позже
Состояние на сегодня: процессоры, системные платы общего назначения
- AArch64 — 2011 (64 bit)
По размеру IPB:
- RISC-V чуть ли не единственная Open Hardware архитектура
Общая структура системы команд RISC-V
Принципы RISC:
- отсутствие вычислительно сложных инструкций,
- фиксированная длина инструкции,
- большое количество регистров общего назначения,
- ограничения на работу непосредственно с оперативной памятью как с медленным устройством
…и их реализация в RISC-V
- + отсутствие дублирующих инструкций, псевдоинструкции
- + трёхадресность,
- + разделение памяти данных и команд,
- + оптимизация под конвейер (см. далее)
- …
- удобство чтения/написания инструкций ассемблера и неудобство чтения машинного кода человеком (упаковка битов, псевдоинструкции и т. п.)
- некоторые регистры более специальные, чем другие
Спецификация RISC-V (это правда можно читать!)
Исходные тексты этого документа (хороший, годный LaTex)
Сконвертированная в HTML спецификация пользовательской системы команд
Организация системы команд RISC-V
(на лекции не перечисляются все команды, даются только примеры, подбор команд по таблице — это ДЗ)
32 регистра общего назначения, доступа к специализированным регистрам нет (в т. ч. нет регистра флагов, даже на аппаратном уровне!)
- 4 базовых типа команд
TODO переписать и перевести:
R — типа «регистр-регистр-регистр» (Register)
I — типа «непосредственное значение-регистр-регистр» (Immediate)
S — типа «регистр-регистр-непосредственное значение» (Store)
U — типа «непосредственное значение-регистр» (Upper)
- Пояснения к схеме:
opcode — код операции (6 битов)
rs1 — № регистра-источника (5 битов)
rs2 — № регистра-опреанда (5 битов)
rd — № регистра-приёмника (5 битов)
imm[11:…] — непосредственный операнд размером в 12 битов
В случае, когда непосредственное значение определяет «приёмник» (смещен адреса для «близкого» перехода или записи результата в память), 12 битов целиком в поле rd не помещаются, и его приходится «распиливать» (инструкция типа S). Непосредственный операнд всегда знаковый, и его знак всегда приходится на 31-й бит.
imm[31:…] — непосредственный операнд размером в 20 битов. Используется в инструкциях типа U для заполнения старших двадцати битов регистра (в операциях «далёкого» перехода и как дополнительная инструкция при записи в регистр полного 32-разрядного непосредственного операнда)
funct — поле функции (6 битов), используется для разных инструкций, у которых код операции одинаковый. Например, все арифметические инструкции типа I имеют одинаковый opcode OP-IMM (чему он равен?), а различаются полем funct. По-видимому, для эффективной реализации R-команд в конвейере удобнее не декодировать опкод, а по-быстрому сравнить его с нулём, и получать значения регистров, параллельно декодируя функцию, чтобы потом её применить.
- Расширение «M»: операции умножения и деления; бывают знаковые и беззнаковые
- Расширения «F» и «D» — математический сопроцессор
- Условные переходы — атомарные операции (нет регистра флагов)
Работа с памятью (в т. ч. псевдоинструкции типа li)
Суть понятия псевдоинструкции на примере li регистр, число:
Нет никакой инструкции «положить число в регистр», зато есть инструкция «сложить I-число с регистром zero (нестираемым нулём) и положить результат в регистр»
Если число в li больше 16 битов, псевдоинструкция раскладывается в две:
записать старшие 20 битов большого числа в старшие 20 битов регистра (младшая при этом обнуляется) — инструкция типа U,
добавить оставшиеся 12 битов числа в регистр — инструкция типа S
Соответственно, программисту не надо в уме прикидывать, влезает ли число в 12 битов, и самому распиливать/объединять части, если не влезает.
- Надо помнить, что 12 битов включает в себя знаковый, так что 11 битов
это — наиболее эффективные способы реализации команды li регистр, число
переходы: короткие (типа S) и длинные (типа J)
- Пример программы для RARS
- будем использовать пока что магические системные вызовы ввода и вывода десятичных чисел, находящихся в регистре
- Ввести два числа, вывести результат:
1 li a7 5 # Системный вызов №7 — ввести десятичное число 2 ecall # Результат — в регистре a0 3 mv t0 a0 # Сохраняем результат в t0 4 ecall # Регистр a7 не менялся, тот же системный вызов 5 add a0 t0 a0 # Прибавляем ко второму число первое 6 li a7 1 # Системный вызов №1 — вывести десятичное число 7 ecall 8 li a7 10 # Системный вызов №10 — останов программы 9 ecall
Д/З
- Актуализировать общие знания об архитектуре ЭВМ — в первую очередь, если что-то не было понятно на лекции. Пригодится.
Установить RARS и запустить в нём программу сложения двух чисел
- Не забыть сразу указать ФИО, группу и факультет, если вы не с ВМК