adrianhudson wrote:
SamCoVT wrote:
If you wanted to do an interrupt based background task (based on one of your 65C22 timers, for example)
Umm, forth or assembler? I doubt I am up to coding an interrupt routing in forth yet!
While I am here, can I ask: I have been coding away in Forth and pasting the code into my terminal program. Eventually Tali crashes. On investigation I suspect the dictionary grows with old versions of words as I edit/test/edit/test until Tali crashes. Is this your expectation or is there something else going on do you think? Do all Forths just grow or do some have housekeeping? I guess that would be non-trivial.
Your interrupt task could easily be in assembly (just put it in your platform file). You already have an ISR that handles serial, so it would have to handle both that as well as a timer, but Garth's primer does a good job showing how to handle multiple interrupt sources. It should be possible to write ISRs in Forth, but it's more complicated and would be a bit of an adventure. Tali is an STC (Subroutine Threaded Code) type Forth, so it compiles runnable 65C02 op-codes into the dictionary. Tali also has an assembler, so you can write assembly directly from Forth and even mix Forth and assembly when compiling. You would need a way for your firmware ISR to be able to run a RAM routine (if it exists) - Tali leaves half of zero page free for you to use so you might put a RAM vector there.
Tali can compile a LOT of words before you run out of space. On a 32K RAM system, there should be about 29K free at startup. The Tali test suite is the only software I know that actually would use all of that RAM, but it has a lot of extreme test cases, like a 4K RAM drive and strings longer than 256 characters. The test suite uses MARKER to set a point to return to at the top of each test file and runs that word at the end of the tests to restore the dictionary.
It is very possible to compile words that crash Tali. In particular, Tali does not have "compiler security" so it is possible to write an IF and forget the THEN or write a DO and forget LOOP. These kinds of words, with mismatched or missing flow control words inside, are likely to crash Tali. Many flow control words compile a jump to address 0000 that is replaced by the ending word once the address to jump to is known (eg. only when we reach THEN do we have the address to jump to if an IF-THEN is false, so THEN goes back and "patches" the IF). There is no code at address 0000, but the 65C02 will read the data there as if it is opcodes and try to run it.
The standard way I test to see if I've made a mistake is to do a
.S after defining a word. If there is extra stuff on the stack (these are the addresses of opcodes that need patching) then I've definitely made a mistake. Here's a silly example to show that:
Code:
: test if 8 . ; ok \ Make a word test that prints 8 if true (but I forgot the THEN).
.s <1> 2063 ok \ Check the stack afterwards - oops, there is an address there and the stack should be empty.
Breaking code into small pieces held in separate words helps to narrow down these kinds of errors.
On a separate topic, some folks are discussing FORGET, however Tali does not have this word. It uses the word
MARKER instead. It's true that you have to know ahead of time that you'd like to come back to a particular spot and create the MARKER word ahead of time. When you run the marker word, Tali removes all words (defined after the marker word) in all wordlists (Tali uses wordlists, which operate a little differently than the older VOCABULARY based Forths) and resets the search order (which controls the order that wordlists are searched in - first one that has a word of that name wins). If a new wordlist has been created after the MARKER word, it is also removed. Here is an example of using MARKER, and you can look at the test files (in /tests) to see them in actual use at the top and bottom of test files.[size=115]
Code:
\ Do some stuff and define words you'd like to keep.
MARKER mymarker \ Creates a new word named mymarker that will return to this spot dictionary-wise.
\ Define some new words. Break something. Want to go back.
mymarker
\ The word mymarker and everything after it will be gone. It basically re-winds the dictionary to that spot.
\ Any side effects, like changed variables or updated blocks in EEPROM, will remain.
\ eg. BASE is not changed/restored
I rarely use MARKER in daily use. I prefer "reproducible state" where I keep all of the definitions and all of the words to run in a file (on my computer) so I can get to a particular state from a cold start. That way, I can reset my board, paste that file in, and be in a known state. I can try to some code, and if it works then I add it to the file and now that is my reproducible state. Also, if I need to go to bed and pick things back up tomorrow, I only have to boot up my board and paste in my code to be right back where I was the day before.