Skip to content
Forth cross-compiler targeting 6502 processors.
Python
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
LICENSE
README.md
foco65

README.md

foco65

Forth cross-compiler targeting 6502 processors. Outputs xasm compatible assembly source code containing Forth runtime and compiled user program.

Runtime

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 Source Code

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 with org directive
  • boot - forth runtime
  • data - user data
  • text - 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).

Syntax

Identifiers

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.

Comments

Syntax:


\ this is a one-line comment
( this is a multi-line
  comment)

Numbers

Syntax:


123   \ decimal number
$BA98 \ hexadecimal number

Word definitions

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 + ;

Data declarations

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"

Constants

Syntax:

value constant name

Example:


$230 constant dladr

Inline assembly blocks

Syntax:

[code]

; assembly code

[end-code]

Compiler directives

Syntax:

[text-section] name

or:

[data-section] name

Words

: @ 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*

Usage

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

Examples

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 ! ;
You can’t perform that action at this time.