Конфигурация FPGA в качестве RISC-V процессора
7 мая 2018
В свете нашумевших атак на CPU (из последних атак — Meltdown и Spectre) наблюдается рост интереса к открытым процессорам. Тот факт, что спецификация и конкретные реализации таких процессоров полностью открыты, существенно упрощает их анализ с точки зрения безопасности. Еще одно преимущество открытых процессоров заключается в том, что любой производитель может просто взять и начать выпускать такие процессоры, и никто его за это не попытается засудить, как в случае с x86/x64 или ARM. Сегодня наиболее хайповыми открытыми процессорами, по всей видимости, являются процессоры RISC-V (читается «риск файф»).
Дополнение: После публикации этой заметки стало известно об уязвимостях NetSpectre, Foreshadow (она же L1FT), а также о бэкдорах в x86-процессорах производства VIA.
Коротко о RISC-V
RISC-V — это открытая спецификация архитектуры набора команд (ISA, Instruction Set Architecture), основанного на принципах сокращенного набора инструкций (RISC, Reduced Instruction Set Computer). Другими словами, RISC-V представляет собой описание ассемблерных инструкций, способа их кодирования, и семантику работы. Придерживание принципов RISC означает, что RISC-V не вводит лишних инструкций без сильной надобности. Например, в нем нет специальных «строковых» операций, таких, как инструкции movs, stos и cmps в ассемблере x86/x64. За счет этого существенно упрощается архитектура процессора. На самом деле, подобные CISC-инструкции являются пережитком прошлого, когда код на ассемблере писался вручную. Современное железо выполняет их даже медленнее, чем аналогичный цикл, написанный в RISC-стиле.
Инструкции RISC-V имеют переменную длину. При этом длина инструкции определяется достаточно просто, подобно тому, как определяется длина символа в кодировке UTF-8. Набор команд является расширяемым. В любой реализации обязательно присутствует базовый набор инструкций, который может быть 32-х, 64-х или 128-и битным. Базовые наборы команд называются соответственно RV32I, RV64I и RV128I. Помимо базовых команд конкретная реализация может предлагать команды, относящиеся к тем или иным расширениям. Например, расширение M содержит в себе команды целочисленного умножения и деления, расширение A — атомарные операции, а расширения F и D — операции над числами с плавающей точкой одинарной и двойной точности соответственно (то есть, float и double).
Fun fact! 128-и битные инструкции были добавлены в RISC-V на будущее. По расчетам создателей данного ISA, учитывая динамику роста современных суперкомпьютеров, а также возможный приход повсеместного NVM (Non-Volatile Memory, то есть, когда диски о оперативная память станут одним устройством), 64-х битных адресов может перестать хватать уже к 2030-му году.
Если, скажем, процессор реализует базовые 32-х битные инструкции, а также поддерживает целочисленное умножение и деление, говорят, что он является RV32IM процессором. То есть, реализованные расширения дописываются в конце следом за обозначением базового набора инструкций. Обозначения RV32IMAFD и RV64IMAFD сокращают до RV32G и RV64G, от general-purpose. То есть, такие процессоры считаются процессорами общего назначения. Помимо упомянутых расширений также есть, или разрабатываются, другие. Например, есть расширение с компактными инструкциями, кодируемыми 16-ю битами (C), инструкциями для манипулирования битами (B), для работы с транзакционной памятью (T), расширение с векторными инструкциями (V), с Packed-SIMD инструкциями (P), и другие.
Звучит занятно, но можно ли это где-то попробовать? Оказывается, что можно. Существует несколько реализаций RISC-V для FPGA, с одной из которых мы познакомимся далее. Это, пожалуй, наиболее быстрый и дешевый способ попробовать RISC-V. Кроме того, существуют готовые отладочные платы с RISC-V микроконтроллерами и процессорами, например HiFive1 и HiFive Unleashed. На последнем можно запустить полноценный Linux. Из дистрибутивов, официально поддерживающих RISC-V, можно привести в пример Debian.
Проект Icicle
Icicle — это реализация ядра RV32I для FPGA семейства Lattice ICE40. Код написан на SystemVerilog и компилируется при помощи IceStorm, открытого стека разработки под данные FPGA. Ядру требуется около 2500 логических ячеек, поэтому на отладочной плате iCEstick его запустить не получится. Однако его можно запустить на BlackIce II, так как используемый в нем ICE40HX4K имеет достаточное количество (3520) логических ячеек.
Компиляция проекта и конфигурация FPGA осуществляются очень просто:
yaourt -S riscv64-unknown-elf-gcc
# компиляция проекта
git clone https://github.com/grahamedgecombe/icicle.git
cd icicle
BOARD=blackice-ii make
# конфигурация FPGA
stty -F /dev/ttyACM0 raw
cat top.bin > /dev/ttyACM0
Соединяем второй USB-порт отладочной платы с компьютером и говорим:
Должны увидеть, что программа постоянно выводит:
Давайте отредактируем progmem.c таким образом:
#define LEDS *((volatile uint32_t *) 0x00010000)
static inline uint32_t rdcycle(void) {
uint32_t cycle;
asm volatile ("rdcycle %0" : "=r"(cycle));
return cycle;
}
int main() {
uint8_t leds = 0xAA;
LEDS = (uint32_t)leds;
for (;;) {
leds = ~leds;
LEDS = (uint32_t)leds;
uint32_t start = rdcycle();
while ((rdcycle() - start) <= FREQ);
}
}
… и переконфигурим FPGA. Если все было сделано правильно, теперь плата будет мигать светодиодами. Гореть будет либо LED1 и LED3, либо LED2 и LED4, переключение горящих светодиодов будет происходить раз в секунду.
А можно ли посмотреть на получившийся ассемблерный код? Почему бы и нет:
У меня код процедуры main получился таким:
130: 000107b7 lui a5,0x10
// a4 := 0xAA
134: 0aa00713 li a4,170
// a3 := 0x16e3 << 12
138: 016e36b7 lui a3,0x16e3
// записать 0xAA (регистр a4) в LEDS
13c: 00e7a023 sw a4,0(a5)
// a2 := 0xAA
140: 0aa00613 li a2,170
// a1 := 0x10 << 12, снова адрес LEDS
144: 000105b7 lui a1,0x10
// a3 := (0x16e3 << 12) + 1536 = 24000000
148: 60068693 addi a3,a3,1536
// начало цикла for
14c: fff64613 not a2,a2
150: 0ff67613 andi a2,a2,255
154: 00c5a023 sw a2,0(a1)
158: c0002773 rdcycle a4
// цикл ожидания
15c: c00027f3 rdcycle a5
160: 40e787b3 sub a5,a5,a4
164: fef6fce3 bleu a5,a3,15c
168: fe5ff06f j 14c
В теории, можно было бы посмотреть на исполнение этого кода в симуляторе Spike. Но, увы, на момент написания этих строк симулятор был сыроват, и не особо преуспевал с симуляцией этого конкретного примера. Хочется надеяться, что со временем это поправят.
Больше информации об ассемблере RISC-V вы найдете в документе The RISC-V Instruction Set Manual, Volume I: User-Level ISA [PDF], а также в шпаргалке Free & Open RISC-V Reference Card [PDF].
Заключение
Итак, сегодня мы узнали, что 2500 LUT достаточно для запуска хоть и простого, но все-таки процессора. Также мы познакомились с RISC-V и выяснили, что при сильном желании уже сегодня можно использовать микроконтроллеры на базе данного ISA вместо, скажем, STM32, и даже поднять десктоп на базе RISC-V. Правда, насколько это удобно и оправданно в современных реалиях — это другой вопрос.
Мы вряд ли увидим массовое использование RISC-V на десктопах и серверах, по крайней мере, в ближайшем будущем. Но стоит помнить, что процессоры нужны не только на десктопах и серверах. Так, Nvidia объявила о намерении использовать RISC-V в графических картах GeForce вместо используемого в настоящее время процессора Falcon. Кроме того, Western Digital собирается использовать процессоры RISC-V в своих будущих продуктах. Среди компаний, поддерживающих RISC-V Foundation, можно привести в пример AMD, IBM, Huawei, Google, Oracle, Lattice Semiconductor, NXP, и другие. Даже Intel, и тот инвестирует в RISC-V.
Лично у меня RISC-V вызывает исключительно одобрение. Хочется надеяться, что в будущем мы увидим много продуктов на его базе.
Дополнение: Также вас могут заинтересовать посты VisionFive 2: одноплатный компьютер на базе RISC-V и Превращаем BlackIce II в Arduino-совместимую RISC-V отладочную плату (гостевой пост Олега Бахарева)
Метки: FPGA, RISC-V, Ассемблер, Электроника.
Вы можете прислать свой комментарий мне на почту, или воспользоваться комментариями в Telegram-группе.