nealcrook / multicomp6809

Software and modifications for Grant Searle's multicomp FPGA design, mostly focussed towards the 6809 variant: Forth (CamelForth), FLEX, CUBIX, NITROS9, FUZIX and the exec09 emulator.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is S" working correctly?

phillipeaton opened this issue · comments

Hi Neal,

Good to see you've still been improving the documentation on this repository, recently.

As I'm creating a target image for my Vectrex 6809, I'm using S" to lay down a text string. However, I don't quite understand what I'm seeing, maybe you can shed some light? My test code is:
HERE EQU HELLO-WORLD-STRING
S" HELLO WORLD" 80 C,
S" HELLO WORLD123" 80 C,

The 80 is used by the Vectrex to terminate a string. For a Vectrex BIOS call to print a string, I would expect to add one to the start address of the string to avoid the length byte . Instead, I have to add three!?

If I take a look at the ROM, I get this (length byte indicated by ^):
image

image

Before the length byte, for both the strings, I'm seeing "0B B0". If I look at addres $0BB0 in the target ROM, it's the first bytes of (S") (I think than's the CFA?):
image
image

This seems wield, why does it need (S") once the string is compiled? Does that look right to you?

I'll soon be releasing my Vectrex Forth, I have completed the Forth to Vectrex BIOS API, now I'm just cleaning up the code before making my repository public. This S" query is part of it taht clear up!

Regards,
Phil

(Sorry, I totally failed to get the ASCII-art to format properly.. but the version I emailed you should look right)

consider these two definitions:

: FOO 45 + ;
: BAR S" ABC" ;

When you look at the code for FOO you won't expect to see "45" sitting there unadorned. You expect to see a prefix to it. Sure enough, the "code" for FOO looks like this:
CFA-DONUM 45 CFA-ADD

The function of CFA-DONUM is to take an inline literal (45) and push it on the stack, and to advance the VM program counter over the inline literal so that the next thing to be processed is CFA-ADD. When you look at t

Similarly, when you look at the code for BAR you can't have the string sitting there unadorned. Words like S" need a compile-time action and an execution-time action. The compile-time action is to (1) compile the CFA of the run-time action (2) leave a gap of 1 byte for the length (3) compile the string (4) go back and fill in the length. The execution-time action is rather like CFA-DONUM: it needs to push the address and length of the string, and then advance the VM program counter over the inline string.

When you look at the source code, you see that S" does the compile-time action and lays down the CFA of (S") to do the execution-time action. If you do this:

HEX ` (S") U.

it should report 0BB0

What's not clear from your example is whether you are using S" within a definition. It sort-of sounds as though you're using it outside a definition... just to compile a string that you will later print? That's fine; you may want to create a new word that does only what you want it to do.

(look in word_formats.txt)

Here are 2 definitions next to each other in the dictionary. Locations 0..10 are the first/oldest definition (because the lfa=0) and location 11 is the start of the second definition.

0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13
v---------------------------------------------+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 00|03| F O O|bd xx yy| xt1 | xt2 | ... |exit |00 02|04
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^ ^ ^ ^
lfa nfa cfa pfa lfa nfa

lfa - link field address
nfa - name field address
cfa - code field address
pfa - parameter field address (CREATEd words only)

There's nothing to stop you compiling a string in between them:

0 1 2 3 4 5 6 7 8 9 a b c d e f 10 11 12 13
v---------------------------------------------------------------+
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|00 00|03| F O O|bd xx yy| xt1 | xt2 | ... |exit |H |E |L |L |O |80|00 02|04
+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
^ ^ ^ ^ ^ ^
lfa nfa cfa pfa lfa nfa
`

the string HELLO (with 80 terminator) is compiled but is hidden: it cannot be found by a dictionary search and is as efficient as it can be. AS LONG AS you somehow remember its start address you can print it.

you can create a new word to do this (maybe V" ) using S" as a starting point. You can store its start address in the metacompiler space (so that it takes no space in the target image but is still available later: ultimately you will want to compile the address as an argument to your BIOS print routine.

hope that all makes sense!

regards,

Neal.

Hi Neal,

Thanks for the detailed description, it confirms what I thought was going on. A word like S" is a confusing one for me currently and, as you guessed, I'm using it outside of a colon definition.

If I type S" 123" at the Gforth OK prompt, I get an address and length back on the stack.

If I try to use S" in my source code before CamelForth has been INCLUDEd, it throws an error, because the original Gforth definition is not in the vocabularies loaded at the time, they get swapped around a lot during loading.

If I include a file with S" after the CamelForth has been INCLUDEd, then it uses the code defined below, which, when it get interpreted outside of a colon definition, it lays it down the string into the ROM preceded by the address of (S").

\ \\   High level: input/output                     (c) 31mar95 bjr
: (S")        \ -- c-addr u        run-time code for S"
    R> COUNT 2DUP + ALIGN >R ;

ALSO FORTH ALSO META DEFINITIONS
: TS"   22 WORD DUP C@ 1+ THERE OVER TALLOT SWAP >TCMOVE ;
PREVIOUS PREVIOUS DEFINITIONS

: S"          \ --             compile in-line string
    ['] (S") COMPILE,
    22 WORD   C@ 1+ ALIGNED  ALLOT ;
EMULATE:  M['] (S") T,  TS"  ;EMULATE   IMMEDIATE

This seems wrong to me, it should just leave the address and count, and then you do what you need with it as part of the include script.

To my less-experienced mind, it appears to have been coded to lay down the string data, which is probably what you want to do, but I can't see why you'd want to lay down the address of (S") beforehand, that makes no sense unless you're compiling. Maybe it would be enough to simply remove M['] (S") T, from the code above?

Maybe it was just a mistake, having all these different host and target modes of interpret/compile actions is making my head spin already!

Anyway, after some good responses on comp.lang.forth (no, really) I coded the following:

These are the relevant target-model words, to which I've added a new TSTR" at the end:

: VIRTUAL ( a - a)   0 400 UM/MOD BASE-SCREEN + BLOCK + ;
: TC@ ( a - c)  VIRTUAL C@ ;
: TC! ( c a)    VIRTUAL C! UPDATE ;
: T@  ( a - n)  DUP TC@ 100 * ( hi)  SWAP 1+ TC@ ( lo)  + ;
: T!  ( n a)   >R 0 100 UM/MOD  R@ TC! ( hi)  R> 1+ TC! ( lo) ;
: >TCMOVE ( s d n) OVER + SWAP DO  DUP C@ I TC!  1+ LOOP DROP ;
: TSTR" ( - )  [CHAR] " PARSE TUCK  \ #chars source #chars
               THERE SWAP >TCMOVE   \ #chars
               TALLOT ;

Then, I needed to extend the metacompiler code with STR" line at the end:

PRESUME C@        EMULATES TC@     
PRESUME C!        EMULATES TC!     
PRESUME HERE      EMULATES THERE
PRESUME ALLOT     EMULATES TALLOT
PRESUME STR"      EMULATES TSTR"

Then, at the point I need it, instead of looking like thsis|

\ g         G     C     E           2     0     2     0
67 C, 20 C, 47 C, 43 C, 45 C, 20 C, 32 C, 30 C, 32 C, 30 C, 80 C,
FD C, 0D C,             \ Intro Music
F8 C, 50 C, 20 C, 80 C, \ Height Width etc.
\ V   E     C     F     O     R     T     H
56 C, 45 C, 43 C, 46 C, 4F C, 52 C, 54 C, 48 C, 80 C,
00 C,   \ End of Header

it now looks like this - much improved:

STR" g GCE 2020€"
FD C, 0D C,             \ Intro Music
F8 C, 50 C, 20 C, 80 C, \ Height Width etc.
STR" VECFORTH€"
00 C,   \ End of Header

The Euro symbol at the end of each string is $80, which is needed on the target.

This code above lays the string down at $0000 in ROM, the Vectrex BIOS looks for it here and if it doesn't find it, it will ignore your code and run the default built-in game.

Where I need to lay down a string elsewhere, I've used the following:

HERE EQU HELLO-WORLD-STRING
STR" HELLO WORLD€"

It's all working well now, and thanks again for the time taken to reply.

Regards,
Phil

Phil,
ANS standard states that the interpretation semantics for S" are undefined.
OTOH, Gforth does define interpretation semantics for S" -- the (Excellent, ) documentation describes the exact interpretation semantics that you describe above.

So I think it is fair to say that both implementations are behaving correctly even though they behave differently.

FORTH metacompilation is definitely a brain-twisting process. If you haven't printed out and treasured Brad Rodriguez's "Moving Forth/Principles of metacompilation" parts 1, 2 and 3 I recommend you check them out: http://www.bradrodriguez.com/papers/

I didn't read these early articles in his series until after I had done my porting work on CamelForth; they contain lots of useful material on the background of the hows and whys of Chromium.

Neal.

correction: those papers are not on Brad's web-site (probably how I missed them for so many years) but in old issues of FORTH DIMENSIONS which you can find at www.forth.org -- issues 14.3, 14,4, 14.5. The last part contains references to older articles by Laxen, also in FD back-issues.

"interpretation semantics for <<insert_word_here>> are undefined"
That phrase causes a lot of arguments :-)

Right, so technically what I'm doing is an undefined usage and also undocumented by CamelForth, thus it falls back on the ANS standard undefined phrase. Oh well, I guess that's part of the challenge, because with Forth "the program is the compiler", and open heart surgery is only ever a PageUp away. In this case, I just plugged in another artery.

Thanks for the links to Brad's papers. A few years back, I did read several of them, but not the ones only printed in FD, I'll certainly check them out. Not sure about printing them, though...I haven't printed something to read for...donkeys years!