Jump to content
IGNORED

fbForth—TI Forth with File-based Block I/O [Post #1 UPDATED: 06/09/2023]


Lee Stewart

Recommended Posts

Regarding case, I think you just need to add some preamble at the beginning to make it clear what it is, and what it is used for. Then, the descriptions for each word can be left as they are.

Here is my attempt from my book on TurboForth:

CASE and ENDCASE are Forth's version of switch() in C or Select Case in some versions of BASIC. It allows you to evaluate a list of choices, without resorting to long, potentially error-prone lists of IF...THEN phrases. Let's have a look at an example program that uses a CASE construct:

: TEST KEY
  CASE
    32 OF ." SPACE " ENDOF
    42 OF ." STAR " ENDOF
    13 OF ." ENTER " ENDOF
    ." UNKNOWN "
 ENDCASE ;
 
: TEST-CASE BEGIN TEST BREAK? AGAIN ;


The above program waits for you to press a key, and checks the actual key pressed against a list of key presses that we are interested in. Namely, the space key, the ENTER key, and the asterisk (shift 8). Any other key shall produce the message UNKNOWN and the program will then continue. Let's have a look at how it works:

KEY pauses and waits for you to press a key. When a key is pressed, the key's ASCII code is pushed to the stack. We then begin 'case by case processing'. CASE compares the value on the stack (removing it as it does so) against each case in the case list. If a matching case is found, the associated code is executed. Note that the code to be executed for a case should be enclosed within the words OF and ENDOF. It is important to realise that, in the event of a matching case, your code between OF and ENDOF is executed, and then case by case processing ends, and the program continues executing at the word immediately following ENDCASE. As you can see, the code is very clear, and quite easy to follow.

Let's have a look at an equivalent written using IF...THEN:

: TEST KEY
  DUP 32 = IF .” SPACE” ELSE
  DUP 42 = IF .” STAR” ELSE
  DUP 13 = IF .” ENTER” ELSE .” UNKNOWN”
  THEN THEN THEN DROP ;


Ouch. All that 'noise' with DUPing values on the stack (because IF consumes the value on the stack, you have to DUP it for the next IF test). You also have to DROP the test value at the end. Noisy, and not very nice. Note also the phrase THEN THEN THEN – as we have already learned, each IF requires a matching THEN. Since the code above uses nested IF...THEN constructs, we need to close them down at the end:

IF something
  IF something else
    IF something else
    THEN
  THEN
THEN


Nasty isn't it? Clearly, CASE processing offers much better advantages in terms of code clarity, and ease of editing later on the down the line. Whenever you want to test a value against a list of cases, CASE is your friend.

Edited by Willsy
  • Like 1
Link to comment
Share on other sites

I think your post was posted 6 time! LMAO! I presume something went wrong at the Atariage end - no big deal, but made me laugh! ...

 

Yeah, it was frustrating! :mad: I gave up last night. Sorry about that!

[ EDIT: They've mercifully been removed :) ]

... This code presumes that the stack was empty before calling the word (apart from the arguments that the word itself needs, of course). ...

 

Uh-oh! :-o Nice catch—thanks! I'll re-post in a bit.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Here is the revised example—
The following example could have been written more efficiently; but, this version makes use of all of the above words. The word 8X8SRCH defined below looks on the stack for the address of an 8x8 array addr of numbers to search and a number n to match. The result will be only a false flag if there is no match, but a true flag, row r and column c of the array if there is a match.
You will notice that the stack depth is stored on the return stack before entering the outer DO loop and moved to the parameter stack when that loop is exited to then calculate the difference. The reason for this maneuver is that there is no way for 8X8SRCH to anticipate how many cells there may be on the stack below n before 8X8SRCH executes.:
: 8X8SRCH                                       «Search an 8x8, row-major array for a number
	( n addr --- F | c r T )                «In:  n = number to match; addr = array address;  Out:  false (0), if not found—or c = column; r = row; true (non-zero), if found
	DEPTH >R                                «Store stack depth to return stack to check at end
	8 0 DO                                  «Array row loop
		8 0 DO                          «Array column loop
			OVER OVER               «Copy n and addr to top of stack
			J 8 * I +               «Convert row and column to address offset into array
			+ @                     «Add offset to  addr and get value at that location
			= IF                    «Do we have a match to n?
				DROP DROP       «Yes; DROP  top 2 numbers from the stack
				I J 1 LEAVE     «Leave column c, row r and 1 for outer loop test; leave inner loop when we next get to LOOP
			ELSE                    «No match
				0               «Leave 0 for outer loop test
			THEN
		LOOP                            «Inner loop end
		IF                              «Did we have a match?
			1                       «Yes; leave true (1)  [stack now:  c  r  1]
			LEAVE                   «Leave outer loop at LOOP
		THEN    
	LOOP                                    «Outer loop end
	DEPTH R> -                              «Get current stack depth, previous depth & difference
	2 = IF                                  «# cells on stack out of loops = 2?
		DROP DROP 0                     «Yes; loop exhausted with no match; DROP everything and leave only false (0)
	THEN
;

 

Link to comment
Share on other sites

No feedback yet, so I think I will post the fbForth 1.0 Manual later tonight or in the morning.

 

Before I post, however, I will add hyperlinks to the TOC page numbers and cross-references. The TOC hyperlinks are easy; but, I may miss some of the cross-references if I can't find an easy way to search for them in OOO Writer. Anybody have any idea how?

 

...lee

Link to comment
Share on other sites

A few minor corrections and a minor renaming of the file:

 

fbForth_1.0_Manual.pdf <---[EDIT] See replacement PDF file (minor corrections) in this post. :)

 

I had an error in the PAD RAM memory map at address 83FAh, a page-number-reference problem in the TOC-page-number hyperlinks and an "Editor's note:" reference somewhere in the Glossary that should have been removed.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

In the interest of getting it right, I fixed another pagination problem with the manual. I discovered it when I was printing the manual and 3-hole-punching it. You will notice that there is no page 181. I believe the problem lay with OOO Writer and my attempt at inserting a different page style in the middle of the document. The section beginning at page 182 seems to have been forced to start on a left-facing, i.e., even-numbered page; so, I had to make the page before it end on an odd-numbered page!?! This will be a problem in the future if I ever add to the manual. Anyway, the corrected manual is attached.

 

fbForth_1.0_Manual_a.pdf <---[EDIT] See replacement PDF file (minor corrections) in this post. :)

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Oh, I feel your pain. That is a constant pain the ass in OOO writer. IIRC, when you are actually writing text and it spills across to the next page, it will correctly create a new page with the correct odd/even page style (you're using page styles, right?) but if you go further up and insert something, you can sometimes find that the stuff after it has the wrong page styles - i.e. odd numbered pages with an even style, and vice-versa.

 

What I did to make it visually obvious was place the page number at the hard left on even pages, and the hard right on odd pages (in the footer). Then, if things go awry, you can actually see it. It's then very simple to back to the first page where the problem occurs and apply the correct page style, and the others should automatically correct themselves (if you've set the "next page style" option in your page style setup).

 

Bit arcane, really, isn't it?

Link to comment
Share on other sites

  • 2 weeks later...
  • 4 weeks later...

I haven't done very much with fbForth lately—except some keyboard scanning stuff in PMs with @Willsy. I am now beginning to work out how I will put fbForth into cartridge space. So far my plan involves the following:

  1. Put all high-level Forth code in the same ROM bank. (Involving more than one bank is fraught with too much bank switching as far as I can tell.)
  2. Put all variables into low RAM space after the Forth block buffers.
  3. Resident vocabulary words ( FORTH , ASSEMBLER ) will need to be modified per TI Forth's FORTH to use variables for the link fields and the pseudo-name field.
  4. I may put all, or as much as possible, of FBLOCKS into ROM.
    • Make some or all optional by devising a modifiable link system in RAM space.
    • Manage the editors by a modifiable link as suggested above.
    • Convert as much of ROM-based FBLOCKS as possible to ALC to allow dictionary space to reside exclusively in one block.

Any comments or implementation ideas are welcome.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

This made me thinking, when converting disk based software to cartridge based software it would be nice to have a generic framework for a virtual file system in ROM where you access files by file names instead of by bank number/offset/length. If only you could put a DSR in a cartridge ROM...

Link to comment
Share on other sites

This made me thinking, when converting disk based software to cartridge based software it would be nice to have a generic framework for a virtual file system in ROM where you access files by file names instead of by bank number/offset/length. If only you could put a DSR in a cartridge ROM...

 

There must be many ways to skin that cat. One way might be to write your own DSRLNK that includes a way to branch to your ROM DSR that does not involve the CRU. It could be either the first option before searching peripheral ROMs or the last option after their failure. You would need unique device names that wouldn't be found by other DSRs. That might be fun to work on—like I need a digression right now! :P

 

...lee

Link to comment
Share on other sites

Re my fbForth-to-cartridge plan, the use of more than one non-high-level Forth bank may complicate bank switching. I am thinking it may be useful to implement a bank-switching stack to make that easier. I suppose that will all depend on whether I allow code in one bank to be called by more than one other bank. Thoughts?

 

...lee

Link to comment
Share on other sites

One of the biggest issues with high level code in multiple banks is how do you tick it? In forth when we tick a word we get a single datum: the word's compilation address (or in some dialects the PFA). However, with forth code in more than one bank, you need two datums: the compilation address and bank, since they're in the same address range. Now you also need a new non-standard word to comma those to memory when compiling calls etc.

 

Also consider that you're building a colon Def in ram:

 

: A b c ;

 

A is in the 32k Ram somewhere, b is in bank 0 and c is in bank 1. C needs to add code to the definition to effect the bank switch, as well as leave data somewhere to indicate which bank to return to. Presumably the return stack. How do we add that code? One can either build extra complexity into the compiler, or make every word in the dictionary (in ROM) immediate so that it compiles itself on its own behalf. None of this makes for a very standard forth.

 

The complexity rapidly snowballs. Forth just wasn't made for a bank switching type of environment!

Edited by Willsy
Link to comment
Share on other sites

One of the biggest issues with high level code in multiple banks is how do you tick it?

...

 

I am well aware of that complexity; but, that was not my question. I plan, indeed, to keep all of the linked Forth word list in ROM in one bank. My question had to do with all of the ALC (non-high-level Forth code—awkwardly stated—sorry | :) ) in more than one other bank that I may want to access from more than ROM-based Forth words—particularly, from other ROM banks. I should probably try to avoid that scenario. It should not be too difficult.

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

Okay sorry for the confusion. Well your suggestion about some sort of stack sounds like a good idea to me. My first thought was that you would save the address to return to to the "bank stack" among with the bank - two cells per entry. However it occurs to me that the least significant bit of the address would never be used, so that represent banks 0 and 1, and, since cart addresses are from 0 to $7fff the most sig. bit is free too. There's another two banks. In practice I'd probably shift the address to branch to left by one bit and use the two least sig. bits for the bank.

 

However, I'm running away with things I fear, as I'm prone to do.

Link to comment
Share on other sites

Okay sorry for the confusion. Well your suggestion about some sort of stack sounds like a good idea to me. My first thought was that you would save the address to return to to the "bank stack" among with the bank - two cells per entry. However it occurs to me that the least significant bit of the address would never be used, so that represent banks 0 and 1, and, since cart addresses are from 0 to $7fff the most sig. bit is free too. There's another two banks. In practice I'd probably shift the address to branch to left by one bit and use the two least sig. bits for the bank.

 

However, I'm running away with things I fear, as I'm prone to do.

 

No, not at all! Those are exactly the kinds of ideas I'm talking about.

 

...lee

Link to comment
Share on other sites

I can tell this conversion of fbForth to cartridge is going to be a long, arduous process. I guess the best thing to do at the outset is to do only the minimum conversion to get the system into cartridge space—then, try to improve the system by hoisting more of FBLOCKS into the fbForth kernel.

 

For the minimum conversion, I will still likely need to do more than the bare minimum because the kernel presently occupies 200 bytes more than 8 KB! I suppose I could stash a small amount of the end of the resident dictionary at A000h to minimize my initial effort for a version 2.0 and then start working on 3.0 (or maybe 2.1?) as soon as 2.0 is operational. I'm rambling; but, you get the idea.

 

...lee

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...