Releases: TG9541/stm8ef
The Long Overdue Release
About the Release
This is the release after the "long past due pre-release". Since the last release Travis-CI.org services had been terminated, and other things in life of the maintainer insisted to be more important than learning about GitHub Actions. For a long time many improvements didn't make it into a binary release.
Now the transition to GitHub Actions is complete. In addition to the old features the volatile release tag contains binaries from the latest successful build-test workflow.
New Features
Improved CREATE ... DOES>
Issue #427 provides a much better implementation of DOES>
- and better means both faster and leaner.
The execution speed of the new solution is on par with an ordinary CREATE, VARIABLE or CONSTANT as can be shown in the following example:
: EMPTY CREATE DOES> ; \ just return the address
: CONS CREATE , DOES> @ ; \ return data
CREATE tcreate
VARIABLE tvar
EMPTY tempty
0 CONS tcons
0 CONSTANT tconstant
The following measurements where done with PulseView on a STM8S001J3M3 with 16MHz HSI and code compiled to Flash ROM.
Test | runtime | cycles |
---|---|---|
tcreate |
1.3µs | 21 |
tempty |
1.82µs | 29 |
tvariable |
1.89µs | 30 |
tconstant |
3.2µs | 51 |
tcons |
3.3µs | 53 |
This means that a runtime of an "empty" DOES>
, which returns the address of any data stored by a word definition, is 1.82µs. That's marginally faster than VARIABLE
and just a bit slower than CREATE
.
The simple constant value implementation : CONS CREATE , DOES> @ ;
is also just a bit slower than the literal stored by CONSTANT
. The latter uses the STM8 instruction TRAP
and requires just 3 byte, just like the CALL
to the word defined through CONS
).
The memory requirements compare as follows:
[bytes] | old | new | diff |
---|---|---|---|
: empty CREATE DOES> ; |
22 | 18 | 4 |
empty a |
13 | 7 | 6 |
STM8S001J3 binary | 4697 | 4662 | 35 |
The old implementation needs 4 bytes more for a "defining word" and 6 bytes more for a "defined" (the new DOES>
has the same memory needs as a word defined by CREATE
, CONSTANT
or VARIABLE
).
Also the STM8 eForth binary is 35 bytes smaller than before.
Improved >REL
>REL
is an implementation of IF ... ELSE ... THEN
using relative addressing modes. It's meant to be used as a compiler extension loaded into RAM as a scaffold for, e.g., compiling fast and extra compact ISRs (interrupt service routines) into Flash ROM.
@Eelkhoorn noticed that RAM space for the scaffolding code can be reduced and provided an improved implementation.
Words for Forth Standard compatibility
Issue #430 and #438 added library words for making STM8 eForth a bit more compatible with the Forth Standard. Some of the words are just "No Operation" dummy words (e.g. ALIGN
), some aliases (e.g., INVERT
), some simple definitions (e.g. >BODY
and some genuine extensions (e.g., VALUE ... TO
).
Please be aware that not all of these Forth Standard words will always do what you expect, e.g.:
VALUE ... TO
(likeDEFER ... IS
) assumes a writable dictionary- some words like
STATE
emulate some just of the standard semantics
Forth Standard | STM8 eForth implementation |
---|---|
>BODY |
: >BODY ( xt -- a-addr ) 3 + ; |
ALIGN |
no op |
ALIGNED |
no op |
C" |
' $" ALIAS C" |
CHAR+ |
' 1+ ALIAS CHAR+ ( c-addr1 -- c-addr2 ) |
CHAR |
: CHAR ( "char" -- c ) BL WORD CHAR+ C@ ; |
CHARS |
no op |
[CHAR] |
: [CHAR] ( "name"<spaces -- ) CHAR POSTPONE LITERAL ; IMMEDIATE |
COMPILE, |
' CALL, ALIAS COMPILE, ( xt -- ) |
ENVIRONMENT? |
: ENVIRONMENT? ( c-addr u -- false ) 2DROP 0 ; |
INVERT |
' NOT ALIAS INVERT ( x1 -- x2 ) |
J |
like I (only for DO ... LOOP , not FOR ... NEXT ) |
STATE |
"kludge" using STATE? and a variable stateflag |
TO |
see VALUE |
VALUE |
limited to writable dictionary (RAM or NVM when writable) see lib/VALUE |
Issue #430 refactored CREATE
and VARIABLE
in order to facilitate implementing the Forth Standard words VALUE
and TO
.
The following additional words are already available in volatile and they will be available in the next release (2.2.29):
Forth Standard | STM8 eForth implementation |
---|---|
CELL+ |
' 2+ ALIAS CELL+ ( c-addr1 -- c-addr2 ) |
CELLS |
' 2* ALIAS CELLS ( n1 -- n2 ) |
FALSE |
' 0 ALIAS FALSE ( -- false ) |
RSHIFT |
like LSHIFT ( n1 u -- n2 ) |
TRUE |
' -1 ALIAS TRUE ( -- true ) |
Improved "pictured number" words
While working on optional words for Forth Standard compatibility it became clear that while Forth Standard compliant "pictured number output" with # ( ud -- ud)
instead of # ( u -- u)
(double instead of single math) would increase the code size only marginally but the math would make printing numbers in a background process slower. This might break applications that print numbers in a background task as the limit of 1ms task run-time is exceeded (unless a fast 32bit/8bit division or buffered I/O is used).
Issue #433 explored options for improving the code. It turned out that #
can be made faster by using the instruction DIV X,A
(with the DIV
/DIVW
erratum work-around). The code could also be made leaner by in-lining the code of DIGIT
and EXTRACT
(these are eForth words which are not available in other 16bit Forth implementations, e.g., the well known F83 - they also don't appear in the Forth Standard).
PulseView and the word ..
(which toggles a GPIO with PLo
and PHi
) were used for testing:
: .. ( u -- u ) PLo <# PHi #S PLo #> PHi TYPE ;
For example, here is the timing for DECIMAL 65535 ..
:
The following table shows that #
and #S
are much faster now:
.. | Base | <# #S #> old [µs] |
<# #S #> improved [µs] |
---|---|---|---|
65535 | 10 | 155 | 31 |
6 | 10 | 53 | 22 |
65535 | 16 | 131 | 29 |
65535 | 2 | 446 | 60 |
The toggles around <#
and #>
revealed that about 4µs can be saved by coding the 16bit <literal> +
in PAD
in assembler (13µs to 9µs - the numbers in the table contain this optimization). In a BG
task PAD
is slightly faster as it returns a constant address. When using numeric output in a background task, e.g. for presenting measurements on a LED display with CR .
, the more efficient "pictured number words" makes a real difference.
Note: Forth Standard compatible "pictured number" words with double number output (e.g. D.
) can be provided later through library words. in In a 16bit Forth it's important to keep in mind that a limitation of UM/MOD ( ud un -- ur uq )
- the 16bit result - correct output for double numbers is limited to "65536 x BASE - 1" (e.g., 655359 for base 10). For larger numbers a 32bit division with 32bit result is required (with 8bit divisor).
Bug fixes and other improvements
Improved .0 (3-digit signed number print)
Issue #432 fixes a few edge cases of .0
, the signed number output for 3 digit (LED) displays: numbers smaller than -994 or larger than 9994 had digit overruns - and thus potentially wrong display values.
The updated version was shown to work for the following values:
-999 .0 DEF. ok
-995 .0 -99 ok
-99 .0 -9.9 ok
0 .0 0.0 ok
999 .0 99.9 ok
1000 .0 100 ok
7876 .0 788 ok
9995 .0 DEF. ok
Leaner console text input words
Issue #435 saved some ROM space in the input words ACCEPT
, KTAP
, and QUERY
.
CREATE and VARIABLE refactored
Common functionality from CREATE
and VARIABLE
was refactored into the new word ENTRY
(used by VALUE
).
Set INT_TLI to COLD
@Eelkhoorn ran into a problem when changing ISR code in a development cycle:
Uploading the I2C interrupt service routine to STM8L (both 051F3 and 151K4) can lead to corrupted ITC_SPR registers, persistent even after power cycle. Writing xt of COLD to INT_TLI (reset vector) solved the issue.
The last four entries of the interrupt vector table (0x8070 to 0x8080) seem to be corrupted after boot for STM8L.
Pull request #440 appears to solve the issue (but the problem needs further analysis and the code may change in the future).
codeload.py: broken #ifdef and #ifndef repaired
Tests with #ifndef <word> \res MCU: ...
worked in e4thcom but made codeload.py crash. Issue #448 solved the problem.
A 5x8 font for dot-matrix displays
A simple 5x8 font for dot-matrix displays `FONT5X8 has been added. It's intended to be used with an additional 6th column (6x8) - an example is provided.
The Long Overdue (Pre-) Release
About the Release
This pre-release is long past due. In the meantime Travis-CI.org services were terminated, and other things in life of the maintainer insisted to be more important than learning about GitHub Actions. For a long time many improvements didn't make it into a binary release.
Now the transition to GitHub Actions is complete. In addition to the old features the volatile release tag will contain the binaries from the latest successful build-test workflow.
New Features
Improved CREATE ... DOES>
Issue #427 provides a much better implementation of DOES>
- and better means both faster and leaner.
The execution speed of the new solution is on par with an ordinary CREATE, VARIABLE or CONSTANT as can be shown in the following example:
: EMPTY CREATE DOES> ; \ just return the address
: CONS CREATE , DOES> @ ; \ return data
CREATE tcreate
VARIABLE tvar
EMPTY tempty
0 CONS tcons
0 CONSTANT tconstant
The following measurements where done with PulseView on a STM8S001J3M3 with 16MHz HSI and code compiled to Flash ROM.
Test | runtime | cycles |
---|---|---|
tcreate |
1.3µs | 21 |
tempty |
1.82µs | 29 |
tvariable |
1.89µs | 30 |
tconstant |
3.2µs | 51 |
tcons |
3.3µs | 53 |
This means that a runtime of an "empty" DOES>
, which returns the address of any data stored by a word definition, is 1.82µs. That's marginally faster than VARIABLE
and just a bit slower than CREATE
.
The simple constant value implementation : CONS CREATE , DOES> @ ;
is also just a bit slower than the literal stored by CONSTANT
. The latter uses the STM8 instruction TRAP
and requires just 3 byte, just like the CALL
to the word defined through CONS
).
The memory requirements compare as follows:
[bytes] | old | new | diff |
---|---|---|---|
: empty CREATE DOES> ; |
22 | 18 | 4 |
empty a |
13 | 7 | 6 |
STM8S001J3 binary | 4697 | 4662 | 35 |
The old implementation needs 4 bytes more for a "defining word" and 6 bytes more for a "defined" (the new DOES>
has the same memory needs as a word defined by CREATE
, CONSTANT
or VARIABLE
).
Also the STM8 eForth binary is 35 bytes smaller than before.
Improved >REL
>REL
is an implementation of IF ... ELSE ... THEN
using relative addressing modes. It's meant to be used as a compiler extension loaded into RAM as a scaffold for, e.g., compiling fast and extra compact ISRs (interrupt service routines) into Flash ROM.
@Eelkhoorn noticed that RAM space for the scaffolding code can be reduced and provided an improved implementation.
Words for Forth Standard compatibility
Issue #430 and #438 added library words for making STM8 eForth a bit more compatible with the Forth Standard. Some of the words are just "No Operation" dummy words (e.g. ALIGN
), some aliases (e.g., INVERT
), some simple definitions (e.g. >BODY
and some genuine extensions (e.g., VALUE ... TO
).
Please be aware that not all of these Forth Standard words will always do what you expect, e.g.:
VALUE ... TO
(likeDEFER ... IS
) assumes a writable dictionary- some words like
STATE
emulate some just of the standard semantics
Forth Standard | STM8 eForth implementation |
---|---|
>BODY |
: >BODY ( xt -- a-addr ) 3 + ; |
ALIGN |
no op |
ALIGNED |
no op |
C" |
' $" ALIAS C" |
CHAR+ |
' 1+ ALIAS CHAR+ ( c-addr1 -- c-addr2 ) |
CHAR |
: CHAR ( "char" -- c ) BL WORD CHAR+ C@ ; |
CHARS |
no op |
[CHAR] |
: [CHAR] ( "name"<spaces -- ) CHAR POSTPONE LITERAL ; IMMEDIATE |
COMPILE, |
' CALL, ALIAS COMPILE, ( xt -- ) |
ENVIRONMENT? |
: ENVIRONMENT? ( c-addr u -- false ) 2DROP 0 ; |
INVERT |
' NOT ALIAS INVERT ( x1 -- x2 ) |
J |
like I (only for DO ... LOOP , not FOR ... NEXT ) |
STATE |
"kludge" using STATE? and a variable stateflag |
TO |
see VALUE |
VALUE |
limited to writable dictionary (RAM or NVM when writable) see lib/VALUE |
Issue #430 refactored CREATE
and VARIABLE
in order to facilitate implementing the Forth Standard words VALUE
and TO
.
The following additional words are already available in volatile and they will be available in the next release (2.2.29):
Forth Standard | STM8 eForth implementation |
---|---|
CELL+ |
' 2+ ALIAS CELL+ ( c-addr1 -- c-addr2 ) |
CELLS |
' 2* ALIAS CELLS ( n1 -- n2 ) |
FALSE |
' 0 ALIAS FALSE ( -- false ) |
RSHIFT |
like LSHIFT ( n1 u -- n2 ) |
TRUE |
' -1 ALIAS TRUE ( -- true ) |
Improved "pictured number" words
While working on optional words for Forth Standard compatibility it became clear that while Forth Standard compliant "pictured number output" with # ( ud -- ud)
instead of # ( u -- u)
(double instead of single math) would increase the code size only marginally but the math would make printing numbers in a background process slower. This might break applications that print numbers in a background task as the limit of 1ms task run-time is exceeded (unless a fast 32bit/8bit division or buffered I/O is used).
Issue #433 explored options for improving the code. It turned out that #
can be made faster by using the instruction DIV X,A
(with the DIV
/DIVW
erratum work-around). The code could also be made leaner by in-lining the code of DIGIT
and EXTRACT
(these are eForth words which are not available in other 16bit Forth implementations, e.g., the well known F83 - they also don't appear in the Forth Standard).
PulseView and the word ..
(which toggles a GPIO with PLo
and PHi
) were used for testing:
: .. ( u -- u ) PLo <# PHi #S PLo #> PHi TYPE ;
For example, here is the timing for DECIMAL 65535 ..
:
The following table shows that #
and #S
are much faster now:
.. | Base | <# #S #> old [µs] |
<# #S #> improved [µs] |
---|---|---|---|
65535 | 10 | 155 | 31 |
6 | 10 | 53 | 22 |
65535 | 16 | 131 | 29 |
65535 | 2 | 446 | 60 |
The toggles around <#
and #>
revealed that about 4µs can be saved by coding the 16bit <literal> +
in PAD
in assembler (13µs to 9µs - the numbers in the table contain this optimization). In a BG
task PAD
is slightly faster as it returns a constant address. When using numeric output in a background task, e.g. for presenting measurements on a LED display with CR .
, the more efficient "pictured number words" makes a real difference.
Note: Forth Standard compatible "pictured number" words with double number output (e.g. D.
) can be provided later through library words. in In a 16bit Forth it's important to keep in mind that a limitation of UM/MOD ( ud un -- ur uq )
- the 16bit result - correct output for double numbers is limited to "65536 x BASE - 1" (e.g., 655359 for base 10). For larger numbers a 32bit division with 32bit result is required (with 8bit divisor).
Bug fixes and other improvements
Improved .0 (3-digit signed number print)
Issue #432 fixes a few edge cases of .0
, the signed number output for 3 digit (LED) displays: numbers smaller than -994 or larger than 9994 had digit overruns - and thus potentially wrong display values.
The updated version was shown to work for the following values:
-999 .0 DEF. ok
-995 .0 -99 ok
-99 .0 -9.9 ok
0 .0 0.0 ok
999 .0 99.9 ok
1000 .0 100 ok
7876 .0 788 ok
9995 .0 DEF. ok
Leaner console text input words
Issue #435 saved some ROM space in the input words ACCEPT
, KTAP
, and QUERY
.
CREATE and VARIABLE refactored
Common functionality from CREATE
and VARIABLE
was refactored into the new word ENTRY
(used by VALUE
).
Set INT_TLI to COLD
@Eelkhoorn ran into a problem when changing ISR code in a development cycle:
Uploading the I2C interrupt service routine to STM8L (both 051F3 and 151K4) can lead to corrupted ITC_SPR registers, persistent even after power cycle. Writing xt of COLD to INT_TLI (reset vector) solved the issue.
The last four entries of the interrupt vector table (0x8070 to 0x8080) seem to be corrupted after boot for STM8L.
Pull request #440 appears to solve the issue. The problem needs further analysis.
Latest unstable binaries (volatile)
About this release
This isn't really a release but a container for the binary artifacts from the latest build (see this GH Release issue). It's not only unstable (if tested!) but also volatile.
This means that the artifacts in the "volatile" release can be used for testing or prototyping but they won't last. In order to keep a trace to the Git version at the end of the file forth.asm
packed in the attached binary archives there is an identification record like the following:
; ##########################################
; # Release info added by GitHub action:
; # repository: TG9541/stm8ef
; # branch name: refs/heads/master
; # sha: 8ee3453ce577181ef5e9bddda94f56d448dbf962
; ##########################################
The Git version used for creating the binary archive in this example is 8ee3453.
Please take note that not all archives provided in the release are up-to-date:
File | Description |
---|---|
stm8ef-bin.tgz | full binary release, suitable for STM8 eForth Modular Build method |
stm8ef-bin.zip | binary release |
stm8ef-rst.tgz | list file for debugging |
Source code (zip) | GitHub source snapshot from original tag (outdated) |
Source code (tar.gz) | GitHub source snapshot from original tag (outdated) |
POSTPONE, DEFER and an ISR/BG bug fix
About the Release
The 2.2.28 development cycle had just started - the plan was to start making STM8 eForth a little bit more standard compliant so that using code from other embedded Forth systems gets easier when @Eelkhoorn found a configuration error of the BG task data stack size: since #377 the stack size as exactly "0" so that the ISR data stack was used (see #424 ).
Other than that, this release contains a potentially braking change: POSTPONE
was introduced and since it has some many advantages over COMPILE
and COMPILE
it's now the default. Please refer to #413 for a discussion of the differences.
New Features
POSTPONE
instead of COMPILE
or [COMPILE]
Modern Forth systems use POSTPONE
instead of COMPILE
or [COMPILE]
. The main objective is code simplification, both for the programmer but also for a Forth system that generate machine code: in STM8 eForth COMPILE
has to analyze the call type (absolute or relative) - which makes the code more complicated.
Why this is important
Making "Forth macros", words that compile code (e.g., IF ... ELSE ... THEN
), requires compiling "compilation instructions" into a word instead of executing them during compilation.
For instance IF
can be implemented as follows:
: >MARK ( --A ) HERE 0 , ;
: IF ( --A ) COMPILE ?branch >MARK ; IMMEDIATE
Since the dictionary entry of IF
is flagged IMMEDIATE
it will be executed, not compiled, when using a condition structure (e.g., 0< IF DROP 0 THEN
). When executed, the word COMPILE
takes the call address (xt
, the execution token) of the next word (?branch
) and compiles it into the destination code (e.g. the conditional phrase above). Note that ?branch
isn't flagged IMMEDIATE
- if it were different it would be executed, not compiled, and COMPILE
would not receive the expected xt
.
Sometimes IMMEDIATE
words need to be compiled into a new word, not executed. In order to get the desired effect [COMPILE]
would be required to enforce compilation of the immediate word, e.g.:
: WHILE ( a --A a ) [COMPILE] IF SWAP ; IMMEDIATE
Here [COMPILE]
overrides the IMMEDIATE
flag of IF
and compiles a call to this immediate word into the code of WHILE
. It would also be possible to write COMPILE [COMPILE] IF
, which would create a macro that compiles IF
into the target code (just like using COMPILE
on a regular word). In practice such a use case is rare.
From this release on it's sufficient to write POSTPONE
instead of COMPILE
or [COMPILE]
. This also makes porting code from more modern Forth systems easier since it's no longer necessary to figure out if it's COMPILE
or [COMPILE]
that you'll have to use instead.
Legacy code can use #require COMPILE
or #require [COMPILE]
, which will load an alias to POSTPONE
, to cover all but the most exotic use cases. If that does't work the legacy words can be re-enabled in the board configuration (and please file an issue).
More examples and technical details are in the following issues:
#413 POSTPONE supersedes COMPILE and [COMPILE]
#414 make COMPILE and [COMPILE] replaceable with ALIAS to POSTPONE
#414 add test for POSTPONE
#417 use COMPILIT instead of COMPILE in core
#419 use POSTPONE in lib
#419 use POSTPONE in >REL
#419 use POSTPONE in [']
#419 use POSTPONE in ALIAS
#419 use POSTPONE in DEFER
#419 use POSTPONE in :NVM
#419 use POSTPONE in S"
#419 use POSTPONE in EVALUATE
#419 use POSTPONE in CONSTANT
#419 use POSTPONE in MARKER
#419 use POSTPONE in VOC
#419 use POSTPONE in VOCABULARY
Add [']
and DEFER ... IS
Issue #411 adds the words [']
(compile literal with xt
of the following word) and DEFER ... IS
.
Please refer to the Forth Standard entries of [']
, DEFER
and IS
.
Other changes
Core optimizations
Issue #416 introduces a more compact CALL,
with COMPILIT
and some other core optimizations, especially for the transition from COMPILE
and [COMPILE]
to POSTPONE
.
Tool changes
Issue #421 makes the codeload.py
line length check less restrictive (trailing comments don't count).
Docs changes
Issue #409 proposes a work around for an STM8L151 serial bootloader erratum
Bug fixes
BG task data stack size configuration error
Issue #424 describes a critical problem of the BG task data stack size configuration:
- Applications that use the BG task and an ISR that uses Forth code may suffer from BG task data stack corruption
- The BG stack has been 8 cells deep since the bug was introduced - this can also lead to foreground task stack corruption!
The regression was introduced when the BG code was factored out in #377. It was still OK until the 2.2.26 release. The first release that contained this bug was 2.2.27.pre1. 2.2.27 was released 9/Mar/2021.
Incorrect TIB
constant export
Issue #420 fixes an incorrect TIB
constant export that broke EVALUATE
. The bug was introduced in release 2.2.24. An automated test of EVALUATE
was added.
Start 2.2.28 Development Cycle: POSTPONE and DEFER
About the Pre-Release
This release is going to modernize eForth by introducing some Forth-Standard words.
fixes #409: work around for STM8L151 serial bootloader erratum
fixes #411: add ['] and DEFER ... IS
#411 add test for DEFER ... IS and [']
fixes #413 POSTPONE supersedes COMPILE and [COMPILE]
fixes #413 POSTPONE supersedes COMPILE and [COMPILE]
fixes #414 implement POSTPONE
#414 add test for POSTPONE
#414 make COMPILE and [COMPILE] replaceable with ALIAS to POSTPONE
#416 some minor core optimizations
#416 some minor core optimizations
#416 more compact CALL,
fixes #417 use COMPILIT instead of COMPILE in core
fixes #419 use POSTPONE in lib
#419 use POSTPONE in >REL
#419 use POSTPONE in [']
#419 use POSTPONE in ALIAS
#419 use POSTPONE in DEFER
#419 use POSTPONE in :NVM
#419 use POSTPONE in S"
#419 use POSTPONE in EVALUATE
#419 use POSTPONE in CONSTANT
#419 use POSTPONE in MARKER
#419 use POSTPONE in VOC
#419 use POSTPONE in VOCABULARY
fixes #420 incorrect TIB constant export
#420 incorrect TIB constant export
#421 codeload.py: less restrictive line length check
UM/MOD Bugfix and Improvements Release
About the release
Whether or not you need any of the new features in this release there is a very good reason to use it: it fixes a very old bug in UM/MOD. It's possible that this bug can be traced to an early FIG-Forth release for the 6502:
Bill Ragsdale: UM/MOD had this or a similar range error in my first published fig-FORTH Model. Fixed in the second edition but by then the damage was done. I suspect that error propagated much later.
The good news: as long as the divisor is smaller than $8000 all is well. More about the bug below.
New Features
A simple debug console
It's sometimes useful to inspect the system (e.g. the stack) while executing a word in an application. That can be done by calling OUTER
, the Forth interpreter, from user code. The new word BYE
leaves this interpreter (but not that of the normal console).
Here is an example session:
#require BYE
\ ...
Closing: ./lib/BYE ok
: test 1 2 3 OUTER . . . ; ok
test<ENTER>.S<ENTER>
1 2 3 <sp ok
. 3 ok
4 ok
bye 4 2 1 ok
Note that there is no prompt indication when the "debug interpreter" gets active after test<ENTER>
. Also note that any ?
response from the interpreter means that the stack was emptied. Only a debug interpreter with a different type of error response would be able to prevent that.
The issue #372 "better BYE for debug console" contains technical details.
Fully Modular Background Task code
The BG code is now "fully modular" which means that it can be replaced with user code by placing a modified copy of bgtask.inc
into a Board folder.
Now the background task can also be run by the STM8L RM0031 device RTC (think "alarm") or by the Wakeup Timer.
Details are in the issues #375 "improve BG task interrupt configuration options" and #377 "factor out BG task code".
Better control of interrupt vectors in the C interface
In STM8 eForth the linker is called by SDCC (which is the main task of SDCC in this project). The C interface in main.c
used to depend on a fixed a set of interrupt vectors which limited the configuration of core features, e.g. the Background Task. This definition is now done by an include file in the Board folder.
Details are in the issue #379 "re-order C-Stub infrastructure".
Relative Addressing for IF .. ELSE .. THEN
Some use cases require STM8 machine code branch instructions instead of ?branch
or branch
that use absolute addressing (e.g. relocatable code in RAM, fast ISRs). Calculating the branch offset is better left to the compiler.
This feature is implemented by exchanging control structures on the fly (i.e. by loading a bit of the compiler into RAM).
#require >REL
NVM
: test ( f -- ) IF ." True" ELSE ." False" THEN ;
RAM
Here, IF
will compile to >Y JREQ rel
and ELSE
to JRA rel
:
' test 20 dump
955B CD 8A C
27 B CD 89 91 5 20 54 72 75 65
20 A ___'_____ True _
956B CD 89 91 6 20 46 61 6C 73 65 81 0 0 0 0 0 ____ False______ ok
While this already solves the problem of relocatable code the most important use case of this solution is using fast bit test ([ a #b ]B@IF
) or anything that can be done with Forth - Assembler interface (e.g. [ c ]A<IF
).
Details are in the issue #382 "IF .. ELSE .. THEN with relative addressing".
More machine code generating words
STM8 eForth doesn't have STM8 assembler words (yet). Instead "macros" are used to generate assembler instructions (e.g. conditional branch, bit and byte transfers). A number of new "macros" have been added to better support time critical ISRs (Interrupt Service Routine).
Word | What it does |
---|---|
[ a ]@ |
push contents of word at literal a to TOS |
[ a ]@IF |
test contents of word at literal a and perform IF w\ relative branch |
[ ... c ]A<IF |
test if A is < literal c and perform IF w\ relative branch |
[ f a #b ]B! |
set bit #b in byte at literal a to literal f |
[ a #b ]B? |
push flag with value of bit #b in byte at literal a to TOS |
[ a #b ]B@IF |
test bit #b at literal a and perform IF w\ relative branch |
[ a #b ]BC |
copy bit #b in byte at literal a to carry flag |
[ a #b ]BCPL |
complement bit #b in byte at literal a |
[ c a ]C! |
set byte at literal a to literal c |
[ a ]C@IF |
test contents of byte at literal a and perform IF w\ relative branch |
[ a #b ]CB |
copy carry flag to bit #b in byte at literal a |
[ f a #b ]SPIN |
spin until bit #b at literal a is equal to f |
[ ... n ]Y<IF |
test if Y is < literal n and perform IF w\ relative branch |
Also see #383 "machine code generating words for ISR programming"
Examples are in the I2C code below.
An I2C Master driver
On the face of it the STM8 I2C interface is a bit difficult to use. An easy to use driver has been added to the core. Example code is here.
Issue #385 implements a generic STM8 I2C Master using the STM8 I2C peripheral. The code is event driven and can be used as a low-level driver for implementing higher-level device drivers.
The file I2CMA
contains an application example. More examples are in this GitHub Gist.
Tools updates
Upgrade to Python3
Issue #390: upgrades build tools to Python3: tools like codeload.py
for build and test still depended on Python2.7, which is now all but dead. Upgrading to Python3 is overdue.
The docker image TG9541/docker-sdcc
also received an upgrade: the new version 3.9.9 uses Python3 and SDCC 3.9.0 (issues with the COM port simulation in uCsim in SDCC 4.0.7 couldn't immediately be resolve).
Improved codeload.py
Issue #394 improved the codeload.py
serial line target response tolerance (e.g. test output) and improved the usefulness of error messages.
Issue #392 introduced support for e4thcom "conditional transfer":
From version 0.8.5 on e4thcom supports conditional transfer code after #ifdef name
, e.g.
\ example: skip the rest of the file if test is defined
#ifdef test \\
\ example define test unless it's defined
#ifndef test : test ;
\ example: load PD_DDR unless it's defined
#ifndef PD_DDR \res MCU: STM8S103
#ifndef PD_DDR \res export PD_DDR
The following rules apply:
- the conditionals
#ifdef <name>
or#ifndef <name>
have to be the first word on a line - ordinary STM8 eForth console input may follow a conditional
#require
,#include
,\res
or\\
may follow a conditional and have to be the first word on a line in all other cases
The change will be added to codeload3.py
(update to Python3 in #390) and the new version will be the new default. The Python2.7 version will be preserved as codeload2.py
.
Bug fixes
UM/MOD bug
@MrMarkB and @Picatout identified and fixed a number of bugs in UM/MOD
that mode quotient and/or remainder invalid in the following cases:
- divisor larger than $7FFF
- MSB of the 32 bit dividend larger than the divisor
- invalid remainder in some other cases
The defect also has some impact on M/MOD
, */MOD
(edge cases and remainder) and */
(remainder). There is no known effect on /MOD
, MOD
and /
.
Following a discussion in the Forth2020 User Group (on FaceBook) it became clear that the bug has indeed a very long history: it's likely that its origin is in an early FIG Forth release for the 6502, and it has since been copied to different architectures and addressed in different ways.
Following the discussion @JeeeK provided a variant of the algorithm with improved entry and exit, and more efficient loop code.
The fixed (and impoved) code was tested with random arguments using a script provided by @MrMarkB.
Please refer to #400 and #401 for details!
Improvements and Other Changes
- issue #396 adds the
inc
folder to tgz binary archives - issue #407 add the words
LSHIFT
andCRC8
for implementations of the 1-Wire ROMSEARCH algorithm
Bug fix UM/MOD
Bug Fix
@MrMarkB and @Picatout identified and fixed a number of bugs in UM/MOD
that mode quotient and/or remainder invalid in the following cases:
- divisor larger than $7FFF
- MSB of the 32 bit dividend larger than the divisor
- invalid remainder in some other cases
The defect also has some impact on M/MOD
, */MOD
(edge cases and remainder) and */
(remainder).
There is no known effect on /MOD
, MOD
and /
.
Tools improvements
Tools now use Python3
fixes #390: upgrade build tools to Python3
codeload.py: #ifdef for conditional transfer and other improvements
fixes #392 support e4thcom conditional transfer
fixes #394 codeload.py: improve serial line target response and error…
Minor fix
fixes #396 add inc folder to tgz binary archive
Known Bugs
- The
hi
message will state that the version umber is2.2.27.pre1
not2.2.27.pre2
as it should
More features release
STM8 eForth 2.2.27 development cycle
As most STM8 devices are now officially supported, this release is going to concentrate on features, e.g. drivers for STM8 peripherals or support of the Wakeup Timer for the Background Task (instead of using TIM2).
A simple debug console
It's sometimes useful to inspect the system (e.g. the stack) while executing a word in an application. That can be done by calling OUTER
, the Forth interpreter, from user code. The new word BYE
leaves this interpreter (but not that of the normal console).
Here is an example session:
#require BYE
\ ...
Closing: ./lib/BYE ok
: test 1 2 3 OUTER . . . ; ok
test<ENTER>.S<ENTER>
1 2 3 <sp ok
. 3 ok
4 ok
bye 4 2 1 ok
Note that there is no prompt indication when the "debug interpreter" gets active after test<ENTER>
. Also note that any ?
response from the interpreter means that the stack was emptied. Only a debug interpreter with a different type of error response would be able to prevent that.
The issue #372 "better BYE for debug console" contains technical details.
Fully Modular Background Task code
The BG code is now "fully modular" which means that it can be replaced with user code by placing a modified copy of bgtask.inc
into a Board folder.
Now the background task can also be run by the STM8L RM0031 device RTC (think "alarm") or by the Wakeup Timer.
Details are in the issues #375 "improve BG task interrupt configuration options" and #377 "factor out BG task code".
Better control of interrupt vectors in the C interface
In STM8 eForth the linker is called by SDCC (which is the main task of SDCC in this project). The C interface in main.c
used to depend on a fixed a set of interrupt vectors which limited the configuration of core features, e.g. the Background Task. This definition is now done by an include file in the Board folder.
Details are in the issue #379 "re-order C-Stub infrastructure".
Relative Addressing for IF .. ELSE .. THEN
Some use cases require STM8 machine code branch instructions instead of ?branch
or branch
that use absolute addressing (e.g. relocatable code in RAM, fast ISRs). Calculating the branch offset is better left to the compiler.
This feature is implemented by exchanging control structures on the fly (i.e. by loading a bit of the compiler into RAM).
#require >REL
NVM
: test ( f -- ) IF ." True" ELSE ." False" THEN ;
RAM
Here, IF
will compile to >Y JREQ rel
and ELSE
to JRA rel
:
' test 20 dump
955B CD 8A C
27 B CD 89 91 5 20 54 72 75 65
20 A ___'_____ True _
956B CD 89 91 6 20 46 61 6C 73 65 81 0 0 0 0 0 ____ False______ ok
While this already solves the problem of relocatable code the most important use case of this solution is using fast bit test ([ a #b ]B@IF
) or anything that can be done with Forth - Assembler interface (e.g. [ c ]A<IF
).
Details are in the issue #382 "IF .. ELSE .. THEN with relative addressing".
More machine code generating words
STM8 eForth doesn't have STM8 assembler words (yet). Instead "macros" are used to generate assembler instructions (e.g. conditional branch, bit and byte transfers). A number of new "macros" have been added to better support time critical ISRs (Interrupt Service Routine).
Word | Explanation |
---|---|
[ a ]@ |
push contents of word at literal a to TOS |
[ a ]@IF |
test contents of word at literal a and perform IF w\ relative branch |
[ ... c ]A<IF |
test if A is < literal c and perform IF w\ relative branch |
[ f a #b ]B! |
set bit #b in byte at literal a to literal f |
[ a #b ]B? |
push flag with value of bit #b in byte at literal a to TOS |
[ a #b ]B@IF |
test bit #b at literal a and perform IF w\ relative branch |
[ a #b ]BC |
copy bit #b in byte at literal a to carry flag |
[ a #b ]BCPL |
complement bit #b in byte at literal a |
[ c a ]C! |
set byte at literal a to literal c |
[ a ]C@IF |
test contents of byte at literal a and perform IF w\ relative branch |
[ a #b ]CB |
copy carry flag to bit #b in byte at literal a |
[ f a #b ]SPIN |
spin until bit #b at literal a is equal to f |
[ ... n ]Y<IF |
test if Y is < literal n and perform IF w\ relative branch |
Also see #383 "machine code generating words for ISR programming"
An I2C Master driver
On the face of it the STM8 I2C interface is a bit difficult to use. An easy to use driver has been added to the core. Example code is here.
Refr tp #385 "generic STM8 I2C Master" for details.
The STM8L Release
About the release
This is release is very much about fully supporting STM8L devices (i.e. the likes of STM8L051F3, STM8L151C6 or STM8L152R8).
While STM8S peripherals are simple and the pin and clock configuration is trivial, the STM8L designers clearly had both "larger" and "many more" spec sheets. The "many more" one can be seen in the number of configuration dependencies the programmer has to infer when trying to use one of the many features of the peripherals. For STM8 eForth this means that things that were implicit or hard-coded needed to be restructured and tested. The device families STM8S and STM8L now are on equal footing and the generalizations gained when adding STM8L support now also makes supporting STM8S variants easier.
This release (finally) adds support for the low-end RM0013 STM8L device STM8L101, and, at the other end of the spectrum, STM8L "High density" devices like STM8L152R8 (also STM8L162 devices can be expected to work).
Configuration folders with docs for typical "Low", "Medium" and High density" devices in both families have been added (refer to Generic Targets for a list of supported devices). So far the hypothesis holds that memory and peripheral properties are the same across a range of package and memory specs variants the devices for which these "6+1 device types" and there is no evidence that the "small world of STM8 devices" is much more complicated than that. If you have reason to believe that a device doesn't fit in this simple schema please file an issue!
Devices in the following device families have not been examined:
- STM8L RM0312 family touch sensing MCUs, e.g. STM8TL5xxx
- STM8S STLUX lighting MCUs and STNRGxxxA power conversion MCUs (including wireless charging STWBC)
It shouldn't be big problem to get a Forth console on any of these devices, but for using the specialized peripherals it's maybe a good idea to apply ST's proprietary C-code libraries and configuration tools.
New Features
STM8L: Peripheral addresses
New or improved register address (efr-) files for e4thcom and codeload.py are now available. @Eelkhoorn first provided an improved STM8L151.efr
file, and in #342 efr files for specific STM8L variants were created.
STM8L "Medium" and "High density" should work with the generic STM8L151.efr
.
Peripheral register addresses of RM0031 "Low density" devices differ from STM8L "Medium density" and "High density" devices. Constants should be imported with \res MCU: STM8L051
.
The final group is RM0013 "Low density" devices like STM8L101F3 or STM8L001J3: here \res MCU: STM8L101
should be used.
STM8 Timers and interrupts
Some applications, like XY-LPWM, need to use a different timer than TIM2 for the background task.
Issue #369 adds this option to the STM8L device families.
By setting BG_USE_TIM3 = 1
in globconf.inc
the Background task (BG) timer will use TIM3 instead of TIM2 in STM8L "Low density" devices. STM8L "Medium" and "High density" devices can also set BG_USE_TIM1 = 1
for using TIM1. There is currently no support for TIM5 in STM8L "High density" devices.
A conflict between a simulated serial port and the background task in an STM8L051F3 device was discovered and fixed in issue #340 STM8L interrupt priority of BG task.
STM8S UART and STM8L USART configurations
STM8L devices in the RM0031 family support USART GPIO function remapping. This can easily lead to a mismatch between the USART GPIO mapping an the GPIO output initialization.
The following issues provide a solution:
- #358 USART options for STM8L High Density devices
- #364 STM8L: general options for USART configuration
- #360 half-duplex USART console option for STM8L devices
Common elements in boardcore.inc
of all STM8L devices, together with docs in the target folders, that also show the default mapping, make the configuration easy.
STM8S "Low" and "High density" devices use matching configuration items. STM8L152R8 has the most options.
Configuration of STM8 memory variants
Issue #330 made EEPROMBASE
, the EEPROM start address, a target.inc
configuration item which can be used to write device independent code.
The new feature was used in issue #339 which removed hard-coded addresses in EEALIAS
so that offloading a part of the dictionary to the EEPROM now works for both STM8S and STM8L devices. STM8L "Low density" devices have a much smaller EEPROM than those in the STM8S family, of course.
Issue #355 introduced a PAGESIZE
constant so that device independent code for "Flash ROM page write" can load it with #require PAGESIZE
.
Note that memory variants should be defined in the configuration folder's target.inc
based on the device type (STM8L or STM8S, "Low", "Medium" or "High density"). If you're engineering a product you should care for selecting the device with the right specs. For casual use memory specs are most likely not that important (if there is evidence of the opposite please share it and file an issue).
Make target for OpenOCD / stm8-gdb
OpenOCD and stm8-gdb can be of great help, especially when dealing with new devices. Issue #350 added support for an ELF target so that binaries that can be loaded into stm8-gdb can be built with make BOARD=<boardname> debug
.
There are notes about using OpenOCD and stm8-gdb is in this Gist which also contain OpenOCD target configuration files for STM8L101 and STM8L051 "Low density" devices.
Experimental debug console
At times it's interesting to examine the state of a Forth program in the middle of the execution. Issue #372 introduces a very simple debug console with the words OUTER
and BYE
.
Here is a simple example:
#require BYE
: test ( n -- )
FOR
I DUP . 2 MOD 0= IF
CR ." Break - mind the stack - continue with BYE" CR
OUTER THEN
NEXT ." done"
;
A debug session on a STM8S003F3, where a FOR ... NEXT
loop is terminated manually by changing the loop counter on the return stack ($3FF growing down), looks like this:
66 7 test 7 6
Break - mind the stack - continue with BYE
$03F0 10 dump
3F0 23 0 0 A 8D 1E 8D 12 1 1D 0 6 8D 1E 8D 12 1_______________ ok
bye 5 4
Break - mind the stack - continue with BYE
$03F0 10 dump
3F0 23 0 0 A 8D 1E 8D 12 1 1D 0 4 8D 1E 8D 12 1_______________ ok
$3FA ? 4 ok
0 $3FA ! ok
bye done ok
. 66 ok
Note that a single misspelled word will clear both the data and the return stacks. This will not only reset the console but it will terminate the program and typing BYE
in this situation will crash the system! There is clearly room for improvement.
Boards and target support
STM8L101F3 Low density support
Several differences between the STM8L101 and other STM8L devices (e.g. option bytes) delayed STM8 eForth support for a long time. STM8 eForth now supports RM0013 devices with NVM
, the TIM2 based BG
task and also the simulated serial interface. A binary release is available and the ordinary STM8 eForth workflows can be used.
Please refer to the docs in the configuration folder STM8L101F3 and the following issues:
- #349 Add support for STM8L101 and STM8L001
- #356 improve STM8L101 docs and efr file
- #356 STM8L101F3: improve target.inc and docs Documentation
Note that statements in the Wiki and other docs that the STM8L101 would not be supported have been changed. Using OpenOCD and gdb-stm8 were instrumental for adding support of this MCU.
STM8L051F3 Low density support
Support for RM0031 STM8L "Low density" devices has long been available. Test results with STM8L devices from applications in the community were used to revise support. Configuration options (e.g. USART, BG timer, simulated serial interface) and docs are now consistent with other STM8L devices.
Please refer to the docs in the STM8L051F3 configuration folder.
STM8L Medium density support
Although there has long been the STM8L-Discovery configuration by @plumbum requests for a more active support of STM8L "Medium density" devices like STM8L151K4 was a recurrent issue (e.g. #218, #267, #268 or #287).
@Eelkhoorn finally sent an STM8L151K4 breakout board to @TG9541 and contributed to configuration files and to testing. Issue #354 implemented support for RM0031 STM8L "Medium density" devices, independent of "Medium+" and "High density" devices.
Please refer to the docs in the STM8L151K4 configuration folder where console configuration options are listed.
STM8L High density support
STM8L "High density" devices have a rather rich feature set and more memory than other STM8L devices. Issue #358 added support for these devices and also describes the various console options. It's possible that this configuration also works for "Medium+ density" devices like the STM8L152R6 but no samples have been tested and feedback would be appreciated.
Please refer to the ...