Arduino Forum

Using Arduino => Microcontrollers => Topic started by: joemac2013 on Feb 18, 2014, 04:11 am

Title: FORTH pre-loaded UNO or NANO?
Post by: joemac2013 on Feb 18, 2014, 04:11 am
Is anyone aware of a supplier of Arduino boards that are pre-loaded with FORTH?
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on Feb 18, 2014, 08:06 am
No.  AMForth runs on Arduino hardware, but the install is a bit obscure and it's not compatible with the Arudino bootloader.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: joemac2013 on Feb 19, 2014, 03:57 am
I have heard of e-Forth also, I will look into them.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: joemcder on Feb 19, 2014, 08:11 pm
Wow Forth.  I used that 30+ years ago on some automation projects.  A very clever compact language.

This is like seeing some aging movie star on TV that I thought was dead for years :)

I'm curious.  On what kind of project are you using Forth?

joemc



Title: Re: FORTH pre-loaded UNO or NANO?
Post by: graynomad on Feb 20, 2014, 04:47 am
Quote
This is like seeing some aging movie star on TV that I thought was dead for years

Reckon :)

_____
Rob
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Grumpy_Mike on Feb 20, 2014, 04:54 am
I saw someone at the Mini Maker Fair in Manchester (England) last year selling an arduino like board (same processor) that ran Forth for less than £20.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: pegwatcher on Feb 20, 2014, 07:44 am
Forth needs a big stack which means lots of SRAM.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Robin2 on Feb 21, 2014, 10:20 pm
I was interested in Forth years ago. I think I have a book I bought (just some photocopied pages) with the source code (probably for an 8086 chip).

Would there be any advantage of using it on an Atmega328 chip compared with the Arduino C++ system?

...R
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Paul__B on Feb 21, 2014, 10:40 pm

Forth needs a big stack which means lots of SRAM.


Actually, no, the program stack would be in Flash.  The return stack uses just two bytes per call which is hardly catastrophic; you are unlikely to nest more than a hundred deep, similarly with data.

FORTH would replace the bootloader since it is the bootloader.  It assembles the code into flash just like bootloading a sketch, but piecemeal.  Using Flash, the interpreter comes up to talk to you on reset, or else it executes your code directly if so instructed.


Would there be any advantage of using it on an Atmega328 chip compared with the Arduino C++ system?


You would not be using the IDE - the serial monitor does not have the necessary functionality to load and save code.  The advantage is continuous but fast interpretation - you instruct it to do something and that happens virtually instantly, you construct pieces and try them out one after the other in a continuous flow.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Robin2 on Feb 22, 2014, 11:17 am


You would not be using the IDE - the serial monitor does not have the necessary functionality to load and save code.  The advantage is continuous but fast interpretation - you instruct it to do something and that happens virtually instantly, you construct pieces and try them out one after the other in a continuous flow.



This is more or less what I thought. I used to think (maybe still do) that Forth was a very clever concept but I suspect that in reality it would be a lot more work to use than Arduino C++

...R
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Paul__B on Feb 22, 2014, 01:13 pm

I used to think (maybe still do) that Forth was a very clever concept but I suspect that in reality it would be a lot more work to use than Arduino C++


I have an itch to do a FORTH for the Arduino platform - hardware that is.  Of course, I have lots of itches.  :D

I did work on it for a while, using the 6809 which had just the right architecture for it (twin stacks).  The limitation was using RAM - you had to run it on a system with either NVRAM (battery backed - which I actually had) or provide a disk interface which got very clumsy.  A Flash based system - such as as Arduino - should make turnkey operation work just fine.

Another advantage we now have is much greater (text, virtual) screen resolution with scrolling - this can be as effective with FORTH as with C++.

One interesting difference is that to modify a deep word in FORTH you have to remove everything on top (FORGET) and then build it again - but that said of course, with C++ you have to recompile the lot every time.  That again is the thing about FORTH - you build it piece by piece and it runs (or can) as you do so.  You write a word to flash the LED, define it as "flashled" and then say (type) the word - and it does.  Instantly.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: joemcder on Feb 22, 2014, 04:38 pm
This discussion is too narrow.  The language is usually far less inportant than the associated library environment.  Arduino ide is basically c++ with a very extensive set of libray objects from many sources.
For example, I often use the "IRremote" and "RF24LibraryMaster"  libraries for remote control of small robots.  Duplicating these under Forth would be a lot of redundant work.

