6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Nov 16, 2024 2:41 pm

All times are UTC




Post new topic Reply to topic  [ 67 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
PostPosted: Thu Jul 11, 2013 11:20 pm 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
Garth, you make many good points. Toolchains spin out of control; assemblers don't.

As for the external macro engine - it' just a source transformation, so in case of conditional assembly, parts of the source will not be included in the output. Is there a tricky part I am missing?

With macros there are plenty of tricky points. For instance - do you just run one pass? Or do you run multiple passes until your output is stable (no more macros to expand). If you have macros defining other macros, it can get strange. Or when macro parameters change during the transformation process.. Some assemblers insist on certain values being constant, often to my dismay.

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


Top
 Profile  
Reply with quote  
PostPosted: Thu Jul 11, 2013 11:50 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8541
Location: Southern California
The toolchain makers want to integrate everything, so if you have different ones for different families of products from different companies, the editor which is where you spend much of your time won't be consistent from one to the next. Why not use a really, really good one (like MultiEdit in my case) so you can know and use the same one for everything. It has the ability, if you want to use it, to highlight structures for different languages, link to different assemblers to highlight errors caught in assembly, etc.. I don't need a proprietary toolchain for that. I've had up to about 34 different files open at once, some minimized, others tiled and windowed different ways, and some just hiding, and this is in DOS, and it's all point-and-click, and uses a hi-res monitor allowing you to see two full pages side by side if you wish. I use the same editor for different assemblers and compilers.

Quote:
As for the external macro engine - it' just a source transformation, so in case of conditional assembly, parts of the source will not be included in the output. Is there a tricky part I am missing?

Regarding the conditional assembly, I was partly thinking of whether it would work the same way in the macros as in non-macro parts of the assembly code. If they were two separate pieces of software written by different people, they might not work the same.

Quote:
With macros there are plenty of tricky points. For instance - do you just run one pass? Or do you run multiple passes until your output is stable (no more macros to expand). If you have macros defining other macros, it can get strange. Or when macro parameters change during the transformation process. Some assemblers insist on certain values being constant, often to my dismay.

I'm a macro junkie. I had only one special case, 22 years ago, where something required the assembler to make more than the normal two passes. I can't remember what it was. It was plenty fast though, and the extra few seconds' wait was no big deal. I've never heard of macros defining macros, although I might be able to imagine a use for it (similar to OOP). Macros must always be defined before they're invoked though, including invocation by another macro, and defining one and then not using it does not carry any penalties like an unused subroutine would. The whole reason for the two-pass assembler of course is that the first pass will encounter references to many program labels that are still ahead and unknown. The operand fields will be left blank and later filled in on the second pass after they have been found. This would go for macros too, where parameters may refer to labels that come after the macro invocation. We did have another topic recently where someone apparently had problems because variables were being referred to before they were defined (which is not a good programming practice), and the assembler did not know yet in the first pass if it should leave one byte or two for the operand for ZP versus abs addressing.

_________________
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: Fri Jul 12, 2013 1:36 am 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
In fasm on x86 and ARM, I used recursive macro definitions extensively to build dictionaries for Forth-like systems. For every word in the bootstrap kernel the HEAD macro was redefined to include its previous definition with the new head appended and linked to previous one. In the end, the macro was executed, creating hundreds of words perfectly linked and ready to go! I learned that trick from the creators of RetroForth, I think (before they decided to use some kind of a VM and the whole project became useless for me). Creating a bootstrap Forth environment with macros is surprisingly impossible with some assemblers.

In particular, you want to keep the pointer to the last word in a variable after its defined, so that the next one can create a link pointer to it. Some assemblers just can't keep that variable set correctly. In many, you cant ORG <variable> or <expression>, so you can't adjust the output pointer or calculate the position of objects in memory dynamically.

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 1:55 am 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
Daryl, thanks for such quick help. I love your monitor and am enjoying it greatly.

Tomorrow I will try to integrate a serial load command. Any tips? It should be trivial, but worth checking...

I was thinking about sending a binary with a 16-bit address, 16-bit size. This way a simple keystroke should be enough to load a file, without any parameters...

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 2:23 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 9:02 pm
Posts: 1747
Location: Sacramento, CA
enso wrote:
Daryl, thanks for such quick help. I love your monitor and am enjoying it greatly.

Tomorrow I will try to integrate a serial load command. Any tips? It should be trivial, but worth checking...

I was thinking about sending a binary with a 16-bit address, 16-bit size. This way a simple keystroke should be enough to load a file, without any parameters...


Sounds easy enough. Read the first 4 bytes, put the first two in the startaddr, startaddr_h pair in zero page. The put the next two in addrptr, addrptr_h pair. These are defined in SBC2os.asm.

Then read a byte, store using sta (startaddr),y or sta (startaddr,x) (with x or y properly set to 0). The increment addrptr pair and decrement the addrptr pair until it reaches 0. As long as you use handshaking to ensure no bytes are lost, it should work.

You can optimize for speed later, if needed.

Daryl

_________________
Please visit my website -> https://sbc.rictor.org/


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 3:18 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Quote:
I did find another bug last year in C32 (with INCLude files in a macro not getting included until the macro is finished) but found a way around it.


I still claim that may not be a bug but a reasonable design choice. Mostly because HXA would do the same thing if I let it, instead of flagging it as an error. Nested macros and nested includes are treated separately, and trying to unite them would at the very least seem to introduce a lot of overhead checking on each input line that in most cases would be wasted effort.

Not that I've actually sat down and tried to work my way through coding it. Just the thought makes me tired (what this forum needs is a good "sleeping" emoticon!).

And anyway, because HXA can nest macros the reason you want file inclusion in them is moot!


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 3:49 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8541
Location: Southern California
enso wrote:
In fasm on x86 and ARM, I used recursive macro definitions extensively to build dictionaries for Forth-like systems. For every word in the bootstrap kernel the HEAD macro was redefined to include its previous definition with the new head appended and linked to previous one. In the end, the macro was executed, creating hundreds of words perfectly linked and ready to go! I learned that trick from the creators of RetroForth, I think (before they decided to use some kind of a VM and the whole project became useless for me). Creating a bootstrap Forth environment with macros is surprisingly impossible with some assemblers.

In particular, you want to keep the pointer to the last word in a variable after its defined, so that the next one can create a link pointer to it. Some assemblers just can't keep that variable set correctly. In many, you cant ORG <variable> or <expression>, so you can't adjust the output pointer or calculate the position of objects in memory dynamically.

In my '816 Forth, the header macro is:
Code:
HEADER:         MACRO NAME, precedence  ; Lay down name and link fields.  NAME is a quoted string or string expression.

 IF HEADERS? && ! OMIT_HEADERS          ; If HEADERS is true and OMIT_HEADERS is false,
                                        ; then go ahead lay down the header.
   last_NFA:    SETL    new_NFA
    new_NFA:    SETL    $
                DFB     precedence | {npc-$-1}, NAME
        npc:                            ; Use this label for the calculation of the name length byte above.
        IF      $ & 1                   ; If next addr is odd,
                DFB     0               ; add a nul byte before you
        ENDI
                DWL     last_NFA        ; lay down the link field.
 ELSE
        IF      $ & 1
                DFB     0               ; Even if headers are not allowed,
        ENDI                            ; you should still align.
 ENDI
                ENDM
 ;-------------------

where HEADERS?, OMIT_HEADERS, last_NFA, and new_NFA are assembler variable set and changed as many times as you like by SETL (SET Label value). The two variables HEADERS? and OMIT_HEADERS offer three levels of headersless code: locally headerless (like for just a word or two), global, and, in between, a range that's wider than just local. (I know the macro is kind of ugly, but macros tend to be that way, which is one reason we like to make them macros and hide that stuff.) Use of the header macro is like:
Code:
        HEADER "1+", NOT_IMMEDIATE      ; ( n -- n+1 )
_1ADD:  PRIMITIVE
        INC   0,X
        GO_NEXT
 ;-------------------

where PRIMITIVE just lays down the address of the INC 0,X as the CFA, and the GO_NEXT macro makes it easy to change all the JMP NEXT's for different versions of NEXT like with or without interrupt support, do single-stepping, program-trace, etc..


Quote:
And anyway, because HXA can nest macros the reason you want file inclusion in them is moot!

Yes, macro nesting is nice. Since C32 doesn't have it, I resorted to the INCLude files as a work-around, and then ran into the problem that required another work-around.

_________________
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: Fri Jul 12, 2013 4:37 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
m4 is useable, just awful. I've used it with mine. For one thing, whereas pretty much every other macro processor on the planet is line oriented, m4 is character oriented. It just makes it that much more of a pain to use.

But it's ubiquitous, so there's that.

There's also the C pre-processor. Less powerful than m4, but more sane. It's good for the simpler stuff like includes and conditional compilation.

The primary benefit of an integrated macro processor is that the listing and error messages can make much more sense. A simple point about the include file, if you use m4 or cpp for that, you'll simply get an error on "line 1234" without having any idea where "line 1234" is, since the assembler see a single, consolidated file, not individual first class chunks.

I need to rewrite the expression parser on mine, I'm unhappy with it, then I'll look at adding an INCLUDE capability, and when that's done I'll likely have enough ammo to just make a generic macro processing facility to it.

And I'm only interested in things that can run natively on the Mac, I spooled up a Linux VM to build the CPU test source file, but I won't do that routinely.

Maybe I should port mine to Emacs, make it native :).


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 9:15 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
Garth, why are you aligning the code field address?

The only reason I can think of this to ensure both bytes are on the same page to avoid the 6502 JMP (indirect) bug but on all later devices this is fixed.

I use the same approach to generating my Forth headers in Dev65 (but I don't align on 65C02)

_________________
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 9:53 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8541
Location: Southern California
BitWise wrote:
Garth, why are you aligning the code field address?

The 2nd "IF" aligns the LFA, and since it takes two bytes, the CFA is automatically aligned. If you compile headerless code, the 3rd "IF" still aligns it the CFA even though there's no name field or link field.

Quote:
The only reason I can think of this to ensure both bytes are on the same page to avoid the 6502 JMP (indirect) bug but on all later devices this is fixed.

I use the same approach to generating my Forth headers in Dev65 (but I don't align on 65C02)

I aligned because, IIRC, it made something easier in the SEE (decompiling) word, partly because I allow all 256 characters in names (including ones with high bit set) except of course space, CR, LF, and a few others that would be extremely impractical. This allows names to have the special ANSI characters like ±½°. Without delving into it again at the moment, I don't remember exactly why it made decompiling easier. It was too many years ago.

_________________
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: Fri Jul 12, 2013 12:35 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10980
Location: England
enso wrote:
GARTHWILSON wrote:
... and teamtempest's (Anton Treuenfels') HXA at http://home.earthlink.net/~hxa/ which includes macros to do the program structures I have been promoting.

Unfortunately, windows or dos only...


HXA works fine on Linux, just have Wine installed and you can invoke it directly.

Cheers
Ed


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 3:10 pm 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
Great, I will give hxa a try!

Thank you for pointing out the error location problem with a separate macro processor. That is a problem - the assembler never sees the original code, and the macro processor is done by the time the error occurs. I am still attached to the idea as a separate macro processor makes the assembly cleaner somehow. Maybe.

One way to handle it is to attach a line-number comment during macro processing, perhaps at the end of the line. Each output line is then matched to the original line number in the comment, so when an error occurs, you know where to look.

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 3:42 pm 
Offline

Joined: Sun Apr 10, 2011 8:29 am
Posts: 597
Location: Norway/Japan
enso wrote:
One way to handle it is to attach a line-number comment during macro processing, perhaps at the end of the line. Each output line is then matched to the original line number in the comment, so when an error occurs, you know where to look.

cpp does something like that. There's a #line statement. It can also be used in the assembly output when compiling (for example) C, so that you can look at the assembly (.S files) and see which section of statements corresponds to which source code line (and it's also used to generate the debugging info used by GDB when tracing executables).

-Tor


Last edited by Tor on Fri Jul 12, 2013 10:33 pm, edited 1 time in total.

Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 4:16 pm 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
Yes, inserting "line=..." or ".line" perhaps statements is even better than messing with comments. The assembler can track them. A similar issue happens with macro expansion and some assemblers really botch the error location.

Garth, in my 32-bit forths I've aligned heads to 8 and 16-byte bounds (as it's a lot faster) and often used the 3 or 4 low bits for flags... BTW, what is the memory footprint of your minimal Forth setup? Forth is a heck of a lot more useful than any monitor...

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 12, 2013 5:10 pm 
Offline
User avatar

Joined: Sat Sep 29, 2012 10:15 pm
Posts: 904
Daryl, I am working on the loader.

I added an 'L' (for load) command into the ASCII command table, the jump table and a 0 in the secondary table. What is the purpose of that table - is it an opportunity to run a different command after the main one is done?

_________________
In theory, there is no difference between theory and practice. In practice, there is. ...Jan van de Snepscheut


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

All times are UTC


Who is online

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