I'm making assembly code for 6502 that I compile for ASM6.
Is there a program to write this so it is easy to read and is there a proposed structure?
I'm just making it in .txt file, I don't know what kind of structure I should have for when it will become too big... what tools I could use.
There are several text editors for which you can use 6502 assembly formatting templates.
I use Notepad++ myself, but there's lots of others (Scintilla, etc.)
The usual filename extension is either .s or .asm I think, but what you want to name the files is really up to you.
thanks!!
is there an example of a full game I'd like to see how to structure a document?
Code Structure -
You will probably make level specific files. Let's say you make a game with 15 mazes. Each maze will be stored ina separate file. Then 1 big file with shared code, possibly more if it gets too big.
Then music files might be 3 files.
-music engine
-music data
-sound effects data
Then each unique nametable will be a separate file (compressed)...
-title screen
-options screen
-in game screens
-victory screen / end credits
Then, if you are using asm6 or nesasm, a master file that links all these together, with include and incbin statements.
If you are using ca65, then the linker / config file will link them all together.
I also like a separate header file to keep all my variable definitions, and define statements.
Edit - and a file with your CHR ROM (graphics).
I think everyone structures their programs and files differently, since assembly gives us much more freedom than any other kind of programming.
I personally like to have a master file that includes everything else at the correct places. First, I have a handful of declaration files for the different modules of my programs (input, audio, graphics, gameplay, etc.) which contain all the constants, variables and macros for each module. Then comes the NES header, which I build using macros from the "header" module. Next in the main file are the actual PRG and CHR banks, with all the .ORGs, .BASEs, . SEGMENTs and whatever else is necessary to structure a valid ROM file, and inside the banks I include all the all functions, tables, tiles, etc. where I want them to be. Even the interrupt vectors are treated as a regular data table.
You do have to be careful when the same code/data must appear multiple times in the ROM (such as when you're simulating a hardwired PRG bank in a mapper that doesn't have one) to avoid "duplicate label" errors. What I do in ASM6 is declare the global label of a function/table/whatever like DrawSprites = * instead of DrawSprites:, and below that I only use temporary labels. In ca65 I scope everything and only create global symbols for things that aren't defined yet. Either way you have to be extra careful to include the thing at the exact same address every time (you can write code to detect screw ups, though).
I guess this is it... I try to mimic some of the features of high level languages and I have strict consistent ways of declaring everything, in order to make things more organized and easier to debug.
You have to find the structure you're most comfortable working with, and you'll probably be changing little things from protect to project as you progressively see what works and what doesn't for you. I'm still tweaking my "formula" every now and then.
Edit: Oh, and for writing code I use Notepad++ with 6502 syntax highlighting. To build the project I have a batch file I can double click that builds the .nes file and automatically opens it in an emulator.
I use ca65 instead of ASM6, but there are several NES-related repositories in
my GitHub account.
I use .asm and Reluached64 as it gives me auto-completion, and quick browsing of sections, labels etc. It has a few built in assembler formats, one of them might be compatible enough with ASM6.
Since it only offers auto complete for a single file, I tend to make giant monolithic asm files, but sections and code folding make it not so bad.
Being a Java programmer I found using this IDE works best for me -
http://www.wudsn.com/index.php/ideIt has asm6 support.
Also it compiles the code and starts your chosen NES emulator with your program in 1 step.
Maybe I'm just too lazy
thanks to all for the reply, really helps me!!
If someone has a simple example of using more than one file with ASM6, I'd be curious to see it
Generally, for a project that has multiple files (which should be anything larger than a "hello world" program), you'll run the assembler on each file separately to generate the object files. Then, you combine those object files together using your linker program. Typically the linker will have the configuration for how to lay everything out in memory. Each separately assembled file has code but no real physical location. The linker determines where in the output file everything should go, and then ties everything together.
If you have any files that are included directly in other assembly sources, you should
not run the assembler on those files separately. This is because using the "include" directive will directly insert the contents into the source at assemble time, so they do not need to be linked together.
Usage will probably look something like this:
Code:
myassembler main.asm -o main.o
myassembler title.asm -o title.o
mylinker -o mygame.nes main.o title.o
I don't know ASM6 specifics (I do SNES with ca65), but I imagine the same concepts apply there as well.
ASM6 doesn't work like that. You can only use multiple files using .include, as a way to make the source code more organized than a huge ASM file with everything. Ultimately, it's as if ASM6 concatenated all the included files to create a huge ASM file before assembling.
Ah, so it's how my project used to be structured. Be careful on the order of your includes, as you will likely need to introduce symbols before they are used, and try to avoid creating circular dependencies too (file A needs something from file B needs something from file A).
In terms of text editors, I recommend Visual Studio Code or
atom. I haven't been able to figure out how to make syntax highlighting for VS Code, but it's
already there for Atom. Both of them have an integrated terminal which is very useful.
With code structure, the way my most recent project has things structured is single-module and three files: nes.s is hardware defines and functions, game.s is software defines and functions, main.s is the NES "frontend" (NMI and reset vectors and stuff) and it's what is actually given to the assembler.
HihiDanni wrote:
Be careful on the order of your includes, as you will likely need to introduce symbols before they are used
asm6 is a however-many pass assembler, so it doesn't have problems with forward-references.
nicklausw wrote:
HihiDanni wrote:
Be careful on the order of your includes, as you will likely need to introduce symbols before they are used
asm6 is a however-many pass assembler, so it doesn't have problems with forward-references.
I think the only difference this makes in ca65 is with allocations on the zero-page.
If they aren't defined
above where they are used, the assembler has to assume 16-bit addressing and you lose the zero-page advantage. Basically just keep your ZP .res stuff at the top of the file and you're fine.
Otherwise, I don't believe it makes a difference. It's a "one-pass" assemble, but it
does fill in forward references (unlike C, which requires forward declarations to even compile).
rainwarrior wrote:
It's a "one-pass" assemble, but it does fill in forward references (unlike C, which requires forward declarations to even compile).
Yet another bullet point on the list of reasons why C is not a good language. When even assemblers do a better job at this...
HihiDanni wrote:
rainwarrior wrote:
It's a "one-pass" assemble, but it does fill in forward references (unlike C, which requires forward declarations to even compile).
Yet another bullet point on the list of reasons why C is not a good language. When even assemblers do a better job at this...
The 6502 assembler has the advantage of being able to assume that it's a 16-bit value. In C it could be
literally anything and it's impossible to make an assumption like that. The assembler isn't doing a
better job with the single pass, it's merely doing a
possible job. (Possible only because it has no such thing as type safety... or types at all.)
Anyways, to bring it back to the question of how to organize files... at least in ca65, in general keep your RAM / ZP reservations at the top of the source file. If your file becomes large enough it's useful to split things up by function. You can put the music code and music data in their own file, for example. This separation can help keep things more manageable-- the music source file now doesn't have to worry about anything that's in the other files, it only has its own concerns.
It's fine to stick everything in one file until later when the program grows large enough, or even keep just a single file assembly through the whole project. Both approaches are currently practical for an NES game.
I've generally concluded that old 65xx assemblers don't really need linkers, therefore no multiple modules. asm6 and bass are extremely fast on their own, both to the point where the multi module advantage of "reassemble some, not all" isn't worth much. If anything, it's just an annoyance to manage all the tons of files with exports and all that.
I haven't had to work on slow hardware in a while, though, so I'm probably lacking sympathy.
Using explicit import and export protects you from typoing a variable name as another module's private variable name.
And I work on an Atom laptop from 2010, though I may soon replace it with a Celeron (
Intel's new name for Atom) laptop from 2017 if I can find a good 11.6" that takes more than 2 GB of RAM and has Linux drivers.
EDIT (45 minutes later): And doesn't beg the user to wipe the hard drive if an application other than a web browser is installed.
tepples wrote:
Using explicit import and export protects you from typoing a variable name as another module's private variable name.
Yeah, but as I said, that advantage doesn't mean much when you have little reason to have multiple modules in the first place.
Quote:
And I work on an Atom laptop from 2010, though I may soon replace it with a Celeron (
Intel's new name for Atom) laptop from 2017 if I can find a good 11.6" that takes more than 2 GB of RAM and has Linux drivers.
I bought a Lenovo Ideapad with the intention of installing Linux on it. Guess what, the BIOS locks you into windows and the drivers are proprietary. So there's one place to avoid looking.
I don't find assembly or linking speeds are an issue at all, even at this point where I have a few megabytes worth of code, it finishes fast enough (~1 second) that I haven't even bothered to consider using makefiles/etc. to only rebuild what's changed.
I just like the structure of having code with different concerns isolated in different files. If well organized, it helps me find where things are, and also avoids namespace pollution issues like the one tepples just mentioned (especially important with macros that can have less obvious effects if accidentally used outside their intended area). I'm also just used to that structure from years of C++ development where it's a necessity.
The only case where I've seen NES assembly take a significant amount of time was when Movax12 made a
high level disassembly of Super Mario Bros using a set of complicated macros that added "high level" features to ca65. I can't remember exactly how long it took but it was probably well over a minute. (Edit: tried it just now, takes 2 full minutes for me, and apparently it even has a modified ca65.exe that is supposedly faster than regular with this macro set.)
rainwarrior wrote:
I just like the structure of having code with different concerns isolated in different files. If well organized, it helps me find where things are, and also avoids namespace pollution issues like the one tepples just mentioned (especially important with macros that can have less obvious effects if accidentally used outside their intended area). I'm also just used to that structure from years of C++ development where it's a necessity.
Bass lets you give as many source files as you want to the command line allowing for a feel of multiple files, and has namespaces in the form of scopes. I think it handles your issues pretty well, but of course I'm not asking you to switch your megabytes of code to a different assembler.
rainwarrior wrote:
and apparently it even has a modified ca65.exe that is supposedly faster than regular with this macro set.)
IIRC, it's not modified, just recompiled with Visual C++ with optimizations. It may have been that the regular ca65—at the time—was compiled without optimizations (with gcc, not that it matters).
cc65's optimization level just
recently went from
-O to
-O3, so the modified binaries probably are just compiler-optimized.
I remember when I was making SNES stuff on my P133, having gone from a BASIC hack Assembler on the C64. The speed blew me away. The SNES assembler would tell me how long it would take to assemble the code. It was typically 0.00165... seconds. C64 games take about 10seconds on a 4mhz 286 with PDS, one of my ex leads told the time he walked to IT and demanded a new PC with a faster processor ( 386 SX 33 ) as 30 seconds to assemble was just unacceptable. These days I figure the assembler spends more time doing the
printf "I'm done here is your file" than it actually does parsing the code. So I can't see that anybody would have be having issues with assembling speed, even if you are on an atom... hell even if you are on a Raspberry Pi 0.
I would also think that making a
master.asm file that is basically
Code:
*=$00
.dsection zp
*=$8000
; init NES here
; fire up title screen
;NMI here
.include "file1.asm"
.include "file2.asm"
.include "file3.asm"
would assembler faster than doing a module and link. As the assembler will be able to pull most of the things it needs into cache in one shot and pass through it. Allowing it to hit the HDD once to get the files and then being all in RAM from then on. Were as if you Assemble, it will pull in the files it wants. Spit out a file, load the linker, load in more files and the files you just made, do more work to figure out were stuff is, make final file. To me this has a far larger dependence on File I/O and would be slower overall.
Quote:
It's fine to stick everything in one file until later when the program grows large enough, or even keep just a single file assembly through the whole project. Both approaches are currently practical for an NES game.
This pleases me. I was worried I might hit issues later but I'll leave everything in one file for now (might even leave it like that for the whole project - haha).