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

All times are UTC




Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Sun Oct 24, 2004 5:53 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
Ok, I feel like I'm daring to set myself up to get flamed for this, but the idea came from our recent discussion on subroutine-threaded Forth and the ease of mixing other assembly programming in with the string of JSR's.

Mixing assembly-language code into a Forth secondary (colon definition) at the source code level is definitely not standard practice, and probably would be heavily frowned upon by many. Normally you would write a primitive (code definition), and then call the primitive from the secondary. It seems however that there might occasionally be an advantage to being able to break into assembly in the middle of the secondary, and return to high-level Forth when you're done.

What experiences or observations or comments does anyone have? In toying with the idea, I wrote some code to do this in my 65816 indirect-threaded Forth. It's relatively simple, although not as simple as doing it in subroutine-threaded Forth. If it has been done, what names have been given to the immediate compile-only words that begin and end the assembly-language section?

_________________
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  
 Post subject:
PostPosted: Mon Oct 25, 2004 6:20 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
No flames here. Inline assembly with ITC or DTC isn't common because, unlike STC, you don't gain much. Using a headerless code definition followed by an ordinary colon definition is often more flexible anyway. Even with something like FIG-Forth, which wasn't designed to use headerless words, it's easy to write a defining word that defines a headerless primitive. Many would argue, however, that inline assembly is a sign that you need to factor your definition. The old "factor, factor, factor" mantra and whatnot.

F-PC (available at www.forth.org and several other sites) uses the names INLINE and END-INLINE to start and end the inline assembly. You just have to keep in mind that it's in interpretation state in between. F-PC is DTC and has separate code and data spaces, so inline assembly compiles to the same thing that a headerless code definition followed by a colon definition would. With ITC, or when the two spaces are not separate, you have to advance the (Forth) IP past the inline assembly at some point before it gets to the NEXT routine, which will be slightly slower and take slightly more space than the headerless code definition with colon definition approach.

I personally don't use inline assembly with DTC or ITC, but I use it all over the place with STC. As a result, I use a "label"-based Forth assembler rather than the more traditional "structured" Forth assembler. In a "structured" assembler, BEGIN, 0<, UNTIL, (or a similar syntax) assembles a BPL that branches to itself. The "label" equivalent is 1 $: BPL 1 $ or a similar syntax (I myself prefer a slightly different, but less common, syntax), which I find much easier to follow, especially when a word has multiple branch instructions. However, if you're only going use inline assembly occasionally (as is more likely to be the case with ITC), then you may find that the structured assembler is sufficient.

Readability is a significant concern with inline assembly, though. I personally find that it's much easier to follow the assembly source code compiled by high-level words (i.e. the JSRs) with inline assembly than the high-level definition (with inline assembly amidst [ and ]) itself. Not quite what I had hoped for, to say the least! The latter can become difficult to follow very, very quickly, unfortunately. Also, some may have trouble switching gears from high-level Forth to assembly back to high-level Forth when trying to comprehend the high-level source of a definition. A few words that abstract implemenation details may prove useful.


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Oct 26, 2004 8:58 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
Quote:
Inline assembly with ITC or DTC isn't common because, unlike STC, you don't gain much.

which may be why I haven't done it up to now. I just thought it might sometimes be one more good tool to add to the others like headerless primitive capability. Hmmm... I don't think Leo Brodie ever had a cartoon of the headless horseman of "Ledgend of Sleepy Hollow" in either of his books.

Quote:
Many would argue, however, that inline assembly is a sign that you need to factor your definition. The old "factor, factor, factor" mantra and whatnot.

Yeah, and I've seen too many examples where readability suffered from over-factoring. I say it's time to quit when the factor is only used once and you get to where there's no way to make its name descriptive of what it does without being unreasonably long, or when the code itself is easier to understand than the name.

Quote:
F-PC (available at http://www.forth.org and several other sites) uses the names INLINE and END-INLINE to start and end the inline assembly.

Thanks. I'll use their names instead of adding more non-standards (if I implement it at all).

Quote:
With ITC...you have to advance the (Forth) IP past the inline assembly at some point before it gets to the NEXT routine, which will be slightly slower and take slightly more space than the headerless code definition with colon definition approach.

I'll have END-INLINE compile a JSR BACK_TO_HI_LVL instruction. BACK_TO_HI_LVL (back to high level) is not actually a subroutine (it ends in JMP NEXT instead of RTS) but it needs the address put on the stack by the JSR to know what to put in IP. It would be a little faster but take more memory (depending on the number of uses) to have END-INLINE compile something like LDA #$+7, STA IP, JMP NEXT (This is with the 65816's accumulator in 16-bit mode.) BACK_TO_HI_LVL is 11 bytes long, including taking care of alignment.

