;
;    Mecrisp - A native code Forth implementation for MSP430 microcontrollers
;    Copyright (C) 2011  Matthias Koch
;
;    This program is free software: you can redistribute it and/or modify
;    it under the terms of the GNU General Public License as published by
;    the Free Software Foundation, either version 3 of the License, or
;    (at your option) any later version.
;
;    This program is distributed in the hope that it will be useful,
;    but WITHOUT ANY WARRANTY; without even the implied warranty of
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;    GNU General Public License for more details.
;
;    You should have received a copy of the GNU General Public License
;    along with this program.  If not, see <http://www.gnu.org/licenses/>.
;

;------------------------------------------------------------------------------
This is the second beta release of an implementation of 
native code Forth for the MSP430 architecture. 

http://sourceforge.net/p/mecrisp

m-atthias@users.sf.net
;------------------------------------------------------------------------------

It fits tightly into 9kb of Flash and should run with 512 Bytes of Ram.
Communication is via serial 9600 baud 8N1 over portpins.

It has two targets:

MSP430F2274 (TX on P3.4, RX on P3.5)
MSP430G2553 (TX on P1.2, RX on P1.1)

If you have wishes for extensions, expect it to grow to 10kb in future.

You can choose to compile to flash or to ram, and it generates
native code with folding, inlining of short words and it opcodes common 
instructions. Note that it doesn't need to save any pointers, 
so info flash keeps untouched.

Hopefully it should be completely interrupt-save and you can hook your Forth
definitions to interrupt vectors. Of course, you should not hook create to a
timer interrupt, unless you want all your memory to be filled with random 
creatures :-)

Altought it is in spirit of ANS, there are some differences: Be careful !

;------------------------------------------------------------------------------

For a quick start, burn the hex file into your msp430f2274 chip. 

Try to set up communication: 
It gives you a welcome message on reset and it's input routine echos back
graphic characters until buffer full. It assumes Unicode utf-8 input.

Start having fun with Mecrisp !

Examples are just fine for RF2500 tool,
which has a red LED between P1.0 and GND,
        a green LED between P1.1 and GND,
             a knob between P1.2 and GND.


Included you will find my MSP430 CPU emulator Mecrimemu, 
if you want to try this out on your x86 linux box.

Its Freepascal source is included unter GPL too, 
but for now, it is a native german speaking tool.

There are some bash skripts to easily invoke it:

mecrisp                    Simply runs Forth
mecrisp-definitions        Runs Forth and feeds in "definitions.txt"

mecrisp-image-definitions  Runs Forth, makes a blank flash dictionary image 
                           and feeds definitions in
mecrisp-image              Runs Forth with flash dictionary image in place

mecrisp-memmap             Runs Forth, feeds in ramdefinitions.txt and 
                           shows disassembler listing for the 
                           executed parts in ram dictionary 
                           and a ram memory map.

The assembler source can be assembled with 
Alfred Arnolds *great* macro assembler AS,
which source is included here to have everything in one place.
Install it, if you like to dive into Mecrisp.

Run the assemble bash skript or use this command for assembling:
asl forth-mecrisp.asm && p2hex forth-mecrisp.p -r 0x0000-0xffff


;------------------------------------------------------------------------------
Inner workings and design ideas behind Mecrisp
;------------------------------------------------------------------------------

As everything is set up to directly write to flash, you always have to use the 
FIG-fashioned <builds does> mechanism instead of create does>.
Builds reserves space for the call-Opcode which otherwise could not be written.

Create in itself only compiles a header structure and does linking, but as 
this is a native code approach, the newly defined word wouldn't do anything
usefull. 

It has a handfull of flags, immediate, inline, folding, ram-allocating, 
opcoding and if the flagbyte is unset, $FF, then the word is invisible. 
Find gives back address of Word and Flags, but Flag 0 means
"normal visible word without anything special." 

If unsuccessful, find will return a zero for address, check for that !

Here is a map of flag meanings:

;   FF  Invisible
; 
;   00  Visible
;   10  Immediate
;   20  Inline - that means, it's contents will be inlined 
                 until $4130, the ret opcode is found.
