Jump to content
IGNORED

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


Lee Stewart

Recommended Posts

Nice! I get now.

  1. If I'm using your fblocks, I just don't worry about it.
  2. If I'm creating an standalone blocks file, and I have have the font block in block #5, I don't have to do anything...
  3. If I want the font block in block #2 or something, I just set the user variable in block #1, then set my graphics mode like I already do and away we go.
  4. If I don't want the runtime cost of loading from disk, (maybe I change graphics modes frequently) I just set the user variable to block #1 ( not a font block ) and we'll get the console font when changing graphics modes.

In development workflow, where I switch between the editor in text80, and mode 2 graphics, it might be nice to be able to effectively disable the behavior of FNT, maybe if the user variable can be set to indicate no font change, or explicitly set to load console font, behavior can be more deliberate. The last one doesn't eliminate the need to fallback if a valid block number is specified. Just offering an idea: maybe -1 is disables the behavior of FNT, and 0 explicitly loads the console font, and any other value attempts to load from the block file, falling back on console font if the block isn't a font block.

 

-M@

 

H-m-m-m—well, if FNT looks for the default font validation code in a particular block, it will have already loaded the entire block into a block buffer, so telling it to look in an invalid block will not save on disk access. The only thing that would save disk access would be to explicitly indicate the console font.

 

Currently, if SCRFNT contains 0, the default font is loaded and, if it contains anything else, the user’s font file is loaded. The user can change the value in SCRFNT ; but, if changed to a non-zero value, USEFFL must have been successfully run at least once. I could make SCRFNT a tri-state variable, where a negative value could indicate the console font; a value of 0, the default font; and a positive value a user font.

 

The more I think about it, the more I think that a default font file is the way to go. I can maintain the current zero/non-zero state for SCRFNT , but change its meaning to

  • Zero = font file, whether default font or user font
  • Non-zero = console font.

We wouldn’t need the additional user variable for font-block number.

 

I would need to rearrange the current system user variables to exclude SCRFNT from getting creamed by COLD when it resets those variables. I would also need to get the default filename into the VRAM location for the user-font-file PAB and modify the disk number there if a key is held during bootup.

 

More to think about...

 

...lee

Link to comment
Share on other sites

I had another interesting idea, I expect everyone has thought of before, but with carts like the ubergrom, fbForth could be in the eeprom, and what if there was a bit in the rom that could be set so it would bload a range of blocks from GROM in the ubergrom atmega chip?

 

I'm not (hopefully) proposing any major change in structure to fbForth. It could continue to own the ROM and ROM banking.

 

The ubergrom seems like nice development aid. Given that it has GRAM space that could be used during development, something like having GSAVE tools on the fblocks tool set that would be like a BSAVE to GRAM, to test with. I haven't thought this through too deeply, but large things could be built using BSAVE swapping techniques Lee outlined in the fbForth manual, and all loaded fast off of cartridge. I imagine the GRAM space would be handy during development, but the GROM space would make more sense to solidify the code into. The GRAM could be useful for an individual app too.

 

I suppose something similar could be done from from extended banks on the ROM side itself, but I imagine that is complicated by the bank switching already in fbForth.

 

I imagine the only change required to fbForth would be a setting in the rom that can be set indicating to bload block 1 or a range of blocks from a grom address instead of from disk. Then the loaded block(s) can take control. ( maybe bload for block 1 isn't right, cause you problably want to execute some word(s) automatically. ) But hopefully I've communicated the concept.

 

Just an idea.

 

-M@

 

Copying GROM to RAM is a good deal slower than copying ROM to RAM, though likely faster than copying from disk.

 

Regarding bank switching for ROM, I can modify my trampoline code to handle a 64KiB ROM (8 banks), which is double what I’m using now. My biggest problem, however, is that I am nearing capacity on the number of additional Forth words I can cram into the kernel due to the scarcity of space in banks 0 and 2—particularly bank 0. Currently, bank 0 must contain the code field and parameter field for every word defined in ROM. I can always move the rest of the code if it happens to be ALC, but I’ve already done that for a lot of words. I did an assessment of words whose bodies I can move to space in other banks and have found about 300 – 350 bytes.

 

For a couple of projects discussed a few posts back, I need 352 bytes for DATA[ ... ]DATA and 160 bytes for CODE: ... ;CODE , so I will need to translate them to ALC or mixed ALC/Forth. It will be difficult to translate these words to all ALC because they rely on other complex words that I would also need to translate. I hesitate to mix much Forth into ALC because, for every Forth word so inserted, there is at least one bank-switch out and one back. Though I certainly enjoy the process, I would have to completely develop the solution before I would know whether everything can be jammed into ROM. I might have to roll it all back in the end. All of these obstacles notwithstanding, I think I shall proceed with the modification, once I decide on how to handle the default font. But I digress...

 

Back to using ROM for BLOADing and/or copying to RAM in other ways, I should think we could manage to come up with code to copy from banks beyond 64KiB; but, it would have to be a different scheme from the one I am using for normal bank-switching in fbForth. Otherwise, the extra 32KiB will have to do.

 

After further thought, it might be possible to write a GROM DSR for one of the GROM banks to handle copying from both GROM and ROM. This is possible because fbForth 2.0 uses Millers Graphics’ GPLLNK and DSRLNK, which invokes console GROM 0’s DSRLNK. That version of DSRLNK, in addition to managing cassette routines and searching peripheral ROMs, also searches GROM headers for the relevant DSR. This project would be fun but, surely, time-consuming. I have no idea if there are any examples of DSRs written in GPL, but that is what we would need to do, I think.

 

Enough rambling for now...

 

...lee

  • Like 1
Link to comment
Share on other sites

<snip>

For a couple of projects discussed a few posts back, I need 352 bytes for DATA[ ... ]DATA and 160 bytes for CODE: ... ;CODE , so I will need to translate them to ALC or mixed ALC/Forth. It will be difficult to translate these words to all ALC because they rely on other complex words that I would also need to translate. I hesitate to mix much Forth into ALC because, for every Forth word so inserted, there is at least one bank-switch out and one back. Though I certainly enjoy the process, I would have to completely develop the solution before I would know whether everything can be jammed into ROM. I might have to roll it all back in the end. All of these obstacles notwithstanding, I think I shall proceed with the modification, once I decide on how to handle the default font. But I digress...

<snip>

 

Oh how I feel your pain, my friend! :woozy:

Link to comment
Share on other sites

Speaking of DATA[ ]DATA, I'm trying to use them :) I know this is not the most efficient technique for the specific problem at hand which I will accomplish using VMBW, but I'm trying to learn idiomatic forth. So here goes: How do you do something like ALLOT on the parameter stack without assembly code? ( The fbForth 2.0 manual shows exactly how to do it in assembly code. )

 

I have something like:

 

: LBANK ( -- addr n ) DATA[ FFF0 F3F6 FFF0 F3F6 FFF0 F3F6 ]DATA ; ( A character pattern I can slide across for a single pixel row scrolling effect )

 

Now I want to apply that to a word like CHAR that expects 4 cells of that to be on the stack.

I can see how I can use the address and loop over the range I want to select, and stuff those onto the stack.

But I imagined that I would capture the stack address, grow the stack, and then perform a MOVE into that stack space. The only way I can see to manually grow the stack is by manipulating the stack pointer register, but that seems wrong as I'm reaching into the implementation of the language. Or is that the idiomatic way in forths?

 

-M@

Link to comment
Share on other sites

Speaking of DATA[ ]DATA, I'm trying to use them :) I know this is not the most efficient technique for the specific problem at hand which I will accomplish using VMBW, but I'm trying to learn idiomatic forth. So here goes: How do you do something like ALLOT on the parameter stack without assembly code? ( The fbForth 2.0 manual shows exactly how to do it in assembly code. )

 

I have something like:

 

: LBANK ( -- addr n ) DATA[ FFF0 F3F6 FFF0 F3F6 FFF0 F3F6 ]DATA ; ( A character pattern I can slide across for a single pixel row scrolling effect )

 

Now I want to apply that to a word like CHAR that expects 4 cells of that to be on the stack.

I can see how I can use the address and loop over the range I want to select, and stuff those onto the stack.

But I imagined that I would capture the stack address, grow the stack, and then perform a MOVE into that stack space. The only way I can see to manually grow the stack is by manipulating the stack pointer register, but that seems wrong as I'm reaching into the implementation of the language. Or is that the idiomatic way in forths?

 

-M@

 

It’s easy enough to manipulate the stack pointer in high-level fbForth; but, you should proceed with extreme caution! fbForth’s workspace starts at >8300. The stack pointer is R9—so, >8312 is its address. The following word will reserve n cells of stack space:

 

HEX

: SALLOT ( n --- ) 2 * MINUS 8312 +! ;

DECIMAL

 

The following shows that there are 4 cells on the stack after supplying ‘4’ to SALLOT :

 

4 SALLOT ok:4

 

However, :-o the stack grows downward toward the dictionary, i.e., the top of the stack is at a lower address than the bottom of the stack. Your word LBANK has its leftmost cell of data at the lowest RAM location of the data stored in the word. For CHAR , you want that cell at the bottom of the stack contents required by CHAR , i.e., at the highest stack address. This means that you must copy the relevant data to the stack backwards! MOVE copies RAM from low to high RAM. You would need to write a word for the other direction, say, -MOVE .

 

Re the idiomatic Forth way to manipulate the stack, that would be via the resident words,

 

SWAP DROP DUP -DUP OVER ROT DEPTH .S SP@ SP! >R R R>

 

and the words from block 41 of the current FBLOCKS:

 

2DUP 2DROP NIP TUCK -ROT PICK ROLL

 

All of that said, there are two additional words defined in block 61 of FBLOCKS that can use an array handled by DATA[ ... ]DATA , viz., DCHAR for text characters and SPDCHAR for sprite characters. These both provide for loading one or more contiguous character or sprite patterns with a single word. So, instead of

 

HEX FFF0 F3F6 FFF0 F3F6 8 CHAR

 

to load a pattern for character #8, you could load the same from your LBANK with

 

LBANK DROP 4 8 DCHAR

 

If you want the character pattern to start from the second cell of LBANK :

 

LBANK DROP 2+ 4 8 DCHAR

 

I’ll stop talking, now...

 

...lee

  • Like 1
Link to comment
Share on other sites

Nice! thanks. I didn't notice DCHAR, I'll have to take a look at it. It makes sense to just write words that consume from addresses when using DATA[ instead of coercing it to be on the stack unnaturally. I'll take it as a clue, "if it doesn't fit, I'm doing it wrong" :)

 

I noticed the ordering issue when I looked at the memory map. Coercing the data onto the stack in the right order is another unnaturally act for the CHAR word. Further reason to look for something like DCHAR. Ah, I wrote something similar to DCHAR, but I used horrible things like 800 instead of PDT. I can retire mine now. Thank you!

 

Looking through the vocabulary in the manual, there just aren't very many words where the usage would be helped by an SALLOT. So maybe now I understand better why it isn't there.

 

BTW: If you ever in the mood to refine the manual, the tips in CHAR and CHARPAT descriptions inform me of the address of the pattern definition table, but ( in my opinion ) should send me to the PDT constant.

 

Thanks again for the help and explanations! Now it's off to clean my code up to use DCHAR. ( I've got an improved 4 sprite layered Formula 1 car, and a smooth scrolling curb, all running out of the interrupt service routine... fun times ;-) )

 

-M@

  • Like 1
Link to comment
Share on other sites

FYI, here is how CHAR was written by TI programmers:

: CHAR ( w1 w2 w3 w4 ch --- )
8 * PDT + >R
-2 6 DO
PAD I + ! -2
+LOOP
PAD R> 8 VMBW ;

And—here is how I translated that to ALC:

 

_CHAR MOV @$PDT(U),R2 ; copy base address of PDT
*++ following is also used by SPCHAR
__CHAR MOV *SP+,R0 ; pop ASCII char code off stack
SLA R0,3 ; X 8
A R2,R0 ; calc char pattern address
MOV @$DP(U),R1 ; copy HERE to R1
AI R1,>44 ; make it point to PAD
MOV R1,R3 ; copy it to R3
AI R3,6 ; + 6 to start backwards copy from stack
CHLOOP MOV *SP+,*R3 ; pop next 2 bytes of pattern and copy to PAD
DECT R3 ; next cell down in PAD
C R3,R1 ; below PAD yet?
JHE CHLOOP ; nope, go get another 2 bytes
LI R2,8 ; yup, load count for VMBW
LIMI 0 ; disable interrupts because our VMBW doesn't
BLWP @VMBW ; update PDT
LIMI 2 ; re-enable interrupts
B @RTNEXT ; back to bank 0 and the inner interpreter

As you can see, it was first necessary to pop the pattern data from the stack to a temporary location (fbForth’s PAD 68 bytes above HERE , not scratchpad RAM at 8300h) before using VMBW .

 

Re refining the manual, I intend to do that; but, first I plan to write an addendum that details the changes since the last update of the manual so folks who have already printed the manual won’t need to reprint the whole thing. I hope you are making notes that I can call on when I get around to the rewrite. :)

 

... ( I've got an improved 4 sprite layered Formula 1 car, and a smooth scrolling curb, all running out of the interrupt service routine... fun times ;-) )

 

That I gotta see! Did you write and install your own ISR per Chapter 10?

 

...lee

Link to comment
Share on other sites

FYI, here is how CHAR was written by TI programmers:

...

And—here is how I translated that to ALC:

...

As you can see, it was first necessary to pop the pattern data from the stack to a temporary location (fbForth’s PAD 68 bytes above HERE , not scratchpad RAM at 8300h) before using VMBW .

It is very interesting to me that the looping is across the destination address. I don't normally think that way, but since the source data is offered at the top of the stack, it makes sense that you can just take them as they are given, and slot them into the place in memory that makes it usable for target word.

 

Re refining the manual, I intend to do that; but, first I plan to write an addendum that details the changes since the last update of the manual so folks who have already printed the manual won’t need to reprint the whole thing. I hope you are making notes that I can call on when I get around to the rewrite. :)

 

Yes, an addendum would be great. Regarding tweaks to the manual... I'll try to preserve some notes.

 

That I gotta see! Did you write and install your own ISR per Chapter 10?

 

...lee

The instructions in Chapter 10 where easy to follow for this. What I find particularly nice about this, is that I have variables defined, for things like speed and a mileage counter, that impact how things behave in the ISR, such as how many bytes to shift the character patterns. With the ISR, I just set all that in motion, and then I'm still at the terminal/prompt and I can just store values into those variables and see immediately how it changes. It can eliminate a lot of edit/compile/reload/run cycles.

 

I don't know how to tell how much code can happen before I'm skipping a beat... I might need to implement the clock first, so I have a symptom when I've put too much code in the ISR.

 

-M@

  • Like 1
Link to comment
Share on other sites

...

Yes, an addendum would be great. Regarding tweaks to the manual... I'll try to preserve some notes.

Cool.

...

The instructions in Chapter 10 where easy to follow for this. What I find particularly nice about this, is that I have variables defined, for things like speed and a mileage counter, that impact how things behave in the ISR, such as how many bytes to shift the character patterns. With the ISR, I just set all that in motion, and then I'm still at the terminal/prompt and I can just store values into those variables and see immediately how it changes. It can eliminate a lot of edit/compile/reload/run cycles.

 

I don't know how to tell how much code can happen before I'm skipping a beat... I might need to implement the clock first, so I have a symptom when I've put too much code in the ISR.

 

If time gets tight, you can always use fbForth ALC.

 

...lee

Link to comment
Share on other sites

In the process of coding some of the resident dictionary's more complex high-level Forth words in ALC to provide space in ROM for DATA[ ... ]DATA words (see posts #1020 and #1028), I squashed a bug or two and made some improvements in DATA[ , which follows:

 

 

 

