NESASM is considered to be a bad tool around here, but what are the technical reasons? The problems I know about are:
1. Addressing mode syntax () vs []. I don't know which is supposed to be standard now, couldn't the assembler just allow both?
2. Recently found line length problem
3. No temp labels like - and +? Not sure about this one, I don't use them.
4. Allows instructions like inc a (changed in my vers now)
Are there any instruction problems or things it fails to assemble? I am specifically looking at nesasm 2.51 avail at
http://bobrost.com/nes/resources.php
I remember hearing something about this:
LDA ($1B),Y
is compiled to be this:
LDA ($001B),Y
So I think you need to define it like:
LDA (<$1B),Y
(My syntax is likely wrong since I never use nesasm)
Al
i thought the zero page bug was only when absolute can be used as well. hence:
lda $00 assembles as lda $0000
and not for lda ($nn, X) or lda ($nn), Y. i don't remember though, haven't used nesasm since '04.
i also could never figure out how the banking system worked.
Yup looks like it assembles lda $00 to lda $0000. The zero page syntax is lda <$00 or lda <label. Hopefully should be easy to fix. Other than being annoying, is there a significant difference besides being one cycle slower and one byte larger? lda ($00),y works correctly so looks like its just not automatically checking for zero page when the option is there.
The simple banking with no config files is one of the reasons I started with NESASM.
It is just split into 8KB data blocks exactly how it will be laid out in the final .nes file. Doesn't matter what bank switching you are using, it only cares about file layout. So a 16KB NROM game would be:
Code:
.ines headers
.bank 0
.org $C000
(code)
.bank 1
.org $E000
(code)
.org $FFFA
(vectors)
.bank 2
(graphics)
i meant beyond 16k nrom. when i designed my assembler i borrowed from nesasm's style:
Code:
.rambank ; not assembled
.org $0000 ; CPU RAM
somevar: .db 0
somevar2: .db 0
.org $6000 ; SRAM
somevar3: .db 0
.org $6000 ; SRAM (mmc5 w/ 2+ banks or whatever)
somevar4: .db 0
; ...etc...
.prgbank 0 ; split 16K
.low
.org $8000
.high
.org $8000
.prgbank 1 ; full 16K
.org $8000
.prgbank 2 ; full 32k
.org $8000
.prgbank 3
.org $C000
.chrbank 0 ; and some chr
.org $0000
; ...
.chrbank 1
.org $0000
; ...
the header directives are exactly the same.
My current game is UNROM, 64KB prg. Divided into the NESASM 8KB bank size thats 8 banks. Divided into UNROM banks thats 3x 16KB swappable banks and 1x 16KB fixed banks. Header info is:
Code:
.bank 0 ;unrom bank 0
.org $8000
.bank 1
.org $A000
.bank 2 ;unrom bank 1
.org $8000
.bank 3
.org $A000
.bank 4 ;unrom bank 2
.org $8000
.bank 5
.org $A000
.bank 6 ;unrom fixed bank
.org $C000
.bank 7
.org $E000
.org $FFFA
vectors
If it had CHRROM that would just be added in a bank 8 at the end. Unlike your code, things in ram/sram don't use the .db because its not actually data in the .nes file. Instead you can reserve space with .rs or just set it manually.
So far these just seem like annoyances of you are used to another system, any big problems?
In my opinion, the fact that it forces you to divide everything in 8KB chunks is already bad enough. If you happen to write code that assembles to more than 8KB, will it automatically use the next 8KB bank?
I really like ASM6 approach to banking... it's much more flexible and you don't have to type much either. It has temporary labels too. I haven't found anything about ASM6 I don't like yet.
The whole nameless lables thing is terrible. I use a "-" for almost every loop. I seem to remember also not being able to do anything but 32k NROM games...
Quote:
I seem to remember also not being able to do anything but 32k NROM games...
You can use any mapper you'd like afaik. I've used MMC1 and MMC3. The problems for me started when I needed more than 8 banks (64k). I got a bunch of address conflicts when assembling. But you can get around this by assembling each 16k or 32k separately and then merge all the binaries.
bunnyboy wrote:
Yup looks like it assembles lda $00 to lda $0000. The zero page syntax is lda <$00 or lda <label. Hopefully should be easy to fix.
It makes sense that it does this. A normal constant is always 16 bits. When used in an 8-bit-only context, you get an error if the high 8 bits are non-zero. When used in a context where it can be 8 bits or 16 bits (like lda addr), it's 16 bits. To force 8 bits, you must use an 8-bit constant (one prefixed with '<'). If you "fix" this to automatically use zero-page when the upper 8 bits are clear, how does one force it to use absolute addressing (useful for self-modifying code)?
Considering its features, the proper way to use zero page would be with the .zp directive. Fix this so it uses zero-page addressing, then there's little reason to mess with the above behavior (using NESASM 2.51 compiled from the source):
Code:
.zp
var1: .ds 1
;var1 = next available zero-page byte
.org $10
var2: .ds 1
;var2 = $10
.code
.bank 0
.org $8000
lda var1 ; should use zero-page, but uses absolute
lda var2 ; ditto
Celius and tokumaru, for once can you participate in a thread without littering it with your opinion, rather than technical analysis (as the original poster requested)? (there are others guilty of this too, just not in this thread... yet)
I'd think that if you wanted 16 bit addresses for Self-modifying code, you should use a symbol to indicate that. Non self-modifying code using the zero page is far more common.
tokumaru,
My only problem with ASM6 is that there doesn't seem to be a way to force 8-bit addresses to be compiled as 16-bit (maybe I should tell loopy about this?), but other than that it is the perfect program. And my in-progress disassembly of SMB2j (info about which can be found at sm2.beneficii.net, smb2.beneficii.net, sm2dis.beneficii.net, smb2dis.beneficii.net, or beneficii.net/smb2) has the assembleable disassembly be assembleable for ASM6. I like it very much. Either you have a system too restrictive and not powerful enough, like NESASM, or a system that is way too complicated and makes you do all these complicated definition files like CC65 or WLA-DX.
In ASM6, I really like the way you can pad something to the end of, like, a bank. In fact, that was what got me sold on it. ^_^
I would like to propose a page on the wiki that talks about the pros and cons of each of the different NES assemblers.
Al
Back when I looked at 65816 assembly (for SNES), the doc I read had guidelines for assemblers in terms of syntax. As I recall, all constants less than 256 default to 8 bits, with constants between 256 and 65535 being 16 bits and constants larger than 65535 being 24 bits (the 65816 has 24-bit addressing modes). To force a quantity to be 8 bits, it is to be preceded with '<'. To force 16-bit quantities, one was supposed to use either '!' or '|', and to force 24-bit values you were to use '>'. For immediate operands, you used '<' for bits 0-7, '>' for bits 8-15, and '^' for bits 16-23. Of course, with the 65816 it's more important to have explicit control over addressing modes since the effective address of 8-bit and 16-bit addressing modes can change depending on the contents of the direct-page or data bank registers.
albailey wrote:
I would like to propose a page on the wiki that talks about the pros and cons of each of the different NES assemblers.
I would start one, but I cannot seem to log in to the wiki with Firefox or with Opera. See
my post in the wiki forum.
loopy wrote:
beneficii wrote:
My only problem with ASM6 is that there doesn't seem to be a way to force 8-bit addresses to be compiled as 16-bit (maybe I should tell loopy about this?)
You're right, it doesn't let you force the address size. It always uses small addresses when possible. Is there a standard way of forcing address size? I'd be happy to add it in.
(edit) sorry for threadjacking, I guess this doesn't have much to do with nesasm.
I don't think there really is a standard. Most commonly I see a directive like 16BIT attached to parentheses around the value in question. Perhaps it could be written as that or BIT16 or something?
Still, I really like how your PAD function allows you to cause an area of code/data to end at a certain address without worrying about where it begins. I wonder how your program implements that when you don't even know the starting address of the code in question. Does it automatically know that it doesn't know the starting address and so tries to find the length of the code in question from the starting label to the ending label?
Like you have:
ending = $e000
.pad ending - (finished - starting)
starting:
code
finished:
--------
So it knows that since it doesn't know the value of starting, it goes to calculate the length of the body of code from starting to finished?
EDIT: How about LONG notation?
beneficii wrote:
I don't think there really is a standard. Most commonly I see a directive like 16BIT attached to parentheses around the value in question. Perhaps it could be written as that or BIT16 or something?
Or do like C does:
Code:
.p02
LDA (char)$00 ; read from zero page
LDA (short)$00 ; read from absolute address
.p816
LDA (char)$00 ; read from direct page
LDA (short)$00 ; read from current data bank
LDA (long)$00 ; read from absolute address