├── TinyMod 3-setup.pdf ├── TinyMod2-setup.pdf ├── TinyMod4-setup.pdf ├── TinyMod-NKRO-setup.pdf ├── stenomod-hinge-setup.pdf ├── README.md ├── ITC-Forth.ino ├── steno_keyboard.ino ├── mux_steno.ino ├── TinyMod3.ino ├── Interpreter.ino ├── TinyMod4.ino ├── M0-Forth.ino ├── Cortex-Forth.ino ├── Arm-Forth-3.ino ├── Jackdaw.ino └── mux_steno_Jackdaw.ino /TinyMod 3-setup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharleyShattuck/Steno-Keyboard-Arduino/HEAD/TinyMod 3-setup.pdf -------------------------------------------------------------------------------- /TinyMod2-setup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharleyShattuck/Steno-Keyboard-Arduino/HEAD/TinyMod2-setup.pdf -------------------------------------------------------------------------------- /TinyMod4-setup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharleyShattuck/Steno-Keyboard-Arduino/HEAD/TinyMod4-setup.pdf -------------------------------------------------------------------------------- /TinyMod-NKRO-setup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharleyShattuck/Steno-Keyboard-Arduino/HEAD/TinyMod-NKRO-setup.pdf -------------------------------------------------------------------------------- /stenomod-hinge-setup.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CharleyShattuck/Steno-Keyboard-Arduino/HEAD/stenomod-hinge-setup.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Steno-Keyboard-Arduino 2 | ====================== 3 | 4 | Arduino code for a homemade steno keyboard. 5 | 6 | steno_keyboard.ino: The original, separate pin for each key. Arduino Mega. 7 | 8 | mux_steno.ino: Second try, multiplexed. Arduino Micro, now modified to use Adafruit Itsy Bitsy and allow pin 8 to ground to choose NKRO keyboard protocol, otherwise TX Bolt. TinyMod2 uses pin 7 for that purpose. 9 | 10 | A new addition is a tiny version of Jackdaw, an orthographic chording system for the TinyMod. Still being developed. 11 | 12 | Interpreter.ino: Unrelated project. A Forth style interpreter. 13 | 14 | Also M0-Forth is a Forth in C for an Arm Arduino, in development. 15 | 16 | M0-Forth is now an abandoned first try. Cortex-Forth is simpler and more efficient. Also, I think, easier to explain. But at this point I've stopped working on that one too. 17 | -------------------------------------------------------------------------------- /ITC-Forth.ino: -------------------------------------------------------------------------------- 1 | // ITC-Forth.ino 2 | 3 | #define RAM_SIZE 0x1200 4 | #define S0 0x1000 5 | #define R0 0x0f00 6 | 7 | // "registers" 8 | int S = S0; // data stack pointer 9 | int R = R0; // return stack pointer 10 | int I = 0; // instruction pointer 11 | int W = 0; // working register 12 | 13 | const int memory [] { 14 | 1, // print A 15 | 2, // delay 1 sec 16 | 3, // branch 17 | 0, // to this address 18 | }; 19 | 20 | void runForth () { 21 | next: 22 | W = memory [I++]; 23 | switch (W) { 24 | case 1: 25 | A: 26 | Serial.write ('A'); 27 | goto next; 28 | case 2: 29 | _delay: 30 | delay (1000); 31 | goto next; 32 | case 3: 33 | branch: 34 | I = memory [I]; 35 | goto next; 36 | } 37 | } 38 | 39 | void setup () { 40 | Serial.begin (9600); 41 | I = 0; 42 | S = S0; 43 | R = R0; 44 | runForth (); 45 | } 46 | 47 | void loop () { 48 | while (1) { 49 | // Serial.write ('A'); 50 | // delay (1000); 51 | }; 52 | } 53 | -------------------------------------------------------------------------------- /steno_keyboard.ino: -------------------------------------------------------------------------------- 1 | // This example program is in the public domain 2 | 3 | // each key switch is connected to a unique I/O pin on one side 4 | // which is weakly pulled high, and ground on the other. 5 | // Pressing the key connects the pin to ground, pulling it low. 6 | 7 | boolean pressed = false; 8 | 9 | // the four bytes of the TX Bolt protocol 10 | byte val0 = 0; 11 | byte val1 = 0; 12 | byte val2 = 0; 13 | byte val3 = 0; 14 | 15 | void setup() { 16 | // all pins weakly pulled high 17 | for (int i=30; i<54; i++) { 18 | pinMode(i, INPUT_PULLUP); 19 | } 20 | // LED on while key pressed 21 | pinMode(13, OUTPUT); 22 | digitalWrite(13, LOW); // Turn off LED 23 | Serial.begin(9600); 24 | } 25 | 26 | void loop() { 27 | // accumulate keys 28 | do { scan(); } while (!pressed); 29 | delay(10); // Debounces 1st keypress 30 | // until all keys released 31 | do { scan(); } while (pressed); 32 | // debounce the release 33 | delay(50); 34 | // show(); // debug 35 | give(); // TX Bolt Protocol 36 | empty(); 37 | } 38 | 39 | // read and accumulate keypresses 40 | // one key at a time 41 | void scan() { 42 | pressed = false; 43 | 44 | // pin, mask, byte 45 | val0 = getKey(36, 1, val0); /* S */ 46 | val0 = getKey(31, 2, val0); /* T */ 47 | val0 = getKey(30, 4, val0); /* K */ 48 | val0 = getKey(33, 8, val0); /* P */ 49 | val0 = getKey(32, 16, val0); /* W */ 50 | val0 = getKey(35, 32, val0); /* H */ 51 | 52 | val1 = getKey(34, 1, val1); /* R */ 53 | val1 = getKey(52, 2, val1); /* A */ 54 | val1 = getKey(53, 4, val1); /* O */ 55 | val1 = getKey(50, 8, val1); /* * */ 56 | val1 = getKey(51, 16, val1); /* E */ 57 | val1 = getKey(48, 32, val1); /* U */ 58 | 59 | val2 = getKey(47, 1, val2); /* F */ 60 | val2 = getKey(45, 2, val2); /* R */ 61 | val2 = getKey(49, 4, val2); /* P */ 62 | val2 = getKey(46, 8, val2); /* B */ 63 | val2 = getKey(43, 16, val2); /* L */ 64 | val2 = getKey(44, 32, val2); /* G */ 65 | 66 | val3 = getKey(41, 1, val3); /* T */ 67 | val3 = getKey(42, 2, val3); /* S */ 68 | val3 = getKey(39, 4, val3); /* D */ 69 | val3 = getKey(40, 8, val3); /* Z */ 70 | val3 = getKey(38, 16, val3); /* # */ 71 | } 72 | 73 | // k = Arduino pin number 74 | // b = bit mask for TX Bolt bit position 75 | // v = current protocol byte 76 | byte getKey(int k, byte b, byte v) { 77 | int val = digitalRead(k); 78 | if (val == 0) { 79 | v = b | v; 80 | pressed = true; 81 | } 82 | return v; 83 | } 84 | 85 | void empty() { 86 | val0 = 0; 87 | val1 = 0; 88 | val2 = 0; 89 | val3 = 0; 90 | } 91 | 92 | void cr() { 93 | Serial.print("\n"); 94 | } 95 | 96 | void space() { 97 | Serial.print(" "); 98 | } 99 | 100 | // show accumulated bytes on terminal 101 | void show() { 102 | Serial.print(val0, HEX); 103 | space(); 104 | Serial.print(val1, HEX); 105 | space(); 106 | Serial.print(val2, HEX); 107 | space(); 108 | Serial.print(val3, HEX); 109 | cr(); 110 | } 111 | 112 | // send TX bytes over serial, 113 | // then clear buffers 114 | void give() { 115 | Serial.write(val0); 116 | val1 = val1 | 64; 117 | Serial.write(val1); 118 | val2 = val2 | 128; 119 | Serial.write(val2); 120 | val3 = val3 | 192; 121 | Serial.write(val3); 122 | empty(); 123 | } 124 | 125 | -------------------------------------------------------------------------------- /mux_steno.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Multiplexed Steno Keyboard 4 | // This example program is in the public domain 5 | // modified August 5, 2018 to make row pins HIGH 6 | // for the diodes. 7 | // modified August 18-19 for NKRO protocol 8 | 9 | boolean pressed; 10 | boolean first; 11 | 12 | // four bytes for the TX Bolt protocol 13 | #define NO_BYTES 4 14 | byte data[NO_BYTES]; 15 | 16 | // matrix wiring 17 | #define NO_ROWS 4 18 | const byte row[]={9, 10, 11, 12}; 19 | #define NO_COLS 6 20 | const byte column[]={A0, A1, A2, A3, A4, A5}; 21 | 22 | // protocol choice on this pin 23 | #define PROTOCOL 7 // TinyMod 2 24 | // #define PROTOCOL 8 // TinyMod 1 25 | 26 | void setup() { 27 | for(int i=0; i 2 | 3 | // Multiplexed Steno Keyboard 4 | // This example program is in the public domain 5 | // modified August 5, 2018 to make row pins HIGH 6 | // for the diodes. 7 | // modified August 18-19 for NKRO protocol 8 | // modified February 27, 2019, for TinyMod3 9 | 10 | boolean pressed; 11 | boolean first; 12 | 13 | // temp storage for key data 14 | #define NO_BYTES 5 15 | byte data[NO_BYTES]; 16 | 17 | #define NO_BOLTS 4 18 | byte bolt[NO_BOLTS]; 19 | 20 | // matrix wiring 21 | #define NO_ROWS 5 22 | const byte row[]={9, 10, 11, 12, 13}; 23 | #define NO_COLS 5 24 | const byte column[]={A1, A2, A3, A4, A5}; 25 | 26 | // protocol choice on this pin 27 | #define PROTOCOL 7 // TinyMod3 28 | 29 | // NKRO protocol 30 | void spit(char a){ 31 | Keyboard.press(a); delay(2); 32 | if(first == true){ 33 | first = false; 34 | } else{ 35 | Keyboard.release(a); 36 | } 37 | } 38 | 39 | void sendNKRO(){ 40 | first = true; 41 | 42 | if (data[4] & 0x01)spit('q'); 43 | if (data[4] & 0x02)spit('w'); 44 | if (data[4] & 0x04)spit('e'); 45 | if (data[4] & 0x08)spit('r'); 46 | if (data[4] & 0x10)spit('t'); 47 | 48 | if (data[3] & 0x01)spit('u'); 49 | if (data[3] & 0x02)spit('i'); 50 | if (data[3] & 0x04)spit('o'); 51 | if (data[3] & 0x08)spit('p'); 52 | if (data[3] & 0x10)spit('['); 53 | 54 | if (data[2] & 0x01)spit('a'); 55 | if (data[2] & 0x02)spit('s'); 56 | if (data[2] & 0x04)spit('d'); 57 | if (data[2] & 0x08)spit('f'); 58 | if (data[2] & 0x10)spit('g'); 59 | 60 | if (data[1] & 0x01)spit('j'); 61 | if (data[1] & 0x02)spit('k'); 62 | if (data[1] & 0x04)spit('l'); 63 | if (data[1] & 0x08)spit(';'); 64 | if (data[1] & 0x10)spit('\''); 65 | 66 | if (data[0] & 0x01)spit('c'); 67 | if (data[0] & 0x02)spit('v'); 68 | if (data[0] & 0x04)spit('3'); 69 | if (data[0] & 0x08)spit('n'); 70 | if (data[0] & 0x10)spit('m'); 71 | 72 | Keyboard.releaseAll(); 73 | } 74 | 75 | void NKRO_keyboard(){ 76 | Keyboard.begin(); 77 | delay(3000); 78 | while(true){ 79 | scan(); 80 | sendNKRO(); 81 | } 82 | } 83 | 84 | // TX Bolt protocol 85 | void arrange() { 86 | for (byte i = 0; i < NO_BOLTS; i++) { 87 | bolt[i] = (i * 0x40); 88 | } 89 | if (data[4] & 0x01) bolt[0] |= 0x01; // S 90 | if (data[2] & 0x01) bolt[0] |= 0x01; // S 91 | if (data[4] & 0x02) bolt[0] |= 0x02; // T 92 | if (data[2] & 0x02) bolt[0] |= 0x04; // K 93 | if (data[4] & 0x04) bolt[0] |= 0x08; // P 94 | if (data[2] & 0x04) bolt[0] |= 0x10; // W 95 | if (data[4] & 0x08) bolt[0] |= 0x20; // H 96 | 97 | if (data[2] & 0x08) bolt[1] |= 0x01; // R 98 | if (data[0] & 0x01) bolt[1] |= 0x02; // A 99 | if (data[0] & 0x02) bolt[1] |= 0x04; // O 100 | if (data[4] & 0x10) bolt[1] |= 0x08; // * 101 | if (data[2] & 0x10) bolt[1] |= 0x08; // * 102 | if (data[0] & 0x08) bolt[1] |= 0x10; // E 103 | if (data[0] & 0x10) bolt[1] |= 0x20; // U 104 | 105 | if (data[3] & 0x01) bolt[2] |= 0x01; // F 106 | if (data[1] & 0x01) bolt[2] |= 0x02; // R 107 | if (data[3] & 0x02) bolt[2] |= 0x04; // P 108 | if (data[1] & 0x02) bolt[2] |= 0x08; // B 109 | if (data[3] & 0x04) bolt[2] |= 0x10; // L 110 | if (data[1] & 0x04) bolt[2] |= 0x20; // G 111 | 112 | if (data[3] & 0x08) bolt[3] |= 0x01; // T 113 | if (data[1] & 0x08) bolt[3] |= 0x02; // S 114 | if (data[3] & 0x10) bolt[3] |= 0x04; // D 115 | if (data[1] & 0x10) bolt[3] |= 0x08; // Z 116 | if (data[0] & 0x04) bolt[3] |= 0x10; // # 117 | 118 | } 119 | 120 | void sendTX(){ 121 | for(int i=0; i 2 | 3 | /* Tiny interpreter, 4 | similar to myforth's Standalone Interpreter 5 | This example code is in the public domain */ 6 | 7 | /* Structure of a dictionary entry */ 8 | typedef struct { 9 | const char *name; 10 | void (*function)(); 11 | } entry; 12 | 13 | /* Data stack for parameter passing 14 | This "stack" is circular, 15 | like a Green Arrays F18A data stack, 16 | so overflow and underflow are not possible 17 | Number of items must be a power of 2 */ 18 | const int STKSIZE = 8; 19 | const int STKMASK = 7; 20 | int stack[STKSIZE]; 21 | int p = 0; 22 | 23 | /* TOS is Top Of Stack */ 24 | #define TOS stack[p] 25 | /* NAMED creates a string in flash */ 26 | #define NAMED(x, y) PROGMEM const char x[]=y 27 | 28 | /* Terminal Input Buffer for interpreter */ 29 | const byte maxtib = 16; 30 | char tib[maxtib]; 31 | /* buffer required for strings read from flash */ 32 | char namebuf[maxtib]; 33 | byte pos; 34 | 35 | /* push n to top of data stack */ 36 | void push(int n) { 37 | p=(p+1)&STKMASK; 38 | TOS=n; 39 | } 40 | 41 | /* return top of stack */ 42 | int pop() { 43 | int n=TOS; 44 | p=(p-1)&STKMASK; 45 | return n; 46 | } 47 | 48 | /* Global delay timer */ 49 | int spd = 15; 50 | 51 | /* top of stack becomes current spd */ 52 | NAMED(_speed, "speed"); 53 | void speed() { spd=pop();} 54 | 55 | /* discard top of stack */ 56 | NAMED(_drop, "drop"); 57 | void drop() { pop();} 58 | 59 | /* recover dropped stack item */ 60 | NAMED(_back, "back"); 61 | void back() { for(int i=1; i0x7f || buffer[0]<' ') buffer[0]='.'; 210 | buffer[1]='\0'; 211 | Serial.print(buffer); 212 | } 213 | push(p); 214 | } 215 | 216 | /* dump 256 bytes of flash */ 217 | NAMED(_dumps, "d"); 218 | void dumps() { 219 | for(int i=0; i<16; i++) { 220 | Serial.println(); 221 | dumpFLASH(); 222 | } 223 | } 224 | 225 | /* dump 16 bytes of RAM in hex with ascii on the side */ 226 | void dumpRAM() { 227 | char buffer[5]=""; 228 | char *ram; 229 | int p=pop(); 230 | ram = (char*)p; 231 | sprintf(buffer, "%4x", p); 232 | Serial.print(buffer); 233 | Serial.print(" "); 234 | for(int i=0; i<16; i++) { 235 | char c=*ram++; 236 | sprintf(buffer, " %2x", (c&0xff)); 237 | Serial.print(buffer); 238 | } 239 | ram = (char*)p; 240 | Serial.print(" "); 241 | for(int i=0; i<16; i++) { 242 | buffer[0]=*ram++; 243 | if(buffer[0]>0x7f || buffer[0]<' ') buffer[0]='.'; 244 | buffer[1]='\0'; 245 | Serial.print(buffer); 246 | } 247 | push(p+16); 248 | } 249 | 250 | /* dump 256 bytes of RAM */ 251 | NAMED(_dumpr, "r"); 252 | void rdumps() { 253 | for(int i=0; i<16; i++) { 254 | Serial.println(); 255 | dumpRAM(); 256 | } 257 | } 258 | 259 | /* End of Forth interpreter words */ 260 | /* ******************************************** */ 261 | /* Beginning of application words */ 262 | 263 | 264 | 265 | 266 | /* End of application words */ 267 | /* ******************************************** */ 268 | /* Now build the dictionary */ 269 | 270 | /* empty words don't cause an error */ 271 | NAMED(_nop, " "); 272 | void nop() { } 273 | 274 | /* Forward declaration required here */ 275 | NAMED(_words, "words"); 276 | void words(); 277 | 278 | /* table of names and function addresses in flash */ 279 | const entry dictionary[] = { 280 | {_nop, nop}, 281 | {_words, words}, 282 | {_dup, dup}, 283 | {_drop, drop}, 284 | {_back, back}, 285 | {_swap, swap}, 286 | {_over, over}, 287 | {_add, add}, 288 | {_and, and_}, 289 | {_or, or_}, 290 | {_xor, xor_}, 291 | {_invert, invert}, 292 | {_negate, negate}, 293 | {_dotS, dotS}, 294 | {_dotShex, dotShex}, 295 | {_dot, dot}, 296 | {_dotHEX, dotHEX}, 297 | {_delay, del}, 298 | {_high, high}, 299 | {_low, low}, 300 | {_in, in}, 301 | {_input, input}, 302 | {_output, output}, 303 | {_input_pullup, input_pullup}, 304 | {_wiggle, wiggle}, 305 | {_fetchp, fetchp}, 306 | {_dumps, dumps}, 307 | {_dumpr, rdumps}, 308 | {_speed, speed} 309 | }; 310 | 311 | /* Number of words in the dictionary */ 312 | const int entries = sizeof dictionary / sizeof dictionary[0]; 313 | 314 | /* Display all words in dictionary */ 315 | void words() { 316 | for(int i=entries-1; i>=0; i--) { 317 | strcpy_P(namebuf, dictionary[i].name); 318 | Serial.print(namebuf); 319 | Serial.print(" "); 320 | } 321 | } 322 | 323 | /* Find a word in the dictionary, returning its position */ 324 | int locate() { 325 | for(int i=entries; i>=0; i--) { 326 | strcpy_P(namebuf, dictionary[i].name); 327 | if(!strcmp(tib, namebuf)) return i; 328 | } 329 | return 0; 330 | } 331 | 332 | /* Is the word in tib a number? */ 333 | int isNumber() { 334 | char *endptr; 335 | strtol(tib, &endptr, 0); 336 | if(endptr == tib) return 0; 337 | if(*endptr != '\0') return 0; 338 | return 1; 339 | } 340 | 341 | /* Convert number in tib */ 342 | int number() { 343 | char *endptr; 344 | return (int) strtol(tib, &endptr, 0); 345 | } 346 | 347 | char ch; 348 | 349 | void ok() { if(ch == '\r') Serial.println("ok");} 350 | 351 | /* Incrementally read command line from serial port */ 352 | byte reading() { 353 | if (!Serial.available()) return 1; 354 | ch = Serial.read(); 355 | if (ch == '\n') return 1; 356 | if (ch == '\r') return 0; 357 | if (ch == ' ') return 0; 358 | if (pos < maxtib) { 359 | tib[pos++] = ch; 360 | tib[pos] = 0; 361 | } 362 | return 1; 363 | } 364 | 365 | /* Block on reading the command line from serial port */ 366 | /* then echo each word */ 367 | void readword() { 368 | pos = 0; 369 | tib[0]=0; 370 | while(reading()); 371 | Serial.print(tib); 372 | Serial.print(" "); 373 | } 374 | 375 | /* Run a word via its name */ 376 | void runword() { 377 | int place = locate(); 378 | if(place != 0) { 379 | dictionary[place].function(); 380 | ok(); 381 | return; 382 | } 383 | if(isNumber()) { 384 | push(number()); 385 | ok(); 386 | return; 387 | } 388 | Serial.println("?"); 389 | } 390 | 391 | /* Arduino main loop */ 392 | 393 | void setup() { 394 | Serial.begin(115200); 395 | Serial.println("Tiny Interpreter:"); 396 | words(); 397 | Serial.println(); 398 | } 399 | 400 | void loop() { 401 | readword(); 402 | runword(); 403 | } 404 | -------------------------------------------------------------------------------- /TinyMod4.ino: -------------------------------------------------------------------------------- 1 | /* Tiny interpreter, 2 | similar to myforth's Standalone Interpreter 3 | This example code is in the public domain */ 4 | 5 | #include 6 | #include 7 | 8 | #define NO_BOLT 4 9 | byte bolt [NO_BOLT]; 10 | 11 | #define NO_GEMINI 6 12 | byte Gemini [NO_GEMINI]; 13 | 14 | /* Structure of a dictionary entry */ 15 | typedef struct { 16 | const char *name; 17 | void (*function)(); 18 | } entry; 19 | 20 | /* Data stack for parameter passing 21 | This "stack" is circular, 22 | like a Green Arrays F18A data stack, 23 | so overflow and underflow are not possible 24 | Number of items must be a power of 2 */ 25 | const int STKSIZE = 8; 26 | const int STKMASK = 7; 27 | int stack[STKSIZE]; 28 | int p = 0; 29 | 30 | /* TOS is Top Of Stack */ 31 | #define TOS stack[p] 32 | /* NAMED creates a string in flash */ 33 | #define NAMED(x, y) const char x[] PROGMEM = y 34 | 35 | /* Terminal Input Buffer for interpreter */ 36 | const byte maxtib = 16; 37 | char tib[maxtib]; 38 | /* buffer required for strings read from flash */ 39 | char namebuf[maxtib]; 40 | byte pos; 41 | 42 | /* push n to top of data stack */ 43 | void PUSH(int n) { 44 | p = (p + 1)& STKMASK; 45 | TOS = n; 46 | } 47 | 48 | /* return top of stack */ 49 | int POP() { 50 | int n = TOS; 51 | p = (p - 1)& STKMASK; 52 | return n; 53 | } 54 | 55 | /* Global delay timer */ 56 | int spd = 15; 57 | 58 | /* top of stack becomes current spd */ 59 | NAMED(_speed, "speed"); 60 | void speed() { 61 | spd = POP(); 62 | } 63 | 64 | /* discard top of stack */ 65 | NAMED(_drop, "drop"); 66 | void DROP() { 67 | POP(); 68 | } 69 | 70 | /* recover dropped stack item */ 71 | NAMED(_back, "back"); 72 | void BACK() { 73 | for (int i = 1; i < STKSIZE; i++) DROP(); 74 | } 75 | 76 | /* copy top of stack */ 77 | NAMED(_dup, "dup"); 78 | void DUP() { 79 | PUSH(TOS); 80 | } 81 | 82 | /* exchange top two stack items */ 83 | NAMED(_swap, "swap"); 84 | void SWAP() { 85 | int a; 86 | int b; 87 | a = POP(); 88 | b = POP(); 89 | PUSH(a); 90 | PUSH(b); 91 | } 92 | 93 | /* copy second on stack to top */ 94 | NAMED(_over, "over"); 95 | void OVER() { 96 | int a; 97 | int b; 98 | a = POP(); 99 | b = POP(); 100 | PUSH(b); 101 | PUSH(a); 102 | PUSH(b); 103 | } 104 | /* add top two items */ 105 | NAMED(_add, "+"); 106 | void ADD() { 107 | int a = POP(); 108 | TOS = a + TOS; 109 | } 110 | 111 | /* bitwise and top two items */ 112 | NAMED(_and, "and"); 113 | void AND() { 114 | int a = POP(); 115 | TOS = a & TOS; 116 | } 117 | 118 | /* inclusive or top two items */ 119 | NAMED(_or, "or"); 120 | void OR() { 121 | int a = POP(); 122 | TOS = a | TOS; 123 | } 124 | 125 | /* exclusive or top two items */ 126 | NAMED(_xor, "xor"); 127 | void XOR() { 128 | int a = POP(); 129 | TOS = a ^ TOS; 130 | } 131 | 132 | /* invert all bits in top of stack */ 133 | NAMED(_invert, "invert"); 134 | void INVERT() { 135 | TOS = ~(TOS); 136 | } 137 | 138 | /* negate top of stack */ 139 | NAMED(_negate, "negate"); 140 | void NEGATE() { 141 | TOS = -(TOS); 142 | } 143 | 144 | /* destructively display top of stack, decimal */ 145 | NAMED(_dot, "."); 146 | void dot() { 147 | Serial.print(POP()); 148 | Serial.print(F(" ")); 149 | } 150 | 151 | /* destructively display top of stack, hex */ 152 | NAMED(_dotHEX, ".h"); 153 | void dotHEX() { 154 | Serial.print(0xffff & POP(), HEX); 155 | Serial.print(" "); 156 | } 157 | 158 | /* display whole stack, hex */ 159 | NAMED(_dotShex, ".sh"); 160 | void dotShex() { 161 | for (int i = 0; i < STKSIZE; i++){ 162 | BACK(); dotHEX(); BACK(); 163 | } 164 | } 165 | 166 | /* display whole stack, decimal */ 167 | NAMED(_dotS, ".s"); 168 | void dotS() { 169 | for (int i = 0; i < STKSIZE; i++){ 170 | BACK(); dot(); BACK(); 171 | } 172 | } 173 | 174 | /* delay TOS # of milliseconds */ 175 | NAMED(_delay, "ms"); 176 | void MS() { 177 | delay(POP()); 178 | } 179 | 180 | /* Toggle pin at TOS and delay(spd), repeat... */ 181 | NAMED(_wiggle, "wiggle"); 182 | void wiggle() { 183 | int a = POP(); 184 | pinMode(a, OUTPUT); 185 | for (int i = 0; i < 20; i++) { 186 | digitalWrite(a, HIGH); 187 | delay(100); 188 | digitalWrite(a, LOW); 189 | delay(100); 190 | } 191 | } 192 | 193 | /* TOS is pin number, set it HIGH */ 194 | NAMED(_high, "high"); 195 | void high() { 196 | digitalWrite(POP(), HIGH); 197 | } 198 | 199 | /* set TOS pin LOW */ 200 | NAMED(_low, "low"); 201 | void low() { 202 | digitalWrite(POP(), LOW); 203 | } 204 | 205 | /* read TOS pin */ 206 | NAMED(_in, "in"); 207 | void in() { 208 | TOS = digitalRead(TOS); 209 | } 210 | 211 | /* make TOS pin an input */ 212 | NAMED(_input, "input"); 213 | void input() { 214 | pinMode(POP(), INPUT); 215 | } 216 | 217 | /* make TOS pin an output */ 218 | NAMED(_output, "output"); 219 | void output() { 220 | pinMode(POP(), OUTPUT); 221 | } 222 | 223 | /* make TOS pin an input with weak pullup */ 224 | NAMED(_input_pullup, "input_pullup"); 225 | void input_pullup() { 226 | pinMode(POP(), INPUT_PULLUP); 227 | } 228 | 229 | /* dump 16 bytes of RAM in hex with ascii on the side */ 230 | void dumpRAM() { 231 | char buffer[5] = ""; 232 | char *ram; 233 | int p = POP(); 234 | ram = (char*)p; 235 | sprintf(buffer, "%4x", p); 236 | Serial.print(buffer); 237 | Serial.print(F(" ")); 238 | for (int i = 0; i < 16; i++) { 239 | char c = *ram++; 240 | sprintf(buffer, " %2x", (c & 0xff)); 241 | Serial.print(buffer); 242 | } 243 | ram = (char*)p; 244 | Serial.print(F(" ")); 245 | for (int i = 0; i < 16; i++) { 246 | buffer[0] = *ram++; 247 | if (buffer[0] > 0x7f || buffer[0] < ' ') buffer[0] = '.'; 248 | buffer[1] = '\0'; 249 | Serial.print(buffer); 250 | } 251 | PUSH(p + 16); 252 | } 253 | 254 | /* dump 256 bytes of RAM */ 255 | NAMED(_dumpr, "dump"); 256 | void rdumps() { 257 | for (int i = 0; i < 16; i++) { 258 | Serial.println(); 259 | dumpRAM(); 260 | } 261 | } 262 | 263 | /* End of Forth interpreter words */ 264 | /* ******************************************** */ 265 | /* Beginning of application words */ 266 | 267 | // the slider switch 268 | #define PROTOCOL 7 269 | 270 | NAMED(_init, "init"); 271 | void INIT() { 272 | // init the raw pins 273 | pinMode(7, INPUT_PULLUP); 274 | pinMode(9, INPUT_PULLUP); 275 | pinMode(10, INPUT_PULLUP); 276 | pinMode(11, INPUT_PULLUP); 277 | pinMode(12, INPUT_PULLUP); 278 | pinMode(A1, INPUT_PULLUP); 279 | pinMode(A2, INPUT_PULLUP); 280 | pinMode(A3, INPUT_PULLUP); 281 | pinMode(A4, INPUT_PULLUP); 282 | pinMode(A5, INPUT_PULLUP); 283 | // init the port expander pins 284 | Wire.begin (); 285 | Wire.beginTransmission (0x20); 286 | Wire.write (0x0c); // GPPUA 287 | Wire.write (0xff); 288 | Wire.write (0xff); 289 | Wire.endTransmission (); 290 | } 291 | 292 | NAMED(_key, "key"); 293 | void KEY() { 294 | PUSH (digitalRead(POP())); 295 | } 296 | 297 | NAMED(_readraw, "rawkeys"); 298 | void read_raw_keys () { 299 | int a = 0; 300 | a |= digitalRead (9); // 1 301 | a |= (digitalRead (10) << 1); // 2 302 | a |= (digitalRead (11) << 2); // 4 303 | a |= (digitalRead (12) << 3); // 8 304 | a |= (digitalRead (A1) << 4); // 10 305 | a |= (digitalRead (A2) << 5); // 20 306 | a |= (digitalRead (A3) << 6); // 40 307 | a |= (digitalRead (A4) << 7); // 80 308 | a |= (digitalRead (A5) << 8); // 100 309 | a ^= 0x01ff; 310 | PUSH (a); 311 | } 312 | 313 | NAMED(_readAB, "readAB"); 314 | void read_AB () { 315 | Wire.beginTransmission (0x20); 316 | Wire.write (0x12); // GPIOA 317 | Wire.endTransmission (); 318 | Wire.requestFrom (0x20, 2); 319 | int a = Wire.read (); 320 | int b = Wire.read (); 321 | a |= b << 8; 322 | a ^= 0xffff; 323 | PUSH (a); 324 | } 325 | 326 | boolean pressed = false; 327 | 328 | NAMED(_readall, "readall"); 329 | void read_all () { 330 | int a = 0; 331 | pressed = true; 332 | read_raw_keys (); 333 | read_AB (); 334 | OVER (); OVER (); OR (); 335 | a = POP (); 336 | if (a == 0) pressed = false; 337 | } 338 | 339 | NAMED(_scan, "scan"); 340 | void scan () { 341 | int a = 0; int b = 0; 342 | do { 343 | do { 344 | read_all (); 345 | } while (!pressed); 346 | delay (30); 347 | read_all (); 348 | } while (!pressed); 349 | a = 0; b = 0; 350 | do { 351 | read_all (); 352 | b |= POP (); 353 | a |= POP (); 354 | } while (pressed); 355 | PUSH (a); PUSH (b); 356 | } 357 | 358 | NAMED(_test, "test"); 359 | void test () { 360 | while (true) { 361 | scan (); dotShex (); Serial.println (); 362 | } 363 | } 364 | 365 | boolean first = true; 366 | 367 | void spit (char a) { 368 | Keyboard.press (a); delay (2); 369 | if (first == true) { 370 | first = false; 371 | } else { 372 | Keyboard.release (a); 373 | } 374 | } 375 | 376 | void send_NKRO () { 377 | int b = POP (); 378 | int a = POP (); 379 | first = true; 380 | 381 | if (a & 0x10) spit ('q'); 382 | if (a & 0x20) spit ('w'); 383 | if (a & 0x40) spit ('e'); 384 | if (a & 0x80) spit ('r'); 385 | if (a & 0x100) spit ('t'); 386 | 387 | if (b & 0x8000) spit ('u'); 388 | if (b & 0x4000) spit ('i'); 389 | if (b & 0x2000) spit ('o'); 390 | if (b & 0x1000) spit ('p'); 391 | if (b & 0x100) spit ('['); 392 | 393 | if (a & 0x08) spit ('a'); 394 | if (a & 0x04) spit ('s'); 395 | if (a & 0x02) spit ('d'); 396 | if (a & 0x01) spit ('f'); 397 | if (b & 0x200) spit ('g'); 398 | 399 | if (b & 0x01) spit ('j'); 400 | if (b & 0x02) spit ('k'); 401 | if (b & 0x04) spit ('l'); 402 | if (b & 0x800) spit (';'); 403 | if (b & 0x400) spit ('\''); 404 | 405 | if (b & 0x08) spit ('c'); 406 | if (b & 0x10) spit ('v'); 407 | if (b & 0x20) spit ('3'); 408 | if (b & 0x40) spit ('n'); 409 | if (b & 0x80) spit ('m'); 410 | 411 | Keyboard.releaseAll (); 412 | } 413 | 414 | void spout (int a, char b) { 415 | if (a) { 416 | Keyboard.press (b); 417 | } else { 418 | Keyboard.press (' '); 419 | } 420 | delay (2); 421 | Keyboard.releaseAll (); 422 | } 423 | 424 | void send_AtoZ () { 425 | int b = POP (); 426 | int a = POP (); 427 | 428 | spout ((b & 0x20), '#'); 429 | 430 | spout ((a & 0x18), 'S'); 431 | spout ((a & 0x20), 'T'); 432 | spout ((a & 0x04), 'K'); 433 | spout ((a & 0x40), 'P'); 434 | spout ((a & 0x02), 'W'); 435 | spout ((a & 0x80), 'H'); 436 | spout ((a & 0x01), 'R'); 437 | spout ((b & 0x08), 'A'); 438 | spout ((b & 0x10), 'O'); 439 | spout (((a & 0x100) | (b & 0x200)), '*'); 440 | spout ((b & 0x40), 'E'); 441 | spout ((b & 0x80), 'U'); 442 | spout ((b & 0x8000), 'F'); 443 | spout ((b & 0x01), 'R'); 444 | spout ((b & 0x4000), 'P'); 445 | spout ((b & 0x02), 'B'); 446 | spout ((b & 0x2000), 'L'); 447 | spout ((b & 0x04), 'G'); 448 | spout ((b & 0x1000), 'T'); 449 | spout ((b & 0x800), 'S'); 450 | spout ((b & 0x100), 'D'); 451 | spout ((b & 0x400), 'Z'); 452 | } 453 | 454 | void init_NKRO () { 455 | Keyboard.begin (); delay (3000); 456 | } 457 | 458 | void NKRO () { 459 | init_NKRO (); 460 | while (1) { 461 | scan (); 462 | send_NKRO (); 463 | } 464 | } 465 | 466 | void AtoZ () { 467 | init_NKRO (); 468 | while (1) { 469 | scan (); 470 | send_AtoZ (); 471 | Keyboard.press ('\n'); 472 | delay (5); 473 | Keyboard.release ('\n'); 474 | } 475 | } 476 | 477 | // Gemini PR protocol 478 | void sendPR(){ 479 | for (byte i = 0; i < NO_GEMINI; i++) { 480 | Gemini[i] = (0); 481 | } 482 | int b = POP (); 483 | int a = POP (); 484 | 485 | Gemini[0] = 0x80; // first byte in a packet 486 | 487 | if (a & 0x10) Gemini[1] |= 0x40; // S1 488 | if (a & 0x08) Gemini[1] |= 0x20; // S2 489 | if (a & 0x20) Gemini[1] |= 0x10; // T 490 | if (a & 0x04) Gemini[1] |= 0x08; // K 491 | if (a & 0x40) Gemini[1] |= 0x04; // P 492 | if (a & 0x02) Gemini[1] |= 0x02; // W 493 | if (a & 0x80) Gemini[1] |= 0x01; // H 494 | 495 | if (a & 0x01) Gemini[2] |= 0x40; // R 496 | if (b & 0x08) Gemini[2] |= 0x20; // A 497 | if (b & 0x10) Gemini[2] |= 0x10; // O 498 | if (a & 0x100) Gemini[2] |= 0x08; // * 499 | if (b & 0x200) Gemini[2] |= 0x04; // * 500 | 501 | if (b & 0x40) Gemini[3] |= 0x08; // E 502 | if (b & 0x80) Gemini[3] |= 0x04; // U 503 | if (b & 0x8000) Gemini[3] |= 0x02; // F 504 | if (b & 0x01) Gemini[3] |= 0x01; // R 505 | 506 | if (b & 0x4000) Gemini[4] |= 0x40; // P 507 | if (b & 0x02) Gemini[4] |= 0x20; // B 508 | if (b & 0x2000) Gemini[4] |= 0x10; // L 509 | if (b & 0x04) Gemini[4] |= 0x08; // G 510 | if (b & 0x1000) Gemini[4] |= 0x04; // T 511 | if (b & 0x800) Gemini[4] |= 0x02; // S 512 | if (b & 0x100) Gemini[4] |= 0x01; // D 513 | 514 | if (b & 0x20) Gemini[5] |= 0x40; // #7 515 | if (b & 0x400) Gemini[5] |= 0x01; // Z 516 | 517 | for(int i=0; i= 0; i--) { 644 | strcpy_P(namebuf, dictionary[i].name); 645 | Serial.print(namebuf); 646 | Serial.print(F(" ")); 647 | if ((i % 5) == 0) Serial.println(); 648 | } 649 | } 650 | 651 | /* Find a word in the dictionary, returning its position */ 652 | int locate() { 653 | for (int i = entries - 1; i >= 0; i--) { 654 | strcpy_P(namebuf, dictionary[i].name); 655 | if(strcmp(tib, namebuf) == 0) return i; 656 | } 657 | return 0; 658 | } 659 | 660 | /* Is the word in tib a number? */ 661 | int isNumber() { 662 | char *endptr; 663 | strtol(tib, &endptr, 0); 664 | if (endptr == tib) return 0; 665 | if (*endptr != '\0') return 0; 666 | return 1; 667 | } 668 | 669 | /* Convert number in tib */ 670 | int number() { 671 | char *endptr; 672 | return (int) strtol(tib, &endptr, 0); 673 | } 674 | 675 | char ch; 676 | 677 | void ok() { 678 | if (ch == '\r') Serial.println(F("ok")); 679 | } 680 | 681 | /* Incrementally read command line from serial port */ 682 | byte reading() { 683 | if (!Serial.available()) return 1; 684 | ch = Serial.read(); 685 | if (ch == '\n') return 1; 686 | if (ch == '\r') return 0; 687 | if (ch == ' ') return 0; 688 | if (pos < maxtib) { 689 | tib[pos++] = ch; 690 | tib[pos] = 0; 691 | } 692 | return 1; 693 | } 694 | 695 | /* Block on reading the command line from serial port */ 696 | /* then echo each word */ 697 | void readword() { 698 | pos = 0; 699 | tib[0] = 0; 700 | while (reading()); 701 | Serial.print(tib); 702 | Serial.print(F(" ")); 703 | } 704 | 705 | /* Run a word via its name */ 706 | void runword() { 707 | int place = locate(); 708 | if (place != 0) { 709 | dictionary[place].function(); 710 | ok(); 711 | return; 712 | } 713 | if (isNumber()) { 714 | PUSH(number()); 715 | ok(); 716 | return; 717 | } 718 | Serial.println(F("?")); 719 | } 720 | 721 | void init_interpreter () { 722 | Serial.begin(9600); delay (3000); 723 | while(!Serial); 724 | Serial.println(F("Forth-like interpreter:")); 725 | WORDS(); 726 | Serial.println(); 727 | } 728 | 729 | void interpret () { 730 | init_interpreter (); 731 | while (1) { 732 | readword (); 733 | runword (); 734 | } 735 | } 736 | 737 | 738 | /* Arduino main loop */ 739 | 740 | void setup() { 741 | INIT(); 742 | if (digitalRead (PROTOCOL)) { 743 | // start_TX (); 744 | start_PR (); 745 | } else { 746 | NKRO (); 747 | // start_PR (); 748 | // AtoZ (); 749 | } 750 | } 751 | 752 | // not using "loop", but Arduino IDE wants it to exist 753 | void loop() { 754 | while (true); 755 | } 756 | -------------------------------------------------------------------------------- /M0-Forth.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Forth virtual machine 3 | 4 | This code is in the public domain. 5 | 6 | */ 7 | 8 | #define RAM_SIZE 0x1000 9 | #define S0 0x1000 10 | #define R0 0x0f00 11 | #define M(a, b) {memory [a] = b;} 12 | #define NAME(m, f, c, x, y, z) {memory [m] = f + c + (x << 8) + (y << 16) + (z << 24);} 13 | #define LINK(m, a) {memory [m] = a;} 14 | #define CODE(m, a) {memory [m] = a;} 15 | 16 | // global variables 17 | int memory[RAM_SIZE]; // RAM is 32 bit word-addressed 18 | String tib = ""; 19 | int S = S0; // data stack pointer 20 | int R = R0; // return stack pointer 21 | int I = 0; // instruction pointer 22 | int W = 0; // working register 23 | int T = 0; // top of stack 24 | int H = 0; // dictionary pointer, HERE 25 | int D = 0; // dictionary list entry point 26 | int base = 10; 27 | 28 | /* A word in the dictionary has these fields: 29 | link 32b point to next word in list, 0 says end of list 30 | name 32b a 32 bit int, made up of byte count and three letters 31 | code 32b the 32 bit token to be compiled, 32 | negative if it's a primitive, (inverted) 33 | positive address if it's a colon definition 34 | data 32b at least a list to execute or a data field of some kind 35 | 36 | when compiling the code value is compiled, unless this is an 37 | immediate word, in which case the word is executed 38 | a bit in the the count field should be the immediate bit 39 | and another bit will be the primitive bit 40 | */ 41 | 42 | // function prototypes for the primitives 43 | void _lit (void); 44 | void _exit (void); 45 | void _branch (void); 46 | void _0branch (void); 47 | void _key (void); 48 | void _emit (void); 49 | void _dup (void); 50 | void _drop (void); 51 | void _swap (void); 52 | void _over (void); 53 | void _fetch (void); 54 | void _store (void); 55 | void _comma (void); 56 | void _plus (void); 57 | void _minus (void); 58 | void _and (void); 59 | void _or (void); 60 | void _xor (void); 61 | void _invert (void); 62 | void _abs (void); 63 | void _negate (void); 64 | void _twostar (void); 65 | void _twoslash (void); 66 | void _times (void); 67 | void _divide (void); 68 | void _mod (void); 69 | void _starslash (void); 70 | void _dot (void); 71 | void _dotS (void); 72 | void _cr (void); 73 | void _space (void); 74 | void _zeroequal (void); 75 | void _zeroless (void); 76 | void _words (void); 77 | void _find (void); 78 | void _execute (void); 79 | void _word (void); 80 | void _hdot (void); 81 | void _qdup (void); 82 | void _initS (void); 83 | void _initR (void); 84 | void _ok (void); 85 | void _dnum (void); 86 | void _hnum (void); 87 | void _dump (void); 88 | void _dotsh (void); 89 | void _head (void); 90 | void _here (void); 91 | void _dovar (void); 92 | void _create (void); 93 | void _allot (void); 94 | void _do (void); 95 | void _loop (void); 96 | void _i (void); 97 | void _parse (void); 98 | void _showtib (void); 99 | void _number (void); 100 | void _constant (void); 101 | void _doconst (void); 102 | void _nop (void); 103 | 104 | // primitive function array 105 | void (*primitive []) (void) = { 106 | _lit, 107 | #define _LIT ~0 108 | _exit, 109 | #define _EXIT ~1 110 | _branch, 111 | #define _BRANCH ~2 112 | _0branch, 113 | #define _0BRANCH ~3 114 | _key, 115 | #define _KEY ~4 116 | _emit, 117 | #define _EMIT ~5 118 | _dup, 119 | #define _DUP ~6 120 | _drop, 121 | #define _DROP ~7 122 | _swap, 123 | #define _SWAP ~8 124 | _over, 125 | #define _OVER ~9 126 | _fetch, 127 | #define _FETCH ~10 128 | _store, 129 | #define _STORE ~11 130 | _comma, 131 | #define _COMMA ~12 132 | _plus, 133 | #define _PLUS ~13 134 | _minus, 135 | #define _MINUS ~14 136 | _and, 137 | #define _AND ~15 138 | _or, 139 | #define _OR ~16 140 | _xor, 141 | #define _XOR ~17 142 | _invert, 143 | #define _INVERT ~18 144 | _abs, 145 | #define _ABS ~19 146 | _negate, 147 | #define _NEGATE ~20 148 | _twostar, 149 | #define _TWOSTAR ~21 150 | _twoslash, 151 | #define _TWOSLASH ~22 152 | _times, 153 | #define _TIMES ~23 154 | _divide, 155 | #define _DIVIDE ~24 156 | _mod, 157 | #define _MOD ~25 158 | _starslash, 159 | #define _STARSLASH ~26 160 | _dot, 161 | #define _DOT ~27 162 | _hdot, 163 | #define _HDOT ~28 164 | _dotS, 165 | #define _DOTS ~29 166 | _cr, 167 | #define _CR ~30 168 | _space, 169 | #define _SPACE ~31 170 | _zeroequal, 171 | #define _ZEROEQUAL ~32 172 | _zeroless, 173 | #define _ZEROLESS ~33 174 | _words, 175 | #define _WORDS ~34 176 | _find, 177 | #define _FIND ~35 178 | _execute, 179 | #define _EXECUTE ~36 180 | _word, 181 | #define _WORD ~37 182 | _qdup, 183 | #define _QDUP ~38 184 | _initS, 185 | #define _INITS ~39 186 | _initR, 187 | #define _INITR ~40 188 | _ok, 189 | #define _OK ~41 190 | _dnum, 191 | #define _DNUM ~42 192 | _hnum, 193 | #define _HNUM ~43 194 | _dump, 195 | #define _DUMP ~44 196 | _dotsh, 197 | #define _DOTSH ~45 198 | _head, 199 | #define _HEAD ~46 200 | _here, 201 | #define _HERE ~47 202 | _dovar, 203 | #define _DOVAR ~48 204 | _create, 205 | #define _CREATE ~49 206 | _allot, 207 | #define _ALLOT ~50 208 | _do, 209 | #define _DO ~51 210 | _loop, 211 | #define _LOOP ~52 212 | _i, 213 | #define _I ~53 214 | _parse, 215 | #define _PARSE ~54 216 | _showtib, 217 | #define _SHOWTIB ~55 218 | _number, 219 | #define _NUMBER ~56 220 | _constant, 221 | #define _CONSTANT ~57 222 | _doconst, 223 | #define _DOCONST ~58 224 | _nop 225 | #define _NOP ~59 226 | }; 227 | 228 | // primitive definitions 229 | 230 | void _lit (void) { 231 | memory [--S] = memory [I++]; 232 | } 233 | 234 | void _exit (void) { 235 | I = memory [R++]; 236 | } 237 | 238 | void _branch (void) { 239 | I = memory [I]; 240 | } 241 | 242 | void _0branch (void) { 243 | T = memory [S++]; 244 | if (T == 0) { 245 | I = memory [I]; 246 | return; 247 | } 248 | I += 1; 249 | } 250 | 251 | void _key (void) { 252 | while (!Serial.available ()) ; 253 | T = Serial.read (); 254 | memory [--S] = T; 255 | } 256 | 257 | void _emit (void) { 258 | char c = memory [S++]; 259 | Serial.write (c); 260 | } 261 | 262 | void _dup (void) { 263 | T = memory [S--]; 264 | memory [S] = T; 265 | } 266 | 267 | void _drop (void) { 268 | S += 1; 269 | } 270 | 271 | void _swap (void) { 272 | T = memory [S++]; 273 | W = memory [S]; 274 | memory [S--] = T; 275 | memory [S] = W; 276 | } 277 | 278 | void _over (void) { 279 | T = memory [S++]; 280 | W = memory [S]; 281 | memory [--S] = T; 282 | memory [--S] = W; 283 | } 284 | 285 | void _fetch (void) { 286 | W = memory [S]; 287 | T = memory [W]; 288 | memory [S] = T; 289 | } 290 | 291 | void _store (void) { 292 | T = memory [S++]; 293 | W = memory [S++]; 294 | memory [T] = W; 295 | } 296 | 297 | void _comma (void) { 298 | T = memory [S++]; 299 | memory [H++] = T; 300 | } 301 | 302 | void _plus (void) { 303 | T = memory [S++]; 304 | T = T + memory [S]; 305 | memory [S] = T; 306 | } 307 | 308 | void _minus (void) { 309 | T = memory [S++]; 310 | W = memory [S] - T; 311 | memory [S] = W; 312 | } 313 | 314 | void _and (void) { 315 | T = memory [S++]; 316 | W = T & memory [S]; 317 | memory [S] = W; 318 | } 319 | 320 | void _or (void) { 321 | T = memory [S++]; 322 | W = T | memory [S]; 323 | memory [S] = W; 324 | } 325 | void _xor (void) { 326 | T = memory [S++]; 327 | W = T ^ memory [S]; 328 | memory [S] = W; 329 | } 330 | 331 | void _invert (void) { 332 | T = memory [S]; 333 | memory [S] = ~T; 334 | } 335 | 336 | void _abs (void) { 337 | T = memory [S]; 338 | memory [S] = abs (T); 339 | } 340 | 341 | void _negate (void) { 342 | T = memory [S]; 343 | memory [S] = -T; 344 | } 345 | 346 | void _twostar (void) { 347 | T = memory [S]; 348 | memory [S] = (T * 2); 349 | } 350 | 351 | void _twoslash (void) { 352 | T = memory [S]; 353 | memory [S] = (T / 2); 354 | } 355 | 356 | void _times (void) { 357 | T = memory [S++]; 358 | W = memory [S]; 359 | memory [S] = (T * W); 360 | } 361 | 362 | void _divide (void) { 363 | T = memory [S++]; 364 | W = memory [S]; 365 | memory [S] = (W / T); 366 | } 367 | 368 | void _mod (void) { 369 | T = memory [S++]; 370 | W = memory [S]; 371 | memory [S] = (W % T); 372 | } 373 | 374 | void _starslash (void) { 375 | // requires double int 376 | } 377 | 378 | void _zeroequal (void) { 379 | T = memory [S]; 380 | if (T == 0) { 381 | memory [S] = -1; 382 | } else { 383 | memory [S] = 0; 384 | } 385 | } 386 | 387 | void _zeroless (void) { 388 | T = memory [S]; 389 | if (T < 0) { 390 | memory [S] = -1; 391 | } else { 392 | memory [S] = 0; 393 | } 394 | } 395 | 396 | void _qdup (void) { 397 | T = memory [S]; 398 | if (T == 0) return; 399 | memory [--S] = T; 400 | } 401 | 402 | void _dot (void) { 403 | T = memory [S++]; 404 | Serial.print (T); 405 | Serial.write (' '); 406 | } 407 | 408 | void _hdot (void) { 409 | T = memory [S++]; 410 | Serial.print (T, HEX); 411 | Serial.write (' '); 412 | } 413 | 414 | void _dotS (void) { 415 | if (S == S0) { 416 | Serial.print ("empty "); 417 | return; 418 | } 419 | W = S0; 420 | while (W > S) { 421 | Serial.print (memory [--W]); 422 | Serial.write (' '); 423 | } 424 | } 425 | 426 | void _dotsh (void) { 427 | if (S == S0) { 428 | Serial.print ("empty "); 429 | return; 430 | } 431 | W = S0; 432 | while (W > S) { 433 | Serial.print (memory [--W], HEX); 434 | Serial.write (' '); 435 | } 436 | } 437 | 438 | void _cr (void) { 439 | Serial.println (" "); 440 | } 441 | 442 | void _space (void) { 443 | Serial.write (' '); 444 | } 445 | 446 | void _words (void) { 447 | int C = 0; 448 | int X = 0; 449 | W = D; 450 | while (W) { 451 | T = memory [W]; 452 | C = (T & 0xff); 453 | X = ((T >> 8) & 0xff); 454 | memory [--S] = X; 455 | _emit (); 456 | X = ((T >> 16) & 0xff); 457 | memory [--S] = X; 458 | if (X != ' ') _emit (); 459 | X = ((T >> 24) & 0xff); 460 | memory [--S] = X; 461 | if (X != ' ') _emit (); 462 | C -= 4; 463 | while (!(C < 0)) { 464 | Serial.print ("_"); 465 | C -= 1; 466 | } 467 | _space (); 468 | W = memory [++W]; 469 | } 470 | _cr (); 471 | } 472 | 473 | void _find (void) { 474 | int X = memory [S++]; 475 | W = D; 476 | while (W != 0) { 477 | T = (memory [W]); 478 | if (T == X) { 479 | memory [--S] = W; 480 | return; 481 | } 482 | W = memory [++W]; 483 | } 484 | memory [--S] = 0; 485 | } 486 | 487 | void _execute (void) { 488 | T = memory [S++]; 489 | memory [--R] = I; 490 | I = (T + 2); 491 | } 492 | 493 | void _initS (void) { 494 | S = S0; 495 | } 496 | 497 | void _initR (void) { 498 | R = R0; 499 | } 500 | 501 | void _ok (void) { 502 | if (tib [tib.length () - 1] == 10) Serial.println (" Ok"); 503 | } 504 | 505 | void _dnum (void) { 506 | boolean sign = false; 507 | W = 0; 508 | while (1) { 509 | T = 0; 510 | while (Serial.available () == 0); 511 | T = Serial.read (); 512 | if (T <= ' ') { 513 | if (sign == true) W = -W; 514 | memory [--S] = W; 515 | return; 516 | } 517 | if (T == '-') { 518 | sign = true; 519 | } else { 520 | W *= 10; 521 | T -= '0'; 522 | W = (T + W); 523 | } 524 | } 525 | } 526 | 527 | void _hnum (void) { 528 | W = 0; 529 | while (1) { 530 | T = 0; 531 | while (Serial.available () == 0); 532 | T = Serial.read (); 533 | if (T <= ' ') { 534 | memory [--S] = W; 535 | return; 536 | } 537 | W *= 16; 538 | T -= '0'; 539 | if (T > 9) T -= 7; 540 | W = (T + W); 541 | } 542 | } 543 | 544 | void _dump (void) { 545 | W = memory [S++]; 546 | Serial.print (W, HEX); 547 | _space (); _space (); 548 | for (int a = 0; a < 8; a++) { 549 | T = memory [W++]; 550 | Serial.print (T, HEX); 551 | _space (); 552 | } 553 | memory [--S] = W; 554 | } 555 | 556 | void _head (void) { 557 | _parse (); 558 | _word (); 559 | _comma (); 560 | memory [--S] = D; 561 | _comma (); 562 | D = H - 2; 563 | } 564 | 565 | void _here (void) { 566 | memory [--S] = H; 567 | } 568 | 569 | void _dovar (void) { 570 | memory [--S] = I; 571 | _exit (); 572 | } 573 | 574 | void _create (void) { 575 | _head (); 576 | memory [--S] = _DOVAR; 577 | _comma (); 578 | } 579 | 580 | void _doconst (void) { 581 | T = memory [I]; 582 | memory [--S] = T; 583 | _exit (); 584 | } 585 | 586 | void _constant (void) { 587 | _head (); 588 | memory [--S] = _DOCONST; 589 | _comma (); 590 | _comma (); 591 | } 592 | 593 | void _allot (void) { 594 | T = memory [S++]; 595 | H += T; 596 | } 597 | 598 | void _do (void) { 599 | T = memory [S++]; 600 | memory [--R] = T; 601 | T = memory [S++]; 602 | memory [--R] = T; 603 | } 604 | 605 | void _loop (void) { 606 | T = memory [R++]; 607 | W = memory [R++]; 608 | W += 1; 609 | if (W == T) { 610 | I += 1; 611 | return; 612 | } 613 | memory [--R] = W; 614 | memory [--R] = T; 615 | I = memory [I]; 616 | } 617 | 618 | void _i (void) { 619 | W = memory [R + 1]; 620 | memory [--S] = W; 621 | } 622 | 623 | // trim leading spaces 624 | void _parse (void) { 625 | char t; 626 | tib = ""; 627 | do { 628 | while (!Serial.available ()); 629 | t = Serial.peek (); 630 | if (t == ' ') t = Serial.read (); 631 | } while (t == ' '); 632 | do { 633 | while (!Serial.available ()); 634 | t = Serial.read (); 635 | tib = tib + t; 636 | } while (t > ' '); 637 | } 638 | 639 | void _showtib (void) { 640 | T = tib.length (); 641 | tib [T - 1] = 0; 642 | Serial.print (tib); 643 | } 644 | 645 | void _word (void) { 646 | char t; 647 | T = (tib.length () - 1); 648 | W = T; 649 | t = tib [0]; 650 | W |= (t << 8); 651 | if (T > 1) { 652 | t = tib [1]; 653 | W |= (t << 16); 654 | } 655 | if (T > 2) { 656 | t = tib [2]; 657 | W |= (t << 24); 658 | } 659 | memory [--S] = W; 660 | } 661 | 662 | void _number (void) { 663 | char t; 664 | T = 0; 665 | for (int i = 0; i < (tib.length () - 1); i++) { 666 | if (i == 0) { 667 | if (tib [i] == '-') continue; 668 | } 669 | t = tib [i]; 670 | if (!isDigit (t)) { 671 | if (tib [0] == '-') T = ~T; 672 | memory [--S] = T; 673 | memory [--S] = -1; 674 | return; 675 | } 676 | T *= base; 677 | t -= '0'; 678 | if (t > 9) t -= 37; 679 | T += t; 680 | } 681 | if (tib [0] == '-') T = -T; 682 | memory [--S] = T; 683 | memory [--S] = 0; 684 | } 685 | 686 | void _nop (void) { 687 | return; 688 | } 689 | 690 | // the setup function runs once when you press reset or power the board 691 | // This will setup stacks and other pointers, initial machine state 692 | // and the initial dictionary 693 | void setup() { 694 | S = S0; // initialize data stack 695 | R = R0; // initialize return stack 696 | // initialize dictionary 697 | 698 | // trailing space kludge 699 | NAME(6, 0, 0, 10, 0, 0) 700 | LINK(7, 0) 701 | CODE(8, _NOP) 702 | CODE(9, _EXIT) 703 | 704 | // exit 705 | NAME(10, 0, 4, 'e', 'x', 'i') 706 | LINK(11, 6) 707 | CODE(12, _EXIT) 708 | // key 709 | NAME(13, 0, 3, 'k', 'e', 'y') 710 | LINK(14, 10) 711 | CODE(15, _KEY) 712 | CODE(16, _EXIT) 713 | // emit 714 | NAME(17, 0, 4, 'e', 'm', 'i') 715 | LINK(18, 13) 716 | CODE(19, _EMIT) 717 | CODE(20, _EXIT) 718 | // dup 719 | NAME(21, 0, 3, 'd', 'u', 'p') 720 | LINK(22, 17) 721 | CODE(23, _DUP) 722 | CODE(24, _EXIT) 723 | // drop 724 | NAME(25, 0, 4, 'd', 'r', 'o') 725 | LINK(26, 21) 726 | CODE(27, _DROP) 727 | CODE(28, _EXIT) 728 | // swap 729 | NAME(29, 0, 4, 's', 'w', 'a') 730 | LINK(30, 25) 731 | CODE(31, _SWAP) 732 | CODE(32, _EXIT) 733 | // over 734 | NAME(33, 0, 4, 'o', 'v', 'e') 735 | LINK(34, 29) 736 | CODE(35, _OVER) 737 | CODE(36, _EXIT) 738 | // @ 739 | NAME(37, 0, 1, '@', 0, 0) 740 | LINK(38, 33) 741 | CODE(39, _FETCH) 742 | CODE(40, _EXIT) 743 | // ! 744 | NAME(41, 0, 1, '!', 0, 0) 745 | LINK(42, 37) 746 | CODE(43, _STORE) 747 | CODE(44, _EXIT) 748 | // , 749 | NAME(45, 0, 1, ',', 0, 0) 750 | LINK(46, 41) 751 | CODE(47, _COMMA) 752 | CODE(48, _EXIT) 753 | // + 754 | NAME(49, 0, 1, '+', 0, 0) 755 | LINK(50, 45) 756 | CODE(51, _PLUS) 757 | CODE(52, _EXIT) 758 | // - 759 | NAME(53, 0, 1, '-', 0, 0) 760 | LINK(54, 49) 761 | CODE(55, _MINUS) 762 | CODE(56, _EXIT) 763 | // and 764 | NAME(57, 0, 3, 'a', 'n', 'd') 765 | LINK(58, 53) 766 | CODE(59, _AND) 767 | CODE(60, _EXIT) 768 | // or 769 | NAME(61, 0, 2, 'o', 'r', 0) 770 | LINK(62, 57) 771 | CODE(63, _OR) 772 | CODE(64, _EXIT) 773 | // xor 774 | NAME(65, 0, 3, 'x', 'o', 'r') 775 | LINK(66, 61) 776 | CODE(67, _XOR) 777 | CODE(68, _EXIT) 778 | // invert 779 | NAME(69, 0, 6, 'i', 'n', 'v') 780 | LINK(70, 65) 781 | CODE(71, _INVERT) 782 | CODE(72, _EXIT) 783 | // abs 784 | NAME(73, 0, 3, 'a', 'b', 's') 785 | LINK(74, 69) 786 | CODE(75, _ABS) 787 | CODE(76, _EXIT) 788 | // negate 789 | NAME(77, 0, 6, 'n', 'e', 'g') 790 | LINK(78, 73) 791 | CODE(79, _NEGATE) 792 | CODE(80, _EXIT) 793 | // 2* 794 | NAME(81, 0, 2, '2', '*', 0) 795 | LINK(82, 77) 796 | CODE(83, _TWOSTAR) 797 | CODE(84, _EXIT) 798 | // 2/ 799 | NAME(85, 0, 2, '2', '/', 0) 800 | LINK(86, 81) 801 | CODE(87, _TWOSLASH) 802 | CODE(88, _EXIT) 803 | // * 804 | NAME(89, 0, 1, '*', 0, 0) 805 | LINK(90, 85) 806 | CODE(91, _TIMES) 807 | CODE(92, _EXIT) 808 | // / 809 | NAME(93, 0, 1, '/', 0, 0) 810 | LINK(94, 89) 811 | CODE(95, _DIVIDE) 812 | CODE(96, _EXIT) 813 | // mod 814 | NAME(97, 0, 3, 'm', 'o', 'd') 815 | LINK(98, 93) 816 | CODE(99, _MOD) 817 | CODE(100, _EXIT) 818 | // */ 819 | NAME(101, 0, 2, '*', '/', 0) 820 | LINK(102, 97) 821 | CODE(103, _STARSLASH) 822 | CODE(104, _EXIT) 823 | // 0= 824 | NAME(105, 0, 2, '0', '=', 0) 825 | LINK(106, 101) 826 | CODE(107, _ZEROEQUAL) 827 | CODE(108, _EXIT) 828 | // 0< 829 | NAME(109, 0, 2, '0', '<', 0) 830 | LINK(110, 105) 831 | CODE(111, _ZEROLESS) 832 | CODE(112, _EXIT) 833 | // space 834 | NAME(113, 0, 5, 's', 'p', 'a') 835 | LINK(114, 109) 836 | CODE(115, _SPACE) 837 | CODE(116, _EXIT) 838 | // cr 839 | NAME(117, 0, 2, 'c', 'r', 0) 840 | LINK(118, 113) 841 | CODE(119, _CR) 842 | CODE(120, _EXIT) 843 | // . 844 | NAME(121, 0, 1, '.', 0, 0) 845 | LINK(122, 117) 846 | CODE(123, _DOT) 847 | CODE(124, _EXIT) 848 | // h. 849 | NAME(125, 0, 2, 'h', '.', 0) 850 | LINK(126, 121) 851 | CODE(127, _HDOT) 852 | CODE(128, _EXIT) 853 | // .s 854 | NAME(129, 0, 2, '.', 's', 0) 855 | LINK(130, 125) 856 | CODE(131, _DOTS) 857 | CODE(132, _EXIT) 858 | // words 859 | NAME(133, 0, 5, 'w', 'o', 'r') 860 | LINK(134, 129) 861 | CODE(135, _WORDS) 862 | CODE(136, _EXIT) 863 | // find 864 | NAME(137, 0, 4, 'f', 'i', 'n') 865 | LINK(138, 133) 866 | CODE(139, _FIND) 867 | CODE(140, _EXIT) 868 | // execute 869 | NAME(141, 0, 7, 'e', 'x', 'e') 870 | LINK(142, 137) 871 | CODE(143, _EXECUTE) 872 | CODE(144, _EXIT) 873 | // word 874 | NAME(145, 0, 4, 'w', 'o', 'r') 875 | LINK(146, 141) 876 | CODE(147, _WORD) 877 | CODE(148, _EXIT) 878 | // ?dup 879 | NAME(149, 0, 4, 'w', 'o', 'r') 880 | LINK(150, 145) 881 | CODE(151, _WORD) 882 | CODE(152, _EXIT) 883 | // d# 884 | NAME(153, 0, 2, 'd', '#', 0) 885 | LINK(154, 149) 886 | CODE(155, _DNUM) 887 | CODE(156, _EXIT) 888 | // h# 889 | NAME(157, 0, 2, 'h', '#', 0) 890 | LINK(158, 153) 891 | CODE(159, _HNUM) 892 | CODE(160, _EXIT) 893 | // dump 894 | NAME(161, 0, 4, 'd', 'u', 'm') 895 | LINK(162, 157) 896 | CODE(163, _DUMP) 897 | CODE(164, _EXIT) 898 | // .sh 899 | NAME(165, 0, 3, '.', 's', 'h') 900 | LINK(166, 161) 901 | CODE(167, _DOTSH) 902 | CODE(168, _EXIT) 903 | // head 904 | NAME(169, 0, 4, 'h', 'e', 'a') 905 | LINK(170, 165) 906 | CODE(171, _HEAD) 907 | CODE(172, _EXIT) 908 | // here 909 | NAME(173, 0, 4, 'h', 'e', 'r') 910 | LINK(174, 169) 911 | CODE(175, _HERE) 912 | CODE(176, _EXIT) 913 | // create 914 | NAME(177, 0, 6, 'c', 'r', 'e') 915 | LINK(178, 173) 916 | CODE(179, _CREATE) 917 | CODE(180, _EXIT) 918 | // allot 919 | NAME(181, 0, 5, 'a', 'l', 'l') 920 | LINK(182, 177) 921 | CODE(183, _ALLOT) 922 | CODE(184, _EXIT) 923 | // quit 924 | NAME(185, 0, 4, 'q', 'u', 'i') 925 | LINK(186, 181) 926 | // begin begin 927 | CODE(187, _INITR) 928 | // begin 929 | CODE(188, _PARSE) 930 | CODE(189, _WORD) 931 | CODE(190, _FIND) 932 | CODE(191, _QDUP) 933 | // while (if) 934 | CODE(192, _0BRANCH) 935 | CODE(193, 198) 936 | CODE(194, _EXECUTE) 937 | CODE(195, _OK) 938 | // repeat 939 | CODE(196, _BRANCH) 940 | CODE(197, 188) 941 | // (then) 942 | CODE(198, _NUMBER) 943 | CODE(199, _0BRANCH) 944 | CODE(200, 195) 945 | CODE(201, _SHOWTIB) 946 | CODE(202, _LIT) 947 | CODE(203, '?') 948 | CODE(204, _EMIT) 949 | CODE(205, _CR) 950 | CODE(206, _INITS) 951 | // again 952 | CODE(207, _BRANCH) 953 | CODE(208, 187) 954 | // abort 955 | NAME(209, 0, 5, 'a', 'b', 'o') 956 | LINK(210, 185) 957 | CODE(211, _INITS) 958 | // again 959 | CODE(212, _BRANCH) 960 | CODE(213, 187) 961 | // constant 962 | NAME(214, 0, 8, 'c', 'o', 'n') 963 | LINK(215, 209) 964 | CODE(216, _CONSTANT) 965 | CODE(217, _EXIT) 966 | 967 | // test 968 | NAME(218, 0, 4, 't', 'e', 's') 969 | LINK(219, 214) 970 | CODE(220, _PARSE) 971 | CODE(221, _WORD) 972 | CODE(222, _HDOT) 973 | // CODE(223, _DOT) 974 | CODE(223, _EXIT) 975 | CODE(224, _EXIT) 976 | 977 | 978 | D = 218; // latest word 979 | H = 225; // top of dictionary 980 | 981 | I = 211; // instruction pointer = abort 982 | 983 | Serial.begin (9600); 984 | while (!Serial); 985 | Serial.println ("myForth Arm"); 986 | // _words (); 987 | } 988 | 989 | // the loop function runs over and over again forever 990 | void loop() { 991 | W = memory [I++]; 992 | if (W < 0) { // primitives are inverted, therefore negative 993 | primitive [~W] (); // execute primitive 994 | } else { // high level words are just addresses 995 | memory [--R] = I; // nest 996 | I = W; // into a high level word 997 | } 998 | // delay (100); 999 | } 1000 | 1001 | -------------------------------------------------------------------------------- /Cortex-Forth.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Forth virtual machine 3 | 4 | This code is in the public domain. 5 | 6 | */ 7 | 8 | #define RAM_SIZE 0x1200 9 | #define S0 0x1000 10 | #define R0 0x0f00 11 | #define NAME(m, f, c, x, y, z) {memory.data [m] = f + c + (x << 8) + (y << 16) + (z << 24);} 12 | #define LINK(m, a) {memory.data [m] = a;} 13 | #define CODE(m, a) {memory.program [m] = a;} 14 | #define DATA(m, a) {memory.data [m] = a;} 15 | #define IMMED 0x80 16 | 17 | // global variables 18 | union Memory { 19 | int data [RAM_SIZE]; 20 | void (*program []) (void); 21 | } memory; 22 | 23 | String tib = ""; 24 | int S = S0; // data stack pointer 25 | int R = R0; // return stack pointer 26 | int I = 0; // instruction pointer 27 | int W = 0; // working register 28 | int T = 0; // top of stack 29 | int H = 0; // dictionary pointer, HERE 30 | int D = 0; // dictionary list entry point 31 | int base = 10; 32 | boolean state = false; // compiling or not 33 | 34 | /* A word in the dictionary has these fields: 35 | name 32b word, a 32 bit int, made up of byte count and three letters 36 | link 32b word, point to next word in list, 0 says end of list 37 | code 32b word, a pointer to some actual C compiled code, 38 | all native code is in this field 39 | data 32b word, at least, a list to execute or a data field of some kind 40 | 41 | 42 | */ 43 | 44 | 45 | // primitive definitions 46 | 47 | void _LBRAC (void) { 48 | state = false; // interpreting 49 | } 50 | 51 | void _RBRAC (void) { 52 | state = true; // compiling 53 | } 54 | 55 | void _NOP (void) { 56 | return; 57 | } 58 | 59 | void _EXIT (void) { 60 | I = memory.data [R++]; 61 | } 62 | 63 | void _DROP (void) { 64 | T = memory.data [S++]; 65 | } 66 | 67 | void _DUP (void) { 68 | memory.data [--S] = T; 69 | } 70 | 71 | void _QDUP (void) { 72 | if (T) _DUP (); 73 | } 74 | 75 | void _KEY (void) { 76 | _DUP (); 77 | while (!Serial.available ()); 78 | T = Serial.read (); 79 | // Serial.write (T); 80 | } 81 | 82 | void _EMIT (void) { 83 | char c = T; 84 | Serial.write (c); 85 | _DROP (); 86 | } 87 | 88 | void _CR (void) { 89 | Serial.println (" "); 90 | } 91 | 92 | void _OK (void) { 93 | if (tib [tib.length () - 1] == 10) Serial.println (" Ok"); 94 | } 95 | 96 | void _SWAP (void) { 97 | W = memory.data [S]; 98 | memory.data [S] = T; 99 | T = W; 100 | } 101 | 102 | void _OVER (void) { 103 | _DUP (); 104 | T = memory.data [S + 1]; 105 | } 106 | 107 | void _FETCH (void) { 108 | T = memory.data [T]; 109 | } 110 | 111 | void _STORE (void) { 112 | W = T, 113 | _DROP (); 114 | memory.data [W] = T; 115 | _DROP (); 116 | } 117 | 118 | void _COMMA (void) { 119 | memory.data [H++] = T; 120 | _DROP (); 121 | } 122 | 123 | void _MINUS (void) { 124 | W = T; 125 | _DROP (); 126 | T = (T - W); 127 | } 128 | 129 | void _PLUS (void) { 130 | W = T; 131 | _DROP (); 132 | T = (T + W); 133 | } 134 | 135 | void _aND (void) { 136 | W = T; 137 | _DROP (); 138 | T = (T & W); 139 | } 140 | 141 | void _OR (void) { 142 | W = T; 143 | _DROP (); 144 | T = (T | W); 145 | } 146 | 147 | void _XOR (void) { 148 | W = T; 149 | _DROP (); 150 | T = (T ^ W); 151 | } 152 | 153 | void _INVERT (void) { 154 | T = ~T; 155 | } 156 | 157 | void _ABS (void) { 158 | T = abs (T); 159 | } 160 | 161 | void _NEGATE (void) { 162 | T = -T; 163 | } 164 | 165 | void _TWOSLASH (void) { 166 | T = (T >> 1); 167 | } 168 | 169 | void _TWOSTAR (void) { 170 | T = (T << 1); 171 | } 172 | 173 | void _LIT (void) { 174 | _DUP (); 175 | T = memory.data [I++]; 176 | } 177 | 178 | void _BRANCH (void) { 179 | I = memory.data [I]; 180 | } 181 | 182 | void _0BRANCH (void) { 183 | if (T == 0) { 184 | I = memory.data [I]; 185 | _DROP (); 186 | return; 187 | } 188 | I += 1; 189 | _DROP (); 190 | } 191 | 192 | void _INITR (void) { 193 | R = R0; 194 | } 195 | 196 | void _INITS (void) { 197 | S = S0; 198 | } 199 | 200 | void _NEST (void) { 201 | memory.data [--R] = I; 202 | I = (W + 1); 203 | } 204 | 205 | void _SHOWTIB (void) { 206 | W = tib.length (); 207 | tib [W - 1] = 0; 208 | Serial.print (tib); 209 | } 210 | 211 | // trim leading spaces 212 | void _PARSE (void) { 213 | char t; 214 | tib = ""; 215 | do { 216 | while (!Serial.available ()); 217 | t = Serial.peek (); 218 | if (t == ' ') { 219 | t = Serial.read (); 220 | // Serial.write (t); 221 | } 222 | } while (t == ' '); 223 | do { 224 | while (!Serial.available ()); 225 | t = Serial.read (); 226 | // Serial.write (t); 227 | tib = tib + t; 228 | } while (t > ' '); 229 | Serial.print (tib); 230 | } 231 | 232 | void _WORD (void) { 233 | char t; 234 | _DUP (); 235 | T = (tib.length () - 1); 236 | W = T; 237 | t = tib [0]; 238 | T |= (t << 8); 239 | if (W > 1) { 240 | t = tib [1]; 241 | T |= (t << 16); 242 | } 243 | if (W > 2) { 244 | t = tib [2]; 245 | T |= (t << 24); 246 | } 247 | } 248 | 249 | void _NUMBER (void) { 250 | char t; 251 | _DUP (); 252 | T = 0; 253 | for (int i = 0; i < (tib.length () - 1); i++) { 254 | if (i == 0) { 255 | if (tib [i] == '-') continue; 256 | } 257 | t = tib [i]; 258 | if (!isDigit (t)) { 259 | if (tib [0] == '-') T = -T; 260 | _DUP (); 261 | T = -1; 262 | return; 263 | } 264 | T *= base; 265 | t -= '0'; 266 | if (t > 9) t -= 37; 267 | T += t; 268 | } 269 | if (tib [0] == '-') T = -T; 270 | if (state == true) { 271 | _DUP (); 272 | T = 1; // forward reference to lit 273 | _COMMA (); // lit 274 | _COMMA (); // the number 275 | } 276 | _DUP (); 277 | T = 0; 278 | } 279 | 280 | void _EXECUTE (void) { 281 | if (state == true) { 282 | if (((memory.data [T]) & 0x80) == 0) { 283 | T += 2; 284 | _COMMA (); 285 | return; 286 | } 287 | } 288 | W = (T + 2); 289 | _DROP (); 290 | memory.program [W] (); 291 | } 292 | 293 | void _FIND (void) { 294 | int X = T; 295 | T = D; 296 | while (T != 0) { 297 | W = (memory.data [T]); 298 | if ((W & 0xffffff7f) == X) { 299 | return; 300 | } 301 | T = memory.data [T + 1]; 302 | } 303 | } 304 | 305 | void _DOT (void) { 306 | Serial.print (T); 307 | Serial.write (' '); 308 | _DROP (); 309 | } 310 | 311 | void _HDOT (void) { 312 | Serial.print (T, HEX); 313 | Serial.write (' '); 314 | _DROP (); 315 | } 316 | 317 | void _DDOTS (void) { 318 | if (S == S0) { 319 | Serial.print ("empty "); 320 | return; 321 | } 322 | _DUP (); 323 | W = (S0 - 1); 324 | while (W > (S)) { 325 | Serial.print (memory.data [--W]); 326 | Serial.write (' '); 327 | } 328 | _DROP (); 329 | } 330 | 331 | void _SPACE () { 332 | Serial.write (' '); 333 | } 334 | 335 | void _ZEROEQUAL () { 336 | if (T == 0) { 337 | T = -1; 338 | return; 339 | } 340 | T = 0; 341 | } 342 | 343 | void _ZEROLESS () { 344 | if (T < 0) { 345 | T = -1; 346 | return; 347 | } 348 | T = 0; 349 | } 350 | 351 | void _DOTWORD () { 352 | int Y = memory.data [W]; 353 | int X = (Y & 0xff); 354 | Serial.write ('['); 355 | Serial.print (X); 356 | Serial.write (' '); 357 | X = ((Y >> 8) & 0xff); 358 | _DUP (); T = X; _EMIT (); 359 | X = ((Y >> 16) & 0xff); 360 | if (X != 0) { _DUP (); T = X; _EMIT (); } 361 | X = ((Y >> 24) & 0xff); 362 | if (X != 0) { _DUP (); T = X; _EMIT (); } 363 | Serial.print ("] "); 364 | } 365 | 366 | void _WORDS (void) { 367 | int i = 0; 368 | W = D; 369 | do { 370 | _DOTWORD (); 371 | W = memory.data [++W]; 372 | i += 1; 373 | if ((i % 8) == 0) _CR (); 374 | } while (memory.data [W + 1]); 375 | } 376 | 377 | void _DEPTH (void) { 378 | W = S0 - S; 379 | _DUP (); 380 | T = W; 381 | } 382 | 383 | void _DUMP (void) { 384 | int a = T; 385 | _DROP (); 386 | for (int i = 0; i < a; i++) { 387 | W = T; 388 | Serial.print (memory.data [T++], HEX); 389 | Serial.write (' '); 390 | _DOTWORD (); 391 | } 392 | } 393 | 394 | void _HERE (void) { 395 | _DUP (); 396 | T = H; 397 | } 398 | 399 | void _ALLOT (void) { 400 | H += T; 401 | _DROP (); 402 | } 403 | 404 | void _HEAD (void) { 405 | _PARSE (); 406 | _WORD (); 407 | _COMMA (); 408 | _DUP (); 409 | T = D; 410 | _COMMA (); 411 | D = H - 2; 412 | } 413 | 414 | void _DOVAR (void) { 415 | _DUP (); 416 | T = (W + 1); 417 | } 418 | 419 | void _CREATE (void) { 420 | _HEAD (); 421 | _DUP (); 422 | _DUP (); 423 | memory.program [S] = _DOVAR; 424 | _DROP (); 425 | _COMMA (); 426 | } 427 | 428 | void _COLON (void) { 429 | _HEAD (); 430 | _DUP (); 431 | _DUP (); 432 | memory.program [S] = _NEST; 433 | _DROP (); 434 | _COMMA (); 435 | _RBRAC (); 436 | } 437 | 438 | void _SEMI (void) { 439 | _DUP (); 440 | T = 25; // forward reference to exit 441 | _COMMA (); // compile exit 442 | _LBRAC (); // stop compiling 443 | } 444 | 445 | void _DOCONST (void) { 446 | _DUP (); 447 | T = memory.data [W + 1]; 448 | } 449 | 450 | void _CONSTANT (void) { 451 | _HEAD (); 452 | _DUP (); 453 | _DUP (); 454 | memory.program [S] = _DOCONST; 455 | _DROP (); 456 | _COMMA (); 457 | _COMMA (); 458 | } 459 | 460 | void _VARIABLE (void) { 461 | _CREATE (); 462 | H += 1; 463 | } 464 | 465 | void _QUESTION (void) { 466 | _FETCH (); 467 | _DOT (); 468 | } 469 | 470 | void _R (void) { 471 | _DUP (); 472 | T = R; 473 | } 474 | 475 | void _DO (void) { 476 | memory.data [--R] = T; 477 | _DROP (); 478 | memory.data [--R] = T; 479 | _DROP (); 480 | } 481 | 482 | void _LOOP (void) { 483 | int X = memory.data [R++]; 484 | W = (memory.data [R++] + 1); 485 | if (W == X) { 486 | I += 1; 487 | return; 488 | } 489 | memory.data [--R] = (W); 490 | memory.data [--R] = X; 491 | I = memory.data [I]; 492 | } 493 | 494 | void _I (void) { 495 | _DUP (); 496 | T = memory.data [R + 1]; 497 | } 498 | 499 | void _CDO (void) { 500 | _DUP (); 501 | T = 4; // forward reference to ddo 502 | _COMMA (); 503 | _DUP (); 504 | T = H; 505 | } 506 | 507 | void _CLOOP (void) { 508 | _DUP (); 509 | T = 5; // forward reference to lloop 510 | _COMMA (); 511 | _COMMA (); // address left on stack by do 512 | } 513 | 514 | void _CBEGIN (void) { 515 | _DUP (); 516 | T = H; 517 | } 518 | 519 | void _CUNTIL (void) { 520 | _DUP (); 521 | T = 3; // forward reference to Obranch 522 | _COMMA (); 523 | _COMMA (); // address left on stack by begin 524 | } 525 | 526 | void _CAGAIN (void) { 527 | _DUP (); 528 | T = 2; // forward reference to branch 529 | _COMMA (); 530 | _COMMA (); // address left on stack by begin 531 | } 532 | 533 | void _CIF (void) { 534 | _DUP (); 535 | T = 3; // forward reference to 0branch 536 | _COMMA (); 537 | _DUP (); 538 | T = H; // address that needs patching later 539 | _DUP (); 540 | T = 0; 541 | _COMMA (); // dummy in address field 542 | } 543 | 544 | void _CWHILE (void) { 545 | _CIF (); 546 | _SWAP (); 547 | } 548 | 549 | void _CTHEN (void) { 550 | _DUP (); 551 | T = H; 552 | _SWAP (); 553 | _STORE (); 554 | } 555 | 556 | void _CREPEAT (void) { 557 | _CAGAIN (); 558 | _CTHEN (); 559 | } 560 | 561 | void _CELSE (void) { 562 | _DUP (); 563 | T = 2; // forward reference to branch 564 | _COMMA (); 565 | _DUP (); 566 | T = H; // address that needs patching later 567 | _DUP (); 568 | T = 0; 569 | _COMMA (); // dummy in address field 570 | _SWAP (); 571 | _CTHEN (); 572 | } 573 | 574 | void _FORGET (void) { 575 | _PARSE (); 576 | _WORD (); 577 | _FIND (); 578 | D = memory.data [T + 1]; 579 | H = T; 580 | _DROP (); 581 | } 582 | 583 | void _TICK (void) { 584 | _PARSE (); 585 | _WORD (); 586 | _FIND (); 587 | } 588 | 589 | void _CLITERAL (void) { 590 | _DUP (); 591 | T = 1; // forward reference to lit 592 | _COMMA (); 593 | _COMMA (); // the number that was already on the stack 594 | } 595 | 596 | void _CFETCH (void) { 597 | W = (T % 4); 598 | T = memory.data [T / 4]; 599 | T = (T >> (W * 8) & 0xff); 600 | } 601 | 602 | void _CSTORE (void) { 603 | int X = (T / 4); 604 | W = (T % 4); 605 | _DROP (); 606 | T = (T << (W * 8)); 607 | T = (T | (memory.data [X] & ~(0xff << (W * 8)))); 608 | memory.data [X] = T; 609 | _DROP (); 610 | } 611 | 612 | 613 | 614 | void setup () { 615 | S = S0; // initialize data stack 616 | R = R0; // initialize return stack 617 | 618 | // initialize dictionary 619 | 620 | // unlinked primitives 621 | CODE(1, _LIT) 622 | # define lit 1 623 | CODE(2, _BRANCH) 624 | # define branch 2 625 | CODE(3, _0BRANCH) 626 | # define zbranch 3 627 | CODE(4, _DO) 628 | # define ddo 4 629 | CODE(5, _LOOP) 630 | # define lloop 5 631 | CODE(6, _INITR) 632 | # define initr 6 633 | CODE(7, _INITS) 634 | # define inits 7 635 | CODE(8, _SHOWTIB) 636 | # define showtib 8 637 | CODE(9, _OK) 638 | # define ok 9 639 | // room to expand here 640 | 641 | // trailing space kludge 642 | NAME(20, 0, 0, 10, 0, 0) 643 | LINK(21, 0) 644 | CODE(22, _NOP) 645 | // exit 646 | NAME(23, 0, 4, 'e', 'x', 'i') 647 | LINK(24, 20) 648 | CODE(25, _EXIT) 649 | # define exit 25 650 | // key ( - c) 651 | NAME(26, 0, 3, 'k', 'e', 'y') 652 | LINK(27, 23) 653 | CODE(28, _KEY) 654 | // emit ( c - ) 655 | NAME(29, 0, 4, 'e', 'm', 'i') 656 | LINK(30, 26) 657 | CODE(31, _EMIT) 658 | # define emit 31 659 | // cr 660 | NAME(32, 0, 2, 'c', 'r', 0) 661 | LINK(33, 29) 662 | CODE(34, _CR) 663 | # define cr 34 664 | // parse // leaves string in tib 665 | NAME(35, 0, 5, 'p', 'a', 'r') 666 | LINK(36, 32) 667 | CODE(37, _PARSE) 668 | # define parse 37 669 | // word ( - n) gets string from tib 670 | NAME(38, 0, 4, 'w', 'o', 'r') 671 | LINK(39, 35) 672 | CODE(40, _WORD) 673 | # define wword 40 674 | // dup ( n - n n) 675 | NAME(41, 0, 3, 'd', 'u', 'p') 676 | LINK(42, 38) 677 | CODE(43, _DUP) 678 | # define dup 43 679 | // drop ( n - ) 680 | NAME(44, 0, 4, 'd', 'r', 'o') 681 | LINK(45, 41) 682 | CODE(46, _DROP) 683 | # define drop 46 684 | // swap ( n1 n2 - n2 n1) 685 | NAME(47, 0, 4, 's', 'w', 'a') 686 | LINK(48, 44) 687 | CODE(49, _SWAP) 688 | # define swap 49 689 | // over ( n1 n2 - n1 n2 n1) 690 | NAME(50, 0, 4, 'o', 'v', 'e') 691 | LINK(51, 47) 692 | CODE(52, _OVER) 693 | # define over 52 694 | // @ ( a - n) 695 | NAME(53, 0, 1, '@', 0, 0) 696 | LINK(54, 50) 697 | CODE(55, _FETCH) 698 | // ! ( n a - ) 699 | NAME(56, 0, 1, '!', 0, 0) 700 | LINK(57, 53) 701 | CODE(58, _STORE) 702 | // , ( n - ) 703 | NAME(59, 0, 1, ',', 0, 0) 704 | LINK(60, 56) 705 | CODE(61, _COMMA) 706 | // find ( n - a) 707 | NAME(62, 0, 4, 'f', 'i', 'n') 708 | LINK(63, 59) 709 | CODE(64, _FIND) 710 | # define find 64 711 | // execute ( a) 712 | NAME(65, 0, 7, 'e', 'x', 'e') 713 | LINK(66, 62) 714 | CODE(67, _EXECUTE) 715 | # define execute 67 716 | // ?dup ( n - 0 | n n) 717 | NAME(68, 0, 3, '?', 'd', 'u') 718 | LINK(69, 65) 719 | CODE(70, _QDUP) 720 | # define qdup 70 721 | // number ( - n -f) gets string from tib 722 | NAME(71, 0, 6, 'n', 'u', 'm') 723 | LINK(72, 68) 724 | CODE(73, _NUMBER) 725 | # define number 73 726 | // depth ( - n) 727 | NAME(74, 0, 5, 'd', 'e', 'p') 728 | LINK(75, 71) 729 | CODE(76, _DEPTH) 730 | # define depth 76 731 | // 0< ( n - f) 732 | NAME(77, 0, 2, '0', '<', 0) 733 | LINK(78, 74) 734 | CODE(79, _ZEROLESS) 735 | # define zeroless 79 736 | 737 | // abort 738 | NAME(80, 0, 5, 'a', 'b', 'o') 739 | LINK(81, 77) 740 | CODE(82, _NEST) 741 | DATA(83, inits) 742 | # define abort 83 743 | // again 744 | DATA(84, branch) 745 | DATA(85, 89) 746 | // quit 747 | NAME(86, 0, 4, 'q', 'u', 'i') 748 | LINK(87, 77) 749 | CODE(88, _NEST) 750 | DATA(89, initr) 751 | // begin quit loop 752 | DATA(90, parse) 753 | DATA(91, wword) 754 | DATA(92, find) 755 | DATA(93, qdup) 756 | DATA(94, zbranch) 757 | DATA(95, 103) // to number 758 | DATA(96, execute) 759 | DATA(97, depth) 760 | DATA(98, zeroless) 761 | DATA(99, zbranch) 762 | DATA(100, 114) // to ok 763 | DATA(101, branch) 764 | DATA(102, 106) 765 | DATA(103, number) 766 | DATA(104, zbranch) 767 | DATA(105, 114) // to ok 768 | DATA(106, showtib) 769 | DATA(107, lit) 770 | DATA(108, '?') 771 | DATA(109, emit) 772 | DATA(110, cr) 773 | DATA(111, inits) 774 | DATA(112, branch) 775 | DATA(113, 89) 776 | DATA(114, ok) 777 | DATA(115, branch) 778 | DATA(116, 90) // continue quit loop 779 | 780 | // . ( n - ) 781 | NAME(117, 0, 1, '.', 0, 0) 782 | LINK(118, 86) 783 | CODE(119, _DOT) 784 | # define dot 119 785 | // .s 786 | NAME(120, 0, 2, '.', 's', 0) 787 | LINK(121, 117) 788 | CODE(122, _DDOTS) 789 | # define ddots 122 790 | // words 791 | NAME(123, 0, 5, 'w', 'o', 'r') 792 | LINK(124, 120) 793 | CODE(125, _WORDS) 794 | # define words 125 795 | // space 796 | NAME(126, 0, 5, 's', 'p', 'a') 797 | LINK(127, 123) 798 | CODE(128, _SPACE) 799 | # define space 128 800 | // h. ( n - ) 801 | NAME(129, 0, 2, 'h', '.', 0) 802 | LINK(130, 126) 803 | CODE(131, _HDOT) 804 | # define hdot 131 805 | // + ( n1 n2 - n3) 806 | NAME(132, 0, 1, '+', 0, 0) 807 | LINK(133, 129) 808 | CODE(134, _PLUS) 809 | # define plus 134 810 | // - ( n1 n2 - n3) 811 | NAME(135, 0, 1, '-', 0, 0) 812 | LINK(136, 132) 813 | CODE(137, _MINUS) 814 | // and (n1 n2 - n3) 815 | NAME(138, 0, 3, 'a', 'n', 'd') 816 | LINK(139, 135) 817 | CODE(140, _aND) 818 | // or ( n1 n2 - n3) 819 | NAME(141, 0, 2, 'o', 'r', 0) 820 | LINK(142, 138) 821 | CODE(143, _OR) 822 | // xor ( n1 n2 - n3) 823 | NAME(144, 0, 3, 'x', 'o', 'r') 824 | LINK(145, 141) 825 | CODE(146, _XOR) 826 | // invert ( n1 - n2) 827 | NAME(147, 0, 6, 'i', 'n', 'v') 828 | LINK(148, 144) 829 | CODE(149, _INVERT) 830 | // abs ( n1 - n2) 831 | NAME(150, 0, 3, 'a', 'b', 's') 832 | LINK(151, 147) 833 | CODE(152, _ABS) 834 | // negate ( n1 - n2) 835 | NAME(153, 0, 6, 'n', 'e', 'g') 836 | LINK(154, 150) 837 | CODE(155, _NEGATE) 838 | // 2* ( n1 - n2) 839 | NAME(156, 0, 2, '2', '*', 0) 840 | LINK(157, 153) 841 | CODE(158, _TWOSTAR) 842 | // 2/ ( n1 - n2) 843 | NAME(159, 0, 2, '2', '/', 0) 844 | LINK(160, 156) 845 | CODE(161, _TWOSLASH) 846 | // dump ( a n - a+n) 847 | NAME(162, 0, 4, 'd', 'u', 'm') 848 | LINK(163, 159) 849 | CODE(164, _DUMP) 850 | // create 851 | NAME(165, 0, 6, 'c', 'r', 'e') 852 | LINK(166, 162) 853 | CODE(167, _CREATE) 854 | // here 855 | NAME(168, 0, 4, 'h', 'e', 'r') 856 | LINK(169, 165) 857 | CODE(170, _HERE) 858 | // allot 859 | NAME(171, 0, 5, 'a', 'l', 'l') 860 | LINK(172, 168) 861 | CODE(173, _ALLOT) 862 | // variable 863 | NAME(174, 0, 8, 'v', 'a', 'r') 864 | LINK(175, 171) 865 | CODE(176, _VARIABLE) 866 | // ? 867 | NAME(177, 0, 1, '?', 0, 0) 868 | LINK(178, 174) 869 | CODE(179, _QUESTION) 870 | // constant 871 | NAME(180, 0, 8, 'c', 'o', 'n') 872 | LINK(181, 177) 873 | CODE(182, _CONSTANT) 874 | // R 875 | NAME(183, 0, 1, 'R', 0, 0) 876 | LINK(184, 180) 877 | CODE(185, _R) 878 | // [ 879 | NAME(186, IMMED, 1, '[', 0, 0) 880 | LINK(187, 183) 881 | CODE(188, _LBRAC) 882 | // ] 883 | NAME(189, 0, 1, ']', 0, 0) 884 | LINK(190, 186) 885 | CODE(191, _RBRAC) 886 | // : 887 | NAME(192, 0, 1, ':', 0, 0) 888 | LINK(193, 189) 889 | CODE(194, _COLON) 890 | // ; 891 | NAME(195, IMMED, 1, ';', 0, 0) 892 | LINK(196, 192) 893 | CODE(197, _SEMI) 894 | // i 895 | NAME(198, 0, 1, 'i', 0, 0) 896 | LINK(199, 195) 897 | CODE(200, _I) 898 | # define _i 200 899 | // do 900 | NAME(201, IMMED, 2, 'd', 'o', 0) 901 | LINK(202, 198) 902 | CODE(203, _CDO) 903 | // loop 904 | NAME(204, IMMED, 4, 'l', 'o', 'o') 905 | LINK(205, 201) 906 | CODE(206, _CLOOP) 907 | // begin 908 | NAME(207, IMMED, 5, 'b', 'e', 'g') 909 | LINK(208, 204) 910 | CODE(209, _CBEGIN) 911 | // until 912 | NAME(210, IMMED, 5, 'u', 'n', 't') 913 | LINK(211, 207) 914 | CODE(212, _CUNTIL) 915 | // if 916 | NAME(213, IMMED, 2, 'i', 'f', 0) 917 | LINK(214, 210) 918 | CODE(215, _CIF) 919 | // then 920 | NAME(216, IMMED, 4, 't', 'h', 'e') 921 | LINK(217, 213) 922 | CODE(218, _CTHEN) 923 | // else 924 | NAME(219, IMMED, 4, 'e', 'l', 's') 925 | LINK(220, 216) 926 | CODE(221, _CELSE) 927 | // forget 928 | NAME(222, 0, 6, 'f', 'o', 'r') 929 | LINK(223, 219) 930 | CODE(224, _FORGET) 931 | // ' 932 | NAME(225, 0, 1, '\'', 0, 0) 933 | LINK(226, 222) 934 | CODE(227, _TICK) 935 | // again 936 | NAME(228, IMMED, 5, 'a', 'g', 'a') 937 | LINK(229, 225) 938 | CODE(230, _CAGAIN) 939 | // while 940 | NAME(231, IMMED, 5, 'w', 'h', 'i') 941 | LINK(232, 228) 942 | CODE(233, _CWHILE) 943 | // repeat 944 | NAME(234, IMMED, 6, 'r', 'e', 'p') 945 | LINK(235, 231) 946 | CODE(236, _CREPEAT) 947 | // literal 948 | NAME(237, IMMED, 7, 'l', 'i', 't') 949 | LINK(238, 234) 950 | CODE(239, _CLITERAL) 951 | // c@ ( b - c) 952 | NAME(240, 0, 2, 'c', '@', 0) 953 | LINK(241, 237) 954 | CODE(242, _CFETCH) 955 | # define cfetch 242 956 | // c! ( c b - ) 957 | NAME(243, 0, 2, 'c', '!', 0) 958 | LINK(244, 240) 959 | CODE(245, _CSTORE) 960 | // type ( b c - ) 961 | NAME(246, 0, 4, 't', 'y', 'p') 962 | LINK(247, 243) 963 | CODE(248, _NEST) 964 | DATA(249, over) 965 | DATA(250, plus) 966 | DATA(251, swap) 967 | DATA(252, ddo) 968 | DATA(253, _i) 969 | DATA(254, cfetch) 970 | DATA(255, emit) 971 | DATA(256, lloop) 972 | DATA(257, 253) 973 | DATA(258, exit) 974 | 975 | 976 | // test 977 | DATA(300, lit) 978 | DATA(301, 10) // i 979 | DATA(302, lit) 980 | DATA(303, 0) // i 981 | DATA(304, ddo) 982 | DATA(305, 200) // i 983 | DATA(306, dot) 984 | DATA(307, lloop) 985 | DATA(308, 305) 986 | DATA(309, 185) // R 987 | DATA(310, dot) 988 | DATA(311, ddots) 989 | DATA(312, cr) 990 | DATA(313, branch) 991 | DATA(314, 300) 992 | 993 | 994 | 995 | D = 246; // latest word 996 | H = 259; // top of dictionary 997 | 998 | // I = 300; // test 999 | I = abort; // instruction pointer = abort 1000 | Serial.begin (9600); 1001 | while (!Serial); 1002 | Serial.println ("myForth Arm Cortex"); 1003 | } 1004 | 1005 | // the loop function runs over and over again forever 1006 | void loop() { 1007 | W = memory.data [I++]; 1008 | memory.program [W] (); 1009 | // delay (300); 1010 | } 1011 | 1012 | 1013 | 1014 | -------------------------------------------------------------------------------- /Arm-Forth-3.ino: -------------------------------------------------------------------------------- 1 | /* 2 | Forth virtual machine 3 | 4 | This code is in the public domain. 5 | 6 | */ 7 | 8 | #define RAM_SIZE 0x1200 9 | #define S0 0x1000 10 | #define _TIB 0x4004 // (4 * S0) + 4 11 | #define R0 0x0f00 12 | #define NAME(m, f, c, x, y, z) {memory.data [m] = f + c + (x << 8) + (y << 16) + (z << 24);} 13 | #define LINK(m, a) {memory.data [m] = a;} 14 | #define CODE(m, a) {memory.program [m] = a;} 15 | #define DATA(m, a) {memory.data [m] = a;} 16 | #define IMMED 0x80 17 | 18 | // global variables 19 | union Memory { 20 | int data [RAM_SIZE]; 21 | void (*program []) (void); 22 | } memory; 23 | 24 | int S = S0; // data stack pointer 25 | int R = R0; // return stack pointer 26 | int I = 0; // instruction pointer 27 | int W = 0; // working register 28 | int T = 0; // top of stack 29 | int H = 0; // dictionary pointer, HERE 30 | int D = 0; // dictionary list entry point 31 | int base = 10; 32 | boolean state = false; // compiling or not 33 | 34 | /* A word in the dictionary has these fields: 35 | name 32b word, a 32 bit int, made up of byte count and three letters 36 | link 32b word, point to next word in list, 0 says end of list 37 | code 32b word, a pointer to some actual C compiled code, 38 | all native code is in this field 39 | data 32b word, at least, a list to execute or a data field of some kind 40 | 41 | 42 | */ 43 | 44 | 45 | // primitive definitions 46 | 47 | void _LBRAC (void) { 48 | state = false; // interpreting 49 | } 50 | 51 | void _RBRAC (void) { 52 | state = true; // compiling 53 | } 54 | 55 | void _NOP (void) { 56 | return; 57 | } 58 | 59 | void _EXIT (void) { 60 | I = memory.data [R++]; 61 | } 62 | 63 | void _DROP (void) { 64 | T = memory.data [S++]; 65 | } 66 | 67 | void _DUP (void) { 68 | memory.data [--S] = T; 69 | } 70 | 71 | void _QDUP (void) { 72 | if (T) _DUP (); 73 | } 74 | 75 | void _KEY (void) { 76 | _DUP (); 77 | while (!Serial.available ()); 78 | T = Serial.read (); 79 | // Serial.write (T); Serial.flush (); 80 | } 81 | 82 | void _EMIT (void) { 83 | char c = T; 84 | Serial.write (c); Serial.flush (); 85 | _DROP (); 86 | } 87 | 88 | void _SWAP (void) { 89 | W = memory.data [S]; 90 | memory.data [S] = T; 91 | T = W; 92 | } 93 | 94 | void _OVER (void) { 95 | _DUP (); 96 | T = memory.data [S + 1]; 97 | } 98 | 99 | void _FETCH (void) { 100 | T = memory.data [T]; 101 | } 102 | 103 | void _STORE (void) { 104 | W = T, 105 | _DROP (); 106 | memory.data [W] = T; 107 | _DROP (); 108 | } 109 | 110 | void _COMMA (void) { 111 | memory.data [H++] = T; 112 | _DROP (); 113 | } 114 | 115 | void _MINUS (void) { 116 | W = T; 117 | _DROP (); 118 | T = (T - W); 119 | } 120 | 121 | void _PLUS (void) { 122 | W = T; 123 | _DROP (); 124 | T = (T + W); 125 | } 126 | 127 | void _AAND (void) { 128 | W = T; 129 | _DROP (); 130 | T = (T & W); 131 | } 132 | 133 | void _OR (void) { 134 | W = T; 135 | _DROP (); 136 | T = (T | W); 137 | } 138 | 139 | void _XOR (void) { 140 | W = T; 141 | _DROP (); 142 | T = (T ^ W); 143 | } 144 | 145 | void _INVERT (void) { 146 | T = ~T; 147 | } 148 | 149 | void _ABS (void) { 150 | T = abs (T); 151 | } 152 | 153 | void _NEGATE (void) { 154 | T = -T; 155 | } 156 | 157 | void _TWOSLASH (void) { 158 | T = (T >> 1); 159 | } 160 | 161 | void _TWOSTAR (void) { 162 | T = (T << 1); 163 | } 164 | 165 | void _LIT (void) { 166 | _DUP (); 167 | T = memory.data [I++]; 168 | } 169 | 170 | void _BRANCH (void) { 171 | I = memory.data [I]; 172 | } 173 | 174 | void _0BRANCH (void) { 175 | if (T == 0) { 176 | I = memory.data [I]; 177 | _DROP (); 178 | return; 179 | } 180 | I += 1; 181 | _DROP (); 182 | } 183 | 184 | void _INITR (void) { 185 | R = R0; 186 | } 187 | 188 | void _INITS (void) { 189 | S = S0; 190 | } 191 | 192 | void _NEST (void) { 193 | memory.data [--R] = I; 194 | I = (W + 1); 195 | } 196 | 197 | /* 198 | void _WORD (void) { 199 | char t; 200 | _DUP (); 201 | T = (tib.length () - 1); 202 | W = T; 203 | t = tib [0]; 204 | T |= (t << 8); 205 | if (W > 1) { 206 | t = tib [1]; 207 | T |= (t << 16); 208 | } 209 | if (W > 2) { 210 | t = tib [2]; 211 | T |= (t << 24); 212 | } 213 | } 214 | 215 | void _NUMBER (void) { 216 | char t; 217 | _DUP (); 218 | T = 0; 219 | for (int i = 0; i < (tib.length () - 1); i++) { 220 | if (i == 0) { 221 | if (tib [i] == '-') continue; 222 | } 223 | t = tib [i]; 224 | if (!isDigit (t)) { 225 | if (tib [0] == '-') T = -T; 226 | _DUP (); 227 | T = -1; 228 | return; 229 | } 230 | T *= base; 231 | t -= '0'; 232 | if (t > 9) t -= 37; 233 | T += t; 234 | } 235 | if (tib [0] == '-') T = -T; 236 | if (state == true) { 237 | _DUP (); 238 | T = 1; // forward reference to lit 239 | _COMMA (); // lit 240 | _COMMA (); // the number 241 | } 242 | _DUP (); 243 | T = 0; 244 | } 245 | */ 246 | 247 | void _EXECUTE (void) { 248 | if (state == true) { 249 | if (((memory.data [T]) & 0x80) == 0) { 250 | T += 2; 251 | _COMMA (); 252 | return; 253 | } 254 | } 255 | W = (T + 2); 256 | _DROP (); 257 | memory.program [W] (); 258 | } 259 | 260 | void _FIND (void) { 261 | int X = T; 262 | T = D; 263 | while (T != 0) { 264 | W = (memory.data [T]); 265 | if ((W & 0xffffff7f) == X) { 266 | return; 267 | } 268 | T = memory.data [T + 1]; 269 | } 270 | } 271 | 272 | void _ZEROEQUAL () { 273 | if (T == 0) { 274 | T = -1; 275 | return; 276 | } 277 | T = 0; 278 | } 279 | 280 | void _ZEROLESS () { 281 | if (T < 0) { 282 | T = -1; 283 | return; 284 | } 285 | T = 0; 286 | } 287 | 288 | void _DEPTH (void) { 289 | W = S0 - S; 290 | _DUP (); 291 | T = W; 292 | } 293 | 294 | void _HERE (void) { 295 | _DUP (); 296 | T = H; 297 | } 298 | 299 | void _ALLOT (void) { 300 | H += T; 301 | _DROP (); 302 | } 303 | 304 | void _DOVAR (void) { 305 | _DUP (); 306 | T = (W + 1); 307 | } 308 | 309 | void _SEMI (void) { 310 | _DUP (); 311 | T = 25; // forward reference to exit 312 | _COMMA (); // compile exit 313 | _LBRAC (); // stop compiling 314 | } 315 | 316 | void _DOCONST (void) { 317 | _DUP (); 318 | T = memory.data [W + 1]; 319 | } 320 | 321 | void _R (void) { 322 | _DUP (); 323 | T = R; 324 | } 325 | 326 | void _DO (void) { 327 | memory.data [--R] = T; 328 | _DROP (); 329 | memory.data [--R] = T; 330 | _DROP (); 331 | } 332 | 333 | void _LOOP (void) { 334 | int X = memory.data [R++]; 335 | W = (memory.data [R++] + 1); 336 | if (W == X) { 337 | I += 1; 338 | return; 339 | } 340 | memory.data [--R] = (W); 341 | memory.data [--R] = X; 342 | I = memory.data [I]; 343 | } 344 | 345 | void _I (void) { 346 | _DUP (); 347 | T = memory.data [R + 1]; 348 | } 349 | 350 | void _CDO (void) { 351 | _DUP (); 352 | T = 4; // forward reference to ddo 353 | _COMMA (); 354 | _DUP (); 355 | T = H; 356 | } 357 | 358 | void _CLOOP (void) { 359 | _DUP (); 360 | T = 5; // forward reference to lloop 361 | _COMMA (); 362 | _COMMA (); // address left on stack by do 363 | } 364 | 365 | void _CBEGIN (void) { 366 | _DUP (); 367 | T = H; 368 | } 369 | 370 | void _CUNTIL (void) { 371 | _DUP (); 372 | T = 3; // forward reference to Obranch 373 | _COMMA (); 374 | _COMMA (); // address left on stack by begin 375 | } 376 | 377 | void _CAGAIN (void) { 378 | _DUP (); 379 | T = 2; // forward reference to branch 380 | _COMMA (); 381 | _COMMA (); // address left on stack by begin 382 | } 383 | 384 | void _CIF (void) { 385 | _DUP (); 386 | T = 3; // forward reference to 0branch 387 | _COMMA (); 388 | _DUP (); 389 | T = H; // address that needs patching later 390 | _DUP (); 391 | T = 0; 392 | _COMMA (); // dummy in address field 393 | } 394 | 395 | void _CWHILE (void) { 396 | _CIF (); 397 | _SWAP (); 398 | } 399 | 400 | void _CTHEN (void) { 401 | _DUP (); 402 | T = H; 403 | _SWAP (); 404 | _STORE (); 405 | } 406 | 407 | void _CREPEAT (void) { 408 | _CAGAIN (); 409 | _CTHEN (); 410 | } 411 | 412 | void _CELSE (void) { 413 | _DUP (); 414 | T = 2; // forward reference to branch 415 | _COMMA (); 416 | _DUP (); 417 | T = H; // address that needs patching later 418 | _DUP (); 419 | T = 0; 420 | _COMMA (); // dummy in address field 421 | _SWAP (); 422 | _CTHEN (); 423 | } 424 | 425 | 426 | void _CLITERAL (void) { 427 | _DUP (); 428 | T = 1; // forward reference to lit 429 | _COMMA (); 430 | _COMMA (); // the number that was already on the stack 431 | } 432 | 433 | void _CFETCH (void) { 434 | W = (T % 4); 435 | T = memory.data [T / 4]; 436 | T = (T >> (W * 8) & 0xff); 437 | } 438 | 439 | void _CSTORE (void) { 440 | int X = (T / 4); 441 | W = (T % 4); 442 | _DROP (); 443 | T = (T << (W * 8)); 444 | T = (T | (memory.data [X] & ~(0xff << (W * 8)))); 445 | memory.data [X] = T; 446 | _DROP (); 447 | } 448 | 449 | void _EQUAL (void) { 450 | W = T; 451 | _DROP (); 452 | if (T == W) { 453 | T = -1; 454 | } else { 455 | T = 0; 456 | } 457 | } 458 | 459 | void _DOT (void) { 460 | Serial.print (T, HEX); 461 | _DROP (); 462 | Serial.write (' '); 463 | } 464 | 465 | void _PLUSSTORE (void) { 466 | W = T; 467 | _DROP (); 468 | T = (memory.data [W] + T); 469 | memory.data [W] = T; 470 | _DROP (); 471 | } 472 | 473 | void _COUNT (void) { 474 | W = (memory.data [T] & 0xff); 475 | T *= 4; 476 | T += 1; 477 | _DUP (); 478 | T = W; 479 | } 480 | 481 | void _ONEPLUS (void) { 482 | T += 1; 483 | } 484 | 485 | void _ONEMINUS (void) { 486 | T -= 1; 487 | } 488 | 489 | void _DEBUG (void) { 490 | _DUP (); 491 | T = R; 492 | _DOT (); 493 | Serial.print (" "); 494 | _DUP (); 495 | T = S; 496 | _DOT (); 497 | Serial.println (" "); 498 | } 499 | 500 | void _CR (void) { 501 | Serial.write (13); 502 | Serial.write (10); 503 | } 504 | 505 | void _SPACE (void) { 506 | Serial.write (32); 507 | } 508 | 509 | void _BL (void) { 510 | _DUP (); 511 | T = 32; 512 | } 513 | 514 | void _DASHTRAILING (void) { 515 | int A = 0; 516 | do { 517 | _OVER (); _OVER (); _PLUS (); _ONEMINUS (); 518 | _CFETCH (); A = T; _DROP (); 519 | if (A == 32) _ONEMINUS (); 520 | } while (A == 32) ; 521 | } 522 | 523 | void setup () { 524 | S = S0; // initialize data stack 525 | R = R0; // initialize return stack 526 | 527 | // initialize dictionary 528 | 529 | // unlinked primitives 530 | CODE(1, _LIT) 531 | # define lit 1 532 | CODE(2, _BRANCH) 533 | # define branch 2 534 | CODE(3, _0BRANCH) 535 | # define zbranch 3 536 | CODE(4, _DO) 537 | # define ddo 4 538 | CODE(5, _LOOP) 539 | # define lloop 5 540 | CODE(6, _INITR) 541 | # define initr 6 542 | CODE(7, _INITS) 543 | # define inits 7 544 | // CODE(8, _OK) 545 | // .# define ok 8 546 | // room to expand here 547 | 548 | // trailing space kludge (is this needed now?) 549 | NAME(20, 0, 0, 10, 0, 0) 550 | LINK(21, 0) 551 | CODE(22, _NOP) 552 | // exit 553 | NAME(23, 0, 4, 'e', 'x', 'i') 554 | LINK(24, 20) 555 | CODE(25, _EXIT) 556 | # define exit 25 557 | // key ( - c) 558 | NAME(26, 0, 3, 'k', 'e', 'y') 559 | LINK(27, 23) 560 | CODE(28, _KEY) 561 | # define key 28 562 | // emit ( c - ) 563 | NAME(29, 0, 4, 'e', 'm', 'i') 564 | LINK(30, 26) 565 | CODE(31, _EMIT) 566 | # define emit 31 567 | // dup ( n - n n) 568 | NAME(32, 0, 3, 'd', 'u', 'p') 569 | LINK(33, 29) 570 | CODE(34, _DUP) 571 | # define dup 34 572 | // drop ( n - ) 573 | NAME(35, 0, 4, 'd', 'r', 'o') 574 | LINK(36, 32) 575 | CODE(37, _DROP) 576 | # define drop 37 577 | // swap ( n1 n2 - n2 n1) 578 | NAME(38, 0, 4, 's', 'w', 'a') 579 | LINK(39, 35) 580 | CODE(40, _SWAP) 581 | # define swap 40 582 | // over ( n1 n2 - n1 n2 n1) 583 | NAME(41, 0, 4, 'o', 'v', 'e') 584 | LINK(42, 38) 585 | CODE(43, _OVER) 586 | # define over 43 587 | // @ ( a - n) 588 | NAME(44, 0, 1, '@', 0, 0) 589 | LINK(45, 43) 590 | CODE(46, _FETCH) 591 | # define fetch 46 592 | // ! ( n a - ) 593 | NAME(47, 0, 1, '!', 0, 0) 594 | LINK(48, 44) 595 | CODE(49, _STORE) 596 | # define store 49 597 | // , ( n - ) 598 | NAME(50, 0, 1, ',', 0, 0) 599 | LINK(51, 47) 600 | CODE(52, _COMMA) 601 | # define comma 52 602 | // find ( n - a) 603 | NAME(53, 0, 4, 'f', 'i', 'n') 604 | LINK(54, 50) 605 | CODE(55, _FIND) 606 | # define find 55 607 | // execute ( a) 608 | NAME(56, 0, 7, 'e', 'x', 'e') 609 | LINK(57, 53) 610 | CODE(58, _EXECUTE) 611 | # define execute 58 612 | // ?dup ( n - 0 | n n) 613 | NAME(59, 0, 3, '?', 'd', 'u') 614 | LINK(60, 56) 615 | CODE(61, _QDUP) 616 | # define qdup 61 617 | // 0< ( n - f) 618 | NAME(62, 0, 2, '0', '<', 0) 619 | LINK(63, 59) 620 | CODE(64, _ZEROLESS) 621 | # define zeroless 64 622 | // + ( n1 n2 - n3) 623 | NAME(65, 0, 1, '+', 0, 0) 624 | LINK(66, 62) 625 | CODE(67, _PLUS) 626 | # define plus 67 627 | // - ( n1 n2 - n3) 628 | NAME(68, 0, 1, '-', 0, 0) 629 | LINK(69, 65) 630 | CODE(70, _MINUS) 631 | # define minus 70 632 | // and (n1 n2 - n3) 633 | NAME(71, 0, 3, 'a', 'n', 'd') 634 | LINK(72, 68) 635 | CODE(73, _AAND) 636 | # define aand 73 637 | // or ( n1 n2 - n3) 638 | NAME(74, 0, 2, 'o', 'r', 0) 639 | LINK(75, 71) 640 | CODE(76, _OR) 641 | # define oor 76 642 | // xor ( n1 n2 - n3) 643 | NAME(77, 0, 3, 'x', 'o', 'r') 644 | LINK(78, 74) 645 | CODE(79, _XOR) 646 | # define xxor 79 647 | // invert ( n1 - n2) 648 | NAME(80, 0, 6, 'i', 'n', 'v') 649 | LINK(81, 77) 650 | CODE(82, _INVERT) 651 | # define invert 82 652 | // abs ( n1 - n2) 653 | NAME(83, 0, 3, 'a', 'b', 's') 654 | LINK(84, 80) 655 | CODE(85, _ABS) 656 | # define aabs 85 657 | // negate ( n1 - n2) 658 | NAME(86, 0, 6, 'n', 'e', 'g') 659 | LINK(87, 83) 660 | CODE(88, _NEGATE) 661 | # define negate 88 662 | // 2* ( n1 - n2) 663 | NAME(89, 0, 2, '2', '*', 0) 664 | LINK(90, 86) 665 | CODE(91, _TWOSTAR) 666 | # define twostar 91 667 | // 2/ ( n1 - n2) 668 | NAME(92, 0, 2, '2', '/', 0) 669 | LINK(93, 89) 670 | CODE(94, _TWOSLASH) 671 | # define twoslash 92 672 | // here 673 | NAME(95, 0, 4, 'h', 'e', 'r') 674 | LINK(96, 92) 675 | CODE(97, _HERE) 676 | # define here 97 677 | // allot 678 | NAME(98, 0, 5, 'a', 'l', 'l') 679 | LINK(99, 95) 680 | CODE(100, _ALLOT) 681 | # define allot 100 682 | // [ 683 | NAME(101, IMMED, 1, '[', 0, 0) 684 | LINK(102, 98) 685 | CODE(103, _LBRAC) 686 | # define lbrac 103 687 | // ] 688 | NAME(104, 0, 1, ']', 0, 0) 689 | LINK(105, 101) 690 | CODE(106, _RBRAC) 691 | # define rbrac 106 692 | // ; 693 | NAME(107, IMMED, 1, ';', 0, 0) 694 | LINK(108, 104) 695 | CODE(109, _SEMI) 696 | // i 697 | NAME(110, 0, 1, 'i', 0, 0) 698 | LINK(111, 107) 699 | CODE(112, _I) 700 | # define _i 112 701 | // do 702 | NAME(113, IMMED, 2, 'd', 'o', 0) 703 | LINK(114, 110) 704 | CODE(115, _CDO) 705 | // loop 706 | NAME(116, IMMED, 4, 'l', 'o', 'o') 707 | LINK(117, 113) 708 | CODE(118, _CLOOP) 709 | // begin 710 | NAME(119, IMMED, 5, 'b', 'e', 'g') 711 | LINK(120, 116) 712 | CODE(121, _CBEGIN) 713 | // until 714 | NAME(122, IMMED, 5, 'u', 'n', 't') 715 | LINK(123, 119) 716 | CODE(124, _CUNTIL) 717 | // if 718 | NAME(125, IMMED, 2, 'i', 'f', 0) 719 | LINK(126, 122) 720 | CODE(127, _CIF) 721 | // then 722 | NAME(128, IMMED, 4, 't', 'h', 'e') 723 | LINK(129, 125) 724 | CODE(130, _CTHEN) 725 | // else 726 | NAME(131, IMMED, 4, 'e', 'l', 's') 727 | LINK(132, 128) 728 | CODE(133, _CELSE) 729 | // again 730 | NAME(134, IMMED, 5, 'a', 'g', 'a') 731 | LINK(135, 131) 732 | CODE(136, _CAGAIN) 733 | // while 734 | NAME(137, IMMED, 5, 'w', 'h', 'i') 735 | LINK(138, 134) 736 | CODE(139, _CWHILE) 737 | // repeat 738 | NAME(140, IMMED, 6, 'r', 'e', 'p') 739 | LINK(141, 137) 740 | CODE(142, _CREPEAT) 741 | // literal 742 | NAME(143, IMMED, 7, 'l', 'i', 't') 743 | LINK(144, 140) 744 | CODE(145, _CLITERAL) 745 | // byte addressing words 746 | // c@ ( b - c) 747 | NAME(146, 0, 2, 'c', '@', 0) 748 | LINK(147, 143) 749 | CODE(148, _CFETCH) 750 | # define cfetch 148 751 | // c! ( c b - ) 752 | NAME(149, 0, 2, 'c', '!', 0) 753 | LINK(150, 146) 754 | CODE(151, _CSTORE) 755 | # define cstore 151 756 | // type ( b c - ) 757 | NAME(152, 0, 4, 't', 'y', 'p') 758 | LINK(153, 149) 759 | CODE(154, _NEST) 760 | # define type 154 761 | DATA(155, over) 762 | DATA(156, plus) 763 | DATA(157, swap) 764 | DATA(158, ddo) 765 | DATA(159, _i) 766 | DATA(160, cfetch) 767 | DATA(161, emit) 768 | DATA(162, lloop) 769 | DATA(163, 159) 770 | DATA(164, exit) 771 | // = 772 | NAME(165, 0, 1, '=', 0, 0) 773 | LINK(166, 152) 774 | CODE(167, _EQUAL) 775 | # define equal 167 776 | // cr 777 | NAME(168, 0, 2, 'c', 'r', 0) 778 | LINK(169, 165) 779 | CODE(170, _CR) 780 | # define cr 170 781 | // space 782 | NAME(171, 0, 5, 's', 'p', 'a') 783 | LINK(172, 168) 784 | CODE(173, _SPACE) 785 | # define space 173 786 | // -trailing ( b c - ) 787 | NAME(174, 0, 9, '-', 't', 'r') 788 | LINK(175, 171) 789 | CODE(176, _DASHTRAILING) 790 | # define dashtrailing 176 791 | // #tib 792 | NAME(177, 0, 4, '#', 't', 'i') 793 | LINK(178, 174) 794 | CODE(179, _DOVAR) 795 | # define ntib 179 796 | DATA(180, 0) 797 | // . // temporary, for initial debug 798 | NAME(181, 0, 1, '.', 0, 0) 799 | LINK(182, 177) 800 | CODE(183, _DOT) 801 | # define dot 183 802 | // tib 803 | NAME(184, 0, 3, 't', 'i', 'b') 804 | LINK(185, 181) 805 | CODE(186, _DOCONST) 806 | # define tib 186 807 | DATA(187, _TIB) 808 | // +! 809 | NAME(188, 0, 2, '+', '!', 0) 810 | LINK(189, 184) 811 | CODE(190, _PLUSSTORE) 812 | # define plusstore 190 813 | // >in ( - b) 814 | NAME(191, 0, 3, '>', 'i', 'n') 815 | LINK(192, 188) 816 | CODE(193, _DOVAR) 817 | # define toin 193 818 | DATA(194, 0) 819 | // count ( a - b c) 820 | NAME(195, 0, 5, 'c', 'o', 'u') 821 | LINK(196, 191) 822 | CODE(197, _COUNT) 823 | # define count 197 824 | 825 | // query 826 | NAME(200, 0, 5, 'q', 'u', 'e') 827 | LINK(201, 195) 828 | CODE(202, _NEST) 829 | # define query 202 830 | DATA(203, lit) 831 | DATA(204, 0) 832 | DATA(205, ntib) 833 | DATA(206, store) 834 | DATA(207, key) // begin 835 | DATA(208, dup) 836 | DATA(209, lit) 837 | DATA(210, 13) 838 | DATA(211, minus) 839 | DATA(212, zbranch) // while 840 | DATA(213, 240) 841 | DATA(214, dup) 842 | DATA(215, emit) 843 | DATA(216, dup) 844 | DATA(217, lit) 845 | DATA(218, 127) // backspace 846 | DATA(219, equal) 847 | DATA(220, zbranch) // if 848 | DATA(221, 229) 849 | DATA(222, drop) 850 | DATA(223, lit) 851 | DATA(224, -1) 852 | DATA(225, ntib) 853 | DATA(226, plusstore) 854 | DATA(227, branch) // else 855 | DATA(228, 238) 856 | DATA(229, tib) 857 | DATA(230, ntib) 858 | DATA(231, fetch) 859 | DATA(232, plus) 860 | DATA(233, cstore) 861 | DATA(234, lit) 862 | DATA(235, 1) 863 | DATA(236, ntib) 864 | DATA(237, plusstore) 865 | DATA(238, branch) // repeat 866 | DATA(239, 207) 867 | DATA(240, drop) 868 | DATA(241, lit) 869 | DATA(242, 0) 870 | DATA(243, toin) 871 | DATA(244, store) 872 | DATA(245, tib) 873 | DATA(246, ntib) 874 | DATA(247, fetch) 875 | DATA(248, dashtrailing) 876 | DATA(249, ntib) 877 | DATA(250, store) 878 | DATA(251, drop) 879 | DATA(252, exit) 880 | 881 | // char ( - c) 882 | NAME(253, 0, 4, 'c', 'h', 'a') 883 | LINK(254, 200) 884 | CODE(255, _NEST) 885 | # define cchar 255 886 | DATA(256, toin) 887 | DATA(257, fetch) 888 | DATA(258, ntib) 889 | DATA(259, fetch) 890 | DATA(260, equal) 891 | DATA(261, zbranch) // if 892 | DATA(262, 267) 893 | DATA(263, lit) 894 | DATA(264, 32) 895 | DATA(265, branch) // else 896 | DATA(266, 271) 897 | DATA(267, tib) 898 | DATA(268, toin) 899 | DATA(269, fetch) 900 | DATA(270, plus) 901 | DATA(271, cfetch) // then 902 | DATA(272, lit) 903 | DATA(273, 1) 904 | DATA(274, toin) 905 | DATA(275, plusstore) 906 | DATA(276, exit) 907 | // trim ( c - c) 908 | NAME(277, 0, 4, 't', 'r', 'i') 909 | LINK(278, 253) 910 | CODE(279, _NEST) 911 | # define ttrim 279 912 | DATA(280, cchar) // begin 913 | DATA(281, over) 914 | DATA(282, minus) 915 | DATA(283, toin) 916 | DATA(284, fetch) 917 | DATA(285, ntib) 918 | DATA(286, fetch) 919 | DATA(287, equal) 920 | DATA(288, oor) 921 | DATA(289, zbranch) // if 922 | DATA(290, 296) 923 | DATA(291, lit) 924 | DATA(292, -1) 925 | DATA(293, toin) 926 | DATA(294, plusstore) 927 | DATA(295, exit) 928 | DATA(296, branch) // again 929 | DATA(297, 280) 930 | // 1+ 931 | NAME(299, 0, 2, '1', '+', 0) 932 | LINK(300, 277) 933 | CODE(301, _ONEPLUS) 934 | # define oneplus 301 935 | // 1- 936 | NAME(302, 0, 2, '1', '-', 0) 937 | LINK(303, 299) 938 | CODE(304, _ONEMINUS) 939 | # define oneminus 304 940 | // bl 941 | NAME(305, 0, 2, 'b', 'l', 0) 942 | LINK(306, 302) 943 | CODE(307, _BL) 944 | # define bl 307 945 | // DATA(308, 32) 946 | // #chars ( c - c n) 947 | NAME(309, 0, 5, '#', 'c', 'h') 948 | LINK(310, 309) 949 | CODE(311, _NEST) 950 | # define nchars 311 951 | DATA(312, toin) 952 | DATA(313, fetch) 953 | DATA(314, swap) 954 | DATA(315, cchar) // begin 955 | DATA(316, over) 956 | DATA(317, equal) 957 | DATA(318, toin) 958 | DATA(319, fetch) 959 | DATA(320, ntib) 960 | DATA(321, fetch) 961 | DATA(322, oneplus) 962 | DATA(323, equal) 963 | DATA(324, oor) 964 | DATA(325, zbranch) // if 965 | DATA(326, 337) 966 | DATA(327, swap) 967 | DATA(328, toin) 968 | DATA(329, fetch) 969 | DATA(330, over) 970 | DATA(331, minus) 971 | DATA(332, oneminus) 972 | DATA(333, swap) 973 | DATA(334, toin) 974 | DATA(335, store) 975 | DATA(336, exit) 976 | DATA(337, branch) // again then 977 | DATA(338, 315) 978 | // word ( c - a) 979 | NAME(339, 0, 4, 'w', 'o', 'r') 980 | LINK(340, 309) 981 | CODE(341, _NEST) 982 | # define wword 341 983 | DATA(342, ttrim) 984 | DATA(343, nchars) 985 | DATA(344, here) 986 | DATA(345, store) 987 | DATA(346, here) 988 | DATA(347, count) 989 | DATA(348, over) 990 | DATA(349, plus) 991 | DATA(350, swap) 992 | DATA(351, ddo) 993 | DATA(352, cchar) 994 | DATA(353, _i) 995 | DATA(354, cstore) 996 | DATA(355, lloop) 997 | DATA(356, 352) 998 | DATA(357, here) 999 | DATA(358, exit) 1000 | // debug 1001 | NAME(359, 0, 5, 'd', 'e', 'b') 1002 | LINK(360, 339) 1003 | CODE(361, _DEBUG) 1004 | # define debug 361 1005 | 1006 | 1007 | D = 359; // latest word 1008 | H = 362; // top of dictionary 1009 | 1010 | 1011 | DATA(407, query) // begin 1012 | DATA(408, cr) 1013 | // DATA(402, tib) 1014 | // DATA(403, ntib) 1015 | // DATA(404, fetch) 1016 | // DATA(405, dashtrailing) 1017 | // DATA(406, ntib) 1018 | // DATA(407, store) 1019 | // DATA(408, drop) 1020 | DATA(409, toin) // begin 1021 | DATA(410, fetch) 1022 | DATA(411, ntib) 1023 | DATA(412, fetch) 1024 | DATA(413, minus) 1025 | DATA(414, zeroless) 1026 | DATA(415, zbranch) // while 1027 | DATA(416, 424) 1028 | DATA(417, bl) 1029 | DATA(418, wword) 1030 | DATA(419, count) 1031 | DATA(420, type) 1032 | DATA(421, cr) 1033 | DATA(422, branch) // repeat 1034 | DATA(423, 409) 1035 | DATA(424, cr) 1036 | DATA(425, branch) // again 1037 | DATA(426, 407) 1038 | 1039 | I = 407; // test 1040 | // I = abort; // instruction pointer = abort 1041 | Serial.begin (9600); 1042 | while (!Serial); 1043 | Serial.println ("myForth Arm Cortex"); Serial.flush (); 1044 | } 1045 | 1046 | // the loop function runs over and over again forever 1047 | void loop() { 1048 | W = memory.data [I++]; 1049 | memory.program [W] (); 1050 | // delay (100); 1051 | } 1052 | -------------------------------------------------------------------------------- /Jackdaw.ino: -------------------------------------------------------------------------------- 1 | // This example program is in the public domain 2 | #include 3 | #include 4 | 5 | const byte i2c1 = 0x20; 6 | const byte i2c2 = 0x21; 7 | 8 | boolean pressed; 9 | 10 | // parts of the keyboard 11 | byte left = 0; 12 | byte center = 0; 13 | byte right = 0; 14 | int controller = 0; 15 | boolean number = false; 16 | boolean caps = false; 17 | boolean ekey = false; 18 | boolean ykey = false; 19 | boolean spacing = false; 20 | boolean autospace = true; 21 | 22 | int read_raw_keys () { 23 | int a=0; 24 | a |= digitalRead (A1); // 10 25 | a |= digitalRead (A2) << 1; // 20 26 | a |= digitalRead (A3) << 2; // 40 27 | a |= digitalRead (A4) << 3; // 80 28 | a ^=0x0f; 29 | return a; 30 | } 31 | 32 | // read the i2c port expander with the given address 33 | unsigned int read_AB (int address) { 34 | Wire.beginTransmission (address); 35 | Wire.write (0x12); // GPIOA 36 | Wire.endTransmission (); 37 | Wire.requestFrom (address, 2); 38 | unsigned int a = Wire.read (); 39 | int b = Wire.read (); 40 | a |= b << 8; 41 | a ^= 0xffff; 42 | a &= 0xffff; 43 | return a; 44 | } 45 | 46 | // global variables keep track of keys stroked 47 | unsigned int raw_keys=0; 48 | unsigned int serial_keys1=0; 49 | unsigned int serial_keys2=0; 50 | 51 | // read and accumulate keys until all released 52 | void scan () { 53 | int a = 0; int b = 0; int c = 0; 54 | serial_keys1 = 0; 55 | serial_keys2 = 0; 56 | raw_keys = 0; 57 | do { 58 | do { 59 | a = read_AB (i2c1 ); 60 | b = read_raw_keys (); 61 | c = read_AB (i2c2); 62 | } while ((a == 0) & (b == 0) & (c == 0)); // not pressed 63 | delay (30); 64 | a = read_AB (i2c1); 65 | b = read_raw_keys (); 66 | c = read_AB (i2c2); 67 | } while ((a == 0) & (b == 0) & (c == 0)); // not pressed 68 | do { 69 | a = read_AB (i2c1); 70 | b = read_raw_keys (); 71 | c = read_AB (i2c2); 72 | serial_keys1 |= a; 73 | raw_keys |= b; 74 | serial_keys2 |= c; 75 | } while ((a != 0) | (b != 0) | (c != 0)); // pressed 76 | } 77 | 78 | // translate scan into a hardware neutral representation 79 | void organize(){ 80 | left = 0; // initial consonants 81 | if (serial_keys2 & 0x2000) left |= 0x01; // a 82 | if (serial_keys2 & 0x1000) left |= 0x04; // c 83 | if (serial_keys2 & 0x0800) left |= 0x10; // w 84 | if (serial_keys1 & 0x8000) left |= 0x40; // n 85 | if (serial_keys2 & 0x0004) left |= 0x02; // s 86 | if (serial_keys2 & 0x0008) left |= 0x08; // t 87 | if (serial_keys2 & 0x0010) left |= 0x20; // h 88 | if (serial_keys1 & 0x0001) left |= 0x80; // r 89 | center = 0; // vowels 90 | if (raw_keys & 0x01) center |= 0x01; // i 91 | if (raw_keys & 0x02) center |= 0x02; // e 92 | if (raw_keys & 0x04) center |= 0x04; // a 93 | if (raw_keys & 0x08) center |= 0x08; // o 94 | if ( serial_keys2 & 0x0200) center |= 0x10; // u 95 | right = 0; // final consonants 96 | if ( serial_keys1 & 0x2000) right |= 0x01; // r 97 | if ( serial_keys1 & 0x1000) right |= 0x04; // l 98 | if ( serial_keys1 & 0x0800) right |= 0x10; // c 99 | if ( serial_keys1 & 0x0400) right |= 0x40; // t 100 | if ( serial_keys1 & 0x0004) right |= 0x02; // n 101 | if ( serial_keys1 & 0x0008) right |= 0x08; // g 102 | if ( serial_keys1 & 0x0010) right |= 0x20; // h 103 | if ( serial_keys1 & 0x0020) right |= 0x80; // s 104 | ekey = false; if ( serial_keys1 & 0x0200) ekey = true; 105 | ykey = false; if ( serial_keys1 & 0x0040) ykey = true; 106 | spacing = false; 107 | if (serial_keys1 & 0x4000) spacing = true; // * 108 | if (serial_keys1 & 0x0002) spacing = true; // * 109 | controller = 0; // 5 keys beyond the basic TinyMod 110 | if (serial_keys2 & 0x0020) controller |= 0x01; 111 | if (serial_keys2 & 0x0040) controller |= 0x02; 112 | if (serial_keys2 & 0x0100) controller |= 0x04; 113 | if (serial_keys2 & 0x0400) controller |= 0x08; 114 | number = false; 115 | if (serial_keys2 & 0x0080) number = true; 116 | } 117 | 118 | // optionally capitalize first character of the string 119 | void spit(String a) { 120 | if(a.length() == 0) return; 121 | if(caps) { 122 | String s; 123 | caps = false; 124 | s = a.substring(0, 1); 125 | s.toUpperCase(); 126 | Keyboard.print(s); 127 | s = a.substring(1); 128 | Keyboard.print(s); 129 | return; 130 | } 131 | Keyboard.print(a); 132 | } 133 | 134 | // left hand strings 135 | const char l00[] PROGMEM = ""; 136 | const char l01[] PROGMEM = "a"; 137 | const char l02[] PROGMEM = "s"; 138 | const char l03[] PROGMEM = "as"; 139 | const char l04[] PROGMEM = "c"; 140 | const char l05[] PROGMEM = "ac"; 141 | const char l06[] PROGMEM = "sc"; // sc 142 | const char l07[] PROGMEM = "asc"; 143 | const char l08[] PROGMEM = "t"; 144 | const char l09[] PROGMEM = "at"; 145 | const char l0a[] PROGMEM = "st"; // st 146 | const char l0b[] PROGMEM = "ad"; 147 | const char l0c[] PROGMEM = "d"; // ct 148 | const char l0d[] PROGMEM = "ast"; 149 | const char l0e[] PROGMEM = "g"; // sct 150 | const char l0f[] PROGMEM = "ag"; 151 | const char l10[] PROGMEM = "w"; // w 152 | const char l11[] PROGMEM = "aw"; // aw 153 | const char l12[] PROGMEM = "sw"; // sw 154 | const char l13[] PROGMEM = ""; // asw 155 | const char l14[] PROGMEM = "p"; // cw 156 | const char l15[] PROGMEM = "ap"; // acw 157 | const char l16[] PROGMEM = "sp"; // scw 158 | const char l17[] PROGMEM = "ass"; // ascn 159 | const char l18[] PROGMEM = "tw"; // tw 160 | const char l19[] PROGMEM = "att"; // atw 161 | const char l1a[] PROGMEM = "x"; // stw 162 | const char l1b[] PROGMEM = "ax"; // astw 163 | const char l1c[] PROGMEM = "dw"; // ctw 164 | const char l1d[] PROGMEM = "add"; // actw 165 | const char l1e[] PROGMEM = "gw"; // sctw 166 | const char l1f[] PROGMEM = "agg"; // asctw 167 | const char l20[] PROGMEM = "h"; 168 | const char l21[] PROGMEM = "ah"; // ah 169 | const char l22[] PROGMEM = "sh"; // sh 170 | const char l23[] PROGMEM = "ash"; // ash 171 | const char l24[] PROGMEM = "ch"; // ch 172 | const char l25[] PROGMEM = "ach"; // ach 173 | const char l26[] PROGMEM = "sch"; // sch 174 | const char l27[] PROGMEM = ""; //asch 175 | const char l28[] PROGMEM = "th"; // th 176 | const char l29[] PROGMEM = "ath"; // ath 177 | const char l2a[] PROGMEM = "'"; // sth 178 | const char l2b[] PROGMEM = "asth"; // asth 179 | const char l2c[] PROGMEM = "f"; // cth 180 | const char l2d[] PROGMEM = "af"; // acth 181 | const char l2e[] PROGMEM = "gh"; // scth 182 | const char l2f[] PROGMEM = "agh"; // ascth 183 | const char l30[] PROGMEM = "wh"; // wh 184 | const char l31[] PROGMEM = "awh"; // awh 185 | const char l32[] PROGMEM = ""; // swh 186 | const char l33[] PROGMEM = ""; // aswh 187 | const char l34[] PROGMEM = "ph"; // cwh 188 | const char l35[] PROGMEM = "aph"; // acwh 189 | const char l36[] PROGMEM = "sph"; // scwh 190 | const char l37[] PROGMEM = "asph"; // ascwh 191 | const char l38[] PROGMEM = "k"; // twh 192 | const char l39[] PROGMEM = "ak"; // atwh 193 | const char l3a[] PROGMEM = "sk"; // stwh 194 | const char l3b[] PROGMEM = "ask"; // astwh 195 | const char l3c[] PROGMEM = "b"; // ctwh 196 | const char l3d[] PROGMEM = "ab"; // actwh 197 | const char l3e[] PROGMEM = ""; // sctwh 198 | const char l3f[] PROGMEM = "abb"; // asctwh 199 | const char l40[] PROGMEM = "n"; 200 | const char l41[] PROGMEM = "an"; // an 201 | const char l42[] PROGMEM = "sn"; // sn 202 | const char l43[] PROGMEM = "ann"; // asn 203 | const char l44[] PROGMEM = "z"; // cn 204 | const char l45[] PROGMEM = "az"; // acn 205 | const char l46[] PROGMEM = "ss"; // scn 206 | const char l47[] PROGMEM = "ass"; // ascn 207 | const char l48[] PROGMEM = "v"; // tn 208 | const char l49[] PROGMEM = "av"; // atn 209 | const char l4a[] PROGMEM = "sv"; // stn 210 | const char l4b[] PROGMEM = ""; // astn 211 | const char l4c[] PROGMEM = "dev"; // ctn 212 | const char l4d[] PROGMEM = "adv"; // actn 213 | const char l4e[] PROGMEM = "gn"; // sctn 214 | const char l4f[] PROGMEM = "agn"; // asctn 215 | const char l50[] PROGMEM = "m"; // wn 216 | const char l51[] PROGMEM = "am"; // awn 217 | const char l52[] PROGMEM = "sm"; // swn 218 | const char l53[] PROGMEM = "asm"; // aswn 219 | const char l54[] PROGMEM = "pn"; // cwn 220 | const char l55[] PROGMEM = "amm"; // acwn 221 | const char l56[] PROGMEM = ""; // scwn 222 | const char l57[] PROGMEM = "app"; // ascwn 223 | const char l58[] PROGMEM = "j"; // twn 224 | const char l59[] PROGMEM = "aj"; // atwn 225 | const char l5a[] PROGMEM = ""; // stwn 226 | const char l5b[] PROGMEM = ""; // astwn 227 | const char l5c[] PROGMEM = "dem"; // ctwn 228 | const char l5d[] PROGMEM = "adm"; // actwn 229 | const char l5e[] PROGMEM = ""; // sctwn 230 | const char l5f[] PROGMEM = "adj"; // asctwn 231 | const char l60[] PROGMEM = "y"; // hn 232 | const char l61[] PROGMEM = "ay"; // ahn 233 | const char l62[] PROGMEM = "sy"; // shn 234 | const char l63[] PROGMEM = "asy"; // ashn 235 | const char l64[] PROGMEM = "cy"; // chn 236 | const char l65[] PROGMEM = "acc"; // achn 237 | const char l66[] PROGMEM = ""; // schn 238 | const char l67[] PROGMEM = ""; // aschn 239 | const char l68[] PROGMEM = "ty"; // thn 240 | const char l69[] PROGMEM = ""; // athn 241 | const char l6a[] PROGMEM = "sty"; // sthn 242 | const char l6b[] PROGMEM = ""; // asthn 243 | const char l6c[] PROGMEM = "dy"; // cthn 244 | const char l6d[] PROGMEM = "aff"; // acthn 245 | const char l6e[] PROGMEM = "gy"; // scthn 246 | const char l6f[] PROGMEM = "aft"; // ascthn 247 | const char l70[] PROGMEM = "my"; // whn 248 | const char l71[] PROGMEM = ""; // awhn 249 | const char l72[] PROGMEM = ""; // swhn 250 | const char l73[] PROGMEM = ""; // aswhn 251 | const char l74[] PROGMEM = "py"; // cwhn 252 | const char l75[] PROGMEM = ""; // acwhn 253 | const char l76[] PROGMEM = "spy"; // scwhn 254 | const char l77[] PROGMEM = "asphy"; // ascwhn 255 | const char l78[] PROGMEM = "kn"; // twhn 256 | const char l79[] PROGMEM = "ackn"; // atwhn 257 | const char l7a[] PROGMEM = "xy"; // stwhn 258 | const char l7b[] PROGMEM = ""; // astwhn 259 | const char l7c[] PROGMEM = "by"; // ctwhn 260 | const char l7d[] PROGMEM = "aby"; // actwhn 261 | const char l7e[] PROGMEM = ""; // scthnr 262 | const char l7f[] PROGMEM = "affl"; // ascthnr 263 | const char l80[] PROGMEM = "r"; 264 | const char l81[] PROGMEM = "ar"; // ar 265 | const char l82[] PROGMEM = "ser"; // sr 266 | const char l83[] PROGMEM = "arr"; // asr 267 | const char l84[] PROGMEM = "cr"; // cr 268 | const char l85[] PROGMEM = "acr"; // acr 269 | const char l86[] PROGMEM = "scr"; // scr 270 | const char l87[] PROGMEM = "ascr"; // ascr 271 | const char l88[] PROGMEM = "tr"; // tr 272 | const char l89[] PROGMEM = "atr"; // atr 273 | const char l8a[] PROGMEM = "str"; // str 274 | const char l8b[] PROGMEM = "astr"; // astr 275 | const char l8c[] PROGMEM = "dr"; // ctr 276 | const char l8d[] PROGMEM = "adr"; // actr 277 | const char l8e[] PROGMEM = "gr"; // sctr 278 | const char l8f[] PROGMEM = "agr"; // asctr 279 | const char l90[] PROGMEM = "wr"; // wr 280 | const char l91[] PROGMEM = ""; // awr 281 | const char l92[] PROGMEM = ""; // swr 282 | const char l93[] PROGMEM = ""; // aswr 283 | const char l94[] PROGMEM = "pr"; // cwr 284 | const char l95[] PROGMEM = "apr"; // acwr 285 | const char l96[] PROGMEM = "spr"; // scwr 286 | const char l97[] PROGMEM = "appr"; // ascwr 287 | const char l98[] PROGMEM = "qu"; // twr 288 | const char l99[] PROGMEM = "attr"; // atwr 289 | const char l9a[] PROGMEM = "xr"; // stwr 290 | const char l9b[] PROGMEM = ""; // astwr 291 | const char l9c[] PROGMEM = "der"; // ctwr 292 | const char l9d[] PROGMEM = "addr"; // actwr 293 | const char l9e[] PROGMEM = ""; // sctwr 294 | const char l9f[] PROGMEM = "aggr"; // asctwr 295 | const char la0[] PROGMEM = "rh"; // hr 296 | const char la1[] PROGMEM = ""; // ahr 297 | const char la2[] PROGMEM = "shr"; // shr 298 | const char la3[] PROGMEM = ""; // ashr 299 | const char la4[] PROGMEM = "chr"; // chr 300 | const char la5[] PROGMEM = "accr"; // achr 301 | const char la6[] PROGMEM = ""; // schr 302 | const char la7[] PROGMEM = ""; // aschr 303 | const char la8[] PROGMEM = "thr"; // thr 304 | const char la9[] PROGMEM = ""; // athr 305 | const char laa[] PROGMEM = ""; // sthr 306 | const char lab[] PROGMEM = ""; // asthr 307 | const char lac[] PROGMEM = "fr"; // cthr 308 | const char lad[] PROGMEM = "afr"; // acthr 309 | const char lae[] PROGMEM = ""; // scthr 310 | const char laf[] PROGMEM = "affr"; // ascthr 311 | const char lb0[] PROGMEM = ""; // whr 312 | const char lb1[] PROGMEM = ""; // awhr 313 | const char lb2[] PROGMEM = ""; // swhr 314 | const char lb3[] PROGMEM = ""; // aswhr 315 | const char lb4[] PROGMEM = "phr"; // cwhr 316 | const char lb5[] PROGMEM = "aphr"; // acwhr 317 | const char lb6[] PROGMEM = ""; // scwhr 318 | const char lb7[] PROGMEM = ""; // ascwhr 319 | const char lb8[] PROGMEM = "kr"; // twhr 320 | const char lb9[] PROGMEM = ""; // atwhr 321 | const char lba[] PROGMEM = ""; // stwhr 322 | const char lbb[] PROGMEM = ""; // astwhr 323 | const char lbc[] PROGMEM = "br"; // ctwhr 324 | const char lbd[] PROGMEM = "abr"; // actwhr 325 | const char lbe[] PROGMEM = ""; // sctwhr 326 | const char lbf[] PROGMEM = "abbr"; // asctwhr 327 | const char lc0[] PROGMEM = "l"; // nr 328 | const char lc1[] PROGMEM = "al"; // anr 329 | const char lc2[] PROGMEM = "sl"; // snr 330 | const char lc3[] PROGMEM = "asl"; // asnr 331 | const char lc4[] PROGMEM = "cl"; // cnr 332 | const char lc5[] PROGMEM = ""; // acnr 333 | const char lc6[] PROGMEM = ""; // scnr 334 | const char lc7[] PROGMEM = ""; // ascnr 335 | const char lc8[] PROGMEM = "q"; // tnr 336 | const char lc9[] PROGMEM = "aq"; // atnr 337 | const char lca[] PROGMEM = "sq"; // stnr 338 | const char lcb[] PROGMEM = "asq"; // astnr 339 | const char lcc[] PROGMEM = "del"; // ctnr 340 | const char lcd[] PROGMEM = "acq"; // actnr 341 | const char lce[] PROGMEM = "gl"; // sctnr 342 | const char lcf[] PROGMEM = "agl"; // asctnr 343 | const char ld0[] PROGMEM = "mr"; // wnr 344 | const char ld1[] PROGMEM = "all"; // awnr 345 | const char ld2[] PROGMEM = ""; // swnr 346 | const char ld3[] PROGMEM = ""; // aswnr 347 | const char ld4[] PROGMEM = "pl"; // cwnr 348 | const char ld5[] PROGMEM = "apl"; // acwnr 349 | const char ld6[] PROGMEM = "spl"; // scwnr 350 | const char ld7[] PROGMEM = "appl"; // ascwnr 351 | const char ld8[] PROGMEM = "jer"; // twnr 352 | const char ld9[] PROGMEM = ""; // atwnr 353 | const char lda[] PROGMEM = "serv"; // stwnr 354 | const char ldb[] PROGMEM = ""; // astwnr 355 | const char ldc[] PROGMEM = ""; // ctwnr 356 | const char ldd[] PROGMEM = "addl"; // actwnr 357 | const char lde[] PROGMEM = ""; // sctwnr 358 | const char ldf[] PROGMEM = "aggl"; // asctwnr 359 | const char le0[] PROGMEM = "ly"; // hnr 360 | const char le1[] PROGMEM = ""; // ahnr 361 | const char le2[] PROGMEM = "sly"; // shnr 362 | const char le3[] PROGMEM = ""; // ashnr 363 | const char le4[] PROGMEM = "cry"; // chnr 364 | const char le5[] PROGMEM = "accl"; // achnr 365 | const char le6[] PROGMEM = ""; // schnr 366 | const char le7[] PROGMEM = ""; // aschnr 367 | const char le8[] PROGMEM = "try"; // thnr 368 | const char le9[] PROGMEM = "athl"; // athnr 369 | const char lea[] PROGMEM = "stry"; // sthnr 370 | const char leb[] PROGMEM = ""; // asthnr 371 | const char lec[] PROGMEM = "fl"; // cthnr 372 | const char led[] PROGMEM = "afl"; // acthnr 373 | const char lee[] PROGMEM = ""; // scthnr 374 | const char lef[] PROGMEM = "affl"; // ascthnr 375 | const char lf0[] PROGMEM = ""; // whnr 376 | const char lf1[] PROGMEM = ""; // awhnr 377 | const char lf2[] PROGMEM = ""; // swhnr 378 | const char lf3[] PROGMEM = ""; // aswhnr 379 | const char lf4[] PROGMEM = "phl"; // cwhnr 380 | const char lf5[] PROGMEM = ""; // acwhnr 381 | const char lf6[] PROGMEM = ""; // scwhnr 382 | const char lf7[] PROGMEM = ""; // ascwhnr 383 | const char lf8[] PROGMEM = "kl"; // twhnr 384 | const char lf9[] PROGMEM = ""; // atwhnr 385 | const char lfa[] PROGMEM = ""; // stwhnr 386 | const char lfb[] PROGMEM = ""; // astwhnr 387 | const char lfc[] PROGMEM = "bl"; // ctwhnr 388 | const char lfd[] PROGMEM = "abl"; // actwhnr 389 | const char lfe[] PROGMEM = ""; // sctwhnr 390 | const char lff[] PROGMEM = ""; // asctwhnr 391 | 392 | const char* const left_side[] PROGMEM = { 393 | l00, l01, l02, l03, l04, l05, l06, l07, 394 | l08, l09, l0a, l0b, l0c, l0d, l0e, l0f, 395 | l10, l11, l12, l13, l14, l15, l16, l17, 396 | l18, l19, l1a, l1b, l1c, l1d, l1e, l1f, 397 | l20, l21, l22, l23, l24, l25, l26, l27, 398 | l28, l29, l2a, l2b, l2c, l2d, l2e, l2f, 399 | l30, l31, l32, l33, l34, l35, l36, l37, 400 | l38, l39, l3a, l3b, l3c, l3d, l3e, l3f, 401 | l40, l41, l43, l43, l44, l45, l46, l47, 402 | l48, l49, l4a, l4b, l4c, l4d, l4e, l4f, 403 | l50, l51, l52, l53, l54, l55, l56, l57, 404 | l58, l59, l5a, l5b, l5c, l5d, l5e, l5f, 405 | l60, l61, l62, l63, l64, l65, l66, l67, 406 | l68, l69, l6a, l6b, l6c, l6d, l6e, l6f, 407 | l70, l71, l72, l73, l74, l75, l76, l77, 408 | l78, l79, l7a, l7b, l7c, l7d, l7e, l7f, 409 | l80, l81, l82, l83, l84, l85, l86, l87, 410 | l88, l89, l8a, l8b, l8c, l8d, l8e, l8f, 411 | l90, l91, l92, l93, l94, l95, l96, l97, 412 | l98, l99, l9a, l9b, l9c, l9d, l9e, l9f, 413 | la0, la1, la2, la3, la4, la5, la6, la7, 414 | la8, la9, laa, lab, lac, lad, lae, laf, 415 | lb0, lb1, lb2, lb3, lb4, lb5, lb6, lb7, 416 | lb8, lb9, lba, lbb, lbc, lbd, lbe, lbf, 417 | lc0, lc1, lc2, lc3, lc4, lc5, lc6, lc7, 418 | lc8, lc9, lca, lcb, lcc, lcd, lce, lcf, 419 | ld0, ld1, ld2, ld3, ld4, ld5, ld6, ld7, 420 | ld8, ld9, lda, ldb, ldc, ldd, lde, ldf, 421 | le0, le1, le2, le3, le4, le5, le6, le7, 422 | le8, le9, lea, leb, lec, led, lee, lef, 423 | lf0, lf1, lf2, lf3, lf4, lf5, lf6, lf7, 424 | lf8, lf9, lfa, lfb, lfc, lfd, lfe, lff 425 | }; 426 | 427 | // lookup string using key stroke as index and print it 428 | void sendLeft() { 429 | char buffer[10]; 430 | strcpy_P(buffer, (char*)pgm_read_word(&(left_side[left]))); 431 | spit(buffer); 432 | } 433 | 434 | void sendCenter () { 435 | if (center & 0x01) { 436 | if ((controller & 0x01) | (controller & 0x02)) { 437 | spit ("u"); 438 | } else { 439 | spit ("i"); 440 | } 441 | } 442 | if (center & 0x02) { 443 | if ((controller & 0x01) | (controller & 0x02)) { 444 | spit ("o"); 445 | } else { 446 | spit ("e"); 447 | } 448 | } 449 | if (center & 0x04) spit ("a"); 450 | if (center & 0x08) { 451 | if ((controller & 0x04) | (controller & 0x08)) { 452 | spit ("e"); 453 | } else { 454 | spit ("o"); 455 | } 456 | } 457 | if (center & 0x10) { 458 | if ((controller & 0x04) | (controller & 0x08)) { 459 | spit ("i"); 460 | } else { 461 | spit ("u"); 462 | } 463 | } 464 | } 465 | 466 | // right hand strings 467 | const char r00[] PROGMEM = ""; 468 | const char r01[] PROGMEM = "r"; 469 | const char r02[] PROGMEM = "n"; 470 | const char r03[] PROGMEM = "rn"; 471 | const char r04[] PROGMEM = "l"; 472 | const char r05[] PROGMEM = "rl"; 473 | const char r06[] PROGMEM = "s"; 474 | const char r07[] PROGMEM = "ll"; // rnl 475 | const char r08[] PROGMEM = "g"; 476 | const char r09[] PROGMEM = "rg"; 477 | const char r0a[] PROGMEM = "ng"; 478 | const char r0b[] PROGMEM = "gn"; // rng 479 | const char r0c[] PROGMEM = "lg"; 480 | const char r0d[] PROGMEM = ""; 481 | const char r0e[] PROGMEM = "d"; // npg 482 | const char r0f[] PROGMEM = "dl"; // rnlg 483 | const char r10[] PROGMEM = "c"; 484 | const char r11[] PROGMEM = "rc"; 485 | const char r12[] PROGMEM = "nc"; 486 | const char r13[] PROGMEM = ""; 487 | const char r14[] PROGMEM = "p"; // lc 488 | const char r15[] PROGMEM = "rp"; // rlc 489 | const char r16[] PROGMEM = "sp"; // nlc 490 | const char r17[] PROGMEM = "pl"; // rnlc 491 | const char r18[] PROGMEM = "b"; // gc 492 | const char r19[] PROGMEM = "rb"; 493 | const char r1a[] PROGMEM = "gg"; 494 | const char r1b[] PROGMEM = ""; 495 | const char r1c[] PROGMEM = "bl"; 496 | const char r1d[] PROGMEM = ""; 497 | const char r1e[] PROGMEM = "ld"; // CWS 25Jan20 498 | const char r1f[] PROGMEM = "lb"; 499 | const char r20[] PROGMEM = "h"; 500 | const char r21[] PROGMEM = "w"; 501 | const char r22[] PROGMEM = "v"; 502 | const char r23[] PROGMEM = "wn"; 503 | const char r24[] PROGMEM = "z"; 504 | const char r25[] PROGMEM = "wl"; 505 | const char r26[] PROGMEM = "sh"; 506 | const char r27[] PROGMEM = "lv"; 507 | const char r28[] PROGMEM = "gh"; 508 | const char r29[] PROGMEM = "rgh"; 509 | const char r2a[] PROGMEM = "m"; 510 | const char r2b[] PROGMEM = "rm"; 511 | const char r2c[] PROGMEM = "x"; 512 | const char r2d[] PROGMEM = ""; 513 | const char r2e[] PROGMEM = "sm"; 514 | const char r2f[] PROGMEM = "lm"; 515 | const char r30[] PROGMEM = "ch"; 516 | const char r31[] PROGMEM = "rch"; 517 | const char r32[] PROGMEM = "nch"; 518 | const char r33[] PROGMEM = "rv"; 519 | const char r34[] PROGMEM = "ph"; 520 | const char r35[] PROGMEM = ""; 521 | const char r36[] PROGMEM = ""; 522 | const char r37[] PROGMEM = "lch"; 523 | const char r38[] PROGMEM = "f"; 524 | const char r39[] PROGMEM = "rf"; 525 | const char r3a[] PROGMEM = "mb"; 526 | const char r3b[] PROGMEM = ""; 527 | const char r3c[] PROGMEM = "lf"; 528 | const char r3d[] PROGMEM = ""; 529 | const char r3e[] PROGMEM = "mp"; 530 | const char r3f[] PROGMEM = ""; 531 | const char r40[] PROGMEM = "t"; 532 | const char r41[] PROGMEM = "rt"; 533 | const char r42[] PROGMEM = "nt"; 534 | const char r43[] PROGMEM = "rnt"; 535 | const char r44[] PROGMEM = "lt"; 536 | const char r45[] PROGMEM = ""; 537 | const char r46[] PROGMEM = "st"; 538 | const char r47[] PROGMEM = "rst"; 539 | const char r48[] PROGMEM = "k"; 540 | const char r49[] PROGMEM = "rk"; 541 | const char r4a[] PROGMEM = "nk"; 542 | const char r4b[] PROGMEM = ""; 543 | const char r4c[] PROGMEM = "kl"; 544 | const char r4d[] PROGMEM = ""; 545 | const char r4e[] PROGMEM = "sk"; 546 | const char r4f[] PROGMEM = "lk"; 547 | const char r50[] PROGMEM = "ct"; 548 | const char r51[] PROGMEM = ""; 549 | const char r52[] PROGMEM = "tion"; 550 | const char r53[] PROGMEM = "ction"; // CWS 25Jan20 551 | const char r54[] PROGMEM = "pt"; 552 | const char r55[] PROGMEM = ""; 553 | const char r56[] PROGMEM = "nst"; 554 | const char r57[] PROGMEM = "lp"; 555 | const char r58[] PROGMEM = "ck"; 556 | const char r59[] PROGMEM = ""; 557 | const char r5a[] PROGMEM = "bt"; 558 | const char r5b[] PROGMEM = ""; 559 | const char r5c[] PROGMEM = "ckl"; 560 | const char r5d[] PROGMEM = ""; 561 | const char r5e[] PROGMEM = ""; 562 | const char r5f[] PROGMEM = ""; 563 | const char r60[] PROGMEM = "th"; 564 | const char r61[] PROGMEM = "rth"; 565 | const char r62[] PROGMEM = "nth"; 566 | const char r63[] PROGMEM = "wth"; 567 | const char r64[] PROGMEM = "lth"; 568 | const char r65[] PROGMEM = ""; 569 | const char r66[] PROGMEM = ""; 570 | const char r67[] PROGMEM = ""; 571 | const char r68[] PROGMEM = "ght"; 572 | const char r69[] PROGMEM = "wk"; 573 | const char r6a[] PROGMEM = "ngth"; 574 | const char r6b[] PROGMEM = ""; 575 | const char r6c[] PROGMEM = "xt"; 576 | const char r6d[] PROGMEM = ""; 577 | const char r6e[] PROGMEM = "dth"; 578 | const char r6f[] PROGMEM = ""; 579 | const char r70[] PROGMEM = "tch"; 580 | const char r71[] PROGMEM = ""; 581 | const char r72[] PROGMEM = ""; 582 | const char r73[] PROGMEM = ""; 583 | const char r74[] PROGMEM = "pth"; 584 | const char r75[] PROGMEM = ""; 585 | const char r76[] PROGMEM = ""; 586 | const char r77[] PROGMEM = ""; 587 | const char r78[] PROGMEM = "ft"; 588 | const char r79[] PROGMEM = ""; 589 | const char r7a[] PROGMEM = ""; 590 | const char r7b[] PROGMEM = ""; 591 | const char r7c[] PROGMEM = ""; 592 | const char r7d[] PROGMEM = ""; 593 | const char r7e[] PROGMEM = "mpt"; 594 | const char r7f[] PROGMEM = ""; 595 | const char r80[] PROGMEM = "s"; 596 | const char r81[] PROGMEM = "rs"; 597 | const char r82[] PROGMEM = "ns"; 598 | const char r83[] PROGMEM = "rns"; 599 | const char r84[] PROGMEM = "ls"; 600 | const char r85[] PROGMEM = "rls"; 601 | const char r86[] PROGMEM = "ss"; 602 | const char r87[] PROGMEM = "lls"; 603 | const char r88[] PROGMEM = "gs"; 604 | const char r89[] PROGMEM = "rgs"; 605 | const char r8a[] PROGMEM = "ngs"; 606 | const char r8b[] PROGMEM = "gns"; 607 | const char r8c[] PROGMEM = ""; 608 | const char r8d[] PROGMEM = ""; 609 | const char r8e[] PROGMEM = "ds"; 610 | const char r8f[] PROGMEM = ""; 611 | const char r90[] PROGMEM = "cs"; 612 | const char r91[] PROGMEM = "rcs"; 613 | const char r92[] PROGMEM = "nces"; 614 | const char r93[] PROGMEM = ""; 615 | const char r94[] PROGMEM = "ps"; 616 | const char r95[] PROGMEM = "rps"; 617 | const char r96[] PROGMEM = "sps"; 618 | const char r97[] PROGMEM = "ples"; 619 | const char r98[] PROGMEM = "bs"; 620 | const char r99[] PROGMEM = "rbs"; 621 | const char r9a[] PROGMEM = "ggs"; 622 | const char r9b[] PROGMEM = ""; 623 | const char r9c[] PROGMEM = "bles"; 624 | const char r9d[] PROGMEM = ""; 625 | const char r9e[] PROGMEM = "lds"; 626 | const char r9f[] PROGMEM = "lbs"; 627 | const char ra0[] PROGMEM = "hs"; 628 | const char ra1[] PROGMEM = "ws"; 629 | const char ra2[] PROGMEM = "ves"; 630 | const char ra3[] PROGMEM = "wns"; 631 | const char ra4[] PROGMEM = "zes"; 632 | const char ra5[] PROGMEM = "wls"; 633 | const char ra6[] PROGMEM = "shes"; 634 | const char ra7[] PROGMEM = "lves"; 635 | const char ra8[] PROGMEM = "ghs"; 636 | const char ra9[] PROGMEM = ""; 637 | const char raa[] PROGMEM = "ms"; 638 | const char rab[] PROGMEM = "rms"; 639 | const char rac[] PROGMEM = "xes"; 640 | const char rad[] PROGMEM = ""; 641 | const char rae[] PROGMEM = "sms"; 642 | const char raf[] PROGMEM = "lms"; 643 | const char rb0[] PROGMEM = "d"; 644 | const char rb1[] PROGMEM = "rd"; 645 | const char rb2[] PROGMEM = "nd"; 646 | const char rb3[] PROGMEM = "wd"; 647 | const char rb4[] PROGMEM = "phs"; 648 | const char rb5[] PROGMEM = "rld"; 649 | const char rb6[] PROGMEM = ""; 650 | const char rb7[] PROGMEM = "ld"; 651 | const char rb8[] PROGMEM = "dg"; 652 | const char rb9[] PROGMEM = ""; 653 | const char rba[] PROGMEM = "mbs"; 654 | const char rbb[] PROGMEM = ""; 655 | const char rbc[] PROGMEM = ""; 656 | const char rbd[] PROGMEM = ""; 657 | const char rbe[] PROGMEM = "mps"; 658 | const char rbf[] PROGMEM = "dd"; 659 | const char rc0[] PROGMEM = "ts"; 660 | const char rc1[] PROGMEM = "rts"; 661 | const char rc2[] PROGMEM = "nts"; 662 | const char rc3[] PROGMEM = ""; 663 | const char rc4[] PROGMEM = "lts"; 664 | const char rc5[] PROGMEM = ""; 665 | const char rc6[] PROGMEM = "sts"; 666 | const char rc7[] PROGMEM = "rsts"; 667 | const char rc8[] PROGMEM = "ks"; 668 | const char rc9[] PROGMEM = "rks"; 669 | const char rca[] PROGMEM = "nks"; 670 | const char rcb[] PROGMEM = ""; 671 | const char rcc[] PROGMEM = ""; 672 | const char rcd[] PROGMEM = ""; 673 | const char rce[] PROGMEM = "sks"; 674 | const char rcf[] PROGMEM = "lks"; 675 | const char rd0[] PROGMEM = "cts"; 676 | const char rd1[] PROGMEM = ""; 677 | const char rd2[] PROGMEM = ""; 678 | const char rd3[] PROGMEM = ""; 679 | const char rd4[] PROGMEM = ""; 680 | const char rd5[] PROGMEM = ""; 681 | const char rd6[] PROGMEM = ""; 682 | const char rd7[] PROGMEM = "lps"; 683 | const char rd8[] PROGMEM = "cks"; 684 | const char rd9[] PROGMEM = ""; 685 | const char rda[] PROGMEM = "bts"; 686 | const char rdb[] PROGMEM = ""; 687 | const char rdc[] PROGMEM = "ckles"; 688 | const char rdd[] PROGMEM = ""; 689 | const char rde[] PROGMEM = ""; 690 | const char rdf[] PROGMEM = ""; 691 | const char re0[] PROGMEM = "ths"; 692 | const char re1[] PROGMEM = "rths"; 693 | const char re2[] PROGMEM = "nths"; 694 | const char re3[] PROGMEM = "wths"; 695 | const char re4[] PROGMEM = ""; 696 | const char re5[] PROGMEM = ""; 697 | const char re6[] PROGMEM = ""; 698 | const char re7[] PROGMEM = ""; 699 | const char re8[] PROGMEM = "ghts"; 700 | const char re9[] PROGMEM = "wks"; 701 | const char rea[] PROGMEM = "ngths"; 702 | const char reb[] PROGMEM = ""; 703 | const char rec[] PROGMEM = ""; 704 | const char red[] PROGMEM = ""; 705 | const char ree[] PROGMEM = "dths"; 706 | const char ref[] PROGMEM = ""; 707 | const char rf0[] PROGMEM = "ds"; 708 | const char rf1[] PROGMEM = "rds"; 709 | const char rf2[] PROGMEM = "nds"; 710 | const char rf3[] PROGMEM = "wds"; 711 | const char rf4[] PROGMEM = "pths"; 712 | const char rf5[] PROGMEM = "rlds"; 713 | const char rf6[] PROGMEM = ""; 714 | const char rf7[] PROGMEM = "lds"; 715 | const char rf8[] PROGMEM = ""; 716 | const char rf9[] PROGMEM = ""; 717 | const char rfa[] PROGMEM = ""; 718 | const char rfb[] PROGMEM = ""; 719 | const char rfc[] PROGMEM = ""; 720 | const char rfd[] PROGMEM = ""; 721 | const char rfe[] PROGMEM = "mpts"; 722 | const char rff[] PROGMEM = ""; 723 | 724 | const char* const right_side[] PROGMEM = { 725 | r00, r01, r02, r03, r04, r05, r06, r07, 726 | r08, r09, r0a, r0b, r0c, r0d, r0e, r0f, 727 | r10, r11, r12, r13, r14, r15, r16, r17, 728 | r18, r19, r1a, r1b, r1c, r1d, r1e, r1f, 729 | r20, r21, r22, r23, r24, r25, r26, r27, 730 | r28, r29, r2a, r2b, r2c, r2d, r2e, r2f, 731 | r30, r31, r32, r33, r34, r35, r36, r37, 732 | r38, r39, r3a, r3b, r3c, r3d, r3e, r3f, 733 | r40, r41, r42, r43, r44, r45, r46, r47, 734 | r48, r49, r4a, r4b, r4c, r4d, r4e, r4f, 735 | r50, r51, r52, r53, r54, r55, r56, r57, 736 | r58, r59, r5a, r5b, r5c, r5d, r5e, r5f, 737 | r60, r62, r62, r63, r64, r65, r66, r67, 738 | r68, r69, r6a, r6b, r6c, r6d, r6e, r6f, 739 | r70, r71, r72, r73, r74, r75, r76, r77, 740 | r78, r79, r7a, r7b, r7c, r7d, r7e, r7f, 741 | r80, r81, r82, r83, r84, r85, r86, r87, 742 | r88, r89, r8a, r8b, r8c, r8d, r8e, r8f, 743 | r90, r91, r92, r93, r94, r95, r96, r97, 744 | r98, r99, r9a, r9b, r9c, r9d, r9e, r9f, 745 | ra0, ra2, ra2, ra3, ra4, ra5, ra6, ra7, 746 | ra8, ra9, raa, rab, rac, rad, rae, raf, 747 | rb0, rb1, rb2, rb3, rb4, rb5, rb6, rb7, 748 | rb8, rb9, rba, rbb, rbc, rbd, rbe, rbf, 749 | rc0, rc1, rc2, rc3, rc4, rc5, rc6, rc7, 750 | rc8, rc9, rca, rcb, rcc, rcd, rce, rcf, 751 | rd0, rd1, rd2, rd3, rd4, rd5, rd6, rd7, 752 | rd8, rd9, rda, rdb, rdc, rdd, rde, rdf, 753 | re0, re2, re2, re3, re4, re5, re6, re7, 754 | re8, re9, rea, reb, rec, red, ree, ref, 755 | rf0, rf1, rf2, rf3, rf4, rf5, rf6, rf7, 756 | rf8, rf9, rfa, rfb, rfc, rfd, rfe, rff, 757 | }; 758 | 759 | void sendRight() { 760 | char buffer[10]; 761 | if(right == 0x0c) { 762 | if(ykey) { 763 | strcpy(buffer, "logy"); 764 | spit(buffer); 765 | return; 766 | } 767 | } 768 | if(right == 0x50) { 769 | if (ekey) { 770 | strcpy(buffer, "cate"); 771 | spit(buffer); 772 | return; 773 | } 774 | } 775 | if(right == 0xc0){ 776 | if (ykey) { 777 | strcpy(buffer, "ys"); 778 | spit(buffer); 779 | return; 780 | } 781 | } 782 | if(right == 0xc8) { 783 | if (ekey) { 784 | strcpy(buffer, "kes"); 785 | spit(buffer); 786 | return; 787 | } 788 | } 789 | // lookup string using stroke as index and print 790 | strcpy_P(buffer, (char*)pgm_read_word(&(right_side[right]))); 791 | spit(buffer); 792 | if (ekey) spit("e"); 793 | if (ykey) spit("y"); 794 | } 795 | 796 | // if we're here then the number key was pressed 797 | void numbers () { 798 | // if (serial_keys2 & 0x0100) { 799 | if (controller == 0x04) { 800 | if (right & 0x40) spit ("9"); 801 | if (right & 0x10) spit ("8"); 802 | if (right & 0x04) spit ("7"); 803 | if (right & 0x01) spit ("6"); 804 | if (center & 0x02) spit ("0"); 805 | if (center & 0x01) spit ("5"); 806 | if (left & 0x40) spit ("4"); 807 | if (left & 0x10) spit ("3"); 808 | if (left & 0x04) spit ("2"); 809 | if (left & 0x01) spit ("1"); 810 | } else { 811 | if (left & 0x01) spit ("1"); 812 | if (left & 0x04) spit ("2"); 813 | if (left & 0x10) spit ("3"); 814 | if (left & 0x40) spit ("4"); 815 | if (center & 0x01) spit ("5"); 816 | if (center & 0x02) spit ("0"); 817 | if (right & 0x01) spit ("6"); 818 | if (right & 0x04) spit ("7"); 819 | if (right & 0x10) spit ("8"); 820 | if (right & 0x40) spit ("9"); 821 | } 822 | } 823 | 824 | void unspace () { 825 | Keyboard.press (KEY_LEFT_CTRL); 826 | Keyboard.write (KEY_LEFT_ARROW); 827 | Keyboard.release (KEY_LEFT_CTRL); 828 | Keyboard.write (KEY_BACKSPACE); 829 | Keyboard.press (KEY_LEFT_CTRL); 830 | Keyboard.write (KEY_RIGHT_ARROW); 831 | Keyboard.release (KEY_LEFT_CTRL); 832 | } 833 | 834 | void run() { 835 | scan (); 836 | organize (); 837 | // ...x not o or u 838 | if ((controller == 0x08) & ((center & 0x18) == 0)) { 839 | caps = true; 840 | } 841 | // .xx. no vowels 842 | if ((controller == 0x06) & (center == 0)) { 843 | autospace = !autospace; 844 | return; 845 | } 846 | // x..x no vowels 847 | if ((controller == 0x09) & (center == 0)) Keyboard.write (KEY_CAPS_LOCK); 848 | // if (spacing & number) { 849 | if (spacing & !number & (center == 0) & (right == 0)) { 850 | if (left == 0xaa) { 851 | Keyboard.write (KEY_DELETE); return; 852 | } 853 | if (left == 0) { 854 | Keyboard.write (KEY_BACKSPACE); return; 855 | } 856 | } 857 | if (number & (left == 0) & (right == 0) 858 | & (center == 0) & (controller == 0)) { 859 | Keyboard.print (" "); 860 | } 861 | if (number) { 862 | numbers (); 863 | return; 864 | } 865 | if ((center == 0) & (left == 0xa0) & (right == 0x0a)) { 866 | Keyboard.write (KEY_RETURN); return; 867 | } 868 | if ((center == 0) & (left == 0x50) & (right == 0x05)) { 869 | Keyboard.write (KEY_TAB); return; 870 | } 871 | if ((left == 0x55) & (right == 0x55)) { 872 | Keyboard.write (KEY_ESC); return; 873 | } 874 | if (left == 0xaa) { 875 | if ((right == 0) & (center == 0) & !number & !spacing) { 876 | Keyboard.releaseAll (); return; 877 | } 878 | if (right == 0x2a) {unspace (); return;} 879 | if (right == 0x0a) { 880 | Keyboard.press (KEY_LEFT_CTRL); 881 | Keyboard.write (KEY_LEFT_ARROW); 882 | Keyboard.release (KEY_LEFT_CTRL); 883 | return; 884 | } 885 | if (right == 0x28) { 886 | Keyboard.press (KEY_LEFT_CTRL); 887 | Keyboard.write (KEY_RIGHT_ARROW); 888 | Keyboard.release (KEY_LEFT_CTRL); 889 | return; 890 | } 891 | if (center == 0x01) Keyboard.press (KEY_LEFT_SHIFT); 892 | if (center == 0x02) Keyboard.press (KEY_LEFT_CTRL); 893 | if (center == 0x08) Keyboard.press (KEY_LEFT_ALT); 894 | if (center == 0x10) Keyboard.press (KEY_LEFT_GUI); 895 | if (spacing & number) { 896 | Keyboard.write (KEY_DELETE); 897 | return; 898 | } 899 | if (right == 0x01) { 900 | Keyboard.write (KEY_HOME); 901 | return; 902 | } 903 | if (right == 0x40) { 904 | Keyboard.write (KEY_END); 905 | return; 906 | } 907 | if (right == 0x04) { 908 | Keyboard.write (KEY_PAGE_UP); 909 | return; 910 | } 911 | if (right == 0x10) { 912 | Keyboard.write (KEY_PAGE_DOWN); 913 | return; 914 | } 915 | if (right == 0x02) { 916 | Keyboard.write (KEY_LEFT_ARROW); 917 | // Keyboard.releaseAll (); 918 | return; 919 | } 920 | if (right == 0x08) { 921 | Keyboard.write (KEY_UP_ARROW); 922 | // Keyboard.releaseAll (); 923 | return; 924 | } 925 | if (right == 0x20) { 926 | Keyboard.write (KEY_DOWN_ARROW); 927 | // Keyboard.releaseAll (); 928 | return; 929 | } 930 | if (right == 0x80) { 931 | Keyboard.write (KEY_RIGHT_ARROW); 932 | // Keyboard.releaseAll (); 933 | return; 934 | } 935 | return; 936 | } 937 | if (right == 0x55) { 938 | if (left == 0x90) spit ("("); 939 | if (left == 0xb0) spit ("["); 940 | if (left == 0x94) spit ("{"); 941 | if (left == 0x98) spit ("<"); 942 | if (left == 0x03) spit (":"); 943 | if (left == 0x0c) spit ("\""); 944 | if (left == 0x30) spit ("|"); 945 | if (left == 0x05) spit ("@"); 946 | if (left == 0x0a) spit ("$"); 947 | if (left == 0x50) spit ("-"); 948 | if (left == 0xa0) spit ("^"); 949 | if (left == 0x5a) spit ("/"); 950 | if (left == 0xc0) spit ("+"); 951 | if (left == 0xf0) spit ("*"); 952 | if (left == 0x01) spit ("."); 953 | if (left == 0x04) spit (","); 954 | if (left == 0x10) spit ("?"); 955 | if (left == 0x40) spit ("!"); 956 | return; 957 | } 958 | if (right == 0xa9) { 959 | if (left == 0x90) spit (")"); 960 | if (left == 0xb0) spit ("]"); 961 | if (left == 0x94) spit ("}"); 962 | if (left == 0x98) spit (">"); 963 | if (left == 0x03) spit (";"); 964 | if (left == 0x0c) spit ("\'"); 965 | if (left == 0x30) spit ("~"); 966 | if (left == 0x05) spit ("#"); 967 | if (left == 0x0a) spit ("%"); 968 | if (left == 0x50) spit ("_"); 969 | if (left == 0xa0) spit ("&"); 970 | if (left == 0x5a) spit ("\\"); 971 | if (left == 0xc0) spit ("="); 972 | return; 973 | } 974 | if ((left == 0x14) & (center == 0)) { 975 | if (right == 0x14) {spit ("."); caps = true; return;} 976 | if (right == 0x28) {spit ("!"); caps = true; return;} 977 | } 978 | if ((left == 0x28) & (center == 0)) { 979 | if (right == 0x14) {spit ("?"); caps = true; return;} 980 | if (right == 0x28) {spit (","); return;} 981 | } 982 | // if ((spacing) & (center == 0) & (left == 0) & 983 | // (right == 0) & (controller == 0) & (!ekey) & (!ykey)) { 984 | // Keyboard.print (" "); 985 | // return; 986 | // } 987 | if (((spacing) & (!autospace)) | ((!spacing) & (autospace))) { 988 | Keyboard.print (" "); 989 | // spacing = false; 990 | } 991 | sendLeft(); 992 | sendCenter(); 993 | sendRight(); 994 | } 995 | 996 | void setup() { 997 | Serial.begin (9600); 998 | Keyboard.begin (); 999 | // raw pins 1000 | pinMode (A1, INPUT_PULLUP); 1001 | pinMode (A2, INPUT_PULLUP); 1002 | pinMode (A3, INPUT_PULLUP); 1003 | pinMode (A4, INPUT_PULLUP); 1004 | // port expander pins 1005 | Wire.begin (); 1006 | Wire.beginTransmission (i2c1); 1007 | Wire.write (0x0c); //GPPUA 1008 | Wire.write (0xff); 1009 | Wire.write (0xff); 1010 | Wire.endTransmission (); 1011 | Wire.begin (); 1012 | Wire.beginTransmission (i2c2); 1013 | Wire.write (0x0c); //GPPUA 1014 | Wire.write (0xff); 1015 | Wire.write (0xff); 1016 | Wire.endTransmission (); 1017 | delay (3000); 1018 | } 1019 | 1020 | void loop () { 1021 | run (); 1022 | } 1023 | -------------------------------------------------------------------------------- /mux_steno_Jackdaw.ino: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | // Multiplexed Steno Keyboard 4 | // This example program is in the public domain 5 | // modified August 5, 2018 to make row pins HIGH 6 | // for the diodes. 7 | // modified August 18-19 for NKRO protocol 8 | // modified February 12, 2019 for Jackdaw 9 | 10 | boolean pressed; 11 | 12 | // four bytes for the TX Bolt protocol 13 | #define NO_BYTES 4 14 | byte data[NO_BYTES]; 15 | 16 | // matrix wiring 17 | #define NO_ROWS 4 18 | const byte row[]={9, 10, 11, 12}; 19 | #define NO_COLS 6 20 | const byte column[]={A0, A1, A2, A3, A4, A5}; 21 | 22 | // parts of the keyboard 23 | byte left = 0; 24 | byte center = 0; 25 | byte right = 0; 26 | boolean star = false; 27 | boolean number = false; 28 | boolean caps = false; 29 | boolean vowels = false; 30 | boolean leaving = false; 31 | boolean spacing = false; 32 | 33 | void setup() { 34 | for(int i=0; i"); return true;} // n angle 240 | if(left == 0xc2) {spit("\""); return true;} // sl backslash 241 | if(left == 0x08) {spit("'"); return true;} // t tick 242 | if(left == 0x02) {spit("*"); return true;} // star 243 | } 244 | } 245 | return false; 246 | } 247 | 248 | boolean briefs() { // after "maybeSpace()" 249 | if((center == 0x0c) & (left == 0xaa)) { 250 | spit("I"); spacing = true; caps = false; return true; 251 | } 252 | if(center == 0) { 253 | if (right == 0x55) { // rlct 254 | if (left == 0x08) {spit("~"); return true;} // Tilde 255 | if (left == 0x60) {spit("@"); return true;} // Yat 256 | if (left == 0x20) {spit("#"); return true;} // Hash 257 | if (left == 0x0c) {spit("$"); return true;} // Dollar 258 | if (left == 0x14) {spit("%"); return true;} // Percent 259 | if (left == 0x84) {spit("^"); return true;} // CaRat 260 | if (left == 0x50) {spit("&"); return true;} // aMpesand 261 | if (left == 0x02) {spit("*"); return true;} // Star 262 | if (left == 0xd4) {spit("+"); return true;} // PLus 263 | if (left == 0xc8) {spit("="); return true;} // eQual 264 | if (left == 0xc2) {spit("/"); return true;} // SLash 265 | if (left == 0x3c) {spit("\\"); return true;} // Backslash 266 | if (left == 0xc4) {spit(":"); return true;} // CoLon 267 | if (left == 0x06) {spit(";"); return true;} // SemiColon 268 | if (left == 0x0e) {spit("`"); return true;} // Grave 269 | if (left == 0x8c) {spit("_"); return true;} // unDeRscore 270 | if (left == 0x2c) {spit("-"); return true;} // DasH 271 | if (left == 0x40) {Keyboard.write(KEY_INSERT); return true;} // iNseRt 272 | if (left == 0xcc) {Keyboard.write(KEY_DELETE); return true;} // DeLete 273 | } 274 | } 275 | return false; 276 | } 277 | 278 | // scan for keypresses 279 | byte pinState(int pin) { 280 | byte state = !digitalRead(pin); 281 | if(state == 1) pressed = true; 282 | return state; 283 | } 284 | 285 | // Activate and read one row 286 | byte getRow(int pin) { 287 | digitalWrite(pin, LOW); 288 | byte row = 0; 289 | for(int i=0; i