Page 1 of 1

Memory Mapped I/O in Tali Forth 2

Posted: Mon Oct 26, 2020 5:02 pm
by Shawn Odekirk
Complete Forth newbie here. I've recently gotten Tali Forth 2 running on my SBC and would like to set some outputs on my 6522 VIA. It is mapped to addresses $8010..$801F.
What is the typical way to write to and read from memory? Are there existing Forth words, or will I need to write my own?

I may have figured it out

It looks like the following works. Is this the correct way to do this?

Code: Select all

hex
FF 8012 !
1 8010 !
Thanks,
Shawn

Re: Memory Mapped I/O in Tali Forth 2

Posted: Mon Oct 26, 2020 6:17 pm
by GARTHWILSON
Sure; but you'll want to give the addresses names that are meaningful to humans, typically with CONSTANTs. They take headers space (unless you're compiling headerless code), but if you use them enough, they'll pay for themselves, since reference to a constant takes only one cell versus a literal which takes two cells. The following is from my workbench computer's ROM Forth:

Code: Select all

\ VIA1 is the base address of the first 6522 on the SBC.  Following are
\ the addresses of different registers in the 6522.  VIA1 is the only IC on NMI.

       6000     EQU VIA1	     \ Base address of first 6522.
  VIA1 0 + CONSTANT VIA1PB      \ Port B
  VIA1 1 + CONSTANT VIA1PA      \ Port A
  VIA1 2 + CONSTANT VIA1DDRB    \ Data Direction Register for port B
  VIA1 3 + CONSTANT VIA1DDRA    \ Data Direction Register for port A
  VIA1 4 + CONSTANT VIA1T1CL    \ Timer 1 Counter Low byte
  VIA1 5 + CONSTANT VIA1T1CH    \ Timer 1 Counter High byte
  VIA1 6 + CONSTANT VIA1T1LL    \ Timer 1 Latch Low byte
  VIA1 7 + CONSTANT VIA1T1LH    \ Timer 1 Latch High byte
  VIA1 8 + CONSTANT VIA1T2CL    \ Timer 2 Counter Low byte
  VIA1 9 + CONSTANT VIA1T2CH    \ Timer 2 Counter High byte
  VIA1 A + CONSTANT VIA1SR      \ Shift Register
  VIA1 B + CONSTANT VIA1ACR     \ Auxiliary Control Register
  VIA1 C + CONSTANT VIA1PCR     \ Peripheral Control Register
  VIA1 D + CONSTANT VIA1IFR     \ Interrupt Flag Register
  VIA1 E + CONSTANT VIA1IER     \ Interrupt Enable Register
  VIA1 F + CONSTANT VIA1PANOHS  \ (same as VIA1PA, but no handshaking)

(and it continues with VIA2, VIA3, ACIA1, ACIA2, and ACIA3). The abbreviations are taken from the data sheet, so they should be easy to remember. My applications are always for technical I/O for workbench control, not human applications like finance; so it's standard for me to keep it in hex most of the time. Since [ HEX ] and [ BINARY ] and [ DECIMAL ] take so much room in colon definitions in the source code lines, I made the IMMEDIATE words [H] and and [D} to take their place.

Re: Memory Mapped I/O in Tali Forth 2

Posted: Mon Oct 26, 2020 6:23 pm
by leepivonka
! is store a cell (2 bytes in Tali)
@ is fetch a cell (2 bytes in Tali)
c! is store a character (1 byte in Tali)
c@ is fetch a character (1 byte in Tali)

Look at the definitions of these words in the Tali source for more implementation detail.

Re: Memory Mapped I/O in Tali Forth 2

Posted: Mon Oct 26, 2020 8:55 pm
by SamCoVT
Hi Shawn,
Congratulations on getting TaliForth running on your SBC!
It looks like you are on the right track and leepivonka's note is important - you'll want to use C@ and C! for accessing byte-wide registers. Here is some code I used to create an I2C bus on two of the pins (heavily influenced by Garth's notes on doing such a thing).

Code: Select all

\ Set up the VIA for I2C.  I'm using the VIA DDR method.

\ PTA7 is data  
\ PTA0 is clock 

hex
7F01 constant via.porta
7F03 constant via.ddra
\ Make port A an input so the bus starts idle.
: i2c-setup 0 via.porta c! 0 via.ddra c! ;

\ Data on PORTA7 (note that 0 = 1 on the I2C bus for writing)
\ : i2c-sda0 via.ddra c@ 80  or via.ddra c! ;  allow-native
\ : i2c-sda1 via.ddra c@ 7f and via.ddra c! ;  allow-native
In this code, I make bit 7 of PORTA a zero and then mess with the DDRA (Data Direction Register for port A) bit 7 to change it between an input and an output. This is a neat way to make an open collector signal without having to add a transistor (but you do need a pull-up resistor). The i2c-sda0 and i2c-sda1 words are commented out because I ended up rewriting them in assembly for speed, but you can see where I am reading the current value of the DDRA register (via.ddra c@) and either ANDing it with 0x7F (7f and) or ORing it with 0x80 (80 or) to change just bit 7, and then I write that value back to the DDRA register (via.ddra c!).

I also like Garth's method of declaring the base address and then computing the offsets to the internal registers. I've since started doing my code that way as it makes it much easier to port to a different machine later - you only have to adjust the first line. I don't believe Tali2 has EQU, so you'd just use CONSTANT for that first address as well.

Note that the . in the names of my constants doesn't do anything special - it's just for me to help me organize my constant names around what they go to.

Re: Memory Mapped I/O in Tali Forth 2

Posted: Sat Oct 31, 2020 12:23 am
by Shawn Odekirk
Thanks to everyone for their comments. They are very helpful.
I am reading "Starting FORTH", but haven't gotten too far yet.

Shawn

Re: Memory Mapped I/O in Tali Forth 2

Posted: Thu Nov 05, 2020 9:30 pm
by SamCoVT
The best way to learn Forth is to use Forth, and Brodie's "Starting Forth" is a good place to start with all of its examples. You can run those examples on Tali Forth 2.

I think the biggest issue I had when starting out was just learning enough words to do useful things. Tali Forth 2's documentation is pretty good once you know a little bit of Forth, so you should work your way through that after you get through Starting Forth. You can go to the Glossary in the Appendix (in manual.pdf found in the TaliForth2/docs folder) to see quick usage information for all of the words that Tali2 supports. Most of Tali2's words are from the ANS 2012 standard, and you can find even more detail on what a word does by referencing https://forth-standard.org and I often use the magnifying glass at the top to search for words.

The good news is that you don't have to learn all the words at once, and once you start using Forth, you'll quickly learn the words most useful to you. My most used words are .S (see what is on the stack) and DUMP (see what is in memory) when I'm testing things out. The word that I always want to use and can never remember the name of is UNUSED (how many bytes of RAM left - and I just had to look it up again to write this), so don't feel bad if you can't remember a word you want to use and have to look it up.

If you get stuck, or just want to know how to approach something, feel free to let us know what you're trying to do and what you've tried so far, and we'll be happy to lend a hand. If you come up with a word you've created and want to know if that's the best way to do it, we can help with that too (although beware that different people might have different "best" answers :D , but they will all be interesting and informative). You are also encouraged to share your "aha!" moments, of which there will be many if you really start digging deep into what Forth can do.

Re: Memory Mapped I/O in Tali Forth 2

Posted: Fri Nov 06, 2020 1:13 pm
by Martin_H
To teach myself Forth (or any computer language) I'll write a bunch of small programs for algorithms I am familiar with. You'll inevitably search for language mechanisms that solve common design problems. For example, building a generalized sort makes you learn about execution tokens which are the equivalent of C's function pointers. Similarly parsing is a common problem to solve.

I then recorded the results in my Forth CS-101 repo:
https://github.com/Martin-H1/Forth-CS-101

Re: Memory Mapped I/O in Tali Forth 2

Posted: Fri Nov 06, 2020 7:25 pm
by GARTHWILSON
Martin_H wrote:
For example, building a generalized sort makes you learn about execution tokens which are the equivalent of C's function pointers.

One of the many, many things I like about Forth is that pointers of any kind are not any different from any other numbers. The absence of such typing in Forth makes it more flexible, and yet Forthers can always finish bug-free applications much faster than the C crowd can.