Showing posts with label 1802. Show all posts
Showing posts with label 1802. Show all posts

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.

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.