Quote:
I use a "label"-based Forth assembler rather than the more traditional "structured" Forth assembler.

My preference as well. Even in indirect-threaded Forth, my assembler is label-based, and mnemonic precedes the operand, like in "normal" assemblers.

Quote:
Readability is a significant concern with inline assembly, though

as is the case anytime you give the user more freedom. It's his reponsibility to avoid situations where a year down the road he himself can't figure out what he did. Rope has enough uses outside of hanging oneself that they still sell it. I won't worry about it too much since I can think of scenarios where it can be made very readable by the programmer who pays attention to such details instead of carelessly writing code that looks like a tornado's path. As someone else (maybe Samuel?) said, Forth acts as an amplifier. A bad programmer will become worse and a good programmer will become better. I might add, a sloppy programmer will write even more-unreadable code, but a neat one can excell in readability. (It almost sounds like ancient Hebrew poetry.)

Thanks for the feedback Bruce

_________________
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  
 Post subject:
PostPosted: Wed Oct 27, 2004 4:21 am 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
GARTHWILSON wrote:
Yeah, and I've seen too many examples where readability suffered from over-factoring.


The art of factoring (and it is an art) does seem to be a key difference between good Forth code and bad Forth code. I have to admit that most of my better Forth code is factored so that each definition is only one or two lines, even though I never intentionally adhere to that principle ("vertical" code is more my style). But you're right that it can get silly sometimes. I've got one library with a (colon) definition where AND OR is entire sequence between the name (and stack comment) and the semicolon. I don't recall why I factored it that way (I haven't looked at the code in some time), but I do remember that it made sense to me at the time.

GARTHWILSON wrote:
I'll have END-INLINE compile a JSR BACK_TO_HI_LVL instruction.


Unlike a headerless primitive defining word, BACK_TO_HI_LVL is needed at run time. Since inline assembly is likely to be used only a few times, it might be worth considering whether the space (and speed) overhead of BACK_TO_HI_LVL is really worth it.

GARTHWILSON wrote:
My preference as well. Even in indirect-threaded Forth, my assembler is label-based, and mnemonic precedes the operand, like in "normal" assemblers.


Incidentally, while I greatly prefer prefix assemblers to postfix assemblers in Forth, I intended to post the prefix example of a BPL to itself, namely: 1 $: 1 $ BPL, (again using the common syntax).

GARTHWILSON wrote:
as is the case anytime you give the user more freedom. It's his reponsibility to avoid situations where a year down the road he himself can't figure out what he did.


That wasn't quite what I was getting at. When I write a Forth system in assembly, I like to put the high-level Forth definitions in the comments of the assembly source. To use the FIG-Forth source as an example, I would insert the comment : COUNT ( addr1 --- addr2 n ) DUP 1+ SWAP C@ ; before label L1622 and the comment : MAX ( n1 n2 --- max ) OVER OVER < IF SWAP DROP THEN ; before label L2523. I find it helpful when the definition is long (line after line of .WORD directives), when there are control structures, or if the assembler labels are cryptic (as they often are). And the stack comment is very helpful also.

However, with high-level STC definitions that contain inline assembly, I find that the assembly source is much easier to follow than the high level definition in the comment (though the stack comment is still nice). Even though I'm not trying to be tricky, but just increase the performance of the code, some of the space optimization techniques I described elsewhere (such as the one with ACCEPT) can make the high-level code fairly confusing. Granted, optimization often makes the code less readable, no matter what language is used, but I'd still rather have the code optimized. And it sure doesn't seem to take me long to make the code a lot uglier!

GARTHWILSON wrote:
As someone else (maybe Samuel?) said, Forth acts as an amplifier.


I believe it was Chuck Moore who said that.


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 05, 2018 10:08 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
The Forth I wrote for the Commodore 64 has a word to go from high level code to assembly called >ASSEM and a word to go from assembly to high level called >FORTH. They do not need paired. A word can start out as a colon definition and go to assembly with >ASSEM and end with a jump to NEXT (or jump to code that jumps or falls through to NEXT) or it can go back to high level with >FORTH. Likewise, a code word can go high level with >FORTH and terminate with ; or go back to assembly with >ASSEM. Here is a short segment of code which uses the C64 REU (ram expansion unit).
Code:
   DF09 LDA,  01F # CMP,  0= IF,  ( test for presence of REU)
      DF0A LDA,  03F # CMP,
   0= NOT ELIF,
      >FORTH TRUE
      ABORT" REU NOT PRESENT"
      >ASSEM
   THEN,
   <rest of code>

It's an easy way to test for the presence of the REU and abort from the code level word. In another example, my version of (TYPE), the vector for TYPE is a code word but I want multitasking support.
Code:
: (TYPE)  ( ADR CNT -- )
   PAUSE   ( task switcher)
   >ASSEM
   2 # LDA,  SETUP JSR,
   <rest of code>

Type starts as a colon definition so PAUSE can be called and goes to assembly level where it stays and ends with a jump to NEXT.

cheers,
Jim


Top
 Profile  
Reply with quote  
PostPosted: Thu Aug 09, 2018 6:58 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
I take it "; " terminates the compiler whether under >ASSEM or >FORTH ?


Top
 Profile  
Reply with quote  
PostPosted: Sun Aug 12, 2018 6:22 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
whartung wrote:
I take it "; " terminates the compiler whether under >ASSEM or >FORTH ?

No. My Forth is a Forth-83 standard ITC Forth for the Commodore 64. Semicolon ; terminates high level (colon) definitions. Code definitions are terminated by END-CODE. A code word must have a jump to NEXT or code that jumps to or falls through ( like PUSH and PUT) to NEXT.
>FORTH is an immediate word that can only be used while interpreting, as in compiling a code definition. If STATE is compiling, then >FORTH aborts with the message "EXECUTION ONLY". >FORTH compiles a JSR to the body of (>FORTH) then sets the context vocabulary to the current one and sets the compiling state.
(>FORTH) pulls the JSR's return address off the return stack, increments it and saves it in N, the scratch pad area in zero page, and the Y register. It then pushes IP to the return stack. It takes the address saved in N and the Y register and stores it in IP and jumps to NEXT. Since (>FORTH) performs the function of 'nest', the word transitions from a code word to a high level 'colon definition' without the need to return to the assembly code level. This high level code can now be written to do anything any other high level code can do. It can have multiple EXIT's (EXIT is the word compiled by semicolon ;) or branch into another high level word.
This is in the kernel source.
Code:
CODE (>FORTH)  ( -- )
   CLC,
   PLA,  1 # ADC,  N STA,
   PLA,  0 # ADC,  TAY,
   IP 1+ LDA,  PHA,
   IP    LDA,  PHA,
   N LDA,
   IP    STA,
   IP 1+ STY,
   NEXT JMP,  END-CODE

And this is in the system loader loaded by the kernel.
Code:
: >FORTH  ( -- )  ?EXEC
   [ ' (>FORTH) >BODY ] LITERAL
   [ ASSEMBLER ] JSR, [ FORTH ]
   CURRENT @ CONTEXT !
   ] ; IMMEDIATE

>ASSEM is an immediate word that can only be used while compiling. If STATE is interpreting, then >ASSEM aborts with the message "COMPILING ONLY". >ASSEM compiles (>ASSEM) into the high level code then sets CONTEXT to the assembler vocabulary and sets the interpreting state.
(>ASSEM) stores IP in N and N+1, then pulls the value off the return stack and stores it in IP, performing an unnest. It then performs an indirect jump through N. Since (>ASSEM) performs the function 'unnest' (what EXIT does), the word transitions from a high level 'colon definition' to a code word without the need to return to high level. This code level word can now be written to do anything any other code word can do.
This is in the kernel source.
Code:
CODE (>ASSEM)  ( -- )
   IP    LDA,  N    STA,
   IP 1+ LDA,  N 1+ STA,
   PLA,  IP STA,  PLA,  IP 1+ STA,
   N ) JMP,  END-CODE

And this is in the system loader loaded by the kernel.
Code:
: >ASSEM  ( -- )
   COMPILE (>ASSEM)
   [ ASSEMBLER ] MEM ASSEMBLER
   [ FORTH ]
   [COMPILE] [ ; IMMEDIATE

Here is my cold start routine for an example. Since this is on a Commodore 64, the system has one line of basic:
Code:
10 SYS 10952

The SYS causes a jump to the cold start routine at address 10952, hexadecimal 2AC8.
Code:
SCR# A1
// COLD
HEX // USER COLD START
: COLD  ( -- )
   SAVE-BUFFERS  EMPTY
   ACLOSE     // CLOSE ALL FILES
   >ASSEM
// POWERUP COLD START
// PATCH THE 'BASIC FUSE'
DECIMAL HERE 0 (UD.)
HEX 80B OVER - SWAP CMOVE>V
   SEI,
   0FF87 JSR, // RAMTAS
   0FF8A JSR, // RESTOR
   0FFE7 JSR, // CLALL
   0FF84 JSR, // IOINIT
   0FF81 JSR, // CINT

SCR# A2
// COLD
   ' WARM @  100 /MOD SWAP
      # LDA,  300 STA,
      # LDA,  301 STA,
   0D # LDY,  (WARM) JSR,
   >FORTH
   RP!
   EMPTY 0 DRIVE CONFIGURE
   0A SPACES
   ." C64      FORTH"
   CR CR
   ." COPYRIGHT (C) 1995-2018 BY JAMES BOYD"
   CR INITIAL ABORT ; -2 ALLOT

At start up, BASIC performs a SYS to the Set Interrupt Disable instruction (SEI,) in the cold start routine. Once the system is up and running, the cold start routine can also be called with the word COLD. COLD first saves the block buffers, empties the dictionary to the lesser of its initial and current sizes (saving this value as the new empty point), and closes all files before transitioning to the low level cold start routine.
The Commodore 64 lacks a backslash key so the double slash // is the word to treat the rest of the line as a comment. The funny names like RAMTAS and RESTOR are the names given to Commodore kernel routines in the Commodore 64 Programmer's Reference Guide.
I blanked out the name I'm using for my Forth for now. I'm having trouble thinking of a really good one.
Sorry about the commas at the end of the names of the op codes, I have them there to be compatible with other C64 Forths. Both 64Forth and Blazin' Forth have commas in the op code names. I'd personally like to remove them from my assembler but I hope to make this Forth publicly available one day and I don't know how much grief it would cause someone to rewrite assembly code, by removing all the commas in the opcode names of their source, to try on this Forth.
For another example, here is the full source for (RR/W), the code to access the REU, Commodore's Ram Expansion Unit, as Forth blocks.
Code:
SCR# 2A
// (RR/W)
HEX
CODE (RR/W)  ( ADR BLK# F CNT -- )
   DF09 LDA,  1F # CMP,  0= IF,
      DF0A LDA,  3F # CMP,
   0= NOT ELIF,
      >FORTH TRUE
      ABORT" REU NOT PRESENT"
      >ASSEM
   THEN,
   DF04 STY,  4 ,X LDA,
   .A ASL,  5 ,X ROL,
   .A ASL,  5 ,X ROL,
   DF05 STA,
   5 ,X LDA,  DF06 STA,

SCR# 2B
// (RR/W)
   0 ,X LDA,  DF07 STA,
   1 ,X LDA,  DF08 STA,
   6 ,X LDA,  DF02 STA,
   7 ,X LDA,  DF03 STA,
   2 ,X LDA,  10 # ORA,  DF01 STA,
   80 # ORA,  DF01 STA,
   BEGIN,
      DF00 LDA,  40 # AND,
   0= NOT UNTIL,
   INX,  INX,  INX,  INX,
   POPTWO JMP,  END-CODE
' (RR/W) IS RR/W

There is one caveat when using >FORTH and >ASSEM with control structures which should be obvious, but I'll mention it anyway. If a transition from low to high or high to low occurs in a control structure, the opposite transition must occur before a matching control structure word is used. I don't have actual examples other than the IF, ELIF, THEN, control block in the code above for the ram expander, so here is some pseudo-code:
Code:
: <A-HIGH-LEVEL-WORD>
   BEGIN
      SOME-HIGH-LEVEL-STUFF
      >ASSEM
      SOME-LOW-LEVEL-STUFF
      >FORTH
   WHILE
      MORE-STUFF
   REPEAT ;
   
CODE <A-CODE-LEVEL-WORD>
   BEGIN,
      SOME-LOW-LEVEL-STUFF
   WHILE,
      MORE-LOW-LEVEL-STUFF
      >FORTH
      SOME-HIGH-LEVEL-STUFF
      >ASSEM
      EVEN-MORE-LOW-LEVEL-STUFF
      >FORTH
      MORE-HIGH-LEVEL-STUFF
      >ASSEM
   REPEAT,
   NEXT JMP,  END-CODE



Cheers,
Jim


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 10, 2018 9:21 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
JimBoyd wrote:
The Forth I wrote for the Commodore 64 has a word to go from high level code to assembly called >ASSEM and a word to go from assembly to high level called >FORTH.

Although your names make a lot of sense (and I like them), I would encourage going with names that are already in use like Bruce brought up, above, INLINE and END-INLINE. Even if they haven't made it into ANS or Forth 2012 standards, common usage is, in a way, a standard in itself. I changed the names of a few of my "inventions" after I found out other better-known Forths used a different name for the same thing. You haven't distributed your Forth yet, and hopefully you don't have much code written to use it yet. The sooner you change it, the easier it will be to change it and promote acceptance.

Although there are things about ANS that I don't think are suitable for 65xx, I know that one thing impeding the acceptance of Forth has been that we independent-minded, free-thinking Forthers all tend to do things our own way. That's a strength of Forth, that it allows us to do that possibly more than any other HLL; but it makes it harder for someone who wants to get into it and is looking over the options and just finds more confusion because he can't find agreement between versions. I remember letters to the editor in Forth Dimensions magazine lamenting that a problem standing in the way of acceptance of Forth is that there was no effective standard. That was before ANS Forth. The X3J14 committee had a huge task on their hands which was not easy. They did the best they could, I believe, and still ruffled a lot of feathers because there was no way to make everyone happy in some areas. Jack Woehr of Vesta Technologies who was on the X3J14 committee says in his book "Forth: The New Model", "When Forth, which some hold to be inextricably wedded to hardware, takes responsibility for cross-platform portability, a certain light-footedness and grace will be surrendered." He admits that optimum portability and optimum efficiency don't come at the same point. Fortunately he also says it's not the committee's intention to force anyone to comply with the standard.

For the parts that don't cramp the 65xx's style though, I try to make my word names conform to what's in common usage.

_________________
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: Mon Sep 10, 2018 10:36 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
JimBoyd wrote:
The Forth I wrote for the Commodore 64 has a word to go from high level code to assembly called >ASSEM and a word to go from assembly to high level called >FORTH.

Although your names make a lot of sense (and I like them), I would encourage going with names that are already in use like Bruce brought up, above, INLINE and END-INLINE.

Thanks, but I can't really take credit for the names. I saw in online documentation for Mosaic Forth ( I was trying to find more information on Forth) it had the names >ASSM and >FORTH. While I agree about standard names in general, long ago I renamed UNDO to UNLOOP, I see a problem with renaming >ASSEM and >FORTH. If I rename >ASSEM to INLINE and >FORTH to END-INLINE it looks fine with words that start high level, transition to assembly, then back to high level.
Code:
HEX
: #  ( D1 -- D2 )
   BASE @ UD/MOD ROT
   INLINE
   0 ,X LDA,  0A # CMP,  CS IF,
      6 # ADC,
   THEN,
   30 # ADC,  0 ,X STA,
   END-INLINE
   HOLD ;

It looks a little strange with a word that starts high level then goes to assembly and stays there.
Code:
HEX
: (TYPE)  ( ADR CNT -- )
   PAUSE  INLINE
   2 # LDA,  SETUP JSR,
   BEGIN,
      BEGIN,
         N CPY,
         0= IF,  N 1+ LDA,
            0= IF,  NEXT JMP,  THEN,
            N 1+ DEC,
         THEN,
         N 2+ )Y LDA,
         ' (EMIT) @ 8 + JSR,
      INY,  0= UNTIL,
      N 3 + INC,
   AGAIN,  END-CODE
   // Where did END-ENLINE go? wasn't that assembly just supposed to be inline code?

And looks really strange with a word that starts as a code definition, then transitions to high level then back.
Code:
HEX
CODE (RR/W)  ( ADR BLK# R/WF CNT -- )
   DF09 LDA,  1F # CMP,  0= IF,
      DF0A LDA,  3F # CMP,
   0= NOT ELIF,
      END-INLINE                       // This looks backwards
      TRUE ABORT" REU NOT PRESENT"     //
      INLINE                           // but it's not.
   THEN,
   DF04 STY,  4 ,X LDA,
   .A ASL,  5 ,X ROL,
   .A ASL,  5 ,X ROL,
   DF05 STA,
   5 ,X LDA,  DF06 STA,
   0 ,X LDA,  DF07 STA,
   1 ,X LDA,  DF08 STA,
   6 ,X LDA,  DF02 STA,
   7 ,X LDA,  DF03 STA,
   2 ,X LDA,  10 # ORA,  DF01 STA,
   80 # ORA,  DF01 STA,
   BEGIN,
      DF00 LDA,  40 # AND,
   0= NOT UNTIL,
   INX,  INX,  INX,  INX,
   POPTWO JMP,  END-CODE
' (RR/W) IS RR/W

I'm not trying to be difficult but it seems that >ASSEM and >FORTH aren't really like INLINE and END-INLINE. It looks as though INLINE and END-INLINE are meant to be paired in that order. >ASSEM and >FORTH don't need to be paired. >ASSEM performs an unnest, like EXIT and >FORTH performs a nest, like do-colon. As my definition of (TYPE) shows, they both don't need to be present in a definition.
[Edit: fixed a typo]


Last edited by JimBoyd on Thu Nov 18, 2021 2:22 am, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 10, 2018 11:00 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
Actually, at the time I wrote >ASSEM and >FORTH, I'd forgotten that the Mosaic Industries version, >ASSM, didn't have an 'E' in the name.


Top
 Profile  
Reply with quote  
PostPosted: Mon Sep 10, 2018 11:16 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
If the function is different, and a major, popular Forth was already using >ASSEM and >FORTH, then I'd say go ahead and keep those names. I just haven't heard of them before. The way I did INLINE and END_INLINE, they don't particularly need to be paired. I also don't use vocabularies though, which might make a difference. There's no conflict between assembly language and Forth words though, because for example AND in assembly language is never just AND; instead, the addressing mode goes with it, like AND#, AND_ZP, etc.. Similarly, there's no conflict with the # of "sharp" (in Forth) and the # of "immediate" in assembly. So I would write for example AND# FOOBAR , (the comma being part of it, for '816 with the accum in 16-bit mode) which I think is a lot more readable than FOOBAR # AND , and there's no parsing because all AND# does is lay down the op code. It's up to the programmer to comma-in the operand (if any). (I've said this in previous posts, but you're a welcome new member who probably hasn't read all the archives yet. :D )

And you posted this while I was writing:
JimBoyd wrote:
Actually, at the time I wrote >ASSEM and >FORTH, I'd forgotten that the Mosaic Industries version, >ASSM, didn't have an 'E' in the name.

If they were going to leave out more letters, too bad they didn't shorten it to >ASM which might be even more clear because of the common use of those three letters for "assembly." "ASSM" could look like "assimilate" or any of a lot of other things.

_________________
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: Mon Sep 10, 2018 11:35 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
(I've said this in previous posts, but you're a welcome new member who probably hasn't read all the archives yet. :D )

Although I haven't read all the archives, not even close, I do remember reading about your assembler. From my code you can probably tell that I actually prefer the FOOBAR # LDA, approach. Maybe I've been using it so long that It's what I'm comfortable with.


Top
 Profile  
Reply with quote  
PostPosted: Tue Sep 11, 2018 3:24 pm 
Offline

Joined: Sun May 13, 2018 5:49 pm
Posts: 247
I ended up sneaking assembly into an Forth word for special cycle-count testing of Tali Forth 2 (an STC Forth). It was done to reduce the overhead of "stopwatching" a word. The simulator this runs in has a (virtual) stopwatch that is started by accessing $F006, stopped by accessing $F007, and the result (as a double-word with the bytes in correct 6502 forth order) shows up at $F008-$F00B. I use self-modifying code that replaces the address of the JSR between starting and stopping the virtual stopwatch. Processing the results is done in Forth. I don't have a Forth assembler loaded, so I just poked the opcodes into the word.

Code:
hex

\ The location of the result
F008 constant cycles

\ direct byte compiled
\  lda $f006
\  lda $f007
: cycles_overhead [ AD c, 06 c, F0 c, AD c, 07 c, F0 c, ] cycles 2@ ;

\ direct byte compiled
\  lda $F006
\  jsr (xt on stack goes here)
\  lda $f007
\ then forth code to fetch and print results.
: cycle_test_runtime
    [ AD c, 06 c, F0 c,    \ lda $F006
      20 c,  0000 ,        \ jsr (address to be filled in)
      AD c, 07 c, F0 c, ]  \ lda $F007
    cycles 2@              \ fetch result
    cycles_overhead d-     \ subtract overhead
    ." CYCLES: " 6 ud.r    \ print results
;

\ cycle_test updates the address of the given xt in cycle_test_runtime
\ then it runs the test.

\ To test a word, put any arguments it needs on the stack, use tick
\ (') on the word to get it's execution token (xt) and then put
\ cycle_test, then any stack cleanup.
\ eg. 5 ' dup cycle_test 2drop
: cycle_test ( xt -- )
    [ ' cycle_test_runtime 4 + ] literal ! cycle_test_runtime ;

To test a word, I just put some test arguments for it on the stack (if it needs them), use ' to get the XT of the word I want to test, and then run my test. Then I clean up the stack. I don't check the results of the operation because the test suite does that elsewhere. This is just to get an idea of how many CPU cycles each word takes. A sample test for DUP might look like:
Code:
5            ' dup           cycle_test 2drop

When run, that looks like:
Code:
5            ' dup           cycle_test 2drop      CYCLES:     37 ok


Top
 Profile  
Reply with quote  
 Post subject: Re:
PostPosted: Tue Sep 25, 2018 11:22 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
dclxvi wrote:
Inline assembly with ITC or DTC isn't common because, unlike STC, you don't gain much.

Well, that depends. What about the case with inline high level code in an assembly ( code ) definition? My Forth is an ITC Forth for the C64 and has blocks. As I've mentioned elsewhere:
JimBoyd wrote:
If you were wondering, my Forth's BLOCK starts out as a code definition. As long as the requested block is the most recently used block, BLOCK stays at code level to replace the block number with the address of the appropriate buffer, then jumps to NEXT. If the requested block is not the most recently used one, BLOCK transitions to high level to deal with it.

It's been my experience that when BLOCK is called, it's usually called quite a few times with the same block number before a different block is requested. I thought,"Wouldn't it be nice if BLOCK were a code definition for all the times where it only has to replace the block number with an address?" Using >FORTH makes it easy to write BLOCK as a code definition if the requested block is the most recently used ( accessed ), yet be able to go to high level code for everything else.
Being able to ABORT or ABORT" from a code definition without the need to pass an error flag to a high level "wrapper word" is handy. I realize that some code words return a flag so the high level routine calling it can decide what to do. FIND comes to mind. If the word is not found in the CONTEXT vocabulary, search the CURRENT one, but I'm refering to a case where if the word were written in high level Forth, it would abort on an error. It would be nice to rewrite that word as a code word for speed, but it needs to abort on an error. It can by including inline high level forth code. It's also an easy way to get the coldstart and warmstart routines running the quit loop, just write it as a transition to high level:
Code:
<cold start stuff>
>FORTH
<high level initialization code>
INITIAL  \\ defered word -- default value is NOOP, a no-op
         \\ used to run additional initialization code
ABORT ;

I've found >FORTH and >ASSEM so useful that I've included them in my assembler and the primitives, (>FORTH) and (>ASSEM) are part of my Forth kernel. Since I already have them, including inline assembly in high level code doesn't cost anything extra. I rewrote # so it has inline assembly. the resulting word was four bytes smaller ( on my ITC Forth ) and the pictured numeric output words were a bit faster. When I have more time, I'll run some timing tests to get an idea of how much faster.
Anyway, I hope this gives food for thought.

Cheers,
Jim


Top
 Profile  
Reply with quote  
PostPosted: Mon Aug 17, 2020 11:08 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
I noticed a typo while following a link from another topic to this one.
JimBoyd wrote:
>ASSEM performs an unnest, like EXIT and >FORTH performs a next, like do-colon.

Although it does jump to next, >FORTH performs a nest.


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 17 posts ]  Go to page 1, 2  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: