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

All times are UTC




Post new topic Reply to topic  [ 36 posts ]  Go to page 1, 2, 3  Next
Author Message
PostPosted: Sun Nov 04, 2018 11:54 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
[Edit: this is the latest version of Fleet Forth's assembler.
Attachment:
Fleet Forth Assembler.zip [10.67 KiB]
Downloaded 50 times
The original version is three posts down

Forth assemblers with structured conditionals have served me well over the years, but I've recently noticed that they can have their shortcomings. I'd like to start a discussion on how to improve an assembler with structured conditionals.
I have three examples of the word (EXPECT) from my Forth's kernel. At the start of the loop if the y-register equals the value in N, the goal is to branch to the JSR to FFCF, one of the routines in the C64 kernel.
The first two examples use various control flow stack manipulators, CS-ROT,CS-SWAP, etc. to manipulate the control flow information.
Code:
// (EXPECT)
HEX
CODE (EXPECT)  ( ADR CNT -- )
   2 # LDA,  SETUP JSR,
   XSAVE STX,  SPAN 1+ STY,
   BEGIN,
         N CPY,
      0= WHILE,
         N 1+ LDA,
      0= NOT WHILE,
         N 1+ DEC,
      CS-ROT THEN,
         0FFCF JSR,  // CHRIN
         0D # CMP,
      0= NOT WHILE,
         N 2+ )Y STA,
         INY,
      CS-DUP 0= UNTIL,
      N 3 + INC,  SPAN 1+ INC,
   REPEAT,
   THEN,
   SPAN STY,  XSAVE LDX,
   NEXT JMP,
END-CODE
' (EXPECT) IS EXPECT


HEX
CODE (EXPECT)  ( ADR CNT -- )
   2 # LDA,  SETUP JSR,
   XSAVE STX,  SPAN 1+ STY,
   BEGIN,
         N CPY,
         0= IF,
         N 1+ LDA,
      0= NOT WHILE,
         N 1+ DEC,
         THEN,  CS-SWAP
         0FFCF JSR,  // CHRIN
         0D # CMP,
      0= NOT WHILE,
         N 2+ )Y STA,
         INY,
      CS-DUP 0= UNTIL,
      N 3 + INC,  SPAN 1+ INC,
   REPEAT,
   THEN,
   SPAN STY,  XSAVE LDX,
   NEXT JMP,
END-CODE

The final example was some prototyping for another approach. It makes use of the four unused bytes at 3FC-3FF. The idea is that there could be an array of available memory locations for control flow data. The words to access this memory could be:
Code:
CS!  ( CONTROL-FLOW-DATA SLOT-NUMBER -- )
CS@  ( SLOT-NUMBER -- CONTROL-FLOW-DATA )

Used as:
Code:
      IF,  0 CS!
            .
            .
      0 CS@ THEN,


Code:
// (EXPECT)
HEX
CODE (EXPECT)  ( ADR CNT -- )
   2 # LDA,  SETUP JSR,
   XSAVE STX,  SPAN 1+ STY,
   BEGIN,
         N CPY,
         0= IF,  3FC 2!
         N 1+ LDA,
      0= NOT WHILE,
         N 1+ DEC,
         3FC 2@  THEN,
         0FFCF JSR,  // CHRIN
         0D # CMP,
      0= NOT WHILE,
         N 2+ )Y STA,
         INY,
      CS-DUP 0= UNTIL,
      N 3 + INC,  SPAN 1+ INC,
   REPEAT,
   THEN,
   SPAN STY,  XSAVE LDX,
   NEXT JMP,
END-CODE


Any comments?
I know this approach doesn't look very Forthy, and would appreciate it if anyone has other ideas to improve an assembler with structured conditionals.


Last edited by JimBoyd on Sun May 14, 2023 8:40 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Mon Nov 05, 2018 12:28 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
I haven't really given this much thought for a Forth assembler since the assembly-language portions I write in the Forth environment are pretty short, just primitives, runtimes, and whatever ISRs I might service in assembly rather than Forth.  For a normal assembler however, I did pattern my program-flow-control macros after after Forth's.  The exceptions are names I thought non-Forthers would be more resistant to, like DO...LOOP which I replaced with FOR...NEXT.  See http://wilsonminesco.com/StructureMacros/ .  I have a lengthier example of how that looks, in the last 20% of the page at http://wilsonminesco.com/multitask/ .  There are a few shorter examples above that.  http://wilsonminesco.com/stacks/pgmstruc.html in the 6502 stacks treatise explains the innards better.  With few exceptions, the macros lay down the same code you would do by hand in assembly.

_________________
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 Nov 05, 2018 10:45 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
I haven't really given this much thought for a Forth assembler since the assembly-language portions I write in the Forth environment are pretty short, just primitives, runtimes, and whatever ISRs I service in assembly rather than Forth.

(EXPECT) really isn't that long at 46 bytes of code ( not counting the CFA ).
Quote:
For a normal assembler however, I did pattern my program-flow-control macros after after Forth's.

They look like another way to do structured conditionals in the assembler.
Notice the first example ( they all compile the same code ). It's from my Forth's kernel. There are three WHILE,s in the loop but only two exit the loop. By use of control flow manipulation with CS-ROT the first WHILE, is resolved by THEN, so it branches to the 0FFCF JSR, instruction.
The next example avoids having a WHILE, that doesn't leave the loop. The first WHILE, is replaced with IF, Since WHILE, is just:
Code:
: WHILE,  ( A1 C1 -- A2 C2 A1 C1 )
   [COMPILE] IF, 2SWAP ; IMMEDIATE

The second WHILE, places its control flow data under the control flow data for IF,. THEN, resolves IF, but CS-SWAP is needed to place WHILE,'s control flow data under BEGIN,'s.
The third example uses an experimental approach to place the control flow data for IF, in a temporary location and later place it back on the stack for THEN,.
Which of the three is easiest to follow? Is there a better way to enhance an assembler with structured conditionals?

By the way, the code is actually two BEGIN, loops with a common starting point. CS-DUP duplicates the control flow data for BEGIN, so it is still available after 0= UNTIL,. I did this so the WHILE,s would branch out of both loops. Again, I'm not sure how well that reads. Since I plan to release my Forth and its accompanying source, I would like the code to be as easy to follow as possible without rewriting it to make it [the assembled code] bigger.
I'd also like to improve my assembler. :D

[Edit: one clarification]


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 03, 2018 10:14 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
I wonder if there is a lack of interest in Forth assemblers with structured conditionals or if Ragsdale's is the only one with which most Forth programmers are familiar? Here is the source for mine.
Attachment:
Fleet Forth Assembler.zip [10.65 KiB]
Downloaded 150 times

Any comments, questions, suggestions?
[Edit: It's released under the LGPL version 2 or later. Do I need to include a copy of the license?]
[Edit: Included license]


Last edited by JimBoyd on Tue Dec 04, 2018 9:19 pm, edited 2 times in total.

Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 12:49 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
The problem with Forth assemblers isn't necessarily the syntax (as off-putting as it may be to some), but the fact that it's in Forth in the first place.

If it were just a stand alone program that takes a text file and spits out an assembled binary, then it's simply a different syntax rather than an entirely different tool chain.

and, yes, you should include a copy of the license in the ZIP file.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 2:24 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
The first 6502 Forth I worked with (around 1990 or '91) was with a metacompiler at work, which had the postfix assembly language and structured conditionals.  I absolutely hated the postfix assembly, which is why, when I wrote my own Forth assembler, I made the mnemonic come first like in normal assemblers and then you comma-in the operand, like AND_ABS foobar , .  I really like using the program flow control macros in a normal assembler though, and although I did not become very fond of what came with the metacompiler in that regard (because of the first problem), Forth does afford a natural macro capability, so I might implement the macros in Forth if I ever write anything in assembly long enough in the Forth environment for that to matter.  Most of these things are pretty short though, just primitives, runtimes, subroutines, and whatever ISRs are not Forth.  They're definitely not whole applications.  I have a longer example in a non-Forth environment near the end of this page, and a couple above it that might be interesting.

Quote:
The problem with Forth assemblers isn't necessarily the syntax (as off-putting as it may be to some), but the fact that it's in Forth in the first place.

One big advantage is that Forth names can include almost any characters.  It's just a tad frustrating that normal assemblers see certain characters and think you're trying to do an operation between the spaces, for example R/W_SPI (since SPI sends and receives a byte at the same time).  Another advantage in Forth is that you can do complex operations between assembly-language instructions to prepare operands, data, conditional assembly, etc., much more than you can with a normal assembler.

_________________
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: Tue Dec 04, 2018 4:34 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
GARTHWILSON wrote:
... I might implement the macros in Forth if I ever write anything in assembly long enough in the Forth environment for that to matter.


That's the basic problem, though.

Forth assemblers (and when I say "Forth assemblers", I'm talking the typical Forth Assembler most of us are familiar with rather than some edge case) are for writing words for a Forth environment, rather than large assembly language programs. So, they're not, typically, designed for some of the problems that regular assemblers are designed for.

Notably, Forth assemblers aren't set up to manage or work with libraries and object files. They don't need a linker. They also don't offer things like cross references, reference tables (labels and their assignments), etc.

Early Forth assemblers were also, naturally, limited by the BLOCK structure of Forth source code, which is why much of it is written with several instructions on a single line vs one instruction per line in traditional assemblers.

Forth assemblers are single pass assemblers as well.

Basically consider someone writing Prince of Persia using a Forth assembler.

There's nothing to stop someone from writing a full boat, stand alone, full featured assembler using the RPN syntax. But, in the end I don't think it would save much in terms of the assembler code, or how wide of an appeal it would have in the end.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 5:41 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
The term "Forth assembler" conjures up in my mind a very small assembler that's just there to support Forth in the way we both stated above.

Quote:
They also don't offer things like cross references, reference tables (labels and their assignments), etc..

It could be done, but it's just a bit cumbersome and I'm sure the need is rare.  In my assembler I do have a set of about two dozen constants that return addresses in the Forth system, including things like NEXTadr, PUSH, CPUSH, and N.

Quote:
Early Forth assemblers were also, naturally, limited by the BLOCK structure of Forth source code, which is why much of it is written with several instructions on a single line vs one instruction per line in traditional assemblers.

I use text source files, but I do like the ability to put multiple assembly-language instructions on a line, grouping them appropriately, and reducing the number of lines.  I suppose a normal assembler could be written to do this, but I have not seen one.  It should be pretty simple.

Quote:
Basically consider someone writing Prince of Persia using a Forth assembler.

Heh heh, not a chance—unless the idea is that it's mostly Forth, with the performance-critical parts being done in these short assembly sections the typical Forth assembler is intended for.

_________________
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: Tue Dec 04, 2018 3:38 pm 
Offline
User avatar

Joined: Fri Dec 11, 2009 3:50 pm
Posts: 3346
Location: Ontario, Canada
JimBoyd wrote:
I wonder if there is a lack of interest in Forth assemblers with structured conditionals or if Ragsdale's is the only one with which most Forth programmers are familiar?
Well, Ragsdale's assembler (which includes structured conditionals) has been around since Day One -- ie, FIG Forth for 6502, which was 1980 or thereabouts. Said assembler very likely has room for improvement, but any revised or alternative version has some catching up to do when it comes to garnering attention.

There has, however, been a fair amount of discussion here on this forum. It's not all tidily arranged in one thread, unfortunately -- that can't 100% be expected, given the way discussions evolve! :P :roll:

In addition to this thread, here are two others with pertinent remarks:
    This and nearby posts in the Petil thread pertain to CASE statements.
    Self Modifying Code (perhaps too broad a title, as you didn't mention the intended context of structured conditionals)

BTW, I'll quickly inject a comment of my own. Ragsdale's assembler (and yours, I think) check to see that conditionals are properly paired, which means (for example) that BEGIN leaves both an address and an error-check code on stack and UNTIL removes these two items. Usually that's fine, but in certain situations the error-check code becomes a nuisance, leading to extra SWAPs ROTs etc. I daresay there's no perfect solution, but perhaps it'd be best if the error-check codes (but not the addresses) got pushed & popped from their own separate stack. (This is a variation of an idea Garth suggested elsewhere.)

-- Jeff

_________________
In 1988 my 65C02 got six new registers and 44 new full-speed instructions!
https://laughtonelectronics.com/Arcana/ ... mmary.html


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 4:24 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
Well, there's this example:

http://www.forth.org/fig-forth/fig-forth_68000.pdf

This is an implementation of Fig-Forth written in an RPN assembler (itself written in Forth). Though if you look at it, you'll see it's more traditional assembler than the typical utility in a Forth system to build assembler based words.

AT A GLANCE, this listing is almost unreadable, to me. By that I mean I would have to give it some thorough study to get past the syntax that they are using. But if you notice, this assembler does NOT offer structured conditionals or loops (this is readily apparent in the FIND word, where you see FIND1, FIND2, etc. labels.

I only mention this as an example of the momentum that typical assembler syntax has, being pretty common across CPUs and instructions sets.

RPN as an expression representation has utility to folks, particularly in calculators as it just works better on going calculations. But having as assembler of this scope relying on RPN, is really designed as a benefit to the computer, not the developer. I don't think I would necessarily enjoy working with the assembler syntax presented here.

But, then, we can get used to anything.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 9:26 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
The first 6502 Forth I worked with (around 1990 or '91) was with a metacompiler at work, which had the postfix assembly language and structured conditionals. I absolutely hated the postfix assembly

I enjoy postfix assembly. I'm curious, you've mentioned how bad that metacompiler was, could that have colored your perception of the assembler?


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 9:55 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
whartung wrote:
The problem with Forth assemblers isn't necessarily the syntax (as off-putting as it may be to some), but the fact that it's in Forth in the first place.

If it were just a stand alone program that takes a text file and spits out an assembled binary, then it's simply a different syntax rather than an entirely different tool chain.

and, yes, you should include a copy of the license in the ZIP file.

Ah but that's not the case with the metacompiler's assembler ( which is also postfix ). When I was developing my metacompiler, I added a feature that I never actually needed ( it was easy to add ). The metacompiler has a word SUB which is used to write subroutines a code word might need. SUB creates a label ( on the host, of course ) but does not create any header or code field on the target. It then switches to the metacompiler assembler vocabulary. Here is a short test routine I wrote last night.
Code:
HEX
C000 BOTTOM!
SUB FLASHER
   0 # LDA,  TAX,  TAY,
   BEGIN,
      D020 STA,  CLC,  1 # ADC,
   CS-DUP 0= UNTIL,
      INY,
   CS-DUP 0= UNTIL,
      INX,
   0= UNTIL,
   RTS,
END-CODE

I know it's not much, even for an example but, it shows that it is possible to use the metacompiler's assembler to write stand alone programs.
This short piece was saved with the metacompiler word TSAVE and loads at address $C000 or decimal 49152 ( an address familiar to Commodore 64 users who also programmed their machines ). The screen shot shows the short BASIC program that uses this routine. The screen shot was taken during the test. Yes it completed successfully.
Attachment:
meta assembler demo.png
meta assembler demo.png [ 18.34 KiB | Viewed 9671 times ]

This has given me food for though about the metacompiler. Currently, the source is compiled with MLOAD or MTHRU but, writing MINCLUDE, a metacompiler version of INCLUDE will be easy to write but, there may be a better way. I'll have to go through the metacompiler code and clean it up and maybe rethink some of the metacompiler design.

Cheers,
Jim

P.S. BOTTOM! could be renamed ORIGIN.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 10:16 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
Dr Jefyll wrote:
In addition to this thread, here are two others with pertinent remarks:
    This and nearby posts in the Petil thread pertain to CASE statements.
    Self Modifying Code (perhaps too broad a title, as you didn't mention the intended context of structured conditionals)

Sorry about that, I kinda got sidetracked on that one. The disscussion digressed to a discussion on fixing that ugly hand calculated offset in my example SMC. My assembler uses structured conditionals, so I'm biased that way. In addition to the SMC use by NEXT, I was hoping to see more examples of SMC in assembly, in any notation, or high level Forth, although I've never had an occasion to use it in high level Forth. Still, it would have been interesting to see some examples. There's chitselb's example here but, I really would have liked to see more examples.
Quote:
BTW, I'll quickly inject a comment of my own. Ragsdale's assembler (and yours, I think) check to see that conditionals are properly paired, which means (for example) that BEGIN leaves both an address and an error-check code on stack and UNTIL removes these two items. Usually that's fine, but in certain situations the error-check code becomes a nuisance, leading to extra SWAPs ROTs etc. I daresay there's no perfect solution, but perhaps it'd be best if the error-check codes (but not the addresses) got pushed & popped from their own separate stack. (This is a variation of an idea Garth suggested elsewhere.)

-- Jeff

That's why I've got CS-DUP CS-DROP CS-SWAP and CS-ROT which also work with high level Forth conditionals. I just treat the address and security number as a single unit.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 04, 2018 10:54 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8428
Location: Southern California
JimBoyd wrote:
GARTHWILSON wrote:
The first 6502 Forth I worked with (around 1990 or '91) was with a metacompiler at work, which had the postfix assembly language and structured conditionals. I absolutely hated the postfix assembly

I enjoy postfix assembly. I'm curious, you've mentioned how bad that metacompiler was, could that have colored your perception of the assembler?

No; the postfix assembly might have colored my perception of the structured conditionals, but I didn't pay much attention to that part anyway.

Part of the problem with postfix assembly is not the postfix itself, but the difficulty in applying vertical alignment for visual factoring, since the addressing mode is separate, and operands are of varying lengths (regardless of what system is being used).  Sometimes operands must be calculated from a longish line of source code; so vertical alignment of instruction mnemonics would require putting them waaaaay off to the right; and then if you want to indent a portion for a structure, well, forget it.  Now there's no room for comments either.

_________________
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: Wed Dec 05, 2018 9:02 pm 
Offline

Joined: Fri May 05, 2017 9:27 pm
Posts: 851
GARTHWILSON wrote:
Part of the problem with postfix assembly is not the postfix itself, but the difficulty in applying vertical alignment for visual factoring, since the addressing mode is separate, and operands are of varying lengths (regardless of what system is being used). Sometimes operands must be calculated from a longish line of source code; so vertical alignment of instruction mnemonics would require putting them waaaaay off to the right; and then if you want to indent a portion for a structure, well, forget it. Now there's no room for comments either.

I don't usually align on the opcode, but rather the first character on a line as shown below:
Code:
HEX
// CLOSE ALL OPEN FILES
CODE ACLOSE  ( -- )
   XSAVE STX,
   BEGIN,
      98 LDY,
   0= NOT WHILE,
      258 ,Y LDA,    // LAST OPENED
      FFC3 JSR,      // CLOSE
   REPEAT,
   XSAVE LDX,
   NEXT JMP,  END-CODE

Is high level Forth so different?


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 36 posts ]  Go to page 1, 2, 3  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 12 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: