6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Apr 27, 2024 4:17 pm

All times are UTC




Post new topic Reply to topic  [ 264 posts ]  Go to page Previous  1 ... 14, 15, 16, 17, 18  Next
Author Message
PostPosted: Tue Dec 06, 2022 12:18 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851

TaliForth should have the word MARKER which creates a self forgetting word.
MARKER <NAME>
When <NAME> is executed, the dictionary and wordlists are reset to their condition prior to the definition of <NAME> .
From Forth Standard.org
Code:
MARKER CORE EXT
( "<spaces>name" -- )

Skip leading space delimiters. Parse name delimited by a space. Create a definition for name with the execution semantics defined below.

name Execution:
( -- )

Restore all dictionary allocation and search order pointers to the state they had just prior to the definition of name. Remove the definition of name and all subsequent definitions. Restoration of any structures still existing that could refer to deleted definitions or deallocated data space is not necessarily provided. No other contextual information such as numeric base is affected.

Other Forths may use FORGET . It parses for the name of a word to forget. Everything defined after this name will be forgotten. Some Forths with FORGET have built in protection to prevent forgetting words in the kernel.
There is also EMPTY for some Forths. This word empties the dictionary to its latest save state (the bootup size or the size since last saving the Forth image.)


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 06, 2022 1:21 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
Jim, thanks for the attention to MARKER.  Calling it a self-forgetting word makes it more clear than material I had read previously.  Admittedly I probably had not paid enough attention and really tried to understand it, possibly because I wondered why there was any need to replace FORGET.  I think FORGET <name> is more intuitive.  It might be more difficult to use in a definition; but why would you?!  I do use FORGET a lot when I'm developing, after I've compiled quite a few versions of a word to see what I like best.

Quote:
Some Forths with FORGET have built in protection to prevent forgetting words in the kernel.

There should be the variable FENCE behind which FORGET is not allowed to go.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 06, 2022 2:25 am 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851

Forth Standard.org has this to say about FORGET .
Code:
FORGET name tries to infer the previous dictionary state from name; this is not always possible. As a consequence, FORGET name removes name and all following words in the name space.

This sounds like it might be a consequence of wordlists.
I also recall mention of problems with some poorly written versions of FORGET .
The FORGET for my Forth works just fine. My Forth does not have wordlists. It has vocabularies which are chained to a parent vocabulary. All vocabulary chains lead to the FORTH vocabulary, the lowest level vocabulary.
FORGET only searches the CURRENT vocabulary, not any parent vocabularies, for the word to forget.
It removes any vocabulary which is defined after the forget point.
It prunes the remaining vocabularies which are all linked in a chain with the last stored in the variable VOC-LINK .
FORGET aborts if the word to be forgotten is lower than the value of FENCE (which can be changed) or lower than the value of the internal fence which is a literal in FORGET . It is the value of the target's HERE when metacompilation is complete. This means that unless FORGET is hot patched, kernel words cannot be forgotten even if FENCE is off.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 06, 2022 3:50 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
...all valid points, but I see problems with MARKER too.

  • To use MARKER, you have to know, in advance, where you might want to back up to.
  • MARKER requires coming up with names you'll remember when it's time to back up to there.
  • Assuming there could be multiple places you'd want to back up to, you have to come up with a lot of names, and keep them straight.
  • MARKER takes extra dictionary space, whereas FORGET could apply to hundreds (or even thousands) of places, all without taking any extra space.
  • In the case of intertwined vocabularies, although MARKER may preserve later-defined words in other vocabularies, I don't see any benefit in memory usage unless words to be forgotten in the current vocabulary take a significant memory space and were defined after any compilation in another vocabulary.  Maybe I'm missing something there.

The way I use Forth, I haven't needed vocabularies.  AIUI, one use of them was for multi-user situations, back when a lot of people had to share a computer, each using a terminal, and the computer was time-sharing—but who does that anymore?  Another one was to have separate vocabularies for Forth versus the assembler versus the editor.  My assembler merges the addressing mode with the mnemonic, so there are no conflicts with Forth names.  I don't use a screen editor either, but rather a nice professional programmers' text editor; and when I implement an editor on my workbench computer, it will probably be a similar thing, not a command-line editor like Brodie describes in "Starting Forth" (my paper copy is the second edition) where for example I stands for "insert" whereas in the Forth vocabulary, it puts a loop index value on the stack.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 06, 2022 3:31 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 247
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 07, 2022 9:28 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
...all valid points, but I see problems with MARKER too.

?
Everything I said after "The FORGET for my Forth works just fine." was to show some of the features of a well designed FORGET . I don't have MARKER and don't want it. I'll review Fleet Forth's FORGET in an upcoming post in 'Fleet Forth design considerations'. I find FORGET indespensable.

SamCoVT wrote:
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.

One place where FORGET really shines is prototyping. Remember back when I redefined >R and friends to hand trace a drive interface word I was rewriting? When I was finished hand tracing that word I removed the redefinitions by typing
FORGET >R


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 07, 2022 10:25 pm 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
Well, this is getting a little esoteric. I rather like the idea of FORGET I have to say. MARKER also seems to have its place.
However:
On a simple machine such as my SBC SamCoVT's way of working is the way I ended up working. Blocks with code in them got tedious very quickly and either a punch of the reset button followed by a file upload is as quick a way as any - for me at least. On a more capable machine, working that way would be less conveniant and MARKERing and/or FORGETting probably a nicer way to work.

Anyway, SamCoVT, on the interrupt routine, I am already done. My other obsession in real life :-) is clocks so I just had to get one working on the SBC - its a background routine to update a RTC and a foreground Forth word to display it.
Thanks also for the info on the ways to crash Tali!


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 07, 2022 11:32 pm 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
When I use SEE to look at a word, often it seems the disassembly goes wrong and gets confused. If I hand dissassemble it there is nothing wrong (and the words work). Is the disassembler still a "work in progress"? I can post examples.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 08, 2022 3:15 am 
Offline

Joined: Fri Apr 15, 2016 1:03 am
Posts: 135
Please post a few examples of disassembly attempts failing. It should be able to be fixed or explained.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 08, 2022 8:18 am 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
leepivonka wrote:
Please post a few examples of disassembly attempts failing. It should be able to be fixed or explained.


Code:
: abc 41 lcdchrout 42 lcdchrout 43 lcdchrout ;

if I use SEE to look at this word I get:

Code:
see abc
nt: 1206  xt: 1211
flags (CO AN IM NN UF HC): 0 0 0 1 0 1
size (decimal): 24

1211  20 88 93 41 00 20 D1 0D  20 88 93 42 00 20 D1 0D   ..A. ..  ..B. ..
1221  20 88 93 43 00 20 D1 0D    ..C. ..

1211   9388 jsr
1214      0 eor.zxi
1216    DD1 jsr
1219   9388 jsr
121C        ?
121D     20 brk
121F      D cmp.ziy
1221   9388 jsr
1224        ?
1225     20 brk
1227      D cmp.ziy
 ok
I guess, looking at it, the problem is the inline numbers.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 08, 2022 10:51 am 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
...and thinking about it more, perhaps I am making assumptions again. I assumed it would be a sort of hybrid disassembler that, since it knew about the words it is disassembling it would skip non-assembler bits like inline numbers.


Top
 Profile  
Reply with quote  
PostPosted: Thu Dec 08, 2022 3:31 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 247
adrianhudson wrote:
...and thinking about it more, perhaps I am making assumptions again. I assumed it would be a sort of hybrid disassembler that, since it knew about the words it is disassembling it would skip non-assembler bits like inline numbers.
If it was smarter, it would do those things. The issue is the literal values (41, 42, 43) in your code. Those are saved as a jsr (at address $9388) to routine that grabs the literal value from RIGHT AFTER the jsr. It then fudges the return stack so that when the routine returns, it returns to JUST AFTER the constant value. The routine is named literal_runtime in Tali's assembly (native_words.asm), but has no name in Forth.

Looking at the hex dump near the top might help see what is going on. The 20 88 93 has a JSR to address $9388. The two bytes that follow that are 41 00 and that's your 41 as a 16-bit number (eg. $0041, stored little end first). Tali's disassembler isn't smart enough to know that the literal value is not opcodes, which is why you see the 0 eor.zxi there. For the next literal constant, that one is not even a valid opcode so you get the ?. Sometimes the data value will match up to a single-byte or 3-byte op-code and then Tali is off by a byte and messes up the next valid opcode as well.

Tali also doesn't look in the dictionary to see if a JSR jumps to a word with a name, like many other Forths do, but it also inlines assembly code for short words (rather than compiling a JSR to them it copies their assemble over into the new word) so that may be of limited use.

The short answer is that Tali's disassembler is not the best and could be better. It does not properly handle literals or other data mixed in with opcodes. If you'd like it to be better, you are welcome to open a ticket on Github. There is room for improvement with even just a small amount of work.


Top
 Profile  
Reply with quote  
PostPosted: Fri Dec 09, 2022 6:14 pm 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
Thanks Sam. I had worked out what was going wrong with the disassembly. It would be a "nice to have" improvement so maybe I will open that ticket.

I have done the ISR and now have an internal clock (as per Garth's code). I have done ROM based subroutines to write to the LCD and IO to i2c and they are working great.

I was looking at Garth's "Zero-overhead interrupt service in Forth" pages and contemplating implementing that within Tali - just as an exercise. Garth says his technique would work in most indirect-threaded systems. Tali is subroutine threaded so the first step is understanding those systems and deciding whether it is actually possible to apply Garth's technique to Tali. All good fun.


Top
 Profile  
Reply with quote  
PostPosted: Sun Dec 11, 2022 10:51 pm 
Offline

Joined: Sat Apr 30, 2022 7:13 pm
Posts: 159
Location: Devon. UK
adrianhudson wrote:
Thank you sir! [SamCoVT] My handshooken SXB is working perfectly!
I may have spoken too hastily...
... actually handshaking isn't working properly, at least it doesn't appear to be. I had put a line delay of 50ms in to my terminal program and forgotten, so it looked like it was working. I just removed it and comms locks up after a few hundred bytes.
The code in the platform file (relating to serial IO) is as in the original taliforth-sbc.asm file and I can see that the RTS line goes high simultaneously with the lockup - so it seems Tali is saying "whoa-hang fire". I have set my console program TeraTerm to RTS/CTS handshaking so I just can't see why it hangs. I note in your SBC [SamCoVT] that you use a Rockwell 65C51 as do I.

I am using a Win10 laptop (sorry, all you Linuxers out there) - does anyone know if I have to do anything else on the Win10 machine?

Edit. I am going to post this somewhere else as it is a) off topic really and b) driving me NUTS!


Top
 Profile  
Reply with quote  
PostPosted: Sat Dec 31, 2022 8:33 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 247
adrianhudson wrote:
Code:
: abc 41 lcdchrout 42 lcdchrout 43 lcdchrout ;

I've updated the master-64tass branch to include proper handling of literals when disassembling. This helps the situation drastically, although it still gets confused by things like strings that jump over the data. I thought I was going to have to do special handling for variables as well, however I found that variables are always compiled "Never Native" (they have to be in order to work properly) and so they will always be a JSR and the regular name lookup works fine for that. Here's the new output from your example.
Code:
: lcdchrout ( do nothing for testing ) ;  ok
: abc 41 lcdchrout 42 lcdchrout 43 lcdchrout ;  ok
see abc
nt: 812  xt: 81D
flags (CO AN IM NN UF HC): 0 0 0 1 0 1
size (decimal): 24

081D  20 88 93 29 00 20 11 08  20 88 93 2A 00 20 11 08   ..). ..  ..*. ..
082D  20 88 93 2B 00 20 11 08    ..+. ..

81D   9388 jsr     LITERAL 29
822    811 jsr     lcdchrout
825   9388 jsr     LITERAL 2A
82A    811 jsr     lcdchrout
82D   9388 jsr     LITERAL 2B
832    811 jsr     lcdchrout
 ok
Note that SEE changes the base to hex, so all the literal values are in hex. If you use DISASM (which takes ( addr n ) to define a range to disassemble) it will use the current BASE. For the above, SEE says that "abc" starts at $81D (looking at XT field) and is 24 bytes long (size field), so in decimal mode I might say "$81D 24 disasm" to see the results in decimal. The $ in front of a number allows you to enter hex values regardless of the current base.

Note for the above note: using disasm in decimal mode shows the addresses in decimal as well.

Edit: I just realized the original example was in hex, in which case everything will work out and you can ignore the above notes!


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 264 posts ]  Go to page Previous  1 ... 14, 15, 16, 17, 18  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: