APCS

Opinions on various assemblers

 

These are my personal opinions of various RISC OS assemblers that are available. I have noted the versions tested, if a comment has been addressed in a later version, do let me know!

 

This is the test program:

r0 RN  0

        AREA |main|, CODE, READONLY
        ENTRY

        ADR    r0, title
        SWI    &02         ; OS_Write0

        SWI    &10         ; OS_GetEnv
        SWI    &02         ; OS_Write0
        SWI    &03         ; OS_NewLine
        SWI    &11         ; OS_Exit


title
        =      "This program was called with:", 10, 13, "   ", 0
        ALIGN

        END
When run, the program outputs a short title, followed by the command line that started the program. For example:
TaskWindow Server v0.01

*cat
Dir. IDEFS::Willow.$.Coding.Projects.Assembler.apcstest Option 00 (Off) 
CSD  IDEFS::Willow.$.Coding.Projects.Assembler.apcstest
Lib. IDEFS::Buffy.$.library
URD  Unset
o            D/      s            D/     test         WR/
*test -this -is a -test
This program was called with:
   test -this -is a -test
*

 

AAsm

(v2.00, Acorn, expensive)

This is a simple assembler that doesn't support areas, and it outputs an Absolute file (there is no linker stage). It is rather like a stripped-down objasm with built-in linker, a throw-back to the 'days of old' prior to the DDE and C code (once upon a time, Acorn suggested that major applications would be written in pure assembler; then, they also once suggested that major applications would be implemented as relocatable modules - duh!).
Removing the AREA and ENTRY lines will allow the test file to compile correctly.
The output is 60 bytes long, as there is no AOF header.

 

ARMmaker

(v0.52, Steven Haslam, freely downloadable)

I cannot get this to output AOF files. I define ENTRY start and AREA main, CODE, READONLY at the start of the program, and ARMmaker replies "Entry point "start" not defined".
I put this down to my unfamiliarity with the program. Asking ARMmaker to output an absolute file worked, creating a 60 byte program (identical to AAsm's output).

The code used for ARMmaker was:

r0 BINDREG R0

        OUTPUT ABSOLUTE

start
        ADR    r0, title
        SWI    "OS_Write0"

        SWI    "OS_GetEnv"
        SWI    "OS_Write0"
        SWI    "OS_NewLine"
        SWI    "OS_Exit"


title
        DCS    "This program was called with:\n\r   "
        DCB    0
        ALIGN
Like Nick Roberts' ASM, this assembler can convert SWI names for you. Sadly, it does not use the 'RN' register assignment convention, but it's a minor point. In it's favour, it does understand C-style characters ("\n\r").

A while back (in 2001) I asked Steven if he had the sources to this assembler as I think it would have been a useful 'learning' tool to accompany this website, and I was planning to add in FP instructions and the newer (ARM 6++) instructions. Unfortunately the sources appear to have been lost to time...

 

AS

(v1.21, Niklas Röjemo, download from src.doc.ac.uk's HENSA mirror)

AS was quite happy with the original objasm input.

As a bonus, AS can also cope with SWI name conversions.
AS is not a 'better' version of objasm as it lacks the macro facilities and the more exotic features of objasm. However, on the plus side it is supplied with source so you can add your own custom bits, or look to see how an assembler works.

 

ASM

(v4.10, Nick Roberts, download from Nick's website)

I use objasm because I have used it in the past, and because I have a basic knowledge of it. However, objasm has a main competitor... Actually, that's not really true. objasm kicks ass, but this, ASM, whips out a General Electrics Minigun and lays waste to swathes of ass. Well, it's an analogy I figured Glenn would like, so sue me. :-)

One of the more complex (and powerful) of the free assemblers, ASM supports IF...THEN, macros, different processors, 32 bit code, includes, labels, maths in instructions (such as DCFE 12345.6 + (1 << 12)), built-in assembly-time mathematical functions (sin, cos, tan, acs, etc etc), floating point code, NOPs, macros, full conditional assembly, structures (!!!), limited-scope labels, pragmas, and re-definable constants.

All in all, this may rate as the best assembler. ASM leaves objasm standing... Then again, it leaves the others standing too!

ASM failed to recognise the RN directive. This isn't a big issue, as the standard (r#) and APCS names are understood by the assembler.
It allows name assignment, and can be used to write quite readable code. The documentation provides us with:

        result = 0
        lhs = result + 1
        rhs = lhs + 2
        
                EXPORT  Long_Add        ; Make the function external
Long_Add:       STMFD   sp!,{lhs ,lhs+1,link}
                ADDS    lhs,lhs,rhs
                ADCS    lhs+1,lhs+1,rhs+1
     ...etc...
The example has been snipped for space reasons. While objasm allows variables to be named, I am not sure it is that flexible. Note the final ADCS instruction.

ASM requires that labels are suffixed with a colon and, like ARMmaker, it wasn't happy with the string syntax so the more traditional EQUS/EQUB has been used.
END was not required, and as you can see ASM is capable of converting SWI names on the fly.
I am describing the differences in ASM so verbosely not because I want to pick on ASM, but because I feel that Nick's minor changes (such as the colon) and the SWI conversion all make for much tidier looking code. I also like the EQUx directives, I use them in BASIC and feel happier with them than with DCx or stuff like '='.

The code used for ASM was:

        AREA main, CODE, READONLY
        ENTRY start

start:
        ADR    r0, title
        SWI    "OS_Write0"

        SWI    "OS_GetEnv"
        SWI    "OS_Write0"
        SWI    "OS_NewLine"
        SWI    "OS_Exit"


title:
        EQUS   "This program was called with:\n\r   "
        EQUB   0
        ALIGN

As always, a descriptive manual is supplied in Impression or text format.
Download ASM

ASM is much looser in it's input than is objasm - it coped with:

AREA main, CODE, READONLY
ENTRY start
start:
ADR r0,title
SWI"OS_Write0"
SWI"OS_GetEnv"
SWI"OS_Write0"
SWI"OS_NewLine"
SWI"OS_Exit"
title:
EQUS"This program was called with:\n\r   "
EQUB 0
ALIGN

There's a quibble! While an attempt to use MRS/MSR under ARM2 or ARM3 causes a warning under objasm; ASM treats this as an error. This means that 'clever' code using MRS/MSR and understanding it to be a 'NOP' on ARM2 and ARM3 won't be compilable (at least, not without resorting to DCD to insert the instruction directly).
Well, it's not a big quibble so far as quibbles go.

For a bigger quibble: ASM doesn't appear to understand ADRL, though what kind of assembler doesn't understand long-ADR? I probably need to RTFM...

 

objasm

(v2.00, Acorn, expensive)

This was used as the benchmark (being Acorn's own), so was obviously happy with the input!
A capable assembler, this was supplied with the Acorn Desktop assembler package. A later and more capable (ie, later processors/facilities) version is now provided with Acorn's C++ development suite.
Being a macro assembler, it has very powerful options for devising macros, although the syntax is a bit difficult for a newbie.
Here's an example from the 32bit development release:

; ****************************************************
; ***  SCPSR - Set and clear bits in PSR from the  ***
; ***  masks $set, $clr, using register $regtmp    ***
; ****************************************************
        MACRO
$label  SCPSR   $set, $clr, $regtmp, $cond, $oldpsr
        LCLS    srcreg
        [ "$oldpsr"=""
srcreg  SETS    "$regtmp"
        |
srcreg  SETS    "$oldpsr"
        ]
$label  mymrs   $cond, $srcreg, CPSR
        [ (($set) :AND: ($clr)) <> 0
        ! 1, "Attempt to simultaneously set and clear a bit in SCPSR"
        ]
CPU32_set PSRto32 $set
CPU32_clr PSRto32 $clr
 [ (CPU32_set :AND: &F0000000) <> 0 :LAND: (CPU32_set :AND: &F0) <> 0
        ORR$cond $regtmp, $srcreg, #CPU32_set :AND: &F0000000
        ORR$cond $regtmp, $regtmp, #CPU32_set :AND: &0FFFFFFF
srcreg  SETS "$regtmp"
 |
 [ CPU32_set <> 0
        ORR$cond $regtmp, $srcreg, #CPU32_set
srcreg  SETS "$regtmp"
 ]
 ]
 [ (CPU32_clr :AND: &F0000000) <> 0 :LAND: (CPU32_clr :AND: &F0) <> 0
        BIC$cond $regtmp, $srcreg, #CPU32_clr :AND: &F0000000
        BIC$cond $regtmp, $regtmp, #CPU32_clr :AND: &0FFFFFFF
srcreg  SETS "$regtmp"
 |
 [ CPU32_clr <> 0
        BIC$cond $regtmp, $srcreg, #CPU32_clr
srcreg  SETS "$regtmp"
 ]
 ]
        somemsr  $cond, CPSR,$srcreg, CPU32_set:OR:CPU32_clr
        MEND
(see what I mean?)

Problems? Well, although objasm is fast and can do all sorts of macros (I now use a number of 'handy' macros like PullRet "R1-R3" to output LDMFD R13!, {R1-R3, PC} etc...) - the main problem, for me, is that cannot perform SWI conversions, and there is the fairly inflexible formatting style.
Firstly, the purists might say that you should use a header file for the SWIs. I would say that either method should be allowed. Certainly, for smaller chunks of code I don't fancy having to include a SWI definition file simply because the assembler is too stupid to do it's own conversions.
Secondly, labels must begin a line. Commands (either to the assembler, or code) must be after some white-space. While this can lead to 'nicer' looking code, I think there should be some flexibility in how the code is processed. The 'C' language is nice in this respect. There are rules and styles for how to write 'nice' C programs, but you can feel free to ignore them all and write something that looks like perl (or random line noise ... there's a difference?). This, though, is a much lesser point.

 

objasm

(v3.27, Castle Ltd, less expensive than before (it comes with the C/C++ tools))

It supports more instructions, it can apparently output Thumb instructions, along with code for little-endian or big-endian memory (!) - but it still can't convert SWI names, and it still reports Unknown opcode if you begin a line with an instruction and no proceeding white-space...

What has been done, which is useful, is it now knows the standard register names - both the APCS types (a1-a4, v1-v6, ip, fp, sp, lr, pc; lower case only) and the 'normal' types (r0-r15, upper or lower case).

 

TLA

(v0.1f, G.F.A.@ Lancaster, download from sunsite's archives)

TLA is a very peculiar assembler. It appears to have a central core which is machine independent along with various opcodes for the ARM processor.
It is obscure (in my opinion), and I wasn't able to get an ADR style instruction assembled. To be precise, the OS_Write0 example (in the documentation) crashed with the same error (branch through zero at <some address in ROM>).
But, for interests sake, I have recoded the program to work with TLA, though I would recommend a different assembler - something that is closer to the DDE style. The code used for TLA was:

        .ENTRY start
        .CODEAREA
        .PROC main

start
        SWI    OS_WriteS
        .ASCII "This program was called with:"
        SWI    OS_NewLine
        SWI    OS_WriteS
        .ASCII "   "

        SWI    OS_GetEnv
        SWI    OS_Write0
        SWI    OS_NewLine
        SWI    OS_Exit

        .END

 

BASIC

For those expecting a résumé of BASIC, please remember we are looking at APCS assemblers! Using Darren Salt's ExtBASasm patch, normal BASIC can actually be convinced to output APCS-linkable code. Yes, honestly!
I am not going to describe this as it is unlikely to be very useful for a beginner to writing APCS code - Nick Roberts' ASM is much easier to get to grips with. The ability to export APCS style code from BASIC might be more useful for people with large projects written in BASIC and assembler, which is in the process of being converted to C... Having said that, the pitfalls are many (with BASIC, you could trash R0-R12 and BASIC wouldn't care - try linking code that does such a thing with a C program and see how far you get!); so we will simply skip over this, and leave you with a thought...
If you have a need to make linkable assembler from BASIC, it is possible. If you don't have a need, don't waste time thinking about it. There are easier ways!

 

And so...

For those with the Acorn DDE, you might find objasm is your best choice - certainly you get a full (verbose) user guide describing practically every nuance of objasm in sickening detail. You too can understand the macro facilities! :-)

Otherwise? It'll be ASM. No question.

 

I would like to hear from people who have experienced one or more assemblers - especially those using both a RISC OS assembler and one on another platform (such as the ARM Ltd ADS). Please, write to me and let me know what you think! (yes, I will want to include your comments here, you may be anonymous if you would prefer)

 

 


Return to assembler index
Copyright © 2004 Richard Murray