nedoPC.org

Electronics hobbyists community established in 2002
Atom Feed | View unanswered posts | View active topics It is currently 28 Mar 2024 02:48



Reply to topic  [ 30 posts ]  Go to page Previous  1, 2
PDFORTH = Public Domain FORTH для PIC16F87X 
Author Message
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Возвращаясь к нашим ламповым экскрементам - нашёл кстати очень удобное описание ключевых слов стандарта 83

Code:
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:
  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:
  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...

_________________
:dj: https://mastodon.social/@Shaos


10 Dec 2014 22:26
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
На самом деле первую часть вот этого:

Code:
  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:
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:
  CALL TEST0
  BTFSC STATUS,2 ; skip if Z=0
  GOTO 0 ; goto if Z=1


что уменьшит размер кода (если IF-ов будет много), но замедлит программу чуть ли не в 2 раза...

P.S. по идее можно научить компилятор самостоятельно делать "inline" компиляцию вставляя внутренности подпрограммы вместо её вызова и делать это пользуясь неким порогом, если длина подпрограммы короче порога, то вставлять текст подпрограммы вместо CALL - порог можно завести как переменную, которую пользователь может менять...

_________________
:dj: https://mastodon.social/@Shaos


10 Dec 2014 23:12
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Shaos wrote:
А вот CONSTANT/VALUE, чтобы отличить его от VARIABLE (а также для скорости) можно делать напрямую без вызова PUSH:
Code:
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, а то и :

_________________
:dj: https://mastodon.social/@Shaos


10 Dec 2014 23:49
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
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) - это было сделано для тех форт-систем, которые совмещали стек возвратов и стек адресов для циклов - в нашем случае этого не понадобиться (т.к. в стек возвратов пика всё равно не залезешь), но для совместимости можно и поддержать...

_________________
:dj: https://mastodon.social/@Shaos


11 Dec 2014 00:31
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Shaos wrote:
P.P.S. Форт у нас интерактивный, т.е. он должен позволять ввести интерактивно что-то и сразу же получить результат - в этом случае компиляции в память программ происходить не должно - придётся делать интерпретацию на лету, хотя для начала можно и компилировать - тогда просто пик быстрее из строя выйдет по причине изношенности флеша, но это уже не суть.


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

_________________
:dj: https://mastodon.social/@Shaos


11 Dec 2014 01:15
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Итак, при включении форт-система ждёт команды от юзера на последовательном порту - если это : то это ввод нового слова - компилируем его строка за строкой пока не встретим ; либо ; IMMEDIATE. Теперь о том как лучше маркировать IMMEDIATE - т.к. до самого последнего момента форт не знает будет это слово IMMEDIATE или нет мы должны маркировать его в конце (либо ставить этот флаг в заголовке уже после компиляции). Предположим, что кроме длины слова и самого слова мы в заголовок ещё воткнём размер слова (для того чтобы оптимизатор мог заранее понять, надо ли при компиляции копировать содержимое слова либо воткнуть CALL) и флаги (один из которых будет IMMEDIATE). Например описание слова DROP может выглядеть так:
Code:
 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?)

_________________
:dj: https://mastodon.social/@Shaos


12 Dec 2014 07:30
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
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" может быть использовано для запрещения отдельных слов (или новых версий слов, чтобы при компиляции использовать старые).

_________________
:dj: https://mastodon.social/@Shaos


13 Dec 2014 09:08
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
Вроде всё хорошо получается - по идее и для других платформ можно сделать имплементацию, включая 8080, 8086 и RW0 (чем не платформа? ; )

_________________
:dj: https://mastodon.social/@Shaos


14 Dec 2014 21:54
Profile WWW
Devil

Joined: 26 May 2003 06:57
Posts: 859
Reply with quote
Post 
Shaos wrote:
bit 12 - immediate for interpreter

В режиме интерпретации абсолютно все слова выполняются, этот флаг не нужен. После выполнения ":" устанавливается переменная state, и интерпретатор (он же и компилятор) выполняет только слова, помеченные immediate, остальные он складывает по адресу here. Слово ";" (кстати помеченное immediate) сбрасывает переменную state. Вот и весь секрет.

_________________
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/


18 Dec 2014 05:47
Profile WWW
Devil

Joined: 26 May 2003 06:57
Posts: 859
Reply with quote
Post 
Shaos wrote:
На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO

Т.к. это immediate-слова, они, как и все остальные immediate-слова, проверяют в самом начале переменную state, и если выполнение в данном контексте не имеет смысла, вываливаются по ошибке (очищается входной буфер, стек).

_________________
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/


18 Dec 2014 06:40
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
b2m wrote:
Shaos wrote:
bit 12 - immediate for interpreter

В режиме интерпретации абсолютно все слова выполняются, этот флаг не нужен. После выполнения ":" устанавливается переменная state, и интерпретатор (он же и компилятор) выполняет только слова, помеченные immediate, остальные он складывает по адресу here. Слово ";" (кстати помеченное immediate) сбрасывает переменную state. Вот и весь секрет.


А как же IF и DO? Они в режиме интерпретации НЕ выполняются, во всяком случае на gforth...

_________________
:dj: https://mastodon.social/@Shaos


18 Dec 2014 07:55
Profile WWW
Admin
User avatar

Joined: 08 Jan 2003 23:22
Posts: 22409
Location: Silicon Valley
Reply with quote
Post 
b2m wrote:
Shaos wrote:
На самом деле gforth отказывается интерактивно выполнять программы, в которых есть компилируемые слова типа IF и DO

Т.к. это immediate-слова, они, как и все остальные immediate-слова, проверяют в самом начале переменную state, и если выполнение в данном контексте не имеет смысла, вываливаются по ошибке (очищается входной буфер, стек).


Я тоже про это думал, но тогда в каждую подпрограмму таких слов придётся вставлять проверку флага - а тут как бы интерпретатор/компилятор эту проверку делает сам и сам ругается, если слово не подразумевается быть интерпретируемым или наоборот - компилируемым, т.е. на лицо экономия в размерах программного кода...

_________________
:dj: https://mastodon.social/@Shaos


18 Dec 2014 11:45
Profile WWW
Devil

Joined: 26 May 2003 06:57
Posts: 859
Reply with quote
Post 
Shaos wrote:
Я тоже про это думал, но тогда в каждую подпрограмму таких слов придётся вставлять проверку флага - а тут как бы интерпретатор/компилятор эту проверку делает сам и сам ругается, если слово не подразумевается быть интерпретируемым или наоборот - компилируемым, т.е. на лицо экономия в размерах программного кода...

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

Если очень хочется, можно сделать флаг "compiler only".

_________________
Страничка эмулятора наших компьютеров
http://bashkiria-2m.narod.ru/


18 Dec 2014 12:43
Profile WWW
Senior

Joined: 12 Jan 2023 07:26
Posts: 165
Reply with quote
И чем эпопея с Форт для PIC16F87X закончилась?

Для более продвинутых PIC есть FlashForth


12 Jan 2023 09:06
Profile
Senior

Joined: 12 Jan 2023 07:26
Posts: 165
Reply with quote
Г.Р.Алпатов: Применение PIC-контроллеров в измерительной технике
Учебно-методическое пособие
(ЮЖНЫЙ ФЕДЕРАЛЬНЫЙ УНИВЕРСИТЕТ)

Pic Forth


12 Jan 2023 09:36
Profile
Display posts from previous:  Sort by  
Reply to topic   [ 30 posts ]  Go to page Previous  1, 2

Who is online

Users browsing this forum: No registered users and 7 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to:  
Powered by phpBB® Forum Software © phpBB Group
Designed by ST Software.