Forth cross-compiler targeting 6502 processors. Outputs xasm compatible assembly source code containing Forth runtime and compiled user program.
Generated Forth runtime is 16-bit indirect-threaded.
Parameter stack is full-descending and addressed by X
register. Address and
size of the parameter stack are by default $600 and 256 respectively and are
user-configurable.
Hardware stack is used as return stack.
The runtime uses 12 bytes on zero page: 2-byte instruction pointer ip
and
5 2-byte work registers: w
, z
, cntr
, tmp
, tmp2
which may be used
in user-defined words (note than on every word entry these registers' contents
are undefined).
On entry runtime initializes instruction pointer and enters user-defined word
main
which is supposed to never exit (i.e. contain an infinite loop).
Generated assembly source code for words/data/code blocks is logically grouped
into sections. Default order of sections is: init
, boot
, data
, text
.
Sections:
init
- top of the output, typically contains user-provided assembly code block withorg
directiveboot
- forth runtimedata
- user datatext
- core words and user program
User-defined data is output into the most recently declared data section (with
[data-section]
word), everything else is output into the most recently
declared text section (with [text-section]
word).
Identifiers are case sensitive.
Constant and data identifiers consist of alphanumeric characters, '_'s, '-'s and '?'s and must start with a letter, '_', '-' or '?'. In generated assembly labels every '-' is replaced by '_' and every '?' is replaced by '_is_'.
Word identifiers consist of printable ASCII characters. Word identifiers consisting only of alphanumeric characters, '_'s, '-'s, '?'s and starting with a letter, '_', '-' or a '?' are translated automatically to valid assembly labels. Other word identifiers require user-defined label specification (see below).
Section identifiers consist of printable ASCII characters.
Syntax:
\ this is a one-line comment
( this is a multi-line
comment)
Syntax:
123 \ decimal number
$BA98 \ hexadecimal number
Syntax:
:
name [ [label]
asm-label ] words ;
or:
:
name
[ [label]
asm-label ]
[code]
; inline-assembly
[end-code]
;
Examples:
: foo begin end-flag until ;
: bar
[code]
lda #1
sta $D5E8
jmp next
[end-code] ;
: +7 ( n1 -- n2 )
[label] plus_7
7 + ;
One-cell variable:
variable
name
Two-cell variable:
2variable
name
Assembly label at current program counter:
create
name
Compile a one-cell value:
value ,
Compile a one-byte value:
value c,
Allocate a byte-array:
length allot
Allocate Atari XL/XE Antic counted string:
,'
text'
Allocate ASCII counted string:
,"
text"
Allocate Atari XL/XE Antic string:
'
text'
Allocate ASCII string:
"
text"
Syntax:
value constant
name
Example:
$230 constant dladr
Syntax:
[code]
; assembly code
[end-code]
Syntax:
[text-section]
name
or:
[data-section]
name
:
@
0=
1-
1+
2/
2*
2@
2!
and
c!
c@
cmove
count
d-
d+
d=
do
drop
dup
fill
i
j
loop
+loop
lshift
<=
<
>=
>
-
+
or
over
rshift
rsp
sp
swap
unloop
u<
u>
while
<>
>r
r>
=
!
[
]
[code]
[end-code]
cell
cells
not
[text-section]
[data-section]
variable
2variable
constant
create
,
c,
,'
'
,"
"
allot
lit
\
(
recursive
[label]
*
/
m*
foco65 [OPTIONS] INPUT-FILE
OPTIONS:
-h display help
-p ADDR,--pstack-bottom=ADDR parameter stack bottom address
-s SECTS,--sections=SECTS specify comma separated list of sections
default: init,boot,data,text
-S INT,--pstack-SIZE=INT parameter stack size
Example:
$ foco65 foo.forth > foo.asx
Typical Atari XL/XE executable program structure.
[text-section] init
[code]
org $2000
[end-code]
\ constant definitions
\ data declarations
\ word definitions
[text-section] text
: main
\ user program initialization
begin
\ user program main loop
again ;
[code]
run boot
[end-code]
Atari XL/XE example: display character table.
[text-section] init
[code]
org $3000
[end-code]
[text-section] text
$230 constant dladr
variable screen
variable cursor
variable line
: cursor-next ( -- u )
cursor @ dup 1+ cursor ! ;
: put-char ( c -- )
cursor-next c! ;
: set-cursor ( u -- )
screen @ + cursor ! ;
: main
dladr @ 4 + @ screen !
0 line !
16 0 do
line @ set-cursor
line @ 40 + line !
16 0 do
i j 4 lshift or put-char
loop
loop
begin again ;
[code]
run boot
[end-code]
Atari XL/XE example of defining word in assembly: wait for keypress and push the pressed key's code on the parameter stack.
: get-char ( -- c )
[code]
lda #0
dex
sta pstack,x
stx w
jsr do_gc
ldx w
dex
sta pstack,x
jmp next
do_gc
lda $E425
pha
lda $E424
pha
rts
[end-code] ;
Increase cell at the given address. Shows defining words not being a valid assembler label.
create array 16 cells allot
\ increase cell at given address
: ++ ( addr -- )
[label] plus_plus
dup @ 1+ swap ! ;