;   40  Foldable or ready for opcoding
;   80  Allocates initialized Ram (automatically zero-foldable). 
;       Low Nibble notes how many cells (16-Bit-Values) are reserved.
;       For example flag 82 reserves 4 Bytes.
;       Reserved Ram is initialized to the values 
;       after the ret opcode of the word.
; 
;   In detail:
;     Foldable or opcodeable
;     40  0-foldable, e.g. constants
;     41  1-foldable, e.g. 1+
;     42  2-foldable, e.g. swap, xor
;     .   ...
;     47  7-foldable
; 
;     "48" is base for opcodable
;     49  opcodable two operand calculus or logic, all are 
;          automatically 2 foldable (often in combination mit inline: $69)
;     4A  opcodable write memory
;     4B  opcodable read  memory
; 

All string routines give and expect adresses of counted strings.
No one takes the character count on the stack !

You will find a FIG-looking design of the interpreter/compiler,
with query, interpret and number, but it's neither FIG nor ANS.

Internally, quit clears both stacks and loops "query interpret".

Query fetches input with key and emit, and stores it into the input buffer,
from where token and parse get their data. Query assumes utf-8 input

Interpret is complicated and performs all optimisations like folding
and opcoding. For details you can look in the source, which is heavily 
documented, but for now only in German.

I like lowercase most, so everything is lowercase in this implemtation,
but as it is case-insensitive, it won't matter. Of course, it is
only case-insensitive for standard ASCII letters, not for chars defined
in utf-8, like German umlauts ä, ö and ü.

You can switch off UTF-8 support in source, and use it with strict
one-byte-per-character encodings. This affects only query, when
you delete entered characters with backspace.

Comments are not defined,
define your favourite comment with:

: ( [char] ) parse drop immediate ;  ( Comment )
or
: { [char] } parse drop immediate ;  { Comment }

Just to your taste !

Do you mention the strange use of immediate inside of the definition ?
Immediate is itself immediate, as inline is too.

If you compile to flash, you have to set up flags before using ;
which in turn calls smudge. Smudge takes all the flags out of a variable in Ram
and finally burns them into flash. In Ram, they also work the usual way.
This is needed for invisibility of freshly defined words,
and the MSP430 flash specs state that you must not write a 16-bit-flash value 
more than twice. As I need the other write access for name length byte, and as
this implementation has a lot of flags that can coexist, I choosed this way.

If you like to make your definitions foldable, consider this:
: 5+ 5 + [ $41 setflags ] ;
Makes your shortcut foldable, if there is at least one constant number waiting.
: 11more 6 5+ + ;
With folding activated for 5+, this will internally optimize to : 11more 11 + ;

11 + internally gets opcoded to add #11, @r4... 

If you use this often, why not define:

: 0-foldable $40 setflags immediate ;
: 1-foldable $41 setflags immediate ;
: 2-foldable $42 setflags immediate ;
...
: 7-foldable $47 setflags immediate ;

This would be the setting for maximal optimisation:
: 5+ 5 +  1-foldable ;
: 11more 6 5+ +  1-foldable ;

Constants are automatically activated for folding, so if you write:

$20 constant P1IN
$21 constant P1OUT
$22 constant P1DIR
$27 constant P1REN

 %1 constant led_red
%10 constant led_green

: led-init led_green led_red or P1DIR c! ;

it will get folded to : led-init 3 $22 c! ;

As c! is opcodable, the opcode for mov #3, &022h is written to the dictionary,
where it consumes 6 bytes.

Normal calls take up 4 Bytes,
literals take up 8 Bytes (sic!),
inlined core words take 2 to 4 bytes.

Special constructs like does> or ." need more.

Do you have an idea how to size-efficiently push a number to data stack ?
I use:
  sub #2, r4         (2 Bytes)
  mov #Constant, @r4 (6 Bytes)

I experimented with the sequence call r9 (2 Bytes) Constant (2 Bytes) 
with a special literal-fetcher-routine which address is always in r9, 
but this eats a lot of clock cycles. 
Nevertheless, you can activate this in source.

Ideas are very welcome ! Did you ever mention that call @sp+ crashes the CPU ?

Variable takes an initialisation value, just like FIG-Forth.

In Ram, it is simply written to the variable cell, which is just
within the dictionary.

In Flash, it decreases a variable-pointer that initially
points to the end of the ram-dictionary, compiles a word
that gives back that address in ram, appends the initialization value
to the flash dictionary and places it in the reserved ram cell.

On each reset of the chip, the dictionary is internally searched for
ram-allocating words, the variable-pointer is updated with every occurrence
and the initialization values are copied from their place after the
ret-opcode of that word to their variable location in ram.

If you define a word with name "init" - its latest definition is called every
startup ! You you can redefine init if you like to add e.g. additional hardware
setup; don't forget to give your old definition of init a call, 
if you have one.

You can write flash with flash! and cflash! - they ensure that flash specs
are regarded, so they won't destroy your flash hardware. They write only
if FF/FFFF is in that place and the requested value is other that FF/FFFF.
They also refuse to write into forth kernel.

Call eraseflash if you want to wipe out everything. Info Flash keeps untouched.

You can switch between compiling to ram and compiling to flash with the words
"compiletoram" and "compiletoflash".

Allot will warn you if you run out of memory. Compiletoram alerts you if 
flash-variable-space-in-ram collides with the ram-dictionary. 
Keep in mind that ram-definitions are blanked out and invisible during 
working in flash. I thought that would be a good idea,
as ram is gone with next reset and your flash-based definitions would jump 
right in the middle of nowhere... No fear, Ram-Dictionary is back by typing
compiletoram, if you haven't overwritten ram-definitions with freshly defined
flash-variables. You get a notice if that happens.

Note that definitions in flash are "backlinked", they point
to the next definition or to FFFF. This way it is possible
to determine the pointers back on reset without the need for rewriteable
storage. This has the side effect that you cannot forget.
I advice you to simply redefine if you have enough flash space left.

In Ram, there is normal search order.
In Flash, determined by a simple comparision on the address "here",
the search starts deeply into the core and proceeds into the user-filled
flash dictionary until the link is FFFF or points to a location where FFFF
is found. The latest found entry with the choosen name is taken.

The very last entry in core dictionary always points to
flash-dictionary-start. My implementation of "words" gives you insight
about flags, places and links, if you are curious.

The DictionaryPointer is regained by looking back from end-of-flash-dictionary
until there is a location that not equals FFFF. Note that if a definition ends
with e.g. a constant or data FFFF and you reset your chip, this is overwritten
by the next defined word. Smudge takes care of that and appends a 0 at the end,
if necessary. Keep it in mind, if you decide to smudge a word and append data
later.

It should be quite easy to port this to other chips,
I have the msp430g2553 in mind.
Simply change your memory needs in the main file and include
your favourite terminal routines.

If you like to change the 8MHz clock frequency, don't forget to change
the flash clock divider to an allowed range too !

If you know the cpu architecture a bit, you surely know the nice feature
that it can do logic operations on memory (port) locations. This is handy
and it saves a lots of space, so I included those optimising shortcuts for you:

cbit@  ( mask address -- flag )
bit@   ( mask address -- flag ) 

cxor!  ( mask address -- )
xor!   ...
cbic!
bic!
cbis!
bis!

The "c" denotes byte access. 

xor toggles bits in that location, as you remember the example above:

: blink led_green P1OUT cxor! ;

will toggle the state of the green light.

bic is "BIt Clear" - and means "not and" to a memory cell.

: darkness led_red led_green or P1OUT cbic! ;

bis means "BIt Set" and does a logic or.
: green-light led_green P1OUT cbis! ;

bit@ is "BIt Test" - it checks if at least one of
the bits in your masks are set in the chosen location.

If you prepared your knob with pull-up resistor,

%100 constant knob
knob P1DIR cbic!
knob P1REN cbis!
knob P1OUT cbis!

you can fetch its state with
: ?knob knob P1IN cbit@ ;

Opcodable words are thighty connected to the inner structure of interpret.
Look there first, before flagging new words as opcodeable 
unless you really want chaos.

Analog is a simply way to fetch an reading of the hardware 10 bit 
analog-digital-converter, slow single shot, with 2,5V internal reference.
Don't forget to do analog enables for your pins !

analog ( u-channel -- u-reading )

A simple example is the internal temperature sensor, read it with
: temperature 10 analog ;

: voltage 11 analog ; 
gives you an idea of the voltage the chip is currently running on.

The ADC result is defined as:
N_adc = 1023 * (U_in - U_ref-) / (U_ref+ - U_ref-)

With positive reference set to 2,5V and negative reference to GND it becomes
N_adc = 1023 * U_in / 2,5V

For internal Vcc voltage measurement, 
U_in is halfed by a voltage divider in hardware.
One example: Vcc of 3,3V should give a reading in channel 11 of 
about 1023 * (3,3V/2) / 2,5V = 676.

: vcc. ."  Vcc is " 0  11 analog  204,6 f/ f. ." V " ;

What is your favourite single-shot ADC10 setup ? 
Which one could serve the many best ?

Interrupt hooks are variables for execution tokens.
They are intitialized to "nop", and can be set with

' blink irq-hook-watchdog !

Enable global interrupts with eint, enable your irq source - 
and have fun. Unset a IRQ-hooks can be done with

' nop irq-hook-watchdog !

but keep in mind that some interrupt sources request that you take care 
of IRQ-flags, failing to reset them will cause that hook to be looped endlessy.

I should be possible to change IRQ handlers on the fly without diabling
the source first.

Here is a working example:
It will toggle the green led on P1.1 if you press the button that is
connected between P1.2 and GND.

( Do you have your favourite port constants already in flash ?)

compiletoflash

$20 constant P1IN
$21 constant P1OUT
$22 constant P1DIR
$23 constant P1IFG
$24 constant P1IES
$25 constant P1IE
$26 constant P1SEL
$27 constant P1REN

compiletoram

7 p1out c!  ( High )
3 p1dir c!  ( Set LEDs as outputs )
4 p1ren c!  ( Activate Pull-Up )
: toggle 2 p1out cxor! 0 p1ifg c! ;  ( Toggle green LED and reset IRQ flag )
' toggle irq-port1 !                 ( Insert IRQ hook )
eint        ( Global IRQ enable )
4 p1ie c!   ( Enable IRQ for P1.2 )

How would you like to have low-power-modes implemented ?



Number has special features:

number ( Counted-String-Address -- 0 )
                                -- n 1 )
                                -- n-low n-high 2 )

I will start at the beginning:

A trailing $ will temporarily change base to hex,
a trailing % to binary. 

Hopefully it is usefull with lots of port adresses and bit masks
intermixed with normal literals !

Normal numbers as "42" "%10110" "$-a0" or "-113" are converted to one-cell-numbers.
Numbers equipped with a dot are converted to double-length-numbers.

And numbers geared with a comma as "3,14159" or "$3,243F"
are converted to s15.16 fixed-point-numbers. They can be printed with f.
For your own beautiful fixed-point output, I give you these tools:

hold<  ( char -- )  Adds a char to the number buffer from behind
f#     ( n -- n )   Processes one after-comma-digit
f#s    ( n -- n )   Processes 16 after-comma-digits.

Look at this example:

: f.3 ( ncomma nwhole )
      tuck     ( nwhole ncomma nwhole )
      dabs     ( nwhole ucomma uwhole )
      0        ( nwhole ucomma uwhole 0 )
      <# #s    ( nwhole ucomma 0 0 )

      [char] , hold<
      rot      ( nwhole 0 0 ucomma )
      f# f# f# ( nwhole 0 0 ucomma )
      drop     ( nwhole 0 0 )

      rot      ( 0 0 nwhole ) 
      sign     ( 0 0 )

      #> type space ;

3,14159 2,0 f* f.3 6,283  ok.

It gives you three digits after the comma.

The other uses of the number formating utilities are as normal:
: ud. <# #s #> type space ;
: d. tuck dabs <# #s rot sign #> type space ;
They are internally implemented this way.

For fixpoint-numbers you can use d+ and d- as usual, 
and do division and multiplication with f/ and f*.

For speed reasons, there are two sets of multiplication and division:
u/mod is a 16 / 16 = 16 mod 16 division
m*    is a 16 * 16 = 32 multiplication.
All the single calculations are based on those.

ud/mod is a 32/32 = 32 mod 32 division with
md* 32*32=64 bit multiplication on its side.
The double number calculations, the fixed-point calculations
and */mod with its double intermediate result are based on that.

Signed division is symmetric in this implementation.
For now, there is no support for hardware multiply, if you implement it,
take care of interrupts while number crunching !

All stack jugglers, logic, calculus, and control structures are ANS compatible.
Pictured numerical output works like ANS, 
but #> gives adress of counted string, you know :-)

Besides the inner workings of the interpreter and compiler, 
the CPU specific parts and some extensions,
I hope you will feel comfortable !


;------------------------------------------------------------------------------
Here comes a word list, 
  with short descriptions of all currently included words:
View it with fixed-width font !
;------------------------------------------------------------------------------

;------------------------------------------------------------------------------
; Terminal-IO
;------------------------------------------------------------------------------

        ?key            ( -- Flag ) Checks if a key is waiting
        key             ( -- Char ) Waits for and fetches the pressed key
        emit            ( Char -- ) Emits a character.

;------------------------------------------------------------------------------
; Stack Jugglers  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

Single-Jugglers:

        depth           ( -- +n ) Gives number of single-cell stack items.
        nip             ( x1 x2 -- x2 )
        drop            ( x -- )
        rot             ( x1 x2 x3 -- x2 x3 x1 )
        swap            ( x1 x2 -- x2 x1 )
        tuck            ( x1 x2 -- x2 x1 x2 )
        over            ( x1 x2 -- x1 x2 x1 )
        ?dup            ( x -- 0 | x x )
        dup             ( x -- x x )

        >r              ( x -- ) (R: -- x )
        r>              ( -- x ) (R: x -- )
        r@              ( -- x ) (R: x -- x )

Double-Jugglers:        They perform the same for double numbers.

        2nip            ( x1 x2 x3 x4 -- x3 x4 )
        2drop           ( x1 x2 -- )
        2rot            ( x1 x2 x3 x4 x5 x6 -- x3 x4 x5 x6 x1 x2 )
        2swap           ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
        2over           ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 )
        2dup            ( x1 x2 -- x1 x2 x1 x2 )

        2>r             ( x1 x2 -- ) (R: -- x1 x2 )
        2r>             ( -- x1 x2 ) (R: x1 x2 -- )
        2r@             ( -- x1 x2 ) (R: x1 x2 -- x1 x2 )

;------------------------------------------------------------------------------
; Logic  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

        ><              ( xy -- yx )   Swap bytes
        rshift          ( x1 -- u x2 ) Logical right-shift of u bit-places
        lshift          ( x1 -- u x2 ) Logical  left-shift of u bit-places
        shr             ( x1 -- x2 )   Logical right-shift of one bit-place
        shl             ( x1 -- x2 )   Logical  left-shift of one bit-place
        bic             ( x1 x2 -- x3 ) Bit clear, identical to "not and"
        not             ( x1 -- x2 )   Invert all bits
        xor             ( x1 x2 -- x3 ) Bitwise Exclusive-OR
        or              ( x1 x2 -- x3 ) Bitwise OR
        and             ( x1 x2 -- x3 ) Bitwise AND

;------------------------------------------------------------------------------
; Calculus for single numbers  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

        um*             ( u1 u2 -- ud )  16*16 = 32 Multiplication
        u/mod           ( u1 u2 -- u3 u4 ) 16/16 = 16 rem 16 Division
                                           u1 / u2 = u4 remainder u3   
        /mod            ( n1 n2 -- n3 n4 ) n1 / n2 = n4 rem n3
        mod             ( n1 n2 -- n3 ) n1 / n2 = remainder n3
        /               ( n1 n2 -- n3 ) n1 / n2 = n3
        *               ( u1|n1 u2|n2 -- u3|n3 ) 16*16 = 16 Multiplication
        min             ( n1 n2 -- n1|n2 ) Keeps smaller of top two items
        max             ( n1 n2 -- n1|n2 ) Keeps greater of top two items
        2-              ( u1|n1 -- u2|n2 ) Subtracts two, optimized
        1-              ( u1|n1 -- u2|n2 ) Subtracts one, optimized
        2+              ( u1|n1 -- u2|n2 ) Adds two, optimized
        1+              ( u1|n1 -- u2|n2 ) Adds one, optimized
        even            ( u1|n1 -- u2|n2 ) Makes even. Adds one if uneven.
        2*              ( n1 -- n2 ) Arithmetric  left-shift
        2/              ( n1 -- n2 ) Arithmetric right-shift
        abs             ( n -- u ) Absolute value
        ?negate         ( n1 n2 -- n3 ) Negate n1 if n2 is negative
        negate          ( n1 -- n2 ) Negate
        -               ( u1|n1 u2|n2 -- u3|n3 ) Subtraction
        +               ( u1|n1 u2|n2 -- u3|n3 ) Addition

