After porting some example code for an upcoming release to the four main NES assemblers, I have a good idea of how they compare for implementing the same small demo programs in a custom file format. Overall, asm6 and ca65 are the clear winners. asm6 is to C as ca65 is to C++; asm6 is good for small to medium programs, and ca65 is good for medium to large, or where you want lots of flexibility and plenty of room to grow. ca65 mainly has more indirection, sort of like how a web page with stylesheets can display in many different ways with the same content. Now if I could only get - and + label support supported by the official ca65, then porting between the two would be a lot easier...
ca65
+ Plenty of room to grow.
+ Powerful macro support.
- Heavyweight; inconvenient for small programs.
- Doesn't support - and + labels, the biggest porting headache.
asm6
+ Simple, elegant model for generating files with things at various addresses.
+ Easy to set up files with minimum of specification.
- Can't switch segments as in ca65, so order of things in file must match output (as far as I can tell).
nesasm
- Inflexible about output format if you're changing addresses (e.g. if you want code assembled for $6000, it must go at a file offset that's a multiple of $2000, + $10).
- Poor error reporting, often doesn't report errors even though you likely made one.
- Very picky about syntax. Uses different format for several things.
wla-dx
+ Supports multiple game console CPUs, allowing same assembler for all development.
- Bizarre set of directives, lack of coherency in object model, poor documentation.
- Way too many bugs, obscure behaviors.
- Silly things required like .w on many 16-bit addresses.
- Arithmetic done in floating-point, with unexpected results.
- Doesn't warn about things that are very likely errors.
- Macro parameters are numeric, rather than text, limiting things you can do.
Awesome, this is the exact post I was looking for a few days ago. Thank you!
Have you contacted Ulrich (main author of ca65) about anoymous +/- label support ? He's a nice guy, maybe its even a planned feature - who knows.
It would duplicate the existing functionality of :+ and :-.
I just haven't taken the time to draft up a proposal and post. I have many things to suggest for ca65. And yes, ca65 has the functionality already, just a different syntax.
Well, I guess CC65 is the best one, I have to admit, although I don't use it. I use WLA, which while flawed, isn't as bas as you describe it.
There is awful bugs in the SPC700 version of WLA, but I didn't ever encounter any in the 6502 version. The error messages are usually informative enough. The segment system is somewhat convenient, and really flexible. For exmemple having a DPCM data that is aligned to $40 bytes and that is always located at $c000-$ffff is something you can pull off easily, without having to "cheat" and force it at $c000 like most assemblers would need you to do. A great feature is overwrite sections, I use it in my game to have non-CHR data in CHR-ROM easily (without the need to truncate my .chr file). I don't think any other assemblers support that. I also found a way to have the same piece of code in each bank (useful for mappers that do 32k switching), but it's a little tricky (you have to include multiple times the same file, and export labels, ask me if you're interested).
The documentation is just fine for me.
A big plus was that his author WAS active and open to bug report and sugettion, but isn't any longer the case, so this is now a handicap.
And surprisingly, you don't mention the biggest issue I have with WLA currently : NO SUPORT OF RELOCATABLE CODE. If you want to copy your code to RAM and execute it from here, it's going to be a headache in most assemblers, including WLA.
Also an issue is that the assembler assumes the target system is ROM. This is fine for (S)NESdev, but is really retarded for C64, FDS or SPC-700 development. In those systems you just load files in RAM and execute from here... Of course you reserve some maximum amount of RAM for the file, so all I did was make the file a "romsection" of the maximum reserved size... (I never did anything serious on those systems, but if I were to release them I'd just cut the size of the file manually after compilation... quite cheap but what else can you do ?)
I think CC65 fixed all the issues I mentioned (confirmation would be fine).
PS : How CC65 handles + and - is really a MAJOR problem. I use them all the time in my code, and I'd never find names for so many labels.
No comment on NESASM's macro support?
A penny for your thoughts on DASM? I've been using it for years, and I'm not sure how it stacks up against these other programs.
The only major drawback with it that I can see is it doesn't support anonymous labels. Then again, I haven't
died from not being able to use them, so it's nothing showstopping in my opinion.
Yeah, the only notable complaint I've had with CA65/CC65 is the anonymous label syntax. I do remember there being a discussion about on the CC65 email list many years ago, not sure what the conclusion was, but maybe there's some insight there if it's available for searching.
They look really ugly, so I tend do just make up garbage names (if it's not a very short branch), which is all anonymous labels are supposed to be good for anyways. I often use local labels (preceded with @), so I can often use the same generic yet more descriptive names anyways.
I used DASM before, I left it then because it didn't have incbin (it does now though), it seemed good but I was a newb at the time and wasn't using macros or any kind of fancy stuff yet. If it's got good macro support (I don't remember), it should be just fine.
x816 seemed like a pretty good assembler, I can't use anymore though without using DOSBox. I mostly used it for my SNES 2A03 emulator, so it has to be assembled in DOSBox if I rebuild it anymore, heheh. Nerdtracker 2 used it originally (later I changed Bananmos' old code to assemble in CA65)
Bregalad wrote:
I think CC65 fixed all the issues I mentioned (confirmation would be fine).
It's kind of funny, for relocatable code (that you want to move yourself) you actually use the .ORG command. And the end of it you use .reloc. So it's the rest of the stuff that's truly relocatable as far as the linker is concerned, heheh.
The most annoying bit about :+ and :- is that it confuses the hell out of emacs' assembly autoindent. Well, aside from the fact that they were broken in a few versions. Unfortunately, automatically rewriting the file to go from +/- to : and :+/:- isn't entirely trivial, since cases like
Code:
- cmp
beq +
bne ++
+bit
bvc -
+rts
get a bit tricky to convert. You can't get away with converting every - or + in the first column to a :, and prepending a : to +'s and -'s after branches, because the ca65 version of that would be
Code:
: cmp
beq :+
bne :++
:bit
bvc :--
:rts
A 2-pass approach could probably do it though. Alternatively, someone could hack in support, though I recall the sourcebase for it being a bit messy.
The heavyweight bit can be mitigated somewhat with a decent premade makefile and linker script.
Oh well, I guess we can get into discussing these unnamed labels. ca65's are workable, but no other assemblers use the convention, whereas the + and - convention is shared by many assemblers. The + and - convention also has the benefit of being fairly clear even without explanation, and somewhat consistent. There's a label named -, followed by a branch to -. Or a label named ++ and a branch before it to ++. Then you see multiple labels of the same name, and the first time you figure out which branch goes to which merely by proximity, and then see the way the + and - dictate direction.
Bregalad wrote:
There is awful bugs in the SPC700 version of WLA, but I didn't ever encounter any in the 6502 version. The error messages are usually informative enough. The segment system is somewhat convenient, and really flexible. For exmemple having a DPCM data that is aligned to $40 bytes and that is always located at $c000-$ffff is something you can pull off easily, without having to "cheat" and force it at $c000 like most assemblers would need you to do.
Under ca65 and ld65, I make a segment with alignment 64 bytes and in the $C000-$FFFF memory area. Then I put all samples in that segment and .align 64 before each .incbin.
Quote:
A great feature is overwrite sections, I use it in my game to have non-CHR data in CHR-ROM easily (without the need to truncate my .chr file).
A .png to .chr converter that can handle sizes less than full banks allows this easily. If I want 512 bytes of ROM in a given 4 KiB CHR bank reserved for data, I make that bank's tile sheet 128x112 pixels instead of 128x128.
Quote:
And surprisingly, you don't mention the biggest issue I have with WLA currently : NO SUPORT OF RELOCATABLE CODE. If you want to copy your code to RAM and execute it from here, it's going to be a headache in most assemblers, including WLA.
Something that ld65 handles easily with its load and run addresses. See nes.ini and ramcode.s of
Forbidden Four.
Quote:
I think CC65 fixed all the issues I mentioned (confirmation would be fine).
PS : How CC65 handles + and - is really a MAJOR problem. I use them all the time in my code, and I'd never find names for so many labels.
For the tightest of loops (such as waiting for vblank or sprite 0, or clearing memory), I occasionally use the
: labels with :+ and :-. But my current coding style, as seen in
Concentration Room, uses
.proc heavily. This allows labels such as "charloop" or "xloop" to be reused from subroutine to subroutine, allowing the labels themselves to reinforce the meaning of the code comments. And before that, back when I was working on
a project that I started in x816 and finished in ca65, I used
@ labels, which are valid only between normal labels. I've seen C compilers for various target platforms generate arbitrarily named @ labels as well.
Regarding unnamed labels:
I may be biased since I never used them but to me it feel more like a mess than anything. For small code with maybe one "-" or maximum two "--" it could be acceptable but the more you add, the mode it becomes messy. I think locals labels are the way to go (with CC65) since you can re-use their name and it can make the code clearer if used properly.
If you read the comments from the author of CC65, this is what he said exactly, word for word:
Code:
Unnamed labels may be accessed by using the colon plus several minus or plus characters as a label designator. Using the '-' characters will create a back reference (use the n'th label backwards), using '+' will create a forward reference (use the n'th label in forward direction). An example will help to understand this:
: lda (ptr1),y ; #1
cmp (ptr2),y
bne :+ ; -> #2
tax
beq :+++ ; -> #4
iny
bne :- ; -> #1
inc ptr1+1
inc ptr2+1
bne :- ; -> #1
: bcs :+ ; #2 -> #3
ldx #$FF
rts
: ldx #$01 ; #3
: rts ; #4
As you can see from the example, unnamed labels will make even short sections of code hard to understand, because you have to count labels to find branch targets (this is the reason why I for my part do prefer the "cheap" local labels). Nevertheless, unnamed labels are convenient in some situations, so it's your decision.
edit: fixed missing )
I very rarely use more than one + or -. That's where a named label becomes useful. But a single - is very common for short loops. I think if you've never used them you might imagine they would be hard to read, but that's because you're imagining complex situations where they wouldn't be the best solution. For a typical file of mine that's about 290 source lines, there were 29 total labels, 13 unnamed, with all but one used for a 2-5 instruction loop. Thus, there is no difficulty in following them. It's clear that it's a loop, and a comment describes its purpose better than a label could. By reserving labels for situations that aren't loops or simple branches over a few instructions (i.e. part of an if construct), the very fact that something has a label communicates information about its use. If named labels were used for everything, this extra expressiveness would be lost as well.
I'm a nesasm guy who has never used nameless labels, but I totally see them as useful. One case that immediately come to mind is extended branches.
@Blargg:
I didn't say that they're evil per se: I'm just biased because I never used them. If used and documented properly, it should have it place I guess. But I saw some example in the past with no documentation and abuse of them (up to 5 or 6 +) so you can see that it can get quite messy in the hands of, I would guess, beginners. So I would not add them in my "coding practices" for beginners.
Nesasm:
As for nesasm popularity, my only guess would be from a "mental image" of it. If you want a "nes assembler", when you see the name "nesasm" then it seems to be the right tool for the job for someone looking for the first time for an assembler, isn't it? That's how I feel about it. I could be wrong thought.
Quote:
As for nesasm popularity, my only guess would be from a "mental image" of it. If you want a "nes assembler", when you see the name "nesasm" then it seems to be the right tool for the job for someone looking for the first time for an assembler, isn't it? That's how I feel about it. I could be wrong thought.
Exactly, that's why I did back when I was a noob.
Quote:
I didn't say that they're evil per se: I'm just biased because I never used them. If used and documented properly, it should have it place I guess. But I saw some example in the past with no documentation and abuse of them (up to 5 or 6 +) so you can see that it can get quite messy in the hands of, I would guess, beginners. So I would not add them in my "coding practices" for beginners.
I rarely, if ever, use more than 2 + or -, however I use these all the time. You can't imagine how I has happy after quiting Nesasm to not have to find labels for
every little damn thing any longer.
Quote:
A .png to .chr converter that can handle sizes less than full banks allows this easily.
True, however I just like to have "full" CHR banks of a 2^n size in .chr files (as opposed to a small set of tiles).
Quote:
Something that ld65 handles easily with its load and run addresses.
This sounds really great. Same that other assemblers lacks this - especially considering that loading code from ROM to RAM is common.
For those of you talking about how good/bad anonymous labels are, let me share my labeling convention.
Code:
[game.asm]
game_init
jsr game_loadlevel
game_main
[...]
jsr system_wait_vblank
[...]
jmp game_main
game_loadlevel
[...] ;Initialize some variables
game_loadlevel_loop
[...] ;Read a pointer or something
game_loadlevel_loop_getchunk
[...] ;Copy a block of bytes to ram
bne game_loadlevel_loop_getchunk
[...] ;Process them somehow
bne game_loadlevel_loop
rts
[system.asm]
system_wait_vblank
[...] ;Check a variable that my NMI routine sets when vblank occurs
beq system_wait_vblank
[...] ;Reset the aforementioned variable
rts
This is how all of my labels look. They might be wordy, but at least you know exactly what each label is for, and I rarely ever have any problems with duplicate labels, or running out of names for labels.
Plus, if you ever start having trouble coming up with label names (too many labels), perhaps you need to revise your code's structure?
Verbose labels obscure the relevant information of what the code is doing. More noise, less signal = less readability = most cost to maintain. Being able to use local @symbols and +/- unnamed labels is what the assembler is for, to allow more concise expression of things, to do the tedious work so you don't have to (in this case, your eyes having to wade through increased noise).
There are several instances where I don't feel the need to name labels. Now that I think of it, this usually happens with labels used to simulate FOR, IF, and other commands present in high-level languages. You don't really need labels to identify these structures.
tokumaru wrote:
There are several instances where I don't feel the need to name labels. Now that I think of it, this usually happens with labels used to simulate FOR, IF, and other commands present in high-level languages. You don't really need labels to identify these structures.
That's one reason why I use NESHLA, avoiding creation of such labels.
Memblers wrote:
Yeah, the only notable complaint I've had with CA65/CC65 is the anonymous label syntax. I do remember there being a discussion about on the CC65 email list many years ago, not sure what the conclusion was, but maybe there's some insight there if it's available for searching. x816 seemed like a pretty good assembler, I can't use anymore though without using DOSBox. I mostly used it for my SNES 2A03 emulator, so it has to be assembled in DOSBox if I rebuild it anymore, heheh. Nerdtracker 2 used it originally (later I changed Bananmos' old code to assemble in CA65)
About the SNES side: CA65 also supports 65816. But CC65 (C compiler) is very limited/incomplete for that CPU. also, DA65 does not support the 65816 yet!
I tried using DOSBox on X816, Does not work, When assembling something with X816 in a DOSBox, It Stops Forever until exiting!
This is why I use CA65 and sometimes ASM6
Yeah, I'd heard the C compiler is mostly geared for 6502.
x816 should work with DOSBox because I've definitely used it (it took a long time assemble the NSF player, which was funny to watch). Maybe it uses a DOS 32-bit extender .exe that wasn't in your path when you ran it? I guess it would've said so, though.
ASM6 sorta reminds me of the x816 (for 6502) in some ways, I guess because it's simple and effective.
blargg wrote:
- Can't switch segments as in ca65, so order of things in file must match output (as far as I can tell).
Sorry about digging up such old thread, but as far as I'm concerned, I'd consider it as a plus of ASM6 - it makes debugging more straightforward and you can know where you made a mistake if assembly file closely resembles ROM in structure. And if you want modularity, you can always .include files that deal with different stuff.
For quick sample it may be but for managing bigger projects ca65 is a must. As for order, it doesn't matter much and it become easier to manage with experience
I too prefer to organize my source code sequentially. Even when using ca65 I don't switch segments all the time, I basically switch once to each bank, in order, and .include all the code/data that's supposed to be there. That doesn't mean that the OPTION of having the assembler do some organization on its own is a bad thing.
Unfortunately, the one time I really needed ca65 to let me shuffle segments around, it couldn't do what I wanted, which was to automatically right-align arbitrarily sized chunks of ROM. You have to either use constant sizes or stich the binaries afterwards.
I like how straightforward ASM6 is, and how versatile it is because it allows all kinds of expressions with all kinds of symbols, even in directives that affect the amount of generated code, such as IF, REPT and ORG. I still think ca65 is cool, but there are a lot of annoyances and limitations that arise from the fact it's single-pass and the mysterious ways in which macros are implemented.
Unfortunately, ASM6 lacks some things that are extremely useful in larger projects, such as any means to keep track of the memory banks each label belongs to. Another extremely annoying thing in ASM6 is how its anonymous labels break the scope of local labels, effectively making it impossible to use both in the same subroutine.
tokumaru wrote:
Another extremely annoying thing in ASM6 is how its anonymous labels break the scope of local labels, effectively making it impossible to use both in the same subroutine.
I always found this extremely strange and bizarre, to the point of seeing it as a bug.
Yeah, forcing users to choose between nameless and local labels doesn't seem like an intentional design choice, but who knows? I haven't seen anyone being bothered by this over the years besides me...
Memblers wrote:
I used DASM before, I left it then because it didn't have incbin (it does now though), it seemed good but I was a newb at the time and wasn't using macros or any kind of fancy stuff yet. If it's got good macro support (I don't remember), it should be just fine.
It depends on what you want out of the macros, but they're decent. Maybe not as big and magical and complex as ca65, but they're not terrible.