Как добавить новую пользовательскую инструкцию в набор команд RISCV
В течение многих дней я пытался смоделировать новые пользовательские инструкции с помощью симулятора RISV ISA, но не смог создать новую инструкцию и скомпилировать ее с помощью ассемблера riscv. Я попытался добавить свой новый код операции в утилиты риск-инструменты / риск-операции / коды операций. Я попытался создать собственный код операции для выполнения функции ADD, а затем заменил ADD моей собственной инструкцией в коде сборки, но ассемблер не смог скомпилировать его, сказав, что инструкция не найдена. Также, когда я пытаюсь использовать встроенные пользовательские инструкции custom0,1,2, я всегда получаю ошибку недопустимых операндов.
1 ответ
Вы можете обратиться к следующему руководству о том, как добавить новые инструкции в компилятор RISCV: https://nitish2112.github.io/post/adding-instruction-riscv/
Однако некоторые шаги имеют незначительные изменения, вероятно, из-за недавних обновлений компилятора, поэтому я снова укажу шаги с обновленными изменениями в этом ответе. Я предполагаю, что путь к рабочему каталогу, который мы используем, равен . Допустим, мы добавим инструкцию по модулю, аналогичную учебнику. Инструкция по модулю и ее семантика в соответствии с приведенным выше руководством:
mod r1, r2, r3
R[r1] = R[r2] % R[r3]
Шаг 0: перейдите в ваш рабочий каталог, который я назову:
cd ~/dir/
Шаг 1: Скопируйте RISCV-GNU-Toolchain в свой рабочий каталог (или~/dir/
как мы называли ранее), если вы еще этого не сделали. Для этого вы можете использовать команду:
$ git clone https://github.com/riscv-collab/riscv-gnu-toolchain.git
Шаг 2: Установите и соберите инструменты riscv, используя следующие команды.
$ git clone https://github.com/riscv/riscv-tools.git
$ git submodule update --init --recursive
$ export RISCV=/path/to/install/riscv/toolchain
$ ./build.sh
Шаг 3: откройте файл~/dir/riscv-tools/riscv-opcodes/opcodes
и добавьте следующую строку:
mod rd rs1 rs2 31..25=1 14..12=0 6..2=0x1A 1..0=3
Объяснение этой строки: Инструкция по модулю, которую мы пытаемся добавить, имеет три регистра: регистр назначения, исходный регистр 1 и исходный регистр 2. Это означает, что эта инструкция соответствует формату R-типа в соответствии с руководством RISCV, которое можно найти здесь: https://riscv.org/wp-content/uploads/2017/05/riscv-spec-v2.2.pdf
Глядя на формат R-типа на рисунке ниже, биты с 31 по 25 определяют FUNCT7, а биты с 14 по 12 определяют FUNCT3. Теперь я не уверен, почему это отличается от руководства, но биты с 6 по 2 являются кодом операции, а не с 6 по 0. Я уверен, что есть причина, но я пока не мог ее понять.
Теперь, сравнивая эту информацию со строкой, которую мы добавили, мы добавили инструкцию по модулю с FUNCT7 как 0x01, FUNCT3 как 0x0 и кодом операции как 0x1A. Вот как учебник хочет определить код операции, FUNCT3 и FUNCT7 для этой инструкции. Вы определенно можете изменить эти числа, если хотите, но вы должны убедиться, что код операции, FUNCT7 и FUNCT3, которые вы выбираете, не совпадают с любой другой инструкцией. По крайней мере, одна из этих трех инструкций должна отличаться от другой инструкции. Например, две инструкции могут иметь один и тот же код операции и FUNCT7, но разные FUNCT3: это верно!
Шаг 4: перейдите в каталог~/dir/riscv-tools/riscv-opcodes
и выполните следующую команду.
cat opcodes-pseudo opcodes opcodes-rvc opcodes-rvc-pseudo opcodes-custom | ./parse-opcodes -c > ~/temp.h
Шаг 5: откройте файл~/temp.h
(вероятно, с помощью командыvi
. Затем найдитеMATCH_MOD
. Вы должны найти следующие две строки:
#define MATCH_MOD 0x200006b
#define MASK_MOD 0xfe00707f
Скопируйте эти две строки и добавьте их в файл~/dir/riscv-gnu-toolchain/riscv-binutils/include/opcode/riscv-opc.h
Объяснение MATCH_MOD и MASK_MOD: инструкция декодируется по следующей формуле:((insn ^ op->match) & op->mask) == 0;
. Таким образом, MASK_MOD и MATCH_MOD используются компилятором точно так, как показано в формуле. Когда результат дает 0, это означает, что он соответствует инструкции по модулю, и вот как он декодируется! -это, насколько я понимаю, кто-то другой может попытаться добавить к этому, если у них есть больше знаний :)
Шаг 6 (Примечание: этот шаг УСТАРЕЛ в руководстве по ссылке выше): Откройте файл.~/dir/riscv-gnu-toolchain/riscv-binutils/opcodes/riscv-opc.c
и добавьте следующую строку:
{"mod", 0, INSN_CLASS_I, "d,s,t", MATCH_MOD, MASK_MOD, match_opcode, 0 },
Шаг 7: Создайте цепочку инструментов riscv gnu, и все готово! Следуйте инструкциям по этой ссылке, чтобы создать набор инструментов: https://github.com/riscv-collab/riscv-gnu-toolchain.
Например, для сборки 64-битного компилятора в Linux вы можете использовать следующие команды:
$ cd ~/dir/riscv-gnu-toolchain
$ mkdir build
$ cd build
$ ../configure prefix=/opt/riscv64
$ sudo make linux
$ export PATH=/opt/riscv64/bin/:$PATH
Обратите внимание , что сборка компилятора может занять некоторое время (на моей машине это занимает почти час).
Шаг 8: Готово!! теперь вы можете протестировать его, как показано в учебнике! Вы можете добавить инструкцию по модулю как встроенную сборку, а затем скомпилировать свой код. На этом этапе вы можете только скомпилировать код. Чтобы запустить ваш код, вы также должны добавить инструкцию в симулятор. Я знаю только, как добавить инструкцию в GEM5, поэтому я собираюсь поделиться этим. Обратите внимание, что шаги для GEM5 в учебнике почти неверны, потому что они по какой-то причине не используют правильный код операции/FUNCT7/FUNCT3, который они определили ранее на шаге 3.
Добавление инструкции в GEM5
Шаг 0: клонируйте gem5 в свой рабочий каталог, используя следующую команду:
$ git clone https://github.com/gem5/gem5.git
Шаг 1: Откройте файл~/dir/gem5/src/arch/riscv/isa/decoder.isa
. Найдите строку, в которой говорится:0x3: decode OPCODE
. Добавьте новую строку и напишите следующее:
0x3: decode OPCODE {
// Add your code HERE:
0x1A: decode FUNCT3 {
format ROp {
0x0: decode FUNCT7 {
0x01: mod({{ Rd = Rs1_sd % Rs2_sd; }});
}
}
}
// END of your Code
0x00: decode FUNCT3 {
format Load {
....
Как вы заметили, код операции — 0x1A, FUNCT7 — 0x01, а FUNCT3 — 0x0, как мы определили ранее! линияformat ROp
определяет формат инструкции как R-тип. По какой-то причине в учебнике не используются правильные числа, поэтому GEM5 не сможет правильно определить инструкцию.
Шаг 2: создайте gem5 с помощью следующей команды, и все готово!!
$ scons build/RISCV/gem5.opt
Шаг 3: После компиляции кода ac с компилятором riscv, который мы создали ранее, вы можете запустить свой код с помощью gem5, используя следующую команду, предполагая, что имя вашего исполняемого файлаmain
:
$ GEM5 ~/dir/gem5/configs/example/se.py -c ./main
Вы можете изменить конфигурацию по умолчанию, используемую se.py, передав для нее другие параметры. Например, следующая команда использует O3CPU с объемом памяти 16 ГБ, типом памяти DD4_2400_4x16, размером кэша данных L1 64 КБ и размером кэша инструкций L1 16 КБ.
$ GEM5 ~/dir/gem5/configs/example/se.py --cpu-clock=5GHz --cpu-type=O3CPU --mem-size=16GB --mem-type=DDR4_2400_4x16 --l1d_size=64kB --l1i_size=16kB --caches -c ./main
Надеюсь, это поможет любому, кто попытается добавить инструкции в RISCV. Мне потребовались месяцы, чтобы работать над всем этим, поэтому я подумал, что будет полезно, если кто-то сможет поместить всю эту информацию в один пост! Пожалуйста, имейте в виду, что мой ответ написан в 2022 году и возможны обновления компилятора RISCV и GEM5, поэтому мой ответ может устареть в ближайшие несколько лет.