Has anyone adapted Arduino libraries to Forth? Is it possible? 

Joe
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on Feb 23, 2014, 09:47 am
Quote
Is it possible?

In theory, sure.  most forth implementations can include arbitrary assembly code added as Forth "Words", so you can add anything.
In reality, the AVR Forth that I'm (slightly) familiar with (amForth) is written using the Atmel assembler, which doesn't permit linking with external libraries, so it would be pretty difficult.  (Just a small matter of converting to Gnu assmebler, or similar.)  Creating a Forth word that calls C functions would be pretty easy.

I've added a sort-of forth interpreter "front end" to a large non-forth program a couple of times.  It's an easy way to get symbolic access and interactive behavior if you want to fiddle with a random library, for instance.

Forth is probably one of the smallest language that gives the programmer access to the program symbol names, which gives you some interesting capabilities.  But it has always seemed to me that Forth has never quite "grown up."  Other languages and environments came along and decided that thing like data structures were important, and Forth seems stuck in this "I'm faster than interpreted BASIC and look I can do IO model based on numbered 1k screens!"
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: polypagan on Mar 07, 2014, 06:24 pm
Forth was developed in 1958 (!) back when system software was hard to come by.  It was used a lot (especially in astronomy) since the '70's.  It's a weird (and useful) mix of operating system and programming language that really makes sense on tiny machines.

I obtained an ATmega328 (non-p) DIP pre-programmed with FlashForth from the fellow whose address can be found at http://flashforth.sourceforge.net/ (http://flashforth.sourceforge.net/) (U$ 10).  Mail takes a little while from Finland.

Replacing the ATmega328p in Uno results in a working Forth system.

Playing with it, I managed to mess up the dictionary (The Uno's USB processor doesn't allow xon-xoff flowcontrol to work and it's easy to overrun the compiler, getting it confused... and it's writing to flash!).

I then used Nick Gammon's fabulous (You da' man, Nick!) hex uploader to burn a new version...
http://www.gammon.com.au/forum/?id=11638 (http://www.gammon.com.au/forum/?id=11638)

Nick's program gets a little upset that FlashForth doesn't start at its lowest address, just set the fuse for $7c00 (EFuse = $fc) and you're good to go.

I re-flashed the ATmega328 and also put FlashForth on a Pro Mini (ATmega328p, works better because USB-TTL converter allows xon-xoff).

Long story here, I run Linux, so used Crossover Linux to run the assembler from Atmel Studio (Studio doesn't work under Crossover, AVRASM does!) to build it.  With a few edits, it can be assembled using Avra under Linux (or whatever), though I haven't tested the code yet.

Stacks cannot be in Flash, must be RAM.  However Forth uses very little RAM. Variables and two stacks live in RAM.  My sense, so far, is that C and C++ make much heavier use of RAM.

I am now in the process of writing analog and digital I/O routines in FlashForth.  Glad to share with anyone who's interested. And I'd like to hear from you if you are working on Forth on AVR's.

And, yes, it does mean abandoning the Arduino IDE and all those user provided libraries.  I do very much like the idea of a tiny operating system on the microcontroller that allows assembly and compilation. (Somehow the Mini is most impressive, being about the size of a large postage stamp!)  Making it do anything non-trivial may take a great while, however.

Two other Forth variants for AVR's are pForth and AmForth.  I have the source and haven't done much with them..... yet.

Cheers!
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: minom on Mar 12, 2014, 03:55 am
I am interested in collaborating on forth implementations on the Arduino platform.  I share your preference for a small footprint o/s for home automation.
Title: Arduino FORTH interest group - 2014
Post by: Paul__B on Mar 12, 2014, 08:10 am
I think that we need to start by each setting up FlashFORTH and evaluating it.  Apart from the flow control problem, it does sound as if it is well implemented.

However fascinating it may be to start from scratch (I was about to look up the original FIGFORTH code), starting from a good codebase makes more sense; and many eyes make for good optimisation.  That is after all, what this forum is about.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Grumpy_Mike on Apr 23, 2014, 05:33 pm
I have come across that board I was talking about. It is here:-
https://sites.google.com/site/libby8dev/fignition (https://sites.google.com/site/libby8dev/fignition)
It is available as a kit to build and is quite cheap.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: fungus on Apr 23, 2014, 05:59 pm

Forth needs a big stack which means lots of SRAM.


Why do you say that? I don't think it needs more than any other language.

Last time I programmed FORTH was about a year ago on a Gameduino (which has a FORTH co-processor on board).



Title: Re: FORTH pre-loaded UNO or NANO?
Post by: technoronin on May 06, 2015, 10:09 pm
I am just now getting into Arduinos and I find the IDE & C++ environment a bit annoying.  I worked with Forth back in the late 1970s & 1980s and I would really enjoy getting back into it.

Given when I used it, I did a lot with FigForth (1977) and MVPForth (79 standard) and I have a strong preference for those.  The 83 standard started adding way too much into the base language.

So, I've been thinking that an Arduino with a microSD would make a really rocking Forth system and it could be fun to design a single board with all the neat stuff on it in the Arduino footprint.

In any case, I'm starting to look into Forth for the Arduino and would enjoy chatting with others as well as getting deeply into the technical details.  Recommendations?
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on May 06, 2015, 10:43 pm
Amforth has had an impressive amount of continuing development.  I haven't been paying attention recently, but I've watched the update notices go by.  That's probably the best starting point; a lot of the other implementations seem to be neglected.

Among other features amforth has extensive customization and minimization options.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: tf68 on May 07, 2015, 04:42 am
In the past AmForth's download has included precompiled hex files for the UNO and other Arduino boards. I would imagine they still include them. All you need is an ISP programmer to install the hex file, and you are good to go.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: technoronin on May 07, 2015, 07:26 pm
Lots of interesting stuff in Amforth, but it looks like the Atmel processors aren't the best suited to doing Forth.  It works, but the memory map is rather ugly and the RAM is a bit limited to implement the old style disk words.

Given that the Arduino ecosystem supports a number of different processor architectures, I wonder if there is another UNO compatible board that would be a better choice.  Are there any Atmel processors that provide enough pins with the same functionality that is available on the UNO board, plus would allow something like 64K of external RAM?  Being able to use existing shields is important.

This is all a hobby for me and I'm really getting the itch to build something.  It would be fun to start with an existing design that has the appropriate copyright and design a board.  I've been wanting to dig into EagleCAD anyway.

At this point, I suppose all of this conversation should go into another thread, or maybe into a different forum.  Feel free to make suggestions.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: CrossRoads on May 07, 2015, 07:37 pm
Look at '1284P boards. 16k SRAM, 128K flash, 32 IO.
I designed my Bobuino pinout to very closely follow the Uno: D0,D1 for serial, D10-11-12-13, for SPI, D18-19 for SCL, etc. This board I offer follows the Uno footprint, with the extra 10 pins broken out as well.
http://www.crossroadsfencing.com/BobuinoRev17/ (http://www.crossroadsfencing.com/BobuinoRev17/)
(http://www.crossroadsfencing.com/BobuinoRev17/Bootloading1284.JPG)
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on May 08, 2015, 12:56 am
A teensy 3.1 ought to make a great Forth system.  Single address space, 64k of RAM (plus lots of flash), and probably really fast.

But... this is where the "support" issue comes in.   With AMForth, there's a team of people (well, at least one person, plus a significant number of users) who is actively working on making sure all of the "annoying" bits of the AVR architecture are adequately dealt with.   For the more capable processors, what you usually get is someone saying "I built C-forth for this chip and it seems to work.  Here's the makefile diff", and that's it.  No "support", no "community."

Title: Re: FORTH pre-loaded UNO or NANO?
Post by: tf68 on May 08, 2015, 05:32 am
AmForth supports the atmega2560 so you should be able to use an Arduino Mega. It works just fine on a 1284p also.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: oric_dan on May 08, 2015, 09:38 pm
Interestingly, there does appear to be some Forth work for the Teensy 3.1, but I haven't looked at it myself. Maybe a flash in the pan.

https://search.yahoo.com/search?p=teensy+forth (https://search.yahoo.com/search?p=teensy+forth)
https://www.google.com/webhp?&rlz=1C1CAFB_enUS638US638&ion=1&espv=2&ie=UTF-8#q=teensy+forth (https://www.google.com/webhp?&rlz=1C1CAFB_enUS638US638&ion=1&espv=2&ie=UTF-8#q=teensy+forth)

I did use Laboratory Microsystems Forth quite a bit on the original IBM 5150 PC back in the mid-80s, and did find it to be fun [once I gave up on the "official" Forth philosophy from Leo Brodie and the guys, and stopped using the stupid stack operations other than dup and over, and went to using ! and @ for most operations instead - that made it fun]. Hmmm, might be fun to look at it for the Teensy.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: ChrisTenone on May 09, 2015, 06:28 am
Oh man! FORTH is the *best* language ever!  When I wanted to program the (then new) Macintosh computer, you got a manual the size of the Chicago phone book, and a couple floppy disks containing an assembly language system (not even really an IDE.) That seemed awkward, so I used that assembler to write Pocket Forth modeled after Brodie's Forth from his two books, and from a DDJ article about subroutine threaded code on the 68000 chip. The rest is ... well, the history of Forth is kind of sad. ANSI Forth and Forth 83 appear to have been changed by making the language more C like and more obscure at the same time. After that, most Forth projects got turned into C projects, and the magic went away.

Arduino seems like it would like Forth, and I just got 328eForth from this guy (http://www.offete.com). It's free, but if you want the complete package, it's $25.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: oric_dan on May 09, 2015, 07:55 am
Wow, I'm assuming that "2165:  stm32eforth720, eForth for Discovery32, $25" on the Disks page successfully supports the F4 chip, but the description on this page seems a little equivocal.

http://www.offete.com/stm32eForth.html (http://www.offete.com/stm32eForth.html)

That would be sublimely awesome as the F4 is a monster of a chip. ST also has a Discovery  F429 board that I've been eyeballing.

http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090 (http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF259090)
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: kowalski on Jan 03, 2017, 06:11 pm
Here is a wild attempt of writing a Forth Virtual Machine for the Arduino.

https://github.com/mikaelpatel/Arduino-FVM (https://github.com/mikaelpatel/Arduino-FVM)

120 primitives/instructions in the Virtual Machine. 3.5 Kbyte without the kernel dictionary strings (pure vm). Byte token thread with a built-in instruction level trace (optional). Multi-tasking with context switch back to the Arduino sketch on forth level yield, delay and halt.

Cheers!
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: ChrisTenone on Jan 04, 2017, 05:55 am
Here is a wild attempt of writing a Forth Virtual Machine for the Arduino.

https://github.com/mikaelpatel/Arduino-FVM

120 primitives/instructions in the Virtual Machine. 3.5 Kbyte without the kernel dictionary strings (pure vm). Byte token thread with a built-in instruction level trace (optional). Multi-tasking with context switch back to the Arduino sketch on forth level yield, delay and halt.

Cheers!

Cool, thanks for posting!  I've put playing with this in my queue.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: kowalski on Jan 22, 2017, 01:32 pm
@ChrisTenone

The latest development of the Arduino Forth Virtual Machine (Arduino-FVM (https://github.com/mikaelpatel/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!
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: ChrisTenone on Jan 22, 2017, 06:37 pm
Sweet! I just downloaded it, and it's in my queue. Thanks for all the work you have (obviously) put into this project.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Robin2 on Feb 15, 2017, 11:02 am
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
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on Feb 15, 2017, 11:35 am

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.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Robin2 on Feb 15, 2017, 08:35 pm
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
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on Feb 15, 2017, 11:43 pm
I think "bitlash" supports running programs from external storage, including "chaining" to a new program.
It's a BASIC-like interpreter...
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Robin2 on Feb 16, 2017, 05:25 pm
I have always assumed that Bitlash would slow things down a great deal - far more than Forth.

...R
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: KeithRB on Feb 16, 2017, 05:33 pm
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.
Title: Passing the address of a function to a simulated stack ..how to do so?
Post by: Chris_H on Feb 21, 2017, 11:14 pm
[ 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)
Title: Passing the address of a function to a simulated stack ..how to do so?
Post by: Chris_H on Feb 21, 2017, 11:22 pm
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.
Title: Passing the address of a function to a simulated stack ..how to do so?
Post by: Chris_H on Feb 21, 2017, 11:36 pm
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)
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: westfw on Feb 22, 2017, 12:13 am
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);
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: GoForSmoke on Feb 22, 2017, 03:39 am
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.

Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Chris_H on Feb 22, 2017, 05:06 am
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
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: GoForSmoke on Feb 22, 2017, 08:50 am
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.
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: MrMark on Feb 22, 2017, 02:22 pm
[ 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?
Maybe I don't understand the question, but I think the tick word does what you want to do.

e.g.

' howtrue EXECUTE

will execute the function "howtrue" in FIG forth and those words are fundamental enough that they should be in any forth kernel.  (I have listing for STM8 eforth at hand and they are both in it.)

https://www.forth.com/starting-forth/9-forth-execution/ (https://www.forth.com/starting-forth/9-forth-execution/)
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: KeithRB on Feb 22, 2017, 04:58 pm
It is in my HP71 Forth. 8^)
Title: Re: FORTH pre-loaded UNO or NANO?
Post by: Chris_H on Feb 26, 2017, 06:22 am
Maybe I don't understand the question, but I think the tick word does what you want to do.

e.g.

' howtrue EXECUTE

will execute the function "howtrue" in FIG forth and those words are fundamental enough that they should be in any forth kernel.
Got one of them, now (didn't, before you suggested it -- didn't think to; didn't know to):

Code: [Select]

SEE ATTACHED

    386 /* Number of words in the dictionary */
    387 const int entries = sizeof dictionary / sizeof dictionary[0];
    388
    389 /* new word: xt>adrs */
    390 void xtTOadrs() { // ( xt -- addrs )
    391   func function;
    392   // must be reflected at top of source
    393   // where the struct is
    394   int plc = pop();
    395   unsigned int adxrs; // REEXAMINE if adxrs cannot be adrs -- why uniqueness
    396   function = (func) pgm_read_word(&dictionary[plc].function);
    397   push((unsigned int) function);
    398   int a = pop();
    399   push(a - 1);
    400 }

    402 /* new word for xt execution */
    403 void execadrs() { // ( adrs -- ) action: execute at adrs
    404   int a = pop();  // an address of a word's execution token
    405   push(a + 1);    // alignment (why?)
    406   func function = ((func) pop());
    407   function();
    408   // fix bottom of stack so that
    409   // adrs is reusable, with 'back EXECUTE':
    410   back(); push(1); negate(); add(); drop();
    411   // starts to look like forth, doesn't it.
    412 }

    414 /* new word for xt execution */
    415 // execute from an xt (execution token) lookup
    416 void execXT() { // ( xt -- ) action: execute    XT exec - the EXECUTE word
    417   xtTOadrs();  // ( xt -- addrs )
    418   execadrs();  // ( adrs -- ) action: execute at adrs
    419 }
    420
    421 /* new alias for new word 'execXT' */
    422 void EXECUTE() { // ( xt -- ) action: execute
    423   execXT();
    424 }
    425
    426 /* short alias for EXECUTE:  xxt 'execute execution token' */
    427 void xxt() {
    428   execXT();
    429 }
    430
    431 /* Display all words in dictionary */
    432 void words() {


Quote
https://www.forth.com/starting-forth/9-forth-execution/ (https://www.forth.com/starting-forth/9-forth-execution/)
I'll be taking another look at Leo Brodie.  Hehe.  I've been doing this a *long* time, without having done so.

Oy.

Thanks, MrMark.  --Chris_H