[Alpha] QASM - A Simplified CA65 with Debugger Output

Discuss technical or other issues relating to programming the Nintendo Entertainment System, Famicom, or compatible systems.

Moderator: Moderators

User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

[Alpha] QASM - A Simplified CA65 with Debugger Output

Post by qbradq »

Edited 06/30/2011 - New version 0.07 introduces a character encoding feature that allows you to specify text as an ASCII string and have the assembler translate it to your custom encoding for you. Also numerous bug fixes, tweaks to the macro system and additional features to incbin and data structures added.

Well I finally got bored enough to write that assembler I've been talking about. Right now it is feature complete in terms of have-to-have features for an assembler. I will be testing the assembler by porting my current project over to it.

The motivation behind this is that I absolutely love TheFox's debugging extensions for Nintendulator, but there are several things I do not like about CA65. So I set out to write an assembler that is to my liking, but also outputs debugging information that is compatible with CA65. I have now accomplished this.

The assembler is written with Python 2.5, so it should be compatible with just about any system under the sun.

Quick points:

1. Traditional one-shot assembler, no intermediate object format
2. Uses segments like CA65, but they are specified within the code in a simpler format
3. Nested segment entry
4. Real lexical scopes that can be nested and referenced before they are defined
5. Anonymous scopes
6. Basic set of directives
7. Generates memory usage map
8. Generates debugging output that is compatible with TheFox's debugging extensions for Nintendulator, yay!
9. Supports macros and complex expressions
10. Supports conditional assembly
11. Now supports data structures

Links:
Project Page
Documentation
Direct Download

If any of you give this a try (or just read the documentation) let me know what you think. I am very interested in what directives others would be interested in being implemented. I have only implemented those directives which I use in my own code, but that may not cover everyone.
Last edited by qbradq on Thu Jun 30, 2011 9:39 am, edited 5 times in total.
User avatar
thefox
Posts: 3139
Joined: Mon Jan 03, 2005 10:36 am
Location: Tampere, Finland
Contact:

Post by thefox »

That is pretty cool. :)

FYI the iNES header in nestest1 is invalid.
Download STREEMERZ for NES from fauxgame.com! — Some other stuff I've done: fo.aspekt.fi
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Why is the header invalid? It's the same one I use on all of my projects. I'd like to know how to fix it :D

Edit: Well I figured something out. I did not have the SRAM bit of the header set.
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

I have finished macro support and updated to version 0.02. The first post has been updated to reflect this and the download link has also been updated.

The documentation was also updated for macros. Here is the macro documentation.
lidnariq
Posts: 10677
Joined: Sun Apr 13, 2008 11:12 am
Location: Seattle

Post by lidnariq »

qbradq wrote:Why is the header invalid? It's the same one I use on all of my projects. I'd like to know how to fix it :D
ines.s says "mapper 1", but the .word value there is $1200 and should be $0010

Code: Select all

$ file nestest1.nes
nestest1.nes: iNES1 ROM, Mapper 0x10, 16x16k PRG, 16x8k CHR, [Horz], [PC10]
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Ah, right you are. I was using that .word instead of two .bytes just to test out the .word directive. I'll fix that now.
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Wow, I implemented complex expressions over my lunch break :D That was a huge surprise to me. I thought it would take days. I guess having done it once before helped out a lot.

So this thing is ready to use for a largish program. I am going to start porting my project over to it now, and hopefully work out any bugs in the process. If anyone else finds this useful, has a bug report or feature request let me know.
User avatar
oRBIT2002
Posts: 643
Joined: Sun Mar 19, 2006 3:06 am
Location: Gothenburg/Sweden

Post by oRBIT2002 »

I'm pretty impressed by people writing their own assemblers. To me it seems like a coders nightmare with all parsing and stuff. :)
Do you have any education that helped you with this project? Or is there a "Programming an assembler for dummies" book somewhere? :)
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

The one article that helped me the most was Let's Build a Compiler, by Jack Crenshaw. This is a very old article but it steps you through the process of writing a left-right parser in detail.

Converting this to an Assembler is straight forward once you understand how a two-pass assembler works.

On the first pass you are really just counting bytes and assigning labels their values. If you run into a label that has not yet been defined you assume it's value to be 0.

On the second pass you now know where all of those labels point to and you can do your real code generation. If you find an undefined label on this pass then you know it is an error.
Wave
Posts: 110
Joined: Mon Nov 16, 2009 5:59 am

Post by Wave »

Seems really good! will you support "Structs" sometime?
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Sure, I can implement structs. Can you give me an example of the syntax? This is a feature I've never used in an assembler.
Wave
Posts: 110
Joined: Mon Nov 16, 2009 5:59 am

Post by Wave »

Something like:

Code: Select all

.equ NUM_PLAYERS 4
.struct struct_players
    .res x NUM_PLAYERS
    .res y NUM_PLAYERS
    .res life NUM_PLAYERS
.endstruct

.res players struct_players

//Load player 3 x position
ldx #2
lda players.x, x
User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Oh cool! So you specify the data structure like in C, but then the assembler lays out the memory as a table like a traditional assembly programmer would.

I love this idea! This will make my project a heck of a lot easier to code. Right now I am doing things like this:

Code: Select all

.res obj_posx_lo MAX_OBJ
.res obj_posx_hi MAX_OBJ

lda obj_posx_lo,x
Thanks for the idea! I'll get cracking on it.
Wave
Posts: 110
Joined: Mon Nov 16, 2009 5:59 am

Post by Wave »

You're welcome :)
Also I miss the .define .ifdef .ifndef .else labels (I readed there's a .define label but for segments) for conditional code.

Like:

Code: Select all

.define pal

.ifdef pal
    .equ velocity 3
.endif
.ifdef ntsc 
    .equ velocity 2
.endif

.ifdef debug
    .out "Debug release"
.else
    .out "NonDebug release"
.endif

User avatar
qbradq
Posts: 952
Joined: Wed Oct 15, 2008 11:50 am

Post by qbradq »

Wow, I completely forgot about conditional assembly. I'll change .define to .memory (it's more descriptive anyway) and add in the conditional assembly bits.

I need to restructure the assembler for all of these "skip this section if" conditions (like skip macro definitions if we are not in the macro pass). My current "for line in lines" approach is a little naive for all of this.

Thanks again for all of the inspiration! You keep reminding me of things I forgot I needed, or never thought of before.
Post Reply