Files
ueforth/ueforth/site/index.html
2021-02-07 00:57:58 -08:00

642 lines
18 KiB
HTML

<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>EForth</title>
<style>
body {
max-width: 800px;
}
h1 {
border-top: 3px solid #777;
background-color: #111;
color: #eee;
padding: 10px;
margin-top: 0;
}
h2 {
border-top: 2px solid #777;
background-color: #ccc;
padding: 10px;
}
h3 {
border-top: 1px solid #777;
background-color: #eee;
padding: 10px;
}
h5 {
margin: 2px;
}
</style>
</head>
<body>
<h1>EForth</h1>
<p>
EForth is a delightfully minimalist approach to Forth originated by Bill Muench and Dr. C. H. Ting.
</p>
<h2>Downloads</h2>
<h3>µEforth</h3>
<p>
A reduced cross-platform EForth version
</p>
<ul>
<li><a href="static/ueforth-arduino-esp32.zip">ueforth-arduino-esp32.zip</a>
- <b>ESP32 Arduino</b> Source Code <b>&larr; SVFIG & Forth2020 folks start here!</b>
<ul>
<li><b>Regular ESP32 (may work better with your particular board)</b>
<ul>
<li><b>Board:</b> ESP32 Dev Module</li>
<li><b>Partition Scheme:</b> No OTA (2M APP, 2M SPIFFS) <b>&larr; Non-default</b></li>
<small>
<li><b>Upload Speed:</b> 921600</li>
<li><b>CPU Frequency:</b> 240MHz</li>
<li><b>Flash Frequency:</b> 80MHz</li>
<li><b>Flash Mode:</b> QIO</li>
<li><b>Flash Size:</b> 4MB</li>
<li><b>Core Debug Level:</b> None</li>
<li><b>PSRAM:</b> Disabled</li>
</small>
</ul>
</li>
<li><b>ESP32-CAM</b>
<ul>
<li><b>Board:</b> AI Thinker ESP32-CAM</li>
</ul>
</li>
</ul>
</li>
<li><a href="static/uEf32.exe">uEf32.exe</a> - Window 32-bit EXE µEforth</li>
<li><a href="static/uEf64.exe">uEf64.exe</a> - Window 64-bit EXE µEforth</li>
<li><a href="static/ueforth.linux">ueforth.linux</a> - Linux 64-bit Executable µEforth</li>
</ul>
<p>
<a href="https://github.com/flagxor/eforth" target="_blank">http://github.com/flagxor/eforth</a>
- Complete Source Code (under ueforth)
</p>
<h2>µEforth</h2>
<h3>µEforth Specific Words</h3>
<h5>Null Terminated Strings</h5>
<p>
As null terminated strings are used by virtually all platforms,
their use is supported in Forth by way of several non-standard
words with the convention of using Z/z to refer to such strings
in names and stack comments.
</p>
<pre>
Z" ( "string" -- z ) Creates a null terminated string on the heap
Z&gt;S ( z -- a n ) Convert a null terminated string to a counted string
S&gt;Z ( a n -- z ) Conver a counted string string to null terminated (copies string to heap)
</pre>
<h5>Raw Strings</h5>
<p>
Raw strings are provided better support using a string
for the duration of the current command, without consuming heap memory.
</p>
<pre>
R" ( "string" -- a n ) Creates a temporary counted string
R| ( string| -- a n ) Creates a temporary counted string ending with |
</pre>
<h5>Utilities</h5>
<pre>
DUMP ( a n -- ) Dump a memory region
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h5>Vocabularies</h5>
<p>
µEforth uses a hybrid of Forth-79 and Forth-83 style vocabularies.
By default vocabularies chain to the vocabulary in which they were defined,
as in Forth-79. However, like Forth-83, <code>ALSO</code>
can be used to add vocabularies to a vocabulary stack of which
<code>CONTEXT @</code> is the first item.
The word <code>ONLY</code> clears the vocabulary stack, but as there is
no separate ONLY vocabulary, it also sets <code>CONTEXT</code>
to the <code>FORTH</code> vocabulary.
The word <code>SEALED</code> modifies the most recently defined vocabulary
such that it does not chain. Note, this must be done before words are added to it.
</p>
<pre>
VOCABULARY ( "name" ) Create a vocabulary with the current vocabulary as parent
FORTH ( -- ) Make the FORTH vocabulary the context vocabulary
DEFINITIONS ( -- ) Make the context vocabulary the current vocabulary
VLIST ( -- ) List the words in the context vocabulary (not chains)
WORDS ( -- ) List the words in the context vocabulary (including chains)
TRANSFER ( "name" ) Move a word from its current dictionary to the current vocabulary
Useful for "hiding" built-in words
ALSO ( -- ) Duplicate the vocabulary at the top of the vocabulary stack
ONLY ( -- ) Reset context stack to one item, the FORTH dictionary
Non-standard, as there's no distinct ONLY vocabulary
ORDER ( -- ) Print the vocabulary search order
SEALED ( -- ) Alter the last vocabulary defined so it doesn't chain
</pre>
<h5>Block Editor</h5>
<pre>
USE ( "name" -- ) Use "name" as the blockfile, e.g. USE /spiffs/foo
OPEN-BLOCKS ( a n -- ) Open a file as the block file
LOAD ( n -- ) Evaluate a block
THRU ( a b -- ) Load blocks a thru b
LIST ( n -- ) List a block
L ( -- ) List the current block
WIPE ( -- ) Blank out the current block
D ( n -- ) Delete a line in the current block
E ( n -- ) Clear a line in the current block
R ( n "text" -- ) Replace a line in the current block
A ( n "text" -- ) Add (insert) a line in the current block
SEE ( "name" -- ) Attempt to decompile a word
VARIABLE ECHO -- Determines if commands are echoed
</pre>
<h3>ESP32 Arduino</h3>
<h4>ESP32 Arduino Opcodes</h4>
<p>
Because Arduino builds a statically linked image for flashing into ESP32 devices,
all C function bindings need to be explicitly added.
This is the current collection.
Typically to reduce confusion, function names have be preserved even through verbose.
In popular cases a shorted higher level name is provided.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino.template.ino">arduino.template.ino</a>.
</p>
<h5>Allocation</h5>
These words are inside the <code>internals</code> vocabulary.
<pre>
MALLOC ( n -- a | 0 ) System malloc
SYSFREE ( a -- ) System free
REALLOC ( a n -- a | 0 ) System realloc
</pre>
<h5>Serial</h5>
These words are inside the <code>Serial</code> vocabulary.
<pre>
Serial.begin ( baud -- ) Start serial port
Serial.end ( -- ) End serial port
Serial.available ( -- f ) Is serial data available
Serial.readBytes ( a n -- n ) Read serial bytes, return number gotten
Serial.write ( a n -- n ) Write serial bytes
Serial.flush ( -- ) Flush serial buffer
</pre>
<h5>Serial Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
SerialBT.new ( -- bt ) Allocate new BT object
SerialBT.delete ( bt -- ) Free BT object
SerialBT.begin ( localname ismaster bt -- f )
SerialBT.end ( bt -- )
SerialBT.available ( bt -- f )
SerialBT.readBytes ( a n bt -- n )
SerialBT.write ( a n bt -- n )
SerialBT.flush ( bt -- )
SerialBT.hasClient ( bt -- f )
SerialBT.enableSSP ( bt -- )
SerialBT.setPin ( z bt -- f )
SerialBT.unpairDevice ( addr bt -- f )
SerialBT.connect ( remotename bt -- f )
SerialBT.connectAddr ( addr bt -- f )
SerialBT.disconnect ( bt -- f )
SerialBT.connected ( timeout bt -- f )
SerialBT.isReady ( checkMaster timeout -- f ) Default checkMaster=false, timeout=0
</pre>
<h5>Bluetooth</h5>
These words are inside the <code>bluetooth</code> vocabulary.
<pre>
esp_bt_dev_get_address ( -- a ) addr of 6 byte mac address
</pre>
<h5>GPIO</h5>
<pre>
pinMode ( pin mode -- ) Set GPIO pin mode
digitalWrite ( pin value -- ) Set GPIO pin state
analogRead ( pin -- n ) Analog read from 0-4095
</pre>
<h5>ledc</h5>
These words are inside the <code>ledc</code> vocabulary.
<pre>
ledcSetup ( channel freq resolution -- freq )
ledcAttachPin ( pin channel -- )
ledcDetachPin ( pin -- )
ledcRead ( channel -- n )
ledcReadFreq ( channel -- freq ) Get frequency (x 1,000,000)
ledcWrite ( channel duty -- )
ledcWriteTone ( channel freq ) Write tone frequency (x 1000)
ledcWriteNote ( channel note octave -- freq )
</pre>
<h5>Short GPIO Names</h5>
<pre>
pin ( value pin# -- ) Set GPIO pin value
adc ( pin# -- n ) Analog read pin, result 0-1023
</pre>
<h5>System</h5>
<pre>
MS ( n -- )
TERMINATE ( n -- ) Call system exit
</pre>
<h5>Files</h5>
<pre>
R/O ( -- mode )
R/W ( -- mode )
W/O ( -- mode )
BIN ( mode -- mode )
CLOSE-FILE ( fh -- ior )
OPEN-FILE ( a n mode -- fh ior )
CREATE-FILE ( a n mode -- fh ior )
DELETE-FILE ( a n -- ior )
WRITE-FILE ( a n fh -- ior )
READ-FILE ( a n fh -- n ior )
FILE-POSITION ( fh -- n ior )
REPOSITION-FILE ( n fh -- ior )
FILE-SIZE ( fh -- n ior )
</pre>
<h5>WiFi</h5>
These words are inside the <code>WiFi</code> vocabulary.
<pre>
WiFi.config ( ip dns gateway subnet -- ) Packaged a.b.c.d little-endian
Wifi.begin ( ssid-z password-z -- )
Wifi.disconnect ( -- )
WiFi.status ( -- n )
WiFi.macAddress ( a -- )
WiFi.localIP ( -- ip )
WiFi.mode ( mode -- ) WIFI_MODE_NULL WIFI_MODE_STA WIFI_MODE_AP WIFI_MODE_APSTA
WiFi.setTxPower ( powerx4 -- ) Set power x4
WiFi.getTxPower ( -- powerx4 ) Get power x4
</pre>
<h5>mDNS</h5>
<pre>
MDNS.begin ( name-z -- ) Start multicast dns
</pre>
<h5>SPIFFS</h5>
These words are inside the <code>SPIFFS</code> vocabulary.
<pre>
SPIFFS.begin ( format-on-fail path-z max-files -- f )
SPIFFS.end ( -- )
SPIFFS.format ( -- f )
SPIFFS.totalBytes ( -- n )
SPIFFS.usedBytes ( -- n )
</pre>
<h5>WebServer</h5>
These words are inside the <code>WebServer</code> vocabulary.
<pre>
WebServer.new ( port -- ws ) Allocate new webserver object
WebServer.delete ( ws -- ) Delete webserver object
WebServer.begin ( port ws -- )
WebServer.stop ( ws -- )
WebServer.on ( path-z xt ws -- ) Set up a web path handle callback
WebServer.handleClient ( ws -- ) Handle one client request
WebServer.hasArg ( z ws -- f ) By name
WebServer.arg ( z ws -- z ) By name
WebServer.argi ( n ws -- z ) By index
WebServer.argName ( n ws -- z) By index
WebServer.args ( ws -- n ) Number of args
WebServer.setContentLength ( n ws -- )
WebServer.sendHeader ( name-z value-z fist ws -- )
WebServer.send ( code mimetype data ws -- )
WebServer.sendContent ( z ws -- )
WebServer.method ( ws -- n ) GET / POST etc.
</pre>
<h5>Wire</h5>
These words are inside the <code>Wire</code> vocabulary.
<pre>
Wire.begin ( -- f )
Wire.setPins ( sda scl -- f )
Wire.setClock ( frequency -- )
Wire.getClock ( -- frequency )
Wire.setTimeout ( ms -- ) Default is 50ms
Wire.getTimeout ( -- ms )
Wire.lastError ( -- n )
Wire.getErrorText ( n -- z )
Wire.beginTransmission ( n -- )
Wire.endTransmission ( sendstop -- f )
Wire.requestFrom ( address quantity sendstop -- n )
Wire.writeTransmission ( addr a n sendstop -- err )
Wire.readTransmission ( addr a n sendstop acount -- err )
Wire.write ( a n -- n )
Wire.available ( -- f )
Wire.read ( -- ch )
Wire.peek ( -- ch )
Wire.busy ( -- f )
Wire.flush ( -- )
</pre>
<h5>Camera</h5>
These words are inside the <code>camera</code> vocabulary.
<pre>
esp_camera_init ( config -- f )
esp_camera_deinit ( -- f )
esp_camera_fb_get ( -- fb )
esp_camera_fb_return ( fb -- )
esp_camera_sensor_get ( -- sensor )
</pre>
<h5>SD_MMC</h5>
These words are inside the <code>SD_MMC</code> vocabulary.
<pre>
SD_MMC.begin ( mount mode1bit ) default mode1bit=false
SD_MMC.end ( -- )
SD_MMC.cardType ( -- n )
SD_MMC.totalBytes ( -- n )
SD_MMC.usedBytes ( -- n )
</pre>
<h4 id="webui">ESP32 WebUI</h4>
<p>
A terminal over the web can be activated.
Contact at port printed or via mDNS <a href="http://ueforth/">http://ueforth/</a>.
</p>
<pre>
webui ( network-z password-z -- )
</pre>
<p>Usage:</p>
<pre>
z" NETWORK-NAME" z" PASSWORD" webui
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/arduino_server.fs">arduino_server.fs</a>.
</p>
<h4 id="autoexec">Autoexec.fs</h4>
<p>
The system will automatically attempt to mount SPIFFS filesystem at <code>/spiffs</code>.
It will then at start attempt to load <code>/spiffs/autoexec.fs</code>
</p>
<p>
One way this feature can be used to configure the Web UI to start by default.
When doing this, be sure to test your Web UI settings work well first.
</p>
<pre>
r| z" NETWORK-NAME" z" PASSWORD" webui | s" /spiffs/autoexec.fs" dump-file
</pre>
<p>
To remove a previously configured <code>autoexec.fs</code> you will need
to be able to reboot in a mode with Forth. One way to do this is to search
for the line in the .ino file that refers to <code>autoexec.fs</code>
and replace it with a different name. Then run the following:
</p>
<pre>
s" /spiffs/autoexec.fs" delete-file
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/arduino/autoboot.fs">autoboot.fs</a>.
</p>
<h3>Windows</h3>
<h4>Windows Opcodes</h4>
<p>
The wealth of Windows .DLL and system functionality can be
accessed via the dynamic loading interface.
A handle to a library is obtained with <code>LOADLIBRARYA</code>,
and then individual symbols are accessed with <code>GETPROCADDRESS</code>.
</p>
<pre>
LOADLIBRARYA ( dllname-z -- module )
GETPROCADDRESS ( module name-z -- fn )
</pre>
<p>
And assembly version of <code>*/MOD</code> is provided to allow the EXE to build without
including MSVCRT.
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows_main.c">windows_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Windows Imports</h4>
<p>
Various Win32 calls are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/windows/windows.fs">windows.fs</a>.
In addition, a terminal that responds to ANSI escape codes is created and connected to
<code>TYPE</code> and <code>KEY</code>.
</p>
<h3>Linux</h3>
<h4>Linux Opcodes</h4>
<p>
Linux libraries and the operating system can be accessed via the use
of the <code>DLSYM</code> word. Functions can be requested by name from
particular modules. As the dynamic linking module is already loaded initially,
a 0 for the module allows the library loading function (<code>dlopen</code>)
to be loaded from Forth.
</p>
<pre>
DLSYM ( module name-z -- fn )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix_main.c">posix_main.c</a>.
</p>
<p>
Native functions all called with CALL(n) (see Windows &amp; Linux Calling below).
</p>
<h4>Linux Imports</h4>
<p>
Various Linux calls including Xlib are imported in
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/posix.fs">posix.fs</a> and
<a href="https://github.com/flagxor/eforth/blob/main/ueforth/posix/xlib.fs">xlib.fs</a>.
In addition, <code>TYPE</code> and <code>KEY</code> are connected to
<code>stdin</code> and <code>stdout</code>.
</p>
<h3>Windows &amp; Linux Calling</h3>
<p>
As unfortunately both Windows and Linux have system and library calls with
as many as 10 parameters (for example <code>XCreateImage</code>),
a collection of calling thunks is required.
A single varidic thunk would be ideal, but is hard to do without per platform
assembly language.
</p>
<pre>
CALL0 ( fn -- n )
CALL1 ( n fn -- n )
CALL2 ( n n fn -- n )
CALL3 ( n n n fn -- n )
CALL4 ( n n n n fn -- n )
CALL5 ( n n n n n fn -- n )
CALL6 ( n n n n n n fn -- n )
CALL7 ( n n n n n n n fn -- n )
CALL7 ( n n n n n n n n fn -- n )
CALL9 ( n n n n n n n n n fn -- n )
CALL10 ( n n n n n n n n n n fn -- n )
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/calling.h">calling.h</a>.
</p>
<h3>Web</h3>
<font style="font-size: 18pt; color: #C00;">Work in Progress - Coming Soon</font>
<h3>µEforth Internals</h3>
<p>
µEforth (micro-Eforth) simplifies EForth even futher, by building just enough
of the core of the system in C to allow the rest to be be built in proper Forth.
</p>
<p>
A handful of "tricky" words that involve internal loops or many steps are built in their own
functions:
</p>
<pre>
FIND ( a n -- xt | 0 )
PARSE ( ch -- a n )
S&gt;NUMBER? ( a n -- n f | 0 )
CREATE ( "name" -- )
EVALUATE1 ( -- )
</pre>
<p>
This includes <code>EVALUATE1</code> which parses a single word and
interprets or compiles it (reusing <code>PARSE</code>,
<code>FIND</code>, and <code>S&gt;NUMBER?</code>).
</p>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/core.h">core.h</a>.
</p>
<p>
A few global variables connect parsing and compilation state between
C and Forth (by way of a memory region accessed via <code>'SYS</code>):
</p>
<pre>
'TIB --- Pointer to the Translation Input Buffer
#TIB --- Length of the Translation Input Buffer
&gt;IN --- Number of characters consumed from TIB
BASE --- Numeric base for printing and parsing
STATE --- State of compiling, -1 for compiling, 0 for interpreting
CURRENT --- Pointer to pointer to last word of current vocabulary
CONTEXT --- Pointer to pointer to last word of context vocabulary
'NOTFOUND --- Execution token of a handler to call on word not found
</pre>
<p>
Error handling is routed via a deferred callback in <code>'NOTFOUND</code>
used when a word is absent from the dictionary.
This is eventually directed to an error routing that prints
a proper error, once I/O and exceptions are available.
</p>
<p>
<a href="https://en.wikipedia.org/wiki/X_Macro">X-Macros</a>
are then used to build up a small set of core opcodes defined in 1-3 lines each:
</p>
<pre>
0= 0&lt; + U/MOD */MOD AND OR XOR
DUP SWAP OVER DROP @ L@ C@ ! L! C!
SP@ SP! RP@ RP! &gt;R R&gt; R@ : ; EXIT
EXECUTE BRANCH 0BRANCH DONEXT DOLIT
ALITERAL CELL DOES&gt; IMMEDIATE 'SYS
</pre>
<p>
See <a href="https://github.com/flagxor/eforth/blob/main/ueforth/common/opcodes.h">opcodes.h</a>.
</p>
<p>
I/O and access to systems outside Forth are connected via a few per platform words.
Typically this set of words should be minimal, while still allowing relevant parts
of the host system to be available to Forth.
</p>
<h2>Classic esp32Forth</h2>
<p>
esp32Forth - Version 6.3 for NodeMCU ESP32S - Tweaked for the Web
</p>
<ul>
<li><a href="static/espforth.ino">espforth.ino</a>
</ul>
<h3>Classic EForth Quirks</h3>
<p>
EForth uses <code>FOR..NEXT</code> in favor of <code>DO..LOOP</code>.
<a href="https://github.com/TG9541/stm8ef/wiki/eForth-FOR-..-NEXT">Details</a>
</p>
<p>
This construct has the odd property that it iterates one "extra" time for zero.
</p>
<pre>
: FOO 10 FOR R@ . NEXT ; FOO
10 9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
To permit a more ordinary loop the <code>AFT</code> word is used in the sequence
<code>FOR..AFT..THEN..NEXT</code>.
</p>
<pre>
: FOO 10 FOR ( 1st time only ) AFT R@ . THEN NEXT ; FOO
9 8 7 6 5 4 3 2 1 0 ok
</pre>
<p>
The even more enigmatic <code>FOR..WHILE..NEXT..ELSE..THEN</code>
is used in place of <code>DO..LEAVE..LOOP</code>.
It allows a while condition to early out of a counted loop.
</p>