Skip to main content

Merlin Assembler Syntax Reference

Target Systems: Apple II series (II+, IIe, IIc, IIgs) CPU Support: 6502, 65C02, 65802, 65816 Versions Covered: Merlin 8, Merlin 16, Merlin Pro Purpose: Complete syntax reference for xasm++ Merlin compatibility


Table of Contents


Overview

Merlin is a professional macro assembler for the 6502 family, originally developed by Glen Bredon for Apple II computers. It provides comprehensive support for:

  • 6502 - Standard 6502 instruction set
  • 65C02 - CMOS enhancements (via XC directive)
  • 65802/65816 - 16-bit extensions (Merlin Pro)
  • Macros - Parameter substitution and expansion
  • Conditional Assembly - DO/ELSE/FIN blocks
  • Relocatable Code - REL/ENT/EXT support
  • 50+ Pseudo-Opcodes - Extensive directive set

Key Philosophy: Simple, powerful, and compatible with Apple II development conventions.


Version Differences

Merlin 8 (Original)

Features:

  • 6502 instruction set only
  • 8-character label limit
  • Basic pseudo-opcodes (ORG, EQU, DFB, DA, ASC, HEX, etc.)
  • Macro support with ]1-]9 parameters
  • DOS 3.3 file operations

Limitations:

  • No 65C02 support
  • DDB byte order varies

Merlin 16 (Enhanced)

Enhancements over Merlin 8:

  • 65C02 support via XC directive
  • 16-character labels
  • Additional string directives (STR, REV, DCI)
  • Relocatable code (REL, ENT, EXT, USE)
  • ProDOS pathname support
  • Consistent DDB byte order (big-endian)

Merlin Pro (Professional)

Enhancements over Merlin 16:

  • Full 65816 support (16-bit mode)
  • MX directive for register size tracking
  • Long addressing modes
  • Enhanced macro capabilities
  • Source-level debugger integration
  • ProDOS 16 support

Recommended: Use Merlin Pro features as baseline for maximum compatibility.


Source Line Format

Line Structure

[label] [opcode] [operand] [;comment]

Fields:

  1. Label (optional): Starts in column 1, alphanumeric + _, ends with whitespace or :
  2. Opcode (required): CPU instruction or pseudo-opcode
  3. Operand (optional): Expression, addressing mode specifier, or directive parameter
  4. Comment (optional): Text following ; or * in column 1

Examples

START    LDA  #$00        ;Initialize accumulator
STA $C000 ;Store to hardware
LOOP INC COUNT ;Increment counter
BNE LOOP ;Branch if not zero
*
* Block comment using asterisk in column 1
*
RTS ;Return

Blank Lines

Blank lines are allowed and ignored. Use for readability.

Column Rules

  • Column 1: Reserved for labels or * comment
  • Whitespace: Tabs or spaces separate fields (typically one tab)
  • Case: Instructions are case-insensitive; labels are case-sensitive in some contexts

Number Formats

Decimal (Default)

Numbers without prefix are decimal:

    LDA  #100        ;Decimal 100
DFB 255 ;Decimal 255

Hexadecimal ($)

Prefix with dollar sign:

    LDA  #$FF        ;Hex FF (255 decimal)
STA $C000 ;Address $C000
DFB $20,$30,$40 ;Multiple hex bytes

Binary (%)

Prefix with percent sign:

    LDA  #%10101010  ;Binary 170
AND #%11110000 ;Binary mask

ASCII Character (')

Single character in single quotes:

    LDA  #'A         ;ASCII 'A' (65)
CMP #'Z ;ASCII 'Z' (90)

High-bit variants:

  • 'A - Normal ASCII (0x41)
  • "A - With high bit set (0xC1) - Note: Some variants

Expressions

Operators

Precedence (highest to lowest):

LevelOperatorsDescription
4< > ^Low byte, high byte, bank byte (unary)
3* /Multiply, divide
2+ -Add, subtract
1& . !Bitwise AND, OR, XOR

Parentheses () override precedence.

Byte Extraction Operators

  • <expression - Low byte (bits 0-7)
  • >expression - High byte (bits 8-15)
  • ^expression - Bank byte (bits 16-23, 65816 only)
ADDR     EQU  $1234
LOBYTE EQU <ADDR ;Result: $34
HIBYTE EQU >ADDR ;Result: $12

Bitwise Operators

  • & - Bitwise AND
  • . - Bitwise OR (period)
  • ! - Bitwise XOR
MASK1    EQU  $F0
MASK2 EQU $0F
BOTH EQU MASK1&MASK2 ;Result: $00
EITHER EQU MASK1.MASK2 ;Result: $FF

Special Symbols

  • * - Current program counter value
  • ]N - Macro parameter (N = 1-9)
HERE     EQU  *           ;Save current address
OFFSET EQU TARGET-* ;Distance to target
BNE *+5 ;Branch forward 5 bytes

Evaluation Rules

  • Left-to-right within same precedence (unlike algebraic)
  • Example: 10+5*2 = 20 (not 20 as in algebra)
  • Use parentheses: 10+(5*2) = 20

Addressing Modes

Mode Summary Table

ModeSyntaxExampleBytesNotes
ImpliedopcNOP1No operand
Accumulatoropc AASL A1Optional A
Immediate#exprLDA #$202Literal value
AbsoluteexprLDA $1000316-bit address
Absolute,Xexpr,XLDA $1000,X3Indexed by X
Absolute,Yexpr,YLDA $1000,Y3Indexed by Y
Zero PageexprLDA $202Auto if < $100
Zero Page,Xexpr,XLDA $20,X2ZP indexed X
Zero Page,Yexpr,YLDX $20,Y2ZP indexed Y
Indirect(expr)JMP ($1000)3Pointer jump
(Indirect,X)(expr,X)LDA ($20,X)2Pre-indexed
(Indirect),Y(expr),YLDA ($20),Y2Post-indexed
RelativelabelBNE LOOP2Auto-calc offset

65C02 Additional Modes

ModeSyntaxExampleNotes
(Zero Page)(expr)LDA ($20)ZP indirect
(Absolute,X)(expr,X)JMP ($1000,X)Indexed indirect JMP

65816 Long Addressing

ModeSyntaxExampleNotes
Absolute LongexprLDA $01000024-bit address
Absolute Long,Xexpr,XLDA $010000,X24-bit + X
[Direct Indirect][expr]LDA [$20]24-bit pointer
[Direct],Y[expr],YLDA [$20],Y24-bit ptr + Y
Stack Relativeexpr,SLDA $02,SStack offset
(SR,S),Y(expr,S),YLDA ($02,S),YSR indirect + Y

Force Addressing Mode

Prefix operators override automatic mode selection:

  • < - Force zero page (2 bytes)
  • > - Force absolute (3 bytes)
  • >> - Force long (4 bytes, 65816)
VALUE    EQU  $05
LDA VALUE ;Auto: zero page (2 bytes)
LDA >VALUE ;Force: absolute (3 bytes)
LDA >>VALUE ;Force: long (4 bytes, 65816)

Pseudo-Opcodes Reference

Assembly Control

ORG - Set Origin

Syntax: ORG expression

Set assembly address:

         ORG  $8000       ;Assemble at $8000

Can be used multiple times to create non-contiguous sections.

END - End Assembly

Syntax: END

Mark end of source file (optional in most contexts).

Symbol Definition

EQU - Equate Symbol

Syntax: label EQU expression

Define constant symbol:

MAXVAL   EQU  255         ;Define constant
IOPORT EQU $C000 ;I/O address
OFFSET EQU END-START ;Computed value

Cannot be redefined. Use = for variables.

= - Variable Assignment

Syntax: label = expression

Define or reassign variable:

COUNTER  =    0           ;Initialize
COUNTER = COUNTER+1 ;Increment

Can be redefined, unlike EQU.

Data Generation

DFB - Define Byte

Syntax: DFB byte[,byte...]

Generate byte values:

         DFB  $20              ;Single byte
DFB $20,$30,$40 ;Multiple bytes
DFB <ADDR,>ADDR ;Low/high bytes

Aliases: DB, FCB (some variants)

DA - Define Address (Word)

Syntax: DA address[,address...]

Generate 16-bit addresses (little-endian):

         DA   $1000            ;Stores $00,$10
DA LABEL1,LABEL2 ;Multiple addresses
DA * ;Current PC

Aliases: DW (some variants)

DDB - Define Double Byte

Syntax: DDB value[,value...]

Generate 16-bit values:

         DDB  $1234            ;Big-endian: $12,$34

Note: Byte order is big-endian in Merlin 16/Pro, may vary in Merlin 8.

HEX - Hexadecimal Bytes

Syntax: HEX hex-digits

Compact hex notation (no $ prefix):

         HEX  20304050         ;4 bytes: $20,$30,$40,$50
HEX FF,00 ;With commas
HEX A0A1A2 ;3 bytes

Rules:

  • Even number of hex digits
  • No $ prefix
  • Case insensitive

ASC - ASCII String

Syntax: ASC "string" or ASC 'string'

Generate ASCII string:

         ASC  "HELLO WORLD"    ;Plain ASCII
ASC 'Text' ;Single quotes OK

Embedded hex:

         ASC  "Line 1"8D       ;String + CR byte

DCI - Define Character Inverted

Syntax: DCI "string"

Last character has high bit inverted:

         DCI  "HELLO"          ;HELL-O (O = $CF not $4F)

Use case: String termination marker.

INV - Inverse String

Syntax: INV "string"

All characters have high bit set:

         INV  "FLASH"          ;All bytes $80-$FF range

REV - Reverse String

Syntax: REV "string"

String stored in reverse order:

         REV  "HELLO"          ;Stores "OLLEH"

STR - Pascal String

Syntax: STR "string"

Length-prefixed string:

         STR  "HELLO"          ;Stores: $05,"HELLO"

Length byte = string length (max 255).

DS - Define Storage

Syntax: DS size[,fill]

Reserve bytes:

         DS   100              ;100 bytes (unfilled)
DS 256,$FF ;256 bytes of $FF
DS \ ;Align to page boundary

Special: DS \ advances to next page boundary.

Listing Control

LST - Listing Control

Syntax: LST [ON|OFF|RTN]

         LST  OFF              ;Disable listing
LST ON ;Enable listing
LST RTN ;Suppress macro expansion

PAG - Page Eject

Syntax: PAG

Force new page in listing.

TTL - Title

Syntax: TTL "title"

Set listing page title:

         TTL  "Main Program"

SKP - Skip Lines

Syntax: SKP n

Insert n blank lines in listing:

         SKP  3                ;3 blank lines

Conditional Assembly

DO - Begin Conditional

Syntax: DO expression

Assemble if expression ≠ 0:

DEBUG    EQU  1
DO DEBUG ;Assemble if DEBUG set
JSR TRACE
FIN

ELSE - Conditional Else

Syntax: ELSE

Alternate block for DO:

         DO   VERSION-2
JSR NEWCODE ;If VERSION=2
ELSE
JSR OLDCODE ;If VERSION≠2
FIN

FIN - End Conditional

Syntax: FIN

End DO/ELSE block.

Macro Directives

MAC - Begin Macro

Syntax: label MAC

Define macro:

MOVE     MAC                   ;Define MOVE macro
LDA ]1 ;Parameter 1
STA ]2 ;Parameter 2
EOM ;End macro

Note: Some variants use .MA instead of MAC.

EOM - End Macro

Syntax: EOM or \<\<\<

End macro definition.

PMC - Print Macro

Syntax: PMC [ON|OFF]

Control macro expansion in listing:

         PMC  ON               ;Show expansion
PMC OFF ;Hide expansion

Relocatable Code

REL - Relocatable

Syntax: REL

Begin relocatable code section:

         REL                   ;Start relocatable
LDA BUFFER ;Uses relocatable addr

ENT - Entry Point

Syntax: ENT symbol[,symbol...]

Export symbols for linker:

         ENT  MAIN,INIT        ;Export these

EXT - External Reference

Syntax: EXT symbol[,symbol...]

Import symbols from other modules:

         EXT  PRINT,GETLN      ;Import these

USE - Use Object File

Syntax: USE filename

Link with object file.

File Operations

PUT - Include File

Syntax: PUT filename

Include source file:

         PUT  MACROS           ;Include macros
PUT LIBRARY ;Include library

SAV - Save Object

Syntax: SAV filename

Specify output file:

         SAV  MYPROG           ;Save as MYPROG

CPU Selection

XC - CPU Mode

Syntax: XC [ON|OFF]

Enable 65C02 instructions:

         XC                    ;Enable 65C02
STZ $00 ;Now legal
XC OFF ;Back to 6502

Merlin Pro: XC 65816 for 65816 mode.

MX - Register Size (65816)

Syntax: MX %mb

Set 65816 register size flags:

         MX   %00              ;16-bit A, 16-bit X/Y
MX %10 ;8-bit A, 16-bit X/Y
MX %11 ;8-bit A, 8-bit X/Y

Bits:

  • Bit 1 (m): M flag (0=16-bit A, 1=8-bit A)
  • Bit 0 (b): X flag (0=16-bit X/Y, 1=8-bit X/Y)

Critical: MX doesn't generate code, only tells assembler immediate operand size.


String Handling

Delimiter Rules

Strings use matching delimiters:

         ASC  "Text in double quotes"
ASC 'Text in single quotes'
ASC /Text with slashes/

High Bit Control

Normal ASCII (high bit clear):

         ASC  "HELLO"          ;$48,$45,$4C,$4C,$4F

Inverse/Flash (high bit set):

         INV  "HELLO"          ;$C8,$C5,$CC,$CC,$CF

Last character marked:

         DCI  "HELLO"          ;$48,$45,$4C,$4C,$CF

Embedded Hex

Insert raw hex in strings:

         ASC  "Line 1"8D       ;String + CR
ASC "Text"00 ;Null-terminated

Format: Two hex digits (no $ prefix) between string segments.

Control Characters

Special sequences for control codes:

         ASC  "Press ^M"       ;^M = RETURN ($0D)
ASC "ESC^[" ;^[ = ESC ($1B)

Supported: ^A through ^Z, ^[, ^], ^\, ^^, ^_


Label Rules

Valid Labels

First character: Letter (A-Z, a-z) Subsequent: Letters, digits, underscore Length: 8 chars (Merlin 8), 16 chars (Merlin 16/Pro) Terminator: Whitespace or colon (optional)

START              ;Basic label
LOOP1 ;With digit
MY_ROUTINE ;With underscore
Label: ;With colon

Invalid Labels

1LABEL             ;Cannot start with digit
MY-LABEL ;Hyphen not allowed
VERYLONGLABELNAME ;Too long (>16 chars)
LDA ;Cannot match mnemonic
ORG ;Cannot match pseudo-op

Local Labels

Format: :NAME or ]NAME (Merlin Pro)

ROUTINE  LDA  #$00
:LOOP STA $C000,X ;Local label
INX
BNE :LOOP ;Reference local
RTS

NEXT LDA #$01
:LOOP STA $C001,X ;Different :LOOP
INX
BNE :LOOP
RTS

Scope: Reset at next global label.

Anonymous Labels

Format: ^ (forward) or - (backward)

         LDA  #$00
^ STA $C000,X ;Define forward label
INX
BNE ^ ;Branch to it

