When implementing a driver for the STM8 I2C peripheral I needed BTJx and JREQ branches in Forth code. This wasn't the first time I did that and I had prepared some code to calculated and fix the relative address at the target "label". When I also needed an ELSE block it struck me that this had been solved before - in IF ... ELSE ... THEN.
Here is the code:
\ STM8eForth : control structures with relative addressing TG9541-201124
\ ------------------------------------------------------------------------------
#require >Y
: THEN ( -- ) [COMPILE] [ HERE OVER - 1- SWAP C! [COMPILE] ] ; IMMEDIATE
: >REL ( -- ) HERE 0 C, ; \ like >MARK for rel. branch
: ELSE ( -- ) [COMPILE] [ $20 C, [COMPILE] ] >REL \ JRA rel
SWAP [COMPILE] THEN ; IMMEDIATE
: JREQ ( F:Z -- ) [COMPILE] [ $27 C, [COMPILE] ] >REL ; IMMEDIATE
: IF ( n -- ) COMPILE >Y [COMPILE] JREQ ; IMMEDIATE
After loading this redefinition of IF .. ELSE .. THEN to RAM, Forth code can be written just like before. When it's no longer needed the temporary compiler change can be discarded and the code using relative addressing remains valid.
The real difference is that now machine code for branch instructions can be used that work like the library words ]C! or ]B!:
#require >REL : ]B@IF ( -- ) 2* $7201 + , , ] >REL ; \ BTJF a,#bit,rel : ]@IF ( -- ) $90CE , , ( LDW Y,a ) ] [COMPILE] JREQ ; NVM VARIABLE vt : testb [ vt 1 ]B@IF ." set" ELSE ." not set" THEN ; : testNZ [ vt ]@IF ." not " THEN ." zero" ; RAM
The word ]B@IF compiles to "BTJF addr,#bit,rel" and ]@IF compiles to "LDW Y,#n JREQ rel".
I plan to add these words and others like ]C@IF (LD A,addr JREQ rel) or ]A<IF (CP A,#c JRPL rel) to the library that directly load >REL.
Discussions
Become a Hackaday.io Member
Create an account to leave a comment. Already have an account? Log In.