Assembly Language Project

183
The Art of Assembly Language

description

project

Transcript of Assembly Language Project

Page 1: Assembly Language Project

The Artof

Assembly Language

Page 2: Assembly Language Project

An assembly language is a low-level programming language for

a computer,microcontroller, or other programmable device, in

which each statement corresponds to a single machine

code instruction. Each assembly language is specific to a

particularcomputer architecture, in contrast to most high-level

programming languages, which are generally portable across

multiple systems.

Assembly language is converted into executable machine code by

a utility program referred to as an assembler; the conversion

process is referred to as assembly, or assembling the code.

Assembly language uses a mnemonic to represent each low-level

machine operation oropcode. Some opcodes require one or

more operands as part of the instruction, and most assemblers

can take labels and symbols as operands to represent addresses

and constants, instead of hard coding them into the

program. Macro assemblers include amacroinstruction facility so

that assembly language text can be pre-assigned to a name, and

that name can be used to insert the text into other code. Many

assemblers offer additional mechanisms to facilitate program

development, to control the assembly process, and to

aiddebugging.

Contents

  [hide] 

Page 3: Assembly Language Project

1 Key conceptso 1.1 Assembler

1.1.1 Number of passes 1.1.2 High-level assemblers

o 1.2 Assembly language2 Language designo 2.1 Basic elements

2.1.1 Opcode mnemonics and extended mnemonics 2.1.2 Data directives 2.1.3 Assembly directives

o 2.2 Macroso 2.3 Support for structured programming

3 Use of assembly languageo 3.1 Historical perspectiveo 3.2 Current usageo 3.3 Typical applications

4 Related terminology5 List of assemblers for different computer architectures6 Further details7 Example listing of assembly language source code8 See also9 References10 Further reading11 External links

[edit]Key concepts

[edit]Assembler

An assembler creates object code by translating assembly

instruction mnemonics into opcodes, and by resolving symbolic

names for memory locations and other entities.[1] The use of

Page 4: Assembly Language Project

symbolic references is a key feature of assemblers, saving

tedious calculations and manual address updates after program

modifications. Most assemblers also include macro facilities for

performing textual substitution—e.g., to generate common short

sequences of instructions as inline, instead of called subroutines.

Assemblers have been available since the 1950s and are far

simpler to write than compilers for high-level languages as each

mnemonic instruction / address mode combination translates

directly into a single machine language opcode. Modern

assemblers, especially forRISC architectures, such

as SPARC or POWER, as well as x86 and x86-64,

optimize Instruction scheduling to exploit the CPU

pipeline efficiently.[citation needed]

[edit]Number of passes

There are two types of assemblers based on how many passes

through the source are needed to produce the executable

program.

One-pass assemblers go through the source code once. Any

symbol used before it is defined will require "errata" at the end

of the object code (or, at least, no earlier than the point where

the symbol is defined) telling the linker or the loader to "go

back" and overwrite a placeholder which had been left where

the as yet undefined symbol was used.

Page 5: Assembly Language Project

Multi-pass assemblers create a table with all symbols and their

values in the first passes, then use the table in later passes to

generate code.

In both cases, the assembler must be able to determine the size

of each instruction on the initial passes in order to calculate the

addresses of subsequent symbols. This means that if the size of

an operation referring to an operand defined later depends on the

type or distance of the operand, the assembler will make a

pessimistic estimate when first encountering the operation, and if

necessary pad it with one or more "no-operation" instructions in a

later pass or the errata. In an assembler with peephole

optimization, addresses may be recalculated between passes to

allow replacing pessimistic code with code tailored to the exact

distance from the target.

The original reason for the use of one-pass assemblers was

speed of assembly— often a second pass would require

rewinding and rereading a tape or rereading a deck of cards. With

modern computers this has ceased to be an issue. The

advantage of the multi-pass assembler is that the absence of

errata makes the linking process (or the program load if the

assembler directly produces executable code) faster.[2]

[edit]High-level assemblers

More sophisticated high-level assemblers provide language

abstractions such as:

Advanced control structures

Page 6: Assembly Language Project

High-level procedure/function declarations and invocations

High-level abstract data types, including structures/records,

unions, classes, and sets

Sophisticated macro processing (although available on

ordinary assemblers since the late 1950s for IBM 700

series and since the 1960s for IBM/360, amongst other

machines)

Object-oriented programming  features such

as classes, objects, abstraction, polymorphism,

and inheritance [3]

See Language design below for more details.

[edit]Assembly language

A program written in assembly language consists of a series of

(mnemonic) processor instructions and meta-statements (known

variously as directives, pseudo-instructions and pseudo-ops),

comments and data. Assembly language instructions usually

consist of an opcode mnemonic followed by a list of data,

arguments or parameters.[4] These are translated by

an assembler into machine language instructions that can be

loaded into memory and executed.

For example, the instruction below tells an x86/IA-32 processor to

move an immediate 8-bit value into a register. The binary code for

this instruction is 10110 followed by a 3-bit identifier for which

register to use. The identifier for the AL register is 000, so the

followingmachine code loads the AL register with the data

01100001.[5]

Page 7: Assembly Language Project

10110000 01100001

This binary computer code can be made more human-readable

by expressing it in hexadecimal as follows

B0 61

Here, B0 means 'Move a copy of the following value into AL',

and 61 is a hexadecimal representation of the value 01100001,

which is 97 in decimal. Intel assembly language provides

the mnemonic MOV (an abbreviation of move) for instructions

such as this, so the machine code above can be written as follows

in assembly language, complete with an explanatory comment if

required, after the semicolon. This is much easier to read and to

remember.

MOV AL, 61h ; Load AL with 97 decimal (61 hex)

In some assembly languages the same mnemonic such as MOV

may be used for a family of related instructions for loading,

copying and moving data, whether these are immediate values,

values in registers, or memory locations pointed to by values in

registers. Other assemblers may use separate opcodes such as L

for "move memory to register", ST for "move register to memory",

LR for "move register to register", MVI for "move immediate

operand to memory", etc.

The Intel opcode 10110000 (B0) copies an 8-bit value into

the AL register, while 10110001 (B1) moves it into CL and

Page 8: Assembly Language Project

10110010 (B2) does so into DL. Assembly language examples for

these follow.[5]

MOV AL, 1h ; Load AL with immediate value 1MOV CL, 2h ; Load CL with immediate value 2MOV DL, 3h ; Load DL with immediate value 3

The syntax of MOV can also be more complex as the following

examples show.[6]

MOV EAX, [EBX] ; Move the 4 bytes in memory at the address contained in EBX into EAXMOV [ESI+EAX], CL ; Move the contents of CL into the byte at address ESI+EAX

In each case, the MOV mnemonic is translated directly into an

opcode in the ranges 88-8E, A0-A3, B0-B8, C6 or C7 by an

assembler, and the programmer does not have to know or

remember which.[5]

Transforming assembly language into machine code is the job of

an assembler, and the reverse can at least partially be achieved

by adisassembler. Unlike high-level languages, there is usually

a one-to-one correspondence between simple assembly

statements and machine language instructions. However, in some

cases, an assembler may provide pseudoinstructions (essentially

macros) which expand into several machine language instructions

to provide commonly needed functionality. For example, for a

machine that lacks a "branch if greater or equal" instruction, an

assembler may provide a pseudoinstruction that expands to the

Page 9: Assembly Language Project

machine's "set if less than" and "branch if zero (on the result of

the set instruction)". Most full-featured assemblers also provide a

rich macro language (discussed below) which is used by vendors

and programmers to generate more complex code and data

sequences.

Each computer architecture has its own machine language.

Computers differ in the number and type of operations they

support, in the different sizes and numbers of registers, and in the

representations of data in storage. While most general-purpose

computers are able to carry out essentially the same functionality,

the ways they do so differ; the corresponding assembly

languages reflect these differences.

Multiple sets of mnemonics or assembly-language syntax may

exist for a single instruction set, typically instantiated in different

assembler programs. In these cases, the most popular one is

usually that supplied by the manufacturer and used in its

documentation.

[edit]Language design

[edit]Basic elements

There is a large degree of diversity in the way the authors of

assemblers categorize statements and in the nomenclature that

they use. In particular, some describe anything other than a

machine mnemonic or extended mnemonic as a pseudo-

operation (pseudo-op). A typical assembly language consists of 3

Page 10: Assembly Language Project

types of instruction statements that are used to define program

operations:

Opcode  mnemonics

Data sections

Assembly directives

[edit]Opcode mnemonics and extended mnemonics

Instructions (statements) in assembly language are generally very

simple, unlike those in high-level language. Generally, a

mnemonic is a symbolic name for a single executable machine

language instruction (an opcode), and there is at least one

opcode mnemonic defined for each machine language instruction.

Each instruction typically consists of an operation or opcode plus

zero or more operands. Most instructions refer to a single value,

or a pair of values. Operands can be immediate (value coded in

the instruction itself), registers specified in the instruction or

implied, or the addresses of data located elsewhere in storage.

This is determined by the underlying processor architecture: the

assembler merely reflects how this architecture works. Extended

mnemonics are often used to specify a combination of an opcode

with a specific operand, e.g., the System/360 assemblers

use B as an extended mnemonic for BC with a mask of 15

and NOP for BC with a mask of 0.

Extended mnemonics are often used to support specialized uses

of instructions, often for purposes not obvious from the instruction

name. For example, many CPU's do not have an explicit NOP

instruction, but do have instructions that can be used for the

Page 11: Assembly Language Project

purpose. In 8086 CPUs the instruction xchg ax,ax is used for nop,

with nop being a pseudo-opcode to encode the instruction xchg

ax,ax. Some disassemblers recognize this and will decode

the xchg ax,ax instruction as nop. Similarly, IBM assemblers

for System/360 andSystem/370 use the extended

mnemonics NOP and NOPR for BC and BCR with zero masks.

For the SPARC architecture, these are known as synthetic

instructions[7]

Some assemblers also support simple built-in macro-instructions

that generate two or more machine instructions. For instance, with

some Z80 assemblers the instruction ld hl,bc is recognized to

generate ld l,c followed by ld h,b.[8] These are sometimes known

aspseudo-opcodes.

Mnemonics are arbitrary symbols; in 1985 the IEEE published

Standard 694 for a uniform set of mnemonics to be used by all

assemblers. The standard has since been withdrawn.

[edit]Data directives

There are instructions used to define data elements to hold data

and variables. They define the type of data, the length and

thealignment of data. These instructions can also define whether

the data is available to outside programs (programs assembled

separately) or only to the program in which the data section is

defined. Some assemblers classify these as pseudo-ops.

[edit]Assembly directives

Page 12: Assembly Language Project

Assembly directives, also called pseudo opcodes, pseudo-

operations or pseudo-ops, are instructions that are executed by

an assembler at assembly time, not by a CPU at run time. They

can make the assembly of the program dependent on parameters

input by a programmer, so that one program can be assembled

different ways, perhaps for different applications. They also can

be used to manipulate presentation of a program to make it easier

to read and maintain.

(For example, directives would be used to reserve storage areas

and optionally their initial contents.) The names of directives often

start with a dot to distinguish them from machine instructions.

Symbolic assemblers let programmers associate arbitrary names

(labels or symbols) with memory locations. Usually, every

constant and variable is given a name so instructions can

reference those locations by name, thus promoting self-

documenting code. In executable code, the name of each

subroutine is associated with its entry point, so any calls to a

subroutine can use its name. Inside

subroutines, GOTO destinations are given labels. Some

assemblers support local symbols which are lexically distinct from

normal symbols (e.g., the use of "10$" as a GOTO destination).

Some assemblers, such as NASM provide flexible symbol

management, letting programmers manage

different namespaces, automatically calculate offsets within data

structures, and assign labels that refer to literal values or the

result of simple computations performed by the assembler. Labels

Page 13: Assembly Language Project

can also be used to initialize constants and variables with

relocatable addresses.

Assembly languages, like most other computer languages, allow

comments to be added to assembly source code that are ignored

by the assembler. Good use of comments is even more important

with assembly code than with higher-level languages, as the

meaning and purpose of a sequence of instructions is harder to

decipher from the code itself.

Wise use of these facilities can greatly simplify the problems of

coding and maintaining low-level code. Raw assembly source

code as generated by compilers or disassemblers—code without

any comments, meaningful symbols, or data definitions—is quite

difficult to read when changes must be made.

[edit]Macros

Many assemblers support predefined macros, and others

support programmer-defined (and repeatedly re-definable)

macros involving sequences of text lines in which variables and

constants are embedded. This sequence of text lines may include

opcodes or directives. Once a macro has been defined its name

may be used in place of a mnemonic. When the assembler

processes such a statement, it replaces the statement with the

text lines associated with that macro, then processes them as if

they existed in the source code file (including, in some

assemblers, expansion of any macros existing in the replacement

text).

Page 14: Assembly Language Project

Note that this definition of "macro" is slightly different from the use

of the term in other contexts, like the C programming language. C

macros created through the #define directive typically are just one

line, or a few lines at most. Assembler macro instructions can be

lengthy "programs" by themselves, executed by interpretation by

the assembler during assembly.

Since macros can have 'short' names but expand to several or

indeed many lines of code, they can be used to make assembly

language programs appear to be far shorter, requiring fewer lines

of source code, as with higher level languages. They can also be

used to add higher levels of structure to assembly programs,

optionally introduce embedded debugging code via parameters

and other similar features.

Macro assemblers often allow macros to take parameters. Some

assemblers include quite sophisticated macro languages,

incorporating such high-level language elements as optional

parameters, symbolic variables, conditionals, string manipulation,

and arithmetic operations, all usable during the execution of a

given macro, and allowing macros to save context or exchange

information. Thus a macro might generate a large number of

assembly language instructions or data definitions, based on the

macro arguments. This could be used to generate record-style

data structures or "unrolled" loops, for example, or could generate

entire algorithms based on complex parameters. An organization

using assembly language that has been heavily extended using

such a macro suite can be considered to be working in a higher-

Page 15: Assembly Language Project

level language, since such programmers are not working with a

computer's lowest-level conceptual elements.

Macros were used to customize large scale software systems for

specific customers in the mainframe era and were also used by

customer personnel to satisfy their employers' needs by making

specific versions of manufacturer operating systems. This was

done, for example, by systems programmers working with IBM's

Conversational Monitor System / Virtual Machine (VM/CMS) and

with IBM's "real time transaction processing" add-ons, Customer

Information Control System CICS, and ACP/TPF, the

airline/financial system that began in the 1970s and still runs

many large computer reservations systems (CRS) and credit card

systems today.

It was also possible to use solely the macro processing abilities of

an assembler to generate code written in completely different

languages, for example, to generate a version of a program

in COBOL using a pure macro assembler program containing

lines of COBOL code inside assembly time operators instructing

the assembler to generate arbitrary code.

This was because, as was realized in the 1960s, the concept of

"macro processing" is independent of the concept of "assembly",

the former being in modern terms more word processing, text

processing, than generating object code. The concept of macro

processing appeared, and appears, in the C programming

language, which supports "preprocessor instructions" to set

variables, and make conditional tests on their values. Note that

Page 16: Assembly Language Project

unlike certain previous macro processors inside assemblers, the

C preprocessor was notTuring-complete because it lacked the

ability to either loop or "go to", the latter allowing programs to

loop.

Despite the power of macro processing, it fell into disuse in many

high level languages (major exceptions being C/C++ and PL/I)

while remaining a perennial for assemblers.

Macro parameter substitution is strictly by name: at macro

processing time, the value of a parameter is textually substituted

for its name. The most famous class of bugs resulting was the

use of a parameter that itself was an expression and not a simple

name when the macro writer expected a name. In the macro: foo:

macro a load a*b the intention was that the caller would provide the

name of a variable, and the "global" variable or constant b would

be used to multiply "a". If foo is called with the parameter a-c, the

macro expansion of load a-c*b occurs. To avoid any possible

ambiguity, users of macro processors can parenthesize formal

parameters inside macro definitions, or callers can parenthesize

the input parameters.[9]

[edit]Support for structured programming

Some assemblers have incorporated structured

programming elements to encode execution flow. The earliest

example of this approach was in the Concept-14 macro set,

originally proposed by Dr. H.D. Mills (March, 1970), and

implemented by Marvin Kessler at IBM's Federal Systems

Division, which extended the S/360 macro assembler with

Page 17: Assembly Language Project

IF/ELSE/ENDIF and similar control flow blocks.[10] This was a way

to reduce or eliminate the use of GOTO operations in assembly

code, one of the main factors causing spaghetti code in assembly

language. This approach was widely accepted in the early '80s

(the latter days of large-scale assembly language use).

A curious design was A-natural, a "stream-oriented" assembler for

8080/Z80 processors[citation needed] from Whitesmiths Ltd.(developers

of the Unix-like Idris operating system, and what was reported to

be the first commercial C compiler). The language was classified

as an assembler, because it worked with raw machine elements

such as opcodes, registers, and memory references; but it

incorporated an expression syntax to indicate execution order.

Parentheses and other special symbols, along with block-oriented

structured programming constructs, controlled the sequence of

the generated instructions. A-natural was built as the object

language of a C compiler, rather than for hand-coding, but its

logical syntax won some fans.

There has been little apparent demand for more sophisticated

assemblers since the decline of large-scale assembly language

development.[11] In spite of that, they are still being developed and

applied in cases where resource constraints or peculiarities in the

target system's architecture prevent the effective use of higher-

level languages.[12]

[edit]Use of assembly language

[edit]Historical perspective

Page 18: Assembly Language Project

Assembly languages date to the introduction of the stored-

program computer. The EDSAC computer (1949) had an

assembler calledinitial orders featuring one-letter mnemonics.[13] Nathaniel Rochester wrote an assembler for an IBM

701 (1954). SOAP (Symbolic Optimal Assembly Program) (1955)

was an assembly language for the IBM 650 computer written by

Stan Poley.[14]

Assembly languages eliminated much of the error-prone and

time-consuming first-generation programming needed with the

earliest computers, freeing programmers from tedium such as

remembering numeric codes and calculating addresses. They

were once widely used for all sorts of programming. However, by

the 1980s (1990s on microcomputers), their use had largely been

supplanted by high-level languages[citation needed], in the search for

improved programming productivity. Today assembly language is

still used for direct hardware manipulation, access to specialized

processor instructions, or to address critical performance issues.

Typical uses are device drivers, low-level embedded systems,

and real-time systems.

Historically, a large number of programs have been written

entirely in assembly language. Operating systems were entirely

written in assembly language until the introduction of

the Burroughs MCP (1961), which was written in ESPOL, an Algol

dialect. Many commercial applications were written in assembly

language as well, including a large amount of the IBM

mainframe software written by large

Page 19: Assembly Language Project

corporations. COBOL, FORTRAN and some PL/I eventually

displaced much of this work, although a number of large

organizations retained assembly-language application

infrastructures well into the '90s.

Most early microcomputers relied on hand-coded assembly

language, including most operating systems and large

applications. This was because these systems had severe

