Showing posts with label Forth. Show all posts
Showing posts with label Forth. Show all posts

Saturday, September 3, 2022

Non sequential computing environment and Forth -2-

In part -1- of this series this table was presented to to show some Forth words.
The header part of the table is in bold.

Table 1
  TOS n1  n2 n3 
 SWAP  TOS n2 n1 n3
 DROP TOS - 1 
 n2  n3
  + TOS - 1
 n1 + n2  n3

This table is not (yet) a real Forth table and also can be simplified.
Calculations in this table are 'normal algebra' and not in Forth RPN calculations.
'Normal algebra' n1 + n2 becomes in RPN  n1 n2 + 
As already mentioned in my previous post the change of TOS depends on the amount of bits. The TOS should perhaps should be decremented by 2 or another value depending on the amount of bits in each stack item and the memory width.  It is a system constant depending on the implementation.
In this article series i will use SWDTH (stack width). In the RPN table  TOS - 1 should be written as TOS  SWDTH -

Table 2
  TOS n1  n2 n3 
 SWAP  TOS n2 n1 n3
 DROP TOS SWDTH -
 n2  n3
  + TOS SWDTH - 
 n1 n2 +   n3

Some things in this table are still confusing (however it looks already more Forth).
For example a 'strange historical convention' of n1 n2 n3 where
n1 is the item on top of the stack,  n2 is the item just below it and n3 is two steps below. Another way is to see n1 n2 n3 as memory locations where values calculated are stored.  n1 is TOS @ and n2 is TOS SWDTH - @

Table 3
  TOS n1  n2  n3 
  TOS TOS @  TOS SWDTH - @  TOS SWDTH 2* - @ 
 SWAP  TOS n2 n1 n3
 DROP TOS SWDTH -
 n2  n3
  + TOS SWDTH - 
 n1 n2 + n3

In a real 'physical' implementation of the table it would be needed to include items above the TOS (Top Of the Stack) in case items are added or pushed to the stack. Also it would be strange to represent the first items above the stack using n0 . It would be more systematic if the item on top of stack was referenced as n0 and use n+1 and n-1 for the items just above or below. However in Forth for many years items on the stack where called n1 n2 n3 and breaking with this convention would cause a lot of confusion. Also we do not want tot use complicated difficult to read terms as TOS @ or TOS SWDTH - @  So i decided (temporary) to use p0 and not n1 see tabel below.

Table 4

TOS ( n0 ? )n1n2n3

TOSp1p0p-1p-2

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPTOS
n2n1n3
DROPTOS SWDTH -

n2n3
+TOS SWDTH -

n1 n2 +n3

In the next evolution of the table i added an example of a Forth word that pushes a value to the stack.
It is the Forth word 0 . It is a number implemented in this Forth table where the value 0 is pushed to the stack.
In the table header a new Forth word PA is introduced ( shorthand for ParameterStackAddress ).
The location is described using Forth word  PA to avoid using n1 n2 n3 or p0 p1 p2 notations, 

 : PA SWDTH * TOS @ + ;

Table 5

TOS ( n0 ? )n1n2n3


p1p0p-1p-2
Location TOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPTOS
n2n1n3
DROPTOS SWDTH -

n2n3
+TOS SWDTH -

n1 n2 +n3
0TOS SWDTH +0n1n2n3

We now have almost everything described in Forth and RPN
To evolve the table further we need to do something with the gaps (empty spaces).

In fact there are several options to handle these gaps.
A) Handle a gap as something that not needs to be changed  ( "Ignore" or "don't change" )

Table 6a

TOS ( n0 ? )n1n2n3


p1p0p-1p-2
LocationTOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPTOSIgnoren2n1Ignore
DROPTOS SWDTH -IgnoreIgnoreIgnoreIgnore
+TOS SWDTH -IgnoreIgnoren1 n2 +Ignore
0TOS SWDTH +0IgnoreIgnoreIgnore

B) Fill gap with a "Null" value
"Null" is a special marker and keyword indicating that something has no value (in SQL )
Using  option 2 ( Null) the small table the table would look as below.

Table 6b

TOS ( n0 ? )n1n2n3


p1p0p-1p-2

TOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPTOSNulln2n1n3
DROPTOS SWDTH -NullNulln2n3
+TOS SWDTH -NullNulln1 n2 +n3
0TOS SWDTH +0n1n2n3

Both representations have advantages and disadvantages.
I like option B) using Null as this removes garbage (data that is no longer needed) from the system. Keeping items in a system that are no longer needed can introduce errors and vulnerabilities,

C) A third option could be using Null and, when no changes are needed use some kind of Noop  (no operation, do nothing) indicator.

Table 6c

TOS ( n0 ? )n1n2n3


p1p0p-1p-2

TOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPNoopNulln2n1Noop
DROPTOS SWDTH -NullNullNoopNoop
+TOS SWDTH -NullNulln1 n2 +Noop
0TOS SWDTH +0NoopNoopNoop

If Null and Noop are Forth words a table can be created that describes Forth words in Forth code. The Noop has as disadvantage that just rewriting the old value perhaps is as fast or even faster then  evaluating that something is a Noop and not changing a value.

Table 7

TOS ( n0 ? )n1n2n3


p1p0p-1p-2

TOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPNoopNull-1 PA0 PANoop
DROPTOS SWDTH -NullNullNoopNoop
+TOS SWDTH -NullNull0 PA -1 PA +Noop
0TOS SWDTH +0NoopNoopNoop

Extending the table with more Forth words gives the next table (Table 8)

Table 8

TOS ( n0 ? )n1n2n3


p1p0p-1p-2

TOS1 PA0 PA-1 PA-2 PA

TOSTOS SWDTH + @TOS @TOS SWDTH - @TOS SWDTH 2* - @
SWAPNoopNull-1 PA0 PANoop
DROPTOS SWDTH -NullNullNoopNoop
+TOS SWDTH -NullNull0 PA -1 PA +Noop
0TOS SWDTH +0NoopNoopNoop
1TOS SWDTH +1NoopNoopNoop
2TOS SWDTH +2NoopNoopNoop
3TOS SWDTH +3NoopNoopNoop
4TOS SWDTH +4NoopNoopNoop
-1TOS SWDTH +-1NoopNoopNoop
-2TOS SWDTH +-2NoopNoopNoop
NoopNoopNoopNoopNoopNoop
-TOS SWDTH -NullNull0 PA -1 PA -Noop
*TOS SWDTH -NullNull0 PA -1 PA *Noop
/TOS SWDTH -NullNull0 PA -1 PA /Noop
=TOS SWDTH -NullNull0 PA -1 PA =Noop
@NoopNull@NoopNoop
!TOS SWDTH -NullNullNullNoop
2*NoopNull2 *NoopNoop
2*NoopNull2*NoopNoop
TOSTOS SWDTH +TOSNoopNoopNoop
TOSTOS SWDTH +"Value"NoopNoopNoop
SWDTHTOS SWDTH +"Value"NoopNoopNoop
SWDTH+NoopNullNoopNoopNoop
SWDTH-NoopNullNoopNoopNoop

In the last part of table 8 some issues can be seen that need (and can) be solved.  Therefor i did write it in Italics and some words i described in multiple ways.

! Can't be full described in this table.The result of ! will be that 2 items are removed from the stack. An address and a value. The value will be stored at the address. However it is not easy to extend the lookup table so it will include all addresses in memory. ( @ can be described in the table. However there must be some kind of low level implementation!)

2* multiplies the value that is on top of stack by two. It can be described as just doing 2 *
Written in Forth code : 2* 2 * ;  
However in some Forth systems this is implemented in low level code as it can be executed fast,  This is just one example, however in general this creates a dilemma when trying to make a table like this. Many Forth words can easy be defined as itself, However that does not explain what these Forth words do. Also sometimes these words can be implemented in another way using other Forth words or should  call low level code.  

TOS ( Top Of Stack) is a variable. It it can be put in the table just calling some implementation of itself. However an easy implementation is pushing 'the value of the address' on the stack.

 SWDTH is a (system) constant, as described in the beginning of this article. A constant can be described in this table as it self, Or just put the value on the stack comparable to TOS

Some sequences of operations appear very often in this table. Examples are
TOS SWDTH + and TOS SWDTH + and also my new Forth word PA
  : PA SWDTH * TOS @ + ;
This indicates that speeding up these sequences can speed up the Forth system. 

We have seen that we can put the descriptions of (several) Forth words in a table.
Can that help us in a new Forth implementation and what about a 'Non sequential computing environment'? Yes, if we can describe Forth words in a table we can describe Forth in a table. This not only makes Forth portable, it also makes it possible we can create Forth in a table environment, e.g. a relational database.

Tuesday, August 30, 2022

P0cForth

What is P0cForth?

P0cForth is NOT another (full) Forth implementation. It is a only minimalistic Forth like system and my idea about P0cForth, I respect other ideas about minimalistic Forth and even opinion that this is so minimal that it is not a real Forth system. That is why it has a 0 in it name.

Why P0cForth?

For a long time I was thinking what Forth words are minimal needed to code to create a Forth (like) system. There are guides what Forth primitives need to be created to bootstrap a full Forth system. However I wanted a minimalist set of Forth words. Not to bootstrap a Forth system, only as a proof of concept for a Forth system that can be extended. A search on internet gives information about several interesting minimal Forth systems. Even systems minimal systems including @ ! however that is not what i wanted.
Also wanted to give it a name. I decided for P0cForth , "Proof of concept Forth" , i changed the o to 0.
It is to have bare minimal system that is relative easy to build (and can be extended) to have a proof of concept Forth system. 

What words/code need to be in P0cForth?

In the Forth2020 Zoom meeting on 9 januari 2021 Dr Ting talked about  Jeforth 2.01.
He mentioned a minimal system with 9 Forth words
: ; * . , dup dolit ret here
He also presented simple demos:
: square dup * ;
: quad square square ;
; octet quad quad ;
8 octet . 4 octet .

I used this 9 words as a start for P0cForth., However, I want to

reduce it even more.

So I ended up with this 5 words:
: ; * . dup 
I decided to reduce the system even more by omitting the interpretation of numbers defining (some) numbers direct as words. This would decrease the programming code and logic. And yes when extending the proof of concept Forth real handling of numbers would be useful and literals and dolit can be very useful. However I wanted to reduce it as much as possible. Literals are a very useful method of implementation, however i did not want to force this as a solution for handling numbers in my definition of P0cForth.
The code created for a number as a Forth words for a target system can be easy copied and adapted for another number. So it could be easy extended to include a lot of other numbers. However i wanted it to  as minimal as possible.
What numbers would be needed  minimal to have a proof of concept Forth system? At first did think at a minimum i would be needing the numbers 0 1 2 3 and (perhaps) -1 With this numbers you can play in the minimal PocForth for testing. And these numbers could be included in the dictionary.
With * and -1 it can be  and easy extend it to numbers in the range -4 to 4 (However if you continue reading to the end you will see this idea was wrong. Only one very special number is sufficient to create all numbers!)
: 4 2 2 * ;
: -2 -1 2 * ;
: -3 -1 3 * ;
: -4 -1 4 * ;
Also the demo mentioned above can be tested (after creating 8)
: 8 4 2 * ;
: square dup * ;
: quad square square ;
; octet quad quad ;
8 octet . 4 octet .

Adding code for a + function would make it possible to extend the number range even further without having gaps.

My first idea of a minimal P0cForth that could be a first start for a minimal Forth as
5 Forth words                 : ; * . dup
5 ‘number words’           -1 0 1 2 3

Creating e.g. a text input stream processor with this 6 different type of words would give a proof of concept system that could be used as a basis to create a full Forth system. 

Two facts made me not complete happy with this set of words.
- The possibility to build a complete Forth with these words is missing. it is only possible to extend this Forth by changing the 'external' code and add more words. However this minimal words can be a good basis of a proof of concept when creating a new Forth.
- And most important I did think it would be possible to reduce this word set even more!
So i started to reducing
1 is not needed as it could be defined by the other words
: 1 -1 dup * ;
If i would add the Forth word + 2 and 3 can be removed 
: 2 1 dup + ;
: 3 1 dup dup + + ;
Also 0 is not needed as it can be created
: 0 -1 1 + ; 
: 0 -1 dup dup * + ;
I would never have imagined that it was only needed to have one number to create other numbers, and that that number would be -1  

P0cForth minimal wordset 
No interpretation of numbers needed and only 7 words 
:  ;  .  *  dup  +  -1

Here some demo code to demonstrate what can be done with this 7 word system
: 0 -1 dup dup * + ;
: 1 -1 dup * ;
: 2 1 dup + ;
: 3 1 dup dup + + ;
: 4 2 dup * ;
: 8 4 2 * ;
: - -1 * + ;
: square dup * ;
: quad square square ;
: octet quad quad ;
3 square .
8 octet . 
4 octet .
8 3 - .
I think it is possible to reduce this 7 word set even more or add more capabilities adapting the selection of this words.
A simple option would be to reduce the word set would be omitting ; and have a the new definition, that in Forth starts with the colon :  close always at the end of the line.

Tuesday, June 28, 2022

Non sequential computing environment and Forth -1-

Some things described in this article series can be used to implement the Forth programming language in a 'non sequential computing environment' and in a 'sequential computer environment..

My first reason to write this article series with the name 'Non sequential computing environment and Forth' is that non sequential computing can bring much computer power and will be easy to scale up if it is simple to use. It is called  'non sequential computing environment' as the terms parallel computing, parallel processing , concurrent computing or multitasking as give associations to to specific other things and solutions. ( https://en.wikipedia.org/wiki/Parallel_computing can help to give some background ) 

A second reason that this article series can be an inspiration for new Forth implementations and has items that can be used in a real implementation by others.

I am experimenting with new Forth implementations and want to report something about it. The third reason for writing this article series is that it can serve as an introduction to my experiments.

I the early days of computers was the cost of the hardware was an important limiting factor

You needed to spend a months salary for a 'simple' computer like a Commodore 64. To get more computing power the most easy way seemed to be is doing everything at a higher speed. Every evolution creating a next generation faster computers (and making the old computers obsolete).

A new fast computer is still relative expensive however there are also a lot of cheap computing devices available. Special hardware ( e.g. FPGA's , small micro controllers, memory ) is getting more and more available for low prices. Yes the newest and fastest hardware is still expensive however the price of getting computer power is extreme low compared to 40 years ago.

Small cheap processors and micro-controllers and FPGAs do have this interesting computing power. For only a few euro's or dollars it is possible to buy devices like raspberry (or other) pi systems or devices like ESP8266 or ESP32. When you look to the hours you need to work to earn sufficient to buy, several years ago, one computing device', nowadays can can buy more than hundred ESP32 devices. The only problem is that we do not (yet) have good software tools to handle that amount of computing power.  

In the 'classic' computer evolution the computer power was increased by a higher clock speed, adding memory caches special instructions and some other tricks. Processes and programs are executed sequential and the speed is increased to get more computing power. If we sacrifice some of the computer speed and could do things non sequential it is possible to scale up extremely by doing things in parallel. Perhaps this even creates 'greener' computers as old computer power does not become obsolete but can still be used as everything is non-sequential.

My opinion is that especially the programming language Forth can play a roll in a non sequential computing environment. Many programmers are trained in sequential programming and thinking. Also most programming languages are created in a sequential way.  Therefore also a mind shift is needed.
I will illustrate non sequential programming with some simple standard examples. Let say we have a simple problem with 2 variables. 

In a non Forth environment e.g.:
A = 5
B = 3
We want to swap the values so A will have the value of B and B will have the value of A.
In most languages it is not possible to put this in a program like
Let A = B
Let B = A
This as everything is executed sequential. In our example first A will get the value 3 ( the value of B ).
And in the second statement B will get the value of A. However at that moment A has the value of B (= 3 ) so in the end A as well as B both will have the value  3 .
In our sequential programming environment for swapping the values of A and B we need to introduce a third variable C and make a program like
Let C = A
Let A = B
Let B = C

In Forth it is a good practice to not use unneeded variables and do all calculations on the stack.
In Forth the values are manipulated on the stack.
Typing 5 3 will push the two values 5 and 3 on the stack.
With .S we can look on the stack and this can display something like (2) 5 3 showing that there a two items on the stack
When we want to swap the order in Forth we give the command SWAP
Checking again with .S gives 3 5

Can Forth do real magic and just SWAP these values in one step?
Unfortunately (most times) no!
This as SWAP (like many other Forth words) in most of the Forth implementations is build using multiple Forth high or low level commands that are executed sequential to do the 'swap'.
Sometimes a the second stack in Forth ( the return stack ) is used to temporary store the value.

A second example is the Forth word DROP . This word removes the top item from the stack. Depending how the stack is implemented in memory it also increments or decrements the Top Of Stack pointer ( the Forth variable TOS ). ( Incrementing or decrementing by 1 is a simple explanation. In fact it also depends on the hardware ( 8 or 16 bits) and the amount of bits of each item on the stack. If the stack items are 16 bits and the memory is just 8 bits the stack needs to be incremented or decremented by 2 and not by 1 ) 

A third, a little more complicated, example of Forth code. An addition.
For example
3 1 +
The values 3 and 1 are pushed on the stack. + does the addition so on top of the stack is now 4
In fact + does multiple things: Not only the two values are added. Also the top of the stack changed  (incremented or decremented depending how it is implemented in Forth.)

What if we could have a Forth that could do this in a non sequential way?
As a first step describing (and implementing) Forth commands in a non sequential way could help.
For most Forth words there are already descriptions in a more or less non sequential way. Often you see explanation of words described  like:

SWAP ( n1 n2 — n2 n1 )

n1 and n2 are the first and second item on the stack
We can represented most all (primitive) Forth words in using a (lookup ) table containing this information. See below a very simple lookup table (with the headers in bold).

Table 1.
  TOS n1  n2 n3 
 SWAP  TOS n2 n1 n3
 DROP TOS - 1
 n2  n3
  + TOS - 1
 = n1 + n2 n3

n3 illustrates that n3 did not change with any of the words SWAP DROP + 
TOS the top of (parameter) stack was also added illustrate that it changes.
E.g. DROP or + will increment TOS.
In part 2 of this article series i will write more in detail about this table.

Monday, March 29, 2021

Forth selfemit2":

  \  selfemit2":  FORTH  : code rewritten / adapted to run in WinForth 
  \  ( ugly as nice code 'goto NameFieldAddres' not quickly found in WinForth )

: selfemit2": here 4 + CREATE , DOES> @ swap 2* + dup @ emit 1+ @ emit ; 

 \  Example

selfemit2": MoTuWeThFrSaSu       \ Self emitting text

1 MoTuWeThFrSaSu   \ Emits Mo
2 MoTuWeThFrSaSu   \ Emits Tu
\ ..
7 MoTuWeThFrSaSu   \ Emits Su

   \ Also generic selfemit": can be made for use as
   \ 3 selfemit": MonTueWedThuFriSatSun
   \ 2 selfemit": MoTuWeThFrSaSu
   \
   \ or a complex flexible lenght that splits words at the capital in
   \  selfemitF": MondayTuesdayWednesdayThursdayFridaySaturdaySunday
   \
   \ For other Forth's or more/less characters BE CREATIVE 
   \ (Code does not work if complete defined string is not stored.
   \  I have seen Forth's that only store some characters and a checksum )
   \
   \          JanJeronimus   29MAR2021 

Saturday, December 12, 2020

Using Forth on my ELF II

Using Forth on my ELF II computer (including a CREATE DOES> explanation ) is the second article in a series about me and using Forth that started with my blogpost “My first computer and Forth” 
With Forth running on my ELF II computer with its RCA 1802 processor now real high level coding was possible.
I used virtual disk blocks with code stored in memory (loaded and saved to my system using audio cassettes). For coding in assembler an 1802 assembler in Forth was available. Also Forth text editor was published in a Forth magazine. I controlled hardware with Forth (an AY-3-8910 audio chip that I had added to my system). Forth became one the most important work horse on my system

In Forth you can new own words in vocabularies using : ; Do (complex) math in RPN using a (Forth) stack. Add extensions for floating point and strings. In my opinion one of the most powerful features of Forth is CREATE DOES> ( in the fig-Forth version when i started with Forth  <BUILD DOES> ).

Explanation of CREATE DOES>

Before i can explain CREATE DOES> (or <BUILD DOES> as it was called when i started with Forth) some fundamentals of Forth must be known. I do not give an in depth explanation however it is always possible to ask questions after reading this article.
Parameters (numbers) in Forth are passed using a stack.
(New) Forth words are stored in memory in a dictionary.
Things you type in using your keyboard are placed in a special memory area, the terminal input buffer. Space or spaces are used as separators between words and there is a character defining the end of line.
The Forth interpreter looks at the first word from the terminal input buffer and tries to find it in its dictionary. If found, there is also code to be executed in the dictionary. If not found Forth tries to convert it to a number and places the number on the stack. If not found Forth shows an error message.
After that (when there was no error) it continues with the next word until the end of line character in the terminal input buffer. The end of line character is just a special Forth word that prints an oke prompt and lets you enter a new line of text in the terminal input buffer.
Defining a new Forth word is placing a new word in the Forth dictionary together with the code that needs to be executed.
Example 1 : ; ( or colon semi-colon ) construction.
: My1stWord DUP 2 + . ;
The : puts My1stWord in the dictionary. DUP 2 + is the Forth code that belongs to My1stWord
; ( semi-colon) indicates that this is the end of the definition made by : ( colon )
Example 2 VARIABLE ( I do not encourage the use variables as often it is better to store things on the stack than in a variables)
15 VARIABLE My1stVar
15 is put on the stack. A variable with the name My1stVar is created containing the initial value 15 . ( I assume you have a Forth system where the initial value is on the stack. it is also possible you have a system where no initial value is needed/used.)
When the new Forth word My1stVar is executed it gives a memory pointer to the address where the value of the variable is stored. To get the value ( 15 ) we can use the Forth word @ This word uses the address (that is on the top of the stack) and fetches the value.
The magic of creating new words is CREATE DOES>
CREATE creates a new word in the dictionary and the DOES> part tells what to do.
Let make the Forth word JVAR to create a variable This is relative simple:
: JVAR CREATE , DOES> ;
: defines the word JVAR
CREATE is a word that creates the dictionary entry. The dictionary entry contains a pointer to the DOES> part. So when the word is found in the dictionary it knows what to do.
, ( comma ) is just a simple word that gets a number from the stack and puts it in the dictionary.
And then there is the DOES> part, in this case seems to do nothing.
When we now enter 12 JVAR My2ndVar The variable with the name My2ndVar is created and available in the Forth Dictionary.
When the new Forth word My2ndVar is executed it gives a memory pointer to the address where the value of the variable My2ndVar is stored. To get the value ( 12 ) we can use the Forth word @
To change this to the behaviour of a “constant” where, when executed not a pointer but the value is on the stack, we could do something like
: My1stCONST My2ndVar @ ;
However this would be an uncommon way to create a constant as this is actually fetching a variable. Creating multiple constants would require for each constant also a variable.
Let us make a word JCONST to create a ‘real’ constant.
: JCONST CREATE , DOES> @ ;
The @ is now in the DOES> part.
32 JCONST My2ndCONST
creates the word My2ndCONST
The DOES> part uses the address and fetches ( @ ) the value.
A very powerful way to make defining words at your own flavor as everything can be adapted in this CREATE DOES> concept.
For example create double size variables initialized with the value 0
: JDVAR CREATE 0 , 0 , DOES> ;
or do you want something else like a constant with a value that increments each time with one when a new constant word is created?

Forth has advantages and disadvantages. Floating point math, use of text strings. It was always a bit different from other computer languages. Most times with what I would call ‘more contact to what is really happening in the system’. I liked using less variables and using the data stack.

In my brain came the idea that the most beautiful programs are the smallest ones. When I was repeatedly typing (almost) the same code (copy and paste was that time not as easy as nowadays) programs could be done differently (and better). When you expect to find here a lot of real Forth code that you can enter in any Forth system I must disappoint you. However I present some ideas and parts of code that you can use in your Forth system if you know some of the internal working of your Forth system and add some code to adapt it to your Forth system.

A (lazy) simple program to control your hardware in Forth only needs
1 :LAMP LAMP_CHILDROOM
2 :LAMP LAMP_LIVING
4 :LAMP LAMP_B
8 :LAMP LAMP_BEDROOM
If you have created a smart defining word :LAMP with your system suddenly can understand what to do when you type
OFF LAMP_LIVING
ON LAMP_BEDROOM
TOGGLE LAMP_CHILDROOM
TEST? LAMP_CHILDROOM
I used TOGGLE to switch it ON when the light was OFF or switch of OFF when it was ON.
TEST? to leave TRUE or FALSE on the stack depending on the current state.
OFF ON TOGGLE and TEST? can be implemented as constants that each push a different value on the stack.
:LAMP is used to define LAMP_CHILDROOM LAMP_LIVING LAMP_B LAMP_BEDROOM
The 1 2 4 or 8 are stored in these words so later on FORTH knows which hardware bit controls which lamp. The DOES> part is executed when the new defined words are executed.
It gives a pointer to the defined word so the correct hardware bit (and/or other parameters) that was stored during the <BUILD can be fetched.
OFF ON TOGGLE and TEST? pushed a value on the stack so the DOES> part can use it to determine what to do.
So on the stack are the bit/hardware parameters and what you like to do ( OFF ON TOGGLE or TEST? )
SWAP these, so what you want to do is on top of the stack. Using a CASE statement you can continue with the code to turn the bit/(hardware) high, low, toggle it or test the current state (and leave that as a flag on the stack).
To turn all the lights of you need something like
OFF LAMP_CHILDROOM
OFF LAMP_LIVING
OFF LAMP_B
OFF LAMP_BEDROOM
or
OFF OFF OFF OFF LAMP_CHILDROOM LAMP_LIVING LAMP_B LAMP_BEDROOM
This as each device needs its own control parameter when coded the way described above.
Some people don't like that.
This can be solved in different ways:
Method 2 could be OFF ON TOGGLE and TEST? are not constants that were pushed on the stack. Implement OFF ON TOGGLE and TEST? as words that change a variable
Method 3 could be don’t eat the value of OFF OF TOGGLE or TEST? from the stack.
Change the code so it is after (successful) execution still on the stack. (Otherwise leave a special number indicating there was an error)
Another option could be that you don’t like the spaces between the command and word at all.
2 :LAMP LAMP_LIVING
You do not want to create one word LAMP_LIVING
It should create multiple words (without spaces):
LAMP_LIVING_OFF
LAMP_LIVING_ON
LAMP_LIVING_TOGGLE
LAMP_LIVING_TEST?
This is also possible because :LAMP can define multiple words e.g.
2 2 2 2 :LAMP LAMP_LIVING_OFF LAMP_LIVING_ON LAMP_LIVING_TOGGLE LAMP_LIVING_TEST?
This as you can make :LAMP consisting of multiple defining words like
: :LAMP :LAMP_OFF :LAMP_ON :LAMP_TOGGLE :LAMP_TEST? ;
:LAMP_OFF has a CREATE DOES> to turn a bit off
:LAMP_ON has a CREATE DOES> to turn a bit on
:LAMP_TOGGLE has a CREATE DOES> to toggle a bit
:LAMP_TEST? has a CREATE DOES> to test a bit
Each of the defining words needs to know the hardware bit (in this case 2)
It is strange and can give errors if you need to do it as described before repeating 2 2 2 2.
Again this can be solved multiple ways:
One method is by duplicating the hardware bit (Except the last time)
: :LAMP DUP :LAMP_OFF DUP :LAMP_ON DUP :LAMP_TOGGLE :LAMP_TEST? ;
Another method is to make the code of the defining words :LAMP_OFF :LAMP_ON :LAMP_TOGGLE :LAMP_TEST? keeping the hardware bit on the stack
: :LAMP :LAMP_OFF :LAMP_ON :LAMP_TOGGLE :LAMP_TEST? DROP ;
The last word does not need to maintain the bit on the stack. However for consistency it let all words keep the hardware bit and DROP it at the end.
This way if you later-on add a new thing like :LAMP_BLINK you do not need to check which words change the stack.
This all to reduce the code from
2 2 2 2 :LAMP LAMP_LIVING_OFF LAMP_LIVING_ON LAMP_LIVING_TOGGLE LAMP_LIVING_TEST?
to
2 :LAMP LAMP_LIVING_OFF LAMP_LIVING_ON LAMP_LIVING_TOGGLE LAMP_LIVING_TEST?
What about improving the code so
2 :LAMP LAMP_LIVING
would create in the Forth dictionary
LAMP_LIVING_OFF LAMP_LIVING_ON LAMP_LIVING_TOGGLE LAMP_LIVING_TEST?
This is not very difficult. You need to know in detail how (your) Forth creates new words.
CREATE (or <BUILD) gets the new word that needs to come in the dictionary from the terminal input buffer (TIB). Adapt this so you start each time again at the same word LAMP_LIVING and add the _OFF _ON _TOGGLE _TEST?
You need to DIG in your system to check how this is implemented. (Perhaps you have the word DIG to check Forth words).
So modify Forths so not the next word from the terminal input buffer is fetched (and eaten) but a word is defined including _OFF _ON _TOGGLE or _TEST?

Unfortunate i learned that in eForth there is no CREATE DOES>.  However i expect some of the ideas presented still can be used. For example modifying the defining words so not only the word comes in the dictionary, also with suffixes appended as _OFF _ON _TOGGLE _TEST?

Friday, November 20, 2020

Found Emma 02 an RCA 1802 emulator

Just found Emma 02 , an 1802 Emulator that can emulates several RCA 1802 systems and could not resist trying a quick install, and it worked.

Internet home         https://www.emma02.hobby-site.com/
(Download             https://www.emma02.hobby-site.com/download.html )
Facebook               https://www.facebook.com/emma02.emu/
Github                    https://github.com/etxmato/emma_02

After the easy installation on my windows machine i did run it.
On the tab "Elf" i pushed at the [Start] button. (bottom left)In the green terminal screen 'For help type HELP.' at the >>> prompt type FOR NEW  or FOR OLD start a Forth.
(It is also possible to type FORTH , and the system wil ask OLD or NEW ) 

It is also possible to emulate other 1802 systems e.g. the COMX-35 (an RCA 1802 computer i never owned) that runs a Basic version.

Thursday, November 19, 2020

FORTH on Arduino -3- (Funduino Joystick game shield)

Having eForth running on my Arduino testing some I/O is what i wanted. Some years ago i posted https://blog.jeronimus.net/2017/04/funduino-joystick-shield.html about an Arduino joystick / button shield. This cheap shield has a joystick some input buttons. (And some connection headers that i did not use in this test.)  
There are several versions of this board. I have the Funduino V1.A The shield gives your Arduino the functionality found on the old Nintendo controllers. It can be used for gaming or control hardware.
2 analog inputs and some digital Ideal to start with this this shield with eForth to do some simple input tests. 


The table below lists how the buttons are connected to the Arduino 

ArduinoButtonPort&bit
D2Key A UPPD2
D3Key B RIGHTPD3
D4Key C DOWNPD4
D5Key D LEFTPD5
D6Key E StartPD6
D7Key F SelectPD7
D8Analog buttonPB0
A0AnalogX JoystickAnalog0
A1AnalogY JoystickAnalog1


The ForthArduino1.pdf contains several I/O examples that can be tested with this board: 

For the analog ports
Paragraph 3.5 mentions
If you connect an external analog signal source to the A0 pin, then type the following commands to read its analog value:

27 C!    \ setup A0 as input pin, which is on PC-0 port
 1 28 C! \ turn on pull-up resister on A0 pin
40 7C C! \ setup reference and multiplexer inputs
C3 7A C! \ start conversion
78 ?     \ display results 78 = low byte 79 = high byte

Example for digital port  ( D8 PB0 button of joystick)

 0 24 C! \ make all Port B pins input
 1 25 C! \ turn on pull-up resistor for Line 8
23 C@  . \ read PINB port and show its contents

23 C@ . \ repeat with switch on and off

What i especially like about eForth on Arduino is that using the terminal you can interactively test and play with the system to adapt it to your own needs.
The AVR Family databook / ATmega328P datasheet contains detailed info about all the internal registers. Also the multiple functions of the pins are explained.
Also you can find the info that i summarized in the table below.


Data register

Data direction
 register
Input pin address

PortBPORTBDDRBPINB
D8
Analog button
0x05 (0x25)
0x04 (0x24)
0x03 (0x23)
PortCPORTC
DDRC
PINC

0x08 (0x28)0x07 (0x27)0x06 (0x26)
PortDPORTD
DDRD
PIND
D2-D7
Key A - F
0x0B (0x2B)0x0A (0x2A)0x09 (0x29)





For reading the other buttons you need to read portD.
 0 2B C! \ make all Port B pins input
FF 2A C! \ turn on pull-up resistor for all lines
29 C@ .  \ read PINB port and show its contents

Some simple words to play with the shield and print the output :
: .PD  0 2A C! FF 2B C! 29 C@ . ;              / Print PortD  ( Buttons)
: .PB  0 24 C!  1 25 C! 23 C@ . ;              / Print PortB ( Joystick button)
: .PX 27 C!  1 28 C! 40 7C C! C3 7A C! 78 ? ;  / Print Joystick X value
: .PY 27 C!  1 28 C! 41 7C C! C3 7A C! 78 ? ;  / Print Joystick Y value
: .JOY .PB .PX .PY ;                           / Print all Joystick values

I used short cryptic words like .PB. More descriptive would be .PrintPortB, For playing with the system it would require more typing more characters. 

In Forth it is also possible to change the output to binary to easy see the bits corresponding to each button:
2 BASE !   /  Set Binary output 
HEX        /  Set Hexadecimal output

Hope this Arduino Forth ( eForth) introductory blog article can be help others starting to use Forth on Arduino.

Tuesday, November 17, 2020

FORTH on Arduino -2-

When i wrote FORTH on Arduino -1- i had some open questions. Now i have some answers and info how to proceed. I did not try it yet. However i like to post it as a short quick update about  eForth in my 'FORTH on Arduino' series.

- To trick the Arduino so it will start a special Forth word if no terminal input is received within a certain time or depending on a High or Low value on an Arduino pin to create a simple reconfigurable embedded Forth system. should be quite easy. In the book 'eForth and Zen' and especially the ForthArduino_1.pdf  ( Tao of Arduino ) by Dr. Chen-Hanson Ting is info how to create a turn key system that, after a reset or at power on starts with Forth word.
A quote from chapter  "3.6 Build a Turnkey Application" where a forth word APPL is created:

To turnkey this application so that it executes APPL command on booting-up, type the following commands:
' APPL 'BOOT ! \ store address of APPL in variable 'BOOT
$100 ERASE \ erase flash
$100 $100 WRITE \ save RAM $100-17F to flash $100-17F
$180 ERASE \ erase flash if this page is used
$180 $180 WRITE \ save RAM $180-1FF to flash $180-1FF

- Using I2C can be done in different way. i would like to use the Arduino library and interface this to Forth. This to also know how to use other Arduino libraries and code that already works in a 'plain Arduino environment'.  I am still looking for more info about this.
Another option is controlling the IO pins fir I2C direct from within Forth as e.g. explained in   https://arduino-forth.com/article/arduino_I2Cinterface


FORTH on Arduino -1-

 FORTH on Arduino

Before trying to install a Forth where changing the bootloader is needed i wanted to experiment with Forths that are more 'plug an play'.

First i tried Yaffaforth

After downloading unpacking it tried to compile it. Seemed that it also needed install FreeMemory. After installing this and spending more time than desired it still kept giveing error messages e.g. 'ip' was not declared in this scope .

As in the Yaffaforth information i found on internet a relative old Arduino version is used and the Yaffaforth is also relative old i decided to try stop and try another Forth for Arduino.

Therefore i moved to eforth of Dr. Ting . This Forth compiled without problems on my PC. Also uploading to the Arduino was easy.

The only issue that needed to be fixed was my terminal configuration. In the code i found the baud-rate and i needed to adjust some CR LF settings. It looks great however i did not yet had time to read all documentation to find a solution for the following issues:

- I want to use more IO including I2C within Forth on my Arduino.

- BUILD DOES> that later changed to CREATE DOES> is not available in eforth. I wanted to use this like i used it years on my RCA 1802 computer.

- How to trick the Arduino so it will start a special Forth word if no terminal input is received within a certain time or depending on a High or Low value on an Arduino pin. This to create a simple reconfigurable embedded Forth system.

So i still have a lot to learn and hope to post something about this process on this blog.. eforth seems a great Forth for Arduino. It was easy to install was for me worth the time spend and i want to investigate it further as you also seem to have access to all arduino libraries.

Saturday, October 17, 2020

My first computer and Forth

When I needed to select my career it was difficult to choose between chemistry and electronics. I decided to go for (analytical) chemistry and kept electronics as a hobby. In my last years at school computers were just coming. The last years i went to school there where 4 terminals (with one printer) connected (i expect via a phone line) to a computer somewhere else and we had to write some computer programs in Basic as exercise.   

There I became fascinated by computers, did know a little bit of electronics, and after finishing school I started working in a pharmaceutical company. 

I wanted to know more about the link between the electronics and computers. In the Popular Electronics Magazine i found an article about the 1802 microprocessor. That was the first article about a microprocessor where I at least thought that I understood something a little bit. Magazines spread interesting articles over multiple editions, so a month later i also needed to buy the next edition as, i expect for a business model, most interesting articles were spread over multiple editions. After this I did read articles about other microprocessors, however at that time a lot of it was very complicated for me.
As the desire to have a real computer for my own grew I started investigating options. I already had a programmable calculator. Buying a ready computer was, at that time, not an option. The only little affordable options were some microprocessor kits and I decided to buy an ELF II with an 1802 processor.

For me important features were that it had a graphic chip so you could create some (black and white) graphic output to display on a TV and the architecture and instruction set of the 1802 was easier for me to understand than that of other processors. I ordered a kit and after soldering I got the ELF II with its 256 byte (¼ k) ram, the graphic processor, a hexadecimal display, a hex keyboard working and started leaning more.

Very soon I also needed the expansion board with a 256 byte containing a small monitor program. The most important in the 256 byte rom was a program to read and write memory to an audio cassette recorder using simple hardware interfaces on this board.

Some of the 256 byte memory was also used as memory for graphics on the TV. 256 byte (¼ K) is not much so I kept looking at the slowly decreasing price of additional memory.
At some point I decided not to for the 4K ram memory board and made a big jump by buying a 64K ram board with 48K ram. I expect it was around that time that my boss told me that it was a little crazy that I had a computer. However he understood it as i was only living during the weekends with my parents a little more than 200 km away from my work. From Monday till Friday I lived in a small room near my work and could enjoy my computer.

And with the huge amount of memory it became possible using programming languages on the ELF II 1802 processor. However often the programming languages used a terminal on the RS232 interface and that was, after already spending more than a month's salary on my computer, above my budget. However i did buy a kit for an ASCII keyboard over the parallel port. 

There was Chip8, Pilot and from a magazine i did type over a terminal program using the video chip using black and white characters. I could not use Basic as this language needed an external terminal on the RS232 port and there was no info or source code about its internal working.

And then there came Forth. I got a cassette tape and a print of the 1802 programming code for Forth also using the RS232 interface. However the standard Forth interface uses only 3 important routines. ?KEY and KEY to check and get input from the keyboard and EMIT to output one character. Making ?KEY and KEY work was not that difficult and in my first Forth experiments i used the hexadecimal display with a button to go to the next character after reading the HEX Ascii value and decoding it to the ASCII value.

My plan was interfacing Forth with the 1802 terminal program as that seemed possible as the source code of these two programs was available. This was my first real big IT project and I am still proud that I, on my own, could make this work.

The first,and easiest step was to move the terminal program (and video memory) to another part in memory. After that came the bigger challenge. The 1802 processor has 16, almost identical, registers of 16 byte. Each of these registers can be assigned as a program counter, stack pointer, a pointer somewhere in memory or to store a bite in the high or low part. These registers are also used in the Forth implementation for the 1802 processor.
However these 16 registers ( 0 to F) are almost identical, not completely!
R0 was (also) used for DMA, direct memory access for the graphical display chip.
After a hardware interrupt (also used for the video display) R1 became the program counter and R2 became (assembler) stack pointer. Also some of the registers were used in the terminal display program.
As these registers were also used in the 1802 Forth code i needed to change this in the Forth code. Nowadays this would be easy. At that time I did not have a working assembler. Only the hex keyboard, a hexadecimal display, a simple monitor program in the rom to inspect and change a hex address using the limited I/O. And after making changes I needed to store my work on an audio cassette tape to continue on another day.  Printing a version with changes was not possible as a printer was not available. So i used a paper notebook to keep track of changes to do and done.

The video display worked using the interrupt code and DMA (direct memory access). Every time to display memory data on the TV screen the video chip gave an interrupt.. It did set R0 to the beginning of the video memory and some other housekeeping. As Forth and the Terminal program used the registers. Also a small assembler program that saved and retrieved some of the 16 registers in memory when going from Forth to the Terminal display program and vice versa was added.

After many evenings of work the changes in the code where ready and the Forth ok prompt appeared on my black and white television and my adventure could continue on a higher level.