Page 1 of 2

[Alpha] QASM - A Simplified CA65 with Debugger Output

Posted: Sat May 28, 2011 9:11 am
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.

Posted: Sun May 29, 2011 5:29 am
by thefox
That is pretty cool. :)

FYI the iNES header in nestest1 is invalid.

Posted: Sun May 29, 2011 7:52 am
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.

Posted: Tue May 31, 2011 8:08 am
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.

Posted: Tue May 31, 2011 9:10 am
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]

Posted: Tue May 31, 2011 9:52 am
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.

Posted: Tue May 31, 2011 11:38 am
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.

Posted: Tue May 31, 2011 12:09 pm
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? :)

Posted: Tue May 31, 2011 12:28 pm
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.

Posted: Wed Jun 01, 2011 12:12 am
by Wave
Seems really good! will you support "Structs" sometime?

Posted: Wed Jun 01, 2011 2:36 am
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.

Posted: Wed Jun 01, 2011 3:22 am
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

Posted: Wed Jun 01, 2011 3:35 am
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.

Posted: Wed Jun 01, 2011 3:45 am
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


Posted: Wed Jun 01, 2011 3:59 am
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.