ESP32Forth eoy 2021
        🙜
   Brad Nelson
        🙜
Decemeber 18, 2021

Agenda
    🙜
 • Floating Point
 • More Kinds of ESP-32
 • Lots of Libraries

Floating Point
    🙜
 • Use what the hardware has
 • Preparing to run ML models
 • ESP-32 only has hardware float32
 • Many libraries take floats

Approach
    🙜
 • Additional floating point stack
 • fp pointer throughout

  register cell_t *ip, *rp, *sp, tos, w;
  register float *fp;
  rp = init_rp;  ip = (cell_t *) *rp--;  sp = (cell_t *) *rp--;
  fp = (float *) *rp--;
  DROP; NEXT;
 
#define PARK DUP; \
  *++rp = (cell_t) fp; \
  *++rp = (cell_t) sp; \
  *++rp = (cell_t) ip

static cell_t fconvert(const char *pos, cell_t n, float *ret) {
  *ret = 0;
  cell_t negate = 0;
  cell_t has_dot = 0;
  cell_t exp = 0;
  float shift = 1.0;
  if (!n) { return 0; }
  if (*pos == '-') { negate = -1; ++pos; --n; }
  for (; n; --n) {
    if (*pos >= '0' && *pos <= '9') {
      if (has_dot) {
        shift = shift * 0.1f;
        *ret = *ret + (*pos - '0') * shift;
      } else {
        *ret = *ret * 10 + (*pos - '0');
      }
    } else if (*pos == 'e' || *pos == 'E') {
      break;
    } else if (*pos == '.') {
      if (has_dot) { return 0; }
      has_dot = -1;
    }
    ++pos;
  }
  if (!n) { return 0; }  // must have E
  ++pos; --n;
  if (n) {
    if (!convert(pos, n, 10, &exp)) { return 0; }
  }
  if (exp < -128 || exp > 128) { return 0; }
  for (;exp < 0; ++exp) { *ret *= 0.1f; }
  for (;exp > 0; --exp) { *ret *= 10.0f; }
  if (negate) { *ret = -*ret; }
  return -1;
}
  
X("F>NUMBER?", FCONVERT, tos = fconvert((const char *) *sp, tos, fp); --sp) \

    } else {
      float f;
      if (fconvert((const char *) name, len, &f)) {
        if (g_sys.state) {
          *g_sys.heap++ = g_sys.DOFLIT_XT;
          *(float *) g_sys.heap++ = f;
        } else {
          *++(*fp) = f;
        }

#define FLOATING_POINT_LIST \
  Y(DOFLIT, *++fp = *(float *) ip++) \

  X("FDUP", FDUP, fp[1] = *fp; ++fp) \
  X("FNIP", FNIP, fp[-1] = *fp; --fp) \
  X("FDROP", FDROP, --fp) \
  X("FOVER", FOVER, fp[1] = fp[-1]; ++fp) \
  X("FSWAP", FSWAP, float ft = fp[-1]; fp[-1] = *fp; *fp = ft) \

  X("F0<", FZLESS, DUP; tos = *fp-- < 0.0f ? -1 : 0) \
  X("F0=", FZEQUAL, DUP; tos = *fp-- == 0.0f ? -1 : 0) \

: f= ( r r -- f ) f- f0= ;
: f< ( r r -- f ) f- f0< ;
: f> ( r r -- f ) fswap f< ;
: f<> ( r r -- f ) f= 0= ;
: f<= ( r r -- f ) f> 0= ;
: f>= ( r r -- f ) f< 0= ;

  X("FNEGATE", FNEGATE, *fp = -*fp) \
  X("F+", FPLUS, fp[-1] += *fp; --fp) \
  X("F-", FMINUS, fp[-1] -= *fp; --fp) \
  X("F*", FSTAR, fp[-1] *= *fp; --fp) \
  X("F/", FSLASH, fp[-1] /= *fp; --fp) \
  X("1/F", FINVERSE, *fp = 1.0 / *fp) \

  X("S>F", STOF, *++fp = (float) tos; DROP) \
  X("F>S", FTOS, DUP; tos = (cell_t) *fp--) \

  X("FP@", FPAT, DUP; tos = (cell_t) fp) \
  X("FP!", FPSTORE, fp = (float *) tos; DROP) \
  X("SF@", FAT, *++fp = *(float *) tos; DROP) \
  X("SF!", FSTORE, *(float *) tos = *fp--; DROP) \

4 constant sfloat
: sfloats ( n -- n*4 ) sfloat * ;
: sfloat+ ( a -- a ) sfloat + ;
: sf, ( r -- ) here sf! sfloat allot ;

: afliteral ( r -- ) ['] DOFLIT , sf, align ;
: fliteral   afliteral ; immediate
: fconstant ( r "name" ) create sf, align does> sf@ ;
: fvariable ( "name" ) create sfloat allot align ;

6 value precision
: set-precision ( n -- ) to precision ;
: #f+s ( r -- ) fdup precision 0 ?do 10e f* loop
                precision 0 ?do fdup f>s 10 mod [char] 0 + hold 0.1e f* loop
                [char] . hold fdrop f>s #s ;
: #fs ( r -- ) fdup f0< if fnegate #f+s [char] - hold else #f+s then ;
: f. ( r -- ) <# #fs #> type space ;

: fsqrt ( r -- r )
  1e 20 0 do fover fover f/ f+ 0.5e f* loop fnip ;

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 FPU
ESP32        - Single Precision FPU
ESP32-SOLO   - Single Precision FPU
ESP32-MINI   - Single Precision FPU
ESP32-S2     - No FPU
ESP32-S3     - Single Precision FPU
 
ESP32-C3     - No FPU
ESP32-C6     - No FPU

Easy to Expand
    🙜
---- userwords.h ----
int my_cool_function(char *foo, int bar, uint8_t *baz);
...
#define USER_WORDS \
  Y(MY_FUNC, n0 = my_cool_function(c2, n1, b0); NIPn(2)) \

Lots of Libraries
    🙜
 • Serial               • Serial Bluetooth
 • LED Controller       • SPIFFS
 • SD_MMC               • WiFi
 • mDNS                 • I2C
 • WebServer (Forth and Native)
 • Camera               • GPIO & Interrupts
 • Remote Control (RMT) • Tasks
 • Blocks

eforth.appspot.com
        ⚘
    QUESTIONS?