As mentioned previously, assembler directives are instructions to the assembler, and are not translated into machine instructions.
The use of directives gives the programmer some control over the operation of the assembler, increasing flexibility in the way programs are written. The following is a list of the common pseudo-ops.
is used to make programs easier to write. The EQU directive creates absolute symbols and aliases by assigning an expression or value to the declared variable
name. Its format is, name: EQU expression Consider the following statement.
- NUMBER1: EQU 36H
The assembler will replace every occurrence of the label NUMBER1 with the value its been equated to, ie, 36 hexadecimal. The statement
will be interpreted by the assembler as
An absolute symbol represents a 16bit value; an alias is a name that represents another symbol. The declared name must be unique, one that has not been previously declared. The redefining of a previous symbol is normally not allowed.
NUM1: EQU 20H
NUM1: EQU 30H ; error
This specifies the address to be used for the generation of code. Subsequent instructions and data address’s begin at the new value. Normally, it is used to set the start address of the program, but can also set the location counter to the value specified.
- ORG 120H
The statement LDAA #FFH begins at byte 120h.
ORG $ + 2
start: LDAA #34H
The instruction associated with the label start is declared to start at the address 2bytes beyond the current value of the location counter (specified by $).
- CPU TYPES
This directive is used by multi-purpose assemblers to specify which target processor is being used. The format for CRS8 is CPU cpuname where cpuname consists of a valid processor name, eg CPU 6802This directive appears before any machine instructions.
- OUTPUT FORMATS
This directive is used to select the output format for the generated machine instructions. Several output formats are available for downloading into EPROM or a
- HOF recordtypewhere recordtype is one of the following
MOT ; motorola formats
INT ; intel formats
TEK ; tektronix formats
This directive appears before any machine
- BYTE STORAGE
The directive used to allocate and initialize bytes (8bits) of storage is DFB definebyteIts format is,
name: DFB initialvalue,,,
The name portion is optional. Consider the following examples for CRS8.
value1: DFB 16
form: DFB 6*2
text: DFB “Enter your name: ”
In the first example, the label value1 is assigned a single byte of storage, which is initialized to 16 decimal.The second example allocates a single byte of storage for the label form, and initializes it equal to 12. The last example allocates 17 bytes of storage for the label text. The first byte will be initialized to E, whilst the last byte is initialized to an ASCII space.
- WORD STORAGE
The directive used to allocate and initialize words (two bytes) of memory storage is,DWM define word, most significant byte first
DWL define word, least significant byte first
Its format is,
name: DWM initialvalue,,,
The name portion is optional.
mess: DWM ‘ab’
The first example allocates one word of storage, having the values 16H followed by 87H. The second example defines mess as a word initialized with the character values a followed by b. The b will be placed in the low-order byte, and the a will be placed in the high order byte. If only one character is specified, the high-order byte will contain 0.
Strings when using the DW directive must not contain more than two characters.
- DATA STORAGE RESERVATION
This directive is used to reserve storage for later use.array:
This example allocates 100 storage bytes, associating the first byte with the label array. The value of these bytes is indeterminate at this point. The 100 bytes will be allocated relative to the current location counter.
- END and Optional Start Address
The END directive specifies the end of the assembly language source listing. It may be followed by an optional entry address. The optional entry address is used by LOADERS to initialize the Program Counter before running the program. If no entry address is specified, execution will start at the first location allocated by the assembler.END
In this example, the END directive informs the assembler that there is no more source statements.
start: LDAA #3FH
In this example, the END directive also specifies that the entry point to the program is the label start, whose address is 0100H.
SAMPLE PROGRAM FOR MC6802 USING CRS8
The following source file has been named MC6802.ASM
CPU 6802 ; 6802 processor HOF MOT ; Motorola Records ORG 0100H ; Start of Data Source: DFB 'Hello and Welcome' Length: EQU $ - Source ;Length of Source Destin: DFS Length ; Buffer which has same ; length as Source ORG 0120H ; Start of Code Entry: LDX #Source ; Point Index Reg to ; Source string LDAB #Length ; Number of characters to move Loop: LDAA 0,X STAA Length,X INX DECB BNE Loop Fin: JMP Fin END Entry
This program is assembled by typing the following command
It is not necessary to type the extension .ASM, and CRS8 will
produce two output files.
MC6802.PRN ; a list file showing the code generated MC6802.HEX ; the record file for downloading to the ; target system or Eprom programmer
The listing file MC6802.PRN looks like
C:6802.TBL CPU 6802 ; 6802 processor C:6802.HEX HOF MOT ; Motorola Records 0100 ORG 0100H ; Start of Data 0100 48656C6C6F Source: DFB 'Hello and Welcome' 0011 = Length: EQU $ - Source ; Length of Source 0111 Destin: DFS Length ; Buffer which has same ; length as Source 0120 ORG 0120H ; Start of Code 0120 CE0100 Entry: LDX #Source ; Point Index Reg to ; Source string 0123 C611 LDAB #Length ; Number of characters ; to move 0125 A600 Loop: LDAA 0,X 0127 A711 STAA Length,X 0129 08 INX 012A 5A DECB 012B 26F8 BNE Loop 012D 7E012D Fin: JMP Fin 0130 END Entry
The first column is the address, the second the instructions or data, and then the mnemonics and comments. This listing is used by the programmer to verify that the assembler has produced the correct instructions and data at the correct addresses. We
can clearly see that it has correctly interpreted the address of Source in the statement LDX #Source as the bytes CE 0100.
The record format file MC6802.HEX looks like
S00D0000433A363830322E48455892 S113010048656C6C6F20616E642057656C636F6D1D S10401106585 S1130120CE0100C611A600A711085A26F87E012D9F S9030120DB
The format of a motorola record is
Digit 0,1 Record Type = S0, S1 or S9 2,3 Number of bytes in Record which includes the load address and checksum bytes 4,5,6,7 Load Address 8 to n-2 Data or coded instructions n-1 to n Checksum value The S0 record identifies the program name The S1 record identifies the data and coded instructions The S9 record identifies the program entry point eg S1 04 0110 65 85 ^ ^ ^ ^ ^checksum ^ ^ ^ ^ data ^ ^ ^ load address ^ ^ number of bytes in record ^ record type
The file is then downloaded to the target system.
ELEMENTARY DATA TYPES
Most programming languages support data types like characters and integers. At the processor level, some instructions support integer type operations such as multiply or divide (except 6802).The programmer is responsible for keeping track of data types. The processor treats all data the same, and if the program goes astray, can interpret data as instructions and vise versa.
Lets look at how elementary data is represented by the programmer for use in assembly language programs.
are single eight bit values represented using the ASCII code. Values range from 0 to 127. The statement
Letter: DFB 'A'
associates one byte of storage to the variable Letter, initializing it to the ASCII character ‘A’ (41H).
are multiple bytes, each byte holding an ASCII character. The statement
String: DFB 'Hello there.'
allocates 12 bytes of storage space. The variable String has the address of the first byte, which has been allocated the character ‘H’ (48H).
are stored as 16 bit values (two bytes or one word), and are signed or unsigned. The statement
Number1: DWM -17D
allocates a word of storage for the variable Number1, initializing the word to -17 decimal. Some processors have different instructions for operations on signed and
unsigned integers. If the processor cannot handle a 16bit value (ie, has only eight bit registers), software will need to be written to do any comparisons on these types.
- Character Arrays
are essentially text strings. Each element of the array has storage space for an ASCII character. Strings in some HLL’s are terminated with an End-Of-String symbol (in C it is ASCII 00h, in PCDOS it is ASCII ‘$’). The following statement
Digits: DFS 10
allocates 10 locations for a character based array called Digits. The following code routine initializes the Digits array (each successive element) to the digits 0 to 9.
ORG 0120H start: LDAA #30H ; ASCII '0' LDAB #11 ; ten digits LDX #Digits loop: STAA 0,X INX ; next element INCA ; next digit DECB BNE loop exit: ....
Typical Array Operations
The following routines are typical of functions which are performed on character based arrays.
This copys a source string to a destination area. The declaration of the routines is, copystr( src, dest )where src and dest represent the address of the source and destination strings. Writing this type of routine is ideally suited to a processor which has more than one Index or Base register. The MC6802, having only one Index register, presents a small problem. The following code shows this program implemented for the MC6802.
CPU 6802 HOF MOT ORG 100H str1: DFS 10 st1len: EQU $ - str1 str2: DFS 10 ORG 120 HSRCINX:DFS 02H ; pointer for src string DSTINX: DFS 02H ; pointer for dest string start: LDX #str1 ; store address of str1 STX SRCINX LDX #str2 ; store address of str2 STX DSTINX jsr initstr1 ; initialise str1 jsr copystr ; copy str1 to str2 exit: bra exit initstr1: LDAA #41H ; character 'A' LDAB #11 ; elements 1 - 30 LDX #str1 ; point to str1 lp1: STAA 0,X ; store character INX ; next element INCA ; next value DECB ; loop around BNE lp1 LDAA #00 ; null terminator STAA 0,X RTS copystr: LDX SRCINX ; pick up source pointer cplp2: LDAA 0,X ; get source character CMPA #00H ; eostr? BEQ cpstrq ; yes, then exit INX ; else inc source pointer STX SRCINX ; store source ptr LDX DSTINX ; get destination pointer STAA 0,X ; store character INX ; inc dest ptr STX DSTINX ; store dest ptr LDX SRCINX ; reload source pointer BRA cplp2 ; repeat cpstrq: LDX DSTINX ; Null terminate dest str CLR 00,X RTS END start1
- String Length
Returns the length of a terminated string. The following code shows this routine implemented for the MC6802. Strlen is entered with the Index register pointing to the string, and returns the length of the string in the B accumulator.
CPU 6802 HOF MOT EOFSTR: EQU 00H ORG 100H str1: DFB 'Hello and Welcome.', 00H ORG 120H start: LDX #str1 ; point to string jsr strlen ; find length of str1 exit: bra exit strlen: LDAB #00 ; character count strlp1: LDAA 0,X ; read character CMPA #EOFSTR ; is it end of string BEQ strexit ; yes, then exit INX ; no, inc str ptr INCB ; inc character count BRA strlp1 ; and repeatstr exit: RTS ; acc B has length END start2
- Search for first occurrence of a character
This routine returns the address of the specified character found in the string. If the address returned is zero, it indicates the character was not found. The following code shows this routine implemented for the MC6802. Strpos is entered with the Index register pointing to the search string, and the A accumulator with the character search value.
CPU 6802 HOF MOT EOFSTR: EQU 00H ORG 100H str1: DFB 'Hello and Welcome.', 00H ORG 120H start: LDAA #6FH ; ASCII 'o' LDX #str1 ; point to src string jsr strpos ; find first 'o' in str1 exit: bra exit strpos: CMPA 0,X ; is char = search value BEQ strex2 ; yes then exit CMPA #EOFSTR ; is it end of string BEQ strex1 ; yes, then exit INX ; no, inc str ptr BRA strpos ; and repeat strex1: LDX #0000H ; not found strex2: RTS ; Index reg has address END start3
- Search for Substring
This routine is used to find the starting address of a substring within a larger string. It accepts a source string pointer, and a pointer to a substring. It returns the address of the substring, if not found it returns address zero.
- Substring Insertion/Replacement
This routine inserts a substring into an existing string.
Most versions overwrite existing characters. It accepts a pointer to the source string, a pointer to the substring to insert, and a numeric value representing the start position where insertion should begin. No characters should overwrite the end-of-string terminator, or be written to memory locations after the terminator. The routine should return a numeric value representing the number of characters inserted.
- String Reverse
This routine reverses the characters in a string. It accepts the address of the string. Hello becomes olleH
- String to Uppercase
This routine converts all characters of a string to uppercase. It accepts the address of the string. Hello becomes HELLO
- String to Lowercase
This routine converts all characters of a string to lowercase. It accepts the address of the string. Hello becomes hello
ARRAY INDEX CALCULATIONS
This refers to calculating the address of a specified element within an array. In single dimensioned arrays, this is equivalent to
BASE_ADDRESS + (ELEMENT_NUMBER * NUMBER_OF_BYTES_PER_ELEMENT)
In multi-dimensioned arrays, this is equivalent to
BASE_ADDRESS + (Col_Num + (Row_num * Num_Col_per_row)) * Num_Bytes_per_Element)