resource constraints, imposed idiosyncratic memory and display

architectures, and provided limited, buggy system services.

Perhaps more important was the lack of first-class high-level

language compilers suitable for microcomputer use. A

psychological factor may have also played a role: the first

generation of microcomputer programmers retained a hobbyist,

"wires and pliers" attitude.

In a more commercial context, the biggest reasons for using

assembly language were minimal bloat (size), minimal overhead,

greater speed, and reliability.

Typical examples of large assembly language programs from this

time are IBM PC DOS operating systems and early applications

such as the spreadsheet program Lotus 1-2-3. Even into the

1990s, most console video games were written in assembly,

including most games for the Mega Drive/Genesis and the Super

Nintendo Entertainment System[citation needed]. According to some

industry insiders, the assembly language was the best computer

language to use to get the best performance out of the Sega

Saturn, a console that was notoriously challenging to develop and

Page 20: Assembly Language Project

program games for.[15] The popular arcade game NBA Jam (1993)

is another example. Assembly language has long been the

primary development language for many popular home computers

of the 1980s and 1990s (such as theSinclair ZX

Spectrum, Commodore 64, Commodore Amiga, and Atari ST).

This was in large part because BASIC dialects on these systems

offered insufficient execution speed, as well as insufficient

facilities to take full advantage of the available hardware on these

systems. Some systems, most notably the Amiga, even have

IDEs with highly advanced debugging and macro facilities, such

as the freeware ASM-One assembler, comparable to that

of Microsoft Visual Studio facilities (ASM-One predates Microsoft

Visual Studio).

The Assembler for the VIC-20 was written by Don French and

published by French Silk. At 1,639 bytes in length, its author

believes it is the smallest symbolic assembler ever written. The

assembler supported the usual symbolic addressing and the

definition of character strings or hex strings. It also allowed

address expressions which could be combined

with addition, subtraction, multiplication, division,logical

AND, logical OR, and exponentiation operators.[16]

[edit]Current usage

There have always been debates over the usefulness and

performance of assembly language relative to high-level

languages. Assembly language has specific niche uses where it is

important; see below. But in general, modern optimizing

Page 21: Assembly Language Project

compilers are claimed[17] to render high-level languages into code

that can run as fast as hand-written assembly, despite the

counter-examples that can be found.[18][19][20] The complexity of

modern processors and memory sub-systems makes effective

optimization increasingly difficult for compilers, as well as

assembly programmers.[21][22] Moreover, and to the dismay of

efficiency lovers, increasing processor performance has meant

that most CPUs sit idle most of the time,[citation needed] with delays

caused by predictable bottlenecks such as I/Ooperations

and paging. This has made raw code execution speed a non-

issue for many programmers.

There are some situations in which developers might choose to

use assembly language:

A stand-alone executable of compact size is required that must

execute without recourse to the run-time components

or librariesassociated with a high-level language; this is

perhaps the most common situation. For example, firmware for

telephones, automobile fuel and ignition systems, air-

conditioning control systems, security systems, and sensors.

Code that must interact directly with the hardware, for example

in device drivers and interrupt handlers.

Programs that need to use processor-specific instructions not

implemented in a compiler. A common example is the bitwise

rotation instruction at the core of many encryption algorithms.

Programs that create vectorized functions for programs in

higher-level languages such as C. In the higher-level language

Page 22: Assembly Language Project

this is sometimes aided by compiler intrinsic functions which

map directly to SIMD mnemonics, but nevertheless result in a

one-to-one assembly conversion specific for the given vector

processor.

Programs requiring extreme optimization, for example an

inner loop in a processor-intensive algorithm. Game

programmers take advantage of the abilities of hardware

features in systems, enabling games to run faster. Also large

scientific simulations require highly optimized algorithms,

e.g. linear algebra with BLAS [18] [23]  or discrete cosine

transformation (e.g. SIMD assembly version fromx264 [24] )

Situations where no high-level language exists, on a new or

specialized processor, for example.

Programs need precise timing such as real-time  programs such as simulations, flight navigation

systems, and medical equipment. For example, in a fly-by-wire system, telemetry must be interpreted and acted upon within strict time constraints. Such systems must eliminate sources of unpredictable delays, which may be created by (some) interpreted languages, automatic garbage collection, paging operations, or preemptive multitasking. However, some higher-level languages incorporate run-time components and operating system interfaces that can introduce such delays. Choosing assembly or lower-level languages for such systems gives programmers greater visibility and control over processing details.

cryptographic algorithms that must always take strictly the same time to execute, preventing timing attacks.

Page 23: Assembly Language Project

Situations where complete control over the environment is

required, in extremely high security situations where nothing

can be taken for granted.

Computer viruses , bootloaders, certain device drivers, or other

items very close to the hardware or low-level operating system.

Instruction set simulators  for monitoring, tracing

and debugging where additional overhead is kept to a

minimum

Reverse-engineering  and modifying program files such as existing binaries that may or may not have originally been

written in a high-level language, for example when trying to recreate programs for which source code is not available or has been lost, or cracking copy protection of proprietary software.

Video games  (also termed ROM hacking), which is possible via several methods. The most widely employed is altering program code at the assembly language level.

Self modifying code , to which assembly language lends itself

well.

Games  and other software for graphing calculators.[25]

Assembly language is still taught in most computer

science and electronic engineering programs. Although few

programmers today regularly work with assembly language as a

tool, the underlying concepts remain very important. Such

fundamental topics as binary arithmetic, memory allocation, stack

processing, character set encoding, interrupt processing,

and compiler design would be hard to study in detail without a

grasp of how a computer operates at the hardware level. Since a

Page 24: Assembly Language Project

computer's behavior is fundamentally defined by its instruction

set, the logical way to learn such concepts is to study an

assembly language. Most modern computers have similar

instruction sets. Therefore, studying a single assembly language

is sufficient to learn: I) the basic concepts; II) to recognize

situations where the use of assembly language might be

appropriate; and III) to see how efficient executable code can be

created from high-level languages. [26] This is analogous to

children needing to learn the basic arithmetic operations (e.g.,

long division), although calculatorsare widely used for all except

the most trivial calculations.

[edit]Typical applications

Assembly language is typically used in a system's boot code,

(BIOS on IBM-compatible PC systems and CP/M), the low-

level code that initializes and tests the system hardware prior

to booting the OS, and is often stored in ROM.

Some compilers translate high-level languages into assembly

first before fully compiling, allowing the assembly code to be

viewed for debugging and optimization purposes.

Relatively low-level languages, such as C, allow the

programmer to embed assembly language directly in the

source code. Programs using such facilities, such as the Linux

kernel, can then construct abstractions using different

assembly language on each hardware platform. The

Page 25: Assembly Language Project

system's portable code can then use these processor-specific

components through a uniform interface.

Assembly language is valuable in reverse engineering. Many

programs are distributed only in machine code form which is

straightforward to translate into assembly language, but more

difficult to translate into a higher-level language. Tools such as

theInteractive Disassembler make extensive use of

disassembly for such a purpose.

Assemblers can be used to generate blocks of data, with no

high-level language overhead, from formatted and commented

source code, to be used by other code.[citation needed]

[edit]Related terminology

Assembly language or assembler language is commonly

called assembly, assembler, ASM, or symbolic machine

code. A generation of IBM mainframe programmers called

it ALC for Assembly Language Code or BAL[27] for Basic

Assembly Language. Calling the language assembler might

be considered potentially confusing and ambiguous, since this

is also the name of the utility program that translates assembly

language statements into machine code. However, this usage

has been common among professionals and in the literature for

decades.[28] Similarly, some early computers called

their assembler their assembly program.[29])

Page 26: Assembly Language Project

The computational step where an assembler is run, including

all macro processing, is termed assembly time. The

assembler is said to be "assembling" the source code.

The use of the word assembly dates from the early years of

computers (cf. short code, speedcode).

A cross assembler (see also cross compiler) is an assembler

that is run on a computer or operating system of a different

type from the system on which the resulting code is to run.

Cross-assembling may be necessary if the target system

cannot run an assembler itself, as is typically the case for small

embedded systems. The computer on which the cross

assembler is run must have some means of transporting the

resulting machine code to the target system. Common

methods involve transmitting an exact byte-by-byte copy of the

machine code or an ASCII representation of the machine code

in a portable format (such as Motorola orIntel hexadecimal)

through a compatible interface to the target system for

execution.

An assembler directive or pseudo-opcode is a command

given to an assembler "directing it to perform operations other

than assembling instructions."[1] Directives affect how the

assembler operates and "may affect the object code, the

symbol table, the listing file, and the values of internal

assembler parameters." Sometimes the term pseudo-opcode is

reserved for directives that generate object code, such as

those that generate data.[30]

Page 27: Assembly Language Project

A meta-assembler is "a program that accepts the syntactic

and semantic description of an assembly language, and

generates an assembler for that language." [31]

[edit]List of assemblers for different computer architectures

Main article: List of assemblers

[edit]Further details

For any given personal computer, mainframe, embedded system,

and game console, both past and present, at least one – possibly

dozens – of assemblers have been written. For some examples,

see the list of assemblers.

On Unix systems, the assembler is traditionally called as,

although it is not a single body of code, being typically written

anew for each port. A number of Unix variants use GAS.

Within processor groups, each assembler has its own dialect.

Sometimes, some assemblers can read another assembler's

dialect, for example, TASM can read old MASM code, but not the

reverse. FASM and NASM have similar syntax, but each support

different macros that could make them difficult to translate to each

other. The basics are all the same, but the advanced features will

differ.[32]

Also, assembly can sometimes be portable across different

operating systems on the same type of CPU. Calling

conventions between operating systems often differ slightly or not

Page 28: Assembly Language Project

at all, and with care it is possible to gain some portability in

assembly language, usually by linking with a C library that does

not change between operating systems.[citation needed] An instruction

set simulator can process theobject

code/ binary of any assembler to achieve portability even

across platforms with an overhead no greater than a typical

bytecode interpreter.[citation needed] This is similar to use of microcode

to achieve compatibility across a processor family.

Some higher level computer languages, such as C and Borland

Pascal, support inline assembly where sections of assembly

code, in practice usually brief, can be embedded into the high

level language code. The Forth language commonly contains an

assembler used in CODE words.

An emulator can be used to debug assembly-language programs.

[edit]Example listing of assembly language source code

Example: x86, 32 bit, using NASM. Note: this is a subroutine not a complete program.

178 ;ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc 179 ; 180 ; counts a zero terminated ASCII string to determine its size 181 ; in: eax = start address of the zero terminated string

Page 29: Assembly Language Project

182 ; out: ecx = count = the length of the string 183 184 zstr_count: ; entry point 185 186 00000030 B9FFFFFFFF mov ecx, -1 ; init the loop counter, pre-decrement to compensate for the increment 187 188 .loop: 189 00000035 41 inc ecx ; add 1 to the loop counter 190 191 00000036 803C0800 cmp BYTE [eax + ecx], 0 ; compare the value at the string's [starting memory address Plus the loop offset], to zero 192 0000003A 75F9 jne .loop ; if the memory value is Not Equal to Zero then jump to the label called '.loop' ; otherwise continue to the next line of code. 193 194 .done: 195 ; we don't do a final increment, because even though the count is base 1, we 196 ; do not include the zero terminator in the string's length. 197 0000003C C3 ret ; return to the calling program 198

Page 30: Assembly Language Project

The above is the List output of NASM, the first column (on the left)

is simply the line number in the listing and is otherwise

meaningless. This subroutine was extracted from a much larger

program, that's why it does not start at zero. The next (second)

column is the relative address, in hex, of where the code will be

placed in memory. The third column is the actual compiled code.

For instance, B9 is the x86 opcode to (load) MOV ECX with an

immediate value; the FFFFFFFF is a -1 in 2's complement binary

arithmetic (32 bits).

The lines with colons are symbolic labels, the labels do not create

code, they are a way to tell the assembler that we want to be able

to reference those locations. The .done: label is only there for

clarity of where the program ends, it does not serve any other

purpose. Putting a dot '.' in front of a label is a feature of NASM, it

declares the label as local to the subroutine.

This article, which discusses assembly language programming, accompanies the book Embedded Microcomputer Systems: Real Time Interfacing published by Brooks-Cole 1999. This document has four overall parts     Overview      Syntax (fields, pseudo ops) (this document)     Local variables     Examples

Assembly Language Syntax     Programs written in assembly language consist of a sequence of source statements. Each source statement consists of a sequence of ASCII characters ending with a

Page 31: Assembly Language Project

carriage return. Each source statement may include up to four fields: a label, an operation (instruction mnemonic or assembler directive), an operand, and a comment. The following are examples of an assembly directive and a regular machine instruction.PORTA  equ   $0000  ; Assembly time constantInp    ldaa  PORTA  ; Read data from fixed address I/O data port

An assembly language statement contains the following fields.     Label Field can be used to define a symbol    Operation Field defines the operation code or pseudo-op    Operand Field specifies either the address or the data.    Comment Field allows the programmer to document the software.

Sometimes not all four fields are present in an assembly language statement. A line may contain just a comment. The first token in these lines must begin with a star (*) or a semicolon (;). For example,; This line is a comment* This is a comment too     * This line is a comment

Instructions with inherent mode addressing do not have an operand field. For example,label  clra       comment       deca       comment        cli        comment        inca       comment

Recommendation: For small programs, you enable automatic assembly colors. The editor will then color each field according to its type.

Recommendation: For large programs, you disable automatic assembly colors, because the system will run too slow. Instead, use the assembler to color the source code.

--------------------------------------------------------------------------------------Label FieldThe label field occurs as the first field of a source statement. The label field can take one of the following three forms:

A. An asterisk (*) or semicolon (;) as the first character in the label field indicates that the rest of the source statement is a comment. Comments are ignored by the Assembler, and are printed on the source listing only for the programmer's information. Examples:

Page 32: Assembly Language Project

* This line is a comment; This line is also a comment

B. A white-space character (blank or tab) as the first character indicates that the label field is empty. The line has no label and is not a comment. These assembly lines have no labels:       ldaa 0       rmb  10

C. A symbol character as the first character indicates that the line has a label. Symbol characters are the upper or lower case letters a- z, digits 0-9, and the special characters, period (.), dollar sign ($), and underscore (_). Symbols consist of one to 15 characters, the first of which must be alphabetic or the special characters period (.) or underscore (_). All characters are significant and upper and lower case letters are distinct.

A symbol may occur only once in the label field. If a symbol does occur more than once in a label field, then each reference to that symbol will be flagged with an error. The exception to this rule is the set pseudo-op that allows you to define and redefine the same symbol. We typically use set to define the stack offsets for the local variables in a subroutine. For more information see the examples of local variables. Set allows two separate subroutines to re-use the same name for their local variables.

With the exception of the equ  = and set  directives, a label is assigned the value of the program counter of the first byte of the instruction or data being assembled. The value assigned to the label is absolute. Labels may optionally be ended with a colon (:). If the colon is used it is not part of the label but merely acts to set the label off from the rest of the source line. Thus the following code fragments are equivalent:here: deca      bne  here

      here  deca      bne  here

A label may appear on a line by itself. The assembler interprets this as set the value of the label equal to the current value of the program counter. A label may occur on a line with a pseudo-op.

The symbol table has room for at least 2000 symbols of length 8 characters or less. Additional characters up to 15 are permissible at the expense of decreasing the maximum number of symbols possible in the table.

Page 33: Assembly Language Project

--------------------------------------------------------------------------------------Operation Field     The operation field occurs after the label field, and must be preceded by at least one white-space character. The operation field must contain a legal opcode mnemonic or an assembler directive. Upper case characters in this field are converted to lower case before being checked as a legal mnemonic. Thus 'nop', 'NOP', and 'NoP' are recognized as the same mnemonic. Entries in the operation field may be one of two types:

Opcode. These correspond directly to the machine instructions. The operation code includes any register name associated with the instruction. These register names must not be separated from the opcode with any white-space characters. Thus 'clra' means clear accumulator A, but 'clr a' means clear memory location identified by the label 'a'. The available instructions depend on the microcomputer you are using

Directive. These are special operation codes known to the Assembler that control the assembly process rather than being translated into machine instructions. The pseudo-op codes supported by this assembler are

Group A Group B Group C meaning

org org .org Specific absolute address to put subsequent object code

= equ   Define a constant symbol

  set   Define or redefine a constant symbol

dc.b db fcb .byte Allocate byte(s) of storage with initialized values

  fcc   Create an ASCII string (no termination character)

dc.w dw fdb .word Allocate word(s) of storage with initialized values

dc.l dl   .long Allocate 32 bit long word(s) of storage with initialized values

ds ds.b rmb .blkb Allocate bytes of storage without initialization

ds.w   .blkw Allocate bytes of storage without initialization

ds.l   .blkl Allocate 32 bit words of storage without initialization

end end .end Signifies the end of the source code (TExaS ignores these)

 

 

--------------------------------------------------------------------------------------Operand Field     The operand field's interpretation is dependent on the contents of the operation field. The operand field, if required, must follow the operation field, and must be preceded by at least one white-space character. The operand field may contain a

Page 34: Assembly Language Project

symbol, an expression, or a combination of symbols and expressions separated by commas. There can be no white-spaces in the operand field. For example the following two lines produce identical object code because of the space between data and + in the first line:    ldaa  data  +  1    ldaa  data

     The operand field of machine instructions is used to specify the addressing mode of the instruction, as well as the operand of the instruction. The following table summarizes the operand field formats.

Operand  Format  6811/6812exampleno operand accumulator and inherent clra<expression> direct, extended, or relative ldaa 4#<expression> immediate ldaa #4<expression>,R indexed with address register ldaa 4,x<expr>,<expr> bit set or clear bset 4,#$01<expr>,<expr>,<expr> bit test and branch brset 4,#$01,there<expr>,R,<expr>,<expr> bit test and branch brset 4,x,#$01,there

The valid syntax of the operand field depends on the microcomputer. For a detailed explanation of the instructions and their addressing modes, see the help system with the TExaS application.

--------------------------------------------------------------------------------------Expressions.      An expression is a combination of symbols, constants, algebraic operators, and parentheses. The expression is used to specify a value that is to be used as an operand. Expressions may consist of symbols, constants, or the character '*' (denoting the current value of the program counter) joined together by one of the operators: + - * / % & | ^ .

     +  add     -  subtract     *  multiply     /  divide     %  remainder after division     &  bitwise and     |  bitwise or     ^  bitwise exclusive or

Page 35: Assembly Language Project

Expressions may include parentheses and other expressions. Expressions are evaluated using the standard arithmetic precedence. Evaluation occurs left to right for multiple operations with the same precedence. Arithmetic is carried out in signed 32-bit twos-complement integer precision (on the IBM PC).