HEX
: DATA[ ( -- addr count ) ( Input Stream: n1 ... nn)
STATE @ IF
COMPILE DATA[] ( compile CFA of DATA[] in new word definition)
0 , ( reserve space for count and zero it)
THEN
HERE ( start address of list)
0 ( start counter)
BEGIN
IN @ IN_TMP ! ( get IN before reading next word)
BL WORD ( get next token to HERE)
HERE @ ( get length and first character)
CASE ( check first character)
055D ( ‘]’) OF IN_TMP @ IN ! ( restore IN to INTERPRET last word)
1 ( last time through loop [flag for UNTIL] )
ENDOF
0128 ( left paren) OF ( comment)
[COMPILE] (
0 ( once more through loop [flag for UNTIL] )
ENDOF
032D ( ‘-’) OF
HERE 2+ @ 2D3E ( ‘->’) = ( ‘-->’)
IF ( load next block)
[COMPILE] -->
ELSE ( convert and compile negative number)
[NUMBER] ( convert and compile number at HERE; inc count)
THEN
0 ( once more through loop [flag for UNTIL] )
ENDOF
0100 ( terminating null) OF
BLK @ ( check input source)
IF ( blocks file--error)
0 ERROR
ELSE ( TIB--OK to get next line)
CR QUERY 0 ( get next line)
THEN
ENDOF
ELSEOF
[NUMBER] ( convert and compile number at HERE; inc count)
0 ( once more through loop [flag for UNTIL] )
ENDOF
ENDCASE
UNTIL ( get next number in input stream)
; IMMEDIATE
DECIMAL

 

 

 

I will post a current FBLOCKS file in a few days.

 

...lee

  • Like 1
Link to comment
Share on other sites

I have posted the latest FBLOCKS file in post #1. It has the latest version of DATA[ ... ]DATA words, which needed a few more changes from the last post above—I wanted to protect DATA[ from HERE possibly being at an odd memory address, which can happen with an odd ALLOT or compiling a byte with C, . Here is the latest DATA[ :

 

 

 

HEX
: DATA[ ( -- addr count ) ( Input Stream: n1 ... nn)
HERE =CELLS DP ! ( insure HERE is even)
STATE @ IF
COMPILE DATA[] ( compile CFA of DATA[] in new word definition)
0 , ( reserve space for count and zero it)
THEN
HERE ( start address of list)
0 ( start counter)
BEGIN
IN @ IN_TMP ! ( get IN before reading next word)
BL WORD ( get next token to HERE)
HERE C@ SWPB HERE 1+ C@ + ( get length and first character)
CASE ( check first character)
055D ( ‘]’) OF IN_TMP @ IN ! ( restore IN to INTERPRET last word)
1 ( last time through loop [flag for UNTIL] )
ENDOF
0128 ( left paren) OF ( comment)
[COMPILE] (
0 ( once more through loop [flag for UNTIL] )
ENDOF
032D ( ‘-’) OF
HERE 3 + C@ 03E ( ‘>’) = ( ‘-->’)
IF ( load next block)
[COMPILE] -->
ELSE ( convert and compile negative number)
[NUMBER] ( convert and compile number at HERE; inc count)
THEN
0 ( once more through loop [flag for UNTIL] )
ENDOF
0100 ( terminating null) OF
BLK @ ( check input source)
IF ( blocks file--error)
0 ERROR
ELSE ( TIB--OK to get next line)
CR QUERY 0 ( get next line)
THEN
ENDOF
ELSEOF
[NUMBER] ( convert and compile number at HERE; inc count)
0 ( once more through loop [flag for UNTIL] )
ENDOF
ENDCASE
UNTIL ( get next number in input stream)
; IMMEDIATE
DECIMAL

 

 

 

...lee

  • Like 2
Link to comment
Share on other sites

I have improved the CODE: ... ;CODE words (see post #1180) to properly exit getCODE and CODE: by having CODE: leave a “magic number”, C0DEh, on the stack for ;CODE to check before it pops two return levels that would send fbForth into oblivion were it to execute outside of CODE: !! :-o Also, the previous code was popping the wrong addresses from the return stack. The new code follows and is also corrected in the above-referenced post:

 

 

 

( Machine coded ALC words revised..LES07APR2016)
HEX
: getCODE ( -- )
BEGIN ( infinite loop that is exited by ;CODE)
IN @ ( save our place in the input stream, IS)
BL WORD ( get next token to HERE)
0 0 HERE (NUMBER) ( see if it's a number)
C@ BL - IF ( conversion failed? see if it's a word)
DROP DROP ( discard double number)
IN ! ( restore IN for ' )
[COMPILE] ' ( get word's PFA)
CFA EXECUTE ( no; execute found word)
ELSE ( successful conversion)
DROP , ( make it a 16-bit number and compile it)
DROP ( drop previous value of IN)
THEN
AGAIN ; ( get next number in input stream)
: CODE: ( -- C0DEh)
?EXEC ( check that we are not compiling)
CREATE SMUDGE ( create word header and make word visible)
C0DE ( leave magic number, C0DEh, on stack for ;CODE)
BEGIN
getCODE ( get code until ;CODE)
BLK @ 0= IF
." ok:" DEPTH .
CR QUERY
THEN
AGAIN ; IMMEDIATE
( ;CODE is now a synonym for DOES>ASM: and terminator for CODE:)
: ;CODE ( -- )
STATE @ IF ( are we compiling?)
[COMPILE] DOES>ASM: ( invoke DOES>ASM: )
ELSE ( are we executing?)
DEPTH IF ( DEPTH > 0?)
C0DE = IF ( magic number, C0DEh, on stack?)
045F , ( compile B *NEXT )
R> R> DROP DROP ( do not return to getCODE or CODE:)
ELSE
0 ERROR ( ERROR!! not paired with CODE:)
THEN
ELSE
0 ERROR ( ERROR!! not paired with CODE:)
THEN
THEN
; IMMEDIATE
DECIMAL

 

 

 

...lee

Link to comment
Share on other sites

I don't know how many die-hard Forthers there are on this forum besides @Willsy, @JonnyBritish, @Vorticon, @jedimatt42, @idflyfish (?), @Opry99er (?) and me; but, as I am beginning to go through the source code of fbForth 2.0 in an effort to clean it up a bit and squeeze some more space out the ROM, I am finding the occasional word inherited from TI Forth that seems to have superfluous code in it. A case in point is CODE , which is used the same as ASM: to start a word definition that will contain Forth Assembler code. Here is the high-level Forth code for CODE , with what I think is superfluous in this color:

 

: CODE ( --- )
?EXEC
CREATE SMUDGE
LATEST PFA DUP CFA !
[COMPILE] [
[COMPILE] ASSEMBLER
; IMMEDIATE

The code in question stores the parameter field address (pfa) of the word just CREATEd in its own code field. However, CREATE already does that:

 

HEX
: CREATE
HERE =CELLS DP !
LATEST ,
-FIND
IF
DROP NFA ID. 4 MESSAGE SPACE
THEN
HERE DUP
C@ 01F MIN DUP
HERE C!
WIDTH @ MIN
1+ =CELLS ALLOT
DUP 0A0 TOGGLE
HERE 1- 080 TOGGLE
CURRENT @ !
HERE 2+ ,
;

CREATE creates the new word's header, which includes the code field, but not the parameter field. The parameter field will eventually be the address immediately following the code field, which, at the end of the just-defined header, is HERE + 2. As you can see in the code above, the putative pfa ( HERE + 2) is compiled (with , ) into the final word of memory of the header (see code in this color), which is the code field of the new word. Can anyone disabuse me of my conclusion that the questioned code in CODE is superfluous?

 

...lee

Edited by Lee Stewart
Link to comment
Share on other sites

There are more things about this that I don't understand, than things that I do. Maybe some questions to help you come to a conclusion:

 

Does the previous SMUDGE change the result of LATEST?

You have a comment in your manual that CREATE doesn't behave the same as in Starting Forth. Is this something that snuck in between adopting some fig-forth-isms, and preserving TI-isms?

 

If this was for a modern computer, I'd make the change, and analyze the output, to see if there is any difference. From your description of what is going on, it certainly seems like one is just re-writing the same value to the same location.

 

-M@

Link to comment
Share on other sites

Does the previous SMUDGE change the result of LATEST?

 

No. The smudge bit is in a word's length byte. If it is set, the length byte will be length+32. (FIND) is the word used by all words searching the dictionary for a name match. The first thing (FIND) does is to check the length byte of each word it finds with the length byte of the search word. Only when the length bytes match does (FIND) check the remainder of the name string for a match. So, with the smudge bit set, the word is effectively hidden from (FIND) .

 

On the other hand, LATEST gets the name field address (nfa) of the last word defined in the CURRENT vocabulary by going directly to the vocabulary's link field through the user variable, CURRENT , i.e., no name search.

You have a comment in your manual that CREATE doesn't behave the same as in Starting Forth. Is this something that snuck in between adopting some fig-forth-isms, and preserving TI-isms?

 

TI Forth (and, by inheritance, fbForth) is pretty much all figForth with, probably, a few influences from Forth-79. I have certainly added to fbForth, but the basic structure of the language is the same. The differences between Starting Forth and fbForth/TI Forth are largely due to the fact that the book follows polyForth. The only familiarity I have with polyForth is from the book—and I largely ignored all polyForth references.

 

I believe the only difference between fbForth's CREATE and other Forth implementations is the smudge bit and the fact that CREATE is generally used by other defining words rather than by itself as in TurboForth (Forth-83), for instance.

From your description of what is going on, it certainly seems like one is just re-writing the same value to the same location.

 

Yup.

 

...lee

Link to comment
Share on other sites

If STORE works like ! then the pfa is being left on the stack.

 

Oops! :-o Good eye, Mark! That should, of course, be ! (previous post corrected). STORE is the ALC label for the code field address (CFA ) of ! in fbForth and TI Forth (and TurboForth, for that matter). That code was my translation of the ALC for readability, not the actual ALC. The actual ALC, for those interested, is in the spoiler below. Even without all of the ALC source code, you should be able to make sense of the CFA address list in the DATA statements. For the most part, there's a one-to-one correspondence between this code and the Forth code of my previous post:

*** CODE *** ( --- )
DATA ASMR_N <--LABEL FIELD
CDE__N DATA 4+TERMBT*LSHFT8+'C','OD','E '+TERMBT <--NAME FIELD
CODE DATA DOCOL <--CODE FIELD
CDE_P DATA QEXEC <--PARAMETER FIELD
DATA CREATE,SMUDGE,LATEST,PFA
DATA DUP,CFA,STORE,LBRCKT,ASSM,SEMIS
*
*
*
*** CREATE *** ( --- )
DATA IDDT_N <--LABEL FIELD
CRAT_N DATA 6+TERMBT*LSHFT8+'C','RE','AT','E '+TERMBT <--NAME FIELD
CREATE DATA DOCOL <--CODE FIELD
CRATP DATA HERE <--PARAMETER FIELD
DATA ECELLS,DP,STORE adjust HERE to even cell boundary
DATA LATEST,COMMA store nfa of latest defined word in our label field
DATA DFIND,ZBRAN,L10BD-$ search for previous instance of new word
DATA DROP,NFA,IDDOT,LIT,>4,MESSAG,SPACE if found, tell user it's a duplicate
L10BD DATA HERE,DUP -FIND has put new word at HERE, now our name field
DATA CAT,LIT,31,MIN,DUP limit namelength to 31 and DUP it (code change)
DATA HERE,CSTORE store corrected name length (code change)
DATA WIDTH,AT,MIN truncate name to WIDTH [default=31] chars if necessary
DATA ONEP,ECELLS,ALLOT reserve name field with even number of bytes
DATA DUP,LIT,>A0,TOGGLE copy nfa to set smudge and starting terminator bits
DATA HERE,ONEM,LIT,>80,TOGGLE set ending terminator bit
DATA CURREN,AT,STORE store nfa in CURRENT vocabulary's 'latest' pointer
DATA HERE,TWOP,COMMA,SEMIS reserve space for code field and store pfa there
* [NOTE: space NOT reserved for parameter field!]

LATEST leaves the nfa of the last-defined word: stack: nfa
PFA get's the word's pfa: stack: pfa
DUP pushes a copy to the stack: stack: pfa pfa
CFA gets the word's cfa: stack: pfa cfa
! stores the word's pfa into its cfa: stack: <empty>

I think it's smudging the word just created, and linking the dictionary, yes?

 

Yes.

 

...lee

Link to comment
Share on other sites

I am almost ready to release fbForth 2.0:6. It has DATA[ ... ]DATA and CODE: ... ;CODE in the kernel. It looks for the default font file, FBFONT (supplied), on the boot disk. Failing finding the file, the console font is loaded, with its small caps for lowercase. Whatever font file the user has set will survive COLD . There is also a COLD-survivable way to force the console font to be loaded. I should probably post it as a beta for a few days/weeks for folks to test first.

 

...lee

  • Like 2
Link to comment
Share on other sites

If you posted a beta, I would definitely give it a go. I would try out the different behaviors with the font file, including not having one. And DATA[ in rom would be handy. I currently have the DATA[ words bsaved into my current block file, and I need to re-org my block file anyway, as I didn't give myself enough learning space. :)

 

-M@

Link to comment
Share on other sites

Great party with half of the grandkids there! :party:

 

The latest build (fbForth 2.0:6) is below. This time, I packed everything in one ZIP file (BIN, RPK and DSK files and FBLOCKS, FBFONT, CHARA1FBF, CHAR@1FBF):

 

fbForth2.0-6_Cartridge_20160409.zip

 

The FBLOCKS file needs to be updated with new binaries for the last three menu options for them to work with this build, but everything else should work fine. There is quite a lot of new and reworked code so, please, let me know what breaks.

 

...lee

  • Like 1
Link to comment
Share on other sites

With the build in the last post, the default value of SCRFNT can be changed to 0 to force COLD to load the console font, with its small caps for lowercase, with the following code:


0 UCONS$ @ 68 + !


UCONS$ contains the address of the default-value table of user variables and 68 (44h) is SCRFNT's position in the table.


The above will not change the default for the current Forth session—it is only useful for a COLD start. For the current session:


0 SCRFNT ! FNT


will immediately load the console font


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