4E4th + TI LaunchPad. Основы языка Forth

В прошлый раз я представил общественности учебное компактное ядро forth, целиком размещаемое в 8 из 16 кБ флеш памяти MSP430G2553 и полноценно функционирующее, несмотря на смешные по нынешним временам 512 байт ОЗУ, в которых разместился буфер вводимых через UART команд, два стека (данных и возвратов) и пользовательский словарь, в который складываются вновь скомпилированные слова.

Дополнительные возможности (по сравнению с прототипом — CamelForth) дает слово save, которое сохраняет новые слова, введенные пользователем, в флеш память, освобождая ОЗУ.
(На самом деле это слово делает что-то другое, пока точно не разобрался. А слова изначально сохраняются в пользовательскую половину флеш памяти.)

Так как был высказан интерес к теме, продолжим изучение основ фортостроения вообще и особенности конкретной реализации 4E4th.

Поскольку на домашнем компьютере у меня стоит Linux Ubuntu, первым делом попробуем подконнектиться к плате. Образ 4E4th уже прошит с прошлого раза, так что нам нужно только запустить терминал и подконнектиться к порту /dev/ttyACM0
В соответствии с инструкцией, пробуем сделать это через терминал kermit.
Пользователи windows могут безболезненно пропустить пару абзацев. А для пингвиноводов выложу ход действий, чтобы не было ненужных запинок на пустом месте.

1. Запускаем терминал.
~$ kermit
?OpenSSL libraries do not match required version:
. C-Kermit built with OpenSSL 1.0.0e 6 Sep 2011
. Version found OpenSSL 1.0.1 14 Mar 2012
OpenSSL versions prior to 1.0.0 must be the same.
Set LD_LIBRARY_PATH for OpenSSL 1.0.0e 6 Sep 2011.
Or rebuild C-Kermit from source on this computer to make versions agree.
C-Kermit makefile target: linux+krb5+openssl
Or if that is what you did then try to find out why
the program loader (image activator) is choosing a
different OpenSSL library than the one specified in the build.

All SSL/TLS features disabled.

C-Kermit 9.0.302 OPEN SOURCE:, 20 Aug 2011, for Linux+SSL+KRB5 (64-bit)
Copyright (C) 1985, 2011,
Trustees of Columbia University in the City of New York.
Type? or HELP for help.
2. Коннектимся.
C-Kermit>set line /dev/ttyACM0
C-Kermit>connect
Connecting to /dev/ttyACM0, speed 115200
Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by? to see other options.
?Carrier required but not detected.
***********************************
Hint: To CONNECT to a serial device that
is not presenting the Carrier Detect signal,
first tell C-Kermit to:

SET CARRIER-WATCH OFF

***********************************

C-Kermit>set speed 9600
/dev/ttyACM0, 9600 bps

C-Kermit>set carrier-watch off
C-Kermit>connect
Connecting to /dev/ttyACM0, speed 9600
Escape character: Ctrl-\ (ASCII 28, FS): enabled
Type the escape character followed by C to get back,
or followed by? to see other options.

Вот, собственно, и все.
Теперь можно общаться через терминал, как обычно.
> boot
4E4th-se v0.34 Apr 5 2012|110001110 Cold
>

Сегодня рассмотрим основные моменты, связанные с языком форт (forth). Форт был создан Чарльзом X. Муром в конце 1960-х — начале 1970-х годов и на тот момент являлся достойной альтернативой не только распространенному бейсику, но и многим операционным системам и средам.
Характерная особенность языка в том, что он на основе нескольких базовых примитивов (от менее чем двадцати до пятидесяти) саморасширяется до любого уровня программной абстракции путем ввода новых слов, состоящих из комбинаций базовых. Кто играл в «алхимию» на андроиде, должен понять :)

Также имеется особенность, которая сразу бросается в глаза и «выворачивает мозг» с непривычки при первом знакомстве — это стек как основной операнд и обратная польская нотация. То есть, практически всегда сначала следуют операнды, а потом действие, которое снимает необходимые данные со стека и кладет обратно результат.

