PDFORTH = Public Domain FORTH для PIC16F87X

8-битные микроконтроллеры PICmicro (ПИКи) от Microchip и совместимые, а также 16-битные PIC24 и 32-битные PIC32

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Возвращаясь к нашим ламповым экскрементам - нашёл кстати очень удобное описание ключевых слов стандарта 83

Code: Select all

IF           flag --                       C,I,79               
                       -- sys   (compiling)
               Used in the form:                     
                       flag IF ... ELSE ... THEN     
               or      
                       flag IF ... THEN              
               If flag is true, the words following IF are executed and the
               words following ELSE until just after THEN are skipped.  The
               ELSE part is optional.                
               
               If flag is false, the words from IF through ELSE , or from
               IF through THEN (when no ELSE is used), are skipped.  sys is
               balanced with its corresponding ELSE or THEN .  
               See:  "9.9 Control Structures"
Итак, компилятор, встречая IF, должен скомпилить его вот в такой код:

Code: Select all

  MOVF INDF,W ; read lower byte from stack
  INCF FSR,F
  IORWF INDF,W ; bitwise OR with higher byte from stack
  INCF FSR,F
  IORLW 0 ; set Z flag based on result
  BTFSC STATUS,2 ; skip if Z=0
  GOTO 0 ; goto if Z=1
при этом запоминая на стеке адресов адрес, где сидит GOTO 0, чтобы потом подменить его на нужный GOTO с адресом, идущим после ELSE или THEN (который в Форте обозначает ENDIF).

Далее компилируем как обычно и при нахождении ELSE пишем:

Code: Select all

  GOTO 0 ; goto to the end
ELSE_LABEL:
корректируя при этом GOTO по сохранённому ранее адресу на стеке адресов, прописывая туда адрес метки, идущей за GOTO, и сохраняя адрес нового GOTO на этом самом стеке для будущей коррекции - назвать его чтоли "system stack"?

Потом добираясь таки до THEN (по русски говоря ENDIF), просто вытаскиваем из системного стека адрес GOTO и корректируем его, прописывая в нём текущий адрес компиляции. Такой подход позволяет обработать оба случая - и с ELSE, и без.

P.S. Так как адреса у нас короче 64K, то старшие биты сохраняемых на стеке адресов (которых при 13-битном адресе имеется целых 3) можно использовать для тегирования сохраняемого, чтобы вылавливать случаи, когда юзер запутавшись пишет LOOP после IF или THEN без IF...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

На самом деле первую часть вот этого:

Code: Select all

  MOVF INDF,W ; read lower byte from stack
  INCF FSR,F
  IORWF INDF,W ; bitwise OR with higher byte from stack
  INCF FSR,F
  IORLW 0 ; set Z flag based on result
  BTFSC STATUS,2 ; skip if Z=0
  GOTO 0 ; goto if Z=1 
можно было бы затолкать в подпрограмму:

Code: Select all

TEST0:
  MOVF INDF,W ; read lower byte from stack
  INCF FSR,F
  IORWF INDF,W ; bitwise OR with higher byte from stack
  INCF FSR,F
  IORLW 0 ; set Z flag based on result
  RETURN
и тогда IF скомпилируется вот в это:

Code: Select all

  CALL TEST0
  BTFSC STATUS,2 ; skip if Z=0
  GOTO 0 ; goto if Z=1 
что уменьшит размер кода (если IF-ов будет много), но замедлит программу чуть ли не в 2 раза...

P.S. по идее можно научить компилятор самостоятельно делать "inline" компиляцию вставляя внутренности подпрограммы вместо её вызова и делать это пользуясь неким порогом, если длина подпрограммы короче порога, то вставлять текст подпрограммы вместо CALL - порог можно завести как переменную, которую пользователь может менять...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote: А вот CONSTANT/VALUE, чтобы отличить его от VARIABLE (а также для скорости) можно делать напрямую без вызова PUSH:

Code: Select all

XXX:
 DECF FSR,F
 MOVLW higher-byte
 MOVWF INDF
 DECF FSR,F
 MOVLW lower-byte
 MOVWF INDF
 RETURN
Другой вопрос как отличить VALUE от CONSTANT, чтобы в первом случае давало модифицировать higher-byte и lower-byte, а во втором - нет. Например в случае CONSTANT можно перед RETURN поставить лишний NOP, хотя возможно в первой версии будет только VALUE...
Проверил в gforth - меняя VALUE меняется и программа, её использующая, а вот пересозданная CONSTANT поведение ранее откомпилированной программы НЕ меняет - т.е. установка константы на стек по сути компилируется прямо так - без CALL (как и чисел). Также вставку кода подпрограммы использующей VALUE непосредственно в код вместо CALL для оптимизации надо запретить, т.к. в таком случае невозможно будет изменить значение VALUE с помощью TO - запрещать оптимизацию некоторых подпрограмм можно путём их маркирования, например расположив NOP в конце (перед RETURN) мы сообщим оптимизирующему компилятору о том, что вызов этой подпрограммы оптимизировать ненадо. Аналогичным образом можно реализовать IMMEDIATE-слова (которые не компилируются, а вызываются сразу после ввода юзером) путём пометки подпрограммы NOP-ом вначале - таким образом можно реализовать FORGET и MARKER, а то и :
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote:P.S. Так как адреса у нас короче 64K, то старшие биты сохраняемых на стеке адресов (которых при 13-битном адресе имеется целых 3) можно использовать для тегирования сохраняемого, чтобы вылавливать случаи, когда юзер запутавшись пишет LOOP после IF или THEN без IF...
Например можно задействовать 2 старших бита (оставив остальные 14 для представления адресов в пределах 16K):

00 - IF...ELSE...THEN
01 - BEGIN ... AGAIN / UNTIL / WHILE
10 - WHILE ... REPEAT
11 - DO ... LOOP (LEAVE, UNLOOP, +LOOP, ?DO, I, J)

Для сложного случая BEGIN ... WHILE ... REPEAT придётся заюзать 2 разных тэга - 01 для первой половины (до WHILE) и 10 - для второй (после WHILE)

P.S. По идее UNLOOP нужен только чтобы прекратить выполнение цикла перед EXIT (которое покидает описание слова - будет компилироваться в RETURN) - это было сделано для тех форт-систем, которые совмещали стек возвратов и стек адресов для циклов - в нашем случае этого не понадобиться (т.к. в стек возвратов пика всё равно не залезешь), но для совместимости можно и поддержать...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote:P.P.S. Форт у нас интерактивный, т.е. он должен позволять ввести интерактивно что-то и сразу же получить результат - в этом случае компиляции в память программ происходить не должно - придётся делать интерпретацию на лету, хотя для начала можно и компилировать - тогда просто пик быстрее из строя выйдет по причине изношенности флеша, но это уже не суть.
На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO - можно по идее тоже самое сделать, но тогда нужно как-то отличать такие слова от обычных - например если они все будут IMMEDIATE (NOP как первая инструкция в коде слова) - т.е. интерактивный интерпретатор будет выполнять слова, пока не встретит первое IMMEDIATE слово, на котором он остановится и сбросит состояние в начало (освободит стек и т.д.).
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Итак, при включении форт-система ждёт команды от юзера на последовательном порту - если это : то это ввод нового слова - компилируем его строка за строкой пока не встретим ; либо ; IMMEDIATE. Теперь о том как лучше маркировать IMMEDIATE - т.к. до самого последнего момента форт не знает будет это слово IMMEDIATE или нет мы должны маркировать его в конце (либо ставить этот флаг в заголовке уже после компиляции). Предположим, что кроме длины слова и самого слова мы в заголовок ещё воткнём размер слова (для того чтобы оптимизатор мог заранее понять, надо ли при компиляции копировать содержимое слова либо воткнуть CALL) и флаги (один из которых будет IMMEDIATE). Например описание слова DROP может выглядеть так:

Code: Select all

 DATA (0x04<<8)|'D' ; word length and 1st character of the name
 DATA (('R'-0x20)<<8)|'O'
 DATA (('P'-0x20)<<8)
 DATA 0x0303 ; flags and size
DROP:
 INCF FSR,f
 INCF FSR,f
 RETURN 
Сразу за именем идёт 14-битный описатель где старшие 6 бит это флаги, а младшие 8 - размер (соответственно размер не должен быть больше 255 пико-слов). Флаги могут быть такими:

bit 13 - immediate
bit 12 - never inline
bit 11 - always inline (хотя это наверное можно сделать через immediate?)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Shaos wrote: На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO - можно по идее тоже самое сделать, но тогда нужно как-то отличать такие слова от обычных - например если они все будут IMMEDIATE (NOP как первая инструкция в коде слова) - т.е. интерактивный интерпретатор будет выполнять слова, пока не встретит первое IMMEDIATE слово, на котором он остановится и сбросит состояние в начало (освободит стек и т.д.).
Тут выходит, что IMMEDIATE для компилятора тоже будет (TO, VALUE, CONSTANT) т.е. флаги надо делать так:

