CamelForth
Resources
- CamelForth Z80
- On RC2014 Picasso (Minit II) ROM it is available in 8 KiB Bank 8 (JP:
0001). - Forth Tutorials
Basics
Stack manipulation
1 2 3 \ put 1 2 and 3 on stack
. \ pip from stack and dispaly
.s \ show stack (gfort)
2 dup \ duplicate: 2 2
1 2 swap \ swap 2 items: 2 1
1 2 over \ copy secondmost item to top: 1 2 1
1 2 drop \ drop top item: 1
1 2 3 rot \ move thirdmost item to top: 2 3 1
Arithmetic
1 2 3 4 + - * \ 3+4=7, 2-7=-5, 1*-5=-5
Defining words
: DUBL 2 * ; \ define DUBL word that puts 2 on stack and multiplies two stack items
3 DUBL \ now can be called like any other word: 6
Printing strings
Strings are put on stack as pair of address and lenght.
s" Hello HxD! \ record string on stack
type \ print the string
Introspection
words \ list defined words
Variables
Variables are words, calling vairable puts its address on stack.
variable blah \ define variable word
42 blah ! \ store 42 in blah variable
blah @ \ put value on stack
blah ? \ read and print variable
5 constant five \ declare constant
five spaces \ print 5 spaces
true \ -1
false \ 0
Control flow
IF checks result on top of the stack (-1 - true, 0 - false). then is end of if.
variable var
4 var !
: test
var @ 5 >
if ." Greater" cr
else ." Less or equal" cr
then
;
test
?DO takes end and start value and LOOP calls next iteration or is end of loop.
DO iterates always once. I in context of iteration puts iteration count on the stack. 2 +loop will step by 2 while -1 +loop will count down. leave breaks the loop.
: test
11 1 ?do i . cr loop
;
test
: fib 0 1
begin
dup >r rot dup r> > \ condition
while
rot rot dup rot + dup . \ body
repeat
drop drop drop ; \ after loop has executed
20 fib
: lcd
begin
swap over mod \ body
dup 0= \ condition
until drop . ;
27 21 lcd
Infinite loop.
: test
begin ." Diamonds are forever" cr again
;
Arrays
Access works by adding offset of size cells to base array address and then accessing via it like normal variable.
create foo 16 cells allot / creates array foo with 16 elements
5 foo 2 cells + ! / store 5 in index 2
foo 2 cells + @ / put value at index 2 on stack
Constants are added with , word.
create sizes 18 , 21 , 24 , 27 , 30 , 255 ,
CamelForth Words
Low level
TABLE 1. GLOSSARY OF WORDS IN CAMEL80.AZM
Words which are (usually) written in CODE.
NAME stack in -- stack out description
Guide to stack diagrams: R: = return stack,
c = 8-bit character, flag = boolean (0 or -1),
n = signed 16-bit, u = unsigned 16-bit,
d = signed 32-bit, ud = unsigned 32-bit,
+n = unsigned 15-bit, x = any cell value,
i*x j*x = any number of cell values,
a-addr = aligned adrs, c-addr = character adrs
p-addr = I/O port adrs, sys = system-specific.
Refer to ANS Forth document for more details.
ANS Forth Core words
These are required words whose definitions are
specified by the ANS Forth document.
! x a-addr -- store cell in memory
+ n1/u1 n2/u2 -- n3/u3 add n1+n2
+! n/u a-addr -- add cell to memory
- n1/u1 n2/u2 -- n3/u3 subtract n1-n2
< n1 n2 -- flag test n1<n2, signed
= x1 x2 -- flag test x1=x2
> n1 n2 -- flag test n1>n2, signed
>R x -- R: -- x push to return stack
?DUP x -- 0 | x x DUP if nonzero
@ a-addr -- x fetch cell from memory
0< n -- flag true if TOS negative
0= n/u -- flag return true if TOS=0
1+ n1/u1 -- n2/u2 add 1 to TOS
1- n1/u1 -- n2/u2 subtract 1 from TOS
2* x1 -- x2 arithmetic left shift
2/ x1 -- x2 arithmetic right shift
AND x1 x2 -- x3 logical AND
CONSTANT n -- define a Forth constant
C! c c-addr -- store char in memory
C@ c-addr -- c fetch char from memory
DROP x -- drop top of stack
DUP x -- x x duplicate top of stack
EMIT c -- output character to console
EXECUTE i*x xt -- j*x execute Forth word 'xt'
EXIT -- exit a colon definition
FILL c-addr u c -- fill memory with char
I -- n R: sys1 sys2 -- sys1 sys2
get the innermost loop index
INVERT x1 -- x2 bitwise inversion
J -- n R: 4*sys -- 4*sys
get the second loop index
KEY -- c get character from keyboard
LSHIFT x1 u -- x2 logical L shift u places
NEGATE x1 -- x2 two's complement
OR x1 x2 -- x3 logical OR
OVER x1 x2 -- x1 x2 x1 per stack diagram
ROT x1 x2 x3 -- x2 x3 x1 per stack diagram
RSHIFT x1 u -- x2 logical R shift u places
R> -- x R: x -- pop from return stack
R@ -- x R: x -- x fetch from rtn stk
SWAP x1 x2 -- x2 x1 swap top two items
UM* u1 u2 -- ud unsigned 16x16->32 mult.
UM/MOD ud u1 -- u2 u3 unsigned 32/16->16 div.
UNLOOP -- R: sys1 sys2 -- drop loop parms
U< u1 u2 -- flag test u1<n2, unsigned
VARIABLE -- define a Forth variable
XOR x1 x2 -- x3 logical XOR
ANS Forth Extensions
These are optional words whose definitions are
specified by the ANS Forth document.
<> x1 x2 -- flag test not equal
BYE i*x -- return to CP/M
CMOVE c-addr1 c-addr2 u -- move from bottom
CMOVE> c-addr1 c-addr2 u -- move from top
KEY? -- flag return true if char waiting
M+ d1 n -- d2 add single to double
NIP x1 x2 -- x2 per stack diagram
TUCK x1 x2 -- x2 x1 x2 per stack diagram
U> u1 u2 -- flag test u1>u2, unsigned
Private Extensions
These are words which are unique to CamelForth.
Many of these are necessary to implement ANS
Forth words, but are not specified by the ANS
document. Others are functions I find useful.
(do) n1|u1 n2|u2 -- R: -- sys1 sys2
run-time code for DO
(loop) R: sys1 sys2 -- | sys1 sys2
run-time code for LOOP
(+loop) n -- R: sys1 sys2 -- | sys1 sys2
run-time code for +LOOP
>< x1 -- x2 swap bytes
?branch x -- branch if TOS zero
BDOS DE C -- A call CP/M BDOS
branch -- branch always
lit -- x fetch inline literal to stack
PC! c p-addr -- output char to port
PC@ p-addr -- c input char from port
RP! a-addr -- set return stack pointer
RP@ -- a-addr get return stack pointer
SCAN c-addr1 u1 c -- c-addr2 u2
find matching char
SKIP c-addr1 u1 c -- c-addr2 u2
skip matching chars
SP! a-addr -- set data stack pointer
SP@ -- a-addr get data stack pointer
S= c-addr1 c-addr2 u -- n string compare
n<0: s1<s2, n=0: s1=s2, n>0: s1>s2
USER n -- define user variable 'n'
High level
TABLE 1. GLOSSARY OF "HIGH LEVEL" WORDS
(files CAMEL80D.AZM and CAMEL80H.AZM)
NAME stack in -- stack out description
Guide to stack diagrams: R: = return stack,
c = 8-bit character, flag = boolean (0 or -1),
n = signed 16-bit, u = unsigned 16-bit,
d = signed 32-bit, ud = unsigned 32-bit,
+n = unsigned 15-bit, x = any cell value,
i*x j*x = any number of cell values,
a-addr = aligned adrs, c-addr = character adrs
p-addr = I/O port adrs, sys = system-specific.
Refer to ANS Forth document for more details.
ANS Forth Core words
These are required words whose definitions are
specified by the ANS Forth document.
# ud1 -- ud2 convert 1 digit of output
#S ud1 -- ud2 convert remaining digits
#> ud1 -- c-addr u end conv., get string
' -- xt find word in dictionary
( -- skip input until )
* n1 n2 -- n3 signed multiply
*/ n1 n2 n3 -- n4 n1*n2/n3
*/MOD n1 n2 n3 -- n4 n5 n1*n2/n3, rem & quot
+LOOP adrs -- L: 0 a1 a2 .. aN --
, x -- append cell to dict
/ n1 n2 -- n3 signed divide
/MOD n1 n2 -- n3 n4 signed divide, rem & quot
: -- begin a colon definition
; end a colon definition
<# -- begin numeric conversion
>BODY xt -- a-addr adrs of param field
>IN -- a-addr holds offset into TIB
>NUMBER ud adr u -- ud' adr' u'
convert string to number
2DROP x1 x2 -- drop 2 cells
2DUP x1 x2 -- x1 x2 x1 x2 dup top 2 cells
2OVER x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 per diag
2SWAP x1 x2 x3 x4 -- x3 x4 x1 x2 per diagram
2! x1 x2 a-addr -- store 2 cells
2@ a-addr -- x1 x2 fetch 2 cells
ABORT i*x -- R: j*x -- clear stack & QUIT
ABORT" i*x 0 -- i*x R: j*x -- j*x print msg &
i*x x1 -- R: j*x -- abort,x1<>0
ABS n1 -- +n2 absolute value
ACCEPT c-addr +n -- +n' get line from terminal
ALIGN -- align HERE
ALIGNED addr -- a-addr align given addr
ALLOT n -- allocate n bytes in dict
BASE -- a-addr holds conversion radix
BEGIN -- adrs target for backward branch
BL -- char an ASCII space
C, char -- append char to dict
CELLS n1 -- n2 cells->adrs units
CELL+ a-addr1 -- a-addr2 add cell size to adrs
CHAR -- char parse ASCII character
CHARS n1 -- n2 chars->adrs units
CHAR+ c-addr1 -- c-addr2 add char size to adrs
COUNT c-addr1 -- c-addr2 u counted->adr/len
CR -- output newline
CREATE -- create an empty definition
DECIMAL -- set number base to decimal
DEPTH -- +n number of items on stack
DO -- adrs L: -- 0 start of DO..LOOP
DOES> -- change action of latest def'n
ELSE adrs1 -- adrs2 branch for IF..ELSE
ENVIRONMENT? c-addr u -- false system query
EVALUATE i*x c-addr u -- j*x interpret string
FIND c-addr -- c-addr 0 ..if name not found
xt 1 ..if immediate
xt -1 ..if "normal"
FM/MOD d1 n1 -- n2 n3 floored signed division
HERE -- addr returns dictionary pointer
HOLD char -- add char to output string
IF -- adrs conditional forward branch
IMMEDIATE -- make last def'n immediate
LEAVE -- L: -- adrs exit DO..LOOP
LITERAL x -- append numeric literal to dict.
LOOP adrs -- L: 0 a1 a2 .. aN --
MAX n1 n2 -- n3 signed maximum
MIN n1 n2 -- n3 signed minimum
MOD n1 n2 -- n3 signed remainder
MOVE addr1 addr2 u -- smart move
M* n1 n2 -- d signed 16*16->32 multiply
POSTPONE -- postpone compile action of word
QUIT -- R: i*x -- interpret from keyboard
RECURSE -- recurse current definition
REPEAT adrs1 adrs2 -- resolve WHILE loop
SIGN n -- add minus sign if n<0
SM/REM d1 n1 -- n2 n3 symmetric signed division
SOURCE -- adr n current input buffer
SPACE -- output a space
SPACES n -- output n spaces
STATE -- a-addr holds compiler state
S" -- compile in-line string
." -- compile string to print
S>D n -- d single -> double precision
THEN adrs -- resolve forward branch
TYPE c-addr +n -- type line to terminal
UNTIL adrs -- conditional backward branch
U. u -- display u unsigned
. n -- display n signed
WHILE -- adrs branch for WHILE loop
WORD char -- c-addr n parse word delim by char
[ -- enter interpretive state
[CHAR] -- compile character literal
['] -- find word & compile as literal
] -- enter compiling state
ANS Forth Extensions
These are optional words whose definitions are
specified by the ANS Forth document.
.S -- print stack contents
/STRING a u n -- a+n u-n trim string
AGAIN adrs -- uncond'l backward branch
COMPILE, xt -- append execution token
DABS d1 -- +d2 absolute value, dbl.prec.
DNEGATE d1 -- d2 negate, double precision
HEX -- set number base to hex
PAD -- a-addr user PAD buffer
TIB -- a-addr Terminal Input Buffer
WITHIN n1|u1 n2|u2 n3|u3 -- f test n2<=n1<n3?
WORDS -- list all words in dict.
Private Extensions
These are words which are unique to CamelForth.
Many of these are necessary to implement ANS
Forth words, but are not specified by the ANS
document. Others are functions I find useful.
!CF adrs cfa -- set code action of a word
!COLON -- change code field to docolon
!DEST dest adrs -- change a branch dest'n
#INIT -- n #bytes of user area init data
'SOURCE -- a-addr two cells: len, adrs
(DOES>) -- run-time action of DOES>
(S") -- c-addr u run-time code for S"
,BRANCH xt -- append a branch instruction
,CF adrs -- append a code field
,DEST dest -- append a branch address
,EXIT -- append hi-level EXIT action
>COUNTED src n dst -- copy to counted str
>DIGIT n -- c convert to 0..9A..Z
>L x -- L: -- x move to Leave stack
?ABORT f c-addr u -- abort & print msg
?DNEGATE d1 n -- d2 negate d1 if n negative
?NEGATE n1 n2 -- n3 negate n1 if n2 negative
?NUMBER c-addr -- n -1 convert string->number
-- c-addr 0 if convert error
?SIGN adr n -- adr' n' f get optional sign
advance adr/n if sign; return NZ if negative
CELL -- n size of one cell
COLD -- cold start Forth system
COMPILE -- append inline execution token
DIGIT? c -- n -1 ..if c is a valid digit
-- x 0 ..otherwise
DP -- a-addr holds dictionary ptr
ENDLOOP adrs xt -- L: 0 a1 a2 .. aN --
HIDE -- "hide" latest definition
HP -- a-addr HOLD pointer
IMMED? nfa -- f fetch immediate flag
INTERPRET i*x c-addr u -- j*x
interpret given buffer
L0 -- a-addr bottom of Leave stack
LATEST -- a-addr last word in dictionary
LP -- a-addr Leave-stack pointer
L> -- x L: x -- move from Leave stack
NFA>CFA nfa -- cfa name adr -> code field
NFA>LFA nfa -- lfa name adr -> link field
R0 -- a-addr end of return stack
REVEAL -- "reveal" latest definition
S0 -- a-addr end of parameter stack
TIBSIZE -- n size of TIB
U0 -- a-addr current user area adrs
UD* ud1 d2 -- ud3 32*16->32 multiply
UD/MOD ud1 u2 -- u3 ud4 32/16->32 divide
UINIT -- addr initial values for user area
UMAX u1 u2 -- u unsigned maximum
UMIN u1 u2 -- u unsigned minimum