org, equ, dc and ds

org, equ, dc and ds

The assembler must choose a memory address for every instruction and every piece of data. It keeps a current assembly address while it reads the source. Placing an instruction or some data uses bytes at that address and advances it by the number of bytes placed there.

An assembler directive tells the assembler how to build the program. A directive does not become an instruction for the processor. This page uses four directives:

directivejob
orgchoose the address for whatever is assembled next
dcplace known data in memory
dsreserve a chosen amount of memory
equgive a name to a number used while assembling

Labels name addresses

A label binds a name to the current assembly address. Write the name followed by a colon:

start:
    move.l #1, d0

    org $2000
values:
    dc.w 10, 20

Here start names the address of an instruction, while values names the address where the first word is stored. The label itself occupies no memory. Both names are addresses; their meaning comes from what the source places at those addresses.

An instruction may use a label before its definition appears. During Build, the assembler reads the complete source, records each label's address, and resolves those references. For example, move.l #values,a0 works even if values: is farther down the file. A forward reference is also allowed in data created by dc.

The expressions on org, ds, and equ lines affect the layout itself, so any names in those expressions must already have been defined.

org: choose the next address

org $2000 sets the current assembly address to $2000. The next instruction or data byte is placed there, and assembly continues from there until another org changes the address.

This editor starts at $1000 when the source has no earlier org. Writing each important address explicitly makes the layout easy to inspect:

    org $1000
start:
    move.l #value, a0   ; the address named by value
    move.l value, d0    ; the long stored at that address

    org $2000
value:
    dc.l $11223344

The assembler resolves the two uses of value to $2000. The # keeps that number as an immediate value, so a0 becomes $00002000. Without #, value is a memory operand, so d0 receives $11223344 from memory.

Build places the instructions beginning at $1000 and the data beginning at $2000. Run starts at the first assembled instruction and executes the two move.l instructions. The org and dc lines guide Build, so they are not execution steps.

dc: place known data

dc means define constant. Its suffix chooses the size of every listed value:

  • dc.b places one byte for each value;
  • dc.w places one two-byte word for each value;
  • dc.l places one four-byte long for each value.

Values are placed in the order written. Words and longs use big-endian byte order, with the most significant byte at the lowest address.

A word or long must begin at an even address. A byte declaration can leave the current address odd, and the assembler does not insert alignment bytes automatically. When that happens, declare a padding byte before the next word or long:

    org $2000
first:   dc.b $12
padding: dc.b 0
pair:    dc.w $3456, $789A
wide:    dc.l $BCDEF012
pointer: dc.l first

The resulting layout is completely determined during Build:

labeladdressbytes in memoryexplanation
first$200012one byte
padding$200100an explicit byte makes the next address even
pair$200234 56 78 9Atwo big-endian words
wide$2006BC DE F0 12one big-endian long
pointer$200A00 00 20 00the address named by first, stored as a long

The value on a dc line can be a label. dc.l first stores the label's numeric address, $00002000, in four bytes.

ds: reserve uninitialised memory

ds means define storage. It advances the current assembly address without giving the reserved bytes known values. The number is a count of the selected size:

declarationspace reserved
ds.b 88 bytes
ds.w 33 words = 6 bytes
ds.l 22 longs = 8 bytes

For example:

    org $2100
bytes: ds.b 8
words: ds.w 3
longs: ds.l 2

bytes is $2100, words is $2108, and longs is $210E. A program must write a reserved location before relying on its contents. ds does not promise zeroes or any other initial value.

equ: name an assembler-time number

equ gives a name to a numeric expression. Its name is written without a colon:

rows  equ 4
cols  equ 5
cells equ rows*cols

    org $1000
    move.l #cells, d0
    move.l stored, d1

    org $2000
stored:
    dc.l cells

Define each name before another equ expression uses it. In this lesson, an expression can use decimal or $-prefixed hexadecimal integers, earlier equ names, parentheses, and the operators +, -, *, and /. Write the expression without spaces, as in rows*cols or (cols+1)*4. Multiplication is ordinary assembler-time arithmetic.

The assembler calculates cells as 20. It places 20 inside the first move.l as an immediate value and also writes 20 into the long at stored. During Run, d0 receives the immediate 20, while d1 reads 20 from memory at $2000.

An equ line emits no bytes, reserves no bytes, and does not advance the current assembly address. The name exists for the assembler; the built program contains the resulting number wherever the name was used.

Check your understanding

1. Declare known data and reserve space

At $3000, declare the three words 100, 200, and 300. Immediately after them, reserve eight uninitialised bytes with the label room. Put the address named by room in a0.

The three dc.w values give the six bytes from $3000 through $3005 defined initial contents. room begins at $3006, and its eight reserved bytes have unspecified contents.

; your code here
Show solution
    move.l #room, a0

    org $3000
values: dc.w 100, 200, 300
room:   ds.b 8

2. Calculate a named value during Build

Define rows as 4 and cols as 5. Define cells from the expression rows*cols, then put the value of cells in d0.

; your code here
Show solution
rows  equ 4
cols  equ 5
cells equ rows*cols
    move.l #cells, d0