Чтобы не быть голословным, приведу несколько примеров. Заодно познакомимся со «словарным запасом» нашей микросистемы, зашитой в контроллер ланчпада.
Весь глосарий (список слов) имеется в репозитории.


> 1 2 3 * + .
7  ok
>

Мы ввели три числа, которые последовательно легли на вершину стека данных (1 в самом низу, 3 сверху), затем умножили верхние два, затем сложили с оставшейся единицей и вывели результат на экран. Аналогично работают любые арифметические операции.
Сразу оговорюсь, что все операции по умолчанию целочисленные и 16-разрядные (что логично для 16-разрядной архитектуры). То есть стек оперирует не байтами, а т.н. ячейками (cell). Для повышенной точности, разрядности или операций с плавающей/фиксированной точкой необходимо подгружать специальные библиотеки.

Обычно при описании нового слова в комментарии приводят стековый портрет, то есть состояние ячеек стека до и после выполнения.
Посмотрим операции для работы со стеком:

DUP    x -- x x        duplicate top of stack
DROP   x --            drop top of stack
SWAP   x1 x2 -- x2 x1  swap top two items
ROT    x1 x2 x3 -- x2 x3 x1
NIP    x1 x2 -- x2

По-моему, дополнительных комментариев не требуется. Там же можно посмотреть остальные слова.
Подробнее сотит рассмотреть более сложные конструкции — условия и циклы.

Условный переход, как нетрудно догадаться, осуществляется с помощью конструкции if-then-else.
Но, естественно, все «не как у людей» :)

variable min
variable max
10 min !
20 max !

: minmax ( n -- minmax(n) )
    dup min @ < if drop min @
    else dup max @ > if drop max @ then
    then ;

Пробуем.
> 15 minmax.
15 ok
> 25 minmax.
20 ok
> 5 minmax.
10 ok
>

Что за китайская грамота? Ничего сложного, если мыслить «задом наперед».
Во-первых, вводим две переменных с помощью слова variable. Данное слово резервирует место в ОЗУ и привязывает его адрес к имени переменной. Далее, использем слова! и @ для записи (store) и чтения (fetch) переменной. Имя переменной имеет смысл адреса.

Далее самое интересное — if. Как видим, порядок слов переставлен — вместо привычного if-then-else необычное if-else-then.
Но все встает на место, если посмотреть стековую нотацию.
Слово if проверяет флаг, выставленный предыдущей операцией сравнения (<, >, 0=, 0< и т.д.) и в случае ненулевого значения выдает адрес ветки, следующей за ним. Если флаг не установлен, то выдается адрес ветки после else. А слово then осуществляет переход по выставленному адресу и выполнение нужной ветки.

Теперь попробуем организовать цикл.
Во-первых, любой цикл можно организовать с помощью уже знакомого нам условного перехода if. Однако, есть ещё несколько специальных слов для организации циклов.
В прошлый раз уже был показан цикл begin-until. Слово until проверяет флаг на стеке и переходит на начало цикла в случае нулевого значения. Если проверка не нужна, вместо until можно использовать again.

Ещё один цикл — аналог итерационного цикла for-next в бейсике и других языках.

: test_do_loop
    do i . loop ;

> 10 0 test_do_loop
0 1 2 3 4 5 6 7 8 9 ok
> 30 15 test_do_loop
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 ok
>
Слово do снимает с вершины стека значение и помещает его в специальную переменную-итератор. Вызвать значение итератора можно словом i во внешнем цикле и j во внутреннем. Далее значение итератора инкрементируется и сравнивается с оставшимся значением на стеке.

: table
 10 1 do
     10 1 do
         i j * u.r
     loop
 cr loop ;

и результат:

> table
    1    2    3    4    5    6    7    8    9
    2    4    6    8   10   12   14   16   18
    3    6    9   12   15   18   21   24   27
    4    8   12   16   20   24   28   32   36
    5   10   15   20   25   30   35   40   45
    6   12   18   24   30   36   42   48   54
    7   14   21   28   35   42   49   56   63
    8   16   24   32   40   48   56   64   72
    9   18   27   36   45   54   63   72   81
 ok
>

Получили красивую таблицу умножения.
(По сравнению с первоначальным вариантом немного улучшил, заменив простой вывод словом "." на форматный «U.R»)

В дополнение к loop есть слово +loop, которое снимает значение с вершины стека и прибавляет к итератору. То есть работает как STEP в бейсике, фортране и т.д.
Также, есть слово leave — аналог break.

Теперь попробуем сделать что-нибудь полезное для хозяйства.

> : getmem c@ dup . emit ." | " ;
 ok
> : dump 0 do dup 1+ swap getmem loop ;
 ok

Первое слово снимает адрес со стека и выдает по нему значение и код символа.
Второе распечатывает заданное количество адресов начиная с указанного.
> source dump
73 s| 6F o| 75 u| 72 r| 63 c| 65 e| 20 | 64 d| 75 u| 6D m| 70 p| ok
Слово source выкладывает на стек адрес и длину введенной строки во входном буфере.
Как видим, так оно и есть.

Задав любой адрес и длину участка памяти (любой), можно снять дамп.
Немного преобразовав слово, можно вывести впереди адрес, а дальше цепочку байт, как в HEX — редакторах.
Это вам домашнее задание :)

Ещё немного подумав, вывести сначала HEX-коды, а потом символьные эквиваленты (включая защиту от непечатных символов).
Но это уже проще сделать, используя массивы. Как? Пожалуй, в следующий раз.

В заключение несколько полезных ссылок для самостоятельного изучения:

Хорошие статьи по форту на википедии (раз и два) и луркоморье.

Книги:
Семёнов Ю.А «Программирование на языке Форт»,
Лео Броуди (Leo Brodie) "Начальный курс программирования на языке forth" (Starting Forth) и "Образ мышления — Forth" (Thinking Forth)
Последнюю книгу рекомендую категорически, независимо от религиозных предпочтений — просто для общего развития.

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

PS:
В конце прошлой статьи добавил небольшой бенчмарк — ногодрыганье в цикле для 4E4th и Energia для наглядного сравнения быстродействия ВМ и нативного кода.

PPS:
По просьбам трудящихся добавил книги из личной коллекции, в т.ч собственноручно сверстанный doc из красивого импортного латекса и текстового русского перевода

Первая часть: Введение
Третья часть: Лезем внутрь
  • +4
  • 06 ноября 2012, 18:45
  • MrYuran
  • 3

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

RSS свернуть / развернуть
В первый раз вижу что на дают ссылку на Лурк в серьезной статье, хотя много полезного там можно найти :)
0
на удивление не типичная для лурка статья.
0
Да не, по таким темам статьи обычно такие и есть. Лулзы, наиболее нужная инфа (вроде «для выхода из vi наберите ...»), лулзовая инфа поглубже.
0
ну, мое знакомство с лурком ограничивается именно лулзовой стороной.
0
Ну, все же кредо лурки — «факты > лулзы». По языкам программирования, некоторому софту (вин/лин/ви/емакс) и еще некоторым областям статьи интересные.
0
Напрасно, лурк зачастую весьма полезен именно как источник фактов. Особенно меня поражает настойчивость в докапывании до деталей истории появления того или иного мема.
0
Семёнов Ю.А «Программирование на языке Форт»
Ссылки не хватает)

Алсо пример с if я так и не понял. Если он возвращает адрес нужной ветки — почему дальше этот адрес дропается? Если сразу переходит на ветку — зачем еще какой-то код сразу после if?

P.S. Как название 4E4th вообще читается?)
0
  • avatar
  • Vga
  • 07 ноября 2012, 02:04
Семёнов Ю.А «Программирование на языке Форт»
Ссылки не хватает)
да вот ведь, на полочке стоит.
(глянул — и правда, все еще стоит...)
0
да и гуглится с полпинка. вот, например
а если лениво — значит, не настолько уж и нужно…
0
Верно, не настолько. Но с другой стороны, если есть ссылка — скачаю «про запас», если оно по интересной теме. Чтобы не забыть об этой книжке и вернуться к ней когда понадобится.

Алсо, можно еще Thinking Forth в формате для скачать, а не почитать онлайн?)
0
угу. у меня этого «Чтобы не забыть об этой книжке и вернуться к ней когда понадобится.» такие залежи, что проще скачать, чем порядок навести… %)

Алсо, можно еще Thinking Forth в формате для скачать, а не почитать онлайн?)
ну это самостоятельно. я за семеновым полез только потому, что удивился, как это он может не валяться на каждом углу.
0
угу. у меня этого «Чтобы не забыть об этой книжке и вернуться к ней когда понадобится.» такие залежи, что проще скачать, чем порядок навести… %)
bookfi.org… %bookname%… скачать… тыц… тыц… тыц… ой, а оно у меня уже есть :)
0
в точку. :)))
0
0
У них же вверху сайта написано Forth For Education, только наоборот читать нужно: 4(For)E(ducation)4(For)th.
0
Может я просто неточно расписал.
Адрес не дропаетая, он задается жестко на этапе компиляции.
Слово if формирует две ветки, а переход в зависимости от флага осуществляет слово then.
4е4th переводится очень просто.
4th обычно означает forth, в некоторых системах доже такое расширение дают форт-исходникам.
4е- 4euro. Итого, форт-система в железе за 4евро.
0
Про if все равно ничего не понял.

4е4th переводится очень просто.
Я все же спрашивал, как это прочитать, а не как оно расшифровывается :) Хотя, как выяснилось, расшифровку я понял неправильно (так же, как ibnteo).
0
Про if все равно ничего не понял.
Ну как же…
Пишем if и следом тру-шную ветку, далее else и альтернативную ветку, обе ветки (или одна, если без else) размещаются в кодовой секции во время компиляции. А слово then осуществляет непосредственный переход на нужную ветку в зависимости от флага на стеке данных. В общем, в следующий раз этот момент надо будет расписать подробно со ссылкой на исходники.
0
Т.е. then по сути является маркером конца if'а?
0
В общем-то да.
Тут есть тонкость.
Есть два режима, компиляции и интерпретации. if-else-then- это слова только режима компиляции.
Как это все работает:
Управляющая структура if else then
if комплирует команду условного перехода на фиктивный адрес -1, запоминая адрес
параметра команды на стеке.
: if -1 ?jmp THERE CELL — ;
then берет со стека адрес, и записывает по этому адресу текущее значение указателя
компиляции. адрес указывает на параметр команды jmp или ?jmp (метод backpatching при
однопроходной компиляции)
: then THERE SWAP w!;
: else -1 jmp THERE CELL — SWAP then;
в итоге из
a (flag ) if b else c then d
должен скомпилироваться код
a
:if ?jmp else
b
jmp then
:else
c
:then
d
0
Бывает, что делают и возможность для использования в режиме исполнения IF… ELSE… THEN
А так условное управление режимом трансляции кода через [IF] [DEF] [UNDEF] подобные слова. На детектирование и выдачи предупреждения на повторное переопределения слова тоже вводят слова, например REQUIRE
0
Загрузил бинарник в Ubuntu через
# mspdebug rf2500 "prog 4e4th.a43
, и не нужно никаких драйверов и загрузчиков ставить.
0
Ностальжи… :-)
Помню, где-то в шестом классе нашел в библиотеке книжку по форту и прочитал за один день. Потом даже писал программы на листочках. Компилятором был я сам, т.к. компьютеров не было с фортом, да и вообще не было ни у кого дома их.
А теперь вон оно как — в контроллер его запихнуть можно. С ума сойти…
0
Форт же. Смотри на лурке «поэтому первое, что делает начинающий фортер...» :)
0
Добавил книги, чтобы не мучили[сь] гугля
0
launchpad
после неудачной попытки обновления версии пишет:
msp430.dll initialization error
что делать?
0
Было чего-то такое. Выключил, включил, сом-порт освежил (удалил/обновил) — и все заработало.
0
В конце статьи на Лурке есть отличный пример: сложение на ассме. Посмотрев на него, у меня сразу в мозгах всё встало на место и я понял, что же такое Форт.
Всё очень просто: Форт — это ассемблер высокого уровня (АВУ).
:-)
0
  • avatar
  • Alfa
  • 07 ноября 2012, 15:21
Практически, так и есть. Своеобразный макроассемблер виртуальной стековой машины.
Между прочим, на нем очень просто написать самый что ни на есть натуральный ассемблер для железа, но с человеческим лицом.
А вот если к нему сверху прикрутить фронтенд с какого-либо ЯВУ… Что, собственно, создатели C# и сделали.
0
То есть, форт вполне годится для уровня RTL — платформонезависимого абстрактного ассемблера
0
IL тогда уж. RTL — библиотека.
0
А это смотря как перевести :)
Register transfer language (англ.) — разновидность структур данных, служащих для представления исполняемого кода программ; также, платформенно-независимый язык ассемблера. Используется, в частности, в GNU Compiler Collection.
GNU RTL
Хотя да, форт таки ближе к IL, чем что бы то ни было.
0
Аббревиатуры такие аббревиатуры… Я под RTL понял «Run-Time Library». Примерно то, что в С называется libc.
0
После первой статьи я склонялся в сторону полезности сабжа. Да, без среды можно подправить глючный блок, или по удаленке писать програмки.
Но вот после этого if-а… я уверен в абсолютной практической непригодности сабжа. Гораздо проще по диалапу выкачать полугиговую студию, чем разобраться в этом.
0
Гораздо проще по диалапу выкачать полугиговую студию, чем разобраться в этом.
Да не. Достаточно один раз вывихнуть мозг. Впрочем, скриптовалки не только фортовые бывают.
0
Я и не против скриптовалок, я за них. Но конкретно рассмотренный пример не дает основного плюса «традиционных скриптовых систем», а именно простоты изменения алгоритма. Чесное слово, проще на асме (самопальной ВМ) наваять.
0
Да не так уж страшен форт… наверное… Если освоить. Оно просто непривычно из-за нотации «задом наперед».
0
Нотация не задом наперёд, а последовательность выполняемых действий словами.
Бывает и при вычислении обычных математических формул не вводят приоритеты операций и тем более скобки.
0
Нотация не задом наперёд, а последовательность выполняемых действий словами.
Не понял.
0
Деление слов на действия и операнды для этих действий это «условная» точка рассмотрения предмета.
Например две фразы эквивалентны,
Включить мотор или Мотор включить и какая из них задом наперёд?
Удобство из личных предпочтений задаёт пишуший, а читателя может коробить написанное.
Слово Форта изоморфно (может быть всем чем угодно) и может пониматься и наполняться смыслом от наших предпочтений. Общее лишь то что приёмное и передающее слова объёденены знанием взаимного контекста использования.
Как то так.
0
Может даже не использования т.к. его может взаимного не быть,
а сопряжения (без знания кто примет выход и от кого мы получаем вход)
Связь только в нашем использовании так или этак возможности конкретного
сопряжения (интерфейса). Отсюда и возможность выстраивать замысловатые
управляющие конструкции языка и неограниченные возможности к мимикрии.
0
Включить мотор или Мотор включить и какая из них задом наперёд?
Только в русском. Да и то, магистра Йоды речь передаваема и им.
А для языков программирования префиксная, постфиксная и инфиксная нотации тем более различимы, и для большинства программеров привычна инфиксная. В форте же постфиксная.
0
Согласен это только привычка видеть или работать с языком
определённым привычным способом. (при обработке же информации в мозгу, как выяснилось последовательность символов в слове не играет существенной роли и прочтение контекста текста почти не срадает).
Только в русском? Тогда почему бы не использовать уже пределённым образом существующий механизм обработки информации в мозге?
0
Зачем загонять мышление, в рамки искуственно выстроенных систем?
Форт тоже искуственная система, но гораздо более демократична
для оперирования информацией. (но тут могут быть возражения)
0
Я тебя не понимаю. Не знаю уж о чем ты там пытаешься сказать, но изложение своих мыслей на русском у тебя определенно страдает.
0
Я тоже не понимаю. Там это где?
0
Я тоже не понимаю. Там это где?
«Тут вам не там!»
0
А разве не «здесь вам не тут!»?
0
У ассемблера тоже сначала команда анализа флагов, а потом команда перехода.
слово IF немного сбивает с толку, но можно само условие обозначить через IF(… )… ELSE… ENDIF
и Форт расширить до понимания такой конструкции.
0
Отчасти поэтому и введено двух-словное определение Форт система,
при этом Форт система может расширится, например, произвольными управляющими конструкциями (это и другие свойства повлияли на выбор использования мною данного языка при знакомстве с ним)
Бывают ещё упрощённые «скриптовалки» но их часто называют Форт подобными (ориентированными на упрощёное использование форт слов)
0
Присоединяюсь!
Для решения типовых задач (поморгать светиками, покрутить серву, считать с датчика температуру или пообщаться с компом по последовательному порту) применительно на MSP430 есть более эффективные инструменты — Форт для этого дела вообще как козе баян.

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

Такое ощущение, что у людей, помешанных на Форте, считается нормальным явлением не только «вывернутое на изнанку» написание программ, а еще и понимание сути вещей: сначала изобретают жуткий инструмент, а потом начинают лихорадочно искать сферу его применения. Куда бы его прикрутить?

Беда.
+1
Что можно возразить?
Только рассмотрение предложенного направления может определить задачи для использования или нет данного инструментария в профессиональной практике.
0
Привыкаешь довольно быстро.
Как это работает внутри — пользователю тоже знать необязательно.
Кстати говоря, можно даже без обратной нотации обойтись, введя для удобства пользователя необходимые immediate слова, которые будут парсить входной буфер и перекладывать последующие аргументы на стек. Это уж чтобы совсем глянцем отсвечивало.
0
Для «глубокого» изменения работающего кода, предусмотрены разные механизмы
Обычное переопределение слов, переопределение векторизованных слов вводимых через DEFER name
стиранием слов из памяти и др. + сама Форт система достаточно прозрачна для понимания.
0
Что означает двойное тире — ?
0
Перечитал первую статью и понял. Все что в скобках — комментарий раскрывающий смысл команды.
0
Да, скобки — это комментарий. Аналог /* */
Обратный слеш — комментарий до конца строки. Так уж повелось, ведь форт был разработан задолго до си.
Но никто не мешает его переопределить

: // \ ;
: /** ( ;
: **/ ) ;

Я сознательно написал **/, т.к. слово */ в форте уже есть и оно означает умножение на дробь
0
Переопределение комментариев в таком виде, скорее всего не приведёт к желаемому результату т.к. это скорее всего «активные» IMMEDIATE слова и для их переопределения обычно в Форт системе существует слово POSTPONE \ скомпилировать семантику выполнения заданного слова
: // POSTPONE \;
: /** POSTPONE (; \ закрывающую скобку обычно ищет само это слово
но могут быть ньюансы, если слова определены только для режима исполнения
Некоторые Форт системы используют основным режимом режим компиляции,
с убиранием или ослаблением влияния STATE переменной
0
Да, так оно и есть.
Но в стандарте 94года добавили возможность использования локальных именованных переменных внутри слова и определили для использования этой возможности удачно или нет такие скобки {… }
0
Если запрограммировать ввод и вывод Морзе кода (кнопка есть, и один из светодиодов), то получим автономное устройство для разработки программ, можно же две батарейки подключить. Форт немногословен, поэтому вводить программу не составит труда. Ну или в крайнем случае, использовать этот интерфейс для перенастройки или снятия данных с работающего где-либо устройства.
+1
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.