Note: Not all Merlin versions support anonymous labels.


Macro System

Macro Definition

MACRONAME MAC                 ;Begin definition
; ... macro body ...
; Use ]1-]9 for parameters
EOM ;End definition

Parameter Substitution

Parameters referenced as ]1 through ]9:

STORE    MAC                   ;Define STORE macro
LDA ]1 ;First parameter
STA ]2 ;Second parameter
EOM

; Invocation:
STORE #$42,BUFFER ;Generates: LDA #$42; STA BUFFER

Macro Label Parameter

]0 contains the macro invocation label (if any):

WAIT     MAC
]0.LOOP DEX ;Use ]0 as label prefix
BNE ]0.LOOP
EOM

; Invocation:
WAIT1 WAIT ;Generates WAIT1.LOOP label
WAIT2 WAIT ;Generates WAIT2.LOOP label

Nested Macros

Macros can invoke other macros:

INNER    MAC
LDA ]1
EOM

OUTER MAC
INNER ]1 ;Call INNER
STA ]2
EOM

OUTER $10,$20 ;Expands both

Listing Control

         PMC  OFF              ;Hide macro expansion
MYMACRO ARG1,ARG2 ;Only show invocation
PMC ON ;Resume expansion display

Conditional Assembly

Basic Structure

         DO   condition
; ... code if condition ≠ 0 ...
FIN

With ELSE

         DO   condition
; ... code if condition ≠ 0 ...
ELSE
; ... code if condition = 0 ...
FIN

Nesting

Conditionals can be nested:

         DO   PLATFORM-1
DO DEBUG
JSR APPLE_DEBUG
FIN
FIN

Common Patterns

Feature flags:

DEBUG    EQU  1
DO DEBUG
JSR TRACE
FIN

Version selection:

VERSION  EQU  2
DO VERSION-2
JSR V2CODE
ELSE
JSR V1CODE
FIN

Platform targeting:

APPLE2E  EQU  1
DO APPLE2E
LDA $C000,X ;//e specific
ELSE
LDA $C000 ;Standard
FIN

65816 Features

Enabling 65816 Mode

         XC   65816            ;Enable 65816 (Merlin Pro)

Register Size Tracking

MX Directive: Tell assembler current register sizes

         REP  #$30             ;16-bit A, X, Y (in code)
MX %00 ;Tell assembler
LDA #$1234 ;Now 16-bit immediate
LDX #$5678 ;16-bit immediate

SEP #$20 ;8-bit A (in code)
MX %10 ;Tell assembler
LDA #$12 ;Now 8-bit immediate

Critical: MX directive doesn't generate code - programmer must manually track REP/SEP.

Long Addressing

24-bit addresses:

         LDA  $123456          ;Load from bank $12, addr $3456
LDA $010000,X ;Bank 1 with X offset

Long indirect:

         LDA  [$20]            ;24-bit pointer at DP $20
LDA [$20],Y ;Plus Y offset

Stack relative:

         LDA  $02,S            ;Load from stack offset
LDA ($02,S),Y ;Stack relative indirect

Additional 65816 Instructions

Stack operations:

         PEA  $1234            ;Push 16-bit literal
PER LABEL ;Push effective address
PHB ;Push data bank
PHD ;Push direct page
PHK ;Push program bank

Long jumps:

         JML  $020000          ;Jump long
JSL $010000 ;Call long subroutine
RTL ;Return long

Register transfers:

         TCD                   ;C to D
TCS ;C to S
TDC ;D to C
TSC ;S to C
TXY ;X to Y
TYX ;Y to X
XBA ;Exchange B and A
XCE ;Exchange C and E

Block moves:

         MVN  $12,$34          ;Move next (increment)
MVP $12,$34 ;Move previous (decrement)

Processor control:

         REP  #$30             ;Reset status bits
SEP #$20 ;Set status bits
COP ;Coprocessor
WDM ;Reserved

Quick Reference Tables