Precedence operationHighest parentheses2 unary + - ~3 binary * / % &lowest binary + - ^ |

 

     Each symbol is associated with a 16-bit integer value that is used in place of the symbol during the expression evaluation. The asterisk (*) used in an expression as a symbol represents the current value of the location counter (the first byte of a multi-byte instruction)

     Constants represent quantities of data that do not vary in value during the execution of a program. Constants may be presented to the assembler in one of four formats: decimal, hexadecimal, binary, or ASCII. The programmer indicates the number format to the assembler with the following prefixes:

    0x    hexadecimal, C syntax    %    binary    'c'    ASCII code for a single letter ‘c’

Unprefixed constants are interpreted as decimal. The assembler converts all constants to binary machine code and are displayed in the assembly listing as hexadecimal.

A decimal constant consists of a string of numeric digits. The value of a decimal constant must fall in the range 0-65535, inclusive. The following example shows both valid and invalid decimal constants:

VALID INVALID REASON INVALID12 123456 more than 5 digits12345 12.3 invalid character

A hexadecimal constant consists of a maximum of four characters from the set of digits (0-9) and the upper case alphabetic letters (A-F), and is preceded by a dollar sign ($). Hexadecimal constants must be in the range $0000 to $FFFF. The following example shows both valid and invalid hexadecimal constants:

Page 36: Assembly Language Project

VALID INVALID REASON INVALID$12 ABCD no preceding "$"$ABCD $G2A invalid character$001F $2F018 too many digits

A binary constant consists of a maximum of 16 ones or zeros preceded by a percent sign (%). The following example shows both valid and invalid binary constants:

VALID INVALID REASON INVALID%00101 1010101 missing percent%1 %10011000101010111 too many digits%10100 %210101 invalid digit

A single ASCII character can be used as a constant in expressions. ASCII constants are surrounded by a single quotes ('). Any character, except the single quote, can be used as a character constant. The following example shows both valid and invalid character constants:

VALID INVALID REASON INVALID'*' 'VALID' too long

For the invalid case above the assembler will not indicate an error. Rather it will assemble the first character and ignore the remainder.

--------------------------------------------------------------------------------------Comment Field     The last field of an Assembler source statement is the comment field. This field is optional and is only printed on the source listing for documentation purposes. The comment field is separated from the operand field (or from the operation field if no operand is required) by at least one white-space character. The comment field can contain any printable ASCII   characters.      As software developers, our goal is to produce code that not only solves our current problem, but can serve as the basis of our future problems. In order to reuse software we must leave our code in a condition such that future programmer (including ourselves) can easily understand its purpose, constraints, and implementation. Documentation is not something tacked onto software after it is done, but rather a discipline built into it at each stage of the development. We carefully develop a programming style providing appropriate comments. I feel a comment that tells us why we perform certain functions is more informative than comments that tell us what the functions are. An examples of bad comments would be:      clr  Flag    Flag=0

Page 37: Assembly Language Project

      sei          Set I=1      ldaa $1003   Read PortC

These are bad comments because they provide no information to help us in the future to understand what the program is doing. An example of good comments would be:      clr  Flag    Signifies no key has been typed      sei          The following code will not be interrupted      ldaa $1003   Bit7=1 iff the switch is pressed

These are good comments because they make it easier to change the program in the future.     Self-documenting code is software written in a simple and obvious way, such that its purpose and function are self-apparent. To write wonderful code like this, we first must formulate the problem organizing it into clear well-defined subproblems. How we break a complex problem into small parts goes a long way making the software self-documenting. Both the concept of abstraction (introduced in the last section) and modular code (to be presented in the next section) address this important issue of software organization.      Maintaining software is the process of fixing bugs, adding new features, optimizing for speed or memory size, porting to new computer hardware, and configuring the software system for new situations. It is the MOST IMPORTANT phase of software development. My personal opinion is that flowchart charts or software manuals are not good mechanisms for documenting programs because it is difficult to keep these types of documentation up to date when modifications are made.     We should use careful indenting, and descriptive names for variables, functions, labels, I/O ports. Liberal use of equ provide explanation of software function without cost of execution speed or memory requirements. A disciplined approach to programming is to develop patterns of writing that you consistently follow. Software developers are unlike short story writers. It is OK to use the same subroutine outline over and over again. In the following program, notice the following style issues:

     1) Begins and ends with a line of *'s     2) States the purpose of the subroutine     3) Gives the input/output parameters, what they mean and how they are passed     4) Different phases (submodules) of the code delineated by a line of -'s

******************* Max ******************************** Purpose: returns the maximum of two 16 bit numbers* This subroutine creates three 16 bit local variables * Inputs: Num1 and Num2 are two 16 bit unsigned numbers

Page 38: Assembly Language Project

*  passed in on the stack* Output: RegX is the maximum of X,Y* Destroyed: CCR* Calling sequence*  ldx  #100*  pshx    Num1 pushed on stack*  ldx  #200*  pshx     Num2 pushed on stack*  jsr  Max*  puly    Balance stack*  puly    Result in RegXFirst   set  0   The first 16 bit local variableSecond  set  2   The second 16 bit local variableResult  set  4   The Maximum of first,secondNum1    set  12  Input parameter1Num2    set  10  Input parameter2Max  pshy        Save registers, that will be modified* - - - - - - - - - - - - - - - - - - - - - - - - - - -     pshx        Allocate Result local variable     pshx        Allocate Second local variable     pshx        Allocate First local variable* - - - - - - - - - - - - - - - - - - - - - - - - - - -     tsx            Create stack frame pointer     ldy  Num1,X     sty  First,X   Initialize First=Num1     ldy  Num2,X     sty  Second,X  Initialize Second=Num2     ldy  First,X     sty  Result,X  Guess that Result=First     cpy  Second,X     bhs  MaxOK     Skip if First>=Second     ldy  Second,X  Since First<Second     sty  Result,X  make Result=SecondMaxOK ldx Result,X  Return Result in RegX* - - - - - - - - - - - - - - - - - - - - - - - - - - -     puly    Deallocate local variables     puly     puly* - - - - - - - - - - - - - - - - - - - - - - - - - - -     puly    Restore registers     rts

****************** End of Max *****************************

--------------------------------------------------------------------------------------Assembly Listing     The assembler output includes an optional listing of the source program and an object files. The listing file is created when the TheList.RTF file is open.      Each line of the listing contains a reference line number, the address and bytes assembled, and the original source input line. If an input line causes more than 8 bytes to be output (e.g., a long FCC directive), the additional bytes are included in the object code (S19 file or loaded into memory) but not shown in the listing. There are

Page 39: Assembly Language Project

three assembly options, each can be toggled on/off using the Assembly->Options command.

(4) cycles shows the number of cycles to execute this instruction

[100] total gives a running cycle total since last org pseudo-op{PPP} type gives the cycle type

The codes used in the cycle type are different for each microcomputer     The assembly listing may optionally contain a symbol table. The symbol table is included at the end of the assembly listing if enabled. The symbol table contains the name of each symbol, along with its defined value. Since the set pseudo-op can be used to redefine the symbol, the value in the symbol table is the last definition.

--------------------------------------------------------------------------------------Assembly Errors

Programming errors fall into two categories. Simple typing/syntax error will be flagged by the TExaS assembler as an error when the assembler tries to translate source code into machine code. The more difficult programming errors to find and remove are functional bugs that can be identified during execution, when the program does not perform as expected. Error messages are meant to be self-explanatory. The assembler has a verbose (see Assembler->Options command) mode that provides more details about the error and suggests possible solutions.

Assembler Error Types1) Undefined symbol: Program refers to a label that does not exist     How to fix: check spelling of both the definition and access2) Undefined opcode or pseudo-op     How to fix: check the spelling/availability of the instruction3) Addressing mode not available     How to fix: look up the addressing modes available for the instruction4) Expression error     How to fix: check parentheses, start with a simpler expression5) Phasing Error occurs when the value of a symbol changes from pass1 to pass2     How to fix: first remove any undefined symbols, then remove forward references6) Address error     How to fix: use org pseudo-op’s to match available memory. Error diagnostic messages are placed in the listing file just after the line containing the error. If there is no TheList.RTF file, then assembly errors are reported

Page 40: Assembly Language Project

inTheLog.RTF file. If there is neither TheList.RTF or TheLog.RTF files, then assembly errors are not reported.

--------------------------------------------------------------------------------------Phasing errors     A phasing error occurs during Pass 2 of the assembler when the address of a label is different than when it was previously calculated. The purpose of Pass 1 of the assembler is to create the symbol table. In order to calculate the address of each assembly line, the assembler must be able to determine the exact number of bytes each line will take. For most instructions, the number of bytes required is fixed and easy to calculate, but for other instructions, the number of bytes can vary. A phasing errors occur when the assembler calculates the size of an instruction different in Pass 2 than previously calculated in Pass 2. Sometimes a phasing error often occurs on a line further down in the program than where the mistake occurs. A phasing error usually results from the use of forward references. In this 6812 example the symbol "index" is not available at the time of assembling the ldaa index,x. The assembler incorrectly chooses the 2 byte IDX addressing mode version rather than the correct 3 byte IDX1 mode.       ldaa  index,xindex  equ 100;  ...loop   ldaa #0

The listing shows the phasing errorCopyright 1999-2000 Test EXecute And Simulate$0000 A6E064         ldaa  index,x$0064         index  equ  100            ;  ...$0003 8600    loop   ldaa  #0##### Phasing errorThis line was at address $0002 in pass 1, now in pass 2 it is $0003

***************Symbol Table*********************index  $0064 loop  $0002 ##### Assembly failed, 1 errors!

When the assembler gets to loop, the Pass 1 and Pass 2 values are off by one causing a phasing error at the loop ldaa #0 instruction. The solution here to simply put the index equ 100 first.

 

--------------------------------------------------------------------------------------Assembler pseudo-op's

Page 41: Assembly Language Project

Pseudo-op's are specific commands to the assembler that are interpreted during the assembly process. A few of them create object code, but most do not. There are two common formats for the pseudo-op's used when developing Motorola assembly language. The TExaS assembler supports both categories. If you plan to export software developed with TExaS to another application, then you should limit your use only the psuedo-op's compatible with that application.

Group A is supported by Motorola's MCUez, HiWare and ImageCraft's ICC11 and ICC12Group B is supported by Motorola's DOS level AS05, AS08, AS11 and AS12Group C are some alternative definitions

Group A Group B Group C meaning

org org .org Specific absolute address to put subsequent object code

= equ   Define a constant symbol

  set   Define or redefine a constant symbol

dc.b db fcb .byte Allocate byte(s) of storage with initialized values

  fcc   Create an ASCII string (no termination character)

dc.w dw fdb .word Allocate word(s) of storage with initialized values

dc.l dl   .long Allocate 32 bit long word(s) of storage with initialized values

ds ds.b rmb .blkb Allocate bytes of storage without initialization

ds.w   .blkw Allocate bytes of storage without initialization

ds.l   .blkl Allocate 32 bit words of storage without initialization

end end .end Signifies the end of the source code (TExaS ignores these)

 

--------------------------------------------------------------------------------------equ equate symbol to a value

     <label> equ <expression> (<comment>)     <label> = <expression> (<comment>)

The EQU (or =) directive assigns the value of the expression in the operand field to the label. The equ directive assigns a value other than the program counter to the label. The label cannot be redefined anywhere else in the program. The expression cannot contain any forward references or undefined symbols. Equates with forward references are flagged with Phasing Errorsphasing_error. In the following example, the local variable names can not be reused in another subroutine:; MC68HC812A4

Page 42: Assembly Language Project

; *****binding phase***************I    equ  -4PT   equ  -3Ans  equ  -1; *******allocation phase *********function pshx    save old Reg X     tsx         create stack frame pointer     leas -4,sp  allocate four bytes for I,PT,Result; ********access phase ************     clr  I,x    Clear I     ldy  PT,x   Reg Y is a copy of PT     staa Ans,x  store into Ans; ********deallocation phase *****     txs    deallocation     pulx   restore old X     rts

In the following example, the equ pseudo-op is used to define the I/O ports and to access the various elements of the linked structure.* ***********Moore.RTF********************** Jonathan W. Valvano 7/18/98 10:54:28 PM* Moore Finite State Machine Controller * PC1,PC0 are binary inputs, PB1,PB0 are binary outputsPORTB  equ  0x01DDRB   equ  0x03PORTC  equ  0x04DDRC   equ  0x06TCNT   equ  0x84  ; 16 bit unsigned clock, incremented each cycleTSCR   equ  0x86  ; set bit 7=1 to enable TCNT* Finite State Machine Controller * C1,C0 are inputs B1,B0 are outputs      org  $800  variables go in RAMStatePt  rmb  2  Pointer to the current state      org  $F000  Put in EEPROM so it can be changedOut   equ  0  offset for output value * 2 bit pattern stored in the low part of an 8 bit byteWait  equ  1  offset for time to waitNext  equ  2  offset for 4 next states* Four 16 bit unsigned absolute addressesInitState  fdb  S1  Initial stateS1   fcb  %01  Output     fcb  5    Wait Time     fdb  S2,S1,S2,S3S2   fcb  %10  Output     fcb  10   Wait Time     fdb  S3,S1,S2,S3S3   fcb  %11  Output     fcb  20   Wait Time     fdb  S1,S1,S2,S1     org  $F800 programs go in ROMMain lds   #$0C00     movb  #$FF,TSCR enable TCNT     ldaa  #%11111111      staa  DDRB B1,B0 are LED outputs     ldaa  #%00000000      staa  DDRC C1,C0 are switch inputs

Page 43: Assembly Language Project

     ldx   InitState State pointer     stx   StatePt* Purpose: run the FSM* 1. Perform output for the current state* 2. Wait for specified amout of time * 3. Input from the switches* 4. Go to the next state depending on the input* StatePt is the current state pointerFSM  ldx   StatePt  1. Do output     ldab  Out,x  Output value for this state in bits 1,0     stab  PORTB     ldaa  Wait,x  2. Wait in this state     bsr   WAIT     ldab  PORTC  3. Read input     andb  #$03   just interested in bits 1,0     lslb     2 bytes per 16 bit address     abx     add 0,2,4,6 depending on input     ldx   Next,x  4. Next state depending on input      stx   StatePt     bra   FSM* Reg A is the time to wait (256 cycles each)WAIT  tfr  a,b      clra    RegD= number of cycles to wait      addd TCNT  TCNT value at the end of the delayWloop cpd  TCNT  EndT-TCNT<0 when EndT<Tcnt      bpl  Wloop      rts      org  $FFFE      fdb  Main  reset vector

--------------------------------------------------------------------------------------set equate symbol to a value

     <label> set <expression> (<comment>)

The SET directive assigns the value of the expression in the operand field to the label. The set directive assigns a value other than the program counter to the label. Unlike the equ pseudo-op, the label can be redefined anywhere else in the program. The expression should not contain any forward references or undefined symbols. The use of this pseudo-op with forward references will not be flagged with Phasing Errors.

In the following example, the local variable names could be reused in another subroutine:; MC68HC812A4; *****binding phase***************I    set  -4PT   set  -3Ans  set  -1; *******allocation phase *********function  pshx    save old Reg X     tsx          create stack frame pointer     leas  -4,sp  allocate four bytes for I,PT,Result

Page 44: Assembly Language Project

; ********access phase ************     clr  I,x    Clear I     ldy  PT,x   Reg Y is a copy of PT     staa Ans,x  store into Ans; ********deallocation phase *****     txs    deallocation     pulx   restore old X     rts

--------------------------------------------------------------------------------------fcb Form Constant Byte

     (<label>) fcb <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) dc.b <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) db <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) .byte <expr>(,<expr>,...,<expr>) (<comment>)

The FCB directive may have one or more operands separated by commas. The value of each operand is truncated to eight bits, and is stored in a single byte of the object program. Multiple operands are stored in successive bytes. The operand may be a numeric constant, a character constant, a symbol, or an expression. If multiple operands are present, one or more of them can be null (two adjacent commas), in which case a single byte of zero will be assigned for that operand. An error will occur if the upper eight bits of the evaluated operands' values are not all ones or all zeros.      A string can be included, which is stored as a sequence of ASCII characters. The delimitors supported by TExaS are " ' and \. The string is not terminated, so the programmer must explicitly terminate it. For example:str1 fcb "Hello World",0

In the following finite state machine the fcb definitions are used to store outputs and wait times.Out   equ  0  offset for output value * 2 bit pattern stored in the low part of an 8 bit byteWait  equ  1  offset for time to waitNext  equ  2  offset for 4 next states* Four 16 bit unsigned absolute addressesInitState  fdb  S1  Initial stateS1   fcb  %01  Output     fcb  5  Wait Time     fdb  S2,S1,S2,S3S2   fcb  %10  Output     fcb  10  Wait Time     fdb  S3,S1,S2,S3S3   fcb  %11  Output     fcb  20  Wait Time     fdb  S1,S1,S2,S1

Page 45: Assembly Language Project

--------------------------------------------------------------------------------------fcc Form Constant Character String

     (<label>) FCC <delimiter><string><delimiter> (<comment>)

The FCC directive is used to store ASCII strings into consecutive bytes of memory. The byte storage begins at the current program counter. The label is assigned to the first byte in the string. Any of the printable ASCII characters can be contained in the string. The string is specified between two identical delimiters. The first non-blank character after the FCC directive is used as the delimiter. The delimitors supported by TExaS are " ' and \.

Examples:

LABEL1  FCC  'ABC'LABEL2  fcc  "Jon Valvano "LABEL4  fcc  /Welcome to FunCity!/

The first line creates the ASCII characters ABC at location LABEL1. Be careful to position the fcc code away from executable instructions. The assembler will produce object code like it would for regular instructions, one line at a time. For example the following would crash because after executing the LDX instruction, the 6811 would try to execute the ASCII characters "Trouble" as instructions.      ldaa  100     ldx  #StrgStrg fcc  "Trouble"

Typically we collect all the fcc, fcb, fdb together and place them at the end of our program, so that the microcomputer does not try to execute the constant data. For example     ldaa  Con8     ldy  Con16     ldx  #Strg     bra  loop* Since the bra loop is unconditional, * the 6811 won't go beyond this point.Strg   fcc  "No Trouble"Con8   fcb  100Con16  fdb  1000

--------------------------------------------------------------------------------------fdb Form Double Byte

Page 46: Assembly Language Project

     (<label>) fdb <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) dc.w <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) dw <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) .word <expr>(,<expr>,...,<expr>) (<comment>)

The FDB directive may have one or more operands separated by commas. The 16-bit value corresponding to each operand is stored into two consecutive bytes of the object program. The storage begins at the current program counter. The label is assigned to the first 16-bit value. Multiple operands are stored in successive bytes. The operand may be a numeric constant, a character constant, a symbol, or an expression. If multiple operands are present, one or more of them can be null (two adjacent commas), in which case two bytes of zeros will be assigned for that operand.

