nanoFOX — простое RISC-V совместимое ядро

    Небольшое вступление:


    Идея написания собственного ядра появилась после прохождения школы-семинара по цифровой схемотехнике в городе Томске. На данном мероприятии проводилось знакомство с текущими языками описания аппаратуры (Verilog HDL и VHDL), а также с небольшим процессорным ядром schoolMIPS. Для понимания устройства ядер было принято решение изобрести собственный велосипед, следуя по пути развития schoolMIPS, но взяв за основу другую систему команд. Вследствие роста популярности RISC-V и открытости его системы команд (MIPS на момент начала написания ядра не имел открытую систему команд) для осуществления разработки будущего ядра был выбран набор инструкций RISC-V, а именно RV32I. RV32I имеет небольшой набор базовых инструкций (37 без учёта специальных) и при желании его можно расширить, например, добавив инструкции целочисленного умножения и деления (RV32M) или поддержку сокращённых инструкций (compressed instructions) (RV32C). Также данный проект задумывался как образовательный, поэтому было решено по максимуму увеличить наглядность работы ядра для эффективной демонстрации его работы.


    По аналогии с schoolMIPS были реализованы следующие версии ядра:


    1. Однотактная версия (00_simple_risc_v_cpu).
    2. Однотактная версия с поддержкой инструкций lw/sw (load word/store word) (01_simple_risc_v_cpu_lwsw).
    3. Конвейерная версия (5-ти стадийный конвейер) (02_pipe_risc_v_cpu).

    На текущий момент описывается следующая версия ядра (03_pipe_risc_v_cpu_fc) с полным набором команд RV32I (без учёта некоторых специальных).


    Краткая информация:


    В ходе описания ядра продумывались пути повышения наглядности работы, отладки и верификации. На данный момент реализованы следующие методы:


    1. Добавление отладочного текстового VGA модуля (для двух однотактных веток ядра). Включение данного модуля позволяет одновременно отслеживать значение 32 регистров на экране монитора, что не возможно при использовании вывода информации на семисегментные индикаторы. На рисунках представленных снизу ядро выполняет подсчёт чисел Леонардо и производится вывод информации на соответствующий отладочный модуль;


      hex_display and DebugScreenCore

      Вывод информации на семисегментные индикаторы:image
      Вывод информации на VGA дисплей:image


    2. Добавление вывода сообщений в терминал симулятора о состоянии регистрового файла и исполняемых на текущий момент инструкциях. Данный метод позволяет лучше анализировать работу ядра на первых стадиях разработки, но не всегда является удобным;


      Терминал

      Инициализация регистрового файла:image
      Изменение значение sp:image


    3. Добавление строковых переменных на waveform с отображением исполняемых инструкций. При помощи этих строковых переменных разработчик может отслеживать правильное выставление управляющих сигналов на всех стадиях конвейера;


      Waveform

      Инициализация регистрового файла:image
      Изменение значения sp:image


    4. Добавление возможности записи отладочной информации о состоянии ядра в текстовый файл. Состояние регистрового файла представляется в табличном виде, а также обозначается инструкция/инструкции, выполняемые на текущий момент ядром. Является аналогом 2 пункта, но позволяет производить больше манипуляций с полученной информацией;


      Текстовый файл

      Инициализация регистрового файла:image
      Изменение значения sp:image


    5. Добавление возможности записи отладочной информации о состоянии ядра в HTML файл. Состояние регистрового файла представляется в табличном виде с пометками об изменении значений ячеек, а также выводятся инструкции, выполняемые на текущий момент ядром. Является аналогом пунктов 2 и 4, но в дополнении к ним позволяет удобно указывать на изменение данных. Как можно видеть на картинках снизу в случае, если значение регистра было не определено, то подсветка регистров осуществляется красным цветом ( регистры s0/fp — t6 ). На 17 цикле значение регистра s0/fp изменяется и ячейка подсвечивается зелёным цветом.
      На 41 цикле в регистр sp загружается значение 0x00010000.


      HTML файл

      Инициализация регистрового файла: image
      Изменение значения sp:image



    Сравнение веток ядра:

    Поддерживаемые инструкции ядра на текущий момент для разных веток:


    Инструкция 00_simple_risc_v_cpu 01_simple_risc_v_cpu_lwsw 02_pipe_risc_v_cpu
    add + + +
    and - - +
    sll - - +
    or + + +
    addi + + +
    ori - - +
    slli + + +
    lw - + +
    jalr - - +
    lui + + +
    beq + + +
    bne - - +
    sw - + +
    jal - - +
    sub + + -

    Поддерживаемая периферия:


    Периферия 00_simple_risc_v_cpu 01_simple_risc_v_cpu_lwsw 02_pipe_risc_v_cpu
    RAM - + +
    PWM - + +
    GPIO - + +
    UART - - +

    Поддерживаемые языки для написания программ:


    Язык 00_simple_risc_v_cpu 01_simple_risc_v_cpu_lwsw 02_pipe_risc_v_cpu
    Assembler + + +
    C - - +

    Необходимые ресурсы ПЛИС для ядра (nf_cpu):


    EP4CE22F17C6 (de0_nano):


    01_simple_risc_v_cpu_lwsw 02_pipe_risc_v_cpu 03_pipe_risc_v_cpu_fc
    Total memory bits 0 / 608,256 ( 0 % ) 2,048 / 608,256 ( < 1 % ) 2,144 / 608,256 ( < 1 % )
    Total logic elements 3,645 / 22,320 ( 16 % ) 1,739 / 22,320 ( 8 % ) 2,058 / 22,320 ( 9 % )
    Total combinational functions 2,653 / 22,320 ( 12 % ) 1,472 / 22,320 ( 7 % ) 1,838 / 22,320 ( 8 % )
    Dedicated logic registers 1,055 / 22,320 ( 5 % ) 575 / 22,320 ( 3 % ) 606 / 22,320 ( 3 % )

    10M50DAF484C7G (de10_lite):


    00_simple_risc_v_cpu 01_simple_risc_v_cpu_lwsw 02_pipe_risc_v_cpu 03_pipe_risc_v_cpu_fc
    Total memory bits 0 / 1,677,312 ( 0 % ) 0 / 1,677,312 ( 0 % ) 2,048 / 1,677,312 ( < 1 % ) 2,144 / 1,677,312 ( < 1 % )
    Total logic elements 2,851 / 49,760 ( 6 % ) 2,881 / 49,760 ( 6 % ) 1,629 / 49,760 ( 3 % ) 1,927 / 49,760 ( 4 % )
    Total combinational functions 2,613 / 49,760 ( 5 % ) 2,653 / 49,760 ( 5 % ) 1,473 / 49,760 ( 3 % ) 1,849 / 49,760 ( 4 % )
    Dedicated logic registers 1,055 / 49,760 ( 2 % ) 1,055 / 49,760 ( 2 % ) 575 / 49,760 ( 1 % ) 606 / 49,760 ( 1 % )

    Развитие проекта.


    Что планируется сделать в будущем:


    1. добавить все инструкции RV32I (на стадии описания);
    2. реализовать отладку;
    3. добавить DMA (ПДП) контроллер;
    4. добавить поддержка других шин AXI, Avalon, Wishbone;
    5. добавить cache (КЭШ) память;
    6. интегрировать различную периферию (SPI, TWI (I2C), Ethernet(10 base-t));
    7. добавить контроллер прерываний;
    8. портировать разные версии на другие отладочные платы;
    9. добавить другие методы повышения наглядности работы ядра;
    10. запуск RTOS, например zephyr.

    Также принимаются рекомендации и предложения по развитию ядра.


    Ссылка на репозиторий: nanoFOX.

    Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.

    Что лучше раскрыть в следующих статьях?

    Поделиться публикацией

    Комментарии 13

      +1
      Знакомы ли Вы с направлением «Forth» CPU и какое мнение по этому подходу?
      Проекты с Github:
      A Forth CPU and System on a Chip, based on the J1, written in VHDL
      N.I.G.E.-Machine

      Extreme FORTH
      и др. проекты.

      P.S. Есть и такой проект на базе Форт процессора в FPGA Gameduino
        0

        Здравствуйте, про Forth CPU что то слышал, но на практике не пробовал, поэтому сказать пока что ничего не смогу.

        +1
        Крайне интересует отладка всего этого хозяйства на различных ПЛИС. Очень хочется по-человечески дебажить код в Eclipse + openOCD. Собственно говоря нужен некий HDL debug module с JTAG интерфейсом.
          +1

          Здравствуйте, да как раз задумывается JTAG отладчик, описание которого ведётся в соседнем репозитории: https://github.com/Dmitriy0111/JTAG_debug .

          +2
          В сравнение веток ядер добавьте, пожалуйста, сколько логики занимает каждое, без периферии.
            +1
            Спасибо за предложение. Добавил в статью.
              +1
              ну так немало, если сравнивать с какими-нибудь оптимизированными под fpga niosами.
              с другой стороны понятно, что 32 регистра по 32 разряда сразу 1024 триггера отъест.

              Конвееризация по максимальной рабочей частоте в ПЛИС какой-нибудь выигрыш даёт?
                0
                Здравствуйте! Пока ещё не успел сравнить с другими soft ядрами, но это в планах. Плюс надо проводить оптимизацию ядра.
                  0
                  как соберетесь, дайте знать, тоже интересно было бы допилить habr.com/ru/post/433342 до набора инструкций минимальных 00_simple_risc_v_cpu/01_simple_risc_v_cpu_lwsw и посравнивать.
            +2
            Сколько ресурсов ПЛИС занимает в минимальной комплектации, без гидроусилителя и стеклоподъемников?
              +1
              Добавил в статью.
              +1
              Мне интересно насколько RISC-V фрагментирован (или подвержен этому) в сравнении с ARM и с чего лучше начать новичку: ARM или RISC-V?
                0
                Здравствуйте! Смотря что Вы хотите делать с ARM или RISC-V? Нельзя забывать о MIPS Open (https://www.mipsopen.com/), где есть много интересной информации, но соответственно по MIPS. Можете посмотреть в сторону SchoolMIPS (https://github.com/MIPSfpga/schoolMIPS) или других ядер (опять же смотря что Вам интересно).

              Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

              Самое читаемое