Pseudo-Opcode Summary

DirectivePurposeExample
Assembly Control
ORGSet originORG $8000
ENDEnd assemblyEND
Symbol Definition
EQUDefine constantMAXVAL EQU 255
=Define variableCOUNT = 0
Data Generation
DFB/DBDefine byte(s)DFB $20,$30
DA/DWDefine addressDA ROUTINE
DDBDefine word (BE)DDB $1234
HEXHex bytesHEX 010203
ASCASCII stringASC "TEXT"
DCIString, last invDCI "TEXT"
INVInverse stringINV "TEXT"
REVReverse stringREV "TEXT"
STRPascal stringSTR "TEXT"
DSReserve spaceDS 256
Listing
LSTListing controlLST OFF
PAGPage ejectPAG
TTLSet titleTTL "Title"
SKPSkip linesSKP 3
Conditional
DOBegin conditionalDO DEBUG
ELSEAlternate blockELSE
FINEnd conditionalFIN
Macros
MACBegin macroMOVE MAC
EOM/<<<End macroEOM
PMCPrint macroPMC OFF
Relocatable
RELRelocatable modeREL
ENTEntry pointENT MAIN
EXTExternal refEXT PRINT
USEUse objectUSE LIBRARY
Files
PUTInclude filePUT MACROS
SAVSave objectSAV OUTPUT
CPU
XCCPU modeXC 65816
MXRegister sizeMX %00

Number Format Quick Reference

FormatSyntaxExampleValue
Decimalnnn255255
Hexadecimal$hh$FF255
Binary%bbbb%11111111255
ASCII'c'A65

Operator Precedence

LevelOperatorsExample
4 (high)< > ^<$1234 = $34
3* /10*5 = 50
2+ -10+5 = 15
1 (low)& . !$F0&$0F = $00

Addressing Mode Byte Counts

ModeBytesExample
Implied1NOP
Accumulator1ASL A
Immediate2LDA #$20
Zero Page2LDA $20
Zero Page,X/Y2LDA $20,X
Absolute3LDA $1000
Absolute,X/Y3LDA $1000,X
(Indirect,X)2LDA ($20,X)
(Indirect),Y2LDA ($20),Y
Indirect3JMP ($1000)
Relative2BNE LOOP
65816 Long
Absolute Long4LDA $123456
Long,X4LDA $123456,X
[Direct]2LDA [$20]
[Direct],Y2LDA [$20],Y

Implementation Notes for xasm++

Critical Parsing Rules

  1. Expression Evaluation: Left-to-right within same precedence level
  2. Addressing Mode Selection: Auto-detect ZP vs absolute based on value
  3. String Delimiters: Support multiple delimiter types
  4. Macro Expansion: Parameter substitution with ]0-]9
  5. Conditional Nesting: Track DO/ELSE/FIN depth

Two-Pass Assembly

Pass 1: Collect symbols, resolve forward references Pass 2: Generate code, check all references resolved

Version-Specific Features

  • Merlin 8: 8-char labels, DDB byte order caution
  • Merlin 16: 16-char labels, relocatable code, consistent DDB
  • Merlin Pro: 65816 support, MX directive, long addressing

Testing Recommendations

  1. Test with original Merlin source files (Prince of Persia, etc.)
  2. Verify all addressing modes with real code
  3. Test macro expansion with nested invocations
  4. Verify MX directive interaction with immediate values
  5. Test string handling (ASC, DCI, INV, REV, STR)
  6. Verify expression evaluation order
  7. Test conditional assembly with nesting

References

  • Merlin 8/16 Manual - Glen Bredon, Roger Wagner Publishing
  • Merlin Pro Manual - Professional edition documentation
  • 65816 Programming Manual - WDC 65816 reference
  • Apple II Reference Manual - Apple Computer, Inc.

Document Version: 1.0 Created: 2026-01-29 For: xasm++ Merlin compatibility implementation Maintainer: xasm++ development team