bit 13 - immediate for compiler
bit 12 - immediate for interpreter
bit 11 - never inline
bit 10 - always inline
bit 9 - reserved
bit 8 - reserved

Два резервных бита можно заюзать для представления длин до 1K (вместе со следущим байтом).

P.S. Длина подпрограммы будет использоваться для того, чтобы перескочить на начало следующей при поиске слов.

P.P.S. Одновременное взведение флагов "never inline" и "always inline" может быть использовано для запрещения отдельных слов (или новых версий слов, чтобы при компиляции использовать старые).
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

Вроде всё хорошо получается - по идее и для других платформ можно сделать имплементацию, включая 8080, 8086 и RW0 (чем не платформа? ; )
Я тут за главного - если что шлите мыло на me собака shaos точка net
b2m
Devil
Posts: 907
Joined: 26 May 2003 06:57

Post by b2m »

Shaos wrote:bit 12 - immediate for interpreter
В режиме интерпретации абсолютно все слова выполняются, этот флаг не нужен. После выполнения ":" устанавливается переменная state, и интерпретатор (он же и компилятор) выполняет только слова, помеченные immediate, остальные он складывает по адресу here. Слово ";" (кстати помеченное immediate) сбрасывает переменную state. Вот и весь секрет.
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/
b2m
Devil
Posts: 907
Joined: 26 May 2003 06:57

Post by b2m »

Shaos wrote:На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO
Т.к. это immediate-слова, они, как и все остальные immediate-слова, проверяют в самом начале переменную state, и если выполнение в данном контексте не имеет смысла, вываливаются по ошибке (очищается входной буфер, стек).
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

b2m wrote:
Shaos wrote:bit 12 - immediate for interpreter
В режиме интерпретации абсолютно все слова выполняются, этот флаг не нужен. После выполнения ":" устанавливается переменная state, и интерпретатор (он же и компилятор) выполняет только слова, помеченные immediate, остальные он складывает по адресу here. Слово ";" (кстати помеченное immediate) сбрасывает переменную state. Вот и весь секрет.
А как же IF и DO? Они в режиме интерпретации НЕ выполняются, во всяком случае на gforth...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 24008
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Post by Shaos »

b2m wrote:
Shaos wrote:На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO
Т.к. это immediate-слова, они, как и все остальные immediate-слова, проверяют в самом начале переменную state, и если выполнение в данном контексте не имеет смысла, вываливаются по ошибке (очищается входной буфер, стек).
Я тоже про это думал, но тогда в каждую подпрограмму таких слов придётся вставлять проверку флага - а тут как бы интерпретатор/компилятор эту проверку делает сам и сам ругается, если слово не подразумевается быть интерпретируемым или наоборот - компилируемым, т.е. на лицо экономия в размерах программного кода...
Я тут за главного - если что шлите мыло на me собака shaos точка net
b2m
Devil
Posts: 907
Joined: 26 May 2003 06:57

Post by b2m »

Shaos wrote:Я тоже про это думал, но тогда в каждую подпрограмму таких слов придётся вставлять проверку флага - а тут как бы интерпретатор/компилятор эту проверку делает сам и сам ругается, если слово не подразумевается быть интерпретируемым или наоборот - компилируемым, т.е. на лицо экономия в размерах программного кода...
В таком случае интерпретация будет медленнее. В форте цикл интерпретатора используется даже при загрузке из файла, а в этом случае скорость интерпретации очень даже критична. Хотя, по сравнению с поиском слова в словаре, проверка флага - просто пшик. Какой-нибудь хеш по первым двум буквам с лихвой окупит эти затраты :)

Если очень хочется, можно сделать флаг "compiler only".
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/
forthuser
Senior
Posts: 165
Joined: 12 Jan 2023 07:26

Re: PDFORTH = Public Domain FORTH для PIC16F87X

Post by forthuser »

И чем эпопея с Форт для PIC16F87X закончилась?

Для более продвинутых PIC есть https://FlashForth.com
forthuser
Senior
Posts: 165
Joined: 12 Jan 2023 07:26

Re: PDFORTH = Public Domain FORTH для PIC16F87X

Post by forthuser »

Г.Р.Алпатов: Применение PIC-контроллеров в измерительной технике Учебно-методическое пособие[/url] (ЮЖНЫЙ ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ):

https://energy4all.ru/forth/books/UMP_PIC-kontrollery.pdf

https://www.forth.org.ru/~cactus/pic_forth.html