RISC-V

RISC-V

Приветствую тебя, мой уважаемый читатель на просторах RISC-V!

Мы начинаем очень интересную тему, которой будет посвящена целая глава, это изучение RISC-V. Я считаю, что это очень интересная тема чтобы в нее углубится, так мировое сообщество производителей железо начало уделять много внимания этому проекту (участники RISC-V) и не только поэтому, это полностью свободное решение в плане прототипирования. Тут вспоминаются слова Линуса Торвальдса о свободном ПО (они будут так же уместны и для свободного CPU).

 «Программы — как секс: лучше, когда бесплатно.»

Немного о RISC-V.

RISC-V – представляет собой открытую архитектуру набора инструкций (ISA) на основе установленных принципов сокращенных набора команд (RISC). В отличие от большинства ISA, RISC-V ISA может свободно использоваться для любых целей, позволяя любому проектировать, производить и продавать микросхемы RISC-V и программное обеспечение. Хотя это не первый открытый ISA,  важно, потому что он предназначен для использования в современных компьютеризированных устройствах, таких как облачные технологии, мобильные телефоны и встраиваемые системы. Такое использование требует, чтобы fpga дизайнеры учитывали эффективность и производительность использования энергии. Набор инструкций также содержит значительное количество поддерживаемого программного обеспечения, которое позволяет избежать ранних слабостей новых наборов инструкций. Проект начался в 2010 году в Калифорнийском университете в Беркли, но многие участники являются добровольцами и промышленными разработчиками за пределами академического сообщества. RISC-V ISA был разработан с учетом небольших, быстрых и маломощных реализаций в реальном времени, но без чрезмерного усложнения архитектуры для конкретного типа микроархитектуры.

В рамках статьи рассмотрим, как запустить RISC-V на fpga, в частности на Xilinx Zynq. Базовым проектом будет fpga-zynq от ucb-bar. В этом проекте используется Rocket Chip генератор (лучший способ следить за новостями о RISC-V – https://twitter.com/risc_v и https://riscv.org/news/). Ядро будет сгенерировано с помощью Rocket Chip генератора из исходников на Chisel.

О Chisel

Chisel – это язык разработки аппаратного обеспечения с открытым исходным кодом, разработанный в UC Berkeley, который поддерживает расширенную аппаратную конструкцию с использованием высокопараметризированных генераторов и многоуровневых аппаратных языков.

  • Язык аппаратного обеспечения
  • Встроенный в язык программирования Scala
  • Алгебраическая конструкция и связь
  • Абстрактные типы данных и интерфейсы
  • Массовые подключения
  • Иерархическое + объектно-ориентированное + функциональное построение
  • Высокая параметризация с использованием метапрограммирования в Scala
  • Поддерживает разбиение доменных языков
  • Достаточного размера стандартная библиотека, включая единицы с плавающей запятой
  • Несколько тактовых доменов
  • Создает низкоуровневый Verilog, предназначенный для перехода на стандартные средства ASIC или FPGA
  • Открытый исходный код на github с модифицированной лицензией BSD
  • Полный комплект документов
  • Растущее сообщество последователей

Пример кода на chisel:

import chisel3._
import chisel3.util._

//A n-bit adder with carry in and carry out
class Adder(val n:Int) extends Module {
  val io = IO(new Bundle {
    val A    = Input(UInt(n.W))
    val B    = Input(UInt(n.W))
    val Cin  = Input(UInt(1.W))
    val Sum  = Output(UInt(n.W))
    val Cout = Output(UInt(1.W))
  })
  //create an array of FullAdders
  val FAs   = Array.fill(n)(Module(new FullAdder()).io)
  val carry = Wire(Vec(n+1, UInt(1.W)))
  val sum   = Wire(Vec(n, Bool()))

  //first carry is the top level carry in
  carry(0) := io.Cin

  //wire up the ports of the full adders
  for (i <- 0 until n) {
    FAs(i).a := io.A(i)
    FAs(i).b := io.B(i)
    FAs(i).cin := carry(i)
    carry(i+1) := FAs(i).cout
    sum(i) := FAs(i).sum.toBool()
  }
  io.Sum := Cat(sum.reverse)
  io.Cout := carry(n)
}
import chisel3._
import scala.collection.mutable.ArrayBuffer

/** Four-by-four multiply using a look-up table.
*/
class Mul extends Module {
  val io = IO(new Bundle {
    val x   = Input(UInt(4.W))
    val y   = Input(UInt(4.W))
    val z   = Output(UInt(8.W))
  })
  val muls = new ArrayBuffer[UInt]()

  // -------------------------------- \\
  // Calculate io.z = io.x * io.y by
  // building filling out muls
  // -------------------------------- \\

  for (i <- 0 until 16)
    for (j <- 0 until 16)
      muls += (i * j).U(8.W)
  val tbl = Vec(muls)
  io.z := tbl((io.x << 4.U) | io.y)
}

Более подробное описание на https://github.com/ucb-bar/chisel-tutorial, уроки по изучению chisel можно скачать следующим образом:

$ git clone https://github.com/ucb-bar/chisel-tutorial.git
$ cd chisel-tutorial
$ git fetch origin
$ git checkout release

Rocket Chip на Zynq FPGA

Git проекта https://github.com/ucb-bar/fpga-zynq. Этот репозиторий содержит файлы, необходимые для запуска rocket RISC-V на разных платах Zynq FPGA (Zybo, Zedboard, ZC706) с Vivado 2016.2. Предпринимались попытки не только автоматизировать процесс создания файлов для этих плат, но и уменьшить дублирование, а также размер этого репозитория. Предварительно созданные образы доступны в подмодулях git, и они только поверхностно клонируются, если требуется.

Данная система позволит вам запустить бинарный код RISC-V на ядре rocket, созданный на поддерживаемой ПЛИС Zynq. В этом разделе описывается совокупность всех задействованных частей и прокси-сервера, описывается остальная часть документации. Переход сверху вниз от бинарного кода RISC-V к системе разработки:

Целевое приложение (бинарный код RISC-V) будет работать поверх любого ядра, в котором работает Rocket Chip. Компилируется с помощью riscv-gcc или riscv-llvm.

RISC-V Kernel (прокси-ядро или RISC-V Linux) работает поверх rocket chip. Прокси-ядро чрезвычайно легкое и предназначено для использования с одним бинарным файлом, связанным с Newlib, в то время как RISC-V Linux подходит для всего остального.

Rocket Chip (rocket ядро ​​с инструкциями L1 и кэшами данных) создается на FPGA. Многие из его структур, как правило, относятся к различным жестким блокам, включая BRAM и DSP-фрагменты. Он связывается с ядром ARM хоста на Zynq через AXI.

Front-end Server (riscv-fesvr) работает на ядре ARM хоста и обеспечивает интерфейс к rocket чипу, работающему на FPGA (подключенном через AXI).

Zynq ARM Core ( одно или двух ядерный Cortex A9) запускает Linux и упрощает взаимодействие с FPGA.

Плата FPGA (Zybo, Zedboard или ZC706) содержит FPGA Zynq и несколько устройств ввода / вывода. При включении питания SD-карта используется для настройки FPGA и загрузку Linux на ядре ARM.

Внешняя связь (TTY через последовательный порт на USB или telnet / ssh через Ethernet) позволяет системе разработки взаимодействовать с платой FPGA.

Система разработки (ПК с SD-кард-ридером) генерирует образ для настройки FPGA.

$ git clone https://github.com/ucb-bar/fpga-zynq.git
$ cd fpga-zynq/zedboard/
$ make init-submodules
$ make rocket

[info] Running zynq.Generator /home/user/fpga-zynq/common/build zynq Top zynq ZynqConfig
[info] [0.002] Elaborating design...
Generated Address Map
        io:cbus:debug 0 - fff, RWX
        io:pbus:TL2:bootrom 1000 - 1fff, RX
        io:pbus:TL2:clint 2000000 - 200ffff, RW
        io:cbus:plic c000000 - fffffff, RW
        mem 80000000 - 8fffffff, RWX [C]

Generated Interrupt Vector

Generated Configuration String
plic {
  priority 0xc000000;
  pending 0xc001000;
  ndevs 0;
};
rtc {
  addr 0x200bff8;
};
ram {
  0 {
    addr 0x80000000;
    size 0x10000000;
  };
};
core {
  0 {
    0 {
      isa rv64imafds;
      timecmp 0x2004000;
      ipi 0x2000000;
      plic {
        m {
         ie 0xc002000;
         thresh 0xc200000;
         claim 0xc200004;
        };
        s {
         ie 0xc002080;
         thresh 0xc201000;
         claim 0xc201004;
        };
      };
    };
  };
};
bootrom {
  addr 0x1000;
  size 0x1000;
}
clint {
  addr 0x2000000;
  size 0x10000;
}

[info] [5.865] Done elaborating.
[success] Total time: 13 s, completed Apr 12, 2018 3:18:54 PM
java -Xmx2G -Xss8M -XX:MaxPermSize=256M -cp /home/user/fpga-zynq/rocket-chip/firrtl/utils/bin/firrtl.jar firrtl.Driver -i /home/user/fpga-zynq/common/build/Top.ZynqConfig.fir -o /home/user/fpga-zynq/common/build/Top.ZynqConfig.v -X verilog
OpenJDK 64-Bit Server VM warning: ignoring option MaxPermSize=256M; support was removed in 8.0
cp /home/user/fpga-zynq/common/build/Top.ZynqConfig.v src/verilog/Top.ZynqConfig.v

Запуск проекта в Xilinx Vivado.

Выполняем следующие команды:

source /media/mcuby/fpga/Xilinx/Vivado/2017.4/settings64.sh (в начале путь до установленной Xilinx Vivado)
gedit src/tcl/zedboard_bd.tcl (необходимо заменить на свою версию Xilinx Vivado, set scripts_vivado_version 2017.4)
make vivado (из каталога платы zedboard)

После запуска Xilinx Vivado, Вы увидите, что на блок диаграмме нет RISC V, он находится в rocketchip_wrapper(rocketchip_wrapper.v). Проект собран для работы.

Полезные ссылки по RISC-V на русском языке:

  1. Генерация и тестирование ядра RISC-V – habrahabr
  2. Наборы команд должны быть свободны: доводы за RISC-V – habrahabr
  3. RISC-V – вики
  4. Недавний форум по RISC-V