* * * * * A Motorola 6809 assembler—there are many like it, but this is mine I think it's time I start talking about some of the software I write, and I might as well start with my latest project that I've been having way too much fun writing, a 6809 assembler written in C [1]. Yes, I could use an existing 6809 assembler, but most of the ones availble as source seem to be based off one written in 1993 by L. C. Benschop. And the code quality there is … of its time … which I think is the most charitable thing I can say about it. Here's the code to convert text to a decimal number: -----[ C ]----- short scandecimal() { char c; short t=0; c=*srcptr++; while(isdigit(c)) { t=t*10+c-'0'; c=*srcptr++; } srcptr--; return t; } -----[ END OF LINE ]----- Lots of globals, lots of “magic” numbers (at least they're described in comments), and vwl mprd variable names. It's not a pleasant code base to work in. Besides, it's something I've been wanting to do since college. So why not? So I have a standard two-pass assembler with a few features I haven't seen in other 6809 assemblers. And that's what I'll be describing here. The first feature is small, but decidedly nice—the ability to have underscores (“_”) in numberic literals. It's more useful for binary literals, such as %10_00_01_11 or %000_01001_0_100_0010 but it can be used for decimal, octal or hexadecimal numbers as well. Another simple feature is the ability to generate a dependency list for make. Since I support the inclusion of multiple assembly files, it makes sense to support this feature as well. I'm not trying to make an assembler that works on the 6809 system (I think it's way too small a system for that), but an assembler that makes it nice to write code for a 6809 system. I also have local labels that work similarly to NASM (Netwide Assembler) [2]. As an example: -----[ Assembly ]----- clear_bytes clra .loop sta ,x+ decb bne .loop rts clear_words stb ,-s clra clrb .loop std ,x++ dec ,s bne .loop rts -----[ END OF LINE ]----- Internally, the assembler will merge the local labels with the previous non- local label, and thus, we get the labels clear_bytes, clear_bytes.loop, clear_words and clear_words.loop. I find it makes for cleaner code. What is easier to understand, this? -----[ Assembly ]----- ;******************************************************************** ; Music Synthesizer ;Entry: $3FF0 Freq delay count ; $3FF1 Envelope table address ; $3FF3 Envelope delay count ; $3FF5 Volume, 1 to 255 ; NOTE: from _TRS_80 Color Computer Assembly Lanauge Programming_, ; page 252 ;******************************************************************** org $3F00 mussyn lda $FF01 ; select sound out anda #$F7 ; reset MUX bit sta $FF01 lda $FF03 ; select sound out anda #$F7 ; reset MUX bit sta $FF03 lda $FF23 ; get PIA ora #8 ; set 6-bit sound enable sta $FF23 ldu #$3FF0 ; point to block ldx 1,u ; get envelope address stx envptr ; save in envptr ldx 3,u ; get envelope delay mus005 lda [envptr] ; get value beq mus090 ; if 0, done ldb 5,u ; get volume mul ; adjust volume anda #$FC ; reset RS-232-C (?) sta $FF20 ; set on ldb ,u ; get frequency delay count mus010 leax -1,x ; decrement envelope count bne mus020 ; go if not 0 ldy envptr ; increment evelope ptr leay 1,y sty envptr ldx 3,u ; get envrolope delay mus020 decb ; decrement frequency count bne mus010 ; go if not 0 lda [envptr] ; DUMMY brn *+2 ; DUMMY ldb 5,u ; DUMMY mul ; DUMMY clr $FF20 ; set off ldb ,u ; get frequency delay mus030 leax -1,x ; decrement envelope count bne mus040 ; go if not 0 ldy envptr ; increment envelope ptr leay 1,y sty envptr ldx 3,u ; get envelope delay mus040 decb ; decrement frequency count bne mus030 ; go if not 0 bra mus005 ; keep on playing mus090 rts envptr fdb 0 end mussyn -----[ END OF LINE ]----- Or this? -----[ Assembly ]----- ;******************************************************************** ; Music Synthesizer ;Entry: $3FF0 Freq delay count ; $3FF1 Envelope table address ; $3FF3 Envelope delay count ; $3FF5 Volume, 1 to 255 ; NOTE: from _TRS_80 Color Computer Assembly Lanauge Programming_, ; page 252 ;******************************************************************** org $3F00 mussyn lda $FF01 ; select sound out anda #$F7 ; reset MUX bit sta $FF01 lda $FF03 ; select sound out anda #$F7 ; reset MUX bit sta $FF03 lda $FF23 ; get PIA ora #8 ; set 6-bit sound enable sta $FF23 ldu #$3FF0 ; point to block ldx 1,u ; get envelope address stx .envptr ; save in envptr ldx 3,u ; get envelope delay .next_byte lda [.envptr] ; get value beq .exit ; if 0, done ldb 5,u ; get volume mul ; adjust volume anda #$FC ; reset RS-232-C (?) sta $FF20 ; set on ldb ,u ; get frequency delay count .sound_on leax -1,x ; decrement envelope count bne .check_freq_on ; go if not 0 ldy .envptr ; increment evelope ptr leay 1,y sty .envptr ldx 3,u ; get envrolope delay .check_freq_on decb ; decrement frequency count bne .sound_on ; go if not 0 lda [.envptr] ; DUMMY brn *+2 ; DUMMY ldb 5,u ; DUMMY mul ; DUMMY clr $FF20 ; set off ldb ,u ; get frequency delay .sound_off leax -1,x ; decrement envelope count bne .check_freq_off ; go if not 0 ldy .envptr ; increment envelope ptr leay 1,y sty .envptr ldx 3,u ; get envelope delay .check_freq_off decb ; decrement frequency count bne .sound_off ; go if not 0 bra .next_byte ; keep on playing .exit rts .envptr fdb 0 end mussyn -----[ END OF LINE ]----- It helps that I allow 63 characters for a label, which is way more than any 6809 assembler I've ever used. The last feature I have are warnings. Given the following code: -----[ Assembly ]----- .start lda <