org, equ, dc and ds

The M68K has no data section: the assembler lays your program out in the order you wrote it, and four directives say where things go and what is in them.

A program is instructions and the data they work on, and something has to say where each of them goes in memory. MIPS and RISC-V do it with sections, .data and .text. The M68K assembler here has no sections at all: it starts at an address, walks your source from top to bottom, and puts each instruction and each piece of data at the next free address. Four directives control that walk.

org: where the next thing goes

org $2000 sets the address the next line is assembled at. Everything after it follows on from there, four bytes per instruction and as many bytes as it needs per piece of data, until the next org.

A new M68K project starts with ORG $1000, and $1000 is also where this editor assembles from when you write no org at all. The program starts running at your first instruction, wherever in memory it landed, not at the lowest address, so a data block placed before the code with an earlier org does not get executed.

One rule: an org can only move forwards. org $1000 after something has already been assembled at $3000 is a build error saying that the address must be greater than the previous one.

Build it, then type 1008 in the memory panel's address box: the four bytes AA BB CC DD are there, because nothing separated the data from the code. Type 2000 and 11 22 33 44 is there instead.

The program stops after move.l #2, d1, and it stops for a plain reason: there is no next instruction. The bytes of here are data and the simulator has no instruction assembled at $1008, so the run ends. On a real 68000 those bytes would be decoded as an instruction and executed, whatever they happened to mean, which is why real programs never fall off the end into their data.

Labels

A label is a name for the address of whatever comes next, and on this assembler it ends with a colon: here:, start:, numbers:. A name without a colon in front of an instruction is read as an instruction name and fails to assemble. The one exception is equ, whose name is written first and takes no colon.

A label is nothing but its address, so nothing distinguishes a label on an instruction from a label on a dc. bra here and move.l here, d0 are both legal on the same label, and one of them makes sense.

dc, ds and dcb: what is in memory

  • dc defines constants. dc.b, dc.w and dc.l write the values you list as bytes, words or longs, in that order, right where the line is. A string in single quotes is written as its characters, one byte each, and a label written as a value becomes its address.
  • ds defines storage. ds.b 8 reserves eight bytes, ds.w 2 two words, ds.l 6 six longs, and it gives them no value: what is in that room until your program writes it is whatever was there.
  • dcb defines a constant block: dcb.b 4, $7E writes $7E four times over. It is ds with something in it.
labeladdressbyteswhat it is
greeting$200048 69 00H, i and the terminator you wrote
counts$200300 01 00 02two words
total$2007DE AD BE EFone long, most significant byte first
room$200Bfour bytesreserved and not written
filler$200F7E 7E 7E 7Efour copies of $7E
pointer$201300 00 20 00the address of greeting, as a long

a0 comes out at 00002000, the same address pointer holds. Two things in that table are worth reading twice. counts starts at $2003, an odd address, because greeting took three bytes and the assembler pads nothing, so move.w counts, d0 on this layout is an address error. And pointer is a long whose value is an address, which is how you write the equivalent of char *p = greeting; in C.

equ: a name for a number

equ gives a name to a number, and the assembler replaces the name with the number everywhere it appears. It reserves no memory and produces no instruction: after assembling, nothing of the name is left in the program.

d0 and d2 both come out at 00000006, and they got there in completely different ways: count became a #6 inside the instruction, while stored became the address $2000 and the instruction went to memory. d1 is 00000018, which is 24, worked out by the assembler.

Use equ for anything you would write as a #define in C: the length of an array, the size of an element, a trap task number, a screen width. Change the number in one place and every use of it changes with it. The one thing it will not do here is arithmetic on another equ with *, so write sizes as sums (limit equ 640-40) or repeat the number.

The shape of a real program

Put together, an M68K program in this editor looks like this: constants at the top, code from $1000, data under its own org after it.

a0 ends at 00002003, which is where buffer begins, three bytes after message. Look at $2000 in the memory panel after running and the four bytes read 48 69 00 41: the string, its terminator, and the A the program wrote into the first byte of the room.

The org $2000 is what keeps the data out of the way. Without it message would sit right after the last instruction, and every instruction you add above would move it, which is fine for the program and inconvenient every time you want to look at a fixed address in the memory panel.

Your turn

Write a data block at $3000 holding the three words 100, 200 and 300, followed by eight bytes of room, and leave the address of that room in a0. It comes out at $3006, since three words take six bytes.

Show solution

The second one wants two names, rows for 4 and cols for 5, and their product in d0, multiplied by the assembler rather than by the program.

Show solution