Лекция Чарльза Мура, создателя Forth: 144-ядерный процессор, зачем? Сложно ли запрограммировать 144 вычислительных ядра?


Создатель 144-ядерного процессора GA144 и языка программирования Forth, известный программист Чарльз Мур (Charles H. Moore), известный также под именем Чак Мур (Chuck Moore), в своей лекции рассказывает о перспективах применения 144-х ядерного асинхронного чипа, созданного его компанией, GreenArrays, а также его программировании. Ведь его чип потребляет всего лишь 7 пДж энергии, что делает его незаменимым в случаях, когда процессор может питаться лишь от автономного источника энергии без возможности подзарядки, начиная от разработок в сфере медицины и заканчивая робототехникой. Незадействованные ядра потребляют всего 100 нановатт, в то время, как активным, требуется всего 4 милливатта при обработке 666 MIPS: плотный код сводит к минимуму количество выполняемых инструкций, уменьшая количество выборки команд, переключения транзисторов и рабочего цикла.

Так как лекция еще не публиковалась ранее, мы опубликовали её для Вас на youtube:

Если кто-то будет в состоянии сделать субтитры — пишите, добавим, будем очень признательны, если кто-то найдет время для выполнения столь важной работы.

Сам процессор поступил в продажу в 2011-м году, по цене $20. В этой публикации мы постарались систематизировать имеющуюся новую информацию и заполнить пробелы, которые могут возникнуть после чтения документации от GreenArrays.

144-ядерный процессор, зачем?


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

Что делает чип GA144 от GreenArrays уникальным?


Вот несколько причин считать его таковым:

— он имеет 144, 18-разрядные ядра;
 — он характеризуется полностью независимыми асинхронными ядрами, потому не имеет часов;
 — он запрограммирован в Forth и GreenArrays, которые в свою очередь предоставляют colorForth, версию arrayForth конкретно для GA144;
 — его аппаратные возможности синхронизации задач на различных ядрах и высокая скорость выполнения кода;
 — возможность программно задавать функциональность линий ввода/вывода.

Но, несмотря на то, что есть достаточно много соответствующей документации по программированию этого чипа, для некоторых начало работы с ним вызывает сложности. Обучающие программы в Интернете, как правило, работают для старой версии arrayForth и не поддерживаются новыми. Основная информация распределена по всей доступной документации. И если есть желание начать квалифицированно работать с GA144, то придется всю её внимательно прошерстить. Хорошо подумайте, прежде чем начать свои эксперименты с ним, быстрого результата не будет. Особенно, если вам нужно запрограммировать чип с IDE, который выглядит примерно так:

7f4fa7c072a34006a1064178c0830cad.jpg

Но не стоит волноваться, постараюсь объяснить в этом посте, как написать пример эталона «Hello World» и запустить его на тренажере, не особо вдаваясь в подробности работы чипа. Скорее всего вы уже имеете некое представление о GA144, Forth и его стек. Кроме того, рекомендую Вам прочитать инструкцию arrayForth, что бы получить базовое представление что это такое.

Первый запуск


Если Вы все сделали верно и запустили arrayForth, вы должны увидеть подобное окошко:

e3f4be6fcadd4ef0aa2af682bc3fceb9.jpg

Вы должны знать, что он использует специальную раскладку клавиатуры для ввода различных видов и цветов синтаксиса (отсюда и пошло colorForth). На странице 13, глава 3 руководства пользователя arrayForth вы можете найти макет, используемый в редакторе. Прежде чем начать писать наш пример «Hello World», мы должны знать о том, как организована память, где мы оставим наш код, какие узлы какой блок кода выполняют и т.д.

Организация памяти


Память в arrayForth организована в 1400 блока, некоторые из них содержат программное обеспечение самой системы, такое как компилятор и симулятор, другие содержат написаный пользователем код или просто пустые. Краткая информация о том, как организованы блоки памяти можно найти на странице 18, глава 4 руководства пользователя arrayForth, а подробное описание можно найти в файле EVB001–02b.html, который располагается в папке установки.

Вы можем видеть, что блоки от 840 до 1078 могут быть использованы для хранения пользовательского кода. Обратите внимание, что блоки с четной нумерацией могут содержать пользовательский код, а блоки с нечетной нумерацией используются для хранения пользовательских комментариев.

Компоновка Узла


Чип GA144 состоит из 144 F18 узлов в сетке 18 × 8:

76ca77b975264b15b474008bcc10132a.jpg

Каждый узел имеет идентификатор, который начинается с 000 на нижнем левом узле и заканчивается 717 для верхнего правого узла. Каждый узел связан с соседними узлами. Крайние узлы имеют выход во вне, либо непосредственно, либо через периферийные устройства, такие как UART, SPI, ADC и т.д. Поэтому необходимо тщательно спланировать расположение вашего приложения.

«Hello World»


Теперь, когда мы знаем немного о GA144, давайте напишем наш первый кусок кода, который выполняет следующие вычисления: 3 (х + 1). Мы разместим наш код в блоке 860, который является доступным для пользовательского кода.

