6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 6:02 pm

All times are UTC




Post new topic Reply to topic  [ 3 posts ] 
Author Message
PostPosted: Tue Aug 10, 2010 9:08 pm 
Offline

Joined: Tue Aug 10, 2010 2:26 pm
Posts: 1
For the past few years, I've been tinkering with a custom version of the ACME assembler, mainly for my own use. I've been thinking about releasing it, but I thought I'd see if there was any interest before I put any more effort into documentation. Obviously, I'd also provide the source code, since ACME was released under the GNU GPL.

The project started as a modification of ACME 0.86, because I wanted to add support for token pasting in macros (ala C pre-processor macros). Over time, I back-ported many of the features from the later versions of ACME, including anonymous labels, floating-point math, and functions.

Eventually, I ported the whole thing to Java and added more features:
  • Full support for Unicode source files, including characters outside of the BMP. Encoding may be specified in the first two lines of the file (via coding=...) or via BOM. Obviously, plain ASCII source files are still supported.
  • Unicode data pseudo-opcodes: !utf8, !utf16le, !utf16be
  • Floating-point data pseudo-opcodes: !fp16, !fp32, !fp64 (IEEE 754), and !fp40 (8-bit BASIC).
  • Iteration over tokens or character sequences: !irp, !irpc
  • Labels can hold string values (allowing strings to be passed to macros), with support for string slicing and concatenation.
  • Can assemble more than 64KB of code via logical banks, each with independent output files.
  • Full 24-bit program counter for 65816 code.
  • Full compatibility with source written for the original C version of ACME

Perhaps the most sophistated feature is the macro processing engine. It supports regular expression matching for arguments, allowing the very syntax of the assembler itself to be augmented. For example, I was able to implement the entire Z80 instruction set as an importable macro package; and it doesn't require any mangling of the Z80 source code, other than adapting it to ACME's syntax for labels.

To illustrate, here is an example of a source file using the Z80 macro package (using a snippet from http://www.andreadrian.de/oldcpu/Z80_number_cruncher.html. I did not write this snippet of Z80 code):

Code:
        !source "Z80.a"    ; import Z80 macro package
        *= $8000
        Z80_ON             ; enable Z80 instruction set
        LD      HL,01213H
        LD      DE,0F000H
        EXX
        LD      HL,01011H
        LD      DE,0
        EXX
        CALL    ADD32
        HALT
ADD32
        ADD     HL,DE   ; 16-BIT ADD OF HL AND DE
        EXX
        ADC     HL,DE   ; 16-BIT ADD OF HL AND DE WITH CARRY
        EXX
        RET


For those familiar with ACME, notice that macro calls no longer require the '+' symbol, and processor mnemonics can be overloaded by macros. For source compatibility, using '+' to call macros is still supported, however.

Here is another example of using the macro processor to alter the behavior of the assembler, this time to enforce MOS assembler "pedantic mode" for the bit-shift mnemonics:

Code:
    ; alter all bit-shift mnemonics
    !irp @mnemo,{asl,lsr,rol,ror} {
        ; error if no argument supplied
        !macro @mnemo* {
            !error "@mnemo requires operand"
        }
       
        ; accept 'a' or 'A' as an argument (accumulator mode)
        !macro @mnemo* @?i="a" {
            &@mnemo
        }
       
        ; all other arguments
        !macro @mnemo* # {
            !outzone &@mnemo @#
        }
    }

    asl          ; this will now cause an error
    asl a        ; but this will work
    asl $1000,x  ; and this will still work, too

Another nifty feature (in my opinion anyway) are a set of !rtxx psuedo-opcodes which use the closest available RTS instruction to return, or else will emit a branch followed by an RTS instruction if one cannot be found. The assembler will even do a "pseudo pass" to find forward-referenced RTS instructions. For example, in the following snippet, the assembler would use the final RTS instruction if it was within branching range:

Code:
    lda LIVES
    !rtne          ; return if not zero
    ; ... more code here
    rts

; if final RTS in range, equivalent to:

    lda LIVES
    bne +
    ; ... more code here
+   rts

; otherwise, equivalent to:

    lda LIVES
    beq +
    rts
+
    ; ... more code here
    rts

One !rtxx pseudo-op can even use an RTS instruction generated by another. Thus, the assembler will attempt to generate the shortest possible code. Also, given the choice between two RTS instructions within range, where one would cause the branch to cross a page-boundary, the assembler will select the other.

Well, I hope I didn't ramble too much -- I didn't even list all the new features :). What do you think? Is there room for a Java-based ACME-compatible cross-assembler, or am I just muddying the waters?

Thanks,

Anthony Tolle


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Tue Aug 10, 2010 9:17 pm 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Quote:
use the closest available RTS instruction to return, or else will emit a branch followed by an RTS instruction if one cannot be found

That's a nice feature!


Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: Mon Aug 16, 2010 4:58 am 
Offline

Joined: Sun Nov 08, 2009 1:56 am
Posts: 411
Location: Minnesota
Most people here already have their own favorite assemblers. It's unlikely they'll change. My own assembler doesn't seem to have made any converts, although it offers some of the features yours does (regular expressions, macros powerful enough to implement the Z80 instruction set, labels that can hold strings, etc - no Unicode support, though, and floating point only via some demo macros).

Still, I'd say go for it. You might interest some visitors here who haven't yet chosen an assembler. More importantly the process of writing documentation, while admittedly tedious, at least for me made me occasionally stop and ask myself "Does it really do that?" (which prompts a new test program) or "Why does that annoying restriction exist?" (which sometimes prompts a way to get rid of it). So the exercise was useful for its own sake, making the assembler better than it might otherwise have been.

Plus, now I have something I can read when I forget some little detail of how things work :-)


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 3 posts ] 

All times are UTC


Who is online

Users browsing this forum: No registered users and 21 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: