Migrating from Devpac to rmac

#assembler #new user

Introduction

So, you have come to the conclusion that it is time to leave Devpac/GenST behind and use rmac instead. Congratulations!

You have probably already heard about how rmac is incredibly fast, because it was written by Landon “Dadhacker” Dwyer to be used on 1980s machines. The project has since passed thru multiple hands, and more processor architectures and platforms have been added.

Today, rmac supports

  • 6502
  • 68000
  • 68020
  • 68030
  • 68040
  • 68060
  • 68881
  • 68882
  • 56001
  • The Atari Jaguar GPU, DSP and Object Processor

It is also very mature, and in active development.

Resources

The official rmac website

http://rmac.is-slick.com/

The rmac manual

For when you’ve read this document and want to go more in-depth

http://rmac.is-slick.com/manual/rmac.html

Quickstart

To assemble your source file example.s into the Atari ST executable example.tos:

rmac -p -v example.s -o example.tos

(technically, the -v switch isn’t necessary, but it outputs interesting verbose information after assembly)

General stuff

Directives and periods

All rmac directives have have a “.” prefix. However, rmac will often (but not always) accept directives without the period. Prefix assembler directives with “.” when in doubt.

Example

; Devpac
dc.b 1,2,3
even
; rmac
.dc.b 1,2,3
.even

Labels

All rmac labels are suffixed with a colon (":"). This lets rmac have labels indented, which is not possible in Devpac.

Example

; Devpac
loop
 nop
 bra loop
; rmac
loop:
 nop
 bra loop

Assembler specific stuff

Forced errors

; Devpac
fail This code went BOINK!
; rmac
.error "This code went BOINK!""

Structs

; Devpac
rsreset
symbol1: rs.l 1
symbol2: rs.w 5
struct_size equ rscount
; rmac
.abs
symbol1: ds.l 1
symbol2: ds.w 5
struct_size .equ ^^abscount
.text

Conditional assembly

If not 0

; Devpac
one_nop_please equ 1
ifne one_nop_please
 nop
endc
; rmac
one_nop_please .equ 1
.if one_nop_please
 nop
.endif

If 0

; Devpac
dont_nop_here .equ 1
ifeq dont_nop_here
 nop
endc
; rmac
dont_nop_here .equ 1
.if dont_nop_here=0
 nop
.endif

As you probably already know, Devpac interprets “ifne” as “if not equal to zero”, and “ifeq” as “if equal to zero”. In rmac, things are a bit more sane.

If defined

; Devpac
ifd MY_DEFINE
 ; do some stuff
endc
; rmac
.if ^^defined MY_DEFINE
 ; do some stuff
.endif

If not defined

; Devpac
ifnd MY_DEFINE
 ; do some stuff
endc
; rmac
.if !(^^defined MY_DEFINE)
 ; do some stuff
.endif

String equality

; Devpac
ifc "string1", "string2"
 ; strings are identical
endc
ifnc "string1", "string2"
 ; strings are not identical
endc
; rmac
.if ^^streq "string1", "string2"
 ; strings are identical
.endif
.if !(^^streq "string1", "string2")
 ; strings are not identical
.endif

Macros

Macro with parameters

As long as the parameters aren’t named:

; Devpac
mWaitForTimer macro
 move.w #1,円d0
 jsr waitforvblwaiter
endm
; rmac
.macro mWaitForTimer
 move.w #1,円d0
 jsr waitforvblwaiter
.endm

Macro with named parameters

Simply can’t be done in Devpac. Replace with numbered parameters.

; rmac
.macro mWaitForTimer time, timezone, day
 move.w #\{time},d0
 move.w #\{timezone},d1
 move.w #\{day},d2
 jsr waitforvblwaiter
.endm
; Devpac
mWaitForTimer macro
 move.w #1,円d0
 move.w #2,円d1
 move.w #3,円d2
 jsr waitforvblwaiter
endm

Macro with parameters treated as hexadecimal in rmac

; rmac - will not work!
.macro PutValInD0
 move.l #$1,円d0
.endm
PutValInD0 1000

Because parameters are always converted to hex internally, this fails. The solution is to not re-interpret it as hex inside the macro, but to pass the parameter as hex, like this:

; rmac - works fine
.macro PutValInD0
 move.l #1,円d0
.endm
PutValInD0 1000ドル

Macro with label(s) inside the macro

Devpac wants macro labels to end in \@, rmac needs it to be \~:

; Devpac
mAbsd0 macro
 tst.l d0
 bpl .notneeded\@
 neg.l d0
 .notneeded\@
endm
; rmac
.macro mAbsd0
 tst.l d0
 bpl .notneeded\~
 neg.l d0
 .notneeded\~
.endm

Sections

In rmac, the target CPU is set using what is basically a section. In Devpac, it’s done using command-line parameters or the GUI.

Because rmac supports so many different CPUs and architectures, we need to start our source code with that LOOKS like a section (".68000" or “.6502”), but it’s actually a directive for what code to generate, see below

;Devpac
section code
 nop
section data
 dc.b 13,10
section bss
 ds.l 4
;rmac
.68000 ; Sets target CPU to 68000, not used in Devpac
.text
 nop
.data
 dc.b 13,10
.bss
 ds.l 4

Rept/Endr

rmac can have nested .rept/.endr directives, Devpac can not. There’s really no workaround, except for a special case where what is being repeated is a single dc.x value - in which case we could use a dcb.x (which would also work in rmac, btw):

;Devpac
rept 4
 dcb.b 1,7 ; byte value 1, repeated 7 times
 dcb.b 5,7 ; byte value 5, repeated 7 times
endr
;rmac
.rept 4
 .rept 7
 .dc.b 1
 .endr
 .rept 7
 .dc.b 5
 .endr
.endr

Other

Order of evaluations in rmac

In rmac, expressions are evaluated from left to right and without respect to operator precedence. Two workarounds are available:

Workaround A

Use parentheses to force the order of evaluation you want

Workaround B

Use the -4 commandline parameter to force C-style order of evaluation.