Процессор Forth J1 в FPGA плате M02mini



    Впервые я познакомился с языком программирования Forth еще в студенческие годы. Было это правда ну очень давно. Уже тогда язык поразил меня тем, что он «не такой как все». При этом, код получался хоть и малопонятный, но компактный и быстрый.

    Недавно я занимался запуском процессора Forth j1 в FPGA плате и пришлось вспоминать фортовские азы программирования. Да уж… чертовски трудно, но получил громадное эстетическое удовольствие. Как будто впервые взял кубик Рубика, и сам собрал его, и пазл сложился и программа работает…

    Что же такого особенного в языке Forth?

    Мне показалось, что главное правило языка Forth — никаких правил. Программист полностью определяет поведение всей системы, структуру памяти, структуру программы и данных и определяет набор слов, которые живут и работают в системе. Я бы сказал, что язык Forth чуть-чуть более высокоуровневый, чем ассемблер. Есть только базовый набор слов, которые могут выполнять какие-то основные вещи вроде арифметических или логических операций и переходов. Новые слова программист определяет сам на основе уже существующих слов. Операнды лежат на стеке и результат выполнения операции так же кладется на стек.

    Например, можно в консоли интерпретатора языка Forth ввести:

    > 1 2 + .

    Здесь интерпретатор из последовательности символов возьмет строку «1», преобразует в число 1, положит на стек данных, потом возьмет строку «2», преобразует в число 2, положит на стек данных. Далее возьмет строку "+" и, поскольку она не преобразуется в число, то попробует найти ее в словаре известных слов. Найдет в словаре слово "+" и выполнит связанное с этим словом действие, суммирование двух чисел на стеке. При этом, два числа со стека будут сняты, но взамен будет положен результат число 3. И снова интерпретатор ищет слова во входном потоке, найдет следующее слово ".", а это слово снимает число со стека и печатает его в консоль.

    Теперь программист может определить для себя совершенно новое слово вот так:

    > : 2+ 2 + ;

    Новое определенное слово будет «2+», а делать оно будет «прибавление 2».

    После этого повсеместно можно применять новое определенное слово «2+»:

    > 1 2+ .

    Напечатает результат число 3.

    Расскажу немного о FPGA проекте. Каждый разработчик FPGA однажды сталкивается с необходимостью выполнять часть логики с помощью обычных последовательных программ. Существует огромное количество софт процессоров. Да и сами производители ПЛИС активно продвигают свои собственные ядра. Intel, например, рекомендует NIOS. Xilinx дает своим пользователям MicroBlaze Soft Processor Core. Каждое ядро занимает драгоценное место в FPGA. Я тогда подумал, а может нужен Forth процессор, он же довольно простой должен быть?

    Тогда я обнаружил для себя, что Forth процессоры люди уже вполне делали!

    Мне нужно только портировать на свою плату и посмотреть, как он работает. Тогда можно будет оценить и быстродействие и необходимые ресурсы для его реализации в ПЛИС.

    Исходный проект форта для ПЛИС обнаружился на github.com.

    Я портировал этот проект для платы Марсоход3 и платы M02mini. Плата M02mini — самая маленькая из известных мне FPGA плат. На ней стоит крошечная, буквально 3 миллиметра FPGA Intel MAX10 с двумя тысячами логических элементов. Тем более было интересно, получится ли в такой крохе запустить хоть какой-то софт процессор. Вот так выглядит плата:

    image

    Тут же на плате есть двухпортовая микросхема FTDI, которая используется и как JTAG программатор и как последовательный порт к ПЛИС. Микросхема FTDI гораздо больше самой ПЛИС.

    Структура процессора J1 очень простая:

    image

    Имеется два не очень глубоких стека: стек данных и стек возвратов, по 16 слов. При желании, конечно можно стек сделать глубже. Программа, как и данные находятся в двухпортовом RAM с тем намерением, чтобы можно было одновременно за такт процессора выбирать следующую инструкцию на исполнение и тут же читать или писать в ОЗУ данные. Подразумевается исполнение одной инструкции за один такт. При этом различные поля инструкции одновременно отвечают за исполнение команд в АЛУ и приращение или уменьшение указателей стека данных и стеков возврата:

    image

    Я бы сказал, что кодирование команд не очень плотное, но дело в том, что последующие слова определяются через предыдущие, вот тут и происходит магия. Итоговый «шитый код» получается очень компактным.

    Несмотря на то, что инструкции 16ти разрядные, сам процессор 32х разрядный. Интересно, что числовые константы в инструкцию кодируются если её старший бит находится в единице. Понятно, что диапазон возможных значений не очень широкий. Если потребуется большее значение числа, то его придется вычислять с помощью сдвигов и логических операций. Кодирование команд процессора выглядит так:

    image

    Очень хочется поделиться своей программой на Forth, это мой простейший интерпретатор. В Форте все пишется на Форте, в том числе и интерпретатор и компилятор и кросс-компилятор.

    Используется gforth, в котором запускается фортовская программа кросс-компилятор cross.fs, которая принимает определения новых базовых слов, тех которые по сути ассемблерные команды basewords.fs, для целевой системы. Дальше программа cross.fs включает в себя собственно реальную программу target.fs, которую мы хотим запустить в FPGA на Forth процессоре:

    > gforth cross.fs basewords.fs target.fs

    В результате исполнения этих Форт программ получится листинг, бинарный файл образа программы, и MIF файл для инициализации памяти в ПЛИС.

    Моя программа интерпретатора выглядит вот так:

    : main
        2drop
    	begin                        \ начало вечного цикла
            tib d# 80 accept cr    \ строка из консоли записывается в tib
                                            \ (text input buffer) длиной 80 байт
            tib# !                        \ длина принятой из консоли строки 
                                            \ записывается в переменную tib#
    		d# 0 >in !         \ изначально разбор строки начинается с 
                                            \ нулевого символа, запишем 0 в переменную >in
    			begin        \ начнем поиск всех слов в принятой строке
    			  parse-name  \ возьмем из tib слова по очереди, на стеке 
                                        \ останется адрес строки и длина строки, "name" -- c-addr u 
    			  dup	    \ возьмем на стек длину слова еще раз, на стеке c-addr u u
    			  while   \ зайдем в обработку слова, если его длина не ноль
    			    2dup d# 0. 2swap >number \ попробуем преобразовать строку в число
    				0=    \ если в строке не осталось символов, 
                                            \ значит была строка-число
    				if
    					2drop  \ удалим лишнее со стека
    					rot rot 2drop \ оставим на стеке только полученное
                                                                \ число и сверху адрес строки с длиной
    				else
    					drop 2drop \ было не число, так что удалим
                                                                \ лишние данные со стека
    					sfind \ попробуем найти слово в словаре
    					if
    						execute \ исполним найденное слово
    					else
    						drop \ слово не найдено в словаре, удалим лишний элемент со стека
    						space msg-unkn print-str \ напечатаем сообщение об ошибке
    					then
    				then
    			repeat
    			2drop \ удалим адрес последней строки и ее длину (нулевую) со стека
    	again \ к началу вечного цикла
    ;
    
    

    Я постарался в комментариях объяснить происходящее.

    Некоторые простые слова легко объяснить:

    dup — повторно кладет на стек верхнее число, w — w w
    2dup — повторно кладет два верхних числа, w1 w2 — w1 w2 w1 w2
    аналогично
    drop — сбрасывает со стека верхнее число, w —
    2drop — сбрасывает 2 верхних числа, w1 w2 —
    2swap — меняет местами две пары верхних чисел на стеке, w1 w2 w3 w4 — w3 4 w1 w2
    rot — достает третье сверху число, w1 w2 w3 — w2 w3 w1
    d# — кладет на стек десятичное число, которое написано сразу после d#

    Более сложные слова и комбинации begin — again, if — else — then определяют переходы и условные переходы.

    Некоторые из других сложных слов:

    sfine — ищет слово в словаре,
    execute — исполняет найденное слово.
    space — печатает пробел,
    print-str — печатает строку…

    Еще раз повторю, что этот мой интерпретатор очень примитивный в том смысле, что с его помощью нельзя определять новые слова из консоли. Но и это, конечно, при желании возможно. В своей работе мне хотелось получить консольный Форт — и я его в принципе получил:



    На видео демонстрации выше показано исполнение простых слов языка Forth в FPGA плате M02mini (Intel MAX10, 2K LE). Команды печатаются к консоли Putty через последовательный порт к плате.

    Остается добавить, что в моей крохотной плате FPGA M02mini проект занимает всего 1232 логических элемента, а получившаяся тактовая частота проекта Fmax=72МГц, что мне кажется совсем не плохо:

    image

    Таким образом, считаю ядро процессора Forth J1 вполне работоспособным и его вполне можно применять в реальных проектах. Сам язык Форт, хоть и кажется мудреным, дает высокую плотность кода и неплохую производительность.

    → Весь проект можно взять на github

    Описание других проектов для платы M02mini можно посмотреть здесь.

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

      +2
      Приветствую Николай, сердечно рад, что проект «Марсоход» продолжает развиваться!
      О форт-процессоре: теперь нужен компилятор из форта в HDL, а затем гибридный компилятор, разваливающий программу на hard и soft части.
        +1
        Хм… но это очень не просто…
        +2
        Реальный форт-процессор был сделан в России где-то в начале 90-х (прошлый век). Это была копия аналогичного процессора фирмы Novix. Были еще различные варианты подобной архитектуры. Но о каком-то успешном использовании слышать не доводилось.
          +3
          Их в космосе летало очень много, с конца восьмидесятых и практически до наших дней.
            +7
            Это была (есть?) линейка Форт-процессоров Дофин.
            После распада СССР эта разработка осталась на Минском Интеграле и имела последнее обозначение K1881BE1T.
            Разработчики этой линейки оставшиеся в России, образовали «кооператив» ТехноФорт (уже почившим, но в Веб архиве остались результаты их некоторой деятельности, разработали, в частности, кассовый пос-терминал POS-64) и разработали, в качестве своих потребностей, архитектуру TF16 (упомянута в серии статей журнала «Компоненты и Технологии» за 2003-2004 в трёх статьях

            «Стековые процесоры, или новое — это хорошо забытое новое»

            Начало
            Часть 1
            Часть 2 (TF16)

            K1894 -TF16 в железе IDM-PLUS МИЭТ Зеленоград (контакты разработчиков)

            Из старой спецификации на К1894 тактовая порядка 80Мгц из периферии SPI I2С Уaрты (4-е) интерфейс к флеш диску, выполнение программы после стартовой загрузки из ОЗУ
            поддержка DSP вариантов команд арифметики.
            Где и кем используется данных нет, вероятно во внутренних разработках самого производителя. С частными пользователями не работают и они им не интересны при бюджетировании государством.

            В NASA активным MISC (Форт) процессором был/есть? RTX2010 (радиационно-стойкий) — применён в миссии полёта зонда к комете Чурюмова-Герасименко

            Чужие: странная архитектура инопланетных компьютеров (процессарная часть зонда)
              +1
              Огромное спасибо за ссылки. Особенно за «Стековые процессоры, или новое — это хорошо забытое новое». Даже о дофине-1630 упомянуто. Правда не совсем точно. В свое время NC4016 поразил меня своей простотой. Я тогда не мог понять почему не имея никакой технологии у нас пытаются переделать 80х86 или PDP. А здесь на 2 микронах куча мегагерц :) Для 1630 я когда-то даже написал С-компилятор, отладчик и всю библиотеку функций. Куча трудов коту под хвост :)
              Был на Интеграле еще и 8-ми разрядный стековый процессор. Но автор статьи видимо об этом не знал.
              PS. Для любителей экзотики :).Asm код С-компилятора 1630.
              /* j = --i + a++; */
              >at=sp-29;
              $_RD(>t,at);
              t-0x1;
              *at>=t;
              >at=sp-27;
              $_RD(>t,at);
              >t+0x1;
              *at>=t>;
              t+n; n>;
              >at=sp-28;
              *at>=t;

                0
                K1894 -TF16 в железе IDM-PLUS МИЭТ Зеленоград

                Заинтересовали! Попробую изучить. Может свяжусь и получится получить образец. Очень не хотелось бы лезть в ПЛИС, если есть готовые процессоры/микроконтроллеры (ничего против ПЛИС не имею, просто для меня пока сложно).
                  0
                  Хм. Изучил подробнее про К1894ВГ1Т (вот тут). Если вкратце, то как-то грустно. Так же попытался выйти на контакт — не вышло. Жаль.
                  0
                  Есть ещё такой Forth-процессор на FPGA: winglion.ru/equinox
                  +9
                  Сам язык Форт, хоть и кажется мудреным, дает высокую плотность кода и неплохую производительность.

                  Fun fact: Форт и хард-процессоры для него активно использовались в космосе, в том числе в хорошо известных проектах — Rosetta, Space Shuttle, Chandra, Deep Impact, Cassini.
                    0
                    Поучите язык Factor, кайф неописуемый
                    andreaferretti.github.io/factor-tutorial
                    rosettacode.org/wiki/Category:Factor
                    dxdy.ru/topic138111.html
                      0
                      10M02DCV36C8, прикольный чип, мне он уже нравится.
                      Но придётся немного подождать, когда его напечатают хотя-бы в количестве 10к штук.
                        0
                        Извиняюсь а что насчёт таймингов?
                        на скриншоте со статьи они не сошлись но в видео вроде как заметен достаточно солидный запас по слакам и тд.
                        Т.е. с формальной точки зрения, на чипе что указан в статье, дизайн работает на Fmax 72МГц или нет?
                          0
                          Могу ли я повторить этот проект используя только Linux или для заливки в FPGA требуется Windows-софт?
                            0
                            Можете. Почему нет? Проблем не должно быть.
                            Вообще проект простой — на любою плату легко переделать.
                            0

                            Прошу простить за мою агрессию + только что проснулся. Мне интересно в каких таких реальных задачах юзать форт процы рентабельно? Просто даже самая простая "ириска" можеты выдавать такие же частотные характеристики и иметь столько же лут объёма, а в некоторых дизайнах вообще до 600лут получалось ужать. Что на счёт кода, он имеет реальное преимущество только если он специально заточен под какую-то задачу, а делать его "для всех" глупая мысль, не так ли? Я считаю это вот всё больше развлекательного характера, ибо реальный толк для производительности от стековой архитектуры есть только в суперскалярниках с реордером. Ну и ещё они энергии меньше жрут… Но это все уже давно знают

                              +1
                              Да скорее всего тут развлекательный характер играет наиважнейшую роль.
                              Пища для ума, разминка для мозга. Врядли что-то еще.
                              0
                              Очень интересно, надо руками пощупать — вдруг оптический обман зрения ;)
                              Если серьезно в своё время много читал о форт-процессорах, а увидеть в реале увы.

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

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