In the following finite state machine the fdb definitions are used to define state pointers. E.g., the InitState and the four Next pointers.Out   equ  0  offset for output value * 2 bit pattern stored in the low part of an 8 bit byteWait  equ  1  offset for time to waitNext  equ  2  offset for 4 next states* Four 16 bit unsigned absolute addressesInitState  fdb  S1  Initial stateS1   fcb  %01  Output     fcb  5    Wait Time     fdb  S2,S1,S2,S3S2   fcb  %10  Output     fcb  10   Wait Time     fdb  S3,S1,S2,S3S3   fcb  %11  Output     fcb  20   Wait Time     fdb  S1,S1,S2,S1

--------------------------------------------------------------------------------------dc.l Define 32 bit constant

     (<label>) dc.l <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) dl <expr>(,<expr>,...,<expr>) (<comment>)     (<label>) .long <expr>(,<expr>,...,<expr>) (<comment>)

The dl directive may have one or more operands separated by commas. The 32-bit value corresponding to each operand is stored into four consecutive bytes of the object program (big endian). The storage begins at the current program counter. The label is assigned to the first 32-bit value. Multiple operands are stored in successive bytes. The operand may be a numeric constant, a character constant, a symbol, or an expression. If multiple operands are present, one or more of them can be null (two adjacent commas), in which case four bytes of zeros will be assigned for that operand.

Page 47: Assembly Language Project

In the following finite state machine the dl definitions are used to define 32 bit constants. S1  dl     100000,$12345678S2  .long  1,10,100,1000,10000,100000,1000000,10000000S3  dc.l  -1,0,1

--------------------------------------------------------------------------------------org Set Program Counter to Origin

     org<expression> (<comment>)     .org<expression> (<comment>)

The ORG directive changes the program counter to the value specified by the expression in the operand field. Subsequent statements are assembled into memory locations starting with the new program counter value. If no ORG directive is encountered in a source program, the program counter is initialized to zero. Expressions cannot contain forward references or undefined symbols.

The org statements in the following skeleton place the variables in RAM and the programs in EEPROM of a MC68HC812A4* ********** <<Name>> ********************     org  $800  variables go in RAM* <<globals defined with rmb's go here>>     org  $F000  programs in EEPROMMain:  lds  #$0C00  initialize stack to RAM* <<one time initializations go here>>loop:* <<repeated operations go here>>     bra  loop* <<subroutines go here>>     org  $FFFE     fdb  Main  reset vector

--------------------------------------------------------------------------------------rmb Reserve Multiple Bytes

     (<label>) rmb <expression> (<comment>)     (<label>) ds <expression> (<comment>)     (<label>) ds.b <expression> (<comment>)     (<label>) .blkb <expression> (<comment>)

The RMB directive causes the location counter to be advanced by the value of the expression in the operand field. This directive reserves a block of memory the length of which in bytes is equal to the value of the expression. The block of memory reserved is not initialized to any given value. The expression cannot contain any

Page 48: Assembly Language Project

forward references or undefined symbols. This directive is commonly used to reserve a scratchpad or table area for later use.

--------------------------------------------------------------------------------------ds.w Reserve Multiple Words

     (<label>) ds.w <expression> (<comment>)     (<label>) .blkw <expression> (<comment>)

The ds.w directive causes the location counter to be advanced by 2 times the value of the expression in the operand field. This directive reserves a block of memory the length of which in words (16 bit) is equal to the value of the expression. The block of memory reserved is not initialized to any given value. The expression cannot contain any forward references or undefined symbols. This directive is commonly used to reserve a scratchpad or table area for later use.

--------------------------------------------------------------------------------------ds.l Reserve Multiple 32-bit Words

     (<label>) ds.l <expression> (<comment>)     (<label>) .blkl <expression> (<comment>)

The ds.l directive causes the location counter to be advanced by 4 times the value of the expression in the operand field. This directive reserves a block of memory the length of which in words (32 bit) is equal to the value of the expression. The block of memory reserved is not initialized to any given value. The expression cannot contain any forward references or undefined symbols. This directive is commonly used to reserve a scratchpad or table area for later use.

--------------------------------------------------------------------------------------end End of program (optional)

     end (<comment>)     .end (<comment>)

The END directive signifies the end of the source code. The TExaS assembler will ignore these pseudo operation codes.

--------------------------------------------------------------------------------------ASCII Character codes

Page 49: Assembly Language Project

           BITS 4 to 6

    0 1 2 3 4 5 6 7

  0 NUL DLE SP 0 @ P ` p

B 1 SOH DC1 : 1 A Q a qI 2 STX DC2 ! 2 B R b rT 3 ETX DC3 # 3 C S c sS 4 EOT DC4 $ 4 D T d t

  5 ENQ NAK % 5 E U e u

0 6 ACK SYN & 6 F V f v

  7 BEL ETB ' 7 G W g w

T 8 BS CAN ( 8 H X h xO 9 HT EM ) 9 I Y i y

  A LF SUB * : J Z j z

3 B VT ESC + ; K [ k {

  C FF FS , < L \ l ;

  D CR GS - = M ] m }

  E SO RS . > N ^ n ~

  F S1 US / ? O _ o DEL

 

--------------------------------------------------------------------------------------S-19 Object code     The S-record output format encodes program and data object modules into a printable (ASCII) format. This allows viewing of the object file with standard tools and allows display of the module while transferring from one computer to the next or during loads between a host and target. The S-record format also includes information for use in error checking to insure the integrity of data transfers.      S-Records are character strings made of several fields that identify the record type, record length, memory address, code/data, and checksum. Each byte of binary data is encoded as a 2-character hexadecimal number: the first character representing the high-order 4 bits, and the second the low-order 4 bits of the byte.

The 5 fields that comprise an S-record are:     1) Type S0, S1 or S9     2) Record Length     3) Address     4) Code/Data     5) Checksum

Eight types of S-records have been defined to accommodate various encoding, transportation, and decoding needs, but only three types are used in most Motorola

Page 50: Assembly Language Project

microcontrollers. The S0 record is a title record containing the ASCII name of the file in the Code/Data field. The address field of this type is usually 0000. The S1 record is a data record containing the information to be loaded sequentially starting at the specified address. The S9 record is a end of file marker, and sometimes contains the starting address to begin execution. In an embedded microcomputer environment, the starting address must be programmed at the appropriate place. For most Motorola microcontrollers, the reset vector is the last two bytes of ROM or EEPROM.

The Record Length contains the count of the character pairs in the length record, excluding the type and record length.

For S0, S1, S9 record types, the Address field is a 4-byte value. For the S1 record type the address specifies where the data field is to be loaded into memory.

There are from 0 to n bytes in the Code/Data field. This information contains executable code, memory loadable data, or descriptive information.

The Checksum field is 2 ASCII characters used for error checking. The least significant byte of the one's complement of the sum of the values represented by the pairs of characters making up the record length, address, and the code/data fields. When generating a checksum, one adds (call the result sum) the record length, address and code/data field using 8 bit modulo arithmetic (ignoring overflows.) The checksum is calculated     checksum = $FF - sumWhen verifying a checksum, one adds (call the result sum) the record length, address code/data field and checksum using 8 bit modulo arithmetic (ignoring overflows.) The sum should be $FF.

Each record may be terminated with a CR/LF/NULL.

The following is a typical S-record module:

     S1130000285F245F2212226A000424290008237C2A     S11300100002000800082629001853812341001813     S113002041E900084E42234300182342000824A952     S107003000144ED492     S9030000FC

The module consists of four code/data records and an S9 termination record.

The first S1 code/data record is explained as follows:

Page 51: Assembly Language Project

     S1  S-record type S1, indicating a code/data record to be loaded/verified at a 2-byte address.

     13  Hex 13 (decimal 19), indicating 19 character pairs, representing 19 bytes of binary data, follow.

     00  Four-character 2-byte address field: hex address 0000, indicates location where the following data is to be loaded.

     The next 16 character pairs are the ASCII bytes of the actual program code/data

     2A  Checksum of the first S1 record.

The second and third S1 code/data records each also contain $13 character pairs and are ended with checksums. The fourth S1 code/data record contains 7 character pairs.

The S9 termination record is explained as follows:

     S9  S-record type S9, indicating a termination record.

     03  Hex 03, indicating three character pairs (3 bytes) to follow.

     00  Four character 2-byte address field, zeroes.  00

     FC  Checksum of S9 record.

This document has four overall parts     Overview      Syntax (fields, pseudo ops) (this document)     Local variables     Examples

Early computer systems were literally programmed by hand. Front panel switches were used to enter instructions and data. These switches represented the address, data and control lines of the computer system.To enter data into memory, the address switches were toggled to the correct address, the data switches were toggled next, and finally the WRite switch was toggled. This wrote the binary value on the front panel data switches to the address specified. Once all the data and instruction were entered, the run switch was toggled to run the program.

Page 52: Assembly Language Project

The programmer also needed to know the instruction set of the processor. Each instruction needed to be manually converted into bit patterns by the programmer so the front panel switches could be set correctly. This led to errors in translation as the programmer could easily misread 8 as the value B. It became obvious that such methods were slow and error prone.

With the advent of better hardware which could address larger memory, and the increase in memory size (due to better production techniques and lower cost), programs were written to perform some of this manual entry. Small monitor programs became popular, which allowed entry of instructions and data via hex keypads or terminals. Additional devices such as paper tape and punched cards became popular as storage methods for programs.

Programs were still hand-coded, in that the conversion from mnemonics to instructions was still performed manually. To increase programmer productivity, the idea of writing a program to interpret another was a major breakthrough. This would be run by the computer, and translate the actual mnemonics into instructions. The benefits of such a program would be

reduced errors faster translation times changes could be made easier and faster

As programmers were writing the source code in mnemonics anyway, it seemed the logical next step. The source file was fed as input into the program, which translated the mnemonics into instructions, then wrote the output to the desired place (paper-tape etc). This sequence is now accepted as common place.

The only advances have been the increasing use of high level languages to increase programmer productivity.

Assembly language programming is writing machine instructions in mnemonic form, using an assembler to convert these mnemonics into actual processor instructions and associated data.

The disadvantages of assembly language programming are

the programmer requires knowledge of the processor architecture and instruction set

many instructions are required to achieve small tasks source programs tend to be large and difficult to follow

Page 53: Assembly Language Project

programs are machine dependent, requiring complete rewrites if the hardware is changed

THE PROGRAM TRANSLATION SEQUENCEdeveloping a software program to accomplish a particular task, the implementor chooses an appropriate language, develops the algorithm (a sequence of steps, which when carried out in the order prescribed, achieve the desired result), implements this algorithm in the chosen language (coding), then tests and debugs the final result.

here is also a probable maintenance phase also associated. The chosen language will undoubtably need to be converted into the appropriate binary bit-patterns which make sense to the target processor (the processor on which the software will be run). This process of conversion is called translation.

The following diagram illustrates the translation sequence necessary to generate machine code from specific languages.

ASSEMBLY LANGUAGE PROGRAMMINGAsemblers are programs which generate machine code instructions from a source code program written in assembly language. The features provided by an assembler are,

allows the programmer to use mnemonics when writing source code programs. variables are represented by symbolic names, not as memory locations symbolic code is easier to read and follow error checking is provided changes can be quickly and easily incorporated with a re-assembly programming aids are included for relocation and expression evaluation

In writing assembly language programs for micro-computers, it is essential that a standardized format be followed. Most manufacturers provide assemblers, which are

Page 54: Assembly Language Project

programs used to generate machine code instructions for the actual processor to execute.

The assembler converts the written assembly language source program into a format which run on the processor. Each machine code instruction (the binary or hex value) is replaced by a mnemonic. A mnemonic is an abbreviation which represents the actual instruction.

+----------+---------+-----------------+| Binary | Hex | Mnemonic |+----------+---------+-----------------+| 01001111 | 4F | CLRA | Clears the A

accumulator +----------+---------+-----------------+| 00110110 | 36 | PSHA | Saves A acc on

stack +----------+---------+-----------------+| 01001101 | 4D | TSTA | Tests A acc for 0 +----------+---------+-----------------+

Mnemonics are used because they

are more meaningful than hex or binary values reduce the chances of making an error are easier to remember than bit values

Assemblers also accept certain characters as representing number bases and addressing modes.

$ prefix or h suffix for hexadecimal $24 or 24h

D for decimal numbers 24D 67

B for binary numbers 0101111B

O or Q for octal numbers 377O 232Q

Page 55: Assembly Language Project

# for immediate addressing LDAA #$34

,X for indexed addressing LDAA 01,X

Assembly language statements are written one per line. A machine code program thus consists of a sequence of assembly language statements, where each statement contains a mnemonic. Each line of an assembly language program is split into four fields, as shown below

LABEL OPCODE OPERAND COMMENTS

The label field is optional. A label is an identifier (or text string symbol). Labels are used extensively in programs to reduce reliance upon programmers remembering where data or code is located. A label can be used to refer to<

a memory location the value of a piece of data the address of a program, sub-routine, code portion etc.

The maximum length of a label differs between assemblers. Some accept up to 32 characters long, others only four characters. A label, when declared, is suffixed by a colon, and begins with a valid character (A..Z). Consider the following example.

START: LDAA #24H

Here, the label START is equal to the address of the instruction LDAA #24H. The label is used in the program as a reference, eg,

JMP START

This would result in the processor jumping to the location (address) associated with the label START, thus executing the instruction LDAA #24H immediately after the JMP instruction. When a label is referenced later on in the program, it is done so without the colon suffix.

Page 56: Assembly Language Project

An advantage of using labels is that inserting or re-arranging code statements do not necessitate re-working actual machine instructions. A simple re-assembly is all that is required. In hand-coding, such changes can take hours to perform.

Each instruction consists of an opcode and possible one or more operands. In the above instruction

JMP START

the opcode is JMP and the operand is the address of the label START.

The opcode field contains a mnemonic. Opcode stands for operation code, ie, a machine code instruction. The opcode may also require additional information (operands). This additional information is separated from the opcode by using a space (or tab stop).

The operand field consists of additional information or data that the opcode requires. In certain types of addressing modes, the operand is used to specify

o constants or labelso immediate datao data contained in another accumulator or registero an address

Examples of operands are

TAB ; operand specified by opcode LDAA 0100H ; two byte operand LDAA START ; label operand LDAA #0FH ; immediate operand

The comment field is optional, and is used by the programmer to explain how the coded program works. Comments are preceded by a semi-colon. The assembler, when generating instructions from the source file, ignores all comments. Consider the following examples,

; H means hexadecimal valuesORG 0100H ;This program starts at address 0100 hex

Page 57: Assembly Language Project

STATUS: DFB 23H ;This byte is identified as STATUS, and is

;initialized to a value of 23 hexCODE: LDAA STATUS ;The label called CODE is identified as a

;machine code instruction which loads the ;A accumulator with the contents of the ;memory location associated with the label ;STATUS, ie, the value 23

JMP CODE ;Jump to the address associated with CODE

Note that the programmer does not need to worry about bit patterns, hex values, and the addresses of STATUS or CODE. The assembler, when fed the above program, will generate the correct code. The code output from the assembler will be,

Memory location Byte value 0100 23 0101 B6 0102 01 0103 00 0104 7E 0105 01 0106 01

Location 0100 holds the value associated with the label STATUSLocations 0101 to 0103 perform the LDAA STATUS instructionLocations 0104 to 0106 perform the JMP CODE instruction

The statement ORG 0100H in the above program is not a machine code instruction. It is an instruction to the assembler, which instructs the assembler to generate the code to run at the designated origin address. Instructions to assemblers are called pseudo-ops. These are used for

o reserving memory for data variables, arrays and structureso determining the start address of the programo determining the entry address of the programo initializing variable values

Page 58: Assembly Language Project

The assembler does not generate any machine code instructions for pseudo-ops or comments. Assemblers scan the source program, generating machine instructions. Sometimes, the assembler reaches a reference to a variable which has not yet been defined. This is referred to as a forward reference problem. The assembler can tackle this problem in a number of ways. It is resolved in a two pass assembler as follows,

On the first pass, the assembler simply reads the source file, counting up the number of locations that each instruction will take, and builds a symbol table in memory which lists all the defined variables cross-referenced to their associated memory address. On the second pass, the assembler substitutes opcodes for the mnemonics, and variable names are replaced by the memory locations obtained from the symbol table.

OPERATION OF A TWO-PASS ASSEMBLERConsider the following source code program for a hypothetical computer. The program computes the so-called Fibonacci numbers, printing all such numbers up to that specified by LIMIT.

Line Label Operation Operand 1 Operand 21 COPY ZERO OLDER2 COPY ONE OLD3 READ LIMIT4 WRITE OLD5 FRONT: LOAD OLDER6 ADD OLD 7 STORE NEW8 SUB LIMIT9 BRPOS FINAL10 WRITE NEW11 COPY OLD OLDER12 COPY NEW OLD13 BR FRONT14 FINAL: WRITE LIMIT15 STOP16 ZERO: CONST 017 ONE CONST 118 OLDER SPACE19 OLD SPACE20 NEW SPACE21 LIMIT SPACE

Page 59: Assembly Language Project

The instruction set of the computer is as follows,

Operation Code Number ofSymbolic Machine Length Operands ActionADD 02 2 1 ACC <- ACC + OPD1BR 00 2 1 Branch to OPD1BRPOS 01 2 1 Branch to OPD1 if ACC> 0COPY 13 3 2 OPD2 <- OPD1LOAD 03 2 1 ACC <- OPD1READ 12 2 1 OPD1 <- input streamSTOP 11 1 0 Halt executionSTORE 07 2 1 OPD1 <- ACCSUB 06 2 1 ACC <- (ACC - OPD1)WRITE 08 2 1 output stream <- OPD1

The functions that the assembler will perform in translating the program are,

9. replace symbolic addresses by numeric addresses10. replace symbolic operation codes by machine operation codes11. reserve storage for instructions and data12. translate constants into machine representation

IMPLEMENTATIONThe assembler uses two counters to keep track of the machine language program. One counter, called the location counter, keeps track of the physical address location being used, and will initially be set to zero for this program (or the value designated by the ORG directive).

The other counter is the line counter, which keeps track of the line number being processed. After each source line has been examined on the first pass, the location counter is incremented by the correct number of bytes.

Page 60: Assembly Language Project

When the assembler processes line 1 of the source, it cannot replace the symbols ZERO and OLDER by their addresses because those symbols have not yet been defined. This is called a forward reference problem.

The assembler will place the symbols into the symbol table, determine the number of bytes to advance by altering the contents of the location counter to 3, then proceed to process the next source line. After processing line 3 of the source, the current state will be,

Line Address Label Operation OPD1 OPD2 1 0 COPY ZERO OLDER 2 3 COPY ONE OLD 3 6 READ LIMIT

and the contents of the symbol table will be

Symbol AddressZERO ---OLDER ---ONE ---OLD ---LIMIT ---Location Counter: 8Line Counter: 4

The symbol table currently holds five symbols, none of which yet has an address. During processing of line 4, the assembler picks up the symbol OLD. It establishes that it is already in the symbol table, so does not enter it again.

During line 5, the assembler encounters FRONT, and it is entered into the symbol table. The assembler also knows its address (10), so it is also placed into the table. After processing line 9 of the program, the current state is,

Line Address Label Operation OPD1 OPD21 0 COPY ZERO OLDER2 3 COPY ONE OLD3 6 READ LIMIT4 8 WRITE OLD5 10 FRONT LOAD OLDER6 12 ADD OLD

Page 61: Assembly Language Project

7 14 STORE NEW8 16 SUB LIMIT9 18 BRPOS FINAL

and the contents of the symbol table will be

Symbol AddressZERO ---OLDER ---ONE ---OLD ---LIMIT ---FRONT 10NEW ---FINAL ---Location Counter: 20Line Counter: 10

The first pass continues, building up the symbol table. When the assembler determines the address of the various symbols in lines 16 to 21, these are entered into the table. At the end of pass 1, the symbol table should list all declared symbols as well as their addresses.

The state at the end of the first pass is,

Line Address Label Operation OPD1 OPD21 0 COPY ZERO OLDER2 3 COPY ONE OLD3 6 READ LIMIT4 8 WRITE OLD5 10 FRONT LOAD OLDER6 12 ADD OLD7 14 STORE NEW8 16 SUB LIMIT9 18 BRPOS FINAL10 20 WRITE NEW11 22 COPY OLD OLDER12 25 COPY NEW OLD13 28 BR FRONT14 30 FINAL WRITE LIMIT15 32 STOP16 33 ZERO CONST 0

Page 62: Assembly Language Project

17 34 ONE CONST 118 35 OLDER SPACE19 36 OLD SPACE20 37 NEW SPACE21 38 LIMIT SPACE

and the contents of the symbol table will be

Symbol AddressZERO 33OLDER 35ONE 34OLD 36LIMIT 38FRONT 10NEW 37FINAL 30Location Counter: 39Line Counter: 22

Code generation is performed on the second pass. Before starting, the line and location counters will be reset to 1 and 0 respectively. The assembler now generates one line of object code for each source line. Line one is translated to

Address Length Opcode OPD1 OPD2 00 3 13 33 35

Successive lines are translated in the same manner. On encountering the label FRONT in line 5, the assembler ignores it. Lines 16 to 21, where space is reserved for variables, the assembler may leave these undefined, or initialize them to zero. The object code generated by the second pass will be,

Address Length Opcode OPD1 OPD2 00 3 13 33 35 03 3 13 34 36 06 2 12 38 08 2 08 36 10 2 03 35 12 2 02 36 14 2 07 37 16 2 06 38

Page 63: Assembly Language Project

18 2 01 30 20 2 08 37 22 3 13 36 35 25 3 13 37 36 28 2 00 10 30 2 08 38 32 1 11 33 1 00 34 1 01 35 1 xx 36 1 xx 37 1 xx 38 1 xx

ASSEMBLER DIRECTIVESAs 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.

EQUATEis 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

LDAA #NUMBER1

will be interpreted by the assembler as

LDAA #36H

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

Page 64: Assembly Language Project

previously declared. The redefining of a previous symbol is normally not allowed.

NUM1: EQU 20H... ...NUM1: EQU 30H ; error

ORIGINThis 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 120HLDAA #FFH

The statement LDAA #FFH begins at byte 120h.

ORG $ + 2start: 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 TYPESThis 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 6802

This directive appears before any machine instructions.

OUTPUT FORMATSThis directive is used to select the output format for the generated machine instructions. Several output formats are available for downloading into EPROM or a target system.

HOF recordtype

Page 65: Assembly Language Project

where recordtype is one of the following

MOT ; motorola formatsINT ; intel formatsTEK ; tektronix formats

This directive appears before any machine instructions.

BYTE STORAGEThe directive used to allocate and initialize bytes (8bits) of storage is

DFB definebyte

Its format is,

name: DFB initialvalue,,,

The name portion is optional. Consider the following examples for CRS8.

value1: DFB 16form: DFB 6*2text: 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 STORAGEThe directive used to allocate and initialize words (two bytes) of memory storage is,

DWM define word, most significant byte firstDWL define word, least significant byte first

Its format is,

name: DWM initialvalue,,,

The name portion is optional.

Page 66: Assembly Language Project

DWM 1687Hmess: 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 RESERVATIONThis directive is used to reserve storage for later use.

array: DFS 100

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 AddressThe 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.

ORG 0100Hstart: LDAA #3FHJMP startEND start

In this example, the END directive also specifies that the entry point to the program is the label start, whose address is 0100H.

Page 67: Assembly Language Project

SAMPLE PROGRAM FOR MC6802 USING CRS8The following source file has been named MC6802.ASM

CPU 6802 ; 6802 processor HOF MOT ; Motorola Records

ORG 0100H ; Start of DataSource: DFB 'Hello and Welcome'Length: EQU $ - Source ;Length of SourceDestin: DFS Length ; Buffer which has same

; length as SourceORG 0120H ; Start of Code

Entry: LDX #Source ; Point Index Reg to ; Source string

LDAB #Length ; Number of characters to move

Loop: LDAA 0,XSTAA Length,XINXDECBBNE Loop

Fin: JMP FinEND Entry

This program is assembled by typing the following command

CRS8 MC6802

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 processorC:6802.HEX HOF MOT ; Motorola Records

0100 ORG 0100H ; Start of Data

Page 68: Assembly Language Project

0100 48656C6C6F Source: DFB 'Hello and Welcome'0011 = Length: EQU $ - Source ; Length of

Source0111 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,X0127 A711 STAA Length,X0129 08 INX012A 5A DECB012B 26F8 BNE Loop 012D 7E012D Fin: JMP Fin0130 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

S00D0000433A363830322E48455892S113010048656C6C6F20616E642057656C636F6D1DS10401106585S1130120CE0100C611A600A711085A26F87E012D9FS9030120DB

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

Page 69: Assembly Language Project

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

egS1 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 TYPESMost 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.

Charactersare 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).

Character Stringsare 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).

Page 70: Assembly Language Project

Integersare 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 Arraysare 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 0120Hstart: LDAA #30H ; ASCII '0'

LDAB #11 ; ten digitsLDX #Digits

loop: STAA 0,XINX ; next elementINCA ; next digitDECBBNE loop

exit: ....

Typical Array OperationsThe following routines are typical of functions which are performed on character based arrays.

CopyThis copys a source string to a destination area. The declaration of the routines

Page 71: Assembly Language Project

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

Page 72: Assembly Language Project

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 LengthReturns 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 characterThis 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

Page 73: Assembly Language Project

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 SubstringThis 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/ReplacementThis 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 ReverseThis routine reverses the characters in a string. It accepts the address of the string. Hello becomes olleH 

String to UppercaseThis routine converts all characters of a string to uppercase. It accepts the address of the string. Hello becomes HELLO 

String to LowercaseThis routine converts all characters of a string to lowercase. It accepts the address of the string. Hello becomes hello 

Page 74: Assembly Language Project

ARRAY INDEX CALCULATIONSThis 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)

IMPLEMENTATION OF HIGH LEVEL LANGUAGE CONSTRUCTSIn High Level Languages such as PASCAL and BASIC, several constructs are available which help to implement programs. You should know how these constructs are implemented in assembly language.The constructs that we will now deal with involve SELECTION and ITERATION. Both types of constructs are implemented using the conditional BRANCH instructions of the processor.

These types of instructions test the state of the various flags of the status register. All variables are memory based. Any manipulation of variables normally involves three steps,

1. Load the variable into a register2. Perform the operation3. Store the result back into the variables location

SIMPLE STATEMENT ASSIGNMENTSAssigning a constant value to a variable

1. Load the constant into a register2. Store the register to the variables memory location eg,3.4. X1 := 20;5.6. LDX #207. STX X1

Use eight bit registers for bytes/characters, and 16bit registers for integers. eg,

Page 75: Assembly Language Project

Letter := 'Y';

LDAA #'Y'STAA Letter

Assigning a variables value to another variable

8. Load the second variable into a register9. Store the register into the first variables memory location eg,10.11. X1 := Y;12.13. LDX Y14. STX X115.

Addition X1 := Y + 7 ; Calculate the right side first. ; Load Y into a register, use an immediate

add with 7, ; then store into variable X1 (following

example uses ; BYTE integers) LDAA Y ADDA #7 STAA X1 eg, X1 := Y + Z ; Calculate the right side first. Load Y and

Z into ; registers, add the two registers together,

store the ; result into variable X1. LDAA Y LDAB Z ABA STAA X1 eg, X1 := Y + Z + 3 + T; Calculate the right hand side first.

If the ; number of variables/constants exceed the

number of

Page 76: Assembly Language Project

; registers available, parenthesise and calculate portions

; at a time. Finally, store the result back into the left

; side variable X1. LDAA T ADDA #3 ; 3 + T LDAB Z ABA ; + Z LDAB Y ABA ; + Y STAA X1

Subtraction X1 := Y - 7 ; Calculate the right side first. Load Y into

a register, ; use an immediate subtract with 7, then

store into ; variable X1. LDAA Y SUBA #7 STAA X1 eg, X1 := Y - Z ; Calculate the right side first. Load Y and

Z into ; registers, subtract the two registers

together, store ; the result into variable X1. LDAA Y LDAB Z SBA ; subtract bx from ax, Z from Y STAA X1 eg, X1 := Y - Z - 3 - T; Calculate the right hand side first.

If the ; number of variables/constants exceed the

number of ; registers available, parenthesise and

calculate portions ; at a time. Finally, store the result back

into the left ; side variable X1. Take special note of the

order of

Page 77: Assembly Language Project

; evaluation, in this case Z is subtracted from Y, 3

; subtracted from that and so on. LDAA Y LDAB Z ABA ; Y - Z SUBA #3 ; - 3 LDAB T SBA ; - T STAA X1

Compound Statements X1 := Y + 4 - Z * 7; Calculate the right hand side first.

If the ; number of variables/constants exceed the number of

registers available, ; parenthesise and calculate portions at a time. Finally,

store the result ; back into the left side variable X1. Take special note

of the order of ; evaluation, in this case multiplication occurs before

addition or ; subtraction. ; The statement can be interpreted as, X1 := (Y + 4) - ( Z

* 7 ) ; or X1 := Y + (4 - Z) * 7 ; Assuming that the real intention is the first grouping,

first calculate ; the term (Z * 7), then the term (Y + 4), and subtract

the first term ; from the second, storing the result into X1. LDAA Z LDAB #7 ; mult A,B ; (Z * 7) LDAB Y ADDB #4 ; (Y + 4) ABA STAA X1 WHERE THE EXPRESSION IS COMPLEX AND INVOLVES A LARGE

NUMBER OF TERMS, THIS WILL REQUIRE THE USE OF TEMPORARY STORAGE LOCATIONS FOR

STORING INTERMEDIATE RESULTS.

Page 78: Assembly Language Project

IF STATEMENTSThis involves the use of an appropriate branch false instruction after a comparison test to the end of the if body.

1. An IF label with a comparison test2. Branch false to an endif label3. The if body statements preceed the endif label

if: ; comparison test ; jump false to endif ; if body statements endif:

Comparing a variable and a constant1. Load the variable into a register2. Compare the register against the constant3. Branch false to a label after the body of the if statement

IF X1 < 10 then Y := Z * 2; if: LDAA X CMPA #10 BCC endif LDAA Z ; if body, Y := Z * 2 LDAB 2 ; mult a, b STAA Y endif:

Comparing a Variable against another Variable1. Load the second variable into a register (t2)2. Load the first variable into a register (t1)3. Compare the two registers (t1-t2 > t1)4. Branch false to a label after the body of the if statement

IF X1 >= Z then Y := X; if: LDAB Z LDAA X CBA BLT endif LDAA X1 ; if body, Y := X1; STAA Y endif:

Page 79: Assembly Language Project

Comparing a Variable for Logic 1 or TRUE1. Load the variable into a register (t1)2. Compare the register against zero3. Branch equal to a label after the body of the if statement

IF X1 then Y := X / 2; if: LDAA X CMPA #0 BEQ endif LDAA X1 ; if body, Y:=X1 / 2; LDAB #2 ; div A, B STAA Y endif:

Comparing a Variable for Logic 0 or FALSE1. Load the variable into a register (t1)2. Compare the register against zero3. Branch above or greater to a label after the body of the if statement

IF X1 then Y := X + 2; if: LDAA X1 CMPA #0 BHI endif LDAA X1 ; if body, Y:=X1 + 2; ADDA #2 STAA Y endif: WHERE THE CONDITION OF THE IF STATEMENT IS EXPRESSED

NEGATIVELY, USING A NOT INSTRUCTION, THEN A BRANCH TRUE INSTRUCTION SHOULD BE

USED INSTEAD OF A BRANCH FALSE INSTRUCTION. eg, IF X1 = 2 then Y := 4; if: LDAA X1 CMPA #2 BNE endif LDAA #4 STAA Y endif:

Page 80: Assembly Language Project

IF NOT X1 = 2 then Y := 4; if: LDAA X CMPA #2 BEQ endif LDAA #4 STAA Y endif:

IF THEN ELSE STATEMENTSThis involves an extension to the previous IF body. The conditional false branch now jumps to an else clause, and the if body jumps unconditionally to the end of the if else statement.

if: ; comparison ; branch false to else clause ; if body statements jmp endif else: ; else statements ; endif:

The same principles apply to the various forms that expressions can take. eg,

IF X = 2 THEN Y := Y + 4 ELSE Z := 0;

if: LDAA XCMPA #2BNE elseLDAA YADDA #4STAA YJMP endif

else: LDAA #0STAA Z

endif:

WHILE LOOPSThis involves the use of a conditional test at the entry of the while body, which

Page 81: Assembly Language Project

branches or jumps false to an endwhile label. The last statement in the while body is a jump unconditional to the start of the while body.

1. Use a while label, comparison test2. Branch false to an endwhile label3. The last statement of the while body is a jump to the while label

while: ; comparison test ; branch false to endwhile ; while body statements jmp while endwhile: WHILE X < 10 DO BEGIN Y := Y + X; X := X + 1 END; while: LDAA X CMPA #10 BHI endwhile LDAB X ; Y := Y + X LDAA Y ABA STAA Y LDAA X ; X := X + 1 ADDA #1 STAA X JMP while endwhile: PREVIOUS RULES CONCERNING NEGATION ALSO APPLY. NOTE THAT

ALL PREVIOUS FUNDAMENTALS OF STATEMENT ASSIGNMENT AND TESTING OF

VARIABLES AGAINST EACH OTHER OR CONSTANTS ARE STILL BEING RIGIDLY APPLIED.

FOR NEXT LOOPS1. Initialise the loop variable2. Use a for label, Perform the comparison test with the final value3. Branch false to an endfor label4. Inside the for loop body, the last statement, should adjust the loop

variable, and use an unconditional branch back to the for label

Page 82: Assembly Language Project

initfor: ; initialise loop variable for: ; comparison test ; jump false endfor ; for body statements ; adjust loop variable for next step

jmp for endfor: FOR X := 1 to 10 do BEGIN Y := Y + X END; initfor: LDAA #1 STAA X for: LDAA X CMPA #10 BHI endfor LDAB X ; Y := Y + X LDAA Y ABA STAA Y LDAA X ; NEXT X ADDA #1 STAA X JMP for endfor: PREVIOUS RULES CONCERNING NEGATION ALSO APPLY. NOTE THAT

ALL PREVIOUS FUNDAMENTALS OF STATEMENT ASSIGNMENT AND TESTING OF

VARIABLES AGAINST EACH OTHER OR CONSTANTS ARE STILL BEING RIGIDLY APPLIED.

6802 Processor Examples

1. The IF statementIn comparing the value of operands, consider the following example.

2.3. IF X = 2 THEN Y = X4.

Page 83: Assembly Language Project

The compare statement must be coded in such a way as to compare the value of X against the constant 2. As the variable X is stored in memory, the programmer should first load a register with the variable X before making the comparison (because most processors do not support a compare between memory contents and immediate data).This example gets coded as,

X: DFB 10Y: DFB 00

....LDAA X ; load A acc with value of XCMPA #02 ; compare A acc with immediate

data BNE IF1 ; exit if false LDAA X ; get value of X STAA Y ; store value of X at variable Y

IF1: ..... ; next statement after if construct

Lets consider another example.

IF X = Y THEN Y = 0

In this case, the code to be generated by the assembler for the compare statement depends upon the addressing modes available. The options available are,

memory to memory compareCMP [X], [Y]register to memory compareCMPA [Y] register to register compareCMPAB

Both X and Y variables are memory based, so if the processor supports a comparison of two memory operands, it could be coded as,

CMP [X],[Y] ; sample only

Page 84: Assembly Language Project

However, most processors do not support this. The most common option is the comparison of a register variable against memory contents. This is coded as follows,

LDAA X ; get variable X CMPA Y ; compare with variable Y BNE IF1 ; exit it not equal LDAA #00H ; set variable Y to zeroSTAA Y

IF1: ....

This code can clearly be optimized (ie, some instructions can be removed without affecting the original intent of the code). So far we have considered comparisons for equality. The conditional branch instruction will vary depending upon what type of comparison test is used. The following tables illustrate common comparison tests and their associated conditional branch instructions.

+-----------------+-------------+--------------+| Signed Operands | Branch True | Branch False |+-----------------+-------------+--------------+| r > m | BGT | BLE | +-----------------+-------------+--------------+| r >=m | BGE | BLT | +-----------------+-------------+--------------+| r = m | BEQ | BNE |+-----------------+-------------+--------------+| r <=m | BLE | BGT |+-----------------+-------------+--------------+| r < m | BLT | BGE |+-----------------+-------------+--------------+

If ....... Then ---- Use Branch False If NOT ... Then ---- Use Branch True

+-----------------+-------------+--------------+|UnSigned Operands| Branch True | Branch False |+-----------------+-------------+--------------+| r > m | BHI | BLS |+-----------------+-------------+--------------+| r >=m | BCC | BCS |

+-----------------+-------------+--------------+

Page 85: Assembly Language Project

| r = m | BEQ | BNE | +-----------------+-------------+--------------+| r <=m | BLS | BHI |+-----------------+-------------+--------------+| r < m | BCS | BCC |+-----------------+-------------+--------------+

The following table represents a cross-reference between branch instructions and the flags they test.

+------+----------------+----------+| 6802 | Flags Tested | 8088 | +------+----------------+----------+| BCC | C = 0 | JNB, JAE | +------+----------------+----------+| BCS | C = 1 | JB, JNAE |+------+----------------+----------+| BNE | Z = 0 | JNE, JNZ | +------+----------------+----------+| BEQ | Z = 1 | JE, JZ |+------+----------------+----------+| BPL | N = 0 | JNS |+------+----------------+----------+| BMI | N = 1 | JS |+------+----------------+----------+ | BHI | C + Z = 0 | JNBE, JA |+------+----------------+----------+ | BLS | C + Z = 1 | JBE, JNA |+------+----------------+----------+| BGE | N EOR V = 0 | JNL, JGE | +------+----------------+----------+| BLT | N EOR V = 1 | JL, JNGE | +------+----------------+----------+| BGT |Z + (N EOR V)= 0| JG, JNLE | +------+----------------+----------+| BLE |Z + (N EOR V)= 1| JLE,JNG | +------+----------------+----------+

These tables are useful in determining the correct conditional instruction to use for a particular comparison on specific data types. Coding the following statement applicable to two unsigned 8bit data values

Page 86: Assembly Language Project

IF X <= Y THEN Y = 4

X: DFB 10HY: DFB 12H

IF: LDAA XCMPA Y BHI IF1LDAA #04H STAA Y

IF1: ....

5. The IF THEN ELSE statementIn comparing the value of operands, consider the following example.

6.7. IF X = 2 THEN Y = X ELSE X = Y

This becomes coded as,

X: DFB 00Y: DFB 00 IF: LDAA X

CMPA #02D BNE ELSE1 LDAA X STAA Y JMP IF1

ELSE1: LDAA Y STAA X

IF1: ....

8. The WHILE WEND statementConsider the following example for unsigned values.

9.10. WHILE X < 10 DO11. Y = Y + 1 X = X + 1 12. WEND

This becomes coded as,

Page 87: Assembly Language Project

X: DFB 00H Y: DFB 00HDO1: LDAB X

CMPB #10D BCC EXIT1 ; for signed use BLTLDAA Y ; increment value of Y ADDA #01 STAA Y LDAA X ; increment value of X ADDA #01 STAA X JMP DO1

EXIT1: ...

Consider the coding of the following HLL program into 6802 assembler.

Program HLLTest();var loop, val1, val2 : Byte;Begin

val1 := 0; val2 := 0; loop := 0; while loop <= 10 do begin

val2 := val2 + loop;loop := loop + 1

end; if val1 < val2 then val1 := val2 else val2 := val1

end.

The 6802 assembler version is

; HLLtest.asmCPU 6802 HOF MOT ORG 100h loop: dfb 0 val1: dfb 0 val2: dfb 0ORG 120h

Page 88: Assembly Language Project

Begin: LDAA #0 ; val1 := 0 STAA val1 LDAA #0 ; val2 := 0 STAA val2 LDAA #0 ; loop := 0 STAA loop

While: LDAA loop ; while loop <= 10 do CMPA #10 BGT if1 LDAA val2 ; val2 := val2 + loopLDAB loop ABASTAA val2 LDAA loop ; loop := loop + 1 ADDA #01STAA loop JMP While ; endwhile

if1: LDAA val2 ; if val1 < val2 then CMPA val1 BGE Else LDAA val2 ; val1 := val2 STAA val1 JMP endif

Else: LDAA val1 ; else val2 := val1 STAA Val2

Endif: NOPSWIEnd Begin

DATA CONVERSION ROUTINESComputer systems use character based keyboards and displays for inputting and outputting data. Conversion routines are necessary to convert data types to character strings and back again.

Consider the entry from a keyboard of an integer value 276. This represents a three character sequence of '2', '7' and '6'. This character sequence will need to be converted into an appropriate 16bit value representing an integer. Also consider displaying the value of a byte as two hex digits. Each nibble must be converted to an ASCII character before displaying on the terminal screen.

Page 89: Assembly Language Project

HEX BYTE TO ASCII CHARACTERSThis routine converts a byte to TWO ASCII characters. eg,

AFH becomes 41H 46H

The algorithm for this is

GET DIGITMASK OFF HIGH NIBBLE CONVERT TO ASCII MASK OFF LOW NIBBLE CONVERT TO ASCII

The following code shows an MC6802 implementation.

CPU 6802HOF MOT ORG 0100H

Val1: DFB 3FH Result: DFS 02H

ORG 120H Start:

LDAA Val1 ; get val1 PSHA ; save val1 ANDA #0F0H ; mask high byteLSRA ; shift to low nibble LSRA LSRA LSRA JSR Conv ; convert high nibble STAA Result ; store it PULA ANDA #0FH ; mask low nibbleJSR Conv ; convert low nibble STAA Result+1 ; store it

Exit: BRA Exit

Conv: CMPA #9H ; check for digit BLS ASCZ ADDA #07 ; adjust for letter

ASCZ: ADDA #30H ; adjust to ASCII RTS

Page 90: Assembly Language Project

END Start

ASCII STRING TO HEX BYTEThis routine converts a two character sequence into a hexadecimal byte, eg.

41H 46H becomes AFH

The algorithm for implementing this routine is,

Get Digit Subtract 30H from Digit If Digit greater than Nine

Subtract 07H from Digit EndIfShift into High Nibble and Store Get Next Digit Subtract 30H from Next Digit If Next Digit greater than Nine

Subtract 07H from Next Digit EndIf OR Next Digit with stored High Nibble and Store

The following code shows an MC6802 implementation.

CPU 6802 HOF MOTORG 0100H

ASC1: DFB 33H ASC2: DFB 46H HexB: DFB 00H

ORG 120H

Start:LDAA ASC1 ; get first digit SUBA #30H CMPA #09H BLS If1 SUBA #07h

If1: ASLAASLA ASLA ASLA

Page 91: Assembly Language Project

STAA HexB LDAA ASC2 ; get next digitSUBA #30H CMPA #09H BLS If2 SUBA #07h

If2: ORAA HexB STAA HexBEND Start

8BIT MULTIPLYThis routine multiplys two 8bit values together generating a 16bit result. The following algorithm (for two unsigned 8bit values) is based on processors which do not have MULTilpy instructions.

Set Product equal to Zero Set Counter equal to Eight While counter not equal to zero Left Shift Product (Multiply by 2) Shift Multiplier so bit goes into Carry If Carry bit is Set Product equals Product plus Multipicand Endif Subtract one from Counter EndWhile

The following program implements this for an MC6802.

CPU 6802 HOF MOT ORG 0100H

Val1: DFB 10HVal2: DFB 20HResult: DFS 02H

ORG 0120H

Start: CLRA ; product MSB = zeroCLRB ; product LSB = zero LDX #0008H ; multiplier = 8

Shift: CPX #0000H BEQ Exit ASLB ; shift product left 1 bit ROLA

Page 92: Assembly Language Project

ASL Val1 ; shift multiplier left to BCC Decr ; examine next bit ADDB Val2 ; Add multiplicand to ADCA #00H ; product if carry is set

Decr: DEXBRA Shift ; loop till all 8bits are done

Exit: STAA ResultSTAB Result+1

Finish: BRA Finish END Start

8BIT DIVIDEThis routine divides two 8bit values generating an 8bit quotient and 8bit remainder.The following algorithm (for two unsigned 8bit values) is based on processors which do not have DIVide instructions.

Set Quotient equal to Zero Set Counter equal to Eight While Counter not equal to zero Left Shift Dividend (Multiply by 2) Left Shift Quotient If 8 MSB's of Dividend >= Divisor then MSB of Dividend = MSB of Divident -

Divisor Add one to Quotient EndIf Subtract one from Counter EndWhile Remainder = MSB of Dividend

The following program implements this for an MC6802.

CPU 6802 HOF MOT ORG 0100H

Val1: DFB 10H ; DividendVal2: DFB 20H ; DivisorQuot: DFB 00HRem: DFB 00H

ORG 0120H

Start: LDX #0008H ; Number of bits in Divisor

Page 93: Assembly Language Project

CLRALDAB Val1 ; Get Dividend

Div: CPX #0000H BEQ Exit ASLB ; Shiftv Dividend and Quotient ROLACMPA Val2 ; is subtraction successfulBCS ChkCnt SUBA Val2 ; Yes, subtract and set bit in

quotient INCB

ChkCnt: DEX BRA DivExit: STAB Quot

STAA Rem END Start

ASCII TO INTEGERThis routine converts an ASCII character string into a 16bit signed integer value. To implement this routine, the following variables are used.

OFFSET DFB ;offset into ASCII string BUFFER DFS ;space for ASCII string BINV DFW ;integer result BASE DFW ;base 10 value

The algorithm for implementing the routine is,

Position Offset to last character in Buffer Set Base equal to 1 Set BinV equal to zero While Offset is not zero do

Get Character stored at Buffer[Offset]If character not '-' sign then

Mask out high nibble Multiply by Base value Add result to Binv Base equals Base * 10 Subtract one from Offset

Else Set HighBit of BinV to 1 Set Offset equal to zero

Endif

Page 94: Assembly Language Project

EndWhile

INTEGER TO ASCIIThis routine converts a 16bit signed integer into an ASCII character string. To implement this routine, the following variables are used.

OFFSET DFB ;offset into ASCII string BUFFER DFS ;space for ASCII string BINV DFW ;integer value BASE DFW ;base 10 value

The algorithm for implementing the routine is,

Offset equals last position in Buffer Get BinVSave BinV value for later use While BinV not less than 10

Divide BinV by 10 BinV equals remainder added with 30H Store result at Buffer[Offset] Offset equals Offset - 1

EndWhile Add 30H to BinVStore result at Buffer[Offset]Restore original BinV value If highbit set on BinV

Subtract one from Offset Store '-' sign at Buffer[Offset]

Endif

PACKED BCD TO DECIMALThis routine converts a two digit packed BCD number into an 8bit decimal number. 93 becomes 5DH. The algorithm for performing this is,

Get Packed BCD Value into Byte Move High Nibble to Low Nibble of Byte Zero High Nibble of Byte Multiply Byte by 10 Add Low Nibble of BCD Value to Byte

The following program shows how this is implemented on the MC6802.

Page 95: Assembly Language Project

CPU 6802 HOF MOT ORG 0100H

Val1: DFB 00HVal2: DFB 0AH ; multiply by 10 decimalResult: DFS 02H ; result of Val1 * Val2PackBCD:DFB 93HDecVal: DFB 00H

ORG 0110H

Start: LDAA PackBCDLSRA ; shift high nibble to low nibble LSRA LSRA LSRA STAA Val1 ; multiply high nibble by 10 JSR Multiply LDAA PackBCD ANDA #0FH ; mask high byte ADDA Result+1 ; add to high byte * 10 STAA DecVal ; store decimal value

Finish: BRA Finish

Multiply: CLRA ; product MSB = zero CLRB ; product LSB = zero LDX #0008H ; multiplier = 8

Shift: CPX #0000H BEQ Exit ASLB ; shift product left 1 bit ROLAASL Val1 ; shift multiplier left to BCC Decr ; examine next bitADDB Val2 ; Add multiplicand to ADCA #00H ; product if carry is

setDecr: DEXBRA Shift ; loop till all 8bits are done

Exit: STAA Result STAB Result+1 RTS END Start

Page 96: Assembly Language Project

MODERN 16 BIT MICROPROCESSORS[8086] In the code examples so far, we have separated out the coded instructions from the data. Modern processors like the 8088 have separate registers which deal with each section of a program.

CS and IP = instructionsDS, BX, SI= data ES, BX, DI= extra data SS, SP, BP= stack

In writing programs for modern processors like the 8088, the program is structured with a minimum of three sections, called SEGMENTS. The three segments represent the CODE, DATA and STACK areas of the program. Information within each segment is accessed differently depending upon the segment type. To access data in the stack segment requires the use of the SS, SP and or BP registers. The following diagrams illustrates how information in the stack and data segments are accessed.

Page 97: Assembly Language Project

Special assembler directives are used to specify the different segments

SEGMENT DIRECTIVESThe following directives illustrate how to define the three basic segments for an 8088 assembly language program.

.STACK 100H

.DATA

.CODE

The value following the stack directive specifies the size of the stack segment.

The programmer is responsible for initializing the segment registers DS and ES to the correct segments of the program. Failure to do so will result in a program which will not access the data and extra data segments properly. The operating system will only initialize the CS, SS, SP and IP registers.

The following code portion illustrates how to setup the data segment register. This is performed at the beginning of the code segment.

.STACK 100H

.DATA

.CODEMOV AX, @DATA ; initialize DSMOV DS, AX

Page 98: Assembly Language Project

DIFFERENT SIZED MEMORY MODELSThe 8088 processor supports several different memory models. We shall look at the most common types.

SMALL memory modelThe small memory model is limited to a single combined segment of 64k bytes. This segment is a combination of the stack, code and data segments. The assembler directive used to specify a small memory model is,

.MODEL SMALL

LARGE memory modelThe large memory model supports multiple segments, each segment limited to 64k bytes. The code and stack segments are limited to 64k bytes each, but we can have two data segments of 64k bytes each. The assembler directive used to specify a large memory model is,

.MODEL LARGE

Use this memory model for all your programs.

SUPPORT FOR DIFFERENT CPU TYPESThe following directives are used to specify the processor type.

.186

.286

.386

.8087

.8086

RETURNING TO PCDOSWhen an assembly language program running under PCDOS terminates, it must return to the operating system so that the user shell program can be re-loaded. The correct format is to use the following code sequence

Page 99: Assembly Language Project

mov ax, 4c00hint 21h

ASSEMBLER DIRECTIVES FOR IBM-PC PROGRAMSThe following is a discussion of the assembler directives applicable to packages like Microsoft Masm and Turbo Assembler. These packages are used to write machine code programs which run under PCDOS.

EQUATESThe EQU directive creates absolute symbols and aliases by assigning an expression or value to the declared variable name. Its format is,

name EQU expression

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.

pi EQU 3.14159clearax EQU xor ax,ax

The first example directs the assembler to replace every occurrence of the name pi with the value 3.1459, whilst the second example instructs the assembler to replace every occurrence of clearax with the instruction xor ax,ax

BYTE STORAGEThe DB directive allocates and initializes a byte (8bits) of storage for each argument. Its format is,

name DB initialvalue,,,

The name portion is optional.

value1 DB 16form DB 6*2text DB "Enter your name:"

In the first example, value1 is assigned a byte, and is initialized to 16, the second example sets form equal to 12 and assigns it a byte, and in the last example,text is defined as a sequence of bytes which each contain a character

Page 100: Assembly Language Project

from the specified string. The first byte will be initialized to 'E', whilst the last byte will be initialized to a space character.

WORD STORAGEThe DW directive allocates a word (2bytes) of storage for each initialized value. Its format is,

name DW initialvalue,,,

The name portion is optional.

DW ?mess DW 'ab'

The first example allocates one word of storage, but does not define its initial value (?). The second example defines mess as a word initialized with the character string 'ab'.

Strings when using the DW directive must not contain more than two characters. 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 00H. The low-order byte appears FIRST for Intel Processors.

TITLEThe title directive specifies the program listing title.

TITLE Graphics

This appears at the top of each page in the assembler list file, after the source file name.

NAMEThe name directive is used to set the name of the current module. The module name is used by the linker when displaying error messages. If no module name is used, the linker will use the name specified using the title directive.

NAME Calculate_Gross

PAGE CONTROLThe PAGE directive can be used to designate the line length and width for the program listing; normally used to generate a page break in the assembler listing file.

Page 101: Assembly Language Project

When assembly is taking place, and the page directive is encountered, the assembler generates a form-feed character to set a new page, and continues the assembly on the new page. In this way, the programmer can organize a printout of modules on a per page basis, so that the printout of more than one module per page does not occur.

PAGE 66,132 ; 66 lines per page ; 132 characters wide

PAGE ; go to new page in list file

PROCEDURESThese directives are used to implement small procedures (modules).

name PROC codetype .... ret name ENDP

The last instruction in a procedure is a RETurn instruction. The codetype is FAR for large memory models, NEAR for small memory models. A procedure must be entered using the appropriate CALL instruction.

DEFINE DOUBLE WORD, DEFINE QUAD WORD and DEFINE TENThe DD directive defines a double word [4bytes] of storage. This is used to reserve storage for 32 bit integers, floating point numbers, or far pointers to code or data [segment:offset pair].

The DQ directive defines a quad word [8bytes] of storage for double precision floating point numbers.

The DT directive defines 10bytes of storage. This is normally used for Packed BCD numbers and a 10 byte temporary real floating point value, as this storage format is also used by the 80x87 arithmetic co-processor.

OFFSETThe offset directive returns the number of bytes a variable begins at, relative to the start of the segment it is in. This is necessary when calling PCDOS routines.

.DATA temp db 10 mess db 'Hi there','$' .CODE

Page 102: Assembly Language Project

start: mov ax, @data mov ds, ax mov ah, 9h mov dx, OFFSET mess ;1 byte in .DATA

segment int 21h ;print message mov ax, 4c00h ;return to PCDOS int 21h END start

SAMPLE PROGRAM FOR IBM-PC

TITLE Doscall ;Doscall.asm source file .MODEL SMALLCR equ 0ahLF equ 0dhEOSTR equ '$'

.stack 200h

.datamessage db 'Hello and welcome.' db CR, LF, EOSTR

.codeprint proc near

mov ah,9h ;PCDOS print function int 21h ret

print endp

start: mov ax, @datamov ds, ax mov dx, offset message call print mov ax, 4c00h int 21h end start

The program is assembled by typing

$ TASM DOSCALLTurbo Assembler V1.0 Copyright(c)1988 by Borland

International

Page 103: Assembly Language Project

Assembling file: DOSCALL.ASM Error messages: None Warning messages: NoneRemaining memory: 257k $

This produces an object file named DOSCALL.OBJ which must be linked to create an executable file which can run under PCDOS.

$ TLINK DOSCALL Turbo LinkV2.0 Copyright (c) 1987, 1988 Borland

International $

The program when run, produces the following output.

$ DOSCALL Hello and welcome. $

MACROSThe macro directive allows the programmer to write a named block of source statements, then use that name in the source file to represent the group of statements. During the assembly phase, the assembler automatically replaces each occurrence of the macro name with the statements in the macro definition.

Macros are expanded on every occurrence of the macro name, so they can increase the length of the executable file if used repeatably. Procedures or subroutines take up less space, but the increased overhead of saving and restoring addresses and parameters can make them slower. In summary, the advantages and disadvantages of macros are,

Advantages

Repeated small groups of instructions replaced by one macro Errors in macros are fixed only once, in the definition Duplication of effort is reduced In effect, new higher level instructions can be created Programming is made easier, less error prone Generally quicker in execution than subroutines

Page 104: Assembly Language Project

DisadvantagesIn large programs, produce greater code size than procedures

When to use Macros

To replace small groups of instructions not worthy of subroutines To create a higher instruction set for specific applications To create compatibility with other computers To replace code portions which are repeated often throughout the program

MACRO DEFINITIONDefining Macros is done as follows,

name MACRO [optional arguments]statementsstatements ENDM

Consider the following macro to return to PCDOS from an assembly language program.

exittodos MACRO mov ax,4C00hint 21h

ENDM

Macros are expanded when the program is assembled. This means that every occurrence of the macro name (apart from the definition) is replaced by the statements in the macro definition. An example will demonstrate this.

TITLE dosmacro .MODEL smallexittodos MACRO mov ax,4C00h

int 21h ENDM

.STACK 100h

.DATAmessage DB 'Hello and Welcome', '$'

.CODE

Page 105: Assembly Language Project

start: mov ax, @data mov ds, ax mov ah, 9h mov dx, OFFSET message int 21h exittodos END start

When assembled, the macro is replaced and the internal representation of the file looks like,

TITLE dosmacro .MODEL smallexittodos MACRO mov ax,4C00h

int 21h ENDM

.STACK 100h

.DATAmessage DB 'Hello and Welcome', '$'

.CODEstart: mov ax, @data

mov ds, ax mov ah, 9h mov dx, OFFSET message int 21h mov ax,4C00h int 21h END start

Macros can also accept values (parameters).

addup MACRO ad1,ad2, ad3 mov ax, ad1mov dx, ad2 mov cx, ad3 ENDM

In this example a macro named addup is created. It accepts three parameters, ad1, ad2 and ad3. The code which follows, consisting of

Page 106: Assembly Language Project

the mov statements, will be used to replace every occurrence of the macro name addup in the source file. The macro is terminated with the ENDM statement.Calling a macro with arguments is done as follows,

addup bx, 2, count

This has the effect of loading the ax register with the contents of the bx register, the dx register with the value 2, and the cx register with the value of count.

Macro definitions may include other macro names, and macros may also be recursive: they can call themselves, eg,

pushall MACRO reg1, reg2, reg3, reg4, reg5, reg6 IFNB <reg1> ;; If parameter not blank push

reg1 ;; push one register and ;; repeat

pushall reg2, reg3, reg4, reg5, reg6 ENDIF ENDM

pushall ax, bx, si, dspushall cs, es

This shows a recursive macro called pushall that continues to call itself until it encounters a blank argument. In effect, it pushes the registers specified in the macro call onto the stack.

The ;; indicates that the comment field of the macro should not be expanded with the macro statements.

IMPLEMENTING FP NUMBERS, ARRAYS, RECORDS AND JUMP TABLES

Floating Point NumbersThe following example shows the declaration of a single precision floating point decimal number (stored in IEEE 754 standard).

FPnum1 DD 1.32740

Page 107: Assembly Language Project

BCD stringsThe following example declares a packed BCD constant.

BCDval DT 123456

Ten bytes are allocated, giving a number range of 0 to 99,999,999,999,999,999,999.

HANDLING ARRAYSArrays and array elements are dealt with using pointers. This involves either based or indexed addressing.

Manipulating an Array Element 1: Load a base/index register with the address of

the first element 2: Calculate the offset position of the required

element (1 byte for characters, 2 bytes for integers etc) 3: Perform the operation by either a) incrementing the base/index register by

the required amount b) use based indexed addressing eg, X := IntArray[4]; mov bx, offset IntArray ; base address mov ax, 4 ; calculate offset mul ax, 2 mov si, ax mov X, [bx + si]

Cycling through an Array using a Loop count variableThe principles are the same, but the offset is the loop count variable adjusted by the number of bytes per element.eg,

FOR Loop := 1 to 10 do BEGIN sum := sum + IntArray[Loop] END; initfor:mov ax, 1 ; Loop := 1 mov Loop, ax mov bx, offset IntArrat ; setup base

register for: mov ax, Loop

Page 108: Assembly Language Project

cmp ax, 10 ja forexit mov ax, Loop ; calculate offset mul ax, 2 mov si, ax mov ax, [bx + si] mov cx, sum ; add sum and

intArray[Loop] add ax, cx mov sum, ax ; update sum jmp for forexit:

Integer ArraysInteger arrays occupy two bytes per element. A typical operation is to sum the contents of an integer array. The following code for an 8086 shows this.

TITLE IntArray .MODEL Large .STACK 200h .DATAmess db 'The total is ','$'result dw ?IntArry dw 10, 34, 76, 25, 14, 9, 3, 22IntAlen dw ($ - IntArry) / 2buff db 6dup( 20h ) db '$'

.CODE

binasc proc far ; convert result to ascii string

mov ax, 0 mov ax, [result] ; get number to convert push ax ; save it mov si, offset buff[5] ; point to string area mov cx, 10 ; divide base factor shl ax, 1 ; clear sign bit shr ax, 1

do1: cmp ax, 10 ; compare with base fact

jb exit1 mov dx, 0 ; clear upper numerator

Page 109: Assembly Language Project

div cx ; divide by base factor add dl, 30h ; convert to ASCII mov [si], dl ; and store it dec si ; next character jmp do1

exit1: add al, 30h ; convert last character mov [si], al ; and store it pop ax ; recover or ax, ax ; and test for sign

bit jns exit2dec si ; store '-' signmov bl, 2dh mov [si], bl

exit2: retbinasc endp

start: mov ax, @datamov ds, ax mov [result], 0000h ; clear result mov cx, IntAlen ; count of elements mov bx, offset IntArry ; point to IntArrymov si, 0000h ; first element xor ax, ax ; clear total

lp1: add ax, [bx + si] ; add value to total inc si ; next element inc sidec cx jne lp1 mov [result], ax ; store total mov dx, offset mess ; print message mov ah, 9h int 21h call binasc ; convert result to

ASCII mov dx, offset buff mov ah, 9h int 21h mov ax, 4c00h ; exit to DOS int 21h END start

Other typical operations involve the determination of the minimum and maximum values.

Page 110: Assembly Language Project

Records (Structures)Records in Pascal support the use of different sized field items. Consider the storage of the following record.

Var example_record = RECORDint_number : integer; fp_number : real; letter : character; END;

The same record is implemented in assembly language by first defining its composition.

ex_rec STRUCint_num dwfp_num dd lett db

ex_rec ENDS

The next step creates a record which has the composition of the previous records definition.

my_rec ex_rec <22, 3.2, 'Hi there.$'>

Each field of the record is accessed in a similar method to that of Pascal, eg,

ex_rec.lett

accesses the lett field of the record ex_rec. The following program shows an implementation for the 8088 processor.

TITLE Records .MODEL Large

ex_rec STRUCint_num dw

fp_num dd

Page 111: Assembly Language Project

mess db " "ex_rec ENDS

.STACK 200h

.DATAmyrec ex_rec <22,1.30, "Hello there.$">

.CODEstart: mov ax, @data

mov ds, ax mov dx, offset myrec.mess mov ah, 9h int 21h mov ax,4c00h int 21h END start

Jump TablesJump tables are an efficient method of implementing switch/case type statements. A jump table consists of an array of addresses. Using an offset into the array selects the address of the routine which handles that particular value.

Jump tables are efficient, because it always take the same time to select any routine from the table. The order may be re-arranged or new routines added simply be increasing the size of the table.

The following program implements a jump table.

TITLE Jump.asm .MODEL Large .STACK 200h .DATAhelp db 'This program exits when a function key is

pressed.' db 10, 13, 'Ctrl A generates underline.', 10, 13 db 'Ctrl B generates bold.', 10, 13 db 'Ctrl C generates blinking.', 10, 13 db 'All other control codes return to normal text.',

10, 13 db 10, 13, 'Start typing characters.', 10, 13,

'$'attrib db 07h ; screen attribute byte

Page 112: Assembly Language Project

; a table of addresses used to decipher recieve control codes

; each entry is the address of the appropriate routine

ctl_tbl label worddw ctrl_null ; 0 dw ctrla ; 1 dw ctrlb ; 2 dw ctrlc ; 3 dw ctrld ; 4 dw ctrle ; 5 dw ctrlf ; 6 dw ctrlg ; 7 dw ctrlh ; 8 10 dw ctrli ; 9 11 dw ctrlj ; a 12 dw ctrlk ; b 13 dw ctrll ; c 14 dw ctrlm ; d 15 dw ctrln ; e 16 dw ctrlo ; f 17 dw ctrlp ; 10 20dw ctrlq ; 11 21 dw ctrlr ; 12 22 dw ctrls ; 13 23 dw ctrlt ; 14 24 dw ctrlu ; 15 25 dw ctrlv ; 16 26 dw ctrlw ; 17 27 dw ctrlx ; 18 30 dw ctrly ; 19 31 dw ctrlz ; 1a 32 dw ctrl_lbkt ; 1b 33dw ctrl_bslash ; 1c 34 dw ctrl_rbkt ; 1d 35 dw ctrl_carat ; 1e 36 dw ctrl_ul ; 1f 37

.CODEbumpcur proc far ; move cursor right one character

mov ah, 3 xor bh, bh int 10h ; read int dh, dl inc dl ; next column cmp dl, 80 ; end of line?

Page 113: Assembly Language Project

jle short bpcur1 xor dl, dl ; go to start of next line inc dh cmp dh, 24 ; end of screen?jl short bpcur1 mov ax, 0601h ; then scroll up xor cx, cx push dx mov dh, 24 mov dl, 80 mov bh, [attrib]int 10h pop dx mov dh, 24 ; position bottom

linebpcur1:xor bh, bh ; set cursor positionmov ah, 2 int 10h ret

bumpcur endp

ctrl_code proc far ; process Control CODES push bx cbw ; convert AL to AX mov bx,ax ; use bx and an index into shl bx,1 ; the ctrl_tbl jmp ctl_tbl[bx] ; jump to key routine

ctrla: and byte ptr [attrib], 0f9h ; underline jmp ctrl_exit

ctrlb: or byte ptr [attrib], 08h ; bold jmp ctrl_exit

ctrlc: or byte ptr [attrib], 80h ; blink on jmp ctrl_exit

ctrld: ; all others normal ctrl_null:ctrle:ctrlf:ctrlg:ctrlh:ctrli:ctrlj:ctrlk:ctrll:ctrlm:ctrln:ctrlo:

Page 114: Assembly Language Project

ctrlp:ctrlq:ctrlr:ctrls:ctrlt:ctrlu:ctrlv:ctrlw:ctrlx:ctrly:ctrlz:ctrl_lbkt:ctrl_bslash:ctrl_rbkt:ctrl_carat:ctrl_ul:

mov byte ptr [attrib], 07h ; normal attributectrl_exit: pop bx

retctrl_code endp

start: mov ax, @data mov ds, ax mov ah, 9h ;print help message mov dx, offset help int 21

hlp1: mov ah, 06h ; read character from keyboard mov dl, 0ffh int 21h jz lp1 ; repeat if character not

ready cmp al, 00h ; if function key then exitje exit cmp al, 32 ; else if control code jae disp1 call ctrl_code ; then process control

code jmp lp1

disp1: push bx xor bx, bx ; page zero on video memory mov bl, [attrib] ; get character attributemov cx, 1 ; one character to write mov ah, 9 ; write char + attributeint 10h ; use BIOS call call bumpcur ; next cursor position jmp lp1 ; repeat

Page 115: Assembly Language Project

exit: mov ax, 4c00h int 21h

END start

PARAMETER PASSINGParameter passing refers to the exchange of data between modules. There are many ways this information can be exchanged.

1. GLOBAL DATA USING COMMON BUFFER OR MEMORYThe data is stored in memory accessible to all modules. The disadvantage of this technique is that the data may be modified by any module, which makes debugging harder.

Consider the following simple program which adds two numbers together, storing the result. All data has been declared as common.

TITLE CommonData .MODEL Large .STACK 200h .DATAnum1 dw 22num2 dw 32result dw 0

.CODEaddnum proc far

mov ax, [num1] mov bx, [num2] add ax, bx mov [result], ax ret

addnum endp

start: mov ax, @data mov ds, ax call addnum ; add num1 and num2 mov ax, 4c00h int 21h END start

Page 116: Assembly Language Project

2. REGISTER VARIABLESThis technique involves passing and returning values using processor registers.

Routines must ensure that they do not corrupt any registers other than those which have been specified. The programmer first determines which registers will be used and which can be altered (contents destroyed).

Consider the following implementation of the previous addition program to use register variables.

TITLE CommonData .MODEL Large .STACK 200h .DATAnum1 dw 22num2 dw 32result dw 0

.CODEaddnum proc far

; accepts num1 in ax, num2 in bx, returns result in dx

push ax add ax, bx mov dx, ax pop ax ret

addnum endp

start: mov ax, @data mov ds, ax mov ax, [num1] mov bx, [num2] call addnum ; add num1 and num2 mov [result], dx mov ax, 4c00h int 21h END start

Page 117: Assembly Language Project

The advantage is that only the calling module alters the data, whilst the module addnum only works on copies of the data. In this way, it is easier to track which modules affect the data variables.

3. STACK VARIABLESParameters may also be passed using the stack. This involves pushing the values onto the stack before the module is called. This may also involve pushing space onto the stack for a return result.

The module then accesses the parameters on the stack using the appropriate addressing mode.

Upon return to the calling module, the stack space is deallocated using appropriate pop or stack pointer adjustment instructions.

There are two ways in which data may be referenced using the stack.

1. Call by ValueThis refers the placing of copies of the data value on the stack. Only the copy is worked with, the original remains unmodified.

2. Call by ReferenceThis refers to the passing of the address of the variable using the stack. This address is used to access the data, thus the original data is used.

Call by value is normally used for simple data types, whilst call by reference is used for data types like arrays and records, because of the amount of memory space they occupy (and stack space is normally limited).

Consider the following program for an MC6802 processor which uses Call by Value to add two variables together.

CPU 6802 HOF MOT ORG 100HNum1: DFB 10Num2: DFB 20Result: DFB 0

Start: PSHA ; Make room for result on stack LDAA Num1 LDAB Num2 PSHA ; Place copy Num1 on stack

Page 118: Assembly Language Project

PSHB ; Place copy of Num2 on stack JSR Addup PULB ; remove copy of Num2 PULA ; remove copy of Num1 PULA ; get result from Addup STAA Result

Exit: BRA Exit

Addup: TSX ; transfer SP into IX register PSHA ; save registers PSHB LDAA 02,X ; Get Num2 LDAB 03,X ; Get Num1 ABA ; Add Num1 and Num2 STAA 04,X ; Store on stack for return PULB ; Recover original register values PULA RTS END Start

PARAMETER PASSING FOR THE 8088 PROCESSOR

ACCESSING THE STACK FRAME INSIDE A MODULELets look at how a module handles the stack frame. Because each module will use the BP register to access any parameters, its first chore is to save the contents of BP.

push bp

It then transfers the address of SP into BP; BP now points to the top of the stack.

mov bp,sp

thus the first two instructions in a module will be the combination,

push bp mov bp,sp

ALLOCATION OF LOCAL STORAGE INSIDE A MODULELocal variables are allocated on the stack using a

Page 119: Assembly Language Project

sub sp, n

instruction. This decrements the stack pointer by the number of bytes specified by n. For example, a module might want to use temporary storage space for an integeri, which equates to the machine code instruction

sub sp, 2

Pictorially, the stack frame looks like,

+---------+ | ihigh |<-- SP +---------+ | ilow | +---------+ | BPhigh |<-- BP +---------+ | BPlow | +---------+

The local variable i can be accessed using SS:BP - 2, so the statement,

i = 24;

is equivalent to

mov [bp - 2], 18

Note that twenty-four decimal is eighteen hexadecimal.

DEALLOCATION OF LOCAL VARIABLES WHEN THE MODULE TERMINATESWhen the module terminates, it must deallocate the space it allocated for the variable i on the stack. Referring to the above diagram, it can be seen that BP still holds the top of the stack as it was when the module was first entered. BP has been used for two purposes,

Page 120: Assembly Language Project

to access parameters relative to it to remember where SP was upon entry to the module

The deallocation of any local variables (in our case the variable i) will occur with the following code sequence,

mov sp, bp ;this recovers SP, deallocating i pop bp ;SP now is the same as on entry to module

THE PASSING OF PARAMETERS TO A MODULEConsider the following module call in a high level langauge.

add_two( 10, 20 );

The language pushes parameters (the values 10 and 20) right to left, thus the sequence of statements which implement this are,

push ax ; assume ax contains 2nd parameter, ie, integer ; value 20 push cx ; assume cx contains 1st parameter, ie, integer ; value 10 call add_two

The stack frame now looks like,

+---------+ | Return |<-- SP +---------+ | address | +---------+ | 00 | ;1st parameter, integer value 10 +---------+ | 0A | +---------+ | 00 | ;2nd parameter, integer value 20 +---------+ | 14 | +---------+

Page 121: Assembly Language Project

Remembering that the first two statements of module add_two() are,

add_two: push bp mov bp, sp

The stack frame now looks like (after those first two instructions inside add_two)

+---------+ | BPhigh |<-- BP <-- SP +---------+ | BPlow | +---------+ | Return | +---------+ | address | +---------+ | 0A | ;1st parameter, integer value 10 +---------+ | 00 | +---------+ | 14 | ;2nd parameter, integer value 20 +---------+ | 00 | +---------+

ACCESSING OF PASSED PARAMETERS WITHIN THE CALLED MODULEIt should be clear that the passed parameters to module add_two() are accessed relative to BP, with the 1st parameter residing at [BP+4], and the 2nd parameter residing at [BP+6].

DEALLOCATION OF PASSED PARAMETERSThe two parameters passed in the call to module add_two() were pushed onto the stack frame before the module was called. Upon return from the module, they are still on the stack frame, so now they must be deallocated. The instruction which does this is,

add sp, 4

Page 122: Assembly Language Project

where SP is adjusted upwards four bytes (ie, past the two integers).

INTERFACING TO HLL ROUTINESThere are times that high level languages need to call assembly language modules. This results due to constraints like speed and memory space.

We shall look at interfacing a Pascal program to an assembly language module.

The Pascal program will declare an integer based array, and pass the address of this array, and the number of elements in the array, to an assembly language module.

Using the address, the assembly language module will add the sum of the array, returning the result to the Pascal program.

The assembly language module is shown below.

TITLE Addup88 .MODEL TPASCAL .CODE PUBLIC AddupAddup Proc Far Array : DWORD, Elements : WORD RETURNS

Reslt : WORD push ds ; save ds register push cx ; save cx register push si ; save si register lds si, Array ; point DS:SI to array element1 mov cx, Elements ; count of elements xor ax, ax ; clear total

lp1: add ax, [si] ; add value to total inc si ; next element inc si dec cx jne lp1 pop si pop cx pop ds RET ; exit to Pascal Module with ; result in AX

Addup ENDPEND

Page 123: Assembly Language Project

This is compiled to OBJECT code by the command

$TASM ADDUP88

The Pascal module is shown below.

Program ADDDEMO (input, output); Uses DOS, CRT; Type IntArray = Array[1..20] of Integer; Var

Numbers : IntArray; Result : Integer; Loop : Integer; {$F+}

Function Addup( var Numbers : IntArray; Elements : Integer )

: Integer ; EXTERNAL; {$L ADDUP88.OBJ} {$F-}

begin for loop:= 1 to 20 do

Numbers[loop] := loop; Result := Addup( Numbers, 20 ); Writeln('The sum of the array is ', Result)

End.

When compiled under Turbo Pascal, the two object modules are linked together, creating an executable file.

ASSEMBLER OPTIONSVarious options are supported by most assemblers. These options provide for

increase productivity to check operation of assembler - macros, equates to simplify control provide flexibility

Page 124: Assembly Language Project

COMMAND FILESCommand files are text files which contain commands to the assembler.

$TASM @MYCMDFIL

will invoke the assembler using the options specified in the file Mycdfil. If this file contained the following,

/a /e myprog, myobj, mylst;

this is equivalent to typing

$TASM /a /e myprog, myobj, mylst;

This simplifies the process of having to repeat all the command line options whilst the program is being debugged.

CONDITIONAL ASSEMBLY OF SOURCE CODE STATEMENTSThe following directives are used to specify to the assembler, whether or not to assemble the bracketed group of statements which follow.

IFELSEENDIFIFDEFIFNDEF

The IF directives and the ENDIF and ELSE directives can be used to enclose the statements to be considered for conditional assembly.

The conditional block of statements is used as follows,

IF debugxor ax,ax

ELSExor bx,bx

ENDIF

Page 125: Assembly Language Project

If the symbol debug equates to true (non-zero), the ax register will be cleared, otherwise the bx register will be cleared.

The IFDEF and IFNDEF directives test whether or not the given variable name/symbol has been defined.

IFDEF bufferbuf1 DB 10 DUP(?)

ENDIF

In this example, buf1 is allocated only if buffer has previously been defined. It consists of ten bytes whose initial value is undefined.

THE INCLUSION OF SOURCE MACROS AND DEFINITIONSA macro or definition file is a collection of definitions or program code which can be included into the source code program. A macro file is simply a file containing macro definitions.

The programmer adds these definitions to the source file using the include directive, and may remove unwanted definitions using the purge directive.

The include directive inserts the definitions or code statements from the specified file into the current source file during assembly, and allows any variables or declarations in the include file to be referenced or accessed in the source program being written.

INCLUDE entryINCLUDE b:\include\c_stuff

LIST FILESList files have already been covered under section 6 dealing with CRS8.

The format for invoking the 8088 assembler is,

TASM sourceasmfile, objfilename, listfilename

or the /l option can be specified on the command line.

The following 8088 assembler directives can disable and enable the output listing.

Page 126: Assembly Language Project

%NOLIST%LIST

Consider the following 8088 assembly language program.

TITLE Doscall ;Doscall.asm source file .MODEL SMALLCR equ 0ahLF equ 0dhEOSTR equ '$' .stack 200h .datamessage db 'Hello and welcome.' db CR, LF, EOSTR .codeprint proc near

mov ah,9h ;PCDOS print function int 21h ret

print endp

start: mov ax, @data mov ds, ax mov dx, offset message call print mov ax, 4c00h int 21h end start

When assembled with the following command line options,

$TASM /l /n Doscall;

It generates a listing file. The list file for the program looks like,

Turbo Assembler Version 1.0 21-05-89 13:27:31 Page 1DOSCALL.ASMDoscall 1 0000 .MODEL SMALL

Page 127: Assembly Language Project

2 3 = 000A CR equ 0ah 4 = 000D LF equ 0dh 5 = 0024 EOSTR equ '$' 6 7 0000 .stack 200h 8 9 0000 .data 10 0000 48 65 6C 6C 6F 20 61 + message db 'Hello and welcome.' 11 6E 64 20 77 65 6C 63 + 12 6F 6D 65 2E 13 0012 0A 0D 24 db CR, LF, EOSTR 14 15 0015 .code 16 0000 print proc near 17 0000 B4 09 mov ah,9h ;PCDOS print function 18 0002 CD 21 int 21h 19 0004 C3 ret 20 0005 print endp 21 22 0005 B8 0000s start: mov ax, @data 23 0008 8E D8 mov ds, ax 24 000A BA 0000r mov dx, offset message 25 000D E8 FFF0 call print 26 0010 B8 4C00 mov ax, 4c00h 27 0013 CD 21 int 21h 28 29 end start

The s on line 22 indicates a segment register value which is filled in by the DOS loader when the program is loaded into memory. The r on line 24 indicates a relative value which is also filled in by the DOS loader.

SYMBOLIC INFORMATIONSymbolic information is useful in determining the size and location of variables, segments etc. This information is used when debugging the program or locating the program in Eprom.

The 8088 assembler options available are,

Page 128: Assembly Language Project

/c cross-reference in list file /l listfile generated /n suppress symbol table in list file /zd line numbers in object code /zi debug info in object code for debugger

When the previous program Doscall.asm is assembled with a list file and symbol plus cross-referencing, the additional information appended to the list file is,

Turbo Assembler Version 1.0 21-05-89 13:35:03 Page 2Symbol TableSymbol Name Type Value Cref defined at #??DATE Text "21-05-89"??FILENAME Text "DOSCALL "??TIME Text "13:35:03"??VERSION Number 0100@CODE Text _TEXT #1 #15@CODESIZE Text 0 #1@CPU Text 0101H@CURSEG Text _TEXT #9 #15@DATA Text DGROUP #1 22@DATASIZE Text 0 #1@FILENAME Text DOSCALL@WORDSIZE Text 2 #9 #15CR Number 000A #3 13EOSTR Number 0024 #5 13LF Number 000D #4 13MESSAGE Byte DGROUP:0000 #10 24PRINT Near _TEXT:0000 #16 25START Near _TEXT:0005 #22 29

Groups & Segments Bit Size Align Combine Class Cref defined at #DGROUP Group #1 1 22 STACK 16 0200 Para Stack STACK #7

Page 129: Assembly Language Project

_DATA 16 0015 Word Public DATA #1 #9_TEXT 16 0015 Word Public CODE #1 1 #15 15

This also shows which lines variables and labels were defined and referenced.

PROGRAM MANAGEMENT TOOLSThese tools are designed to make the process of maintaining programs easier.

MAKEThis utility is designed to ease updating of programs, especially multiple module programs.

It works by using a list of dependencies. These dependencies illustrate the relationship between the source, include, object and executable versions of the program.

The dependencies are stored in a file called makefile.

Consider a program which has the following dependencies.

MYDBASE.EXE comprises the modules start.obj search.obj fileio.obj keybdio.obj videoio.obj

Each object file is generated from an assembler source file of the same name.

The command sequence to create the executable program is,

tasm start tasm search tasm fileio tasm keybdio tasm videoio tlink start search fileio keybdio videio, mydbase;

The dependencies and command sequences required are entered into the makefile as follows.

Page 130: Assembly Language Project

mydbase.exe: start.obj search.obj fileio.obj keybdio.obj videoio.obj

tlink start search fileio keybdio videio, mydbase;

start.obj: start.asm tasm start

search.obj: search.asm tasm search

fileio.obj: fileio.asm tasm fileio

keybdio.obj: keybdio.asm tasm keybdio

videoio.obj: videoio.asm tasm videio

The program is assembled and linked by typing

make

It works by comparing date and time stamps of the files in each dependency list. Consider the lines

keybdio.obj: keybdio.asm tasm keybdio

It compares the date/time stamp of keybdio.asm against keybdio.obj. If the object file is newer than the assembly file, it will not re-assemble.

If the assembler file has a newer date/time stamp, it will execute the command tasm keybdio to generate a new object file.

The use of make files simplifies the re-assembly by only assembling those files which have been modified.

SOURCE CODE REVISION SYSTEMSSource code revision systems are used to keep track of different versions of a program. It keeps a record of all the changes made to the program.

Page 131: Assembly Language Project

Previous revisions can be extracted from the database, and a printout detailing the changes (time, who, line#) can be obtained.

LIBRARY MAINTENANCEThis applies to the maintenance of OBJECT code libraries.

An Object code library contains routines which can be reused in any program. The code for the routine is extracted from the library and combined with the users object code at linking time.

Users can create their own library routines. The source files are assembled into object code then added to a library.

The following code represents a routine for placement into a Video routines library.

TITLE SetCur .CODE PUBLIC setcur setcur proc far ; set cursor to position in DX register

mov ah, 2 ; dh = y co-ordinate, dl = x co-ordinate xor bh, bh int 10h ret

setcur endpEND

After assembling into Object code, the object code is placed into a video library using the TLIB utility.

TLIB video +setcur.obj

The following source file shows how to use the code in a library.

TITLE Libdemo .STACK 200h .CODEEXTRN setcur:farstart: mov dx, 0 ; cursor 0,0

Page 132: Assembly Language Project

call setcur mov ax, 4c00h int 21h

END start

After assembling the file Libdemo.asm, the command to link the object and library code together is,

TLINK Libdemo,libdemo.exe,libdemo.map, video

LINKERSThe assembler for 8088 PCDOS programs generates object code files. These cannot be executed directly on the computer system, but require further processing in order to generate a runfile. This further process is called the linking phase.

Functions performed by a linker include:

combines object modules together combines segments of the same type together resolves addresses unknown at assembly time allocates storage generates symbolic information generates a load module

8088 LINKER OPTIONSThe following options are used to obtain information which is helpful in debugging programs; or generate code for 386 processors.

/m add public symbols /x no map file /s map file with segments, publics symbols and start

address /t generate .COM file /v add debug info /3 386 code

The Map File FacilityIf the linker is requested to generate a map file, it will list the names, load addresses,

Page 133: Assembly Language Project

and lengths of all segments in a program. It also lists the names and load addresses of any groups in the program, the start address, and messages about any errors the linker may have encountered.

The map file generated by the linker for the program DOSCALL.ASM is,

Start Stop Length Name Class 00000H 00014H 00015H _TEXT CODE 00016H 0002AH 00015H _DATA DATA 00030H 0022FH 00200H STACK STACK Address Publics by Name Address Publics by ValueProgram entry point at 0000:0005

DEFINITION OF LINKING TERMS

Relocatable/RelativeThe code generated by the linker is all relative to the location counter. This means that all references to memory is relative to a base/index register, segment register or program counter. This allows the operating system to load the program anywhere in physical memory.

Relocatable code is a must for multi-user and multi-tasking operating systems. The program is preceded by a header file, which the operating systems loader uses to perform relocation.

Absolute/FixedIf the linker generates code which is absolute, all memory references are to absolute addresses, thus the program must reside in a designated memory space. If this space is unavailable, the program cannot be run and must wait.

Absolute code is normally used on small single processor systems (ie, CPM), and is not suitable for multi-user environments.

Absolute code does not contain a header file used for relocation, if a header file exists, it will specify the absolute load address of the code which follows the header file.

CommonVariables, labels or symbols may be designated as common. In this way, they

Page 134: Assembly Language Project

are made accessible to those modules which wish to reference them by way of calls or data usage. The common data is shared by the various modules.

The linker combines multiple definitions into a single overlayed segment.

External/PublicPublic data segments are located in one module but called from another.

The Public directive makes the variable, label or symbol in the current segment available to all other modules. It thus transforms locally defined symbols into global symbols.

The Extern directive makes a global symbols name and type known in a source file so that it may be used/referenced in that file. An extern item is a variable, label or symbol that has been declared using the public directive in another module of the program.

Example of program using public/extern directives:

Main Module NAME main .MODEL small PUBLIC exit ;defines exit as being known to

other modules EXTERN print:near ;defines print as existing in

another module .STACK 100h .DATA .CODEstart: mov ax, @data ; Load segment location

mov ds, ax ; into DS register jmp print ; goto PRINT in other module

exit: mov ax, 4C00h ; call terminate function int 21h END start

Task Module NAME task .MODEL small PUBLIC print ;defines print as public so it

can ;be used by the calling module

Page 135: Assembly Language Project

EXTERN exit:near ;defines exit as existing in another module

; outside this one .DATAstring DB "Hello",13,10,"$" .CODEprint: mov dx, OFFSET string ;Load location of string

mov ah, 09h ;call string display function

int 21h jmp exit ;go back to main module

END

In this example, the symbol exit is declared public in the main module so that it can be accessed from another source module (task).

The main module also contains an external declaration of the symbol print. This declaration defines print to be a near label so that it can be accessed from the module main, even though it is assumed to be located and declared public in another source module.

A jmp instruction later in main has the label print as its destination.

The symbol print is declared public in the task module so that it may be accessed from another module (main).

The symbol exit is defined as a near label so that it can be accessed from this module, even though it is assumed to be located and declared public in the other module.

Before this program can be executed, the two source files (one containing main, the other task) must be assembled individually, then linked together using a linker.

The symbol listing for each source file shows the segment allocations.

MAIN.ASM Symbol TableSymbol Name Type Value??DATE Text "21-05-89"??FILENAME Text "MAIN "??TIME Text "14:20:27"??VERSION Number 0100@CODE Text _TEXT

Page 136: Assembly Language Project

@CODESIZE Text 0@CPU Text 0101H@CURSEG Text _TEXT@DATA Text DGROUP@DATASIZE Text 0@FILENAME Text MAIN@WORDSIZE Text 2EXIT Near _TEXT:0008PRINT Near ----:---- ExternSTART Near _TEXT:0000

Groups & Segments Bit Size Align Combine ClassDGROUP Group STACK 16 0100 Para Stack

STACK _DATA 16 0000 Word Public

DATA_TEXT 16 000D Word Public

CODE

TASK.ASM Symbol TableSymbol Name Type Value??DATE Text "21-05-89"??FILENAME Text "TASK "??TIME Text "14:20:14"??VERSION Number 0100@CODE Text _TEXT@CODESIZE Text 0@CPU Text 0101H@CURSEG Text _TEXT@DATA Text DGROUP@DATASIZE Text 0@FILENAME Text TASK@WORDSIZE Text 2EXIT Near ----:---- ExternPRINT Near _TEXT:0000STRING Byte DGROUP:0000

Groups & Segments Bit Size Align Combine ClassDGROUP Group _DATA 16 0008 Word Public

DATA_TEXT 16 000A Word Public

CODE

Page 137: Assembly Language Project

The map listing form the linker clearly shows how these segments have been combined.

MAIN.MAP (Output from Linker) Start Stop Length Name Class 00000H 00017H 00018H _TEXT CODE 00018H 0001FH 00008H _DATA DATA 00020H 0011FH 00100H STACK STACK

Detailed map of segments0000:0000 000D C=CODE S=_TEXT G=(none) M=MAIN.ASM ACBP=480000:000E 000A C=CODE S=_TEXT G=(none) M=TASK.ASM ACBP=480001:0008 0000 C=DATA S=_DATA G=DGROUP M=MAIN.ASM ACBP=480001:0008 0008 C=DATA S=_DATA G=DGROUP M=TASK.ASM ACBP=480002:0000 0100 C=STACK S=STACK G=DGROUP M=MAIN.ASM ACBP=74

Address Publics by Name 0000:0008 EXIT 0000:000E PRINT

Address Publics by Value 0000:0008 EXIT 0000:000E PRINT

Program entry point at 0000:0000

SEGMENT DIRECTIVESSo far, 8088 programs have been implemented using single segments with the directives

.CODE .STACK .DATA

This simplifies writing programs, but has several drawbacks.

little control over segment placing and combining limited to three segments

The use of the segment directives provide the necessary controls for implementing large multiple segment programs. The programmer can specify which segments should be overlayed, combined, or stand alone.

Page 138: Assembly Language Project

Segment over-ride prefixs may be applied to certain instructions.

mov ax, cs:20h

obtains data from the code segment rather than the data segment.

The format for declaring a segment is,

name SEGMENT align combine_type class name ENDS

Align specifies whether the segment starts at a byte, word or paragraph (10 byte) boundary. The default is paragraph.

Combine_type specifies whether the segment is PUBLIC, COMMON, MEMORY, PRIVATE, PUBLIC or STACK.

PUBLIC The linker concatenates all segments with the same name to form a single contigous segment. The length is the sum of all the segments.

COMMON The linker locates all segments with the same name at the same address (overlayed on top of each other). The length becomes the longest segment.

MEMORY Same as Public

PRIVATE The linker does not combine this segment with any other segment.

STACK The linker concatenates all segments with the same name to form a single contiguous segment. The length is the sum of all the segments. SS is initialised to the beginning of the segment, SP to the length of the segment.

Class controls the ordering of the segments at linking time. Segments with the same class name are loaded together. A segment of class CODE would be loaded before a segment of class STACK. The class name is enclosed using single or double quotes.

Page 139: Assembly Language Project

An example program follows.

TITLE Segdemostck segment para private 'STACK' db 200h dup (?)stck ends

data segment byte public 'DATA'message db 'Hello there','$'

data ends

data2 segment byte public 'DATA2'message2 db 'Segment Data2','$'

data2 ends

code segment para private 'CODE'assume ds:data, ss:stckstart: mov ax, seg data

mov ds, ax mov ah, 9 mov dx, offset message int 21h

assume ds:data2 mov ax, seg data2 mov ds, ax mov ah, 9 mov dx, offset message2 int 21h mov ax, 4c00h int 21h

code endsend start

The map file for segdemo.exe is,

Start Stop Length Name Class 00000H 001FFH 00200H STCK STACK 00200H 0020BH 0000CH DATA DATA 0020CH 00219H 0000EH DATA2 DATA2 00220H 0023CH 0001DH CODE CODE

Detailed map of segments

Page 140: Assembly Language Project

0000:0000 0200 C=STACK S=STCK G=(none) M=SEGDEMO.ASM ACBP=60

0020:0000 000C C=DATA S=DATA G=(none) M=SEGDEMO.ASM ACBP=28

0020:000C 000E C=DATA2 S=DATA2 G=(none) M=SEGDEMO.ASM ACBP=28

0022:0000 001D C=CODE S=CODE G=(none) M=SEGDEMO.ASM ACBP=60

This clearly shows the ordering (class) and concatenation of segments which are the same type.

Assembly Language

Page 141: Assembly Language Project

The following is provided as reference material to the Assembly process, and the LC-

3b AssemblyLanguage. It has been extracted from Intro to Computing Systems: From

bits and gates to C and beyond, 2e, McGraw-Hill, 2004. In my urgency to get this on

theweb site, I may have inadvertentlycreated inconsistencies. If youfind anything here

that is missing an antecedent or otherwise makes no sense, please contact me and/or

one of the TAs. – Yale Patt

7.1 LC-3b Assembly Language

We will begin our study of the LC-3b assembly language by means of an example.

The program in Figure 7.1 multiplies the positive integer initially stored in NUMBER

by six by adding the integer to itself six times. For example, if the integer is 123, the

program computes the product by adding 123

123

123

123

123

123.

The program consists of 21 lines of code. We have added a line number to each line

of the program in order to be able to refer to individual lines easily. This is a common

practice. These line numbers are not part of the program. Ten lines start with a semicolon, designating that they are strictly for the benefit of the human reader. More on

this momentarily. Seven lines (06, 07, 08, 0C, 0D, 0E, and 10) specify actual instructions to be translated into instructions in the ISA of the LC-3b, which will actually be

carried out when the program runs. The remaining four lines (05, 12, 13, and 15) contain pseudo-ops,which are messages from the programmer to the translation program

to help in the translation process. The translation program is called an assembler (in

this case the LC-3b assembler), and the translation process is called assembly.

7.1.1 Instructions

Page 142: Assembly Language Project

Instead of an instruction being 16 0s and 1s, as is the case in the LC-3b ISA, an instruction in assembly language consists of four parts, as shown below:

LABEL OPCODE OPERANDS ; COMMENTS.