

-------------------------------------------------------------------------------

Mecrisp-Ice - A conveniently enhanced fork of Swapforth by James Bowman

  It makes your Lattice Icestick FPGA development board
  to behave just like a microcontroller.


The original Swapforth and J1a processor implementation can be found here:
http://www.excamera.com/sphinx/article-j1a-swapforth.html

I would not have been possible without the first open-source FPGA toolchain:
http://www.clifford.at/icestorm/

Many, many thanks to James Bowman and the whole Icestorm team !

http://mecrisp.sourceforge.net/
m-atthias@users.sf.net

-------------------------------------------------------------------------------

HIC SUNT DRACONES - HIC SUNT DRACONES - HIC SUNT DRACONES

This is the first experimental release, so beware: Monsters may be inside !

-------------------------------------------------------------------------------

Shortly after Clifford Wolff, Mathias Lasser and Cotton Seed managed to build
the first working completely open-source FPGA toolchain for the iCE40-HX1K,
James Bowman started porting his elegant J1 processor design.

I have been involved in testing and enhanced the resulting monumental work
with stronger optimisations and a handfull of features for convenience.

-------------------------------------------------------------------------------

What you need:

* A Lattice Icestick with an iCE40-HX1K FPGA
    http://www.latticesemi.com/icestick

* Or a Lattice HX8K breakout board with an iCE40-HX8K FPGA    

* The Iceprog tool to flash the included binary
    http://www.clifford.at/icestorm/

* A terminal, picocom is fine.

-------------------------------------------------------------------------------

Which board for you ?

If you just wish to play with a stack processor,
if you have small ideas,
if you desire to have IrDA communication,
if you wish a cheap, cool looking board,
if you are fine without tinkering with additional logic

  --> HX1K Icestick is your choice.
  
If you have large ideas in Forth,
if you need a lot of IO pins,
if you wish to wire in additional peripherals, opcodes or whatever you imagine,
if you love to have single cycle multiplier and barrel shifters

  --> HX8K breakout board will give you a nice time.  

-------------------------------------------------------------------------------

Basic usage, same for HX1K and HX8K:

  Flash the binary:
  iceprog -b j1a.bin

  Open a terminal:
  picocom -b 115200 /dev/ttyUSB$n --imap lfcrlf,crcrlf --omap delbs,crlf --send-cmd "ascii-xfr -s -l 30 -n"

  Toggle DTR line to Reset by pressing Crtl+A Ctrl+T Crtl+A Ctrl+T

  You should get a welcome message.

  If you hard crash it, iceprog -t or a power cycle should recover.

-------------------------------------------------------------------------------

Some notes for Forth users new to this target and its peripheral possibilities:

The Icestick has 8 kb of initialised RAM which is mapped from address
$0000 to $1FFF and a SPI flash to store the FPGA bitstream and additional
user generated memory images.

Data and return stack are 16 elements deep. James implemented them as
part of the CPU itself, so they are not accessible through memory.

Pinout and board layout:

       /--------------------------------------
      /                 Header 1:  76543210-+
     /            ________              ++
    /            |        |      R      --
[USB]  FT        |  FPGA  |    R G R    73   Ir
[USB]  DI        |        |      R      62   DA
    \            |________|             51
     \                                  40
      \                 Header 2:  01234567-+
       \--------------------------------------

  Numbers are bit numbers
  + is 3.3 V   - is GND
  G Green LED  R Red LEDs


There is a separate IO address space, with those registers available:

     Addr  Bit READ            WRITE

     0001  0   PMOD in
     0002  1   PMOD out        PMOD out
     0004  2   PMOD dir        PMOD dir
     0008  3   misc.out        misc.out

     0010  4   header 1 in
     0020  5   header 1 out    header 1 out
     0040  6   header 1 dir    header 1 dir
     0080  7                   eint

     0100  8   header 2 in
     0200  9   header 2 out    header 2 out
     0400  10  header 2 dir    header 2 dir
     0800  11                  dint

     1000  12  UART RX         UART TX
     2000  13  misc.in
     4000  14  ticks           clear ticks
     8000  15

Contents of misc.out and misc.in:

   Bitmask Bit  misc.out        misc.in

     0001    0  SPI CS          UART Ready to Transmit
     0002    1  SPI MOSI        UART Character received
     0004    2  SPI SCK         SPI MISO
     0008    3  IrDA-TXD        IrDA-RXD
     0010    4  IrDA-Sleep      RTS
     0020    5  CTS             Random
     0040    6  Green LED
     0080    7  Red LED
     0100    8  Red LED
     0200    9  Red LED
     0400   10  Red LED

If you are already familiar with MSP430 chips,
you will know this IO port style:

* The IN register gives the current electrical state
* The contents of the OUT registers determine what level the outputs should be
* The DIR register let you switch a pin to be an output by writing an one into

You can set two registers at once if you OR together their addresses.
  255 $440 io! should set all header pins as outputs.

Inputs can ORed together the same way and give an ORed result.

You can detect short-circuited pins -
  for example if a pin is set to output and low, but shortened to Vcc,
  then the OUT register will read back low, as set by you, but the
  IN register will read high for that pin.

Misc.out and misc.in are a mixed back of wires and flags available.

No fear to destroy the IrDA transceiver with too long pulses as it turns off
the IR LED itself when IrDA-TXD is high for more than 50 us.

The UART data register is for both incoming and outgoing data,
a read from it will clear the "Character received" flag
and you should only write to it when "Ready to Transmit" is set.

Ticks contains a 16 bit cycle counter that counts up with 48 MHz (HX8K: 36 MHz)
Any write to it clears it and sets its value back to zero.

Memory location $1FFE (HX8K: $3FFE) is an interrupt vector for the ticks counter overflow.
You can place an opcode there, perhaps ALU Exit ($608C) or a JMP to a handler.
Interrupts can be enabled with eint and disabled with dint.

-------------------------------------------------------------------------------

Notes on HX8K:
--------------

This feels very similiar to Mecrisp-Ice on HX1K, just with a few differences:

  + Double amount of memory: 16 kb instead of 8 kb
  + Double stack depth: 32 elements each instead of 16
  + Barrel shifter for single cycle lshift rshift arshift
  + Single cycle multiplication
  + Fast opcodes for 1+ and 1-
  + rdepth
  + 8 LEDs instead of 5
  + Lots of gates free for experiments
  - 36 MHz only
  - No IrDA
  - Variable @ needs 2 instructions and 5 cycles instead of 1 instruction and 2 cycles  

The peripheral map is the same, but the IN, OUT and DIR registers
are up to 16 bits wide, with the following connections:

 $0001 Port A IN     $0010 Port B IN     $0100 Port C IN 
 $0002 Port A OUT    $0020 Port B OUT    $0200 Port C OUT
 $0004 Port A DIR    $0040 Port B DIR    $0400 Port C DIR

 
                     Red LEDs
                     76543210
  1.2V 3.3V   oo                 oo   oo
  1.2V B13    oo                 oo   oo
  A12  B12    oo     ________    oo   oo
  GND  GND    oo    |        |   oo   oo
  A11  B11    oo    |  FPGA  |   oo   oo
  A10  B10    oo    |        |   oo   oo
  A9   B9     oo    |________|   oo   oo
  GND  GND    oo                 oo   oo
  A8   B8     oo                 oo   oo
  A7   B7     oo                 oo   oo
  A6   B6     oo  Jumper config: oo   oo
  GND  GND    oo                 oo   oo
  A5   B5     oo     |     ||    oo   oo
  A4   B4     oo                 oo   oo
  A3   B3     oo        Green    oo   oo
  GND  GND    oo        LED      oo   oo
  A2   B2     oo     FT          oo   oo
  A1   B1     oo     DI          oo   oo
  A0   B0     oo                 oo   oo
  GND  GND    oo     [USB]       oo   oo
                     [USB]
  

  Port C is currently unconnected, you can wire the bits as you wish
  in the constraints PCF file.
  
-------------------------------------------------------------------------------

Special features included in Mecrisp-Ice:
-----------------------------------------

You can save the complete current memory contents into the SPI flash
sectors 1 to 63. Sector 0 contains the FPGA bitstream, sector 1 will be
loaded automatically on startup if you save a memory image into this.

sector# load
sector# save
sector# erase

There is a variable "init" which is executed after loading an image.

So if you wish to create a turnkey application, prepare everything in RAM
and type:

  ' fireworks init !
  1 save

Replace fireworks with whatever you wish to be executed on startup.
Nothing is executed if init contains a zero, which is the default.

If you are not sure if it will work properly, save to any other sector
and load manually. The init mechanism works the same on all sectors.

On HX8K: Sectors 0, 1 and 3 contain the bitstream.
         Sector 3 will be loaded automatically if available.

-----------------------------------------

For your convenience, some introspection features are preloaded for default.

Things to try:

  0 8192 dump
  insight
  see +

They will be removed by typing "new" so that you have more space available.

-----------------------------------------

Inline optimisations and constant folding are included !

-------------------------------------------------------------------------------

Main differences to Mecrisp and Mecrisp-Stellaris:

Unlike Mecrisp and Mecrisp-Stellaris, this is running completely
in RAM memory. So there is no need for special memory handling !

You can use CREATE with DOES> and if you need a buffer,
just CREATE ... ALLOT it.

By the way: If you save a memory image, the last contents of the variables
are saved during the process and reloaded with the image. Variables are
initialised, but there is no logic to reinitialise them on Reset to the
values assigned at compilation.

-------------------------------------------------------------------------------

If you wish to build the whole package yourself:

* Gforth
* Freepascal
* Yosys for synthesis
* Arachne-PNR for place and route
* Icestorm tools for bitstream generation

... and their dependencies.

In a nutshell, you need to type:

  compile
  iceprog -b j1a.bin

That's all.

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

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

        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.

;------------------------------------------------------------------------------
; Stack Jugglers
;------------------------------------------------------------------------------

Single-Jugglers:

        depth           ( -- +n ) Gives number of single-cell stack items.
        rdepth          ( -- +n ) HX8K only: Number of items on return stack.
        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 )

        >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.

        2drop           ( 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 )

;------------------------------------------------------------------------------
; Logic
;------------------------------------------------------------------------------

        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
        invert          ( x1 -- x2 )   Invert all bits
        not             ( x1 -- x2 )   Invert all bits = Bitwise not
        xor             ( x1 x2 -- x3 ) Bitwise Exclusive-OR
        or              ( x1 x2 -- x3 ) Bitwise OR
        and             ( x1 x2 -- x3 ) Bitwise AND
        false           ( --  0 ) False-Flag
        true            ( -- -1 ) True-Flag

;------------------------------------------------------------------------------
; Calculus for single numbers
;------------------------------------------------------------------------------

        /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
        umin            ( u1 u2 -- u1|u2 ) Keeps unsigned smaller
        umax            ( u1 u2 -- u1|u2 ) Keeps unsigned greater
        1-              ( u1|n1 -- u2|n2 ) Subtracts one, optimized
        1+              ( u1|n1 -- u2|n2 ) Adds one, optimized

        2*              ( n1 -- n2 ) Arithmetric  left-shift
        2/              ( n1 -- n2 ) Arithmetric right-shift
        abs             ( n -- u ) Absolute value
        negate          ( n1 -- n2 ) Negate
        sgn             ( u1 n1 -- n2 ) Give u1 the sign of n2
        -               ( u1|n1 u2|n2 -- u3|n3 ) Subtraction
        +               ( u1|n1 u2|n2 -- u3|n3 ) Addition

;------------------------------------------------------------------------------
; Calculus involving double numbers
;------------------------------------------------------------------------------

        um*             ( u1 u2 -- ud )    16*16 = 32 Multiplication

        um/mod          ( ud u1 -- u2 u3 ) ud / u1 = u3 remainder u2

        m+              ( d1 n -- d2 ) Addition of a double with a single
        m*              ( n1 n2 -- d )     n1 * n2 = d
        fm/mod          ( d n1 -- n2 n3 )  d / n1 = n3 remainder r2 floored
        sm/rem          ( d n1 -- n2 n3 )  d / n1 = n3 remainder r2 symmetric

        */              ( n1 n2 n3 -- n4 )     n1 * n2 / n3 = n4
        */mod           ( n1 n2 n3 -- n4 n5 )  n1 * n2 / n3 = n5 remainder n4

        d2*             ( d1 -- d2 ) Arithmetric  left-shift

        dabs            ( d -- ud ) Absolute value
        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
;------------------------------------------------------------------------------

        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 )       Positive ?
        0<              ( n -- flag )       Negative ?
        0<>             ( x -- flag )
        0=              ( x -- flag )
        <>              ( x1 x2 -- flag )
        =               ( x1 x2 -- flag )

        d0=             ( d -- flag )

        within          ( x1 x2 x3 -- ? )   Check if x1 is within x2 and x3.

;------------------------------------------------------------------------------
; Tools for number input
;------------------------------------------------------------------------------

        number          ( c-addr len -- 0 )
                                     -- n 1 )
                                     -- n-low n-high 2 )
                        Tries to convert a string to a number.

;------------------------------------------------------------------------------
; Number base
;------------------------------------------------------------------------------

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

;------------------------------------------------------------------------------
; Memory access
;------------------------------------------------------------------------------

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

        constant  name  ( u|n -- )  Makes a single constant.
        variable  name  ( u|n -- )  Makes an initialized single variable

        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

        c@              ( c-addr -- char ) Fetches byte from memory
        c!              ( char c-addr ) Stores byte in memory

IO memory area:

        io@             ( c-addr -- x ) Fetches from IO register
        io!             ( x c-addr -- ) Stores  into IO register

        xor!            ( mask c-addr -- ) Toggle bits
        bic!            ( mask c-addr -- ) Clear BIts
        bis!            ( mask c-addr -- ) Set BIts

;------------------------------------------------------------------------------
; Strings and beautiful output
;------------------------------------------------------------------------------

String routines:

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

        rtype           ( c-addr length u -- )
                        Prints a string in a field u characters wide.

        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.

        ( Comment )     Ignore Comment
        \ Comment       Comment to end of line

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

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

Counted string routines:

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

Pictured numerical output:

        [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 -- 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
        ud.             ( ud -- ) Print unsigned double number
        d.              ( d -- ) Print double number

        u.r             ( u width -- ) Print      unsigned right aligned
         .r             ( n width -- ) Print        signed right aligned
        d.r             ( d width -- ) Print double signed right aligned

        buf0            ( -- a-addr ) Start of number output buffer
        buf             ( -- a-addr ) End   of number output buffer
        hld             ( -- a-addr ) Variable with current position

Deep insights:

        words           ( -- ) Prints list of defined words.
        .x2             ( c -- ) Prints  8 bit unsigned in hex base
        .x              ( u -- ) Prints 16 bit unsigned in hex base
                                 This is independent of number subsystem.

;------------------------------------------------------------------------------
; User input and its interpretation
;------------------------------------------------------------------------------

        tib             ( -- c-addr ) Input buffer
        pad             ( -- c-addr ) Location to hold temporary data

        refill          ( -- ? ) Refill input buffer, return true if successful
        source!         ( c-addr len -- ) Change source
        source          ( -- c-addr len ) Current source
        >in             ( -- addr ) Variable with current offset into source

        /string         ( c-addr1 u1 n -- c-addr2 u2 ) Cut n leading characters
        parse-name      ( -- c-addr len ) Get next token from input buffer
        parse           ( char -- c-addr len )
                        Cuts anything delimited by char out of input buffer

        evaluate        ( any addr len -- any ) Interpret given string
        quit            ( many -- ) (R: many -- ) Resets Stacks
        abort           ( many -- ) (R: many -- ) Print ? and quit

;------------------------------------------------------------------------------
; Dictionary expansion
;------------------------------------------------------------------------------

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

        allot           ( n -- ) Tries to advance Dictionary Pointer by n bytes
        here            ( -- a-addr|c-addr )
                        Gives current position in Dictionary

        ,               ( u|n -- ) Appends a single number to dictionary
        c,              ( char -- ) Appends a byte to dictionary

        unused          ( -- u ) How many free space is still available ?

        cornerstone name    Create a permanent dictionary wayback point
        new                 Core wayback point.

;------------------------------------------------------------------------------
; Dictionary expansion  (more internal)
;------------------------------------------------------------------------------

        s,              ( c-addr len -- ) Inserts a string with a maximum
                                          of 255 characters without runtime
        sliteral        ( c-addr len -- ) Insert a string with runtime

        literal         ( u|n -- ) Compiles a literal

        compile,        ( a-addr -- ) Compiles a call to a subroutine

        forth           ( -- a-addr ) Variable with entry point for dictionary

        ahead           ( -- a-addr ) Prepare a forward jump

;------------------------------------------------------------------------------
; Flags and inventory
;------------------------------------------------------------------------------

        immediate       ( -- ) Makes current definition immediate.
        foldable        ( n -- ) Current word becomes foldable with n constants

        sfind           ( c-addr len -- c-addr len 0 | a-addr flags )
                               Searches for a string in Dictionary.

;------------------------------------------------------------------------------
; Compiler essentials
;------------------------------------------------------------------------------

        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.
        create name     ( -- ) Create a definition with default action
        >body           ( a-addr -- a-addr ) Address of data field after create
        state           ( -- a-addr ) Address of state variable
        ]               ( -- ) Switch to compile state
        [               ( -- ) Switch to execute state
        ;               ( -- ) Finishes new definition
        : name          ( -- ) Opens new definition
        :noname         ( -- a-addr ) Opens new definition without name

;------------------------------------------------------------------------------
; Control structures
;------------------------------------------------------------------------------

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   .. ... .....
    all others
  endcase

        case            ( n -- n )       Begins case structure
        of              ( m -- )         Compares m with n, choose this if n=m
        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


        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.

        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

        bounds          ( addr len -- limit index )
                        Calculate values to loop over a string

;------------------------------------------------------------------------------
; SPI and low-level flash memory access
;------------------------------------------------------------------------------

        spix            ( c1 -- c2 ) Exchange one byte on SPI
        >spi            ( c -- ) Send one byte to SPI
        spi>            ( -- c ) Receive one byte from SPI
        idle            ( -- ) Set SPI flash to idle state
        spiwe           ( -- ) Write enable on SPI flash
        waitspi         ( -- ) Wait for write or erase to finish

;------------------------------------------------------------------------------
; Memory images
;------------------------------------------------------------------------------

Sectors from 1 to 63. Sector 1 is automatically loaded after Reset.

        load            ( sector# -- ) Loads an image
        save            ( sector# -- ) Saves an image
        erase           ( sector# -- ) Erase an image

        init            ( -- a-addr ) Variable containing either zero
                                      or the address of a turnkey definition
                                      which is executed automatically

;------------------------------------------------------------------------------
; Misc hardware
;------------------------------------------------------------------------------

        leds            ( x -- ) Display bitpattern on LEDs
        ms              ( u -- ) Wait u milliseconds

        ticks           ( -- u ) Read current ticks
        now             ( -- )   Clear tick counter
        delay           ( u -- ) Wait until u ticks are reached

        randombit       ( -- 0 | 1 ) Gives a random bit
        random          ( -- x ) Gives a random number

        eint            ( -- ) Enable ticks counter overflow interrupt
        dint            ( -- ) Disable interrupt

;------------------------------------------------------------------------------
; Insight tools that are gone after NEW
;------------------------------------------------------------------------------

        .s              ( many -- many ) Prints stack contents

        dump            ( addr len -- ) Dump memory contents

        insight         ( -- ) Complete printout of dictionary structure

        name.           ( a-addr -- ) If this is the code-start of a definition,
                                      try to print its name.
        memstamp        ( a-addr -- ) Show memory location nicely
        disasm-$        ( -- a-addr ) Variable for current disasm position
        disasm-cont     ( -- a-addr ) Variable: Continue up to this position
        disasm-step     ( -- ) Disassemble one more instruction

        seec            ( -- ) Continue to see at disasm-$
        see name        ( -- ) See the definition


Matthias Koch, Summer 2015
