the C statement, a = b+c; // produces many statements of machine code
can be expressed in assembler as:
mov ax, b move a copy of the value in b to ax
add ax, c add a copy of the value in c to ax
mov a, ax move the value in ax to a
each of which produce approximately one line of machine code.
C will run on intel, motorola, sun, &etc.
Assembler for intel x86 will not work on motorola 68000 family of
machines or sun.
The intel assembler is one of the most complex in existence today
100's of instructions, complex architecture, &etc.
Why learn assembler?
1. to learn the architecture of the machine.
2. for its utility --
some programs are difficult in high level and easier in assembler
direct communication with the o/s
high-speed graphics
interface with a device (modem, disk drive)
3. bypass or remove restrictions placed by a high level language
4. knowledge of assembler helps you to solve problems
5. changes the way your mind works
"God made 0's and 1's, man made all the rest"
-- Leibnitz
EBCDIC = Extended Binary Coded Decimal Interchange Code
Hexidecimal is used to express
0100 0001 as 41
4 1
In order to do this, it is necessary to memorize the
following table of hexidecimal/binary/decimal
Decimal Binary Hex
0 0000 0000 0
1 0000 0001 1
2 0000 0010 2
3 0000 0011 3
4 0000 0100 4
5 0000 0101 5
6 0000 0110 6
7 0000 0111 7
8 0000 1000 8
9 0000 1001 9
10 0000 1010 A
11 0000 1011 B
12 0000 1100 C
13 0000 1101 D
14 0000 1110 E
15 0000 1111 F
The decimal number 378 means
3 x 100 +
7 x 10 +
8 x 1
The hexidecimal number 3A7 means
3x16^2
10x16^1
7x16^0
The binary number 10 means
1x2^1 +
0x2^0
binary 101
1x2^2 = 4
0x2^1 = 0
1x2^0 = 1
-------
5
1000 = 1x2^3 + = 8
0x2^2 + = 0
0x2^1 + = 0
0x2^0 = 0
--------
8
Hexidecimal 10 means
1x16^1 + = 16
1x16^0 = 0
----------
16
0101 1011 convert to base 10
7654 3210 (place #'s)
1x2^6 = 64
1x2^4 = 16
1x2^3 = 08
1x2^1 = 2
1x2^0 = 1
--
91
in hex,
0101 = 5
1011 = B
it is 5B
to convert 91 to hex, divide by 16
91/16 =
5
-------
16/91
80
--
11
5, with a remainder of 11 (remainder is less than 16)
11 is B in hexidecimal, so, we have 5B
How to convert positive decimal whole numbers to binary
divide by 2, successively until we arrive at a quotient of 0
divide by 2, write down remainder. (either 1 or 0)
divide the quotient (result) by 0
repeat until quotient (result) = 0
starting from the most significant digit, write down the
remainders (the most significant digit is the last one)
convert 53(decimal) to binary
53/2 = 26, remainder 1
26/2 = 13, remainder 0
13/2 = 06, remainder 1
6/2 = 3, remainder 0
3/2 = 1, remainder 1
1/2 = 0, remainder 1 (the most significant digit, because it represents
the greatest number of 2's)
the remainders are the binary value, starting from the bottom:
110101
Fractions:
Suppose the decimal value of 1.6875, what is this in binary?
decimal = binary
1. 1.
since .6 is > 1/2 then,
we could say 1.1
1.6875 -
1.1000 =
------
0.1875
add 1/4, which would be
.001
now we have 1.11, which is 1 + 1/2 + 1/4, which is
2^0 + 2^-1 + 2^-2
This is too hard, so first, convert the part to the left, as shown above.
Then convert the right part, by multiplying, instead of dividing.
How to convert positive decimal fractional numbers to binary
(it is not necsssary to know this for the course)
multiply by 2, successively until we arrive at 0
multiply by 2, write down whole # portion. (either 1 or 0)
remove whole number portion and multiply remaining fraction by 2
repeat until 0
write down the 1's and 0's starting from the most
significant digit (found at the top)
.6875 x 2 = 1.2750 part in front of decimal = 1
.375 x 2 = 0.750 part in front of decimal = 0
.75 x 2 = 1.50 part in front of decimal = 1
.5 x 2 = 1.0 part in front of decimal = 1
write down the 1's and 0's starting from the top
53.6875 (dec) = 110101.1011
.1011 = 1/2 + 1/8 + 1/16 = .5 + .125 + .0625 = .6875
Round-off errors result from the impossibility of converting
to an exact number.
For example, .6 is represented by .1001100110011001...
(ad infinitum)
Eventually, because of the fixed-length arithmetic, the number
is truncated, so that you actually can't get back a .6, you get
a .59999999999, which (hopefully) is rounded off to .6.
How to represent negative decimal numbers in binary
Now it is necessary to understand the architecture of the computer.
A unit of memory, a byte, has an address of where it is located,
represented by 5 hexidecimal digits. (This is simplified.)
The first byte of RAM is is at 00000
next one is at 00001
...
0000F
00010
00011
..
0001F
000
FFFFF = 1,048,575 in decimal
Each byte is made up of 8 bits, each of which always has a 0 or a 1
at all times; there are no blank places.
A word is 2 bytes (16 bits)
A double word is 4 bytes (32 bits)
Negative numbers are represented in 2's complement form.
positive numbers
0000 0000
0000 0001
0000 0010
0000 0011
..up to
0111 1111 (the largest positive # possible in 8 bits, 127)
The first bit is known as the sign bit.
0 represents a positive number.
1 represents a negative number, shown in 2's complement form.
To represent -3, convert to 2's complement form, compute by
flipping all the bits and add 1 to the end.
positive 3 = 0000 0011
flipped bits = 1111 1100
add 1 = 1111 1101
if you add +3 binary + flipped bits 3, you get 0.
0000 0011
1111 1101
---------
1000000000
|
L------------- the extra bit falls off the end, so you end of with a 0.
Imagine the 2's complement # system as a circle. At the top is 0.
(0000 0000) The 1st number to the right would be 0000 0001, on
to the bottom (6 o'clock), where the number is 0111 1111. (127)
Add one to this number, and you get 1000 0000, which is -128.
1000 0000
0111 1111 flip bits
1000 0000 add 1
Keep adding one, until finally, just to the left of 0 at the top is
negative 1, represented by 1111 1111. Proceeding counter-
clockwise, we have negative 2 = 1111 1110, negative 3 is 1111 1101.
Negative 4 is 1111 1100.
4 = 0000 0100
flip = 1111 1011
add 1 = 1
---------
-4 = 1111 1100
flip = 0000 0011
add 1 = 0000 0100
you get 4 again.
Memorize the ASCII tables in HEX
The characters shown in the chart remain the same for both
7-bit and 8-bit ascii.
(this is flipped compared to the book!)
0 1 2 3 4 5 6 7 8 9 A B C D E F
0
1
2 ! " # $ % & ' ( ) * + , - . /
3 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
4 @ A B C D E F G H I J K L M N O
5 P Q R S T U V W X Y Z [ \ ] ^ _
6 ` a b c d e f g h i j k l m n o
7 p q r s t u v w x y z { | } ~
60 IS THE THING UNDER THE TILDE
0 1 2 3 4 5 6 7 8 9 0
0 0 P p
1 ! 1 A Q a q
2 " 2 B R b r
3 3 C S c s
4 4 D T d t
5 5 E U e u
6 6 F
7 7 G
8 8 H
9 9 I
A J
B K
C L
D M
E N
F O
So, the numbers start with 0 at 30.
The caps start at 41 for A (4 is 0100 1 is 0001, so 41 is 0100 0001)
the lower case start at 61 for a
add 20 hex to the A, you get the a
Some beginning assembler
MOV dest, source
^ |
\ ____ /
ADD addend, augend
(The sum ends up in the addend.
MOV AX, 3
ADD AX, 2
now, AX has 5.
3 and 2 are constants, AX is a register.
So the source can be
memory
another register
in the instruction (called an immediate value)
MOV AX, 3 is an immediate value because 3 is part of the instruction
MOV AX, [0120] is a memory reference. Get a copy of the # at location 120
and put it into AX
MOV [0124], AX copies AX into memory location 124 the contents of AX,
obliterating any value already there.
DEBUG is a little Assembler. It will also dis-assemble any code
written in assembler.
- is the prompt of DEBUG.
he typed in a 100
this means assemble starting at location 100
debug responded with
1BE3:0100 this is a real address in the system,
1BE3 is the segment address, 0100 is the offset
to find out where 1Be3 is, add a 4-bit 0 the end of the segment and
tack the offset onto the end, so this address is actually
1BE300100 (It is not necessary to know this)
he typed in MOV AX,5
it puts 0000 0000 0000 0101 into AX
The numbers in debug are in HEX!
it responded 1BE3:0103
he typed add ax, 10
it adds a hex 10, (dec. 16) into AX
it responded 1BE3:0106
he typed add ax, 20
it says 1BE3:0109
he says mov [120], ax
it said 1BE3:010C
he said int 21
but realized this was a mistake, so he hit enter twice to
get back the - prompt.
So he typed in a 10c
to redo the line he typed at 1BE3:010C, so it
prompted him with 1BE3:010C
and he typed int 20
and hit enter twice to get back the - prompt, where
he typed in u 100 10e
which means disassemble starting from 100 to 10e (disassemble
from the start to the end of the program.
int 21 destroys memory (you might have to reboot after this)
int 20 returns control to dos.
page lists all the interrupts
anyway, as a result of u 100 10e it showed:
1BE3:0100 B80500 MOV AX,0005
(so B8 is an operation code, which means MOV into register AX)
(notice it puts the two bytes, 00 and 05 in reverse order,
so 00 05 becomes 05 00.)
(AX now contains 00 05)
1BE3:0103 051000 ADD AX,0010
Debug instructions
? List of commands
a Assemble [address] you can type in code this way
c compare range addr
d Dump [range]
e Enter address [list]
f Fill range list
g Go [=address] addresses runs the whole shebang?
h Hex Value1 Value2
i Inupt port
r Show registers Appears to show the same thing
as t, but doesn't cause any code
to be executed.
t Trace
u UnAssemble
Operands you can use in assembler instructions
operand example expl.
register add bx, ax ax is a register
constant add ax, 10 10 is a constant
variable add ax, loc1 loc1 is a memory location named
by a symbol, which contains some number
indicating a memory address (loc1 is a
pointer?)
memory location
add ax, [0120]
How to you declare variables in assembler? What are the variable naming
rules and conventions?
There is info on debug in an appendix of the textbook.
Also the DOS manual lists these commands.
Also in the tutorial he gave us on the diskette.
All of the following are 16-bit registers.
AX, BX, CX, DX
Each of the 16-bit registers is made up of 2 parts, for example AX
is made up of AH and AL, BX is made up of BH and BL, and so on.
The segment registers are:
SS Stack Segment
DS Data Segment
BS Base segment
ES Extra segment
IP Instruction pointer
In debug, r gives you:
These are registers: AX BX CX DX SP BP SI DI DS ES SS CS IP
These are flags: NV UP EI NZ NA PO NC
NC is the carry flag.
AX, BX, CX and DX can be used for arithmetic.
DX will hold part of the result for multiply and divide.
CX may be decremented as the result of certain loop instructions,
and can be used as a counter in looping instructions, such as
LOOP, in which case it will continue until CX is 0.
(This appears to be like a repeat..until)
AX is used for accumulating sums.
BX appears to be for miscellaneous use.
DS is used for pointing to your program's data segment.
CS holds segment address of your code.
IP is the instruction pointer. It holds the address of the next
instruction that will be executed.
When you execute an add, some of the flags, such as
NZ, NA and NC are set.
Recommended books for additional study:
Assembler Language, Jeff Duntemann
Turbo Assembler, Tom Swan
Lab exercises to do today.
1. Assemble a program which muves immediate values to each of the
registers. Find out which registers cannot be modified and
suggest why not.
2. Using only add and sub instructions assemble a short program that
sets the carry flag using both unsigned addition and unsigned
subtraction.
3. DOS keeps most of its variables at segment 0040, in low memory.
Snoop around using debug. Use r to set ds register to 0040 and then
d to examine memory.
Print out the results to hand in.
Text: Assembly Language for the IBM-PC, Kip R. Irvine.
First week's reading assignment: Read all of chapter 1 (p. 1-20),
and appendix A, pages 519-top of page 525.
Review questions to do at end of Chapter 1: 1-12, 14.
Refer to ASCII table inside back cover for question 9.
We will be quizzed on these questions in class.
[back to the main csc220 page] [To the downloadable files] [To Maggie's homepage]