You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
NOTE: In the DEFINE state, c4a changes the state to COMPILE after adding the next word. NOTE: Unlike ColorForth, ';' compiles EXIT and then changes the state to INTERPRET.
Tachyon's influence on c4a
In c4a, a program is a sequence of WORD-CODEs.
A WORD-CODE is a 16-bit unsigned number.
Primitives are assigned numbers sequentially from 0 to [BYE].
If a WORD-CODE is less than or equal to [BYE], it is a primitive.
If the top 4 bits are set, it is 13-bit unsigned literal, 0-$0FFF.
If it is between 'BYE' and $F000, it is the code address of a word to execute.
Development board considerations
c4a is intended to be used with development boards via the Arduino IDE.
However, it can be built for PCs as well for testing.
I am not aware of 64-bit dev boards.
So a CELL in c4a is 32-bits.
C4A has many built-in primitives, for the following reasons:
Program flash is often quite large, so why not use it?
To give C4A more functionality out of the box.
C4A also runs faster because of it.
Building c4a
PCs - Windows and Linux, and probably others
Windows: there is a c4a.sln file for Visual Studio
only the x86 target (32-bit) is supported.
Linux: there is a makefile.
only the 32-bit configuration (-m32) is supported.
Others:
c4a is simple enough that it should be easy to migrate it to any platform.
Development boards via the Arduino IDE:
I use the Arduino IDE v2.x
There is a c4a.ino file
File 'c4a.h' controls parameters for the target board
Edit the section where IS_BOARD is defined to set the configuration for the board
Use #define FILE_NONE to disable support for blocks and LittleFS
The version must be 4.2.0 or later. Versions older than 4.0.0 do not support boards using
the RP2350 microcontroller.
Use #define FILE_PICO to include support for LittleFS
For the Teensy-4.x:
Use #define FILE_TEENSY to include support for LittleFS
c4a memory areas
c4a provides a single memory area. See 'mem-sz' (MEM_SZ in c4a.h) for its size.
It is broken into 3 areas: CODE, VARS, and DICTIONARY.
The CODE area is an aray of WORD-CODEs starting at the beginning of the memory.
here is an offset into the CODE area.
The size of the CODE area is code-sz. See CODE_SZ in c4a.h.
NOTE: Use wc@ and wc! to get and set 16-bit values in the code area.
NOTE: Use cv@ and cv! to get and set 32-bit values in the code area.
NOTE: CODE slots 0-25 (0 wc@ .. 25 wc@) are reserved for c4a system values.
NOTE: CODE slots 26-(BYE) are unused by c4a.
NOTE: Using wc@ and wc!, c4a provides storage space for many 16-bit variables.
NOTE: Using cv@ and cv!, c4a provides storage space for many 32-bit variables.
NOTE: These are free for the user/application to use as desired.
The VARS area is defined to begin at address code-sz wc-sz * memory +.
vhere is the absolute address of the first free byte the VARS area.
The DICTIONARY is at the end of the memory. 'last' grows toward the beginning of the memory.
last is the address of the most recently created word.
A dictionary entry is [xt:2][flags:1][len:1][name:NAME_LEN][0:1]
The default NAME_LEN is 11 (see c4a.h), so 'de-sz' is 16.
Use ->memory to turn an offset into an address.
WORD
STACK
DESCRIPTION
memory
(--A)
A: starting address of the c4a memory
mem-sz
(--N)
N: size in BYTEs of the c4a memory
code-sz
(--N)
N: number of in WORD-CODE slots in the code area
stk-sz
(--N)
N: size in CELLs of the built-in stacks
wc-sz
(--N)
N: size in BYTEs of a WORD-CODE
de-sz
(--N)
N: size in BYTEs of a dictionary entry
(dsp)
(--N)
N: Address of the data stack pointer
(rsp)
(--N)
N: Address of the return stack pointer
(lsp)
(--N)
N: Address of the loop stack pointer
(asp)
(--N)
N: Address of the A stack pointer
(bsp)
(--N)
N: Address of the B stack pointer
(tsp)
(--N)
N: Address of the T stack pointer
(here)
(--N)
N: Address of the HERE variable
(last)
(--N)
N: Address of the LAST variable
base
(--N)
N: Address of the BASE variable
state
(--N)
N: Address of the STATE variable
c4a Strings
Strings in c4a are NULL-terminated with no count byte.
Format specifiers in ftype and ."
Similar to the printf() function in C, c4a supports formatted output using '%'.
For example : ascii dup dup dup ." char: %c, decimal: #%d, binary: %%%b, hex: $%x%n" ;.
Format
Stack
Description
%b
(N--)
Print TOS in base 2.
%c
(N--)
EMIT TOS.
%d
(N--)
Print TOS in base 10.
%e
(--)
EMIT escape (#27).
%i
(N--)
Print TOS in the current base.
%n
(--)
Print CR/LF (13/10).
%q
(--)
EMIT " (#34).
%s
(A--)
Print TOS as a string (formatted).
%S
(A--)
Print TOS as a string (unformatted).
%x
(N--)
Print TOS in base 16.
%B
(--)
Change foreground to blue.
%G
(--)
Change foreground to green.
%P
(--)
Change foreground to purple.
%R
(--)
Change foreground to red.
%W
(--)
Change foreground to white.
%Y
(--)
Change foreground to yellow.
%[x]
(--)
EMIT [x].
The editor
c4a has a built-in editor. It colorizes the code based on tags in the text.
For details, see the Editor documentation. NOTE: Saving a block updates the block in the RAM-disk. NOTE: It does NOT automatically write that block to disk. NOTE: Use 'flush' to write it back to disk/flash.
The A, B, and T stacks
c4a includes A, B, and T stacks.
These are somewhat similar to ColorForth's operations for a and b, but in c4a, they are stacks.
The size of the stacks is configurable (see stk-sz).
The words below are available for all 3 stacks.
Note that there are also additional words r!r@+ and r@- for the return stack.
WORD
STACK
DESCRIPTION
>a
(N--)
Push N onto the A stack.
a!
(N--)
Set A to N.
a@
(--N)
N: value of A.
a@+
(--N)
N: value of A, then increment A.
a@-
(--N)
N: value of A, then decrement A.
!a
(N--)
Store N through A.
!a+
(N--)
Store N through A, then increment A.
!a-
(N--)
Store N through A, then decrement A.
@a
(--N)
Fetch N through A.
@a+
(--N)
Fetch N through A, then increment A.
@a-
(--N)
Fetch N through A, then decrement A.
a>
(--N)
Pop N from the A stack.
adrop
(--)
Drop A-TOS
Temporary words
c4a provides 10 temporary words, 't0' .. 't9'.
They are case-sensitive.
't0' is a temporary word; 'T0' is NOT.
They do not take valuable dictionary space.
They can be used to improve factoring, or as variable or constant names.
t0:t5 are normal words, t6:t9 are INLINE.
Tasks
c4a supports a simple cooperative multi-tasking system.
The task system is not preemptive.
Words add-task (xt--n), yield (--), del-task (n--) are provided.
Each task has its own data stack, return stack, and loop stack.
The A, B, and T stacks are shared by all tasks.
c4a WORD-CODE primitives
NOTE: Since c4a is intended for dev boards, it has many more primitives than C4.
This is primarily because there is more program memory than RAM.
It provides more built-in functionality.
And the system is faster.
The primitives in c4a:
BASE
STACK
DESCRIPTION
(lit)
(--WC)
WC: WORD-CODE for LIT primitive
(jmp)
(--WC)
WC: WORD-CODE for JMP primitive
(jmpz)
(--WC)
WC: WORD-CODE for JMPZ primitive
(jmpnz)
(--WC)
WC: WORD-CODE for JMPNZ primitive
(njmpz)
(--WC)
WC: WORD-CODE for NJMPZ primitive
(njmpnz)
(--WC)
WC: WORD-CODE for NJMPNZ primitive
(exit)
(--WC)
WC: WORD-CODE for EXIT primitive
exit
(--)
EXIT word
dup
(X--X X)
Duplicate TOS (Top-Of-Stack)
?dup
(X--X
X X)
swap
(X Y--Y X)
Swap TOS and NOS (Next-On-Stack)
drop
(N--)
Drop TOS
2dup
(X Y--X Y X Y)
Duplicate TOS and NOS
2drop
(X Y--)
Drop TOS and NOS
over
(X Y--X Y X)
Push NOS
nip
(X Y--Y)
Drop NOS
tuck
(X Y--Y X Y)
Perform SWAP, OVER
c@
(A--C)
C: the CHAR at absolute address A
w@
(A--W)
W: the WORD at absolute address A
@
(A--N)
N: the CELL at absolute address A
wc@
(N--WC)
WC: the WORD-CODE in CODE slot N
cv@
(N--)
Code-Variable: Fetch a 32-bit value from CODE slots N/N+1
c!
(C A--)
Store CHAR C to absolute address A
w!
(W A--)
Store WORD W to absolute address A
!
(N A--)
Store CELL N to absolute address A
wc!
(WC N--)
Store WORD-CODE WC to CODE slot N
cv!
(N--)
Code-Variable: Store a 32-bit value to CODE slots N/N+1
if
(X--)
Jump to 'then' if X == 0 (IMMEDIATE)
if0
(X--)
Jump to 'then' if X <> 0 (IMMEDIATE)
-if
(X--X)
Jump to 'then' if X == 0 (IMMEDIATE)
then
(--)
Target for 'if' branch (IMMEDIATE)
begin
(--)
Begin a loop (IMMEDIATE)
again
(--)
Jump to matching 'begin' (IMMEDIATE)
while
(X--)
Jump to matching 'begin' if X <> 0 (IMMEDIATE)
-while
(X--X)
Jump to matching 'begin' if X <> 0 (IMMEDIATE)
until
(X--)
Jump to matching 'begin' if X == 0 (IMMEDIATE)
MATH
STACK
DESCRIPTION
+
(X Y--N)
N: X + Y
-
(X Y--N)
N: X - Y
*
(X Y--N)
N: X * Y
*/
(N X Y--N')
N': (N * X) / Y - Scale N by X/Y
/
(X Y--Q)
Q: X / Y quotient (integer division)
mod
(X Y--M)
M: X modulo Y
/mod
(X Y--M Q)
M: X modulo Y, Q: quotient of X / Y
<<
(X Y--Z)
Z: X left-shifted Y bits
>>
(X Y--Z)
Z: X right-shifted Y bits
1+
(X--Y)
Increment TOS
1-
(X--Y)
Decrement TOS
2+
(X--Y)
Y: X + 2
2*
(X--Y)
Y: X * 2
2/
(X--Y)
Y: X / 2
CELLS
(X--Y)
Y: X * CELL
CELL+
(X--Y)
Y: X + CELL
<
(X Y--F)
F: 1 if (X < Y), else 0
<=
(X Y--F)
F: 1 if (X <= Y), else 0
=
(X Y--F)
F: 1 if (X == Y), else 0
>=
(X Y--F)
F: 1 if (X >= Y), else 0
>
(X Y--F)
F: 1 if (X > Y), else 0
0=
(N--F)
F: 1 if (N == 0), else 0
and
(X Y--N)
N: X AND Y
or
(X Y--N)
N: X OR Y
xor
(X Y--N)
N: X XOR Y
com
(X--Y)
Y: X with all bits flipped (one's complement)
min
(X Y--Z)
Z: the minimum of (X and Y)
max
(X Y--Z)
Z: the maximum of (X and Y)
negate
(X--Y)
Y: -X
abs
(X--Y)
Y: the absolute value of X
MORE PRIMS
STACK
DESCRIPTION
for
(N--)
Begin FOR loop with bounds 0 and N-1.
i
(--I)
N: Current FOR loop index.
next
(--)
Increment I. If I >= N, exit, else start loop again.
unloop
(--)
Unwind the loop stack. NOTE: does NOT exit the loop.
>r
(N--)
Push N onto the return stack
r!
(N--)
Set R to N
r@
(--N)
N: copy of R
r@+
(--N)
N: copy of R, then increment it
r@-
(--N)
N: copy of R, then decrement it
r>
(--N)
Pop N from the return stack
rdrop
(--)
Drop R-TOS
>t
(N--)
Push N onto the T stack
t!
(N--)
Set T to N
t@
(--N)
N: copy of T
t@+
(--N)
N: copy of T, then increment T
t@-
(--N)
N: copy of T, then decrement T
t>
(--N)
Pop N from the T stack
tdrop
(--)
Drop T-TOS
>a
(N--)
Push N onto the A stack
a!
(N--)
Set A to N
a@
(--N)
N: copy of A
a@+
(--N)
N: copy of A, then increment A
a@-
(--N)
N: copy of A, then decrement A
@a
(--C)
Fetch BYTE C through A
@a+
(--C)
Fetch BYTE C through A, then increment A
@a-
(--C)
Fetch BYTE C through A, then decrement A
!a
(C--)
Store BYTE C through A
!a+
(C--)
Store BYTE C through A, then increment A
!a-
(C--)
Store BYTE C through A, then decrement A
a>
(--N)
Pop N from the A stack
adrop
(--)
Drop A-TOS
>b
(N--)
Push N onto the B stack
b!
(N--)
Set B to N
b@
(--N)
N: copy of B
b@+
(--N)
N: copy of B, then increment B
b@-
(--N)
N: copy of B, then decrement B
@b
(--C)
Fetch BYTE C through B
@b+
(--C)
Fetch BYTE C through B, then increment B
@b-
(--C)
Fetch BYTE C through B, then decrement B
!b
(C--)
Store BYTE C through B
!b+
(C--)
Store BYTE C through B, then increment B
!b-
(C--)
Store BYTE C through B, then decrement B
b>
(--N)
Pop N from the B stack
bdrop
(--)
Drop B-TOS
STRINGS
STACK
DESCRIPTION
s-len
(S--N)
N: Length of string S
s-cpy
(D S--D)
Copy string S to D
s-cat
(D S--D)
Concatenate string S to D
s-eq
(D S--F)
F: 1 if string S is equal to D (case sensitive)
s-eqi
(D S--F)
F: 1 if string S is equal to D (NOT case sensitive)
A: Buffer, N: Size, FH: File Handle, X: num chars written
loaded?
(XT A--)
Stops current load if A <> 0 (see find)
load
(N--)
N: Block number to load
load-next
(N--)
Close the current block and load block N next
blocks
(--)
Dump block cache
block-addr
(N--A)
N: Block number, A: Address in cache
flush
(--)
Write RAM disk to flash/disk
edit
(N--)
N: Block number to edit
SYSTEM
STACK
DESCRIPTION
emit
(C--)
Output char C
key
(--C)
Read char C
key?
(--F)
F: 1 if key available, else 0
;
(--)
Compile EXIT, set STATE=INTERPRET (IMMEDIATE)
lit,
(N--)
Compile a push of number N
,
(WC--)
WC: WORD-CODE to store at HERE, HERE += WC-SZ
v,
(N--)
N: CELL to store at VHERE, VHERE += CELL
vc,
(B--)
N: BYTE to store at VHERE, VHERE += 1
const
(N--)
ADD-WORD, generate LIT [N] EXIT
var
(N--)
ADD-WORD, generate LIT [VHERE] EXIT, VHERE += N
val
(--)
ADD-WORD, generate LIT 0 EXIT
(val)
(--)
ADD-WORD, generate LIT [HERE-4] EXIT
next-wd
(--L)
L: length of the next word from the input stream
immediate
(--)
Mark the last created word as IMMEDIATE
inline
(--)
Mark the last created word as INLINE
outer
(S--)
Send string S to the c4a outer interpreter
addword
(--)
Add the next word to the dictionary
timer
(--N)
N: Current time
ms
(MS--)
Sleep for MS milliseconds
see X
(--)
Output the definition of word X
find
(--XT A)
XT: Execution Token, A: Dict Entry address (0 0 if not found)
add-task
(XT--N)
XT: addr of code, N: task slot
del-task
(N--)
Delete task in slot N
.tasks
(--)
Print all tasks
yield
(--)
Yield to the next task
here
(--)
Current value of (HERE)
last
(--)
Current value of (LAST)
vhere
(--)
Current value of (VHERE)
words
(--)
Print list of words and primitives
words-n
(N--)
Print list of N most recently defined words
(.)
(N--)
Output N in the current BASE
.
(N--)
Output N in the current BASE, followed by a SPACE
.s
(--)
Output the stack in the current BASE
allot
(N--)
VHERE += N
bl
(--N)
N: 32 - the ascii value for a space
tab
(--)
EMIT a tab (ascii 9)
cr
(--)
EMIT CR/LF (13, 10)
space
(--)
EMIT a single space
PC ONLY
STACK
DESCRIPTION
system
(S--)
S: String to send to system()
bye
(--)
Exit c4a
DEV BOARD
STACK
DESCRIPTION
pin-input
(P--)
Open pin P for input
pin-output
(P--)
Open pin P for output
pin-pullup
(P--)
Open pin P for input with pullup
dpin@
(P--N)
N: value at digital pin P
dpin!
(N P--)
Write N to digital pin P
apin@
(P--N)
N: value at analog pin P
apin!
(N P--)
Write N to analog pin P
bye
(--)
No-op
c4a default words
Default/built-in words are defined in function sys_load() in file sys-load.cpp.
For details, or to add or change the default words, modify that function.