Go Down

Topic: FORTH pre-loaded UNO or NANO? (Read 14398 times) previous topic - next topic

kowalski

@ChrisTenone

The latest development of the Arduino Forth Virtual Machine (Arduino-FVM) includes a Token Compiler and a traditional Forth outer interpreter that allows definitions in data and program memory.

Token Compiler, https://github.com/mikaelpatel/Arduino-FVM/blob/master/examples/Compiler/Compiler.ino
Forth Interpreter, https://github.com/mikaelpatel/Arduino-FVM/blob/master/examples/Forth/Forth.ino

The byte token threaded inner interpreter introduces tail call optimization. The built-in instruction level trace will show how this optimization works at run-time.

Cheers!

ChrisTenone

Sweet! I just downloaded it, and it's in my queue. Thanks for all the work you have (obviously) put into this project.
What, I need to say something else too?

Robin2

I am posting here as it seems to be the most recent Thread about Forth.

I dabbled with Forth years ago. My recollection is that it performs very well yet is pretty much an interpreted language. How would it compare with the same task programmed in C++?

I've been wondering if I could have the interpreter in the Arduino and the code for my user program on an SD Card. If so, then it should be possible to send another "text" file which it loads onto the SD Card and thens switches over to use the new file as its program?

Does that make sense? is it possible with any of the existing implementations?

Would reading the program from an SD Card slow things too much to be useful?

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

westfw


Quote
I dabbled with Forth years ago. My recollection is that it performs very well yet is pretty much an interpreted language. How would it compare with the same task programmed in C++?
Forth is usually "compiled" into a very efficient token-like sort-of interpreted "threaded code."
I don't think it really compares very well to a true compiled language like C, but it does pretty good, and in some cases might be more space-efficient.

Quote
I've been wondering if I could have the interpreter in the Arduino and the code for my user program on an SD Card. If so, then it should be possible to send another "text" file which it loads onto the SD Card and thens switches over to use the new file as its program?
Probably not so much.  On AVRs, Forth programs are usually burnt into flash (though they don't NEED to be, if they're small enough, I guess.)  Most of the Forths I've looked at have assumed lots of RAM...

Forth does have a pre-filesystem mass storage concept, which is mostly (IMO) pretty bogus, but it does mean that it could support EEPROM or Serial flash chips without having to implement a filesystem.

Robin2

Thanks. On that basis I suspect it would be more trouble than it might be worth.

And it did occur to me after I had posted Reply #32 that if I could "send" a program file and have it used as "the" program there would probably be a major problem if the new program crashed.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

westfw

I think "bitlash" supports running programs from external storage, including "chaining" to a new program.
It's a BASIC-like interpreter...

Robin2

I have always assumed that Bitlash would slow things down a great deal - far more than Forth.

...R
Two or three hours spent thinking and reading documentation solves most programming problems.

KeithRB

Well you can always do what I did for an expression evaluator called "functionfactory" for ImageFX on the Amiga:

Use lex, Yacc and a grammar to create a parser for your input and "compile" it. I don't think you have the memory for that, though.

Chris_H

#38
Feb 21, 2017, 11:14 pm Last Edit: Feb 22, 2017, 12:44 am by Chris_H Reason: changed 0x6500 to observed value; added sample from objdump
[ Would to hitch-hike and not start a new Forth thread. ]

SEE CODE

Passing the address of a function to a simulated stack ..how to do so?


Hi, I'm trying to suss out (understand) how to pass the address of a function to a simulated stack structure, from inside a standard Arduino IDE based block of code

(I don't even know what language this is -- C or C++ perhaps -- whatever is considered standard, and compiles in the distribution IDE for Arduino).

The application consists of a host PC talking to an Arduino M0 Pro Atmel SAMD21G18A utilizing ARM Cortex M0+ technology via USB tty (the development board presents a new device, /dev/ttyACM0 to the Linux host PC, as soon as the USB cable connects the two machines together).

The two machines chat via something similar to RS-232c, only it is imposed over USB somehow.  minicom (or GTKTerm for that matter) is used on the Linux host PC to talk to the microcontroller development board (the Arduino M0 Pro, currently about USD 40.00 from several vendors).

     *   *   *

The application code causes the Arduino board to function similarly to a (rather brain-dead) dial-up BBS (bulletin board system) in that they chat using ASCII characters, as well as ANSI.SYS escape codes (using MS-DOS jargon).

The application is meant to more or less simulate not only a dial-up BBS experience (just barely so) but more to the point, to simulate a working GForth environment (again, only the rudaments, and not with close adherance to the original, by any means).

CODING WORDS INLINE has not proved to be of much difficulty; Charley Shattuck lit the path nicely.  What I wanted to do next was to start work on branch-conditionals (as I'll call them).  Tests.  I want to be able to implement something that, in Forth, might read:

Code: [Select]
$ cat ~/howtrueistthat.fs

: howtrue
." equals zero - yes, that is true here.  It does equal zero."
;

: 0=? ( n -- ) \ equals zero? - test
  0= IF howtrue exit then ;

$ gforth ~/howtrueistthat.fs
Gforth 0.7.2, Copyright (C) 1995-2008 Free Software Foundation, Inc.
Type `bye' to exit
5 0=?  ok
0 0=? equals zero - yes, that is true here.  It does equal zero. ok
bye
$

Now, the trick is, to pass the address of 'howtrue' into the stack, (faked stack) so that it can be conditionally called, depending on how things progress as the user interacts with this primitive 'system'.

I don't know how to
a) learn or ascertain the exact address of 'howtrue' except by disassembly, which doesn't quite help, here; and

b) how to exec code at that address, once found and passed into the (faked) stack.

I can see by the assembler dump that the code addresses exist and seem to beg to be exec'd by calling their actual addresses (in flashROM space, near 0x42e0 or so):

Code: [Select]
$ /usr/bin/arm-none-eabi-objdump  -S  -z \
        -I/home/proj/Arrduino/public_aa \
          /tmp/arduino_build_263967/public_aa.ino.elf

--- excerpt ---

000042e0 <_Z2eqv>:
}


/* is TOS equal to TOS -1? */
NAMED(_eq, "="); // ( n n -- bool )  consumes both arguments, returns boolean
void eq() {
    42e0:       b510            push    {r4, lr}
  int a;
  int b;
  a = pop();
    42e2:       f7ff ffb3       bl      424c <_Z3popv>
    42e6:       1c04            adds    r4, r0, #0
  b = pop();
    42e8:       f7ff ffb0       bl      424c <_Z3popv>
  if ( a == b ) {
    42ec:       4284            cmp     r4, r0
    42ee:       d101            bne.n   42f4 <_Z2eqv+0x14>
    true_();
    42f0:       f7ff ff96       bl      4220 <_Z5true_v>
  }
}
    42f4:       bd10            pop     {r4, pc}

000042f6 <_Z3zeqv>:



EDIT: changed ref. address and added sample objdump

(1 of 3 intended, sequential posts)

Chris_H

THE CODE

This isn't Charley's unmodified code -- has local mods.

Code: [Select]


/* public_aa.ino */
/* Tue Feb 21 20:48:49 UTC 2017 */

/* locally from: interpreter-cortex_m0.ino */

const char versionbuf[] = "VERSION 0.0.01bP ";

/* mcu: Atmel SAMD21G18A
   board: Arduino M0 Pro
   Technology: ARM Cortex M0+ */

/* derived from: a Forth-like interpreter for the M0
   in the Arduino IDE language environment,
   by Charley Shattuck */

/* https://github.com/CharleyShattuck/Feather-M0-interpreter

   A Forth text interpreter for the Adafruit Feather M0, using the Arduino IDE.

   Charley says:

   This example code is in the public domain */


/*  ***************** code ****************************  */

/* Structure of a dictionary entry */
typedef struct {
  const char *name;
  void (*function)();
} entry;

/* const stores in flashROM: */
const char str[] = "My rather curiously long string, as deposited in flashROM.";

/* simulated stack, with a storage depth of 16 integer values */

const int STKSIZE = 16; // must be a power of 2
const int STKMASK = 15; // STKSIZE less 1
int stack[STKSIZE]; // let's call it a stack as that is how it will be used, sort-of.
int p = 0;

/* TOS is Top Of Stack */
#define TOS stack[p]
/* NAMED creates a string in flash */
#define NAMED(x, y) const char x[]=y

/* Terminal Input Buffer for interpreter */
const byte maxtib = 16;
char tib[maxtib];

/* buffer required for strings read from flash */
char namebuf[maxtib];
byte pos;

/* push n to top of data stack */
void push(int n) {
  p = (p + 1)& STKMASK;
  TOS = n;
}

/* return top of stack */
int pop() {
  int n = TOS;
  p = (p - 1)& STKMASK;
  return n;
}

/* ************* forth words ************* */

/* discard top of stack */
NAMED(_drop, "drop");
void drop() {
  pop();
}

/* recover dropped stack item */
NAMED(_back, "back");
void back() {
  for (int i = 1; i < STKSIZE; i++) drop();
}

/* copy top of stack */
NAMED(_dup, "dup");
void dup() {
  push(TOS);
}

/* exchange top two stack items */
NAMED(_swap, "swap");
void swap() {
  int a;
  int b;
  a = pop();
  b = pop();
  push(a);
  push(b);
}

/* add top two items */
NAMED(_add, "+");
void add() {
  int a = pop();
  TOS = a + TOS;
}


/* locally-contributed code follows */

/* multiply top two items */
NAMED(_mult, "*");
void mult() {
  int a = pop();
  int b = pop();
  TOS = a * b;
}

/* invert all bits in top of stack */
NAMED(_invert, "invert");
void invert() {
  TOS = ~(TOS);
}

/* negate top of stack */
NAMED(_negate, "negate");
void negate() {
  TOS = -(TOS);
}

/* push boolean 'true' (-1) */
NAMED(_true, "true");
void true_() {
  push(1);
  negate();
}


/* consider the binary representation for the numbers
    expressed in decimal, here */

/* logic is inverted, not negated */


/* push boolean 'false' (0) onto the stack */
NAMED(_false, "false");
void false_() {
  true_();
  invert();
}


/* is TOS equal to TOS -1? */
NAMED(_eq, "="); // ( n n -- bool )  consumes both arguments, returns boolean
void eq() {
  int a;
  int b;
  a = pop();
  b = pop();
  if ( a == b ) {
    true_();
  }
}

/* Is TOS equal to zero? */
NAMED(_zeq, "0="); // ( n -- bool )  yes it consumes TOS
void zeq() {
  int a = 0;
  push(a);
  eq();
}

/* need a visible consequence to a boolean decision,
   for testing at the serial tty (console) linux knows
   as the /dev/ttyACM0 tty device.

   So, 'truemsg' and 'falsemsg'.
*/

/* smart mouthed computer */
NAMED(_truemsg, "truemsg");
void truemsg() {
  char buffer[10] = "So true. "; Serial.print(buffer);
}

/* and a bit curt or abrupt. */
NAMED(_falsemsg, "falsemsg");
void falsemsg() {
  char buffer[15] = "That's false. "; Serial.print(buffer);
}

/* "is not equal to zero */
NAMED(_zneq, "0<>"); // ( bool -- )
void zneq() {
  int bool_ = pop();
  if (bool_) {
    truemsg();
  }
  else {
    falsemsg();
  }
}


NAMED(_empty, "empty"); // ( n n n n ... -- )  empty the stack or zero it out, in this case
void empty() {
  for (int i = 0; i < 18; i++) push(0);
}


/* end of locally-added code */


/* resume original author's coding: */

/* destructively display top of stack, decimal */
NAMED(_dot, ".");
void dot() {
  Serial.print(pop());
  Serial.print(" ");
}

/* display whole stack, decimal */
NAMED(_dotS, ".s");
void dotS() {
  for (int i = 0; i < STKSIZE; i++) dot();
}

/* dump 16 bytes of RAM in hex with ascii on the side */
void dumpRAM() {
  char buffer[5] = "";
  char *ram;
  int p = pop();
  ram = (char*)p;
  sprintf(buffer, "%4x", p);
  Serial.print(buffer);
  Serial.print("   ");
  for (int i = 0; i < 16; i++) {
    char c = *ram++;
    sprintf(buffer, " %2x", (c & 0xff));
    Serial.print(buffer);
  }
  ram = (char*)p;
  Serial.print("   ");
  for (int i = 0; i < 16; i++) {
    buffer[0] = *ram++;
    if (buffer[0] > 0x7f || buffer[0] < ' ') buffer[0] = '.';
    buffer[1] = '\0';
    Serial.print(buffer);
  }
  push(p + 16);
}

/* dump 256 bytes of RAM */
NAMED(_dumpr, "dump");
void rdumps() {
  for (int i = 0; i < 16; i++) {
    Serial.println();
    dumpRAM();
  }
}

/* more local code */

char ascii_char;

/* send one ascii character to the serial port */
NAMED(_emit, "emit");
void emit() {
  ascii_char = pop();
  Serial.print(ascii_char);
}

NAMED(_2emit_, "2emit");
void _2emit() {
  emit();
  emit();
}

/* everybody loves a nop */
NAMED(_nopp, "nop");
void nopp() { }

/* End of Forth interpreter words */

/* Now build the dictionary */

/* empty words don't cause an error */
NAMED(_nop, " ");
void nop() { }

/* Forward declaration required here */
NAMED(_words, "words");
void words();

/* How many words are in the dictionary? */
NAMED(_entries_, "entries");
void _entries();

/* table of names and function addresses in flash */
const entry dictionary[] = {
  {_nop, nop},
  {_words, words},
  {_entries_, _entries},
  {_drop, drop},
  {_dup, dup},
  {_back, back},
  {_swap, swap},
  {_add, add},
  {_mult, mult},
  {_invert, invert},
  {_negate, negate},
  {_true, true_},
  {_false, false_},
  {_eq, eq},
  {_zeq, zeq},
  {_truemsg, truemsg},
  {_falsemsg, falsemsg},
  {_zneq, zneq},
  {_empty, empty},
  {_dotS, dotS},
  {_dot, dot},
  {_dumpr, rdumps},
  {_2emit_, _2emit},
  {_emit, emit},
  {_nopp, nopp},
};

const int entries = sizeof dictionary / sizeof dictionary[0];

/* Display all words in dictionary */
void words() {
  for (int i = entries - 1; i >= 0; i--) {
    strcpy(namebuf, dictionary[i].name);
    Serial.print(namebuf);
    Serial.print(" ");
  }
}

/* how many words are there? */
void _entries() {
  int a;
  a = entries;
  Serial.print(a);
  Serial.print(" ");
}

/* Find a word in the dictionary, returning its position */
int locate() {
  for (int i = entries; i >= 0; i--) {
    strcpy(namebuf, dictionary[i].name);
    if (!strcmp(tib, namebuf)) return i;
  }
  return 0;
}

/* Is the word in tib a number? */
int isNumber() {
  char *endptr;
  strtol(tib, &endptr, 0);
  if (endptr == tib) return 0;
  if (*endptr != '\0') return 0;
  return 1;
}

/* Convert number in tib */
int number() {
  char *endptr;
  return (int) strtol(tib, &endptr, 0);
}

char ch;

void ok() {
  if (ch == '\r') Serial.print("ok\r\n");
}

/* Incrementally read command line from serial port */
byte reading() {
  if (!Serial.available()) return 1;
  ch = Serial.read();
  Serial.print(ch); // char-by-char input, echo
  if (ch == '\n') {
    Serial.print("\r\n"); // echo
    return 1;
  }
  if (ch == '\r') {
    return 0;
  }
  if (ch == ' ') return 0;
  if (pos < maxtib) {
    tib[pos++] = ch;
    tib[pos] = 0;
  }
  return 1;
}

/* Block on reading the command line from serial port */

/* then echo each word */ // later: not anymore.  We don't do that now.
void readword() {
  pos = 0;
  tib[0] = 0;
  while (reading());
  // Serial.print(tib);  // we do our own echo now
}

/* Run a word via its name */
void runword() {
  int place = locate();
  // test for upper bound of 'place'
  // this was critical to making Charley's code function without the Serial Monitor e.g. from within minicom or GTKTerm.
  if ((place != 0) & (place < (entries - 1))) {
    dictionary[place].function();
    ok();
    return;
  }
  if (isNumber()) {
    push(number());
    ok();
    return;
  }
  Serial.println("?");
}

/* Arduino main loop */

void setup() {

  Serial.begin(38400);
  while (!Serial);
  Serial.println ("Forth-like interpreter:\r\n");
  Serial.print(versionbuf);
  words(); // optional - may comment this out.
  Serial.println();
}

void loop() {
  readword();
  runword();
}

// end.

Chris_H

sample run:

Code: [Select]

Forth-like interpreter:

VERSION 0.0.01bP nop emit 2emit dump . .s
empty 0<> falsemsg truemsg 0= = false true
negate invert * + swap back dup drop entries words   

5 3 .s 3 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 *
ok
.s
15 0 0 0 0 0 0 0 0 0 0 0 0 0 3 5 ok
empty .s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ok
224 123 .s
123 224 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ok
negate + .s
101 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -123 ok
101 negate + 0<> That's false. .s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 -101 0 ok

215 125 90 + 0<> So true. .s
215 0 0 0 0 0 0 0 0 0 0 0 0 0 90 215 ok

empty .s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ok

125 90 + 0<> So true. .s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 90 215 ok


(3 of 3 intended posts .. thanks for patience and indulgence.
-Chris in NW Connecticut USA 41N 73W)

westfw

#41
Feb 22, 2017, 12:13 am Last Edit: Feb 22, 2017, 12:16 am by westfw
Quote
I don't know how to
 a) learn or ascertain the exact address of 'howtrue' except by disassembly, which doesn't quite help, here; and
 b) how to exec code at that address, once found and passed into the (faked) stack.
In C, the addresses of a function are just the name of the function, declared (as in the "entry" struct in the existing code):

Code: [Select]
  void (*AddressOfFunction)();

  AddressOfFunction = millis;  // Load the address of the millis() function into the pointer



Web search for "C function pointers."
This table in the code is a table of names (string pointers stored in flash, created by the NAMED() macro in the code), and pointers to the functions that implement that word...
Code: [Select]

/* table of names and function addresses in flash */
const entry dictionary[] = {
  {_nop, nop},
  {_words, words},
  {_entries_, _entries},
  {_drop, drop},
  {_dup, dup}, ...


And you could print, even in a normal Arduino, a function's address just by casting it to an int:
Code: [Select]
Serial.print((unsigned int)millis, hex);

GoForSmoke

I have a copy of Prof. Ting's eforth328 but haven't loaded the hex on a board.

I did enough forth in the 80's to know what's so good about it. It's not slow to execute, it's not slow to write, it is object-oriented, it doesn't have extra rules and it makes compact code. The forth stack and word definitions make laying out code easier than any other high level language I've dealt with.

https://gitlab.com/jjonethal/eforth328/tree/master

I did contact Prof. Ting about eforth for the 1284P. His view was to put it all in RAM, there's plenty for a small forth system.

Back in the 80's a friend of mine had a board with a Rockwell 65F11. That had forth instructions in the microcode, forth assembler commands! There was at least one 6800 based forth and I dunno how many other chips had forth in them or were made just to run forth, some up in satellites.

Forth is pretty ideal for small environments.

1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Chris_H

GoForSmoke: I saw a 'microprocessor trainer' board or
somesuch at the Heathkit store (yeah, they had retail
stores at one point).

That was a lot of money to earn on a paper route, or
caddying at the golf course (about 100 dollars, I think).

This new stuff is great, price-wise.

In C, the addresses of a function are just the name of the function..
.
.
Web search for "C function pointers."
.
.
And you could print .. a function's address just by casting it to an int..
Thank you, westfw.  The approach looks very much useful to me:
Code: [Select]
/* public_ee.ino */
/* +westfw */

/* "is not equal to zero */
NAMED(_zneq, "0<>"); // ( int -- addrs )
void zneq() {
  void (*AddressOfFunction)();
  unsigned int addrs;
  if (pop()) { // int treated as boolean
    addrs = (unsigned int)truemsg;
    Serial.print((unsigned int)truemsg, HEX);
    Serial.print(" ");
    AddressOfFunction = &truemsg; // Load the address of the truemsg() function
                                  // into the pointer
    AddressOfFunction(); // exec - very nice.  [b]THANK YOU[/b].
    push(addrs); // the knowledge is not lost, either:  the address is pushed onto TOS, as well.
    char buffer[] = "Look at TOS now. "; Serial.print(buffer);
  }
  else { // shoot the works: both conditional branches are covered:
    addrs = (unsigned int)falsemsg;
    Serial.print(addrs, HEX);
    Serial.print(" ");
    AddressOfFunction = &falsemsg;
    AddressOfFunction();
    push(addrs);
    char buffer[] = "Do look at TOS. "; Serial.print(buffer);
  }
}


Doodling in flashROM, no efficiency sought just yet:
Code: [Select]
$ objdump

00004148 <_Z7truemsgv>:

NAMED(_truemsg, "truemsg");
void truemsg() {
    4148: b51f      push {r0, r1, r2, r3, r4, lr}
  char buffer[10] = "So true. "; Serial.print(buffer);
    414a: 220a      movs r2, #10
    414c: a801      add r0, sp, #4
    414e: 4904      ldr r1, [pc, #16] ; (4160 <_Z7truemsgv+0x18>)
    .
    .

00004168 <_Z8falsemsgv>:

NAMED(_falsemsg, "falsemsg");
void falsemsg() {
    4168: b51f      push {r0, r1, r2, r3, r4, lr}
  char buffer[15] = "That's false. "; Serial.print(buffer);
    416a: 220f      movs r2, #15
    416c: 4668      mov r0, sp
    416e: 4904      ldr r1, [pc, #16] ; (4180 <_Z8falsemsgv+0x18>)
    .
    .

00004304 <_Z4zneqv>:

/* "is not equal to zero */
NAMED(_zneq, "0<>"); // ( int -- addrs )
void zneq() {
    4304: b570      push {r4, r5, r6, lr}
    4306: b086      sub sp, #24
  void (*AddressOfFunction)();
  unsigned int addrs;
  if (pop()) { // int treated as boolean
    4308: f7ff ffa0 bl 424c <_Z3popv>
    430c: 4c18      ldr r4, [pc, #96] ; (4370 <_Z4zneqv+0x6c>)
    430e: 4e19      ldr r6, [pc, #100] ; (4374 <_Z4zneqv+0x70>)
    4310: 2800      cmp r0, #0
    4312: d012      beq.n 433a <_Z4zneqv+0x36>
    addrs = (unsigned int)truemsg;
    Serial.print((unsigned int)truemsg, HEX);
    4314: 4d18      ldr r5, [pc, #96] ; (4378 <_Z4zneqv+0x74>)
    4316: 2210      movs r2, #16
    4318: 1c29      adds r1, r5, #0
    431a: 1c20      adds r0, r4, #0
    431c: f000 fd53 bl 4dc6 <_ZN5Print5printEji>
    Serial.print(" ");
    4320: 1c31      adds r1, r6, #0
    4322: 1c20      adds r0, r4, #0
    4324: f000 fce0 bl 4ce8 <_ZN5Print5printEPKc>
    AddressOfFunction = &truemsg; // Load the address of the truemsg() function
                                  // into the pointer
    AddressOfFunction();
    4328: f7ff ff0e bl 4148 <_Z7truemsgv>
    push(addrs);
    432c: 1c28      adds r0, r5, #0
    432e: f7ff ff5b bl 41e8 <_Z4pushi>
    char buffer[] = "Look at TOS now. "; Serial.print(buffer);
    4332: a801      add r0, sp, #4
    4334: 4911      ldr r1, [pc, #68] ; (437c <_Z4zneqv+0x78>)
    4336: 2212      movs r2, #18
    4338: e011      b.n 435e <_Z4zneqv+0x5a>
  }
  else {
    addrs = (unsigned int)falsemsg;
    Serial.print(addrs, HEX);
    433a: 4d11      ldr r5, [pc, #68] ; (4380 <_Z4zneqv+0x7c>)
    433c: 2210      movs r2, #16
    433e: 1c29      adds r1, r5, #0
    4340: 1c20      adds r0, r4, #0
    4342: f000 fd40 bl 4dc6 <_ZN5Print5printEji>
    Serial.print(" ");
    4346: 1c31      adds r1, r6, #0
    4348: 1c20      adds r0, r4, #0
    434a: f000 fccd bl 4ce8 <_ZN5Print5printEPKc>
    AddressOfFunction = &falsemsg;
    AddressOfFunction();
    434e: f7ff ff0b bl 4168 <_Z8falsemsgv>
    push(addrs);
    4352: 1c28      adds r0, r5, #0
    4354: f7ff ff48 bl 41e8 <_Z4pushi>
    char buffer[] = "Do look at TOS. "; Serial.print(buffer);
    4358: 490a      ldr r1, [pc, #40] ; (4384 <_Z4zneqv+0x80>)
    435a: a801      add r0, sp, #4
    435c: 2211      movs r2, #17
    435e: f002 f8e7 bl 6530 <memcpy>
    4362: 1c20      adds r0, r4, #0
    4364: a901      add r1, sp, #4
    4366: f000 fcbf bl 4ce8 <_ZN5Print5printEPKc>
  }
}
    436a: b006      add sp, #24
    436c: bd70      pop {r4, r5, r6, pc}
    436e: 46c0      nop ; (mov r8, r8)
    4370: 20000188 .word 0x20000188
    4374: 00007057 .word 0x00007057
    4378: 00004149 .word 0x00004149
    437c: 0000702e .word 0x0000702e
    4380: 00004169 .word 0x00004169
    4384: 00007040 .word 0x00007040

END.


as seen on TV:
Code: [Select]
Forth-like interpreter:

VERSION 0.0.01ee-01a-P nop emit 2emit dump .h . .sh .s
empty 0<> falsemsg truemsg 0= = false true negate
invert * + swap back dup drop entries words

5 4 3 2 1 empty .s
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ok

empty 0x37 0<> 4149 So true. Look at TOS now. .sh
4149 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ok

empty 1 1 negate + 0<> 4169 That's false. Do look at TOS. .sh
4169 0 0 0 0 0 0 0 0 0 0 0 0 0 0 FFFF ok

GoForSmoke

There is an AVR bootloader that does allow writing to flash at runtime.

Before 1986 the only inexpensive computers I remember were the toys (Commodore, Atari, Sinclair, RadioShack) that weren't really toys. I'd have given a LOT to have had the least of those before 1980.

I remember going to a Jan 2nd fest in 1986 and seeing the clones and clone parts. My world changed.
1) http://gammon.com.au/blink  <-- tasking Arduino 1-2-3
2) http://gammon.com.au/serial <-- techniques howto
3) http://gammon.com.au/interrupts
Your sketch can sense ongoing process events in time.
Your sketch can make events to control it over time.

Go Up