An assembler source program is a sequence of source statements. Each source statement is coded on one single line of text and can be a comment line (consisting of only a comment), or a source line. Each source statement includes one or more of the following four fields: a label field, an operation field, one or several operands and possibly a comment. As an example of a source line:

value:EQU$AA; value = $AA

where 'value' is the label field, 'EQU' is the operation field, '$AA' is the operand, and the comment section at the end begins with a semi-colon.

Syntax defines the format and type of fields allowed in an assembler source code program. This tells us how to set up comments, where to put directives, etc.

Directives are instructions used by the assembler to help automate the assembly process and to improve program readability. Examples of common assembler directives are ORG (origin), EQU (equate), and DS.B (define space for a byte). Directives are NOT part of the Motorola assembly language machine instructions, such as 'ldaa' or 'movb'. Machine instructions generate machine code, assembler directives do not. Directives are used essentially in a pre-processing stage of the assembly process.

The assembler directives listed below are the most common ones used for Code Warrior. Other assemblers may use similar directives, but you need to consult the manuals for each assembler to be sure of the details. The syntax and assembler directives for Code Warrior are fully described in the Manual_Assembler_HC12.pdf.

Essential Code Warrior Syntax

Note that while directives are not case sensitive, labels and symbols ARE case-sensitive: 'Buf1:' != 'buf1:' != 'BUF1:', etc.

    * Comments - A comment is used to explain the purpose and usage of a block of statements or to describe an algorithm. A comment line contains a semicolon followed by text. A comment can also be placed at the end of a source line. Comments are included in the assembly listing, but are not significant to the assembler.


      ; this is a comment line

      ldaa#$01; put $01 into reg A -> comment at end of source line

    * Labels - A label is a symbol followed by a colon. Labels are required on assembler directives that define the value of a symbol (for instance, EQU). For these directives, labels are assigned the value corresponding to the expression in the operand field. Note the labels MUST begin in column zero; there can't be any white space before a label (but note that some directives like ORG noted below do require whitespace in the leading column).


      length:EQU$18; length = $18

      loop:ldaa$01; loop = address of 'ldaa' statement

    * String Constants - A string constant is a series of printable characters enclosed in single (') or double quote ("). Double quotes are only allowed within strings delimited by single quotes. Single quotes are only allowed within strings delimited by double quotes.


      'ABCD', "ABCD", 'A', "'B", "A'B", 'A"B'

      are all valid string constants

Common Code Warrior Directives

NB: The directives below are 'operation fields' and CANNOT begin in the first column of a line. If a label does not precede a directive, you MUST indent or put a space before the directives noted below. Directives are case-insensitive, so 'equ' = 'EQU' = 'Equ'. Use the case that gives the best readability. In contrast, remember that the case of labels and symbols IS case-sensitive: 'Buf1:' != 'buf1:' != 'BUF1:', etc.

    * ABSENTRY - This directive is used to specify the application Entry Point when the assembler generates directly an absolute file (the option -FA2 ELF/DWARF 2.0 Absolute File must be enabled). We must use this directive for absolute assembly files generated in this course. As with the ORG directive, ABSENTRY must be indented (it must have whitespace in the leading columns).


         ABSENTRY Entry; for absolute assembly, mark this as application entry point

    * DC.B - Define constant in memory of length one byte. This assigns a memory address M to a constant and initializes the constant. For strings, one byte is allocated per ASCII character in the string. We use the 'dc' directive for constants whose value will not change during program execution. In production code, these values usually will go in ROM (EEPROM or FLASH).


      num1:dc.b$FC; num1 has address and is initialized to $FC

      vec1:dc.b1,2,3,4,5; vec1 points to start address of vector [1,2,3,4,5]

      string1:dc.b'hello'; this creates a string 'hello' whose storage address begins at string1.

      You can think of 'num1' as an address or as the contents of that address, depending on the context of the code. For instance, imagine that after assembling the program, we find that num1 is assigned to memory address $2000 (you could find this our by disassembling the code using the 'asm' command, for example). The contents of address $2000 is the 8 bit number $FC. If you write 'ldaa num1', we would put the contents of the address $2000 into reg A, which is the same as saying we would put the value $FC into reg A. So, writing 'ldaa num1' is like a synonym for 'ldaa #$FC'. If we wrote 'ldd #num1', this would put the address $2000 into reg D; this is like a synonym for 'ldd #$2000'. Note that if you tried to use 'ldaa #num1', you would get a warning during assembly since you are trying to put a 16 bit number (the address $2000) into an 8 bit register, reg A. Reg D is 16 bits so we don't get that warning. Similar results apply to the use of the dc.w, ds.b and ds.w directives noted below. Note the similarity to pointers in C.

    * DC.W - Define constant in memory of length one word (two bytes). Two bytes are allocated for numeric expressions and are assigned to address M:M+1. ASCII strings are right aligned on a two-byte boundary.


      k1:dc.w$90AE; k1 has address M:M=+1 and is initialized to $90AE

    * DS.B - The DS directive is used to reserve memory for variables. The content of the memory reserved is not initialized. The length of the block is [size] * [count] where count is the number of units. We use the DS directive for variables whose value will change during program execution. The DS directive should be used in RAM.


      counter:ds.b2; reserve two continuous bytes in memory

      buffer1:ds.b5; reserve five continuous bytes in memory

    * EQU - The equate directive is used to substitute values for symbols or labels. The format is 'label: EQU value', so whenever the assembler encounters 'label', it replaces this with 'value'. This is especially handy for improving program readability. For instance, we could write 'ldx #$0032', or we could use 'portb: EQU $0032' followed later by 'ldx #portb'. The latter 'ldx' instruction is more readable than the former. The EQU directive only tells the assembler to substitute a value for a symbol or label, and doesn't involve any type of ROM or RAM. EQU directives are typically placed at the beginning of an assembly program.


      portb:EQU$0032; port B is located at address $0032

      portb_ddrEQUportb + 2; port B Data Direction Register = $0034

      kb:EQU$1024; kb = 1024 bytes

    * OFFSET - The OFFSET directive declares an offset section and initializes the location counter to the value specified in expression following offset. An offset section is useful to simulate data structures or a stack frame.


      OFFSET 0

      ID: DS.B 1

      COUNT: DS.W 1

      VALUE: DS.L 1

      SIZE: EQU *

    * ORG - The origin directive sets the location counter to the value specified. Subsequent statements are assigned memory locations starting with the new location counter value. The location counter is a counter in the assembler program that is used to assign storage addresses for the program. For instance, it will set the location in memory where the constants are stored, and where the executable machine code begins. As the program is assembled, the location counter keeps track of the current location in storage. Note that the location counter is a software construct defined in the assembler program, and exists only during the assembly process. It is NOT the same as the program counter, which is an actual register in the HCS12 that keeps track of the address of the current instruction as an executable is running on the HCS12. Note that unlike labels, ORG must be indented (it must have whitespace in the leading columns).


          ORG$2000; note that ORG is INDENTED

    * SET - Similar to the EQU directive, the SET directive assigns the value to the symbol. Unlike EQU, however, the label associated with SET can be redefined.


      c1:SET$12; 'c1' substitutes for $12

      c1:SET$18; 'c1' substitutes for $18 - couldn't redefine c1 if EQU was used

    * XDEF - Make a symbol public (needed by the linker to find out where the entry point is). This is required for all of our programs, and is usually the first line following the header comments. As with the ORG directive, XDEF must be indented (it must have whitespace in the leading columns).


         XDEFEntry; export the Entry symbol, which is a label at the start of our program

    * * - The asterisk symbol is basically a synonym for 'this address'.


      Mem1:set*; label 'Mem1' is address of this statement

Other Code Warrior Information

It is worth emphasizing again the use of WHITE SPACE . "White space" is something which puts space at the beginning of a line, and is either a space character(s) or a tab character(s) or any mix of these. The incorrect use of whitespace is one of the most common problems encountered by beginning Code Warrior programmers. Note that some directives such as the EQU label have no white space. Labels such as "Entry:" also have no white space. Others such as ORG must have white space. Machine instructions such as "mov #ledson, portb" must also have white space. A machine instruction in Code Warrior will not work if there is no whitespace before it.

CCS Assembler Directives