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

Набор непривилегированных инструкций RISC-V

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

Первые две инструкции записывают в регистр x1 значение 0x10000000. Для этого в регистр x1 записывается число 1, после чего сдвигается влево на 28 позиций, в результате чего в регистр x1 формируется значение 0x10000000. Третья инструкция загружает байт из памяти по адресу, задаваемому регистром x1.

Синтаксис вызова этой команды следующий: lb rd, imm(rs1). Это можно развернуть в следующее представление: rd = M[rs1+imm][7:0]. Значение одного байта, задаваемого конструкций bits[7:0], загружается в регистра, определяемый как rd (register destination) из памяти по адресу, взятому из регистра, определяемого как rs1 (Register Source), к которому добавляется непосредственное значение смещения imm.

Из приведённого примера видно, что задавать адрес в регистре с использованием описанных инструкций довольно неудобно. Для исправления этого был разработан ряд инструкций U-формата (U-Format, Upper) (Табл.3.7):

Таблица 3.7.
Инструкция Имя Формат Код funct3 Описание
lui Load Upper Imm. U 0110111 - rd = imm << 12
auipc Add Upper Imm. to PC U 0010111 - rd = PC + (imm << 12)

Инструкция lui rd, imm задаёт значение регистра, определяемого как rd, равным непосредственному значению imm, сдвинутому на 12 бит влево. А инструкция auipc rd, imm устанавливает значение регистра, определяемого как rd, в результат сложения значения регистра программного счётчика PC и непосредственного значения imm, сдвинутого влево на 12 бит.

Разберём следующий пример:

Адрес    Машинный код   Значение	           Комментарий
0x0      0x100000b7	     lui   x1, 0x10000  Загружает 0x10000000 в регистр x1
0x4      0x10000117	     auipc x2, 0x10000  Загружает 0x10000004 в регистр x2

Инструкция lui x1, 0x10000 задаёт регистру x1 значение 0x10000 << 12, таким образом, x1 = 0x10000000, поскольку сдвиг влево на 12 бит "добавляет" три нуля в шестнадцатеричном представлении. Инструкция auipc x2, 0x10000 устанавливает содержимое регистра x2 равным сумме текущего значения PC (счётчика команд), которое в данный момент равно 0x04 с прибавленным значением 0x10000 << 12. Таким образом, значение регистра x2 после выполнения этого кода будет равно 0x10000004.

Управление

Каждая из предыдущих рассмотренных инструкций устанавливает программный счётчик PC на адрес следующей инструкции, расположенной в памяти: pc = pc + 4. Для реализации возможности контроля за процессом исполнения используются инструкции B-формата (B-Format, Branching), которые реализуют механизм ветвления. Они используются для условного перехода к инструкции, адрес которой указывается непосредственно в составе соответствующих команд в случае, если условие выполняется (Табл.3.8):

Таблица 3.8.
Инструкция Тип Формат Код funct3 Описание
beq Branch == B 1100011 0x0 if (rs1 == rs2) pc+=imm
bne Branch != B 1100011 0x1 If (rs1 != rs2) pc+=imm
blt Branch < B 1100011 0x4 if (rs1 < rs2) pc+=imm
bge Branch >= B 1100011 0x5 if (rs1 >= rs2) pc+=imm
bltu Branch < Un. B 1100011 0x6 if (rs1 < rs2) pc+=imm
bleu Branch >= Un. B 1100011 0x7 if (rs1 >= rs2) pc+=imm

Инструкция ветвления сравнивает значения регистров rs1 и rs2 способом, определяемым самой инструкцией. Если условие истинно, программный счётчик увеличивается на непосредственное значение imm. В выражении blt rs1, rs2, imm проверяется, что rs1 меньше, чем rs2, и если это так, программный счётчик PC изменяется следующим образом: pc = pc + imm. В противном случае он принимает значение адреса следующей инструкции в памяти (pc = pc +4).

Инструкции blt и bge учитывают знак числа, инструкции bltu и bleu - нет, воспринимают числа как беззнаковые.

Рассмотрим пример:

Адрес    Машинный код   Значение           Комментарий
0x00     0xffb00093     addi x1, x0, -5    x1 = -5
0x04     0x00500113     addi x2, x0, 5     x2 = 5
0x08     0x0020c463     blt  x1, x2, 0x8   if (x1 < x2) pc = pc + 8 
0x0c     0x00100193     addi x3, x0, 1     skipped if (x1 < x2): x3 = 1
0x10     0x00200193     addi x3, x0, 2     x3 = 2

Инструкция по адресу 0x08 проверяет условие, что x1 < x2, то есть -5 < 5. Поскольку выражение истинно, программный счётчик устанавливается в значение 0x10 и инструкция по адресу 0x0c пропускается (не выполняется). Если бы инструкция по адресу 0x08 была bltu, отрицательное значение, хранящиеся в регистре x1 (-5) интерпретировалось бы как положительное значение, равное 0xFFFFFFFB (представление положительного числа, в двоичном коде идентичного отрицательному числу -5), а значит условие бы не выполнилось.

Помимо инструкций для условного перехода, есть инструкции для безусловного перехода: jalr и jal. Эти инструкции позволяют переходить на требуемый адрес путём модификации программного счётчика PC, однако при этом сохраняют адрес возврата, который равен PC+4 на момент вызова инструкции. Такой подход позволяет вернуться в то место, откуда произошёл переход. Именно так реализуется модульность разрабатываемых программ.

Инструкции записываются в разных форматах (Табл.3.9):

Таблица 3.9.
Инструкция Тип Формат Код funct3 Описание
jal Jump and Link J 1101111 - rd = PC+4; PC += imm
jalr Jump and Link Register I 1100111 0x0 rd = PC+4; PC = rs + imm

Инструкция jal rd, imm добавляет непосредственное значение к программному счётчику PC, PC += imm, и пишет адрес инструкции, следующей за jal в регистр, задаваемый как rd. Инструкция jalr rd, rs, imm устанавливает программный счётчик в значение, равное результату сложения регистра, задаваемого как rs, и непосредственного значения imm, pc = rs + imm, и пишет адрес возврата в регистр, задаваемый как rd.

Рассмотрим пример:

Адрес     Машинный код      Значение         Комментарий
0x00      0x00c000ef        jal x1,0xc       set pc to 0x0 + 0xc = 0xc, 
                                             x1 = pc + 4 = 0x4
0x04      0x00000013        addi x0, x0, 0   no operation
0x08      0x00010093        addi x1, x2, 0   set x1 = x2
0x0c      0x00008167        jalr x2, x1, 0   set pc to x1, 
                                             x2 = pc + 4 = 0x10
0x10      0x00100093        addi x1, x0, 1   x1 = 1

Программа работает следующим образом. Она начинается с инструкции jal x1, 0xc, которая расположена по адресу 0x00. В результате своего выполнения адрес возврата пишется в регистр x1 (следующая инструкция за инструкцией по адресу 0x00 размещается по адресу 0x04, именно это число помещается в регистр x1) и осуществляется переход по адресу 0x0c. По адресу 0x0c размещается инструкция jalr x2, x1, 0, которая пишет уже свой адрес возврата (значение 0x10) в регистр x2 и осуществляет переход по адресу, который лежит в регистре x1 (там размещается адрес возврата для первого выполненного перехода, это адрес 0x04). Программа продолжает выполняться и исполняется инструкция, расположенная по адресу 0x04, которая ничего не делает. Следующая за ней инструкция, расположенная по адресу 0x08) записывает значение 0x10 (адрес возврата для команды jalr) в регистр x1. После этого, вторая итерация выполнения команды jalr по адресу 0xc передаёт управление по адресу 0x10 (значение регистра x1). Итого, программный счётчик PC последовательного принимает следующие значения: 0x00, 0x0c, 0x04, 0x08, 0x0c, и 0x10.

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