Assembly Language Programming
Inside the Central Processing Unit (CPU) all information are presented in binary form. In order to utilize the computer we need to communicate with the CPU, however, binary format is not convenient for human user. Therefore, computer engineers developed different kinds of programming languages so that users can easily communicate with the CPU by writing programs.
There are high level programming languages such as C, C++, Java, C#, Pascal
Assembly language is regarded as a low-level programming language because the syntax used in assembly language is very close to the hardware itself. For example, if you want to do a move/copy/assign operation, then you use an instruction called MOV that comes from the operation move.
Advantages of using assembly programming language
-
The program can run faster because the program can fully utilize the CPU
-
The syntax is similar for different kinds of microprocessor so after learning the assembly language for one processor you can adapt to other processors very easily
-
Help users to understand the architecture of the microprocessor as well as how a CPU performs its functions
Before you can write your program, you must know
-
the operations or instructions that are supported by the microprocessor (the instruction set!). For example if there is no multiply operation in the instruction then you can only use addition to carry out a multiply.
-
the functions of different registers, you need to utilize the registers during programming
-
how external memory is organized and how it is addressed to obtain instructions and data
If the above are available then you can program your microprocessor at once.
How to learn programming – the CLP model
-
C –Concept
-
L – Logic thinking
-
P – Practice
-
Concept – we must learn the basic syntax, such as how a program statement is written
-
Logic thinking – programming is a problem solving process so we must think logically in order to derive a solution
-
Practice – write more programs
Assembly language programming
The native language is machine language using 0,1 (binary) to represent an operation or data. A single machine instruction can take up one or more bytes of code. Assembly language is used to write the program using alphanumeric symbols (or mnemonic), eg ADD, MOV, PUSH etc.
After you have written your program, the program will then be assembled (similar to compiled) and linked into an executable program.
The executable program could be .com, .exe, .bin, .hex files
Assembly program
xxx.asm
Example of a very simple instruction
Consider a very simple instruction mov AL, 00H, it is to move a value 00 (HEX) to the AL register of 8086.
Machine code for mov AL, 00H is B4 00 (2 bytes)
After assemble, the value B400 will be stored in the memory
When the program is being executed, then the value B400 is read from memory, decoded and carried out the task.
When you write assembly language program, only put one instruction in each statement. You cannot do things like:
A=(B+C)*100
To achieve the above, you may need to do a sequence of operations:
Move B to A (A=B)
Add C to A (A=A+C)
Multiply A with 100 (A=A*100)
Usually, the term statement is used to describe a line in an assembly language program.
A statement must specify which operation (opcode) to be performed as well as the operands
Eg ADD AX, BX
ADD is the operation
AX is called the destination operand
BX is called the source operand
The result is AX = AX + BX
General format for an assembly language statement
Label Instruction Comment
Start: Mov AX, BX ; copy BX into AX
The label (Start:) is only used to identify a location within your program. You do not need to include a label in every statement!!!!!!
The word Start is the name of a label. A label’s name is defined by a user provided that it is not a reserved word and do not put space between the name. After the name, you must include the : to indicate that it is a label.
Comment is used to document the program so that user can understand the logic of the program. Comment is identified by the ; put in front of it
Memory structure
The memory of a computer is organized in bytes. Each byte occupy one address.
So Even, or odd-addressed bytes of data can be independently accessed.
In a program, if you want to use an 8-bit data, it is represented by directive db (b-byte) and 16-bit by dw (w-word).
To store a 16-bit data, the MSB (Most Significant Byte) is stored at the higher byte address and the LSB at the lower byte address.
For example a 16 bit value ABCD (Hex) will occupy two address locations, for example 12344H and 12345H, then the low byte CD will be stored in 12344H and the high byte AB will be stored in 12345H.
Only 4 64K-byte segments are active at the same time and these are: code, stack, data, and extra
To access the active segments, it is via the segment register: CS (code), SS (stack), DS (data), ES (extra). When you write your program, you sometimes need to properly define the different segments.
To get an instruction: we need to generate an address for the instruction (code).
The address for an instruction is the sum of CS and IP.
The segment register points to the lowest addressed location in the current code segment
CS + IP will give a 20-bit address
IP will be incremented so it points to the next instruction (sometimes we use term Program Counter (PC) instead of IP )
This is the concept of offset and base, do you still remember which is the offset and which is the base?
Registers
In assembly language programming, you cannot operate on two memory locations in the same instruction. So you usually need to store (move) value of one location into a register and then perform your operation. After the operation, you then put the result back to the memory location. Therefore, one form of operation that you will use very frequently is the store (move) operation!!!
There are different categories of registers in a microprocessor. For 8086, the data registers are most frequently used in programming.
Data Registers in 8086
There are four data registers: AX, BX, CX,and DX. All four registers are 16-bit but they can be used to store 2 8-bit data. Then the name AH, AL, BH, BL, CH, CL, DH, DL are used. H- High, L – Low. Meaning that the 16-bit register eg AX is divided into two 8-bit registers AH and AL.
The AX register is called the accumulator, usually used for storing result after an operation.
Each of the 4 data registers can be used as the source or destination of an operation during an arithmetic, logic, shift, or rotate operation. In some operations, the use of the accumulator (AX) is assumed, eg in multiplication operation; details will be given in the following.
Special use of the data registers
In based addressing mode, base register BX is used as a pointer to an operand in the current data segment. Details given in the section on addressing modes.
The CX register is used as a counter in some instructions, eg. CL contains the count of the number of bits by which the contents of the operand must be rotated or shifted by multiple-bit rotate. In a looping operation, content of CL represents the number of iterations to be executed.
DX, data register, is used in all multiplication and division operations, it also contains an input/output port address for some types of input/output operations.
Pointer and index registers
In addition to the data registers, there are the pointer and index registers, all 16-bit. Some pointer and index registers can be used as a general purpose register, ie can be used as an operand in arithmetic or logic operations. However, most pointer and index registers have special purposes.
The Stack (or the Stack segment) – is used as a temporary storage.
Data can be stored by the PUSH instruction and extracted by the POP instruction
To access the Stack, you must use the SP (Stack Pointer) and BP (Base Pointer), details will be given in the section on stack.
The BP contains an offset address in the current stack segment. This offset address is employed when using the based addressing mode and is commonly used by instructions in a subroutine that reference parameters that were passed by using the stack
The Source index register (SI) and Destination index register (DI) are used to hold offset addresses for use in indexed addressing (similar to a pointer in C++ programming) of operands in memory. When indexed type of addressing is used, then SI refers to the current data segment and DI refers to the current extra segment. Details can be found in the section on addressing mode.
The index registers can also be used as source or destination registers in arithmetic and logical operations. But must be used in 16-bit mode.
Data types
In 8086 assembly language, the data types are simple, only 8-bit, 16-bit, and 32-bit (this is called a double word). You cannot define data as integer, float or char, as in C++.
Integer could be signed or unsigned and in byte-wide or word-wide format.
For a signed integer, the MSB can be used to determine the sign (0 for positive, 1 for negative).
For example the value 1001 0100 is negative if it is a signed value
The range of Signed integer (8-bit) is from 127 to –128,
For signed word (16-bit) it is from 32767 to –32768
Latest microprocessors can also support 64-bit or even 128-bit data
Example of a simple Assembly Program
The above shows a very simple 8086 assembly program. You can see the basic syntax used in the program and how the code segment is defined using the .code keyword.
The flow of the program is top-down, ie from start to end and only one statement is executed at each time.
In general, an assembly program must include the code segment!!
Code segment stores the program codes.
Other segments, such as stack segment, data segment, are not compulsory.
There are key words used to indicate the beginning of a segment as
well as the end of a segment.
Example
DSEG segment ‘data’ ; define the start of a data segment
DSEG ENDS ; defines the end of a data segment
Segment is the keyword
DSEG is the name of the segment
Similarly key words are used to define the beginning of a program, as well as the end.
Start Proc Far and RET are used to define the start and end of the main program.
Another example
Syntax for defining different components in a program:
FAR – is related to program execution. When you request execution of a program, the program loader uses this procedure as the entry Point for the first instruction to execute.
Assume – to associate the name of a segment with a segment register
assume ss:stacksg, ds: datasg, cs:codesg
In the above, the SS register is associated with the stacksg segment (which is the stack).
In some assembler, you need to move the base address of a segment directly into the segment register!!! Examples will be available in the following.
END – ends the entire program and appears as the last statement. Usually the name of the first or only PROC designated as FAR is put after END
Fortunately, if you are doing something simple you do not need to include all the segment declarations in the program. For example:
start:
mov DL, 0H ; move 0H to DL
mov CL, op1 ; move op1 to CL
mov AL, data ; move data to AL
step:
cmp AL, op1 ; compare AL and op1
jc label1 ; if carry =1 jump to label1
sub AL, op1 ; AL = AL –op1
inc DL ; DL = DL+1
jmp step ; jump to step
label1:
mov AH, DL ; move DL to AH
HLT ; Halt end of program
data db 45 ; just like a string
op1 db 6
Assembler for 8086 – to assmble your programs
WASM – a freeware can be download from internet
(http://user.mc.net/~warp/software_wasm.html)
Emu8086 (http:// www.emu8086.com)
The emu8086 consists of a tutorial and the reference for a complete instruction set.
During the lectures, this software is being used to demonstrate the program examples.
Keil - www.keil.com
Assembly language Program
Assembly language program should be more effective and it will take up less memory space and run faster. In real-time application, the use of assembly program is required because program that is written in a high-level language probably could not respond quickly enough. The syntax for different microprocessor may be different but the concept is the same so once you learn the assembly programming for one microprocessor, you can easily program other kinds of system. For example, programming the 8051 series is very similar to the 8086.
Defining data in a program
Data is stored in the data segment.
You can define constants, work areas (a chunk of memory ) in your program.
Data can be defined in different length (8-bit, 16-bit)
8-bit then use DB 16-bit then use DW
The definition for data:
[name] Dn expression
Name – a program that references a data item by means of a name.
The name of an item is otherwise optional
Dn – this is called the directives. It defines length of the data
Expression – define the values (content) for the data
Examples for data
FLDA DB ? ; define an uninitialized item called FLDA 8-bit
FLDB DB 25 ; initialize a data to 25
Define multiple data under the same name (like an array)
FLDC DB 21, 22, 23, 34 ; the data are stored in adjacent bytes
FLDC stores the first value
FLDC + 1 stores the second value
You can do mov AL, FLDC+3
DUP – duplicate
DUP can be used to define multiple storages
DB 10 DUP (?) ; defines 10 bytes not initialize
DB 5 DUP (12) ; 5 data all initialized to 12
What about DB 3 DUP( 5 DUP (4))
String :
DB ‘this is a test’
EQU – this directive does not define a data item; instead, it defines
a value that the assembler can use to substitute in other instructions
(similar to defining a constant in C programming or using the #define )
factor EQU 12
mov CX, factor
Addressing modes
Function of the addressing modes defines how to access operands of an instruction.
There are 9 modes: register addressing, immediate addressing, direct addressing, register indirect addressing, based addressing, indexed addressing, based indexed addressing, string addressing, and port addressing
To fetch the operand, require the BIU to do the read/write bus cycle to the memory subsystem if necessary, different addressing modes provide different ways of computing the address of an operand.
Example in C++ programming, you can do:
Int *x, y;
X = &y ; this is indirect addressing
OR
Int x[10], y;
*(X+1) = y ;
The above examples in C++ illustrate different syntax to obtain the data by different addressing modes.
When using different addressing modes, you must clearly know how the offset address is being calculated. With different kinds of addressing mode, the offset address may be evaluated with different components, while the base address could come from either the data segment or the extra segment.
Register addressing mode
The operand to be accessed is specified as residing in an internal register of the 8086
Eg MOV AX, BX
Move (MOV) contents of BX (the source operand), to AX (the destination operand)
In the above operation, both operands are in the internal registers and this is called register addressing mode.
Immediate addressing mode
This involves the use of an immediate value.
Source operand (or the immediate value) is part of the instruction
Usually immediate operands represent constant data, the operands can be either a byte or word
e.g MOV AL, 15
15 is a byte wide immediate source operand
Or it could be MOV AL, #15
The immediate operand is stored in program storage memory (i.e the code segment)
This value is also fetched into the instruction queue in the BIU and no external memory bus cycle is initiated!
Direct addressing mode
This is also a simple addressing mode and it is for moving a byte or word between a memory location and a register. The memory location most likely represents a variable.
The locations following the instruction opcode hold an Effective memory Address (EA) instead of the data.
The EA is an offset address representing the storage location of the operand from the current value in the data segment register
Physcial address = DS + offset
The instruction set does not support a memory-to-memory transfer!
Example:
Mov AL, var1 ; move the content of var1 to AL register
Var1 db 12 ; define a memory location var1 to store the value 12
Then after the move AL = 12
In the above, the var1 can be regarded as a variable. In order to get the data represented by var1, a memory read cycle is needed. Data is assumed to be stored in the data segment (DS) and content of DS should be used as the segment address.
Register indirect addressing mode
This addressing mode is for transferring a byte or a word between a register and a memory location addressed by an index or pointer register.
The effective address (EA) is stored either in a pointer register or an index register
The pointer register can be either the base register BX or base pointer register BP.
The index register can be the source index register SI, or the destination index register DI
The default segment is either DS or ES.
Refer to the following memory table
Eg MOV AL, [SI]
If SI = 01235H then after the move then AL = 18 according to the following memory table.
Value stored in the SI register is used as the offset address. Using the offset address, you can then obtain the Physical address of the data.
The segment register is DS in this example
In register indirect addressing mode, the EA (effective address) is a variable and depends on the index, or base register value
Eg mov [BX], CL
If CL = 88 and BX = 01233 then after the move content of address 01233H becomes 88
Which segment register will be used for the above operation?
Table 1 Memory map
Address (in HEX)
|
Content
|
|
|
|
|
01236
|
19
|
01235
|
18
|
01234
|
20
|
01233
|
|
|
|
|
|
|
|
Base-plus-index addressing mode
This moves a byte or a word between a register and the memory location addressed by a base register (BP or BX) plus an index register (DI or SI). You need a base value and an index in order to extract the proper data.
Physical address of the operand is obtained by adding a direct or indirect displacement to the contents of either base register BX or base pointer register BP and the current value in DS and SS, respectively.
Eg MOV [BX+SI], AL
Move value in AL to a location (DS+BX+SI)
If BP is used then use SS register instead of DS
The base register (BX) often holds the beginning location of a memory array, while the index register (SI) holds the relative position of an element in the array
Register relative addressing mode
For moving a byte or a word between a register and a memory location addressed by an index or base register plus a displacement
Eg MOV AL, ARRAY[SI]
EA = value of SI + address of ARRAY
Physical address = EA + DS
Eg mov AX, [BX+4]
Eg mov AX, array[DI+3]
This is similar to the base-plus-index
Base relative plus index addressing mode
For the transfer of a byte or a word between a register and the memory location addressed by a base and an index register plus a displacement, there are 3 components.
This addressing mode is a combination of the based addressing mode and the indexed addressing mode together
Eg MOV AH, [BX+DI+4]
EA = value of BX + 4 + value of DI
Physical address = DS + EA
This can be used to access data stored as a 2-D matrix
Eg mov AX, array[BX+DI]
Summary of different addressing modes
MOV AL, BL
|
Register addressing mode
|
MOV AL, 15H
|
immediate
|
MOV AL, abc
MOV AL, [1234H]
|
direct
|
MOV AL, [SI]
|
Register indirect
|
MOV AL, [BX+SI]
|
Base plus index
|
MOV AL, [BX+4]
MOV AL, ARRAY[3]
|
Register relative
|
MOV AL, [BX+DI+4]
MOV AL, ARRAY[BX+DI]
|
Base relative plus index
|
In register indirect addressing mode such as MOV AL, [SI] the value of SI represents an address. How to move an address of a variable to a register?
This is achieved by the instruction LEA (load effective address).
LEA is similar to the following C++ syntax
int* x ;
x = &y ; // assign the address of y to point x
Syntax of LEA
LEA SI, ARRAY ; move the address of variable ARRAY to the SI register
MOV AL, [SI] ; value of 12 is moved to AL
ARRAY db 12 ; define a memory location ARRAY and 12 is the stored in it
Example
1. Select an instruction for each of the following tasks:
-
Copy content of BL to CL
-
Copy content of DS to AX
2. Suppose that DS=1100H, BX=0200H, LIST=0250H, and SI=0500H, determine the physical address being accessed by each of the following instructions:
mov LIST[SI], DX
mov CL, LIST[BX+SI]
mov CH, [BX+SI]
String addressing mode
The string instructions of the 8086 instruction set automatically use the source (SI) and destination index registers (DI) to specify the effective addresses of the source and destination operands, respectively.
The instruction is MOVS
There is no operand after movs
Don’t need to specify the register but SI and DI are being used during the program execution so you must set the value of SI and DI before you use MOVS.
Port addressing mode
Port addressing is used in conjunction with IN and OUT instructions to access input and output ports. Any of the memory addressing modes can be used for the port address for memory-mapped ports, details in the I/O section.
For ports in the I/O address space, only the direct addressing mode and an indirect addressing mode using DX are available
Eg IN AL, 15H ; second operand is the port number
Input data from the input port at address 1516 of the I/O address space to register AL
Eg IN AL, DX
Load AL with data coming from a port, which number is stored in DX
Exercises
1. Compute the physical address for the specified operand in each of the following instructions:
MOV [DI], AX (destination operand)
MOV DI, [SI] (source operand)
MOV XYZ[DI], AH (destination operand)
Given CS=0A00, DS=0B00, SI=0100, DI=0200,
BX=0300, XYZ=0400
2. Express the decimal numbers that follows as unpacked and packed BCD bytes (BCD – binary coded decimal)
-
29 b. 88
3. How would the BCD numbers be stored in memory starting at address 0B000
Example
Determine which is being moved in each “MOV” statement for the following assembly program.
; first define a data segment
dat segment para 'data'
ival db 10H
array db 8, 2, 3, 4
dat ends
; COM file is loaded at CS:0100h
; define the code segment - instructions
CSEG segment 'code'
beng proc FAR
mov AX, dat ; assign data segment address to AX
mov DS, AX ; now DS is pointing to the data segment or DS stores the base ; address of the data segment
mov AX, BX ; register addressing mode
mov BL, ival ; direct addressing
mov AL, 7fH ; immediate addressing mode
mov BL, 04fH
add AL, BL ; AL = AL+BL
mov [10], AL ; direct addressing mode
mov CL, [11]
mov cl, array+2
LEA BX, array ; load effective address of array to BX
mov al, 2
mov dl, [bx] ; register indirect addressing
mov SI, 2
mov dh, [bx+SI] ; base+index addressing
mov ah, array[3] ; base relative addressing
mov al, [bx+si+1] ; base relative + index
mov cl, array+2
beng endp
CSEG ends
end beng
Determine values being moved in each operation.
Share with your friends: |