;------------------------------------------------------------------------------
; Calculus involving double numbers  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

        */              ( n1 n2 n3 -- n4 )     n1 * n2 / n3 = n4
        */mod           ( n1 n2 n3 -- n4 n5 )  n1 * n2 / n3 = n5 remainder n4 
        m/mod           ( d n1 -- n2 n3 )      d / n1 = n3 remainder r2
        m*              ( n1 n2 -- d )         n1 * n2 = d
        um/mod          ( ud u1 -- u2 u3 )     ud / u1 = u3 remainder u2
        ud/mod          ( ud1 ud2 -- ud3 ud4 ) 32/32 = 32 rem 32 Division
                                               ud1 / ud2 = ud4 remainder ud3
        udm*            ( ud1 ud2 -- ud3-Low ud4-High ) 32*32=64 Multiplication
        d2/             ( d1 -- d2 ) Arithmetric right-shift
        d2*             ( d1 -- d2 ) Arithmetric  left-shift
        dabs            ( d -- ud ) Absolute value
        ?dnegate        ( d1 n -- d2 ) Negate d1 if n is negative
        dnegate         ( d1 -- d2 ) Negate
        d-              ( ud1|d1 ud2|d2 -- ud3|d3 ) Subtraction
        d+              ( ud1|d1 ud2|d2 -- ud3|d3 ) Addition
        s>d             ( n -- d ) Makes a signed single number double length

;------------------------------------------------------------------------------
; Comparisions  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

Single-Comparisions:
        u<=             ( u1 u2 -- flag )  Unsigned comparisions
        u>=             ( u1 u2 -- flag )
        u>              ( u1 u2 -- flag )
        u<              ( u1 u2 -- flag )
        <=              ( n1 n2 -- flag )    Signed comparisions
        >=              ( n1 n2 -- flag )
        >               ( n1 n2 -- flag )
        <               ( n1 n2 -- flag )
        0<              ( n - flag )         Negative ?
        0<>             ( x -- flag )
        0=              ( x -- flag )
        <>              ( x1 x2 -- flag )
        =               ( x1 x2 -- flag )

Double-Comparisions:            They perform the same for double numbers.
        du>             ( ud1 ud2 -- flag )
        du<             ( ud1 ud2 -- flag )
        d>              ( d1 d2 -- flag )
        d<              ( d1 d2 -- flag )
        d0<             ( d -- flag )
        d0=             ( d -- flag )
        d<>             ( d1 d2 -- flag )
        d=              ( d1 d2 -- flag )

;------------------------------------------------------------------------------
; Tools (not only) for s15.16 fixed point numbers  (speciality!)
;------------------------------------------------------------------------------

Fixpoint numbers are stored ( n-comma n-whole ) and can be handled 
like signed double numbers.

        f/              ( df1 df2 -- df3 ) Division of two fixpoint numbers
        f*              ( df1 df2 -- df3 ) Multiplication

        hold<           ( char -- ) 
                        Adds character to pictured number output buffer
                        from behind.
        f#S             ( n-comma1 -- n-comma2 )
                        Adds 16 comma-digits to number output
        f#              ( n-comma1 -- n-comma2 )
                        Adds one comma-digit to number output
        f.              ( df -- )
                        Prints a fixpoint number

        number          ( Counted-String-Address -- 0 )
                          cstr-addr              -- n 1 )
                                                 -- n-low n-high 2 )
                        Tries to convert a string to a number.
                                                    
;------------------------------------------------------------------------------
; Number base  (exactly ANS)
;------------------------------------------------------------------------------

        binary          ( -- ) Sets base to 2
        decimal         ( -- ) Sets base to 10
        hex             ( -- ) Sets base to 16
        base            ( -- a-addr ) Base variable address

;------------------------------------------------------------------------------
; Memory access  (subtle differences to ANS, special cpu-specific extensions)
;------------------------------------------------------------------------------

Ram and ports:
        cmove           ( c-addr1 c-addr2 u -- ) Moves u Bytes in Memory
        cbit@           ( mask c-addr -- flag ) Test BIts in byte-location
        bit@            ( mask a-addr -- flag ) Test BIts in word-location
        cxor!           ( mask c-addr -- ) Toggle bits in byte-location 
        xor!            ( mask a-addr -- ) Toggle bits in word-location
        cbic!           ( mask c-addr -- ) Clear BIts in byte-location   
        bic!            ( mask a-addr -- ) Clear BIts in word-location
        cbis!           ( mask c-addr -- ) Set BIts in byte-location
        bis!            ( mask a-addr -- ) Set BIts in word-location
        2constant name  ( ud|d -- ) Makes a double constant.
        constant  name  ( u|n -- )  Makes a single constant.
        2variable name  ( ud|d -- ) Makes an initialized double variable
        variable  name  ( n|n -- )  Makes an initialized single variable
        +!              ( u|n a-addr -- ) Add to memory location
        2!              ( ud|d a-addr -- ) Stores double number in memory
        2@              ( a-addr -- ud|d ) Fetches double number from memory
        c!              ( char c-addr ) Stores byte in memory
        c@              ( c-addr -- char ) Fetches byte from memory
        !               ( u|n a-addr -- ) Stores single number in memory
        @               ( a-addr -- u|n ) Fetches single number from memory

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.
        cflash!         ( char c-addr -- ) Writes byte to flash
        flash!          ( u|n a-addr -- ) Writes single number to flash


;------------------------------------------------------------------------------
; Strings and beautiful output (subtle differences to ANS)
;------------------------------------------------------------------------------

String routines:
        compare         ( cstr-addr-1 cstr-addr-2 -- flag ) 
                        Compares two counted strings
        skipstring      ( cstr-addr -- a-addr )
                        Increases the pointer to the aligned end of the string.

        type            ( cstr-addr -- )
                        Prints a counted string.

        s" Hello"       Compiles a string and 
                        ( -- cstr-addr )
                        gives back its address when executed.

        ." Hello"       Compiles a string and
                        ( -- )
                        prints it when executed.

Pictured numerical output:
        .digit          ( u -- char ) Converts a digit to a char
        digit           ( char -- u ) Converts a char to a digit

        [char] *        Compiles code of following char
                        ( -- char ) when executed

        char *          ( -- char ) gives code of following char
        hold            ( char -- ) Adds character to pictured number 
                                    output buffer from the front.

        sign            ( n -- ) Add a minus sign to pictured number
                                 output buffer, if n is negative

        #S              ( ud1|d1 -- 0 0 ) Add all remaining digits
                        from the double length number to output buffer
        #               ( ud1|d1 -- ud2|d2 ) Add one digit from the
                        double length number to output buffer
        #>              ( ud|d -- cstr-addr ) 
                        Drops double number and finishes 
                        pictured numeric output ready for type
        <#              ( -- ) Prepare pictured number output buffer
        u.              ( u -- ) Print unsigned single number
        .               ( n -- ) Print single number
        ud.             ( ud -- ) Print unsigned double number
        d.              ( d -- ) Print double number

Deep insights:
        words           ( -- ) Prints list of defined words.
        .s              ( many -- many )    Prints        stack contents
        .rs             ( R: many -- many ) Prints return stack contents


;------------------------------------------------------------------------------
; User input and its interpretation (more FIG style, speciality!)
;------------------------------------------------------------------------------

        query           ( -- ) Fetches user input to input buffer
        token           ( -- cstr-addr ) Cuts one token out of input buffer
        parse           ( char -- cstr-addr )
                        Cuts anything delimited by char out of input buffer

        interpret       ( any -- any ) Execute, compile, fold, optimize...
        quit            ( many -- ) (R: many -- ) Resets Stacks

        ?comp           ( -- ) Aborts, if not in compile mode
        ?stack          ( -- ) Aborts, if stack is out of borders

;------------------------------------------------------------------------------
; Dictionary expansion  (speciality!)
;------------------------------------------------------------------------------

        ,               ( u|n -- ) Appends a single number to dictionary
        c,              ( char -- ) Appends a byte to dictionary
        align,          ( -- ) Makes Dictionary Pointer even, if uneven.
        string,         ( cstr-addr -- ) Inserts a string without runtime
        literal,        ( u|n -- ) Compiles a literal with runtime
        inline,         ( a-addr -- ) Inlines the choosen subroutine
        call,           ( a-addr -- ) Compiles a call to a subroutine
        ret,            ( -- ) Compiles a ret opcode
        allot           ( n -- ) Tries to advance Dictionary Pointer by n bytes
                                 Aborts, if not enough space available
        here            ( -- a-addr|c-addr ) 
                        Gives current position in Dictionary

        compiletoram    ( -- ) Makes ram   the target for compiling
        compiletoflash  ( -- ) Makes flash the target for compiling

