aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMitch Bradley <wmb@firmworks.com>2017-01-03 13:22:50 -1000
committerMitch Bradley <wmb@firmworks.com>2017-01-03 13:34:40 -1000
commit1df190251fd04c9fa426f7ef69d3a8a084460b5e (patch)
treea32511a845ab3db5ec615209b773911426e5d8a2
parente36b2ecec8cd07cacf59b6a49dc3e860d4e628b0 (diff)
downloadcforth-1df190251fd04c9fa426f7ef69d3a8a084460b5e.tar.gz
First try at ESP32 version
-rw-r--r--build/esp32/.gitignore3
-rw-r--r--build/esp32/Makefile34
-rw-r--r--build/esp32/sdk_build/.gitignore2
-rw-r--r--build/esp32/sdk_build/Makefile2
-rw-r--r--build/esp32/sdk_build/main/component.mk6
-rw-r--r--build/esp32/sdk_build/sdkconfig187
-rw-r--r--src/app/esp32/app.fth42
-rw-r--r--src/app/esp32/consio.c113
-rw-r--r--src/app/esp32/fileio.c221
-rw-r--r--src/app/esp32/targets.mk85
-rw-r--r--src/app/esp32/textend.c33
-rw-r--r--src/app/esp32/tmain.c17
-rw-r--r--src/cforth/targets.mk2
13 files changed, 746 insertions, 1 deletions
diff --git a/build/esp32/.gitignore b/build/esp32/.gitignore
new file mode 100644
index 0000000..ece9a1a
--- /dev/null
+++ b/build/esp32/.gitignore
@@ -0,0 +1,3 @@
+*.DSYM
+tccalls.fth
+tdate.c
diff --git a/build/esp32/Makefile b/build/esp32/Makefile
new file mode 100644
index 0000000..7a9b0ab
--- /dev/null
+++ b/build/esp32/Makefile
@@ -0,0 +1,34 @@
+# Builds CForth for ESP8266
+
+default: forth.elf
+
+TOPDIR=../..
+
+# CONFIG += -DBITS32 -DT16
+CONFIG += -DBITS32
+
+CFLAGS += -m32
+
+CC := gcc
+
+# Change these to reflect the locations of external stuff on your system,
+# either here or on the command line, e.g. COMPORT=COM27 make download
+XTGCCPATH ?= /c/msys32/opt/xtensa-esp32-elf/bin/
+CROSS ?= $(XTGCCPATH)xtensa-esp32-elf-
+
+# ESP32 SDK
+IDF_PATH ?= $(TOPDIR)/../esp-idf
+IDF_TEMPLATE_PATH ?= $(TOPDIR)/../esp-idf-template
+
+COMPORT ?= COM27
+
+include $(TOPDIR)/src/app/esp32/targets.mk
+
+forth.elf: app.o
+ @IDF_PATH=$(IDF_PATH) make --no-print-directory -C sdk_build
+
+flash: app.o
+ @IDF_PATH=$(IDF_PATH) make --no-print-directory -C sdk_build flash
+
+clean::
+ @rm -rf sdk_build/build
diff --git a/build/esp32/sdk_build/.gitignore b/build/esp32/sdk_build/.gitignore
new file mode 100644
index 0000000..13fa9a7
--- /dev/null
+++ b/build/esp32/sdk_build/.gitignore
@@ -0,0 +1,2 @@
+build/
+sdkconfig.old
diff --git a/build/esp32/sdk_build/Makefile b/build/esp32/sdk_build/Makefile
new file mode 100644
index 0000000..f97e089
--- /dev/null
+++ b/build/esp32/sdk_build/Makefile
@@ -0,0 +1,2 @@
+PROJECT_NAME := forth
+include $(IDF_PATH)/make/project.mk
diff --git a/build/esp32/sdk_build/main/component.mk b/build/esp32/sdk_build/main/component.mk
new file mode 100644
index 0000000..c96f957
--- /dev/null
+++ b/build/esp32/sdk_build/main/component.mk
@@ -0,0 +1,6 @@
+#
+# Main component makefile.
+
+# COMPONENT_OBJS := ../../../app.o main.o
+
+COMPONENT_OBJS := ../../../app.o
diff --git a/build/esp32/sdk_build/sdkconfig b/build/esp32/sdk_build/sdkconfig
new file mode 100644
index 0000000..f1bb237
--- /dev/null
+++ b/build/esp32/sdk_build/sdkconfig
@@ -0,0 +1,187 @@
+#
+# Automatically generated file; DO NOT EDIT.
+# Espressif IoT Development Framework Configuration
+#
+
+#
+# SDK tool configuration
+#
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+CONFIG_PYTHON="python"
+
+#
+# Bootloader config
+#
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_WARN=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_INFO is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=2
+
+#
+# Security features
+#
+# CONFIG_SECURE_BOOT_ENABLED is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_PORT="COM27"
+CONFIG_ESPTOOLPY_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_BAUD=115200
+# CONFIG_ESPTOOLPY_COMPRESSED is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="40m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=y
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_CUSTOM_APP_BIN_OFFSET=0x10000
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_APP_OFFSET=0x10000
+CONFIG_PHY_DATA_OFFSET=0xf000
+CONFIG_OPTIMIZATION_LEVEL_DEBUG=y
+# CONFIG_OPTIMIZATION_LEVEL_RELEASE is not set
+
+#
+# Component config
+#
+CONFIG_BTC_TASK_STACK_SIZE=3072
+# CONFIG_BLUEDROID_MEM_DEBUG is not set
+CONFIG_BT_RESERVE_DRAM=0
+
+#
+# ESP32-specific config
+#
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_160 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_240=y
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=240
+CONFIG_ESP32_ENABLE_STACK_WIFI=y
+# CONFIG_ESP32_ENABLE_STACK_BT is not set
+CONFIG_MEMMAP_SMP=y
+# CONFIG_MEMMAP_TRACEMEM is not set
+CONFIG_TRACEMEM_RESERVE_DRAM=0x0
+CONFIG_WIFI_ENABLED=y
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2048
+CONFIG_MAIN_TASK_STACK_SIZE=4096
+# CONFIG_NEWLIB_STDOUT_ADDCR is not set
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# CONFIG_CONSOLE_UART_DEFAULT is not set
+CONFIG_CONSOLE_UART_CUSTOM=y
+# CONFIG_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART_CUSTOM_NUM_0=y
+# CONFIG_CONSOLE_UART_CUSTOM_NUM_1 is not set
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_TX_GPIO=1
+CONFIG_CONSOLE_UART_RX_GPIO=3
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+# CONFIG_ULP_COPROC_ENABLED is not set
+CONFIG_ULP_COPROC_RESERVE_MEM=0
+# CONFIG_ESP32_PANIC_PRINT_HALT is not set
+CONFIG_ESP32_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32_PANIC_GDBSTUB is not set
+CONFIG_ESP32_DEBUG_OCDAWARE=y
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+# CONFIG_TASK_WDT is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
+CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=0
+CONFIG_ESP32_PHY_AUTO_INIT=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# CONFIG_ETHERNET is not set
+
+#
+# FreeRTOS
+#
+CONFIG_FREERTOS_UNICORE=y
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+# CONFIG_FREERTOS_CORETIMER_2 is not set
+CONFIG_FREERTOS_HZ=1000
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY is not set
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=3
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_BREAK_ON_SCHEDULER_START_JTAG=y
+# CONFIG_ENABLE_MEMORY_DEBUG is not set
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+# CONFIG_FREERTOS_DEBUG_INTERNALS is not set
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_COLORS=y
+
+#
+# LWIP
+#
+# CONFIG_L2_TO_L3_COPY is not set
+CONFIG_LWIP_MAX_SOCKETS=4
+CONFIG_LWIP_THREAD_LOCAL_STORAGE_INDEX=0
+# CONFIG_LWIP_SO_REUSE is not set
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+# CONFIG_LWIP_IP_FRAG is not set
+# CONFIG_LWIP_IP_REASSEMBLY is not set
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_SSL_MAX_CONTENT_LEN=16384
+# CONFIG_MBEDTLS_DEBUG is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_MPI_USE_INTERRUPT=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
diff --git a/src/app/esp32/app.fth b/src/app/esp32/app.fth
new file mode 100644
index 0000000..fe9d1a3
--- /dev/null
+++ b/src/app/esp32/app.fth
@@ -0,0 +1,42 @@
+\ Load file for application-specific Forth extensions
+
+fl ../../lib/misc.fth
+fl ../../lib/dl.fth
+fl ../../lib/random.fth
+fl ../../lib/ilog2.fth
+fl ../../lib/tek.fth
+
+warning @ warning off
+: bye standalone? if restart then bye ;
+warning !
+
+: .commit ( -- ) 'version cscount type ;
+
+: .built ( -- ) 'build-date cscount type ;
+
+: banner ( -- )
+ cr ." CForth built " .built
+ ." from " .commit
+ cr
+;
+
+0 [if]
+\ Replace 'quit' to make CForth auto-run some application code
+\ instead of just going interactive.
+\ : app banner hex init-i2c showstack quit ;
+: interrupt? ( -- flag )
+ ." Type a key within 2 seconds to interact" cr
+ #20 0 do key? if key drop true unloop exit then #100 ms loop
+ false
+;
+: load-startup-file ( -- ) " start" included ;
+[then]
+
+: app
+ banner hex
+ quit
+;
+
+alias id: \
+
+" app.dic" save
diff --git a/src/app/esp32/consio.c b/src/app/esp32/consio.c
new file mode 100644
index 0000000..7bb65a0
--- /dev/null
+++ b/src/app/esp32/consio.c
@@ -0,0 +1,113 @@
+/*
+ * Console I/O routines
+ */
+
+#include "forth.h"
+#include "compiler.h"
+#include "stdlib.h"
+#include "driver/uart.h"
+
+int isinteractive() { return (1); }
+int isstandalone() { return (1); }
+
+void raw_emit(unsigned char c)
+{
+ uart_write_bytes(0, &c, 1);
+}
+
+void emit(u_char c, cell *up)
+{
+ if (c == '\n')
+ raw_emit('\r');
+ raw_emit(c);
+}
+
+u_char key_is_avail = 0;
+u_char the_key;
+
+int key_avail(cell *up)
+{
+ if (key_is_avail) {
+ return (cell)-1;
+ }
+ if(uart_read_bytes(0, &the_key, 1, 0)) {
+ key_is_avail = 1;
+ return (cell)-1;
+ }
+ return 0;
+}
+
+int key(cell *up)
+{
+ cell this_key;
+ while (!key_avail(up)) {}
+ key_is_avail = 0;
+ return (cell)the_key;
+}
+
+static const char *TAG = "forth";
+#define BUF_SIZE (1024)
+void uart_on(void)
+{
+ int uart_num = UART_NUM_0;
+ uart_config_t uart_config = {
+ .baud_rate = 115200,
+ .data_bits = UART_DATA_8_BITS,
+ .parity = UART_PARITY_DISABLE,
+ .stop_bits = UART_STOP_BITS_1,
+ .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,
+ .rx_flow_ctrl_thresh = 122,
+ };
+ //Set UART parameters
+ uart_param_config(uart_num, &uart_config);
+ //Set UART log level
+// esp_log_level_set(TAG, ESP_LOG_INFO);
+ //Set UART pins,(-1: default pin, no change.)
+ //For UART0, we can just use the default pins.
+ //uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
+ //Install UART driver( We don't need an event queue here)
+ //We don't even use a buffer for sending data.
+ uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0);
+}
+
+void init_io(int argc, char **argv, cell *up)
+{
+ key_is_avail = 0;
+ uart_on();
+}
+
+int caccept(char *addr, cell count, cell *up)
+{
+ return lineedit(addr, count, up);
+}
+
+// Defines the resolution of c_puts
+void output_redirect(const char *str) {
+ puts(str);
+}
+
+void alerror(char *str, int len, cell *up)
+{
+ while (len--)
+ emit((u_char)*str++, up);
+
+ /* Sequences of calls to error() eventually end with a newline */
+ V(NUM_OUT) = 0;
+}
+
+// moreinput() returns 0 when the console input stream has been closed for good
+int moreinput() { return (1); }
+
+char *getmem(u_cell nbytes, cell *up)
+{
+ return (char *)malloc(nbytes);
+}
+
+void memfree(char *ptr, cell *up)
+{
+ free(ptr);
+}
+char * memresize(char *ptr, u_cell nbytes, cell *up)
+{
+ return (char *)realloc(ptr, nbytes);
+}
diff --git a/src/app/esp32/fileio.c b/src/app/esp32/fileio.c
new file mode 100644
index 0000000..4d72ba3
--- /dev/null
+++ b/src/app/esp32/fileio.c
@@ -0,0 +1,221 @@
+// I/O subroutines for C Forth 93.
+// This code mostly uses C standard I/O, so it should work on most systems.
+//
+// Exported definitions:
+//
+// init_io(argc,argv); Initialize io system
+// emit(char, up); Output a character
+// n = key_avail(); How many characters can be read?
+// error(s, up); Print a string on the error stream
+// n = caccept(addr, count); Collect a line of input
+// char = key(); Get the next input character
+// name_input(filename);
+
+// newlib configuration to match esp-idf/components/newlib/include/sys/config.h
+// If we do not do this, we get linker errors about undefined _impure_ptr
+#define __DYNAMIC_REENT__
+#define _REENT_SMALL_
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "forth.h"
+#include "compiler.h"
+
+int ansi_emit(int c, FILE *fd);
+extern int key();
+extern void exit();
+extern FILE *fopen();
+
+#define STRINGINPUT (FILE *) -1
+
+cell
+freadline(cell f, cell *sp, cell *up) // Returns IO result, actual and more? on stack
+{
+ printf("In freadline\n");
+ // Stack: adr len -- actual more?
+
+ u_char *adr = (u_char *)sp[1];
+ register cell len = sp[0];
+
+ register cell actual;
+ register int c;
+
+ sp[0] = -1; // Assume not end of file
+
+ for (actual = 0; actual < len; ) {
+ if ((c = getc((FILE *)f)) == EOF) {
+ if (actual == 0)
+ sp[0] = 0;
+
+ if (ferror((FILE *)f)) {
+ sp[1] = actual;
+ return(READFAIL);
+ }
+ break;
+ }
+ if (c == CNEWLINE) { // Last character of an end-of-line sequence
+ break;
+ }
+
+ // Don't store the first half of a 2-character newline sequence
+ if (c == SNEWLINE[0])
+ continue;
+
+ *adr++ = c;
+// printf("%c", c);
+ ++actual;
+ }
+// printf("\n");
+
+
+ sp[1] = actual;
+ return(0);
+}
+
+cell
+pfclose(cell f, cell *up)
+{
+ return( (cell)fclose((FILE *)f) );
+}
+
+cell
+pfflush(cell f, cell *up)
+{
+ return( (cell)fflush((FILE *)f) );
+}
+
+cell
+pfsize(cell f, u_cell *high, u_cell *low, cell *up)
+{
+ FILE *fd = (FILE *)f;
+ long old, end;
+ old = ftell(fd);
+ fseek(fd, 0L, SEEK_END);
+ end = ftell(fd);
+ fseek(fd, old, SEEK_SET);
+ *high = 0;
+ *low = end;
+ return((cell)(end==-1 ? SIZEFAIL : 0));
+}
+
+char *
+expand_name(char *name)
+{
+ char envvar[64], *fnamep, *envp, paren, *fullp;
+ static char fullname[MAXPATHLEN];
+ int ndx;
+
+ fullp = fullname;
+ fullname[0] = '\0';
+
+ fnamep = name;
+
+ while (*fnamep) {
+ if (*fnamep == '$') {
+ fnamep++;
+ ndx = 0;
+ if (*fnamep == '{' || *fnamep == '(') { // multi char env var
+ paren = (*fnamep++ == '{') ? '}' : ')';
+
+ while (*fnamep != paren && ndx < MAXPATHLEN && *fnamep != '\0') {
+ envvar[ndx++] = *(fnamep++);
+ }
+ if (*fnamep == paren) {
+ fnamep++;
+ } else {
+ ndx = 0;
+ fnamep = name;
+ }
+ } else /* single char env. var. */
+ envvar[ndx++] = *(fnamep++);
+ envvar[ndx] = '\0';
+
+ if (ndx > 0 && (envp = getenv(envvar)) != NULL) {
+ strcpy(fullp, envp);
+ fullp += strlen(envp);
+ } else {
+ printf("Can't find environment variable %s in %s\n", envvar,name);
+ exit(1);
+ }
+ ndx = 0;
+ } else {
+ *fullp++ = *fnamep++;
+ }
+ }
+ *fullp = '\0';
+ return (fullname);
+}
+
+// r/o Open existing file for reading
+// w/o Open or create file for appending
+// r/w Open existing for reading and writing
+// r/o create-flag or Open or create file for appending, read at beginning
+// w/o create-flag or ???
+
+// 0:r/o 1:w/o 2:r/w 3: undefined
+static char *open_modes[] = { "rb", "ab", "r+b", "" };
+static char *popen_modes[] = { "r", "w", "rw", "" };
+cell pfopen(char *name, int len, int mode, cell *up)
+{
+ char cstrbuf[MAXPATHLEN];
+ char *s = expand_name(altocstr(name, len, cstrbuf, MAXPATHLEN));
+
+ FILE *res = fopen(s, open_modes[mode&3]);
+ return (cell)res;
+}
+
+static char *create_modes[] = { "a+b", "wb", "w+b", "" };
+cell pfcreate(char *name, int len, int mode, cell *up)
+{
+ char cstrbuf[512];
+
+ return( (cell)fopen(expand_name(altocstr(name, len, cstrbuf, 512)), create_modes[mode&3]) );
+}
+
+cell pfread(cell *sp, cell len, void *fid, cell *up) // Returns IO result, actual in *sp
+{
+ size_t ret;
+ *sp = (cell)fread((void *)*sp, 1, (size_t)len, (FILE *)fid);
+
+ return (*sp == 0) ? ferror((FILE *)fid) : 0;
+}
+
+cell pfwrite(void *adr, cell len, void *fid, cell *up) // Returns IO result, actual in *sp
+{
+ size_t ret;
+ ret = (cell)fwrite(adr, 1, (size_t)len, (FILE *)fid);
+
+ return (ret == 0) ? ferror((FILE *)fid) : 0;
+}
+
+cell pfseek(void *fid, u_cell high, u_cell low, cell *up)
+{
+ (void)fseek((FILE *)fid, low, 0);
+ return 0;
+}
+
+cell pfposition(void *fid, u_cell *high, u_cell *low, cell *up)
+{
+ *low = ftell((FILE *)fid);
+ *high = 0;
+ return 0;
+}
+
+void clear_log(cell *up) { }
+void start_logging(cell *up) { }
+void stop_logging(cell *up) { }
+cell log_extent(cell *log_base, cell *up) { *log_base = 0; return 0; }
+
+void pfmarkinput(void *fp, cell *up) {}
+void pfprint_input_stack(void) {}
+
+void read_dictionary(char *name, cell *up) { FTHERROR("read_dictionary unsupported\n"); }
+
+void write_dictionary(char *name, int len, char *dict, int dictsize,
+ cell *up, int usersize)
+{
+ FTHERROR("write_dictionary unsupported\n");
+}
diff --git a/src/app/esp32/targets.mk b/src/app/esp32/targets.mk
new file mode 100644
index 0000000..110178d
--- /dev/null
+++ b/src/app/esp32/targets.mk
@@ -0,0 +1,85 @@
+# APPPATH is the path to the application code, i.e. this directory
+APPPATH=$(TOPDIR)/src/app/esp32
+
+# APPLOADFILE is the top-level "Forth load file" for the application code.
+APPLOADFILE = app.fth
+
+# APPSRCS is a list of Forth source files that the application uses,
+# i.e. the list of files that APPLOADFILE floads. It's for dependency checking.
+APPSRCS = $(wildcard $(APPPATH)/*.fth)
+
+# Makefile fragment for the final target application
+
+SRC=$(TOPDIR)/src
+
+# Target compiler definitions
+CROSS ?= /Volumes/case-sensitive/esp-open-sdk/xtensa-lx106-elf/bin/xtensa-lx106-elf-
+TCC=$(CROSS)gcc
+TLD=$(CROSS)ld
+TOBJDUMP=$(CROSS)objdump
+TOBJCOPY=$(CROSS)objcopy
+
+LIBDIRS=-L$(dir $(shell $(TCC) $(TCFLAGS) -print-libgcc-file-name))
+
+VPATH += $(SRC)/cforth
+VPATH += $(SRC)/lib
+VPATH += $(APPPATH)
+INCS += -I$(APPPATH)
+
+INCS += -I$(IDF_TEMPLATE_PATH)/build/include
+INCS += -I$(IDF_PATH)/components/freertos/include
+INCS += -I$(IDF_PATH)/components/esp32/include
+INCS += -I$(IDF_PATH)/components/driver/include
+INCS += -I$(IDF_PATH)/components/nvs_flash/include
+
+include $(SRC)/common.mk
+include $(SRC)/cforth/targets.mk
+
+OPTIMIZE = -O2
+
+TCFLAGS += \
+ -g \
+ -fno-inline-functions \
+ -nostdlib \
+ -mlongcalls \
+ -mtext-section-literals \
+ -DXTENSA
+
+DUMPFLAGS = --disassemble -z -x -s
+
+# Platform-specific object files for low-level startup and platform I/O
+
+ttmain.o: vars.h
+
+PLAT_OBJS += ttmain.o
+PLAT_OBJS += tfileio.o
+
+# Object files for the Forth system and application-specific extensions
+
+FORTH_OBJS = tembed.o textend.o
+
+# Recipe for linking the final image
+
+DICTIONARY=ROM
+DICTSIZE=0x4000
+
+app.o: tdate.o
+ @echo Linking $@ ...
+ @$(TLD) -o $@ -r $(PLAT_OBJS) $(FORTH_OBJS) tdate.o
+
+# This rule builds a date stamp object that you can include in the image
+# if you wish.
+
+tdate.o: $(PLAT_OBJS) $(FORTH_OBJS)
+ @(echo "`git rev-parse --verify --short HEAD``if git diff-index --exit-code --name-only HEAD >/dev/null; then echo '-dirty'; fi`" || echo UNKNOWN) >version
+ @echo 'const char version[] = "'`cat version`'";' >tdate.c
+ @echo 'const char build_date[] = "'`date --utc +%F\ %R`'";' >>tdate.c
+ @cat tdate.c
+ @echo TCC $@
+ @$(TCC) -c tdate.c -o $@
+
+EXTRA_CLEAN += *.elf *.dump *.nm *.img date.c $(FORTH_OBJS) $(PLAT_OBJS) tdate.c version
+
+PREFIX += CBP=$(realpath $(TOPDIR)/src)
+
+include $(SRC)/cforth/embed/targets.mk
diff --git a/src/app/esp32/textend.c b/src/app/esp32/textend.c
new file mode 100644
index 0000000..9f572f5
--- /dev/null
+++ b/src/app/esp32/textend.c
@@ -0,0 +1,33 @@
+// Forth interfaces to platform-specific C routines
+// See "ccalls" below.
+
+#include "forth.h"
+#include "freertos/FreeRTOS.h"
+
+extern cell *callback_up;
+
+cell version_adr(void)
+{
+ extern char version[];
+ return (cell)version;
+}
+
+cell build_date_adr(void)
+{
+ extern char build_date[];
+ return (cell)build_date;
+}
+
+void ms(cell msecs)
+{
+ vTaskDelay(msecs/ portTICK_PERIOD_MS);
+}
+
+extern void software_reset(void);
+
+cell ((* const ccalls[])()) = {
+ C(build_date_adr) //c 'build-date { -- a.value }
+ C(version_adr) //c 'version { -- a.value }
+ C(ms) //c ms { i.ms -- }
+ C(software_reset) //c restart { -- }
+};
diff --git a/src/app/esp32/tmain.c b/src/app/esp32/tmain.c
new file mode 100644
index 0000000..a30b055
--- /dev/null
+++ b/src/app/esp32/tmain.c
@@ -0,0 +1,17 @@
+// Top-level routine for starting Forth
+
+#include "forth.h"
+#include "esp_system.h"
+#include "nvs_flash.h"
+
+
+// Defines startup routine for nodemcu-firmware
+void app_main(void)
+{
+ nvs_flash_init();
+
+ cell *up;
+ init_io(0, (char **)0, (cell *)up); // Perform platform-specific initialization
+ up = (void *)init_forth();
+ execute_word("app", up); // Call the top-level application word
+}
diff --git a/src/cforth/targets.mk b/src/cforth/targets.mk
index d979aaa..00faa69 100644
--- a/src/cforth/targets.mk
+++ b/src/cforth/targets.mk
@@ -180,7 +180,7 @@ makeccalls: makeccalls.c
@echo CC $<
@$(CC) -o makeccalls $<
-clean:
+clean::
@rm -f $(ARTIFACTS) forth forth.dic app.dic $(EXTRA_CLEAN)
tidy: