It is currently Mon May 20, 2019 7:34 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 15 posts ] 
Author Message
PostPosted: Sat Mar 30, 2019 6:35 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
I'm building an audio driver in ASM6, and I'm up to where I build a table of sound effect addresses and lengths. But when I try to express lookup tables using macros, I get "Incomplete expression" errors.

When I assemble this source file and provide -L to expand macros in the listing file:
Code:
macro sfxdef name, baseaddr, length, period, channel
name = <((* - sfx_table) / 4)
dw baseaddr
db (channel<<2)|((period - 1)<<4)
db length
endm

base $C000
sfx_table:
sfxdef SFX_foo, foo_data, 1, 1, 0
sfxdef SFX_bar, bar_data, 1, 1, 0

foo_data: db $89,$10
bar_data: db $84,$20


This listing is produced:
Code:
                                macro sfxdef name, baseaddr, length, period, channel
                                name = <((* - sfx_table) / 4)
                                dw baseaddr
                                db (channel<<2)|((period - 1)<<4)
                                db length
                                endm
                               
                                base $C000
0C000                           sfx_table:
0C000                           sfxdef SFX_foo, foo_data, 1, 1, 0
0C000                           SFX_foo = <((* - sfx_table) / 4)
*** Incomplete expression.
0C000 08 C0                     dw foo_data
0C002 00                        db (0<<2)|((1 - 1)<<4)
0C003 01                        db 1
0C004                           sfxdef SFX_bar, bar_data, 1, 1, 0
0C004                           SFX_bar = <((* - sfx_table) / 4)
*** Incomplete expression.
0C004 0A C0                     dw bar_data
0C006 00                        db (0<<2)|((1 - 1)<<4)
0C007 01                        db 1
0C008                           
0C008 89 10                     foo_data: db $89,$10
0C00A 84 20                     bar_data: db $84,$20


What is causing these errors, and what should I understand in order to figure out how to fix them?

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Sat Mar 30, 2019 6:42 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11345
Location: Rio de Janeiro - Brazil
Isn't this because the * is being interpreted as the multiplication operator, since ASM6 uses $ for the PC?


Top
 Profile  
 
PostPosted: Sat Mar 30, 2019 6:48 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
Thanks for help. Now I have to figure out how to programmatically distinguish the two in the ca65 code I'm converting without having to hand-edit both copies every time I change something.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Sat Mar 30, 2019 6:53 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11345
Location: Rio de Janeiro - Brazil
Well, you could use ca65's dollar_is_pc feature and start using $ all around...


Top
 Profile  
 
PostPosted: Sat Mar 30, 2019 7:09 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
A new question

Translating * to $ at the start or end of an expression or parenthesized subexpression fixes one layer of the above MCVE but changes the error message I get when I assemble the whole project. If I try to translate the ca65 idiom for an include guard to ASM6, it ends up not recognizing the macro at all, instead producing "Illegal instruction" but only for the first use of each such macro.

Source:
Code:
ifndef INCLUDE_GUARD
INCLUDE_GUARD = 1

macro sfxdef name, baseaddr, length, period, channel
name = <(($ - sfx_table) / 4)
dw baseaddr
db (channel<<2)|((period - 1)<<4)
db length
endm

endif

base $C000
sfx_table:
sfxdef SFX_foo, foo_data, 1, 1, 0
sfxdef SFX_bar, bar_data, 1, 1, 0

foo_data: db $89,$10
bar_data: db $84,$20

Listing:
Code:
                                ifndef INCLUDE_GUARD
                                INCLUDE_GUARD = 1
                                macro sfxdef name, baseaddr, length, period, channel
                                name = <(($ - sfx_table) / 4)
                                dw baseaddr
                                db (channel<<2)|((period - 1)<<4)
                                db length
                                endm
                                endif
                               
                                base $C000
0C000                           sfx_table:
0C000                           sfxdef SFX_foo, foo_data, 1, 1, 0
*** Illegal instruction.
0C000                           sfxdef SFX_bar, bar_data, 1, 1, 0
0C000                           SFX_bar = <(($ - sfx_table) / 4)
0C000 0A C0                     dw bar_data
0C002 00                        db (0<<2)|((1 - 1)<<4)
0C003 01                        db 1
0C004                           
0C004 89 10                     foo_data: db $89,$10
0C006 84 20                     bar_data: db $84,$20

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Mon Apr 01, 2019 1:50 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
The macro does different things (both wrong) on different invocations. The first time it says "Illegal instruction" and the second time it generates incorrect code. This makes me think I'm hitting an ASM6 bug. I decided to work around it in the translator by detecting whether a particular .ifndef is an include guard and changing it to a .if 1 if so.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Mon Apr 01, 2019 6:04 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 995
Location: cypress, texas
Maybe that "*** Illegal Instruction" is attempting to say that your dw baseaddr and db length are confusing for asm6 bc you haven't defined the values of baseaddr and length? :)


Top
 Profile  
 
PostPosted: Mon Apr 01, 2019 6:18 pm 
Offline
User avatar

Joined: Thu Apr 23, 2009 11:21 pm
Posts: 995
Location: cypress, texas
unregistered wrote:
Maybe that "*** Illegal Instruction" is attempting to say that your dw baseaddr and db length are confusing for asm6 bc you haven't defined the values of baseaddr and length? :)

Sorry tepples, I just noticed that you do define the values in your macro calls... maybe this error is created bc you db length before you call the macro? I think tokumaru taught me that the macro has to be defined before it can be called... maybe the same logic applies to whatever baseaddr and length are. :)


Top
 Profile  
 
PostPosted: Mon Apr 01, 2019 6:19 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 11345
Location: Rio de Janeiro - Brazil
Sounds like a bug indeed.


Top
 Profile  
 
PostPosted: Tue Apr 02, 2019 5:48 am 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
In any case, I've reduced another test case.

It seems like most actual bugs in ASM6 disappear once a forward reference is made no longer forward.


Attachments:
macromystery.asm [1.79 KiB]
Downloaded 33 times

_________________
Pin Eight | Twitter | GitHub | Patreon
Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 11:36 am 
Offline

Joined: Tue Apr 05, 2005 7:30 pm
Posts: 183
Are you trying to use include guards because multiple source files include the same stuff?

_________________
Be whatever the situation demands.


Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 1:16 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
doppelganger wrote:
Are you trying to use include guards because multiple source files include the same stuff?

Yes. Both the driver and the instrument/sequence data include one of the header files, and I can't guarantee which gets included first because ASM6 requires them to be included in output file order.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 2:37 pm 
Offline

Joined: Tue Apr 05, 2005 7:30 pm
Posts: 183
So both the driver and instrument/sequence data are assembled together in one unit?

_________________
Be whatever the situation demands.


Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 2:42 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 21385
Location: NE Indiana, USA (NTSC)
ASM6 normally assembles everything as one translation unit, so yes, driver and data are assembled together. It's possible though tricky to assemble something as multiple translation units with ASM6. If so, the separately assembled translation unit has to have entry points at fixed addresses, such as $8000, $8003, $8006, $8009, etc.

_________________
Pin Eight | Twitter | GitHub | Patreon


Top
 Profile  
 
PostPosted: Tue Apr 09, 2019 10:33 pm 
Offline

Joined: Tue Apr 05, 2005 7:30 pm
Posts: 183
The problem with the traditional .ifndef type include guard is that ASM6 is a multiple-pass assembler, and anything inside an .ifndef with a following .define inside it will get processed on the first pass, but not on the second. The ASM6 only states that .ifdef and .ifndef operate depending on whether the operand symbol is defined/not defined, without any mention as to whether the definition is supposed to occur prior to the directive or not, so it's implied then that forward references are included as part of .ifdef/.ifndef's operation.

The fallout, of course, is that when ASM6 gets to the second pass, the included file's contents end up not getting output at all.

What you obviously wanted was the first include, and ONLY the first include, to occur. After thinking it over, I may have an ASM6-specific workaround.

Let's say you have your driver in driver.asm and instruments/sequence data in song.asm, and they both include a file called foo.asm for whatever reason. Now, since ASM6 is assembling these as one translation unit, it follows that there must be a top-level source file for the driver and data to go into, assuming one of them isn't the top-level file (I don't know enough about your code to make too many assumptions here).

Now, you obviously don't want foo.asm included twice. My idea is this: define a symbol in the top-level file that precedes the driver and data files that matches whatever symbol you'd have used for foo.asm's include guard:

Code:
FOO_ASM = 1


Then, at the beginning of foo.asm, put this in:

Code:
.if FOO_ASM
FOO_ASM = 0
;insert contents of foo.asm here
.endif


And hopefully that should cause only the very first .include of foo.asm to have any effect on the unit's output, since FOO_ASM will be set to nonzero on the first include, but zero on any subsequent includes, until the next pass.

_________________
Be whatever the situation demands.


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 15 posts ] 

All times are UTC - 7 hours


Who is online

Users browsing this forum: No registered users and 2 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:  
Powered by phpBB® Forum Software © phpBB Group