Jump to content
Lee Stewart

fbForth—TI Forth with File-based Block I/O [Post #1 UPDATED: 11/16/2019]

Recommended Posts

WooHoo!! :grin: :-o I got it working on MESS and the real iron with my nanoPEB!!! I guess I'll need to await Tursi's fix to check it out on Classic99 with a DSK image. There were 2 changes necessary. Changing the AIB to 8320h and swapping the bytes of the number of records in the file before storing in AIB+8 did it. (The need for byte swapping is because the number of records in a file is recorded that way in the FDR.) I was lucky I had 8320h–832Dh free. I don't know what the DSR is doing to memory at ARG, but very little of the right information was making it there.

 

Well done!! I've tested with my new Classic99, and both FIAD and DOAD are working fine in it.

 

Scratchpad stomping... I should add some of that to my DSR, that's a tricky one to track down.

 

Well, I will go ahead and release Classic99 tonight. And congratulations! :)

 

Share this post


Link to post
Share on other sites

Yeah, Scratchpad stomping is a big gotcha. Basically, as far as I can tell, the TI and Corcomp disk controller cards use some PAD memory, that, in TF, is in use for other stuff. This had me stumped for a long time, because the problem doesn't manifest itself at all in Classic99, but does in MESS. In the end, I had TF restore SP to what it needs after every disk access.

Share this post


Link to post
Share on other sites

The HFDC Manual does a relatively good job of documenting the memory locations for the various level 1 and 2 routines.

You may have been stomping on a few of the pointer words and bytes, such as 0x8350 (error return) and PAB setup by putting your AIB in the first ranges.

 

I have no choice with 8350h—It's use is mandated by the DSR for pointing to the AIB at input and, as you say, error return. As to the others, I must surely have been stepping on toes.

 

I usually place my AIB at 0x8300 and 0x8310 or thereabouts. If you intend to use hard drive devices, be sure you reserve sufficient AIB space to account for the extra bytes required.

 

I'll need to visit that soon, I suppose. The fbForth (and TI Forth, for that matter) workspace is at 8300h–831Fh and its inner interpreter starts at 832Eh, so I have only 4 bytes to spare following my current AIB.

 

If you are tight on space, saving then restoring the scratchpad used by the AIB bytes is a less desirable but workable option.

 

...lee

Share this post


Link to post
Share on other sites

Well done!! I've tested with my new Classic99, and both FIAD and DOAD are working fine in it.

 

Scratchpad stomping... I should add some of that to my DSR, that's a tricky one to track down.

 

Well, I will go ahead and release Classic99 tonight. And congratulations! :)

 

Thanks for all your assistance.

 

...lee

Share this post


Link to post
Share on other sites

Yeah, Scratchpad stomping is a big gotcha. Basically, as far as I can tell, the TI and Corcomp disk controller cards use some PAD memory, that, in TF, is in use for other stuff. This had me stumped for a long time, because the problem doesn't manifest itself at all in Classic99, but does in MESS. In the end, I had TF restore SP to what it needs after every disk access.

 

I've been able to avoid SP save/restore thus far. It may still bite me before this is over. I need to write the manual after you beta testers get back to me. And then, I guess, it's on to cartridge land, where I will surely need your able assistance.

 

...lee

Share this post


Link to post
Share on other sites
Yeah, Scratchpad stomping is a big gotcha. Basically, as far as I can tell, the TI and Corcomp disk controller cards use some PAD memory, that, in TF, is in use for other stuff. This had me stumped for a long time, because the problem doesn't manifest itself at all in Classic99, but does in MESS. In the end, I had TF restore SP to what it needs after every disk access.

 

Yes, Classic99's DSR doesn't use any TI memory to execute, so scratchpad is unharmed, and VDP memory is unchanged. This is a nice advantage until you want to work with other people's disk controllers. Originally I thought adding the VDP memory pointers would be enough, but I think I will add a debug option to munge memory used by the disk controller, just for the purpose of catching these errors earlier.

Share this post


Link to post
Share on other sites

In the interest of testing fbForth, I thought I would try the SSN problem discussed in the TI FORTH thread. It works just fine! In my discussion of the problem, I made a mistake in determining the number of permutations possible with the derived restriction of 5 as the required middle digit. It should be 4!4! = 576, not 4!3! = 144. It is corrected in the PDF file included in the attachment. The other file is the requisite blocks file (SSNBLOCKS) for fbForth. To load it after fbForth is up and running, you would do the following:

 

USEBFL DSK1.SSNBLOCKS

1 LOAD

 

The above assumes the file is on DSK1—it may, of course, be elsewhere. To run the solution, type FIND_SSN . To continue to look for another number, type NEXT_SSN . To start over, type INIT_SSN followed by FIND_SSN . To remove all the words loaded for this problem, type FORGET IT . IT is a no-op definition that was loaded first to be used as a marker for unloading everything after it.

 

...lee

 

fbForth_SSN_problem.zip

Share this post


Link to post
Share on other sites

Lee,

 

I haven't tried fbForth yet, as I'm TurboForthing at the moment, but I will get to it.

 

I just wanted to make a comment re USE. For a long time I had the rather syntax-friendly USE <filename> as you do in your post above, however, it's a serious PITA to use that from within a running program. Consequently I changed the syntax to require a string passed via the stack, as in:

 

S" <filename>" USE

 

Not as friendly, but now super simple (and useful) to use from a running program. This might be worthy of consideration for your system!

 

Mark

Share this post


Link to post
Share on other sites

Lee,

 

I haven't tried fbForth yet, as I'm TurboForthing at the moment, but I will get to it.

 

I just wanted to make a comment re USE. For a long time I had the rather syntax-friendly USE <filename> as you do in your post above, however, it's a serious PITA to use that from within a running program. Consequently I changed the syntax to require a string passed via the stack, as in:

 

S" <filename>" USE

 

Not as friendly, but now super simple (and useful) to use from a running program. This might be worthy of consideration for your system!

 

Mark

 

You are probably right; but, fbForth has two words from TI Forth, WLITERAL and SLIT (comparable to LITERAL and LIT except that they are for strings) that I can probably use for that purpose. WLITERAL compiles SLIT followed by the string with a leading length byte into the dictionary during compilation of a new word. When the word executes, SLIT leaves the address of the string's length byte on the stack. I will need to rework USEBFL and/or its support word(s) before I can make proper use of it; but, I figured I was likely going to have to do that sooner or later, anyway. :P

 

...lee

Share this post


Link to post
Share on other sites

Lee,

 

I haven't tried fbForth yet, as I'm TurboForthing at the moment, but I will get to it.

 

I just wanted to make a comment re USE. For a long time I had the rather syntax-friendly USE <filename> as you do in your post above, however, it's a serious PITA to use that from within a running program. Consequently I changed the syntax to require a string passed via the stack, as in:

 

S" <filename>" USE

 

Not as friendly, but now super simple (and useful) to use from a running program. This might be worthy of consideration for your system!

 

Mark

 

Ok—Here are two words I had defined to change blocks files:

 

( helper routine that gets blocks filename into PAD and passes info )

: BFLNAM
( --- info )

PAD 16 BLANKS
( fill PAD with 16 blanks)

PAD HERE - DUP ALLOT
( temporarily put HERE at PAD, saving distance)

MINUS
( negate distance for restoring HERE)

BL WORD
( get the string to HERE [old PAD] )

ALLOT
( restore HERE)

PAD 2+
( bump pointer 2 bytes for our temporary info block)

DUP 2+ [email protected] 48 - 8 SLA OVER !
( get disk # and store)

;

 

( select a different blocks file from input stream )

( usage: USEBFL DSK1.BLOCKS )

( this routine uses PAD for temporary info block until successful return )

( hopefully, nothing tramples it while we're gone!?! )

: USEBFL
( --- )

EMPTY-BUFFERS
( unconditionally abandon any dirty blocks)

BFLNAM
( process filename from input stream and get info )

DUP
( save a copy of info before calling OPNBFL)

OPNBFL
( open file)

( if we made it back here, copy info to current blocks file info block)

USEB

;

 

And, here they are rather clumsily redefined to work in definitions, as well:

 

( helper routine that gets blocks filename into PAD or HERE , depending on flag, and passes info )

: BFLNAM_2
( flag --- info )

IF

PAD HERE - DUP ALLOT
( temporarily put HERE at PAD, saving distance)

MINUS
( negate distance for restoring HERE)

BL WORD
( get the string to HERE [old PAD] )

ALLOT
( restore HERE)

PAD

ELSE

BL WORD
( get the string to HERE )

15 HERE C!
( change string length to 15 for SLIT to correctly manage info block use )

HERE
( save HERE )

16 ALLOT
( move HERE past info block )

ENDIF

2+
( bump pointer 2 bytes for our temporary info block)

DUP 2+ [email protected] 48 - 8 SLA OVER !
( get disk # and store)

;

 

: USEBFL_2

STATE @

IF

COMPILE EMPTY-BUFFERS
( at execution, unconditionally abandon any dirty blocks )

COMPILE SLIT
( at execution, will put address of info block-2 on stack and step over following stored info )

0 BFLNAM_2 DROP
( get block filename to HERE but DROP address returned; SLIT will provide it )

COMPILE 2+
( at execution, correct address returned by SLIT )

COMPILE DUP
( at execution, save a copy of info for USEB )

COMPILE OPNBFL
( at execution, "open" block file )

COMPILE USEB
( at execution, if we make it back here, copy info to current blocks file info block )

ELSE

EMPTY-BUFFERS
( unconditionally abandon any dirty blocks)

1 BFLNAM_2
( process filename from input stream and get info )

DUP
( save a copy of info before calling OPNBFL)

OPNBFL
( open file)

( if we made it back here, copy info to current blocks file info block)

USEB

ENDIF

; IMMEDIATE

 

These appear to work just fine; but, like I said, they're clumsy. There must surely be a better way that doesn't require so much use of COMPILE ; but, I have a little trouble with using so much indirection! It's not second nature, yet! Suggestions (@Willsy?) for streamlining these definitions are certainly welcome.

 

...lee

Share this post


Link to post
Share on other sites

I think rather than having USEBFL_2 compile lots of code directly into a definition, I'd have it simply compile a reference to a static colon definition. I.e:

 

: USEBFL_2
STATE @ IF
COMPILE (USEBFL_2)
ELSE
...
...
...
THEN ; IMMEDIATE

: (USEBFL2)
EMPTY_BUFFERS
...
...
etc
;

 

Not sure how simple that would be, since your code compiles SLITs that do work at run-time.

 

Pain in the ass, isn't it?

 

FWIW: TF V1.2 has a word (as a loadable extension) called MACRO:

 

It's used like this:

 

MACRO: FRED 100 0 DO I . LOOP ;

 

: SOME-WORD <code here> FRED <more code here> ;

 

If you then de-compile SOME-WORD, you'll see that the code in the macro FRED was directly compiled into SOME-WORD. To be clear, SOME-WORD does not contain a CALL to FRED (that would just be normal Forth) - the macro FRED get's in-lined into SOME-WORD. Removes all those noisy and space-consuming COMPILES. MACRO: in turn uses EVALUATE (in the TF ROM) which evaluates a string as code:

 

: TOM S" : HELLO 10 0 DO I . LOOP;" EVALUATE ;
TOM ok:0
HELLO
0 1 2 3 4 5 6 7 8 9 ok:0

 

I can send you the code for MACRO: if you think it will be useful, but you'd (probably) need to implement EVALUATE yourself. But it's actually easy - push "interpreter context" (i.e. TIB address, >IN, BLK et al to return stack, just as if you were going to do a LOAD, then set terminal buffer and length to the string that contains the code to evaulate, zero BLK, and call the interpreter. On return, restore context from the return stack and you're done.

 

Something like this (this is pretty much how it's done in TF, except the save and restore of interpreter state are factored into their own definitions, as they are used by LOAD.

 

: EVALUATE ( addr len -- )
\ save interpreter context:
BLK @ >R
>IN @ >R
TIB @ >R
#TIB @ >R

\ set new interpreter context:
BLK 0!		 \ zero BLK
>IN 0!		 \ zero >IN
#TIB !		 \ len to #TIB (length of TIB)
TIB !		 \ addr to TIB (address of TIB)

INTERPRET	 \ call interpreter

\ restore interpreter context:
R> #TIB !
R> TIB !
R> >IN !
R> BLK !
;

 

Here's my code for MACRO: (this may be out of date, as I am taking the code from my work machine, which I'm sure is out of date. I'll post more up-to-date code tonight, but this will give you food for thought, and anyway, I'm sure it's not directly transferable to fbForth anyway, so treat it as conceptual ;-)

 

[ He he... BLK>FILE is really cool... I just type "45 45 BLK>FILE CLIP" and block 45 is exported to the Windows clipboard, and I just paste it in! Way to go Classic99!!! ]

 

--BLOCK-00045---------
: move$ blk @ if vmbr else cmove then ;
: macro:
bl word header $8320 , ascii ; word
compile blk compile @ compile >r compile blk compile 0!
compile (s") dup c, dup >r here swap move$
r> allot align compile evaluate
compile r> compile blk compile !
$832C , immediate 1 >in +! ;
CR .( MACRO: Loaded.) CR .( Usage example:)
.( MACRO: LoopTo100 100 0 DO I . LOOP 
.( : TEST LoopTo100  CR
.( Invoking LoopTo100 inlines the code in LoopTo100 into TEST)
.( Can make code more readable by removing)
.( the need to use COMPILE and [COMPILE])

macro: LoopTo100 100 0 do i . loop ; : test LoopTo100 ;

 

Some food for thought for you there ;-)

 

Notes:

BL WORD HEADER - this creates a dictionary entry with the name taken from the input stream.

$8320 , - this compiles DOCOL into the dictionary entry.

ASCII ; WORD - this calls WORD and WORD is looking for ; as the delimiter (normally it's a space, as in BL WORD)

MACRO: then compiles some code to save context (I think I may not need that, as EVALUATE does it).

Then it compiles (S") which at runtime returns the address and length of the string in front of it. Your equivalent would be SLIT I think.

Then MOVE$ (move string) is used to copy the string up to but not including the semi-colon into the definition.

We then ALLOT over the string, and ALIGN (string may be odd number of bytes).

Compile a call to evaluate.

Compile some context restoration code (may not be necessary).

Compile a call to EXIT/UN-NEST ($832C ,)

Set the definition that we just built to be immediate, with IMMEDIATE

I then advance the index into the TIB (>IN) by 1, since the call to "ASCII ; WORD" would leave us pointing directly at the semi-colon in the string, and we don't want that!

That's it.

I think in the newer version, move$ is simplified (no need to check BLK due to changes I made in WORD).

Share this post


Link to post
Share on other sites

I think rather than having USEBFL_2 compile lots of code directly into a definition, I'd have it simply compile a reference to a static colon definition.

...

 

Yeah, something like that. I think I will need to limit (USEBFL_2) (maybe I'll call it (UB) ) to the three lines after COMPILE 2+ because they are the only lines common to both sections:

 

: (UB)

DUP

OPNBFL

USEB ;

 

: USEBFL_2

STATE @

IF

COMPILE EMPTY-BUFFERS

COMPILE SLIT

0 BFLNAM_2 DROP

COMPILE 2+

COMPILE (UB)

ELSE

EMPTY-BUFFERS

1 BFLNAM_2

(UB)

ENDIF ; IMMEDIATE

 

 

Thanks for all the information!

 

...lee

Share this post


Link to post
Share on other sites

fbForth v0.91 is attached to the next post. I've made the changes discussed above regarding BFLNAM , USEBFL and (UB) . USEBFL is now a state-smart word that can be used as a command or inside a definition.

 

I made one other change and that was to MENU , the word that displays load options residing in FBLOCKS. It now checks block #1 (the welcome block) in the current blocks file to see that the 3rd and 4th characters are "fb". If they are, it will load block #2 to display the menu pages (currently 2 pages). Otherwise, it will quit with an appropriate error message, viz., "MENU ? DSK1.FBLOCKS not current".

 

...lee

 

—see next post for corrected ZIP file—

Share this post


Link to post
Share on other sites

I'm wondering whether I should try to implement 80-column mode for text for those emulators (and real iron?) that have that capability. I would probably need to unravel some likely convoluted code in FBLOCKS to do it. I would definitely need to modify the 40-column editor or write a new 80-column editor. @Willsy, does not TurboForth allow only an 80-column text mode? Anyone have suggestions or comments?

 

...lee

Share this post


Link to post
Share on other sites

TF runs in 32, 40 and 80 column modes. EMIT is aware of the horizontal line length and adjusts the X & Y cursor/next character position, and invokes screen scrolling accordingly.

 

Try:

 

0 GMODE WORDS

1 GMODE WORDS

2 GMODE WORDS

 

...you'll notice the screen behaves correctly in all three modes. XMAX returns a value equal to the screen row length. It is set by GMODE.

 

The editor runs in 40 and 80 column modes. If you are in 32 column mode (1 GMODE) and invoke the editor then the editor switches the VDP to 40 column mode. The editor then runs with an overlapping window, kind of like Funnelweb.

 

If you are in 80 column mode and you invoke the editor, then there's no windowing.

 

post-24932-0-62241000-1372407229_thumb.png

40-column mode, left window

 

post-24932-0-23875200-1372407255_thumb.png

40-column mode, right window

 

post-24932-0-02692700-1372407279_thumb.png

80-column mode

Share this post


Link to post
Share on other sites

TF runs in 32, 40 and 80 column modes. EMIT is aware of the horizontal line length and adjusts the X & Y cursor/next character position, and invokes screen scrolling accordingly.

 

Try:

 

0 GMODE WORDS

1 GMODE WORDS

2 GMODE WORDS

 

...you'll notice the screen behaves correctly in all three modes. XMAX returns a value equal to the screen row length. It is set by GMODE.

 

The editor runs in 40 and 80 column modes. If you are in 32 column mode (1 GMODE) and invoke the editor then the editor switches the VDP to 40 column mode. The editor then runs with an overlapping window, kind of like Funnelweb.

 

If you are in 80 column mode and you invoke the editor, then there's no windowing.

 

...

 

Yeah, I was pretty much aware of all that; but, I wasn't sure whether you limited the additional capabilities of 9938/9958 systems to 80-column text or allowed for the other graphics modes, as well. From what I could get out of your source code, it looked like only 80-column text. :P

 

...lee

Share this post


Link to post
Share on other sites

Oh, I see. :dunce: Sorry - I've got my slow head on today!

 

Yes, it's just 80 columns. There's just no room left in the 16K EPROM (I should have specced a 32K ROM!) for any more code, and I have no experience with the 38/58. In fact, I've never even developed anything like a line-drawing routine so I'm sure anything that I came up with in that direction would be a load of rubbish!

Share this post


Link to post
Share on other sites

Oh, I see. :dunce: Sorry - I've got my slow head on today!

 

Yes, it's just 80 columns. There's just no room left in the 16K EPROM (I should have specced a 32K ROM!) for any more code, and I have no experience with the 38/58. In fact, I've never even developed anything like a line-drawing routine so I'm sure anything that I came up with in that direction would be a load of rubbish!

 

I actually was only thinking about 80-column text until I looked through Fred's docs for TI994w, in which he displays |:) more options—the additional graphics modes do require more VRAM, however.

 

...lee

Share this post


Link to post
Share on other sites

@Willsy...

 

On another note, I'm beginning to think seriously about hoisting fbForth into cartridge space—this, before I've done anything about an fbForth manual :ponder: ! What suggestions do you have regarding design guidelines for accomplishing that? At the very least, it looks like you limited bank 1 to ALC support code and not any actual threaded dictionary code. I am wondering also about the utility of including RAM in ROM space and whether that is even a good idea. I'm RAMbling, sorry. Any help you might offer will be greatly appreciated!

 

...lee

Share this post


Link to post
Share on other sites

Hi Lee

 

You're correct. The current architecture of TF is such that all threaded code (and, critically, all dictionary entries) are in bank 0, and supporting assembly code in bank 1.

 

I gave a lot of thought to allowing threaded Forth in bank 1 (or, indeed all banks) and decided against it, because the implementation would be very tricky, for two reasons:

  • FIND. FIND (for other readers, FIND is the word that searches the dictionary for a word, and returns its address) would be complicated (or, at least, more complicated) because it would have to handle bank switching in order to continue traversing the dictionary from one bank to the next. That introduces a number of further complications:
    • What happens to FIND when the bank is switched? We're left with two options:
      • Place an identical copy of FIND at the same address in all banks
      • Place a portion of FIND in PAD RAM

A further problem becomes apparent when thinking about the actual threaded code that gets compiled into a definition.

 

Imagine this:

 

: DOUBLE DUP + ;

 

Lets look at the threaded code (pretend addresses used):

 

>8340 >6026 >705E >834E

 

So, here, >8340 and >834E are the addresses of DOCOL and EXIT (in pad ram)

>6026 is the address of DUP

>705E is the address of +

 

Which bank is DUP in?

Which bank is + in?

 

If they're both in the same bank, you might be fine. But what if DUP is in bank 0, and + is in bank 1? Now the compiler needs to check that at compile and compile additional code to invoke a bank switch in preperation for the next word to be executed. So, (symbolically shown, rather than addresses):

 

DOCOL (BANK0) DUP (BANK1) + (BANK0) EXIT

 

Getting complicated (and slow) isn't it?

 

For that reason, (not so much FIND, I could easily solve the problem with FIND) I decided it was un-tenable to allow threaded code in any bank other than bank 0. I rather suspect you'll arrive at the same conclusion with fbcForth (c=cartridge ;-)) and end up restricting the dictionary to bank 0, with some code (that you want to be fast, without the overhead of a bank switch - e.g. DUP, +, SWAP et al - all the common words) implemented in assembly language, directly in bank 0 (where the overhead of a bankswitch would be prohibitive in terms of the overall execution time of simple words) and more complex words (sprite handling, HCHAR et al) in assembly in bank 1, where the overhead of a bank switch is insignificant in terms of overall execution time.

 

TF uses trampoline code in PAD for jumping into bank1 and resuming in bank0:

 

BL @BANK1

DATA <address of routine in bank1>

 

and return back to bank 0:

 

B @retB0

 

The actual code to accomplish this in pad is very small. Have a look at Initialisation.a99 in the bank1 folder.

 

And that's another point - the cartridge has to do a lot of setup before it can run - a sort of bootstrap - so the TF cart has to install the lower case char set, and install its own support code in RAM, and set up all TF's variables in RAM etc - because (obviously) there's no loader to do it for you!

 

Regarding RAM in a cart, the perfect design (at least for TF) is 1K of ram directly in the cart, always visible from every bank (so you lose 1K of ROM from every bank). With this architecture, I could comfortably fit *everything* TF needs to run in the 1K of ram, including stacks, buffers etc (TF uses ~700 bytes (IIRC) to support itself) leaving every single byte of the 8K and 24K banks free for the user. That would be orgasmic. Unfortunately, no such cartridge exists.

 

I had a chap working on a 2nd generation cart board that had exactly that. In addition, it had *hardware* stacks - two of them!

 

MOV Rx,@>6FFE - push to data stack

MOV @>6FFE,Rx - pop from data stack

 

MOV Rx,@>6FFC - push to return stack

MOV @>6FFC,Rx - pop from return stack

 

How cool is that!! The stacks were in the internal ram in the cart. However, the project stalled - it turns out it's impossible to do one of the operations - either the push or the pop - can't remember. I think maybe the pop... It's because the pop needed pre-decrement on the address generator (which was a 74LS device, which would later be mopped up into a PLD) or something like that, and there's no way to derive it from the signals present in the cart port.

 

Mark

Share this post


Link to post
Share on other sites

Thanks, Mark. I still don't think I'm quite ready to jump into cartridge development; but, I do need to start a game plan to get me there in the most efficient manner. Probably, the most difficult procedure for me will be converting colon definitions to ALC. We'll see.

 

...lee

Share this post


Link to post
Share on other sites

I've just run into a snag on the real iron with my nanoPEB when I try to use MKBFL to create a blocks file. Interestingly, the nanoPEB's DSR creates the file with the correct number of sectors. It fails, however, with the first attempt at writing a blank sector. This does not happen with any of the emulators I've tried. They all (I believe it's all of them) create the file but fail to add the sectors. I had to write blank sectors, which I needed to do anyway; but, all the sectors should have been added to the file at creation. All the emulators correctly write the blank sectors. I am not really sure what's going on with the nanPEB's DSR; but, I think it is mangling the transfer block and additional information block between calls to the DSR. I guess I should completely repopulate the TB and AIB before each call and not rely on any information surviving between calls. I was lulled into complacency with the emulators, I guess. I'll try to run this to ground later tomorrow.

 

...lee

Share this post


Link to post
Share on other sites

I have MKBFL working now on the real iron with nanoPEB. I will clean up the ALC and post fbForth v0.92 today or tomorrow.

 

To summarize the situation, TI Forth's block I/O support ALC has three functions: drive-select. read-disk and write-disk. There is no need of a special drive-select function in fbForth. I have four functions in fbForth for block I/O support: "open"-blocks-file, create-blocks-file, read-block and write-block. The latter two are file-sector equivalents of TI Forth's read/write-disk. Three of the four I/O functions in fbForth call DSRLNK only once and each time they get a new TB and AIB, so there is no issue with the TB and AIB getting trashed. The issue is with the create-blocks-file function because, after the first call to DSRLNK, which creates the file, I am looping through a block of code that writes four sectors of blanks for each block in the new file and I was relying on the survival of most of the TB and AIB between calls. I was renewing only what the docs say changes and then what changed in Classic99. Now, of course, I should probably renew everything each time through the loop. Like I said, I'll clean up the ALC and re-post soon. :P

 

...lee

  • Like 1

Share this post


Link to post
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.

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...