
           NUMBER SYSTEMS
  Most humans use the decimal system, which consists of ten 
digits (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), because humans have ten 
fingers. The computer does not have fingers, so it prefers other 
number systems instead. Here they are. . . . 

               Binary
  Look at these powers of 2:
20 =  1

21 =  2

22 =  4

23 =  8

24 = 16

25 = 32

26 = 64
  Now try an experiment. Pick your favorite positive integer, and 
try to write it as a sum of powers of 2.
  For example, suppose you pick 45; you can write it as 32+8+4+1. 
Suppose you pick 74; you can write it as 64+8+2. Suppose you pick 
77. You can write it as 64+8+4+1. Every positive integer can be 
written as a sum of powers of 2.
  Let's put those examples in a table:
Original  Written as sum   Does the sum contain . . . 
number    of powers of 2   64?  32?  16?  8?   4?   2?   1?
45        32+8+4+1         no   yes  no   yes  yes  no   yes
74        64+8+2           yes  no   no   yes  no   yes  no
77        64+8+4+1         yes  no   no   yes  yes  no   yes
  To write those numbers in the binary system, replace ``no'' by 
0 and ``yes'' by 1:
Decimal systemBinary system
45          0101101 (or simply 101101)
74          1001010
77          1001101
  The decimal system uses the digits 0, 1, 2, 3, 4, 5, 6, 7, 8, 
and 9 and uses these columns:
thousands      hundreds      tens      units
For example, the decimal number 7105 means ``7 thousands + 1 
hundred + 0 tens + 5 units''.
  The binary system uses only the digits 0 and 1, and uses these 
columns:
sixty-fours      thirty-twos      sixteens      eights      fours      
twos      units
  For example, the binary number 1001101 means ``1 sixty-four + 0 
thirty-twos + 0 sixteens + 1 eight + 1 four + 0 twos + 1 unit''. 
In other words, it means seventy-seven.
                                         In elementary school, 
you were taught how to do arithmetic in the decimal system. You 
had to memorize the addition and multiplication tables:
         DECIMAL ADDITION

   0  1  2  3  4  5  6  7  8  9
 Ŀ
0 0  1  2  3  4  5  6  7  8  9
1 1  2  3  4  5  6  7  8  9 10
2 2  3  4  5  6  7  8  9 10 11
3 3  4  5  6  7  8  9 10 11 12
4 4  5  6  7  8  9 10 11 12 13
5 5  6  7  8  9 10 11 12 13 14
6 6  7  8  9 10 11 12 13 14 15
7 7  8  9 10 11 12 13 14 15 16
8 8  9 10 11 12 13 14 15 16 17
9 9 10 11 12 13 14 15 16 17 18
 
    
      DECIMAL MULTIPLICATION
    
   0  1  2  3  4  5  6  7  8  9
 Ŀ
0 0  0  0  0  0  0  0  0  0  0
1 0  1  2  3  4  5  6  7  8  9
2 0  2  4  6  8 10 12 14 16 18
3 0  3  6  9 12 15 18 21 24 27
4 0  4  8 12 16 20 24 28 32 36
5 0  5 10 15 20 25 30 35 40 45
6 0  6 12 18 24 30 36 42 48 54
7 0  7 14 21 28 35 42 49 56 63
8 0  8 16 24 32 40 48 56 64 72
9 0  9 18 27 36 45 54 63 72 81
 
                                         In the binary system, 
the only digits are 0 and 1, so the tables are briefer:
BINARY ADDITION

   0  1
 Ŀ
0 0  1
1 1 10because two is written "10" in binary
 
 
BINARY MULTIPLICATION
 
   0  1
 Ŀ
0 0  0
1 0  1
 
                                         If society had adopted 
the binary system instead of the decimal system, you'd have been 
spared many hours of memorizing!
                                         Usually, when you ask 
the computer to perform a computation, it converts your numbers 
from the decimal system to the binary system, performs the 
computation by using the binary addition and multiplication 
tables, and then converts the answer from the binary system to 
the decimal system, so you can read it. For example, if you ask 
the computer to print 45+74, it will do this:
 45 converted to binary is   101101
+74 converted to binary is +1001010
                            1110111 converted to decimal is 119
                               
                               because 1+1=10

  The conversion from decimal to binary and then back to decimal 
is slow. But the computation itself (in this case, addition) is 
quick, since the binary addition table is so simple. The only 
times the computer must convert is during input (decimal to 
binary) and output (binary to decimal). The rest of the execution 
is performed quickly, entirely in binary.
  You know fractions can be written in the decimal system, by 
using these columns:
units      point      tenths      hundredths      thousandths
For example, 1 5/8 can be written as 1.625, which means ``1 unit 
+ 6 tenths + 2 hundredths + 5 thousandths''.
  To write fractions in the binary system, use these columns 
instead:
units      point      halves      fourths      eighths
For example, 1 5/8 is written in binary as 1.101, which means ``1 
unit + 1 half + 0 fourths + 1 eighth''.
  You know 1/3 is written in the decimal system as 0.3333333 . . 
. , which unfortunately never terminates. In the binary system, 
the situation is no better: 1/3 is written as 0.010101. . . .  
Since the computer stores only a finite number of digits, it 
cannot store 1/3 accurately ___ it stores only an approximation.
  A more distressing example is 1/5. In the decimal system, it's 
.2, but in the binary system it's .0011001100110011. . . .  So 
the computer can't handle 1/5 accurately, even though a human 
can.
  Most of today's microcomputers and minicomputers are inspired 
by a famous maxicomputer built by DEC and called the DECsystem-10 
(or PDP-10). Though DEC doesn't sell the DECsystem-10 anymore, 
its influence lives on!
  Suppose you run this BASIC program on a DECsystem-10 computer:
10 PRINT "MY FAVORITE NUMBER IS";4.001-4
20 END
The computer will try to convert 4.001 to binary. Unfortunately, 
it can't be converted exactly; the computer's binary 
approximation of it is slightly too small. The computer's final 
answer to 4.001-4 is therefore slightly less than the correct 
answer. Instead of printing MY FAVORITE NUMBER IS .001, the 
computer will print MY FAVORITE NUMBER IS .000999987.
  If your computer isn't a DECsystem-10, its approximation will 
be slightly different. To test your computer's accuracy, try 
4.0001-4, and 4.00001-4, and 4.000001-4, etc. You might be 
surprised at its answers.
  Let's see how the DECsystem-10 handles this:
10 FOR X = 7 TO 193 STEP .1
20     PRINT X
30 NEXT X
40 END
The computer will convert 7 and 193 to binary accurately, but 
will convert .1 to binary only approximately; the approximation 
is slightly too large. The last few numbers it should print are 
192.8, 192.9, and 193, but because of the approximation it will 
print slightly more than 192.8, then slightly more than 192.9, 
and then stop (since it is not allowed to print anything over 
193).
  There are only two binary digits: 0 and 1. A binary digit is 
called a bit. For example, .001100110011 is a binary 
approximation of 1/5 that consists of twelve bits. A sixteen-bit 
approximation of 1/5 would be .0011001100110011. A bit that is 1 
is called turned on; a bit that is 0 is turned off. For example, 
in the expression 11001, three bits are turned on and two are 
off. We also say that three of the bits are set and two are 
cleared.
  All information inside the computer is coded, in the form of 
bits:
Part of the computerWhat a 1 bit isWhat a 0 bit is
electric wire high voltage  low voltage
punched paper tapea hole in the tapeno hole in the tape
punched IBM carda hole in the cardno hole in the card
magnetic drum a magnetized areaa non-magnetized area
core memory   core magnetized clockwisecore magnetized 
counterclockwise
flashing lightthe light is onthe light is off
  For example, to represent 11 on part of a punched paper tape, 
the computer punches two holes close together. To represent 1101, 
the computer punches two holes close together, and then another 
hole farther away.
                                                             Octal
                                                     Octal is a 
shorthand notation for binary:
Octal                                                  Meaning
0                                                      000
1                                                      001
2                                                      010
3                                                      011
4                                                      100
5                                                      101
6                                                      110
7                                                      111
Each octal digit stands for three bits. For example, the octal 
number 72 is short for this:
111010

 7  2
                                                     To convert a 
binary integer to octal, divide the number into chunks of three 
bits, starting at the right. For example, here's how to convert 
11110101 to octal:
 11110101

 3  6  5
                                                     To convert a 
binary real number to octal, divide the number into chunks of 
three bits, starting at the decimal point and working in both 
directions:
 10100001.10011

 2  4  1 . 4  6

                                                          Hexadecimal
                                                     Hexadecimal 
is another short-hand notation for binary:
Hexadecimal                                                  
Meaning
0                                                            0000
1                                                            0001
2                                                            0010
3                                                            0011
4                                                            0100
5                                                            0101
6                                                            0110
7                                                            0111
8                                                            1000
9                                                            1001
A                                                            1010
B                                                            1011
C                                                            1100
D                                                            1101
E                                                            1110
F                                                            1111
For example, the hexadecimal number 4F is short for this:
01001111

  4   F
To convert a binary number to hexadecimal, divide the number into 
chunks of 4 bits, starting at the decimal point and working in 
both directions:
 11010110100.1111111

  6   B   4   .  F   E


     CHARACTER CODES
  To store a character in a string, the computer uses a code.

          ASCII
  The most famous code is the American Standard Code for 
Information Interchange (ASCII), which has 7 bits for each 
character. Here are examples:
                ASCII code
CharacterASCII codein hexadec'l
space   0100000 20
!       0100001 21
"       0100010 22
#       0100011 23
$       0100100 24
%       0100101 25
&       0100110 26
'       0100111 27
(       0101000 28
)       0101001 29
*       0101010 2A
+       0101011 2B
,       0101100 2C
-       0101101 2D
.       0101110 2E
/       0101111 2F
0       0110000 30
1       0110001 31
2       0110010 32
etc.
9       0111001 39
:       0111010 3A
;       0111011 3B
<       0111100 3C
=       0111101 3D
>       0111110 3E
?       0111111 3F
@       1000000 40
A       1000001 41
B       1000010 42
C       1000011 43
etc.
Z       1011010 5A
[       1011011 5B
\       1011100 5C
]       1011101 5D
^       1011110 5E
_       1011111 5F
  ``ASCII'' is pronounced ``ass key''.
  Most terminals use 7-bit ASCII. Most microcomputers and the 
PDP-11 use an ``8-bit ASCII'' formed by putting a 0 before 7-bit 
ASCII.      
  PDP-8 computers use mainly a ``6-bit ASCII'' formed by 
eliminating 7-bit ASCII's leftmost bit, but they can also handle 
an ``8-bit ASCII'' formed by putting a 1 before 7-bit ASCII.
  PDP-10 computers use mainly 7-bit ASCII but can also handle a 
``6-bit ASCII'' formed by eliminating ASCII's second bit. For 
example, the 6-bit ASCII code for the symbol $ is 0 00100.
  CDC computers use a special CDC 6-bit code.
                                                EBCDIC
                             Instead of using ASCII, IBM 
mainframes use the Extended Binary-Coded-Decimal Interchange Code 
(EBCDIC), which has 8 bits for each character. Here are examples:
                                   EBCDIC code                   
EBCDIC code
Character                          in hexadecimal        
Character                                                        
in hexadecimal
space                              40                    A       
C1
                                  4A                    B       
C2
<                                  4C                    etc.
(                                  4D                    I       
C9
+                                  4E                    J       
D1
                                  4F                    K       
D2
&                                  50                    etc.
!                                  5A                    R       
D9
$                                  5B                    S       
E2
*                                  5C                    T       
E3
)                                  5D                    etc.
;                                  5E                    Z       
E9
                                  5F                    0       
F0
-                                  60                    1       
F1
/                                  61                    etc.
,                                  6B                    9       
F9
%                                  6C
_                                  6D
>                                  6E
?                                  6F
:                                  7A
#                                  7B
@                                  7C
'                                  7D
=                                  7E
"                                  7F
``EBCDIC'' is pronounced ``ebb sih Dick''.
                             IBM 360 computers can also handle an 
``8-bit ASCII'', formed by copying ASCII's first bit after the 
second bit. For example, the 8-bit ASCII code for the symbol $ is 
01000100. But IBM 370 computers (which are newer than IBM 360 
computers) don't bother with ASCII: they stick strictly with 
EBCDIC.
                             80-column IBM cards use Hollerith 
code, which resembles EBCDIC but has 12 bits instead of 8. 
96-column IBM cards use a 6-bit code that's an abridgement of the 
Hollerith code.
                             Here's a program in BASIC:
10 IF "9"<"A" THEN 100
20 PRINT "CAT"
30 STOP
100 PRINT "DOG"
110 END
Which will the computer print: CAT or DOG? The answer depends on 
whether the computer uses ASCII or EBCDIC.
                             Suppose the computer uses 7-bit 
ASCII. Then the code for ``9'' is hexadecimal 39, and the code 
for ``A'' is hexadecimal 41. Since 39 is less than 41, the 
computer considers ``9'' to be less than ``A'', so the computer 
prints DOG.
                             But if the computer uses EBCDIC 
instead of ASCII, the code for ``9'' is hexadecimal F9, and the 
code for ``A'' is hexadecimal C1; since F9 is greater than C1, 
the computer considers ``9'' to be greater than ``A'', so the 
computer prints CAT.

                                                 Bytes
                             A byte usually means: eight bits. 
For example, here's a byte: 10001011.
                             For computers that use 7-bit ASCII, 
programmers sometimes define a byte to be 7 bits instead of 8. 
For computers that use 6-bit ASCII, programmers sometimes define 
a byte to be 6 bits. So if someone tries to sell you a computer 
whose memory can hold ``16,000 bytes'', he probably means 16,000 
8-bit bytes, but might mean 7-bit bytes or 6-bit bytes.

                                                Nibbles
                             A nibble is 4 bits. It's half of an 
8-bit byte. Since a hexadecimal digit stands for 4 bits, a 
hexadecimal digit stands for a nibble.

           SEXY ASSEMBLER
  In this chapter, you'll learn the fundamental concepts of 
assembly language, quickly and easily.
  Unfortunately, different CPU's have different assembly 
languages.
  I've invented an assembly language that combines the best 
features of all the other assembly languages. My assembly 
language is called SEXY ASS, because it's a Simple, EXcellent, 
Yummy ASSembler.
  After you study the mysteries of the SEXY ASS, you can easily 
get your rear in gear and become the dominant master of the 
assemblers sold for Apple, Radio Shack, IBM, DEC, etc. Mastering 
them will become so easy that you'll say, ``Assembly language is 
a piece of cheesecake!''

           Bytes in my ASS
  Let's get a close-up view of the SEXY ASS. . . . 
  CPU registers The computer's guts consist of two main parts: 
the brain (which is called the CPU) and the main memory (which 
consists of RAM and ROM).
  Inside the CPU are many electronic boxes, called registers. 
Each register holds several electrical signals; each signal is 
called a bit; so each register holds several bits. Each bit is 
either 1 or 0. A ``1'' represents a high voltage; a ``0'' 
represents a low voltage. If the bit is 1, the bit is said to be 
high or on or set or true; if the bit is 0, the bit is said to be 
low or off or cleared or false.
  The CPU's most important register is called the accumulator (or 
A). In the SEXY ASS system, the accumulator consists of 8 bits, 
which is 1 byte. (Later, I'll explain how to make the CPU handle 
several bytes simultaneously; but the accumulator itself holds 
only 1 byte.)
  Memory locations Like the CPU, the main memory consists of 
electronic boxes. The electronic boxes in the CPU are called 
registers, but the electronic boxes in the main memory are called 
memory locations instead. Because the main memory acts like a 
gigantic post office, the memory locations are also called 
addresses. In the SEXY ASS system, each memory location holds 1 
byte. There are many thousands of memory locations; they're 
numbered 0, 1, 2, 3, etc.
  Number systems When using SEXY ASS, you can type numbers in 
decimal, binary, or hexadecimal. (For SEXY ASS, octal isn't 
useful.) For example, the number ``twelve'' is written ``12'' in 
decimal, ``1100'' in binary, and ``C'' in hexadecimal. To 
indicate which number system you're using, put a percent sign in 
front of each binary number, and put a dollar sign in front of 
each hexadecimal number. For example, in SEXY ASS you can write 
the number ``twelve'' as either 12 or %1100 or $C. (In that 
respect, SEXY ASS copies the 6502 assembly language, which also 
uses the percent sign and the dollar sign.)
                                         Most of the time, we'll 
be using hexadecimal, so let's quickly review what hexadecimal is 
all about. To count in hexadecimal, just start counting as you 
learned in elementary school ($1, $2, $3, $4, $5, $6, $7, $8, 
$9);but after $9, you continue counting by using the letters of 
the alphabet ($A, $B, $C, $D, $E, and $F). After $F (which is 
fifteen), you say $10 (which means sixteen), then say $11 (which 
means seventeen), then $12, then $13, then $14, etc., until you 
reach $19; then come $1A, $1B, $1C, $1D, $1E, and $1F. Then come 
$20, $21, $22, etc., up to $29, then $2A, $2B, $2C, $2D, $2E, and 
$2F. Then comes $30. Eventually, you get up to $99, then $9A, 
$9B, $9C, $9D, $9E, and $9F. Then come $A0, $A1, $A2, etc., up to 
$AF. Then come $B0, $B1, $B2, etc., up to $BF. You continue that 
pattern, until you reach $FF. Get together with your friends, and 
try counting up to $FF. (Don't bother pronouncing the dollar 
signs.) Yes, you too can count like a pro!
                                         Each hexadecimal digit 
represents 4 bits. Therefore, an 8-bit byte requires two 
hexadecimal digits. So a byte can be anything from $00 to $FF.
                                         Main segment I said that 
the main memory consists of thousands of memory locations, 
numbered 0, 1, 2, etc. The most important part of the main memory 
is called the main memory bank or main segment: that part 
consists of 65,536 memory locations (64K), which are numbered 
from 0 to 65,535. Programmers usually number them in hexadecimal; 
the hexadecimal numbers go from $0000 from $FFFF. ($FFFF in 
hexadecimal is the same as 65.535 in decimal.) Later, I'll 
explain how to use other parts of the memory; but for now, let's 
restrict our attention to just 64K main segment.
                                         How to copy a byte 
Here's a simple, one-line program, written in the SEXY ASS 
assembly language:
        LOAD    $7000
It makes the computer copy one byte, from memory location $7000 
to the accumulator. So after the computer obeys that instruction, 
the accumulator will contain the same data as the memory 
location. For example, if the memory location contains the byte 
%01001111 (which can also be written as $4F), so will the 
accumulator.
                                         Notice the wide space 
before and after the word LOAD. To make the wide space, press the 
TAB key.
                                         The word LOAD tells the 
computer to copy from a memory location to the accumulator. The 
opposite of the word LOAD is the word STORE: it tells the 
computer to copy from the accumulator to a memory location. For 
example, if you type ___ 
        STORE   $7000
the computer will copy a byte from the accumulator to memory 
location $7000.
                                         Problem: write an 
assembly-language program that copies a byte from memory location 
$7000 to memory location $7001. Solution: you must do it in two 
steps. First, copy from memory location $7000 to the accumulator 
(by using the word LOAD); then copy from the accumulator to 
memory location $7001 (by using the word STORE). Here's the 
program:
        LOAD    $7000
        STORE   $7001

             Arithmetic
  If you say ___ 
        INC
the computer will increment (increase) the number in the 
accumulator, by adding 1 to it. For example, if the accumulator 
contains the number $25, and you then say INC, the accumulator 
will contain the number $26. For another example, if the 
accumulator contains the number $39, and you say INC, the 
accumulator will contain the number $3A (because, in hexadecimal, 
after 9 comes A).
  Problem: write a program that increments the number that's in 
location $7000; for example, if location $7000 contains $25, the 
program should change that data, so that location $7000 contains 
$26 instead. Solution: copy the number from location $7000 to the 
accumulator, then increment the number, then copy it back to 
location $7000. . . . 
        LOAD    $7000
        INC
        STORE   $7000
  That example illustrates the fundamental rule of 
assembly-language programming, which is: to manipulate a memory 
location's data, copy the data to the accumulator, manipulate the 
accumulator, and then copy the revised data from the accumulator 
to memory.
  The opposite of INC is DEC: it decrements (decreases) the 
number in the accumulator, by subtracting 1 from it.
  If you say ___ 
        ADD     $7000
the computer will change the number in the accumulator, by adding 
to it the number that was in memory location $7000. For example, 
if the accumulator had contained the number $16, and memory 
location $7000 had contained the number $43, the number in the 
accumulator will change and become the sum, $59. The number in 
memory location $7000 will remain unchanged: it will still be 
$43.
  Problem: find the sum of the numbers in memory locations $7000, 
$7001, and $7002, and put that sum into memory location $7003. 
Solution: copy the number from memory location $7000 to the 
accumulator, then add to the accumulator the numbers from memory 
locations $7001 and $7002, so that the accumulator to memory 
location $7003. . . . 
        LOAD    $7000
        ADD     $7001
        ADD     $7002
        STORE   $7003
  The opposite of ADD is SUB, which means SUBtract. If you say 
SUB $7000, the computer will change the number in the 
accumulator, by subtracting from it the number in memory location 
$7000.

        Immediate addressing
  If you say ___ 
        LOAD     #$25
