mirror of
https://github.com/MPSU/APS.git
synced 2026-06-10 11:13:33 +00:00
English version draft
Assisted-by: Claude:claude-4.6-sonnet
This commit is contained in:
173
Other/rv32i.md
173
Other/rv32i.md
@@ -1,155 +1,155 @@
|
||||
# RV32I - Стандартный набор целочисленных инструкций RISC-V
|
||||
# RV32I — Standard Integer Instruction Set of RISC-V
|
||||
|
||||
Разделы статьи:
|
||||
Sections:
|
||||
|
||||
- [Краткая справка по RISC-V и RV32I](#Краткая-справка-по-risc-v-и-rv32i)
|
||||
- [Brief Overview of RISC-V and RV32I](#brief-overview-of-risc-v-and-rv32i)
|
||||
- [RV32I](#rv32i)
|
||||
- [Псевдоинструкции](#Псевдоинструкции)
|
||||
- [Основные типы команд](#Основные-типы-команд)
|
||||
- [Pseudo-instructions](#pseudo-instructions)
|
||||
- [Base Instruction Formats](#base-instruction-formats)
|
||||
|
||||
> Большая часть данного документа в той или иной степени является переводом спецификации RISC-V[[1]](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), распространяемой по лицензии [CC-BY-4.0 ](https://creativecommons.org/licenses/by/4.0/).
|
||||
> Most of this document is, to varying degrees, a translation of the RISC-V specification[[1]](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf), distributed under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
||||
|
||||
## Краткая справка по RISC-V и RV32I
|
||||
## Brief Overview of RISC-V and RV32I
|
||||
|
||||
RISC-V — открытая и свободная система набора команд (Instruction Set Architecture, ISA) на основе концепции компьютера с сокращённым набором команд (Reduced Instruction Set Computer, RISC). Чтобы понять архитектуру любого компьютера, нужно в первую очередь выучить его язык, понять, что он умеет делать. Слова в языке компьютера называются «инструкциями», или «командами», а словарный запас компьютера — «системой команд»[[2, стр. 360](https://reader.lanbook.com/book/241166?lms=3ec5abac958be145faed85c101d197fb)].
|
||||
RISC-V is an open and free Instruction Set Architecture (ISA) based on the concept of a Reduced Instruction Set Computer (RISC). To understand the architecture of any computer, one must first learn its language — understand what it is capable of doing. The words in a computer's language are called "instructions" or "commands", and the computer's vocabulary is called the "instruction set"[[2, p. 360](https://reader.lanbook.com/book/241166?lms=3ec5abac958be145faed85c101d197fb)].
|
||||
|
||||
В архитектуре RISC-V имеется обязательный для реализации минимальный список команд — набор инструкций **I** (Integer). В этот набор входят различные логические и арифметические операции с целыми числами, работа с памятью, и команды управления. Этого достаточно для обеспечения поддержки компиляторов, ассемблеров, компоновщиков и операционных систем (при условии реализации дополнительных привилегированных инструкций). Плюс, таким образом обеспечивается удобный "скелет" ISA и программного инструментария, вокруг которого могут быть построены более специализированные ISA процессоров путем добавления дополнительных инструкций.
|
||||
The RISC-V architecture includes a mandatory minimum set of instructions — the **I** (Integer) instruction set. This set covers various integer arithmetic and logical operations, memory access, and control instructions. It is sufficient to support compilers, assemblers, linkers, and operating systems (provided that the required privileged instructions are also implemented). Furthermore, it provides a convenient "skeleton" ISA and software toolchain around which more specialized processor ISAs can be built by adding additional instructions.
|
||||
|
||||
Строго говоря RISC-V — это семейство родственных ISA, из которых в настоящее время существует четыре базовые ISA. Каждый базовый целочисленный набор инструкций характеризуется `шириной целочисленных регистров` и соответствующим `размером адресного пространства`, а также `количеством целочисленных регистров`. Существует два основных базовых целочисленных варианта, `RV32I` и `RV64I`, которые, соответственно, обеспечивают 32- или 64-битное адресное пространство и соответствующие размеры регистров регистрового файла. На основе базовой `RV32I` существует вариант подмножества `RV32E`, который был добавлен для поддержки небольших микроконтроллеров и имеет вдвое меньшее количество целочисленных регистров — 16, вместо 32. Разрабатывается вариант `RV128I` базового целочисленного набора инструкций, поддерживающий плоское 128-битное адресное пространство. Также, стоит подчеркнуть, что размеры регистров и адресного пространства, во всех перечисленных стандартных наборах инструкций, не влияют на размер инструкций — во всех случаях они кодируются 32-битными числами. То есть, и для `RV32I`, и для `RV64I` одна инструкция будет кодироваться 32 битами. Базовые целочисленные наборы команд используют представление знаковых целых чисел в дополнительном коде.
|
||||
Strictly speaking, RISC-V is a family of related ISAs, of which four base ISAs currently exist. Each base integer instruction set is characterized by the `width of integer registers` and the corresponding `address space size`, as well as the `number of integer registers`. There are two primary base integer variants, `RV32I` and `RV64I`, which provide 32-bit or 64-bit address spaces and correspondingly sized register file entries. Based on `RV32I`, there is a subset variant `RV32E`, added to support small microcontrollers, with half the number of integer registers — 16 instead of 32. A variant `RV128I` of the base integer instruction set is under development, supporting a flat 128-bit address space. It is also worth noting that register widths and address space sizes in all listed standard instruction sets do not affect instruction size — in all cases instructions are encoded as 32-bit words. That is, both `RV32I` and `RV64I` encode each instruction in 32 bits. The base integer instruction sets use two's complement representation for signed integers.
|
||||
|
||||
Кроме обязательного подмножества целочисленных инструкций, RISC-V предусматривает несколько стандартных опциональных расширений. Вот некоторые из них:
|
||||
In addition to the mandatory integer instruction subset, RISC-V defines several standard optional extensions. Some of them are:
|
||||
|
||||
- **M** — Целочисленное умножение и деление (Integer Multiplication and Division)
|
||||
- **A** — Атомарные операции (Atomic Instructions), инструкции для атомарного чтения-изменения-записи в память для межпроцессорной синхронизации
|
||||
- **F**, **D** — Расширения для арифметических операций над числами с плавающей точкой одинарной и двойной точности соответственно. Добавляют отдельный регистровый файл для чисел с плавающей точкой (с разрядностью ячеек 32/64 бит), а также инструкции для работы с этими числами.
|
||||
- **C** — Набор сжатых инструкций (Compressed Instructions), позволяющий кодировать инструкции 16-битными словами, что позволяет уплотнить программный код (если одну и ту же программу можно писать 16-битными словами вместо 32-битных, значит её размер сократится в 2 раза). Разумеется, у такого уплотнения есть своя цена, иначе инструкции просто кодировали бы 16-ю битами вместо 32. У сжатых инструкций меньший диапазон адресов и констант.
|
||||
- **Zicsr** — Инструкции для работы с контрольными и статусными регистрами (Control and Status Register (CSR) Instructions). Используется, например, при работе с прерываниями/исключениями и виртуальной памятью
|
||||
- **Zifencei** — Инструкции синхронизации потоков команд и данных (Instruction-Fetch Fence)
|
||||
- **M** — Integer Multiplication and Division
|
||||
- **A** — Atomic Instructions: instructions for atomic read-modify-write memory operations for inter-processor synchronization
|
||||
- **F**, **D** — Extensions for single- and double-precision floating-point arithmetic, respectively. They add a separate floating-point register file (with 32/64-bit cell widths) and instructions for working with those numbers.
|
||||
- **C** — Compressed Instructions: allows encoding instructions as 16-bit words, reducing code size (if the same program can be written with 16-bit words instead of 32-bit ones, its size is halved). Of course, this compaction comes at a cost — otherwise instructions would simply be encoded in 16 bits instead of 32. Compressed instructions have a smaller range of addresses and immediates.
|
||||
- **Zicsr** — Control and Status Register (CSR) Instructions. Used, for example, when working with interrupts/exceptions and virtual memory.
|
||||
- **Zifencei** — Instruction-Fetch Fence instructions
|
||||
|
||||
Поддерживаемые процессором команды отражаются в названии набора инструкций. Например, `RV64IMC` это архитектура RISC-V с 64-битными регистрами и 64-битным адресным пространством, поддерживающая кроме стандартных целочисленных операций умножение и деление **M**, и может выполнять сжатые инструкции **C**.
|
||||
The instructions supported by a processor are reflected in the instruction set name. For example, `RV64IMC` is a RISC-V architecture with 64-bit registers and a 64-bit address space, supporting standard integer operations plus integer multiplication and division **M**, and the ability to execute compressed instructions **C**.
|
||||
|
||||
Одной из целей проекта RISC-V является его использование в качестве стабильного объекта для разработки программного обеспечения. Для этого ее разработчики определили комбинацию базового ISA (`RV32I` или `RV64I`) и некоторых стандартных расширений (**IMAFD + Zicsr + Zifencei**) как "general-purpose" ISA (набор инструкций общего назначения), а для комбинации расширений набора команд **IMAFDZicsrZifencei** стали использовать аббревиатуру **G**. То есть `RV32G` это тоже самое, что и `RV32IMAFDZicsrZifencei`.
|
||||
One of the goals of the RISC-V project is to serve as a stable target for software development. To this end, its designers defined the combination of a base ISA (`RV32I` or `RV64I`) and certain standard extensions (**IMAFD + Zicsr + Zifencei**) as a "general-purpose" ISA, and adopted the abbreviation **G** for the extension combination **IMAFDZicsrZifencei**. That is, `RV32G` is equivalent to `RV32IMAFDZicsrZifencei`.
|
||||
|
||||
> Чтобы устройство управления понимало, когда оно имеет дело с набором сжатых команд **C**, то есть с 16-битными инструкциями, а когда с другими наборами команд, то есть с инструкциями длиной 32 бита, каждая 32-битная инструкция в младших битах имеет `11`. Если в двух младших битах что-то отличное от `11`, значит это 16-битная инструкция!
|
||||
> For the control unit to distinguish when it is dealing with the compressed instruction set **C** (i.e., 16-bit instructions) versus other instruction sets (i.e., 32-bit instructions), every 32-bit instruction has `11` in its two least significant bits. If the two least significant bits are anything other than `11`, it is a 16-bit instruction!
|
||||
|
||||
В рамках дисциплины АПС изучается базовая ISA `RV32I` и расширение для работы с регистрами контроля и статуса `Zicsr`, обеспечивающими поддержку подсистемы прерываний.
|
||||
Within the APS course, the base ISA `RV32I` and the CSR extension `Zicsr` are studied, providing support for the interrupt subsystem.
|
||||
|
||||
На _рис. 1_ показана видимая пользователю структура для основного подмножества команд для целочисленных вычислений `RV32I`, а также расширения `Zicsr`. Эта структура содержит `регистровый файл`, состоящий из 31 регистра общего назначения **x1** — **x31**, каждый из которых может содержать целочисленное значение, и регистра **x0**, жестко привязанного к константе 0. В случае `RV32`, регистры **xN**, и вообще все регистры, имеют длину в 32 бита. Кроме того, в структуре присутствует `АЛУ`, выполняющее операции над данными в регистровом файле, `память` с побайтовой адресацией и шириной адреса 32 бита, а также блок 32-битных регистров контроля и статуса с шириной адреса в 12 бит.
|
||||
_Fig. 1_ shows the user-visible state for the base integer subset `RV32I` and the `Zicsr` extension. This state includes a `register file` consisting of 31 general-purpose registers **x1** — **x31**, each of which can hold an integer value, and register **x0** hardwired to the constant 0. In `RV32`, registers **xN** and all other registers are 32 bits wide. The state also includes an `ALU` performing operations on register file data, `memory` with byte-addressable access and a 32-bit address bus, and a block of 32-bit control and status registers with a 12-bit address width.
|
||||
|
||||
Также существует еще один дополнительный видимый пользователю регистр: счетчик команд — `PC` (Program Counter), который содержит адрес текущей инструкции. `PC` изменяется либо автоматически, указывая на следующую инструкцию, либо в результате использования инструкций управления (операции условного и безусловного переходов).
|
||||
There is also one additional user-visible register: the program counter — `PC` (Program Counter), which holds the address of the current instruction. The `PC` is updated either automatically to point to the next instruction, or as a result of control-flow instructions (conditional and unconditional branches).
|
||||
|
||||

|
||||
|
||||
_Рисунок 1. Основные компоненты архитектуры RISC-V._
|
||||
_Figure 1. Main components of the RISC-V architecture._
|
||||
|
||||
Поскольку RISC-V является `Load & Store` архитектурой, все операции с числами выполняются только над данными в регистровом файле (если необходимо обработать данные из основной памяти, их необходимо сперва загрузить в регистровый файл (Load), а после обработки выгрузить обратно в основную память (Store)).
|
||||
Since RISC-V is a `Load & Store` architecture, all arithmetic and logical operations are performed only on data in the register file. If data from main memory needs to be processed, it must first be loaded into the register file (Load) and, after processing, stored back to main memory (Store).
|
||||
|
||||
Из _рисунка 1_ можно легко заключить, что функционально все инструкции сводятся к трём типам:
|
||||
From _Figure 1_, it is easy to conclude that all instructions functionally fall into three categories:
|
||||
|
||||
- операции на АЛУ над числами в регистровом файле или регистрах контроля и статуса;
|
||||
- операции обмена данными между регистровым файлом и памятью;
|
||||
- манипуляции с `pc` (другими словами — управление программой) или системой (через регистры контроля и статуса).
|
||||
- ALU operations on data in the register file or control and status registers;
|
||||
- data exchange operations between the register file and memory;
|
||||
- manipulations of `pc` (i.e., program control flow) or the system (via control and status registers).
|
||||
|
||||
Как было сказано ранее, память имеет 32-битную шину адреса и имеет побайтовую адресацию. Это значит, что каждый из 2<sup>32</sup> байт памяти имеет свой уникальный адрес, по которому к нему можно обратиться, чтобы считать из него или записать в него новую информацию. Однако, инструкции кодируются 32-битными числами, а один байт это всего 8 бит, значит одна инструкция занимает сразу 4 адреса в памяти. Подразумевается, что из такой памяти можно читать одновременно из нескольких последовательных адресов, то есть устройство управления процессора сообщает памяти начальный адрес требуемой ячейки, и количество ячеек (одну, две или четыре), которые нужно прочитать или записать.
|
||||
As mentioned earlier, memory has a 32-bit address bus and is byte-addressable. This means that each of the 2<sup>32</sup> bytes in memory has its own unique address, which can be used to read from or write to it. Since instructions are encoded as 32-bit words and one byte is only 8 bits, a single instruction occupies 4 consecutive byte addresses in memory. It is assumed that multiple consecutive addresses can be read at once — the processor's control unit tells the memory the starting address of the required cell and the number of cells (one, two, or four) to read or write.
|
||||
|
||||
Одна ячейка памяти, содержащая 8 бит называется `байт`. Две последовательные 8-битные ячейки называются `полусловом` — 16 бит. Четыре последовательные 8-битные ячейки называются `словом` — 32 бита. Если процессор собирается выполнить инструкцию, которая занимает четыре байта по адресам `0x00000007 — 0x00000004`, то он обращается к памяти, сообщая, что "нужны 4 байта начиная с адреса `0x00000004`", в ответ процессор получает 32-битное число — инструкцию, которая была "склеена" из байт, хранящихся в памяти по адресам: 4, 5, 6 и 7, для данного примера. К памяти также можно обратиться за полусловом или за байтом. Предполагается реализация выровненного доступа к памяти, то есть адреса слов и полуслов всегда должны быть кратны 4 и 2, соответственно.
|
||||
A single 8-bit memory cell is called a `byte`. Two consecutive 8-bit cells are called a `halfword` — 16 bits. Four consecutive 8-bit cells are called a `word` — 32 bits. If the processor is going to execute an instruction that occupies four bytes at addresses `0x00000007 — 0x00000004`, it accesses memory by requesting "4 bytes starting at address `0x00000004`", and in response receives a 32-bit number — the instruction assembled from bytes stored at addresses 4, 5, 6, and 7 in this example. Memory can also be accessed for a halfword or a byte. Aligned memory access is assumed, meaning word and halfword addresses must always be multiples of 4 and 2, respectively.
|
||||
|
||||
Аппаратное обеспечение компьютера «понимает» только нули и единицы, поэтому инструкции закодированы двоичными числами в формате, который называется машинным языком.
|
||||
Computer hardware "understands" only zeros and ones, so instructions are encoded as binary numbers in a format called machine language.
|
||||
|
||||
Инструкция компьютера кодирует в себе операцию, которую нужно исполнить, и данные, которые ей для этого потребуются. Такими данными могут быть адреса операндов и результата, различные константы.
|
||||
A computer instruction encodes the operation to be performed and the data required to perform it. Such data may include operand and result addresses, as well as various constants.
|
||||
|
||||
В архитектуре RISC-V каждая несжатая инструкция представлена 32-разрядным словом. Микропроцессоры — это цифровые системы, которые читают и выполняют команды машинного языка. Для людей чтение и разработка компьютерных программ на машинном языке представляются нудным и утомительным делом, поэтому мы предпочитаем представлять инструкции в символическом формате, который называется языком ассемблера[[2, стр. 360](https://reader.lanbook.com/book/241166?lms=3ec5abac958be145faed85c101d197fb)]. Ассемблер позволяет выполнить взаимно однозначный переход от машинного кода к тестовому и обратно.
|
||||
In the RISC-V architecture, each uncompressed instruction is represented as a 32-bit word. Microprocessors are digital systems that read and execute machine language instructions. Reading and writing computer programs in machine language is tedious and error-prone for humans, so instructions are preferably represented in a symbolic format called assembly language[[2, p. 360](https://reader.lanbook.com/book/241166?lms=3ec5abac958be145faed85c101d197fb)]. An assembler enables a one-to-one translation between machine code and text and back.
|
||||
|
||||
## RV32I
|
||||
|
||||
В _таблице 1_ приводятся 47 команд стандартного набора целочисленных инструкций `RV32I`: мнемоники языка ассемблера, функции, описания, форматы кодирования и значения соответствующих полей при кодировании. В RISC-V предусмотрено несколько форматов кодирования инструкций (_рис. 3_). Формат кодирования — это договоренность о том, какая информация в каком месте 32-битной инструкции хранится и как она представлена. У всех операций есть поле `opcode` (operation code - код операции), в котором закодировано "что нужно сделать". По полю `opcode` устройство управления понимает, что требуется сделать процессору и каким именно способом закодирована инструкция (**R**, **I**, **S**, **B**, **U** или **J**). В 32-битных инструкциях два младших бита всегда равны `11` (бывают 16-битные инструкции из набора сжатых инструкций).
|
||||
_Table 1_ lists the 47 instructions of the standard `RV32I` integer instruction set: assembly mnemonics, functions, descriptions, encoding formats, and the values of the corresponding fields during encoding. RISC-V defines several instruction encoding formats (_Fig. 3_). An encoding format is an agreement about what information is stored at which position within a 32-bit instruction and how it is represented. Every operation has an `opcode` (operation code) field that encodes "what needs to be done". Based on the `opcode` field, the control unit determines what the processor must do and which encoding format is used (**R**, **I**, **S**, **B**, **U**, or **J**). In 32-bit instructions, the two least significant bits are always `11` (16-bit instructions from the compressed instruction set are an exception).
|
||||
|
||||
Почти все инструкции имеют поле `func3`, и некоторые — поле `func7` (в зависимости от формата кодирования и некоторых исключений). Их названия определены разрядностью: 3 и 7 бит, соответственно. В этих полях, если они есть у инструкции, закодировано уточнение операции. Например, код операции `0010011` указывает на то, что будет выполняться некоторая операция на АЛУ между значением из регистрового файла и константой. Поле `func3` уточняет операцию, для данного примера, если оно будет равно 0x0, то АЛУ выполнит операцию сложения между значением из регистра и константой из инструкции. Если `func3` равно 0x6, то будет выполнена операция "логическое ИЛИ".
|
||||
Almost all instructions have a `funct3` field, and some have a `funct7` field (depending on the encoding format and certain exceptions). Their names reflect their bit widths: 3 and 7 bits, respectively. These fields, when present, encode a refinement of the operation. For example, opcode `0010011` indicates that some ALU operation will be performed between a register file value and a constant. The `funct3` field specifies the exact operation: if it equals 0x0, the ALU performs addition between the register value and the instruction constant; if `funct3` equals 0x6, a bitwise OR operation is performed.
|
||||
|
||||

|
||||
|
||||
_Таблица 1. Инструкции набора RV32I с приведением их типов, функционального описания и примеров использования._
|
||||
_Table 1. RV32I instruction set with types, functional descriptions, and usage examples._
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Обратите внимание на операции `slli`, `srli` и `srai` (операции сдвига на константную величину). У этих инструкций немного измененный формат кодирования **I\***. Формат кодирования **I** предоставляет 12-битную константу. Сдвиг 32-битного числа более, чем на 31 не имеет смысла. Для кодирования числа 31 требуется всего 5 бит. Выходит, что из 12 бит константы используется только 5 бит для операции сдвига, а оставшиеся 7 бит – не используются. А, главное (какое совпадение!), эти 7 бит находятся ровно в том же месте, где у других инструкций находится поле `func7`. Поэтому, чтобы у инструкций `slli`, `srli` и `srai` использующих формат **I** не пропадала эта часть поля, к ней относятся как к полю `func7`.
|
||||
> Note the `slli`, `srli`, and `srai` instructions (constant-shift operations). These instructions use a slightly modified **I\*** encoding format. The **I** encoding format provides a 12-bit immediate. Shifting a 32-bit number by more than 31 is meaningless. Encoding the number 31 requires only 5 bits. This means that of the 12 immediate bits, only 5 are used for the shift amount, and the remaining 7 bits are unused. And, crucially (what a coincidence!), these 7 bits are located in exactly the same position as the `funct7` field of other instructions. Therefore, to avoid wasting this part of the field for `slli`, `srli`, and `srai` — which use the **I** format — those bits are treated as the `funct7` field.
|
||||
|
||||
Таблица 2 является фрагментом оригинальной спецификации RISC-V[1, стр. 554](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf). Сверху приводятся 6 форматов кодирования инструкций: **R**, **I**, **S**, **B**, **U** и **J**, а ниже приводятся конкретные значения полей внутри инструкции. Под `rd` подразумевается 5-битный адрес регистра назначения, `rs1` и `rs2` - 5-битные адреса регистров источников, `imm` — константа, расположение и порядок битов которой указывается в квадратных скобках. Обратите внимание, что в разных форматах кодирования константы имеют различную разрядность, а их биты упакованы по-разному.
|
||||
Table 2 is a fragment of the original RISC-V specification[[1, p. 554](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf)]. The top part shows the 6 instruction encoding formats: **R**, **I**, **S**, **B**, **U**, and **J**, and the lower part shows the specific field values within each instruction. `rd` denotes the 5-bit destination register address, `rs1` and `rs2` are 5-bit source register addresses, and `imm` is an immediate value whose bit positions and order are indicated in square brackets. Note that in different encoding formats, immediates have different widths and their bits are packed differently.
|
||||
|
||||

|
||||
|
||||
_Таблица 2. Базовый набор инструкций RV32I._
|
||||
_Table 2. RV32I base instruction set._
|
||||
|
||||
На _рис. 2_, для наглядности, приводится пример кодирования пары инструкций из книги Харриса и Харриса "Цифровая схемотехника и архитектура компьютера RISC-V" в машинный код[[2, стр. 401](https://reader.lanbook.com/book/241166?lms=0477e9ee9acd7b9544b3ad74ba7e4dc5)].
|
||||
_Fig. 2_ shows, for illustration, an example of encoding a pair of instructions from Harris & Harris "Digital Design and Computer Architecture: RISC-V Edition" into machine code[[2, p. 401](https://reader.lanbook.com/book/241166?lms=0477e9ee9acd7b9544b3ad74ba7e4dc5)].
|
||||
|
||||

|
||||
|
||||
_Рисунок 2. Пример двоичного кодирования инструкций RISC-V._
|
||||
_Figure 2. Example of binary encoding of RISC-V instructions._
|
||||
|
||||
Примечание: `s2`, `s3`, `s4`, `t0`, `t1`, `t2` — это синонимы регистров `x18`, `x19`, `x20`, `x5`, `x6`, `x7` соответственно. Введены **соглашением о вызовах** (calling convention) для того, чтобы стандартизировать функциональное назначение регистров. Подробнее об этом будет в лабораторной работе по программированию.
|
||||
Note: `s2`, `s3`, `s4`, `t0`, `t1`, `t2` are aliases for registers `x18`, `x19`, `x20`, `x5`, `x6`, `x7`, respectively. These aliases are defined by the **calling convention** to standardize the functional purpose of registers. More details will be covered in the programming lab.
|
||||
|
||||
## Псевдоинструкции
|
||||
## Pseudo-instructions
|
||||
|
||||
В архитектуре RISC-V размер команд и сложность аппаратного обеспечения минимизированы путем использования лишь небольшого количества инструкций. Тем не менее RISC-V определяет псевдоинструкции, которые на самом деле не являются частью набора команд, но часто используются программистами и компиляторами. При преобразовании в машинный код псевдоинструкции транслируются в одну или несколько инструкций RISC-V[[2, стр. 399](https://reader.lanbook.com/book/241166?lms=7329d34bdab9c539e3ec7a571ee68929)]. Например, псевдоинструкция безусловного перехода `j`, преобразуется в инструкцию безусловного перехода с возвратом `jal` с регистром `x0` в качестве регистра-назначения, то есть адрес возврата не сохраняется.
|
||||
In the RISC-V architecture, instruction count and hardware complexity are minimized by using a small number of instructions. Nevertheless, RISC-V defines pseudo-instructions, which are not actually part of the instruction set but are commonly used by programmers and compilers. When translated to machine code, pseudo-instructions are converted into one or more RISC-V instructions[[2, p. 399](https://reader.lanbook.com/book/241166?lms=7329d34bdab9c539e3ec7a571ee68929)]. For example, the unconditional jump pseudo-instruction `j` is translated into the jump-and-link instruction `jal` with register `x0` as the destination, meaning the return address is not saved.
|
||||
|
||||

|
||||
|
||||
_Таблица 3. Список псевдоинструкций RISC-V._
|
||||
_Table 3. List of RISC-V pseudo-instructions._
|
||||
|
||||
## Основные типы команд
|
||||
## Base Instruction Formats
|
||||
|
||||
В основе ISA лежит четыре основных типа команд (R/I/S/U), которые изображены на _рис. 3_. Все они имеют фиксированную длину в 32 бита и должны быть выровнены в памяти по четырехбайтовой границе. Если адрес перехода (в случае безусловного перехода, либо успешного условного перехода) не выровнен, генерируется исключение о невыровненном адресе инструкции. Исключение не генерируется в случае невыполненного условного перехода.
|
||||
The ISA is built on four base instruction formats (R/I/S/U), shown in _Fig. 3_. All of them have a fixed length of 32 bits and must be aligned in memory on a four-byte boundary. If a branch target address (in the case of an unconditional branch or a taken conditional branch) is not aligned, an instruction address misaligned exception is generated. No exception is generated for a not-taken conditional branch.
|
||||
|
||||

|
||||
|
||||
_Рисунок 3. Типы кодирования инструкций RISC-V._
|
||||
_Figure 3. RISC-V instruction encoding formats._
|
||||
|
||||
Для упрощения декодирования, архитектура команд RISC-V сохраняет положение адресов регистров-источников (`rs1` и `rs2`) и регистра назначения (`rd`) между всеми типами инструкций.
|
||||
To simplify decoding, the RISC-V instruction encoding keeps the positions of the source register addresses (`rs1` and `rs2`) and the destination register address (`rd`) consistent across all instruction formats.
|
||||
|
||||
За исключением 5-битных непосредственных операндов, используемых в командах CSR, все непосредственные операнды (`imm`) проходят знаковое расширение. Для уменьшения сложности аппаратуры, константа размещается в свободные (от полей `func3`/`func7`/`rs1`/`rd`) биты инструкции, начиная от левого края. В частности, благодаря этому ускоряется схема знакового расширения, поскольку знаковый бит всех непосредственных операндов всегда находится в 31-ом бите инструкции.
|
||||
With the exception of the 5-bit immediates used in CSR instructions, all immediate operands (`imm`) are sign-extended. To reduce hardware complexity, the immediate is placed in the bits of the instruction that are not occupied by `funct3`/`funct7`/`rs1`/`rd` fields, starting from the most significant bit. In particular, this speeds up the sign-extension logic, since the sign bit of all immediates is always located at bit 31 of the instruction.
|
||||
|
||||
### Способы кодирования непосредственных операндов
|
||||
### Immediate Encoding Variants
|
||||
|
||||
Существует еще два формата кодирования констант в инструкции (**B**/**J**-типа), представленные на _рис. 4_.
|
||||
There are two additional immediate encoding formats (**B**/**J**-type), shown in _Fig. 4_.
|
||||
|
||||
Единственное различие между форматами **S** и **B** заключается в том, что в формате **B**, 12-битная константа используется для кодирования кратных двум смещений адреса при ветвлении (примечание: кратность двум обеспечивается сдвигом числа на 1 влево). Вместо того, чтобы сдвигать непосредственный операнд относительно всех бит инструкции на 1 влево, средние биты (`imm[10:1]`) и знаковый бит остаются в прежних местах, а оставшийся младший бит константы формата **S** (`inst[7]`) кодирует `imm[11]` бит константы в формате **B**.
|
||||
The only difference between the **S** and **B** formats is that in the **B** format, the 12-bit immediate encodes branch address offsets that are multiples of two (note: the factor-of-two alignment is achieved by shifting the value left by 1). Instead of shifting the immediate relative to all instruction bits by 1 to the left, the middle bits (`imm[10:1]`) and the sign bit remain in their original positions, and the remaining least significant bit of the **S**-format immediate (`inst[7]`) encodes the `imm[11]` bit of the **B**-format immediate.
|
||||
|
||||
Аналогично, единственное различие между форматами **U** и **J** состоит в том, что в формате **U** 20-разрядная константа сдвигается влево на 12 бит, в то время как в формате **J** — на 1. Расположение бит в непосредственных значениях формата **U** и **J** выбирались таким образом, чтобы максимально увеличить перекрытие с другими форматами и между собой.
|
||||
Similarly, the only difference between the **U** and **J** formats is that in the **U** format, the 20-bit immediate is shifted left by 12 bits, whereas in the **J** format it is shifted left by 1. The bit positions of the **U** and **J** immediates were chosen to maximize overlap with other formats and with each other.
|
||||
|
||||

|
||||
|
||||
_Рисунок 4. Кодирование констант в инструкциях B и J типа._
|
||||
_Figure 4. Immediate encoding in B- and J-type instructions._
|
||||
|
||||
На _рис. 5_ показаны непосредственные значения (константы), создаваемые каждым из основных форматов команд, также они помечены, чтобы показать, какой бит команды (`inst[y]`) какому биту непосредственного значения соответствует.
|
||||
_Fig. 5_ shows the immediate values (constants) produced by each base instruction format, annotated to indicate which instruction bit (`inst[y]`) corresponds to which bit of the immediate value.
|
||||
|
||||

|
||||
|
||||
_Рисунок 5. Иллюстрация общих частей при кодировании констант различных типов инструкций._
|
||||
_Figure 5. Illustration of shared bit positions in immediate encoding across instruction types._
|
||||
|
||||
> Знаковое расширение — одна из самых важных операций над непосредственными значениями (особенно в `RV64I`). Поэтому в RISC-V знаковый бит всех непосредственных значений всегда содержится в 31-м бите инструкции. Это позволяет выполнять знаковое расширение параллельно с декодированием команды.
|
||||
> Sign extension is one of the most critical operations on immediates (especially in `RV64I`). Therefore, in RISC-V the sign bit of all immediates is always located at bit 31 of the instruction. This allows sign extension to be performed in parallel with instruction decoding.
|
||||
>
|
||||
> Несмотря на то, что более сложные микроархитектурные реализации имеющие отдельные сумматоры для вычисления адресов условных и безусловных переходов, могут не получить выигрыш от одинакового расположения битов непосредственных значений во всех типах команд, прежде всего мы хотели снизить аппаратные затраты для простейших реализаций.
|
||||
> Although more complex microarchitectural implementations with separate adders for branch and jump address calculation may not benefit from having immediate bits placed identically across instruction types, the primary goal was to reduce hardware cost for the simplest implementations.
|
||||
>
|
||||
> Меняя местами биты в кодировке непосредственных значений инструкций **B** и **J**-типа вместо использования динамических мультиплексоров для умножения константы на 2, мы уменьшили разветвленность сигнала команды и затраты на мультиплексирование примерно в 2 раза. Скремблированное кодирование непосредственных значений добавит незначительную задержку при статической компиляции. Для динамической генерации инструкций есть небольшие дополнительные издержки, однако для наиболее частых коротких ветвлений вперед предусмотрено простое кодирование непосредственных значений.
|
||||
> By rearranging bits in the immediates of **B**- and **J**-type instructions instead of using dynamic multiplexers to multiply the constant by 2, the instruction signal fanout and multiplexing overhead were reduced by approximately a factor of two. The scrambled immediate encoding adds negligible delay during static compilation. For dynamic instruction generation, there is a small additional overhead, but simple encoding of immediates is provided for the most common short forward branches.
|
||||
|
||||
### Команды для целочисленных вычислений
|
||||
### Integer Computational Instructions
|
||||
|
||||
Большинство инструкций целочисленных вычислений работают с 32-битными значениями, хранящимся в регистровом файле. Такие команды либо кодируются как операции `константа-регистр`, используя формат **I**-типа, либо как операции `регистр-регистр`, используя формат **R**-типа. В обоих случаях результат сохраняется в регистр `rd` . Ни одна инструкция целочисленных вычислений не вызывает арифметических исключений.
|
||||
Most integer computational instructions operate on 32-bit values held in the register file. These instructions are either encoded as `immediate-register` operations using the **I**-type format, or as `register-register` operations using the **R**-type format. In both cases, the result is written to register `rd`. None of the integer computational instructions cause arithmetic exceptions.
|
||||
|
||||
> Мы не стали добавлять поддержку специального набора команд для проверок на переполнение целочисленных арифметических операций в основной набор команд, поскольку многие проверки на переполнение могут быть достаточно дешево реализованы в RISC-V с использованием инструкций ветвления. Проверка на переполнение для беззнакового сложения требует только одной дополнительной команды перехода после сложения:
|
||||
> We did not add support for a special set of instructions for detecting overflow in integer arithmetic operations in the base instruction set, since many overflow checks can be implemented quite cheaply in RISC-V using branch instructions. Overflow detection for unsigned addition requires only one additional branch instruction after the addition:
|
||||
>
|
||||
> ```asm
|
||||
> add t0, t1, t2
|
||||
> bltu t0, t1, overflow
|
||||
> ```
|
||||
>
|
||||
> Для знакового сложения, если известен знак одного операнда, проверка на переполнение требует только одного ветвления после сложения:
|
||||
> For signed addition, if the sign of one operand is known, overflow checking requires only one branch after the addition:
|
||||
>
|
||||
> ```asm
|
||||
> addi t0, t1, + imm
|
||||
> blt t0, t1, overflow
|
||||
> ```
|
||||
>
|
||||
> Этот метод в общем случае подходит при сложении с непосредственным операндом. В остальных случаях при знаковом сложении требуются три дополнительные команды после сложения, использующих утверждение, что сумма должна быть меньше, чем один из операндов, тогда и только тогда, когда другой операнд отрицателен.
|
||||
> This approach is generally applicable when adding an immediate operand. In the general case of signed addition, three additional instructions are needed after the add, using the assertion that the sum must be less than one of the operands if and only if the other operand is negative.
|
||||
>
|
||||
> ```asm
|
||||
> add t0, t1, t2
|
||||
@@ -158,51 +158,52 @@ _Рисунок 5. Иллюстрация общих частей при код
|
||||
> bne t3, t4, overflow
|
||||
> ```
|
||||
>
|
||||
> В RV64 проверки 32-разрядных знаковых сложений могут быть дополнительно оптимизированы путем сравнения результатов выполнения команд ADD и ADDW для каждого из операндов.
|
||||
> In RV64, checks for 32-bit signed addition overflow can be further optimized by comparing the results of the ADD and ADDW instructions for each operand.
|
||||
|
||||
### Команда типа константа-регистр
|
||||
### Immediate-Register Instructions
|
||||
|
||||

|
||||
|
||||
`ADDI` суммирует знакорасширенную 12-битную константу с регистром `rs1`. Арифметическое переполнение игнорируется, и результатом являются младшие 32 бита результата. Команда `ADDI rd, rs1, 0` используется для реализации ассемблерной псевдоинструкции `MV rd, rs1`.
|
||||
`ADDI` adds a sign-extended 12-bit immediate to register `rs1`. Arithmetic overflow is ignored, and the result is the lower 32 bits of the sum. The instruction `ADDI rd, rs1, 0` is used to implement the assembly pseudo-instruction `MV rd, rs1`.
|
||||
|
||||
`SLTI` (установить, если меньше, чем константа) помещает значение 1 в регистр `rd`, если регистр `rs1` меньше, чем расширенное непосредственное значение, когда оба значения обрабатываются как знаковые числа, иначе в `rd` записывается 0. `SLTIU` аналогична, но сравнивает значения как беззнаковые числа (то есть непосредственное значение сначала расширяется до 32 бит, а затем обрабатывается как число без знака). Обратите внимание, что команда `SLTIU rd, rs1, 1` устанавливает `rd` в 1, если `rs1` равен нулю, в противном случае `rd` устанавливается в 0 (псевдоинструкция ассемблера `SEQZ rd, rs`).
|
||||
`SLTI` (Set Less Than Immediate) writes 1 to register `rd` if register `rs1` is less than the sign-extended immediate, treating both values as signed numbers; otherwise, 0 is written to `rd`. `SLTIU` is similar but compares values as unsigned numbers (i.e., the immediate is first sign-extended to 32 bits and then treated as an unsigned number). Note that `SLTIU rd, rs1, 1` sets `rd` to 1 if `rs1` equals zero, otherwise `rd` is set to 0 (assembly pseudo-instruction `SEQZ rd, rs`).
|
||||
|
||||
Примечание: у студентов часто возникает вопрос: зачем вообще нужны инструкции вида `SLT`, если есть инструкции вида `BLT`? Например, они могут использоваться для вычисления сложных условий переходов. Один из примеров таких условий вы видели выше, в примере обработке результата сложения на переполнение. Кроме того, несмотря на ограниченность этих инструкций (все они проверяют только на **строго меньше**), мы можем добиться операции **строго больше** поменяв операнды местами, а если результат обоих операций даст `0` — значит операнды равны. Поскольку идея RISC архитектуры в том, чтобы переложить организацию всех этих ухищрений на компилятор, этих инструкций оказывается достаточно.
|
||||
Note: students often ask why instructions like `SLT` are needed if there are instructions like `BLT`. For example, they can be used to evaluate complex branch conditions. One such example was shown above in the overflow detection example. Additionally, despite their apparent limitation (all of them check only for **strictly less than**), the **strictly greater than** condition can be achieved by swapping the operands, and if both operations return `0` — the operands are equal. Since the idea of a RISC architecture is to delegate the organization of all such tricks to the compiler, these instructions are sufficient.
|
||||
|
||||
`ANDI`, `ORI`, `XORI` — это логические операции, которые выполняют побитовое И, ИЛИ и исключающее ИЛИ над регистром `rs1` и непосредственным 12-битным значением с знаковым расширением и помещают результат в `rd`. Обратите внимание, что команда `XORI rd, rs, -1` выполняет побитовую логическую инверсию значения регистра `rs1` (псевдоинструкция `NOT rd, rs`).
|
||||
`ANDI`, `ORI`, `XORI` are logical operations that perform bitwise AND, OR, and XOR between register `rs1` and a sign-extended 12-bit immediate, placing the result in `rd`. Note that `XORI rd, rs, -1` performs a bitwise logical inversion of register `rs1` (pseudo-instruction `NOT rd, rs`).
|
||||
|
||||

|
||||
|
||||
Сдвиги на константу кодируются как разновидность формата команд **I**-типа. Операнд, который должен быть сдвинут, находится в `rs1`, а величина сдвига кодируется в младших 5 битах поля непосредственного значения. Тип сдвига вправо определяется 30-ым битом. `SLLI` - логический сдвиг влево (нули задвигаются в младшие биты); `SRLI` - логический сдвиг вправо (нули задвигаются в старшие биты); `SRAI` - арифметический сдвиг вправо (исходный знаковый бит задвигается в старшие биты).
|
||||
Shifts by a constant are encoded as a specialization of the **I**-type instruction format. The operand to be shifted is in `rs1`, and the shift amount is encoded in the lower 5 bits of the immediate field. The type of right shift is determined by bit 30. `SLLI` — logical shift left (zeros are shifted into the low-order bits); `SRLI` — logical shift right (zeros are shifted into the high-order bits); `SRAI` — arithmetic shift right (the original sign bit is shifted into the high-order bits).
|
||||
|
||||

|
||||
|
||||
`LUI` (загрузка старшей части непосредственного значения) используется для получения 32-битных констант и использует формат **U**-типа. `LUI` помещает непосредственное значение **U**-типа в старшие 20 бит регистра назначения `rd`, заполняя младшие 12 бит нулями.
|
||||
`AUIPC` (прибавить старшую часть непосредственного значения к `pc`) используется для построения адресов относительно `pc`, и использует формат **U**-типа. `AUIPC` формирует 32-битное смещение из 20-битного непосредственного значения **U**-типа, заполняя младшие 12 битов нулями, прибавляет это смещение к значению `pc`, а затем размещает результат в регистре `rd`.
|
||||
`LUI` (Load Upper Immediate) is used to build 32-bit constants and uses the **U**-type format. `LUI` places the **U**-type immediate into the upper 20 bits of destination register `rd`, filling the lower 12 bits with zeros.
|
||||
|
||||
> Команда `AUIPC` поддерживает последовательности из двух команд для получения произвольных смещений `pc` как для передачи потока управления, так и для доступа к данным. Комбинация `AUIPC` и 12-битного непосредственного значения в `JALR` может передавать управление на любой 32-битный адрес `pc`, в то время как `AUIPC` сложенное с 12-битным непосредственным значением смещения в обычных командах загрузки или сохранения позволяет получить доступ к любому 32-битному адресу данных относительно `pc`.
|
||||
>Текущее значение `pc` можно получить, установив непосредственное значение **U**-типа в 0. Несмотря на то, что команда `JAL+4` также позволяет получить значение `pc`, она может вызывать остановки конвейера в более простых микроархитектурах или засорять структуры буфера предсказания переходов (BTB) в более сложных микроархитектурах.
|
||||
`AUIPC` (Add Upper Immediate to PC) is used to build PC-relative addresses and uses the **U**-type format. `AUIPC` forms a 32-bit offset from the 20-bit **U**-type immediate, fills the lower 12 bits with zeros, adds this offset to the value of `pc`, and places the result in register `rd`.
|
||||
|
||||
### Команды типа регистр-регистр
|
||||
> The `AUIPC` instruction supports two-instruction sequences for obtaining arbitrary PC-relative offsets for both control-flow transfers and data accesses. The combination of `AUIPC` and the 12-bit immediate in `JALR` can transfer control to any 32-bit PC address, while `AUIPC` added to the 12-bit offset immediate in ordinary load or store instructions allows access to any 32-bit data address relative to `pc`.
|
||||
> The current value of `pc` can be obtained by setting the **U**-type immediate to 0. Although `JAL+4` also allows obtaining the `pc` value, it may cause pipeline stalls in simpler microarchitectures or pollute branch prediction buffer (BTB) structures in more complex ones.
|
||||
|
||||
В `RV32I` определено несколько арифметических операций **R**-типа. Все операции берут исходные операнды из регистров `rs1` и `rs2` и записывают результат в регистр `rd`. Полями `funct7` и `funct3` задается тип операции.
|
||||
### Register-Register Instructions
|
||||
|
||||
`RV32I` defines several **R**-type arithmetic operations. All operations take source operands from registers `rs1` and `rs2` and write the result to register `rd`. The operation type is specified by the `funct7` and `funct3` fields.
|
||||
|
||||

|
||||
|
||||
`ADD` и `SUB` выполняют сложение и вычитание соответственно. Переполнения игнорируются, и младшие 32 бита результатов записываются в место назначения. `SLT` и `SLTU` выполняют знаковое и беззнаковое сравнения соответственно, записывая 1 в `rd`, если `rs1 < rs2`, или 0 в противном случае. Обратите внимание, что команда `SLTU rd, x0, rs2` устанавливает `rd` в 1, если `rs2` не равно нулю, иначе устанавливает `rd` в ноль (псевдоинструкция ассемблера `SNEZ rd, rs`). `AND`, `OR` и `XOR` выполняют побитовые логические операции.
|
||||
`ADD` and `SUB` perform addition and subtraction, respectively. Overflows are ignored, and the lower 32 bits of the results are written to the destination. `SLT` and `SLTU` perform signed and unsigned comparisons, respectively, writing 1 to `rd` if `rs1 < rs2`, or 0 otherwise. Note that `SLTU rd, x0, rs2` sets `rd` to 1 if `rs2` is non-zero, otherwise sets `rd` to zero (assembly pseudo-instruction `SNEZ rd, rs`). `AND`, `OR`, and `XOR` perform bitwise logical operations.
|
||||
|
||||
`SLL`, `SRL` и `SRA` выполняют соответственно логический сдвиг влево, логический сдвиг вправо и арифметический сдвиг вправо значения в регистре `rs1` на величину сдвига, содержащуюся в младших 5 битах регистра `rs2`.
|
||||
`SLL`, `SRL`, and `SRA` perform logical left shift, logical right shift, and arithmetic right shift, respectively, on the value in register `rs1` by the shift amount contained in the lower 5 bits of register `rs2`.
|
||||
|
||||
### Команда NOP
|
||||
### NOP Instruction
|
||||
|
||||

|
||||
|
||||
Инструкция `NOP` не изменяет **архитектурное состояние** процессора, за исключением увеличения `pc` и опциональных счетчиков производительности. `NOP` кодируется как `ADDI x0, x0, 0`.
|
||||
The `NOP` instruction does not change any **architectural state** of the processor, except for advancing `pc` and optional performance counters. `NOP` is encoded as `ADDI x0, x0, 0`.
|
||||
|
||||
> Команды `NOP` могут быть использованы для выравнивания сегментов кода по микроархитектурно значимым границам адресов или для резервирования места для модификаций встраиваемого кода. Хотя существует множество возможных способов кодирования `NOP`, мы использовали каноническое кодирование `NOP`, чтобы обеспечить возможность микроархитектурной оптимизации, а также для более читаемого вывода при дизассемблировании.
|
||||
> `NOP` instructions can be used to align code segments to microarchitecturally significant address boundaries or to reserve space for modifications to inline code. Although there are many possible encodings of `NOP`, the canonical `NOP` encoding is used to enable microarchitectural optimizations and to produce more readable disassembly output.
|
||||
|
||||
## Список использованной литературы
|
||||
## References
|
||||
|
||||
1. [The RISC-V Instruction Set Manual Volume I: Unprivileged ISA, Document Version 20240411, Editors Andrew Waterman and Krste Asanović, RISC-V Foundation, April 2024](https://github.com/riscv/riscv-isa-manual/releases/download/20240411/unpriv-isa-asciidoc.pdf);
|
||||
2. [Д.М. Харрис, С.Л. Харрис / Цифровая схемотехника и архитектура компьютера: RISC-V / пер. с англ. В. С. Яценков, А. Ю. Романов; под. ред. А. Ю. Романова / М.: ДМК Пресс, 2021](https://e.lanbook.com/book/241166).
|
||||
2. [D.M. Harris, S.L. Harris / Digital Design and Computer Architecture: RISC-V Edition / M.: DMK Press, 2021](https://e.lanbook.com/book/241166).
|
||||
|
||||
Reference in New Issue
Block a user