Skip to content

Commit

Permalink
Documentation overhaul, incl. UPLOAD and BOOT
Browse files Browse the repository at this point in the history
  • Loading branch information
dalnefre committed Jul 6, 2014
1 parent d02728b commit 6f978a9
Show file tree
Hide file tree
Showing 4 changed files with 137 additions and 56 deletions.
140 changes: 104 additions & 36 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,116 @@ by Richard W.M. Jones <[email protected]> originally at <http://annexia.org/forth
Comments embedded in the original provide an excellent FORTH implementation tutorial.
See the `/annexia/` directory for a copy of this original source.

Firmware files to make bootable images are maintained at <https://github.com/raspberrypi/firmware>.
See the `/firmware/` directory for local copies used in the build process.

## What is this ?

Jonesforth-ARM is a Forth interpreter developed for ARM.

The algorithm for our unsigned DIVMOD instruction is extracted from 'ARM
Software Development Toolkit User Guide v2.50' published by ARM in 1997-1998

Compared to the original interpreter:

* We did not keep the jonesforth.f section allowing to compile assembly from
the Forth interpreter because it was X86 specific.
Firmware files to make bootable images are maintained at <https://github.com/raspberrypi/firmware>.
See the `/firmware/` directory for local copies used in the build process.

* We pass all the original JonesForth's tests on ARM (except one which
depends on the above X86 assembly compilation).
## What is this ?

* We added a native signed DIVMOD instruction (S/MOD)
_pijFORTHos_ is a bare-metal FORTH interpreter for the Raspberry Pi.
It follows the general strategy given by the excellent examples at <https://github.com/dwelch67/raspberrypi>

Another project porting Jonesforth on ARM is ongoing at
https://github.com/phf/forth
The interpreter uses the RPi miniUART as a console (115200 baud, 8 data bits, no parity, 1 stop bit).
If you have _pijFORTHos_ on an SD card in the RPi,
you can connect it to another machine (even another RPi) using a USB-to-Serial cable <http://www.adafruit.com/products/954>.
When the RPi is powered on (I provide power through the cable),
a terminal program on the host machine provides access to the FORTH console.

## Build and run instructions

If you are building on the ARM target, just type,

$ make

to build the forth interpreter.

After building, we recommend that you run the test-suite by executing,

$ make test

To launch the forth interpreter, type

$ cat jonesforth.f - | ./jonesforth

## Contributors:

ABECASSIS Felix, BISPO VIEIRA Ricardo, BLANC Benjamin, BORDESSOULES Arthur,
BOUDJEMAI Yassine, BRICAGE Marie, ETSCHMANN Marc, GAYE Ndeye Aram,
GONCALVES Thomas, GOUGEAUD Sebastien, HAINE Christopher, OLIVEIRA Pablo,
PLAZA ONATE Florian, POPOV Mihail
If you are building on the RPi, just type:

$ make clean all

Then, copy the firmware and kernel to a blank SD card:

$ cp firmware/* /media/_SD-card_
$ cp kernel.img /media/_SD-card_

Put the prepared SD card into the RPi, connect the USB-to-Serial cable, and power-up to the console.

## Built-in FORTH Words

The table below shows the words pre-defined in _pijFORTHos_ :

| Word | Stack | Description |
|------|-------|-------------|
| DROP | ( a -- ) | drop the top element of the stack |
| SWAP | ( a b -- b a ) | swap the two top elements |
| DUP | ( a -- a a ) | duplicate the top element |
| OVER | ( a b c -- a b c b ) | push the second element on top |
| ROT | ( a b c -- b c a ) | stack rotation |
| -ROT | ( a b c -- c a b ) | backwards rotation |
| 2DROP | ( a b -- ) | drop the top two elements of the stack |
| 2DUP | ( a b -- a b a b ) | duplicate top two elements of stack |
| 2SWAP | ( a b c d -- c d a b ) | swap top two pairs of elements of stack |
| ?DUP | ( 0 -- 0 \| a -- a a ) | duplicate if non-zero |
| 1+ | ( a -- a+1 ) | increment the top element |
| 1- | ( a -- a-1 ) | decrement the top element |
| 4+ | ( a -- a+4 ) | increment by 4 the top element |
| 4- | ( a -- a-4 ) | decrement by 4 the top element |
| + | ( a b -- a+b ) | addition |
| - | ( a b -- a-b ) | subtraction |
| * | ( a b -- a*b ) | multiplication |
| = | ( a b -- p ) | where p is 1 when a == b, 0 otherwise |
| <> | ( a b -- p ) | where p = a <> b |
| < | ( a b -- p ) | where p = a < b |
| > | ( a b -- p ) | where p = a > b |
| <= | ( a b -- p ) | where p = a <= b |
| >= | ( a b -- p ) | where p = a >= b |
| 0= | ( a -- p ) | where p = a == 0 |
| 0<> | ( a -- p ) | where p = a <> 0 |
| 0< | ( a -- p ) | where p = a < 0 |
| 0> | ( a -- p ) | where p = a > 0 |
| 0<= | ( a -- p ) | where p = a <= 0 |
| 0>= | ( a -- p ) | where p = a >= 0 |
| AND | ( a b -- a&b ) | bitwise and |
| OR | ( a b -- a|b ) | bitwise or |
| XOR | ( a b -- a^b ) | bitwise xor |
| INVERT | ( a -- ~a ) | bitwise not |
| LIT | ( -- x ) | used to compile literals in FORTH word |
| ! | ( value addr -- ) | write value at addr |
| @ | ( addr -- value ) | read value from addr |
| +! | ( amount addr -- ) | add amount to value at addr |
| -! | ( amount addr -- ) | subtract amount to value at addr |
| C! | ( c addr -- ) | write byte c at addr |
| C@ | ( addr -- c ) | read byte from addr |
| CMOVE | ( src dst len -- ) | copy len bytes from src to dst |
| >R | (S: a -- ) (R: -- a ) | move the top element from the data stack to the return stack |
| R> | (S: -- a ) (R: a -- ) | move the top element from the return stack to the data stack |
| RDROP | (R: a -- ) | drop the top element from the return stack |
| RSP@ | ( -- addr ) | get return stack pointer |
| RSP! | ( addr -- ) | set return stack pointer |
| DSP@ | ( -- addr ) | get data stack pointer |
| DSP! | ( addr -- ) | set data stack pointer |
| KEY | ( -- c ) | read a character from the console |
| EMIT | ( c -- ) | write character c to the console |
| WORD | ( -- addr len ) | read next word from stdin |
| NUMBER | ( addr len -- n e ) | convert string to number n, with e unparsed characters |
| FIND | ( addr len -- dictionary_addr \| 0 ) | search dictionary for entry matching string |
| >CFA | ( dictionary_addr -- executable_addr ) | get execution address from dictionary entry |
| >DFA | ( dictionary_addr -- data_field_addr ) | get data field address from dictionary entry |
| CREATE | ( addr len -- ) | create a new dictionary entry |
| , | ( n -- ) | write the top element from the stack at HERE |
| [ | ( -- ) | change interpreter state to Immediate mode |
| ] | ( -- ) | change interpreter state to Compilation mode |
| : | ( -- ) | define a new FORTH word |
| ; | ( -- ) | end FORTH word definition |
| IMMEDIATE | ( -- ) | set IMMEDIATE flag of last defined word |
| HIDDEN | ( dictionary_addr -- ) | set HIDDEN flag of a word |
| HIDE | ( -- ) | hide definition of next read word |
| ' | ( -- xt ) | return the codeword address of next read word (compile only) |
| BRANCH | ( -- ) | change FIP by offset which is found in the next codeword |
| 0BRANCH | ( p -- ) | branch if the top of the stack is zero |
| LITSTRING | ( -- s ) | as LIT but for strings |
| TELL | ( addr len -- ) | write a string to the console |
| QUIT | ( -- ) | the first word to be executed |
| /MOD | ( a b -- r q ) | where a = q * b + r |
| S/MOD | ( a b -- r q ) | alternative signed /MOD using Euclidean division |
| CHAR | ( -- c ) | ASCII code of the first character of the next word |
| UPLOAD | ( -- addr len ) | XMODEM file upload to memory image |
| DUMP | ( addr len -- ) | pretty-printed memory dump |
| BOOT | ( addr len -- ) | boot from memory image (see UPLOAD) |
| EXECUTE | ( xt -- ) | jump to the address on the stack |
3 changes: 0 additions & 3 deletions jonesforth.f
Original file line number Diff line number Diff line change
Expand Up @@ -973,9 +973,6 @@ similar to a function pointer in C. We map the execution token to a codeword ad
- 4 / ( returns number of 4-byte cells )
;

: 16# HEX ; ( ALIAS FOR HEX )
: 10# DECIMAL ; ( ALIAS FOR DECIMAL )

( Print the version and OK prompt. )
: WELCOME
S" TEST-MODE" FIND NOT IF
Expand Down
46 changes: 31 additions & 15 deletions jonesforth.s
Original file line number Diff line number Diff line change
Expand Up @@ -38,18 +38,18 @@
@ Reserve three special registers:
@ DSP (r13) points to the top of the data stack
@ RSP (r11) points to the top of the return stack
@ FIP (r10) points to the next forth word that will be executed
@ FIP (r10) points to the next FORTH word that will be executed
@ Note: r12 is often considered a "scratch" register

DSP .req r13
RSP .req r11
FIP .req r10

@ Implement NEXT, which:
@ 1. finds the address of the forth word to execute
@ 1. finds the address of the FORTH word to execute
@ by dereferencing the FIP
@ 2. increment FIP
@ 3. executes the forth word
@ 3. executes the FORTH word
.macro NEXT
ldr r0, [FIP], #4
ldr r1, [r0]
Expand Down Expand Up @@ -90,7 +90,7 @@ jonesforth:
.endm

@ DOCOL is the assembly subroutine that is called
@ at the start of every forth word execution.
@ at the start of every FORTH word execution.
@ It saves the old FIP on the return stack, and
@ makes FIP point to the first codeword.
@ Then it calls NEXT to start interpreting the word.
Expand All @@ -109,8 +109,8 @@ cold_start:


@@ Now we define a set of helper macros that are syntactic sugar
@@ to ease the declaration of Forth words, Native words, Forth variables
@@ and Forth constants.
@@ to ease the declaration of FORTH words, Native words, FORTH variables
@@ and FORTH constants.

@ define the word flags
.set F_IMMED, 0x80
Expand All @@ -120,7 +120,7 @@ cold_start:
@ link is used to chain the words in the dictionary as they are defined
.set link, 0

@ defword macro helps defining new forth words in assembly
@ defword macro helps defining new FORTH words in assembly
.macro defword name, namelen, flags=0, label
.section .rodata
.align 2
Expand Down Expand Up @@ -156,15 +156,15 @@ name_\label :
code_\label : @ assembler code follows
.endm

@ EXIT is the last codeword of a forth word.
@ EXIT is the last codeword of a FORTH word.
@ It restores the FIP and returns to the caller using NEXT.
@ (See DOCOL)
defcode "EXIT",4,,EXIT
POPRSP FIP
NEXT


@ defvar macro helps defining Forth variables in assembly
@ defvar macro helps defining FORTH variables in assembly
.macro defvar name, namelen, flags=0, label, initial=0
defcode \name,\namelen,\flags,\label
ldr r0, =var_\name
Expand All @@ -189,7 +189,7 @@ var_\name :
defvar "BASE",4,,BASE,10


@ defconst macro helps defining Forth constants in assembly
@ defconst macro helps defining FORTH constants in assembly
.macro defconst name, namelen, flags=0, label, value
defcode \name,\namelen,\flags,\label
ldr r0, =\value
Expand Down Expand Up @@ -245,7 +245,7 @@ defcode "OVER",4,,OVER
PUSHDSP r0 @ ( a b c b )
NEXT

@ ROT ( a b c -- b c a) rotation
@ ROT ( a b c -- b c a ) rotation
defcode "ROT",3,,ROT
POPDSP r0 @ ( a b ) r0 = c
POPDSP r1 @ ( a ) r1 = b
Expand Down Expand Up @@ -494,7 +494,7 @@ defcode "INVERT",6,,INVERT
NEXT


@ LIT is used to compile literals in forth word.
@ LIT is used to compile literals in FORTH word.
@ When LIT is executed it pushes the literal (which is the next codeword)
@ into the stack and skips it (since the literal is not executable).
defcode "LIT", 3,, LIT
Expand Down Expand Up @@ -549,7 +549,7 @@ defcode "C@",2,,FETCHBYTE
NEXT

@ CMOVE ( source dest length -- ) copies a chunk of length bytes from source
@ address to dest address
@ address to dest address [FIXME: handle overlapping regions properly]
defcode "CMOVE",5,,CMOVE
POPDSP r0
POPDSP r1
Expand Down Expand Up @@ -887,7 +887,7 @@ defcode "]",1,,RBRAC
str r1, [r0]
NEXT

@ : ( -- ) Define a new forth word
@ : ( -- ) Define a new FORTH word
defword ":",1,,COLON
.int WORD @ Get the name of the new word
.int CREATE @ CREATE the dictionary entry / header
Expand Down Expand Up @@ -932,7 +932,7 @@ defword "HIDE",4,,HIDE
.int HIDDEN @ Set F_HIDDEN flag.
.int EXIT @ Return.

@ TICK ( -- ) returns the codeword address of next read word
@ ' ( -- ) returns the codeword address of next read word
@ only works in compile mode. Implementation is identical to LIT.
defcode "'",1,,TICK
ldr r1, [FIP], #4
Expand Down Expand Up @@ -1190,13 +1190,29 @@ defcode "CHAR",4,,CHAR
PUSHDSP r1
NEXT

@ UPLOAD ( -- addr len ) XMODEM file upload to memory
defcode "UPLOAD",4,,UPLOAD
ldr r0, =0x10000 @ Upload buffer address
ldr r1, =0x7F00 @ Upload limit (32k - 256) bytes
PUSHDSP r0 @ Push buffer address on the stack
bl hexdump @ r0 = rcv_xmodem(r0, r1);
PUSHDSP r0 @ Push upload byte count on the stack
NEXT

@ DUMP ( addr length -- ) Pretty-printed memory dump
defcode "DUMP",4,,DUMP
POPDSP r1
POPDSP r0
bl hexdump @ hexdump(r0, r1);
NEXT

@ BOOT ( addr len -- ) Boot from memory image (see UPLOAD)
@ : BOOT DROP EXECUTE ; \ Equivalent FORTH definition
defcode "BOOT",4,,BOOT
POPDSP r0
POPDSP r1
bx r1

@ EXECUTE ( xt -- ) jump to the address on the stack
@-- WARNING! THIS MUST BE THE LAST WORD DEFINED IN ASSEMBLY (see LATEST) --@
defcode "EXECUTE",7,,EXECUTE
Expand Down
4 changes: 2 additions & 2 deletions start.s
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
@@ and is the first code that runs to boot the O/S kernel.
@@
@@ View this file with hard tabs every 8 positions.
@@ | | | | | max width ->
@@ | | | | | max width ->
@@ | | . | . . . . max width ->
@@ | | . | . . . . max width ->
@@ If your tabs are set correctly, the lines above should be aligned.
@@

Expand Down

0 comments on commit 6f978a9

Please sign in to comment.