@
@    Mecrisp-Stellaris - A native code Forth implementation for ARM-Cortex M microcontrollers
@    Copyright (C) 2013  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 third stable release of Mecrisp-Stellaris,
a port of Mecrisp to the ARM Cortex M architecture.

It runs out of the box on:
  - TI Stellaris/Tiva Launchpad  with LM4F120H5QR / TM4C123GH6PM
  - TI Tiva Connected Launchpad  with TM4C1294NCPDT
  - STM Nucleo 401RE             with STM32F401RE
  - STM F0 Discovery             with STM32F051R8
  - STM VL Discovery             with STM32F100RB
  - Shenzhen LC Technology board with STM32F103C8T6
  - STM F4 Discovery             with STM32F407VGT6 
  - STM F429 Discovery           with STM32F429ZIT6
  - Freescale Freedom FRDM-KL25Z with KL25Z128VLK4

Contributions:
  - Teensy 3.1                   with MK20DX256VLH7
  - Chinese QF-LM4F232           with LM4F232H5QC
  - nRFgo Starter Kit            with nRF51822

http://mecrisp.sourceforge.net/

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

Mecrisp finally got a younger sister and mastered the jump
to the ARM Cortex M instruction set.

They share most of the design ideas, so Mecrisp-Stellaris can compile 
directly into Flash, generates native code with constant folding and
inlining of short words. 

Communication is via serial 115200 baud 8N1 over
  - UART0  in LM4F120   (connected to USB-serial bridge on Stellaris Launchpad)
  - UART0  in TM4C1294  (connected to USB-serial bridge on Tiva Connected Launchpad)
  - USART1 in STM32F051 (TX on PA9, RX on PA10)
  - USART1 in STM32F100 (TX on PA9, RX on PA10)
  - USART1 in STM32F103 (TX on PA9, RX on PA10)
  - USART2 in STM32F401 (TX on PA2, RX on PA3 connected to USB-serial bridge on Nucleo board)
  - USART2 in STM32F407 (TX on PA2, RX on PA3)
  - USART1 in STM32F429 (TX on PA9, RX on PA10)
  - UART0  in KL25Z128  (connected to USB-serial bridge on Freedom board)
  - UART5  in LM4F232
  - UART0  in MK20DX256 (RX1/TX1 on Teensy 3.1.  Physical pins #2/#3 (these are also Digital IO 0/1 lines)
    	      		Digital IO pins 18/19 are setup for CTS/RTS respectively

Hardware and configuration for LM4F120 and TM4C123:
  Connect your cable to the Debug-USB-Port, 
  set "PWR SELECT" switch to DEBUG and
  close VDD jumper.

  Flashing is possible with lm4flash:
  https://github.com/utzig/lm4tools

  On startup, this runs with internal PIOSC at 16 MHz, 
  which is specified +-3% over whole temperature range.

Hardware and configuration for TM4C1294:
  Connect your cable to the Debug-USB-Port, 
  set "POWER SELECT" jumpers (JP1) to "ICDI",
  close both "MCU 3V3" (JP2) and "+3v3" (JP3) jumpers and
  set communication jumper blocks (JP4 and JP5) both to UART mode.

  Flashing is possible with lm4flash:
  https://github.com/utzig/lm4tools

  On startup, this runs with internal PIOSC at 16 MHz, 
  which is specified +-3% over whole temperature range.

Hardware and configuration for STM32F401:
  Connect USB cable to ST-Link USB port.
  Terminal is included into the debug section on Nucleo boards.
  
  Flashing is possible with st-flash:
  https://github.com/texane/stlink

  Flash memory is mirrored in hardware starting from address 0. Mecrisp uses
  the low address range to generate short opcodes for calling core words, but
  for flashing the binary, you have to use the "true address" $08000000.
  st-flash erase
  st-flash write mecrisp-stellaris-stm32f401.bin 0x08000000

  On startup, this runs with internal 16 MHz HSI clock.

Hardware and configuration for STM32F407:
  Connect USB cable to ST-Link USB port,
  connect your favourite serial link to PA2 (TX) and PA3 (RX),
  keep logic voltage levels in mind !
  
  Flashing is possible with st-flash:
  https://github.com/texane/stlink

  Flash memory is mirrored in hardware starting from address 0. Mecrisp uses
  the low address range to generate short opcodes for calling core words, but
  for flashing the binary, you have to use the "true address" $08000000.
  st-flash erase
  st-flash write mecrisp-stellaris-stm32f407.bin 0x08000000

  On startup, this runs with external 8 MHz crystal HSE clock,
  as internal oscillator is specified -8% + 4.5% over whole temp range.

Hardware and configuration for STM32F429:
  Similiar to STM32F407.

  Connect USB cable to ST-Link USB port,
  connect your favourite serial link to PA9 (TX) and PA10 (RX),
  keep logic voltage levels in mind !

  st-flash erase
  st-flash write mecrisp-stellaris-stm32f429.bin 0x08000000

  On startup, this runs with external 8 MHz crystal HSE clock.

Hardware and configuration for STM32F051:
  Similiar to STM32F407.

  Connect USB cable to ST-Link USB port,
  connect your favourite serial link to PA9 (TX) and PA10 (RX),
  keep logic voltage levels in mind !

  st-flash erase
  st-flash write mecrisp-stellaris-stm32f051.bin 0x08000000

  On startup, this runs with internal 8 MHz HSI clock.

Hardware and configuration for STM32F100:
  Similiar to STM32F407.

  Connect USB cable to ST-Link USB port,
  connect your favourite serial link to PA9 (TX) and PA10 (RX),
  keep logic voltage levels in mind !

  st-flash erase
  st-flash write mecrisp-stellaris-stm32f100.bin 0x08000000

  On startup, this runs with internal 8 MHz HSI clock.

Hardware and configuration for KL25Z128:
  Connect USB cable to SDA-USB-PORT

  Flashing is via mass storage interface -
    the board will appear as Flash Disk, just copy .srec file in.
    Maybe you have to do an OpenSDA firmware update before.

  On startup, this runs with internal FLL at 20.97 MHz.

  If you wish to try Mecrisp-Stellaris without target hardware, 
  there is a Cortex M0 instruction set emulator prepared for use with 
  Freescale Freedom binary images. Go into kl25z128/thumbulator 
  directory, type "make", copy the binary and then type 
  "thumbulator mecrisp-stellaris-kl25z128.bin" to run.

Hardware and configuration for MK20DX256VLH7 on a Teensy 3.1 board:
  ( Contributed by Mark Schweizer )

  Connect USB cable to USB port
  Open Teensy Loader Application (https://www.pjrc.com/teensy/loader.html) on your PC
  Select the "mecrisp-stellaris-mk20dx256.hex" file in the mk20dx256 directory
  Select the "Auto" button (this automatically loads the coad and resets the Teensy when the programming button is pushed)
  Press the button on the Teensy 3.1 board to initite the bootloader
  Connect a serial cable to TX1/RX1 (physical pins #2/#3 (these are also Digital IO 0/1 lines)
  Optionally connect CTS/RTS to physical pins #25/26 (these are also Digital IO 18/18 lines)

     		  R C
     		  T T
       		  S S
       	 	    
    o o o o o o o o o o o o o o
   |--------------------------o
   |     	     	      o
USB|       Teensy 3.1 	      o
   |     		      o
   |--------------------------o
    o o o o o o o o o o o o o o

    G R T
    N X X
    D
  
  On startup, this runs with internal FLL at 20.97 MHz.  See MCG.txt for how to switch to 96MHz


Hardware and configuration for nRF51822:
  ( Contributed by John Huberts )

  I have been using the nRFgo Motherboard fitted with a nRF51822 module 
  to do the development and testing. Programming is done using nRFStudio
  and the Segger J-LINK LITE that comes with the dev kit.

  I was also able to debug using GDB in the nRF51 Eclipse IDE

  The motherboard has a DB9 for serial port connection but jumpers need to 
  be placed between P15 (RXD, TXD) and P9 (P2.0, P2.1). If you don't have a
  serial port on your PC then you will need a USB-serial cable.

  The UART can be configured to use other pins on the SOC by changing these 
  lines in in terminal.s:

  .equ RX_PIN_NUMBER, 16
  .equ TX_PIN_NUMBER, 17


Mecrisp-Stellaris itself is sending LF for line ending,
but recognizes both LF and CR. Invoke Picocom with something like
picocom -b 115200 /dev/ttyACM0 --imap lfcrlf,crcrlf --omap delbs,crlf

For changing line ending to CR-LF or whatever else you like,
look at the beginning of mecrisp-stellaris-....s.

Assembling is done with the GCC-Arm-Embedded toolchain:
https://launchpad.net/gcc-arm-embedded/


Differences to Mecrisp for MSP430 are:

* Fetch-Modify-Store operations like +! or bic! are not atomic.

* Comfortable hardware support is done in Forth this time.
   You can contribute your favourite hardware handling routines 
   to be included in upcoming releases !

* For design ideas, have a look into Mecrisp for MSP430, too !

* Chip specific sources have added English comments and hints included
    for simplify porting to other ARM Cortex-M chips.

;------------------------------------------------------------------------------
; Turnkey applications
;------------------------------------------------------------------------------

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.

;------------------------------------------------------------------------------
; Porting
;------------------------------------------------------------------------------

Mecrisp-Stellaris can assemble without change for M0, M3 and M4 cores.

M0 cores lack conditional execution "ite eq...", which has to be circumvented 
by conditional branches. stmdb psp!, {tos} is missing, which I use to push to 
data stack and they have no division in hardware. 

There is an assembler switch "m0core" to assemble the core with replacement 
code for ARM Cortex-M0 chips. Depending on your flash capabilities, there are
two useful switches: 

  "charkommaavailable" which is self-explaining and 
  "emulated16bitflashwrites" if your particular Flash controller
                             cannot write data in separate 16-Bit chunks.

Core needs about 14 kb flash at the moment, but reserves 16 kb for upcoming
additions, and needs 1.5 kb RAM for stacks and buffers plus variables for 
interrupt handlers plus RAM dictionary space. Bare minimum for ARM to get it 
running will be around 16kb/2kb, but to have fun with it and leave space for 
real applications, go with at least of 32 kb flash and 4 kb RAM. 

Look at the flash specification for your particular chip.

The compiler only depends on 2-aligned 16-Bit flash writes
one time per location, you can remove c, and align, without issues 
from the compiler, but 8-Bit flash writes are nice to have 
for compatibility with standard code. 

For special cases having only 4-aligned 32-bit one-time writes to Flash,
there is a hflash! emulation layer.

Flash erasing is only available for the user, it doesn't need erase cycles 
while compiling. 

Keep these criteria in mind, pick your favourite chip and add it as your 
contribution. It won't be too difficult, start with an UART echo written 
in assembly without libraries, and I will be there for your help.

You have to change memory map, hardware initialisation and interrupt vectors,
write key?, key, emit?, emit for a first reaction and flash write access
for final success. There is a common mimimum set of handlers across 
ARM Cortex CPUs, which will help you to get it running for the first time.

Unfortunately, there is a lot of bit twiddling necessary for peripherial 
modules, as they differ a lot across manufacturers. ARMs seem to only share 
core components like CPU, interrupt controler and a very basic systick timer.

I don't have the time to support a lot of different chips with examples. 

TI ADCs have a sequencer FIFO buffer, ST ADCs need a DMA channel configured. 
TI Flash controller offers 32 bit aligned writes only, but as many as you 
wish per location until all bits are zero; 
ST-M3 have 16 bit aligned Flash write only, 
ST-M4 have 8 bit, 16 bit and 32 bit Flash writes available, 
but only once per location. 

I would like to focus on core development, support porting to other chips and 
families with adaptions in core, but leave writing initialisation code, 
testing and writing Forth examples to "family maintainers" which are deep 
into their chip of choice. 


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

;------------------------------------------------------------------------------
; Terminal-IO  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

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

        hook-emit?      ( -- a-addr ) Hooks for redirecting
        hook-key?       ( -- a-addr )   terminal IO
        hook-key        ( -- a-addr )     on the fly
        hook-emit       ( -- a-addr ) 

        serial-emit?    ( -- Flag )  Serial interface
        serial-key?     ( -- Flag )    terminal routines
        serial-key      ( -- Char )      as default communications
        serial-emit     ( Char -- ) 

        hook-pause      ( -- a-addr ) Hook for a multitasker
        pause           ( -- )        Task switch, none for default

;------------------------------------------------------------------------------
; 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 )
        -rot            ( x1 x2 x3 -- x3 x1 x2 )
        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 )
        pick            ( ... xi+1 xi ... x1 x0 i -- ... x1 x0 xi )
                                  Picks one element from deep below

        >r              ( x -- ) (R: -- x )
        r>              ( -- x ) (R: x -- )
        r@              ( -- x ) (R: x -- x )
        rdrop           (  --  ) (R: 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 )
        2-rot           ( x1 x2 x3 x4 x5 x6 -- x5 x6 x1 x2 x3 x4 )
        2swap           ( x1 x2 x3 x4 -- x3 x4 x1 x2 )
        2tuck           ( x1 x2 x3 x4 -- x3 x4 x1 x2 x3 x4 )
        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 )
        2rdrop          ( -- )       (R: x1 x2 -- )

Stack pointers:

        sp@             ( -- a-addr )  Fetch  data stack pointer
        sp!             ( a-addr -- )  Store  data stack pointer
        rp@             ( -- a-addr )  Fetch return stack pointer
        rp!             ( a-addr -- )  Store return stack pointer

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

        arshift         ( x1 u -- x2 ) Arithmetric right-shift of u bit-places
        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
        ror             ( x1 -- x2 )   Logical right-rotation of one bit-place
        rol             ( x1 -- x2 )   Logical  left-rotation 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
        clz             ( x1 -- u ) Count leading zeros
        false           ( --  0 ) False-Flag
        true            ( -- -1 ) True-Flag

;------------------------------------------------------------------------------
; Calculus for single numbers  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------
        u/mod           ( u1 u2 -- u3 u4 ) 32/32 = 32 rem 32 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 ) 32*32 = 32 Multiplication
        min             ( n1 n2 -- n1|n2 ) Keeps smaller of top two items
        max             ( n1 n2 -- n1|n2 ) Keeps greater of top two items
        umin            ( u1 u2 -- u1|u2 ) Keeps unsigned smaller
        umax            ( u1 u2 -- u1|u2 ) Keeps unsigned greater
        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 ) Negate
        -               ( u1|n1 u2|n2 -- u3|n3 ) Subtraction
        +               ( u1|n1 u2|n2 -- u3|n3 ) Addition

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

        um*             ( u1 u2 -- ud )        32*32 = 64 Multiplication
        ud*             ( ud1 ud2 -- ud3 )     64*64 = 64 Multiplication
        udm*            ( ud1 ud2 -- ud3-Low ud4-High ) 64*64=128 Multiplication

        um/mod          ( ud u1 -- u2 u3 )     ud / u1 = u3 remainder u2
        ud/mod          ( ud1 ud2 -- ud3 ud4 ) 64/64 = 64 rem 64 Division
                                               ud1 / ud2 = ud4 remainder ud3

        m*              ( n1 n2 -- d )         n1 * n2 = d
        m/mod           ( d  n1 -- n2 n3 )     d  / n1 = n3 remainder r2
        d/mod           ( d1 d2 -- d3 d4 )     d1 / d2 = d4 remainder d3
        d/              ( d1 d2 -- d3 )        d1 / d2 = d3
        */              ( n1 n2 n3 -- n4 )     n1 * n2 / n3 = n4
        u*/             ( u1 u2 u3 -- u4 )     u1 * u2 / u3 = u4
        */mod           ( n1 n2 n3 -- n4 n5 )  n1 * n2 / n3 = n5 remainder n4
        u*/mod          ( u1 u2 u3 -- u4 u5 )  u1 * u2 / u3 = u5 remainder u4

        d2*             ( d1 -- d2 ) Arithmetric  left-shift
        d2/             ( d1 -- d2 ) Arithmetric right-shift
        dshl            ( ud1 -- ud2 ) Logical left-shift, same as d2*
        dshr            ( ud1 -- ud2 ) Logical right-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 s31.32 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 32 comma-digits to number output
        f#              ( n-comma1 -- n-comma2 )
                        Adds one comma-digit to number output
        f.              ( df -- )
                        Prints a fixpoint number with 32 fractional digits
        f.n             ( df n -- )
                        Prints a fixpoint number with n fractional digits

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

        move            ( c-addr1 c-addr2 u -- ) Moves u Bytes in Memory
        fill            ( c-addr u c ) Fill u Bytes of Memory with value c

        cbit@           ( mask c-addr -- flag ) Test BIts in byte-location
        hbit@           ( mask a-addr -- flag ) Test BIts in halfword-location
        bit@            ( mask a-addr -- flag ) Test BIts in word-location

        cxor!           ( mask c-addr -- ) Toggle bits in byte-location
        hxor!           ( mask a-addr -- ) Toggle bits in halfword-location
        xor!            ( mask a-addr -- ) Toggle bits in word-location

        cbic!           ( mask c-addr -- ) Clear BIts in byte-location
        hbic!           ( mask a-addr -- ) Clear BIts in halfword-location
        bic!            ( mask a-addr -- ) Clear BIts in word-location

        cbis!           ( mask c-addr -- ) Set BIts in byte-location
        hbis!           ( mask a-addr -- ) Set BIts in halfword-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
        nvariable name  ( n1*u|n n1 -- ) Makes an initialized variable with
                                         specified size of n1 words
                                         Maximum is 15 words

        buffer: name    ( u -- ) Creates a buffer in RAM with u bytes length

        2@              ( a-addr -- ud|d ) Fetches double number from memory
        2!              ( ud|d a-addr -- ) Stores double number in memory

        @               ( a-addr -- u|n ) Fetches single number from memory
        !               ( u|n a-addr -- ) Stores single number in memory
        +!              ( u|n a-addr -- ) Add to memory location

        h@              ( c-addr -- char ) Fetches halfword from memory
        h!              ( char c-addr ) Stores halfword in memory
        h+!             ( u|n a-addr -- ) Add to halfword memory location

        c@              ( c-addr -- char ) Fetches byte from memory
        c!              ( char c-addr ) Stores byte in memory
        c+!             ( u|n a-addr -- ) Add to byte memory location

;------------------------------------------------------------------------------
; Strings and beautiful output (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

String routines:

        type            ( c-addr length -- )
                        Prints a counted string.

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

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

        cr              ( -- ) Emits line feed
        bl              ( -- 32 ) ASCII code for Space
        space           ( -- ) Emits space
        spaces          ( n -- ) Emits n spaces if n is positive

        compare         ( caddr-1 len-1 c-addr-2 len-2 -- flag )
                        Compares two strings

        accept          ( c-addr maxlength -- length ) Read input into a string.

Counted string routines:

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

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

        cexpect         ( cstr-addr maxlength -- ) Read input into a counted string.

        count           ( cstr-addr -- c-addr length )
                        Convert counted string into addr-length string

        skipstring      ( cstr-addr -- a-addr )
                        Increases the pointer to the aligned end of the string.
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|nd2 ) Add one digit from the
                        double length number to output buffer
        #>              ( ud|d -- c-addr len )
                        Drops double-length number and finishes
                        pictured numeric output ready for type
        <#              ( -- ) Prepare pictured number output buffer
        u.              ( u -- ) Print unsigned single number
        .               ( n -- ) Print single number

Deep insights:

        words           ( -- ) Prints list of defined words.
        .s              ( many -- many ) Prints stack contents, signed
        u.s             ( many -- many ) Prints stack contents, unsigned
        h.s             ( many -- many ) Prints stack contents, unsigned, hex
        dump            ( addr -- ) Dumps a bit of memory
        hex.            ( u -- ) Prints 32 bit unsigned in hex base,
                                 needs emit only.
                                 This is independent of number subsystem.

;------------------------------------------------------------------------------
; User input and its interpretation (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

        query           ( -- ) Fetches user input to input buffer
        tib             ( -- cstr-addr ) Input buffer

        current-source  ( -- addr ) Double-Variable which contains source
        setsource       ( c-addr len -- ) Change source
        source          ( -- c-addr len ) Current source
        >in             ( -- addr ) Variable with current offset into source

        token           ( -- c-addr len ) Cuts one token out of input buffer
        parse           ( char -- c-addr len )
                        Cuts anything delimited by char out of input buffer

        evaluate        ( any addr len -- any ) Interpret given string
        interpret       ( any -- any ) Execute, compile, fold, optimize...
        quit            ( many -- ) (R: many -- ) Resets Stacks
        hook-quit       ( -- a-addr ) Hook for changing the inner quit loop

;------------------------------------------------------------------------------
; Dictionary expansion  (exactly ANS, some logical extensions)
;------------------------------------------------------------------------------

        align           ( -- ) Aligns dictionary pointer
        aligned         ( c-addr -- a-addr ) Advances to next aligned address
        cell+           ( x -- x+4 ) Add size of one cell
        cells           ( n -- 4*n ) Calculate size of n cells

        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

        ,               ( u|n -- ) Appends a single number to dictionary
        ><,             ( u|n -- ) Reverses high and low-halfword, then 
                                     appends it to dictionary
        h,              ( u|n -- ) Appends a halfword to dictionary

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

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

        string,         ( c-addr len -- ) Inserts a string of maximum 255 characters 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
        jump,           ( Hole-for-Opcode Destination ) 
                        Writes an unconditional Jump
                        to a-addr-Destination with the given Bitmask as
                        Opcode into the halfword sized a-addr-Hole
        cjump,          ( Hole-for-Opcode Destination Bitmask ) 
                        Writes a conditional Jump
                        to a-addr-Destination with the given Bitmask as
                        Opcode into the halfword sized a-addr-Hole
        ret,            ( -- ) Compiles a ret opcode

        flashvar-here   ( -- a-addr ) Gives current RAM management pointer
        dictionarystart ( -- a-addr ) Current entry point for dictionary search
  
    Available depending on chip capabilities:

        c,              ( char -- ) Appends a byte to dictionary
        align,          ( -- ) Makes Dictionary Pointer even, if uneven.
        align4,         ( -- ) Aligns on 4.

        movwmovt,       ( x Register -- ) Generate a movw/movt-Sequence to
                                          get x into any given Register. M3/M4 only
       registerliteral, ( x Register -- ) Generate shortest possible sequence
                                          to get x into given low Register.
                                          On M0: A movs-lsls-adds... sequence
                                          M3/M4: movs / movs-mvns / movw / movw-movt

       12bitencoding    ( x -- x false | bitmask true )
                                          Can x be encoded as 12-bit immediate ?

;------------------------------------------------------------------------------
; 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            ( c-addr len -- a-addr flags )
                               Searches for a String in Dictionary.
                               Gives back flags, which are different to ANS !

        0-foldable      ( -- ) Current word becomes foldable with zero constants
        1-foldable      ( -- ) Current word becomes foldable with one constants
        2-foldable      ( -- ) Current word becomes foldable with two constants
        3-foldable      ( -- ) Current word becomes foldable with 3   constants
            ...
        7-foldable      ( -- ) Current word becomes foldable with 7   constants

;------------------------------------------------------------------------------
; 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
        ['] name        ( -- a-addr)  Tick that compiles the executable address
                                      of found word as literal
        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.
        (create) name   ( -- ) Create a definition with no code at all
        create name     ( -- ) Create a definition with default action which
                               cannot be changed later. Use <builds does> instead.
                               Equivalent to : create <builds does> ;
        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.

Decisions:

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

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

Case:

n case
     m1   of ... endof
     m2   .. ... .....
   flag  ?of ... endof
    all others
  endcase

        case            ( n -- n )       Begins case structure
        of              ( m -- )         Compares m with n, choose this if n=m
        ?of             ( flag -- )      Flag-of, for custom comparisions
        endof           ( -- )           End of one possibility
        endcase         ( n -- )         Ends case structure, discards n

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

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

        dint            ( -- ) Disables Interrupts
        eint            ( -- ) Enables  Interrupts
        nop             ( -- ) No Operation. Hook for unused IRQs !

        irq-systick     ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-fault       ( -- a-addr ) For all faults and unhandled interrupts

;------------------------------------------------------------------------------
; Specials for LM4F120:
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        cflash!         ( char c-addr -- )  Writes byte to flash
        hflash!         ( u|n a-addr -- )   Writes halfword to flash
        flash!          ( u|n 4-a-addr -- ) Writes single number to flash, 
                                              4 aligned !
Interrupts:

        irq-porta       ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-portb
        irq-portc
        irq-portd
        irq-porte
        irq-portf
        irq-timer0a
        irq-timer0b
        irq-timer1a
        irq-timer1b
        irq-timer2a
        irq-timer2b
        irq-adc0seq0
        irq-adc0seq1
        irq-adc0seq2
        irq-adc0seq3
        irq-terminal

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for TM4C1294:
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 16k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        cflash!         ( char c-addr -- )  Writes byte to flash
        hflash!         ( u|n a-addr -- )   Writes halfword to flash
        flash!          ( u|n 4-a-addr -- ) Writes single number to flash, 
                                              4 aligned !
Interrupts:

        irq-porta       ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-portb
        irq-portc
        irq-portd
        irq-porte
        irq-portf
        irq-portg
        irq-porth
        irq-portj
        irq-portk
        irq-portl
        irq-timer0a
        irq-timer0b
        irq-timer1a
        irq-timer1b
        irq-timer2a
        irq-timer2b
        irq-timer3a
        irq-timer3b
        irq-adc0seq0
        irq-adc0seq1
        irq-adc0seq2
        irq-adc0seq3
        irq-adc1seq0
        irq-adc1seq1
        irq-adc1seq2
        irq-adc1seq3
        irq-ethernet
        irq-terminal

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for STM32F051:
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        hflash!         ( u|n a-addr -- )   Writes halfword to flash

Interrupts:

        irq-adc         ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-exti0_1
        irq-exti2_3
        irq-exti4_15
        irq-tim1_up
        irq-tim1_cc
        irq-tim2
        irq-tim3

  Look into vectors.s and interrupts.s to add more interrupts.
  
;------------------------------------------------------------------------------
; Specials for STM32F100 and STM32F103:
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        hflash!         ( u|n a-addr -- )   Writes halfword to flash

Interrupts:

        irq-adc         ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-exti4
        irq-exti3
        irq-exti2
        irq-exti1
        irq-exti0

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for STM32F401, STM32F407 and STM32F429:
;------------------------------------------------------------------------------

Flash:
        eraseflash       ( -- ) Erases everything. Clears Ram. Restarts Forth.
        eraseflashsector ( u -- ) Erases one sector of Flash

        cflash!         ( char c-addr -- )  Writes byte to flash
        hflash!         ( u|n a-addr -- )   Writes halfword to flash

Interrupts:

        irq-adc         ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-exti4
        irq-exti3
        irq-exti2
        irq-exti1
        irq-exti0
        irq-tim2
        irq-tim3
        irq-tim4

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for KL25Z128:
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        hflash!         ( u|n a-addr -- )   Writes halfword to flash - emulated
        flash!          ( u|n 4-a-addr -- ) Writes single number to flash, 
                                              4 aligned !

Interrupts:

        irq-adc         ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-dac
        irq-cmp
        irq-porta
        irq-portd

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for MK20DX256:
;------------------------------------------------------------------------------

        ipsr            ( -- ipsr ) Interrupt Program Status Register

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        hflash!         ( u|n a-addr -- )   Writes halfword to flash - emulated
        flash!          ( u|n 4-a-addr -- ) Writes single number to flash, 
                                              4 aligned !

Interrupts:

        irq-adc0        ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-adc1
        irq-dac
        irq-cmp0
        irq-cmp1
        irq-cmp2
        irq-porta
        irq-portb
        irq-portc
        irq-portd
        irq-porte
        irq-uart0S
        irq-uart0E

  Look into vectors.s and interrupts.s to add more interrupts.

;------------------------------------------------------------------------------
; Specials for nRF51822
;------------------------------------------------------------------------------

Flash:
        eraseflash      ( -- ) Erases everything. Clears Ram. Restarts Forth.

        eraseflashfrom  ( a-addr -- ) Starts erasing at this address.
                                      Clears Ram. Restarts Forth.

        flashpageerase  ( a-addr -- ) Erase one 1k flash page only. Take care:
                                      No Reset, no dictionary reinitialisation.

        hflash!         ( u|n a-addr -- )   Writes halfword to flash

Interrupts:

        irq-power       ( -- a-addr ) Memory locations for IRQ-Hooks
        irq-radio
        irq-uart
        irq-spi0
        irq-spi1
        irq-gpiote
        irq-adc
        irq-tim0
        irq-tim1
        irq-tim2
        irq-rtc0
        irq-temp
        irq-rng
        irq-ecb
        irq-ccm_aar
        irq-wdt
        irq-rtc1
        irq-qdec
        irq-lpcomp
        irq-swi0
        irq-swi1
        irq-swi2
        irq-swi3
        irq-swi4
        irq-swi5

  Look into vectors.s and interrupts.s to add more interrupts.

Matthias Koch, Summer 2013, updated Spring 2014