the computer will put the number $25 into the accumulator. The 
$25 is the data. In the instruction ``LOAD #$25'', the symbol 
``#'' tells the computer that the $25 is the data instead of 
being a memory location.
  If you were to omit the #, the computer would assume the $25 
meant memory location $0025, and so the computer would copy data 
from memory location $0025 to the accumulator.
  An instruction that contains the symbol # is said to be an 
immediate instruction; it is said to use immediate addressing. 
Such instructions are unusual.
  The more usual kind of instruction, which does not use the
symbol #, is called a direct instruction.
                                         Problem: change the 
number in the accumulator, by adding $12 to it. Solution:
        ADD     #$12
                                         Problem: change the 
number in memory location $7000, by adding $12 to that number. 
Solution: copy the number from memory location $7000 to the 
accumulator, add $12 to it, and then copy the sum back to the 
memory location. . . . 
        LOAD    $7000
        ADD     #$12
        STORE   $7000
                                         Problem: make the 
computer find the sum of $16 and $43, and put the sum into memory 
location $7000. Solution: put $16 into the accumulator, add $43 
to it, and then copy from the accumulator to memory location 
$7000. . . . 
        LOAD    #$16
        ADD     #$43
        STORE   $7000

                                                     Video RAM
                                         The video RAM is part of 
the computer's RAM, and holds a copy of what's on the screen.
                                         For example, suppose 
you're running a program that analyzes taxicabs, and the screen 
(of your TV or monitor) shows information about various cabs. If 
the upper-left corner of the screen shows the word CAB, the video 
RAM contains the ASCII code numbers for the letters C, A, and B. 
Since the ASCII code number for C is 67 (which is $43), and the 
ASCII code number for A is 65 (which is $41), and the ASCII code 
number for B is 66 (which is $42), the video RAM contains $43, 
$41, and $42. The $43, $41, and $42 represent the word CAB.
                                         Suppose that the video 
RAM begins at memory location $6000. If the screen's upper-left 
corner shows the word CAB, memory location $6000 contains the 
code for C (which is $43); the next memory location ($6001) 
contains the code for A (which is $41); and the next memory 
location ($6002) contains the code for B (which is $42).
                                         Problem: assuming that 
the video RAM begins at location $6000, make the computer write 
the word CAB onto the screen's upper-left corner. Solution: write 
$43 into memory location $6000, write $41 into memory location 
$6001, and write $42 into memory location $6002. . . . 
        LOAD    #$43
        STORE   $6000
        LOAD    #$41
        STORE   $6001
        LOAD    #$42
        STORE   $6002
                                         The computer knows that 
$43 is the code number for ``C''. When you're writing that 
program, if you're too lazy to figure out the $43, you can simply 
write ``C''; the computer will understand. So you can write the 
program like this:
        LOAD    #"C"
        STORE   $6000
        LOAD    #"A"
        STORE   $6001
        LOAD    #"B"
        STORE   $6002
  That's the solution if the video RAM begins at memory location 
$6000. On your computer, the video RAM might begin at a different 
memory location instead. To find out about your computer's video 
RAM, look at the back of the technical manual that came with your 
computer. There you'll find a memory map: it shows which memory 
locations are used by the video RAM, which memory locations are 
used by other RAM, and which memory locations are used by the 
ROM.

                Flags
  The CPU contains flags. Here's how they work.
  Carry flag A byte consists of 8 bits. The smallest number you 
can put into a byte is %00000000. The largest number you can put 
into a byte is %11111111, which in hexadecimal is $FF; in 
decimal, it's 255.
  What happens if you try to go higher than %11111111? To find 
out, examine this program:
        LOAD    #%10000001
        ADD     #%10000010
In that program, the top line puts the binary number %10000001 
into the accumulator. The next line tries to add %10000010 to the 
accumulator. But the sum, which is %100000011, contains 9 bits 
instead of 8, and therefore can't fit into the accumulator.
  The computer splits that sum into two parts: the left bit (1) 
and the remaining bits (00000011). The left bit (1) is called the 
carry bit; the remaining bits (00000011) are called the tail. 
Since the tail contains 8 bits, it fits nicely into the 
accumulator; so the computer puts it into the accumulator. The 
carry bit is put into a special place inside the CPU; that 
special place is called the carry flag.
  So that program makes the accumulator become 00000011, and 
makes the carry flag become 1.
  Here's an easier program:
        LOAD    #%1
        ADD     #%10
The top line puts %1 into the accumulator; so the accumulator's 8 
bits are %00000001. The bottom line adds %10 to the number in the 
accumulator; so the accumulator's 8 bits become %00000011. Since 
the numbers involved in that addition were so small, there was no 
need for a 9th bit ___ no need for a carry bit. To emphasize that 
no carry bit was required, the carry flag automatically becomes 
0.
  Here's the rule: if an arithmetic operation (such as ADD, SUB, 
INC, or DEC) gives a result that's too long to fit into 8 bits, 
the carry flag becomes 1; otherwise, the carry flag becomes 0.
                                         Negatives The largest 
number you can fit into a byte %11111111, which in decimal is 
255. Suppose you try to add 1 to it. The sum is %100000000, which 
in decimal is 256. But since %100000000 contains 9 bits, it's too 
long to fit into a byte. So the computer sends the leftmost bit 
(the 1) to the carry flag, and puts the tail (the 00000000) into 
the accumulator. As a result, the accumulator contains 0.
                                         So in assembly language, 
if you tell the computer to do %11111111+1 (which is 255+1), the 
accumulator says the answer is 0 (instead of 256).
                                         In assembly language, 
%11111111+1 is 0. In other words, %11111111 solves the equation 
x+1=0.
                                         According to high school 
algebra, the equation x+1=0 has this solution: x=-1. But we've 
seen that in the assembly language, the equation x+1=0 has the 
solution x=%11111111. Conclusion: in assembly language, -1 is the 
same as %11111111.
                                         Now you know that -1 is 
the same as %11111111, which is 255. Yes, -1 is the same as 255. 
Similarly, -2 is the same as 254; -3 is the same as 253; -4 is 
the same as 252. Here's the general formula: -n is the same as 
256-n. (That's because 256 is the same as 0.)
                                         %11111111 is 255 and is 
also -1. Since -1 is a shorter name than 255, we say that 
%11111111 is interpreted as -1. Similarly, %11111110 is 254 and 
also -2; since -2 is a shorter name than 254, we say that 
%11111110 is interpreted as -2. At the other extreme, %00000010 
is 2 and is also -254; since 2 is a shorter name than -254, we 
say that %11111110 is interpreted as 2. Here's the rule: if a 
number is ``almost'' 256, it's interpreted as a negative number; 
otherwise, it's interpreted as a positive number.
                                         How high must a number 
be, in order to be ``almost'' 256, and therefore to be 
interpreted as a negative number? The answer is: if the number is 
at least 128, it's interpreted as a negative number. Putting it 
another way, if the number's leftmost bit is 1, it's interpreted 
as a negative number.
                                         That strange train of 
reasoning leads to the following definition: a negative number is 
a byte whose leftmost bit is 1.
                                         A byte's leftmost bit is 
therefore called the negative bit or the sign bit.
                                         Flag register You've 
seen that the CPU contains a register called the accumulator. The 
CPU also contains a second register, called the flag register. In 
the SEXY ASS system, the flag register contains 8 bits (one 
byte). Each of the 8 bits in the flag register is called a flag; 
so the flag register contains 8 flags.
                                         Each flag is a bit: it's 
either 1 or 0. If the flag is 1, the flag is said to be up or 
raised or set. If the flag is 0, the flag is said to be down or 
lowered or cleared.
                                         One of the 8 flags is 
the carry flag: it's raised (becomes 1) whenever an arithmetic 
operation requires a 9th bit. (It's lowered whenever an 
arithmetic operation does not require a 9th bit.)
                                         Another one of the flags 
is the negative flag: it's raised whenever the number in the 
accumulator becomes negative. For example, if the accumulator 
becomes %11111110 (which is -2), the negative flag is raised 
(i.e. the negative flag becomes 1). It's lowered whenever the 
number in the accumulator becomes non-negative.
                                         Another one of the flags 
is the zero flag: it's raised whenever the number in the 
accumulator becomes zero. (It's lowered whenever the number in 
the accumulator becomes non-zero.)
                Jumps
  You can give each line of your program a name. For example, you 
can give a line the name FRED. To do so, put the name FRED at the 
beginning of the line, like this:
FRED    LOAD    $7000
The line's name (FRED) is at the left margin. The command itself 
(LOAD    $7000) is indented by pressing the TAB key. In that 
line, FRED is called the label, LOAD is called the operation or 
mnemonic, and $7000 is called the address.
  Languages such as BASIC let you say ``GO TO''. In assembly 
language, you say ``JUMP'' instead of ``GO TO''. For example, to 
make the computer GO TO the line named FRED, say:
        JUMP    FRED
The computer will obey: it will JUMP to the line named FRED.
  You can say ___ 
        JUMPN   FRED
That means: JUMP to FRED, if the Negative flag is raised. So the 
computer will JUMP to FRED if a negative number was recently put 
into the accumulator. (If a non-negative number was recently put 
into the accumulator, the computer will not jump to FRED.)
  JUMPN means ``JUMP if the Negative flag is raised.'' JUMPC 
means ``JUMP if the Carry flag is raised.'' JUMPZ means ``JUMP if 
the Zero flag is raised.''
  JUMPNL means ``JUMP if the Negative flag is Lowered.'' JUMPCL 
means ``JUMP if the Carry flag is Lowered.'' JUMPZL means ``JUMP 
if the Zero flag is Lowered.''
  Problem: make the computer look at memory location $7000; if 
the number in that memory location is negative, make the computer 
jump to a line named FRED. Solution: copy the number from memory 
location $7000 to the accumulator, to influence the Negative 
flag; then JUMP if Negative. . . . 
        LOAD    $7000
        JUMPN   FRED
  Problem: make the computer look at memory location $7000. If 
the number in that memory location is negative, make the computer 
print a minus sign in the upper-left corner of the screen; if the 
number is positive instead, make the computer print a plus sign 
instead; if the number is zero, make the computer print a zero. 
Solution: copy the number from memory location $7000 to the 
accumulator (by saying LOAD); then analyze that number (by using 
JUMPN and JUMPZ); then LOAD the ASCII code number for either 
``+'' or ``-'' or ``0'' into the accumulator (whichever is 
appropriate); finally copy that ASCII code number from the 
accumulator to the video RAM (by saying STORE). . . . 
        LOAD    $7000
        JUMPN   NEGAT
        JUMPZ   ZERO

        LOAD    #"+"
        JUMP    DISPLAY

NEGAT   LOAD    #"-"
        JUMP    DISPLAY

ZERO    LOAD    #"0"

DISPLAY STORE   $6000

                                                 Machine language
                                         I've been explaining 
assembly language. Machine language resembles assembly language; 
what's the difference?
                                         To find out, let's look 
at a machine language called SEXY MACHO (because it's a Simple, 
EXcellent, Yummy MACHine language Original).
                                         SEXY MACHO resembles 
SEXY ASS; here are the major differences. . . . 
                                         In SEXY ASS assembly 
language, you use words such as LOAD, STORE, INC, DEC, ADD, SUB, 
and JUMP. Those words are called operations or mnemonics. In SEXY 
MACHO machine language, you replace those words by code numbers: 
the code number for LOAD is 1; the code number for STORE is 2; 
INC is 3; DEC is 4; ADD is 5; SUB is 6; and JUMP is 7. The code 
numbers are called the operation codes or op codes.
                                         In SEXY ASS assembly 
language, the symbol ``#'' indicates immediate addressing; a lack 
of the symbol ``#'' indicates direct addressing instead. In SEXY 
MACHO machine language, you replace the symbol ``#'' by the code 
number 1; if you want direct addressing instead, you must use the 
code number 0.
                                         In SEXY MACHO, all code 
numbers are hexadecimal.
                                         For example, look at 
this SEXY ASS instruction:
        ADD     #$43
To translate that instruction into SEXY MACHO machine language, 
just replace each symbol by its code number. Since the code 
number for ADD is 5, and the code number for # is 1, the SEXY 
MACHO version of that line is:
5143
                                         Let's translate STORE 
$7003 into SEXY MACHO machine language. Since the code for STORE 
is 2, and the code for direct addressing is 0, the SEXY MACHO 
version of that command is:
207003
                                         In machine language, you 
can't use any words or symbols: you must use their code numbers 
instead. To translate a program from assembly language to machine 
language, you must look up the code number of each word or 
symbol.
                                         An assembler is a 
program that makes the computer translate from assembly language 
to machine language.
                                         The CPU understands only 
machine language: it understands only numbers. It does not 
understand assembly language: it does not understand words and 
symbols. If you write a program in assembly language, you must 
buy an assembler, which translates your program from assembly 
language to machine language, so that the computer can understand 
it.
                                         Since assembly language 
uses English words (such as LOAD), assembly language seems more 
``human'' than machine language (which uses code numbers). Since 
programmers are humans, programmers prefer assembly language over 
machine language. Therefore, the typical programmer writes in 
assembly language, and then uses an assembler to translate the 
program to machine language, which is the language that the CPU 
ultimately requires.
  Here's how the typical assembly-language programmer works. 
First, the programmer types the assembly-language program and 
uses a word processor to help edit it. The word processor 
automatically puts the assembly-language program onto a disk. 
Next, the programmer uses the assembler to translate the 
assembly-language program into machine language. The assembler 
puts the machine-language version of the program onto the disk. 
So now the disk contains two versions of the program: the disk 
contains the original version (in assembly language) and also 
contains the translated version (in machine language). The 
original version (in assembly language) is called the source 
code; the translated version (in machine language) is called the 
object code. Finally, the programmer gives a command that makes 
the computer copy the machine-language version (the object code) 
from the disk to the RAM and run it.
  Here's a tough question: how does the assembler translate 
``JUMP FRED'' into machine language? Here's the answer. . . . 
  The assembler realizes that FRED is the name for a line in your 
program. The assembler hunts through your program, to find out 
which line is labeled FRED. When the assembler finds that line, 
it analyzes that line, to figure out where that line will be in 
the RAM after the program is translated into machine language and 
running. For example, suppose the line that's labeled FRED will 
become a machine-language line which, when the program is 
running, will be in the RAM at memory location $2053. Then ``JUMP 
FRED'' must be translated into this command: ``jump to the 
machine-language line that's in the RAM at memory location 
$2053''. So ``JUMP FRED'' really means:
        JUMP    $2053
Since the code number for JUMP is 7, and the  addressing isn't 
immediate (and therefore has code 0 instead of 1), the 
machine-language version of JUMP FRED is:
702053

                                                  System software
                                         The computer's main 
memory consists of RAM and ROM. In a typical computer, the first 
few memory locations ($0000, $0001, $0002, etc.) are ROM: they 
permanently contain a program called the bootstrap, which is 
written in machine-language.
                                         When you turn on the 
computer's power switch, the computer automatically runs the 
bootstrap program. If your computer uses disks, the bootstrap 
program makes the computer start reading information from the 
disk in the main drive. In fact, it makes the computer copy a 
machine-language program from the disk to the RAM. The 
machine-language program that it copies is called the DOS.
                                         After the DOS has been 
copied to the RAM, the computer starts running the DOS program. 
The DOS program makes the computer print a message on the screen 
(such as ``Welcome to CP/M'' or ``Welcome to MS-DOS'') and print 
a symbol on the screen (such as ``A>'') and then wait for you to 
type a command.
                                         That whole procedure is 
called bootstrapping (or booting up), because of the phrase 
``pull yourself up by your own bootstraps''. By using the 
bootstrap program, the computer pulls itself up to new 
intellectual heights: it becomes a CP/M machine or an MS-DOS 
machine or an Apple DOS machine or a TRSDOS machine.
                                         After booting up, you 
can start writing programs in BASIC. But how does the computer 
understand the BASIC words, such as PRINT, INPUT, IF, THEN, and 
GO TO? Here's how. . . . 
                                         While you're using 
BASIC, the computer is running a machine-language program, that 
makes the computer seem to understand BASIC. That 
machine-language program, which is in the computer's ROM or RAM, 
is called the BASIC language processor or BASIC interpreter. If 
your computer uses Microsoft BASIC, the BASIC interpreter is a 
machine-language program that was written by Microsoft 
Incorporated (a ``corporation'' that consists of Bill Gates and 
his pals).

                                               How assemblers differ
                                         In a microcomputer, the 
CPU is a single chip, called the microprocessor. The most popular 
microprocessors are the 8088, the 68000, and the 6502.
                                         The 8088, designed by 
Intel, hides in the IBM PC and clones. (The plain version is 
called the 8088; a souped-up version, called the 80286, is in the 
IBM PC AT.)
                                         The 68000, designed by 
Motorola, hides in the computers that rely on mice: the Apple 
Mac, Commodore Amiga, and Atari ST. (The plain version is called 
the 68000; a souped-up version, called the 68020, is in the Mac 
2; an even fancier version, called the 68030, is in fancier 
Macs.)
                                         The 6502, designed by 
MOS Technology (which has become part of Commodore), hides in 
old-fashioned cheap computers: the Apple 2 family, the Commodore 
64 & 128, and the Atari XL & XE.
                                         Let's see how their 
assemblers differ from SEXY ASS.
  Number systems SEXY ASS assumes all numbers are written in the 
decimal system, unless preceded by a dollar sign (which means 
hexadecimal) or percent sign (which means binary).
  68000 and 6502 assemblers resemble SEXY ASS, except that they 
don't understand percent signs and binary notation. Some 
stripped-down 6502 assemblers don't understand the decimal system 
either: they require all numbers to be in hexadecimal.
  The 8088 assembler comes in two versions.
  The full version of the 8088 assembler is called the Microsoft 
Macro ASseMbler (MASM). It lists for $150, but discount dealers 
sell it for just $83. It assumes all numbers are written in the 
decimal system, unless followed by an H (which means hexadecimal) 
or B (which means binary). For example, the number twelve can be 
written as 12 or as 0CH or as 1100B. It requires each number to 
begin with a digit: so to say twelve in hexadecimal, instead of 
saying CH you must say 0CH.
  A stripped-down 8088 assembler, called the DEBUG 
mini-assembler, is part of DOS; so you get it at no extra charge 
when you buy DOS. It requires all numbers to be written in 
hexadecimal. For example, it requires the number twelve to be 
written as C. Do not put a dollar sign or H next to the C.
  Accumulator Each microprocessor contains several accumulators, 
so you must say which accumulator to use. The main 8-bit 
accumulator is called ``A'' in the 6502, ``AL'' in the 8088, and 
``D0.B'' in the 68000.
  Labels SEXY ASS and the other full assemblers let you begin a 
line with a label, such as FRED. For the 8088 full assembler 
(MASM), add a colon after FRED. Mini-assemblers (such as 8088 
DEBUG) don't understand labels.
  Commands Here's how to translate from SEXY ASS to the popular 
assemblers:
Computer's actionSEXY ASS650268000    8088 MASM
put 25 in accumulatorLOAD #$25LDA #$25MOVE.B #$25,D0MOV AL,25H
copy location 7000 to acc.LOAD $7000LDA $7000MOVE.B $7000,D0MOV 
AL,[7000H]
copy acc. to location 7000STORE $7000STA $7000MOVE.B D0,$7000MOV 
[7000H],AL
add location 7000 to acc.ADD $7000ADC $7000ADD.B $7000,D0ADD 
AL,[7000H]
subtract loc. 7000 from acc.SUB $7000SBC $7000SUB.B $7000,D0SUB 
AL,[7000H]
increment accumulatorINCADC #$1ADDQ.B #1,D0INC AL
decrement accumulatorDECSBC #$1SUBQ.B #1,D0DEC AL
put character C in acc.LOAD #"C"LDA #'CMOVE.B #'C',D0MOV AL,"C"
jump to FRED  JUMP FREDJMP FREDJMP FREDJMP FRED
jump if negativeJUMPN FREDBMI FREDBMI FREDJS FRED
jump if carry JUMPC FREDBCS FREDBCS FREDJC FRED
jump if zero  JUMPZ FREDBEQ FREDBEQ FREDJZ FRED
jump if negative loweredJUMPNL FREDBPL FREDBPL FREDJNS FRED
jump if carry loweredJUMPCL FREDBCC FREDBCC FREDJNC FRED
jump if zero loweredJUMPZL FREDBNE FREDBNE FREDJNZ FRED
  Notice that in 6502 assembler, each mnemonic (such as LDA) is 
three characters long.
  To refer to an ASCII character, SEXY ASS and 8088 MASM put the 
character in quotes, like this: ``C''. 68000 assembler uses 
apostrophes instead, like this: 'C'. 6502 assembler uses just a 
single apostrophe, like this: 'C.
  Instead of saying ``jump if'', 6502 and 68000 programmers say 
``branch if'' and use mnemonics that start with B instead of J. 
For example, they use mnemonics such as BMI (which means ``Branch 
if MInus''), BCS (``Branch if Carry Set''), and BEQ (``Branch if 
EQual to zero'').
  To make the 68000 manipulate a byte, put ``.B'' after the 
mnemonic. (If you say ``.W'' instead, the computer will 
manipulate a 16-bit word instead of a byte. If you say ``.L'' 
instead, the computer will manipulate long data containing 32 
bits. If you don't specify ``.B'' or ``.W'' or ``.L'', the 
assembler assumes you mean ``.W''.)
  8088 assemblers require you to put each memory location in 
brackets. So whenever you refer to location 7000 hexadecimal, you 
put the 7000H in brackets, like this: [7000H].

          DEBUG
                                                     When you buy 
PC-DOS for your IBM PC (or MS-DOS for your clone), you get a disk 
that contains many DOS files. One of the DOS files is called 
DEBUG. It helps you debug your software and hardware.
                                                     It lets you 
type special debugger commands. It also lets you type commands in 
assembly language.

                                                         How to start
                                                     Put the main 
DOS disk in drive A, then turn the computer on. Type the date and 
time.
                                                     Press the 
CAPS LOCK key, so that everything you type will be capitalized. 
If you're using PC-DOS instead of MS-DOS, put the disk marked 
``DOS Supplemental Programs'' into drive A.
                                                     After the A 
prompt, type the word DEBUG, so your screen looks like this:
A>DEBUG
When you press the ENTER key after DEBUG, the computer will print 
a hyphen, like this:
-
After the hyphen, you can give any DEBUG command.

                                                           Registers
                                                     To see 
what's in the CPU registers, type an R after the hyphen, so your 
screen looks like this:
-R
When you press the ENTER key after the R, the computer will 
print:
AX=0000  BX=0000  CX=0000  DX=0000
That means the main registers (which are called AX, BX, CX, and 
DX) each contain hexadecimal 0000. Then the computer will tell 
you what's in the other registers, which are called SP, BP, SI, 
DI, DS, ES, SS, CS, IP, and FLAGS. Finally, the computer will 
print a hyphen, after which you can type another command.
                                                     Editing the 
registers To change what's in register BX, type RBX after the 
hyphen, so your screen looks like this:
-RBX
                                                     The computer 
will remind you of what's in register BX, by saying:
BX 0000
:
To change BX to hexadecimal 7251, type 7251 after the colon, so 
your screen looks like this:
:7251

That makes the computer put 7251 into register BX.
  To see that the computer put 7251 into register BX, say:
-R
That makes the computer tell you what's in all the registers. It 
will begin by saying:
AX=0000  BX=7251  CX=0000  DX=0000
  Experiment! Try putting different hexadecimal numbers into the 
registers! To be safe, use just the registers AX, BX, CX, and DX.
  Segment registers The computer's RAM is divided into segments. 
The segment registers (DS, ES, SS, and CS) tell the computer 
which segments to use.
  Do not change the numbers in the segment registers! Changing 
them will make the computer use the wrong segments of the RAM and 
wreck your DOS and disks.
  The CS register is called the code segment register. It tells 
the computer which RAM segment to put your programs in. For 
example, if the CS register contains the hexadecimal number 0E9F, 
the computer will put your programs in segment number 0E9F.

       DEBUG's mini-assembler
  To use assembly language, type A100 after the hyphen, so your 
screen looks like this:
-A100
  The computer will print the code segment number, then a colon, 
then 0100. For example, if the code segment register contains the 
hexadecimal number 0E9F, the computer will print:
0E9F:0100
  Now you can type an assembly-language program!
  For example, suppose you want to move the hexadecimal number 
2794 to register AX and move 8156 to BX. Here's the 
assembly-language program:
MOV AX,2794
MOV BX,8156
Type that program. As you type it, the computer will 
automatically put a segment number and memory location in front 
of each line, so your screen will look like this:
0E9F:0100 MOV AX,2794
0E9F:0103 MOV BX,8156
0E9F:0106
After the 0E9F:0106, press the ENTER key. The computer will stop 
using assembly language and will print a hyphen.
  After the hyphen, type G=100 106, so your screen looks like 
this:
-G=100 106
That tells the computer to run your assembly-language program, 
going from location 100 to location 106, so the computer will 
start at location 100 and stop when it reaches memory location 
number 106.
  After running the program, the computer will tell you what's in 
the registers. It will print:
AX=2794  BX=8156  CX=0000  DX=0000
It will also print the numbers in all the other registers.
                                         Listing your program To 
list your program, type U100 after the hyphen, so your screen 
looks like this:
-U100
The U stands for ``Unassemble'', which means ``list''. The 
computer will list your program, beginning at line 100. The 
computer will begin by saying:
0E9F:0100 B89427     MOV   AX,2794
0E9F:0103 BB5681     MOV   BX,8156
                                         The top line consists of 
three parts. The left part (0E9F:0100) is the address in memory. 
The right part (MOV AX, 2794) is the assembly-language 
instruction beginning at that address.
                                         The middle part (B89427) 
is the machine-language translation of MOV AX,2794. That middle 
part begins with B8, which is the machine-language translation of 
MOV AX. Then comes 9427, which is the machine-language 
translation of 2794; notice how machine language puts the digits 
in a different order than assembly language.
                                         The machine-language 
version, B89427, occupies three bytes of RAM. The first byte 
(address 0100) contains the hexadecimal number B8; the next byte 
(address 0101) contains the hexadecimal number 94; the final byte 
(address 0102) contains the hexadecimal number 27.
                                         So altogether, the 
machine-language version of MOV AX,2794 occupies addresses 0100, 
0101, and 0102. That's why the next instruction (MOV BX,8156) 
begins at address 0103.
                                         After the computer 
prints that analysis of your program, the computer will continue 
by printing an analysis of the next several bytes of memory also. 
Altogether, the computer will print an analysis of addresses up 
through 011F. What's in those addresses depends on which program 
your computer was running before you ran this one.
                                         Editing your program To 
edit line 0103, type:
-A103
Then type the assembly-language command you want for location 
103.
                                         When you finish the 
command and press the ENTER key, the computer will give you an 
opportunity to edit the next line (106). If you don't want to 
edit or create a line 106, press the ENTER key again.
                                         After editing your 
program, list it (by typing U100), to make sure you edited 
correctly.
                                         Arithmetic This 
assembly-language program does arithmetic:
MOV AX,7
ADD AX,5
To feed that program to the computer, say A100 after the hyphen, 
then type the program, then press the ENTER key an extra time, 
then say G=100 106.
                                         That program's top line 
moves the number 7 into the AX register. The next line adds 5 to 
the AX register, so the number in the AX register becomes twelve. 
In hexadecimal, twelve is written as C, so the computer will say:
AX=000C
The computer will also say what's in the other registers.
                                         The opposite of ADD is 
SUB, which means subtract. For example, if you say ___ 
SUB AX,3
the computer will subtract 3 from the number in the AX register, 
so the number in the AX register becomes smaller.
  To add 1 to the number in the AX register, you can say:
ADD AX,1
For a short cut, say this instead:
INC AX
That tells the computer to INCrement the AX register, by adding 
1.
  To subtract 1 from the number in the AX register, you can say:
SUB AX,1
For a short cut, say this instead ___ 
DEC AX
which means ``DECrement the AX register''.
  Half registers A register's left half is called the high part. 
The register's right half is called the low part.
  For example, if the AX register contains 9273, the register's 
high part is 92, and the low part is 73.
  The AX register's high part is called ``A high'' or AH. The AX 
register's low part is called ``A low'' or AL.
  Suppose the AX register contains 9273 and you say:
MOV AH,41
The computer will make AX's high part be 41, so AX becomes 4173.
  Copying to memory Let's program the computer to put the 
hexadecimal number 52 into memory location 7000.
  This command almost works:
MOV [7000],52
In that command, the brackets around the 7000 mean ``memory 
location''. That command says to move, into location 7000, the 
number 52.
  Unfortunately, if you type that command, the computer will 
gripe, because the computer can't handle two numbers 
simultaneously (7000 and 52).
  Instead, you split that complicated command into two simpler 
commands, each involving just one number. Instead of trying to 
move 52 directly into location 7000, first move 52 into a 
register (such as AL), then copy that register into location 
7000, like this:
MOV AL,52
MOV [7000],AL
  After running that program, you can prove the 52 got into 
location 7000, by typing:
-E7000
That makes the computer examine location 7000. The computer will 
find 52 there and print:
0E9F:7000 52.
That means: segment 0E9F's 7000th location contains 52.
  If you change your mind and want it to contain 53 instead, type 
53 after the period.
  Next, press the ENTER key, which makes the computer print a 
hyphen, so you can give your next DEBUG command.
  Interrupt 21 Here's how to write an assembly-language program 
that prints the letter C on the screen.
  The ASCII code number for ``C'' is hexadecimal 43. Put 43 into 
the DL register:
0E9F:0100 MOV DL,43
  The DOS code number for ``screen output'' is 2. Put 2 into the 
AH register:
0E9F:0102 MOV AH,2

                                         To make the computer use 
the code numbers you put into the DL and AH registers, tell the 
computer to do DOS interrupt subroutine #21:
0E9F:0104 INT 21
                                         So altogether, the 
program looks like this:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,2
0E9F:0104 INT 21
0E9F:0106
                                         To make the computer do 
that program, say G=100 106. The computer will obey the program, 
so your screen will say:
C
                                         After running the 
program, the computer will tell you what's in all the registers. 
You'll see that DL has become 43 (because of line 100), AH has 
become 02 (because of line 102), and AL has become 43 (because 
INT 21 automatically makes the computer copy DL to AL). Then the 
computer will print a hyphen, so you can give another DEBUG 
command.
                                         Instead of printing just 
C, let's make the computer print CCC. Here's how. Put the code 
numbers for ``C'' and ``screen output'' into the registers:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,02
Then tell DOS to use those code numbers, three times:
0E9F:0104 INT 21
0E9F:0106 INT 21
0E9F:0108 INT 21
0E9F:010A
To run that program, say G=100 10A. The computer will print:
CCC
                                         Jumps Here's how to make 
the computer print C repeatedly, so that the entire screen gets 
filled with C's.
                                         Put the code numbers for 
``C'' and ``screen output'' into the registers:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,02
                                         In line 104, tell DOS to 
use those code numbers:
0E9F:0104 INT 21
To create a loop, jump back to line 104:
0E9F:0106 JMP 104
                                         Altogether, the program 
looks like this:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,03
0E9F:0104 INT 21
0E9F:0106 JMP 104
0E9F:0108
                                         To run that program, say 
G=100 108. The computer will print C repeatedly, so the whole 
screen gets filled with C's. To abort the program, tap the BREAK 
key while holding down the CONTROL key.
                                         Interrupt 20 I showed 
you this program, which makes the computer print the letter C:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,2
0E9F:0104 INT 21
0E9F:0106
If you run that program by saying G=100 106, the computer will 
print C and then tell you what's in all the registers.
                                         Instead of making the 
computer tell you what's in all the registers, let's make the 
computer say:
Program terminated normally

  To do that, make the bottom line of your program say INT 20, 
like this:
0E9F:0100 MOV DL,43
0E9F:0102 MOV AH,2
0E9F:0104 INT 21
0E9F:0106 INT 20
0E9F:0108
  The INT 20 makes the computer print ``Program terminated 
normally'' and then end, without printing a message about the 
registers.
  To run the program, just say G=100. You do not have to say 
G=100 108, since the INT 20 ends the program before the computer 
reaches 108 anyway. The program makes the computer print:
C
Program terminated normally
  Strings This program makes the computer print the string ``I 
LOVE YOU'':
0E9F:0100 MOV DX,109
0E9F:0103 MOV AH,9
0E9F:0105 INT 21
0E9F:0107 INT 20
0E9F:0109 DB "I LOVE YOU$"
0E9F:0114
  The bottom line contains the string to be printed: ``I LOVE 
YOU$''. Notice you must end the string with a dollar sign. In 
that line, the DB stands for Define Bytes.
  Here's how the program works. The top line puts the string's 
line number (109) into DX. The next line puts 9, which is the 
code number for ``string printing'', into AH. The next line (INT 
21) makes the computer use the line number and code number to do 
the printing. The next line (INT 20) makes the program print 
``Program terminated normally'' and end.
  When you run the program (by typing G=100), the computer will 
print:
I LOVE YOU
Program terminated normally
  If you try to list the program by saying U100, the listing will 
look strange, because the computer can't list the DB line 
correctly. But even though the listing will look strange, the 
program will still run fine.
  Saving your program After you've created an assembly-language 
program, you can copy it onto a disk and save it. Here's how.
  First, make sure the program ends by saying INT 20, so that the 
program terminates normally.
  Next, invent a name for the program. The name should end in 
.COM. For example, to give your program the name LOVER.COM, type 
this:
-NLOVER.COM
  Put 0 into register BX (by typing -RBX and then :0).
  Put the program's length into register CS. For example, since 
the program above starts at line 0100 and ends at line 0114 
(which is blank), the program's length is ``0114 minus 0100'', 
which is 14; so put 14 into register CX (by typing -RCX and then 
:14).
  Finally, say -W, which makes the computer write the program 
onto the disk. The computer will say:
Writing 0014 bytes

                                                     Quitting
                                         When you finish using 
DEBUG, tell the computer to quit, by typing a Q after the hyphen. 
When you press the ENTER key after the Q, the computer will quit 
using DEBUG and say:
A>
                                         After quitting, you can 
give any DOS command you wish. If you used assembly language to 
create a program called LOVER.COM, you can run it by just typing:
A>LOVER
The computer will run the program and say:
I LOVE YOU
Then the computer will print ``A>'', so you can give another DOS 
command.
                                         Notice that the computer 
doesn't bother to print a message saying ``Program terminated 
normally''. (It prints that message only when you're in the 
middle of using DEBUG.)
                                         Now you know how to 
write assembly-language programs. Dive in! Write your own 
programs!

     INSIDE THE CPU
  Let's peek inside the CPU and see what lurks within!

     Program counter
  Each CPU contains a special register called the program 
counter.
  The program counter tells the CPU which line of your program to 
do next. For example, if the program counter contains the number 
6 (written in binary), the CPU will do the line of your program 
that's stored in the 6th memory location.
  More precisely, here's what happens if the program counter 
contains the number 6. . . . 
  A. The CPU moves the content of the 6th memory location to the 
CPU's instruction register. (That's called fetching the 
instruction.)
  B. The CPU checks whether the instruction register contains a 
complete instruction written in machine language. If not ___ if 
the instruction register contains only part of a machine-language 
instruction ___ the CPU fetches the content of the 7th memory 
location also. (The instruction register is large enough to hold 
the content of memory locations 6 and 7 simultaneously.) If the 
instruction register still doesn't contain a complete 
instruction, the CPU fetches the content of the 8th memory 
location also. If the instruction register still doesn't contain 
a complete instruction, the CPU fetches the content of the 9th 
memory location also.
  C. The CPU changes the number in the program counter. For 
example, if the CPU has fetched from the 6th and 7th memory 
locations, it makes the number in the program counter be 8; if 
the CPU has fetched from the 6th, 7th, and 8th memory locations, 
it makes the number in the program counter be 9. (That's called 
updating the program counter.)
  D. The CPU figures out what the instruction means. (That's 
called decoding the instruction.)
  E. The CPU obeys the instruction. (That's called executing the 
instruction.) If it's a ``GO TO'' type of instruction, the CPU 
makes the program counter contain the address of the memory 
location you want to go to.
                             After the CPU completes steps A, B, 
C, D, and E, it looks at the program counter and moves on to the 
next instruction. For example, if the program counter contains 
the number 9 now, the CPU does steps A, B, C, D, and E again, but 
by fetching, decoding, and executing the 9th memory location 
instead of the 6th.
                             The CPU repeats steps A, B, C, D, 
and E again and again; each time, the number in the program 
counter changes. Those five steps form a loop, called the 
instruction cycle.

                                         Arithmetic/logic unit
                             The CPU contains two parts: the 
control unit (which is the boss) and the arithmetic/logic unit 
(ALU). When the control unit comes to step D of the instruction 
cycle, and decides some arithmetic or logic needs to be done, it 
sends the problem to the ALU, which sends back the answer.
                             Here's what the ALU can do:
Name of operation                        Example Explanation
plus, added to, +                         10001010add, but 
remember that 1+1 is 10 in binary
                                         +10001001
                                         100010011

minus, subtract, -                        10001010subtract, but 
remember 10-1 is 1 in binary
                                         -10001001
                                          00000001

negative, -,                             -10001010left of the 
rightmost 1, do this:
the two's complement of                   01110110replace each 0 
by 1, and each 1 by 0

not, ~, the complement of,               ~10001010replace each 0 
by 1, and each 1 by 0
the one's complement of                   01110101

and, &, ^                                 10001010put 1 wherever 
both original numbers had 1
                                         ^ 10001001
                                          10001000

or, inclusive or, v                       10001010put 1 wherever 
some original number had 1
                                         v 10001001
                                          10001011

eXclusive OR, XOR, v~                     10001010put 1 wherever 
the original numbers differ
                                         v~10001001
                                          00000011
                             Also, the ALU can shift a register's 
bits. For example, suppose a register contains 10111001. The ALU 
can shift the bits toward the right:
before                         10111001

after                          01011100
It can shift the bits toward the left:
before                         10111001

after                          01110010
It can rotate the bits toward the right:
before                         10111001

after                          11011100
It can rotate the bits toward the left:
before                         10111001

after                          01110011
It can shift the bits toward the right arithmetically:
before                         10111001

after                          11011100
It can shift the bits toward the left arithmetically:
before                         10111001

after                          11110010
                             Doubling a number is the same as 
shifting it left arithmetically. For example, doubling six (to 
get twelve) is the same as shifting six left arithmetically:
six                            00000110

twelve                         00001100

  Halving a number is the same as shifting it right 
arithmetically. For example, halving six (to get three) is the 
same as shifting six right arithmetically:
six 00000110

three00000011
Halving negative six (to get negative three) is the same as 
shifting negative six right arithmetically:
negative six11111010

negative three11111101
  Using the ALU, the control unit can do operations such as:
A.Find the number in the 6th memory location, and move its 
negative to a register.
B.Change the number in a register, by adding to it the number in 
the 6th memory location.
C.Change the number in a register, by subtracting from it the 
number in the 6th memory location.
  Most computers require each operation to have one source and 
one destination. In operations A, B, and C, the source is the 6th 
memory location; the destination is the register.
  The control unit cannot do a command such as ``add together the 
number in the 6th memory location and the number in the 7th 
memory location, and put the sum in a register'', because that 
operation would require two sources. Instead, you must give two 
shorter commands:
1. Move the number in the 6th memory location to the register.
2. Then add to that register the number in the 7th memory 
location.

                      Flags
  The CPU contains a flag register, which comments on what the 
CPU is doing. In a typical CPU, the flag register has six bits, 
named as follows:
the Negative bit
the Zero bit
the Carry bit
the Overflow bit
the Priority bit
the Privilege bit
  When the CPU performs an operation (such as addition, 
subtraction, shifting, rotating, or moving), the operation has a 
source and a destination. The number that goes into the 
destination is the operation's result. The CPU automatically 
analyzes that result.
  Negative bit If the result is a negative number, the CPU turns 
on the Negative bit. In other words, it makes the Negative bit be 
1. (If the result is a number that's not negative, the CPU makes 
the Negative bit be 0.)
  Zero bit If the result is zero, the CPU turns on the Zero bit. 
In other words, it makes the Zero bit be 1.
  Carry bit When the ALU computes the result, it also computes an 
extra bit, which becomes the Carry bit.
  For example, here's how the ALU adds 7 and -4:
 7 is                  00000111
-4 is                  11111100
binary addition gives 100000011

                        result
                    Carry
So the result is 3, and the Carry bit becomes 1.
  Overflow bit If the ALU can't compute a result correctly, it 
turns on the Overflow bit.
  For example, in elementary school you learned that 98+33 is 
131; so in binary, the computation should look like this:
             128 64 32 16 8  4  2  1
98 is            1  1  0  0  0  1  0
33 is               1  0  0  0  0  1
the sum is    1  0  0  0  0  0  1  1, which is 131

But here's what an 8-bit ALU will do:
            sign 64 32 16 8  4  2  1
98 is         0  1  1  0  0  0  1  0
33 is         0  0  1  0  0  0  0  1
the sum is 0  1  0  0  0  0  0  1  1

         Carry        result
Unfortunately, the result's leftmost 1 is in the position marked 
sign, instead of the position marked 128; so the result looks 
like a negative number.
                                                     To warn you 
that the result is incorrect, the ALU turns on the Overflow bit. 
If you're programming in a language such as BASIC, the 
interpreter or compiler keeps checking whether the Overflow bit 
is on; when it finds that the bit's on, it prints the word 
OVERFLOW.
                                                     Priority bit 
While your program's running, it might be interrupted. 
Peripherals might interrupt, in order to input or output the 
data; the real-time clock might interrupt, to prevent you from 
hogging too much time, and to give another program a chance to 
run; and the computer's sensors might interrupt, when they sense 
that the computer is malfunctioning.
                                                     When 
something wants to interrupt your program, the CPU checks whether 
your program has priority, by checking the Priority bit. If the 
Priority bit is on, your program has priority and cannot be 
interrupted.
                                                     Privilege 
bit On a computer that's handling several programs at the same 
time, some operations are dangerous: if your program makes the 
computer do those operations, the other programs might be 
destroyed. Dangerous operations are called privileged 
instructions; to use them, you must be a privileged user.
                                                     When you 
walk up to a terminal attached to a large computer, and type 
HELLO or LOGIN, and type your user
number, the operating system examines your user number to find 
out whether you are a privileged user. If you are, the operating 
system turns on the Privilege bit. When the CPU starts running 
your programs, it refuses to do privileged instructions unless 
the Privilege bit is on.
                                                     Microcompute
rs omit the Privilege bit, and can't prevent you from giving 
dangerous commands. But since the typical microcomputer has only 
one terminal, the only person your dangerous command can hurt is 
yourself.
  Levels of priority & privilege Some computers have several 
levels of priority and privilege.
  If your priority level is ``moderately high'', your program is 
immune from most interruptions, but not from all of them. If your 
privilege level is ``moderately high'', you can order the CPU to 
do most of the privileged instructions, but not all of them.
  To allow those fine distinctions, large computers devote 
several bits to explaining the priority level, and several bits 
to explaining the privilege level.
  Where are the flags? The bits in the flag register are called 
the flags. To emphasize that the flags comment on your program's 
status, people sometimes call them status flags.
  In the CPU, the program counter is next to the flag register. 
Instead of viewing them as separate registers, some programmers 
consider them to be parts of a single big register, called the 
program status word.
  Tests You can give a command such as, ``Test the 3rd memory 
location''. The CPU will examine the number in the 3rd memory 
location. If that number is negative, the CPU will turn on the 
Negative bit; if that number is zero, the CPU will turn on the 
Zero bit.
  You can give a command such as, ``Test the difference between 
the number in the 3rd register and the number in the 4th''. The 
CPU will adjust the flags according to whether the difference is 
negative or zero or carries or overflows.
  Saying ``if'' The CPU uses the flags when you give a command 
such as, ``If the Negative bit is on, go do the instruction in 
memory location 6''.
                                                 Speed
                             Computers are fast. To describe 
computer speeds, programmers use these words:
Word                               AbbreviationMeaning
millisecond                        msec or msthousandth of a 
second; 10-3 seconds

microsecond                        sec or smillionth of a 
second; 10-6 seconds

nanosecond                         nsec or nsbillionth of a 
second; 10-9 seconds

picosecond                         psec or pstrillionth of a 
second; 10-12 seconds
                             1000 picoseconds is a nanosecond; 
1000 nanoseconds is a microsecond; 1000 microseconds is a 
millisecond; 1000 milliseconds is a second.
                             Earlier, I explained that the 
instruction cycle has five steps:
A.                           Fetch the instruction.
B.                           Fetch additional parts for the 
instruction.
C.                           Update the program counter.
D.                           Decode the instruction.
E.                           Execute the instruction.
The total time to complete the instruction cycle is about a 
microsecond. The exact time depends on the quality of the CPU, 
the quality of the main memory, and the difficulty of the 
instruction, but usually lies between .1 microseconds and 10 
microseconds.
                             Here are 5 ways to make the computer 
act more quickly:
Method                                 Meaning
multiprocessing                        The computer holds more 
                                       than one CPU. (All the 
                                       CPUs work simultaneously. 
                                       They share the same main 
                                       memory. The operating 
                                       system decides which CPU 
                                       works on which program. 
                                       The collection of CPUs is 
                                       called a multiprocessor.)

instruction lookahead                  While the CPU is finishing 
                                       an instruction cycle (by 
                                       doing steps D and E), it 
                                       simultaneously begins 
                                       working on the next 
                                       instruction cycle (steps A 
                                       and B).

array processing                       The CPU holds at least 16 
                                       ALUs. (All the ALUs work 
                                       simultaneously. For 
                                       example, when the control 
                                       unit wants to solve 16 
                                       multiplication problems, 
                                       it sends each problem to a 
                                       separate ALU; the ALUs 
                                       compute the products 
                                       simultaneously. The 
                                       collection of ALUs is 
                                       called an array 
                                       processor.)

parallel functional units              The ALU is divided into 
                                       several functional units: 
                                       an addition unit, a 
                                       multiplication unit, a 
                                       division unit, a shift 
                                       unit, etc. All the units 
                                       work simultaneously; while 
                                       one unit is working on one 
                                       problem, another unit is 
                                       working on another.

pipeline architecture                  The ALU (or each ALU 
                                       functional unit) consists 
                                       of a ``first stage'' and a 
                                       ``second stage''. When the 
                                       control unit sends a 
                                       problem to the ALU, the 
                                       problem enters the first 
                                       stage, then leaves the 
                                       first stage and enters the 
                                       second stage. But while 
                                       the problem is going 
                                       through the second stage, 
                                       a new problem starts going 
                                       through the first stage. 
                                       (Such an ALU is called a 
                                       pipeline processor.)

                                                Parity
                             Most large computers put an extra 
bit at the end of each memory location. For example, a memory 
location in the PDP-10 holds 36 bits, but the PDP-10 puts an 
extra bit at the end, making 37 bits altogether. The extra bit is 
called the parity bit.
                             If the number of ones in the memory 
location is even, the CPU turns the parity bit on. If the number 
of ones in the memory location is odd, the CPU turns the parity 
bit off.
                             For example, if the memory location 
contains these 36 bits ___ 
000000000100010000000110000000000000
there are 4 ones, so the number of ones is even, so the CPU turns 
the parity bit on:
0000000001000100000001100000000000001

              content             parity
If the memory location contains these 36 bits instead ___ 
000000000100010000000100000000000000
there are 3 ones, so the number of ones is odd, so the CPU turns 
the parity bit off:
0000000001000100000001000000000000000

              content             parity

  Whenever the CPU puts data into the main memory, it also puts 
in the parity bit. Whenever the CPU grabs data from the main 
memory, it checks whether the parity bit still matches the 
content.
  If the parity bit doesn't match, the CPU knows there was an 
error, and tries once again to grab the content and the parity 
bit. If the parity bit disagrees with the content again, the CPU 
decides that the memory is broken, refuses to run your program, 
prints a message saying PARITY ERROR, and then sweeps through the 
whole memory, checking the parity bit of every location; if the 
CPU finds another parity error (in your program or anyone 
else's), the CPU shuts off the whole computer.
  Cheap microcomputers (such as the Apple 2c and Commodore 64) 
lack parity bits, but the IBM PC has them.

                       UAL
  Universal Assembly Language (UAL) is a notation I invented that 
makes programming in assembly language easier.
  UAL uses these symbols:
SymbolMeaning
M5    the number in the 5th memory location
R2    the number in the 2nd register
P     the number in the program counter

N     the Negative bit
Z     the Zero bit
C     the Carry bit
V     the oVerflow bit
PRIORITYthe PRIORITY bits
PRIVILEGEthe PRIVILEGE bits
F     the content of the entire flag register

F[5]  the 5th bit in the flag register
R2[5] the 5th bit in R2
R2[LEFT]the left half of R2; in other words, the left half of the 
data in the 2nd register
R2[RIGHT]the right half of R2
M5 M6 long number whose left half is in 5th memory location, 
right half is in 6th location
  Here are the UAL statements:
StatementMeaning
R2=7    Let number in the 2nd register be 7 (by moving 7 into the 
2nd register).
R2=M5   Copy the 5th memory location's contents into the 2nd 
register.
R2= = M5Exchange R2 with M5. (Put 5th location's content into 2nd 
register and vice versa.)

R2=R2+M5Change the integer in 2nd register, by adding to it the 
integer in 5th location.
R2=R2-M5Change the integer in 2nd register, by subtracting the 
integer in 5th location.
R2=R2*M5Change the integer in 2nd register, by multiplying it by 
integer in 5th location.
R2 REM R3=R2/M5 Change R2, by dividing it by the integer M5. Put 
division's remainder into R3.

R2=-M5  Let R2 be the negative of M5.
R2=NOT M5Let R2 be the one's complement of M5.
R2=R2 AND M5Change R2, by performing the AND operation.
R2=R2 OR M5Change R2, by performing the OR operation.
R2=R2 XOR M5Change R2, by performing the XOR operation.

SHIFTL R2Shift left.
SHIFTR R2Shift right.
SHIFTRA R2Shift right arithmetically.
SHIFTR3 R2Shift right, 3 times.
SHIFTR (R7) R2 Shift right, R7 times.
ROTATEL R2Rotate left.
ROTATER R2Rotate right.

TEST R2 Examine number in 2nd register, and adjust flag 
register's Negative and Zero bits.
TEST R2-R4Examine the difference between R2 and R4, and adjust 
the flag register.

CONTINUENo operation. Just continue on to the next instruction.
WAIT    Wait until an interrupt occurs.

IF R2<0, P=7If the number in the 2nd register is negative, put 7 
into the program counter.
IF R2<0, M5=3, P=7 If R2<0, do both of the following: let M5 be 
3, and P be 7.
  M5 can be written as M(5) or M(2+3). It can be written as 
M(R7), if R7 is 5 ___ in other words, if register 7 contains 5.

                Addressing modes
  Suppose you want the 2nd register to contain the number 6. You 
can accomplish that goal in one step, like this:
R2=6
Or you can accomplish it in two steps, like this:
M5=6
R2=M5
Or you can accomplish it in three steps, like this:
M5=6
M3=5
R2=M(M3)
Or you can accomplish it in an even weirder way:
M5=6
R3=1
R2=M(4+R3)
                                                     Each of 
those methods has a name. The first method (R2=6), which is the 
simplest, is called immediate addressing. The second method 
(R2=M5), which contains the letter M, is called direct 
addressing. The third method (R5=M(M3)), which contains the 
letter M twice, is called indirect addressing. The fourth method 
(R5=M(4+R3)), which contains the letter M and a plus sign, is 
called indexed addressing.
                                                     In each 
method, the 2nd register is the destination. In the last three 
methods, the 5th memory location is the source. In the fourth 
method, which involves R3, the 3rd register is called the index 
register, and R3 itself is called the index.
                                                     Each of 
those methods is called an addressing mode. So you've seen four 
addressing modes: immediate, direct, indirect, and indexed.
                                                     Program 
counter To handle the program counter, the computer uses other 
addressing modes instead.
                                                     For example, 
suppose P (the number in the program counter) is 2073, and you 
want to change it to 2077. You can accomplish that goal simply, 
like this:
P=2077
Or you can accomplish it in a weirder way, like this:
P=P+4
Or you can accomplish it in an even weirder way, like this:
R3=20
P=R3 77
                                                     The first 
method (P=2077), which is the simplest, is called absolute 
addressing.
                                                     The second 
method (P=P+4), which involves addition, is called relative 
addressing. The ``+4'' is the offset.
                                                     The third 
method (P=R3 77) is called base-page addressing. R3 (which is 20) 
is called the page number or segment number, and so the 3rd 
register is called the page register or segment register.

            8088 DETAILS
  The first microprocessor (CPU on a chip) was invented by Intel 
in 1971 and called the Intel 4004. Its accumulator was so short 
that it held just 4 bits! Later that year, Intel invented an 
improvement called the Intel 8008, whose accumulator held 8 bits. 
In 1973 Intel invented a further improvement, called the Intel 
8080, which understood more op codes, contained more registers, 
handled more RAM (64K instead of 16K), and ran faster. Drunk on 
the glories of that 8080, Microsoft adopted the phone number 
VAT-8080, and the Boston Computer Society adopted the soberer 
phone number DOS-8080.
  In 1978 Intel invented a further improvement, called the 8086, 
which had a 16-bit accumulator and handled even more RAM & ROM 
(totalling 1 megabyte). Out of the 8086 came 16 wires (called the 
data bus), which transmitted 16 bits simultaneously from the 
accumulator to other computerized devices, such as RAM and disks. 
Since the 8086 had a 16-bit accumulator and 16-bit data bus, 
Intel called it a 16-bit CPU.
  But computerists complained that the 8086 was impractical, 
since nobody had developed RAM, disks, or other devices for the 
16-bit data bus yet. So in 1979 Intel invented the 8088, which 
understands the same machine language as the 8086 but has an 
8-bit data bus. To transmit 16-bit data through the 8-bit bus, 
the 8088 sends 8 of the bits first, then sends the other 8 bits 
shortly afterwards. That technique of using a few wires (8) to 
imitate many (16) is called multiplexing.
  When 16-bit data buses later became popular, Intel invented a 
slightly souped-up 8086, called the 80286 (nicknamed the 286).
  Then Intel invented a 32-bit version called the 80386 
(nicknamed 386). Intel has also invented a multiplexed version 
called the 386SX, which understands the same machine language as 
the 386 but transmits 32-bit data through a 16-bit bus by sending 
16 of the bits first and then sending the other 16. The letters 
``SX'' mean ``SiXteen-bit bus''. The original 386, which has a 
32-bit bus, is called the 386DX; the letters ``DX'' mean ``Double 
the siXteen-bit bus''.
  Then Intel invented a slightly souped-up 80386DX, called the 
80486 (nicknamed 486). It comes in two versions: the fancy 
version (called the 486DX) includes a math coprocessor, which is 
circuitry that understands commands about advanced math; the 
stripped-down version (called the 486SX) lacks a math 
coprocessor.
  Here's how to use the 8088 and 8086. (The 286, 386, and 486 
include the same features plus more.)
                                                     Registers
                                         The CPU contains 
fourteen 16-bit registers: the accumulator (AX), base register 
(BX), count register (CX), data register (DX), stack pointer 
(which UAL calls S but Intel calls SP), base pointer (BP), source 
index (SI), destination index (DI), program counter (which UAL 
calls P but Intel calls the instruction pointer or IP), flag 
register (which UAL calls F), code segment (CS), data segment 
(DS), stack segment (SS), and extra segment (ES).
                                         In each of those 
registers, the sixteen bits are numbered from right to left, so 
the rightmost bit is called bit 0 and the leftmost bit is called 
bit fifteen.
                                         The AX register's 
low-numbered half (bits 0 through 7) is called A low (or AL). The 
AX register's high half (bits 8 through fifteen) is called A high 
(AH).
                                         In the flag register, 
bit 0 is the carry flag (which UAL calls C), bit 2 is for parity, 
bit 6 is the zero flag (Z), bit 7 is the negative flag (which UAL 
calls N but Intel calls sign or S), bit eleven is the overflow 
flag (V), bits 4, 8, 9, and ten are special (auxiliary carry, 
trap, interrupts, and direction), and the remaining bits are 
unused.

                                                 Memory locations
                                         Each memory location 
contains a byte. In UAL, the 6th memory location is called M6 or 
M(6). The pair of bytes M7 M6 is called memory word 6, which UAL 
writes as MW(6).

                                                  Instruction set
                                         The next page shows the 
set of instructions that the 8088 understands. For each 
instruction, I've given the assembly-language mnemonic and its 
translation to UAL, where all numbers are hexadecimal.
                                         The first line says that 
INC (which stands for INCrement) is the assembly-language 
mnemonic that means x=x+1. For example, INC AL means AL=AL+1.
                                         The eighth line says 
that IMUL (which stands for Integer Multiply) is the 
assembly-language mnemonic that means x=x*y. For example, IMUL 
AX,BX means AX=AX*BX.
                                         In most equations, you 
can replace the x and y by registers, half-registers, memory 
locations, numbers, or more exotic entities. To find out what you 
can replace x and y by, experiment!
                                         For more details, read 
the manuals from Intel and Microsoft. They also explain how to 
modify an instruction's behavior by using flags, segment 
registers, other registers, and three prefixes: REPeat, SEGment, 
and LOCK.
Math
INCrement   x=x+1
DECrement   x=x-1

ADD         x=x+y
ADd Carry   x=x+y+C

SUBtract    x=x-y
SuBtract Borrowx=x-y-C

MULtiply    x=x*y UNSIGNED
Integer MULtiplyx=x*y

DIVide      AX=AX/x UNSIGNED
Integer DIVideAX=AX/x

NEGate      x=-x

Decimal Adjust AddIF AL[RIGHT]>9, AL=AL+6
            IF AL[LEFT]>9, AL=AL+60
Decimal Adjust SubtrIF AL[RIGHT]>9, AL=AL-6
            IF AL[LEFT]>9, AL=AL-60

Ascii Adjust AddIF AL[RIGHT]>9, AL=AL+6, AH=AH+1
            AL[LEFT]=0
Ascii Adjust SubtractIF AL[RIGHT]>9, AL=AL-6, AH=AH-1 AL[LEFT]=0
Ascii Adjust MultiplyAH REM AL=AL/0A
Ascii Adjust DivideAL=AL+(0A*AH)
            AH=0

Logic
AND         x=x AND y
OR          x=x OR y
XOR         x=x XOR y
CoMplement CarryC=NOT C

SHift Left  SHIFTL(y) x
SHift Right SHIFTR(y) x
Shift Arithmetic RightSHIFTRA(y) x

ROtate Left ROTATEL(y) x
ROtate RightROTATER(y) x

Rotate Carry LeftROTATEL(y) C x
Rotate Carry RightROTATER(y) C x

CLear Carry C=0
CLear DirectionDIRECTION=0
CLear InterruptsINTERRUPTS=0

SeT Carry   C=1
SeT DirectionDIRECTION=1
SeT InterruptsINTERRUPTS=1

TEST        TEST x AND y
CoMPare     TEST x-y

SCAn String ByteTEST AL-M(DI); DI=DI+1-(2*DIRECTION)
SCAn String WordTEST AX-MW(DI); DI=DI+2-(4*DIRECTION)

CoMPare String ByteTEST M(SI)-M(DI)
            SI=SI+1-(2*DIRECTION)
            DI=DI+1-(2*DIRECTION)
CoMPare String WordTEST MW(SI)-MW(DI)
            SI=SI+2-(4*DIRECTION)
            DI=DI+2-(4*DIRECTION)
Moving bytes
MOVe                                               x=y

Load AH from F                                     AH=F[RIGHT]
Store AH to F                                      F[RIGHT]=AH

Load register and DS                               x=MW(y); 
DS=MW(y+2)
Load register and ES                               x=MW(y); 
ES=MW(y+2)

LOaD String Byte                                   AL=M(SI); 
SI=SI+1-(2*DIRECTION)
LOaD String Word                                   AX=MW(SI); 
SI=SI+2-(4*DIRECTION)

STOre String Byte                                  M(DI)=AL; 
DI=DI+1-(2*DIRECTION)
STOre String Word                                  MW(DI)=AX; 
DI=DI+2-(4*DIRECTION)

MOVe String Byte                                   M(DI)=M(SI);
                                                   DI=DI+1-(2*DIR
ECTION)
                                                   SI=SI+1-(2*DIR
ECTION)
MOVe String Word                                   MW(DI)=MW(SI)
                                                   DI=DI+2-(4*DIR
ECTION)
                                                   SI=SI+2-(4*DIR
ECTION)

Convert Byte to Word                               AH=-AL[7]
Convert Word to Dbl                                DX=-AX[0F]

PUSH                                               S=S-2; MW(S)=x
PUSH F                                             S=S-2; MW(S)=F

POP                                                x=MW(S); S=S+2
POP F                                              F=MW(S); S=S+2

IN                                                 x=PORT(y)
OUT                                                PORT(x)=y
ESCape                                             BUS=x

eXCHanGe                                           x= =y
XLATe                                              AL=M(BX+AL)
Load Effective Address                             x=ADDRESS(y)

Program counter
JuMP                                               P=x

Jump if Zero                                       IF Z=1, P=x
Jump if Not Zero                                   IF Z=0, P=x

Jump if Sign                                       IF N=1, P=x
Jump if No Sign                                    IF N=0, P=x

Jump if Overflow                                   IF V=1, P=x
Jump if Not Overflow                               IF V=0, P=x

Jump if Parity                                     IF PARITY=1, 
P=x
Jump if No Parity                                  IF PARITY=0, 
P=x

Jump if Below                                      IF C=1, P=x
Jump if Above or Eq                                IF C=0, P=x
Jump if Below or Eq                                IF C=1 OR Z=1, 
P=x
Jump if Above                                      IF C=0 AND 
Z=0, P=x

Jump if Greater or Eq                              IF N=V, P=x
Jump if Less                                       IF N<>V, P=x
Jump if Greater                                    IF N=V AND 
Z=0, P=x
Jump if Less or Equal                              IF N<>V OR 
Z=1, P=x

Jump if CX Zero                                    IF CX=0, P=x

LOOP                                               CX=CX-1; IF 
CX<>0, P=x
LOOP if Zero                                       CX=CX-1; IF 
CX<>0 AND Z=1, P=x
LOOP if Not Zero                                   CX=CX-1; IF 
CX<>0 AND Z=0, P=x

CALL                                               S=S-2; 
MW(S)=P; P=x
RETurn                                             P=MW(S); S=S+2

INTerrupt                                          S=S-6; 
MW(S)=P; MW(S+2)=CS; MW(S+4)=F P=MW(4*x); CS=MW(4*x+2)
                                                   INTERRUPTS=0; 
TRAP=0
INTerrupt if Overflow                              IF V=1, S=S-6, 
MW(S)=P, MW(S+2)=CS,
                                                   MW(S+4)=F, 
P=MW(10), CS=MW(12),
                                                   INTERRUPTS=0, 
TRAP=0
Interrupt RETurn                                   P=MW(S); 
CS=MW(S+2); F=MW(S+4); S=S+6

No OPeration                                       CONTINUE
HaLT                                               WAIT
WAIT                                               WAIT FOR 
COPROCESSOR
