Опубликован: 19.01.2025 | Доступ: свободный | Студентов: 0 / 0 | Длительность: 05:57:00
Лекция 4:

Лабораторная работа №3. Изучение архитектуры RISC-V на примере ассемблерной программы

< Лекция 3 || Лекция 4 || Лекция 5 >

3.1 Цель и задачи

Целью работы является получить представление о наборе команд RISC-V (базовый instruction set architecture (ISA), основные типы инструкций)

Для достижения поставленной цели требуется решить следующие задачи:

  1. Ознакомиться с основными компонентами компьютера.
  2. Понять взаимосвязь между SW и HW процессора (ISA - мост между SW и HW).
  3. Понимать взаимосвязь между процессором и языком ассемблера.
  4. Знать основные этапы компиляции программы и место ассемблера.
  5. Изучить классический RISC - конвейер.
  6. Понимать принцип кодирования инструкции на языке ассемблера в машинный код.

Презентация к блоку "Ассемблер RISC-V"

3.2. Основные теоретические сведения

Место RISC-V в современных архитектурах согласно системе команд:

  • CISC: одна инструкция = много последовательных операций.
  • RISC: одна инструкция = операция, ограниченная по времени выполнения.
  • VLIW: одна инструкция = много параллельных операция (или одна большая).

Принципы RISC:

  • отсутствие вычислительно сложных инструкций,
  • фиксированная длина инструкции,
  • большое количество регистров общего назначения,
  • ограничения на работу непосредственно с оперативной памятью как с медленным устройством.

Особенности инструкций:

  • отсутствие регистра флагов в RISC-V.
  • формат из 3-х операндов.
  • дополнительные функции отдельных инструкций (add вместо mov).
  • базовый набор и стандартные расширения.
  • наличие псевдоинструкций.

В архитектуре RISC-V имеется обязательное для реализации небольшое подмножество команд (набор инструкций I - Integer) и несколько стандартных опциональных расширений. В базовый набор входят инструкции условной и безусловной передачи управления/ветвления, минимальный набор арифметических/битовых операций на регистрах, операций с памятью (load/store), а также небольшое число служебных инструкций.

Операции ветвления не используют каких-либо общих флагов, как результатов ранее выполненных операций сравнения, а непосредственно сравнивают свои регистровые операнды. Базис операций сравнения минимален, а для поддержки комплементарных операций операнды просто меняются местами.

3.2.1 Базовый набор регистров и альтернативные имена в стандарте ABI (application binary interface)

Базовое подмножество команд использует следующий набор регистров (Таблица 3.1): специальный регистр x0 (zero), 31 целочисленный регистр общего назначения (x1 - x31), регистр счётчика команд (PC, используется только косвенно), а также множество CSR (Control and Status Registers, может быть адресовано до 4096 CSR).

Таблица 3.1. Набор регистров RISC-V (регистровый файл)
Номер Название Описание
x0 zero Константа нуля (zero register)
x1 ra Адрес возврата (return address)
x2 sp Указатель стека (stack pointer)
x3 gp Глобальный указатель (global pointer)
x4 tp Указатель потока (thread pointer)
x5-x7 t0-t2 Временные переменные (temporary registers)
x8 s0/fp Сохраняемая переменная /Указатель фрейма стека (saved register / frame pointer)
x9 s1 Сохраняемая переменная (saved register)
x10-x11 a0-a1 Аргументы функций/Возвращаемые значения (function arguments / return values)
x12-x17 a2-a7 Аргументы функций (function arguments)
x18-x27 s2-s11 Сохраняемые переменные (saved registers)
x28-x31 t3-t6 Временные переменные (temporary registers)

Для лучшей читаемости кода инструкции ассемблера обычно используют специальные имена, например s1, но они также могут использовать номер регистра (например, x9 для регистра номер 9). В нулевом регистре x0 всегда хранится константа 0; попытка записать в него другое значение игнорируется. Регистры от s0 до s11 (регистры 8-9 и 18-27) и от t0 до t6 (регистры 5-7 и 28-31) используются для хранения переменных; ra и регистры от a0 до a7 служат для вызовов функций. Регистры 2-4 носят имена sp, gp и tp. Нет операций над частями регистров, нет каких-либо выделенных "регистровых пар".

Регистр gp (global pointer) представляет собой специальную константу, указывающую в блок данных, где хранятся константы и глобальные переменные. Значение данного регистра инициализируется в начале работы программы (это делает линковщик, когда компонует программу) смещением 0x800 от начала данной секции, что позволяет получать доступ к содержимому секции используя 12-битное смещение со знаком, что значительно упрощает доступ к константам и глобальным переменным. Изменять значение регистра gp самостоятельно не рекомендуется.

Архитектура RISC-V использует только little-endian модель (Рис. 3.1) - первый байт операнда в памяти соответствует наименее значащим битам значений регистрового операнда. RISC-V применяет память с побайтовой адресацией. Это значит, что каждый байт памяти имеет уникальный адрес. Поскольку 32-битное слово состоит из четырех 8-битных байтов, то адрес каждого слова (word address) кратен 4. Старший байт (most significant byte, MSB) находится слева, а младший байт (least significant byte, LSB) - справа.

Формат little-endian

Рис. 3.1. Формат little-endian

Инструкции базового набора имеют длину 32 бита. Формат 32-битной машинной команды (признаки - младшие биты всегда quot;11quot; и 2-4 биты ? quot;111quot;).

Типы команд и их кодирование для RISC-V

Рис. 3.2. Типы команд и их кодирование для RISC-V

Обозначения на Рис. 3.2:

  • rs1 (5бит) - номер регистра в котором находится первый операнд
  • rs2 (5бит) - номер регистра в котором находится второй операнд
  • rd (5бит) - номер регистра в который будет записан результат
  • opcode (7бит) +funct7+funct3 (10бит) определяют операцию
  • imm - непосредственный операнд (константа) в дополнительном коде

Таким образом, в архитектуре RISC-V используются четыре формата инструкций: типа R, типа I, типа S/B и типа U/J.

3.3. Задание к лабораторной работе

Напишите программу на ассемблере, которая пересылает константу 1 в регистр х1. К полученному результату прибавьте 1 и сохраните результат в регистре х1.

  • Скомпилируйте программу.
  • Представьте программу в машинном коде.
  • Выполните вручную декодирование программы в соответствии с типами используемых инструкций.
  • Повторите перечисленные выше действия, используя альтернативные имена регистров в стандарте ABI.

3.3.1. Описание последовательности выполнения работы

Скомпилируйте исходную программу и убедитесь в ее работоспособности в RISC-V ОС, либо через qemu-riscv64.

С помощью утилиты objdump дизассемблируйте бинарный файл программы.

Используя информацию о том, как кодируются инструкции, выполните декодирование в виде таблицы.

3.3.2. Пример выполнения задания на защиту

-----code-----
.text
.global _st  	art
_start:
addi x1, x0, 1
addi x1, x1, 1
addi a7, x0, 93  # set a7 = 93, Linux call exit
ecall
 
Disassembly of section .text:
00000000000100b0 <_start>:
100b0:      	00100093 	addi x1, x0, 1
100b4:      	00108093 	addi x1, x1, 1
100b8:      	05d00893 	addi a7, x0, 93
100bc:      	00000073 	ecall
-----end code-----

Инструкция addi относится к I-типу, opcode=0x13, funct3=0x0

addi x1, x0, 1 0000 0000 0001 0000 0 000 0000 1 001 0011
addi x1, x1, 1 0000 0000 0001 0000 1 000 0000 1 001 0011

3.4. Вопросы для контроля

  1. Что входит в базовый набор инструкций?
  2. За что отвечают регистры a2-a7?
  3. Поясните, как кодируются инструкции типа J.
< Лекция 3 || Лекция 4 || Лекция 5 >