It is currently Sun Oct 22, 2017 1:15 am

All times are UTC - 7 hours





Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Jan 18, 2017 5:23 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
In this post, tokumaru wrote:
Garth wrote:
one feature I liked was that it allowed macros to have varying numbers of input parameters.

You can create macros like this in ca65 too, I do it all the time.

How does this work? I thought each macro's declaration specified the maximum number of arguments that it takes. Do you just declare a macro with, say, 32 arguments and say "too bad" to a process that wants to generate more?

For example: By default, the .word command asserts that each argument's value is in the range 0 to 65535. Let's say I want to make a counterpart that instead asserts that each value is in the range -32768 to 32767. The force_range option only switches between no range checking at all and unsigned range checking, not signed range checking. The issue about lack of signed range checking cites a mailing list conversation started by rainwarrior, in which Marc Rintsch recommended that one create a macro that performs the signed range checking.

So here's what I came up with (in small text because it's so wide):

Code:
.macro signedword r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31,r32
.local r1value
  .ifblank r1
    .exitmacro
  .else
    r1value = r1
    .assert -32768 <= r1value && r1value <= 32767, error, "Range error (value not in [-32768..32767])"
    .word r1value & $FFFF
    signedword r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15,r16,r17,r18,r19,r20,r21,r22,r23,r24,r25,r26,r27,r28,r29,r30,r31,r32
  .endif
.endmacro


But calling this with more than 32 arguments produces Error: Too many macro parameters. Though source code line length conventions make it unlikely that I'll use more than a dozen or so arguments, a preprocessor for data tables might use that many.

For comparison, C has variadic functions and variadic macros, and Python has def function(arg1, arg2, *restofargs).

If nobody can figure out a better way to make a ca65 macro that takes an arbitrary number of arguments, I plan to report this on cc65's issue tracker on GitHub.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 5:25 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
Garth wrote:
Does it allow making macros that don't require a given number of input parameters? (just to confirm.)

You have to name all the parameters the macro can possibly take, but you're not required to supply them all when calling the macro. Iterating over a variable number of parameters requires recursion, and to avoid writing the lda #0 multiple times you might need an auxiliary macro (or some sort of flag indicating that the first iteration has already happened).

Here's a simple implementation using an auxiliary macro:
Code:
.macro CLR_FLAG var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15
   .ifnblank var0
      lda #0
      CLR_FLAG2 var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15
   .endif
.endmacro

.macro CLR_FLAG2 var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15
   .ifnblank var0
      sta var0
      CLR_FLAG2 var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15
   .endif
.endmacro


And here's it with a flag:
Code:
.macro CLR_FLAG var0, var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, flag
   .ifnblank var0
      .ifblank flag
         lda #0
      .endif
      sta var0
      CLR_FLAG var1, var2, var3, var4, var5, var6, var7, var8, var9, var10, var11, var12, var13, var14, var15, , 1
   .endif
.endmacro


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 5:27 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
Calling your macro with 17 arguments will produce Error: Too many macro parameters.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 5:45 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
Well, there is a limit... I often don't bother writing extremely robust macros that can deal with every little error because they end up looking pretty bloated. I normally only write macros for myself, so I prefer not to waste much time making them foolproof.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 7:16 pm 
Offline
Formerly ~J-@D!~
User avatar

Joined: Sun Mar 12, 2006 12:36 am
Posts: 445
Location: Rive nord de Montréal
Movax12 has a technique that involve putting your arguments insides curly braces, and parsing that to extract your arguments (the curly braces around the parameters make exactly one argument for the macro). But, I have a feeling this is not what you're after.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 9:27 pm 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
What actual (i.e. non-anecdotal) need is there for this in ca65, or any assembler for that matter? Demonstrate this to me. My initial opinion as of this writing is that this is for the most part pointless. And while I obviously have utmost respect for Garth (esp. given his stature on the 6502.org forum), he has what I've concluded to e a very unhealthy fixation on macros (almost all responses from him involve macro advocacy).

NOTE: I'm talking about ca65, not cc65 where in C you can have variable arguments (ex. void foo(int blah, ...) then access said bits using va_{start,arg,copy,end}() functions -- these are at run-time, which I feel is important to note here).


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 9:37 pm 
Offline

Joined: Sun Sep 19, 2004 11:12 pm
Posts: 19115
Location: NE Indiana, USA (NTSC)
It was for a lookup table containing signed 16-bit starting velocities for particular projectiles in The Curse of Possum Hollow.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 10:24 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
I use macros to structure my programs better. You can obviously code in assembly the barebones way, using little more than labels and a couple of directives (org, for example), but assembly is so devoid of rules that sometimes it's hard to manage all the variables, the interaction between modules and so on. Even if you come up with strategies to handle this sort of thing, repeating the patterns manually all the time can be very error prone. This is where macros come in, you can automate all that functionality so it doesn't clutter your source code and you'll know it'll work consistently every time you use it.

I made moderate use of macros back when I used ASM6, but after switching to ca65 I couldn't help taking advantage of some of that macro goodness. I coded a set of assembler extensions to help me with declaring variables, encapsulating functions, aligning code/data to the end of the addressing space (for simulating a fixed bank in a mapper with 32KB switching), and now my code looks pretty clean, as it's composed almost exclusively by actual game code, and all the ROM and RAM organization is handled through simple macro calls.

Lots of my tasks need to work with a variable amount of parameters. For example, my functions are all isolated from the global scope, so that I can easily reuse labels or include the same function over and over (due to the need of having it present in several banks) without the risk of running into "label already defined" errors. But since I might need to address something inside a function's scope from the outside, I have to "export" labels to the global scope. To do that, I simply created a macro called "promote" (didn't want to create confusion with the existing .export and .global directives) that takes the names of labels from inside the scope and creates aliases for them in the global scope, prefixed by the function's name to leave no doubts as to where that label is.

That's just one example, I probably have 10 or so macros handling variable amounts of parameters.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 10:31 pm 
Offline

Joined: Thu Aug 28, 2008 1:17 am
Posts: 591
koitsu wrote:
what I've concluded to e a very unhealthy fixation on macros (almost all responses from him involve macro advocacy).

I'd say your lack of consistent work in assembly has gained you an ignorant perception of macros. Anyone who's coded in enough assembly over the years, especially on something like the 65x, usually comes to the realization that macros are the next level. If you have the years of experience, but haven't reached this level.. then I don't know what to say. But to call someone else's preference for macros unhealthy, seems pretty ignorant to me. Especially someone who probably has spent waaayy more time in 65x assembly than you.

_________________
__________________________
http://pcedev.wordpress.com


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 10:58 pm 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
I think koitsu had his fair share of ASM coding in the past, but doesn't do much of it these days. I assume tools back then weren't as versatile as they are today, and from the little I've heard (feel free to correct me if I'm wrong, I wasn't around back then) he made mostly hacks, not programs he architectured from the ground up.

If my assumptions are correct, I don't find his opinions on these topics surprising. Hacking is... well, for lack of a better term, a hacky activity. You have to work with the space you can get, dancing around someone else's code, without necessarily appreciating all the aspects of the architecture that was envisioned by the original creators. Sure it will make more sense to define variables with EQU than reserving bytes from a base address. Macros will definitely seem silly if you're working on top of binary code or disassembled code that don't use any.

Maybe if he started developing something from the ground up he'd appreciate the help that all these newer tools provide. Macros and assembler directives are definitely a step up from straight up ASM code, maybe not as much as straight up ASM is to coding directly in hex, but still. It boosts your productivity and the robustness of your code, once you take the time to study how everything works. If you simply try to use that stuff just for the heck of it without realizing WHY you need it, then it definitely isn't gonna work out.

Note that I'm not looking down on the work of hackers, they can do really amazing and creative stuff, often under sub-optimal conditions. I doubt I'd make a good hacker myself. I'm just saying that it's a different craft, even though most areas of knowledge overlap with those of game developers.


Top
 Profile  
 
PostPosted: Wed Jan 18, 2017 11:54 pm 
Offline
User avatar

Joined: Sun Jan 22, 2012 12:03 pm
Posts: 5730
Location: Canada
Several x86 assemblers from the '80s called themselves "macro assemblers" (example: MASM) to deliberately highlight their macro features.

I can't say what 6502 assemblers were like in the past, but the idea of macros in assembly is several decades old.

Whether or not they're being overused in NESdev might be more of a philosophical/ideological question though. ;P (I've got little opinion on this, except it's sometimes difficult to understand shared code when its in someone's personally constructed macro language. This problem is a thousand times worse in web development frameworks though.)