860<пробел>edit<пробел>

Эта команда открывает редактор и отображает нам пустой блок:

f0c4cd56eba44c699a5fddfa00d6b81e.png

Введите следующую команду:

0<пробел>org<пробел>br<пробел>

На мониторе вы должны увидеть схожую картину:

ef37e6f5f03048169d1da84d8b9740f0.jpg

Если вы знаете ассемблер, то вы должны понимать, что желтая часть 0 орг означает, что все, что будет вписано далее будет помещено в ячейку памяти от 0 и выше. Синий br является командой редактора, которая не компилируется в исполняемый код, а скорее говорит редактору, что нужно добавить две новые линии. Если бы это было cr, то только одна новая линия была бы добавлена.
Далее, мы определим три слова (функции): setup, calc и mul.

setup — даст значение переменной х в нашей формуле 3 (х + 1) и сохранить его в регистре.
calc — будет извлекать значение в регистре а, добавлять к нему, и умножать его на три.
mul — это функция, которая выполняет 18-битное умножение, так как F18 узел не имеет одной команды умножения.

Давайте сначала соберем код для функции mul:

mul<пробел>a!<пробел>0<пробел>17<пробел>for<пробел>+*<пробел>unext<пробел>drop<пробел>drop<пробел>a<пробел>;<пробел>

9b1e0354e2b94e64a7ca5d7b2784157b.jpg

Далее идет функция calc:

calc<пробел>a<пробел>1<пробел>+<пробел>3<пробел>mul<пробел>;<пробел>

643a9dcb7e964af58737de41772d72cf.jpg

Окончательная функция setup:

setup<пробел>4<пробел>a!<пробел>calc<пробел>;<пробел>br<пробел>

99215fc508024ed49e04ae2846e8c379.jpg

В этом случае, у нас выбрано х = 4, что приведет к 3 (4 + 1) = 15 = 0×0F в шестнадцатеричном. Мы практически закончили! Последняя часть нашего примера «Hello World», чтобы убедиться, что точка входа нашей программы (настройка) вызывается, когда узел загружается с нашим кодом. Мы можем установить его так:

0a9<пробел>org<пробел>setup<пробел>;<пробел>

Это дает нам последнюю строку нашего кода, и помещает точку входа в наш код по адресу 0xA9, где и будет вызываться установка.

fb2a5ab94a664a98897d6074bab76792.jpg

Теперь нажмите пробел, чтобы выйти из режима редактирования (вы увидите, что в нижней части красный 860 c правой стороны станет серым). Нам необходимо скомпилировать код, это можно сделать, введя compile и нажав пробел. Вы также можете сохранить состояние всех блоков 1400 с помощью функции «save» (тип сохранения и пространство).

Настройка узлов


Таким образом, мы написали код, но как же мы поместим его в один из узлов? Это та часть, которая не затрагивается, если просмотрите более старую документацию. Блок 200 содержит инструкции для загрузки кода из блоков на узлы. Это именно то место, где мы можем загрузить наш код. Для начала нужно изменить все инструкции, которые не являются белого или синего цвета, на белый. Вы можете сделать это, поместив курсор на инструкцию/номер и кликая, пока она не побледнеет.:)

Мы поместим загрузочные инструкции после первой строки.

400<пробел>node<пробел>860<пробел>load<пробел>br<пробел>

Эта строка выбирает узел 404 и загружает в него блок 860. Выглядит это как-то так:

aa345c537f1849138508e588cec2d2c3.jpg

Причина, по которой мы поместили все это в блоке 200 в том, что softsim тренажер, который находится в arrayForth (блоки 148–150), изначально настраивает имитатор (блок 148) и код загрузки приложения хранится в блоке 200 (блок 150).

Вы можете повторить этот шаг, если вы хотите разместить один и тот же блок в другом узле (работает один и тот же код параллельно), или если вы хотите загрузить другой блок кода в другом узле. Если бы мы запустили симулятор сейчас, мы бы увидели, что узел 404 не выполняет никакого кода. Для того, чтобы убедиться, что узел будет запускать программный счетчик, который указывает на правильную точку входа, мы должны изменить блок 216. Этот блок содержит конфигурацию и testsbeds для тренажера.

Открываем блок 216:

216<пробел>edit<пробел>

И добавьте следующий код перед строкой, которая начинается с комментарием «rom write test 200 +node 13 /p,»:

0a9<пробел>404<пробел>enter<пробел>br<пробел>

Блок 216 теперь выглядит следующим образом:

68a8e344e3784f6eb36c4a7fd14844dd.jpg

Теперь правильная точка входа для узла 404 была установлена, мы готовы запустить наш код в симуляторе!

Запуск тренажера


Введите softsim и нажмите пробел, чтобы запустить симулятор.

41908652d8464450b984ae325f5c98a6.jpg

Страница 33, глава 7 инструкции arrayForth описывает, как работает симулятор, но постараюсь еще кратко объяснить.

В правом верхнем углу, есть сетка 18 на 8, представляющая все узлы GA144. Зеленый символ означает узел, который работает, серый означает, что узел приостановлен. Если бы не модифицированный блок 216, как описано выше, узел 404 (5-й слева и 4 сверху) был бы серым, так как не работал бы наш пример «Hello World». Существует также красный и желтый X, которые представляют собой «фокус» узел и «другой» узел, соответственно. В правом нижнем углу отображается содержимое памяти фокусного узла. Если нажать клавишу »/», то в правый верхний угол будет заменен содержимым памяти «другого» узла. Это полезно, если у вас есть два узлах взаимодействующих между собой. Левая часть экрана отображает внутреннее состояние узлов, содержимое регистров. Выделенная сетка 8 на 4 узла отмечена синим прямоугольником в обзоре сетки в правом верхнем углу, ее можно перемещать, чтобы выбрать узлы, внутренне состояние которых мы хотим узнать:

8b42279e7e744d88b3659e7e10e2dfe4.jpg

Сверху вниз:

  1. Номер узла (серый), адрес COM-порт (белый)
  2. Номер слота (белый), название опкод (зеленый)
  3. Регистр команд (белый)
  4. Таймер памяти (зеленый), программный счетчик (белый)
  5. А, регистр (белый)
  6. B, B регистр (белый)
  7. IO, IO регистр (бирюзовый)
  8. R, верхняя часть стека возврата (красный)
  9. T, верхняя часть стека данных (зеленый)
  10. S, стек данных (зеленый)
  11. @ Представляет собой коммуникационный порт, который используется

Запуск нашего кода


Если поместить красный X на узле 404, а также настроить синий прямоугольник, чтобы включить узел 404, мы сможем увидеть, что происходит с узлом, на котором мы хотим запустить наш пример:

eb82095c3289437f97581e64971afbb0.jpg

Нажав несколько раз n, мы можем видеть, что узел 404 выполняет наш код:

2611f9929b8f4d51bbfa4e3d5bba06a1.jpg

Ниже приведено краткое обьяснение того, что происходит в хронологическом порядке. Во-первых, указывается адрес памяти, а рядом нумерованный список инструкций, который соответствуют слотам команд (см. F18 Technology документ для получения более развернутой и обширной дополнительной информации).

0xA9

  1. Перейти к 0xA.

0xA
  1. Поместить значение, хранящееся в 0xB (который 4) в стеке.
  2. Хранить в верхней части стека в регистре А.
  3. NOP.
  4. NOP.

0xC
  1. Перейти к 0×6.

0×6
  1. Поместить значение, хранящееся в регистре А в стеке.
  2. Поместить значение, хранящееся в 0×7 (1) в стеке.
  3. Выполнять сложение.
  4. Поместить значение, хранящееся в 0×8 (3) в стеке.

0×9
  1. Перейти к 0×0.

0×0
  1. Хранить в верхней части стека в регистре А.
  2. Поместить значение, хранящееся в 0×1 (0) в стеке.
  3. Поместить значение, хранящееся в 0×2 (0×11 = 17) в стеке.
  4. NOP.

0×3
  1. Хранить в верхней части стека на верхней части стека возврата.
  2. NOP.
  3. NOP.
  4. NOP.

0×4
  1. Выполнить шаг умножения.
  2. Перейти к следующей инструкции, если стек возвратов равен 0, в противном случае вернуться к предыдущему слоту.
  3. Падение значения, хранящегося на вершине стека данных.
  4. NOP.

0×5
  1. Падение значения, хранящегося на верхней части стека данных.
  2. Поместить значение, хранящееся в регистре А в стеке.
  3. Вернуть.

Когда последняя инструкция exectued, мы можем видеть, что значение 0xF или 15 в десятичной системе счисления на вершине стека, подтверждая, что наш пример работает правильно! Я надеюсь, что этот пост поможет заполнить пробелы после прочтения документации GreenArrays.

Статья опубликована при содействии хостинг-провайдера ua-hosting.company. Потому, пользуясь случаем, хотим напомнить об акции:

VPS (KVM) c выделенными накопителями (полноценный аналог выделенных серверов начального уровня от $29) в Нидерландах и США бесплатно на 1–3 месяца для всех + бонус 1 месяц для geektimes

Не забывайте, что Ваши заказы и поддержка (сотрудничество с Вами), позволят опубликовать в будущем еще большее количество интересного материала. Будем признательны Вам за Ваши отзывы и критику и за возможные заказы. ua-hosting.company — рады сделать Вас счастливее.

Комментарии (2)

  • 16 марта 2017 в 11:24

    0

    Статья интересная, перевод омерзителен.

    > Когда последняя инструкция exectued

    Человек бы заметил.

  • 16 марта 2017 в 11:32

    0

    Это что-то «инопланетное» (что IDE, что перевод).

© Habrahabr.ru