;------------------------------------------------------------------------------
; Flags and inventory  (speciality!)
;------------------------------------------------------------------------------

        smudge          ( -- ) Makes current definition visible, burns 
                               collected flags to flash and 
                               takes care of proper ending
        inline          ( -- ) Makes current definition inlineable.
                               For flash, place it inside your definition !
        immediate       ( -- ) Makes current definition immediate.
                               For flash, place it inside your definition !
        setflags        ( char -- ) Sets Flags with a mask. This isn't immediate,
                               but for flash, place it inside your definition !
        create name     ( -- ) Creates and links a new invisible dictionary 
                               header that does nothing.
                               Use FIG-style <builds .. does> !
        find            ( cstr-addr -- a-addr flags ) 
                               Searches for a String in Dictionary.
                               Gives back flags, which are different to ANS !

;------------------------------------------------------------------------------
; Compiler essentials  (subtle differences to ANS)
;------------------------------------------------------------------------------

        execute         ( a-addr -- ) Calls subroutine
        recurse         ( -- ) Lets the current definition call itself
        ' name          ( -- a-addr ) Tries to find name in dictionary
                                      gives back executable address
        postpone name   ( -- ) Helps compiling immediate words.
        does>           ( -- ) executes: ( -- a-addr )
                               Gives address to where you have stored data.
        <builds         ( -- ) Makes Dictionary header and reserves space
                               for special call.
        state           ( -- a-addr ) Address of state variable
        ]               ( -- ) Switch to compile state
        [               ( -- ) Switch to execute state
        ;               ( -- ) Finishes new definition
        : name          ( -- ) Opens new definition

;------------------------------------------------------------------------------
; Control structures (exactly ANS)
;------------------------------------------------------------------------------
Internally, they have complicated compile-time stack effects.

        ?pairs          ( u1 u2 -- ) Aborts, if u1 and u2 are not equal

Decisions:

flag if ... then
flag if ... else ... then

        then            ( -- )           This is the common
        else            ( -- )           flag if ... [else ...] then
        if              ( flag -- )      structure.

Indefinite Loops:

begin ... again
begin ... flag until
begin ... flag while ... repeat

        repeat          ( -- ) Finish of a middle-flag-checking loop.

        while           ( flag -- ) Check a flag in the middle of a loop

        until           ( flag -- ) begin ... flag until 
                                    loops as long flag is true
        again           ( -- )  begin ... again 
                                is an endless loop
        begin           ( -- )


Definite Loops:

limit index   do ... [one or more leave(s)] ... loop
             ?do ... [one or more leave(s)] ... loop 
              do ... [one or more leave(s)] ... n +loop
             ?do ... [one or more leave(s)] ... n +loop


        k               ( -- u|n ) Gives third  loop index
        j               ( -- u|n ) Gives second loop index
        i               ( -- u|n ) Gives innermost loop index


        unloop          (R: old-limit old-index -- )
                        Drops innermost loop structure,
                        pops back old loop structures to loop registers

        exit            ( -- ) Returns from current definition.
                               Compiles a ret opcode.

        leave           ( -- ) (R: old-limit old-index -- )
                        Leaves current innermost loop promptly

        +loop           ( u|n -- ) 
                        (R: unchanged | old-limit old-index -- )
                        Adds number to current loop index register
                        and checks whether to continue or not

        loop            ( -- ) 
                        (R: unchanged | old-limit old-index -- ) 
                        Increments current loop index register by one
                        and checks whether to continue or not.

        ?do             ( Limit Index -- ) 
                        (R: unchanged | -- old-limit old-index )
                        Begins a loop if limit and index are not equal

        do              ( Limit Index -- )
                        (R: -- old-limit old-index )
                        Begins a loop

;------------------------------------------------------------------------------
; Hardware access
;------------------------------------------------------------------------------

        analog          ( u-channel -- u-value ) Reads analog-digital-converter
        dint            ( -- ) Disables Interrupts
        eint            ( -- ) Enables  Interrupts
        nop             ( -- ) No Operation. Hook for unused IRQs !

        irq-port1       ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-port2
        irq-adc
        irq-timera1
        irq-timera0
        irq-watchdog
        irq-timerb1
        irq-timerb0



So long. 

If you are looking for details - the source code is heavily documented,
but in this initial release only for those speaking German.

Please report bugs or ideas to me ! 
I will be pleased to hear of your experience !

Matthias Koch, Summer 2011