ESP32forth
       🙜
February 12, 2022

TOPICS
------
• Raw Strings
• ESP32 variants
• Memory

const char boot[] = R"""(
: (   41 parse drop drop ; immediate
: \   10 parse drop drop ; immediate
( Now can do comments! )
  
( Constants and Variables )
: constant ( n "name" -- ) create , does> @ ;
: variable ( "name" -- ) create 0 , ;
...
   
)""";

ESP32 Hardware Explosion
    🙜
ESP8266      - Tensilica Xtensa L106 - 80MHz  - Single Core
ESP32        - Tensilica Xtensa LX6  - 240MHz - Dual Core
ESP32-SOLO
& ESP32-MINI - Tensilica Xtensa LX6  - 240MHz - Single Core
ESP32-S2     - Tensilica Xtensa LX7  - 240MHz - Single Core
ESP32-S3     - Tensilica Xtensa LX7  - 240MHz - Single Core
 
ESP32-C3     - RISC-V                - 160MHz - Single Core
ESP32-C6     - RISC-V                - 160MHz - Single Core

ESP32 Hardware Explosion                                   
    🙜
ESP8266      - 80KiB RAM  - 17 GPIO
ESP32        - 320KiB RAM - 34 GPIO
ESP32-SOLO   - 520KiB RAM - 22 GPIO - NO ARDUINO!
ESP32-MINI   - 520KiB RAM - 28 GPIO - NO ARDUINO!
ESP32-S2     - 320KiB RAM - 43 GPIO - USB OTG / No BLE
ESP32-S3     - 384KiB RAM - 44 GPIO - USB OTG
 
ESP32-C3     - 400KiB RAM - 22 GPIO (Pin compat 8266)
ESP32-C6     - 400KiB RAM - 22 GPIO - NO ARDUINO!

ESP32 Hardware Explosion                                   
    🙜
ESP8266      - NO SUPPORT
ESP32        - SUPPORTED
ESP32-SOLO   - NO SUPPORT
ESP32-MINI   - NO SUPPORT
ESP32-S2     - SUPPORTED
ESP32-S3     - NO SUPPORT
 
ESP32-C3     - SUPPORTED
ESP32-C6     - NO SUPPORT

MEMORY EMBARRASSMENT
--------------------
100KB Heap
73KB Used up!
27KB Free :-(

ESP32 MEMORY MAP
----------------
0x3FFA_E000 - 0x3FFD_FFFF SRAM2 (200KB)
0x3FFE_FFFF - 0x3FFF_FFFF SRAM1 (128KB)
0x4000_0000 - 0x4005_FFFF ROM
0x4006_0000 - 0x4006_FFFF Reserved
0x4007_0000 - 0x4007_FFFF SRAM0 (64KB) [Cache]
0x4008_0000 - 0x4009_FFFF SRAM0 (128KB)
0x400A_0000 - 0x400B_FFFF SRAM1 (128KB) [Remap]

FORTH MEMORY MAP
----------------
base + 0x00000    Float Stack
base + 0x00800    Return Stack
base + 0x01000    Data Stack
base + 0x01800    Forth Heap
base + 0x08000      ~ Initially used
base + 0x1BC80      ~ Limit

ESP32forth v7.0.6.15 - rev b64e43f70152280caffc
ESP32-D0WDQ6   240 MHz   2 cores   4194304 bytes flash
     System Heap: 201476 free + 346176 used = 547652 total (36% free)
                  97788 bytes max contiguous
Forth dictionary: 80956 free + 26692 used = 107648 total (75% free)
3 x Forth stacks: 2048 bytes each
 ok
--> 

ESP32forth v7.0.6.15 - rev b64e43f70152280caffc
FAKE-ESP32   240 MHz   2 cores   4194304 bytes flash
     System Heap: 90000 free + 327680 used = 417680 total (21% free)
                  81920 bytes max contiguous
Forth dictionary: 1052220 free + 27076 used = 1079296 total (97% free)
3 x Forth stacks: 2048 bytes each
 ok
--> include common/ansi.fs include common/all_tests.fs
-----------------------------------------
  PASSED: 103   RUN: 103   FOUND: 103
  ALL TESTS PASSED
-----------------------------------------

( Lazy loaded Telnet )
: telnetd r|
  
vocabulary telnetd   telnetd definitions also sockets
...
only forth definitions
telnetd
  
| evaluate ;

ORIGINAL OPCODES
----------------
0= 0< + U/MOD */MOD   AND OR XOR
LSHIFT RSHIFT   DUP SWAP OVER DROP
@ SL@ SW@ C@ ! L! W! C!   SP@ SP! RP@ RP!
>R R> R@   : ; EXIT
EXECUTE BRANCH 0BRANCH DONEXT DOLIT
ALITERAL CELL DOES> IMMEDIATE 'SYS

n10 n9 n8 n7 n6 n5 n4 n3 n2 n1 n0 - cell_t integer values
                   c4 c3 c2 c1 c0 - char* values
                   b4 b3 b2 b1 b0 - uint8_t* byte values
                   a4 a3 a2 a1 a0 - void* values

void myword(int a, int b, int c);
int send_message(const char *message, int code);
   🙜
Y(myword, myword(n2, n1, n0); DROPn(3)) \
X("send-message", SEND_MESSAGE, \
  n0 = send_message(c1, n0); DROP) \

#define VOCABULARY_LIST \
  V(forth) V(internals) ...
   🙜
void myword(int a, int b, int c);
int send_message(const char *message, int code);
   🙜
YV(vocabulary, myword, myword(n2, n1, n0); DROPn(3)) \
XV(vocabulary, "send-message", SEND_MESSAGE, \
   n0 = send_message(c1, n0); DROP) \

#define OPCODE_LIST \
  X("0=", ZEQUAL, tos = !tos ? -1 : 0) \
  X("0<", ZLESS, tos = (tos|0) < 0 ? -1 : 0) \
  X("+", PLUS, tos += *sp--) \
  X("U/MOD", USMOD, w = *sp; *sp = (ucell_t) w % (ucell_t) tos; \
                    tos = (ucell_t) w / (ucell_t) tos) \
  X("*/MOD", SSMOD, SSMOD_FUNC) \
  Y(LSHIFT, tos = (*sp-- << tos)) \
  Y(RSHIFT, tos = (*sp-- >> tos)) \
  Y(AND, tos &= *sp--) \
  Y(OR, tos |= *sp--) \
  Y(XOR, tos ^= *sp--) \
  Y(DUP, DUP) \
  Y(SWAP, w = tos; tos = *sp; *sp = w) \
  Y(OVER, DUP; tos = sp[-1]) \
  Y(DROP, DROP) \
  X("@", AT, tos = *(cell_t *) tos) \
  X("SL@", SLAT, tos = *(int32_t *) tos) \
  X("SW@", SWAT, tos = *(int16_t *) tos) \
  X("C@", CAT, tos = *(uint8_t *) tos) \
  X("!", STORE, *(cell_t *) tos = *sp--; DROP) \
  X("L!", LSTORE, *(int32_t *) tos = *sp--; DROP) \
  X("W!", WSTORE, *(int16_t *) tos = *sp--; DROP) \
  X("C!", CSTORE, *(uint8_t *) tos = *sp--; DROP) \
  X("SP@", SPAT, DUP; tos = (cell_t) sp) \
  X("SP!", SPSTORE, sp = (cell_t *) tos; DROP) \
  X("RP@", RPAT, DUP; tos = (cell_t) rp) \
  X("RP!", RPSTORE, rp = (cell_t *) tos; DROP) \
  X(">R", TOR, *++rp = tos; DROP) \
  X(">R", TOR, *++rp = tos; DROP) \
  X("R>", FROMR, DUP; tos = *rp; --rp) \
  X("R@", RAT, DUP; tos = *rp) \

  Y(EXECUTE, w = tos; DROP; JMPW) \
  YV(internals, BRANCH, ip = (cell_t *) *ip) \
  YV(internals, 0BRANCH, if (!tos) ip = (cell_t *) *ip; else ++ip; DROP) \
  YV(internals, DONEXT, *rp = *rp - 1; if (~*rp) ip = (cell_t *) *ip; else (--rp, ++ip)) \
  YV(internals, DOLIT, DUP; tos = *ip++) \
  YV(internals, ALITERAL, COMMA(g_sys.DOLIT_XT); COMMA(tos); DROP) \
  Y(CELL, DUP; tos = sizeof(cell_t)) \
  Y(FIND, tos = find((const char *) *sp, tos); --sp) \
  Y(PARSE, DUP; tos = parse(tos, sp)) \
  XV(internals, "S>NUMBER?", \
      CONVERT, tos = convert((const char *) *sp, tos, g_sys.base, sp); \
      if (!tos) --sp) \
  Y(CREATE, DUP; DUP; tos = parse(32, sp); \
            create((const char *) *sp, tos, 0, ADDR_DOCREATE); \
            COMMA(0); DROPn(2)) \
  X("DOES>", DOES, DOES(ip); ip = (cell_t *) *rp; --rp) \
  Y(IMMEDIATE, DOIMMEDIATE()) \
  XV(internals, "'SYS", SYS, DUP; tos = (cell_t) &g_sys) \
  YV(internals, YIELD, PARK; return rp) \
  X(":", COLON, DUP; DUP; tos = parse(32, sp); \
                create((const char *) *sp, tos, SMUDGE, ADDR_DOCOLON); \
                g_sys.state = -1; --sp; DROP) \
  YV(internals, EVALUATE1, DUP; float *tfp = fp; \
               sp = evaluate1(sp, &tfp); \
               fp = tfp; w = *sp--; DROP; if (w) JMPW) \
  Y(EXIT, ip = (cell_t *) *rp--) \
  XV(internals, "'builtins", TBUILTINS, DUP; tos = (cell_t) &g_sys.builtins->code) \
  XV(forth_immediate, ";", SEMICOLON, COMMA(g_sys.DOEXIT_XT); UNSMUDGE(); g_sys.state = 0)

#define EXTRA_OPCODE_LIST \
  Y(nip, NIP) \
  Y(rdrop, --rp) \
  X("*/", STARSLASH, SSMOD_FUNC; NIP) \
  X("*", STAR, tos *= *sp--) \
  X("/mod", SLASHMOD, DUP; *sp = 1; SSMOD_FUNC) \
  X("/", SLASH, DUP; *sp = 1; SSMOD_FUNC; NIP) \
  Y(mod, DUP; *sp = 1; SSMOD_FUNC; DROP) \
  Y(invert, tos = ~tos) \
  Y(negate, tos = -tos) \
  X("-", MINUS, tos = (*sp--) - tos) \
  Y(rot, w = sp[-1]; sp[-1] = *sp; *sp = tos; tos = w) \
  X("-rot", MROT, w = tos; tos = *sp; *sp = sp[-1]; sp[-1] = w) \
  X("<", LESS, tos = (*sp--) < tos ? -1 : 0) \
  X(">", GREATER, tos = (*sp--) > tos ? -1 : 0) \
  X("<=", LESSEQ, tos = (*sp--) <= tos ? -1 : 0) \
  X(">=", GREATEREQ, tos = (*sp--) >= tos ? -1 : 0) \
  X("=", EQUAL, tos = (*sp--) == tos ? -1 : 0) \
  X("<>", NOTEQUAL, tos = (*sp--) != tos ? -1 : 0) \
  X("0<>", ZNOTEQUAL, tos = tos ? -1 : 0) \
  Y(bl, DUP; tos = ' ') \
  Y(nl, DUP; tos = '\n') \
  X("1+", ONEPLUS, ++tos) \
  X("1-", ONEMINUS, --tos) \
  X("2*", TWOSTAR, tos <<= 1) \
  X("2/", TWOSLASH, tos >>= 1) \

  X("4*", FOURSTAR, tos <<= 2) \
  X("4/", FOURSLASH, tos >>= 2) \
  X("+!", PLUSSTORE, *(cell_t *) tos += *sp--; DROP) \
  X("cell+", CELLPLUS, tos += sizeof(cell_t)) \
  X("cells", CELLSTAR, tos *= sizeof(cell_t)) \
  X("cell/", CELLSLASH, DUP; tos = sizeof(cell_t); DUP; *sp = 1; SSMOD_FUNC; NIP) \
  X("2drop", TWODROP, NIP; DROP) \
  X("2dup", TWODUP, DUP; tos = sp[-1]; DUP; tos = sp[-1]) \
  X("2@", TWOAT, DUP; *sp = ((cell_t *) tos)[1]; tos = *(cell_t *) tos) \
  X("2!", TWOSTORE, DUP; ((cell_t *) tos)[0] = sp[-1]; \
      ((cell_t *) tos)[1] = *sp; sp -= 2; DROP) \
  Y(cmove, memmove((void *) *sp, (void *) sp[-1], tos); sp -= 2; DROP) \
  X("cmove>", cmove2, memmove((void *) *sp, (void *) sp[-1], tos); sp -= 2; DROP) \
  Y(fill, memset((void *) sp[-1], tos, *sp); sp -= 2; DROP) \
  Y(erase, memset((void *) *sp, 0, tos); NIP; DROP) \
  Y(blank, memset((void *) *sp, ' ', tos); NIP; DROP) \
  Y(min, tos = tos < *sp ? tos : *sp; NIP) \
  Y(max, tos = tos > *sp ? tos : *sp; NIP) \
  Y(abs, tos = tos < 0 ? -tos : tos) \
  Y(here, DUP; tos = (cell_t) g_sys.heap) \
  Y(allot, g_sys.heap = (cell_t *) (tos + (cell_t) g_sys.heap); DROP) \
  Y(aligned, tos = CELL_ALIGNED(tos)) \
  Y(align, g_sys.heap = (cell_t *) CELL_ALIGNED(g_sys.heap)) \
  X(",", COMMA, *g_sys.heap++ = tos; DROP) \
  X("c,", CCOMMA, *((uint8_t *) g_sys.heap) = tos; DROP; \
      g_sys.heap = (cell_t *) (1 + ((cell_t) g_sys.heap))) \
  X(">flags", TOFLAGS, tos = *TOFLAGS(tos)) \
  X(">params", TOPARAMS, tos = *TOPARAMS(tos)) \
  X(">size", TOSIZE, tos = TOSIZE(tos)) \

  X(">link&", TOLINKAT, tos = (cell_t) TOLINK(tos)) \
  X(">link", TOLINK, tos = *TOLINK(tos)) \
  X(">name", TONAME, DUP; *sp = (cell_t) TONAME(tos); tos = *TONAMELEN(tos)) \
  X(">body", TOBODY, tos = (cell_t) TOBODY(tos)) \
  XV(internals, "'heap", THEAP, DUP; tos = (cell_t) &g_sys.heap) \
  Y(current, DUP; tos = (cell_t) &g_sys.current) \
  XV(internals, "'context", TCONTEXT, DUP; tos = (cell_t) &g_sys.context) \
  XV(internals, "'latestxt", TLATESTXT, DUP; tos = (cell_t) &g_sys.latestxt) \
  XV(internals, "'notfound", TNOTFOUND, DUP; tos = (cell_t) &g_sys.notfound) \
  XV(internals, "'heap-start", THEAP_START, DUP; tos = (cell_t) &g_sys.heap_start) \
  XV(internals, "'heap-size", THEAP_SIZE, DUP; tos = (cell_t) &g_sys.heap_size) \
  XV(internals, "'stack-cells", TSTACK_CELLS, DUP; tos = (cell_t) &g_sys.stack_cells) \
  XV(internals, "'boot", TBOOT, DUP; tos = (cell_t) &g_sys.boot) \
  XV(internals, "'boot-size", TBOOT_SIZE, DUP; tos = (cell_t) &g_sys.boot_size) \
  XV(internals, "'tib", TTIB, DUP; tos = (cell_t) &g_sys.tib) \
  X("#tib", NTIB, DUP; tos = (cell_t) &g_sys.ntib) \
  X(">in", TIN, DUP; tos = (cell_t) &g_sys.tin) \
  Y(state, DUP; tos = (cell_t) &g_sys.state) \
  Y(base, DUP; tos = (cell_t) &g_sys.base) \
  XV(internals, "'argc", ARGC, DUP; tos = (cell_t) &g_sys.argc) \
  XV(internals, "'argv", ARGV, DUP; tos = (cell_t) &g_sys.argv) \
  XV(internals, "'runner", RUNNER, DUP; tos = (cell_t) &g_sys.runner) \
  Y(context, DUP; tos = (cell_t) (g_sys.context + 1)) \
  Y(latestxt, DUP; tos = (cell_t) g_sys.latestxt)

QUESTIONS?
    ⚘
Thank you!