Top
 Profile  
 
PostPosted: Thu Jan 19, 2017 12:44 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
As for my background: my personal (User:Koitsu) nesdev wiki page provides all of that. I did a lot more 65xxx assembly in my youth and teenage years (~1987-1993) than I do now, but I've "authored" enough (most was on the Apple IIGS) -- but I certainly did not author any of the demo bits or utility portions I did using a plethora of macros (table generation using BASIC, most certainly! But not macros). Macros were quite available (and capable!) in Merlin 16 and ORCA/M in my prime. But throughout my life, I didn't provide help on forums or public mediums that involved -- paraphrasing -- a kind of "constant focus" on macros. I've always preferred people understand how to do something (in the native language they're programming in) so that they then can then make macros for themselves, etc.. Same can be said of subroutines, frameworks, or anything else (if you want a good example of how and where it gets out of control, see this thread and this thread -- I put way too many hours into trying to decipher a gigantic mess of such on the SNES/65816 for Espozo. It's irrefutable).

Sorry, this sounds really judgemental of Garth. It's not quite what I intended (honest!). It's just a very common go-to I see in his replies, and it irks me because I feel very strongly that a person should know how something works. I don't like handing people "magic solutions" (particularly code); this kind of belief is horribly prevalent in today's programming world (see: Ruby). I'm cool with macros, as long as someone takes the time to explain to the person to which they're being recommended *how* it works. I know a **lot** of programmers, for sake of example, who don't like using other people's code or things -- they'd rather understand how something works and write the function/routine/macro themselves. Matter of opinion. It just irks me is all.

That said, he certainly has more 65xx experience than I do -- but then again, I'd guess most of the senior commonplace folks on this forum do. Whether or not that's relevant is up to the reader.

All said: I'm still waiting for a demonstration of why variable-length macro arguments are helpful/useful. This isn't a challenge for debate, it's a more of a "show me how this would be useful, because I just don't see it; educate me!" thing. I can see it in a higher level language, but not for native 65xxx. Just because I'll be 40 this month doesn't mean I'm not interested in being shown new things and their usefulness (though fully admit I am quite the reluctant soul ;-) ).


Top
 Profile  
 
PostPosted: Thu Jan 19, 2017 1:37 am 
Offline
User avatar

Joined: Sat Feb 12, 2005 9:43 pm
Posts: 10066
Location: Rio de Janeiro - Brazil
koitsu wrote:
I'm still waiting for a demonstration of why variable-length macro arguments are helpful/useful.

I don't know if this will help convince you (you might very well just say "you wouldn't need macros in the first place if everything was global"), but here's an example of how I could code a (very pointless) subroutine using my macro extensions:
Code:
   ;"Add" subroutine
   .block Add

   ;local variables
   .memory System_Scratchpad
      Value: .res 1
   .endmemory

WithoutCarry:

   clc

WithCarry:

   adc Value
   rts

   ;make some labels visible from the outside
   .promote Value, WithoutCarry, WithCarry ;this processes a variable number of arguments

   .endblock

And then I can use the function it like this:
Code:
   lda #$40
   sta Add_Value ;might have to be sta z:Add_Value to force ZP addressing if this comes before the variable is declared
   lda #$10
   jsr Add_WithoutCarry

It may look stupid for such a trivial example, but when you consider the amount of labels a full-sized game has, it makes sense to encapsulate anything that doesn't need to be global, so you don't have to work with long labels inside the subroutines themselves or worry about labels being redefined. My macros also help with multiple inclusions of the same subroutine, since they don't put in the global space labels that have already been put there previously (e.g. that .promote command won't do anything if this same routine is included again in another bank). The entry point defaults to the top of the block (a global label named "Add" will point to the top of the block), but you can select an alternate entry point like this:
Code:
   .block Whatever, EnterHere

Loop:

   txa
   
EnterHere: ;the global label "Whatever" will point here

   ldx #$10
   dex
   bne Loop

   rts

   .endblock

Like I said, it may look dumb in this context, but macros can greatly increase robustness and productivity when you get the assembler to help you organize and manage things, instead of doing everything by hand.


Top
 Profile  
 
PostPosted: Thu Jan 19, 2017 2:04 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
To be fair, I took the time to go through Garth's posts to see if I was overreacting (because I certainly do tend to overreact). Of his 19 posts, there are great/direct answers, but there are some where "strange focuses" (and in many cases, focuses on macros) show up almost immediately. Just hear me out first, don't reply until you read past the itemised list:

* viewtopic.php?p=184968#p184968 -- doesn't mention macros directly, but said link quickly starts going over use of some magical StackOps.asm (what assembler is this?!) solution regarding "virtual stacks" (a thing I have never heard of in my life). The important point: the OP asked a pretty damn simple and direct question (see quoted material)
* viewtopic.php?p=184962#p184962 -- almost instantly starts going over use of macros for handling if/else in 6502, compounded by (again) an assembler we aren't familiar with around here (note: maybe we (the royal nesdev) should look into whatever assembler this is!)
* viewtopic.php?f=10&t=15199 -- not a post by Garth himself, but is actually a thread *about macros*. So, hey, this one's highly on-point, and sounds like some stuff was going on in PMs too (awesome, honest!)
* viewtopic.php?p=183751#p183751 -- more macro advocacy (gotta read it)
* viewtopic.php?p=183712#p183712 -- first post ever, instantly about macros (subject is about handling multiple loops)

The posts of his I *didn't* link tend to go over actual code or theories more clearly, e.g. I have this problem and how do I solve it in 6502, with good answers. So am I overreacting, given 19 posts where only 4 or 5 have a macro-centric focus? I am absolutely overreacting, and for for that I apologise.

I'm not back-patting when I say this, but: I think on some level it shows that I do read almost all the posts here on the forum and correlate certain "themes" or "focuses" with particular individuals (yeah Tepples I'm looking at you buddy ;-) Haha). When I start to see a kind of "advocacy pattern" that I feel doesn't necessarily help teach someone something, but is instead just "providing magic answers/solutions", it irks/concerns me. I jumped the gun on this for sure though.

Purely in contrast, I'll point to this thread where DRW asked a really good question and got a) good reference material including formula (which happens to be easily implemented in 6502 given /2 and *8 aspects), b) a clever answer from psychopathicteen (I'd forgotten about masking used in this particular manner), and c) a great answer from tokumaru about manipulating attribute table bytes this way being time consuming so instead just stick the AT in RAM and copy it to the actual AT when/as needed. I think that's probably one of my favourite posts in the past few months.

So, to Garth: sorry. I didn't mean to "call you out" or make you feel unwelcome. If I did, I truly deeply apologise. It's just that when I read your posts, I now expect macro advocacy, and had forgotten that the majority of what you've brought here isn't just that.

I also hope that tomaitheous can understand where I'm coming from in my concerns.


Top
 Profile  
 
PostPosted: Thu Jan 19, 2017 2:22 am 
Offline
User avatar

Joined: Sun Sep 19, 2004 9:28 pm
Posts: 3192
Location: Mountain View, CA, USA
@tokumaru -- Thanks for the example. I'm now on my 4th time reading it through.

Ignoring our disagreement about globals vs. locals (I fully agree with you about label concerns and re-use!), I find what you've posted to be daunting (read: scary). I cannot imagine trying to debug this if something went awry with either an address the linker generated, or with "memory management" (the fact that the .res bytes pertain only to that individual .block/.endblock). I believe I understand how and why this works (it almost looks like a kind of half-ass implementation of a C++ class?) and I think it's neat. But man I would never want to see a listing file of anything you've assembled using that. ;-)

What I *don't* understand is how variable argument lengths for macros relates to your example. The only case I can work out is .promote being relevant to that subject? There is no .block/.endblock in ca65 (that I know of), so these too are macros, but they don't appear to have argument lists (re: jsr Add_WithoutCarry is not a macro call, it's a subroutine)? Iinstead it looks like {blockname}_{labelname} is the syntax you use... so is the point that you want to be able to do something like nested blocks, ex. end result of jsr Add_WithoutCarry_OtherBlock_LabelName_Block3_MoreStuff_HowLong_CanThisGet, or does it pertain to .promote specifically? If the latter: I now understand (and sympathise) with your concern/want. If not the latter: need more input!

Apologies if my question isn't clear enough. Ask and I can probably reword it.


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

All times are UTC - 7 hours


Who is online

Users browsing this forum: Bing [Bot] and 7 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