Arduino-FVM
Byte Token Threaded Forth Virtual Machine (FVM) for Arduino
FVM.h
Go to the documentation of this file.
1 
24 #ifndef ARDUINO_FVM_H
25 #define ARDUINO_FVM_H
26 
27 #include <Arduino.h>
28 
32 typedef const PROGMEM char* str_P;
33 
34 class FVM {
35  public:
36  enum {
37  /*
38  * Control structure and literals
39  */
40  OP_EXIT = 0,
42  OP_LIT = 2,
43  OP_CLIT = 3,
44  OP_SLIT = 4,
45  OP_VAR = 5,
46  OP_CONST = 6,
47  OP_FUNC = 7,
48  OP_DOES = 8,
49  OP_PARAM = 9,
50  OP_BRANCH = 10,
52  OP_DO = 12,
53  OP_I = 13,
54  OP_J = 14,
55  OP_LEAVE = 15,
56  OP_LOOP = 16,
57  OP_PLUS_LOOP = 17,
58  OP_NOOP = 18,
59  OP_EXECUTE = 19,
60  OP_HALT = 20,
61  OP_YIELD = 21,
62  OP_SYSCALL = 22,
63  OP_CALL = 23,
64  OP_TRACE = 24,
65  OP_ROOM = 25,
66 
67  /*
68  * Memory access
69  */
70  OP_C_FETCH = 26,
71  OP_C_STORE = 27,
72  OP_FETCH = 28,
73  OP_STORE = 29,
75  OP_DP = 31,
76  OP_HERE = 32,
77  OP_ALLOT = 33,
78  OP_COMMA = 34,
79  OP_C_COMMA = 35,
80  OP_COMPILE = 36,
81 
82  /*
83  * Return stack
84  */
85  OP_TO_R = 37,
86  OP_R_FROM = 38,
87  OP_R_FETCH = 39,
88 
89  /*
90  * Parameter stack
91  */
92  OP_SP = 40,
93  OP_DEPTH = 41,
94  OP_DROP = 42,
95  OP_NIP = 43,
96  OP_EMPTY = 44,
97  OP_DUP = 45,
99  OP_OVER = 47,
100  OP_TUCK = 48,
101  OP_PICK = 49,
102  OP_SWAP = 50,
103  OP_ROT = 51,
105  OP_ROLL = 53,
106  OP_TWO_SWAP = 54,
107  OP_TWO_DUP = 55,
108  OP_TWO_OVER = 56,
109  OP_TWO_DROP = 57,
110 
111  /*
112  * Constants
113  */
116  OP_ZERO = 60,
117  OP_ONE = 61,
118  OP_TWO = 62,
119  OP_CELL = 63,
120  OP_CELLS = 64,
121 
122  /*
123  * Bitwise logical operations
124  */
125  OP_BOOL = 65,
126  OP_NOT = 66,
127  OP_TRUE = 67,
128  OP_FALSE = 68,
129  OP_INVERT = 69,
130  OP_AND = 70,
131  OP_OR = 71,
132  OP_XOR = 72,
133 
134  /*
135  * Arithmetic operations
136  */
137  OP_NEGATE = 73,
138  OP_ONE_PLUS = 74,
140  OP_TWO_PLUS = 76,
142  OP_TWO_STAR = 78,
144  OP_PLUS = 80,
145  OP_MINUS = 81,
146  OP_STAR = 82,
148  OP_SLASH = 84,
149  OP_MOD = 85,
151  OP_LSHIFT = 87,
152  OP_RSHIFT = 88,
153 
154  /*
155  * Math operations
156  */
157  OP_WITHIN = 89,
158  OP_ABS = 90,
159  OP_MIN = 91,
160  OP_MAX = 92,
161 
162  /*
163  * Relational operations
164  */
170  OP_LESS = 98,
171  OP_EQUALS = 99,
172  OP_GREATER = 100,
173  OP_U_LESS = 101,
174 
175  /*
176  * Dictionary functions
177  */
178  OP_LOOKUP = 102,
179  OP_TO_BODY = 103,
180  OP_WORDS = 104,
181 
182  /*
183  * Basic I/O
184  */
185  OP_BASE = 105,
186  OP_HEX = 106,
187  OP_DECIMAL = 107,
189  OP_KEY = 109,
190  OP_EMIT = 110,
191  OP_CR = 111,
192  OP_SPACE = 112,
193  OP_SPACES = 113,
194  OP_U_DOT = 114,
195  OP_DOT = 115,
196  OP_DOT_S = 116,
197  OP_DOT_QUOTE = 117,
198  OP_TYPE = 118,
199  OP_DOT_NAME = 119,
200  OP_QUESTION = 120,
201 
202  /*
203  * Arduino extensions
204  */
205  OP_MICROS = 121,
206  OP_MILLIS = 122,
207  OP_DELAY = 123,
208  OP_PINMODE = 124,
214 
216  CORE_MAX = 128,
217 
219  KERNEL_MAX = 256,
220 
223 
225  TOKEN_MAX = 511
226  };
227 
229 #if defined(ARDUINO_ARCH_AVR)
230  typedef int16_t cell_t;
231  typedef uint16_t ucell_t;
232  typedef int32_t cell2_t;
233  typedef uint32_t ucell2_t;
234 #else
235  typedef int32_t cell_t;
236  typedef uint32_t ucell_t;
237  typedef int64_t cell2_t;
238  typedef uint64_t ucell2_t;
239 #endif
240 
248  typedef int8_t code_t;
249  typedef const PROGMEM code_t* code_P;
250 
251  struct task_t {
252  Stream& m_ios;
253  cell_t m_base;
254  bool m_trace;
255  code_P* m_rp;
256  code_P* m_rp0;
257  cell_t* m_sp;
258  cell_t* m_sp0;
259 
269  task_t(Stream&ios, cell_t* sp0, code_P* rp0, code_P fn) :
270  m_ios(ios),
271  m_base(10),
272  m_trace(false),
273  m_rp(rp0),
274  m_rp0(rp0),
275  m_sp(sp0 + 1),
276  m_sp0(sp0)
277  {
278  *++m_rp = fn;
279  }
280 
285  void push(cell_t value)
286  {
287  *++m_sp = value;
288  }
289 
294  cell_t pop()
295  {
296  return (*m_sp--);
297  }
298 
303  int depth()
304  {
305  return (m_sp - m_sp0 - 1);
306  }
307 
312  bool trace()
313  {
314  return (m_trace);
315  }
316 
321  void trace(bool flag)
322  {
323  m_trace = flag;
324  }
325 
331  task_t& call(code_P fn)
332  {
333  *++m_rp = fn;
334  return (*this);
335  }
336  };
337 
338  template<int PARAMETER_STACK_MAX, int RETURN_STACK_MAX>
339  struct Task : task_t {
340  cell_t m_params[PARAMETER_STACK_MAX];
341  code_P m_returns[RETURN_STACK_MAX];
342 
349  Task(Stream& ios, code_P fn = 0) :
350  task_t(ios, m_params, m_returns, fn)
351  {}
352  };
353 
357  struct obj_t {
358  code_t op;
359  code_t noop;
360  cell_t* value;
361  } __attribute__((packed));
362 
366  struct var_t {
367  code_t op;
368  cell_t* value;
369  } __attribute__((packed));
370 
374  struct const_t {
375  code_t op;
376  cell_t value;
377  } __attribute__((packed));
378 
383  typedef void (*fn_t)(task_t &task, void* env);
384  struct func_t {
385  code_t op;
387  void* env;
388  } __attribute__((packed));
389 
397  FVM(uint8_t* dp0 = 0, size_t bytes = 0, uint8_t words = 0) :
398  DICT_MAX(bytes),
399  WORD_MAX(words),
400  m_next(0),
401  m_dp(dp0),
402  m_dp0(dp0)
403  {
404  m_body = (code_t**) dp0;
405  m_name = 0;
406  if (words == 0) return;
407  dp0 += sizeof(code_t**) * words;
408  m_name = (char**) dp0;
409  dp0 += sizeof(char**) * words;
410  m_dp = dp0;
411  m_dp0 = dp0;
412  }
413 
418  uint8_t* dp()
419  {
420  return (m_dp);
421  }
422 
427  void dp(uint8_t* dp)
428  {
429  m_dp = dp;
430  }
431 
436  bool compile(int op)
437  {
438  if (op < 0 || op > TOKEN_MAX) return (false);
439  if (op < KERNEL_MAX) {
440  if (op >= CORE_MAX) *m_dp++ = OP_SYSCALL;
441  *m_dp++ = op;
442  }
443  else if (op < APPLICATION_MAX) {
444  *m_dp++ = APPLICATION_MAX - op - 1;
445  }
446  else {
447  *m_dp++ = OP_CALL;
448  *m_dp++ = op - APPLICATION_MAX;
449  }
450  return (true);
451  }
452 
457  void literal(int val)
458  {
459  if (val < INT8_MIN || val > INT8_MAX) {
460  *m_dp++ = OP_LIT;
461  *m_dp++ = val;
462  *m_dp++ = val >> 8;
463  }
464  else {
465  *m_dp++ = OP_CLIT;
466  *m_dp++ = val;
467  }
468  }
469 
475  bool create(const char* name)
476  {
477  if (m_next == WORD_MAX) return (false);
478  m_name[m_next] = (char*) m_dp;
479  strcpy((char*) m_dp, name);
480  m_dp += strlen(name) + 1;
481 #if defined(ARDUINO_ARCH_AVR)
482  m_body[m_next] = (code_t*) (m_dp + CODE_P_MAX);
483 #else
484  m_body[m_next] = (code_t*) m_dp;
485 #endif
486  m_next += 1;
487  return (true);
488  }
489 
494  bool variable(const char* name)
495  {
496  if (!create(name)) return (false);
497  *m_dp++ = OP_VAR;
498  *m_dp++ = 0;
499  *m_dp++ = 0;
500 #if !defined(ARDUINO_ARCH_AVR)
501  *m_dp++ = 0;
502  *m_dp++ = 0;
503 #endif
504  return (true);
505  }
506 
512  bool constant(const char* name, int val)
513  {
514  if (!create(name)) return (false);
515  *m_dp++ = OP_CONST;
516  *m_dp++ = val;
517  *m_dp++ = val >> 8;
518 #if !defined(ARDUINO_ARCH_AVR)
519  *m_dp++ = val >> 16;
520  *m_dp++ = val >> 24;
521 #endif
522  return (true);
523  }
524 
529  const char* name(int op)
530  {
531  return (op < m_next ? m_name[op] : 0);
532  }
533 
538  code_t* body(int op)
539  {
540 #if defined(ARDUINO_ARCH_AVR)
541  return (op < m_next ? m_body[op] - CODE_P_MAX : 0);
542 #else
543  return (op < m_next ? m_body[op] : 0);
544 #endif
545  }
546 
552  bool forget(int op)
553  {
554  op = op - APPLICATION_MAX;
555  if (op < 0 || op > m_next) return (false);
556  m_dp = (uint8_t*) m_name[op];
557  m_next = op;
558  return (true);
559  }
560 
568  int scan(char* bp, task_t& task);
569 
576  int lookup(const char* name);
577 
584  int resume(task_t& task);
585 
592  int execute(int op, task_t& task);
593 
601  int execute(code_P fn, task_t& task)
602  {
603  return (resume(task.call(fn)));
604  }
605 
614  int execute(const char* name, task_t& task)
615  {
616  return (execute(lookup(name), task));
617  }
618 
625  int interpret(task_t& task);
626 
627  // Threaded code and dictionary to be provided by sketch (program memory)
628  static const code_P fntab[] PROGMEM;
629  static const str_P fnstr[] PROGMEM;
630 
631  // Address mapping; max program memory code pointer
632  static const uint16_t CODE_P_MAX = 0x8000;
633 
634  protected:
635  // Kernel dictionary (optional)
636  static const str_P opstr[] PROGMEM;
637 
638  // Data allocation pointer and dynamic dictionary
639  const size_t DICT_MAX;
640  const uint8_t WORD_MAX;
641  uint8_t m_next;
642  uint8_t* m_dp;
643  uint8_t* m_dp0;
644  code_t** m_body;
645  char** m_name;
646 };
647 
652 #define FVM_OP(code) FVM::OP_ ## code
653 
658 #define FVM_LIT(n) \
659  FVM::OP_LIT, \
660  FVM::code_t(n), \
661  FVM::code_t((n) >> 8)
662 
667 #define FVM_CLIT(n) \
668  FVM::OP_CLIT, \
669  FVM::code_t(n)
670 
675 #define FVM_CALL(fn) FVM::code_t(-fn-1)
676 
684 #define FVM_CREATE(id,var,does,data) \
685  const int var = id; \
686  const char var ## _PSTR[] PROGMEM = #data; \
687  const FVM::obj_t var ## _VAR PROGMEM = { \
688  FVM_CALL(does), \
689  FVM_OP(NOOP), \
690  (FVM::cell_t*) &data \
691  }
692 
699 #define FVM_VARIABLE(id,var,data) \
700  const int var = id; \
701  const char var ## _PSTR[] PROGMEM = #data; \
702  const FVM::var_t var ## _VAR PROGMEM = { \
703  FVM_OP(CONST), \
704  (FVM::cell_t*) &data \
705  }
706 
714 #define FVM_CONSTANT(id,var,name,val) \
715  const int var = id; \
716  const char var ## _PSTR[] PROGMEM = name; \
717  const FVM::const_t var ## _CONST PROGMEM = { \
718  FVM_OP(CONST), \
719  val \
720  }
721 
728 #define FVM_COLON(id,var,name) \
729  const int var = id; \
730  const char var ## _PSTR[] PROGMEM = name; \
731  const FVM::code_t var ## _CODE[] PROGMEM = {
732 
740 #define FVM_FUNCTION(id,var,fn,env) \
741  const int var = id; \
742  const char var ## _PSTR[] PROGMEM = #fn; \
743  const FVM::func_t var ## _FUNC PROGMEM = { \
744  FVM_OP(FUNC), \
745  fn, \
746  (FVM::cell_t*) &env \
747  }
748 
755 #define FVM_SYMBOL(id,var,name) \
756  const int var = id + FVM::KERNEL_MAX; \
757  const char var ## _PSTR[] PROGMEM = name
758 
759 #endif
Allocate and assign character.
Definition: FVM.h:79
Convert top of stack to invert boolean.
Definition: FVM.h:126
Micro-seconds.
Definition: FVM.h:205
Base for number conversion.
Definition: FVM.h:185
code_t noop
OP_NOOP.
Definition: FVM.h:359
Decrement top of stack.
Definition: FVM.h:139
Yield virtual machine.
Definition: FVM.h:61
Inverse rotate three top stack elements.
Definition: FVM.h:104
Right shift.
Definition: FVM.h:152
Multiply by two.
Definition: FVM.h:142
Swap two top stack elements.
Definition: FVM.h:102
Duplicate double stack elements.
Definition: FVM.h:107
Increment top of stack.
Definition: FVM.h:138
Print value of variable.
Definition: FVM.h:200
Not equal zero.
Definition: FVM.h:165
Bitwise XOR top two elements.
Definition: FVM.h:132
Decrement by two.
Definition: FVM.h:141
uint8_t * m_dp0
Definition: FVM.h:643
code_t op
OP_VAR/OP_CONST.
Definition: FVM.h:367
Stack width in bytes.
Definition: FVM.h:119
Access data area application variable.
Definition: FVM.h:179
Print new-line.
Definition: FVM.h:191
Read character if available.
Definition: FVM.h:188
static const str_P opstr[]
Definition: FVM.h:636
Within boundard.
Definition: FVM.h:157
Equal.
Definition: FVM.h:171
Rotate given number of stack elements.
Definition: FVM.h:105
Duplicate index stack element.
Definition: FVM.h:101
static const code_P fntab[]
Definition: FVM.h:628
Handle function wrapper call.
Definition: FVM.h:47
Quotient for division of top two elements.
Definition: FVM.h:148
Load data.
Definition: FVM.h:72
Handle object pointer.
Definition: FVM.h:48
int resume(task_t &task)
Definition: FVM.cpp:143
Substract top two elements.
Definition: FVM.h:145
Halt virtual machine.
Definition: FVM.h:60
Add inline token.
Definition: FVM.h:80
Greater than.
Definition: FVM.h:172
Update data.
Definition: FVM.h:74
Print name of token.
Definition: FVM.h:199
Duplicate top of stack and rotate.
Definition: FVM.h:100
int depth()
Definition: FVM.h:303
Set hexa-decimal number conversion base.
Definition: FVM.h:186
Write digital pin.
Definition: FVM.h:210
Call application token.
Definition: FVM.h:63
bool create(const char *name)
Definition: FVM.h:475
bool forget(int op)
Definition: FVM.h:552
Definition: FVM.h:339
void(* fn_t)(task_t &task, void *env)
Definition: FVM.h:383
Milli-seconds.
Definition: FVM.h:206
Empty stack.
Definition: FVM.h:96
Duplicate double next top of stack.
Definition: FVM.h:108
Negate top of stack.
Definition: FVM.h:137
Increment by two.
Definition: FVM.h:140
static const uint16_t CODE_P_MAX
Definition: FVM.h:632
Divide by two.
Definition: FVM.h:143
Number of elements.
Definition: FVM.h:93
Print spaces.
Definition: FVM.h:193
code_t * body(int op)
Definition: FVM.h:538
Stack pointer.
Definition: FVM.h:92
Handle constant.
Definition: FVM.h:46
code_P * m_rp
Return stack pointer.
Definition: FVM.h:255
Mark loop block as completed.
Definition: FVM.h:55
Start loop block.
Definition: FVM.h:52
Bitwise inverse top element.
Definition: FVM.h:129
uint8_t * m_dp
Definition: FVM.h:642
Call system token.
Definition: FVM.h:62
bool constant(const char *name, int val)
Definition: FVM.h:512
FVM(uint8_t *dp0=0, size_t bytes=0, uint8_t words=0)
Definition: FVM.h:397
Push constant(2)
Definition: FVM.h:118
Current loop index.
Definition: FVM.h:53
void trace(bool flag)
Definition: FVM.h:321
Convert cells to bytes for allot.
Definition: FVM.h:120
Add top two elements.
Definition: FVM.h:144
const char * str_P
Definition: FVM.h:32
cell_t m_base
Number conversion base.
Definition: FVM.h:253
Allocate number of bytes.
Definition: FVM.h:77
void dp(uint8_t *dp)
Definition: FVM.h:427
uint8_t * dp()
Definition: FVM.h:418
Less than zero.
Definition: FVM.h:166
Minimum value.
Definition: FVM.h:159
code_t op
CALL(FN).
Definition: FVM.h:358
Print top of stack as unsigned.
Definition: FVM.h:194
Set trace mode.
Definition: FVM.h:64
Multiply/Divide top three elements.
Definition: FVM.h:147
Not equal.
Definition: FVM.h:169
const char * name(int op)
Definition: FVM.h:529
Push constant(-1)
Definition: FVM.h:115
const code_t * code_P
Definition: FVM.h:249
Data pointer.
Definition: FVM.h:76
code_t op
OP_CONST.
Definition: FVM.h:375
bool variable(const char *name)
Definition: FVM.h:494
Maximum value.
Definition: FVM.h:160
Outer loop index.
Definition: FVM.h:54
Multiply top two elements.
Definition: FVM.h:146
Lookup word in dictionary.
Definition: FVM.h:178
void literal(int val)
Definition: FVM.h:457
Load character (signed byte)
Definition: FVM.h:70
Bitwise OR top two elements.
Definition: FVM.h:131
Bitwise AND top two elements.
Definition: FVM.h:130
char ** m_name
Definition: FVM.h:645
bool trace()
Definition: FVM.h:312
Push constant(0)
Definition: FVM.h:116
Threaded code return.
Definition: FVM.h:40
int execute(const char *name, task_t &task)
Definition: FVM.h:614
bool m_trace
Trace mode.
Definition: FVM.h:254
static const str_P fnstr[]
Definition: FVM.h:629
Threaded code return if zero/false.
Definition: FVM.h:41
Push constant(1)
Definition: FVM.h:117
Wait for character and read.
Definition: FVM.h:189
Execute operation token.
Definition: FVM.h:59
Duplicate top of stack if not zero.
Definition: FVM.h:98
Push false(0)
Definition: FVM.h:128
int execute(int op, task_t &task)
Definition: FVM.cpp:1837
Convert top of stack to boolean.
Definition: FVM.h:125
Greater than zero.
Definition: FVM.h:168
int execute(code_P fn, task_t &task)
Definition: FVM.h:601
Print character.
Definition: FVM.h:190
cell_t * m_sp
Parameter stack pointer.
Definition: FVM.h:257
Set decimal number conversion base.
Definition: FVM.h:187
Drop top of stack.
Definition: FVM.h:94
code_P * m_rp0
Return stack bottom pointer.
Definition: FVM.h:256
cell_t pop()
Definition: FVM.h:294
Duplicate next top of stack.
Definition: FVM.h:99
cell_t value
Value of constant (PROGMEM).
Definition: FVM.h:376
Less than.
Definition: FVM.h:170
cell_t * m_sp0
Parameter stack bottom pointer.
Definition: FVM.h:258
void * env
Pointer to environment (SRAM).
Definition: FVM.h:387
Drop next top of stack.
Definition: FVM.h:95
int interpret(task_t &task)
Definition: FVM.cpp:1848
Write pwm pin.
Definition: FVM.h:213
code_t ** m_body
Definition: FVM.h:644
Pop data from return stack.
Definition: FVM.h:86
int lookup(const char *name)
Definition: FVM.cpp:101
Duplicate inline indexed stack element.
Definition: FVM.h:49
Equal to zero.
Definition: FVM.h:167
Delay milli-seconds (yield)
Definition: FVM.h:207
bool compile(int op)
Definition: FVM.h:436
Push constant(-2)
Definition: FVM.h:114
Digital pin mode.
Definition: FVM.h:208
Remainder for division of top two elements.
Definition: FVM.h:149
int64_t cell2_t
Definition: FVM.h:237
Drop double top of stack.
Definition: FVM.h:109
uint32_t ucell_t
Definition: FVM.h:236
Copy from return stack.
Definition: FVM.h:87
End loop block (n increment)
Definition: FVM.h:57
int8_t code_t
Definition: FVM.h:248
Rotate three top stack elements.
Definition: FVM.h:103
Handle variable reference.
Definition: FVM.h:45
fn_t fn
Pointer to function.
Definition: FVM.h:386
Push true(-1)
Definition: FVM.h:127
Quotient and remainder.
Definition: FVM.h:150
Swap two double stack elements.
Definition: FVM.h:106
void push(cell_t value)
Definition: FVM.h:285
Store data.
Definition: FVM.h:73
Read digital pin.
Definition: FVM.h:209
Left shift.
Definition: FVM.h:151
No operation.
Definition: FVM.h:58
Read analog pin.
Definition: FVM.h:212
task_t(Stream &ios, cell_t *sp0, code_P *rp0, code_P fn)
Definition: FVM.h:269
Store character.
Definition: FVM.h:71
const uint8_t WORD_MAX
Definition: FVM.h:640
Print top of stack.
Definition: FVM.h:195
End loop block (one increment)
Definition: FVM.h:56
Absolute value.
Definition: FVM.h:158
Print contents of parameter stack.
Definition: FVM.h:196
Duplicate top of stack.
Definition: FVM.h:97
code_t op
OP_FUNC.
Definition: FVM.h:385
int32_t cell_t
Definition: FVM.h:235
int scan(char *bp, task_t &task)
Definition: FVM.cpp:121
Push instruction pointer and branch always.
Definition: FVM.h:44
uint8_t m_next
Definition: FVM.h:641
uint64_t ucell2_t
Definition: FVM.h:238
Definition: FVM.h:34
Print string.
Definition: FVM.h:198
Branch always (offset -128..127)
Definition: FVM.h:50
Task(Stream &ios, code_P fn=0)
Definition: FVM.h:349
Print program memory string.
Definition: FVM.h:197
task_t & call(code_P fn)
Definition: FVM.h:331
const size_t DICT_MAX
Definition: FVM.h:639
Dictionary state.
Definition: FVM.h:65
cell_t * value
Pointer to value (SRAM).
Definition: FVM.h:360
Allocate and assign from top of stack.
Definition: FVM.h:78
cell_t * value
Pointer to value (SRAM).
Definition: FVM.h:368
Data pointer variable.
Definition: FVM.h:75
List dictionaries.
Definition: FVM.h:180
Branch if zero/false (offset -128..127)
Definition: FVM.h:51
Print space.
Definition: FVM.h:192
Inline literal constant.
Definition: FVM.h:42
Toggle digital pin.
Definition: FVM.h:211
Push data on return stack.
Definition: FVM.h:85
Unsigned less than.
Definition: FVM.h:173
Inline literal signed character constant.
Definition: FVM.h:43
Stream & m_ios
Input/Output stream.
Definition: FVM.h:252