Documenti di Didattica
Documenti di Professioni
Documenti di Cultura
QRTHE
THIRD EDITION
Harness the power of the
microprocessor
Build real-world
Disk Inside
80x86
"
.^
'"
programs, including a
to
your
C and
programs
Disk includes
examples
in
all
the
protected-mode and
code
book
plus
in
the
C-I--H
C and
programs
Windows programming
Master advanced techniques such as step-
Assembly
Language
for the
PC,
Third Edition
John Socha
and
Peter Norton
Brady Publishing
New
York
London
Toronto
Sydney
Tokyo
Singapore
Copyright
whole or
in part in
any form.
Brady Publishing
A Division of Prentice
1
Columbus
Hall
Computer Publishing
Circle
New York, NY
10023
ISBN: 1-56686-016-4
Library of Congress Catalog No.: 92-44830
The rightmost
number
Printing Code:
rightmost single-digit
first
double-digit
is
the
printing of the
4 3
95 94 93
Manufactured
in the
Limits of Liability and Disclaimer of Warranty: The author and publisher of this book
have used their best efforts in preparing
efforts include the
this
in
it.
These
publisher
kind,
expressed or implied, with regard to these programs or the documentation contained in this
book.
tial
damages
in
of,
these programs.
The
registered
magazine Sofialk
in
in the
program
first
John concentrated on
as
to find files
ScrnSave (the
on hard
first
disks). After
and
The Norton Commander, which became a best-selling software product. He is also the coauthor of the best-selling book PC-World DOS 5 Complete Handbook and the author of Learn Programming znd Visual Basic 2 with
writing
En-
Ap-
plied Physics
utility
software in
Kirkland, Washington.
first
is
IBM
PC, was published in 1 983, and was followed later in the year by another Brady
book, his immensely popular guide to
Born
in
1943 and
raised in Seattle,
DOS.
Army and
War
he
He received a priestly teaching certificate after studying for five years in a Zen
Buddhist monastery. Mr. Norton held a variety of positions in the computer
industry before he created the
Norton
Utilities soft^vare
own company,
Peter
program
in 1982.
Norton Computing,
last
He
Inc., to
many
to the
Angeles
and
area.
their
Los
Credits
Publisher
Michael Violano
Managing Editor
Kelly D.
Dobbs
Editor
Tracy Smith
Production Editors
Bettina Versaci
Tom Dilbn
Developmental Editor
Perry King
Editorial Assistant
Lisa Rose
Book Designer
Michele Laseau
Cover Designer
HUB Graphics
Production
Team
Katy Bodenmiller
Christine
Cook
Lisa Daugherty
Carta Hall-Batton
Howard Jones
John Kane
Loren Christopher Malloy
Sean Medlock
Tim Montgomery
Roger Morgan
Linda Quigley
Michelle Self
Susan Shepard
Angie Trzepacz
Contents
Introduction
Part
1
xv
Machine Language
Way
Using Debug
Hex Numbers
12
Five-Digit
13
15
Bits, Bytes,
Two's Complement
^An
Odd
Sort of Negative
Summary
2
Using Registers
Using
Memory
the 80x86
Negative
Number
19
24
25
as Variables
in the
80x86
17
21
Topics Covered
80x86
Numbers
27
30
32
Style
in the
26
80x86
33
34
35
Summary
38
Printing Characters
Topics Covered
40
41
INT
42
Exiting
44
Assembly Language
for the
^A
Two-Line Program
Entering Programs
46
47
Registers
50
Summary
52
54
Topics Covered
Rotating
55
Numbers through
Repeating
to a
Number
59
Number
61
Command
63
Summary
Printing
63
Numbers
in
Hex
67
Comparing Numbers
68
Using
Using Rotate
Using
Bits
68
Conditional Jumps
Printing a Single
Hex Digit
To Get the Upper Nibble
Putting
It
All Together
Summary
Reading Characters
Reading
70
70
71
73
75
77
11
Topics Covered
One
Character
Number
Two-Digit Hex Number
80
81
82
83
Reading a
84
Summary
7 Using Procedures to Write Reusable Code
VI
66
Topics Covered
56
58
a Block of Code
45
85
86
Topics Covered
87
Writing Procedures
88
Contents
Part
II
Return Addresses
91
Class
Assembly Language
Welcome
to the Assembler
101
Debug
Writestr in
106
Debug
Using Comments
for
109
1 1
11
108
108
Code
Summary
10
102
105
Using Labels
96
100
at
94
99
Topics Covered
Looking
90
114
Topics Covered
115
116
A Program Skeleton
123
Summary
124
118
122
126
Printing in Decimal
Topics Covered
127
128
131
135
138
Segments
Topics Covered
How Memory Is
133
139
The Stack
The Program Segment
140
144
Prefix (PSP)
146
Vll
Assembly Language
for the
DOSSEG Directive
NEAR and FAR CALLs
The
More on
12
13
the
INT
147
149
152
Instruction
Interrupt Vectors
153
Summary
154
Course Corrections
How
to Build
Dskpatch
Topics Covered
157
158
The Game
Summary
161
162
Modular Design
Building Programs
in Pieces
165
Separate Assembling
166
170
174
Program
176
List
177
PWB
178
Jump
179
to Definitions
181
List
Summary
181
Dumping Memory
184
Topics Covered
185
to Access
Memory
186
189
Base-Relative Addressing
191
Setting
DS
to Point to
Adding Characters
Dumping 256
Summary
Vlll
175
BuildingTEST.EXE
Editing Files in
15
164
Topics Covered
Setting the
14
156
to the
Dump
Bytes of Memory
193
194
197
202
204
Topics Covered
205
Making
206
Life Easier
Contents
Format of the
16
NMake
207
File
Patching up Disp_sec
208
Reading a Sector
210
The .DATA?
Summary
215
Directive
216
219
220
Adding Addresses
222
to the Display
227
Adding Numbers
232
to the Display
Summary
Part
III
17
234
ROM BIOS
The
239
240
244
Moving
246
the Cursor
248
'.
Summary
252
256
258
Topics Covered
259
A New WRITE_CHAR
260
Clearing to the
End of a Line
Summary
19
237
238
Topics Covered
18
218
The Dispatcher
264
267
268
Topics Covered
269
Building a Dispatcher
270
277
281
IX
Assembly Language
20
for the
A Programming Challenge
282
Topics Covered
283
284
Simple Editing
21
286
288
289
290
296
Summary
297
300
Topics Covered
301
Moving
302
the
Phantom Cursors
Simple Editing
306
Summary
310
312
Topics Covered
313
Hex Input
314
Decimal Input
323
Summary
327
328
Topics Covered
329
A New READ_STRING
330
337
342
Summary
25
Dskpatch
Topics Covered
22 Simple Editing
23
285
to
In Search of Bugs
344
Topics Covered
345
Fixing
DISPATCHER
Summary
346
348
350
Topics Covered
351
352
Contents
Down
Tracking
354
355
Bugs
358
360
CodeView
Turbo Debugger
Microsoft's
361
Borland's
365
Summary
369
370
Topics Covered
371
Scrolling
by Haifa Sector
372
Summary
Part IV
375
377
Advanced Topics
28 Relocation
378
Topics Covered
Writing
379
COM Programs
380
380
Relocation
381
386
ASSUME
390
Topics Covered
391
Segment Override
392
Another Look
at
ASSUME
394
Summary
30
AVeryFastWRITE_CHAR
396
Topics Covered
397
398
31
395
Memory
400
403
Summary
411
C and C++
Programs
412
Topics Covered
413
414
XI
Assembly Language
for the
Using Clear_screen
One
Passing
in
C++
418
420
Parameter
426
428
Memory Models
429
432
436
Using Other
Writing
432
in
Assembly
441
Summary on
443
In-Line Assembly
444
DISKLITE,
RAM-Resident Program
446
Topics Covered
447
RAM-Resident Programs
448
Intercepting Interrupts
448
Disklite
450
Is
Protected
458
459
460
Topics Covered
What
Mode?
460
Memory
461
463
Addressing Extended
Working
in
Windows
Validating Pointers,
Determining the
The
465
Pan
Size of
Segments
465
467
471
32-Bit Registers
Validating Pointers,
Pan
II
472
478
Simimar)^
480
Topics Covered
481
482
DOS
XII
440
Summary^
32
439
and
483
Contents
RAM
Resident Programs
Advanced
DOS
Programming
483
484
Windows Programming
484
Software Design
485
Other References
485
Guide
to the
Disk
486
Topics Covered
487
Chapter Examples
488
489
DISKLITE Program
Windows Code
C/C++ Libraries
492
Listing of Dskpatch
494
492
492
Topics Covered
495
Descriptions of Procedures
496
CURSOR.ASM
496
DISK_IO.ASM
496
DISPATCH.ASM
497
DISP_SEC.ASM
497
DSKPATCH.ASM
EDITOR.ASM
498
KBD_IO.ASM
498
PHANTOM.ASM
499
VIDEO_IO.ASM
500
Dskpatch Make
Program
501
File
Dskpatch Linkinfo
File
Listings for
498
Dskpatch Procedures
502
503
CURSOR.ASM
503
DISK_IO.ASM
507
DISPATCH.ASM
510
DISP_SEC.ASM
512
DSKPATCH.ASM
EDITOR.ASM
KBD_IO.ASM
519
PHANTOM.ASM
531
VIDEO IO.ASM
537
520
522
Xlll
Assembly Language
for the
C C/C++
Libraries in
Assembly
Topics Covered
547
Descriptions of Procedures
548
SOCHALIBJNC
548
MAKEFILE
CURSOR.ASM
FASTWRIT.ASM
548
HARDWARE.ASM
551
KBD_IO.ASM
551
MOUSE.ASM
552
548
549
Makefile
553
SOCHALIBJNC
CURSOR.ASM
554
FASTWRIT.ASM
561
HARDWARE.ASM
577
KBD_IO.ASM
580
MOUSE.ASM
584
555
592
Miscellaneous Tables
Topics Covered
593
594
598
598
INT lOh
D-6 INT I6h
D-7 INT 21h
599
Table D-5
Functions
600
Table
Functions
603
Functions
604
Table
Index
XIV
546
606
609
Introduction
Why Learn Assembly Language?
There are now more reasons than ever
to learn
like
C/C++
When we wrote
the
first
release
programs
in
programmers
assembly language.
guage. These days, very few programs are written entirely in assembly language.
on
to
C++, which
guage. So
in C,
is
if people are
are
moving
programming
lan-
to learn
will
make you
never actually write any assembly-language subroutines or code for your pro-
grams.
Many of the
idiosyncrasies
you
will find in
-32,768
to 32,767,
and you
all
artifacts
why an
design.
When
It
you
learn
of computer languages
PC compatible computer.
takes
you
common denominator.
level
will see
its
or Pascal programs
clear to you.
C/C++
closer to the
is
the low-
as
you will
see in
is
world of
mode and Windows programming. You will learn about some features of
Windows programming that you probably won't find in any other book. This
is
because there are programming techniques that you can do and learn about
language.
Assembly Language
for the
common
is
C/C++ and
fast;
is
Windows
programs.
The most
Computers, modern
for speed.
But there are times when even compiled C/C++ or Pascal code won't be
enough. Very often
in these cases
a small
fast
amount of assembly-
first
edition of
book. Years ago you had to use an assembler, such as Microsoft's Macro
all
compilers these days support in-line assembly, which allows you to add a few
lines
lines
of
much easier to use small amounts of assembly language in your programs. You will learn how to use in-line assembly
C/C++
in
it
Chapter 31.
There are
to write larger
Windows,
you
will
amounts
DOS
or
Windows NT),
Driver (also
The Approach
We Use
will
By
go
the time
you
you
will
know how
to write large
XVI
make
their
work
simpler.
Introduction
work
out of writing complex programs. If you have ever had that sinking, where-
you
do-I-start feeling,
We will
to write programs. It
also try to
is
also fiin!
show you how comments can help you write better procomments explain why you. are doing something, rather
grams. Well-written
code
is
doing, but
This book
is
not
it
all
certainly
theory.
may not
be clear
will find
it
Dskpatch
is
it
why
work
you
will see
in a real
one
that you
can continue to use both in whole and in part long after you have finished
with
this
book.
Book
Organization of This
you up
details.
With
approach you
this
instructions before
you have
will
to write small
programs in
lot
The
be able to learn a
DOS because
We have also
it is
a lot easier
concepts and techniques you learn will also apply to programs you write
in other operating
is
environments, so
and
II,
if you
want
to
program
for
Windows, you
know
Whether
of interest to you.
XVll
Assembly Language
Part
for the
focuses
on
the
bits, bytes,
of real examples that use a program called Debug, which comes with
Debug
your
will allow us to
PC
of
as
it
runs
DOS.
DOS.
Part
how
to
computer.
Part
II,
how
to
than cover
assembler
We will
then
move on
in order for
programs.
clear
all
commands needed
you
to learn
how
Part
I,
and
We will also cover techniques like modtilar design that help in writing
III,
and
in PCs.
to 28,
we
will concentrate
on using
we will
larger than a
them
Pan IV covers a number of advanced topics that will be of interest to you when
you Stan to write real programs. The first two chapters cover details about COM
programs, memory, and segments. Then there is a chapter on writing directly
to screen memory for very fast screen displays. Next, there is a chapter on writing
assembly-language procedures that you can use in your C/C++ programs. You
will learn
for
There
is
Next is
a lot
a chapter
DISKLITE
XVlll
of material in
is
program
called
that adds a disk light to your screen. Finally, you will find a
Introduction
some
interesting details
microprocessor.
What
Is
on the Disk?
book
this
in a directory called
CHAPS. We
ADVANCED. Appendix A
Appendix B contains
for
C and C++
The
book. Appendix
in this
set
programs that
of libraries for
you'll find
on the disk
is
who
at the
also
we used
to write the
means
is
It
by hundreds of
listings
are a
all
gram
as the
will
that
I,
Edit program in
DOS
in this book.
II
5 or later,
as Microsoft's
TASM
XIX
Assembly Language
Finally, to
QuickC
for the
for
or Microsoft
Windows
programs.
Dskpatch
In our
displaying characters
tion.
Dskpatch
these characters
is
and numbers
how
You will
DOS
get
file
XX
where
useful
and
it
in
hexadecimal nota-
will allow us to
change
could,
so
is
good way
just
to
a disk.
book an introduction
also a source
in a disk sector.
stores information
will
of usefiil subroutines.
this
it is
Machine Language
lA
P^
'8A
"
76
4C
ye
|c^
|3F
68
|96
|c1h|a|p|t|e|rj
Debug
and Computer
Learning
Arithmetic
In
this
This
is
nificant impact
on
all
programs you
will write,
arithmetic.
It
has a sig-
Topics Covered
A
Way
Two's Complement
Assembly Language
In
this
for the
chapter you will start working with the microprocessor inside your
You
computer arithmetic.
of almost
will use a
It is
to start
good
Debug
called
assembly-language programs.
all
all
Debug
program
com-
working with
is
at the heart
programs.
PC compatible computers:
Pentium).
is
is
The 8088
microprocessor was
first
80486 microprowill
be called the
IBM PC and
the slowest, least powerful microprocessor. Very few computers are built with
the
8088 microprocessor.
first
in the
is
and
mum microprocessor required to run Windows 3.1. Most computers are currendy built around the
faster
Windows
can use.
8088 microprocessor
Windows,
DOS
for the
computers. In
this
book we
microprocessor, which
for
8088
will
will
run on any of
run on
all
MS-
work on
MS-DOS
tions so the
programs you
However,
book you will find some coverage of Windows prothe protected mode of xhe 80286 and better microprocessors, which
gramming in
is
all
computers.
later in the
80x86 microprocessors.
as
used in PCs,
Way
For your
first
all,
you count
by starting
to II
at
one
1,2,3,4,5,6,7,8,9,10,
11.
on
00, 101.
The numbers
10, 11,
00,
more
it
counts to
and so on
digits,
are binary
and
0, instead
numbers, based
of the ten asso-
number we know
1,10,
number 10
as two.
We are interested in binary numbers because they are the form in which numbers are used
ers thrive
cumbersome
to write out.
The
strings
solution? Hexadecimal
you
this chapter,
how
to the chapter
how
bits, bytes,
numbers
you will
a far
more
learn both
ways
computers count,
and words.
bits, bytes,
If
you
and words,
summary.
Counting with
Hexadecimal Numbers
Since hexadecimal numbers are easier to handle than binary numbers
least in
terms of length
will begin
at
DEBUG.COM, a program included with DOS. You will use Debug here
use
and
is
instruc-
we
it
doesn't
mal, you will need to learn something about hex numbers. But
a short side trip
little
about
Debug
itself.
first, let's
take
Assembly Language
for the
Using Debug
Why does this program carry the name Debug? Bugs, in the computer world,
are mistakes in a program. A working program has no bugs, while a nonworking or "limping" program has at least one bug.
how
is
known
at a
as debugging,
Debug.
According to computer
of computing
failed.
folklore, the
in particular, a
After a long search, technicians found the source of their troubles: a small
moth caught between the contacts of a relay. The technicians removed the moth
and wrote a note in the log book about "debugging" the Mark I.
1%
From
here on, in interactive sessions like this one, the text you type will
it
from your
as follows:
c>HTTTH
Type
(DEBUG
and
you should see a response similar to the ones we show in these sessions.
You won't always see exactly the same responses because your computer
probably has a different amount of memory from the computer on which
we wrote this book. (We will begin to encounter such differences in the
next chapter.) In addition, notice that we use uppercase letters in all examples. This
1
(el)
Now, with
DOS
C>Qj|g||fi
lowercase
the
is
all
letter
examples in
letters.
prompt (which
is
C>
after
To
leave
C>
is
see in response to
a
DOS
Debug and
prompt and
prompt.
command
means Debug
DOS,
return to
press Enter.
your
It
if
waiting for a
Q (for
just type
is
is
you
command.
Quit) at the
hyphen
like,
to
Debug.
C>DEBUG
numbers.
by
name suggests,
it
starting with 2 + 3.
H works
We know
is
are
still
in
Debug
Is this
text:
-H 3 2
0005
0001
Debug prints both the sum (0005) and the difference (0001) of 3 and 2. The
Hexarithmetic command, shown in Figure 1-1, always calculates the sum and
difference of
two numbers,
2).
as
it
did here. So
the
is
sum of 3
far,
+ 2 in decimal, and
1 is
same
for
the differ-
surprises.
you
as
it
may look,
however,
it
FFFF
is
get
number. In
fact,
it is
for
2-3.
Strange
-H 2 3
0005
FFFF
shortly.
how an F
But first,
let's
explore the
Assembly Language
for the
Number A
Number B
-H 3D5C 2A10
676C 134C
A+B
A-B
To
see
try nine
plus one,
-H 9
000A
0008
we
try for
is
the hex
number for
ten.
Now, what
as 15?
H 9 6
000F
0003
gether
The
digits
(6),
F), see
Figure 1-2.
digits alto-
The name
when combined,
through 15.
see that
256
different
also bears
some
digits.
Decimal
Hex
digit
2
3
4
5
6
7
8
2
3
These
same
5
6
7
8
9
and hex.
9
10
are the
both decimal
digits
for
A
B
C
D
11
12
13
14
15
These
digits
hexadecimal
new
are
digits.
E
F
far,
single-digit
hex numbers.
Now,
these
let's
see
numbers
how you
to decimal
numbers.
Just as with decimal numbers,
adding more
digits
on the
left.
10
(ten).
10
in
hex
is
after
16 and 10
is
result
is
a two-digit
num-
hex
again.
really 16,
The
9.
number,
Os apart
that
lOh
is
the
hexadecimal for
decimal ten.
Now let's look at how to convert numbers between hex and decimal. You know
that
lOh
is
16,
but
how do you
how is
the decimal
number 1 73 convened
to hex?
D3h from
D3h,
lOh? Or,
Assembly Language
for the
You cannot
rely
on Debug
Chapter 10,
we
will write a
program
it
cannot speak
in decimal. In
to convert a
notation so that our programs can talk to us in decimal. But right now,
will
familiar
we
tens,
and
six ones.
276 means
as fol-
lows:
7
6
100 =
200
10 =
70
276
276
and there
are 16
hex
D3h
mentioned
digits, versus
earlier.
-^ 13
16 =
3^3*1=
D3h
is
D3h
is
thirteen sixteens
211
by 1000, 100,
digits
10,
and
by 16 and
1.
Which
digits
1.
by 100,
You would
10,
10
as follows:
10'
1000
10'
100
10'
10
10"
and
1;
for the
four hex digits? For decimal, the numbers 1000, 100, 10, and
of 10,
use
as follows:
digits
Can we
208
mal
10 for decimal, so
digits.
Of course.
are
all
powers
You can
use the
numbers
4096
16'
256
16'
16
16"
A
C
for
hex
Learning
digits,
in-
are as follows:
-^10
-^12
*
*
8-^8*
3AC8h
more examples.)
4096 = 12288
256
2560
16
192
15048
3AC8h
12
7Ch
F
9
^
F
*
*
10
15
12
AFlCh
-*
-
768
1,017
4,096
256
16
1
=
=
=
=
40,960
3,840
16
12
44,828
11
65,536
4,096
256
13
16
2^2*
3B8D2h
16 = 240
256
1^1*
^
-*
124
15
3F9h
16 = 112
1 =
12
-^
-^
-*
Figure 1-3:
to decimal
=
=
=
=
=
196,608
45,056
2,048
208
2
243,922
11
Assembly Language
for the
digit.
For
this,
we will
use
that have
more
as follows:
H 3A7 1ED
0594
01BA
lEDh =
594h.
if you
wish)
calculations directly in
hex.
Five-Digit
So
far,
hex math
Hex Numbers
is
quite straightforward.
as follows (See
Figure
more examples):
-H 5C3Fe 4BC6
"
Error
11
F451
+ CB03
1BF54
3A7
92A
CDl
C
+
19
11
1111
BCD8
+ FAE9
1B7C1
Figure 1-4:
That
here?
is
12
BCD8
0509
ClEl
Hexarithmetic
enough
an unexpected response.
The
to hold four
hex
digits,
no more.
You
will learn
Thus,
digits.
if you try to
you get
in a
Learning
as
answer.
-H ceee oeee
F000
9000
Converting Decimal to
you have only seen
So
far
at
how
Hex
the conversion
to convert decimal
numbers
from hex
to hex.
earlier, in
will write
to decimal.
As mentioned
Chapter
decimal
as
num-
you
by
start
recalling a bit
will begin
by
of grade school
math.
When you
first
mainder of
learned division,
to get
when you
4 with a
numbers
re-
to hex.
493, by 10?
493
10
49
49 remainder 3
4/10
remainder
remainder
4 9 3
The
digits
of 493 appear
as the
(3).
a hex-to-decimal conversion
was
to replace
that
that
all
you needed
is,
starting
for
is
can divide by
6,
13
Assembly Language
for the
493
16 = 30 remainder 13 (Dh)
30
16 =
1/16
remainder 14 (Eh)
remainder
(1 h)
4 9 3
lEDh
16,
to
is
E D
it.
final
to
16 = 66
Remainder
13
66
16 =
Remainder
16 =
Remainder
1069
all
there
hex conversions.
f
4
T t t
2 D h
1069
57,109
16 = 3,569
Remainder
i
3,569
16 =
223
Remainder
Remainder
15
Remainder
13
'
;
223
16 =
16
13
^
13
57,109
Figure 1-5:
14
t t T t
D F 1 5 h
is
you
recall,
there
FFFFh
said that
How can
65535.
if
5-1 =
4. Is that
that be?
Well,
and you
is
is still
Does
it
(alias
behave
-1) to
FFFFh
as a negative
to decimal,
we
We
get
number?
5,
-H 5 FFFF
0006
0004
Debug
seems to treat
programs we
When
one
FFFFh
will write.
To
as -1.
see
why
not,
let's
to the next
column,
do
this
as
-1 in
addition by hand.
as follows:
9 5
The
isn't
to
gives 2,
as follows:
F h
3 h
1
2 h
5 to
FFFFh.
15
Assembly Language
for the
1111
h
F F F F h
4 h
Since
Fh
Strange as
seems,
it
FFFFh
behaves
as
only the
last
is
namely,
4.
this overflow. It
is
overflow an error, or
Is this
move
is
and
yes.
You can
choose either answer. Don't the answers contradict each other? Not
really,
as
happens to be the
case
FFFFh
four-digit
answer
is
is
largest
called an
wwz^^^^ number.
is
a positive
number, and
it
to
all
is
an
error.
On the other hand, you can treat FFFFh as a negative number, as Debug did
when you used
1
as
long
as
the
to
add FFFFh
FFFFh
all
flow
not an error.
is
H command
behave
as negative
numbers. For
fact,
the
to 5.
FFFFh behaves
as
The 80x86 microprocessor can view numbers either as unsigned or signed; the
choice is yours. There are slightly different instructions for each, and we will
explore these differences in later chapters as we begin to use numbers on the
80x86. Right now, before you can learn to actually write the negative
3C8h, we need
to
16
unmask the
bit
and
see
how it fits
into the
of, say,
scheme of bytes,
Words,
and Binary Notation
Bits, Bytes,
It is
dumb.
When Debug
internal
rather
is
prints a
It
number
in hex,
it
time
The 80x86
knows only
number it uses must be formed from a long
binary (base 2) number system.
power,
all its
PC
the
two
microprocessor, with
to write binary
numbers
in
and
Is.
program
program
and
digits
string of Os
uses a small
about
to learn
5,
1,
This
is
the
to convert
we
we need
first
so any
will build
its
such
to learn
themselves.
by the number's
base, 2:
Powers of 2:
2' = 8
2^
= 4
2'
= 2
2"=1
So
that:
*8
OM
*2
* 1
11
1011b
Likewise,
1 1 1
or
lb
is
Bh
Fh, or 15.
write, while
16 hex
digits, so
1 1 1
lb
0000b
different
is
is
numbers
(see
17
Assembly Language
for the
Binary
Decimal
IHexadeclmal
0000
0001
0010
2
3
4
5
6
7
8
9
1010
2
3
4
5
6
7
8
9
10
1011
11
1100
12
13
14
IS
0011
0100
0101
0110
0111
1000
1001
1101
1110
1111
A
B
C
D
E
F
through F.
A two-digit hex number, such as 4Ch, can be written asOlOOllOOb.It's comwhich we separate into groups of four
4Ch,
Very
is
we
find
it
digits,
The
number
100b,
is
of eight binary
or two bytes,
throughout
this
bits in a
long string,
A group
is
often,
with bit
is
bit
digits
is
in
3.
known
as a byte,
book, because
bits, bytes,
are
all
fundamental to
the 80x86.
bits
per hex
is
digit),
for decimal
convenient.
and four
Two
digits
numbers.
fit
hex
digits
fit
exactly into
two
decimal digits for one byte, numbers larger than 99 cannot be written, so you
lose the values
from 100
to
255
more than
digits
you must
ignore
more than
half the
three-digit decimal numbers because the numbers 256 through 999 cannot
18
Sign
bit
Bit
Byte
4
M
figure 1-7:
Word
^An Odd
Two's Complement
Sort of Negative
Number
Now you are ready to learn more about negative numbers. We said before that
the
them
in binary.
The
is
all
behave
as negative
as follows:
Positive numbers:
0000h
7FFFh
0111
1111
1111
1111b
Negative numbers:
80e0h
FFFFh
1111
1111
1111
always 0. For
ence
is,
all
1111b
all
in fact, the
way that
the
is
always
1.
This
5)
is
differ-
number
19
Assembly Language
for the
is
numbers
numbers
as
as the
3C8h,
to
its
two's-complement form
number
to
is
just so
it
being
but
we
will
how the 80x86 microprocessor negates numbers. The conseem a bit strange. You won't see why it works, but you will see
you can
version will
first
complement.
its
To
num-
that
unsigned
your convenience.
at
bit.
in
see
does work.
form
(negative) of any
To
reverse
versing
is
first
called complementing,
all
the zeros
number,
first
write the
that:
0000 0000
100 1100
becomes:
1011 0011
1111 1111
1111 1111 10
11
11
1
answer, FFB4h,
subtract
4Ch from
If you wish,
lOOOOh.
is
20
if you
use Debug's
H command to
to
addition.
Oh.
And from
FFB4h
(4C + (-4C) =
0)
Learning
Summary
This chapter has been a
fairly steep
may
Soon,
in
enough
it
cHmb
Debug
to converse with
have required a
fair
amount of mental
to a gentler pace
Now
in hex.
exercise.
take a breath of
and
learned
fresh air
and
look back on where you have been and what you have found.
Debug
In chapters to come,
but, since
you
will
become
it
Once we covered
to decimal.
you had
program
do these
to
we were
able to
important
wander
characters
you will encounter frequently as you continue to explore the world of the 80x86
and assembly-language programming.
Finally,
we moved on
to learn
the two's-
led
you
you
to signed
wrong answer
pay off in
in
which
later chapters,
Debug
will act as
an interpreter
between you and the 80x86 microprocessor waiting inside your PC.
In the next chapter,
We will rely on
Debug
again,
it
You
stores
so far to learn
and, in Chapter 3,
numbers
on the screen.
21
Assembly Language
You will
for the
also learn
22
able to write a
it's
program
to convert binary
num-
c|h|a<p|t|e|r
Doing Arithmetic
with the
In
this
grams
will
how
80x86
to build
your
first
Topics Covered
Using Registers as Variables
Using
Memory
Addition,
in
80x86
Subtraction,
Multiplication
in
and
the
in
80x86
Style
80x86
Negative Numbers
Bytes
the
Style
the
80x86
80x86
Division,
Summary
80x86
Style
Assembly Language
for the
K,snowing something of Debugs hex arithmetic and the 80x86's binary arithmetic,
commands
how
to learn
the
80x86 does
its
math.
uses internal
It
called instructions.
PC.
interpreter,
We use
it
the
80x86 micropro-
You begin by asking Debug to display what it can about small pieces of memory
called registers, in
store
like variables in
BASIC
language, the
these registers
are not
command
Register,
as follows:
-R
AX=0000
BX=0000
CX=0000
DX=0000
SP=FFEE
DS=3756
ES=3756
SS=3756
CS=3756
IP=0100
3756:0100 E485
different
Those numbers
display.
numbers
reflect the
in the
later
first
four registers,
The
you will
of your
learn
You
of information. Concentrate on
all
of which
Debug says
are equal
other registers, SP, BP, SI, DI, DS, ES, SS, CS, and IP, are
we
will deal
with in
later chapters.
four-digit
Chapter
1,
Here, you can see that each of the 13 registers in the 80x86
is
one word, or 16
bits long.
This
as 16-bit
is
registers
can be 32
bits long,
lines
in a computer.
The
lot
registers.
DI=0000
amount of memory
will
SI=0000
NV UP DI PL NZ NA PO NC
AL,85
IN
BP=0000
Windows
We
BASIC
registers.
AX register as
variables.
register, the
it.
command tells
follows:
-R AX
AX 0000
:3A7
Look
at the registers
again to see
if
the
-R
AX=03A7
BX=0000
CX=0000
DX=0000
SP=FFEE
DS=3757
ES=3756
SS=3756
CS=3756
IP=0100
3756:0100 E485
It
by specifying the
From
here on,
register's
we
will
Debug's Hexarithmetic
Debug
name and
be using
You may
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
AL,85
IN
does. Furthermore,
R command
BP=0000
command
to
with the
new number
this
registers.
number 3A7h
register
entering the
in
Chapter
1,
we
will use
Debug merely
as
an
inter-
we can work direcdy with the 80x86. We will give the 80x86 instructions
registers: we will place a number in the BX register
and then instruct the 80x86 to add the number in BX to the number in AX
and put the answer back into AX First, you need a number in the BX register.
This time, let's add 3A7h and 92Ah. Use the R command to store 92Ah into BX.
preter so
to
Using
BX=092A
CX=0000
DX=0000
SP=FFEE
DS=3756
ES=3756
SS=3756
CS=3756
IP=0100
3756:0100 E485
IN
contain
BP=0000
SI=0000
as
you
DI=0000
NV UP DI PL NZ NA PO NC
AL,85
27
Assembly Language
tell
for the
BX
to
AX? By
AX and BX
how do
registers,
computer's memory.
Your
need
to use here.
vast
amount of memory.
numbers
that
tell
the
the
tell
far
80x86
to
add the
BX register
to
AX. Then, we
will ex-
80x86 where
to find
it?
As
it
will
memory
into 64K pieces known as segments. Most of the time, you will be looking at
memory within one of these segments without really knowing where the segment starts. You can do this because of the way the 80x86 labels memory.
AH
bytes in
up.
highest
which means
maximum number of labels it can use is 64K. Even so, experience tells you
that the 80x86 can call on more than 64K of memory by being a little bit tricky.
It uses two numbers, one for each 64K segment and one for each byte, or offthe
set,
64K of memory.
In
offsets,
80x86
the
you will
multiple of 16 bytes, so by
at a
effectively
on
this
to access
megabyte of memory.)
The
addresses (labels)
are offsets
from the
start
of a segment. You
mean
that
you
are at
offset
an
within the
offset
of lOOh
number
for
you so
tion to
28
is
1 1
you
will learn
you can
trust
Debug
the segment
you can work within one segment without having to pay atten-
only
by their
offsets.
lOlh
is
refers to
one byte
segment, and
in the
lOOh
in
memory.
Start of
segment
3756
3750:0100
01h
ADD
BX
AX,
DBh
3750:0101
Figure 2-1: Instruction begins lOOh bytes from the start of the segment.
AX,BX.
We will
ever segment
will say that
Debug
it is
starts to use.
In referring to your
is
ADD
in
what-
instruction,
first
we
byte of
the instruction.
Debug's
Enter.
command
for
is
called E, for
ADD
in-
struction.
-E lee
3756:0100
E4.01
-E 101
3756:0101
85. D8
The numbers
01 h and
instruction at
memory
D8h
locations
machine language
for the
ADD
number you see will probably be different, but that difference won't affect your
29
Assembly Language
for the
Debug probably
program. Likewise,
for each
numbers
number
in
that
numbers
will
the
started
numbers
Debug.
(If
are data
you
of the seg-
just started
left
probably be 00.)
80x86
Addition,
Style
BX=092A
CX=0000
DX=0000
SP=FFEE
DS=3756
ES=3756
SS=3756
CS=3756
IP=0100
3756:0100
ADD
01 D8
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
AX,BX
neatly placed in
memory,
just
it
to
Olh
is
at address
lOOh, while
D8h is at
numbers
AX,BX confirms
that
where
it
no mean-
that have
the message
ADD
instruction correctly.
{executeix). First,
you need
to
tell
the
80x86
The 80x86
finds
segment and
two
special
CS and IP, which you can see listed in the preceding register display.
The segment number is stored in the CS, or Code Segment, register, which we
registers,
CS
look
register for
you (CS=3756,
is
in
you can
see that
is
stored in
The 80x86 uses the offset in the IP regisactually find our first instruction. You can tell it where to look by setting
30
full
3756:0100.
Debug
first
instruction
IP^OIOO.
The
IP register
you
is
already set to
Knowing
this,
we have
in place
to
OOh whenever
dehberately chosen
and the
instruction.
OOh
to set the IP
We will
we
will tell
Trace)
com-
regis-
use Debug's
instruction at a time
as the ad-
After each trace, the IP should point to the next instruction. In this case,
ters.
102h. Since
will point to
line
it
program. Ask
Debug to
trace
left:
T command as follows:
-T
AX=0CD1
BX=092A
CX=0000
DX=0000
SP=FFEE
DS=3756
ES=3756
SS=3756
CS=3756
IP=0102
3756:0102 AC
The
The
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ AC PE NC
LODSB
at
which
is
02h, so the
memory location
the
last line
of the
register display
2-2 and 2-3 summarize the before and after of running the add instruction.
80x86 where
to find
struction at 01 OOh.
using the
do
it
reg-
T again,
your 80x86
just yet
for limbo.
CDlh
CS
always points to the next instruction for the 80x86. If you typed
its
in
AX? For
that
you need
Can you
just
R command to set IP to
change the IP
register to
to
92Ah
tell
the
ADD in-
01 OOh? Try
it
by
lows:
AX=0CD1
BX=092A
CX=0000
DX=0000
SP=FFEE
DS=3756
ES=3756
SS=3756
CS=3756
IP=0100
3756:0100
That's done
ADD
it.
Try the
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ AC PE NC
AX.BX
15FBh. Itdoes.
31
Assembly Language
for the
AX
BX
03A7
092A
JPUM >
ADD
AX,
^ LODSB
Figure 2-2: Before executing the
BX
0CD1
092A
IP
register
Now,
set the
contain
ADD instruction.
AX
ADD
LODSB
IP:102
AX,
15FB,
BX =
BX
ADD instruction.
AX =
BX
092A.
try subtraction.
R display before
using the
command. That
Subtraction,
80x86
Style
80x86 executes
want
it to.
We are going to write an instruction that will subtract BX from AX. After two
subtractions, you will have 3A7h in AX the point from which you started
before your two additions.
into
32
memory.
You
twice:
from the
first
as
it
turns out
command
if
you can
ac-
you separate
it
subtract instruction:
-E lee
3756:0100
D8.D8
01.29
The register display (remember to reset the IP register to lOOh) should now
show the instruction SUB AX,BX, which subtracts the BX register from the
AX register and leaves the result in AX. The order of AX and BX may seem
backwards, but the instruction is like the BASIC statement AX = AX - BX
except that the 80x86, unlike
first
variable (register).
Execute
this instruction
Change IP
to
to point
with the
back to
T command. AX
this instruction,
at the
bottom of the
should contain
and execute
it
CDl.
again (remember
be 03A7.
Negative
In the
last
chapter,
for negative
FFFFh
for -1. If
trace
will
work
the
in
to calculate negative
should place
Numbers
uses the
(-1) into
AX.
Set
AX equal
at address
two's-complement form
SUB
test, to see
FFFFh
80x86
if correct,
to zero
and
instruction
BX to
one, then
AX =
FFFFh.
numbers
handy, you
may wish
to try
some
33
Assembly Language
for the
Bytes
in
80x86
the
digits.
Does the 80x86 microprocessor know how to perform math with bytes?
Yes,
does.
it
word
Since one
is
known as
first
two hex
digits)
and
the low byte (the second two hex digits). Each of these registers can be called
by
its letter
for the
word
low
register, see
X for a word, H
DL and DH
and
DX
is
Figure 2-4.
AH
AL
L_
AX
Figure 2-4: The
To test byte-sized math with an ADD instruction, you enter the two bytes OOh
and C4h,
register
result in the
02h
in the
and you
is
high byte,
AH.
in the
AH register and
is
AH register.
34
you
in the
register display,
AL register.
Debug
If the
change the
to
AX
register already
AL register to
really
meant
to
way
isn't a
to
change
just the
word registers.
register
with Debug.
you saw
To try this ADD instruction, load the AX register with 0103h. Your ADD
AH,AL instruction is still at memory location OlOOh, so reset the IP register
to 1 OOh and, with 1 h and 03h now in the AH and AL registers, trace through
this instruction. This time, AX contains 0403h: 04h, the sum of Olh + 03h is
now in the AH register.
Multiplication
80x86
You have
and
Division,
Style
seen the
that
it
tion
is
called
clever processor.
The
see
multiply instruc-
We will enter this into memory, but first a word about the MUL instruction.
Where does the MUL instruction store its answer? In the AX register? Not
quite; we have to be carefiil here. As you will soon see, multiplying two 16-bit
numbers can
two
its
registers,
the lower,
time to time.
Back
Debug and
to
and
ister
set
you did
AX = 7C4Bh and BX =
display as
lOOh.
You
and subtraction
at
instructions,
F7h E3h,
by the
AX register,
register
you name
in the
DX:AX
pair of
registers.
35
Assembly Language
for the
hand.
The
MUL
do the multiplication by
instruction,
same
effect in
hex
as in
decimal, so to
multiply by lOOh simply add two zeros to the right of a hex number. Thus,
lOOh
7C4Bh
will split
it
7C4B00h. This
into the
Use Debug
the
result
is
too long to
fit
into
the
You
word 4B00h.
Figures 2-5
DX contains
one word, so we
be longer than two words, but will often be longer than one word
(as
you just
DX:AX
pair of registers.
DX
AX
BX
0000
7C4B
0100
BX
!^!^ MUL
^ LODSB
Figure 2-5: Before executing the
MUL instruction.
DX
AX
BX
007C
4B00
0100
BX
MUL
\pm> LODSB
K
36
MUL instruction.
What about division? When you divide numbers are divided, the 80x86 keeps
both the result and the remainder of the division. To see how the 80x86's division works,
first
F7h F3h
at
MUL instruction, DIV uses DX:AX without being told, so you see
DIV BX. Now, load the registers so that DX = 007Ch and AX = 4B12h; BX
the
is
all
should
still
Again,
let's first
12h
left
that
AX =
over.
remainder
ter 10,
contain OlOOh.
calculate results
When
7C4Bh,
by hand: 7C4B12h
(see Figures
when we write
program
and
DX = 0012h, which
numbers
to hex
AX
BX
007C
4B12
0100
>
DIV
^ LODSB
Figure 2-7: Before executing the
by using
BX
DIV instruction.
DX
AX
BX
0012
7C4B
0100
DIV
ipuo?
Figure 2-8: After executing the
the
1.)
DX
iPiloo
is
to convert decimal
at
>
BX
LODSB
DFV instruction.
37
Assembly Language
Summary
It is
in
real
program
You began
this
one
to print a character
will
move
look
on the screen.
at the
ground
on.
ity to variables in
a small, fixed
uses to locate
After learning
how
segment and
to
single-instruction programs
multiply,
chapters
we
will use
much
grams.
useftil
to build
AX
and
BX
some
subtract,
registers. In ftiture
how to tell Debug to execute or trace through a single inYou will come to rely heavily on Debug to trace through your pro-
Of course, as programs grow in size, this tracing will become both more
and more
tedious. Later
Let's turn
38
we moved on
also learned
struction.
how
registers,
You
offset addresses.
back to
real
learn
Debug command.
H A
I
Printing
Characters
In
this
line
program
ters
Finally,
on your
you
program
will build a
screen.
program
that displays a
whole
all
by
string of charac-
Topics Covered
IMTrising DOS
Functions
INT 20h
Putting the Pieces TogetherA Two-Line Program
Exiting
Programs
Entering Programs
MOVing Data
into Registers
Summary
Assembly Language
1 ou
screen.
your
flex
for the
fingers.
Then move on
do something soHd, so
more
to even
to
roll
up your
sleeves
and
registers
interesting
building
work
and from
instruction,
there, learning
a small pro-
another
way
DOS
to
speak.
ask
called
AX and
let's
4lh
Debug
into
instruction for
DOS
INT 21h in machine code, CDh 21h. This is a two-byte instrucDIV instruction in the last chapter. Put INT 21h in memory,
starting at location lOOh, and use the R command to confirm that the instruction reads INT 21 (remember to set IP to lOOh if it isn't already there).
functions
is
Now you
command
one instruction
in
DOS
You
to
at a time,
do the
but the
last
chapter.
The
INT instruction
calls
command
upon
a large
program
actual work.
it
one instruction
at a time. Instead,
DOS
You can do
the address at
with Debug's
this
to stop.
{Go
till)
command,
The command
is
followed by
as follows:
G 102
BX=0000
CX=0000
DX=0041
SP=FFEE
DS=3970
ES=3970
SS=3970
CS=3970
IP=0102
3970:0102 8BE5
42
MOV
SP.BP
BP=0000
SI=0000
to
at loca-
A
AX=0241
"sub-
you want
run your one-line program, but stop before executing the instruction
tion 102h.
trace
executes
DI=0000
NV UP DI PL NZ NA PO NC
DOS
printed the character A, and then returned control to your small pro-
program, so you
in a sense,
is,
Printing Characters
at location
will
at
102h
is
behind by another
is
102h.
INT
21
MOV
SP,BP
it
isn't
will
when
it
it
Debug
to
run
was done.
How did DOS know that it should print the A? The 02h in the AH register
DOS to print a character. Another number in AH would tell DOS to
told
list
DOS
uses the
number
You
In
later,
of functions in Appendix
but
if
you
are curious
book.)
this
As
Appendix D, you
acters
your
tion. Since
PC
ASCII code
for
in the
it
of ASCII
The numbers are
register as the
ASCII
an uppercase A.
can display.
DL
hex, here
is
all
the char-
good chance
for
you
to practice
converting decimal numbers to hex. Pick a character from the table and convert
it
to hex
verify
(remember
to reset IP to lOOh).
that
if you
had
distance through
far
it
to see
what
left
exit
Debug with
behind.
43
Assembly Language
for the
AX=0200
BX=0000
CX=0000
DX=0041
SP=FFEE
DS=3970
ES=3970
SS=3970
CS=3970
IP=0100
3970:0100 CD21
INT
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
21
-T
AX=0200
BX=0000
CX=0000
DX=0041
SP=FFE8
DS=3970
ES=3970
SS=3970
CS=3372
IP=0180
3372:0180 80FC4B
CMP
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
AH, 48
-T
AX=0200
BX=0000
CX=0000
DX=0041
SP=FFE8
DS=3970
ES=3970
SS=3970
CS=3372
IP=0183
3372:0183 7405
JZ
01
BP=0000
SI=0000
DI=0000
NV UP DI NG NZ AC PE CY
8A
i
AX=0200
BX=0000
CX=0000
DX=0041
SP=FFE8
DS=3970
ES=3970
SS=3970
CS=3372
IP=0185
3372:0185 2E
CS:
3372:0186 FF2EAB0B
JMP
BP=0000
SI=0000
DI=0000
NV UP DI NG NZ AC PE CY
CS:0BAB=0BFF
FAR [0BAB]
-Q
These
last
first
number of the
ecutes before
as easy as
it
to run the
there
3970
to
3372.
it
sounds.
program
task
is
not
different version of
a torrent of instructions
DOS,
the instructions
you
from DOS.
see
when you
try this
using a
may
be
different.)
Exiting
INT 20h
Programs
Do you remember that your INT instruction was 2 1 h? If you changed the 2 1 h
to a 20h, you would have INT 20h instead. INT 20h is another interrupt
instruction,
full
we
44
and
it tells
DOS we want
to exit
our program so
DOS
can take
(remember
to check the
INT 20h
Printing Characters
R command):
G 102
AX=0000
BX=0000
CX=0000
DX=0000
SP=FFEE
DS=3970
ES=3970
SS=3970
CS=3970
IP=0100
3970:0100 CD20
INT
BP=0000
DI=0000
SI=0000
NV UP DI PL NZ NA PO NC
20
R
AX=0000
BX=0000
CX=0000
DX=0000
SP=FFEE
DS=3970
ES=3970
SS=3970
CS=3970
IP=0100
3970:0100 CD20
INT
just
INT 20
You can
example are
use this
trol gracefully to
with
INT 20h
DOS
only because
f/> instruction),
which
we
instruction at the
(or
an
is
DI=0000
SI=0000
NV UP DI PL NZ NA PO NC
20
BP=0000
is
started
where we
Debug
The
aftesh.
end of a program
and then
started.
to return con-
Flitting the
Pieces Together
A Two-Line Program
Starting at location
21h
CDh
grams
20h) one
at location
lOOh.)
When you had only one instruction, you could "list" that instruction with the
R command, but now you have two instructions. To see them, use the
U {Unassemble)
command, which
lists
part of a
program
in
memory:
45
Assembly Language
-U
for the
100
3970:0100 C021
INT
21
3970:0102 CO20
INT
20
3970:0104 O98O460250B8
ESC
3970: 01 0A 8000
LEA
AX,[BX+SI]
3970: 01 0C 50
PUSH
AX
3970:0100 E82A23
CALL
243A
3970:0110 8BE5
MOV
SP,BP
3970:0112 83C41A
AOO
SP,+1A
3970:0115 50
POP
BP
3970:0116 C3
RET
3970:0117 55
PUSH
BP
3970:0118 83EC02
SUB
SP,+02
3970:0116 8BEC
MOV
BP,SP
3970:0110 823E0E0000
CMP
The
first
two instructions
just entered.
The other instructions are remnants left in memory. As your prowill fill this display with more of your own code.
AH register with 02h and the DL register with the number for
any character (just as you did earlier when you changed the AX and DX regis-
Now,
ters),
you
fill
the
place
4lh
into
DL, you
For example,
if
A
Program terminated normally
Try
this a
ways to
DL
before
we move on
to other
Entering Programs
From
To
46
we
will use
as follows:
3970:0100 CD21
INT
21
3970:0102 CD20
INT
20
instruction long.
last
pro-
So
far,
such
bers,
much
CDh,
as
way
easier
is
for
Printing Characters
it
as
num-
is
to enter instructions.
command, Debug
includes an
command, which
allows
structions direcdy.
you
to enter the
{Assemble)
mnemonic, or human-readable,
command
for
in-
your short
-A 100
3970:0100 INT 21
3970:0102 INT 20
3970:0104
When you
all
you have
to
do
is
press
Moving Data
Although we have
with
an
it.
relied
into Registers
on Debug quite
a bit,
set the
we won't
called
MOV. Once you know enough about this instruction, you can take your small
program
to print a character
and make
a real
program
one
DOS.
let's
isters.
Place
ABCDh
1234h
into
into
DX (ABh in DH,
AX
and
CDh
AH
in
register,
and 34h
in
AL) and
A command:
MOV
AH.DL
47
Assembly Language
for the
AH; DL
is
this
one
line,
you
later,
You have
BX.AX
MOV
moved words,
just
reset
between
registers.
The
MOV
bytes; never
word
Let's
bytes. It
makes
sense, for
into a byte?
do so
now with
396F:0100 B402
MOV
is
as follows:
AH, 02
The second byte of the instruction, 02h, is the number we wish to move.
a different number into AH. Change the second byte to another
number, such as Clh, with the E 101 command.
ister.
Try moving
Now, put
all
asterisk, *, all
by
itself,
with no need to
set the
AH and
DL registers. The program uses MOV instructions to set the AH and DL registers
before the
INT
21 h
call to
396F:0100 B402
MOV
AH, 02
396F:0102 B22A
MOV
DL,2A
396F:0104 CD21
INT
21
396F:0106 CD20
INT
20
You
48
DOS. The
it
with the
on your
screen, as follows:
Printing Characters
i
*
Now
that
you have
disk as a
We can
run a
.COM
program from
DOS
it
simply by typing
command
the following
-N
{Name)
gives a
name
to a
file
DOS.
from
name. Since
its
one.
it
to
it
The Debug
Type
it
to disk.
to
our program.
WRITESTR.COM
This
file
command does
not write a
file
to the disk,
though
command
that
you
it
program so
you
it
will
refer to the
struction
tions, so
unassemble
is
your program
is
(this
listing
won't always be
true).
in-
instruc-
first
will
Debug
produce
BX:CX for
that your
8.)
program
is
mand,
is set,
write
it.
Debug
so putting 8h into
file,
it
set
BX
to zero.
to disk with
Once
Debug's
the
uses
CX
file is
name and
(for Write)
com-
as follows:
-w
called
WRITESTR.COM,
Use the
DOS
Dir
Q, and look
for
it.
command
to
list
so exit
the
De-
file:
C>DIR WRITESTR.COM
Directory of
C:
49
Assembly Language
for the
WRITESTR COM
08-28-92
File(s)
10:05a
bytes
C>
The
directory listing
tells
it is
To
You
will see a *
you
that
WRITESTR.COM
is
DOS
that
prompt.
example
a final
number
in the
AH
you use
register, to write a
You have
character
whole
string of characters.
memory and
learn
for
memory,
string into
start at location
it
You
DOS where
will
to find
number 02h
tell
finds a S
symbol
INT 21h
prints
one
prints
an entire string,
in the string.
To
put a
with the code for your program. Enter the following nimibers by using the
instruction
200:
48
65
6C
6C
6F
2C
20
44
4F
53
20
68
65
72
65
2E
24
The
this
last
is
number, 24h,
the
ASCII code
a minute,
50
is
the program,
for a $ sign,
You will
see
and
what
it tells
MOV
AH, 09
396F:0102 BA0002
MOV
DX,0200
396F:0105 CD21
INT
21
396F:0107 CD20
INT
20
that
396F:0100 B409
DOS
as follows:
200h
is
Printing Characters
DX
it
G
Hello, DOS here.
Now
that
memory,
in
it is
other
to the screen
somewhat
like
tell
just entered.
-D
200
396F:0200
48 65 6C 6C 6F 2C 20 44-4F 53 20 68 65 72 65 2E
396F:0210
24 5D C3 55 83 EC 30 SB-EC C7 06 10 00 00 00 E8
$]CU.10.1G
numbers (such
first line
you
see
is
396F:0200
is
the
first
character
On
in.
the
The
Wherever you
see a period
(.)
in the
ASCII window,
you
in the example),
as
in the
letter pi.
PC
it
represents either a
Debug's
character
set,
D command
so a period
is
You can
use the
whether those data are characters or ordinary numbers. (For more information, refer to the
Your
Debug
string-writing
procedure
is
section in your
program
is
DOS
manual.)
you used
to write
it
to the disk.
WRITESTR.COM
The
to disk,
except this time you have to set your program length to a value long enough
to include the string at 200h.
The program
begins at line
51
Assembly Language
see
for the
mand
and
That's
it
21 Ih.
CX
register
and
set
it,
BX
to zero.
Use the
file.
string of characters.
string with a $ in
follow-
H com-
to a disk
end of a
(])
use the
You can
program
at location
command
is
but in a
from one
final
note
DOS
later chapter,
you
will learn
Summary
The
real
first
program. In
this chapter,
and a
some new
First
to the point
string of characters
on the
you
also learned
things.
INT instructions
not
you
in
much detail,
but enough to
80x86 micro-
Debug has, once again, been a useful and faithfiil guide. We have been relying
heavily on Debug to display the contents of registers and memory, and in this
chapter we used its abilities even more. Debug ran your short programs with
the G command.
You
also learned
struction for
tion
to the disk
and run
instruction gave
struction, so
52
about the
INT 20
moving numbers
directly
you the
into
and between
to build a
from
registers.
The
MOV in-
exit instruc-
an
INT
to print
21 (print)
in-
one character.
Finally,
we rounded out
out the
rest
We will
as
use
all
INT
Printing Characters
21 h function to print an
unassemble commands, you won't need to remember the machine codes for
these instructions.
to
move on
chapter you will build a short program to take one byte and print
it
on the
53
H A
I
Printing Binary
Numbers
In
this
tools
are the
>
Topics Covered
Rotating
Numbers through
Summary
Number
Command
Assembly Language
In
for the
chapter you will build a program to write binary numbers to the screen
this
as strings
need, and
your work here will help solidify ideas you have already covered. This chapter
adds a few instructions to those you already know, including another ver-
also
sion of
ADD and some instructions to help repeat parts of your program. Let's
to
bers, so
fifth
Go
they can hold either a zero or a one. If you need to carry a one into the
hex
digit,
it
back to the
AX and
into
of the second
ADD
into
line
flag.
instruction of Chapter 3
BX, then
of Debug's
trace
through the
because your
last
(ADD
(or, as
we will
say,
it's
set).
To
add one
to the zero in
bit here
(it
AX by resetting IP to
is
lOOh and
affected
by each
ADD instruction, and this time there shouldn't be any overflow, so the carry
should be
reset.
stands for
No
You
The
carry does
Carry, in the
become
your
56
zero, as indicated
DOS manual.
by the
NC, which
R display.
you
are curious,
you
in
mation could be
want
You
useful.
example, the
first
If you
would want to
move
could
print in the
this entire
byte
left
Numbers
at a time, so
you
left to right.
For
character you
how
will print
Printing Binary
place,
dropping
process for each succeeding digit, the carry flag would pick ofi^your binary digits.
how
it
3985:0100 D0D3
RCL
This instruction
The
flag.
BL
moved
you
you
Figure
bit
(hence the
RCL
,1)
moves
4-L
In the process,
enough
After
left.
all
the
BX
the
register,
and
then trace
Carry
110
111
B7h
110
110
1110
6Eh
10 11
10 10
BAh
10 11
111
B7h
10
1
In the
first
moves
flag
into bit
number
You
110
rotation, bit
moves continue
nal
moving the
bits are
through
by one
is
(0) as in
or rotated to the
as follows:
to the left
instruction
To
BL,1
program
is
DDh
of BL;
all
other bits
back in the
you
After
still
rotations
BL
move
left
flag;
register.
screen, but
We start here
need a few
program
to write binary
or
numbers
to the
convert the
57
Assembly Language
for the
CF
BL
0110 1110
RCL
BL,1
instruction.
Number
The normal
ADD
ADD AX,BX,
flag. If you
30h
is
30h
table,
and
you
the character
if
DL =
and 31h
is
when
the character
the carry
30h
is
1.
clear,
(1), execut('0'),
which
31h (T).
gives
ADC
numbers:
DL,30
With one
instruction
to a character that
you can
print.
At this point,
you have
a complete program. After you have built the program you will execute
structions
one
at
58
in-
this pro-
repeat your
Through
its
instruction
to
once
Printing Binary
Numbers
Looping Repeating a
Block of Code
As mentioned, the
LOOP
tion.
eral.
is
As with BASIC'S
ister
FOR-NEXT command in Basic, but not as genFOR-NEXT loop, you need to tell LOOP how many
it
You do
this
in reg-
can also
similar to the
CX; when
it
Count.
You can
general-purpose register, but as you will see in the next chapter, you can
to repeat op-
erations.
Here
BL
is
a simple
into
BH
program that
rotates the
MOV
BX,A3C5
MOV
CX,0008
RCL
BX,1
LOOP
0106
396F 01 0A CD20
INT
20
moving
The loop starts at 1 06h (RCL BX, 1 and ends with the LOOP instruction.
The number following LOOP ( 1 06h) is the address of the RCL instruction.
When you run the program, LOOP subtracts one from CX, then jumps to
address 106h if CX is not equal to zero. The instruction RCL BX,1 (Rotate
)
Carry
Left,
one place)
is
CX
is
set to eight
ment
in
is
at the
unlike the
BASIC). The
start
RCL
If you
is
NEXT state-
know
no
somewhat akin
to the
REPEAT-
UNTIL pair of instructions, where the REPEAT instruction just labels the start
of the block of instructions to loop through.
59
Assembly Language
for the
0106:
Decrement
CX
LOOP 0106
Continue
when CX
20
INT
Figure 4-2: The
There
LOOP instruction.
are different
If you
type G, you won't see any change in the register display, because
all
ters
an
isters.
and
INT
starts carrying
it
20 instruction
Try G. You
(as it will in
one step
at a time,
Debug saves
G command. Then, if
your program),
it
restores
it
encoun-
all
the reg-
any
out a
you can
trace
different, either.
through
this
registers
change
at
each step, as
lows:
-t
AX=0000
BX=0000
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0100
0CDE:0100 BBC5A3
MOV
BX=A3C5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0103
MOV
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
BX,A3C5
AX=0000
0CDE:0103 B90800
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NO
CX,0008
-T
AX=0000
BX=A3C5
CX=0008
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
GS=0CDE
IP=0106
0CDE:0106 D1D3
60
RCL
simply
BX,1
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
fol-
AX=0000
BX=478A
CX=0008
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0108
0CDE:0108 E2FC
LOOP
BP=0000
Printing Binary
Numbers
DI=0000
SI=0000
OV UP 01 PL NZ NA PO CY
0106
-T
AX=0000
BX=478A
CX=0007
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0COE
CS=0CDE
IP=0106
0CDE:0106 D1D3
RCL
BP=0000
01=0000
SI=0000
OV UP 01 PL NZ NA PO CY
BX.I
-f
AX=0000
BX=C551
CX=0001
DX=0000
SP=FFEE
OS=0COE
ES=0COE
SS=0CDE
CS=0COE
IP=0108
0CDE:0108 E2FC
LOOP
BP=0000
01=0000
SI=0000
NV UP 01 PL NZ NA PO CY
0106
-T
AX=0000
BX=C551
CX=0000
OX=0000
SP=FFEE
OS=0COE
ES=0COE
SS=0CDE
CS=0CDE
IP=010A
0CDE:010A CO20
Alternatively,
cluding, the
sult
If
INT
INT 20
BP=0000
01=0000
SI=0000
NV UP 01 PL NZ NA PO CY
20
lOA
to execute the
instruction at lOAh.
The
program up
to,
registers will
re-
of your program.
you
try this,
you
will see
CX
Later,
but
either
BX
C551
see other
a Binary
BX
C5D1,
is
now
in the
number
BH
Building a
or
you will
and
flag before
Let's
in binary notation.
Program to Display
Number
You have seen how to strip off binary digits one at a time and convert them to
ASCII characters. If you add an INT 2 1 h instruction to print your digits, your
program will be finished as you can see in the following program. The first
61
Assembly Language
instruction sets
DL register).
MOV
AH, 02
MOV
CX,0008
MOV
DL,00
RCL
BL,1
ADC
DL,30
INT
21
LOOP
0105
INT
20
The program
is
as follows:
You have seen how all the pieces work alone; here is how they work together.
You rotate BL (with the instruction RCL BL,1) to pick off the bits of a number. Pick a number you want printed in binary and load it into the BL register; then run this program with a G command. After the INT 20h instruction, the
still
G command
contains the
number you
had
before.
BL
The ADC DL,30 instruction in your program converts the carry flag to a or
a 1 character. The instruction MOV DL,0 sets DL to zero first, then the ADC
instruction adds 30h to DL, and then finally adds the carry. Since 30h is the
ASCII code for a 0, the result of ADC DL,30 is the code for when the carry
is clear (NC) or 1 if the carry is set (CY).
to see what happens when you run this program, trace through it.
mind that you will need to be a bit careful in single-stepping through
it with the T command. It contains an INT 21h instruction and, as you saw
when you first encountered INT 21h, DOS does a great deal of work for that
one instruction. That is why you cannot use T on the INT 21.
If you
Keep
want
in
INT
tracing, type
struction.
trace
through
all
Your
you
G command,
the
tell
Debug
That
Debug
is.
through
it,
INT
62
to con-
entered.
LOOP
as a breakpoint;
you
in-
known
During your
INT 21h
breakpoints are
Printing Binary
Nunnbers
when you
INT 20h
reach the
G command by itself.
or not you have tried out the instructions to trace through the pro-
INT instruction
an
to trace over
that starts
INT
at, say,
instruction,
As
it
like
to trace
ovemn
you need
INT
of the instruc-
instruction.
instructions
you.
INT 21h
lOE.
We will make heavy use of the P command in the rest of this book, because
is
a nice
way
to trace over
commands
DOS.
such
That
is all
we will
this
is
program
INT, which
call
on
large
programs
modify
like
it
for
you
to practice
on
62h.)
Summary
This chapter provided a chance to catch your breath a
on new concepts
in Chapters
through
3.
bit after
first
encounter with
it
flags
made
and had
number
63
Assembly Language
quite simple.
which
It
rotates a byte or
word
to the
left,
one
RCL,
bit at a time.
Once you learned about the carry flag and rotating bytes and words, you learned
a new version of the add instruction, ADC. You used this later to build your
program to print a number in binary notation.
This
is
register
where the
structions a
That
LOOP
By
loading the
CX
with a loop count, you could keep the 80x86 executing a loop of in-
is all
you needed
to write
set
CX to 8,
in
as Debug does.
5,
you will have a better idea of how Debug translates numbers from binary to
reading the numbers
hex. Then, we will move on to the other end of Debug
64
H A
Printing
in
In
Numbers
Hex
this chapter
you
displays a binary
will learn
number
some new
tools
in hexadecimal notation.
flags.
You will
learn
instruction.
Topics Covered
Comparing Numbers
Printing a Single
Hex
Summary
^^
Digit
Assembly Language
for the
fairly straightforward. You were lucky bemade it easy to print a binary number as a string of and
1 characters. Now we will move on to printing numbers in hex notation. The
work will be a bit less direct and we will begin to repeat ourselves in our pro-
1 he program
in
Chapter 4 was
grams, writing the same sequence of instructions more than once. But that type
of repetition won't
In Chapter 7
last forever.
you
will learn
about procedures
of instructions.
print
numbers
First,
you
learn
in hex.
Comparing Numbers
In the
last
carry flag,
chapter you learned something about status flags and examined the
which
is
represented as either
other flags are equally useful, keeping track of the status for the
operation. There are eight flags altogether,
and you
will learn
arithmetic
last
about them
as
is
CY means
In
0.
all flags 1
means
true
true
flag
would be
Look
at
reset to
see
to subtract
two numbers.
flag will
known
in the
tests
or
If the
whereas
if
set to
SUB
1
Zero).
appear as
set,
R display as ZR (Zero).
NZ {Not
an example that
it
is 1
and
You
two numbers
SUB
instruction
ZR on your display.
tract instruction:
396F:0100 29D8
Now,
trace
SUB
AX,BX
ZR or NZ to appear in the zero flag. If you place the same number (F5li in
the following example) into both the AX and BX registers, you will see the
for
68
and cleared
Printing
r\
Nunnbers
in
Hex
-R
AX=00F5
BX=00F5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0100
0CDE:0100 29D8
SUB
BP=0000
SI=0000
DI=0000
NV UP DI PL NZ NA PO NC
AX, BX
-T
AX=0000
BX=00F5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0102
0CDE:0102 3F
BP=0000
SI=0000
DI=0000
NV UP DI PL ZR NA PE NC
AAS
-R IP
IP 0102
:1M
-R
AX=0000
BX=00F5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0100
0CDE:0100 29D8
SUB
BP=0000
SI=0000
DI=0000
NV UP DI PL ZR NA PE NC
AX, BX
-T
AX=FF0B
BX=00F5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0102
0CDE:0102 3F
If
SI=0000
DI=0000
NV UP DI NG NZ AC PO CY
AAS
(Negative)
BP=0000
Yes
and PL
tell
another
(Plus),
and
set to
FFFFh, which
is
-1
in two's-
from the
flag, called
is
is
when
number
is
NG
a negative two's-
complement number.
Another new flag you will be interested in
is
is
0.
overflow
flag.
(Remember,
would not be an
Try several
trying
error
different
them out
if
numbers
until
you
and
reset
this
flag.)
each of these
flags,
69
Assembly Language
for the
Conditional Jumps
instructions.
address if the
last
80x86
the
than
to
at the
The JZ
jump
JZ
to
SUB
in-
and
start
next instruction.
is
set
The
opposite of JZ
uses
396F:0100 2C01
SUB
AL,01
396F:0102 75FC
JNZ
0100
396F:0104 CD20
INT
20
Put a number
like three in
AL
so
you
will
at a time, to see
how condi-
it's
good defensive
prac-
tice.
Using
allows
you
to
first
what happens,
through
-A lee
70
of changing the
number. The
many
set
result
conditional
both
is
jump
AX and BX to
0CDE:0102
to
first
SUB
number.
CMP {Compare)
result an^'where
used only to
and with-
the
you
To
trace
AX=00F5
BX=00F5
CX=0000
DX=0000
SP=FFEE
DS=0CDE
ES=0CDE
SS=0CDE
CS=0CDE
IP=0102
0CDE:0102 3F
The
To
zero flag
use
now
is
set
in
Hex
01=0000
NV UP DI PL ZR NA PE NC
registers.
CMP to print a single hex digit. Create a set of instructions that uses
manner similar
to
BASIC's
is
SI=0000
Mumbers
AAS
on.
BP=0000
Printing
IF-THEN
LOOP did
statement. This
such conditions
and so
You will not have to worry about which flags are set when the first number
than the second; the instructions know which flags to look at.
less
Printing a Single
Start
Hex Digit
and Fh
is
your choice to
ASCII
character
a single
BL register.
Since
it.
Look
at the steps
Character
ASCII Code
Character
(Hex)
/
2F
30
31
2
3
4
5
6
7
8
9
32
33
34
35
36
37
38
39
>
3A
3B
ASCII Code
(Hex)
<
=
>
9
3C
3D
3E
3F
40
41
42
43
44
45
46
47
49
C
D
E
F
G
H
Figure 5-1: Partial ASCII table showing the characters used by hex
through
F,
digits.
71
Assembly Language
for the
The problem
characters.
is
that these
by seven
As a result, the conversion to ASCII will be different for the two groups
Ah
differ-
endy.
IF
ELSE
BL = BL + &H37
END IF
is
fairly simple.
It is far
more primitive
than
is
another
machine-language program.
BL = BL + &H30
IF
END IF
You can convince yourself that this program works by trying it with some choice
examples. The numbers 0, 9, Ah, and Fh are particularly good because these
four numbers cover all the boundary conditions, which are areas where we
often run into problems.
Notice that
we just
Here,
bers.
than AH, so we
the
the
register
AH. We
will
before hex
numbers
that could be
confusing. In fact,
since it never hurts
to
are, respectively,
By using
bers 9
number Ah with
and Fh
a hex number,
The machine-language version of this program contains a few more steps, but
it is essentially the same as the BASIC version. It uses the CMP instruction, as
well as a conditional jump instruction called JL {Jump ifLess Than). The program to take a single-digit hex number in the BL register and print it in hex is
as follows:
MOV
AH, 02
3985:0102 88DA
MOV
DL.BL
3985:0104 80C230
ADD
DL,30
numbers.
3985:0107 80FA3A
CMP
DL,3A
it is
place a
72
range.
different conversion
sen the correct place to switch between these two conversion schemes.
3985:0100 B402
to
two
schemes in the program. By using 9 and OAh, you confirm that you have cho-
good idea
numThe num-
3985:010A 7C03
JL
010F
3985: 01 0C 80C207
ADD
DL,07
3985: 01 0F CD21
INT
21
3985:0111 CD20
INT
20
The
Printing
Numbers
in
Hex
CMP instruction, as you saw before, subtracts two numbers (DL - 3Ah)
it
to the
BL and
if
DL is
trace
through
this
less
for
CMP and our algorithm to convert hex to ASCIL Remember to use either
the G command with a breakpoint or the P command when you run the INT
instructions.
0107
CMP
DL,3A
01 OA
JL
01 OF
01 OC
ADD
DL,07
01 OF
INT
21
X
Jump if
DL < 3Ah
<
for
any
which
see that
section,
you can
flag.
a concept
RCL
In the
bits
known
rotate
RCL
last
bit if you
which you
as a logical operation^
word
BL
left
by one
to the left
RCL BL, 1
bit.
You can
count in the
this section,
hex number. In
lower four
rotate
you will
To
single-digit
hex number.
bit,
CL register.
73
Assembly Language
Note
for the
Although
RCL BL,2 isn't a legal 8088 instruction, it works just fine with
the
common
The CL
by the
register
used here in
is
much
the
denominator
same way
as the
CX register
is
used
The 80x86
than the
uses
CX
register,
The
eight-bit
shift
count.
CL
because
register
is
it
makes no sense
more than
large
to rotate
enough
more than 16
to hold
your
times.
maximum
How does all this tie in with printing a two-digit hex number? The plan is to
rotate the byte in DL four bits to the right. To do so, you will use a slightly
different rotate instruction called SHR {Shift Right) Using SHR, you will be
.
able to
bits).
CF
DL
0110 1110
SHR DL, 1
You
also
becomes equal
to enter
to the nibble
SHR DL,
the right.
bits,
bits
you
of DL
it
all
would move
bit
in
end up
all
were
DL one bit to
do
that three
You
that shifting in
count. Setting
can do
your instruction
more
Instruction.
DL becomes equal to the upper hex digit. To see how this works, place 4 into
74
CL
and
5Dh
into
DL. Then
and
enter
trace
Numbers
Printing
in
Hex
SHR
instruction:
3985:0100 D2EA
SHR
DL.CL
this digit
number
BL
in the
is
the
with a program
register
far,
first digit in
like the
the
MOV
AH, 02
MOV
DL.BL
MOV
CL,04
SHR
DL.CL
ADD
DL,30
CMP
DL,3A
JL
0113
ADD
DL,07
INT
21
INT
20
first
hex
digit:
Using
Now
that
how you
bits
can
isolate
first
of the two
digits in a
digit.
You
bits. It is
hex number,
four
to take
let's
see
upper four
easy to set the upper four bits to zero with an instruction called
In formal logic,
false,
true
then
two
is
true, if
A must also
and zero
you can
"A
create
be
B andQ
false. If
are
you take
as a truth table.
what is known
if either
or
one
is
for
combinations of A, B, and C,
table for
ANDing
bits together:
AND
AND
75
Assembly Language
for the
Down the left and across the top are the values for the two bits. The results for
of each byte or word that are in the same position. For example, the statement
BL.
result in
We
of BL and CL,
can make
bits 1, bits 2,
this clearer
and so on,
with an example in
binary, as follows:
10 110 10
1110 110
AND
110 10
Furthermore, by ANDing OFh to any number, you can
set the
upper four
bits
to zero, as follows:
11110
AND
11
1
7Bh
OFh
10 11
Next you can put
isolates the
OBh
ANDing OFh
to the
upper four
bits,
in
BL,
and then
tion.
MOV
AH, 02
MOV
DL,BL
AND
DL,0F
ADD
DL,30
3985
01
0A 80FA3A
CMP
DL,3A
3985
01
0D 7C03
JL
0112
ADD
DL,07
INT
21
INT
20
Try
this
of your number in
76
BL on
the screen.
BL
before
you move on
to
put
Putting
There
isn't
It
All
much
to
CI
Printing
Numbers
in
Hex
Together
change when you put
all
You need
only to change the address of the second JL instruction used to print the sec-
ond hex
digit.
MOV
MOV
DL.BL
MOV
CL,04
3985::0106 D2EA
SHR
DL.CL
3985::0108 80C230
ADD
DL,30
3985::010B 80FA3A
CMP
DL,3A
is
as follows:
AH, 02
3985::010E 7C03
JL
0113
3985::0110 80C207
ADD
DL,07
3985;:0113 CD21
INT
21
3985::0115 88DA
MOV
DL,BL
3985::0117 80E20F
AND
DL,0F
3985::011A 80C230
ADD
DL,30
3985::011D 80FA3A
CMP
DL,3A
3985::0120 7C03
JL
0125
3985::0122 80C207
ADD
DL,07
3985::0125 CD21
INT
21
3985::0127 CD20
INT
20
After you have entered this program, you will have to type
U, to see the entire unassembled listing.
Note
new
at
will learn
that
U 100, followed by
how
set
lAh
instruction called
CALL.
Summary
In this chapter, you learned
you can
translates
read.
numbers from
to
of the
These
two-letter flags
you
you a
see
on the
right side
By looking
77
Assembly Language
for the
tell
whether the
result
of the
last
how
to print a single-digit
number into
the upper.
CMP instruction.
hex number.
SHR instruction,
You
enabling you to
digit, as before.
AND instruction allowed you to isolate the lower hex digit from
By putting
a two-digit hex
all
you wrote
program
to print
number.
know enough
78
to reading
will learn
to write a procedure to
Now, on
you
hex numbers.
do the
program
job.
7.
By then you
that will
Then, you
will also
be
ClH A
You
Reading
Characters
In this chapter you will learn how to
will build a small
board.
a two-digit
Topics Covered
Reading One Character
Summary
^^m
Assembly Language
low
for the
that
hex
digits
you
from
are going to
the keyboard
AH
register before
INT 21h
enter
396F:0100 CD21
Olh
Place
you
INT 21h
OlOOh
INT
into
will see
an
at location
To
call.
INT
for
21h,
21
is
try function
as follows:
DOS
is
waiting
you press a key (don't do so yet). Once you press a key, DOS will place
ASCII code for that character into the AL register. You will use this in-
until
the
a semicolon
Fl
is
(;)
one of a
after
set
like the
DOS
returned
is
see
in
what
AL and
ently
keys,
F 1 key.
characters.
(You
will find a
The
is
first
special
character
special key.
To
would have
to execute
INT 21h
twice.
But
in
our example, you read only the first character, the zero, and leave the scan code
in
first
character
when we develop
is
it
the
ASCII code
you
82
work with
the normal
ASCII
characters.
began to
left
behind
for a semicolon.
it
life.
Until then,
we
Reading Characters
Hex Number
Next you need
you transformed
a single-digit
in
Chapter
F.
37h
(for
it
through
to a byte.
3985::0100 B401
MOV
3985::0102 CD21
INT
21
3985::0104 2C30
SUB
AL,30
3985:10106 3C09
CMP
AL,09
3985:10108 7E02
JLE
010C
3985::010A 2C07
SUB
AL,07
3985::010C CD20
INT
20
JLE {Jump
as
A through F). Here is a simple program that will read one ASCII
Most of these
when
such
or D, from a hex character to a byte, you must subtract either 30h (for
9) or
5,
through 9 or A through
characters in
you used
AH, 01
your program,
is
this instruction
jumps
if
to 9h.
To
a character.
program works
correctly only
when the input is one of the digits through 9 or the uppercase letters A through
F. You will correct this minor failing in the next chapter when you learn
about subroutines, or procedures. Until then, we will be sloppy and ignore error
conditions. You will have to type correct characters for your program to work
properly.
83
Assembly Language
for the
Reading a Two-Digit
Hex Number
digits isn't much more comphcated than reading one, but it
many more instructions. Begin by reading the first digit, then place
DL register and multiply by 16. To perform this multiDL register left four bits, which places a hex zero (four zero
it
CL set to
you just
read.
The
instruction
by inserting zeros
known
as
it
ing on the
number
CF
CL
DL
0110 1110
Figure 6-1: The
Finally,
ber in
SHL DL,1
with the
DL (the
instruction.
first digit
shifted over,
You can
84
MOV
AH, 01
INT
21
MOV
DL.AL
SUB
DL,30
CMP
DL,09
JLE
0111
SUB
DL,07
MOV
CL,04
SHL
DL.CL
INT
21
SUB
AL,30
CMP
AL,09
JLE
01 IF
SUB
AL,07
ADD
DL.AL
INT
20
digit to the
all
num-
these details
such
Use
as
it is
good
Reading Characters
bound-
numbers 00, 09, OA, OF, 90, AO, FO, and some other number,
3C.
tion.
it is
(Make
sure
letters for
INT 20h
instruc-
Summary
You have
finally
had
function (number
1) to
grams with
all
the
new
information. Using a
in previous
new INT 21
to test pro-
boundary conditions.
in the
80x86.
85
cIhjaIpItIeIr
Using Procedures
to Write Reusable
Code
In
this
how
in
cedures are something you will use heavily in almost any program you write.
In this process you will also learn about the stack, and you will build a
digits.
new
Topics Covered
Writing Procedures
Summary
Assembly Language
In
for the
we
will discuss
MASM,
the
will
one last set of examples and learn about subroutines and a special place
numbers
look
at
to store
Writing Procedures
A procedure
is
list
BASIC
You move
such
lists
that will
become
to
same
list
of instructions
You
at
each
we
will
clear later.
You
a pair of instructions.
call a
i^fT" instruction.
Here
a simple
is
BASIC program,
write in machine language. This program calls a subroutine ten times, each
as follows:
DIM SHARED A
A = &H41
FOR
TO 10
DoPrint
A = A +
NEXT
SUB DoPrint
PRINT CHR$(A);
END SUB
QBasic
is
actually
much
sions of
BASIC
to use the
below, here
is
BASIC
the above
88
BASIC,
looks
more
like the
program rewritten
machine code we
in a primitive version
will write
of BASIC,
10 A = &H41
20 FOR
'ASCII for
A'
TO 10
30 GOSUB 1000
40 A = A +
50 NEXT
60 END
needed
line
numbers, by beginning
added
structions to be
of the subroutine.
to the
You
at line 1000 to leave room for more inmain program without affecting the line number
will
200h,
far
You
CALL
it is
will
location 200h.
at
lOOh.
200h, which
calls
at
also replace
GOSUB
the procedure at
memory
You will
starts
executing the
instructions at 200h.
The FOR-NEXT loop of the BASIC program (as you saw in Chapter 4) can
be written as a LOOP instruction. The other pieces of the main program (except for the INC instruction) should be familiar. They are as follows:
3985:0100 B241
MOV
DL,41
3985:0102 B90A00
MOV
CX,000A
3985:0105 E8F800
CALL
0200
3985:0108 FEC2
INC
DL
3985: 01 0A E2F9
LOOP
0105
3965:0100 CD20
INT
20
The
the
first
INT 21 h
instruction itself
That
alphabet.
is,
it
is
located
INC DL,
the
3985:0200 B402
MOV
AH, 02
3985:0202 CD21
INT
21
3985:0204 C3
RET
register,
new
enter at
because
DL
in
DL
DL.
in the pro-
DL
200h
is
as follows:
89
Assembly Language
for the
first
instruction
Type
(LOOP)
to see the
following the
CALL
in
P command
to see
run
to
CALL
LOOP
MOV
0200:
AH,02
0202: INT
21
0204: INC
DL
RET
0206:
it
Stack
so the
sees the
80x86
RET
memory known
registers that
in
will
know where
to
is
itself,
on the
there
is
a portion of
register,
two
which
points to the top of the stack, and the SS {Stack Segment), which holds the
segment number.
In operation, a stack for the 80x86
is
90
is
the
first
to
come
off,
so another
of trays in a
trays underneath.
name
for a stack
The
is
cafeteria,
last tray
LIFO,
on
for Last
is
precisely
make
396F:0100 E8FD00
CALL
0200
0300
396F:0200 E8FD00
CALL
396F:0203 C3
RET
396F:0300 E8FD00
CALL
396F:0303 C3
RET
396F:0400 C3
RET
nested
CALLs
0400
The instruction at lOOh calls one at 200h, which calls one at 300h, which calls
one
at
(RET)
RET
stack.
instruction at 303h,
Try entering
as the
program
and
CALLs
like the
RET
re-
instruction, at 300h, so
But there
it
encounters a
cess
instructions at 303h.
which
instruction. This
CALL
at
stack, so each
RET
follows the
calls,
and
trace
may not seem very interesting right now, there are other uses for this stack,
a good understanding of how it works will come in handy. (In a later
chapter,
you
will
stack
is
carefiil to restore
words of data
you
are
instruction /)5/; the return address (one word) onto the top of the stack, while
91
Assembly Language
register,
that
instructions
PUSH
it.
it
into the IP
You can do
to
the
push
Address
Stack
0098
SPrioo>
0100
0203
0102
0203
0104
It is
you
like
as
Programs are
built
from many
levels
By
at the end,
interactions
92
long
in
Chapter
13,
easier.
when we
discuss
restores
is
it)
that saves
and
CX and DX:
396F:0200
51
PUSH
396F:0201 52
PUSH
DX
396F:0202 B90800
MOV
CX,0008
396F:0205 E8F800
CALL
0300
396F:0208 FEC2
INC
DL
396F:020A E2F9
LOOP
0205
CX
396F:020C 5A
POP
DX
396F:020D 59
POP
CX
396F:020E C3
RET
Address
SPI98
>
Stack
0098
0303
0100
0203
0102
0203
0104
POPs
stack,
POP
93
Assembly Language
at
change these
registers in the
calls this
to
saved
variables
CX and DX,
this proce-
You will
as
you
become
registers
in
tasks.
to
As long
worry about
which
Chapter
programming
6,
is
now
will
want
to display
ing a
pass
it
function,
8h
into the
INT
Using
which
it
will
acter to a
94
number
(4 1 h)
8, that reads a
21
is
then echo.
hex number
will sift
02.
this function,
it
The
is
receives
3985:0100 CD21
on the
number between
ing an
to a hex
it
through
F),
as follows:
3985 0200 52
PUSH
DX
MOV
AH, 08
INT
21
CMP
AL,30
JB
0203
CMP
AL,46
3985:0206 77F6
JA
0203
3985:0200 3C39
CMP
AL,39
3985:020F 770A
JA
0216
3985:0211 B402
MOV
AH, 02
DL.AL
3985:0213 88C2
MOV
3985:0215 CD21
INT
21
3985:0217 2C30
SUB
AL,30
3985:0219 5A
POP
DX
3985:021A C3
RET
3985:0216 3C41
CMP
3985:0210 72E4
JB
0203
3985:021F 6402
MOV
AH, 02
3985:0221 88C2
MOV
DL.AL
3985:0223 CD21
INT
21
3985:0225 2C37
SUB
AL,37
3985:0227 5A
POP
DX
3985:0228 C3
RET
The procedure
to see if it
read
is
is
reads a character in
and JB
is
line
211h, you
know
that
the procedure.
treat the
The
you have
a valid digit
RET
both
as
as
unsigned
num-
signed numbers.)
between
(JA \sjump
and
result in the
9, so
you
AL regis-
two
two numbers
earlier treated
A through F
is
much
not a valid character, the conditional jump instructions sends the 80x86
ifAbove,
By
Reusable Code
AL,41
bers,
just one.)
Here
is
the same.
No-
a very simple
program
to
the procedure:
3985:0100 E8FD00
CALL
0200
3985:0103 CD20
INT
20
executing the
You
character.
Type
k,
which
93
Assembly Language
You should
value in
and so on.
number with
CALL
MOV
DL.AL
MOV
CL,04
SHL
DL.CL
CALL
0200
ADD
DL.AL
MOV
AH, 02
INT
21
INT
20
this
error handling
is
(the char-
the
program
0200
it
number
number you
in.
':'
fairly straightforward.
hex
you wrote
You
is
much
if it
instruc-
did complicate
valid
input.
You can
main program
dure
use
at
200h
stores the
to
hex number
change DL.
On
in
DX register in
DL,
so
the procedure.
The
200h must
be very
strict
registers
between procedures,
used by a procedure.
Summary
Your programming
is
becoming more
sophisticated.
You have
learned about
procedures, which enable you to reuse the same set of instructions without
96
rewriting
them each
time.
so
learned
how
You
You
You have
more than
instruction) at the
in a procedure.
By
write,
you can
registers are
CALL
armed with
this
to read
hex numbers
is
instruction)
registers in
POP
interactions
procedures that
Finally,
here
PUSH
you
that a
stack.
and seen
RET instruction
similar to
this time,
one you
Now you are ready to move on to Part II, where you will learn how to use the
assembler.
gram
to
The
as in this chapter,
pro-
97
Assembly Language
63T57r9A|75|B6|D2|FD
95
|8A
35
|6F^
#'
|47
|63
4A
H A
I
Welcome
to
the Assembler
In this chapter you will learn how to build programs using either the Microsoft
Macro Assembler or the Borland Turbo Assembler. Building programs with
the assembler is much easier than building them with Debug. You will learn
how to assemble and link programs and how to comment your programs and
use labels so they are easy to understand.
Topics Covered
Building a Program without
Debug
Looking
at Writestr in
Using
Debug
Comments
Using Labels
for
Summary
Code
Assembly Language
/\t
for the
long
last
you
are ready to
DOS
simpler.
From now
directly,
program
that will
mne-
bler,
how to
you will
get back
on course
details
effort.
on the assem-
in learning
how to write
assembly-language programs.
Building a
Program
without
Debug
Up
to this point,
structions.
grams without
create text, or
it,
you
will
files
named
is
You will
the
Debug
the
name
file
MOV
AH, 02
MOV
DL,2A
396F:0104 CD21
INT
21
396F:0106 CD20
INT
20
DOS's
named WRITESTR.ASM
bler source
file).
Here,
as
(the extension
1:
.CODE
MOV
AH,2h
MOV
DL,2Ah
3.
.ASM means
.MODEL SMALL
102
program you
To
built
refresh
and
your
case,
the
for the
version:
396F:0102 B261
a file
create a source
396F:0100 B402
to write pro-
memory, here
Use
human-readable
language program.
DEBUG and
leave
this
is
an assem-
as well as
upper-
INT
21h
INT
20h
Welcome
to the
Assembler
END
This
is
the
essary changes
in the
and
tells
after
numbers
is
3,
all
numbers
are decimal.
(see
You
but
an h
Chapter
program. This h
sembler assumes
in
it
after
each hex
numbers
number
are in hexadeci-
tell it
otherwise by placing an h
Figure 8-1).
The assembler can become conftised by numbers, such as ACh, that look
like a name or an instruction. To avoid this, always type a zero before a
hex niunber that begins with a letter. For example, type OACh
not ACh.
This
MOV
a label
DL,ACh
This
MOV
is
is
number
DL,OACh
The
tells
MASM
that this is a
number
llfM!
letter,
otherwise the
number as a name.
103
Assembly Language
for the
The following program demonstrates what happens when you assemble a pro-
gram with
SMALL
MODEL
CODE
MOV
DL.ACh
INT
20h
END
The output
is
as follows:
Microsoft
(R)
Copyright
(0)
ACh
C>
ACh
OACh
to
.MODEL SMALL
.CODE
MOV AH,2h
MOV DL,2Ah
INT 21
INT 20h
END
A bit of a mess;
we
do.
Now let's return to the three new lines in your source file. The three new lines
are
all
directives (also
of the source
Later on,
let's
you
file
on the assembler.
104
so the assembler
END
knows
is
fijrther discussion
The
it is
and directions
to the as-
finished
when
it
sees
But
an
END.
right
now,
Welcome
CI
to the
Assembler
you
are using a
disk
files
culprit.
word
WRITESTR.ASM,
of
lines
to actually assemble
mind
ASCII
one
that not
characters. Microsoft
save your
files.
DOS,
is
files
processor, bear in
there
type:
C>TYPE WRITESTR.ASM
You should
see the
characters in your
same
text
file,
word processor
You
will
DOS
and
need to read
this
you
END statement
(available in
you entered
gram
as
later) will
and
your
in
programs.
work well
file.
of
MASM
"ML /C WRITESTR.ASM",
finally a semicolon:
file
"MASM
You
DOS
will also
Edit pro-
a version
of
files.
MASM
Note
files.
you
The
like
treat as errors)
to enter
mand
mand
it.
need a blank
you entered,
Instead of using a
will
name (without
WRITESTR;".
com-
.ASM
extension),
use a slightly
command like
"ML /C WRITESTR.ASM", you will need to use the command TASM
followed by the file name (without the .ASM extension), and finally a
semicolon: "TASM WRITESTR;".
different syntax for assembling
files.
Instead of using a
105
Assembly Language
Now,
for the
let's
sembler, type
using Borland's
Turbo As-
WRITESTR. ASM
C>IIL /C
Microsoft
(R)
Copyright
(C)
C>
called
a lot of
an objectfile.
It
find
on your
disk.
produced a
This
is
file
called
an intermediate
DOS
program
called the
create an
EXE ver-
Linker.
it.
Link
WRITESTR.OBJ
OBJ
file
and
C>LINK WRITESTR;
Microsoft
(R)
Copyright
(C)
Version 5.13
LINK
warning L4021
LINK
no stack segment
C>
linker
ing a COM
file
(you
will see
Writestr.
106
to
is
why you might want a stack segment. You also can ignore the warning
see
how
all
of these
is
why later).
but
is
this
just
steps.
still
isn't
the
last step.
will create a
COM version of
For your
name
you
final step,
will use a
implies, converts an
EXE
difference between
EXE
and
file
now
Welcome
to the
to a
COM
files,
but
we won't
as its
There
file.
Assembler
is
COM
file
by typing the
following:
C>EXE2BIN WRITESTR WRITESTR.COM
C>
The
all
of the Writestr
tell
files
list
C>DIR WRITESTR.*
Volume in drive C has no label
Volume Serial Number is 191C-8737
Directory of C:\SOURCE\ASM
WRITESTR ASM
73 10-13-92
1:51p
WRITESTR OBJ
107 10-13-92
2:04p
WRITESTR EXE
520 10-13-92
2:07p
WRITESTR COM
8 10-13-92
2:12p
4 file(s)
708 bytes
Type
writestr to
properly
DOS
The
run the
(recall that it
results
first
may seem
three
little
files
become much
clearer
a bit.
anticlimactic, because
may vary
3.
You
when you
are not;
it
a great deal.
you
never once had to worry about where your program was put in memory, as
in
gramming much
easier.
200h.
You
For example,
main program
all
of the assembler:
it
will
make
immediately
after the
program looks
to
pro-
called at
procedure
how your
Debug.
107
Assembly Language
for the
Looking at Writestr
To
see
how Debug
Debug
in
WRITESTR.COM,
COM
read your
file
into
it,
as
follows:
397F:0100 B402
MOV
AH, 02
397F:0102 B22A
MOV
DL,2A
397F:0104 CD21
INT
21
397F:0106 CD20
INT
20
This
is
exactly
did not
These
make
directives
it
through
do not appear
of bookkeeping
are for
all.
3.
This
is all
Debug
What happened
in the final
of some extra
Using
Chapter
to
sees in
of your source
them?
at the cost
directives to simplify
when you
at
in
lines.
will see
Chapter
how
use of
1 1
Comments
Because you are no longer operating directly with Debug, you are free to add
more
to
your program that the assembler sees but won't pass on to the 80x86.
Perhaps the most important additions you can make are comments, which are
invaluable in
comments
BASIC
after a
or the
//
in
program you
108
an improvement
to think
mark
(')
comments
to
your
in
line after a
line
this
means.
MODEL
Welcome
to the
SMALL
Assembler
Many programmers
CODE
MOV
AH,2h
MOV
DL 2Ah
INT
21h
code
INT
20h
understand. Not!
'*'
't
need comments
to be printed
because well-written
is
easy to
be
able to understand
Using Labels
for
Code
to figure
oufw\\Y
the code
is
doing
To round
let's
which
book-
are another
comments should
your code
program
to another with
instructions.
part of
why
therefore say
in
is
doing
what
it's
doing.
jump
The assembler takes care of this problem with Libels names you
any instructions or memory locations. A label takes
As soon
as the
assembler sees a
it
on
label,
to the
it
replaces the
80x86,
as in
Figure 8-2.
DIGIT1:
labels.
109
Assembly Language
Labels can be
up
to 3
characters long
through
As a
9),
and
a period
The
old version
is
number.
It
MOV
AH, 01
INT
21
MOV
DL.AL
SUB
DL,30
CMP
DL,09
JLE
0111
SUB
DL,07
MOV
CL,04
SHL
DL.CL
INT
21
SUB
AL,30
CMP
AL,09
JLE
011F
SUB
AL,07
ADD
DL.AL
INT
20
fiinction of this
ments and
.MODEL
it
may
labels
They cannot
an ^f symbol
(.),
start
with a digit
11 F.
as follows:
your mind,
numbers, and
letters,
a period
The
($).
(?),
program
is
not obvious. If
makes
this
you
to
this
program
understand
program much
easier to
it
is
again.
not fresh in
Adding com-
understand
as follows:
SMALL
.CODE
character input
MOV
AH,1h
INT
21h
MOV
DL.AL
SUB
DL,30h
CMP
DL,9h
JLE
DIGIT1
SUB
DL,7h
;No,
MOV
CL,4h
;Prepare to multiply by 16
SHL
DL.CL
1,
and 9?
(four bits)
DIGIT1
110
Welcome
to the
Assembler
INT
21h
SUB
AL,30h
CMP
AL,9h
;Is it a digit
JLE
DIGIT2
;Yes,
SUB
AL,7h
;No,
Repeat conversion
9?
subtract 7h
DIGIT2:
ADD
DL.AL
INT
20h
;And exit
END
The
labels here,
because a colon
are of a type
when
we will
known
7V4^ labels,
The term
as
cover in Chapter
1 1
along with
DIGIT2
it
DIGIT 1
replaced by
replaced by OllFh.
Summary
This has been quite a chapter. In a way,
world.
it is
as if you
new
The assembler is much easier to work with than Debug, so you can now
begin to write
real
What have you learned here? You began by learning how to create a source file
and then you went through the
from an
OBJ
file
to
steps
COM
file,
from Chapter
3.
directives that
before, but
MODEL, CODE,
and
fact,
familiar once
Chapter
it
it
will
not be apparent
why
until
1 1
Ill
Assembly Language
for the
You may have wondered how you survived without comments. Comments add so much to the readability of programs that you should not skimp on them.
Next, you learned about comments.
Finally
able.
You
will use
book. Let's
all
move on
112
labels,
how
the assembler
rest
of
this
makes pro-
|c|h|a|p<t1e|r
Wnting
Procedures
Assembly
Language
in
in
die
this
This
is
WRITE_CHAR
and
WRITE_HEX
FUes altered:
VIDEO_IO.ASM
Topics Covered
\
of
A Program
Modular Design
Skeleton
Summar^
Assembly Language
for the
it is
You
will see
how
we
will return to
to write procedures
much more
with the help of the hard-working assembler. Then, you will move on to
Dskpatch program
You will
in later chapters.
like
MODEL, CODE,
1 1
and
where
will learn
first
program and
mentioned procedures, we
its
procedures so that
a large gap
left
for changes
You
built a small
does
all
CALL
MOV
DL,41
3985:0102 B90A00
MOV
CX 000A
3985:0105 E8F800
CALL
0200
3985:0108 FEC2
INC
DL
LOOP
0105
3985:0100 CD20
INT
20
3985:0200 B402
MOV
AH, 02
3985:0202 CD21
INT
21
3985:0204 C3
RET
as
in
and comments,
more readable
addresses to in-
so
shown
Chapter
It
7.
The program
appeared
did
as follows:
3985: 01 0A E2F9
work of assigning
A through J.
3985:0100 B241
labels
the
to leave a gap
116
it
without
Now you
It will
to
far
Listing 9-1
Writing Procedures
in
Assembly Language
SMALL
.MODEL
.CODE
PRINT_A_J
PROC
MOV
DL, 'A
MOV
CX,10
jPrint 10 characters,
CALL
WRITE,_CHAR
;Print character
INC
DL
LOOP
PRINT__LOOP
INT
20h
starting with A
PRINT_LOOP:
PRINT_A_J
Return to DOS
ENDP
WRITE_CHAR
PROC
MOV
AH, 2
INT
21h
RET
WRITE_CHAR
ENDP
PRINT A J
END
directives here:
at
200h
As you can
are
see,
PROC defines the beginning of a procedure; ENDP defines the end. The label in front of each
the
is
the
more readable
the procedure,
replace your
CALL 200
in
instruc-
the
name of
between
procedures.
The
you
main procedure
END
tell
^where the
tell
the assembler
which
to use
PRINT_A_J
is
the
By
writing
END
main procedure.
PRINT_A_J,
Later,
you will
are
117
Assembly Language
dealing with
in
for the
.COM files,
our source
and you
Now you
into a
called
file
will
first
file.
PRINTAJ.ASM
of
last
chapter.
.COM
Remember
version,
that
program
by using
you need
to use
ML /C PRINTAJ.ASM
LINK PRINTAJ;
EXE2BIN PRINTAJ PRINTAJ.COM
Ifyou encounter any
error messages that
you do not
try.
recog-
crash
program
when
Chapter
When
it
encounters the
INT 20h
EXE
before yon
run
Printaj.
you
will see in
1 1
you
the assembler
fits
example, type
Debug
to unassemble the
program and
Debug by
typing
its
name
as part
of the
see
command
how
a par-
line.
For
-u
MOV
DL,41
MOV
CX,000A
CALL
01 0E
INC
DL
3985 01 0A E2F9
LOOP
0105
3985 01 0C CD20
INT
20
MOV
AH, 02
INT
21
3985 0112 C3
RET
118
to print a
number in
hex,
and again
in
Chapter
7,
5,
where
where you
saw how
to simplify the
program by using
add
Writing Procedures
a procedure to print
MOV
MOV
0100
0102
0105
0108
CALL
LOOP
01 OA
INT
in
Assembly Language
one hex
digit.
one character.
DL,41
CX,OA
01 OC
0105
20
t
01 OC
MOV
AH,02
01 OE
INT
INC
21
0110
0112
Figure 9-1:
DL
RET
By using a central procedure to write a character to the screen, you can change
way this procedure writes characters without affecting the rest of the pro-
the
gram.
It will
file
New
File
the
file
VIDEOJO.ASM (VIDEO_9.ASM)
SMALL
.CODE
TEST_WRITE_HEX
PROC
MOV
DL,3Fh
CALL
WRITE_HEX
continues
119
Assembly Language
Listing
for the
9-2 continued
INT
PUBLIC
20h
Return to DOS
ENDP
WRITE_HEX
This procedure converts the byte in the DL register to hex and writes
the two hex digits at the current cursor position.
On Entry:
DL
PROC
;Entry point
PUSH
CX
PUSH
DX
MOV
DH.DL
MOV
CX,4
SHR
DL.CL
WRITE_HEX
procedure
CALL
WRITE_HEX_DIGIT
MOV
DL,DH
AND
DL,0Fh
CALL
WRITE_HEX_DIGIT
POP
DX
POP
CX
RET
WRITE HEX
PUBLIC
ENDP
WRITE_HEX_DIGIT
DL
WRITE CHAR
Uses:
WRITE_HEX_DIGIT PROC
120
PUSH
DX
CMP
DL,10
JAE
HEX LETTER
;No,
convert to a letter
Writing Procedures
in
Assembly Language
ADD
DL,"0"
;Yes,
JMP
Short WRITE_DIGIT
DL,"A"-10
CALL
WRITE_CHAR
POP
DX
convert to a digit
HEX_LETTER:
ADD
WRITE_DIGIT:
RET
WRITE_CHAR
PUBLIC
function call.
On Entry:
DL
WRITE_CHAR
PROG
PUSH
AX
MOV
AH, 2
INT
21h
POP
AX
RET
WRITE CHAR
ENDP
END
The
DOS
some
of
;And return
is
a small
diamond. You
will see a
new version
WRITE_CHAR that will print a diamond in Pan III, where you will learn
about the
use the
ROM
DOS
BIOS
IBM
will just
The new directive PUBLIC is here for future use. You will also use this directive in Chapter 1 3 when you learn about modular design. PUBLIC simply tells
the assembler to generate some more information for the linker. The linker
allows
source
you
files,
the procedure
named
after the
PUBLIC
PUBLIC
from
different
directive should be
made
public, or
files.
121
Assembly Language
for the
ing
many
procedures to the
file as
as a
hex num-
book,
The procedure
what
main program
it
says:
it
TEST_WRITE_HEX
tests
WRITE_CHAR.
WRITE_HEX,
As soon
procedures,
three
you
as
you
that
just
WRITE_HEX_DIGIT
and
which uses
TEST_WRITE_HEX
remove
will
from
VIDEO_IO.ASM.
Create the
WRITE_HEX. Change
the
3Fh
tried in
at
memory
location
two
to
thoroughly
lOlh
to each
digits 0, 9,
digits),
test
of the
A, and F in
then use
to
run
TEST_WRITE_HEX.
You will
use
many simple
test
programs to
test
new procedures
it all
at once.
new
that
you have
much
faster
and
code.
The Beginnings
of Modular Design
Note
we have
included a block of
and
comments
tell
which
forth, as well as
registers the
it
uses.
at the description.
There
it
is
to use
no need to relearn
call
As one
feature of your
any procedure by
it.
We have also used PUSH and POP instructions to save and restore any registers used within each procedure. We will do this for every procedure we write,
except for test procedures. This approach, too,
..
__
will
be using.
is
we
Recall that
save
and
restore
any
'~]
Writing Procedures
register
we
used so
in
Assembly Language
about complex interactions between procedures trying to fight over the small
number of registers
ters as
it
in the
provided
likes,
it
them before
is fi-ee
the
to use as
RET
many
instruction.
regisIt is
small price to pay for the added simplicity. In addition, without saving and
restoring registers, the task of rewriting procedures
You would be
Also
the
tr)'
sure to lose
many
to use
programming
when
cedures
much
sometimes we
will all
for example,
we
would be mind-rending.
on the
will
to
screen.
A Program Skeleton
As you have seen
certain
need
in this
to write a
tell
you
for
is
as fol-
lows:
.MODEL
SMALL
.CODE
Some_procedure
PROC
20h
INT
Some_procedure
END
ENDP
Sonie_procedure
We will
You can
use
it,
as
shown
directives to this
program skeleton
Or, you can use some of the programs and procedures from
starting point.
in later chapters.
book
as
your
1
23
Assembly Language
Summary
You
are really
the time.
By
this chapter,
to
manageable.
that a procedure begins with a PROC definition and ends with an
ENDP directive. We rewrote PRINT_A_J to test your new knowledge of pro-
You saw
went on
cedures, then
to rewrite
is little
more procedures. In
many
briefly
fact,
you
small procedures.
Modular programs
will
be easier to write and easier to read. They will also be easier for someone
else
phy
to
you
and
effort.
logic
programs
design.
many interactions.
will learn
larger
124
this
will
move on
1 1
to developing
of modular
H A
Printing in
Decimal
In
this
notation.
You will
also learn
about a few
their programs,
tricks that
Files altered:
VIDEOJO ASM
VIDEO
You will
You
will learn
about the
XOR
and the
file:
in decimal
(exclusive or)
Disk
number
10.
ASM
Topics Covered
Reviewing the Conversion to Decimal
i
The
Shortcuts
WfelTE.DECIAVKL
Summary
Assembly Language
for the
we would
effort.
to shorten
But
if you
there.
word
will find
you will also learn about two new types of logical operations
a
word
to
add
tricks,
to the
AND
let's
to decimal digits.
Reviewing the
Conversion to Decimal
Division
is
12345/10
yields
example, 5
is
1234
left,
left.
digit. If
and
its
and 5
remainder. Calculating
as the
you divide by
Repeated division by
DIV
strips
remainder. In this
1
again,
you
will
The
top digit
neath
it.
remainders
shown
128
is
the
So, if you
as
first digit
in
as
you
calculate
in Figure 10-1.
digits are
them and
under-
print the
in correct order, as
10
Printing in
Decimal
12345
Stack
Figure 10-1:
The
following program
is
You
it
will get to
are a
few
tricks
let's try
number
in deci-
WRITE_DECIMAL to see if
works.
Place
Make
sure
along
you place
WRITE_DECIMAL ^/^r TEST_WRITE_HEX, which you will be replacing with TEST_WR1TE_DECIMAL. To save some work,
WRITE_DECIMAL uses WRITE_HEX_DIGIT to convert one nibble (four
bits) into a digit.
listing in
WRITE_DECIMAL
129
Assembly Language
for the
DX
Uses:
WRITE_DECIMAL
PROC
PUSH
AX
PUSH
CX
PUSH
DX
PUSH
SI
MOV
AX.DX
MOV
SI, 10
XOR
CX,CX
XOR
DX,DX
DIV
SI
PUSH
DX
INC
CX
OR
AX, AX
;N =
JNE
NON_ZERO
;Nope, continue
NON_ZERO:
yet?
WRITE_DIGIT_LOOP:
POP
DX
CALL
WRITE_HEX_DIGIT
LOOP
WRITE_DIGIT_LOOP
END_DECIMAL:
POP
SI
POP
DX
POP
CX
POP
AX
RET
WRITE DECIMAL
ENDP
you
will see
ther, the
why
it
DI, or Destination
WRITE_DECIMAL
as if
You
will also
registers
meet
have special
its
Later
bro-
uses,
but
registers,
we used
SI,
even
though we could have used BX, simply to show that SI (and DI) can serve
general-purpose registers
130
if
need
be.
as
10
Printing in Decinnal
VIDEO_IO.ASM.
insert the test
First,
PROC
MOV
DX, 12345
CALL
WRITEDECIMAL
INT
20h
This procedure
Return to DOS
ENDP
tests
WRITE_DECIMAL
these changes
and
give
VIDEO_IO
a whirl.
Convert
file
it
to
its
.COM
in
who
(IBM used
sharing
is
wrote the
The first is an efficient instruction to set a regmuch more efficient than MOV AX,0, and perhaps it is
ister to zero. It
here
tricks
The
is
not
effort,
but
it is
following instruction
sets the
you
will find
people using, so
AX register to zero.
131
Assembly Language
for the
AX, AX
XOR
How? To
understand
that,
we need to
The exclusive
of
OR
is
similar to an
is
XOR.
true if only
one
bit
is
XOR
true,
not
if
both are
true.
Thus,
if you exclusive
10 10
110
XOR 10
OR a number to
10
10
you
itself,
get zero:
0000 0000
That
is
the trick.
You won't
book, but
As a short
aside,
you
find
it
many people
interesting.
AX register to zero:
AX, AX
Now for the other trick. It is just about as devious as our XOR scheme to clear
a register,
and
it
it is
and
little
more
struction with a
JNE (Jump
^Jump
if
if
Not
Not
we
OR the OR function.
zero.
To do
this,
write
OR AX,AX
we
It's
could use
more
fiin,
(We could
also
Zero.)
OR instruction, like any of the math instructions, sets the flags, includtrue
ing the zero flag. Like AND, OR
a logical concept. But here, a result
The
is
if
132
one
is
true.
is
10
OR
Printing in
Decimal
If we take a
OR
number and OR it
10 11
10
10 11
10
10 11
10
to
itself,
The OR instruction is also useful for setting just one bit in a byte. For example,
we can set bit 3 in the number we just used:
10 11
10
OR 0000 1000
10 11
There
these
will
two
110
this
book, but
WRITE_DECIMAL
To see how WRITE_DECIMAL performs its task, study the listing; we won't
cover many details here. However, we do need to point out a few more things.
First,
the
stack, so
CX register
is
used to count
to remove.
LOOP instruction
CX register to store the repeat count. This choice makes the digitoutput loop (WRITE_DIGIT_LOOP) almost trivial, because the LOOP
instruction uses the CX register directly. You will use CX often when you
convenient choice, because you can build a loop with the
133
Assembly Language
for the
tion at
problem,
as
at
lOlh
to
65535 (FFFFh).
if you
(WRITE_DECIMAL
numbers.)
You must be
An
(at least
E command does),
the
80x86
stores
MOV instruction
is
as
follows:
3985:0100 BA3930
You can
tell
MOV
DX,3039
102h
is
30h (BA
is
the
at
is
39h,
The order
A word consists
byte
is
of two
parts, the
lower
b\T:e
The lower
b)T;e.
the least significant byte (39h in 3039h), while the upper byte
as
you can
makes
is
the
sense, then,
puter architectures, such as the Motorola 680x0 family used in the Apple
this
if
Use
unassemble the
134
for the
word
starting at
TEST_WRITE_DECIMAL
first
instruction.
h,
to see if
see
you got
it
how this
right, or
10
MOV
0102:
30
0101:
39
0100:
BA
Printing in Decinnal
DX,3039
3039h
MOV
instruction
the
Summary
You added a few new instructions to your repertoire, as well as a few tricks for
fiin. You also learned about two other registers, SI and DI, that you can use as
general-purpose registers. They have other uses that you will see
in later chapters.
You
AX
register to zero.
equivalent of
CMP AX,0
to test the
word
in
if it is zero. Finally,
memory by checking
WRITE_DECIMAL.
that
Take a breather now. We've got a few different chapters scheduled next. Chapter
1 1
Even
so,
we need
135
Assembly Language
for the
After that,
learning
on
disks,
you
what
will
to
make
and
get
back on track by
sectors, tracks,
a bit
of probing
things.
From there, we can plot a simple course for preliminary versions of Dskpatch.
En route, you will get a chance to see how to develop large programs. Programmers don't write an entire program, then debug it. They write sections
and try each section before they move on programming is much less work
that way. You have used this approach to a limited extent by writing and test-
ing
WRITE_HEX
and
WRITE_DECIMAL,
for
which the
test
programs
were very simple. The test programs from here on will be more
complex, but more interesting, too.
136
Segments
In
this chapter
you
will learn
for controlling
large programs,
Files altered:
None
opics Covered
How Memory
Is
The Stack
The Program Segment
The
DOSSEG
NEAR
and
Prefix (PSP)
Directive
FAR CALLs
Instruction
Interrupt Vectors
Summary
Assembly Language
In
for the
you encountered
segments.
80x86 manages
the
to address a full
under
own
with
Now the time has come to look at segments themselves, and at how
80x86
needed
for a full
and
in later chapters
level
it
you
one).
megabyte of memory.
Segments
Segments are about the only part of the 80x86 that you have not covered
They
are,
pan of this
call
microprocessor. In
computerese
for a
yet.
fact,
make-
shift fix to a
problem.
The problem,
in this case,
is
mode).
65535
is
the largest
64K of memory
number
a single
word can
hold. Intel, designers of the 80x86, used segments and segment registers to "fix"
this
So
far,
to
worry about
this
problem.
using
80x86
ter.
is
But we never
actually
really said
how.
is
CS
register
and the IP
regis-
registers, the
80x86 does
not form a two-word number for the address. If you were to take CS:IP
32-bit
140
to
number (two
16-bit
numbers
side
as a
11
DOS. The
far
more than
80x86's method
is
slightly
The CS
segment
is
it
Segments
can
more complicated.
64K of memory.
80x86 divides memory into many overlapnew segment starting every 16 bytes. The first segment
(segment 0) starts at memory location 0; the second (segment 1) starts at lOh
(16); the third starts at 20h (32), and so on.
As you can
0000:0000
Segment
65,535
0001:0000
16
0000: FFFF
t
65,551
0001:FFFF
The
actual address
contains
3FA8 and
is
just
CS
DO 17,
IP contains
if
the
long.
CS
is
register
evident as
follows.
CSM6 :00
+
IP
1111
1010 10000000
:1101000000010111
0011001010 10010111
1
141
Assembly Language
We
for the
multiplied by 16 by shifting
you can
right, as
see in Figure
CS
left
1-2.
|o|o|i|i|i|i|i|i|i|o|i|o|i[o|o|o]
<J3
Segment (CS)
|1|1|0|1|0|0|0|0|0|0|0|1|0|1|1|1|
Offset
(IP)
01001100101010010111
Figure 11-2: The absolute address ofCS:IP
is
CS
this
but
The 80x86
been looking
tion
is
Before
at
stored. In
for data,
IP.
and SS
we go
Segment),
(Extra Segment).
The CS
DS
(Data Seg-
register
you have
much the same way, DS is the segment where the 80x86 looks
where the 80x86 places the
is
on,
let's
look
at a short
Listing 11-1
ES
CS (Code
used by the 80x86 for the segment where the next instruc-
is
16 +
may seem like a strange way to address more than 64K of memory
how well it really works.
Now,
it
file
stack.
program, which
program
TEST_SEG.ASM
uses
two
is
quite different
from
as follows:
jAllocate a IK stack
STACK
.CODE
TEST_SEGMENT
AH 4Ch
INT
21h
;Return to DOS
TEST_SEGMENT
END
142
PROG
MOV
ENDP
TEST_SEGMENT
11
and
COM
file
for
it.
Segments
link in
different
from
step!)
The
COM
result will
be
TEST_SEG.EXE, which
is
slightly
file.
3985:0000
PSP
-100h bytes
3995:0000
20h bytes
3997:0000
Figure 11-3:
You have to
files.
For
at all for
as
you
use a
COM
files,
but
it
from EXE
doesn't
Note
work
on you
in order to exit
will use
INT 21h,
more on
function
4Ch
From now
to exit programs.
143
Assembly Language
for the
When you
the
use
Debug on
COM
file,
first
256
Debug sets
all
from the
start
we will
need,
an
see
EXE file.
C>DEBUG TEST_SEG.EXE
R
AX=0000
BX=0000
CX=0004
DX=0000
SP=0400
DS=3985
ES=3985
SS=3997
CS=3995
IP=0000
3995:0000 B44C
The
as
you can
SI=0000
DI=0000
NV UP EI PL NZ NA PO NC
AH,4C
MOV
values of the SS
BP=0000
and CS
from those
for
DS
and ES
1-3.
The Stack
Two
is
this
program. The
STACK
segment (which
is
is
actually called
_TEXT)
is
where
all
your
in-
byte stack.
The
like
IP
is
is
create a stack
given by SS:SP.
is
an
SP
is
offset
Stack Segment.
Actually, "top-of-stack"
is
you defined
in
memory. Here, SP
a stack area
144
is
is
really at the
400h, which
is
is still
at the
top of the
memory you
11
back
If you think
declare a stack
segment
COM programs?
and
all
Segments
to the
CD
which
Why didn't
two questions:
raises
you have
to
for
All the
to this segment.
Since you had just one segment, you didn't need a separate stack segment. As
to
you
if you
is
at the
The stack
as follows:
is
AX=e000
Bx=e000
CX=0000
DX=0000
SP=FFEE
DS=3995
ES=3995
SS=3995
CS=3995
IP=0100
3995:0100 B402
MOV
BP=0000
SI=0000
DI=0000
NV UP EI PL NZ NA PO NC
AH 02
,
DOS always sets the stack pointer to the very end of the segment when
a
COM
file
into
memory. For
.STACK
directive
for
from
this reason,
it
loads
to declare a stack
if you
removed
C>DEBUG TEST_SEG.EXE
R
AX=0000
BX=0000
CX=0004
DX=0000
SP=0000
DS=3985
ES=3985
SS=3995
CS=3995
IP=0000
MOV
3090:0000 B44C
The
stack
is
BP=0000
SI=0000
DI=0000
NV UP EI PL NZ NA PO NC
AH,4C
is
at SS:0,
it
has no
Always declare a
stack segment with
.STACK in EKE
programs.
down in memory). For these reasons, you must declsu^c a stack segment for EXE
programs.
Getting back to the two-segment example, notice that the Stack Segment (SS)
is
is
at
unassembling starting
INT
at
(this will
segment 3995
two
less
145
Assembly Language
for the
u cs:e
3995:0000 B44C
MOV
AH, 40
3995:0002 CD21
INT
21
3995:0004 65
DB
65
3995:0005 2028
AND
[BX+SI],CH
3995:0007 59
POP
CX
3995:0008 2F
DAS
3995:0009 4E
DEC
SI
3995:000A 293F
SUB
[BX],DI
INT 21h
in this
Prefix
(PSP)
The
is
actually called a
PSP (Program
Segment Prefix) and
contains information for use by
DOS.
registers
less
lOOh
(or
may
COM
starts.
This
is
DS
at seg-
see that
the
same
file.
In other words, do
make
use
ofthis
area.
this
at the start
starting at
start
of
146
3985:0080
39 20 41 6E 64 20 6E 6F-77 20 66 6F 72 20 73 6F
3985:0090
6D 65 20 63 68 61 72 61-63 74 65 72 73 20 77 65
me characters we
3985:00A0
27 60 60 20 73 65 65 20-69 6E 20 74 68 65 20 6D
3985:0060
65 6D 6F 72 79 20 64 75-6D 70 0D 20 6D 65 6D 6F
3985:0000
72 79 20 64 75 6D 70 0D-00 00 00 00 00 00 00 00
ry dump
11
The
first
39h
The PSP
INT 20h
EXE
program. The
4Ch
You should
of the PSP.
uses
when
exiting
from
it
a pro-
does for a
exit ftinction
DOS
book, but
in this
or the
clear, the
an
Segments
use
INT 21h,
grams.
The code for COM files always starts at an offset of 1 OOh in the code segment
to leave room for this 256-byte PSP at the start. This is unlike the EXE file,
which had
its
code
start at
memory.
written as
COM
most
EXE
programs. So in the
entirely with
between
EXE
rest
all
programs
programs are
al-
DOSSEG Directive
The
you take
segment
The
is
a look again at
higher in
DOSSEG directive at the start of the program tells the assembler that you
last.
more about
ment
first,
DOSSEG and the order of segments when you add another seg-
to hold data.
147
Assembly Language
for the
Memory
layout for
.COM
programs
SS
Program, data,
and stack
lOOh
SP
Memory
programs
DS, ES
>
CS:IP
Program
SS
Data segment
Stack area
SP
Figure 11-4:
148
11
Segments
rest
of the information
in this chapter
them
later if
it
is
in this
back to
programming.
Let's step
back for
where you
short program
first
let's
MOV
DL,41
3985:0102 B90A00
MOV
CX,000A
3985:0105 E8F800
CALL
0200
3985:0108 E2FB
LOOP
0105
3985: 01 0A CD20
INT
20
see
look
CALL
CALL
instructions
in
Chap-
You wrote
a very
program
at the short
instruction.
3985:0100 B241
As you can
by looking
at the
The
first
left,
byte
byte, so
(108h
you have
NEAR,
NEAR CALLs
like
which
known
is
64K bytes
is
long.
larger than
So
that
how is
it
CALLs
that
you
calls.
times
uses a single
rather than
offset.
as intrasegment
CS
register.
change
CALLs.
You can also have FAR CALLs that change both the CS and IP registers. Such
CALLs are often known as intersegment CALLs because they call procedures
in other segments.
these
Assembly Language
single
for the
word onto
In the case of
word
its
return address.
in-
FAR CALLs
and RETs,
word
is
dealing with another segment. In other words, you need to save a two-word
return address on the stack: one
one
CS
for the
How does
register,
the assembler
know which
for IP.
of these two
to use?
When should it use the FAR CALL, and when should it use the NEAR CALL?
By putting a NEAR or FAR directive after the PROC directive. By way of
example, look at the following program:
PROC ONE
PROC
FAR
RET
PROC ONE
ENDP
PROC_TWO
PROC
CALL
NEAR
PROC ONE
RET
PROC TWO
ENDP
When
This definition
In the case of a
conversely,
it
generates a
FAR CALL, as shown in Figure 1-5, if the proceas a FAR procedure. In other words, the as1
For the
RET
150
w determine
needed.
is
RET
PROC_ONE will
instruction. In
be a
FAR RET,
shown
in Figure
RET
1
instruc-
1-6, because
PROC_ONE
PROC TWO
is
is
declared to be a
a
FAR
11
[1
RET
in
Segments
NEAR RET.
1
PROC_TWO
PROC
NEAR
PROC_ONE ^
CALL
FAR CALL
RET
PROC_TWO
ENDP
PROC_ONE
PROC
FAR
RET
PROC_ONE
Figure 11-5: The assembler produces a
PROC ONE
FAR CALL.
PROC
FAR
FAR
HET<
PROC ONE
ENDP
ENDP
Return
FAR RET.
What happens when you don't put a NEAR or FAR directive after the PROC?
The assembler uses the information in the .MODEL directive to determine
NEAR or FAR if you don't explicitly declare a proceNEAR or FAR. We're using the .MODEL SMALL directive, which
as
tells
are
NEAR
MEDIUM)
tell
explicitly declared as
the assembler to
.MODEL
so
all
the procedures
directives (such as
if
NEAR.
151
Assembly Language
for the
Instruction
The INT instruction is much like a CALL instruction, but with a minor difference. The name INT comes from the word interrupt. An interrupt is an
external signal that causes the
to
80x86
to execute a procedure
When
80x86
the
it is
interrupt.
treated as if it did.
receives an interrupt,
it
two words
flag,
the carry
the zero
flag,
this
information onto
Your IBM
inside your
ond, for example. Each of these interrupts causes the 80x86 to stop what
pulses.
Now,
it is
envision such
AH,
JNE
N0T_2
Assiune
means
AH = 2, so the zero flag will be set after the CMP instruction, which
that the
Now, imagine
tions.
it
JNE
instruc-
checks the zero flag (with the JNE instruction). If the 80x86 didn't save and
flags,
end
CMP
instruction.
and an IRET
-^
INT 21
inter-
The same
is
true for an
INT
in-
I)
An
like this:
Top Of stack
To
152
NOT_2.
11
into lower
memory,
so the
Old
Flag Register
Why save
a very
good reason
without
Debug uses
the
80x86
trace
the
for saving
this feature.
it
80x86
issues
mode known
an
INT
after
as single-step
it
at a time.
INT
external interis
no. There
INT instructions.
In
Trap
Flag.
This
mode. Debug
WTien the
flag puts
uses this to
trap flag
is set,
in single-step
mode
80x86 won't be
the trap
flags for
surprise.
possible.
into a special
when an
no
is
The INT
the interrupt
fact,
actually high-
is
memory.
is
Segments
procedure. Since
INT
Then, you
will receive
you
is
another
just
INT
it is
useful to
always appropriate.
Some
interrupt procedures bypass the restoration of the flag registers. For ex-
ample, the
INT 21h
procedure in
DOS
process.
Many
of the
flag registers
INT 21h
dures that read or write disk information return with the carry flag set
sort (such as
no disk
proceif there
in the drive).
Interrupt Vectors
WTiere do these interrupt instructions get the addresses for procedures? Each
interrupt instruction has an interrupt number, such as the
The 80x86
tors,
which
21h
in
INT
21h.
located at the
INT 21h
procedure
is
number by 4
at
(4 *
21h
this address
= 84h), because
we need
by
four
153
Assembly Language
for the
you
DOS
We will use this trick at the end of this book to add a disk
We will
on
course.
Summary
This chapter contained a
lot
of information.
You won't
use
it all,
need to learn more about segments. Chapter 13 covers modular design, and
you
will use
You began
ments.
To
some
aspects of segments to
this chapter
easier.
detail,
you
built
with two different segments. You also learned that you need
function
ponant
You
4Ch
since
also
rather than
you
will
INT 20h to exit from EXE programs. This is imEXE programs from now on in this book.
be using
sets
into seg-
EXE program
to use INT 21h,
an
Prefbc) at
You won't use this knowledge in this book, but it helps you see why DOS
aside such a large chunk of memory for the purpose.
Finally
directives.
These
all
segments. In this book, you will barely use the power of these directives, because our
MEDIUM memory
model), these directives are invaluable. If you are interested, you will find the
details in
154
Segments
11
At the very end of this chapter you learned more about the roots of the helpful
INT
instruction.
to write larger
Now, you
and more
down and
learn
how
155
H A
I
Course
Corrections
How To Bufld
Dskpatch
In
this
None
will
Topics Covered
Disks, Sectors,
and So Forth
for Building
Summary
Dskpatch
Assembly Language
and
interesting places.
aimlessly.
We
Then you
you
as
We will
will
will later
spend the
rest
of
this
own.
way we wrote
stage of your
want
to go.
it.
we will
Instead,
program
as
you write
at once; that
is
not
it.
will deal
with
Disks, Sectors,
and So Forth
The information on your floppy disks
512 bytes of information.
ted with
is
divided into
sectors.
DOS 2.0 or above has a total of 720 sectors, or 720 * 512 = 368,640
bytes (see Table 12-1 for other types of disks). If you could look direcdy at
these sectors,
on the
the
files
use
Debug
disk.
to learn
You cannot
more about
not by
sectors
directly, or
but Dskpatch
yourself
and
get an idea of
at
will. Let's
how you
will dis-
Debug
has a
command, L
number
tor 5
on
As an example,
let's
look
memory
in drive
158
at the data.
A (drive
(or
what
in drive A, then
12
Course Corrections
C\
Sectors/disk
Directory
5-1/4"
360K
720
5h
5-1/4"
1.2M
2,400
Fh
3-1/2"
720K
1,440
7h
3-1/2"
1.44M
2,880
13h
As you can
at
an
offset
of 100 within
Address to load
segment at
Sector
number
-L 100
5
Disk drive
A
Figure 12-1:
To
Number
of
sectors to read
display sector
5,
Dump command as
follows:
D 100
396F 0100
49 42 4D 42 49 4F 20 20-43 4F 4D 27 00 00 00 00
396F 0110
00 00 00 00 00 00 00 60-68 06 02 00 00 12 00 00
396F 0120
49 42 4D 44 4F 53 20 20-43 4F 4D 27 00 00 00 00
396F 0130
00 00 00 00 00 00 00 60-68 06 07 00 00 43 00 00
396F 0140
43 4F 4D 4D 41 4E 44 20-43 4F 4D 20 00 00 00 00
396F 0150
00 00 00 00 00 00 00 60-68 06 18 00 00 45 00 00
396F 0160
41
396F 0170
00 00 00 00 00 00 33 9C-6e 06 00 00 00 00 00 00
53 53 45 4D 42 4C 45-52 20 20 08 00 00 00 00
IBMBIO
COM'
'h.
IBMDOS
COM'
'h.
C.
COMMAND COM
'h.
ASSEMBLER
3.0.
E..
159
Assembly Language
for the
P
396F:0180
46 57 20 20 20 20 20 20-43 4F 4D 20 00 00 00 00
396F:0190
00 00 00 00 00 00 00 00-6F 05 2A 00 80 AF 00 00
396F:01A0
46 57 20 20 20 20 20 20-4F 56 4C 20 00 00 00 00
396F:01B0
00 00 00 00 00 00 00 00-72 05 56 00 81 02 00 00
396F:01C0
46 57 20 20 20 20 20 20-53 57 50 20 00 00 00 00
396F:01D0
00 00 00 00 00 00 98 8A-FF 06 57 00 00 C8 00 00
396F:01E0
43 4F 4E 46 49 47 20 20-44 41 54 20 00 00 00 00
396F:01F0
00 00 00 00 00 00 ID 82-A1 06 89 00 00 28 00 00
We will
use a format
Dskpatch
will
will
much
FW
COM
FW
OVL
FW
SWP
CONFIG
DAT
o. *../..
r.V
W..H..
(..
You
be able to display sectors on the screen and move the cursor about the sector
display,
as
is
will also
be able to
characters in
the name.
Dskpatch
is
an end in
itself.
It is
by no means
we
will also
your
procedures for display output, display manipulation, keyboard input, and more.
sector
MS-DOS
IBM PC
was designed
characters
can display.
to run
on many
Why is
different
author of
Debug
but no one
Dskpatch
ters
with a
is
for
bit
PC
and
as 7,
which
in Part III
for
all
characters.
you
other characters.
will learn
Debug
Most com-
to continue to
such
at
all
no reason
is
The
DOS
There
256
difi^erent charac-
However,
how
all
You
to display them.
We will also make heavy use of the fiinction keys so that you can display the
next sector by pressing the F4 key.
160
to that byte
You will
and typing
also be able to
in a
new number.
It will
be just like
12
using a
word
processor,
Course Corrections
easily
details will
normal display
will
look
like
a vast
its
Debug.
88 81 82 83 84 85 86 87 as 89
ee
IB
28
38
48
58
68
78
88
98
ne
B8
C8
De
EB
FB
tS3t3C
82 EB
88 88
28 28
C8 8E
IB 53
BF BB
CD 13
89 BE
16 IE
7C
fiS
IE BB
88 BB
BB 81
ft6 75
E8 5F
98
BB
88
28
D8
BF
BE
72
28
7C
49
7C
88
E8
8A
ee
4D
44 4F
48 BB FB 89
88 BB ee 29
28 28 2e 46
BC BB 7C 16
3E 7C B9 BB
18 7C 88 4D
79 33 C8 39
7C ne 18 7C
83 86 BE 7C
7C 89 16 4B
83 C3 48 F7
85 8B 16 52
ftC 88 72 16
8D 7F 28 B9
33 C8 CD 16
Bfl
53
2E 38
88 12 88 82
F8 IB 6E 48
41 54 31 32
87 BB 78 ee
88 FC F3
F9 89 47 82
86 13 7C 74
F7 26 16 7C
83 D2 ee 03
7C B8 2e 88
F3 81 86 49
7C 01 58 7C
8B FB B9 BB
BB 88 F3 ne
5E IF SF 84
8B BC BD BE BF
Be
BB
42
28
36
86
C7
88
83
58
F7
7C
E8
BB
74
8F
812345G789nBCDEF
'02 81 81 ee
88
52
2B
C5
88
41
28
37
IF C6
87 3E
BB BE
86 IC
7C 89
26 11
83 16
92 88
BE E6
18 BE
44 82
^eHSD0S5.8 OQQ
BB 88
44 59
Ffi
IE
45
7C
13
7C
16
7C
4B
72
7D
9E
CD
ai
e<{<>
jo^^nSBRflDV
FfiT12
3
33
56
FE
FB
7C
13
52
i.-Hx 6+7 AU
l(=i^
_St>!{|<J "<n|=E
)ti4T:eMeG8l|<>:i
=!!ra3L9!!!tflifl!!!
e4
:a'
!=-:<-:!!
_A!*4!ai, uPie-R
=< i
A3:<f[=<Q*i:i.K;
+i_R! iP;0(t rT)
esu r-ij-flrf Jfy<
8B
!uI!e_K!=i
7C
ID
F3
7D
'uHU
i|<f
mtJR}
3 l=_"DO=i
19
source
files.
you
will learn
how to
Even
together.
here
when
if
files
for
in
many different
Chapter
all
these programs
to
14.
At
to be linked
now,
they'll
be
general-purpose procedures. In any case, you will get a better idea of how to
write long programs as
You have
memory
WRITE_HEX to
and WRITE_DECIMAL to write a
number
Now, you will write some programs to display a block of
much the same way Debug's D command does. Start by display-
number
chapters.
in decimal.
in
work toward
Assembly Language
for the
we have chosen,
display of
half a sector.
bytes from
Dskpatch includes
so
after
you have
memory, you
built a full-screen
will build
half a sector
on the
With
sector
screen,
dump
and you
will
be able to use
different sectors.
Debug
attractive, display, so
making
it
pretty
another proce-
You
dure to read a sector from the disk into our area of memory.
will
dump
will
have a func-
comes
next.
more work and some more procedures, you will rebuild the halfdisplay to be much more pleasing aesthetically. It still won't be a full-
a bit
screen display, so
display will
that allow
it
come
you
ready to learn
next,
and you
Debug's
about
will learn
how to
characters.
Next will come the keyboard input and command procedures so you can
interacting with Dskpatch.
About
you will
that time
also
start
correction.
Summary
You have
groundwork
for
let's
move on
Then,
162
in
Chapter
14,
a better idea of
Chapter 13
to split a
test
will lay
program
procedures
H A
I
Modular Design
Building
Programs
in
Pieces
In this chapter you will learn how to break your programs into more than one
You will also learn more about modular design, which is the foundation
file.
FUes altered:
Disk
files:
is
will take a
look
at Microsoft's
files.
Pro-
complex
Topics Covered
Separate Assembling
of
Modular Design
Summary
Assembly Language
ithout
sets
some ground
to write.
rules for
rest
different source
will
how
to
files.
Separate Assembling
In Chapter 10,
we added
VIDEO_IO.ASM, and we
the procedure
also
TEST_WRITE_DECIMAL.
VIDEO_IO.ASM
you
program
/*x,
>-'
'^^^
and put
as
shown
it
two
files
File
WRITE_DECIMAL
of
its
separately
own,
called
to
procedure called
a short test
in a file
in Listing 13-1.
added
procedure out of
TEST.ASM. Then,
The TEST.ASM
file is as
follows:
TEST.ASM (TEST13.ASM)
DOSSEG
.MODEL
SMALL
STACK
.CODE
EXTRN
WRITE_DECIMAL:PROC
TEST_WRITE_DECIMAL
MOV
DX, 12345
PROC
CALL
WRITE_DECIMAL
MOV
AH,4Ch
INT
21
TEST_WRITE_DECIMAL
END
Return to DOS
ENDP
You have seen most of this source file before, but the EXTRN directive is new.
The statement EXTRN WRITE DECIMALrPROC tells the assembler two
166
13
things
that
WRITE_DECIMAL
is
Modular Design
in another, external,
Building Programs
file,
and
that
it is
in
Pieces
procedure.
directive. Since
be
FAR CALL
if we had placed a FAR after WRITE_DECIMAL. You can use NEAR or FAR
generates a
in place
of the
PROC
in the
EXTRN
procedure.
it is
It
would generate
statement
if
you wanted
to explicitly
.MODEL
directive de-
procedure types.
Code Segment
Data Segment
.CODE segment
.DATA segment
(from
(from
file 1)
file 1)
.CODE segment
(from
file 2)
.DATA segment
(from
Figure 13-1:
file 2)
CALL
PROC _ONE
Figure 13-2:
These
are
you begin
WRITE_.DECIMAL
-^]
ENDP
memory. At
that point,
you
files
will introduce
until
another
167
Assembly Language
for the
need
it
for data.
in Video_io.
change
Finally,
END TEST_WRITE_DECIMAL
at
the end of
VIDEO_IO.ASM
was moved
to
ternal procedures.
That
after the
now
in
END
is,
call
directive in
VIDEO_IO.ASM
files.
You
don't need a
name
is
TEST.ASM.
When you have finished making these changes, your VIDEO_IO.ASM source
file
included in
.MODEL
VIDEO_13.ASM on
SMALL
.CODE
PUBLIC
WRITE HEX
PUBLIC
WRITE HEX
ENDP
PUBLIC
WRITE CHAR
168
WRITE CHAR
ENDP
the disk.
The complete
listing
is
13
PUBLIC
WRITE DECIMAL
Modular Design
Building Programs
in
Pieces
WRITE DECIMAL
ENDP
END
VIDEO_IO.ASM
you link the two
files just as
file
TEST.ASM knows
name.
through the
all it
before, using
needs to
ML /c
know about
files.
ML can assemble more than one file at a time. All you have to do include
the files you want to assemble
the ML /c. For example,
is
all
kLi
aft:er
files
this
command:
You can
TEST.EXE
create the
OBJ files
ML to create an EXE
files
file
from your
disk,
file
direcdy.
directly
delete the
OBJ
TEST.EXE:
When
program
will always
list.
Now you
following
command
files
to link these
TEST.EXE:
C>LINK TEST VIDE0_I0;
LINK stitches the procedures of these two files together to create one file containing the entire program.
for the resulting
EXE
file,
It
so
uses the
first file
name you
entered as the
name
169
Assembly Language
That's
gram
it;
for the
is
from the
single
file
files.
The
final
EXE pro-
TEST_WRITE_DECIMAL.
We will make heavy use of separate source files from here on. Their value will
become
program
a test
simple
to
dump
test version
you
so will allow
sections of
to save effort.
in hex.
You
you
will write
to see
how
effort
memory
They
to write a
good
in the process.
are called
There
ways
you
much
are
summarized
like; either
all
the time.
Your job
will
all registers,
in that register.
2.
registers
you use
For example:
170
DL,
DX
AL,
AX
BX:AX
DS:DX
to pass information.
be
13
Modular Design
CX
CF
Set
when
there
is
3.
There
Define
is
all
as
AL
or
Information returned
Procedures called
modular design
registers,
comment
parallel
(registers
An
header:
changed)
in
programming and
in engineering.
a very
tions,
without knowing
ferent voltages
and
inside.
Pieces
AX.
an obvious
in
Building Programs
But
if
dif-
each box and create special connections between boxes. Fortunately for the
number of standard
why we
is
will lay
make your
task
much
important in assembly-
down
will see
by the end of
this
book,
in detail.
/i// registers,
register.
There
aren't that
many
of a procedure, you
careful to restore
in
all
free
them
registers in the
them
at the
cedure and
POPs
80x86. By saving
PUSH
will see us
instructions appearing
first
doing
this
in each pro-
at the end.
171
Assembly Language
The only
for the
exception
is
to
the calling procedure. For example, a procedure that reads a character from
the keyboard
must somehow return the character. Don't save any registers that
Short procedures also help the register-shortage problem. At times, you will
write a procedure that
is
and
read.
You will
see
more of this
data.
For
you
this
You
CX register
The
is
procedure
you use
register for
will also
You will
when we
a procedure
spaces
by calling
Use the
10.
to return
CX
some
will
do
write a procedure
Not
all
is
an
error,
is
no reason
and so on). In
There
is
this case,
you
and
flags.
clear
it
when-
For example,
write-protection,
error code.
re-
learn
to
register
But
DS:DX
and begin
easier to write
to pass information.
this
one character
to write
this
for data
we
registers
be anywhere in memory.
new segment
also
it
as
many
DOS
an
different functions.
is
is
no need
why we
to learn
place a detailed
header contains
all the
comment header
if all
you want
to
do
is
use
it.
It tells
you what
to
place in each register before calling the procedure, and what information the
172
13
which of these memory variables are read and which are changed.
header should
with
list
much of this
information
is
Pieces
but some
in
in
say
Finally, each
An example of a full-blown
header
as follows:
For example,
"
On entry:
DS:DX
Returns:
AX
Calls:
GOTO_XY, WRITE_STRING
(procedures called)
Reads:
STATUS_LINE_NO
Writes:
DUMMY
to use
comment header
to learn
how
to use
it.
There
will
just glance
be no need to delve
what
it
does.
You may discover from time to time that your comment headers don't tell you
enough
so
When you
so
it
how
cedure or program
write the program
comment header
you don't
the
is
first try.
we have
The
don't
in
we
easier,
and we
first
know
exactly
drafts,"
of modular design.
will
be cer-
version of a pro-
we
how
to
will write
through and get something that works. Then we can backtrack and do a good
job by rewriting each procedure to conform to these laws.
Programming is a process
we
will
that goes
all,
this
book
173
Assembly Language
for the
Dskpatch. There
fore
we
settled
is
not
on the
versions
we wrote
bear very
little
be-
resem-
see.
first
time.
Be prepared
memory.
It
satisfied,
The moral
won't be the
is:
A program
final version;
never done
is
will be other
.
but
it
Workbench
The Microsoft MASM 6.0 package includes a fiill programming environment,
called the Programmer's Workbench. This can make your job of building assembly language programs
much easier.
In
reality,
we
will
who
continue to use
adventuresome,
it.
num-
don't like
We
will use PW^ to build TEST.EXE so you can see how you might use PWB to
build your own assembly-language programs that use multiple files. We will
assume that you asked to install PWB when you installed MASM 6 if you
In this section
we would
like to give
didn't,
When
you
first start
PWB
you
you an introduction
to using
PWB.
one shown
in Fig-
ure 13-3. At this point you could simply start typing a program, then use the
174
^^
file.
files,
you
13
Modular Design
Building Programs
in
Pieces
it.
program.
you will
boxes.
list,
which
see.
Before
to use them.
To
The keyboard
PWB
you can
we go
pull
down
to use the
that constitute a
menus and
file,
as
dialog
interface centers
highlights the
in the
all
first letter
of each
you
from the
menu
is
Set
Program List.
menu
item,
want
will
down,
list,
which
to pull
indicates that
down
the
Make
the other
depending on
When you
you see
choices,
letters
files
a hst of
is
PWB makes heavy use of both features, so you will need to know how
key,
program
PWB can use this list of files to automatically create the EXE
case,
that only
175
Assembly Language
for the
such
as
menu
menu
is
even
easier.
Simply
will
click
menu
titles,
on any of the
allows
gram
and
down
pull
You will
you
list,
the
open an
Program
Program
existing
select the
which
You need
is
a dialog
to create a
box that
new
pro-
which you can do by typing a name and pressing Enter. Type TEST
press Enter.
PWB
will display
on the
new program
list.
if
you want
<Yes> button
you do want
to create a
Figure 13-4.
Run Options
Edit Progrart List
D :\BOOKSsfiSSEHBLY 3\C0DE
.
TEST.fiSM
TEST.MftK
UIOEO 10. ASH
\nSSEMBLy 3\CGDENt
.
<
CXD
<
Enter Esc=Cance
is
Tab=Next Field
176
<Cancel>
list.
You want
<
elp
>
Ipseudo
to create
>
awe List>
o Top of List
to
add two
lists,
files
or modify
to this
lists.
them once
program
list:
13
Modular Design
Building Programs
in
Pieces
window
two
these
Press
files
to the
Tab
Program
The
steps
to
add
moves
window
(probably
a single Tab).
2.
4.
program
PWB
TEST.ASM,
TEST.ASM
see
then
in the
Program
window.
List
3.
to highlight
will
screen that
VlDEO_IO.ASM
on
to the
Program
List.
list.
think for a couple of seconds, then you will see the mostly-blank
It
TEST.EXE
Building
Make menu again and you will notice it is quite different. Now
all the items in this menu are enabled. But you will also notice that test.exe
appears in the Build menu item. This means you can build TEST.EXE simply by pulling down the Make menu and selecting Build. What is even better
Pull
is
down
that
the
the
files
that
it
only assembles
You can
Program
tell
which
List
Program List.
item in the
Make
menu. Ifyou
need to be changed.
is
currently selected by
see
TEST.EXE, you
know
LINK
What
does
EXE file.
less
this
mean? By
Packed
disk space.
default,
PWB
tells
EXE files are files that have been compressed so they take up
The problem
here
is
that your
program
is
so small
it
Program
that
List with
name
is
currently selected.
cannot be
program, the
is
you
that the
TEST.EXE
LINK failed.
Ml
Assembly Language
for the
What you have to do is change the way PWB tells LINK to create your EXE
file. Pull down the Options menu and select link Options
Then in the LINK
Options dialog box press Alt+R or
option
such
[
is
as [X]).
not checked
You want
to
on
click
on
make
sure
an
x in
.>
to bring
make
sure
square brackets,
it
Finally, click
Tab key
select
To
(it is
click
Alt+E or
Press
to
on the
move
<OK>
<OK>
all
Make menu.
You can
Now
should work.
It
Opxions
Run
Browse
<LINT1TLED>
Build
Build operat-ion has been conpleted
B Errors/Marnings
un Pro9ran>
<
HBI
Id
ebug Proc|raM>
<Cancel>
<
^o^
<
^W)I
Editing FUes in
PWB
your Program
is
List.
your program.
178
An easier way to
it
get to your
to
jump
files,
ver\'
however,
is
another fea-
13
Modular Design
Building Programs
Before you can use the Browse feature, however, you need to enable
down
the Options
menu and
select the
it.
in
Pieces
Pull
dialog box appears, press Alt+B to check the "Generate Browse Information"
option (so
it
selecting Build
it)
and
box saying that the Build operation finished. Whenever you rebuild your program with the Generate Browse Information option checked, PWB keeps a
lot of information on your program which it needs for all the items in the
Browse menu.
down
the Browse
Relationship.
DOSSEG
.MODEL
SMALL
.STOCK
.CODE
EXTRN
HRITE_DEClMfiL:PROC
IESI_WRIIE_DECIIL
PROC
MOO
DX, 12345
CftLL
WR I IE_ DECIMAL
MOU
AH ,4Ch
INT
21h
TEST WRITE DECIMAL
ENDP
END
iReturn to DOS
Figure 13-6:
Jump
TEST.ASM in
its
own
edit
window.
to Definitions
Move the cursor to the name WRITE_DECIMAL after the CALL. Now pull
down the Browse menu and select "Goto Definition." You will see the dialog
179
Assembly Language
box
shows
you
for the
all
of the procedures,
labels, etc. in
WRITE_DECIMAL
now
in the file
VIDEO IO.ASM.
Fi le
Edit
Search
Uie u
Hake
Run
Goto I ef inition
Tmrl^^H
N ne s
NON_ZERO
STOCK
lEST.asB
UIDEO_IG.as (78)
TEST_MRITE_DEClHftL
UIDEO_IO.asr
HRITE CHAR
MRITE DECIMAL
MRITE_DIGIT
RITE_DIGIT_LO0P
WRITE _HEX
WRITE HEX DIGIT
<Cancel>
l=Help
Entex-
Esc=Cance
easily
using this
menu
subroutine
tion...
flu
jump
is
to
item.
>
jump
any definition
You can
in
also find
any of the
all
files
of your project by
the Browse
It
your
files
won't
you
180
to
use
elp
Tab=Next Field
You can
<
reflect
built
PWB.
again.
13
Modular Design
Building Progranns
in
Pieces
List
PWB has one rather rude habit that probably keeps a lot of programmers from
When you exit and then start PWB again, remembers all the files
using
it.
it
You have
You do
this
is
the last
it
be in uppercase
list
you were
letters).
Type
using.
Program
List
List that
List...
a little-known switch
Program
Program
to
You can
is
you were
start
PWB.
to select the
an easier solution.
have
PWB
automatically load
/PL switch
(this
must
the following:
C>pwb /PL
There
are far
you an
give
more
features of
idea of how to
use
PWB
than
we can show
You can
wonderful
rest
ML and LINK to do
will give
you
all
will
and other
details
of us-
many people who detest PWB, and they would not be happy
for the rest of this book. To back up that claim, most programmers we know like to use the Brief editor, along with the Make program
you will learn in Chapter 15.1 personally don't know of any programmers who
second, there are
if
we used
use
PWB
PWB.
Summary
This has been a chapter for you to remember and use in the future.
by teaching you
files
how
to separate a
program into
We began
that can be assembled independently, then stitched together with the linker.
We used the PUBLIC and EXTRN directives to inform the linker that there
181
Assembly Language
for the
are connections
files
can
files.
is
in another
tells
the
file.
Then we moved on to The Three Laws of Modular Design. These rules are
meant to make your programming job simpler, so use them when writing your
own programs (just as you will see us use them in this book). You will find it
easier to write,
Finally,
we
182
and
all fairness,
you
if
nice features
In
is
nice to
get
accustomed
are used to
so
it is
use.
to
its
lot
of
quirks.
a matter of what
icrHiArp|TiEiR
Dumping
Memory
In
chapter you
memory. You
this
access
will learn
how to set DS
so
your program
will allow
acters,
much
Files altered:
Disk
Hies:
as
it
you
Debug can
to display
DISP_Sl4.ASM,
CURSOR14ASM,
and
to
as char-
VIDEO_l4ASM
opics ^-overe
Csing Addressing Modes to Access
Memory
DS
to Point tojyour
Adding Characters
Data Segment
to the
Summary
of
Dump
Memory
Assembly Language
for the
way we
originally wrote
be unfamiliar.
Most
Some of the
it.
much
in
the
you
will
all
same
instructions in
the information
all
on building Dskpatch
tailed information,
detail.
will concentrate
(For de-
of the instructions in
all
the
80x86
instructions,
cepts,
instructions
and begin
III,
farther
DOS
details
of
programs
and keyboard.
dump
to use
memory as
by writing a short
To
begin,
test
you need
program
to learn
to
how
variables.
Access Memory
You have seen two addressing modes; they are known as the register zndi immediate zddxessin^ modes. The first mode you learned about was the register mode,
which
AX and BX as variables.
AX BX
,
number
MOV
AX
to the
in
This example moves the byte or word of memory immediately following the
instruction into a register. In this sense, the
is
396F:0100 B80200
The
instruction
is
AX, 0002
B8h, and the two bytes of data (02h and OOh) follow
186
first
in
memory).
this
14
Now
you
allows
will learn
you
how
instruction, but
it
Dumping Memory
to use
of fixed
this,
you
will
one byte
with an example.
at a time.
Each byte
is
between each of the 16 hex numbers. Enter the program into the
file
DISP_SEC.ASM and
file
assemble
it.
new
DISP SEC.ASM.
New
File
DISP_SEC.ASM
<^^^
DOSSEG
.MODEL
SMALL
STACK
.DATA
SECTOR
PUBLIC
SECTOR
DB
10h,
11h,
12h,
13h,
14h,
15h,
16h,
17h
DB
18h,
19h,
lAh,
IBh,
1Ch,
IDh,
lEh,
1Fh
EXTRN
WRITE_HEX:PROC
EXTRN
;Test pattern
.CODE
DISP_LINE
PROC
MOV
AX.DGROUP
MOV
DS.AX
XOR
BX,BX
;Set BX to
MOV
CX,16
;Dump 16 bytes
MOV
;Get
CALL
WRITE HEX
HEX_LOOP
1
byte
187
Assembly Language
for the
DL,'
CALL
WRITE_CHAR
INC
BX
LOOP
HEX_LOOP
MOV
AH,4Ch
INT
21h
DISP_LINE
;Return to DOS
ENDP
END
DISP LINE
You
to see
how
it
create an
EXE file named DISP_SEC.EXE. LINK creates a program by putting the pieces
together in the same order as the names
the
main procedure
the
LINK command
needs to be the
procedure (Disp_sec in
list
on the command
this case).
line.
program, the
name of the
file
first file
name in
at the
main
end of the
Linking will always be the same, with more names before the semicolon when
files.
In general, the preceding step for the Bles file l,file2, and so on,
is
as follows:
Now, run
the
EXE file.
12 13 14 15 16 17 18 19 1A 1B 1C ID IE IF
mode known
188
the pro-
as
register
The following instruction uses a new adIndirect Memory Addressing addressing memory
with
offset,
or
Relative.
14
MOV
DL,SECTOR[BXI
In order to see
what
;Get
this really
CJ
Dumping Memory
byte
first
more about
learn
segments.
0431 +
MOV ^Dt:;SECTOR[ B X]
BX
SECTOR:
Figure 14-1: Translation
0434
0433
0432
0013
0012
0431
0010
0011
ofSECTOR[BX].
The
64K of data.
segment
fined by
.STACK)
are defined as
64K
segment
as
shown
in
Figure 14-2.
This grouping of the stack and data segments into one segment
a
mechanism
creates a
is
handled by
group called
DGROUP
far
189
1
Assembly Language
for the
There are
rectives.
this
and
at
memory maps
DS,
to see
segments in
how programs
this
group
.MODEL, .DATA,
Knowing some of
use later when you
the scenes.
come
in
SS
DGROUP
_DATA
STACK
and data
(DGROUP).
DOSSEG directive is that the STACK segment is loaded into memory above the DATA seg-
we
as a result
it
of the
(lOh,
Ih, 12h,
and so on)
program
is
run by
need to
set).
So by putting the stack segment after the data segment, you don't
set aside
190
14
End
Start of File
File
Dumping Memory
of File
T
Disk
T
EXE
File
Header
.CODE .DATA
.STACK
Base-Relative Addressing
It is
The
following two
at
SECTOR,
an address.
DB
10h,
11h,
12h,
13h,
14h,
15h,
16h,
17h
DB
18h,
19h,
1Ah,
1Bh,
ICh,
IDh,
1Eh,
IFh
;Test pattern
MOV
recall,
DL, SECTOR
191
Assembly Language
for the
This
K = L(10)
In fact, the
offsenn
MOV instruction
is
much
moves the
first
the same.
if
DL.
first
not
legal
instruction
register.
sixth
and the
is
SECTOR
to write
is
DX
is
word
SECTOR
as a
word
tell
label in this
instruction.)
There
are
the addressing
modes
are
summarized
in
Format ofAddress
Register
register (such as
Immediate
data (such
as
192
later.
All of
Modes
Segment Register Used
AX)
None
12345)
None
be covered
Table 14-1.
[BX]
DS
[BP]
SS
[DI]
DS
[SI]
DS
14
Dumping Memory
Addressing Mode
Format ofAddress
Base Relative*
label [BX]
DS
label[BP]
SS
label [DI]
DS
label [SI]
DS
label[BX+SI]
DS
label[BX+DI]
DS
label [BP+SI]
SS
label[BP+DI]
SS
Direct Indexed*
Base Indexed*
String
Commands:
can be replaced by
[disp+...],
Write
where
disp
is
to
ES:DI
displacement. Thus,
we could
would be 10 + BX.
Setting DS to Point
to Your Data Segment
This discussion has glossed over one minor
that both the
when
DS
and ES
registers
detail.
In Chapter
1 1
we mentioned
DOS starts the program. The first two lines in DISP_LINE set DS so it
AX.DGROUP
MOV
DS,AX
The first line moves the segment address for our data group (called DGROUP)
that contains .DATA and .STACK into the AX register. The second line sets
DS
so
it
193
Assembly Language
There
for the
is
here. If you
remember
registers, we said that the segment used for programs depends on how
much memory is already in use. In other words, you cannot know the value of
DGROUP until DOS loads the program in memory. How, then do you know
what number to load into AX?
ment
There
EXE
is
dresses in your
program
DGROUP
is
known
file
that contains a
as relocation.
DOS
uses this
list
of ad-
informa-
in the
MOV
loads
Chapter 28.
There
another fine point of writing programs for the 80x86 family of mi-
is
we
DS, DGROUP
as follows.
instructions because
register
on the 80x86;
AX register.
first
you have
to
more
it less
expensive
program.
Dump
You are almost finished writing the procedure that creates a dump display similar to Debug's. So far, you have dumped the hex numbers for one line; in the
next step, you will add the character display following the hex display. The
new version of DISP_LINE (in DISP_SEC.ASM), with a second loop added
to display the characters,
is
as follows:
194
DISP.UNE
in
DISP_SEC.ASM
PROC
MOV
AX, DGROUP
MOV
DS.AX
14
XOR
BX.BX
;Set BX to
MOV
CX,16
;Dump 16 bytes
MOV
DL,SECTOR[BX]
;Get
CALL
WRITE_HEX
MOV
DL,
CALL
WRITE_CHAR
INC
BX
LOOP
HEX_LOOP
Dumping Memory
HEX_LOOP:
MOV
DL,'
CALL
WRITE_CHAR
MOV
CX,16
XOR
BX.BX
byte
;Set BX back to
ASCII_LOOP:
MOV
CALL
WRITE_CHAR
INC
BX
LOOP
ASCII_LOOP
MOV
AH,4Ch
INT
21h
DISP_LINE
Assemble
Return to DOS
ENDP
this, link
you should
it
to Vicieo_io,
and
try
it.
see.
Od isp_sec
18 11 12 13 14 15 IG 17 18 19
1ft
IB IC ID IE IF
<t!!<lg_tTi-*^-*T
C>_
now, rewrite
and IFh),
as
it
you can
195
Assembly Language
for the
C>disp_sec
IB 11 12 13 14 15 18 17 18 19
1ft
IB IC ID IE IF
C>
Replace the
ofDISP_LINE.
WRITE_CHAR
in
VIDEO_IO.ASM
new
WRITE_CHAR
in
VIDEOJO.ASM
WRITE_CHAR
a period.
On entry:
WRITE_CHAR
DL
PROC
PUSH
AX
PUSH
DX
CMP
DL,32
JAE
IS_PRINTABLE
;No,
MOV
DL,'.'
;Yes,
MOV
AH, 2
INT
21h
POP
DX
POP
AX
then print as is
IS_PRINTABLE:
RET
WRITE CHAR
ENDP
Try this new procedure with Disp_sec, and change the data
ters to
196
to various charac-
14
of
Now
or 16 bytes, of
next step
is
to
dump 256
to
dump one
line,
Dumping Memory
Memory
memory. The
You will need two new procedures and a modified version of DISP_LINE.
The new procedures are DISP_HALF_SECTOR, which will soon evolve into
a finished procedure to display half a sector,
SEND_CRLF
is
very simple, so
New
file
File
move
let's start
called
and
SEND_CRLF, which
(CRLF
sends
with
it.
CURSOR.ASM,
CR
EQU
13
;Carriage return
LF
EQU
10
;Line feed
.MODEL
SMALL
.CODE
PUBLIC
SEND CRLF
correctly.
SEND_CRLF
PUSH
PROC
AX
PUSH
DX
MOV
AH, 2
MOV
DL,CR
INT
21h
MOV
DL,LF
INT
21h
197
Assembly Language
for the
14-4 continued
Listing
POP
DX
POP
AX
RET
SEND CRLF
ENDP
END
name
EQU
CR
CR to
The
;Carriage return
MOV DL,CR
is
equivalent to
DOS
EQU direc-
using the
be equal to 13.
13
So the instruction
pair,
whenever
it
it
sees
CR.
Likewise,
sees LF.
CR
EQU
13
\
13
MOV
Figure 14-6: The
Note
From
EQU directive
here on,
we
will
programs
will
lets
show
us use
DUpf<
names
in places
of numbers.
line to see if
it's
new
Add
D e lete
198
CAt
you won't
shown
it
14
(Complete
the
new
Dumping Memory
version of
New
Version of DISP_SEC.ASM
DISP_S14.ASM)
listing in
DOSSEG
.MODEL
SMALL
STACK
.DATA
SCCTOn
SECTOR
BB-
10h,
11h,
12h,
13h,
14h,
15h,
6 h,
17h
B6-
lOh,
19h,
1Ah,
IDh,
1Ch,
1Dh,
ICh,
1Fh
T e 9t pattern
DB
16 DUP
DB
16 DUP
11h)
DB
16 DUP
12h)
^^V^l
DB
16 DUP
13h)
16 DUP
14h)
DB
16 DUP
15h)
^^lB
|H
|H
DB
16 DUP
[16h)
DB
16 DUP
[I7h)
'I^^^H
DB
16 DUP
[18h)
J^^^H
DB
16 DUP
DB
16 DUP
[lAh)
DB
16 DUP
[IBh)
DB
16 DUP
[ICh)
DB
16 DUP
[IDh)
DB
16 DUP
(lEh)
16 DUP
[iFh)
PUBLIC
DISP_HALF_SECTOR
dfj^^M
^^^H
'^H
^^^B
J^H
IH^H
J^^^H
l^^^l
^^^H
sHH
.CODE
SEND_CRLF:PROC
EXTRN
..................
....
^^1
...
Uses:
^^m
DISP_LINE, SEND_CRLF
j"
DISP_HALF_SECTOR
MOV
PROC
AX,DGROUP
199
Assembly Language
for the
DS,AX
XOR
DX,DX
MOV
CX,16
Display 16 lines
Return to DOS
HALF_SECTOR:
CALL
DISP_LINE
CALL
SEND_CRLF
ADD
DX,16
LOOP
HALF_SECTOR
MOV
AH,4Ch
INT
21h
ENDP
PUBLIC
DISP_LINE
EXTRN
WRITE_HEX:PROC
EXTRN
then in ASCII
On entry:
DS:DX
Uses:
VrRITE_CHAR, WRITE_HEX
Reads:
SECTOR
"
J
DISP_LINE
Mev-Mev-
'
"""
''
PROC
AX.DCnOUP
DS,AX
;S e t DS to point to data
AUIl
UA UA
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BX,DX
MOV
CX,16
;Dump 16 bytes
PUSH
BX
MOV
;Get
CALL
WRITE_HEX
MOV
DL,'
CALL
WRITE CHAR
HEX_LOOP
200
byte
14
INC
BX
LOOP
HEX_LOOP
MOV
DL,'
CALL
WRITE_CHAR
;Adcl
MOV
CX,16
POP
BX
Dumping Memory
;* ''<^5.^s&issai^SJP.
ASCII_LOOP:
MOV
CALL
WRITE_CHAR
INC
BX
LOOP
ASCII LOOP
POP
DX
POP
CX
POP
BX
RET
AH 4Ch
-MOV-
R e turn
to DOS
-^NT-
DISP LINE
ENDP
END
The changes
are
all fairly
and
DISP_LINE
is
you
that you
be
first
link the
restore
you
will
list.
PUSH
added
and
POP
in-
DISP_LINE. Actu-
left are to
files (after
in this
all
We have also
graphics characters so
When
the
ASCII_LOOP.
straightforward. In
later.
You should
one
in Figure
14-7
when
You
will
chapter,
have more
where you
files
move on
to the next
half a sector.
201
Assembly Language
for the
C>disp_sec
18
11
12
13
14
15
16
17
18
19
in
IB
IC
ID
IE
IF
18
11
12
13
14
15
16
17
18
19
in
IB
IC
ID
IE
IF
18
11
12
13
14
15
16
17
18
19
in
IB
IC
ID
IE
IF
18
11
12
13
14
15
16
17
18
19
18
11
12
13
14
15
16
17
18
19
18 18
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
18
11
12
13
14
15
16
17
18
19
18
11
12
13
IB
IC
ID
IE
IF
IB
IC
ID
IE
IF
IB
IC
ID
IE
IF
IB
IC
ID
IE
IF
IB
IC
ID
IE
IF
14
15
16
17
18
19
m m m m m m
IB
IC
ID
IE
IF
18 18
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
in in
IB IB
IC IC
ID ID
IE IE
IF IF
18
11
12
13
14
15
16
17
18
19
18
11
12
13
14
15
16
17
18
19
IB
IC
ID
IE
IF
IB
IC
ID
IE
IF
m m
18 18
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
in in
IB IB
IC IC
ID ID
IE IE
IF IF
18
11
12
13
14
15
16
17
18
19
ia
IB
IC
ID
IE
IF
C>_
Summary
You know more about
the diflferent
memory modes
for addressing
memory
and registers in the 80x86 microprocessor. You learned about indirect memory
addressing,
You
also
which you
first
used indirect
this chapter,
memory
half a sector.
At
last,
to see
more advantage
202
We will
as
dumps
to
|c1h|a|
p |t
|r
Dumping a
Disk Sector
In
this
programs (you
how
to use
NMake
NMake
to rebuild).
to simplify building
You
your
how
to
large variables.
Files altered:
Disk
files:
DISP_S15ASM, DISK_I15.ASM
Topics Covered
Making
Format
Life
of the
Easier
NMake
FII9
Patching up Disp_sec
Reading a Sector
The .DATA?
Directive
Summary
Assembly Language
for the
to read a sector
b)T:es
it
memory
in
SECTOR. Then, your dump procedures will dump the first half of
Making
With
files
plicated.
two?
Life Easier
from the
all
last
three of the
files
checked to see
if
you
if you
ing
it
is
just
made
changed because
just
files
you
PWB.
and
tedious,
and
files
will
really like to
do
is
as
Dskpatch grows
files
in
you have
changed.
Fortunately, both the assemblers covered in this
book
(MASM
and Turbo
Assembler) allow you to do just that. Microsoft and Borland provide programs
called
work.
Then
all
file
respectively, that
you have
to
do
is
do
exactly
tells
NMake,
or
Make, how
to
do
type:
C>NMAKE
NMake
(lie"
If
you
files
Make, you
will type
MAKE
instead of
NMAKE.
If
you
are using
MASM
5 or earlier,
you
will
have to type
MAKE
MAKEFILE because Make did not automatically look for a specific file,
NMake and Borland's Make look for the file MAKEFILE.
whereas both
206
15
The
files.
you
file
NMake
this in the
file,
DOS
If the
ASM version
NMake knows
OBJ
There
is
DOS'
C-MOS
simply looks
has a
more
at
NMake
may
will
this file
both the
ASM
to point out.
a Disk Sector
work
if
file
again.
correctly only if
your computer's
Format
The format
format
it
files
file.
than the
version,
what
Dumping
is
NMake
of the
we
will use
with
File
NMake
is
fairly simple.
The
as follows:
NMake
File
MAKEFILE
dispsec
obj
disp_sec asm
.
ml /c disp_sec.asm
video_io obj
.
video_io asm
ml /c video_io.asm
cursor. obj:
cursor. asm
ml /c cursor. asm
names on the
the
first line)
file
name on
right. If any
are
more
the
of the
left
files
on the
right (such as
first file
file
DISP_SEC.ASM
(DISP_SEC.OBJ),
in
NMake will
from
ofMake
MASM 5 or
execute
all
the indented
file
commands
that appear
on the following
DISP_SEC.ASM. Then
lines.
Enter
lines
two
must be at the
C>NMAKE
207
Assembly Language
for the
using
ing:
C>nniake
Microsoft
(R)
Version 1.13
Microsoft
(R)
Copyright
(c)
Assembling: dispsec.asm
link disp_sec video_io cursor;
Microsoft
(R)
Copyright
(c)
Version 5.13
C>
NMake has done the minimum amount of work necessary to rebuild your program. If you have an older version of the Microsoft Macro Assembler that
doesn't include
grade.
You
and
will
it
Make, you
be covered
It is
called
CodeView,
Patching up Disp_sec
Disp_sec, as
you used
we
left
as a test
it,
Now, you
will
change
procedure
will
be in Disk_io.
First,
modify Disp_sec
main procedure
208
will
to
make
it
file
of procedures, just
as
now
be in Disk_io.
Then you
will
15
moving
are
Since
we
Dumping
a Disk Sector
these to a different
file.
memory
starting at
SECTOR,
there
no
is
need to supply test data. We can replace all the 16 DB statements after
SECTOR with two lines which reserves 8,192 bytes for storing a sector.
SECTOR
PUBLIC
SECTOR
DB
need such
2 bytes long.
Why,
then,
do you
panies used large sectors with larger hard disks (300 megabytes, for example)
instead of adding
fore 3.31
still
want
These
more
sections,
by no means
to be certain that
in a sector that
into the
we have
SECTOR.
we will
for versions of
DOS
be-
but
we
too large to
fit
cover soon,
we will assume
that sectors
Now what you need is a new version of DISP_HALF_SECTOR. The old version
is
In the
display
256
bytes, starting
again,
DX
we used
to test
DISP_LINE.
Disp_sec
Among
is
you can
256
first half,
DISP_HALF_SECTOR in
Listing
procedure that
anywhere
Once
test
final,
bytes.
version of
as follows:
in
DISP_SEC.ASM (Complete
PUBLIC
DISP_HALF_SECTOR
EXTRN
SEND CRLF:PROC
On entry:
DS:DX
--
should be
aultiple of 16.
209
Assembly Language
Listing
;
for the
5-2 continued
DISP_LINE, SEND_CRLF
Uses:
PROC
DISP_HALF_SECTOR
MOV
AX DG R OUP
DS.AX
S c t DS to point to data
DX,DX
-MGV-
-^(OR-
PUSH
CX
PUSH
DX
MOV
CX,16
;Display 16 lines
HALF_SECTOR
CALL
DISP_LINE
CALL
SEND_CRLF
ADD
DX,16
LOOP
HALF_SEGTOR
POP
DX
POP
CX
RET
T IIT
O1 h
ENDP
Let's
move on
Reading a Sector
In this
as
first
version of
final version
of READ_SECTOR.
you
is
210
follows:
is
The
test
version of the
file
of
15
Listing
15-3 The
New
File
Dumping
a Disk Sector
DOSSEG
SMALL
.MODEL
STACK
.DATA
EXTRN
SECTOR: BYTE
EXTRN
.CODE
This procedure reads the first sector on disk A and dumps the first
half of this sector.
READSECTOR
PROC
MOV
AX.DGROUP
MOV
DS.AX
MOV
AL,0
MOV
CX,1
Read only
MOV
DX,0
LEA
BX, SECTOR
INT
25h
XOR
DX.DX
Set offset to
CALL
DISP_HALF_SECTOR
MOV
AH,4Ch
INT
21 h
READ_SECTOR
END
dress,
within SECTOR
Return to DOS
ENDP
READ SECTOR
are three
new
or offset, of
ated by
sector
POPF
There
.DATA)
The
first
into the
for
211
Assembly Language
for the
0000
DGROUP
.DATA segment
SECTOR:
0381
.STACK segment
LEA
Figure 15-1:
^ MOV
SECTOR
DX,
BX, 0381
BX, SECTOR
LEA
After this
DOS
SECTOR
is
DISP_SEC.ASM. You
rective as follows
.DATA,
This
and
tell
that
READ_SECTOR.
it is
by using the
It is
over in
EXTRN di-
in Figure 15-2.
set
of instructions
tells
212
file as
it is
SECTOR
is
file,
and
15
EXTRNs
in a
number of source
files.
the
it is
way we
|~1
Dumping
a Disk Sector
one
place.
.DATA
EXTRN
SECTOR:BYTE
I
byte variable.
LINK
EXTRN directive.
DOS
25h,
INT 25h
instruction.
from
a disk.
AL
CX
Number
of sectors to read
DX
Number
of the
DS:BX
sectors. If
AL
= 0,
All versions of
DOS
reads
doing
in this
You
first
sector
which
is
0)
from drive A.
32M bytes
a hard disk.
one time
are
first
at
The number in
we
provide
address.
will
thf>
problem
book, but
it
and
Note
can be
code
if you
to read
from a floppy
want
to use
disk, as
Dskpatch on
in the
disk.
213
Assembly Language
for the
DOS can read more than one sector with a single call, and reads the number
of sectors given by CX. Here, we set CX to one so DOS will read just one secit
tor of
512
bytes.
first
sector
on the
You can
we will.
disk.
DS:BX is the full address for the area in memory where you want DOS to store
the sector(s) it reads. In this case, you have set DS:BX to the address of SECTOR so you can call DISP_HALF_SECTOR to dump the first half of the
first
sector read
Finally,
you
will notice a
in drive A.
POPF
INT
25h. As mentioned before, the 80x86 has a register called the status register
that contains the various flags, like the zero
instruction
on the
first
When DOS
stack.
and carry
flags.
returns
from
it
registers,
this
can
POPF
is
a special
Why do you
need
INT 25h,
it
on return
if
there was a disk error, such as trying to read from drive A: with no disk in the
drive.
in this
hence
Now
Or,
listed first.
two
if
on the
disk_io Ob]
stack.
instruction.
you have
NMake
(or Borland's
disk_io asm
.
ml /c disk_io.asm
Change
the
disk_io.exe:
link
first
two
214
remove
lines to the
register
to
POPF
we have
Then, link the four files Disk_io, Disp_sec, Video_io, and Cursor, with Disk_io
the
book, but
before
you run
15
Odisk
EB
82
88
54
ce
3C
EB
88
41
8E
IG 53
8F SB
CD 13
89 BE
16 IE
7C 03
IE 8B
88 BB
Be 81
fiG 75
E8 5F
Dumping
a Disk Sector
io
98
88
88
4C
DB
BF
8E
72
28
7C
49
7C
88
E8
80
88
4D 53 44 4F
GB 89 F9 87
88 88 88 29
4C 28 31 46
BC 88 7C 16
3E 7C B9 BB
18 7C 88 4D
79 33 C8 39
7C 08 18 7C
83 86 BE 7C
7C 89 16 4B
83 C3 48 F7
85 SB 16 52
OC ee 72 16
8D 7F 28 B9
33 C8 CD 16
53 35 2E 38
88 BF 88 82
8D 85 IC 19
41 54 31 32
87 BB 78 88
BB FC F3 04
F9 89 47 82
86 13 7C 74
F7 2G 16 7C
83 D2 88 03
7C B8 28 88
F3 81 86 49
7C 01 58 7C
8B FB B9 BB
BB 88 F3 06
5E IF 8F 84
BB
BB
55
28
36
86
C7
88
83
58
F7
7C
E8
88
74
8F
82
88
4E
28
C5
IF
87
8B
86
7C
26
83
92
BE
18
44
81 81 BB
88 88 88
49 4E 53
28 FO 33
37 IE 56
CG 45 FE
3E 7C FB
BE 13 7C
IC 7C 13
89 16 52
11 7C 8B
16 4B 7C
88 72 ID
E6 7D F3
BE 9E 7D
82 CD 19
5<KSD0S5.8
..'.)ia. .UNINS
TOLL 1F0T12
3
lJU'.
!..iix.6+7.U
.Si>:{|.."<n. .[
.1.
!eMeG.H>!-r
= .ru3l9.
it.i.
e.
..!... !ai,.uP!e.R
iuiie.K!') .=a.:i
.!.H=^ JiS.K;
.
.f).
.i.R!iF;5B.r.
.o;<.r.v/i|.. ="*><
%.i*
S
{|. .<t.=IR>
.3l-=."..5D. =
.
c>_
The .DATA?
If you
Directive
you have
that
to reserve
C>DIR DISK_IO.EXE
Directory of C:\SOURCE\ASM
DISK_IO
8920 10-17-92
EXE
1
file(s)
3:28p
8920 bytes
As you can
see,
Disk_io.exe
is
is
There
is
mostly
filled
with
memory. So does
the disk.
memory
You can do
this
by
215
Assembly Language
for the
you do not
care
Change
DISP_SEC
that define
what value
memor)^ variable
SECTOR to
has.
the following:
DATA?
There
PUBLIC
SECTOR
SECTOR
DB
two changes
are
the assembler
tells
rather than a
you
are
do not need
you do not
in
making
b)T:es long.
small
all
in the
file.
room
all
as
initial
Second there
(?) tells
has.
variables with
(?).
If you
in the
DUP
(?)
in
The .DATA?
on the
care
.DATA, and
after the
of each byte in
into
After
?,
DB
is
directive allows
you
.DATA?.
It
should
to keep
now
be only 727
disk.
We will come back later to add more to Disk_io; we have enough for now. In
the next chapter,
we will
some
graphics
Summary
Now
that
make
life
different source
this chapter,
files,
Dskpatch
216
from
SECTOR,
so
vou used an
becoming some-
files
is
EXTRN
definition in
a different source
DISKJO.ASM
to
15
tell
SECTOR,
and
let it
know
that
Dumping
SECTOR
is
a Disk Sector
a byte
variable.
You
also learned
about the
LEA
BX
register.
DISK_IO
uses a
also learned
about the
DOS
POPF
You used
instruction to
pop
this instruction to
when
it
word
remove the
flags
INT
25h.
returned from
and
which
The half-sector display is not very attractive yet. In the next chapter you
use some of the graphics characters available on the PC to make it more
will
aes-
thetically pleasing.
217
C H A
I
Enhancing the
Sector Display
In this chapter you will continue building the Dskpatch program, adding lines
around the
will learn
display,
oflFsets
along the
left side,
instructions:
LODSB
which
working with
Direction),
Files altered:
Disk
hex
two new
files:
and the
top. Finally,
and
CLD
of data.
you
(Clear
Adding Addresses
to the Display
Adding Numbers
to the Display
Summar>
Assembly Language
for the
ou have come
been applicable to
DOS
II.
Everything covered so
III,
you
w^ill
far
has
begin to write
and additions
will
several
more proce-
numbers on the
add
left
new
information.
dump.
It will
add
Let's begin
with graphics.
has a
number of line-drawing
dump
dump and
characters
display.
the
file
DISP_SEC.ASM,
be-
.MODEL directive and the .DATA? directive. Leave one or rwo blank
lines before
and
Listing 16-1
Add
(No Complete
to the
Listing
Top
of
DISP.SEC.ASM
on Disk)
220
draw boxes
tween the
to
VERTICAL_BAR
EQU
0BAh
HORIZONTAL_BAR
EQU
0CDh
UPPER_LEFT
EQU
0G9h
UPPER_RIGHT
EQU
0BBh
LOWER_LEFT
EQU
0C8h
LOWER_RIGHT
EQU
0BCh
TOP_T_BAR
EQU
0CBh
BOTTOM_T_BAR
EQU
0CAh
TOP_TICK
EQU
0D1h
BOTTOM TICK
EQU
0CFh
16
we put
a zero before
know
these are
labels.
We could just as easily have written hex numbers instead of these definitions
in the procedure,
DL,VERTICAL_BAR
MOV
DL 0BAh
,
Most people
find the
Now,
the
here
is
first
instruction clearer.
VERTICAL_BAR
shown
character,
DISP_LINE
of
Listing
in
DISP_SEC.ASM
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BX,DX
;Write separator
MOV
DL,'
CALL
WRITE_CHAR
'
MOV
DL,VERTICAL_BAR
CALL
WRITE_CHAR
MOV
DL,'
CALL
WRITE_CHAR
MOV
CX,16
;Dump 16 bytes
PUSH
BX
MOV
;Get
CALL
WRITE_HEX
MOV
DL,'
CALL
WRITE_CHAR
m^^^r-.^
HEX_LOOP:
INC
BX
LOOP
HEX LOOP
byte
221
Assembly Language
for the
DL,VERTICAL_BAR
CALL
WRITE_CHAR
MOV
DL,
MOV
CX,16
POP
BX
;Write separator
;Add another space before characters
'
'
ASCII_LOOP:
MOV
CALL
WRITE_CHAR
INC
BX
LOOP
ASCII_LOOP
MOV
DL,'
CALL
WRITE_CHAR
MOV
DL,VERTICAL_BAR
CALL
WRITE_CHAR
POP
DX
POP
CX
POP
BX
RET
DISP LINE
ENDP
Use NMake to build the new Disk_io, or assemble this new version of Disp_sec
and link your four
lowing the
files
(remember
LINK command).
to place Disk_io
first in
the
list
of files
fol-
222
first
number
will
will
down
the
16
88
88
53
33
56
FE
FB
7C
6<eMSD0S5.B
C>disk_io
EB
82
ee
54
CB
16
BF
CD
89
IB
7C
IE
88
B8
OG
E8
3C 98
E8 88
88 88
41 4C
8E D8
53 BF
8B BE
13 72
BE 28
IE 7C
fl3 49
8B 7C
BB 88
81 E8
75 BA
5F 88
4D
68
88
4C
BC
3E
18
79
7C
B3
7C
83
85
ftC
8D
33
44 4F 53 35
F9 87 86 8F
88 29 8D 85
31 46 41 54
7C 18 87 BB
B9 BB 88 FC
88 4D F9 89
CB 39 86 13
18 7C F7 26
BE 7C 83 D2
16 4B 7C B8
48 F7 F3 81
16 52 7C 01
72 16 8B FB
28 B9 BB 88
CD 16 5E IF
53
89
88
28
88
7C
7C
33
08
88
89
C3
8B
88
7F
C8
2E 38 88
88 82 88
IC 19 55
31 32 28
78 88 36
F3 04 86
47 82 C7
7C 74 88
IG 7C 83
88 03 58
28 88 F7
86 49 7C
58 7C E8
B9 BB 88
F3 06 74
8F 84 8F
82
88
4E
28
C5
81
88
49
28
37
IF C6
87 3E
8B BE
BG IC
7C 89
26 11
83 16
92 88
BE EG
18 BE
44 82
81
88
4E
FO
IE
45
7C
13
.0
l"Jl.
.iix.G+7.U
"In. hE
.St>!{|.
.1.
!eMeG.||.>!/
= .ra3L9.
8B
7C
It.i.
e. la. !=. !...:.
..:... ian.uPie.R
=*
1
uI e K
..
\=<. .lla.K!
.i.RliPISK.r.
7C 13
16 52
7C
4B
72
7D
9E
CD
'
.
)ia. .UNINS
TOLL 1F0T12
3
"1
ID
.i|.
F3
7D
*u.U
19
.5;<.r.i\r{|.
^^^i<
{|. .<=t.JR>
.3l=."..D. =
.
c>_
The process is fairly simple, since you already have the procedure WRITE_HEX
for writing a number in hex. But you do have a problem in dealing with a
WRITE_HEX
sector
Here
is
IFFh), the
lOOh, or
it
will be a
digits for
first.
1.
w^
numbers
So, if the
number
will
number
is
is
below
DISP_LINE
numbers,
you
will print a
as follows:
numbers
Additions to
DISP_LINE
in
DISP_SEC.ASM
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BX,DX
NOV
DL,'
"1
CMP
Bx,ieeh
JB
WRITE_ONE
MOV
DL,r
'1'
223
Assembly Language
for the
WRITE_CHAR
CALL
MOV
DL,BL
CALL
WRITE_HEX
MOV
DL
CALL
WRITE_CHAR
MOV
DL,VERTICAL_BAR
jWrite separator
The
results are
Odisk
88
18
28
38
48
58
68
78
88
98
AS
B8
C8
08
E8
F8
,
'
'
shown
in Figure 16-2.
io
EB
82
88
54
ce
3C
E8
88
41
BE
IS 53
8F 8B
CD 13
89 8E
IG IE
7C 03
IE 8B
88 BB
B8 81
A6 75
E8 5F
98
88
88
4C
08
BE
BE
72
28
7C
49
7C
88
E8
4D
68
88
4C
BC
3E
18
53
89
88
28
88
7C
7C
33
ne
86
89
C3
8B
88
7F
79
7C
83
7C
83
85
PC
Sft 8D
88 33 C8
44
F9
88
31
7C
B9
88
C8
18
BE
16
48
16
4F
87
29
46
IG
8B
4D
39
7C
7C
4B
F7
52
72 16
28 B9
CD 16
53
88
8D
41
87
88
F9
86
F7
83
7C
F3
7C
BB
BB
5
35
8F
B5
54
BB
EC
B9
13
26
D2
BB
81
ni
FB
88
IF
2E 38 88
88 82 88
IC 19 55
31 32 28
78 88 36
F3 04 86
47 82 C7
7C 74 88
16 7C 83
88 03 58
28 88 F7
86 49 7C
58 7C EB
BB BB 88
F3 06 74
8F 84 8F
82
88
4E
28
C5
81
BB
49
28
37
IF C6
87 3E
BB BE
86 IC
7C 89
26 11
83 16
92 88
BE EG
18 BE
44 82
81
88
4E
FO
IE
45
7C
13
6<eMSD0S5.8
88
BB
53
33
56
FE
FB
7C
7C 13
16 52
7C 8B
4B 7C
72 ID
7D F3
9E 7D
CD 19
.c
'
.
)U. .UNINS
TOLL 1F0T12
3
IflJl^.
.T1X.6+7.U
= .ra3L9. It.i.
a .! sA .!...!
e
.
..!... ISti.uPIb.R
uI e K
=S
1
f=<. .Ila.K!
I
.Tl.
=)
.i.RliPISK.r.
.55(.r.i\ri|. .^>'y<
=u.i4 a. .m.JR}
S .3l=.".ft.AD. =
.
C>_
left.
You are getting closer to the full display. But on the screen, your display is not
quite centered. You need to move it to the right by about three spaces. By
making this one last change, you have finished your version of DISP_LINE.
You could make the change by calling WRITE_CHAR three times with a space
character, but
will
called
224
16
ri
register
to write
N copies of the character whose ASCII code you placed in DL. Then
you
writes
one character
will
code for
a space) into
to
add
to
is
as
follows:
Listing
PUBLIC
VIDEOJO.ASM
character
DL
Character code
CX
WRITE CHAR
Uses:
WRITE_CHAR_N_TIMES
PROC
PUSH
CX
CALL
WRITE_CHAR
N_TIMES:
LOOP
N_TIMES
POP
CX
RET
WRITE CHAR
You can
TIMES
see
how
WRITE_CHAR.
for
ENDP
If you are
something so simple,
when we
call
is,
it is
to write a procedure
WRITE_CHAR_N_TIMES
is
much
clearer
The changes to DISP_LINE to add three spaces on the left of your display are
shown in Listing 16-5. Make the changes to DISP_SEC.ASM:
225
Assembly Language
for the
Listing 16-5
Changes
to
DISP_LINE
PUBLIC
DISP_LINE
EXTRN
WRITE_HEX:PROC
EXTRN
WRITE_CHAR:PROC
EXTRN
in
DISP_SEC.ASM
then in ASCII.
On entry:
DS:DX
Uses:
Reads:
SECTOR
DISP_LINE
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BX.DX
MOV
DL,'
MOV
CX,3
CALL
WRITE_CHAR_N_TIMES
CMP
BX,100h
JB
WRITE_ONE
;No,
MOV
DL,
'1
;Yes,
'1'
WRITE ONE:
you had
to
add an
EXTRN
state-
Try
this
Next we
tom
226
lines
of the boxes.
now
centered.
the top
and bot-
is
16
we have
cause
is
to think about.
as
it
sounds, be-
must go around
corners,
at the
top
WRITE_PATTERN,
which
will write a
on the
screen.
Then,
all
section.
a pattern. Right
file
VIDEO IO.ASM:
Listing
Usting
in
VIDEO_16.ASM)
PUBLIC
WRITE_PATTERN
form
DB
On entry:
DS:DX
Uses:
WRITE_CHAR_N_TIMES
WRITE_PATTERN
PROC
PUSH
AX
PUSH
CX
PUSH
DX
PUSH
SI
227
Assembly Language
Listing
for the
16-6 continued
PUSHF
CLD
MOV
SI.DX
OR
AL.AL
JZ
END_PATTERN
;Yes,
MOV
DL,AL
;No,
PATTERN_LOOP:
LODSB
LODSB
(0h)?
return
set up to write character N times
MOV
CL.AL
XOR
CH.CH
CALL
WRITE_CHAR_N_TIMES
JMP
PATTERN_LOOP
END_PATTERN
POPF
POP
POP
DX
POP
CX
POP
AX
RET
WRITE PATTERN
ENDP
how this procedure works, we will show you how to write data
for patterns. You will place the data for the top-line pattern into the file
Disp_sec, which is where you will use it. To this end, you will add another
procedure called INIT_SEC_DISP to initialize the sector display by writing
Before you see
Then you
INIT_SEC_DISP procedure.
where you defined
will
First,
modify
READ_SECTOR
to call
DISP_SEC.ASM
.DATA
TOP_LINE_PATTERN
DB
228
LABEL
'
BYTE
',7
DB
UPPER_LEFT,1
DB
H0RIZ0NTAL_BAR,12
DB
T0P_TICK,1
DB
H0RIZ0NTAL_BAR,11
HH
^^
ir
your
.DATA?
16
DB
n:
H0RIZ0NTAL_BAR,,11
DB
T0P_TICK,1
DB
DB
HORIZONTAL_BAR ,12
TOP_T_BAR
DB
HORIZONTAL_BAR,,18
DB
UPPER_RIGHT,1
DB
BOTTOM..LINE..PATTERN
T0P_TICK,1
DB
DB
'
LABEL
B^
BYTE
',7
DB
L0WER_LEFT,1
DB
H0RIZ0NTAL_BAR,,12
DB
B0TT0M_TICK,1
DB
HORIZONTAL_BAR,,11
DB
B0TT0M_TICK,1
DB
H0RIZ0NTAL_BAR,ill
DB
B0TT0M_TICK,1
DB
HORIZONTAL_BAR,,12
DB
BOTTOM_T_BAR
OB
HORIZONTAL_BAR, 18
DB
L0WER_RIGHT,1
DB
DB
DATA?
SECTOR
Note
you put
that
you need
all
the
new
all
data into
because
these variables.
DB statement contains part of the data for one line. The first byte the
character to print; the second byte tells WRITE_PATTERN how many times
Each
is
to repeat that character. For example, the top line starts with seven blank spaces,
followed by one upper-left-corner character, followed by twelve horizontalbar characters, and so on.
The
last
DB
is
We will continue the modifications and show you the result before we discuss
the inner workings of WRITE_PATTERN. Here is the test version of
INIT_SEC_DISP. This procedure writes
display,
just before
DISP HALF
SECTOR
it
in the
file
DISP_SEC.ASM,
as follows:
229
Assembly Language
for the
Listing 16-8
Add
This Procedure to
DISP_SEC.ASM
PUBLIC
INIT_SEC_DISP
EXTRN
WRITE_PATTERN:PROC, SEND_CRLF:PROC
Uses:
Reads:
TOP_LINE_PATTERN
INIT_SEC_DISP
PUSH
BOTTOM_LINE_PATTERN
PROC
DX
LEA
DX,TOP_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
SEND_CRLF
XOR
DX,DX
CALL
DISP_HALF_SECTOR
LEA
DX BOTTOM_L I NEPATTERN
CALL
WRITE_PATTERN
POP
DX
RET
By using
the
ENDP
LEA
WRITE_PATTERN
knows where
DX
register,
than
WRITE_HALF_SECTOR_DISP, so that a
Listing
EXTRN
DISKJO.ASM
INIT_SEC_DISP PROC
This procedure reads the first sector on disk A and dumps the first
READ_SECTOR
230
in
PROC
MOV
AX.DGROUP
MOV
DS,AX
16
MOV
AL,0
MOV
CX,1
;Read only
MOV
DX,0
LEA
BX, SECTOR
INT
25h
DX.DX
;S e t
INIT_SEC_DISP
MOV
AH,4Ch
;Return to DOS
INT
21h
POPF
xon
-C^LIrr-
all
you need
to
sector
offs e t to
ENDP
READ SECTOR
That's
you changed
if
you
files
using
NMake) and
give
it
now have.
C>disk_ o
88
30
E8
88
41
8E
IG 53
8F 8B
OD 13
89 BE
EB
82
88
54
08
18
28
38
48
58
68
78
88
98
16 IE
70 03
IE 8B
88 BB
68 81
R6 75
E8 5F
B8
08
D8
8
F8
98
88
88
40
D8
BF
BE
72
28
70
49
70
88
E8
an
88
4D
68
88
40
BO
3E
53
89
88
28
88
70
18 70
79 33
70 1^8
83 86
70 89
83 03
85 8B
flO 88
8D 7F
33 08
44 4F 53
F9 87 88
88 29 8D
31 46 41
70 16 87
B9 8B 88
88 4D F9
08 39 86
35
BF
85
54
BB
FO
89
13
18 70 F7 26
8E 70
16 4B
48 F7
16 52
72 16
28 Bg
OD 16
83
70
F3
70
8B
SB
5E
D2
B8
81
ni
FB
88
IF
2E 38 88
88 82 88
10 19 55
31 32 28
78 88 36
F3 04 86
47 82 07
70 74 88
16 70 83
88 P3 58
28 88 F7
86 49 70
58 70 E8
B9 BB 88
F3 (\S 74
8F 84 8F
82
BB
4E
28
05
81 81 88
88 BB
4E 53
Ffi 33
IE 56
45 FE
70 FB
13 70
70 13
16 52
70 8B
4B 70
72 ID
7D F3
9E 7D
OD 13
BB
49
28
37
IF 06
87 3E
8B BE
86 10
70 89
26 11
83 16
92 88
BE E6
18 BE
44 82
6<eMSD0S5.B
.a.
'
)ia. .UNINS
TOLL 1FPT12
3
l*iJUl.!..ilx.6+7.U
.ST>!^|.."<n..|=E.
.1. !eMSG.||.>!/
= r93 L9
t i
.
!a. !=.
e.
..:... la^i.uPie.K
=
uI e K
1
f=<. .iis.k;
ll.
i "]
.i.R!iP!Sffi.r.
.5!<.r.i\ri|..='>'><
^u.U
\\.
.<H.JK>
5 .3l-.".ft.flD. =
c>_
Let's see
how WRITE_PATTERN
instructions.
instructions
acters.
That
LODSB
is
stands for
works. As mentioned,
Load String
Byte,
which
is
it
uses
work with
strings
of char-
not quite what you are doing here, but the 80x86 doesn't care
two new
purposes just
LODSB
fine.
231
Assembly Language
LODSB
for the
moves
DS
tion,
AL
in
register
before.
Before the
You
LODSB
already
instruc-
MOV SI,DX.
LODSB
The
instruction
powerful.
one
instruction
the beginning.
That
LODSB
LODSB
to do.
flag. If you
would decrement
is
had
LODSB
CLD {Clear
what the
instruction,
Aside from
LODSB and CLD, notice that we also used the PUSHF and POPF
instructions to save
we
and
We
procedure that
calls
WRITE PATTERN.
it is
on
to Part III,
better things.
Right now, notice that the display lacks a row of numbers across the top.
Such numbers
down
the
00 01
columns
cedure to print
02 03 and so forth
this
232
any
WRITE_TOP_HEX_NUMBERS
INIT SEC DISP.
to
to sight
DISP_SEC.ASM
just
after
16
Listing
EXTRN
Uses:
WRITE_TOP_HEX_ NUMBERS
PUSH
OX
PROC
PUSH
DX
MOV
DL,
MOV
CX,9
CALL
WRITE_CHAR_N_TIMES
XOR
DH,DH
'
;Write 9 spec
'
Start with
HEX_NUMBER_LOOP:
MOV
DL,DH
CALL
WRITE_HEX
MOV
DL,'
CALL
WRITE_CHAR
INC
DH
CMP
DH,10h
JB
HEX_NUMBER_LOOP
MOV
DL,'
MOV
CX,2
CALL
WRITE_CHAR_N_TIMES
XOR
HEX_DIGIT_LOOP
;Done yet?
jWrite hex nu
DL.DL
:
CALL
WRITE_HEX_DIGIT
INC
DL
CMP
DL,10h
JB
HEX_DIGIT_LOOP
CALL
SEND_CRLF
POP
DX
POP
CX
RET
ENDP
233
Assembly Language
for the
1
Modify INIT_SEC_DISP
(also in
WRITE_TOP_HEX_NUMBERS
DISP_SEC.ASM)
before
it
as follows so
it
calls
display.
in
DISP_SEC.ASM
Uses:
Reads:
WRITE_TOP_HEX_NUIIIBERS
TOP_LINE_PATTERN
INIT_SEC_DISP
BOTTOM_LINE_PATTERN
PROC
PUSH
DX
CALL
LEA
DX,TOP_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
SEND_CRLF
XGR
DX,DX
CALL
DISP_HALF_SECTOR
LEA
DX,BOTTOM_LINE_PATTERN
CALL
WRITE_PATTERN
POP
DX
RET
ENDP
play,
the
are
still
some
differences
change WRITE_CHAR so
between
it
shown
this display
as
256
and center
in Figure
and the
6-4.
final version.
characters the
We
PC can dis-
using
Summary
You have done a lot of work on
dures, changing old ones,
From now
234
on,
if you
you
file
you
Odisk
will
Appendix
B.
16
The
listing there
88
EB
82
88
54
C8
18
28
38
48
58
68
78
88
98
n8
B8
C8
D8
E8
F8
IB
3C
E8
88
41
8E
53
8B
8F
CD 13
89 8E
IG IE
98
88
88
4C
D8
BF
8E
72
28
7C
49
7C
88
E8
4D
68
88
4C
BC
3E
18
79
7C
83
7C
83
85
?C A3
IE 8B
88 BB
ftC
B8 81
ne 75 8fl 8D
E8 5F 88 33
53
89
88
28
88
7C
7C
33
A8
86
89
C3
8B
88
7F
C8
44
F9
88
31
7C
B9
88
C8
18
BE
16
48
16
16
BB
4D
39
7C
7C
4B
F7
52
72 16
28 B9
CD 16
53 35 2E 38
88 8F 88 82
8D 85 IC 19
41 54 31 32
87 BB 78 88
88 FC F3 ft4
F9 89 47 82
86 13 7C 74
F7 26 16 7C
83 D2 88 03
7C B8 28 88
F3 81 86 49
7C 01 58 7C
8B FB B9 8B
BB 88 F3 06
5E IF 8F 84
88
88
55
28
36
86
C7
88
83
58
F7
7C
E8
88
74
8F
82
88
4E
28
C5
81
88
49
28
37
IF C6
87 3E
8B 8E
86 IC
7C 89
26 11
83 16
92 88
BE E6
18 BE
44 82
learn
two new
instructions:
4F
B7
29
46
81 88
88 88
4E 53
Fft 33
IE 56
45 FE
7C FB
13 7C
7C 13
16 52
7C 8B
4B 7C
72 ID
7D F3
9E 7D
CD 19
81234567890BCDEF
5<eHSD0S5.8
..'.)ia. .UNINS
3
TOLL 1F0T12
IflJia.i
.i,x.6+7.U
.St>!{|. ."<n.
.1
= .ry3L9.
e
[a.
|=E
!eMeG.||.>!/
.
\=ti
It.i
.
'
laTi.uPle.R
luIie.Ki^ .=.!i
[=<. .I!a.K!
.i.RliPISIt.r.
il.
.5;.r.i/fl. .Jp}!
.
the final
is
88 81 82 83 84 85 86 87 88 89 8n 8B 8C 8D 8E 8F
Figure 16-4:
in
you
on
tricks, just
to use
is
one of the
LODSB
which
They will
save
book you
you
from memory.
will learn
a lot of time.
235
TTT
I
The IBM PC's
ROM BIOS
[23|<a[3Fl9Tgj
l|A8|43|2EiBD
|A9 |60|CE|5D|42 | C8
63T57
^
96
\^^^
The
ri
i
I
ROM BIOS
Routines
In
this
to clear
how to
use the
INT
lOh
your screen and move the cursor to any location on the screen. You
will rewrite
Dskpatch so that it
it
draws.
hard-wired numbers. Finally, you will add a status line to the top of Dskpatch's
screen.
Files altered:
VIDEO_IO.ASM, DISK_IO.ASM
Disk files: DSKPAT17.ASM, DISP_S17.ASM, CURSOR17.ASM,
VIDEO_17.ASM, DISK_I17.ASM
bpics Covere
The
ROM BIOS
Display Routines
Summaiy
Assembly Language
for the
Vrfomputer
Memory)
number of routines,
tines for
this
your computer.
much
very
like
all
ROM provides routines for performing input and output at a very low
level, it is
BIOS,
Output System.
DOS uses the ROM BIOS for such activities as sending characters to the screen
and reading and writing
to the disk,
and you
ROM BIOS
We will concentrate on the BIOS routines needed for Dskpatch. Among them
is
which includes
couldn't
The
you used an
INT
lOh
INT 21h
calls
ROM
the functions
BIOS
routines
In this chapter,
to
when you
we
DOS.
just as
calls
routines provide
ROM
will use
Dskpatch: one to clear the screen, and the other to move the cursor to any
screen location
do the
job. Later,
with these
DOS.
you
Hence, you
will see
is
avail-
ROM routines. Begin by using INT lOh to clear the screen before
The INT lOh instruction is your entry to a number of different functions. Recall
that, when you used the DOS INT 21h instruction, you selected a particular
240
17
function by placing
its
flinction
AH
register.
A full
way
list
number
in the
The
ROM
BIOS Routines
(AH)=0
The AL
mode
number.
Text Modes
(AL)=0
(AL)=1
40 by 25, color
(AL)=2
(AL)=3
80 by 25, color
(AL)=7
(AH)=1
(AL)=4
(AL)=5
(AL)=6
(CH)
is
is
monochrome
to 3
adapter. Valid
(CL)
The power-on
CH=6
bottom
13 for the
range:
The top
monochrome
is
display
isCH=llandCL=12.
241
Assembly Language
for the
(DH,DL)
(BH)
corner
left
The
display page.
has
room
is
is
the
color-graphics adapter
but
0.
position.
(BH)
Page number
On exit
(DH,DL)
(CH,CL)
Cursor
(AH) =4
Read
(AH) =5
light
size
pen position.
(AL)
and
(AH)=6
number of the
(AH) =3
position;
(0,0).
1;
from
(from
to 3 for
to
7 for modes
modes 2 and
3).
ScroU up.
Number
(AL)
of lines to blank
the window.
line.
Normal
at the
bottom of
one
scrolling blanks
window.
(CH,CL)
left
(DH,DL)
right corner of
corner of
window.
(BH)
(AH) =7
Scroll
Same
as scroll
242
down.
up (function
window
6),
but
blank
at
17
(AH)=8
Read
attribute
ROM
The
BIOS Routines
cursor.
(BH)
(AL)
Character read.
(AH)
modes
only).
(AH)-9
(AH)=10
(AH)=11
(CX)
Number
attribute
on
screen.
(AL)
Character to write.
(BL)
Attribute to write.
(BH)
Display page.
(CX)
Number
(AL)
Character to write.
attribute).
to 13
(AH)=14
Write
move
(AH)=15
teletype. Write
(AL)
Character to write.
(BL)
(BH)
mode
only).
state.
mode
(AL)
Display
(AH)
Number
(BH)
currently
set.
of characters per
line.
243
Assembly Language
for the
doubles
You
6, Scroll Active
Page Up, to
clear
don't actually want to scroll the screen, but this function also
as a clear-screen function.
file
CURSOR.ASM.
Added
to
CORSOR.ASM
CLEAR SCREEN
CLEAR_SCREEN
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
XOR
AL,AL
XOR
CX,CX
MOV
DH,24
MOV
DL,79
MOV
BH,7
MOV
AH, 6
INT
10h
POP
DX
POP
CX
POP
BX
POP
AX
RET
CLEAR SCREEN
It
ENDP
appears that
even though
powerful.
dow).
It
INT
all
you want
to set the
do
is
window
and 24 and
244
to
lot
of information,
This function
is
rather
can actually clear any rectangular part of the screen (called a win-
You have
last lines to
all
setting the
white
columns
(for use
to
by
setting the
first
and
all
black
(for use
the instruction
tells this
Now
latter,
The
~1
17
which
is
ROM
BIOS Routines
specified with
you need
modify the
to
test
procedure,
it.
READ_SECTOR,
to call
CLEAR_SCREEN just before starts to write the sector display. We did not
CALL in INIT_SEC_DISP, because you will want to use
it
place this
INIT_SEC_DISP
rest
of the screen.
Listing
EXTRN
in
for
CLEAR_
the following
DISKJO.ASM
INIT_SEC_DISP:PROC, CLEAR_SCREEN:PROC
This procedure reads the first sector on disk A and dumps the first
half of this sector.
READ_SECTOR
PROC
MOV
AX.DGROUP
MOV
DS.AX
MOV
AL,0
MOV
CX,1
;Read only
MOV
DX,0
LEA
BX, SECTOR
INT
25h
sector
POPF
CALL
CLEAR_SCREEN
CALL
INIT_SEC_DISP
MOV
AH 4Ch
INT
21h
READ_SECTOR
Return to DOS
ENDP
245
Assembly Language
for the
is
to be before
probably
The
at the
we didn't mention anything about movBASIC, the CLS command does two things
the screen and then moves the cursor to the top of the screen. Our
cleared,
clears
procedure doesn't do
that;
you
will
function
GOTO_XY
file
as to the
top after a
clear).
Enter
this
procedure
CURSOR.ASM:
Added to CGRSOR.ASM
CURSOR 17. ASM)
(Complete Listing
<^^>
PUBLIC
in
GOTO_XY
On entry:
DH
Row (Y)
DL
Column
PROC
GOTO XY
PUSH
AX
PUSH
BX
246
Display page
MOV
BH,0
MOV
AH, 2
INT
10h
POP
BX
POP
AX
RET
GOTO XY
(X)
ENDP
17
You
will use
GOTO_XY in
a revised version
of
The
INIT_SEC_DISP
ROM
fications
made
INIT_SEC_DISP
to
in
DISP SEC.ASM
T""
in
PUBLIC
INIT_SEC_DISP
EXTRN
move
to
the cursor to the second line just before you write the half-sector display.
BIOS Routines
Modi-
are as follows:
DISP_SEC.ASM
EXTRN
Reads:
WRITE_TOP_HEX_NUMBERS, GOTO_XY
TOP_LINE_PATTERN, BOTTOM_LINE PATTERN
INIT_S EC_DISP
PROC
PUSH
DX
W/^KM
XOR
^^^H^K
MOV
GOTO_XY
CALL
WRITE_TOP_HEX_NUMBERS
LEA
DX,TOP_LINE_PATTERN
I^^^^HI
CALL
is
nicely centered.
It is easier to
work with
the screen
improve
WRITE_CHAR so
that
it
will write
the
WRITE_HEADER.
screen to
show
This procedure
top of the
247
Assembly Language
for the
is
much
that needs to
WRITE_HEADER.
Many of our procedures as they are now have numbers hard-wired into
for example,
READ_SECTOR reads
on
sector
You
will
drive A.
We want to
variables, so
them;
place
memory variables.
You will begin by putting all memory variables into one file, DSKPATCHASM,
to make your work simpler. Dskpatch.asm will be the first file in your program so
the memory variables will be easy to find there. The DSKPATCHj\SM, complete with a long list of memory variables is as folows:
New
File
DSKPATCH.ASM
DOSSEG
.MODEL
SMALL
STACK
.DATA
PUBLIC
SECTOR_OFFSET
SECTOR_OFFSET is the offset of the halfsector display into the full sector. It must
be a multiple of 16, and not greater than 256
SECTOR_OFFSET
PUBLIC
DW
CURRENT_SECTOR_NO, DISK_DRIVE_NO
CURRENT_SECTOR_NO
DW
Initially sector
DISK DRIVE NO
DB
Initially Drive A:
PUBLIC
LINES_BEFORE_SECTOR, HEADER_LINE_NO
PUBLIC
HEADER_PART_1
HEADER_PART_2
sector display.
248
17
LINES_BEFORE_SECTOR
DB
HEAOER_LINE_NO
DB
HEADER_PART_1
DB
HEADER PART 2
DB
The
ROM
BIOS Routines
'
Disk
'
,0
Sector
'
,0
DATA?
PUBLIC
SECTOR
SECTOR
DB
EXTRN
.CODE
EXTRN
DISK_PATCH
MOV
AX.DGROUP
MOV
DS.AX
CALL
CLEAR_SCREEN
CALL
READ_SECTOR
CALL
MOV
AH,4Ch
INT
21h
DISKPATGH
The main
them
Return to DOS
ENDP
DISK PATCH
END
seen
INIT_SEC_DISP:PROC
PROC
procedure,
all
DISK_PATCH,
calls
INIT_SEC_DISP
you
You have
READ_SECTOR and
segment.
Before using Dskpatch, you need to modify Disp_sec to replace the definition
of
249
Assembly Language
Let's take
for the
it
in
DSKPATCH.ASM as
Listing
.
DATA?
PUBLIC
SECTOR
SCCTOn
BB-
81 9 2
DUP(?)
DISK_IO.ASM so that it contains only procedures and so that READ_SECTOR uses memory variables (not hard-wired
numbers) for the sector and disk-drive numbers. The new version of
DISK IO.ASM is as follows:
Next you
Listing 17-7
Changes to DISKJO.ASM
DOSSEG
SMALL
M ODEL
STACK
.DATA
EXTRN
SECTOR: BYTE
EXTRN
DISK_DRIVE_NO:BYTE
EXTRN
PUBLib
feeA6jieT6ft
EXTRN
INIT_SEC_DISP PROC
.CODE
r-
CLEAn_SCnEEN PROC
:
250
Reads:
CURRENT_SECTOR_NO, DISK_DRIVE_NO
Writes:
SECTOR
y. ,..
t..-
17
READSECTOR
BIOS Routines
DS.AX
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AL,DISK_DRIVE_NO
MOV
CX,1
;Read only
MOV
DX , CURRENT_SECTOR_NO
LEA
BX, SECTOR
INT
25h
POPF
ROM
PROC
AX DOnOUP
MOV-
MOV
The
Drive number
1
sector
||m
POP
DX
POP
CX
POP
BX
POP
AX
RET
CALL
CLEAR SCREEN
GAtt-
MOV-
A H ,4Ch
R e turn to
DOS
itff-
READ_SECTOR
ENDP
END
and
to
drives. If
you
start
DSKPATCH.ASM,
NMake
program
to rebuild
DSKPATCH.COM, you will need to make some additions to your Make file
named
Makefile.
Listing
The
17-8 The
dskpatch.exe:
New
Version of
MAKEFILE
251
Assembly Language
17-8 continued
Listing
Ov
for the
dskpatch.obj
dskpatch.asm
ml /c dskpatch.asm
disk_io.asm
disk_io.obj:
ml /c disk_io.asm
disp_sec.obj
disp_sec.asm
ml /c disp_sec.asm
video_io ob
.
video_io asm
.
ml /c video_io.asm
cursor. obj:
cursor. asm
ml /c cursor. asm
that if you are using Malce from MASM 5 or earlier, the first two
shown here must be at the end of your MaJcefile. If you are not using
Remember
lines
NMake,
be sure to reassemble
all
three
files
files
with Dskpatch
listed first:
it
Disk A
will
look
like this:
Sector
by a blank
space),
252
two
and
strings of characters,
a disk letter, such as A.
DISP_SEC.ASM:
Disk and
To
begin,
17
The
ROM
BIOS Routines
Listing
PUBLIC
WRITE_HEADER
EXTRN
HEADER_LINE_NO:BYTE
EXTRN
HEADER_PART_1 :BYTE
.DATA
EXTRN
HEADER_PART_2:BYTE
EXTRN
DISK_DRIVE_NO:BYTE
EXTRN
CURRENT_SECTOR_NO:WORD
EXTRN
.CODE
EXTRN
This procedure writes the header with disk-drive and sector number.
Uses:
Reads:
HEADER_LINE_NO, HEADER_PART_1
HEADER_PART_2
DISK_DRIVE_NO, CURRENT_SECTOR NO
WRITE_HEADER
PUSH
PROC
DX
XOR
DL.DL
MOV
DH,HEADER_LINE_NO
CALL
GOTO_XY
LEA
DX,HEADER_PART_1
CALL
WRITE_STRING
MOV
DL,DISK_DRIVE_NO
ADD
DL, 'A'
CALL
WRITE_CHAR
jPrint drives A, B,
LEA
DX,HEADER_PART_2
CALL
WRITE_STRING
MOV
DX CURRENT_SECTOR_NO
CALL
WRITE_DECIMAL
POP
DX
RET
WRITE HEADER
The procedure
to use
it
ENDP
WRITE_STRING
to write a string
HEADER_PART_1
you can
see,
we plan
string.
253
Assembly Language
for the
We have chosen to supply our own string-output procedure so that our strings
can contain any character, including the $ which could not be printed with
DOS function 9. In places where DOS uses a $ to mark the end of a string, we
will use a
hex
0.
VIDEO_IO.ASM:
Listing
PUBLIC
WRITE_STRING
DB
On entry:
DS:DX
Uses:
WRITE CHAR
WRITE_STRING
PROC
PUSH
AX
PUSH
DX
PUSH
SI
PUSHF
CLD
MOV
SI,DX
STRING_LOOP:
;Get a character into AL register
LODSB
yet?
OR
AL,AL
JZ
END_OF_STRING
MOV
DL.AL
;No,
CALL
WRITE_CHAR
JMP
STRING_LOOP
write character
END_OF_STRING:
;Restore direction flag
POPF
POP
SI
POP
DX
POP
AX
RET
WRITE STRING
254
ENDP
17
As
it
stands now,
WRITE_STRING
WRITE_CHAR
as a
period
(.),
because
We
EXTRN
CLEARSCREEN:!
EXTRN
INIT_SEC_DISP
BIOS Routines
design
is
that
include
to
in
the
of that
you
will
CALL
to
DSKPATCH.ASM
PROC
MOV
AX,DGROUP
MOV
DS,AX
CALL
CLEARSCREEN
CALL
WDITE.HEAOER
CALL
READ_SECTOR
CALL
INIT_SEC_DISP
MOV
AH,4Ch
INT
21h
DISK PATCH
ROM
DISK_PATCH
we
The
Return to DOS
ENDP
Dskpatch should
now produce
one
in Figure 17-1.
255
:
.
Assembly Language
for the
Sector 8
Disk n
88 81 82 83 84 8S 86 87 88 89 80 86 BC BD BE BF
ei23456789fi6CDEF
88
18
28
38
48
58
68
78
88
98
n8
B8
C8
DB
8
F8
3C
E8
88
41
8E
16 53
8F 8B
CD 13
89 BE
EB
82
88
54
C8
16 IE
7C 03
IE 86
88 BB
Be 81
P6 75
E8 5F
98 4D 53 44
88 68 89 F9
88 BB 88 BB
4C 4C 28 31
D8 BC 88 7C
BF 3E 7C B9
BE 18 7C 88
72 79 33 C8
28 7C flB 18
7C 83 86 BE
49 7C 89 16
7C B3 C3 48
88 85 8B 16
EB ftC 88 72
Bfl 8D 7F 28
88 33 C8 CD
4F
87
29
46
16
BB
4D
39
7C
7C
4B
F7
52
IB
69
16
53
88
8D
41
87
88
F9
86
F7
83
7C
F3
70
86
8B
5E
35
BF
85
54
BB
FC
89
13
26
D2
68
81
01
FB
88
IF
2E 38 88
BB 82 BB
IC 19 55
31 32 28
78 88 36
F3 04 86
47 82 C7
7C 74 88
16 7C 83
88 03 58
28 88 F7
86 49 7C
58 7C E8
69 86 88
F3 06 74
8F 84 8F
82
88
4E
28
C5
81
88
49
28
37
IF C6
87 3E
86 BE
86 IC
7C 89
26 11
83 16
92 88
6E E6
18 6E
44 82
81
88
4E
FO
IE
45
7C
13
BB
88
53
33
56
FE
FB
7C
7C 13
16 52
7C 86
46 7C
72 ID
7D F3
9E 7D
CD 19
6<eMSD0S5.8
.a.
'
)ia. .UNINS
TOLL 1F0T12
3
LftJ'J'.
.iix.6-|-7.U
.ST>!{|.."in.. hE.
i. !eH eG.||.>U
= .ra3L9. ;t.i.
e
a .! =A .!...!
..!... !a.uP!fe.R
uI e K
=A
1
[=<. .lia.K!
Tl. .i.R!iPI5(t.r.
.
! "^
'
.5S(.r.i\ri|. .='>'><
c>_
top.
Summary
At
last
a full
Dskpatch program.
First
you learned about INT lOh, function number 6, which you used to clear
You briefly saw that this function has more uses than you will take
the screen.
advantage of in
this
fiinction 2 of
INT
lOh
easier to
memory variables,
will
in other
work
to
move
for
on
To make programs
you
256
Now
in
DSKPATCH.ASM.
17
Finally,
Thanks
to
will
ROM
BIOS Routines
will
do
As mentioned, an
The
this
re-
WRITE_CHAR.
257
H1A
rc~f
The
p rt
Clltimate
WRITE CHAR
In
this chapter,
you
will finally
new INT
you
move
can display
using sev-
9 to display a character on
it
difficult,
of
one position
CURSOR.ASM, VIDEO_IO.ASM
Topics Covered
A New WRITE_CHAR
Clearing to the
End
Summary
of a Line
Assembly Language
for the
the screen
will see
some of them
in this chapter.
DOS alone has not enabled you to display all 256 of the characters that
PC
sion of
is
WRITE_CHAR that
displays
new ver-
INT
lOh function.
Why
is
digits) to sector
to the right
WRITE_HEADER so that
CLEAR_TO_END_OF_LINE,
it
of
anything
else
line.
A New WRITE_CHAR
The ROM BIOS
fiinction 9 for
and color
Dskpatch: attribute
is
ally for
it
on
The
as in Figure 18-1.
You will
a foreground color of
(black characters
a white background).
You can
inverse video
we
a phantom cursor.
For now, we
will call
a character.
The INT
lOh, function 9 writes the character and attribute at the current cursor
position. Unlike
position unless
used
later, in a
character, so
Here
260
is
the
DOS,
it
you
writes
will
move
right
WRITE CHAR in
the
file
VIDEO lO.ASM:
to
18
Intensity
= Normal intensity
= Bright
RGB
Blink
Value
= Normal
= Blinking text
2
3
i
B R
Figure 18-1:
G B
R G B
Background
Text
Color
Color
Color
Black
Blue
Green
Cyan
Red
Violet
6
7
White
Brown
WRITE_CHAR
EXTRN
in
VIDEOJO.ASM
This procedure outputs a character to the screen using the ROM BIOS
routines, so that characters such as the backspace are treated as
On entry:
DL
Uses:
CURSOR RIGHT
WRITE_CHAR
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
261
Assembly Language
for the
Mev
IG PRINTA B LE
DL,32
;I 9
IS PniNTA B LE:
;No,
-BH
-AH-i
g+h
""ov
AH, 9
HP""*' MOV
BH,e
r e plac e
with a p e riod
'i^^^^^H Hp
^>^^^^H
V^Hf
MOV
th e n print as is
mf
m
B
B
B
H
Ye3,
-Mev-
HHB
MOV
AL,DL
;Character to write
MOV
BL,7
INT
ieh
CALL
CURSOR_RIGHT
POP
DX
POP
cx
POP
BX
POP
AX
Normal attribute
RET
WRITE CHAR
ENDP
normal
in
text
struction to set
As
BH
We will
first
(as
included
opposed
to 0.
move
the cursor right one character position or to the beginning of the next
hne
the
if
movement would
column
CURSOR.ASM.
Added
to
CGRSOR.ASM
CURSOR RIGHT
This procedure moves the cursor one position to the right or to the
next line if the cursor was at the end of a line.
262
2
3
18
SEND_CRLF
Uses
>
...........
CURSOR. RIGHT
PUSH
...
.......
........
.^
PROC
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AH,
MOV
BH,0
;0n page
INT
10h
MOV
AH,
INC
DL
CMP
DL,79
JBE
OK
CALL
SEND_CRLF
JMP
DONE
OK:
INT
10h
DONE:
POP
DX
POP
CX
POP
BX
POP
AX
RET
CURSOR_ RIGHT
ENDP
CURSOR_RIGHT
uses
dure
first
two new
INT
bytes, the
CURSOR_RIGT
DL was
cursor. If
in
move
column
(79), the
these changes,
in Figure 18-2.
less
returned in two
it
makes
With
is
in
at the last
return/line-feed pair to
column 79 check
which
column number
CURSOR_RIGHT a
own
programs.
that
it
this
as
shown
than 20h and seeing whether some strange character has replaced the pe-
produced
in the
ASCII window.
263
Assembly Language
Sector 8
Disk n
88 81 82 83 84 85 88 87 88 89
I
88
18
28
38
48
58
68
70
88
98
ne
B8
C8
08
E8
FB
EB
82
88
54
C8
3C
E8
88
41
8E
53
8B
13
8E
IE
98
88
88
4C
D8
IG
BF
8F
8E
72
CD
aa
28
IG
7C
7C f3 49
IE 8B 7C
88 BB 88
B8 81 E8
06 75
E8 5F 08
4D
68
88
4C
BC
3E
18
79
7C
83
7C
83
85
(K
8D
33
8B BC BD BE BF
0123456789ftBCDEF
53
89
88
28
88
7C
7C
33
08
86
89
C3
8B
08
7F
C8
44
F9
88
31
7C
4F
87
29
46
16
B9 BB
88 4D
C8 39
IB 7C
BE 7C
16 4B
48 F7
16 52
72 16
28 B9
CD 16
53
88
8D
41
87
08
F9
06
F7
83
7C
F3
7C
8B
BB
5E
35
BF
8S
54
BB
FC
89
13
26
DZ
B8
81
2E 38 88
08 02 88
IC 19 55
31 32 28
78 88 36
F3 04 86
47 82 C7
7C 74 88
16 7C 83
00 03 58
28 80 F7
86 49 7C
fll 50 7C E8
FB B9 BB B8
88 F3 06 74
IF 8F 84 8F
new
82
88
4E
28
C5
Bl
88
4E
FO
81
88
49
28
37
IF C6
87 3E
8B BE
86 IC
7C 89
26 11
83 16
92 08
BE E6
18 BE
44 82
6<eHSDOSS.0 BQE
at > . S 8
88
00
53
33
IE 56
45 FE
7C FB
13 7C
7C 13
16 52
7C 8B
4B 7C
72 ID
7D F3
9E 7D
CD 19
)ia'-iUNINS
TOLL 1F0T12
Ui^
l..flx 6+7AU
_ST>:fl<J "<nhE
riflT:eMeGaJ|.>:T
=!!ru3L9*!!!tBifl!!!
e4 :i^:=-:v4<-:!!
-AivMia, uPie-R
u I e^
=A4 V
A<}!J=<9I!a_K;
1 +i_RliP:at r~
S* r-ifiS =lv><
!
! =^
*uHU
5
J<f <*tTJ(t>
3 l=_'-ft^D8=i
WRITE_CHAR
End
Clearing to the
In the
last
chapter,
CLEAR_SCREEN
you used
window
frinction 6
The
is
which you
of the window, in
less
to the
this case,
window
is
that frinction 6
end of the
is
the
line.
CLEAR_TO_END_OF_LINE;
264
we mentioned
follows:
to clear part
lefr side
INT
of a Line
cursor,
CURSOR_RIGHT). The
You can
CURSOR.ASM
as
6
3
18
Added
to
CURSOR.ASM
(Complete
CURSOR 18.ASM)
PUBLIC
^Ch'
This procedure clears the line from the current cursor position to
the end of that line.
AX
PUSH
BX
PUSH
CX
PROC
PUSH
DX
MOV
AH,
XOR
BH.BH
INT
10h
MOV
AH,
XOR
AL,AL
Clear window
MOV
CM, DM
MOV
CL,DL
MOV
DL,79
MOV
BH,7
INT
10h
POP
DX
POP
CX
POP
BX
POP
AX
RET
ENDP
You will use this procedure in WRITE_HEADER to clear the rest of the line
when you start reading other sectors (that will be covered soon). You cannot
see
display.
But
revise
it
265
Assembly Language
for the
Listing
4^
PUBLIC
WRITE_HEADER
DISP_SEC.ASM
in
.DATA
EXTRN
HEADER_LINE_NO:BYTE
EXTRN
HEADERPARTI BYTE
EXTRN
HEADER_PART_2:BYTE
EXTRN
DISK_DRIVE_NO:BYTE
EXTRN
CURRENT_SECTOR_NO:WORD
EXTRN
EXTRN
GOTO_XY:PROC, CLEAR_TO_END_OF_LINE:PROC
.CODE
This procedure writes the header with disk-drive and sector number.
Uses:
CLEAR_TO_END_OF_LINE
HEADER_LINE_NO, HEADER_PART_1
Reads:
HEADER_PART_2
WRITE_HEADER
PROC
PUSH
DX
XOR
DL.DL
MOV
DH,HEADER_LINE_NO
CALL
GOTO_XY
LEA
DX,HEADER_PART_1
CALL
WRITE_STRING
MOV
DL,DISK_DRIVE_NO
ADD
DL, 'A'
CALL
WRITE_CHAR
;Print drives A, B,
LEA
DX HEADER_PART_2
CALL
WRITE_STRING
...
MOV
DX CURRENT_SECTOR_NO
CALL
WRITE_DECIMAL
CALL
CLEAR_TO_END_OF_LINE
POP
DX
RET
WRITE HEADER
ENDP
file
final version
of
and the
266
WRITE_HEADER
you
will
continue by adding
18
F3 and F4
commands. You
on the
will
disk.
Summary
This chapter has been
mation or
the
tricks.
You
relatively easy,
did learn
how
without
to use
much
INT
in the
lOh,
In the process,
you
also
saw how
with
INT
lOh
function 3 so that the cursor could be moved right one position after you wrote
a character.
writes just
Finally,
The
reason:
INT
lOh
you put
INT Oh
it
move
it
function 6 to
work by clearing
to business again as
we
dispatcher.
267
A P T
The Dispatcher
In
tliis
tains a lot
of code and
Files altered:
sets the
rest
III.
KBD_IO.ASM, DISK_IO.ASM
Disk files: DSKPAT19.ASM, DISP_S19.ASM, DISP_I19.ASM,
KBD_IOl9.ASM, DISK_I19.ASM
R'
Topics Covered
Building a Dispatcher
Assembly Language
for the
In any language it is
To
some
do
interactivity to
we need
life,
you do
this,
to
that," so
make it
we will
interactive. It
is
human
Dskpatch.
example,
when you
F3 key
press the
call a
to read
procedure called
sector,
PREVIOUS_SECTOR. To do this,
to Dskpatch.
PATCHER, the central dispatcher, and some other procedures for display fornew procedures, PREVIOUS_SECTOR and
NEXT_SECTOR, which will be called through DISPATCHER.
matting. Next, you will add two
Building a Dispatcher
The Dispatcher will be
and
call
it.
dispatcher does
its
work, but
see
first let's
how
numbers
for a
prompt
first
just
read charthe
dis-
will
soon see
into Dskpatch.
later
line as follows:
HEADER,.LINE_NO
DB
HEADER,.PART_1
DB
HEADER PART 2
DB
PUBLIC
DATA_SEG
PROMPT_LINE..NO,
'Disk
on you
modifications to
270
keyboard input
how
You
it fits
will.
all
'
in
DSKPATCH.ASM
,0
Sector'
',0
EDITOR_PROMPT
PROMPT..LINE_NO
DB
EDITOR..PROMPT
DB
DB
'
21
,e
19
The Dispatcher
You will add more prompts later to take care of such matters as inputting a
new sector number. Your job will be made simpler by using a common proce-
prompt on
this
new
line 21 (because
version of
is
is
as follows:
EXTRN
it.
PROC
MOV
AX.DGROUP
MOV
DS,AX
CALL
CLEAR_SCREEN
CALL
WRITE_HEADER
CALL
READ_SECTOR
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
CALL
DISPATCHER
MOV
AH,4Ch
INT
21h
DISK PATCH
in
DSKPATCH.ASM
EXTRN
DISK_PATCH
The
in
;Return to DOS
ENDP
The
following listing
is
the
first
we do
version of the
file
use
some new
tricks
DISPATCH.ASM.
271
Assembly Language
for the
SMALL
.CODE
EXTRN
NEXT_SECTOR:PROC
;In
DISK_IO.ASM
EXTRN
;In
.DATA
This table contains the legal extended ASCII keys and the addresses
of the procedures that should be called when each key is pressed.
DISPATCH_TABLE
DB
72
DW
OFFSET
LABEL
BYTE
DB
61
DW
OFFSET _TEXT:PREVIOUS_SECTOR
;F3
DB
62
DW
OFFSET _TEXT:NEXT_SECTOR
;F4
DB
.CODE
PUBLIC
DISPATCHER
EXTRN
Uses:
DISPATCHER
AX
PUSH
BX
DISPATCH LOOP:
272
PROC
PUSH
19
CALL
READ_BYTE
OR
AH, AH
AX =
-1
if no character read,
The Dispatcher
JS
DISPATCH_LOOP
JNZ
SPECIAL_KEY
DISPATCH LOOP
JMP
SPECIAL_KEY:
CMP
AL,68
;F10--exit?
JE
END_DISPATCH
;Yes,
leave
BX,DISPATCH_TAB
LEA
SPECIAL_LOOP:
CMP
;End of table?
JE
NOT_IN_TABLE
;Yes,
CMP
AL,[BX]
JE
DISPATCH
;Yes,
ADD
BX,3
;No,
JMP
SPECIAL_LOOP
then dispatch
try next entry
DISPATCH:
INC
BX
CALL
;Call procedure
JMP
DISPATCH_LOOP
NOT_IN_TABLE:
JMP
;Do nothing,
DISPATCH_LOOP
END_DISPATCH:
POP
BX
POP
AX
RET
DISPATCHER
ENDP
END
Each code
should
call
is
when
DISPATCHER
when
273
Assembly Language
for the
\
READ_BYTE, which
code 61),
The
is
called
by
DISPATCHER calls
dispatch table, so
following
we used
example,
line, for
tells
PREVIOUS_SECTOR procedure.
OFFSET _TEXT:PREVIOUS_SECTOR
DW
The calculation of this offset is relative to the start of your code segment
_TEXT, which is why we put the _TEXT: in front of the procedure name.
(As it turns out here, this _TEXT: isn't absolutely necessary. Still, in the interest of clarity, we will write OFFSET _TEXT: anyway.)
Notice that
a
tell
all
past,
words, or
we have
all
bytes.
But
here,
not
CMP
compare words or
bytes.
[BX],0
By writing the
a byte,
CMP
to
tell
BX points to
a byte compare.
On
lems because AL
that
you want
is
a byte register
a byte compare.
NEAR CALL needs one word for the address, while the FAR CALL needs two.
The
following instruction
pointed to by [BX]
274
should generate a
as the address.
DISPATCH_TABLE.
CALL
it
tells
The
WORD PTR,
NEAR CALL
address
is
that [BX]
the one
we
stored in
19
For
The Dispatcher
FAR CALL, which uses a rwo-word address, you would use the instrucCALL DWORD PTR [BX]. DWORD stands for Doul?le Word, or two
tion
words.
As you
will see in
easily
DISPATCH_TABLE.
still
to
entries in
fore you can test this new version of Dskpatch. You are missing READ_BYTE,
WRITE_PROMPT_LINE, PREV10US_S ECTOR, and NEXT_SECTOR.
The
numbers. At
this point,
is
the
keyboard,
file
where you
characters,
a simple version
which
ASCII
The
first
of READ_BYTE
version of
as follows:
is
to
KBD_IO.ASM,
SMALL
.CODE
PUBLIC
READ_BYTE
version of READ_BYTE.
a test
Returns:
AL
READBYTE
AH
PROC
XOR
AH, AH
INT
16h
OR
AL,AL
JZ
EXTENDED_CODE
;Yes
AH, AH
NOT_EXTENDED:
XOR
275
Assembly Language
for the
19-4 continued
Listing
DONE_READING:
RET
EXTENDED_CODE:
MOV
AL,AH
MOV
AH,1
JMP
DONE_READING
ENDP
READ BYTE
END
to the
6h, which
acter
it
acter
AH
The
scan code
such
as F3,
is
is
reads a char-
AL will
keys,
be
0),
but they do have scan codes (you will find a table of scan codes in Appendix
D).
sets
READ_BYTE puts this scan code into the M. register for special keys, and
AH to 1. Next, add the new procedure WRITE_PROMPT_LINE to
DISP SEC.ASM
Listing 19-5
as follows:
Add
(Complete Listing
DISP_SEC.ASM
DISP_S19.ASM)
This Procedure to
in
PUBLIC
WRITE_PROMPT_LINE
EXTRN
CLEAR_TO_END_OF_LINE:PROC, WRITE_STRING:PROC
EXTRN
GOTO XY:PROC
EXTRN
.DATA
.CODE
This procedure writes the prompt line to the screen and clears the
end of the line.
On entry:
276
DS:DX
"1
19
Uses:
Reads:
The Dispatcher
WRITE_PROMPT__LINE
PUSH
DX
PROC
XOR
DL.DL
MOV
DH,PROMPT_LINE_NO
CALL
GOTO_XY
POP
DX
CALL
WRITE_STRING
CALL
CLEAR_TO_END_OF_LINE
RET
WRITE_PROMPT__LINE
There
really isn't
ENDP
much
writes the
is
to this procedure. It
of the prompt
line
line,
cleared
(in
to the begin-
DSKPATCH.ASM) to line 2 1
of the
line.
WRITE_PROMPT_LINE is
by CLEAR_TO_END_OF_LINE.
when
The
cursor
is
Then,
at the
rest
end
of the
NEXT_SECTOR,
Add
to read
Listing
DISKJO.ASM
DISKJ19.ASM)
PUBLIC
and
sectors.
DISK_IO.ASM.
Lsting on
PREVIOUS_SECTOR
(Complete
PREVIOUS_SECTOR
EXTRN
EXTRN
EXTRN
CURRENT_SECTOR_NO:WORD, EDITOR_PROMPT:BYTE
.DATA
.CODE
277
I
Assembly Language
19-6 continued
Listing
Uses:
WRITE_PROMPT_LINE
Reads:
CURRENT_SECTOR_NO, EDITOR_PROMPT
Writes:
CURRENT SECTOR NO
PREVIOUS_SECTOR
PUSH
PROC
AX
PUSH
DX
MOV
AX CURRENT_SECTOR_NO
OR
AX, AX
JZ
DONT_DECREMENT_SECTOR
DEC
AX
MOV
CURRENT_SECTOR_NO AX
CALL
WRITE_HEADER
CALL
READ_SECTOR
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
DONT_DECREMENT_SECTOR
POP
DX
POP
AX
RET
ENDP
PREVIOUS SECTOR
PUBLIC
NEXT_SECTOR
EXTRN
INIT_SEC_DISP:PROC, WRITE_HEADER:PROC
EXTRN
WRITE_PROMPT_LINE:PROC
EXTRN
CURRENT_SECTOR_NO:WORD, EDITOR_PROMPT:BYTE
.DATA
.CODE
Uses:
WRITE_PROMPT_LINE
Reads:
CURRENT_SECTOR_NO, EDITOR_PROMPT
Writes:
CURRENT SECTOR NO
NEXT_SECTOR
PUSH
278
PROC
AX
19
PUSH
DX
MOV
AX CURRENT_SECTOR_NO
INC
AX
MOV
CURRENT_SECTOR_NO,AX
CALL
WRITE_HEADER
CALL
READ_SECTOR
The Dispatcher
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
POP
DX
POP
AX
RET
ENDP
NEXT SECTOR
Now you
new
version of Dskpatch
by assembling
all
the
Dskpatch,
files
Makefile are
make
Listing
to
list
19-7 Changes to
dskpatch.exe:
tJie
Make
tells
file
Make you
line):
File
MAKEFILE
cursor. obj:
cursor. asm
ml /c cursor. asm
dispatch. Ob]
dispatch. asm
ml /c dispatch. asm
kbd_io obj
.
kbd_io asm
.
ml /c kbd io.asm
279
Assembly Language
for the
Remember that the first three lines need to be at the end of your file if you are
using Make from MASM 5 or earlier. If you don't have Make or NMake, you
may wish to write the following short batch file to link and create your EXE
file:
files,
to
change
list
this
EXE
batch
file,
rather than
program.
This version of Dskpatch has three active keys: F3 reads and displays the previous sector, stopping at sector 0; F4 reads the next sector;
try.
FlO
exits
Figure 19-1.
Sector 8
Disk A
88 81 82 83 84 85 86 87 88 89 80 BB BC BD BE 8F
86
IB
28
38
48
58
68
78
88
98
B8
CB
DB
EB
FB
EB
82
88
54
ce
16
8F
CD
89
3C
EB
88
41
8E
53
8B
13
BE
16 IE
7C 03
IE 8B
88 BB
B8 81
06 75
E8 5F
98
88
88
4C
DB
BF
BE
72
28
7C
49
7C
88
E8
80
88
53
89
88
28
88
7C
7C
33
08
86
89
C3
8B
88
7F
CB
4D
68
BB
4C
BC
3E
18
79
7C
83
7C
83
85
OC
8D
33
44
F9
88
31
7C
B9
88
CB
18
BE
16
48
16
4F
87
29
46
16
BB
4D
39
7C
7C
4B
F7
52
72 16
28 B9
CD 16
53
88
8D
41
87
88
F9
86
F7
83
7C
F3
7C
8B
BB
5E
35
BF
85
54
BB
FC
89
13
26
D2
B8
81
01
FB
88
IF
2E 38 88
88 82 BB
IC 19 55
31 32 28
78 88 36
F3 04 86
47 82 C7
7C 74 88
16 7C 83
BB 03 58
28 88 F7
86 49 7C
58 7C E8
B9 BB 88
F3 06 74
8F 84 8F
82
88
4E
28
C5
81
88
49
28
37
IF C6
87 3E
8B BE
86 IC
7C 89
26 11
83 16
92 88
BE E6
18 BE
44 82
81
88
4E
FO
IE
45
7C
13
280
line.
88
88
53
33
56
FE
FB
7C
7C 13
16 52
7C 8B
4B 7C
72 ID
7D F3
9E 7D
CD 19
from
81234567890BCDEF
6<eHSD0S5.8 beg
Soc 'o.. B
)ia>-iUNINS
3
TOLL lFflT12
tflJUl
l-'iix
6+71U
.S-t>'4S ''<nft=E"
iflTleHSGBl|>IJ=!!ru3'-9#!!!tDiJ)!!l
eJ|
la^:=&.IV>-:!!
.l!M!a^ uPle_R
lull e-K
~ti4
l(flf=<E*Ila-KI
i_RliPI5R r
Tl
GBi( r-iJ-JM Jp}!
SufliA
\\g
mTJR}
3l=-"AftD=i
19
The Dispatcher
covered
far
now
on,
we
will clip
we
will
along
and
in that respect
be following in Chapters 20
at a fairly rapid
pace so
These chapters
new
to learning
ters
you
to learn from,
new subjects,
on Dskpatch
come back
are ready to
so
hang on, or
again,
you
IV of this book,
(if you
we can
come back
we'll
your
many
own
When you
programs.
program-
mms
Of course,
if you are
chomping
can use
if
you want
From Chapter 21
discover
at the bit
20
will give
you
on,
we
will present
many
are
different procedures
and
let
you
related to setting
you on your
you how
to write a large
So take the
rest
tom
suits
own programs.
to write
you
best.
Chapter 20
is
for
we will return
and move what we call a phanIn Chapter 21
displays.
281
A Programming
Challenge
In
this
chapter
we
Chapters 21 through 27. If you want to try writing some procedures yourself,
read this chapter
if you
first.
want some
Files altered:
hints
None
if you
get stuck, or
Assembly Language
his
to
book contains
gating
You may want
for the
six
this chapter.
We will
start
changes.
making
want
many details
to
it.
to xx\ navi-
and plot your way through Chapters 2 1 and 22. Then you can
make a copy of
you
If you
If you don't
now.
tr\'
wish to
It is ver\'
you
here,
to write the
try writing
your imagination.
Then when
on how
changes, or using
you r own
chapter, then go
the choice
offollow-
version.
ceed
through
is
a suggestion
to pro-
on
In Chapter 21
will place
it
A phantom cursor
is
is
similar to a
character wide.
Sector e
Disk H
ee ei 82 ea 84 85 ee e7 88 89 an ee 8C 80 BE BF
ee
18
28
38
48
58
G8
78
88
98
m
B8
C8
De
E8
FB
7KC
82
88
54
C8
Ee
ee
41
8E
IG 53
8F 8B
CD 13
89 eE
IG IE
7C 03
IE ea
88 BB
Be ei
ne 75
E8 5F
9e
ee
ee
4C
oe
BF
eE
72
2e
7C
49
7C
ee
E8
en
ee
53
eg
ee
2e
ee
7C
18 7C
79 33
7c fte
e3 ee
7C 89
e3 C3
es 8B
ftc ee
8D 7F
33 ce
4D
Be
ee
4C
Bc
3E
44
F9
ee
31
7C
B9
88
ce
le
eE
IG
48
IG
4F
e7
29
46
16
eB
4D
39
7C
7C
4B
F7
52
72 16
28 B9
CD 16
53 35 2E 38
ee eF ee 82
8D 85 IC 19
41 54 31 32
87 BB 78 ee
ee FC F3 A4
F9 83 47 B2
ee 13 7C 74
F7 2G IB 7C
83 D2 ee 03
7C B8 2e ee
F3 ei ee 49
7C fll se 7C
8B FB B9 eB
eB ee F3 ne
5E IF 8F e4
82
ee
4E
28
C5
81
ee
49
2e
37
IF 06
e7 3E
8B BE
BG IC
7C 89
2B 11
83 16
92 ee
BE EB
18 BE
44 e2
ee
ee
55
2e
3B
ee
C7
ee
83
58
r7
7C
E8
ee
74
8F
81 ae
ee Be
4E 53
33
IE 56
Fft
45 FE
7C FB
13 7C
7C 13
IB 52
7C 8B
4B 7C
72 IB
7D F3
9E 7D
CD 19
Figure 20-1:
284
in the
does not blink and the background turns white, with the
window
one
screen:
B12345e789flBCDEF
2<Et4SDOS5.e OGG
Bl "o-. S B
)ia-iUNINS
lOLL lFfiT12
3
IflJU !.^x 6-1-7 AU
_St>!|<}
'IM^hE*
riflT!eeGa|.>;j=!!ry3L94!!ltDifl!!:
efl
;*>;=_!*-:!!
_A:4la, uFle-K
luIie-Ki^
=4!i
A<f ;fW=<3I!aK!
\ i_R; ipsai rr-ij-flrf Jp}!
*uHU \i <*tt=IR>
5 3 l-=_*A*De=A
S*
n A Programming Challenge
20
in
Chapter
attribute
18.
for the
phantom
cursor, so
at-
your
PC
This byte
code of 7h displays
you want
The
latter
tells
a
is
characters to 70h?
INT
a character
real
Move
and an
window with
cursor (use
and save
INT
You
lOh function 3
this in variables).
phantom
window.
For the next four characters, read the character code (fiinction 8)
its
to 70h).
You can write a phantom cursor in the ASCII window in much the same way.
Once you have a working phantom cursor in the hex window, you can add
the extra code for the ASCII window.
Keep
in
mind
that your
cursors,
only temporary.
working
so
number of small procedures to do the work. Look at the proceChapter 21 when you are finished to see one way of doing this.
you have
dures in
first try is
Simple Editing
Once you have your phantom cursors, you will want to move them around on
the screen. You need to pay attention to boundary conditions in order to keep
the phantom cursors inside each of the two windows. You also want your two
phantom cursors to move together because they represent the hex and ASCII
representations of the
same
thing.
285
Assembly Language
for the
How can you move each phantom cursor? Each of the four cursor keys on the
keypad sends out a
down; 75
for cursor
need to add
to
procedures to
To
actually
nates
and 11
left;
72
number
DISPATCH_TABLE,
move
the
phantom
and write
phantom
special function
it
again. If
a character
for cursor
80
it,
then change
careftil
about
its
two coordi-
how you
wrote the
fairly simple.
this
character
and replace the byte under the phantom cursor with the character
just read.
The
Read
Change
ASCII window
Here
Change
is
number
to
in the
a simple hint
Dispatch requires
EDIT_BYTE)
as follows:
a character
the hex
is
little
more than
that does
to
just read.
SECTOR.
calling a
EDIT_BYTE
responsible for
is
SECTOR.
now?
still
become somewhat
like to see
Dskpatch do than
ter or a
does right
new version of READ_BYTE that will read either one charactwo-digit hex number and wait for you to press the Enter key before it
a
286
it
con-
it
trickier
own version,
sounds.
We will
list" is
not
this
as
simple
problem.
as
20
In Chapter 25,
we
will
in
is
disk. (In
analogous to the
INT 25h
that
you used
Finally, in
is
will learn
fiinction,
from the
but you
will find
Challenge
how
to read a sector
A Programming
Chapter 26 we
which
such
Chapter 27, we will make some changes to Dskpatch so you can see
the other half of the sector display. These changes won't allow
as freely as
we would
like,
you
to scroll
287
C H A
R
1
The Phantom
Cursors
In
this
the screen
one
Files altered:
Disk
files:
in the
DISP_SEC.ASM,
on
"opics
Covered
Summaryj
Assembly Language
In
for the
this
is
shadow
phantom
the ASCII window. A phantom cur-
the
acters.
display appears
Since the
work by
phantom
placing a
WRITE_PHANTOM
you
will begin
your
INIT_SEC_DISP. That
the phantom cursors every time you write a new sector dis-
call to
in
play.
in
DISP_SEC.ASM
as follows:
in
DISP_SEC.ASM
PUBLIC
INIT_SEC_DISP
EXTRN
WRITE_PATTERN:PROC, SEND_CRLF:PROC
EXTRN
GOTO_XY:PROC, WRITE_PHANTOM:PROC
.DATA
EXTRN
LINES_BEFORE_SECTOR:BYTE
EXTRN
CODE
This procedure initializes the half-sector display.
Uses:
TOP_LINE_PATTERN, BOTTOM_LINE_PATTERN
Writes:
SECTOR OFFSET
LINES_BEFORE_SECTOR
290
21
f^
PROC
INIT_SEC_DISP
PUSH
DX
XOR
DL,DL
MOV
DH LINES_BEFORE_SECTOR
CALL
GOTO_XY
CALL
WRITE_TOP_HEX_NUMBERS
LEA
DX,TOP_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
SEND_CRLF
XOR
DX.DX
MOV
SECTOR_OFFSET,DX
CALL
DISP_HALF_SECTOR
LEA
DX BOTTOM_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
WRITE_PHANTOM
POP
DX
RET
INIT SEC DISP
ENDP
INIT_SEC_DISP
to use
and
initiaUze
sector.
Let's
move on
to
WRITE_PHANTOM
itself.
WRITE_PHANTOM.
the
phantom
First,
you
bit
of
four characters to inverse video (attribute 70h). This creates a block of white,
tom
cursors will be in
PHANTOM. ASM,
WRITE_ATTRIBUTE_N_TIMES,
file
PFiANTOM.ASM:
291
Assembly Language
for the
1
Usting 21-2 The new file PHANTOM. ASM
(Complete listing in PHANT02 1 ASM)
.
D.
.MODEL
SMALL
.DATA
REAL_CURSOR_X
DB
REAL_CURSOR_Y
PUBLIC
DB
PHANTOM_CURSOR_X
PHANTOM_CURSOR_X
DB
PHANTOM CURSOR Y
DB
PHANTOM_CURSOR_Y
.CCDE
PUBLIC
MOV_TO_HEX_POSITION
EXTRN
GOTO_XY:PROC
EXTRN
.DATA
.CODE
This procedure moves the real cursor to the position of the phantom
Uses:
GOTO_XY
Reads:
LINES_BEFORE_SECTOR, PHANTOM_CURSOR_X
MOV_TO_HEX_POSITION
PHANTOM_CURSOR_Y
PROC
PUSH
AX
PUSH
CX
PUSH
DX
MOV
DH LINES_BEFORE_SECTOR
ADD
DH,2
ADD
DH PHANTOM_CURSOR_Y
MOV
DL,8
MOV
CL,3
MOV
AL PHANTOM_CURSOR_X
MUL
CL
ADD
DL.AL
CALL
GOTO_XY
POP
DX
POP
CX
POP
AX
RET
292
ENDP
21
PUBLIC
MOV_TO_ASCII_POSITION
EXTRN
GOTO_XY:PROC
EXTRN
.DATA
.CODE
This procedure moves the real cursor to the beginning of the phantom
cursor in the ASCII window.
Uses:
GOTOXY
Reads:
LINES_BEFORE_SECTOR, PHANTOM_CURSOR_X
PHANTOM_CURSOR_Y
PROC
AX
PUSH
DX
MOV
DH LINES_BEFORE_SECTOR
ADD
DH,2
ADD
DH PHANTOM_CURSOR_Y
MOV
DL,59
ADD
DL,PHANTOM_CURSOR_X
CALL
GOTO_XY
POP
DX
POP
AX
RET
PUBLIC
ENDP
SAVE_REAL_CURSOR
This procedure saves the position of the real cursor in the two
REAL CURSOR
SAVE_REAL_CURSOR
REAL CURSOR Y.
X and
X,
REAL CURSOR Y
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AH, 3
XOR
BH,BH
INT
10h
MOV
REAL_CURSOR_Y,DL
MOV
REAL_CURSOR_X DH
POP
DX
293
Assembly Language
Listing
for the
21-2 continued
POP
ex
POP
BX
POP
AX
RET
ENDP
PUBLIC
RESTORE_REAL_CURSOR
EXTRN
GOTO_XY:PROC
This procedure restores the real cursor to its old position, saved in
REAL CURSOR X and REAL CURSOR Y.
Uses:
GOTO_XY
Reads:
REALCURSORX
RESTORE_REAL_CURSOR
REALCURSORY
PROC
PUSH
DX
MOV
DL,REAL_CURSOR_Y
MOV
DH,REAL_CURSOR_X
CALL
GOTO_XY
POP
DX
RET
ENDP
PUBLIC
WRITE_PHANTOM
EXTRN
WRITE_ATTRIBUTE_N_TIMES:PROC
.
.
as the
WRITE_ATTRIBUTE_N_TIMES, SAVE_REAL_CURSOR
Uses:
RESTORE_REAL_CURSOR
MOV_TO_HEX_POSITION
ITE_PHANTOM
PUSH
294
PROC
CX
PUSH
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_POSITION
MOV
CX,4
MOV
DL,70h
CALL
WRITE ATTRIBUTE
TIMES
21
CALL
MOV_TO_ASCI I_POSITION
MOV
CX,1
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
RESTORE_REAL_CURSOR
POP
DX
POP
OX
RET
WRITE PHANTOM
ENDP
PUBLIC
ERASE_PHANTOM
EXTRN
WRITE_ATTRIBUTE_N_TIMES PROC
:
WRITE PHANTOM.
WRITE_ATTRIBUTE_N_TIMES
Uses:
RESTORE_REAL_CURSOR
SAVE_REAL_CURSOR
MOV_TO_HEX_POSITION
ERASE_PHANTOM
PUSH
PROC
CX
PUSH
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_POSITION
MOV
OX,
MOV
DL,7
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
MOV_TO_ASCII_POSITION
MOV
CX.I
CALL
CALL
RESTORE_REAL_CURSOR
POP
DX
POP
CX
RET
ERASE PHANTOM
ENDP
END
295
Assembly Language
for the
function
number 3
tion in the
(7).
SAVE_REAL_CURSOR.
two bytes
and then
posi-
INT
lOh
WRITE_PHANTOM
and
phantom
tom cursor in
the hex
right.
then writes a phantom cursor one character wide in the ASCII window. Fi-
of it now.
First, it will
cause the
INT
number 9,
WRITE_ATTRIBUTE_N_TIMES
do three
things.
this be-
andthe
WRITE_ATTRIBUTE_N_TIMES
to
You will do
will
attribute
new attribute along with the character just read. Finally, the procedure will
move the cursor right to the next character position, so you can repeat the whole
process
times.
You can
in the
file
itself.
VIDEO lO.ASM
Listing
296
PUBLIC
WRITE_ATTRIBUTE_N_TIMES
EXTRN
CURSOR_RIGHT:PROC
Place
as follows:
21
CX
On entry:
~l
DL
CURSOR RIGHT
Uses:
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BL,DL
XOR
BH.BH
MOV
DX,CX
MOV
CX,1
MOV
AH, 8
INT
10h
MOV
AH, 9
INT
10h
CALL
CURSORRIGHT
ATTR_LOOP:
;Write attribute/character
DEC
DX
JNZ
ATTR_LOOP
;No,
POP
DX
POP
CX
POP
BX
POP
AX
continue
RET
WRITE ATTRIBUTE
This
first
is
With
both the
it,
you have
TIMES ENDP
it
you
again.
Summary
You now have
eight
files
to link,
still
in
Dskpatch.
Of these, you have changed two files, Disp_sec and Video_io, and created one,
Phantom. If you are using NMake or the short batch file we suggested in
Chapter 20, remember to add your new
file,
Phantom,
to the
list.
297
Assembly Language
When
for the
before, but
Dskpatch
will see
is
it
back where
it
should be
in Figure
Sector 8
Disk n
80 Bl 82 03 84 85 06 07 88 09 00 8B 8C 8D 8E 0F
81234567890BCDEF
ae
le
28
38
48
58
68
78
88
98
ne
B8
C8
D8
E8
FB
msmac.
02 E0
88 88
54 41
CB 8E
16 53
8F 8B
CD 13
89 BE
16 IE
7C
ft3
IE 0B
88
B8
OB
E8
BE
81
75
5F
98
88
88
4C
D0
BF
0E
72
28
7C
49
7C
88
E8
8n
88
4D 53
68 89
88 88
4C 28
BC 00
3E 7C
18 7C
79 33
7C 08
83 06
7C 89
83 C3
85 8B
nC 88
8D 7F
33 C8
,
44
F9
88
31
7C
B9
88
C8
53
88
8D
41
87
88
F9
86
18
F7
8E
83
16
7C
48
F3
16
7C
72 16 8B
28 BS 8B
CD 16 5E
4F
07
29
46
16
8B
4D
39
7C
7C
4B
F7
52
2E 38 88
00 02 88
IC 19 55
31 32 28
78 00 36
F3 04 86
47 82 C7
7C 74 08
16 7C 83
08 03 58
28 00 F7
86 49 7C
58 7C E8
B9 0B 80
F3 06 74
IF 8F 84 8F
35
8F
85
54
BB
FC
89
13
26
D2
B8
81
01
FB
88
82
88
4E
28
C5
81
88
49
28
37
IF C6
87 3E
8B BE
06 IC
7C 89
26 11
83 16
92 88
BE E6
18 BE
44 82
81
88
4E
FO
IE
45
7C
13
7C
16
7C
4B
72
7D
9E
CD
:
00
88
53
33
56
FE
FB
7C
13
52
8B
7C
ID
F3
7D
19
g<EMSD0S5.8 OQQ
ao[ '-. 8
)ia-lUNINS
TOLL 1F0T12
3
4iJU' :_.iix 6+7AU
_Si>;{|<J "<ii|=E
aiJ)T!eMeGB|}.>:j^
1
=!!r93L9!!!tBiJ)!!:
e4 iat'I^A.!**^:!!
-A!J]:an uF:e_K
i^&4
u I e.K ^
A<I!^;::<@*na-K!
i_R{iP;51{ r"
il
EBSj r-ifp J^}!
-uHiA 4|<f l-ttJR}
5 3 L=_"ooDO=l
:
i'
cursors.
The next chapter covers adding procedures to move your newly formed phantom cursors. It will also cover how to add a simple editing procedure which
allows you to change the byte under the phantom cursor.
298
H A
I
Simple Editing
In
this
you
to input
FUes altered:
Disk
files:
new
Then you
will
add
move
the
phantom
Topics Covered
Moving the Phantom Cursors
Simple Editing
Summary
Assembly Language
X ou
for the
have almost reached the point at which you can begin to edit your
sector display
change numbers
to
You
will
soon
move
the
phantom
cursors to different
bytes within the half-sector display. This task turns out to be fairly simple,
now
that
ERASE_PHANTOM
and
WRITE PHANTOM.
the
erasing the
PHANTOM_CURSOR_X or
WRITE_PHANTOM to write the
PHANTOM_CURSOR_Y;
and using
phantom cursor at the new position. You must be careful not to let the
move outside the window, which is 16 bytes wide and 16 bytes high.
To move
the
phantom
cursors,
you
will
DISPATCHER
needs no changes
DISPATCH_TABLE. You
just
cursor
is
in the table
DISPATCH .ASM
Listing 22-1
MODEL
Changes
to
life
are as follows:
DISPATCH.ASM
SMALL
.CODE
NEXT_SECTOR PROC
EXTRN
PREVIOUS_SECTOR:PROC
EXTRN
EXTRN
.DATA
302
;In DISK_IO.ASM
EXTRN
;In DISK_IO.ASM
j.
,, .;*;
22
Simple Editing
This table contains the legal extended ASCII keys and the addresses
of the procedures that should be called when each key is pressed.
The format of the table is
DB
72
DW
OFFSET
LABEL
BYTE
TEXT: PHANTOM UP
DISPATCHTABLE
K
w
DB
61
DB
72
DW
DB
80
DW
OB
75
DW
OFFSET _TEXT:PHANTOM_LEFT
DB
77
DW
OFFSET _TEXT:PHANTOM_RIGHT
As you can
:F3
ir0
"^'^^"'^^^^^^H
^^^^^M
Cursor down
^^^^^1
;Cursor left
^H
'SH
see,
it is
cedure names in
Jm
;Cursor right
simple to add
i^Hl
commands
to
if you
for each.
We
to
file
how
are
the
they
move
the
phantom
cursors are
as follows:
303
Assembly Language
for the
f
22-2 Add these procedures to PHANTOM.ASM
(Complete listing in PHANT022.ASM)
Listing
WRITE_PHANTOM
Uses:
ERASE_PHANTOM
Reads:
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
Writes:
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
PHANTOM UP
PUBLIC
PROC
PHANTOM_UP
CALL
ERASE_PHANTOM
DEC
PHANTOM_CURSOR_Y
JNS
WASNT_AT_TOP
MOV
PHANTOM_CURSOR_Y,
WRITE_PHANTOM
WASNT_AT_TOP
CALL
RET
ENDP
PHANTOM_UP
PHANTOM_DOWN
PUBLIC
PROC
PHANTOM_DOWN
CALL
ERASE_PHANTOM
INC
PHANTOM_CURSOR_Y
CMP
PHANTOM_CURSOR_Y 16
JB
WASNT_AT_BOTTOM
;No,
MOV
PHANTOM_CURSOR_Y 15
;Was at bottom,
WRITE_PHANTOM
WASNT_AT_BOTTOM
CALL
so write phantom
RET
PHANTOM_DOWN
PUBLIC
PHANTOM_LEFT
304
ENDP
PHANTOM_LEFT
PROC
CALL
ERASE_PHANTOM
DEC
PHANTOM_CURSOR_X
JNS
WASNT_AT_LEFT
MOV
PHANTOM_CURSOR_X
;Was at left,
22
Simple Editing
WASNT_AT_LEFT:
WRITE_PHANTOM
CALL
RET
ENDP
PHANTOM LEFT
PUBLIC
PHANTOM RIGHT
PHANTOMRIGHT
PROC
CALL
ERASE_PHANTOM
INC
PHANTOM_CURSOR_X
CMP
PHANT0M_CURS0R_X,16
JB
WASNT_AT_RIGHT
MOV
PHANT0M_CURS0R_X,15
;Was at right,
WRITE_PHANTOM
WASNT_AT_RIGHT:
CALL
RET
PHANTOM RIGHT
ENDP
PHANTOM_LEFT
you
will
you begin
and
have to change
Test Dskpatch
the screen.
now
to see if
together,
and
ter 27,
At
move
when
the cursor
the cursor
is
at the
bottom of the
ter 26,
we
you
will
scroll
change both
when you
up one
line,
however, so
Chap-
to
that time,
own windows.
adding another
is
rather messy,
we will save these procedures until almost the end. Through Chap-
will
first
half sector.
Now,
let's
305
Assembly Language
for the
Simple Editing
You
Enter key.
You
READ_BYTE, which
you
of
will write a
for
you
READ_BYTE
to press the
to develop
of the procedure that waits until you press either the Enter key or a special
key, such as a function or cursor key.
The editing procedure will be called EDIT_BYTE. It will change one byte both
on the screen and in memory (SECTOR). EDIT_BYTE will take the character in the DL register, write it to the memory location within SECTOR that is
currently pointed to by the phantom cursor, and then change the display.
DISPATCHER
CALL
CALL to
DISPATCH.ASM,
to
version of
DISPATCHER
EDIT_BYTE and
in
it,
is
follows:
DISPATCHER
EXTRN
in
DISPATCH.ASM
this procedure reads characters from the keyboard and, if the character
is a command key (such as a cursor key),
READ_BYTE,
Uses:
DISPATCHER
306
PROC
PUSH
AX
PUSH
BX
as
22
Simple Editing
DISPATCH_LOOP:
CALL
READ_BYTE
OR
AH, AH
;AX =
;
-1
if no character read,
JS
DISPATCHLOOP
JNZ
SPECIAL_KEY
try again
,,,,
DL,AL
MOV
CALL
EDIT_BYTE
JMP
DISPATCH LOOP
CMP
AL,68
;F10-exit?
JE
ENDDISPATCH
SPECIAL_KEY:
;Yes,
;Llse
LEA
leave
BX to look through table
BX,DISPATCH_TABI
SPECIAL_LOOP:
CMP
JE
NOT_IN_TABLE
;Yes,
CMP
AL,[BX]
,0
;End of table?
JE
DISPATCH
;Yes,
ADD
BX,3
;No,
JMP
SPECIAL_LOOP
then dispatch
try next entry
DISPATCH:
INC
BX
CALL
;Call procedure
JMP
DISPATCH_LOOP
NOT_IN_TABLE:
JMP
;Do nothing,
DISPATCH_LOOP
END_DISPATCH:
POP
DX
POP
BX
POP
AX
RET
DISPATCHER
ENDP
you
to write
is
a lot
list
of
CALLs
to other
307
Assembly Language
for the
work with
DL register, so
a character in the
CALL (or PUSH, POP) is the LEA instruction to set the address of the prompt
for WRITE_PROMPT_LINE. Most of the procedure calls in EDIT_BYTE
when you edit a byte. You will see
of EDIT_BYTE when you come to the procedure listing.
are for
tails
EDIT_BYTE
Because
cedure
WRITE_TO_MEMORY
to
in
SECTOR.
cursor.
Then
it
DL
register to the
(Complete
.MODEL
file EDITOR.ASM
EDITOR22.ASM)
Listing
listing in
SMALL
.CODE
.DATA
EXTRN
SECTOR: BYTE
EXTRN
SECTOR_OFFSET:WORD
EXTRN
PHANTOM_CURSOR_X:BYTE
EXTRN
.CODE
DL
OFFSET
308
SECTOR_OFFSET + (16
Reads:
PHANTOM_CURSOR_X
Writes:
SECTOR
PHANTOM_CURSOR_Y) + PHANTOM_CURSOR_X
PHANTOM_CURSOR_Y
SECTOR_OFFSET
22
Simple Editing
WRITE_TO_MEMORY PROC
PUSH
AX
PUSH
BX
PUSH
CX
MOV
BX,SECTOR_OFFSET
MOV
AL PHANTOM_CURSOR_Y
XOR
AH, AH
MOV
GL,4
SHL
AX.CL
ADD
BX.AX
MOV
AL,PHANTOM_CURSOR_X
XOR
AH, AH
Multiply PHANTOM_CURSOR_Y by 16
ADD
BX,AX
MOV
;Now,
POP
CX
POP
BX
POP
AX
(16
Y)
RET
PUBLIC
EDITBYTE
EXTRN
EXTRN
MOV_TO_HEX_POSITION:PROC, MOV_TO_ASCII_POSITION:PROC
EXTRN
EXTRN
EXTRN
.DATA
.CODE
On entry:
DL
SAVE_REAL_CURSOR
Uses:
RESTORE_REAL_CURSOR
MOV_TO_HEX_POSITION
MOV_TO_ASCI I_POSITION
Reads:
EDIT_BYTE
PUSH
PROC
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_POSITION
CALL
CURSOR RIGHT
hex window
309
Assembly Language
Listing
for the
22-4 continued
CALL
WRITE_HEX
CALL
MOV_TO_ASCII_POSITION
CALL
WRITE_CHAR
CALL
RESTORE_REAL_CURSOR
CALL
WRITE_PHANTOM
CALL
WRITE_TO_MEMORY
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
POP
DX
in the ASCII
window
RET
EDIT BYTE
ENDP
END
Build
this
new
how
it
works.
By
the way, if
add
EDITOR.ASM
EDIT_BYTE you
to your Makefile.
phantom
As you type
you
Link
to
new version,
The version of
letters in this
This means that you cannot enter hex numbers, you can only type
other symbols on your keyboard.
see a
letters
key.
and
Summary
Dskpatch now
consists of nine
files:
None of these
310
files,
files is
this chapter,
reassembling
it,
you changed
all
fairly
the
quickly by
files
together
22
change
but
in the
it is
Simple Editing
will see a
not very safe yet, since you can change a byte by hitting any key.
as pressing
You
Enter to change a
intentionally.
READ_BYTE does
to allow
you
number and
to accept a
READ_BYTE,
READ_BYTE
new
character by
will write
input procedures
311
H A
I
Hex and
Decimal Input
In
this chapter
you
will build
two subroutines,
READ_BYTE
and
READ_DECIMAL to read hex and decimal numbers. You will build and test
these subroutines using a test program, rather than the full
This makes
it
FUes altered:
make sure
KBD_IO.ASM, TEST.ASM
Dskpatch program.
Topics Covered
Hex
Input
Decimal Input
Summary
Assembly Language
ou
for the
will
encounter two
one procedure
new procedures
a single character,
and another
for reading a
Both procedures
keyboard input in
this chapter:
word by reading
the characters of
for
into Dskpatch.
You
working with
will be
Since Dskpatch
relies
on the function
file
You
Hex
will
READ_BYTE
to
its
keys, there
we
will
Input
READ_BYTE.
READ_BYTE
Let's begin
by rewriting
would read
one byte
modify
to Dispatch. Dispatch
In the
would then
call
EDIT_BYTE would
last
chapter,
the Editor if
and return
READ_BYTE
to
by the phantom cursor. If not. Dispatch looked for special fiinction keys in
DISPATCH_TABLE
procedure
named
As mentioned
in
was
there; if so,
in the table.
phantom
cursor.
Sometimes people
the
you
are clumsy,
on the
You
will
add
this feature
by using
DOS INT 21h function OAh to read a string of characters. DOS only re-
when you
press Enter.
314
too
disaster.
EDIT_BYTE will
it
later.
23
affect
READ_BYTE, you
need to write
a test
READ_BYTE in isolation. That way, if anything strange happens you will know it is READ_BYTE and not some other part of Dskpatch.
program
to test
test
procedure
will
be simpler
if you
characters read.
Listing
.MODEL
The
details are in
TEST.ASM
as follows:
TEST.ASM
SMALL
STACK
.DATA
',0
ENTER_PROMPT
DB
'Enter characters:
CHARACTER_PROMPT
DB
'Character code:
SPECIAL_CHAR_PROMPT
DB
'
,0
',0
.CODE
EXTRN
EXTRN
EXTRN
_READ_BYTE
PROC
MOV
AX DGROUP
MOV
DS.AX
LEA
DX,ENTER_PROMPT
CALL
WRITE_STRING
CALL
READ_BYTE
CALL
SEND_CRLF
LEA
DX,CHARACTER_PROMPT
CALL
WRITE_STRING
MOV
DL,AL
CALL
WRITE_HEX
CALL
SEND_CRLF
LEA
DX SPECIAL_CHAR_PROMPT
,
315
Assembly Language
WRITE_STRING
MOV
DL.AH
XOR
DH.DH
CALL
WRITE_DECIMAL
CALL
SEND_CRLF
MOV
AH 4Ch
INT
21h
TEST_READ_BYTE
Return to DOS
ENDP
END
To
assemble
and Cursor
it
any
that
character. Otherwise,
it
code and a
to
tell
you
will display
The bulk of the instructions in TEST.ASM are for formatting. One thing you
may have noticed is that we have used some of the procedures in Kbd_io,
Video_io, and Cursor without regard to the other
do
this
these
because
files.
we were
file
It is
into general-purpose
move on
only will
to rewriting
this save
also allow
you
our project.
We could
good idea
to separate
your procedures
specific procedures so
you can
to use the
easily
write.
READ_STRING
and
in
by source
files
to type.
READ_BYTE
if you
it
will
change your
procedure
it
316
23
READ_BYTE
CONVERT_HEX_DIGIT,
STRING_TO_UPPER
and
STRING_TO_UPPER,
HEX_TO_BYTE.
uses:
HEX_TO_BYTE
and
either f3 or
F3
number F3h. By
letters, we add
HEX_TO_BYTE
STRING_TO_UPPER,
byte number.
HEX_TO_BYTE
to convert each
hex
DOS,
makes use of
digit to a four-bit
after
you
call
string to a single-
CONVERT_HEX_DIGIT
number.
How do you ensure that DOS won't read more than two hex digits? The DOS
function
OAh
memory
de-
DB
NUM_CHARS_READ
DB
STRING
DB
The
first
80 DUP (0)
many
characters.
be discarded, and
When
you
NUM_CHARS_READ,
DOS
will
beep to
to the
let
DOS
number of characters
it
READ_BYTE
checks
NUM_CHARS_READ
to find out
hex number. If
NUM_CHARS_READ was set to one, READ_BYTE returns a single character in the AL register. If NUM_CHARS_READ was set to two,
READ_BYTE uses HEX_TO_BYTE to convert the two-digit hex string to a
byte.
317
'
Assembly Language
The new
for the
file
KBD_IO.ASM,
with
READ_KEY.
Listing
.MODEL
This
will
all
four
new procedures
READ_BYTE
is
shown
in List-
it
to
of
KBDJO.ASM
SMALL
.DATA
KEYBOARDINPUT
LABEL
CHAR_NUM_LIMIT
DB
NUM_CHARS_READ
DB
CHARS
DB
BYTE
80 DUP (0)
.CODE
PUBLIC
STRING_TO_UPPER
This procedure converts the string, using the DOS format for strings,
to all uppercase letters.
On entry:
DS:DX
STRING_TO_UPPER PROC
PUSH
AX
PUSH
BX
PUSH
CX
MOV
BX.DX
Point to character count
INC
BX
MOV
CL,[BX]
XOR
CH.CH
UPPER_LOOP:
INC
BX
MOV
AL,[BX]
a
CMP
AL
JB
NOT_LOWER
CMP
AL, 'z'
'
JA
NOT_LOWER
ADD
AL, 'A'
MOV
[BX],AL
'a'
NOT_LOWER
318
LOOP
UPPER_LOOP
POP
CX
;Nope
23
POP
BX
POP
AX
RET
On entry:
AL
Returns:
AL
Nibble
CF
Character to convert
PROC
CMP
AL, '0'
JB
BAD_DIGIT
;Nope
CMP
AL, '9'
JA
TRYHEX
SUB
AL, '0'
CLC
convert to nibble
RET
TRY_HEX
CMP
AL, 'A'
JB
BAD_DIGIT
;Not hex
CMP
AL, 'F'
JA
BAD_DIGIT
;Not hex
SUB
CLC
;Is hex,
convert to nibble
RET
BAD_DIGIT:
STC
error
RET
ENDP
Ef
HEX_TO_BYTE
This procedure converts the two characters at DS:DX from hex to one
byte.
On entry:
DS:DX
Returns:
AL
Byte
CF
Uses:
319
Assembly Language
23-2 continued
Listing
PROC
HEX_TO_BYTE
PUSH
BX
PUSH
CX
MOV
BX.DX
MOV
AL,[BX]
CALL
CONVERT_HEX_DIGIT
JC
BAD_HEX
MOV
CX,4
;Now multiply by 16
SHL
AL.CL
MOV
AH,AL
INC
BX
MOV
AL,[BX]
CALL
CONVERT_HEX_DIGIT
Retain a copy
JC
BAD_HEX
OR
AL.AH
CLC
DONE_HEX:
POP
CX
POP
BX
RET
BAD_HEX:
;Set carry for error
STG
DONE_HEX
JMP
ENDP
HEX TO BYTE
This
is, a
On entry:
READ_ STRING
DS:DX
PROC
PUSH
AX
MOV
AH 0Ah
INT
21h
POP
AX
input
RET
READ_ STRING
PUBLIC
320
ENDP
READ BYTE
'
23
AL
AH
= 0)
-1
if
no characters read
Reads:
Writes:
KEYBOARD_INPUT, etc.
Uses:
READ_BYTE
PROC
PUSH
DX
MOV
CHAR_NUM_LIMIT,3
LEA
DX,KEYBOARD_INPUT
CALL
READ_STRING
CMP
NUM_CHARS_READ,1
JE
ASCII_INPUT
;Just one,
JB
NO_CHARACTERS
CALL
STRING_TO_UPPER
;No,
LEA
DX, CHARS
CALL
HEX_TO_BYTE
JC
NO_CHARACTERS
;Error,
so return
'no characters
read
XOR
AH, AH
DONE_READ:
POP
DX
RET
NO_CHARACTERS:
XOR
AH, AH
NOT
AH
JMP
DONE_READ
;Set to
;
Return
'no
-1
characters read'
in AH
ASCII_INPUT:
MOV
AL, CHARS
XOR
AH, AH
JMP
DONE_READ
READ BYTE
PUBLIC
ENDP
READ KEY
321
Assembly Language
for the
23-2 continued
Listing
Returns:
AL
AH
1
READ_KEY
1)
PROG
XOR
AH, AH
INT
16h
OR
AL.AL
JZ
EXTENDED_CODE
;Yes
AH, AH
NOT_EXTENDED:
XOR
DONE_READING:
RET
EXTENDED_CODE
MOV
AL.AH
MOV
AH,1
JMP
DONE_READING
READ KEY
ENDP
END
At
this point,
tr\'
this version
files:
Test,
of READ_B\nrE.
READ_BYTE. You
cannot read
Test.
You cannot
READ_B\TE
DOS'
was
pressed. Because
OAh
322
(1
OAh. This function was used so you could use the Backspace key
characters before the Enter key
key
own READ_STRING
to ensure that
to delete
you can
special
procedure.
You
23
function
OAh
for
and then
acter,
try the
line,
~)
The new
on the next
version of
Kbd_io
in
the next chapter will treat the line-feed character (Control-Enter) as an ordi-
move
Before moving on to
READ_STRING, you
will
to display sector
and
READ_BYTE
fix
will write a
number
it
so that
you
567.
Decimal Input
If you recall, the largest
word
is
65536.
When
you use
READ_STRING
to read a string
of decimal
digits,
will tell
still
be able to read numbers from 65536 to 99999, even though these numbers
don't
fit
into
65535, or
To
if it tries to
will
by
you did
ten, tack
in
Chapter
4*10"^ +
or, as
10''(
on the second
method, we could,
tion as
it
if
is
You
word, you
digit,
multiply
49856
it
by
ten,
multiply
this
as:
you
will
do the
calculation:
for errors as
you
try to read a
number
larger than
65535? With
re-
numbers, the
last
323
Assembly Language
handle an
an error
KBD
word MUL,
error.
Here
(a digit that
is
is
so
JC {Jump
READ_DECIMAL,
not between
and
9).
which
is
set
if Carry
when
set)
DX
is
not
instruction to
file
IO.ASM:
23-3 Add
(Complete listing
Listing
PUBLIC
tiiis
in
procedure to
KBDJO.ASM
KBO_I023.ASM)
READ_DECIMAL
Returns:
AX
CF
Uses:
READ_STRING
Reads:
KEYBOARD_INPUT, etc.
Writes:
READ_DECIMAL
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
CHAR_NUM_LIMIT,6
LEA
DX,KEYBOARD_INPUT
(65535)
CALL
READ_STRING
MOV
CL NUM_CHARS_READ
XOR
CH,CH
CMP
CL,0
JLE
BAD_DECIMAL_DIGIT
signal error
XOR
AX, AX
XOR
BX,BX
CONVERTDIGIT:
324
MOV
DX,10
jMultiply number by 10
MUL
DX
;Multiply AX by 10
JC
BAD_DECIMAL_DIGIT
MOV
SUB
DL, '0'
(4 bits)
23
JS
BAD_DECIMAL_DIGIT
CMP
DL,9
JA
BAD_DECIMAL_DIGIT
;Yes
ADD
AX.DX
;No,
INC
BX
LOOP
CONVERT_DIGIT
so add it to number
DONE_DECIMAL:
POP
DX
POP
CX
POP
BX
RET
BAD_DEGIMAL_DIGIT:
STC
JMP
READ_DECIMAL
DONEDECIMAL
ENDP
To make certain
it
boundary conditions.
much
the
to test this
procedure with
all
the
to test
READ_BYTE is as
follows:
Listing
.MODEL
SMALL
STACK
.DATA
ENTER_PROMPT
DB
'
NUMBER_READ_PROMPT
08
'NuBber read:
C H AnACTCn P n OMPT
-B6-
'
,9
,0
Charact e r cod e:
B6-
SPLCIAL C H AR PROMPT
-y^
'-^
.CODE
EXTRN
EXTRN
WRITE_STRING:PROC, SEND_CRLF:PROC
EXTRN
PROC
325
Assembly Language
MOV
AX.DGROUP
MOV
DS.AX
LEA
DX,ENTER_PROMPT
CALL
WRITE_STRING
CALL
READ_DECIMAL
JC
"BOB
SEND_CRLF
LEA
DX , NUIIBER_READ_PROMPT
CALL
WRITE_STRING
MOV
DX,AX
CALL
WRITE_DECIIIAL
CALL
SEND_CRLF
-bA
DX SPECIAL_CHAn_PnOMrT
-GAtt
WniTC STniNG
^^^^
-M6V
DL.A H
-mf\
D H ,D H
-GAtt
WniTE_DECIMAL
-GAtt
SE N D CnLf
MOV
AH,4Ch
INT
21h
DECIIIAJ^,^,^^,,
Return to DOS
,j^jtgg,
END
again,
^^^^M
Mili^
CALL
TEST READ
Once
23-4 continued
Listing
ERROR:
for the
you need
to link four
files:
file),
Kbd_io,
Video_io, and Cursor. Try the boundar)' conditions, using both valid digits
and
numbers
as 0,
which
326
is
When
you
number
try a
after
in a valid
you
digit) ,
number
number.
23
Summary
We will
test
procedures
later
when we
will learn
to write a
how
program
discuss
ways
to use a slighdy
Now, on
where you
will write
improved versions of
327
H A
j
Improved
Keyboard Input
In this chapter you will concentrate on keyboard input where you will build
a new version of RJEAD_STRING. This new version will be able to read strings
as well as special keys,
chapter,
such
as cursor
and function
Files altered:
Disk file:
you
keys.
cursor keys in
it
At the end of
this
Dskpatch. Dskpatch
SECTOR.
KBDJO.ASM
KBO I024.ASM
i.
Topics Covered
A New READ_STRINQ
Gser vs Programmer Friendly
Summary
m^!im
Assembly Language
W
we
for the
first
wrote
it
we
we will
yourself
some of
will write a
new
just as
version of
find a can of Raid to exorcise this small bug, but see if you can find
first.
all
the
boundary conditions
for
Dskpatch.)
A New READ_STRING
The modular-design philosophy
procedure
will
is
book
is
no
single
is
too long.
It
should be rewritten
of
this
quickly drawing to an end, and you need to write a few more proce-
the
calls for
is
still
edit only
yet.
BACK_SPACE,
READ_STRING
new procedure,
found
in the
DOS function OAh. When you press the Backspace key, BACK_SPACE will
erase the last character typed
On
screen,
BACK_SPACE will
string in
memory.
left
one character, writing a space over it, and then moving left one character again.
This sequence will perform the same backspace deletion provided by
In the buffer,
pointer,
BACK_SPACE
DS:SI+BX,
so
it
DOS.
memory. In other
words,
it.
tells
characters
it
has read;
if
you
try to read
more than
this
from the buffer, you will see the characters you erased. Otherwise, you
number
You have to be careful not to erase any characters when the
empty. Remember that your string-data area appeared as follows:
won't.
330
buffer
is
24
CHAR_NUM_LIMIT
DB
NUM_CHARS_READ
DB
STRING
DB
The
80 DUP (0)
string buffer starts at the second byte of this data area, or at an offiet of
2 from the
which
is
start.
So
BACK_SPACE
equals 2. Place
(Complete
listing in
added to
is
if
BX
is
set to
empty when
BX
as follows:
KBDJO.ASM
KBO_I024.ASM)
PUBLIC
BACK_SPACE
EXTRN
WRITE CHAR:PROC
the screen when the buffer is not empty. BACK_SPACE simply returns
DS:SI+BX
Returns:
DS:SI+BX
Uses:
WRITE CHAR
BACK_SPACE
PROC
PUSH
AX
PUSH
DX
CMP
BX,2
JE
END_BS
;Yes,
DEC
BX
MOV
AH,
MOV
DL.BS
INT
21h
MOV
DL,20h
CALL
WRITE_CHAR
MOV
DL.BS
INT
21h
END_BS: POP
DX
POP
AX
;Back up again
RET
BACK SPACE
ENDP
331
Assembly Language
move on
Let's
is
for the
for only
to the
one procedure.
it is
complicated by so
many
pos-
sible conditions.
READ_STRING does so many things because a few more features were added.
If you press the Escape key, READ_STRING clears the string buffer and remove
all
from the
when you
more
screen. Instead,
and moves
the line
DOS
versatile
it
Our
all
the characters in
than the
also erases
it
(\)
character at the
end of
DOS READ_STRING
function.
READ_STRING uses three special keys: the Backspace, Escape, and Enter keys.
You could write the ASCII codes for each of these keys in READ_STRING
whenever you need them; instead add a few definitions
to the beginning of
Listing
24-2 Additions to
KBDJO.ASM
.MODEL
SMALL
BS
EQU
CR
EQU
13
;Carriage-return character
ESCAPE
EQU
27
Backspace character
Escape character
.DATA
Here is
that
READ_STRING. Although it is rather long, you can see fi-om the listing
it is
KBD_IO.ASM
332
new version:
24
Listing
READ_STRING
EXTRN
in
~I
KBD iO.ASM
DS:DX
actually read.
No characters read
-1
Uses:
READ_STRING
PROC
PUSH
AX
PUSH
BX
PUSH
SI
MOV
SI,DX
PROC
START_OVER
MOV
BX,2
CALL
READ_KEY
OR
AH, AH
JNZ
EXTENDED
STRING_NOT_EXTENDED:
CMP
AL.CR
JE
END_INPUT
CMP
AL.BS
Is it a backspace character?
JNE
NOT_BS
Nope
CALL
BACK_SPACE
CMP
BL,2
Is buffer empty?
JE
START_OVER
Yes,
JMP
SHORT READ_NEXT_CHAR
No,
NOT_BS: CMP
AL, ESCAPE
JE
PURGE_BUFFER
CMP
BL,[SI]
333
Assembly Language
Listing
for the
24-3 continued
JA
BUFFER_FULL
;Buffer is full
MOV
[SI+BX] ,AL
INC
BX
PUSH
DX
MOV
DL.AL
CALL
WRITE_CHAR
POP
DX
READ_NEXT_CHAR
CALL
READ_KEY
OR
AH, AH
JZ
;Char is valid
beep
DX
MOV
DL,7
MOV
AH, 2
INT
21h
POP
DX
JMP
CX
MOV
CL,[SI]
XOR
CH,CH
BACKSPACE
LOOP
PURGE_LOOP
far back
POP
CX
JMP
START OVER
PURGE_LOOP:
CALL
334
24
buffer-full condition.
BUFFER_FULL:
JMP
just beep
return
-1
EXTENDED:
MOV
[SI+2] ,AL
MOV
BL,0FFh
;Nuni
JMP
chars read =
for special
-i
END_INPUT:
SUB
BL,2
MOV
[SI+1],BL
POP
SI
END_STRING:
POP
BX
POP
AX
RET
READ STRING
ENDP
if you
READ_STRING
READ_STRING
characters
it
It
READ_STRING
allows
press the
you
F3 key
to
first
do so only
after pressing
to
tell
you
problem
that
later in
key
it
places the
number of
The
read into the second byte of the string area and returns.
new
if you
the chapter).
If
READ_STRING
you pressed
causes
is
at this
byte to see
how many
characters
335
Assembly Language
for the
Next,
READ_STRING goes
erwise
back to the
the
start,
start
where
it
it
Finally,
to 2
when
BACK_SPACE
by calling the
You can
procedure
string buffer
and echoed
is full.
In the
last
chapter,
in
KBD_IO.ASM
are as follows:
Listing
PUBLIC
in
KBDJO.ASM
READ BYTE
Returns:
AL
hex number.
= 0)
AH
1
-1
if no characters read
Uses:
Reads:
KEYBOARD_INPUT, etc.
Writes:
KEYBOARD_INPUT, etc.
READBYTE
336
PROC
PUSH
DX
MOV
CHAR_NUM_LIMIT,3
LEA
DX,KEYBOARD_INPUT
CALL
READ_STRING
CMP
NUM_CHARS_READ,1
JE
ASCII_INPUT
JB
NO CHARACTERS
24
CMP
JE
SPECIAL_KEY
;Yes
CALL
STRING_TO_UPPER
;No,
LEA
DX, CHARS
CALL
HEX_TO_BYTE
JC
NO_CHARACTERS
;Error,
XOR
AH, AH
DONE_READ
POP
DX
RET
NO_CHARACTERS
XOR
AH, AH
;Set to
NOT
AH
;Return
-1
JMP
DONE_READ
in AH
ASCII_INPUT:
MOV
AL, CHARS
XOR
AH, AH
JMP
DONE READ
..^^
SIPECIAL_KEY:
MOV
MOV
AH,1
JMP
DONE_READ
READ_BYTE
it
^H
ENDP
I^^^^^^b
much
new
versions of
READ_BYTE
all
is
and
a
READ_STRING,
bug
here.
Try
to find
READ_BYTE and HEX_TO_BYTE. (Remember that there are nine files that
to an EXE program: Dskpatch, Dispatch,
type a
it is
letter,
such
2isf,
at
you because the READ_STRING procedure does not return control once you
have started entering a hex number until you press either the Escape or the
337
Assembly Language
for the
1
Enter key. Unfortunately, the user probably won't
ing at
tated
them and
Programs
grammer
them
at
no apparent
for
Programmer Friendly
irri-
programming
to
rather
considerable effort in
become
reason.
Tvf
as follows:
There
is
rarely cause to
allowed.
to
to write.
Sometimes they
will
is
simple
than not, you will find that you have to expend additional effort and
development time
Try
By doing
one we placed
you
so
will eliminate
many
(anificially) into
READ_STRING.
Tr\^ out
your ideas on
real users,
not
just
really
stand
why so you
can make
easier to use.
There
we have recommended
it
are a
on the
issue
of writing user-
entirely to design;
you
will find in
The
real
problem with
READ_STRING
is
that
it is
modal. As soon
as
you
type one character, you cannot do anyahing else until you finish typing or press
Esc.
is
What READ_STRING
as
should do
338
a letter
it
is
and then
you can
press
character.
will
24
move
the cursor.
A new version
of
READ_STRING
Listing
is
PROC
PUSH
AX
PUSH
BX
as follows:
READ_STRING
that
in
KBDJO.ASM
PROC
PUSH
SI
MOV
SI,DX
BX,2
START_OVER
MOV
READ_LOOP:
CALL
READ_KEY
OR
AH, AH
JNZ
EXTENDED
Yes,
STRING_NOT_EXTENDED
No,
CMP
AL,CR
JE
END_INPUT
CMP
AL.BS
Is it a backspace character?
JNE
NOT_BS
Nope
Yes, delete character
CALL
BACKSPACE
JMP
READ_LOOP
IMP
uMI
NOT_BS: CMP
AL, ESCAPE
r^iiAn
NO
UrlAM
conLinucrcnOinynormacfiarac lcps
6^
punoc Durrcn
;Y e 3,
JNE
NOT_ESC
CALL
PURGE_BUFFER
;Yes,
JMP
READ_LOOP
th e n purg e th e buffer
NOT_ESC:
CMP
BL,[SI]
JA
BUFFER_FULL
;Buffer is full
MOV
[SI+BX],AL
INC
BX
PUSH
DX
MOV
DL,AL
CALL
WRITE_CHAR
POP
DX
JMP
READ LOOP
339
Assembly Language
Listing
for the
24-5 continued
ni:AD_NEXT_CHAn
GAtt
nCAD KCY
-6fl-
A H .AH
-d2-
STniNG N OT EXTENDED
wh e n th e buff e r is not
e mpty
jChar is valid
SIGNALERROR:
PUSH
DX
MOV
DL,7
MOV
AH, 2
INT
21h
POP
DX
JMP
Empty th e
s tring
buff e r and
e ras e
all th e
puncc B urrcn;
PUS H
-MOV-
-ex
CL,[SI]
C H ,C H
PUnOE LOOP:
CALL
DACK_SPACC
v/ill
LOOP
PUnOE LOOP
far back
-POP-crttP-
k ee p
-ex
START OVER
character. Send
sinc e th e buff e r is
e mpty
buffer-full condition.
BUFFER_FULL:
JMP
340
just beep
24
return
-1
EXTENDED:
CALL
PURGE_BUFFER
MOV
[SI+2],AL
MOV
BL,0FFh
JMP
-1
for special
END_INPUT:
BL,2
MOV
[SI+1] ,BL
POP
SI
SUB
END_STRING:
POP
BX
POP
AX
RET
READ STRING
ENDP
input buffer.
>
DS:SI
PURGE_BUFFER
PUSH
CX
MOV
CL,[SI]
XOR
CH,CH
BACK_SPACE
LOOP
PURGE_LOOP
far back
POP
CX
PURGE_LOOP
CALL
RET
PURGE BUFFER
ENDP
341
Assembly Language
You
for the
is
a good sign
Summary
You wrote a new version of READ_STRING
the small
works
bug
that
you
as advertised.
READ_STRING,
will find
and
fix in
With
you
the exception of
READ_STRING
it is
you learned that READ_STRING was not user friendly since it beeped
when you tried to move the cursor after you have started to type a hex number. You fixed both of these problems at the end of this chapter. Now it is time
to
342
in
Dskpatch.
|c|H|AlplT|Ei
In
Search
of
Bugs
In this chapter you will learn how to fix a small bug that appeared in Dskpatch
when you put all the pieces together. See if you can find the bug by trying all
the boundary conditions for the hex input prompt,
FUes altered:
Disk
file:
DISPATCH.ASM
DISPAT25.ASM
Topics Covered
Fixing
-ii-Bw
DISPATCHER
Summary
'^^^
Assembly Language
If you
ber,
for the
try the
you
ag,
which
Enter key. Since the string ^^is not a hex number, there
the sort
is
is
we can
find only
is
num-
press the
at least, erase
it
The bug
here isn't the fault of READ_BYTE, even though it appeared when you rewrote that procedure. Rather, the problem is in the way we wrote
conditions of a program; not just the pieces, but the entire program.
prompt
you
line
and
it
calls
of the
and
DISPATCH
line.
does not
call
EDIT_BYTE. What
is
the solution?
Fixing
There
DISPATCHER
are actually
to rewrite
won't do
two ways
Dskpatch
that.
to be
to solve this
Remember: Programs
to redesign
DISPATCHER. We
you have
to stop
prompt
tions to
line
whenever
acr^sBUE
PUBLIC
DISPATCHER
EXTRN
EXTRN
EXTRN
346
DISPATCH.ASM
iHHHH^HHHHHHjH
^^^^^^^^^^^^H
.DATA
.CODE
in
^^^^^^^^^^^^H
25
In
Search of Bugs
Uses:
Reads:
EDITOR PROMPT
DISPATCHER
PUSH
PROC
AX
PUSH
BX
PUSH
DX
DISPATCH_LOOP:
CALL
READ_BYTE
OR
AH, AH
;AX =
;
m-
js
^lHrEHARS_READ
JNZ
SPECIAL_KEY
MOV
DL,AL
-1
if no character read,
CALL
EDIT_BYTE
JMP
DISPATCH_LOOP
CMP
AL,68
;F10- -exit?
JE
END_DISPATCH
;Yes,
edit byte
SPECIAL_KEY:
leave
LEA
BX,DISPATCH_TAB
SPECIAL_LOOP:
CMP
JE
NOT_IN_TABLE
;Yes,
CMP
AL,[BX]
,0
;End of table?
JE
DISPATCH
;Yes,
ADD
BX,3
;No,
JMP
SPECIAL_LOOP
BX
then dispatch
try next entry
DISPATCH:
INC
347
Assembly Language
Listing
25-1 continued
CALL
;Call procedure
JMP
DISPATCH__LOOP
NOT_IN_TABLE:
;Do nothing,
DISPATCH LOOP
JMP
''''-
NO_CHARS_READ:
"
'
*i^Am^ii,s3ji9tmmfmaammmmammamma^^ammammmmm
"^^^^^^^^^^^^^^Hp
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
JMP
DISPATCH_LOOP
;Try again
,*,
END_DISPATCH:
POP
DX
POP
BX
POP
AX
RET
DISPATCHER
This bug
EN
fix
go hand
is
it
does
make DIS-
and
in
at
increasing elegance.
Summary
DISPATCHER
is
elegant because
it is
Rather than using many comparisons for each special character you might type,
you
Doing
so
made
DISPATCHER sim-
pler and more reliable than a program containing different instructions for each
DISPATCHER;
might
not by
much
arise.
348
By adding
the small
fix,
we complicated
require
you
25
adding
fixes that
make
program. You
after
In
Search of Bugs
the
this
you add
of debugging
method
for
and more
reliable
rules
programs.
cover another
debugging programs.
349
cIhIaIpItIeIr
Writing
Modfied
Sectors
In
this chapter
programs.
you
You will
will learn
also
function to Dskpatch so
Files altered:
Disk
files:
it
DISPATCH.ASM, DISK_IO.ASM
Topics Covered
'Writing to the Disk
Roadmap
CodeView
SumiViary
Assembly Language
In
for the
this chapter,
you
will build a
a procedure to
a sector.
F2
is
We have
shifted keys
without
this
WRITE SECTOR to
made
you from
DISPATCH. ASM
to
to
the table.
EXTRN
NEXT_SECTOR PROC
EXTRN
PREVIOUSSECTORrPROC
EXTRN
;In
:
EXTRN
EXTRN
WRITE_SECTOR:PROC
DISKIO.ASM
;In DISK_IO.AS*l
.DATA
This table contains the legal extended ASCII keys and the addresses
of the procedures that should be called when each key is pressed.
352
DB
72
DW
OFFSET PHANTOM_UP
LABEL
BYTE
DB
61
DW
OFFSET _TEXT:PREVIOUS_SECTOR
DB
62
writ-
to.
Listing
DISPATCH_TABLE
hap-
The
not done
pening.
if it is
;F3
F4
add
26
DW
72
DW
jCursor up
:
DB
80
DW
OFFSET _TEXT:PHANTOM_DOWN
;Cursor down
DB
75
DW
OFFSET _TEXT:PHANTOM_LEFT
jCursor left
DB
77
DW
OFFSET _TEXT:PHANTOM_RIGHT
DB
85
DW
OFFSET _TEXT:WRITE_SECTOR
jCursor right
is
asks
that
Shift F2
WRITE_SECTOR
25h
OFFSET _TEXT:NEXT_SECTOR
DB
DB
change
~l
itself is
you wish
almost identical to
READ_SECTOR. The
only
Whereas the
INT
DOS to read one sector, its companion function, INT 26h, asks DOS
WRITE_Sector
into
DISK_IO.ASM
as
follows:
Listing
PUBLIC
WRITE_SECTOR
Reads:
WRITE_SECTOR
PUSH
PROC
AX
PUSH
BX
PUSH
OX
PUSH
DX
MOV
AL,DISK_DRIVE_NO
;Drive number
MOV
CX,1
;Write
MOV
DX CURRENT_SECTOR_NO
jLogical sector
LEA
BX, SECTOR
INT
26h
sector
jDiscard the fl
POPF
POP
DX
353
Assembly Language
/^\
Listing
26-2 continued
o.
POP
ex
POP
BX
POP
AX
RET
WRITE SECTOR
ENDP
Now reassemble
try
function just yet. Find an old disk you don't need and put
make
first
sure this
is
sector
Dskpatch's write
it
in drive A.
Run
in drive A.
a scratch disk
destroying.
in
it
had
come
Make
a note of the
before.
on;
drive A.
1),
A to
large
enough
that
is
composed of nine
CodeView
354
different
find
in the
program? Dskpatch
addition, Dskpatch
form
if you
two ways
files
that
one procedure
musr be linked
to
to find procedures:
by using a road
or Borland's
Turbo Debugger.
26
When we (the authors) originally wrote Dskpatch, something went wrong when
we added WRITE_SECTOR; pressing the Shift-F2 key caused our machine
to hang.
be correct. Finally,
we
WRITE_SECTOR
DISPATCH_TABLE.
traced the
bug
and
Everything appeared to
than
it
should have been. You can see the bug shown against a gray background
as follows:
DISPATCH TABLE
LABEL
BYTE
DB
77
DW
OFFSET _TEXT:PHANTOM_RIGHT
;Cursor right
DW
85
DW
OFFSET _TEXT:WRITE_SECTOR
;Shift F2
DB
;Encl
DATA SEG
As an
exercise in debugging,
(diskfile
learn
add more
how
in the
to
this
change to your
file
DISPATCH.ASM
Road Map
to use
find procedures
make
DISPAT26.ASM), then
Building a
will help
of the table
ENDS
make
LINK to
build a
and variables
file
grown
has
in
map of Dskpatch.
memory. The
This
map
LINK command
and you
it.
LINK DSKPATCH DISK_IO DISP_SEC VIDEO_IO CURSOR DISPATCH KBD_IO PHANTOM EDITOR;
You
will
file
LINKINFO
file
containing
all
because
LINK
allows
the information.
you
to
We will call
355
Assembly Language
for the
\
LINK @LINKINFO
With
the
names used
file
so
far,
LINKINFO
appears as follows:
The plus
(+) at die
end of the
line.
that
tells
LINK to
create a
map
LINKINFO
file is as
of the proce-
file.
The
entire
follows:
The last two lines are new parameters. The first, DSKPATCH, tells LINK you
want the .EXE file to be named DSKPATCH.EXE; the second new line tells
LINK to create a listing file called DSKPATCH. MAP to create the road map.
switch tells LINK to provide a list of all the procedures and vari-
The /map
ables that
Workbench
Programmer's
provides these same abilities with a nice user interface. This was
response
file.
You will probably want to change your Makefile so it uses LINK @LINKINFO
instead of the long link line. The map file produced by the linker is about 140
lines long. The file is too long to be reproduced in its entirety, so we reproduced only the
file,
DSKPATCH.MAP,
start
Stop
as follows:
Length Name
Class
CODE
DATA
DATA
BSS
STACK
Origin
Group
0058:0
DGROUP
Address
356
is
Publics by Name
26
0000 03DB
BACK_SPACE
0000:0274
CLEARSCREEN
0000:0285
CLEAR_TO_END_OF_LINE
0000:0330
CONVERT_HEX_DIGIT
005B:000A
CURRENT_SECTOR_NO
0000:0296
CURSOR_RIGHT
005B:000C
DISK_DRIVE_NO
0000:0010
DISK_PATCH
0000:02E2
DISPATCHER
0000:0127
0000: 01 El
WRITE_HEX_DIGIT
0000:0255
WRITE_PATTERN
0000:0534
WRITE_PHANTOM
0000: 01 9F
WRITE_PROMPT_LINE
0000:0081
WRITE_SECTOR
0000:0162
WRITESTRING
0000:00F0
WRITE_TOP_HEX_NUMBERS
0000:0572
WRITE_TO_MEMORY
005B:00FA
_edata
0058:2100
_end
Address
0000:0010
Publics by Value
DISK_PATCH
0000:002E
PREVIOUS_SECTOR
0000:0040
NEXT_SECTOR
0000:0068
READ_SECTOR
0000:0081
WRITE_SECTOR
0000:009A
INIT_SEC_DISP
0000:00C4
WRITE_HEADER
0000:00F0
WRITE_T0P_HEX_NUM8ERS
0000:0127
0058::000D
LINES_BEFORE_SECTOR
0058::000E
HEADER_LINE_NO
0058::000F
HEADER_PART_1
0058::0015
HEADER_PART_2
0058::0026
PROMPT_LINE_NO
0058::0027
EDITOR_PROMPT
0058::00F8
PHANTOM CURSOR X
357
Assembly Language
for the
005B:00F9
PHANTOM_CURSOR_Y
005B:00FA
SECTOR
005B:00FA
_eclata
0058:2100
_end
in
map
memory). The
code) and
shows a
it tells
list
you where
of segments in
DGROUP, and contain all your data. For those of you interested in
_DATA contains all the memory variables defined in the .DATA
group
more
first
detail,
segment (such
the
if your
procedures are in a different order than our procedures (you can check
the order in
Appendix
B).
and variables
listed
in alphabetic order.
declared to be
in this
map.
The final section of the map lists all the procedures and memory variables again,
but
the
this
list,
You
you
procedure
Tracking
If you
were to
try
DISPATCHER starts
down
the
bug
lists
If you
include
check this
at address
2E2h.
in Dskpatch.
Down Bugs
it,
you would
find that everything works with the exception of Shift-F2 which caused
what
it
will
Since everything worked (and works now) except for Shift-F2, our
when we wrote
358
is
no
do on your machine.
the
first
guess
bug into
26
You know
that
and FIO)
all
gram
listing for
ing instruction
the heart of
bug
in
know works
DISPATCHER (in
is
DISPATCHER
start
DISPATCHER,
because
it
calls ail
the other
routines.
CALL
In particular, this
CALL
WRITE_SECTOR when
you
anuiii
you
see them,
you
will
DISPATCHER, look in the Dskpatch. map file to find its address. Then
in the following code, use the addresses
the addresses
You
tion.
will use
shown
Debug
you
see in
in this book.
to start
Dskpatch with
a breakpoint set
on
this instruc-
instruction. It can be
found by
unassembling
by another
JMP
02FC
3AC1 :030A 43
INC
BX
CALL
[BX]
JMP
02E5
359
Assembly Language
for the
Now
that
set a
breakpoint
CALL
instruction
at this address,
is
at location
WRITE_SECTOR.
First, use the command G 30B to execute Dskpatch up to this instruction.
You will see Dskpatch start up and then wait for you to type a command. Press
is
the
command
that
is
causing problems.
You
following:
-G SOB
AX=0155
BX=00A1
CX=06AC
DX=0027
SP=03F8
DS=3B1C
ES=3AB1
SS=3D2C
CS=3AC1
IP=030B
At
this
CALL
point the
BX
register
[BX]
is
DI=0000
if it
L 2
3B1C:00A0
00 81
is
displayed
first).
But
if you
look
SI=0000
NV UP EI PL NZ NA PO NC
DS:00A1=8100
BP=0000
load
map
any procedures
at
at the
fact,
is
totally
wrong.
In your original bug-hunting, once
it
we discovered
and the
table
We
all
knew
took a closer look at the data for Shift-F2 and found the
have had a DB. Having a road
look
at
that
was wrong,
DISPATCHER
we
DW where we should
tools.
360
26
both debuggers of
whereas
just addresses in
these
two
You may only want to read one of the next two sections; since one section covers Microsoft's CodeView and the other Borland's Turbo Debugger, there is
some repetition of material between the two sections.
CodeView
Microsoft's
CodeView is
market
the older of the two debuggers, having been introduced onto the
in 1986,
It is
now
included with every Microsoft Macro Assembler package (we are using version 6.0) as well as
this section,
CodeView
CodeView
shares
is
so useful that
if you
some
new
similarities
Source-level debugging
lets
upgrading
to consider
will see in
you
similarities.
ments, rather than just instructions and addresses in your display. For example,
if
to
unassemble the
in
first line
following:
3AC1:0010 B81C3B
MOV
With CodeView, on
AX,3B1C
you
you can
MOV
AX.DGROUP
is
handy
Whenever Dskpatch
is
to this
same screen
lost.
debugging Dskpatch.
one
for
screens:
active,
you
one
see
its
for
Dskpatch and
screen;
whenever
361
Assembly Language
CodeView
swapping
active,
is
as
you
see
its
screen.
You
of screen
Before you can use CodeView's symbolic debugging features you need to
tell
both the assembler and the linker to save debugging information. This can be
in the assembler
and the
/CODEVIEW switch
in
the linker.
Modify each
it
line in
your
MAKEFILE
a response
file
for
LINK as
file
by hand) so
so
it
uses
follows:
I
Listing
dskpatch.exe:
link @linkinfo
dskpatch.obj:
dskpatch.asm
nl /c /Zi dskpatch.asn
disk_io Ob j
.
diskio asm
.
Then change
Listing
file
LINKINFO
dskpatch /CODEVIEW;
362
'*""
'^
file
as follows:
LINKINFO
26
Finally, delete
can type
all
the *.obj
NMAKE /A to
when you
files
NMake
have
You should
(alternatively,
reassemble everything).
one
Now
in
you
you
are
Figure 26-
C>CV DSKPATCH
known
HDh
47:
file!
This
is
why CodeView
HDH
EXTRN
EXTRN
EXTRH
DlSK^Pfl TCH
48.
49:
58:
MOU
52
53
54
55
5G
57
58
CALL
CftLL
CALL
CALL
LEA
HB
0)1853
Naming:
is
debugger.
as a source-level
PROC
DS
,flX
CLEOR_SCREEN
HRITE HEADER
READ_SECTOR
IMIT_SEC_DISP
DX ED I TOR_P ROMPT
,
HDh
l.:i^Jl.BilT37
Now that you have CodeView up and running, you can look at the procedure
DISPATCHER without knowing where
Press Alt-S (to pull down the
it is.
patcher into the dialog box that pops up and press Enter to see the code for
DISPATCHER. Finally, use the cursor keys (or the Page Down key)
CALL WORD PTR [BX] instruction.
to scroll
to the
the cursor
struction, press
F7 (which
You will
you
see
on the
Dskpatch draw
will
its
line
with the
screen.
it
reaches the
[BX] in-
CALL).
you won't
see
the
F4
return
363
Assembly Language
Press the
for the
F2 key to
not already
if it is
you
on the
visible. If
will see
two short
lines as follows:
DS 00A1
:
8100
fix
^-j.iujJ4>.mj.iu.MiJ.ti.TTgTingv
^Qt
CALL
JHP
Cyie53 Warning
DX,ED1T0R_PR0MPI
MR1IE_PR0MPT_LINE
DISPATCH_LOOP
ei55
SI = 8898
DI = 9988
DS = G289
ES = 62 IE
SS = G499
CS ' SZZt
IP = 8388
MOT_IN_IftBLE
JMP
NO_CHfiRS_REOD
LEA
BX = ami
ex = 8988
DX = 8B27
SP = 83F8
BP = 8888
Erase
inva
antj
FL
3282
;Tra again
HU UP EI PL
NZ Nn PO HC
DS
:e8fll
8188
<FB=Irace> <FlB=Step> <FS=Go> <F6=HindOH> <F3=Displau>
memory
(Register).
is
the
CALL
instruction
Type AJt-F
(to pull
Don't forget
364
down
the File
to
change the
and go
to exit
from CodeView.
directly to the
Summary.
DW back to a DB in Dispatch.asm.
26
You may
want
also
file.
But
(Dskpatch
is
In any case,
fore
this
about
you
to
/CODEVIEW switch
EXE
1 1
will
so Link
/CODEVIEW switch
be-
to other people.
Turbo Debugger
section.
face as
Debug. As you
interface.
many debugging features that are not present in Debug. You will use two of
the new features here: source-level debugging and screen swapping.
Source-level debugging
lets
ments, rather than just instructions and addresses, in the display. For example,
if
to
unassemble the
line in
first
following:
3AC1:0010 B81C3B
MOV
AX,3B1C
you can
ure 26-3):
AX.DGROUP
MOV
handy
for
debugging Dskpatch.
in different places. In
lost the
Dskpatch
it
and one
for
itself.
Whenever Dskpatch
do
tell
active,
is
you
see
its
same screen
screen.
Turbo Debugger
is
is
separate screens:
active,
you
see
its
for
Dskpatch
screen;
whenever
features
you need
one
screen.
both the assembler and the linker to save debugging information. You
this
with the
/zi
365
Assembly Language
for the
I
Modify each
line in
the
/zi
file
for
TLINK (notice
Listing
name.
file
we
that
file
are using
by hand) so
so
it
it
has
uses a response
TLINK):
dskpatch.exe:
tlink @linkinfo
dskpatch.asm
dskpatch.obj:
tasii /zi
diskio.obj:
Then change
Listing
dskpatch.asa
disk_io.asm
file
LINKINFO
file
as follows:
LINKINFO
dskpatch /v;
to rebuild everything
the
B must be
(or type
"make -B"
uppercase).
Now you are ready to start Tiu^bo Debugger. Type the following and you should
see a display like the
one
in Figure 26-3:
C>TD DSKPATCH
Notice that you are viewing the actual source file! This
is
366
known
as a source-level
debugger.
is
26
^HHBrmrn
EXTRN
EXTRN
EXTRN
"W
CALL
CALL
CALL
CALL
LEA
CALL
CALL
CLEAR SCREEN
HRITE HEADER
READ SECTOR
IN IT SEC DISP
DX .EDITOR PRONPT
HRITE PROMPT LINE
DISPATCHER
MOW
AH,4Ch
Zlh
ENDP
DISK_PfiTCH
>
INT
Dia(_PATCH
;Roturn to DOS
_i
itaB
figure 26-3: The initial view ofDskpatch.exe inside Turbo Debugger.
is.
at the
procedure
down
the
View menu, followed by V to show the variable window (Figure 26-4). Use
the cursor-up and -down keys to move the cursor to dispatcher; press Enter to
show
to the
scroll
';'=fiVyi
'
-^
Fl-ltelp F2-Bkpt F3-od F4-HBre FS-Zoom FB-Mext F7- trace F8-Step F9-itun FIB-Hemt
window allows
us to jump to
a procedure.
367
Assembly Language
for the
the cursor
struction, press
F4 and follow
its
the
[BX] in-
screen.
swapped
To
screens.
Once you
flip
to
Turbo Debugger's
At
this
any key
dure Dskpatch
about to
is
call.
For
Ctrl-W to bring up
in [BX]
and
you can
see in the
will return
press Enter.
You
this,
add
a watch,
box that
a dialog
is
to
watch
Watches window, 8 1 00
the value
one
in Figure 26-5.
lie
dit
lew
un
reakpoint-s
=CJ=*lodule di spatch tile: dispat.ch.asn
the value
much more
;F1B exit?
;yes, leave
;Use BX to look through table
CMP
JE
ftL,68
LEA
BX .DISPATCH TABLE
END_DISPAICH
SPECIfU. LOOP
DISPfilCH
IMC
BX
HORD PTR CBX]
DISPATCH LOOP
;Ca
1 1
MOT_IN_TABLE
1
:End of table?
jVes, ketj was not in the table
;ls it this table entry?
;yes, then dispatch
;No , tru next entry
CALL
JMP
^^^^1 Ml
Hatches
Type Alt-X
Do
368
to exit
CALL
instruction.
As
quickly.
CMP
JE
CMP
JE
ADD
JMP
you
screen.
a value. Press
Shift-
DW back to a DB in Dispatch.asm.
26
You may also want to change back the LINKINFO file. You added the /v switch
so Link would add the debugging information to the .EXE file. But this debugging information makes the EXE file quite a bit larger (Dskpatch is about
2K
probably want to remove the /v switch before you give your programs to
other people.
Summary
That ends our discussion of debugging techniques. In the next chapter, we will
add the procedures
By the way,
book you
don't forget to
fix
will learn a
the
number of advanced
in
topics.
369
lciH|A|p|T|E|R
The Other
Half Sector
In
this
sectors.
FUe
altered:
Disk
file:
PHANTOM.ASM
PHANT027.ASM
it
bpics Covered
Scrolling
by Half a Sector
Summary
Assembly Language
for the
i,
L/skpatch should behave
like a
word
when you
processor
move the
move
try to
up one line, vwth a new line appearing at the bottom. The version of Dskpatch
this book does that. In this chapter, you will add
The
versions of
to 16 (there are
SCROLL_UP
and
SCROLL_DOWN that you will add to Dskpatch here scroll by full half sectors, so
you
sector.
by Half a Sector
Scrolling
restore the
cursor to the top or bottom of the half-sector display whenever you try to
move
bottom of the
display.
You
will
change
display.
and
its
Listing 27-1
PHANTOM_UP
Changes
to
PHANTOM.ASM
PROC
CALL
ERASE_PHANTOM
DEC
PHANTOM_CURSOR_Y
JNS
MHU
MUV
WASNT_AT_TOP
CALL
SCROLL_DOim
WRITE_PHANTOM
jwas
ST.
Lne xop,
WASNT_AT_TOP
CALL
RET
372
PHANTOM_UP
ENDP
PHANTOM DOWN
PROC
and
27
CALL
ERASEPHANTOM
INC
PHANTOM_CURSOR_Y
CMP
PHANT0M_CURS0R_Y,16
JB
WASNT_AT_BOTTOM
M6V
P H A N TO M _GUnSOn_Y
CALL
SCROLL_UP
The Other
Half Sector
;Wa3 at bottom,
SO write phantom
so put bock th e r e
WASNT_AT_BOTTOM
WRITE_PHANTOM
CALL
RET
PHANTOM DOWN
ENDP
Don't forget
to
PHANTOM_DOWN
SCROLL
DOWN as follows:
PHANTOM.ASM
SCROLL UP
and
PHANTOM_UP
and
to
Uses:
ERASE_PHANTOM, WRITE_PHANTOM
'"'''''^ll
SCROLL_DOWN, SCROLL_UP
Reads:
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
Writes:
PHANTOM_CURSOR_X
PHANTOM_CURSOR_Y
SCROLL_UP
and
cause they switch the display to the other half sector. For example,
looking at the
you will
and
first
see the
sector display
writes the
half sector,
both
phantom
SCROLL_UP
and
start
of the
You can
see
all
if you are
it
the details
These two
373
Assembly Language
for the
Listing
EXTRN
DISP_HALF_SECTOR:PROC, GOTO_XY:PROC
EXTRN
SECTOR_OFFSET:WORD
EXTRN
LINES_BEFORE_SECTOR:BYTE
.DATA
CODE
These two procedures move between the two half -sector displays.
Uses:
SAVE_REAL_CURSOR
Reads:
LINES_BEFORE_SECTOR
Writes:
SECTOROFFSET
SCROLL_UP
PUSH
GOTO_XY
RESTORE_REAL_CURSOR
PHANTOM_CURSOR_Y
PROC
DX
CALL
ERASE_PHANTOM
CALL
SAVEREALCURSOR
XOR
DL.DL
MOV
DH LINES_BEFORE_SECTOR
ADD
CALL
DM, 2
GOTOXY
;Display the second half sector
MOV
DX,256
MOV
SECTOR_OFFSET,DX
CALL
DISP_HALF_SECTOR
CALL
RESTORE_REAL_CURSOR
MOV
PHANTOM_CURSOR_Y
CALL
POP
WRITE_PHANTOM
DX
RET
SCROLL_UP
SCROLLDOWN
PUSH
DX
CALL
ERASE_PHANTOM
CALL
SAVE_REAL_CURSOR
XOR
DLjDL
MOV
DH LINES_BEFORE_SECTOR
ADD
CALL
374
ENDP
PROC
DH,2
GOTO_XY
XOR
DX.DX
MOV
SECTOR_OFFSET,DX
CALL
DISP_HALF_SECTOR
CALL
27
PHANT0M_CURS0R_Y,15
MOV
Half Sector
WRITE_PHANTOM
CALL
The Other
DX
POP
RET
ENDP
SCROLL DOWN
as
Start
and you
the cursor at the top of the screen. Press the cursor-up key
you
move
try to
will see
first
sector display.
play and
at the
you
Modify Dskpatch
phantom
cursor
is
so that
at the
it
top of the
first
half-sector dis-
half-sector display
and
press the
If you're
cursor-down key,
Summary
This chapter ends the coverage of Dskpatch (with the exception of Chapter
30, where
to use
Dskpatch
as a "live"
a usable program,
and a
set
of procedures
you
your
when
it
is
never done
TSR or
COM
375
Advanced Topics
l95|
8F|B2]70_
3|CF|3F|91
liA 8|4 3|2E|B D
9i60|CE[^[42
63l57[9A|75|B6|D2|FD^^_^
IhTa
p It
e |r.
Relocation
In
this
run.
You
will build a
also introduce
you
some programs.
program
by
itself.
We will
see in
Writing
COM Programs
Assembly Language
for the
in Parts II
for
and
III
EXE
pro-
it
loads an
program
that does
its
own
relocation process,
relocation (since
you
will build a
COM
COM programs). Since you haven't dealt with using the assembler to
build COM programs yet, we will stan with a short look at some new directives that you will need to write COM programs.
port for
Writing
COM Programs
Throughout
grams, which
this
is
EXE
pro-
what you will probably write most of the time. Some programs,
however, need to be
like the
to build
COM
in
this
chap-
Building
COM program
In a
are set
programs
all
Full
Using
is
loads.
Segment
Definitions
We will not use the simplified segment definitions (such as .CODE). Instead,
we will
use the
the open.
since
like
You will
it
procedure definitions,
segment.
380
full
as
usefiil to
be able to read
fiill
will
be out in
segment definitions
you can
see in this
much
28
TEXT
SEGMENT
TEXT
ENDS
Rather than
start a
Relocation
with a
provide the
in this example).
In addition to the segment definitions, you need to use another directive called
fi^om the
to.
With
full
segment
directives,
you use
ASSUME
segment
new
directive,
you need
to provide this
ASSUME,
information
.MODEL directive).
For
as follows:
This statement
tells
code (which
the case
is
when
CS
register will
be pointing to your
DS
register
points to the data segment, and that SS points to the stack segment.
The
will
have to
set
up the
last
two
registers yourself.)
with the 256 byte PSP. In order to reserve room for the PSP,
gram code
at
ORG
lOOh
(or
lOOh.
The
ORG
tells
You
will see
all
of these
Chapter 32.
Relocation
Each of our
EXE
register so
it
segments called
sets the
DS
DGROUP.
MOV
AX DGROUP
MOV
DS.AX
381
Assembly Language
for the
The question
about
it,
is,
If you
think
programs can be loaded anywhere into memory. This means that the
value of
when
it
program
in
turns out,
it
EXE
loads an
numbers such
cess patches
the
for
as
DOS
known
performs an operation
is
as
memory.
To understand this process, you will write a COM program that does its own
relocation. The goal is to set the DS register to the beginning of the _DATA
segment, and the SS register to the beginning of the
STACK segment.
you need
bit
of trickery.
First,
memory in
to ensure that
This
your
Fortunately,
segment
we have
file.
nique to
segment
registers,
make
sure
How
is
we have placed
labels
are
this.
When
you
your source
set
directives,
DS
.MAP
file
to check the
by looking
in
which
segment
LINK
order).
Those
and
END_OF_CODE_SEG, END_OF_DATA_SEG,
to be because
segment definitions
_TEXT
for
fiill
COM programs).
SEGMENT
it
starts
each
new segment on
how
a paragraph
boundary
at a
hex
skips to the
next paragraph boundary to start each segment, there will be a short, blank
label END_OF_CODE_SEG at the
_DATA, you include this blank area. If you had put
END_OF_CODE_SEG at the end of _TEXT, you would not include the
area
beginning of
382
28
The
1
is
blank area
the
GROUP
_TEXT
bytes long.)
to set SS.
The
TEXT,
this
number by
COM
file, is
as follows:
DATA, STACK
SEGMENT
ORG
WRITE_SSTRING
100h
PROC
FAR
MOV
MOV
CL,4
SHR
AX,CL
MOV
BX CS
ADD
AX.BX
;Add CS to this
MOV
DS.AX
(16 bytes)
DATA
MOV
SHR
AX,CL
ADD
AX.BX
;Add CS to this
MOV
SS.AX
MOV
MOV
SP,AX
MOV
AH, 9
LEA
DX, STRING
INT
21
;Write string
MOV
AH,4Ch
INT
21h
WRITE STRING
TEXT
of the program
is 1
same technique
ASSUME
filled
listing
Relocation
use the
unassemble
of the
instruction
130h, which
will see a
at the
Return to DOS
ENDP
ENDS
383
Assembly Language
_DATA
for the
SEGMENT
END_OF_CODE_SEG LABEL
STRING
DATA
STACK
BYTE
DB
ENDS
SEGMENT
BYTE
END_OF_DATA_SEG LABEL
DB
DUP
END_OF_STACK_SEG
STACK
(
'
STACK
LABEL
;'
'
BYTE
ENDS
WRITE STRING
END
this
program, just
as
you would an
COM program.
EXE2BIN
other words,
Debug
EXE
to BINary.
EXE
You
file
session as follows:
C>DEBUG WRITESTR.COM
-U
MOV
3AB1:0103 B104
MOV
CL,04
SHR
AX,CL
AX, 01 30
MOV
BX,CS
3AB1:0109 03C3
ADD
AX,BX
3AB1:010B 8ED8
MOV
DS,AX
3AB1:010D B85001
MOV
AX, 01 50
SHR
AX.CL
ADD
AX.BX
MOV
SS.AX
MOV
AX, 0046
MOV
SP.AX
MOV
AH, 09
MOV
DX,0000
-U
384
into (2) a
BINary
INT
21
MOV
AH,4C
INT
21
3AB1:0126 0000
ADD
[BX+SI],AL
3AB1:0128 0000
ADD
[BX+SI],AL
(COM)
all this
work
file;
in
in the
28
3AB1 01 2A 0000
ADD
(BX+SIJ.AL
ADD
[BX+SI] ,AL
ADD
[BX+SI] ,AL
3AB1 0130 48
DEC
AX
3AB1 0131 65
DB
65
3AB1 0132 6C
DB
6C
3AB1 0133 6C
DB
6C
0134 6F
DB
6F
SUB
AL,20
3AB1 0137 44
INC
SP
3AB1 0138 4F
DEC
DI
3AB1 0139 53
PUSH
BX
3AB1 01 3A 206865
AND
[BX+SI+65] ,CH
3AB1 01 3D 7265
JB
01A4
3AB1
3AB1 013F 2E
CS:
AND
Relocation
AL,00
-G 120
AX=0946
3X=3AB1
CX=0004
DX==0000
SP=0046
DS=3AC4
ES=3AB1
SS=3AC6
CS==3AB1
IP=0120
There
are a couple of
following
CGROUP
You
ally
INT
GROUP
TEXT,
in the
DI=0000
21
create
DATA,
you
STACK
group called
SI=0000
NV UP EI PL NZ NA PE NC
line:
here
new
BP=0000
program. Creating
this
CGROUP, you can get the offset from the start of the program by ask-
ing for the offset from the start of this group as follows:
MOV
called
STACK.
385
Assembly Language
You
will
for the
this type
EXE programs.
But it helps
DOS
to understand what's
scenes.
its
An EXE
COM program
this, a
own
relocation, as
this reason,
For a
we
essentially a
is
final
it
lets
DOS
look at
it
When DOS
For
is
loads a
let's
how DOS
examine
differences
loads
it
steps:
DOS
area
the
creates the
you saw
Chapter
1 1
prefix (PSP),
which
this
is
the
PSP
256 byte
contains
line typed.
DOS next copies the entire COM file from the disk into memory,
immediately
in
command
program segment
after the
DOS then sets the three segment registers DS, ES, and SS to the start
of the PSP.
DOS
which
sets the
is
Finally,
SP
the last
register to the
word
DOS jumps
the
386
in the segment.
program, which
COM program).
register to
sets
lOOh
the
CS
(the stan
of
28
DOS
volved, because
Every
EXE
file
are
somewhat more
Relocation
in-
EXE file has a header that is stored at the start of the file. This header, or
relocation table,
is
all
the informa-
in this header.
program
at the
is
C>EXEHDR DSKPATCH
Microsoft
(R)
Copyright
(C)
8fc
Magic number:
5a4d
00fc
Pages in file:
0005
Relocations:
0001
Paragraphs in header:
0020
0241
ffff
0270:0400
Word checksum:
ec2c
Entry point:
0000:0010
Version 2.01
11K
C>
table,
you can
is
MOV AXjDGROUP instruction. Any time you make a reference to a segaddress, as with MOV AX,DGROUP, Link will add a relocation entry
ment
to the table.
into
The segment
memory,
There
are also
example, the
so
address
you must
some other
initial
is
DOS
not
known
it
until
let
tell
you the
initial
Memory
pro-
needed).
387
Assembly Language
Because
for the
DOS
gram
memory. The
steps
DOS
it
when
takes
follows in loading an
load-
EXE
pro-
as follows:
DOS
creates the
just as
it
does for a
COM program.
DOS
checks the
program
starts.
after the
PSP.
DOS
finds
EXE header
Then
it
and patches
to find
all
header information.
DOS
then
sets the
ES and DS
change
DS
of the
own
its
EXE
header. In
the case illustrated, the header states that SS:SP will be placed at
0050, and
set
SS so
it is
Finally,
DOS jumps
provided in the
EXE
to the start
CS
388
EXE header.
of
1c|h|a|p|t|e|r
More on
Segments and
ASSUME
In
this
in real
to
chapter you will learn about segment overrides, which are ver>'
programs.
You will
use
and
full
segment
in
Chapter 30
usejflil
is much faster than using the ROM BIOS rouYou will also learn more about ASSUME statements
them
definitions.
!|f\
Segment Override
Another Look
at
ASSUME
Summary
Assembly Language
for the
1
Segment Override
So
far
book (which
this
some
cases
actually several
so
is
DGROUP),
You have
Most commercial
DOS
A classic example
is
memory and,
in the interest
of
PC
is
located at segment
the screen.
In this section you will write a short program that shows you
two
different segments
segments. In
the
ES
fact,
by using the
many programs
DS
and ES
registers to
how
to write to
memory
use
memory.
full
segment definitions
to give
use them.
We
also
standing of the
segment
used
fiill
ASSUME
segment definitions
is
an
EXE program.
It is
as follows:
DOSSEG
SEGMENT
DW
DS_VAR
DATA
392
a better under-
_DATA
you
fiill
definitions.
Our program
is
to give
ENDS
it
has
The program
29
EXTRA_SEG
SEGMENT PUBLIC
ES_VAR
DW
EXTRA SEG
ENDS
STACK
TEXT
10 DUP
(
'
STACK
'STACK'
ENDS
SEGMENT
SS: STACK
ASSUME
MOV
AX,_DATA
MOV
DS.AX
MOV
AX EXTRA_SEG
MOV
ES,AX
MOV
AX DS_VAR
MOV
BX ES ES_VAR
MOV
AH,4Ch
INT
21h
;Return to DOS
PROC
TEST_SEG
TEST_SEG
_TEXT
ASSUME
SEGMENT STACK
DB
STACK
ENDP
ENDS
TEST SEG
END
This program will help you learn about segment overrides and the
ASSUME
directive.
Notice that the data segments and the stack segment come before the code
segment.
rations.
We have also put the ASSUME directive after all the segment decla-
As you
program which
Take
arrangement
is
a direct result of
MOV instructions
in the
are as follows:
MOV
AX DS_VAR
MOV
BX ES ES_VAR
393
Assembly Language
The
for the
DS,
tells
the
80x86
As with the ES
refers to data.
80x86
The 80x86
register in this
to use
80x86
from
uses when
it
the
tell
has four special instructions, one for each of the four segment reg-
isters.
to use
to use a specific
segment
register rather
You
MOV AX,ES:ES_VAR
2CF4:000D 26
ES:
2CF4:000E 8B1E0000
MOV
is
actually
when
the in-
memory. For
encoded
unassemble the
the
tell
test
as
two
program:
BX,[0000]
This shows that the assembler translated the instruction into a segmentoverride instruction, followed by the
struction will read
trace
through
this
its
data from the ES, rather than the DS, segment. If you
program, you
Another Look at
Let's take a
look
at
what happens when you remove the ES: from the program.
Change
the line
MOV
BX,ES:ES_VAR
SO
it
ASSUME
reads:
MOV
BX ES_VAR
,
when you
read from
you want
front of the
394
of
this change.
to use the
You
that the
Debug
segment override
it
ES
to
look
is still
in
needed to
29
tive,
is
in the
ASSUME
ASSUME
direc-
tells
memory variable,
through the
this
ASSUME
segment.
The
list
which segment
to find out
declared
which segment
in.
Then
register
when
it
is
it
searches
pointing to
generates the
instruction.
ES_VAR was
in the
segment called
own.
If you
it
EXTRA_SEG;
the
ES
register
was point-
were to move
The
the assembler
its
would
assembler automatically
ASSUME directives
Summary
In this chapter you learned
with them.
You learned about segment overrides, which allow you to read and
You will use such overrides in the next chapter
Finally,
ASSUME directive.
395
HTA
A Very Fast
WRITE CHAR
In
this chapter
you will
modify Dskpatch so
rather than using the
Files altered:
it
displays characters
are going to
by writing
your screen,
directly to
ROM BIOS.
VIDEO_IO.ASM
files: DSKPAT30.ASM, KBD_IO.ASM, CURSOR30.ASM,
VIDEO 30.ASM
Disk
Memory
Summary
Assembly Language
for the
1
In
grams
book we mentioned
do so
that
for speed.
Assembly-language programs
have noticed that the Dskpatch program does not draw the screen
as
quickly
many commercial programs. It is slow because we have been using the ROM
BIOS routines to display characters on screen. Most programs bypass the ROM
BIOS and write characters directly to screen memory in favor of raw speed.
as
Segment
memory
memory
is
and how
it
know where
stores characters.
has
its
them non-overlapping
screen segments.
Monochrome
ics cards,
and
Monochrome
(it
refers to
depends on the
display).
They have
on the screen
segment
at
BOOOh.
earlier days.
amber
are
in green, white, or
text colors at
still
a few
their screen
CGA cards
from the
memor\^
segment
at
B800h.
Users should not need to
up
to the
can use
program
INT
11 h,
to determine
which returns
398
know which
4 and 5
tell
list
you
is
active.
For
this
It is
you
the display
is
monochrome
or color.
30
Very Fast
WRITE.CHAR
The screen segment will be at BOOOh (monochrome) if both bits are 1 and
B800h (color) if otherwise (we will ignore the case when no display adapter is
,
installed).
AL
returned
by INT 11 h
I
00
No
01
40 X 25 color
10
80x25
11
80 X 25 monochrome
display adapter
color
know which
INIT_WR1TE_CHAR, which determines the screen segment, before making any calls to WRITE_CHAR. You
will place this call at the start of DISK_PATCH to make sure it is called begram, you will need to
fore
to
call
the procedure
add
DSKPATCH.ASM
Listing 30-1
(Complete
Changes
listing in
to
DSKPATCH.ASM
DSKPAT30.ASM)
EXTRN
WRITE_PROMPT_LINE PROC
EXTRN
INIT_WRITE_CHAR PROC
DISK_PATCH
DISPATCHER: PROC
PROC
MOV
AX,DGROUP
MOV
DS.AX
CALL
INIT_WRITE_CHAR
CALL
CLEAR_SCREEN
CALL
WRITE HEADER
Next, add
INIT_WRITE_CHAR to VIDEOJO.ASM
as follows:
399
Assembly Language
for the
Listing
PUBLIC
VIDEOJO.ASM
INIT_WRITE_CHAR
You need to call this procedure before you call WRITECHAR since
SCREEN SEG
PUSH
AX
PUSH
BX
MOV
BX,0B800h
INT
11h
AND
AL,30h
CMP
AL,30h
JNE
SETBASE
;No,
MOV
BX,06000h
;Yes,
MOV
SCREEN_SEG,BX
POP
BX
POP
AX
it's color,
so use B800
it's monochrome,
so use B000
SET_BASE
RET
INIT WRITE CHAR ENDP
Note
that
you
it
will learn
how the
characters
and
Writing Directly to
Screen Memory
If
you were
screen
to use
Debug
to look at screen
memory when
is
DSKPATCH ASM
you would
400
the
first line
of the
30
Very Fast
WRITE.CHAR
-B8e0:e
6800:0000
44 07 53 07 4B 07 50 07-41 07 54 07 43 07 48 07
6800:0010
20 07 41 07 53 07 4D 07-20 07 20 07 20 07 20 07
from Chapter
is
18,
ter
on the screen
uses
is
Each 7
changes to
Listing
is
the
in the
and the
WRITE_CHAR
.A.S.M
D.S.K.P.A.T.C.H.
attribute in the
upper byte.
VIDEO_IO.ASM
30-3 Changes to
in
new version of
memory. Make
Let's write a
as follows:
VIDEOJO.ASM
PUBLIC
WRITE_CHAR
EXTRN
'y
On entry:
DL
Uses:
CURSOR_RIGHT
Reads :
SCREEN SEG
WRITE_CHAR
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
PUSH
ES
401
Assembly Language
Listing
for the
30-3 continued
MOV
AX,SCREEN_SEG
MOV
ES,AX
PUSH
DX
MOV
AH,
XOR
BH,BH
On page
INT
ieh
MOV
AL,DH
MOV
BL,80
MUL
BL
AX = row
ADD
AL.DL
80
ADC
AH,e
SHL
AX,1
MOV
BX,AX
POP
OX
MOV
DH,7
MOV
ES:[BX],DX
CALL
CURSOR_RIGHT
POP
ES
POP
DX
POP
CX
POP
BX
POP
AX
RET
WRITE CHAR
Finally,
ENDP
you need
Usting 30-4
to
add
memory variable
Add DATA_SEG
to
VIDEO_IO.ASM:
to the start of
VIDEOJO.ASM
.MODEL SMALL
.DATA
SCREEN SEG
.CODE
402
DW
OB80Oh
30
Aher making
Dskpatch (you
will
Very Fast
WRITE_CHAR
need to assemble
Dskpatch
does not write to the screen any faster than before because you are moving the
down
the process.
is
be, instead of
SCREEN_X
to).
For
is
we
this
will introduce
There
as well as write a
Listing
be,
move
the
easy,
WRITE_CHAR cal-
culates the offset of the cursor into the screen buffer each time
will
you
you can
call
also
it.
Since
keep track
SCREEN PTR.
30-5 Changes to
WRITE_CHAR
in
VIDEOJO.ASM
o.
CURSOR, RIGHT
Uses:
Reads:
SCREEN_SEG
WRITE_CHAR
SCREEN_PTR
^^^W|
PROG
PUSH
AX
PUSH
BX
rv
PUSH
DX
PUSH
ES
MOV
AX SGREEN_SEG
MOV
ES,AX
MOV
BX,SCREEN_PTR
PUSH
M OV
-XOR-
-BX-
AH 3
,
BH BH
,
-+tl
column
403
Assembly Language
Listing
for the
30-5 continued
-M0V-
AL,DH
-Mev-
BL,80
Th e n e ane 8
-MUt-
m-
-Bt
now
charact e ns p e r lin e
-8
-ABe-
AL.DL
-me-
A H ,0
-SHt-
AX,1
B X,AX
-MOV-POP-
Add th e column
n e ston e
-BX
th e chanact e n
MOV
DH,7
MOV
ES:[BX],DX
CALL
CURSOR_RIGHT
POP
ES
POP
DX
TY
POP
BX
POP
AX
RET
WRITE CHAR
ENDP
WRITE_CHAR
has
memory variables
to the
become
also
in
VIDEOJO.ASM:
.DATA
in
VIDEOJO.ASM
.DATA
PUBLIC
SCREEN_PTR
PUBLIC
SCREEN_X, SCREEN_Y
SCREENSEG
DW
0B800h
SCREEN_PTR
DW
SCREEN_X
DB
SCREEN_Y
DB
.CODE
404
You must
DATA_SEG
o.
quite simple.
30
The changes
to
WR1TE_ATTRIBUTE_N_TIMES so
it
Very Fast
WRITE_CHAR
Uses:
CURSOR_RIGHT
Reads:
SCREEN_SEG, SCREEN_PTR
in
WRITE_ATTRIBUTE_N_TIMES PROC
AX
PUSH
PySH
BX
PUSH
cx
m
^^
PUSH
PUSH
DI
PUSH
ES
MOV
AX,SCREEN_ SEG
MOV
ES,AX
MOV
INC
DI
MOV
AL,DL
ATTR_LOOP
;Save one attribute
^^^H
DI
INC
SCREEN_X
^^|
^^|
LOOP
ATTR_LOOP
;Write N attributes
DEC
DI
MOV
SCREEN_PTRl,DI
STOSB
INC
POP
POP
^H
ES
DI
POP
BX
POP
cx
..
*-
-pep-
POP
AX
RET
405
Assembly Language
the
STOSB {STOre
LODSB
fairly clear,
the SI register.
STOSB
is
new
in-
the opposite of
STOSB stores the byte from AL into the address at ES:DI, then
increments DI.
All of the other changes
in
KBD_IO)
change
GOTO_XY so
Listing
you need
to
make
fix
are to procedures in
it
sets
PTR.
30-8 Changes to
GOTO_XY in CURSOR.ASM
PUBLIC
GOTO_XY
EXTRN
SCREEN_PTR:WORD
EXTRN
SCREEN_X:BYTE, SCREEN_Y:BYTE
.DATA
;
mm
^|g
.CODE
On entry:
GOTO_XY
406
DH
Row
DL
Column
(Y)
(X)
PROC
PUSH
AX
PUSH
BX
Display page
MOV
BH,0
MOV
AH, 2
INT
10h
MOV
AL,DH
MOV
BL,8e
MUL
BL
;AX = row
ADD
AL,OL
;Add column
ADC
AH,0
;AX = row
SHL
AX,1
MOV
SCREEN._PTR,AX
MOV
SCREEN._X DL
MOV
SCREEN..Y DH
80
80 + column
30
POP
BX
POP
AX
Very Fast
WRITE_CHAR
RET
ENDP
GOTO XY
As you can
acter
moves the
GOTO_XY. You
must
also
modify
memory variables.
30-9 Changes to
Listing
CaRSOR_RIGHT
PUBLIC
CURSOR_RIGHT
EXTRN
SCREEN_PTR:WORD
EXTRN
in
CGRSOR.ASM
.DATA
;
t-^^^
j^^^l
^m
.CODE
This procedure moves the cursor one position to the right or to the
next line if the cursor was at the end of a line.
Uses:
SEND_CRLF
Writes:
CURSC R_RIGHT
PROC
INC
SCREEN_PTR
INC
SCREEN_PTR
INC
SCREEN_X
CMP
SCREEN_X,79
JBE
OK
CALL
SEND_CRLF
JIHiHfc
OK:
RET
CURSOR RIGHT
ENDP
407
Assembly Language
30-10 Changes
Listing
in
for the
to
CLEAR_TO_END_OF_LINE
CaRSOR.ASM
PUSH
CX
PUSH
DX
MOV
AH 3
BH BH
on pag e
-+0+1
in DL,
DH
DL,SCREEN_X
MOV
The
H e ad
MOV
DH,SCREEN_Y
MOV
AH, 6
XOR
AL,AL
Clear window
next few steps require an explanation. Because you are no longer updat-
ing the position of the real cursor, the real and virtual cursors will often be out
of synchronization. Usually
this
is
cases,
how-
when you have to synchronize both cursors; sometimes you will want to
move the real cursor to where you think the cursor is, and sometimes you will
want to move the virtual cursor. For example, before asking the user for input,
you need to move the cursor to where you think the cursor should be. You
ever,
will
do
this
UPDATE_REAL_CURSOR,
which moves
On the other hand, SEND_CRLF moves the real cursor, so you must call
UPDATE_VIRTUAL_CURSOR to move the virtual cursor to where the real
cursor
is
after
CURSOR.ASM
are as follows:
Listing 30-1
Procedures added to
PUBLIC
CURSOR.ASM
This procedure moves the real cursor to the current virtual cursor
position.
input.
UPDATE_REAL_CURSOR
408
PROG
PUSH
DX
MOV
DL,SCREEN_X
MOV
DH,SCREEN_Y
30
CALL
GOTO_XY
POP
DX
Very Fast
WRITE_CHAR
RET
PUBLIC
ENDP
PROC
UPDATE_VIRTUAL_CURSOR
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AH,
XOR
BH.BH
;0n page
INT
10h
CALL
GOTO_XY
POP
DX
POP
CX
POP
BX
POP
AX
DL
RET
ENDP
Note that you are using GOTO_XY to update the three variables SCREEN_X,
dures.
The changes
Listing
to
SEND_CRLF
listing in
are as follow^s:
to SEND_CRLF
CURSORBO.ASM)
30-12 Changes
(Complete
two proce-
in
CORSOR.ASM
SEND_CRLF
PROC
PUSH
AX
PUSH
DX
409
Assembly Language
Listing
HHI
for the
30-12 continued
MOV
AH, 2
MOV
DL,CR
INT
21h
MOV
DL,LF
INT
21h
CALL
UPDATE_VIRTUAL_CURSOR
POP
DX
POP
AX
RET
SEND CRLF
ENDP
This change makes sure that you know where the cursor is
after
The changes
to
Listing
(Complete
EXTRN
listing in
in
KBDJO.ASM
KBD_IO30.ASM)
Nr^
READ_STRING
PROC
PUSH
AX
PUSH
BX
PUSH
SI
MOV
SI.DX
BX,2
CALL
CALL
READ_KEY
OR
AH, AH
START_OVER
MOV
READ LOOP:
410
30
Reassemble
all
three
files
that
you changed
(Vicleo_io, Cursor,
is
Very Fast
WRITE.CHAR
and Kbd_io)
much
faster
than
before.
Summary
Speeding up
had
to
efifon.
be quite a
bit
results
easier to
you
will learn
how
to write procedures
and functions
for
411
H A
I
Using Assembly
Language
and C++
Programs
In
this chapter
for
C/C++. You
you
will learn
will learn
how
about
assembly-language subroutines
will learn
in
Topics Covered
A Clear Screen
for
Passing
C
C++
One Parameter
Gsing Other
Summary on
Writing
Memory Models
C/C++ Procedures
Writing In-Line
in
Assembly Code
Summary
Assembly
Assembly Language
for the
C and C++
C from here on to refer to both C and C++, since C++
a superset
will use
in-line assembly.
directly to
your
BASIC, we
are concentrating
on
C because C
is
like Pascal or
are written in
C, with a
has
become
provides
many
it is
modern
operator. Because
as the
++ increment
you will want to write parts of your program in assembly language for speed or
low-level access to your machine, etc.
the
programs in
this
chapter,
We will
you can
you will
need Microsoft
We
C compiler
call it directly
C programs
is
see,
so
.MODEL directive being used allows you to define the memory model of
the program you are building. (We have only used the SMALL memory model
in this book.) Starting with version 5.1 of MASM, Microsoft added an extension to the .MODEL directive that allows you to write programs to attach to
a number of different languages (including C and Pascal). To tell MASM that
you are writing a C procedure, you append a ",C" to the end, as follows:
.MODEL
SMALL,
CLEAR SCREEN
CLEAR_SCREEN
PUSH
414
CLEAR_SCREEN,
The
or later or Borland's
Microsoft
by rewriting
MASM version 5.
Turbo Assembler.
start
PROC
AX
7 of this book.
at the as-
31
PUSH
BX
PUSH
OX
(Jsing
Assembly Language
in
PUSH
DX
XOR
AL.AL
XOR
OX, OX
MOV
DH,24
MOV
DL,79
MOV
BH,7
MOV
AH,
INT
10h
POP
DX
POP
OX
POP
BX
POP
AX
RET
CLEAR SCREEN
This
is
shown
ENDP
you have
to
do
to con-
hold
all
of the
C procedures written
in assembly
Listing
.MODEL
file
CLIB.ASM
SMALL,
.CODE
CLEAR_SCREEN
PROC
XOR
AL.AL
XOR
CX,CX
MOV
DH,24
MOV
DL,79
MOV
BH,7
MOV
AH, 6
INT
10h
RET
CLEAR SCREEN
ENDP
END
415
Assembly Language
(If
you
are using
.MODEL
with
MASM5
on the
first line,
will
and
QUIRKS
lines after
on the second
line.)
You will notice that we have removed all of the PUSH and POP instructions
we used to save and restore registers. These instructions are used in assembly
language programs so you do not have to keep track of which registers were
much
guage
save the
simpler.
called.
or
DX registers at
all
since the
You
iNotf
compiler always
to return values.
as-
You
and
to save
them
in
in
assembly language.
your procedures.
Preserve:
SI,
Following
this
is
a very short
program
Listing
(use
CLD)
is all
does.
31-2 The
file
test.c
mainO
{
clear_screen(
files
steps to assemble
together to form
ML /C CLIB.ASM
CL -C TEST.C
416
link
31
With some
letters,
linkers or compilers
we have
case since
Assembly Language
CJsing
to
tell
letters in
the
(The
names
Note
in uppercase
code.
CL -C command compiles a file without linking it.) The last line is a bit
match your
in
so
you
will
TEST.EXE
is
know where
a fairly small
to find clear_screen() in
program, the
Following
mation we
is
to create a
map
map showing
all
turns
C programs.
Address
Publics by Name
0054:00EC
STKHQQ
0000: 001
_clear_screen
0054:0108
_edata
0054: 01 E0
_end
0054:00DA
environ
0054:0063
_errno
0000: 01 A2
_exit
0000:0010
main
As you can
see,
clear_screen.
(C compilers
also
the
the procedure
is
put an underscore
.MODEL directive
tells
in front
MASM
to
in front
all
procedure names.
add an underscore
at the front
of all
file.
417
Assembly Language
the
to
be
you can
keyword
to
keep a
You
use
PRIVATE
for the
is
changes the
PROC
directive so
procedure from
PUBLIC
being declared
PUBLIC. For
cally will
it
The
PUBLIC
This
files.
",C" addition to
.MODEL
be declared
us.
not include a
available to other
if
you
are writing a
procedure in
as-
PUBLIC
for you.
example, this
definition creates a
private procedure
Load TEST.EXE
for you.
called PrivateProc:
for
your
into
Using the
C compiler),
is
for _clear_screen:
PrivateProc
PROC PRIVATE
You willfind
C>DEBUG TEST.EXE
-U 1A
4A8A:001A 32C0
XOR
AL.AL
PRIVATE
4A8A:001C 33C9
XOR
OX, OX
keyword in the
4A8A:001E B618
MOV
DH,18
library code in
4A8A:0020 B24F
MOV
DL,4F
Appendix
4A8A:0022 B707
MOV
BH,07
4A8A:0024 B406
MOV
AH, 06
4A8A:0026 CD10
INT
10
4A8A:0028 C3
RET
examples of using
the
C.
This
is
at the
exactly
end of the
in
CLIB.ASM.
number of other
we would not be
areas
where
it
as
PUBLIC.
If this
were the
Using Clear_screen
C++
in
C+
called
decorating.
as a result
C++
of something
Names
indicate how many and
418
31
defines.
For example,
if you
in
had
a func-
tion called
some_f unc(int
it
double)
to look
something
like this:
Fid
some_f unc
you
C++
compiler added
Fid.
other
The Fsnys
letters
name from
that
The two
some_func
is
a function, as
all
whenever you
to ensure that
call
you
are using
all
C++
in this
to a class,
example
and the
mangled names
underscores sepa-
which
opposed
to.
name,
as well as
an external function.
There
need
is
some way
to
tell
function. Fortunately,
C++
no
function as an external
is
call
an external
to
some_func
your
as follows in
C++
source
file:
double)
C++ compiler
C+ + source
using
You can
files,
to declare all
tax:
of the
functions as extern
extern "C"
some_func(int, double);
another_func(int)
}
names in your
function
calls.
419
Assembly Language
for the
Passing
One Parameter
would
the other hand, use the stack to pass parameters to procedures. This
the
is
where
MASM 5.1 .MODEL extensions really come into play. MASM automati-
cally generates
much
the stack.
To
see
how
this
works,
we
C procedures.
add to CLIB.ASM:
Listing
The
DB
WRITE_STRING
PROC
PUSHF
CLD
MOV
SI, STRING
(forward)
STRING_LOOP:
;Get a character into the AL register
LODSB
420
OR
AL.AL
JZ
END OF STRING
yet?
31
CJsing
C3
Assembly Language
in
MOV
AH, 14
XOR
BH.BH
;Write to page
INT
10h
JMP
STRING_LOOP
END_OF_STRING:
POPF
RET
ENDP
WRITE STRING
however,
it
is
The
first
piece,
USES
SI, tells
PROC statement.
and DI
registers if
piece
is
see,
the
USES
SI causes
STRING, and
want
to call the
acter
(BYTE), which
eter a
parameter
is
the
we
first
that
it is
a pointer
(PTR)
By giving
its
name,
that
is
you
to a char-
this
param-
as in
MOV
si,string'
Procedure name
WriteChar
List of
Proc Uses SI
DI,
parameters
List of registers
to preserve
Figure 31-1: The Proc directive allows you to define both parameters that are passed on
the stack
and which
registers will
be preserved.
421
Assembly Language
for the
MASM.
will
become
clear as
soon
as
you
see the
code generated by
to
TEST.C:
Listing
main(
{
clearscreenO
write_string("This is a string!");
^m.
Recompile
TEST.C
(with
CL
LINK
you
use).
_clear_screen
0000:0024
edata
0056: 01 EA
0056: 01 F0
_end
0056 00DA
_environ
0056:00B3
_errno
0000: 01 C6
_exit
0000:0010
_main
0000:0033
_write_string
is
background):
-U 33
4A8A:0e33 55
4A8A:0034 8BEC
4A8A:e036 56
422
PUSH
MOV
PUSH
4A8A:0037 9C
PUSHF
4A8A:0038 FC
CLD
4A8A:0039 8B7604
MOV
4A8A:003C AC
LODSB
BP
BPjSP
SI
SI,[BP+04]
AL.AL
4A8A:003D 0AC0
OR
4A8A:003F 7408
JZ
0049
4A8A:0041 B40E
MOV
AH,0E
4A8A:0043 32FF
XOR
BH.BH
31
Clsing
4A8A:0045 CD10
INT
10
4A8A:0047 EBF3
JMP
003C
4A8A:0049 9D
POPF
4A8A:ee4A 5E
4A8A:0e4B 5D
POP
POP
4A8A:004C C3
RET
Assembly Language
in
MASM added quite a few instructions to the ones you wrote. The PUSH SI
and POP SI instructions should be clear since we said that MASM would save
and
quire
some
The BP
BP
is
is
The
SI.
explanation.
register
you look
USES
is
a special-purpose register
at the table
a little different
we have not
from other
said
segment
DS
register.
This
is
much
about. If
in registers.
So the instruc-
tion
SI,[BP+04]
MOV
from the
ister
is
stack,
even
if
SS
is
ister to access
which the
BP
register,
them on
you have
to set
DS
as
or
ES (which
Because the
BP regBP reg-
the stack.
it
of SP,
MOV BP,SP instruction does for us. But since the C procedure that
restore the
tions
BP
MOV
BP,SP
POP
BP
how
the stack
would look
The C call,
for a procedure,
left.
By pushing
the rightmost
423
Assembly Language
for the
\
parameter
first,
the
last,
first
be closest to the "top of the stack"; in other words, closest to SP. Doing so
means
paraml
that
will always
how
instruction created
by the write_string(
BP,SP
instruction.
the stack as
much
PUSH
MOV
re-
You
turn address onto the stack, at which point our procedure gains control.
MASM generates
all
registers,
and by
you do not have to concern yourself with writing these instructions in the correct
order.
The
first
same
at the
offset
is
for
SMALL memory model (it would be 6 for memory models that require a
FAR return address, since a FAR return requires both the old CS and IP valthe
ues to be
on the
stack).
Looking
at the
unassembled
listing above,
you
will
instruction into
MOV SI,[BP+4], see Figure 31-3. If you had used a memory model with FAR
procedures, this would be translated into MOV SI,[BP+6].
C passes parameters on the stack in the opposite order from most other highlevel languages. Pascal,
BASIC, and
BP
first,
FORTRAN,
with the
last
for example,
parameter
last,
push the
onto the
stack.
procedure
calls
This
is
first
offset
from
FORTRAN where
as
defined in the
procedure.
C procedures, however, you can pass more parameters on the stack than are
a good example. The
defined in the procedure. The C printf( function
In
is
pass to printf(
string.
first
To
to
depends entirely on
allow
in reverse order so
parameter will always be closest to SP, and not depend on the number
424
how many %
'~\
31
Stack
in
C and C + + Programs
High
memory
[BP+6]
Parameter 2
[BP+4]
Parameter
Stack grows
down in
memory
Return Address
SP
BP
Old
BP
Old
SI
value
value
Low
memory
Figure 31-2:
WRITE STRING
PROC
STRING:PTR BYTE
This
MOV
887604
SI,
STRING
is at
MOV
is
the
first
parameter, which
[BP+4]
SI,rBP+4]
425
Assembly Language
for the
is
useful in
your
programs.
Listing
GOTO_XY
X:WORD, Y WORD
PROC
MOV
AH, 2
MOV
BH,0
MOV
MOV
INT
10h
Display page
RET
GOTO_XY
ENDP
Listing
to use goto_xy(
):
main(
{
clear_screen(
goto_xy(35,ie);
write_string{ "This is
string!");
There
are
two items of
interest in
goto_xy(
).
First,
cedure
call:
goto_xy(x,
you
we wrote them
we
in the pro-
MASM
handles the differences in order on the stack so you don't have to change your
426
31
code, or
to
do
The
is
know what
other change
is
Assembly Language
in
C and C + + Programs
order parameters are pushed onto the stack. All you have
Y to be words,
CJsing
a bit
in the
more
Pascal.
subtle.
languages, never push a byte onto the stack, they always push words onto the
stack.
onto the
PUSH
is
bytes,
move
instructions
DL,X
MOV
error. Instead,
you have
to
BYTE PTR X to access X as a byte. But this does not always work in MASM.
following
at the
DH.BYTE PTR Y
MOV
Although
MASM
this line
5 because
mented before
works correctly
in
MASM 6,
it
MASM 6.
line:
definitions in
book, are a way to add features to the assembler by substituting text for
this
when you
macros. So
write
If you
put
BYTE PTR
know how
BYTE PTR X
You can
and Y,
is
text de-
does not
fix this
in front
of this, you
will get
to handle, as follows:
X and Y, which
the assembler that [BP+4] refers to a word, but you wish to treat
tells
it
as a
byte:
The
parentheses simply
parentheses
for
first.
we will
MASM 6.
427
Assembly Language
for the
In addition to writing
want
to write
is
(two words) in
DX:AX, with
the low
word
in
AX.
If you
want
to return types
with 3 bytes or more than 4 bytes, you will need to consult the Microsoft Macro
Assembler Programmer's Guide, or the Turbo Assembler User's Guide '[or
Here
Byte
AL
Word
AX
Long
DX:AX
The
programs:
31-7 Add
tiiis
details.
CLIB.ASM,
is
a rewrite
of
programs.
procedure to CLIB.ASM.
PROC
READ_KEY
XOR
AH, AH
INT
16h
OR
AL.AL
JZ
EXTENDED_CODE
;Yes
XOR
AH, AH
JMP
DONE_READING
NOT_EXTENDED:
EXTENDED_CODE
MOV
AL,AH
MOV
AH,1
DONE_READING:
RET
READ KEY
428
ENDP
31
Listing 3 1 -8
the center,
Listing
is
a version
and wait
of test. c that
you
until
in
back to
DOS.
niain(
{
clear_screen(
goto_xy(35,10)
!=
')
'
Using Other
All of the
and
all
Memory Models
In the
a single data
the data
is
in the
segment pointed
to
are
NEAR calls
by DS.
all calls
for either
to
code or data,
work with
these other
how do
memory
models?
The
is
easy,
is
hard.
easiest
to first
will find
memory
models.
429
Assembly Language
for the
memory models
DS
Model
Calls
Data
TINY
Near
Near
DGROUP
SMALL
Near
Near
DGROUP
COMPACT
Near
Far
DGROUP
MEDIUM
Far
Near
DGROUP
LARGE
Far
Far
DGROUP
HUGE
Far
Far
DGROUP *
Pointers
NEAR calls are the same as all the calls you have seen so far. All of the procedures are in a single segment, so
ing the
CS
register.
all
without chang-
On the other hand, FAR calls are used when you have more
in C, since they often have
is
needs both an offset and a segment value for the ftinction you
both CS:IP).
stack.
Along with
The same
grams written
in
actually a
but
this
group called
NEAR data is
DGROUP
limited to
64K
offset
and a segment,
430
pro-
as
you
segment which
in size.
both an
Many
C use more than 64K of data, which means they need to use
31
Clsing
C}
Assembly Language
in
C and C + + Programs
memory models
Model
Code
Data
TINY
_TEXT
SMALL
_TEXT
DGROUP
COMPACT _TEXT
MEDIUM
filenamej:E)(.T
DGROUP
LARGE
filenameJTEXJ
HUGE
filename_TEXJ
In
DS
DGROUP
Note
NEAR pointers and references. (NEAR data is any data you define with
.DATA or .DATA?.)
such
ate
as the
your
However, there
are cases
NEAR variables.
DGROUP.
we
will
You can
assume that
DS
CALLs and
pointers.
points to
In this chapter
When you
assembly-language subroutines,
it
must be built
if you
it
for
If you
link
some
small
model assembly-language
FAR CALLs, which means that the NEAR returns in your assembly-language
subroutines won't return properly to your
restores the IP register,
CS
program since
NEAR return
register.
431
Assembly Language
to
do
Writing
is
you
will
memory
have to deal
Switching between
are using
your
files,
is
memory model that you have specified. If you wanted to rewrite all of the
functions in CLIB.ASM for the medium model, you would change the first
line of CLIB.ASM to read the following:
.MODEL
MEDIUM, C
Working with
Working with
all
RETF
as
you
have done until now, that the data will be in the segment currendy pointed to
by the
you
have to use slightly different code than before. For example, the code you have
in write_string(
to retrieve a pointer to
from DS:SI)
SI, STRING
MOV
However,
in the
is
STRING in SI
LDS
LDS
MEDIUxM
You will
model.
;Place address into SI for LODSB
SI, STRING
stands for
LODSB instruc-
as follows:
(the
To
see
it
how
this
works,
DS
register
let's first
and an index
look
at the
432
reg-
machine
EXE
file
31
at
CJsing
CJ
you
Assembly Language
LDS
in
instruction appears as
follows:
SI,[BP+06]
LDS
DS
STRING
register, as well as
the
is
The
loaded by
LDS
register as the
There
is
first
register that
loaded by
FAR pointer
LDS
LDS
into
represented by
is
uses).
DS. In
it
non-segment
STRING
into DS:SI.
is
name
is
second
segment value,
loads the
register.
stack.
on the
an index
DS because it changes
LDS
change the
it
WRITE_STRING
PROC
SI
SI
DS
and DS.
Now we will show you another example that is a little trickier. Say you have a
procedure that takes a pointer to an integer that has the following C definition (we will write the procedure in assembly).
some_func(int *number)
The
SMALL,
.CODE
some_func(int *number)
SOME_FUNC
PROC
MOV
ex, NUMBER
MOV
[BX],10
RET
SOME FUNC
ENDP
433
Assembly Language
for the
1
NUMBER
Since
is
a pointer to the
itself,
you need an
extra step.
The
first
this address.
In the
.MODEL
this
as follows:
LARGE,
.CODE
some_func(int *number)
SOME_FUNC
PROC
LES
BX, NUMBER
MOV
ES:[BX],10
RET
SOME FUNC
You
ENDP
we used the LES (Load ES) instruction inLES and LDS work in the same way, except that LES loads ES:reg
stead of LDS.
while
ES
causes an extra
you do need
register
The
last case
we
DS
will cover
to include
in
segment.
is
When
you
are
NEAR data, you can simply refer to the name of the variable. For
to load NUMBER into the AX register, you will use the following
dealing with
example,
instruction:
MOV
AX,
NUMBER
BER, but
this
may
DS
not be the
case.
Most compilers (C
DS
always points
as well as
to,
than
64K
and
if
other lan-
this
segment
434
NUM-
will
DS won't
31
in
C and C + + Programs
point to the segment that contains your global variable, so you will have to set
MOV
AX,
MOV
ES, AX
MOV
AX,
The SEG
ES: NUMBER
it
segment of a
When
variable.
the assembler
number since
when you only have a single data segment. However, this code is
a single move statement, since you have three move statements.
The
slower than
80486), so
it is
a very quick
command. However,
this
Note
same command is
80386 and 9
command
bottom
Chapter 33,
this
The
line
is
cycles
that as long as
is
you
very
are
will see in
working with a
DOS program,
the
fast.
Table 31-3 summarizes the different types of code you need to read different
types of
parameters.
parameters
C Parameter
char c
mov
mov
int
number
al,Byte Ptr c
mov ax,number
al,Byte Ptr c
mov ax,number
(default data segment)
435
Assembly Language
for the
C Parameter
int far
int
number
*number
N/A
mov
ax, seg
mov
es,
ax
mov
ax,
esmumber
bx,number
lea
mov
bx,number
les
mov
bx, [bx]
number
bx,es:[bx]
memory models.
Fortunately, there
that
for
any
is
for a
memory model
if you
number of dif-
write subroutines
.MODEL directive at the start of the file. The trick uses something known as
conditional assembly.
With
conditional assembly you can have two versions of code that will be as-
test.
this
is
is
good candidate
would
for
write to handle
as follows:
IF
@DataSize
LES
BX, NUMBER
;Yes,
MOV
ELSE
load BX with address
MOV
BX, NUMBER
;No,
MOV
[BX],10
;Change value at BX
ENDIF
The
IF,
ELSE, and
ENDIF
directives allow
have
436
NEAR pointers;
otherwise,
you
@DataSize
is
to control
a special
When @DataSize
FAR pointers.
you have
which code
will
0,
it
means you
31
Although
this
well,
it
much more
looks
is.
you want
To
see
time
rather than
will
we will
use
it
to define
it
We
some
two
want
of
sets
of assembly-language
you
will use
IF
two
you
complicated than
Progranns
to refer to a pointer.
we
C and C++
LES
this
in
for creating
@DataSize
lodDS
TEXTEQU <LDS>
;Yes,
lodES
TEXTEQU <LES>
refES
TEXTEQU <ES:>
in front of refs
ELSE
lodDS
TEXTEQU <MOV>
;No,
lodES
TEXTEQU <MOV>
refES
TEXTEQU <>
ENDIF
are using.
lodES
BX, NUMBER
MOV
refES [BX],10
This
rent
is
and
it
on the
cur-
memory model.
directive
very much like
a directive new to MASM 6. It
EQU directive you learned in Chapter 14. EQU allows you to assign numeric values to a name; TEXTEQU allows you to assign text values to a name.
The brackets (< and >) in a TEXTEQU delimit the text that will be substituted whenever MASM sees the name, such as lodDS, that you have defined.
The TEXTEQU
is
is
the
437
Assembly Language
The
final step
to take
to use another
is
TEXTEQU macro to
fi^om the ML command line. You can deMASM starts to assembly your program by using the
memory model
following syntax:
ML /C /DLANG_MODEL=LARGE CLIB.ASM
Your
.MODEL
To use a different memory model, simply change the LARGE on the ML command line to any of the other names for memory models.
Table 31-4 summarizes the syntax you
macros
in Listing 31-9.
C Parameter
Model-Independent Code
char c
mov
al,
mov
ax,
int
number
Byte Ptr c
number
number
mov
ax, seg
mov
es,
ax
mov
ax,
es:number
number
*number
mov
438
C parameters
31
CJsing
Assembly Language
in
Assembly
in
and
1
steps
you
will
want
to use.
can change
is
list
freely.
Parameters:
You can
access
all
in the
directly
PROC statement.
by
The
on the
stack,
that uses
to
which
Huge model
global variable
register
by
by moving
4.
Far
first
is
NEAR segment,
is
DS
in another segment,
in
you
will
C Pointers/Data:
most
register
5.
need to
set the
ES
if
and then
ES.
If you are
global variables that are not stored in the default data segment,
will
for
register so
it
you
like in
assembly-language subroutines,
DX:AX registers
for
and
FAR pointers.
439
Assembly Language
for the
Writing In-line
Assembly Code
The final subject we will cover in this chapter is in-line assembly. Most C and
C++ compilers allow you to write code directly in your C files, rather than
requiring
you
to write separate
ASM
files
to
to
your
programs.
The
syntax you will need to use varies very slightly between Borland's
Turbo
C++, Microsoft's QuickC, and Microsoft's C++ compilers, but only by some
underscore characters. Each compiler has a special keyword that indicates when
you "turn on" assembly language mode. For Borland, you use asm; for
Microsoft's QuickC compiler you use _asm; for Microsoft C/C++ 7 you use
asm.
The
result
is
mostly a
The C language began without any real standards, so differown private keywords (such as asm and _asm).
of histor)'.
However, there
is
ANSI C
standard.
The ANSI committee now "allows" compiler writers to add their own,
keywords
as
long
as
compiler we used in
we
will rewrite
as in
private
asm. For
GOTO_XY as
A C version
of
GotoXY
Microsoft C:
31-10
Listing
GOTO_XY using
in-line
assembly.
void GotoXY(
int X,
//
X coordinate,
0. .79
int y
//
Y coordinate,
0. .??
//
//
_asm
{
440
mov
ah, 2
mov
dl
Byte Ptr X
in
31
mov
dh,
int
10h
in
Byte Ptr y
//
asm in Microsoft C/
You use asm, rather than _asm, in Borland C++; and
C++ 7. What you will notice about this new subroutine is that it is a mix
between
An
assembly-language code
is
C subroutine, and some C references are inside the assemblyNow let's look at the code actually generated for GotoXY for
language code.
the
PUSH
BP
MOV
BP.SP
PUSH
SI
PUSH
DI
MOV
AH 02
MOV
DL,[BP+06]
MOV
DH,[BP+08]
INT
10
POP
DI
POP
SI
MOV
SP.BP
POP
BP
RETF
You will
X and Y parameters
stack, at offset
is
[BP+06], which
the
refers to a value
it is
up
that
little
the
on the
MASM would
file.
all
ables
as
you
the data
are
working with
(TINY, SMALL,
global variable.
An
is
memory model
MEDIUM),
very easy:
that uses
NEAR pointers
x:
the
is
name of the
as folows:
441
Assembly Language
for the
//
main(
//
//
//
int
>
asm
{
mov
ax,
In other words, you can reference the variable directly by name, and everything works without any problems because the variable x is in the default seg-
ment,
DGROUP,
LARGE, HUGE)
DS
and the
in
its
the
DS
to set a
segment
value in
its
register
register
if you
may not
it
may be placed
(ES
is
from
x[0]
and
An
x[l]
is
as follows:
mainO
//
//
30000
x[
change
//
int
to
you how
DGROUP.
register points to
_asm
{
Let's
mov
ax,
seg X
//
mov
es,
ax
//
Set ES so it points to x
mov
ax,
es:x
//
Read x[0]
mov
bx,
es:x[2]
//
Read x[l]
look
loads the
X.
The
two
at this
program
in detail.
first
ES
register so
it
The
last
then read two values from this array. Each of these two instructions
442
assembly-language instruction
AX register with the number of the segment that contains the array
lines
The
to
by DS.
this array.
to
The X[2]
actually reads
31
The 2
we wrote
2 bytes),
is
here
is
is
an
offset, in bytes,
in
element
1.
When you write in-line assembly code that reads either pointers or global variables,
with
either
it
works
just
NEAR or just with FAR pointers, or you can write general-purpose code
ES
you
will
but the
and
data. If you
fastest code),
want the
when you
code
memory
NEAR
language macros in the previous section, to generate the correct code based on
memory model.
the current
Summary on
Assembly
In-Line
Register Usage:
all
the details):
The same
assembly are
Parameters:
You can
access
the form [bp+x] for you; this will refer to the parameters stored
stack
3.
on the
Local
name. All
access
any
local
on the
C variables directly by
stack, so the
compiler will
4.
address
on
Global
refer to
memory model
that uses
NEAR pointers
443
Assembly Language
or
for the
when
(which
is
However,
if a
global variable
is
in
another segment, you will have to load the ES register using the
method shown
5.
Far
above.
If you are
Pointers/Data:
global variables that are not stored in the default data segment,
will
6.
need to
set the
ES
register so
it
offset in
7.
for
in-line
and
use either
need to return an
will
or assembly-style
for Char,
FvVR pointers.
^AL
DX:AX registers
C
AX for Int,
in assembly-language subroutines,
DX:AX for
you
C++
comments
inside
you must
use
comments.
Summary
That wraps up our coverage of using assembly language
in
grams. In Appendix C, and on the disk included with this book, you will find
all
want
you
are using.
for the
assembler and a
444
may
you
will
MASM
or C++,
be differences
if you are
31
The
in
code
in
445
H^l
DISKUTE, a
RAM-Resident
Program
In
this
Disklite.
letter in
Disk
file:
DISKLITE.ASM
Topics Covered
RAM-Resident Programs
Intercepting Interrupts
Disklite
Assembly Language
for the
RAM-Resident Programs
RAM-resident programs are almost always written
maximum
The
ROM
access to the
Disklite
program you
to
weighs in
at just
247
bytes.
and
since
size
large, users
is
is
is
too
the whole
point.
ROM BIOS or
how existing functions work, or to
example, watches the ROM BIOS routines
Disklite, for
to disks so
it
screen.
Many programmers
like to
light
much else you can do. Programmers also like to watch the disk
light when they are testing programs that read from or write to a disk to
is
not
are accessing.
if you
place your
an on-screen drive
you
Intercepting Interrupts
As we mentioned above,
BIOS
is
performed by the
issuing an
INT
INT
13h
memory
is
to
as
you saw
in
Chapter
448
ROM
and writing
by watching the
it
holds the
INT
11, use a
call.
Each
FAR address
13h instruction
will
32
INT 3h
1
4) in
memory
as the address
ROM
of the rou-
BIOS's routine.
ROM
BIOS.
Now
imagine that you changed the interrupt vector to point to your procedure.
Then
control of the
INT
INT
INT
13h did,
calls
this
is
new
as well as the
to
is
What
BIOS INT 13h
ROM
routines.
low
In
memory
ROM
BIOS
INT
Figure 32-1:
routine to
0000:0000
INT
0000:004C
13
INT 13h
own program
tines
by simulating an
stored
to
first,
INT 1 3h
vector,
you
4Ch
call.
your
like a
vector
you can
INT
pass control
instructions as follows:
13h routines
on
to the
instruction. All
in the variable
you need
to
do
is
save
ROM_DISKETTE_INT,
Assembly Language
for the
PUSHF
ROM DISKETTE INT
CAL
When the ROM finishes accessing the disk, you will receive control again. This
means you can execute some code before, as well as after, you call the ROM's
disk ftinctions. This
remove, a drive
is
letter.
exactly
INT
^3\^
JC
DISK
if you are
detail.
INTERCEPT_DISKETTEJNT
entry code
ROM DISKETTE
ERROR
INT
END
ROM
BIOS
Disk
Services
Figure 32-2: Intercepting INT 13h.
But there
system,
is
DOS
DOS
function
is
calls
certain
some
difficult, so
ser-
in this book.
this,
but
However, you
chapter.
Disklite
Most of the other details of Disklite should either be familiar or documented
well enough so you can figure them out. There are a few details, however, that
are new or a bit out of the ordinary.
450
32
of
First
all,
we
notice that
of Disklite. Instead,
then
save
all
minimum.
much
and there may
else's
large
enough
13h
request.
stack
when we
You
get an
can-
INT
stack.
The procedures
WRITE_TO_SCREEN
should be
fairly
clear.
You have
seen
GET_DISPLAY_BASE before; the other two should be clear from the last
SAVE_SCREEN saves the two characters in the upper-right corner;
chapter
and
to restore
two characters that were on the screen before you displayed the drive
the
letter.
DISPLAY_DRIVE_LETTER
number
A:,
in the
DL register.
leaves
INlT_VEGTORS
INT
13h takes
a drive
drives,
disks,
hard disk, you subtract 80h and then add the number of
you with
interrupt vector
That
is
first
INIT_VEGTORS
shows the
details
and
floppy disk.
GET_NUM_FLOPPIES.
DOS. First you display an author message, and then you call
GET_NUM_FLOPPIES to set NUM_FLOPPIES to the number of floppy
to
INT 21h
flinctions
that read
set the
and
INT
13h
set interrupt
vectors.
You
Disklite.
As
it
we put both
end of
when we
451
Assembly Language
for the
memory
first
after
you load
ftinction call
Disklite.
INT 27h,
This
is
it
why we
to
in
memory
The DOS
keep them in
so
call
your program
takes an offset
points to
except ^or
as
much initialization code here as you want without it consuming any memory
You can
use the
on
run
disk.
ML
this
on the very
it,
installed.
file
run
been
appear
will
To
drive.
test
Usting 32-1
DISKUTE.ASM Program
(Disk
file
DISKUTE.ASM)
In
other words, it does not stay on while the disk spins without any
activity.
This program intercepts the INT 13h vector, which is the entry point
for the ROM BIOS'
diskette routine.
's
entry point.
SEGMENT
CODE_SEG
452
ASSUME
CS:CODE_SEG, DS:CODE_SEG
ORG
100h
32
BEGIN:
INIT VECTORS
JMP
AUTHOR STRING
DB
DB
0Dh, 0Ah,
DD
DISPLAY_BASE
DW
OLD_DISPLAY_CHARS
DB
4 DUP
DISPLAYCHARS
DB
'A'
NUM FLOPPIES
DB
UPPER LEFT
$'
(?)
70h,
70h
EQU
diskette I/O
1.
in the
4.
INTERCEPT_DISKETTE_INT
Assume
PROC
FAR
PUSHF
PUSH
AX
PUSH
SI
PUSH
DI
PUSH
DS
PUSH
ES
CALL
GET_DISPLAY_BASE
CALL
SAVE_SCREEN
CALL
DISPLAY_DRIVE_LETTER
POP
ES
POP
DS
POP
DI
POP
SI
453
Assembly Language
for the
AX
;Restore the old flags
POPF
PUSHF
ROM_DISKETTE_INT
CALL
PUSHF
PUSH
AX
PUSH
SI
PUSH
DI
PUSH
DS
PUSH
ES
LEA
SI OLD_DISPLAY_CHARS
CALL
WRITE_TO_SCREEN
POP
ES
POP
DS
POP
DI
POP
SI
POP
AX
POPF
RET
ENDP
i
This procedure calculates the segment address for the display adapter;
that we re using.
'
Destroys:
AX
PROC
GET_DISPLAY_BASE
Assume
NEAR
INT
11h
AND
AX,30h
CMP
AX,30h
MOV
AX,0B800h
JNE
DONE_GET_BASE
MOV
AX,0B000h
DONE_GET_BASE
MOV
DISPLAY_BASE,AX
RET
454
ENDP
32
Destroys:
AX,
SI,
PROC
SAVE_SCREEN
DI,
DS,
ES
NEAR
Assume
MOV
SI,UPPER_LEFT
LEA
DI ,OLD_DISPLAY_CHARS
MOV
AX,DISPLAY_BASE
MOV
DS.AX
MOV
AX, OS
MOV
ES,AX
CLD
MOVSW
MOVSW
RET
ENDP
SAVE SCREEN
This procedure displays the drive letter in the upper-right corner of;
the screen.
Destroys:
AX,
SI
DISPLAY_DRIVE_ LETTER
PROC
NEAR
Assume
MOV
AL,DL
CMP
AL,80h
JB
DISPLAY_LETTER
;No,
SUB
AL,80h
AL,NUM_FLOPPIES
ADD
DISPLAY_LETTER
then continue
ADD
AL, 'A'
LEA
SI,DISPLAY_CHARS
MOV
CS:[SI] ,AL
CALL
WRITE_TO_SCREEN
RET
ENDP
455
h9
Assembly Language
for the
On entry:
CS:SI
Destroys:
AX,
DI
SI,
WRITE_TO_SCREEN
Assume
ES
DS,
PROC
NEAR
MOV
DI,UPPER_LEFT
MOV
AX,DISPLAY_BASE
MOV
ES.AX
MOV
AX,CS
MOV
DS,AX
CLD
MOVSW
MOVSW
RET
ENDP
WRITE TO SCREEN
INIT_VECTORS
Assume
456
PROC
NEAR
CS:CODE_SEG, DS:CODE_SEG
Print out the author notice
LEA
DX,AUTHOR_STRING
MOV
AH,
INT
21
CALL
MOV
AH,35h
MOV
AL,13h
INT
21h
MOV
MOV
MOV
AH,25h
MOV
AL,13h
MOV
INT
21h
32
MOV
DX, Offset
INT
27h
INITVECTORS
ENDP
INIT VECTORS
This procedure determines how many logical floppy disk drives are in
the system.
The next drive letter will be used for hard disk drives.
6ET_NUM_FL0PPIES
Assume
PROC
OS: CODE SEG,
INT
11h
MOV
CL,6
NEAR
DS:CODE SEG
;Get the equipment flag
SHR
AX.CL
AND
AL,3
INC
AL
;Returns
CMP
AL,1
JA
DONE_GET_FLOPPIES
;No,
MOV
AL,2
;Yes,
for
floppy
DONE_GET_FLOPPIES:
MOV
NUMFLOPPIES.AL
RET
GET NUM FLOPPIES
ENDP
ENDS
CODE SEG
END
BEGIN
457
r~r~i c nrrATFfr
Protected-Mode
and Windows
F>rogramming
In this chapter you will learn the concepts needed to write programs that work
in protected-mode environments, such as Microsoft Windows. We will then
show you how to write code to test pointers to make sure they are valid, and
then show you how to write code to take special advantage of the 80386 instructions in your Windows programs. Please note that you must use MASM
to assemble the
WINLIB.ASM
file
in this chapter.
Topics Covered
What
Is
Protected
Working
in
Mode?
Windows
Summary
Assembly Language
for the
What
Protected
Is
a special
mode on
Mode?
the
80x86
that
designed to provide
is
DOS
seen in the
memory. However,
divide
in
memory into a number of separate chunks and the access rights for these
it
Windows is discussed,
could be.
which
ters
is
by looking
both very
and very
much
different
to
when
memory,
to.
First let's
and limitations
IBM PC
at
are.
address one
in the
this
have learned in
They can
this
book.
80x86
do
suppon protected-mode programs. The original reason for adding the protected
mode to
the
80286 was
to support
than 16
When
making
all
to extend the
the segment
bits. Intel
to allow
plans.
Intel
460
there
with, short of
to develop
IBM PC
not
DOS, was
the
wave of the
ftiture.
33
So
Intel
Windows Progrannming
8088
as a taster
manage
large
DOS
for the
one was
also
UNIX where a program can crash without causing other programs to crash
like
(Windows
As we
all
know,
DOS
all,
of this protection).
and
in operating systems,
UNIX
never
came
Windows,
along.
Addressing Extended
Memory
Table 33-1 shows the amount of memory you can use with the current microprocessors in the
80x86
family.
As you can
see, all
Table 33-1
8088
Memory
Protected
*
Mode
The 80386sx
companies
Mb
is
No
limited to
to use the
the
Mb
No
16 Mb,
80386 rather
8086
80286
Mb
16
Yes
rather than
80386sx*
16
Mb
80386dx 80486
4
Gb
Yes
Yes
Gb. In order
Size
to
make
it
easy for
Gb
Yes
computer
than the 80286. Intel built the 80386sx, which only has
80286 does.
The first change we will look at is how the meaning of segment registers changes
when you switch to protected mode. In normal mode, which is called real mode.
461
Assembly Language
you can
for the
much more
contain
and
much
The hidden
memory
dressing extended
part
where
is
all
is
16
the
bits long,
work of ad-
takes place.
8 bits
16 bits
24
bits
16 bits
-MM
'
80286
Access
Rights
Base
Address
Limit Size
(bytes)
(bytes)
Segment
I
80386
-WN 32
-WM-
24
16 bits
Visible part of
I
segment
register
You will
32 bits
bits
bits
registers
its size,
rights.
notice that the hidden part of the segment register contains the actual
base address of a segment, measured in bytes rather than paragraphs (16 bytes).
On
16,772,216, or 16
24
bits
462
is
33
The other nvo pieces, access rights and the segment Hmit size, provide some oi
the protection features we mentioned above. Each segment in protected mode
has access rights that control whether
right to read
from a
seg-
size,
to,
the
memory
80x86 generates
own
program attempting
Windows
GPF
3.1,
known
you have
al-
(general-protection fault),
to read or write
how do you
memory that
it
GPF).
The
question, then,
how
does the operating system determine which segments you can and can-
is
one or more
tables
The answer is
80x86 contains
that the
tables.
assign a value to a
number,
segment
up the
access rights in a table called the descriptor table (see Figure 33-2)
table
is
a table that
mode, you
actual address
.
and
The descriptor
memory.
The operating system sets up the descriptor table and uses a special protectedmode instruction to tell the 80x86 where to find this table (there are actually
two instructions, called LGDT and LLDT, which stand for Load Global/
Local Descriptor Table). The hidden part of each segment register is loaded
with the values the 80x86 finds in the descriptor
The 80x86
is
allows
you
to have a
uses to
have
table.
manage its own private memory. In theory, each program you run should
its
own
all
Windows,
programs share,
which means Windows programs do not have the kind of protection from each
other that they
would have
if
table.
463
Assembly Language
for the
Segment Register
Selector
Selector
^H^^^^^^^l
A
w
w
KiHHM^I
Descriptor
Table
Figure 53-2:
When you
selector table to
table has a
ments
at
It
it
many
this
in the
the
it
to be a
problem
for
most
call
indicate
tell
GlobalAlloc for
Since
the
Windows
programs.
register,
Each descriptor
is
load a segment
used for?
which descriptor
It
table
what
(local or global)
and
also privi-
ways get them from GlobalLock or a similar function), the actual values
these bits aren't very important to
you
as a
in
programmer.
or whatever
protected-mode operating system you are using, can move your memory around
memory,
all it
has to do
Your application
will
464
is
selector as if it
table.
were a segment,
33
Working
look
Let's take a
be very
at
you write
plain
difficult, if
sume here
that
written
Windows programs
For our
first
(2
it.
example,
in
in
In the
when
it
tected
mode
would be
since
is
if
you
offset)
is
legal.
is
done by looking
if it is
GPF
if
the selector
is
not
valid, or
ex-
(Windows
we won't
the segment
to
C.
if
are times
Windows Programming
Windows
in
whose names
start
Windows
3.0.)
There
if it is
are
The LSL
instruction allows
you
by looking
Let's start
you
allows
land
C program
will find in
you
to display
at the
VERR instruction
to test
VERR.
This small
how
to write simple
Windows programs
EasyWin. The
test
works.
We will
uses a fea-
C compilers, which
programs
it
program
test
calls it
to see
function
in this section
all
use printf(
to
465
;
(
Assembly Language
for the
select the
in this dialog
box.
VERR instruction
The
tor. If
the
the selector
is
a valid selector
VERR instruction
word and
it is
otherwise
it
Windows, with
lector to see if
which
The
is
valid:
#include
<windows.h>
#include
<stdio.h>
main(
{
BYTE huge
IpNum;
valid;
int
IpNum = (LPBYTE)
valid =
_asm
(5
65536);
-1
//
-1
//
//
verr
jz
doneCheckl
//
mov
valid,
//
No,
doneCheckl
if
(valid)
printf
'Pointer is valid\n")
printf
'Invalid pointer\n'"
else
)
return 0;
This program
is
So you have
instruction. If
466
The problem is that the VERR instrucbut C programs work with variables in memory,
repon whether
a se-
VERR sets
JZ
33
You will
If
notice that
you wanted
to check a
this code,
with a different
it is
valid.
Such
label,
//
//
//
//
//
valid.
//
//
//
//
Returns:
-1
//
//
//
//
//
BOOL ValidPtr
//
mov
ax,
//
verr
//
jnz
doneTest
//
No,
not
ax
//
_asm
{
-1
doneTest:
This function does exactly what the in-line code in our previous example did,
except that
it's
now
a function.
You
We mentioned
turn word values in the AX register.
value in the
AX
register.
in
Chapter 3 1 that
functions re-
The
far pointer.
test
As long
as the selector
pens
if
the selector
is
is
invalid, the
is
far tested
we do
In this case
size
using the
up
467
Assembly Language
for the
you have a
AX,
Adding one
SI.
For example,
you can
address:
SI
to this
By putting this
ment.
size.
#inclucle
<windows.h>
#include
<stdio.h>
is
valid,
test
and
program
if it
is, it
follows:
BOOL ValidPtr(
void FAR *lp,
//
WORD cwSize
//
mov
ax,
//
verr
//
jnz
doneTest
//
No,
not
ax
//
doneTest:
7
7 This function returns the size
7 pointer.
7
The size,
size
7 Returns:
7
468
in bytes,
of a segment
-1
33
DWORD SegSize(
void FAR "Ip
//
//
i = 0;
DWORD
Isl
//
mov
Word Ptr
//
Save size in
//
//
-1
i,
ax
i++;
return
i;
main()
{
HANDLE hmem;
BYTE huge
IpNum;
valid;
int
hmem = GlobalAlloc(GMEM_MOVEABLE,
10L);
if
(ValidPtr(lpNum))
printf( "Pointer is valid\nSize = %ld", SegSize(lpNum)
else
printf( "Invalid pointer\n");
GlobalUnlock(hmem)
GlobalFree(hmem)
return 0;
}
When
you run
this
program,
it
Pointer is valid
Size = 32
The size returned by this function is actually a little larger than the chunk of
memory you asked for ( 1 bytes) because Windows always returns chunks of
memory that are a multiple of 32 bytes in size.
469
Assembly Language
There
is
for the
problem with
ment you
allocate
from
this
OL
to
size
of the seg-
66000L.
Then run
SegSize(
this
program
now
in
returns the
wrong
that
size.
Pointer is valid
Size = 480
To
understand why,
we
first
need to look
at
how Windows
normally works
but unlike
offset,
far pointers,
ES
huge pointer,
it
pointer and
it
word from
loads the
a far pointer
LES
BX,
farPtr
MOV
AX,
ES:[BX]
register
might appear
they can
(selector) part
BX register,
work
memory using a
of the
as follows:
The interesting part, however, is the code that handles array indexes or adding
a number to a pointer. When you are dealing with a far pointer, these operations simply change the value of the offset. But with huge pointers, you may
need to change both the offset andi\i& segment
memory chunks
lector.
larger than
64 Kb
(selector) value. In
other words,
se-
For example, you would need 4 selectors for 200,000 bytes of memory
(3 *
65536 = 196,608,
you
call
creates
so
you need 4
selectors for
200,000
bytes).
4 contiguous
selectors to access
all
So when
Windows
first
selector gives
next GA
ary,
than
because the lower three bits should not be changed since they are
re-
470
33
knows
that the
Windows Programming
when you
larger than
64 Kb
Windows creates 4 contiguous selectors, just as you and your C/C++ compiler
would
expect.
But the
first
have a limited
size
that
you
memory
The second
of 199,999
chunk of
199,999
J 4th Selector
196,607
3rd Selector
131,071
2nd Selector
65,535
St Selector
J. 200,000 bytes
how
a large GbbalAlbc
memory allocated.
on
80386 or
better processor?
AX
is
the 16-bit
471
Assembly Language
for the
version of AL,
in front of
can add
ADD
to a 32-bit
EAX,
registers
number by using
at least the
first tell
it
assembler allows only 8088 instructions to ensure that your programs will run
on any
DOS
computer).
You
turn
on 80386
SMALL,
.MODEL
.386
Now you
larger than
if it's valid,
In this section
size
We
as
of a segment, and to
work
correctly in
you
and
also
offset.
cases
all
you can
and the
selector
II
of a segment
of subroutines in
how
64 Kb. Following
is
The
follow-
to use these
you
get
when
33-1.
Selector
200000
size
==
size
==
134464
Selector 2 size
==
68928
Selector 3 size
==
3392
Selector
Invalid pointer
When
flects
the
amount of space
in
to the
allocated. This
is
very
that
work with
single segment.
472
large
chunks of data
You can do
this for
(larger
two reasons:
first,
Windows
sets
up the
33
selector so
first
GlobalAlloc
EBX
register
used so
far.
^// of the
memory you
Windows Programming
call;
with 32-bit
of the usual
offsets instead
file
6-bit offsets
in Listing 33-2,
you have
MASM6.
Listing
33-1 WINTEST.C:
#include <stdio.h>
BOOL
niain(
{
HANDLE hmem;
BYTE huge
IpNum;
DWORD Size;
int i;
hmem
for (i = 0;
i < 4;
i++)
size = SegSize(lpNum)
i,
SegSize(lpNum)
IpNum += 65536L;
}
if
else
printf( "Invalid pointer\n");
GlobalUnlock(hmem)
GlobalFree(hmem)
return 0;
473
Assembly Language
for the
Listing
if it
is
This file contains the following functions that you can call from
C:
.MODEL
BOOL
BOOL
SMALL,
.386
.CODE
The 80286 processor always clears the upper four bits when it
transfers
80386 and above do not, which is how we can tell when we have an
80286.
Returns:
Is286
proc
ZR
NZ
80386 or above
private
Put flags onto the stack
pushf
pop
ax
or
ah,0F0h
push
ax
popf
pushf
pop
ax
and
ah,0F0h
ret
Is286
474
endp
33
Windows Programming
long
SegSize proc
call
IS286
ie
SegSize286
movzx
Isl
eax,
inc
eax
mov
edx,
eax
shr
edx,
16
jmp
doneSegSize
SegSize386:
ebx
Add
SegSize286:
Set upper word to
xor
dx,
mov
Isl
ax,
bx
add
ax,
Add
adc
dx,
dx
Propagate carry to dx
doneSegSize:
ret
SegSize endp
This function is
Returns:
AX
-1
ValidOffset
INVOKE
Valid offset
proc
SegSize, Ip
cwSize
sub
ax,
sbb
dx,
or
dx,
jmp
IsValidOffset
Propagate borrow
dx
Is segment > 64 K?
Yes,
475
Assembly Language
Listing
for the
33-2 continued
Word Ptr Ip, ax
cmp
InvalidOffset
ja
Yes,
IsValidOffset:
xor
ax,
not
ax
Return TRUE
imp
DoneValidOffset
ax
InvalidOffset:
xor
DoneValidOffset
ax,
Return FALSE
ax
ret
ValidOffset
endp
And if so, it makes sure you can read at least cwSize bytes
starting at *lp.
ValidReadPtr
proc
verr
jnz
InvalidReadPtr
No,
INVOKE
imp
DoneValidReadPtr
Return FALSE
InvalidReadPtr:
xor
ax,
ax
DoneValidReadPtr
ret
ValidReadPtr
endp
starting at *lp.
BOOL ValidWritePtr(void FAR *lp, WORD cwSize);
476
33
ValidWritePtr
proc
Windows Programming
lp:Ptr, cwSize:Word
verr
jnz
InvalidWritePtr
No,
INVOKE
jmp
DoneValidWritePtr
Return FALSE
InvalidWritePtr:
xor
ax
ax,
DoneValidWritePtr
ret
ValidWritePtr
endp
end
There are
few things in
this
need to
The
call this
the processor
by Robert
80x86
L.
is
PC Magazine Programmer's
The
if
is
the Is286
First,
be available.
Hummel, which
is
book we know of on
the
processors.
special directive
may
added
to
be
new
using the
you
is
the
we wrote SegSize
to
its
INVOKE directive.
it
very easy to
call a
This
is
high-level
it
was
easiest to call
it
assembly-language instructions that push the correct parameters onto the stack
by using
PUSH
function.
is
instructions,
CALL instruction to
call
your
that the
you have
selected.
477
Assembly Language
for the
Summary
In this chapter
we have
sembly language
in
your
Windows
as-
can do
C/C++
fast
in
386-Enhanced mode. In
is
this
treat large
what you
mode you
chunks of
assembly language.
In this chapter
This
is
a bibliography
tion.
478
of
usefiil
|c|h|Ip|t|e|r
Closing Words
and Bibliography
Dy now
Throughout
this
all
all
rather
result,
you
But most assembly language programs can be written with what you have
learned here.
Topics Covered
DOS
and
ROM
RAM
BIOS Programming
Resident Programs
Advanced
DOS
Programming
Windows Programming
Software Design
Other Ref^ences
Assembly Language
for the
is
better
way
first
programs
to take the
to write
more about writing assembly language prothis book and modify them. If you think of a
to learning
in
We
You can do
you have
After
all
means
This
it.
itself
by rewriting
in
is
how we
BASIC, and
bits
tried
try
will
own programs. Don't start from scratch here, either; that is rather difficult for
your first time out. To begin, use the programs in this book as a framework.
Don't build a completely new structure or technique (your equivalent of
modular design)
until
you
feel
programs.
If
book
plete
of books
list is
we have
by no means complete,
as the
may
books
will
80x86 instruction
Following
set.
is
list
we
have read. Also, some of the references are older than you might expect because
we
the books
may now
programming
Some of
Hummel, Robert
L.,
PC Programmer's
the
all
80x86
processors. In
This
Microsoft's
not
as
is
the best
book
have ever
bugs. Highly
is
fact, it is
and
seen on
as well as
ways
to
work around
the
recommended.
good
as
(see above),
but
it
iAPX88
is
482
on the
original
34
The
following
book
is
signers at Intel,
also talks
good
P.,
Closing
at Intel:
as a reference, this
book
is
complete and
is
in the
Norton, Peter and Richard Wilton, The New Peter Norton Programmer's Guide
to the
to
all
and
programs.
to Peter's
Brown,
It also
includes a
Press, 1986.
A nice
companion
Programmer's Guide.
Ralf,
DOS, and
Third-Party
all-around reference to
Calls,
PC Interrupts: A
Programmer's Reference
ROM-BIOS
and
DOS
is
to
BIOS,
calls.
programs because
single place.
But there
are
much
for people
who want
to write
RAM-
for information:
It
covers
resident programs.
483
Assembly Language
for the
PC Magazine, published by ZifF Davis often publishes inft)rmation on RAMresident programs, as well as example programs.
Advanced
After
far
you have
beyond
started
book.
this
Duncan, Ray,
A subscription
maga-
to this
DOS Programming
DOS, you want this book. This explains all about EMS memory, extended
memory, XMS, VCPI, DPMI, and so on.
from
Schulman, Andrew,
et al,
about says
it all
and Data
Very
Structures,
to
Re-
interesting.
Windows Programming
There
are
are a
some of the
best ones:
Petzold, Charles,
Programming Windows
This
is
Windows programming.
Norton, Peter and Paul Yao, Peter Norton's Windows 3.1 Power Programming
Techniques,
book.
Bantam,
You will
find
992. This
is
more advanced
This book is
rial
484
Windows
3.1:
Windows
Windows programming.
some good
programs.
Developer's Guide,
related to
Windows programming
M&T Books,
1992.
34
Schulman, Andrew,
is
et al.
992. This
of Windows.
Software Design
We have a few favorite books when
recommend
Brooks, Frederick
neering,
it
comes
to software design.
The books we
read.
who
is
Normal, Donald
book provides
A.,
a lot
Other References
Startz, Richard,
PCs, Brady Books, 1983 (Out of print). If you need to write programs that
use the
this
book should
987. This
is
to
help.
PC & PS/2
good book about writing programs for the EGA and VGA
display adapters.
485
AT p fp Te
d XT\ X
to this
a lot of improvements.
gram discussed
^^NDOWS
special
in
in the
in the
CHAPS
Chapter 32
is
and why.
file
for
directory. This
appendix
for
Dskpatch
are in
CLIB
files
director}^
cluded in the
The
DISKLITE. The
Chapter 33.
Finally, a
C/C++ programming
on the
is
in-
disk,
Topics Covered
Chapter Examples
Advanced Version
of
Dskpatch
DISKLITE Program
Windows Code
C/C++
Libraries
Assembly Language
for the
Chapter Examples
All the chapter examples are
CHAPS
directory.
The examples
we began
enough
so
to build
Dskpatch, which, by the end of this book had grown to nine different
files.
The
files
are
all
in quickly.
But
starting in
Chapter
9,
CLIB.ASM which
is
dis-
cussed in Chapter 3 1
I
In any one chapter, only a few of these nine
files
throughout each chapter, however, there was not enough room on the disk to
store each version
as
in, say.
The
table at the
still
ter, just
on
course, or
look at
either check
file
you don't
file
want
changes.
to
make
It also
sure \-ou
file(s)
to
your
files.
disk.
The complete list of all the files on the companion disk that cover the chapterby-chapter changes to Dskpatch
488
is
as follows:
VIDE0_9.ASM
VIDE0_16.ASM
DISP_S19.ASM
KBD_I024.ASM
VIDEO_10.ASM
DISK_I16.ASM
KBD_I019.ASM
DISPAT25.ASM
VIDE0_13.ASM
DSKPAT17.ASM
DISK_I19.ASM
DISPAT26.ASM
TEST13.ASM
DISP_S17.ASM
DISP_S21 .ASM
DISK_I26.ASM
DISP_S14.ASM
CURS0R17.ASM
PHANT021 .ASM
PHANT027.ASM
CURS0R14.ASM
VIDE0_17.ASM
VIDE0_21 .ASM
DSKPAT30.ASM
VIDE0_14.ASM
DISK_I17.ASM
DISPAT22.ASM
KBD_IO30.ASM
DISP_S15.ASM
DISP_S18.ASM
EDIT0R22.ASM
CURSOR30.ASM
DISKIIS.ASM
CURS0R18.ASM
PHANT022.ASM
VIDEO_30.ASM
DISP_S16.ASM
VIDE0_18.ASM
KBD_I023.ASM
CLIB.ASM
DSKPAT19.ASM
DISPAT19.ASM
TEST23.ASM
Advanced Version
As we said, the disk contains more than
not
really finish
just the
to
make it a
to the Disk
Dskpatch
examples
in this
usable
book.
We did
many things
program. The disk con-
of
Guide
ADVANCED
are
directory as
shown
in
Figure A- 1.
Sector
Disk C
88 81 82 83 84 85 86 87 88 89 80 86 8C 8D BE 8F
I3M3C 98 4D 53 44 4F 53
88
02 00 82 88
CD 54 86 88
42 41 4B 28
C8 BE DB EC
16 53 BF 3E
BF 8B BE 18
CD 13 72 79
89 8E 28 7C
IG IE 7C 83
7C 03 49 7C
IE 8B 7C 83
88 BB 88 85
B8 01 E8 nc
6 75 80 8D
E8 5F 88 33
10
20
38
40
58
Ee
78
88
98
ne
68
C8
08
E8
FB
Press
ft
i^^H
88
88
28
B8
7C
7C
33
F8 CB
88 29
28 46
7C
B9
88
C8
flB 18
86 BE
89
C3
8B
88
16
BB
4D
39
7C
7C
16 4B
48 F7
16 52
72 16
7F 28 B9
C8 CD 16
35 2E 38
BB 23 BB ec
FF 18 64 88
41 54 31 36
87 BB 78 88
08 FC F3 04
F9 89 47 82
86 13 7C 74
F7 26 16 7C
83 D2 88 03
7C B8 28 BB
F3 01 06 49
7C 01 58 7C
SB FB B9 BB
BB BB F3 06
5E IF 8F B4
BB
88
42
28
36
86
C7
08
83
58
F7
7C
E8
88
74
8F
88
80
41
28
37
IF C6
87 3E
8B BE
86 IC
7C 89
26 11
83 16
92 00
BE E6
18 BE
44 82
82
23
52
20
C5
ei234567890BCDEF
81
80
44
FO
IE
45
7C
13
7C
08
00
59
2<EMSD0S5.e BQ?
e e f, )
33
56
FE
FB
7C
BOK
7C
4B
72
7D
3E
CD
8B
7C
=!
dOBRODV
FOTIG
ifiJia
:-.j,x
6+7AU
.St>M|<J "<n#t=E"
SifltieM eGBll.>U
=!!ry3L9!!:tnifl!!;
13
16 52
efl
;a>!=A_:*^!(!
_A:*JJ;a uPie.R
iuIle-Kh =A4:i
*<J!^H~^'3 I !*-<!
'/i-KiiP'.m ril
ID
F3
7D
*uBU
19
0_ 3 l=-*ooDO=i
r_VTi|<t ='>'><
f35S<
i|<J
i'ttJfi}
zlSSTM 3]EESm
fmm
e:jjEmi
9i^H
Hi^EB
As
it
stands (in this book), Dskpatch can read only the next or previous sector.
Thus,
if
you wanted
575 times.
to
The
figure out
Right now,
where
to look for
file.
book version
and
is
can, or
it
file.
In
its
The advanced version of Dskpatch has too many changes to describe in detail
here, so we will take a quick look at the new fianctions we added to the disk
version. You will find many of the changes by exploring Dskpatch and by
making your own changes.
489
Assembly Language
for the
still
has nine
files, all
disk.
DSKPATCH. ASM
DISPATCH. ASM
DISP_SEC.ASM
KBDIO.ASM
CURSOR. ASM
EDITOR. ASM
PHANTOM. ASM
VIDEO_IO.ASM
DISK_IO.ASM
MASM
users can assemble the program with the included MAKEFILE and
LINKINFO files; TASM users can assemble with the BORLAND. MAK file.
You will also find an assembled and linked EXE version ready to run, so you
able to
tell
improvements
just
That is more than you can remember if you don't use Dskpatch very
often, so the
is
F4
line" at the
bottom of the
display.
as follows:
F3,
it.
and F2
to write a sector
back to the
sector,
the
book.
F5
a letter, such as
letter.
Just press
(without a colon,
When
you
:),
F5
or
press the
change Dskpatch so
you change
drives.
it
drive.
We have set
F6
Changes the
sector
sector
number,
it up so that
wrong disk.
it is
very
in decimal.
Dskpatch
sector.
F7
Changes Dskpatch
to
file
file
490
I
from within
mode and
F5 ends
file.
to the Disk
file
Asks for an
F8
that
Guide
within a
offset
it
file.
This
is
F4
just like
file.
If you
FIO
from Dskpatch.
Exits
you
file.
back in
may want
really
to
want
to the
to leave
will lose
last sector.
it
You
asks if you
Dskpatch.
A number of other changes are not as obvious as those we just mentioned. For
example, Dskpatch
the cursor to the
Dskpatch
now
bottom
line
In addition,
Home
one
move
by one
Moves
the
display
and
line,
putting a
phantom
you
sector.
End
Moves
the
phantom
half-sector display
and
you
by four
This
see the
second half-sector.
PgUp
feature
to
lines.
is
PgUp
a nice
the
PgDn
direction
by four
lines in the
oppo-
from PgUp.
You can modify the advanced Dskpatch to better suit your own needs. That is
why the disk has all the source files for the advanced Dskpatch so you can
pressing
like
and
learn
from
F4 causes you
capabilities.
end of a disk or
file,
As
it
stands, if
491
Assembly Language
for the
1
reset the sector to the last sector
on
catches
so
it
the disk or
and
file.
to rewrite
quickly.
DISKLITE Program
The DISKLITE
file,
DISKLITE.ASM. The
file
developed in Chapter 3 1
Windows Code
The
WINDOWS
files.
WTNLIB.ASM
the function.
Use
C/C++
As mentioned
the disk,
492
It also
MASM 6.
Appendix C. These
files
you
a set
of C/C++
libraries
libraries
on
provide mouse
They show
of assembly-language subroutines that work with
A list of the
Libraries
in
which
if
contains the
MASM 6
is
CLIB
directory
CURSOR. ASM
FASTWRIT.ASM
HARDWARE. ASM
MOUSE. ASM
MAKEFILE
SOCHALIB INC
.
is
routines.
library
as follows:
KBDIO.ASM
-
file
CLIB.LIB.
z
<
y)
Y'^(
t-
ji
<
i
(-
i
Z
5
Z
^
rt
~l
X
^
Z
5
r*
Z
5
"3
3C
2
Q
z
Ji
<
z
?
o
z
iS
Z
<
a
a
le
a;
z
3
z
2
z
r*
U!
O
>
>
o
u
c
>
u
a
o'
U
c
o
O
:}
O
u
a
>
>
>
>
o'
a
Z
s
<
o
31
<
'
o
u
a
O
u
a
a
>
>
2
z
<
>
<
<
CM
r-
1
z
<
r
0.
g
z
<
z
a.
?
5
z
a.
1-
Z
2
Z
-y>
<
:^
a
u
s^
a
C
C
32
U
'5
'5
p-
^flC
3
U
z
<
M
K
%
o
a:
i
3
Z
V)
<
z
M
<
ai
1
^O
z
<n
<
':a
g
a
O
a
03
2
<
z
<
z
3
(/>
z
n
<
in
3)
a.
a.
a.
'i
vj
0.
1
3D
Z
aj
<
z
<
(n
^
i
a.
CO
a.
':3
z
<
X
G
A
?
<
o.
(J
z
3
f-
c-
<
<
j^
c:
^2
^H
<
a.
a.
a.
<
<
o
<^
<
L
^
'&
tt
z
2
(>
2?
Ob
S
i
z
5
'5
o
r-
^"^^
o>
a>
iS
go
z
1
493
'i
|p|piE|N|D|
|A
Listing of
Dslq)atch
1
his
appendix contains the final version of Dskpatch. If you are writing your
on your way.
We have
in this
appen-
Topics Covered
Descriptions of Procedures
Dskpatch Make
File
Dskpatch LinkinFo
Program
Listings for
File
Dskpatch Procedures
Assembly Language
for the
Descriptions of Procedures
CaRSOR.ASM
CLEAR_SCREEN Like
the
screen.
the
GOTO_XY
the cursor
Very much
on the
like the
BASIC
SEND_CRLF Sends
moves
next
LOCATE command;
screen.
to the start
of the
line.
DISKJO.ASM
NEXT_SECTOR Adds one to the current sector number,
that sector into
memory and
rewrites the
PREVIOUS_SECTOR Reads
Dskpatch
then reads
screen.
That
is,
(CURRENT_SECTOR_NO)
memory variable SECTOR.
It also
496
buffer,
SECTOR.
SECTOR,
Listing of
Dskpatch
memory
to the disk.
DISPATCH.ASM
DISPATCHER The
keyboard and then
Dskpatch.
from the
calls
on other procedures
to
to
do
all
the
work of
DISPATCH_TABLE in
this file.
DISP_SEC.ASM
DISP_HALF_SECTOR Does
ASCII
work of displaying
all
the hex
by
calling
DISP_LINE
the
and
16 times.
16
INIT_SEC_DISP
you
see in
and top hex numbers, but does not write the header or
WRITE_HEADER Writes the header at the top of the screen you see
in
the
number of the
sector
you
of the
line to
then
prompt.
much
The procedure
is
not useful
else.
497
Assembly Language
for the
DSKPATCHASM
DISK_PATCH The (very short) main program of Dskpatch.
DISK_PATCH simply calls a number of other procedures, which do
all
the work.
It also
many of the
includes
EDITOR.ASM
EDIT_BYTE
byte both in
this
in a sector.
SECTOR.
by the phantom
cursor.
KBDJO.ASM
BACK_SPACE
one
Used by the
character, both
whenever you
READ_STRING
procedure to delete
buffer,
A into
the hex
with uppercase
number OAH.
only
letters.
HEX_TO_BYTE Converts
hexadecimal
CONVERT_HEX_DIGIT works
letter
string,
such
as
from
hex
value.
A5, into a
to be digits or uppercase
letters.
to read a string
of characters.
498
Listing of
Dskpatch
a single key
through 255 for ordinary characters, and lOOh plus the scan code for
special keys.
READ_STRING
Reads
keyboard. This procedure also reads special function keys, whereas the
DOS READ_STRING
all
uppercase
converts a
letters.
PHANTOM.ASM
ERASE_PHANTOM
Removes
the two
phantom
cursors
from the
phantom
MOV_TO_ASCII_POSITION Moves
the
phantom
cursor in the
half-sector display.
phantom
all
cursors.
window of the
the start of
half-sector display.
move
display.
left
but
PHANTOM_UP Moves the phantom cursor up one line in the halfsector display, or scrolls the display if you try to
move
the top.
499
Assembly Language
for the
RESTORE_REAL_CURSOR Moves
recorded by
SAVE_REAL_CURSOR.
SAVE_REAL_CURSOR Saves
want
position
to restore
its
cursor
real
finished
if
two
you
making changes
to
the screen.
version of
first
You
will find a
more advanced
The advanced
book.
this
SCROLL_UP
SCROLL_UP
sector.
and
On
the disk,
more advanced
versions of
line
instead of 16.
one
in the
on a w^hite background.
VIDEO_IO.ASM
Contains most of the general-purpose procedures you will want to use in your
own
programs.
INIT_WRITE_CHAR Call
other procedures in this
this
file. It
initializes the
call
any of the
500
uses
it
to
cursors.
ROM
BIOS
you want
to
move
will
ODH).
Listing of
Dskpatch
uses the
to
it
meaning
appear on the
Call
SEND_CRLF
WRITE_CHAR_N_TIMES
screen. This procedure
is
useful for
drawing
lines
of characters, such
as
number
in the range
and writes
it
defined by a pattern.
a single-digit
as
WRITE_STRING A very
which you can write
on the
useful, general-purpose
must be
Dskpatch Make
the makefile that
as
screen.
procedure with
dskpatch.exe:
on the screen
is
it
to the screen.
WRITE_PATTERN
Following
number.
WRITE_HEX_DIGIT Writes
ter
an unsigned
to 65,535.
to the screen as
The
last
a zero byte.
File
to build
Dskpatch automatically.
dskpatch. obj
dskpatch. asm
501
Assembly Language
for the
disk_io Ob j
.
clisk_io asm
ml /c /Zi disk_io.asm
clisp_sec obj
.
dispsec asm
ml /c /Zi disp_sec.asm
video_io obj
.
video_io asm
ml /c /Zi videoio.asm
cursor. obj:
cursor. asm
dispatch. obj
dispatch. asm
kbd_io obj
.
kbd_io asm
ml /c /Zi kbd_io.asm
phantom. obj:
phantom. asm
editor. obj:
editor. asm
Dskpatch Linkinfo
The
linkinfo
file is as
follows:
DSKPATCH
DSKPATCH /MAP;
502
File
Program Listings
Listing of
Dskpatch
for
Dsiq)3tch Procedures
CaRSOR.ASM
CR
EQU
13
jCarriage return
LF
EQU
10
;Line feed
.MODEL
SMALL
.CODE
PUBLIC
CLEAR SCREEN
CLEARSCREEN
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
XOR
AL.AL
XOR
CX,CX
MOV
DH,24
MOV
DL,79
MOV
BH,7
MOV
AH, 6
INT
10h
POP
DX
POP
CX
POP
BX
POP
AX
RET
CLEAR SCREEN
ENDP
PUBLIC
GOTO_XY
EXTRN
EXTRN
SCREEN_X:BYTE, SCREEN_Y:BYTE
.DATA
503
Assembly Language
for the
.CODE
GOTO_XY
DH
Row
DL
Column (X)
(Y)
PROC
PUSH
AX
PUSH
BX
MOV
BH,0
;Display page
MOV
AH,
INT
10h
MOV
AL.DH
MOV
BL,80
MUL
BL
;AX = row
ADD
AL,DL
;Add column
ADC
AH,0
;AX = row
SHL
AX,1
MOV
SCREEN_PTR,AX
MOV
SCREEN_X,DL
MOV
SCREEN_Y,DH
POP
BX
POP
AX
80
80 + column
RET
GOTO XY
ENDP
PUBLIC
CURSOR_RIGHT
DATA
EXTRN
SCREEN_PTR:WORD
EXTRN
SCREEN_X:BYTE, SCREEN_Y:BYTE
.CODE
This procedure moves the cursor one position to the right or to the
next line if the cursor was at the end of a line.
Uses:
SEND_CRLF
Writes;
CURSOR_RIGHT
504
PROC
INC
SCREEN_PTR
INC
SCREEN PTR
INC
SCREEN_X
CMP
SCREEN_X,79
JBE
OK
CALL
SEND_CRLF
Listing of Dsl<patch
OK:
RET
ENDP
CURSOR RIGHT
PUBLIC
UPDATE_REAL_CURSOR
This procedure moves the real cursor to the current virtual cursor
position.
input.
UPDATE_REAL_CURSOR
PROC
PUSH
DX
MOV
DL.SCREENX
MOV
DH,SCREEN_Y
CALL
GOTO_XY
POP
DX
RET
PUBLIC
ENDP
UPDATE_VIRTUAL..CURSOR
PUSH
PROC
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AH, 3
XOR
BH.BH
;0n page
INT
10h
CALL
GOTO_XY
POP
DX
POP
CX
POP
BX
POP
AX
DL
RET
ENDP
505
6
2
Assembly Language
for the
PUBLIC
This procedure clears the line from the current cursor position to
the end of that line.
CLEAR_TO_END_ OF _LINE
PRO
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
DL,SCREEN_X
MOV
DH,SCREEN_Y
MOV
AH,
XOR
AL.AL
;Clear window
MOV
CH.DH
MOV
CL.DL
MOV
DL,79
MOV
BH,7
INT
leh
POP
ox
POP
ox
POP
BX
POP
AX
RET
PUBLIC
END
SEND_CRLF
correctly.
Uses: UPDATE VIRTUAL CURSOR
SEND_CRLF
PUSH
506
PROC
AX
PUSH
DX
MOV
AH,
MOV
DL.CR
INT
21h
MOV
DL.LF
INT
21h
CALL
UPDATE_VIRTUAL_CURSOR
POP
DX
POP
Listing of
Dskpatch
AX
RET
SEND CRLF
ENDP
END
D1SK_10.ASM
.MODEL
SMALL
.DATA
EXTRN
SECTOR: BYTE
EXTRN
DISK_DRIVE_NO:BYTE
EXTRN
CURRENT_SECTOR_NO:WORD
PUBLIC
PREVIOUS_SECTOR
.CODE
EXTRN
EXTRN
EXTRN
DATA
CODE
if possible.
Uses:
WRITE_PROMPT_LINE
Reads:
CURRENT_SECTOR_NO, EDITOR_PROMPT
Writes:
CURRENT SECTOR NO
PREVIOUS_SECTOR
PUSH
PROC
AX
PUSH
DX
MOV
AX CURRENT_SECTOR_NO
OR
AX, AX
JZ
DONT_DECREMENT_SECTOR
DEC
AX
MOV
CURRENT_SECTOR_NO AX
CALL
WRITE_HEADER
CALL
READ SECTOR
507
Assembly Language
for the
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
DONT_DECREMENT_SECTOR
POP
DX
POP
AX
RET
PREVIOUS SECTOR
PUBLIC
ENDP
NEXT_SECTOR
EXTRN
INIT_SEC_DISP:PROC, WRITE_HEADER:PROC
EXTRN
WRITE_PROMPT_LINE:PROC
EXTRN
CURRENT_SECTOR_NO:WORD, EDITOR_PROMPT:BYTE
.DATA
.CODE
Uses:
WRITE_PROMPT_LINE
Reads:
CURRENT_SECTOR_NO, EDITOR_PROMPT
Writes:
CURRENT SECTOR NO
NEXT_SECTOR
PUSH
PROC
AX
PUSH
DX
MOV
AX,CURRENT_SECTOR_ NO
INC
AX
MOV
CURRENT_SECTOR_NO AX
CALL
WRITE_HEADER
CALL
READ_SECTOR
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
POP
DX
POP
AX
RET
NEXT SECTOR
PUBLIC
ENDP
READSECTOR
Reads:
508
CURRENT_SECTOR_NO, DISK_DRIVE_NO
Writes:
READ SECTOR
PUSH
Listing of
Dskpatch
SECTOR
PflOC
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AL,DISK_DRIVE_NO
MOV
CX,1
;Read only
MOV
LEA
BX, SECTOR
INT
25h
Drive number
1
sector
POPF
POP
DX
POP
CX
POP
BX
POP
AX
RET
READ SECTOR
PUBLIC
ENDP
WRITE_SECTOR
Reads:
WRITE_SECTOR
PROC
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AL,DISK_DRIVE_NO
MOV
CX,1
;Write
MOV
DX CURRENT_SECTOR_NO
LEA
BX, SECTOR
INT
26h
POPF
DX
POP
CX
POP
BX
POP
AX
sector
Logical sector
POP
Drive number
RET
WRITE SECTOR
ENDP
END
509
Assembly Language
for the
DISPATCH.ASJVI
.MODEL
SMALL
.CODE
EXTRN
NEXT_SECTOR:PROC
EXTRN
PREVIOUS_SECTOR:PROC
EXTRN
;In DISK_IO.ASM
;In
:
EXTRN
EXTRN
WRITE_SECTOR:PROC
DISKIO.ASM
;In DISK_IO.ASM
.DATA
This table contains the legal extended ASCII keys and the addresses
of the procedures that should be called when each key is pressed.
DISPATCH_TABLE
DB
72
DW
OFFSET
LABEL
BYTE
TEXT: PHANTOM UP
DB
61
DW
OFFSET _TEXT:PREVIOUS_SECTOR
;F3
;F4
DB
62
DW
OFFSET _TEXT:NEXT_SECTOR
DB
72
DW
OFFSET
;Cursor up
TEXT PHANTOM_UP
:
;Cursor down
DB
80
DW
DB
75
DW
OFFSET _TEXT:PHANTOM_LEFT
DB
77
DW
OFFSET _TEXT:PHANTOM_RIGHT
DW
85
DW
OFFSET _TEXT:WRITE_SECTOR
.CODE
510
;Cursor right
Shift F2
DB
PUBLIC
;Cursor left
DISPATCHER
EXTRN
EXTRN
WRITE_PROMPT_LINE:PROC
EXTRN
DATA
Listing of
Dskpatch
.CODE
if the char
If the
Uses:
Reads:
EDITOR PROMPT
DISPATCHER
PROC
PUSH
AX
PUSH
BX
PUSH
DX
DISPATCHLOOP:
CALL
READ_BYTE
OR
AH, AH
;AX =
;
-1
if no character read,
JS
NO_CHARS_READ
JNZ
SPECIALKEY
MOV
DL.AL
try again
CALL
EDIT_BYTE
JMP
DISPATCH LOOP
CMP
AL,68
;F10--exit?
JE
ENDDISPATCH
edit byte
SPECIALKEY:
;Yes,
leave
LEA
BX,DISPATCH_TABLE
SPECIALLOOP:
CMP
End of table?
JE
NOT_IN_TABLE
Yes,
CMP
AL,[BX]
JE
DISPATCH
ADD
BX,3
No,
JMP
SPECIAL LOOP
DISPATCH:
INC
BX
CALL
;Call procedure
JMP
DISPATCH LOOP
311
Assembly Language
for the
NOT_IN_TABLE:
JMP
;Do nothing,
DISPATCH LOOP
NO_CHARS_READ:
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
JMP
DISPATCH_LOOP
;Try again
END_DISPATCH:
POP
DX
POP
BX
POP
AX
RET
DISPATCHER
ENDP
END
DISP.SECASM
SMALL
.MODEL
VERTICAL_BAR
EQU
0BAh
HORIZONTAL_BAR
EQU
0CDh
UPPER_LEFT
EQU
0C9h
UPPER_RIGHT
EQU
0BBh
LOWER_LEFT
EQU
0C8h
LOWER_RIGHT
EQU
OBCh
TOP_T_BAR
EQU
0CBh
BOTTOM_T_BAR
EQU
0CAh
TOP_TICK
EQU
0D1h
BOTTOM TICK
EQU
0CFh
.DATA
LABEL
TOP_LINE_PATTERN
DB
'
BYTE
,7
512
^1
DB
Listing of
Dskpatch
UPPER_LEFT,1
DB
HORIZONTAL_BAR 12
DB
T0P_TICK,1
DB
HORIZONTAL_BAR
DB
T0P_TICK,1
DB
HORIZONTAL_BAR
DB
T0P_TICK,1
DB
HORIZONTAL_BAR 12
DB
TOP_T_BAR
DB
HORIZONTAL_BAR 18
DB
UPPER_RIGHT,1
11
11
DB
INE._PATTERN
DB
'
LABEL
BYTE
B
',7
DB
L0WER_LEFT,1
DB
HORIZONTAL_BAR 12
DB
B0TT0M_TICK,1
DB
HORIZONTAL_BAR
DB
B0TT0M_TICK,1
DB
HORIZONTAL_BAR
DB
B0TT0M_TICK,1
DB
HORIZONTAL_BAR 12
DB
BOTTOM_T_BAR
DB
HORIZONTAL_BAR 18
DB
L0WER_RIGHT,1
11
11
DB
.DATA?
EXTRN
SECTOR: BYTE
.CODE
PUBLIC
INIT_SEC_DISP
EXTRN
EXTRN
.DATA
EXTRN
LINES_BEFORE_SECTOR:BYTE
EXTRN
.CODE
Uses:
513
Assembly Language
for the
Reads:
TOP_LINE_PATTERN, BOTTOMLINEPATTERN
Writes:
SECTOR OFFSET
LINES_BEFORE_SECTOR
INIT_SEC_DISP
PUSH
PROC
DX
XOR
DL,DL
MOV
DH,LINES_BEFORE_SECTOR
CALL
GOTO_XY
CALL
WRITE_TOP_HEX_NUMBERS
LEA
DX,TOP_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
SEND_CRLF
XOR
DX,DX
MOV
SECTOR_OFFSET,DX
CALL
DISP_HALF_SECTOR
LEA
DX BOTTOM_LINE_PATTERN
CALL
WRITE_PATTERN
CALL
WRITE_PHANTOM
POP
DX
RET
INIT SEC DISP
ENDP
PUBLIC
WRITE_HEADER
EXTRN
HEADER_LINE_NO:BYTE
EXTRN
HEADER_PART_1 BYTE
EXTRN
HEADER_PART_2 BYTE
EXTRN
DISK_DRIVE_NO:BYTE
EXTRN
CURRENT_SECTOR_NO:WORD
EXTRN
EXTRN
GOTO_XY:PROC, CLEAR_TO_END_OF_LINE:PROC
.DATA
.CODE
This procedure writes the header with disk-drive and sector number.
GOTO_XY, WRITE_STRING, WRITE_CHAR, WRITEDECIMAL
Uses:
CLEAR_TO_END_OF_LINE
HEADER_LINE_NO, HEADER_PART_1
Reads:
HEADER_PART_2
DISK_DRIVE_NO, CURRENT_SECTOR_NO
WRITE_HEADER
PUSH
514
PROC
DX
XOR
DL.DL
MOV
DH,HEADER_LINE_NO
CALL
Listing of
Dskpatch
GOTO_XY
LEA
DX.HEADERPARTI
CALL
WRITE_STRING
MOV
DL,DISK_DRIVE_NO
ADD
DL, A'
CALL
WRITE_CHAR
;Print drives A, B,
LEA
DX,HEADER_PART_2
CALL
WRITE_STRING
MOV
DX CURRENT_SECTOR_NO
CALL
WRITE_DECIMAL
CALL
CLEAR_TO_END_OF_LINE
POP
DX
RET
WRITE HEADER
ENDP
EXTRN
EXTRN
WRITE_HEX_DIGIT:PROC, SEND_CRLF:PROC
Uses:
WRITE_HEX_DIGIT, SEND_CRLF
WRITE_TOP_HEX_NUMBERS
PUSH
CX
PUSH
DX
PROC
MOV
DL,'
MOV
CX,9
CALL
WRITECHARNTIMES
XOR
DH,DH
Start with
HEX_NUMBER_LOOP
MOV
DL,DH
CALL
WRITE_HEX
MOV
DL,'
CALL
WRITE_CHAR
INC
DH
CMP
DH,10h
JB
MOV
DL,'
MOV
CX
CALL
WRITE_CHAR_N_TIMES
XOR
DL,DL
'
;Done yet?
515
Assembly Language
for the
HEX_DIGIT_LOOP
CALL
WRITE_HEX_DIGIT
INC
DL
CMP
DL,10h
JB
HEX_DIGIT_LOOP
CALL
SEND_CRLF
POP
DX
POP
CX
RET
ENDP
PUBLIC
DISP_HALF_SECTOR
EXTRN
SEND_CRLF:PROC
On entry:
DS:DX
should be
multiple of 16.
DISP_LINE, SEND_CRLF
Uses:
DISP._HALF_SECTOR
PUSH
PRO
CX
PUSH
DX
MOV
CX,16
;Display 16 lines
HALF _SECTOR:
CALL
DISP_LINE
CALL
SEND_CRLF
ADD
DX,16
LOOP
HALF_SECTOR
POP
DX
POP
CX
RET
DISP HALF SECTOR
END
PUBLIC
DISP_LINE
EXTRN
WRITE_HEX:PROC
EXTRN
WRITE_CHAR:PROC
EXTRN
516
J
'
On entry:
DS:DX
Uses:
Reads:
SECTOR
OISP_LINE
Listing of
Dskpatch
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
BX.DX
MOV
DL,'
MOV
CX,3
CALL
WR I TE_CHAR_N_T I ME S
CMP
BX,100h
JB
WRITE_ONE
MOV
DL,
'1
then place
;Yes,
'1'
WRITE_ONE:
CALL
WRITECHAR
;Copy lower byte into DL for hex output
MOV
DL,BL
CALL
WRITE_HEX
MOV
DL,
CALL
WRITECHAR
;Write separator
'
'
MOV
DL,VERTICAL_BAR
CALL
WRITE_CHAR
MOV
DL,'
CALL
WRITE_CHAR
MOV
CX,16
;Du(np
PUSH
BX
MOV
;Get
CALL
WRITE_HEX
MOV
DL,'
CALL
WRITE_CHAR
INC
BX
LOOP
HEX LOOP
'
HEX LOOP:
MOV
DL,VERTICAL_BAR
CALL
WRITECHAR
MOV
DL,'
CALL
WRITE_CHAR
MOV
CX,16
POP
BX
'
byte
;Write separator
517
Assembly Language
for the
ASCIILOOP:
MOV
CALL
WRITE_CHAR
INC
BX
LOOP
ASCII LOOP
MOV
DL,'
CALL
WRITE_CHAR
'
MOV
DL,VERTICAL_BAR
CALL
WRITE_CHAR
POP
DX
POP
CX
POP
BX
RET
DISP LINE
ENDP
PUBLIC
WRITE_PROMPT_LINE
EXTRN
EXTRN
GOTO_XY:PROC
EXTRN
.DATA
.CODE
This procedure writes the prompt line to the screen and clears the
end of the line.
On entry:
DS:DX
Uses:
Reads:
PROMPT LINE NO
WRITE_PROMPT_LINE
PUSH
DX
PROC
XOR
DL,DL
MOV
DH,PROMPT_LINE_NO
CALL
GOTO_XY
POP
DX
CALL
WRITE_STRING
CALL
CLEAR_TO_END_OF_LINE
RET
END
518
ENDP
Listing of Dskpatcii
DSKPATCH.ASM
DOSSEG
.MODEL
SMALL
.STACK
.DATA
PUBLIC
SECTOR OFFSET
SECTOR_OFFSET is the offset of the halfsector display into the full sector.
be a multiple of 16,
SECTOR OFFSET
PUBLIC
It must;
DW
CURRENT_SECTOR_NO, DISK_DRIVE_NO
CURRENT_SECTOR_NO
DW
Initially sector
DISK_DRIVE_NO
DB
Initially Drive A:
PUBLIC
LINES_BEFORE_SECTOR, HEADER_LINE_NO
PUBLIC
HEADER_PART_1
HEADER_PART_2
sector display.
LINES_BEFORE_SECTOR
DB
HEADER_LINE_NO
DB
HEADER_PART_1
DB
'Disk
HEADER_PART_2
DB
'
PUBLIC
',0
Sector ',0
PROMPT_LINE_NG, EDITORPROMPT
PROMPT_LINE_NO
DB
EDITOR_PROMPT
DB
DB
'
21
',0
.DATA?
PUBLIC
SECTOR
SECTOR
.CODE
DB
519
Assembly Language
for the
EXTRN
EXTRN
EXTRN
EXTRN
DISK_PATCH
INIT_WRITE_CHAR:PROC
PROC
MOV
AX.DGROUP
MOV
DS,AX
CALL
INIT_WRITE_CHAR
CALL
CLEAR_SCREEN
CALL
WRITE_HEADER
CALL
READ_SECTOR
CALL
INIT_SEC_DISP
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
CALL
DISPATCHER
MOV
AH,4Ch
INT
21h
DISK PATCH
END
Return to DOS
ENDP
DISK PATCH
EDITOR.ASM
.MODEL
SMALL
.CODE
.DATA
EXTRN
SECTOR: BYTE
EXTRN
SECTOR_OFFSET:WORD
EXTRN
PHANTOM_CURSOR_X BYTE
EXTRN
CODE
This procedure writes one byte to SECTOR, at the memory location
520
DL
Listing of
Dskpatch
OFFSET = SECTOR_OFFSET
Reads:
PHANTOM_CURSOR_X
Writes:
SECTOR
PHANTOM_CURSOR_Y
(16
PHANTOM_CURSOR_Y
PHANTOM_CURSOR_X
SECTOR_OFFSET
AX
PUSH
BX
PUSH
CX
MOV
BX SECTOR_OFFSET
MOV
AL PHANTOM_CURSOR_Y
XOR
AH, AH
MOV
CL,4
SHL
AX.CL
ADD
BX.AX
MOV
AL PHANTOM_CURSOR_X
Multiply PHANTOM_CURSOR_Y by 16
;BX = SECTOR_OFFSET +
(16
Y)
XOR
AH, AH
ADD
BX.AX
MOV
SECTOR [BX],DL
;Now,
POP
CX
POP
BX
POP
AX
RET
WRITE TO MEMORY ENDP
PUBLIC
EDIT_BYTE
EXTRN
SAVE_REAL_CURSOR PROC
EXTRN
MOV_TO_HEX_POSITION PROC
EXTRN
WRITE_PHANTOM:PROC, WRITE_PROMPT_LINE:PROC
EXTRN
EXTRN
RESTORE_REAL_CURSOR PROC
:
MOV_TO_ASCII_POSITION PROC
:
.DATA
.CODE
On entry:
DL
Uses:
SAVE_REAL_CURSOR
RESTORE_REAL_CURSOR
MOV_TO_HEX_POSITION, MOV_TO_ASCII_POSITION
EDITOR PROMPT
521
Assembly Language
for the
EDIT_BYTE
PROG
PUSH
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_PGSITION
CALL
CURSOR_RIGHT
CALL
WRITE_HEX
CALL
MOV_TO_ASCII_POSITION
CALL
WRITE_CHAR
CALL
RESTORE_REAL_CURSOR
CALL
WRITE_PHANTOM
CALL
WRITE_TO_MEMORY
LEA
DX,EDITOR_PROMPT
CALL
WRITE_PROMPT_LINE
POP
DX
RET
EDIT BYTE
ENDP
END
KBD IO.ASM
.MODEL
SMALL
BS
EQU
;Backspace character
OR
EQU
13
;Carriage-return character
ESCAPE
EQU
27
Escape character
.DATA
KEYBOARD_INPUT
LABEL
CHAR_NUM_LIMIT
DB
NUM_CHARS_READ
DB
CHARS
DB
BYTE
80 DUP (0)
.CODE
PUBLIC
STRING_TO_UPPER
This procedure converts the string, using the DOS format for strings,
to all uppercase letters.
On entry:
DS:DX
522
i:l
Listing of
Dskpatch
STRING_TO_UPPER PROC
PUSH
AX
PUSH
BX
PUSH
CX
MOV
BX.DX
INC
BX
MOV
CL, [BX]
XOR
CH.CH
UPPER_LOOP:
INC
BX
MOV
AL,[BX]
CMP
AL, 'a'
JB
NOT_LOWER
;Nope
CMP
AL
JA
NOT_LOWER
ADD
AL, 'A'
MOV
[BX] ,AL
'a'
NOT_LOWER
LOOP
UPPER_LOOP
POP
CX
POP
BX
POP
AX
RET
(hex)
to a nibble
(4 bits).
On entry:
AL
Returns:
AL
Nibble
CF
Character to convert
PROC
CMP
AL, '0'
JB
BAD_DIGIT
;Nope
CMP
AL, 'g'
JA
TRY_HEX
SUB
AL,'0'
CLC
convert to nibble
RET
523
Assembly Language
for the
TRY_HEX:
CMP
AL, 'A'
JB
BAD_DIGIT
;Not hex
CMP
AL, 'F'
JA
BAD_DIGIT
;Not hex
SUB
;Is hex,
CLC
convert to nibble
RET
BAD_DIGIT:
STC
error
RET
E
ENDP
HEXTOBYTE
This procedure converts the two cnaracters at DS:DX from hex to one
byte.
On entry:
DS:DX
Returns:
AL
Byte
CF
Uses:
HEX_TO_BYTE
PROC
PUSH
BX
PUSH
CX
MOV
BX.DX
MOV
AL,[BX]
CALL
CONVERT_HEX_DIGIT
JC
BAD_HEX
MOV
CX,4
;Now multiply by 16
SHL
AL.CL
MOV
AH,AL
INC
BX
MOV
AL,[BXJ
CALL
CONVERT_HEX_DIGIT
JC
BAD_HEX
OR
AL.AH
Retain a copy
CLC
DONE_HEX:
POP
CX
POP
BX
RET
524
i\
Listing of
Dskpatch
BAD_HEX
STC
DONE_HEX
JMP
HEX TO BYTE
ENDP
PUBLIC
READSTRING
EXTRN
WRITE_CHAR:PROC
EXTRN
function.
And
DS:DX
actually read.
No characters read
-1
READ_STRING
PUSH
PROC
PROC
AX
PUSH
BX
PUSH
SI
MOV
SI, OX
BX,2
START_OVER
MOV
READ_LOOP
CALL
UPDATE_REAL_CURSOR
CALL
READ_KEY
OR
AH, AH
JNZ
EXTENDED
Yes,
STRING_NOT_EXTENDED:
No,
CMP
AL,CR
JE
END_INPUT
CMP
AL,BS
Is it a backspace character?
525
h2
Assembly Language
for the
JNE
NOTBS
;Nope
CALL
BACK_SPACE
;Yes,
JMP
READ_LOOP
NOT_BS: CMP
delete character
AL, ESCAPE
JNE
NOT_ESC
;No,
CALL
PURGE_BUFFER
;Yes,
JMP
READ_LOOP
NOT_ESC
CMP
BL,[SI]
JA
MOV
BUFFER_FULL
;Buffer is full
[SI+BX],AL
INC
BX
PUSH
DX
MOV
DL.AL
CALL
WRITE_CHAR
POP
DX
JMP
READ LOOP
beep
SIGNAL_ERROR
PUSH
DX
MOV
DL,7
MOV
AH,
INT
21
POP
DX
JMP
character.
buffer-full condition.
BUFFER_FULL:
JMP
return
526
-1
just beep
EXTENDED:
Listing of
Dskpatch
CALL
PURGE_BUFFER
MOV
[SI+21,AL
MOV
BL,0FFh
JMP
-1
for special
END_INPUT:
BL,2
MOV
[SI+1],BL
POP
SI
SUB
END_STRING:
POP
BX
POP
AX
RET
READ STRING
ENDP
DS:SI
PURGE_BUFFER
PUSH
CX
MOV
CL,(SI]
XOR
CH.CH
characters in buffer.
PURGE_LOOP:
BACK_SPACE
BACK_SPACE
LOOP
PURGE_LOOP
far back
POP
CX
CALL
RET
PURGE BUFFER
ENDP
PUBLIC
BACK_SPACE
EXTRN
WRITE_CHAR:PROC
EXTRN
UPDATE_REAL_CURSOR:PROC
EXTRN
527
Assembly Language
for the
BACK_SPACE simply
On entry:
DS:SI+BX
Returns:
DS:SI+BX
Uses:
WRITE CHAR
BACK_SPACE
PROC
PUSH
AX
PUSH
DX
CMP
BX,2
JE
END_BS
;Yes,
DEC
BX
MOV
AH, 2
MOV
DL,BS
INT
21h
CALL
UPDATE_VIRTUAL_CURSOR
MOV
DL,20h
CALL
WRITE_CHAR
CALL
UPDATE_REAL_CURSOR
MOV
DL.BS
;Back up again
INT
21h
CALL
UPDATE_VIRTUAL_CURSOR
END_BS: POP
DX
POP
AX
RET
BACK SPACE
PUBLIC
ENDP
READ BYTE
Returns:
This is just
AL
= 0)
AH
1
-1
528
Uses:
Reads:
KEYBOARDINPUT, etc.
Writes:
KEYBOARD_INPUT, etc.
READ_BYTE
Listing of
Dskpatch
PROC
PUSH
DX
MOV
CHAR_NUM_LIMIT,3
LEA
DX,KEYBOARD_INPUT
CALL
READSTRING
CMP
NUM_CHARS_READ,1
JE
ASCII_INPUT
JB
NO_CHARACTERS
CMP
JE
SPECIALKEY
;Yes
CALL
STRING_TO_UPPER
;No,
LEA
DX, CHARS
CALL
HEX_TO_BYTE
JC
NO_CHARACTERS
Error,
XOR
AH, AH
DONE_READ
POP
DX
RET
NO_CHARACTERS
XOR
AH, AH
;Set to
'no
NOT
AH
jReturn
-1
JMP
DONE_READ
characters read'
in AH
ASCII_INPUT:
MOV
AL, CHARS
XOR
AH, AH
JMP
DONE_READ
SPECIALKEY:
MOV
AL,CHARS[0]
MOV
AH,1
JMP
DONEREAD
READ BYTE
PUBLIC
ENDP
READ_KEY
Returns:
AL
AH
if
1
READ_KEY
PROC
XOR
AH, AH
INT
16h
OR
AL.AL
JZ
EXTENDED CODE
;Yes
529
Assembly Language
for the
NOT_EXTENDED:
XOR
AH, AH
MOV
AL,AH
MOV
AH,1
JMP
DONE_READING
DONE_READING:
RET
EXTENDED_CODE
READ KEY
ENDP
PUBLIC
READDECIMAL
Returns:
AX
CF
Uses:
READSTRING
Reads:
KEYBOARD_INPUT, etc.
Writes:
KEYBOARD_INPUT, etc.
READ_DECIMAL
PROC
PUSH
BX
PUSH
CX
PUSH
DX
MOV
CHAR_NUM_LIMIT,6
LEA
DX,KEYBOARD_INPUT
CALL
READ_STRING
MOV
CL NUM_CHARS_READ
XOR
CH.CH
CMP
CL,0
JLE
BAD_DECIMAL_DIGIT
XOR
AX, AX
XOR
BX.BX
signal error
CONVERT_DIGIT:
530
MOV
DX,10
;Multiply number by 10
MUL
DX
;Multiply AX by 10
JC
BAD_DECIMAL_DIGIT
MOV
SUB
DL, '0'
JS
BADDECIMALDIGIT
CMP
DL,9
JA
BAD_DECIMAL_DIGIT
Yes
ADD
AX.DX
No,
INC
BX
LOOP
CONVERT_DIGIT
Listing of
Dskpatch
SO add It to number
DONE_DECIMAL:
POP
DX
POP
CX
POP
BX
RET
BAD_DECIMAL_DIGIT:
;Set carry to signal error
STC
JMP
READ DECIMAL
DONE_DECIMAL
ENDP
END
PHANTOM.ASM
.MODEL
SMALL
.DATA
REAL_CURSOR_X
REAL_CURSOR_Y
PUBLIC
DB
DB
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
PHANTOM_CURSOR_X
DB
PHANTOM CURSOR Y
DB
.CODE
Uses:
ERASE_PHANTOM, WRITE_PHANTOM
SCROLL_DOWN, SCROLL_UP
Reads:
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
Writes:
PHANTOM_CURSOR_X, PHANTOM_CURSOR_Y
531
Assembly Language
for the
PHANTOM_UP
PUBLIC
PHANTOM_UP
PROC
CALL
ERASE_PHANTOM
DEC
PHANTOM_CURSOR__Y
JNS
WASNT_AT_TOP
CALL
SCROLL_DOWN
WRITE_PHANTOM
scroll
WASNT_AT_TOP
CALL
RET
PHANTOM_UP
ENDP
PHANT0M_DOWN
PUBLIC
PHANTOM_DOWN
PROC
CALL
ERASE_PHANTOM
INC
PHANTOM_CURSOR__Y
CMP
PHANTOMCURSOR _Y,16
JB
WASNT_AT_BOTTOM
;No,
CALL
SCROLL_UP
;Was at bottom,
WRITE_PHANTOM
WASNT_AT_BOTTOM
CALL
so write phantom
scroll
RET
PHANTOM_DOWN
PUBLIC
PHANTOM_LEFT
ENDP
PHANTOM_LEFT
PROC
CALL
ERASE_PHANTOM
DEC
PHANTOM_CURSOR..X
JNS
WASNT_AT_LEFT
MOV
PHANTOM_CURSOR_.X,0
;Was at left,
WRITE_PHANTOM
WASNT_AT_LEFT:
CALL
RET
PHANTOM_LEFT
PUBLIC
PHANTOM_RIGHT
ENDP
PHANTOM_RIGHT
PROC
Erase at current position
CALL
ERASE_PHANTOM
INC
PHANTOM_CURSOR_ X
CMP
PHANTOM_CURSOR__X,16
JB
MOV
WASNT_AT_RIGHT
so put back there
PHANTOM_CURS0R._X,15
;Was at right,
WRITE_PHANTOM
WASNT_AT_RIGHT:
CALL
RET
PHANTOM RIGHT
532
ENDP
;;
PUBLIC
MOV_TO_HEX_POSITION
EXTRN
GOTOXY PROC
EXTRN
Listing of
Dskpatch
.DATA
.CODE
This procedure moves the real cursor to the position of the phantom
Uses:
GOTOXY
Reads:
LINES_BEFORE_SECTOR, PHANTOM_CURSOR_X
MOV_TO_HEX_POS I T I ON
PHANTOM_CURSOR_Y
PROC
PUSH
AX
PUSH
CX
PUSH
DX
MOV
DH.LINESBEFORESECTOR
ADD
DH,2
ADD
DH PHANTOM_CURSOR_Y
MOV
DL,8
MOV
CL,3
MOV
AL PHANTOM_CURSOR_X
MUL
CL
ADD
DL,AL
CALL
GOTO_XY
POP
DX
POP
CX
POP
AX
to get column
RET
MOV TO HEX POSITION
ENDP
PUBLIC
MOV_TO_ASCII_POSITION
EXTRN
GOTO_XY:PROC
EXTRN
.DATA
.CODE
This procedure moves the real cursor to the beginning of the phantom
Uses:
GOTO_XY
Reads:
LINES_BEFORE_SECTOR, PHANTOM_CURSOR_X
PHANTOM_CURSOR_Y
533
Assembly Language
for the
AX
PUSH
DX
PROC
MOV
DH LINES_BEFORE_SECTOR
ADD
DH,2
ADD
DH PHANTOM_CURSOR_Y
MOV
DL,59
ADD
DL PHANTOM_CURSOR_X
CALL
GOTO_XY
POP
DX
POP
AX
RET
PUBLIC
ENDP
This procedure saves the position of the real cursor in the two
Writes:
X and
REAL CURSOR Y.
REAL_ CURSOR_X
REAL_CURSOR_Y
SAVE_REAL_CURSOR
PROG
PUSH
AX
PUSH
BX
PUSH
CX
PUSH
DX
MOV
AH, 3
XOR
BH,BH
INT
10h
;Save position
MOV
REAL__CURSOR_Y DL
MOV
REAL__CURSOR_X DH
POP
DX
POP
CX
POP
BX
POP
AX
on page
RET
SAVE REAL CURSOR
ENDP
PUBLIC
RESTORE_REAL_CURSOR
EXTRN
GOTO_XY:PROC
This procedure restores the real cursor to its old position, saved
in REAL CURSOR X and REAL CURSOR Y.
534
Uses:
GOTO_XY
Reads:
REAL_CURSOR_X
REAL_CURSOR_Y
DX
MOV
DL
Dskpatch
PROC
REST0RE_REAL_CURSOR
PUSH
Listing of
MOV
REALCURSORY
DH.REALCURSORX
CALL
GOTO_XY
POP
DX
RET
ENDP
PUBLIC
WRITE_PHANTOM
EXTRN
WRITE_ATTRIBUTE_N_TIMES:PROC
as the;
WRITE_ATTRIBUTE_N_TIMES, SAVE_REAL_CURSOR
Uses:
RESTORE_REAL_CURSOR
MOV_TO_HEX_POSITION
WRITE_PHANTOM
PROC
PUSH
CX
PUSH
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_POSITION
MOV
CX,4
MOV
DL,70h
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
MOV_TO_ASCII_POSITION
MOV
CX,1
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
RESTORE_REAL_CURSOR
POP
DX
POP
CX
RET
WRITE PHANTOM
ENDP
PUBLIC
ERASE_PHANTOM
EXTRN
WRITE_ATTRIBUTE_N_TIMES:PROG
WRITE PHANTOM.
Uses:
WRITEATTRIBUTENTIMES, SAVEREALCURSOR
RESTORE_REAL_CURSOR
MOV_TO_HEX_POSITION
535
Assembly Language
for the
ERASE_PHANTOM
PROC
PUSH
CX
PUSH
DX
CALL
SAVE_REAL_CURSOR
CALL
MOV_TO_HEX_POSITION
MOV
CX,4
MOV
DL,7
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
MOV_TO_ASCI I_POSITION
MOV
CX,1
CALL
WRITE_ATTRIBUTE_N_TIMES
CALL
RESTORE_REAL_CURSOR
POP
DX
POP
CX
RET
ERASE PHANTOM
ENDP
EXTRN
DISP_HALF_SECTOR:PROC, GOTO_XY:PROC
EXTRN
SECTOR_OFFSET:WORD
EXTRN
.DATA
.CODE
These two procedures move between the two half -sector displays.
WRITE_PHANTOM, DISP_HALF_SECTOR
Uses:
SAVE_REAL_CURSOR
Reads:
LINES_BEFORE_SECTOR
Writes:
SECTOR_OFFSET, PHANTOM_CURSOR_Y
SCROLL_UP
PUSH
ERASE_PHANTOM, GOTO_XY
RESTORE_REAL_CURSOR
PROC
DX
CALL
ERASE_PHANTOM
CALL
SAVE_REAL_CURSOR
XOR
DL,DL
MOV
DH LINES_BEFORE_SECTOR
,
ADD
DH
CALL
GOTO_XY
MOV
DX,256
MOV
SECTOR_OFFSET DX
CALL
DISP_HALF_SECTOR
CALL
RESTORE REALCURSOR
536
Listing of
MOV
PHANTOM_CURSOR_Y,0
CALL
WRITE_PHANTOM
POP
DX
Dskpatch
RET
SCROLL. UP
SCROLL. DOWN
PUSH
ENDP
PROC
DX
CALL
ERASE_PHANTOM
CALL
SAVE_REAL_CURSOR
XOR
DL.DL
MOV
DH LINES_BEFORE_SECTOR
,
ADD
DH,2
CALL
GOTO_XY
XOR
DX.DX
MOV
SECTOR_OFFSET,DX
CALL
DISP_HALF_SECTOR
CALL
RESTORE_REAL_CURSOR
MOV
PHANT0M_CURS0R_Y,15
CALL
WRITE_PHANTOM
POP
DX
RET
SCROLL DOWN
ENDP
END
VIDEO IO.ASM
.MODEL
SMALL
.DATA
PUBLIC
SCREEN_PTR
PUBLIC
SCREEN_X, SCREEN_Y
SCREEN_SEG
DW
SCREEN_PTR
DW
SCREEN_X
DB
SCREEN Y
DB
0B800h
.CODE
537
Assembly Language
PUBLIC
WRITE_STRING
DS:DX
Uses:
WRITE CHAR
WRITE_STRING
PROC
PUSH
AX
PUSH
DX
PUSH
SI
PUSHF
CLD
MOV
The
DB
(forward)
SI.DX
OR
AL.AL
JZ
HOV
END_OF_STRING
DL.AL
CALL
WRITECHAR
JMP
STRING LOOP
STRING_LOOP:
LODSB
yet?
END_OF_STRING:
POPF
POP
SI
POP
DX
POP
AX
RET
WRITE STRING
PUBLIC
ENDP
WRITE_HEX
This procedure converts the byte in the DL register to hex and writes;
the two hex digits at the current cursor position.
On Entry:
DL
WRITE_HEX
Entry point
PROC
PUSH
CX
PUSH
DX
538
MOV
DH,DL
MOV
CX,4
SHR
DL.CL
CALL
WRITE_HEX_DIGIT
MOV
DL.DH
AND
DL,0Fh
CALL
WRITE_HEX_DIGIT
POP
DX
POP
CX
Listing of
Dskpatch
RET
WRITE HEX
PUBLIC
ENDP
WRITE_HEX_DIGIT
On Entry:
DL
WRITE CHAR
Uses:
WRITE_HEX_DIGIT PROC
PUSH
DX
CMP
DL,10
JAE
HEX_LETTER
;No,
ADD
DL,"0"
;Yes,
JMP
Short WRITE_DIGIT
DL,"A"-10
CALL
WRITE_CHAR
POP
DX
convert to
letter
convert to a digit
HEX_LETTER
ADD
WRITE_DIGIT:
RET
PUBLIC
INIT_WRITE_CHAR
You need to call this procedure before you call WRITE_CHAR since
SCREEN SEG
539
Assembly Language
for the
PUSH
AX
PUSH
BX
MOV
BX,0B800h
INT
11h
AND
AL,30h
CMP
AL,30h
JNE
SET_BASE
;No,
MOV
BX,0B000h
;Yes,
MOV
SCREEN_SEG,BX
POP
BX
POP
AX
SET_BASE
RET
INIT WRITE CHAR ENDP
PUBLIC
WRITE_CHAR
EXTRN
CURSOR_RIGHT:PROC
DL
Uses:
CURSOR_RIGHT
Reads:
SCREEN_SEG, SCREEN_PTR
WRITECHAR
540
On entry:
PROC
PUSH
AX
PUSH
BX
PUSH
DX
PUSH
ES
MOV
AX,SCREEN_SEG
MOV
ES.AX
MOV
BX,SCREEN_PTR
MOV
DH,7
MOV
ES:[BX],DX
CALL
CURSOR RIGHT
POP
ES
POP
DX
POP
BX
POP
AX
Listing of
Dskpatch
RET
WRITE CHAR
PUBLIC
EN
WRITE_DECIMAL
On Entry:
DX
Uses:
WRITE_DECIMAL
PROC
PUSH
AX
PUSH
CX
PUSH
DX
PUSH
SI
MOV
AX.DX
MOV
SI, 10
XOR
CX.CX
NON_ZERO
XOR
DX,DX
DIV
SI
PUSH
DX
INC
CX
OR
AX, AX
;N =
JNE
NON_ZERO
;Nope, continue
yet?
WRITE_DIGIT_LOOP:
POP
DX
CALL
WRITE_HEX_DIGIT
LOOP
WRITE_DIGIT_LOOP
END_DECIMAL:
POP
SI
POP
DX
POP
CX
POP
AX
RET
WRITE DECIMAL
ENDP
541
Assembly Language
for the
PUBLIC
WRITE_CHAR_N_TIMES
character
DL
Character code
CX
WRITE CHAR
Uses:
WRITECHARNTIMES
PROC
PUSH
CX
CALL
WRITE_CHAR
N_TIMES:
LOOP
N_TIMES
POP
CX
RET
WRITE_CHAR_N_TIMES
ENDP
CX
DL
CURSOR RIGHT
Uses:
WRITE_ATTRIBUTE_N_TIMES PROC
PUSH
AX
PUSH
CX
PUSH
DI
PUSH
ES
MOV
AX.SCREENSEG
MOV
ES.AX
MOV
DI,SCREEN_PTR
INC
DI
MOV
AL,DL
ATTR_LOOP
;Save one attribute
STOSB
542
INC
DI
INC
SCREEN_X
LOOP
ATTR LOOP
jWrite N attributes
Listing of
DEC
DI
MOV
SCREENPTR.DI
POP
ES
POP
DI
POP
CX
POP
AX
Dskpatch
RET
WRITE_ATTRIBUTE_N_TIMES ENDP
PUBLIC
WRITEPATTERN
form
DB
On entry:
DS:DX
Uses:
WRITE CHAR
WRITE_PATTERN
TIMES
PROC
PUSH
AX
PUSH
CX
PUSH
DX
PUSH
SI
PUSHF
CLD
MOV
SI,DX
PATTERNLOOP
;Get character data into AL
LODSB
OR
AL.AL
JZ
END_PATTERN
;Yes,
MOV
DL,AL
;No,
(0h)?
return
set up to write character N times
LODSB
MOV
CL,AL
XOR
CH,CH
CALL
WRITE_CHAR_N_TIMES
JMP
PATTERN LOOP
343
Assembly Language
for the
END_PATTERN:
;Restore direction flag
POPF
POP
SI
POP
DX
POP
CX
POP
AX
RET
WRITE PATTERN
END
544
ENDP
C/C++ Libraries
in Assembly
I
in
his
appendix contains the source listings for the C/C++ Hbraries mentioned
Chapter 3 1 These
.
files
All
you have
change
is
you
will
need
file.
C/C++ com-
Topics Covered
Descriptions of Procedures
Assembly Language
for the
Descriptions of Procedures
The CLIB
bly
files
directory
C/C++ files
move a mouse
to
to
do
Chapter 3 1
The included
CLIB. LIB
this
book contains
cursor.
need
in
and
assem-
programs.
five
C/C++
C/C++
files.
files
You will
files.
SOCHAUB.INC
This
is
an include
file
used by
all
the other
ASM files.
MAKEFILE
This makefile
is
file.
CaRSOR.ASM
The
sor
seven functions and procedures in this module control the hardware cur-
you
see
on the
screen.
void SetCursor(int
size)
this
For example,
at the start
size
of the
call
SetCursor with
the
DOS
of
Then
to restore
exits.
hardware cursor.
If the cursor
is
turned
off,
such
as
by using
548
it
is
like
visible.
GetVisibleCursor except
is
turned
off,
you
will get a cursor size that will turn the cursor off
this value
C/C++
Libraries in
when you
Assembly
use
with SetCursor.
CursorOn
call
calls to
you
to
call
cursor.
You cannot
after
nest calls
A block cursor
is
underscore cursor.
FASTWRIT.ASM
The 12 procedures
in this
your screen. These procedures also work together with the procedures in
MOUSE.ASM
mouse
to
make
mouse
cursor before
writing to the screen, so you do not have to worry about hiding the
cursor yourself. If you
mouse
cursor, leading to
cursor,
mouse
You
will
in this
need
this
procedure to
initialize
you
call
module.
The procedures
in this
module put
want
characters in
fast.
You
will
KBD_IO.ASM.
549
Assembly Language
for the
void FastWriteRawChar(char
c)
The
But
some
this
procedure displays
them
characters as symbols
all
void FastWriteChar(char
c)
on the screen
meaning.
special
However,
it
ASCII 7 produces
gives special
meaning
to
of the current
a beep;
line.
void FastWriteString(char
screen. This procedure uses
*s)
in the string.
void FastWriteUDeciinal(int
as
Displays the
i)
number
on the screen
from
to
65535.
void FastWriteNChars(char
the character c
on the
c,
on the
FastWriteRawChar
screen.
x, int y)
Moves
the cursor to
hardware cursor
CursorOn
to the
to hide the
new
(x, y).
screen.
This
FASTWRIT.ASM
and the
it
matches
void FastGetXY(int
cursor in
550
(x, y).
call to
FastFlush.
C/C++
Libraries in
Assembly
HARDWARE.ASM
The
file
hardware.
int
no
cards,
= color
40 x 25
card,
it is
if
you have an
EGA or VGA
KBD_IO.ASM
The
five
int
functions in this
file
It
returns the
ASCII code
upper byte to
int
code
in the
or scan code.
It
character code
ASCII
code.
ASCII code
sets the
uses the
it
AND the scan code. The DOS call returns only the
On
(or
for
non-ASCII
keys)
in the
is
is
keyboard buffer.
ately after
wrong
int
It is
good idea
immedi-
characters.
KeyWaiting(void) Reports
buffer,
ReadRawChar would
and
if
if so, it returns
return; otherwise,
it
returns -1.
551
Assembly Language
for the
which
80h
Insert state
40h
Caps Lock on
20h
Num Lock on
lOh
Scroll
08h
Alt key
04h
Control key
02h
Left: shift:
Right
shift:
down:
on
Lock on
down
is
is
key
is
key
shift:
down
down
down
is
MOaSE.ASM
The procedures
in this
mouse
DOS
in
programs.
These procedures
mouse
are designed to
on the
screen.
this
call
any of the
by
calling function 0,
which
is
be
The
IBM
much
mouse), which
faster in
such
may
Init_mouse(
hardware the
first
must be
call:
all
mouse
a sofrware
mouse
mouse
reset.
After Init_mouse( )
552
mouse
cases.
(a serial
Once
mouse
do a software
does
it
or the
IBM
do
reset first.
Only
if
reset
seconds, which
is
hardware
reset.
Libraries in
mouse.
some
C/C++
initializes the
In
try to
can take
as
much
It tries
work
when
Assembly
mouse
as five
Norton Commander.
void UiihideMouse(void) Makes the mouse
to
calls to
UnhideMouse and
HideMouse.
void
calls to
void GetMousePosition(iiit
void SetMousePosition(int
the
mouse on
int
MouseButtons(int
x, int y)
Allows you to
of
mouse on
GetMousePosition,
the screen.
It also
it
returns
repons which
pressed:
Both buttons up
down
Left button
Right button
down
3 Both buttons
down
Makefile
Following
is
#
# This makefile creates the "Socha Libraries".
# change the defintion below of
553
Assembly Language
for the
.MODEL
.asm. obj
ml /DMEM_MODEL=$(MEM_MODEL)
/C
/Zi $<
# This line causes all the files to be assembled and added to the library.
#
Clib. lib:
SOCHAUB.INC
This
file is
used by
all
the
use these macros to write code that works in all memory models.
if
@DataSize
lodDS
textequ <lds>
;Yes,
lodES
textequ <les>
refES
textequ <es:>
in front of refs
else
use MOV to get pointer
lodDS
textequ <mov>
;No,
lodES
textequ <mov>
refES
textequ <>
endif
if ?CodeSize
use Far
else
554
;No,
use Near
C/C++
Libraries in
Assembly
CaRSOR.ASM
.MODEL
MEM_MODEL,C
INCLUDE sochalib.inc
This file contains a number of procedures that work with the screen
cursor.
SetCursor
GetVisibleCursor
GetCursor
CursorOf
CursorOn
CursorBlock
CursorUnderscore
gotoxy
get_xy
block cursor
get_active_page
set_cursor
fix_cursor (private)
.CODE
On Entry:
Uses:
But be careful!
DH
Row (Y)
DL
Column
(X)
555
Assembly Language
for the
gotoxy
proc
uses ax bx si di bp
call
get_active_page
mov
bh.al
mov
ah, 2
int
10h
ret
goto_xy
endp
cursor to
Returns:
AH
Row (Y)
AL
Column (X)
Uses:
get_xy
proc
uses bx dx si di bp
call
get_active_page
mov
bh,al
mov
ah,
int
10h
mov
ax,dx
ret
get_xy
endp
This procedure gets the page number for the page shown on the screen
and returns it in the AL register.
Returns:
AL
getactivepage
mov
ah, 15
int
10h
mov
al,bh
ret
getactivepage
556
uses bx si di bp
endp
C/C++
Libraries in
Assembly
.DATA
old_cursor_type
dw
.CODE
Usually
GetVisibleCursor(
SetCursor
cursorSize:Word
proc
cursorSize
mov
dx,
call
set_cursor
ret
SetCursor
endp
This procedure sets the end and start lines of the cursor.
On entry:
Writes:
setcursor
DH
DL
private use
call
GetCursor
mov
old_cursor_type, ax
;And save it
mov
ch.dh
mov
cl.dl
mov
ah,1
int
10h
ret
set cursor
endp
557
Assembly Language
for the
This procedure gets the start and end scan lines of the cursor.
If the cursor was not visible, it returns a visible cursor.
Call
GetCursor if you want the exact information on the old cursor.
Returns:
AH
AL
GetVisibleCursor
proc
call
GetCursor
cmp
ah,0Fh
jb
cursor_not_off
;No,
mov
ax,607h
;Yes,
call
fix cursor
cursornotoff
ret
GetVisibleCursor
endp
This procedure gets the start and end scan lines of the cursor.
You
it stores 0607h into the cursor type, which is the wrong value
Returns:
GetCursor
AH
AL
proc
uses bx ex dx si di bp
xor
bh,bh
mov
ah,
int
10h
mov
ax,cx
call
fix_cursor
ret
GetCursor
558
endp
u3
C/C++
Libraries in
Assembly
This procedure 'fixes* the cursor start and end scan lines in case
the ROM BIOS gave us bogus information:
On entry:
AH
AL
67h
607h
Returns:
extrn
fix_cursor
AX
GetDisplayRows:procRef
proc
private
;Is this a bogus COMPAQ cursor?
cmp
ax,67h
jne
not_bogus_compaq
;No,
mov
ax,607h
not_bogus_compaq
push
ax
int
I1h
and
al,30h
cmp
al,30h
pop
ax
jne
cursor_type_valid
;No,
is_monochrome:
push
ax
call
GetDisplayRows
cmp
ax, 25
pop
ax
ja
cursor_type_valid
;Yes,
cmp
ax,607h
;Yes,
jne
cursor_type_valid
;No,
mov
AX,0B0Ch
then continue
cursor_type_va lid:
ret
fix_cursor
endp
Uses:
SET CURSOR
339
Assembly Language
for the
CursorOff
proc
uses ax dx
mov
dh,0Fh
mov
dl,e
call
set_cursor
ret
CursorOff
endp
set_cursor
Uses:
Note: This procedure preserves the registers so you can call it from
assembly language.
CursorOn
proc
uses dx
mov
dx old_cursor_type
call
set_cursor
ret
CursorOn
endp
different number of
lines for the character cell, this procedure has to check the display;
type.
extrn
CursorBlock
GetDisplayTyperprocRef
proc
uses ax bx
xor
dh,dh
mov
dl,7
call
GetDisplayType
cmp
al,3
jne
block_is_graphics
;No,
mov
dl,13
block_is_graph Lcs:
call
set_cursor
ret
CursorBlock
560
endp
C/C++
Libraries in
Assembly
GetDisplayType:procRef
extrn
CursorUnderscore
proc
uses ax dx
mov
dh,6
mov
dl,7
call
GetDisplayType
cmp
al,3
jne
underscore_is_graphics
;No,
mov
dh,11
mov
dl,12
underscore_is_graphics
setcursor
call
ret
CursorUnderscore
endp
end
FASTWRIT.ASM
.MODEL
MEM_MODEL,C
INCLUDE sochalib.inc
Copyright
BELL
equ
TAB
equ
LF
equ
10
CR
equ
13
561
Assembly Language
for the
The procedures in this module are all designed for very fast writes
DOS is very slow, and so is the ROM BIOS.
So these
procedures poke characters directly, and very quickly, into memory.
to the screen.
Call this procedure any time you change the display mode
or screen.
InitFastDisplayModule
FastFlush
FastWriteRawChar
FastWriteChar
FastReadAttr
FastWriteString
FastWriteUDecimal
FastWriteNChars
Writes N copies of
FastWriteSpaces
FastGotoXY
FastSetCursor
FastGetXY
character
move_to_screen
fast_write_raw_char
fast_write_char
calc_display_offset
fast_goto_xy
Public variables:
This is a public variable
charattribute
clearattr
displaylines
.DATA
public
char_attribute
562
clear_attr
db
7,
wait_retrace_flag
db
0,
;1
topview_flag
db
0,
retrace
C/C++
displaybase
dw
display_offset
dw
displaypage
displaylines
db
dw
0B800h
25
Libraries in
screenx
screeny
screenptr
dw
line_buffer
dw
80 DUP (0)
line_ptr
dw
line_buffer
linecount
dw
line start
dw
max_lines
Assembly
dw
dw
equ
screen_offset
50
dw
0,
80,
160,
240,
320
dw
400,
480,
560,
640,
720
dw
800,
880,
960,
1040,
1120
dw
1200,
1280,
1360,
1440,
1520
dw
1600,
1680,
1760,
1840,
1920
dw
2000,
2080,
2160,
2240,
2320
2720
dw
2400,
2480,
2560,
2640,
dw
2800,
2880,
2960,
3040,
3120
dw
3200,
3280,
3360,
3440,
3520
dw
3600,
3680,
3760,
3840,
3920
dw
4000,
4080,
4160,
4240,
4320
dw
4400,
4480,
4560,
4640,
4720
.CODE
extrn
GetDisplayType:procRef
In HARDWARE module
extrn
EgaActive:procRef
In HARDWARE module
extrn
GetDisplayRows:procRef
In HARDWARE module
extrn
getxy :procRef
In CURSOR
module
extrn
get_active_page:procRef
In CURSOR
module
Call this procedure at least once before you call *any* other
procedures.
procedures use.
InitFastDisplayModule
proc
push
ax
push
dx
mov
display_base,0B000h
563
Assembly Language
for the
mov
(Jisplay_lines,25
mov
wait_retrace_flag,0
call
GetDisplayType
cmp
al,3
je
is_monochrome
;Yes,
mov
display_base 0B800h
call
EgaActive
or
ax, ax
jnz
is_ega
mov
wait_retrace_f lag
imp
Short finishinit
;Yes,
,
(-1)
is monochrome:
call
EgaActive
or
ax, ax
Jz
finish init
;No,
-1
isega:
This section of code gets the number of
screen lines for EGA and VGA monitors.
call
GetDisplayRows
cmp
al,max_lines
jbe
setdisplaylines
;No,
mov
al,max_lines
;Yes,
then set
set to
maxlines
set_display_lines
mov
finish init:
This section of code gets the current page
and calculates the offset.
564
push
ex
call
get_active_page
mov
display_page,al
mov
ah,al
xor
al,al
;AX = page
256
C/C++
Libraries in
Assembly
Multiply AX by 16
mov
cl,4
shl
ax.cl
;AX = page
mov
display_offset,ax
pop
ex
bx
push
di
push
es
;Get what we think is the display base
mov
bx,display_base
mov
es,bx
xor
di.di
ES:DI
mov
ah,0FEh
int
10h
mov
ax.es
cmp
ax.bx
je
notintopview
No,
mov
topview_flag,1
mov
display_base,ax
mov
display_offset,di
mov
display_page,0
mov
wait_retrace_f lag
Use page
,
for TopView
not_in_topview:
pop
es
pop
di
pop
bx
get_xy
mov
dx.ax
call
fast_goto_xy
call
FastReadAttr
mov
char_attribute,al
mov
clearattr.al
pop
dx
pop
ax
ret
InitFastDisplayModule
endp
565
Assembly Language
for the
void FastFlush(void)
Note: this subroutine preserves all the registers so you can call it
FastFlush
proc uses ax ex si di es
mov
cx,line_count
jcxz
done_fast_flush
lea
ax,line_buffer
mov
line_ptr,ax
;Reset
mov
si, ax
mov
ax,line_start
mov
di,ax
mov
ax,display_base
mov
es,ax
lineptr to start
of buffer
call
move_to_screen
mov
ax,line_start
mov
cx,line_count
shl
cx,1
add
ax, ex
mov
screen_ptr,ax
mov
line_start,ax
mov
line_count,0
done_fast_flush
ret
FastFlush
endp
extrn
HideMouse:procRef
extrn
UnhideMouse:procRef
On entry:
566
DS:SI
DI
move_to_screen
Libraries in
proc
private uses ax es
call
HideMouse
jcxz
donemoveto
mov
ax,display_base
mov
es,ax
push
CX
push
di
test
wait_retrace_f lag,
jnz
move_to_wait
;Yes.
movsw
jmp
Assembly
CX, SI, DI
eld
rep
C/C++
CX
Destroys:
;No,
Short f inish_move_t
move_to_wait
push
bx
push
dx
mov
dx,03DAh
move_to_loop:
;Get character from off-screen buffer
lodsw
mov
bx.ax
to_still_in_retrace
in
al,dx
test
al,1
jnz
to_still_in_retrace
cli
to_wait_f or_retrace
in
al,dx
test
al,1
jz
to_wait_for_retrace
mov
ax.bx
loop
move_to_loop
pop
dx
pop
bx
567
Assembly Language
for the
finish_move_to:
pop
di
pop
ex
test
topview_flag,1
;Are we in TopView?
Jz
done_move_to
mov
ah,0FFh
int
10h
done_move_to:
call
UnhideMouse
ret
move_to_screen
endp
FastWriteRawChar
proc
char: Word
mov
dl,
call
fast_write_raw_char
ret
FastWriteRawChar
endp
DL
Reads:
CHAR_ATTRIBUTE
fast_write_raw_char
568
On entry:
push
ds
pop
es
proc
private uses ax di es
;Set ES so it points to data segment
C/C++
Libraries in
cmp
screen_x,79
ja
done_write_raw
;No,
mov
di,line_ptr
mov
ah,char_attribute
mov
al.dl
Assembly
stosw
inc
screen_x
inc
line_count
mov
line_ptr,di
done_write_raw:
ret
endp
fast_write_raw_char
FastWriteChar
char: Word
proc
mov
dl,
call
fast_write_char
ret
FastWriteChar
endp
Bell
Tab
10
Line Feed
13
Carriage Return
On entry:
DL
fast_write_char
private
test
dl,0F0h
jz
special
Special character?
569
Assembly Language
for the
not_special:
call
ret
special:
cmp
dl.CR
Is it a carriage return?
je
do_cr
cmp
dl.LF
Is it a line feed?
je
do_lf
cmp
dl.TAB
Is it a tab?
je
do_tab
cmp
dl.BELL
Is it a bell?
je
do_bell
imp
Short not_special
do cr:
push
dx
mov
xor
dl,dl
call
fast_goto_xy
pop
dx
ret
do If:
push
ax
mov
ax,display_lines
dec
ax
cmp
screen_y,ax
pop
ax
passed_bottom
dx
mov
inc
dh
mov
call
fast_goto_xy
pop
dx
ret
passed_bottom:
570
jae
push
push
ax
push
bx
push
ex
push
dx
push
si
C/C++
Libraries in
push
di
push
bp
mov
ax,0601h
fflOV
bh,char_attribute
;Use char,
mov
cx,0
mov
mov
dl,4Fh
int
lOh
bp
pop
di
pop
si
pop
dx
pop
ex
pop
bx
pop
ax
dec
pop
Assembly
ret
do bell:
ret
do tab:
push
ex
push
dx
mov
dl,'
mov
cx,screen_x
and
ex, 7
neg
ex
add
ex, 8
'
;CX
:= 8
(SCREEN_X MOD 8)
ab_loop:
call
fast_write_raw_ehar
loop
tab_loop
pop
dx
pop
ex
ret
ast write char
endp
This procedure reads the attribute of the character under the cursor
Returns:
AX
571
Assembly Language
for the
proc
FastReadAttr
uses dx di es
mov
ax,display_base
mov
es.ax
mov
di,screen_ptr
inc
di
adapter.
there's only
test
wait_retrace_flag,1
jz
read_dont_wait
mov
dx,03DAh
read_still_in_retrace
in
al.dx
test
al,l
jnz
read_still_in_retrace
cli
read_wait_f or_retrace
in
al.dx
test
al,l
jz
read_wait_for_retrace
al,es: [di]
readdontwait
mov
sti
xor
ah, ah
ret
FastReadAttr
endp
It uses the
Uses:
FastWriteString proc
lodES
572
On entry:
si, string
C/C++
Libraries in
Assembly
write_string_loop:
mov
al.refES [si]
inc
si
or
al,al
jz
end_of_string
;Yes,
mov
dl.al
;No,
call
fast_write_char
imp
Short write_string_loop
end_of string:
ret
FastWriteString endp
On entry:
DX
Uses:
proc
FastWriteUDecimal
num:Word
;Put number in AX, where we want it
num
mov
ax,
mov
bx,10
xor
ex, ex
;Start with
notzero:
xor
dx.dx
div
bx
push
dx
inc
ex
or
ax, ax
;N ==
jnz
not zero
;No,
pop
dx
add
dl,
call
fast_write_char
loop
write_digit_loop
yet?
put more digits on stack
write_digit_loop
'0'
;Convert to
'0'
.
.
'9'
ret
FastWriteUDecimal
endp
Calls:
573
Assembly Language
for the
FastWriteNChars proc
mov
dl,
mov
ex,
count
jcxz
done_fast_write_chars
call
f ast_write_raw_char
loop
chars_loop
chars_loop:
done_f ast_write_chars
ret
FastWriteNChars endp
On entry:
CX
Calls:
FAST_WRITE_N_CHARS
FastWriteSpaces proc
INVOKE
count :Word
FastWriteNChars,
'
',
count
ret
FastWriteSpaces endp
(Note:
On entry:
Returns:
DH
Row
DL
Column
calc_display_offset
push
574
proc
private
bx
mov
bl,dh
xor
bh,bh
;Convert to a word
shl
bx,l
mov
ax,screen_offset[bx]
mov
bl,dl
xor
bh,bh
jConvert to a word
add
ax,bx
shl
ax,l
add
ax,display_of f set
pop
bx
C/C++
Libraries in
Assembly
ret
calc_display_off set
endp
f ast_goto_xy
void FastGotoXY(x, y)
FastGotoXY
proc
x:Word, y :Word
mov
Byte Ptr y
dl, Byte Ptr x
call
fast_goto_xy
mov
dh,
ret
FastGotoXY
extrn
endp
goto_xy:procRef
In CURSOR module
This is a version of GOTO_XY that works with the other fast screen
procedures.
the screen.
On entry:
But be careful!
DH
Row(Y)
DL
Column (X)
GOTO XY
Uses:
fast_goto_xy
proc
private uses ax bx dx
Flush any unwritten characters
call
FastFlush
mov
dec
bl
cmp
dh,bl
jbe
do_goto_xy
;No,
cmp
dhjbl
mov
dh.bl
jg
do_goto_xy
;Yes,
mov
dh,0
call
goto_xy
mov
mov
call
calc_display_offset
mov
screen_ptr,ax
do_goto_xy:
575
Assembly Language
for the
mov
line_start,ax
ret
fast_goto_xy
endp
This procedure will move the real cursor to the position of the
fast cursor, which is just a pair of numbers stored in memory.
Note: This procedure preserves the registers so you can call it from
assembly language.
FastSetCursor
proc
uses dx
mov
mov
call
goto_xy
ret
FastSetCursor
endp
module procedures.
moving the cursor to
FASTGOTOXY
Instead of
position.
Column
Returns:
Row
FastGetXY
bx,
Get pointer to
mov
ax,
screen_x
Get current
mov
refES [bx], ax
lodES
bx,
mov
ax,
screen_y
mov
refES [bx], ax
ret
FastGetXY
if
576
proc
lodES
endp
into es:[bx]
position
variable
into es:[bx]
PUBLIC
FAST_CLEAR_TO_EOL
EXTRN
CLEAR WINDOW:NEAR
C/C++
Libraries in
Assembly
This procedure clears the line from the current cursor position to
the end of the line.
PUBLIC
_FAST_CLEAR_TO_EOL
_FAST_CLEAR_TO_EOL
LABEL
NEAR
FAST_CLEAR_TO_EOL
PROC
NEAR
PUSH
AX
PUSH
BX
MOV
MOV
MOV
AL,79
CMP
BL.AL
JA
MOV
DONT_CLEAR_TO_EOL
;No,
AH.BH
CALL
CLEAR WINDOW
DONT_CLEAR_TO_EOL:
POP
BX
POP
AX
RET
FAST CLEAR TO EOL
ENDP
endif
end
HARDWARE.ASM
.MODEL
MEM_MODEL,C
INCLUDE sochalib.inc
JS
--
577
Assembly Language
for the
GetDisplayType
is_ega (private)
EgaActive
GetDisplayRows
rom_seg
segment at 40h
org
4Ah
DW
crt cols
org
87h
egainfo
DB
rom_seg
ends
.CODE
Returns:
AX
Destroys:
No display cards
1
If monochrome card
AH
GetDisplayType
proc
;Get equipment flags
int
11h
mov
cl,4
shr
aXjCl
and
ax,
ret
GetDisplayType
endp
Volume
2,
Returns:
578
Number
11
ZR
NZ
Otherwise
is_ega
C/C++
Libraries in
proc
private use
mov
ax,1200h
mov
bl,10h
mov
bh,0FFh
mov
cl,0Fh
int
ieh
cmp
cl,0Ch
jae
not_ega
No,
cmp
bh,1
ia
not_ega
No,
cmp
bl,3
Assembly
ja
not_ega
No,
xor
ax, ax
done_is_ega:
ret
notega:
is_ega
xor
ax, ax
inc
ax
imp
clone_is_ega
endp
Returns:
EgaActive
-1
proc
uses es
call
is_ega
jnz
eganotactive
;No,
mov
ax,rom_seg
mov
es,ax
test
es:ega_info,8
jnz
ega_not_active
;No
xor
ax, ax
;Yes,
not
ax
imp
done_ega_active
return
-1
579
Assembly Language
for the
ega_not_active:
xor
done_ega_active
ax, ax
;Return
ret
EgaActive
endp
Returns:
AX
GetDisplayRows
25
> 25
proc uses bx si di bp es
call
EgaActive
or
ax, ax
mov
al,25
done_get_rows
;No,
mov
ax,1130h
xor
bh.bh
Return
if no EGA card
return 25 lines
int
10h
inc
dl
mov
al.dl
;Returns result in AX
ah, ah
done_get_rows:
xor
ret
GetDisplayRows
endp
end
KBD_IO.ASM
.MODEL
MEM_MODEL,C
INCLUDE sochalib.inc
580
Copyright
C/C++
Libraries in
Assembly
ReadKeyO
scan_to_ext ended
ReadRawKey(
ClearKbdBufferO
KeyWaitingO
ShiftKeysO
if it is empty.
.CODE
public ReadKey
This procedure uses the ROM BIOS routines to read a single character.
It returns the ASCII code for keys that generate an ASCII character.
But if you push one of the key-pad or function keys, this procedure
will return the scan code in the lower byte and set the upper byte
to 1.
Returns:
ReadKey proc
xor
ah, ah
int
16h
call
scan_to_extended
eld
ret
ReadKey endp
581
Assembly Language
for the
t
This procedure converts a scan -code/ASCII -code pair into an extended
character.
If the lower byte is 0, this procedure puts the scan
code into the lower byte and sets the upper byte to 1.
Otherwise, it
sets the upper byte to 0.
On entry:
Returns:
AH
AL
ASCII code, or
This procedure now works also for the grey keys on the
Note:
proc
private
or
al,al
je
special. key
cmp
al,0E0h
je
special key
;Yes,
xor
ah, ah
;No,
xchg
al,ah
mov
ah,1
;And set AH =
then handle it
return the ASCII code
ret
special_key
ret
scan to extended
end
This procedure reads one character (or one special function key) from
the keyboard and returns the ASCII code, or scan code.
This procedure uses the ROM BIOS call so it can read both the
ASCII code.
Returns:
AH
This is
AL
582
ReadRawKey
C/C++
Libraries in
Assembly
proc
mov
ah,0
int
16h
eld
ret
ReadRawKey
endp
This procedure clears the keyboard buffer of any characters that may
still be around.
ClearKbdBuffer
proc
push
dx
mov
ax,0C06h
mov
dl,0FFh
int
21h
pop
dx
eld
ret
ClearKbdBuffer
endp
This procedure checks the keyboard buffer to see if there are any
NOTE: The ROM BIOS returns a scan code and character code of
after
NOTE: This procedure issues an INT 28h before checking the keyboard
system resources.
KeyWaiting
proc
int
28h
mov
ah,1
int
16h
jnz
done_kbd_hit
xor
ax, ax
jReturn
-1
for no character
583
h2
Assembly Language
for the
not
done_kbcl_hit:
eld
ret
KeyWaiting
endp
INS_STATE
80h
CAPS_STATE
40h
NUM_STATE
20h
SCROLL_STATE
10h
Scroll lock is on
ALT_SHIFT
08h
CTL_SHIFT
04h
LEFT_SHIFT
02h
RIGHT_SHIFT
01
ShiftKeys
mov
proc
ah,
int
16h
xor
ah, ah
eld
ret
ShiftKeys
endp
end
MOaSE.ASM
.MODEL
MEM_MODEL,C
INCLUDE sochalib.inc
:J
584
Copyright
C/C++
Libraries in
Assembly
InitMouse(
InitMouseSw(
-1
Mouse installed
No mouse installed
HideMouser(
UnhideMouse(
Get_mouse_position(&x, &y);
Set_mouse_position x y
Mouse_buttons(&x, &y);
.DATA
public
mouse_installed
DB
swapbuttons
mousevisible
DW
DB
;Visible if >
DB
;Make it a word
DW
mouse cursor
.CODE
Returns:
AX
-1
check_int_33
proc
private
uses bx es
p
mov
ax,3533h
int
21h
mov
ax,es
or
ax, ax
jz
no_int_33
;No,
or
bx,bx
jz
no_int_33
;No,
then return
then return
585
Assembly Language
for the
mov
ax,0FFFFh
jmp
Short done_check_int_33
Return
-1,
no_int_33:
xor
ax, ax
done_check_int_33
ret
check_int_33
endp
0,
which is
can take several seconds (a serial mouse or an IBM mouse), which may
not be acceptable.
Once
Init_inouse() must be called at least to initialize
the mouse hardware the first time since not all mouse
After Init_mouse()
From then on you can call Init_mouse_sw() for a fast
reset.
Init_mouse_sw(
InitMouse
proc
mov
bx,0
call
do_init_mouse
ret
InitMouse
endp
It tries to do a
software
do a hardware reset.
In some cases
586
InitMouseSw
C/C + +
Libraries in
Assembly
proc
mov
bx,1
call
doinitmouse
ret
InitMouseSw
endp
This procedure resets the mouse software, and checks to see if the
mouse and mouse software are installed.
On entry:
It
Do a hardware reset
BX
Do a soft reset
Returns:
AX
do_init_mouse
EgaActive procRef
:
proc
private
call
check_int_33
or
ax, ax
jz
no_mouse
;No,
or
bx,bx
;Yes,
jz
do_hardware_reset
;Yes,
do_reset:
No,
mov
ax, 33
int
33h
cmp
ax, 33
je
do_hardware_reset
cmp
ax,
jne
do_hardware_reset
No,
Cfflp
bx,2
je
finish_init
Yes,
-1
do_hardware_reset
mov
ax,0
int
33h
or
ax, ax
jz
no_mouse
;No,
f inishinit:
mov
ax, 10
xor
bXjbx
587
Assembly Language
for the
mov
cx.OFFFFh
mov
dx,7700h
int
33h
;Returns
mov
mouse_visible,0
call
EgaActive
or
ax, ax
Is EGA active?
jz
done_init_is_mouse
No,
mov
ax,1130h
xor
bh,bh
int
10h
inc
dl
DL = # rows
cmp
dl,25
je
done_init_is_mouse
mov
al.dl
mov
cl,8
mul
cl
dec
ax
AX = screen height
mov
dx.ax
DX = screen height
mov
ax, 8
mov
CX,0
int
33h
-1
doneinitis mouse
xor
ax, ax
not
ax
clone_init_mouse
;Return
-1
mouse_installed,al
xor
ax, ax
jmp
doneinitmouse
mov
ret
no_mouse:
do_init_mouse
endp
unhide
In
588
I
UnhideMouse
C/C++
Libraries in
Assembly
proc
test
mouse_installed,0FFh
jz
dor,e_unhide
;No,
inc
mouse_visible
cmp
mouse_visible,1
jne
done_unhide
;No,
push
ax
;Yes,
mov
ax,1
int
33h
pop
ax
don't do anything
doneunhide:
ret
UnhideMouse
endp
HideMouse
proc
;Is the mouse installed?
test
mouse_installed 0FFh
donehide
;No,
dec
mouse_visible
cmp
mouse_visible,0
jne
done_hide
;No,
push
ax
mov
ax, 2
int
33h
pop
ax
don't do anything
done_hide:
ret
HideMouse
endp
coordinates.
proc
test
mouse_installed 0FFh
jz
done_get_mouse
;No,
mov
ax, 3
int
33h
lodES
bx,x
;Get address of X
589
Assembly Language
for the
shr
cx,1
shr
cx,1
shr
cx,1
mov
refES [bx],cx
;Save X coordinate
shr
dx,1
shr
dx,1
shr
dx,1
lodES
bx.y
;Get address of Y
mov
refES [bx],dx
;Save Y coordinate
clone_get_mouse
ret
GetMousePosition
endp
coordinates.
SetMousePosition(int
SetMousePosition
x,
proc
int y)
x:Word, y:Word
test
mouse_installed,0FFh
Jz
done_set_mouse
;No,
mov
ax, 4
mov
cx,x
shl
cx,1
shl
cx,1
shl
cx,1
mov
dx,y
shl
dx,1
shl
dx,1
shl
dx,1
int
33h
done_set_mouse:
ret
SetMousePosition
endp
int *y);
590
C/C++
Libraries in
Assembly
Both buttons up
9
1
FastFlush:procRef
extrn
MouseButtons
proc
x:Ptr Word,
Ptr Word
if mouse not installed
xor
ax, ax
;Return
test
jz
done_mouse_buttons
;No,
call
FastFl ush
mov
ax,
int
33h
mov
ax,bx
cmp
ax,
Jb
middle _not_down
;No,
mov
ax, 3
;Yes,
imp
Short finish_buttons
or
ax, ax
jz
finish _buttons
;Yes,
cmp
swap_buttons,0
jz
finish _buttons
;No,
xor
ax,
middle_not_down
then return
then continue.
set to both buttons
calculate coordinates
finish_buttons:
lodES
bx,x
shr
cx,1
shr
cx,1
shr
ex,
mov
refES [bx],cx
lodES
bx,y
shr
dx,1
shr
dx,1
shr
dx,1
mov
refES [bx],dx
done_mouse_buttons
ret
MouseButtons
endp
end
591
NID
fx
Miscellaneous
Tables
1 he eight reference
setting character
tables in this
colors,
and
interrupts.
Assembly Language
Decimal
594
Hex
Character
Graphic
Decimal
Hex
Character
000
00
nul
028
IC
FS
001
01
029
ID
GS
002
02
030
IE
RS
003
03
031
IF
US
004
04
032
20
SP
005
05
033
21
II
006
06
034
22
007
07
035
23
008
08
036
24
009
09
037
25
010
OA
038
26
%
&
Oil
OB
CT
039
27
012
OC
040
28
013
OD
041
29
>
014
OE
jj
042
2A
015
OF
043
2B
016
10
044
017
11
-*
045
2C
2D
018
12
046
2E
019
13
!!
047
2F
020
14
048
30
021
15
049
31
022
16
050
32
023
17
051
33
024
18
052
34
025
19
053
35
026
lA
->
054
36
027
IB
<r-
055
37
>
Graphic
1
'
Graphic
Hex
Decimal
Hex
056
38
086
56
057
39
087
57
058
3A
088
58
059
3B
>
089
59
060
3C
<
090
5A
061
3D
091
5B
062
3E
>
092
5C
063
3F
>
093
5D
064
40
094
5E
065
41
095
5F
066
42
096
60
067
43
097
61
068
44
098
62
069
45
099
63
070
46
100
64
071
47
101
65
072
48
G
H
102
66
073
49
103
67
074
4A
104
68
075
4B
105
69
076
4C
106
6A
077
4D
107
6B
078
4E
108
6C
079
4F
N
O
109
6D
080
50
110
6E
081
51
111
6F
082
52
112
70
083
53
113
71
084
54
114
72
085
55
115
73
Character
Miscellaneous Tables
Decimal
Character
595
Assembly Language
for the
Graphic
Decimal
596
Hex
Character
Graphic
Decimal
Hex
Character
116
74
146
92
117
75
147
93
118
l(i
148
94
119
11
149
95
120
78
150
96
121
79
151
97
ii
122
7A
152
98
123
7B
153
99
124
154
9A
125
7C
7D
155
9B
<t
126
7E
156
90
127
7F
DEL
157
9D
128
80
158
9E
Pt
129
81
ii
159
9F
130
82
160
AO
131
83
161
Al
132
84
162
133
85
163
134
86
164
135
87
165
136
88
166
137
89
167
138
8A
168
139
8B
169
A2
A3
A4
A5
A6
A7
A8
A9
140
170
AA
141
8C
8D
171
AB
yz
142
8E
172
8F
173
AC
AD
143
A
A
144
90
174
AE
145
91
ae
175
AF
n
ISf
a
o
I
r-
Graphic
Decimal
Hex
Character
Graphic
Decimal
Hex
206
208
CE
CF
DO
209
Dl
210
Character
176
BO
177
Bl
178
B2
179
B3
180
B4
181
B5
182
B6
-II
212
183
B7
71
213
184
B8
214
185
B9
il
215
186
BA
II
216
187
BB
ii
217
D2
D3
D4
D5
D6
D7
D8
D9
188
BC
218
DA
189
BD
219
DB
190
BE
220
191
BF
221
DC
DD
192
CO
222
DE
193
CI
223
DF
194
C2
C3
C4
C5
C6
C7
C8
C9
224
EO
195
196
197
198
199
200
201
I
I
I
I
-\
207
211
ir
^
=f
-n-
^
^
r
rr
jf
+
^
225
El
j8
226
E2
227
E3
1=
228
E4
\[
229
E5
230
E6
\i
^
ff
231
E7
232
E8
202
CA
203
CB
233
E9
204
CC
CD
1^
234
EA
235
EB
205
Miscellaneous Tables
597
Assembly Language
for the
Graphic
icimal
Hex
Graphic
Character
Decimal
Hex
246
F6
-5-
247
F7
a:
Character
236
EC
237
ED
238
EE
248
F8
239
EF
249
F9
240
FO
250
FA
241
Fl
251
FB
242
F2
>
252
FC
Tl
243
F3
<
253
FD
244
F4
254
FE
245
F5
255
FF
oo
Blue
Green
Cyan
Red
Violet
Brown
White
Add
16 + foreground color
8 to the foreground color for the bright versions, or add 8 to the back-
ground color
to turn
on
blinking.
keys
character code
a decimal
two-
followed by
598
a scan code.
The
all
Miscellaneous Tables
Tab
15
Shift
16-25
Q,
W,
E, R, T, Y,
H,
30-38
44-50
59-68
F 1 through F 1
71
Home
72
Cursor
73
PgUp
75
Cursor Left
11
Cursor Right
79
End
80
Cursor
81
PgDn
82
Ins
83
Del
84-93
Shift
94-103
104-113
114
Control PrtSc
J,
I,
O, P
K, L
Up
Down
Fl through FIO
115
116
117
Control
End
118
Control
PgDn
119
Control
Home
120-131
132
Control
Table
U,
1, 2, 3, 4, 5, 6, 7, 8, 9, 0, -,
PgUp
D-4 Table
of Addressing
Modes
Addressing Mode
Format ofAddress
Register
register (such as
AX)
None
Immediate
None
continues
599
Assembly Language
for the
\
Addressing Mode
Format ofAddress
Base Relative*
Direct Indexed*
[BX]
DS
[BP]
SS
[DI]
[SI]
DS
DS
label[BX]
DS
label[BP]
SS
label[DI]
DS
DS
labei[SI]
Base Indexed*
DS
DS
label[BX+SI]
label[BX+DI]
[BP+SI]
SS
label[BP+DI]
SS
label
String
Commands:
can be replaced by
[disp+...],
Write
where
disp
IS
to
ES:DI
a displacement. Thus,
we could
would be 10 + BX.
The AL
mode number.
Text Modes
600
(AL)=0
(AL)=1
40 by 25, color
(AL)=2
(AL)=3
80 by 25, color
(AL)=7
The
top line
Miscellaneous Tables
Mode
Graphics
(AH)=1
(AL)=4
(AL)=5
(AL)=6
(CH)
is
(CL)
Last scan
Une of the
to 3
cursor.
left
(BH)
is
room
The
is
the
most
0.
position.
Page number
(DH,DL)
(CHjCL)
Cursor
size
(AH) =4
Read
(AH) =5
(AL)
upper
number of the
(BH)
light
position; the
exit
(0,0).
On
is
(DH,DL)
(AH) =3
monochrome
pen position
(see
from
(from
to 3 for
to 7 for
modes 2 and
modes
3)
601
Assembly Language
for the
(AH)=6
ScroU up.
Number
(AL)
of lines to blank
window. Normal
(AH) =9
one
line.
window.
(CH,CL)
left
(DH.DL)
(BH)
corner of window
ScroU down.
bottom of the
scrolling blanks
(AH)=7
at the
Read
attribute
blank
at the
top of the
cursor.
(BH)
(AL)
Character read
(AH)
modes
only)
(BH)
Display page
(CX)
Number
(text
modes
only)
anribute on screen
(AL)
Character to write
(BL)
Attribute to write
(AH)=11
(BH)
Display page
(CX)
Numberof times
(AL)
Character to write
to 13
to write character
602
for
(AH)=14
Write
teletype. Write
A'Viscellaneous Tables
(AH)= 1 5
(AL)
Character to write
(BL)
(BH)
Display page
(text
mode)
state.
mode
(AL)
Display
(AH)
Number
(BH)
currently set
INT
in this
book
to read char-
(AH)=0
Keyboard
you
to type a charac-
ter
on the keyboard.
scan code in
AH.
It
returns the
ASCII code
list
in
AL will
AL and
be
the
set to 0.
See
press (0 for
special keys).
(AH)
(AH)=1
Keyboard
any
ZF
if a
character
is
waiting,
1 if
there are
no
characters waiting.
(AL)
(AH)
to be read.
603
Assembly Language
for the
(AH)=2
Shift status. This function returns a byte with the state of the
various shift keys:
Status of the shift keys:
(AL)
7 6 5 4 3 2
Caps Lock on
plete
list,
Num Lock on
Scroll
Alt key
Left shift
....
on
Insert
Right
Lock on
down
down
shift
down
21h Functions
INT 21h functions used in this book. For a more comIBM DOS Technical Reference msmuA.
(AH)=1
(AL)
(AH) =2
an ASCII
this
in the
AL
register.
For
meaning
screen.
to this function:
move
the cursor
left
one character
position.
Tab:
Move
604
Tab
stops are
Line feed:
ODh
Carriage return:
current
Move
of the
to the start
line.
(DL)
(AH)=8
Move
OAh
Miscellaneous Tables
a character
from the
(AL)
(AH) =9
the
DS:DX
by the
string pointed to
end of the
$ character.
DS:DX
(AH)=OAh Read
string.
(AH)=25h
new
(AH)=35h
details.
routine.
(AL)
Interrupt number.
DS:DX
(AH)=4Ch
number given
(AL)
Interrupt number.
ES:BX
Exit to
for
DOS.
both
Returns to
DOS,
like
INT
interrupt
in
AL.
20h, but
it
works
works only
(AL)
batch
set to 0,
commands
IF and
DOS
ERRORLEVEL to
detect errors.
605
Assembly Language
for the
DOS
calls for
sectors.
On entry:
(AL)
(CX)
Number of sectors
(DX)
Number
sector
DS:BX
is
of the
to read at
first
one time
0)
On entry:
(AL)
(CX)
Number
of sectors to write
(DX)
Number
of the
sector
DS:BX
is
first
at
one time
0)
we want
to
Information Returned by
Both
register.
or
They also
POPF
ample)
to
remove
this
use a
for
AX
POP
an ex-
Returns:
Carry Flag
606
(AL)
DOS
(AH)
error code
error
80h The
Miscellaneous Tables
failed
03h Tried
sector
we
asked for
error
Destroys
SI,
DI,
BP
607
Index
Symbols
$ character, 52
access rights,
accessing
365
/Zi switch,
/zi
switch,
369
362
365
adapters
(underscore) in
procedures,
color graphics,
monochrome
417
OAh
460
DOS
80286 microprocessor,
4,
398
ADC instruction, 58
ADD instruction, 30-34
Add with Carry, see ADC
322
471-472
function,
32-bit registers,
398
display,
460
instruction
80386 microprocessor, 4
addresses
482
hex,
222-226
80486 microprocessor, 4
LEA, 211
moving, 211
return
485
8088 microprocessor, 4
80x86,
popping, 91
saving,
see
microprocessors
starting,
90
141
addressing
direct
memory, 192
Assembly Language
for the
memory, 188
indirect
modes, 186
accessing
memory, 186-189
600
600
memory, 600
register,
600
5,
17-19
61-63
displaying,
57
printing,
BP
AND instruction, 75
shift,
language, 88
binary numbers,
18-20
boundary conditions, 72
mode, 188,
191-193,600
BASIC
bits,
489-492
register,
423
breakpoints, 62
84
594
asembling separate files, 166-170
.ASM
330-331,336,498,528-530
base indexed addressing mode, 193,
600
600
ASCII
BACK_SPACE procedure,
characters, 71,
bugs, 6
extension, 102
358-360
building
Assemble command, 47
100-104
assembler, 102
TEST.EXEfile, 177-178
hexadecimal numbers, 103
procedures, 116-118
assembling
WRITESTR.ASM
BX register,
26-27
byte registers, 34
bytes,
18-19
program, 106
high,
34
assembly
conditional,
in-line,
low, 34
436-438
lower, 134
443-444
global variables,
writing,
441-443
microprocessors, 34-35
upper, 134
440-441
assembly language, 88
ASSUME directive,
attributes,
automatic response
AX register,
610
381, 392-395
260
26-27
C/C++
files,
355
language
fiinctions,
418-419
parameters,
439
Index
accessing,
passing,
435-438
420-426
procedures
compared
414-415
to assembly,
GOTO_XY,
416
42
82
CL
register,
CLD
426
READ_KEY, 428
WRITE_STRING,
74
instruction, 218,
232
420-421,
instruction
CLEAR_SCREEN procedure,
426
writing,
220-222
printing,
reading,
CLEAR_SCREEN,
C/C++
graphics,
414-415,496,503
439
libraries,
CLEAR_TO_END_OF_LINE
492
caIc_display_ofFset procedure,
calculating negative numbers,
CALL instruction,
244,
574
33
506
88-91, 149-151,
424
264-267
FAR, 430
581,583
intersegment, 149
intrasegment, 149
NEAR, 430
GOTO_XY procedure,
nested, 91
calling procedures,
89
420-421
CMP instruction, 70
(CRLF), 197
CS
Code Segment,
CF,
see
Carry Flag
CGROUP group,
385
CHAPS
486-488
directory,
CHAR_NUM_LIMIT procedure,
see
register
codes
ASCII
color,
character,
594
598
extended, 82
317
character strings, writing, 50-52
keyboard, 598-599
characters
machine, 28
model-independent
$,52
adding to dumps, 194-196
accessing
creating,
437
attributes,
426
260
echoing, 94
editing, 286,
438
repeating, 59
scan, 82,
306-310
parameters,
276
611
Assembly Language
for the
color
codes,
598
OBJ
words
count,
creating
Enter, 29, 33
106
128-129
to decimal digits,
shift,
registers,
74
Makefile,
206
Hexarithmetic, 7
map, 356
Link, 188
source, 102,
Load, 158-159
text,
105-106
102
Name, 49
libraries,
Proceed, 63
Register,
26
phantom
CRLF
Trace, 3 1 42
,
Unassemble, 45
comment
headers, 172-174
complementing numbers, 20
cursors,
285
(Carriage Return-Line
register, 30,
141-142
CURRENT_SECTOR_NO
memory variable, 251
CLEAR_TO_END_OF_LINE
complements, 20
conditional
CURSOR.RIGHT procedure,
assembly, 436-438
jumps, 70
conditions, boundary,
553-554
Feed), 197
CS
Write, 49
72
conversions, verifying, 43
CONVERT_HEX_DIGIT
procedure, 317, 498, 523-525
converting
fix_cursor procedure,
94
hex to ASCII, 71
612
files,
files
42, 45
till,
EXE
48
Dump,
Go
to
Assemble, 47
51
files
559
Index
GetVisibleCursor procedure,
558
GOTO_XY procedure,
246,
SEND_CRLF
procedure,
Debug program,
commands
Assemble, 47
Dump,
51
Enter, 29, 33
Go
409-410,496, 506
5-7
till,
42, 45
Hexarithmetic, 7
UPDATE_REAL_CURSOR
Link, 188
UPDATE_VIRTUAL_CURSOR
procedure, 409, 496, 505
CURSOR_RIGHT procedure,
262-263, 407, 496, 504
Load, 158-159
Name, 49
Proceed, 63
Register,
26
Trace, 3 1 42
,
Unassemble, 45
Write, 49
reading
files into,
118
debuggers
cursors
moving, 246-247
Source-Level, 361
285
see also.
Debug program
debugging, 6
549-561
CX register,
CY status,
CodeView, 361-365
source-level,
360-361, 365
decimal
56
input,
323-326
numbers, converting
to hexadecimal, 13-14
FAR, 432-441
moving
into registers,
47-50
NEAR, 432-438
Data Segment, 142, 193-194
defining
DATA?
descriptor tables,
directive,
DATA_SEG
215-216
procedure, 270
380-381
463-464
GDT, 463
LDT, 463
613
Assembly Language
for the
170-174
see
DI
register
direct
READ_SECTOR procedure,
memory
addressing,
92
104
DATA?, 215-216
DOSSEG,
211,230-231,245,496,509
updated version, 250-251
.MODEL, 381
ASSUME, 381,392-395
WRITE_SECTOR procedure,
353-354, 497, 509
DISK_PATCH
procedure, 249,
255,271,498,520
147
ELSE, 436
DISKLITE
END,
Disklite program,
104
directory, 486,
492
448
ENDIF, 436
DISKLITE.ASM
ENDP, 117
ENDS, 381
EQU, 198
EXTRN, 166, 212
DISPLAY_DRIVE_LETTER
FAR, 150-151
GET_NUM_FLOPPIES
IF,
PUBLIC,
file,
452-457
GET_DISPLAY_BASE
454
procedure, 451,
436
INVOKE, 477
NEAR, 150-151
PROC, 117,421
INIT_VECTORS
procedure,
451-452,456
INTERCEPT_DISKETTE_INT
procedure, 451-454
121
SEG, 435
SAVE_SCREEN
SEGMENT, 381
TEXTEQU, 437
WRITE_TO_SCREEN
ADVANCED,
procedure, 451,
486, 489-492
CHAPS, 486-488
DISKLITE.ASM
floppy, 158
writing
root,
159
456
file,
492
disks
GLIB, 486
WINDOWS, 492
procedure,
451,455
directories
to,
352-354
DISP_HALF_SECTOR
procedure, 197, 208-210,
497,516
614
file
PREVIOUS_SECTOR
mode,
600
directives,
251
130
193,
variable,
DISK_IO.ASM
NEXT_SECTOR procedure,
DH register, 34
DI
DISK_DRIVE_NO memory
Index
DISP_LINE
procedure, 194,
221-224,497,517
DISP_SEC.ASM
displaying
187-188,
file,
250
registers,
26
displays
DISP_HALF_SECTOR
DISP_LINE
procedure,
194-195,221-226,497,517
INIT_SEC_DISP
procedure,
232-234
numbers
in,
scrolling,
305
DIV instruction,
37
division, microprocessors,
DL register,
WRITE_HEADER procedure,
253,266,497,514
WRITE_PROMPT_LINE
procedure, 276-277, 497, 518
WRITE_TOP_HEX_NUMBERS
procedure, 233, 497, 515
DISPATCH.ASM
file,
272-273,
302-303, 306-307
DISPATCHER,
346-348, 497,
WRITE_SECTOR procedure,
register,
105
147
142, 193-194
502-503, 531-537
DISPATCH.ASM
352-353
DISPATCH_TABLE procedure,
file,
510-512
DSKPATCH.ASM
273, 303
DISPATCHER procedure,
359,
497,511
comparing words, 274
dispatch table,
274
prompt
linkinfi) file,
511
line,
270
display routines,
240
DISPLAY_DRIVE_LETTER
procedure, 451, 455
37
34
file,
519-520
PHANTOM.ASM file,
531-537
VIDEO_IO.ASM
file,
537-544
makefile,
501-502
overview^,
161-162
dump, 160
special keys,
491
615
Assembly Language
for the
EQU directive,
ERASE_PHANTOM
INIT_WRITE_CHAR
356-358
to,
register,
392
142,
OR, 131
EXE2BIN.EXE program, 107
Exclusive
dumps
adding characters
procedure,
ES
procedure, 399
DSKPATCH.MAP file,
Dump command, 5
198
194-196
45
exit instructions,
DX register, 26, 34
extended codes, 82
extended
memory addressing,
461-463
Extending DOS:
EBX register,
473
Guide
echoing characters, 94
EDIT_BYTE
procedure, 306-307,
498, 522
A Programmer's
Protected-Mode
DOS,
484
extensions
.ASM, 102
editing
.OBJ, 106
characters, 286,
files
to
in
PWB,
306-3 1
178-179
external
files,
166
procedures, 168
ES
EXTRN directive,
166,
register
212
WRITE_TO_MEMORY
procedure, 498, 521
editors, text,
102
ELSE
432-441
436
data,
END directive,
104
directive,
directive,
436
149, 274,
430
directive,
ENDIF
616
FAR
CALL instruction,
ftinctions,
150-151
432
FAST_CLEAR_TO_EOL
procedure, 577
Index
FastWriteUDecimal procedure,
fast_write_raw_char procedure,
550, 573
INIT_FAST_DISPLAY_MODULE
procedure, 562
568
FastFlush procedure, 549, 566
InitFastDisplayModule
FASTWRIT.ASM
file
calc_display_ofFset procedure,
574
FAST_CLEAR_TO_EOL
procedure, 577
574
574
fast_write_char procedure,
FastWriteUDecimal procedure,
569-571
fast_write_raw_char procedure,
568
FastFlush procedure, 549, 566
550, 573
files
CLIB.ASM
575
FastReadAttr procedure, 550,
572
FastSetCursor procedure, 550,
576
FastWriteChar procedure, 550,
569
FastWriteNChars procedure,
550, 574
FastWriteRawChar procedure,
550, 568
574
FastWriteString procedure, 572
420-421
CURSOR.ASM, 197-198
CLEAR_SCREEN
procedure, 244, 496, 503
CLEAR_TO_END_OF_LINE
procedure, 265, 408, 496,
506
CURSOR_RIGHT
procedure, 262-263, 407,
496, 504
617
Assembly Language
for the
CursorUnderscore procedure,
DISP.LINE
procedure,
561
194-195,221-226,497,517
get_active_page procedure,
556
procedure,
290-291.497,514
WRITE_HEADER
GetVisibleCursor procedure,
558
246,
SEND_CRLF
procedure,
409-410,496,506
SetCursor procedure, 548,
557
UPDATE_REAL_CURSOR
procedure, 408, 496, 505
UPDATE_VIRTUAL_CURSOR
procedure, 409, 496, 505
DISKJO.ASM
NEXT_SECTOR procedure,
277-279, 496, 508
PREVIOUS_SECTOR
procedure, 277-279, 496,
507
READ_SECTOR procedure,
211,230-231,245,496,
509
updated version, 250-251
WRITE_SECTOR
procedure, 353-354, 497,
509
DISP_HALF_SECTOR
procedure, 209-210, 497,
516
514
GOTO_XY procedure,
618
INIT_SEC_DISP
WRITE_PROMPT_LINE
procedure, 276-277, 497,
518
WRnE_TOP_HEK_NUMBERS
procedure, 233, 497, 515
DISPATCH.ASM,
272-273,
302-303, 306-307
DISPATCHER procedure,
346-348,497,511
WRITE_SECTOR
procedure, 352-353
DSKPATCH.ASM, 248-249
DATA_SEG procedure, 270
DISK_PATCH procedure,
255,271,498,520
INIT_WRITE_CHAR
procedure, 399
DSKPATCH.MAP, 356-358
editing in PWB, 178-179
EDITOR.ASM, 308-310
EDIT_BYTE procedure,
498,
522
WRITE_TO_MEMORY
procedure, 498, 521
external,
166
FASTWRIT.ASM
calc_display_offset procedure,
574
Index
FAST_CLEAR_TO_EOL
procedure, 577
569-571
551,581
GetDisplayType procedure,
551,578
is_ega procedure,
fast_write_raw_char
procedure, 568
KBD JO.ASM,
2nd
version,
579
275-276
318-322
BACK_SPACE procedure,
331,498,528,530
566
FastGetXY procedure, 550,
ClearKbdBuffer procedure,
551,581-583
576
CONVERT_HEX_DIGIT
procedure, 498, 523-525
575
FastReadAttr procedure, 550,
HEX_TO_BYTE procedure,
498, 524-526
572
FastSetCursor procedure,
550, 576
FastWriteChar procedure,
PURGE_BUFFER
procedure, 527-529
550, 569
FastWriteNChars procedure,
READ_BYTE procedure,
336-337,498,529-531
550, 574
FastWriteSpaces procedure,
READ_DECIMAL
procedure, 324-325, 499,
530, 533
READ_KEY procedure,
550, 574
FastWriteString procedure,
FastWriteUDecimal proce-
573
INrr_FASr_DISPLAY_MODULE
procedure, 562
InitFastDisplayModule
procedure, 549, 563
move_to_screen procedure,
567
FiARDWARE.ASM
499,
529, 532
READ_STRING
572
dure, 550,
GetDisplayRows procedure,
procedure,
332-335,339-341,410,
499, 525-527
ReadRawKey
procedure, 551,
581-583
scan_to_extended procedure,
581-582
ShiftKeys procedure, 552,
581,584
579
619
Assembly Language
for the
STRING_TO_UPPER
procedure, 499, 523-525
LINKINFO
changes,
362
Turbo Debugger changes,
366
CodeView debugger
changes,
362
Mouse_buttons procedure,
585
553,591
Set_mouse_position
procedure, 585
SetMousePosition procedure,
549
553, 590
UnhideMouse procedure,
553, 585, 589
object,
106
packing, 177
PHANTOM.ASM,
292-295,
304-305
ERASE_PRANTOM
548
MOV_TO_ASCII_POSrnON
366
updated version, 251
MOV_TO_HEX_POSITION
makefiles
206
553-554
356
do_init_mouse procedure,
Get_mouse_position
procedure, 585
GetMousePosition procedure,
532
procedure, 499, 532
PHANTOM_RIGHT
PHANTOM_UP procedure,
372-373, 499, 532
RESTORE_REAL_CURSOR
procedure, 500, 535
553, 589
585, 589
587
HideMouse
PHANTOM_DOWN
PHANTOM_LEFT
MOUSE.ASM
620
585-587
MouseButtons procedure,
map,
585-586
CodeView debugger
creating,
procedure, 553,
SAVE_REAL_CURSOR
procedure, 500, 534
Index
SCROLL_DOWN
WRITE_HEX_DIGIT
WRITE_PATTERN
SCROLL_UP procedure,
WRITE_PHANTOM
543
WRITE_STRING
Debug program,
254,501,538
WINLIB.ASM, 474-477
118
separate, assembling,
166-170
SOCHALIB.INC, 554
source, creating, 102,
105-106
fix_cursor procedure,
flags,
Overflow
Sign Flag, 69
416
TEST.EXE,
72
adding to numbers, 58
422
559
56
Carry Flag,
TEST.ASM, 166
TEST.C
test.c,
procedure,
Flag,
Trap
Flag,
Zero
Flag, 68,
69
153
466
text, creating,
102
VIDEO_IO.ASM, 404
DATA_SEG memory
segment
402
C/C++
DOS,
language, 418-419
121
FAR, 432
INT lOh,
INT I6h,
INT 21h,
INT 25h,
INT 26h,
501,540
Is286, 474,
WRriEjmilBlJrE_NJlMES
procedure, 296-297, 405,
500, 542
WRITE_CHAR procedure,
WRITE_CHAR_N_TIMES
procedure, 225, 501, 542
WRITE_DECIMAL
procedure, 501, 541
WRITE_HEX procedure,
501,538
380-381
functions
INIT_WRITE_CHAR
variable,
definitions,
name
600-603
603-604
604-605
606-607
606
477
decorating,
418
NEAR, 432
printf(
),
465
return values,
SegSize(
),
439
469, 473-475
ValidOffset(
),
475-476
621
Assembly Language
for the
ValidPtr,
GOTO_XY procedure,
467-468
ValidReadPtr(
ValidWritePtr(
),
473, 476
),
values, returning,
246,
440-441,496,504,556
GPF
477
428-429
(general-protection fault),
463
CGROUP, 385
DGROUP, 381,430
463
436-438
general-protection fault (GPF),
general-purpose
registers,
463
26
GET_DISPLAY_BASE
procedure.
451,454
585
procedure, 451-452,
457
GetDisplayRows procedure.
551,581
578
579
headers
comment, 172-174
writing,
252-255
222-226
hex input, 314-323
580
GetDisplayType procedure, 551,
GetMousePosition procedure, 553,
498, 524-526
hexadecimal numbers, 5
589
GetVisibleCursor procedure, 548,
arithmetic, 7-9
558
global descriptor table
(GDT), 463
in-line assembly,
441-443
,',
to decimal, 9-12
434
command,
C/C++, 439
till
317,
converting
global variables
reading,
1
1
HEX_TO_BYTE procedure,
578
622
file
is_ega procedure,
GET_NUM_FLOPPIES
Go
HARDWARE.ASM
Get_mouse_position procedure,
in
42, 45
reading,
94-96
Index
single digit
printing,
71-73
585-586
reading, 83
two-digit, reading,
84-85
words, 12
input
Hexarithmetic
HideMouse
command, 7
589
decimal, 323-326
hex,
314-323
high bytes, 34
register
227-232
instructions,
ADC,
ADD,
AND,
26
58
30-34
75
intrasegment, 149
nested, 91
436
192, 599
DIV,37
executing,
in-line assembly,
443-444
global variables,
441-443
440-441
incrementing
registers,
89
INIT_SEC_DISP
30
45
20h, 44
21h, 42
25h, 213
procedure,
INIT_VECTORS
exit,
Indirect
procedure,
451-452,456
INIT_WRITE_CHAR procedure,
399-400, 500, 540
InitFastDisplayModule procedure,
549, 563
218, 232
CMP, 70
writing,
CLD,
tracing over,
63
IRET, 152,449
JA,95
JB,95
JL,72
JLE, 83
JNZ, 70
JZ,70
623
Assembly Language
for the
LDS, 432
intercepting interrupts,
LSL, 467
interrupts,
MOV, 47,
MUL,
35
vectors,
274
OR, 132-133
POP, 92, 122
POPF, 214
PUSH, 92, 122
RCL, 57, 73
RET, 88-90
returning
to,
152
448-450
intercepting,
149,
IRET
instruction
192
NEAR CALL,
448-450
153-154
INVOKE directive,
IP
register,
IRET
477
30-32
instruction,
152,449
579
is_ega procedure,
90
isolating nibbles
SHE, 84
SHR, 74
lower, 75-76
upper, 73-75
STOSB, 406
SUB, 33
J
\^
VERR, 465
VERW,
JA
465
instruction,
95
131
JL
instruction,
72
Rinctions, 241-243,
JLE
JNZ
600-603
Jump
Jump
Jump
83
70
if Above, see]
A instruction
if
if
instruction
Jump
if
Less
Than, see]L
if
Not
instruction
21h, 42
Jump
25h,213
240
INTERCEPT_DISKE1 lEJNT
procedure, 451-454
instruction,
Jump
20h, 44
instruction,
instruction
llh,398
624
95
JB
word-multiply, 36
XOR,
INT lOh
instruction,
if
jumps, conditional, 70
JZ
instruction,
70
Index
KBD_IO.ASM
2ncl version,
581-583
file,
275-276
kludges, 140
318-322
BACK_SPACE
procedure, 331,
498, 528-530
581-583
labels,
CONVERT_HEX_DIGIT
procedure, 498, 523-525
HEX_TO_BYTE procedure,
498, 524-526
1 1
symbols
in,
110
languages
assembly, 88
BASIC, 88
C/C++
581-583
accessing parameters,
PURGE_BUFFER procedure,
435-438
527-529
CLEAR_SCREEN
READ_BYTE procedure,
procedure, 414-415
336-337,498,529-531
functions,
READ_DECIMAL procedure,
parameters,
499,
439
529, 532
READ_STRING
418-419
READ_KEY procedure,
procedures, 41
procedure,
332-335,339-341,410,499,
525-527
420-421,426
writing procedures,
439
machine, 30
QBasic, 88
scan_to_extended procedure,
581-582
430, 434,
441
584
LDS
STRING_TO_UPPER
procedure, 499, 523-525
LDT
LEA
Out (LIFO), 90
instruction,
432
463
libraries
C/C++, 492
function,
special,
109-111
NEAR,
160,490-491
creating,
553-554
625
Assembly Language
LIFO
for the
linear addressing
90
modes, 140
changes,
Dskpatch program,
502-503, 531-544
512-518
DISP_LINE
in
to
DISP_SEC.ASM,
194-195
A new
WRITE_CHAR in
VIDEO_IO.ASM, 196
Listing 14-4
DISPATCH.ASM
file,
510-512
The new
CURSOR.ASM,
file
197-198
DSKPATCH.ASM
file,
519-520
PHANTOM.ASM file,
VIDEO_IO.ASM
DISP_HALF_SECTOR in
file,
DISP_SEC.ASM, 209-210
Listing 15-3 The new file
355
DISKJO.ASM, 211
Listing 16-1 Add to the
531-537
537-544
file,
The program
PRINTAJ.ASM, 117
Listing 9-2 The new file
Listing 9- 1
VIDEO_IO.ASM
(VIDEO_9ASM), 119-121
Listing 1 0- 1 Add to
VIDEO_IO.ASM, 129-130
Listing 10-2 Replace
TEST_WRITE_HEX in
VIDEO_IO.ASM with this
626
Changes
Listing 14-3
procedure, 131
TEST. ASM,
Listing 14-2
LINKINFO. LINK
file
166
362
files,
The
Listing 14-1
file
CodeView debugger
linkinfo
The program
TEST_SEG.ASM, 142
Listing 13-1
LINKINFO
Listing 11-1
top of
DISP_SEC.ASM, 220
Listing 16-2
Changes
DISP_LINE
in
to
DISP_SEC.ASM,
221-222
Listing 16-3 Additions to
DISP_LINE
in
DISP_SEC.AS,
223-224
Listing
VIDEO_IO.ASM, 225
Listing 16-5
Changes
DISP_LINE
226
in
to
DISP_SEC.ASM,
Index
Listing 16-6
Add
this
procedure to
DISP_SEC.ASM, 228-229
Add this procedure
DISP_SEC.ASM, 230
Listing 16-8
Changes
Listing 18-1
to
Changes
added
to
added
to
265
DATA_SEG in
DSKPATCH.ASM,
Listing
9-3
270
271
The new
file
The new
KBDJO.ASM,
file
275-276
Listing
248-249
9-5
added
to
to
DISK_IO.ASM, 277-279
DISP_SEC.ASM, 250
Listing
to
file
DISK_IO.ASM, 250-251
The new version of
MAKEFILE, 251
added
VlDEO_IO.ASM, 254
Listing 21-1
Changes
to
PHANTOM.ASM,
added
Make
to
to
DISP_SEC.ASM, 253
Listing 17-10 Procedure
MAKEFILE, 279
INIT_SEC_DISP in
DISP_SEC.ASM, 290-291
Listing 21-2 The new file
Listing 17-8
to
8-4 Changes to
Listing 19-4
Changes to
Changes
CURSOR.ASM,
Listing
added
DISPATCH.ASM, 272-273
Changes to
INIT_SEC_DISP in
DISP_SEC.ASM, 247
Listing 17-5 The New File
Listing 17-7
262-263
DISK_PATCH in
DSKPATCH.ASM,
CURSOR.ASM, 246
DSKPATCH.ASM,
261-262
to
DISK_IO.ASM, 245
Listing 17-6
DISP_SEC.ASM, 266
READ_SECTOR in
Listing 17-4
to
CURSOR.ASM, 244
255
WRITE_HEADER in
to
INIT_SEC_DISP in
DISP_SEC.ASM, 234
Changes
VIDEOJO.ASM,
CURSOR.ASM,
DISK_IO.ASM, 230-231
Listing 16-10 Add this procedure
to DISP_SEC.ASM, 233
Listing 17-2
Changes
to
WRITE_CHAR in
Listing
to
READ_SECTOR in
Listing 16-11
Changes
DISK_PATCH in
DSKPATCH.ASM,
VIDEO_IO.ASM, 227-228
Listing 16-7 Additions to
Listing 16-9
Listing 17-11
292-295
added to
VIDEO_IO.ASM, 296-297
627
Assembly Language
for the
Listing 22-1
Changes
to
DISPATCH.ASM, 302-303
Listing 22-2 Add these procedures
to
PHANTOM.ASM,
Listing 22-3
Changes
304-305
Listing 26-4
to
DISPATCHER in
response
DISPATCH.ASM, 306-307
Listing 22-4 The new
The
test
Listing 26-6
program
Changes
response
TEST.ASM, 325-326
KBD_IO.ASM,
to
Listing 27-2
Changes
PHANTOM.ASM,
to
372-373
to
373
Changes
Listing 30-4
to
to
to
added
to
VIDEO_IO.ASM, 400
The New
READ_STRING in
KBD_IO.ASM, 333-335
Added
374-375
DSKPATCH.ASM, 399
Listing 30-3
Listing 24-3
Changes
to
VIDEO_IO.ASM, 401-402
Add DATA_SEG
the start of
VIDEOJO
to
.ASM,
402
READ_BYTE in KBD_IO.ASM,
Listing 30-5
336-337
WRITE_CFLAR in
VIDEO_IO.ASM, 403-404
Listing 30-6 Changes to .DATA in
VIDEO_IO.ASM, 404
Listing 24-5
Changes
READ_STRING
to
in
KBD_IO.ASM, 339-341
Listing 25-1
Changes
to
DISPATCHER in
DISPATCH.ASM, 346-348
Listing 26-1
Changes
to
DISPATCH.ASM, 352-353
Listing 30-7
Changes
Changes
to
to
WRITE_ATTRIBUTE_N_TIMES
in VIDEO_IO.ASM, 405
Listing 30-8
Changes
to
GOTO_XY in CURSOR.ASM,
406-407
628
LINKINFO, 366
Changes
PHANTOM.ASM,
KBD_IO.ASM, 332
Changes
to
to the
331
Listing 24-4
LINKINFO, 362
Changes
file
Listing 27-1
Listing 30-1
added
to the
Changes made
PHANTOM.ASM,
to
to
Makefile, 366
file
TEST.ASM, 315-316
Listing 23-2 The new version of
KBD_IO.ASM, 318-322
Listing 23-3 Add this procedure to
KBD_IO.ASM, 324-325
Listing 23-4
Changes
file
Listing 26-5
EDITOR.ASM, 308-310
Listing 23- 1
added to
DISK_IO.ASM, 353-354
Listing 26-3 Changes made
MAKEFILE, 362
Index
Listing 30-9
Changes
Program, 452-457
CURSOR.ASM, 407
Listing
30-10 Changes
Procedures added to
CURSOR.ASM,
408-409
to
473
functions,
WINLIB.ASM: The
Listing 33-2
valid,
it is
and get
to the size
program, 175
lists,
loading, 181
in
setting,
KBD_IO.ASM, 410
176-177
LDS
Listing 31-1
added
to
CLIB.ASM, 420-421
Listing 31-4
Changes
to
TEST.C,
added
to
CLIB.ASM, 426
Changes
to
TEST.C,
see
211
LSL
LODSB
see
loading program
local variables,
181
lists,
(LDT), 463
94
memory, 398-400
instruction, 218, 231-232
locating screen
Add
this
procedure to
CLIB.ASM, 428
Changes
LODSB
logical operations,
to
TEST.C,
429
Listing 31-9
instruction
426
Listing 31-8
Load
see
instruction
Listing 31-7
Load DS,
instruction
422
Listing 31-6
if
of a
segment, 474-477
30-13 Changes to
READ_STRING
and ValidReadPtr
the SegSize
SEND_CRLF in
CURSOR.ASM, 409-410
Listing
WINTEST.C: A
Listing 33-1
to
CLEAR_TO_END_OF_LINE
CURSOR.ASM, 408
Listing 30-1
DISKLITE.ASM
Listing 32-1
to
CURSOR_RIGHT in
73
LOOP instruction,
59
looping, 59-61
The
definitions for
437
31-10 A C version of
GOTO_XY using in-line
Listing
low
bytes,
34
lower
bytes,
134
nibbles, isolating,
LSL
instruction,
75-76
467
assembly, 440-441
629
Assembly Language
for the
microprocessors, 27-30
models, 429-432
COMPACT,
HUGE, 430
macros, 427
MAKEFILE
file,
LARGE,
279
CodeView debugger
362
430
MEDIUM,
430-432
changes,
segments, 431
SMALL,
430, 433
switching,
438
TINY, 430
protected-mode, 460-461
CursorUnderscore procedure,
screen,
392
549
398-400
locating,
GetVisibleCursor procedure,
segments, 140-144
code, 144
makefiles
stacks, 90,
creating,
206
variables,
creating libraries,
553-554
144-146
CURRENT_SECTOR_NO,
251
defining,
files,
creating,
356
maps
load,
358
355-358
DISK_DRIVE_NO,
SCREEN_X, 403
SCREEN_Y, 403
251
80286,
4,
460
80486, 4
accessing,
186-189
sizes,
461
8088,4
addition, 30-32
87
maps, 417
630
215-216
80386, 4
memory
address
189-191
248
map
400-403
dumping, 197
sectors,
548
to,
34-35
37
memory, 27-30
division,
ill
Index
multiplication,
35-36
modifying
negative numbers, 33
DISPATCHER, 346-348
protected-mode memory,
READ_SECTOR procedure,
460-461
subtraction, 32-33
registers,
C parameters,
438
LARGE,
Get_mouse_position procedure,
585
430-432
GetMousePosition procedure,
553, 589
430, 433
switching,
438
585, 589
TINY, 430
modes
585-586
386-Enhanced, 470
585-587
addressing, 186
memory, 186-189
accessing
191-193
Set_mouse_position procedure,
591
600
memory, 600
register indirect, 192,
protected, 4,
600
140
460
descriptor tables,
microprocessors, 460-461
real,
192
MOV_TO_ASCII_POSITION
procedure, 293, 499, 534
MOV_TO_HEX_POSITION
461
single-step,
585
SetMousePosition procedure,
553, 590
linear addressing,
600
600
base-relative, 188,
register,
398
file
segments, 431
SMALL,
display adapters,
430
MEDIUM,
monochrome
MOUSE.ASM
437
models, memory, 429-432
COMPACT, 430
creating,
HUGE,
27
model-independent code
accessing
245
153
631
Assembly Language
for the
moving
nibbles, isolating
lower, 75-76
211
addresses,
cursors,
data
upper, 73-75
NMake
246-247
into registers,
phantom
47-50
cursors, 286,
302-305
NUM_CHARS_READ procedure,
317
numbers
MUL instruction, 35
multiplication, microprocessors,
binary, 5, 17-19
35-36
displaying,
printing,
61-63
57
comparing, 70-71
complementing, 20
copying between
48
decimal, 9-14
Name command,
49
hexadecimal, 5
arithmetic, 7-9
NC
status,
56
NEAR
CALL
430
data,
13-14
converting to decimal, 9-12
432-438
directive,
functions,
labels,
150-151
432
calculating,
33
Two's Complement, 20
in displays,
33
Complement,
20
Two's
calculating,
selector,
NEXT_SECTOR procedure,
signed, 16
232-234
CALL instructions, 91
The New Peter Norton Programmer's
Guide to the IBM PC & PS/2, 483
nested
NG status, 69
94-96
words, 12
1 1
632
registers,
rotating,
56-58
463
unsigned, 16
NV status, 69
NZ status, 68
Index
phantom
cursors, 260,
creating,
object
offsets,
284-285
285
28, 188
304-305
operations, logical,
OR instruction,
OV status, 69
73
ERASE_PHANTOM
132-133
MOV_TO_ASCII_POSITION
overflow, 16
Overflow
69
Flag,
MOV_TO_HEX_POSITION
392-394
overrides, segment,
PHANTOM_DOWN
procedure, 372-373, 499, 532
packing
files, 1
PHANTOM_LEFT procedure,
77
499, 532
parameters
C/C++
language,
accessing,
passing,
PHANTOM_RIGHT
439
435-438
PHANTOM_UP procedure,
420-427
passing
multiple,
RESTORE_REAL_CURSOR
426-427
non-C
languages,
single,
420-425
424
SAVE_REAL_CURSOR
procedure, 500, 534
passing
information to
registers,
172
parameters
C/C++
language, 420-427
multiple,
426-427
non-C
languages,
single,
420-425
424
PC Interrupts: A Programmer's
BIOS, DOS, and
Reference to
Third-Party
Calls,
483
PC Magazine,
484
Peter Norton
Windows 3. 1 Power
's
SCROLL_DOWN procedure,
SCROLL_UP
procedure,
WRITE_PHANTOM
procedure, 500, 535
PHANTOM_DOWN procedure,
303-304, 372, 499, 532
PHANTOM_LEFT procedure,
304, 499, 532
PFIANTOM_RIGHT procedure,
305, 499, 532
633
Assembly Language
for the
PHANTOM_UP procedure,
303-304, 372-373, 499, 532
PL
status,
317,498,523-525
CURSOR_RIGHT,
69
pointers
262-263,
huge, 470
validating,
465-467, 472-473
DATA_SEG, 270
DISK_PATCH, 249,
popping
DISP_HALF_SECTOR,
PREV10US_SECT0R procedure.
277-279, 496, 507
PRINT_AJ
procedure, 117
PRINTAJ.ASM
printf(
program, 117
function,
465
printing
single
hex
42
330-331, 336,
498, 528-530
language,
498,
522
117,421
BACK_SPACE,
ERASE_PHANTOM,
295, 499,
536
416
calc_display_ofFset,
calling,
497,517
EDIT_BYTE, 306-307,
71-73
procedures, 88
C/C++
208-210,497,516
DISP_LINE, 194,221-224,
do_init_mouse, 587
digits,
PROC directive,
197,
451,455
binary numbers, 57
characters,
255, 271,
498, 520
return addresses, 91
words, 91-94
external,
fast_goto_xy, 575
89
317
fast_w^rite_char,
569-571
fast_write_raw_char, 568
check_int_33, 585
CLEAR_SCREEN,
168
FAST_CLEAR_TO_EOL, 577
574
CHAR_NUM_LIMIT,
244,
414-415,496,503
CLEAR_TO_END_OF_LINE,
260, 264, 408, 496, 506
634
CONVERT_HEX_DIGIT,
FastFlush, 549,
566
Index
InitFastDisplayModule, 549,
563
FastWriteString, 572
INTERCEPT_DISKETTE_INT,
559
451-454
is_ega,
579
KeyWaiting, 551,581-583
get_active_page, 556
Mouse_buttons, 585
GET_DISPLAY_BASE,
451,
Get_mouse_position, 585
GET_NUM_FLOPPIES,
451-452,457
get_xy,
MOV_TO_ASCII_POSITION,
454
MOV_TO_HEX_POSITION,
292, 296, 499, 533
move_to_screen, 567
556
NEXT_SECTOR,
277-279,
496, 508
NUM_CHARS_READ,
PHANTOM_DOWN,
GOTO_XY,
504
PHANTOM_LEFT,
304, 499,
532
PHANTOM_RIGHT,
goto_xy, 556
hex-output, 118
HEX_TO_BYTE,
317
305,
499, 532
317, 498,
524-526
PFiANTOM_UP,
303-304,
PREVIOUS_SECTOR,
INrr_FAST_DISPLAY_MODULE,
PRINT_AJ, 117
PURGE_BUFFER, 527, 529
READ_BYTE, 275, 276,
562
INIT_SEC_DISP, 228-229,
245,290-291,497,514
INIT_VECTORS,
451-452,
456
INIT_WRITE_CHAR,
399-400, 500, 540
314-316,336-337,498,529,
531
READ_DECIMAL,
323-325,
READ_KEY,
532
635
Assembly Language
for the
READ_SECTOR,
208-210,
230-231,245,496,509
READ_STRING,
172, 316,
330-335,339-341,410,499,
ReadKey, 551,581
testing,
122
172,224-226,501,542
RESTORE_REAL_CURSOR,
SAVE_REAL_CURSOR,
293-296, 500, 534
SAVE_SCREEN, 451,455
scan_to_extended, 581, 582
SCROLL_DOWN,
WRITE_DECIMAL,
372, 500,
128-129,
133-135,501,541
WRITE_HEADER,
247,
252-253,266,497,514
WRITE_HEX, 501,538
WRITE_HEX_DIGIT, 122,
501,539
WRITE_PATTERN,
227-228,
231-232,501,543
537
SCROLL_UP,
372-375, 500,
WRITE_PHANTOM,
197, 409-410,
WRITE_PROMPT_LINE,
536
SEND_CRLF,
271,
276-277,497,518
496, 506
set_cursor,
WRITE_SECTOR,
557
Set_mouse_position, 585
253-254,
420-421,426, 501,538
WRITE_TO_MEMORY,
584
STRING_TO_UPPER,
352-354,
497, 509
WRITE_STRING,
317,
308,
498, 521
WRITE_TO_SCREEN,
499, 523-525
TEST_WRITE_DECIMAL,
451,
456
WRITE_TOP_HEX_NUMBERS,
131
TEST_WRITE_HEX,
122
95
232-233,497,515
writing, 88-90
Proceed command, 63
UPDATE_REAL_CURSOR,
program
UPDATE_VIRTUAL_CURSOR,
408, 496, 505
WRrrE_ATTRIBUrE_N_TIMES,
296, 405, 500, 542
636
195-196, 260,
400-404,501,540
2nd version, 260-264
WRITE_CHAR_N_TIMES,
525-527
testing,
WRITE_CHAR,
lists,
175
loading, 181
setting,
176-177
Program Segment
146-147
Prefix (PSP),
Index
programmer
friendly programs,
WRITE_TO_SCREEN
procedure, 451, 456
338
Programmer's Guide
to
PC & PS/2
485
Video Systems,
DOS
Edit, 105
Dskpatch, 160
debugging, 354-355
function keys, 160, 490-491
174-175
makefile,
files
overview, 161-162
177-178
creating,
178-179
editing,
jumping
to definitions,
program
list
179-180
dump, 160
sector
entering,
46-47
EXE2BIN.EXE, 107
loading, 181
Linker, 106
176-177
setting,
501-502
linking,
106-107
Make, 206
programs
building, 100-104
NMake, 206-208
PRINTAJ.ASM, 117
COM, writing,
programmer
Debug,
5,
Disklite,
380
running, 50
skeletons,
file,
452-457
small
DISPLAY_DRIVE_LETTER
GET_DISPLAY_BASE
454
GET_NUM_FLOPPIES
procedure, 451-452,
INIT_VECTORS
457
procedure,
451-452,456
procedure, 453-454
INTERCEPT_DISKErrE_INT
451,455
338-339
VIDEO_IO.ASM,
119-121,
Windows, 465
32-bit registers,
segment
size,
471-472
467-471
procedure, 45
SAVE_SCREEN
129-130
INTERCEPT_DISKErrE_INT
PROC
123
memory-model, 189
CodeView, 361-365
procedure, 451,
338
RAM-resident, 448
6-7
448
DISKLITE.ASM
friendly,
procedure,
472-473
WINTEST.C, 473
637
Assembly Language
for the
WRITESTR.ASM,
writestr.exe,
READ_DECIMAL procedure,
106
WRITESTR.COM,
49, 108
READ_KEY procedure,
383-384
protected mode, 4,
descriptor tables,
460
463-464
READ_SECTOR procedure,
208-210, 230-231, 245, 496, 509
READ_STRING
extended, 461-463
microprocessors, 460-46
protection exception, general, 463
Prefix),
146-147
499, 525-527
characters,
121
PURGE_BUFFER procedure,
single digit,
83
two-digit, 84-85
527-529
instruction, 92,
122
PWB
82
global variables,
PUSH
into
files
directive,
procedure, 172,
316,330-335,339-341,410,
reading
see directives
PUBLIC
(Programmer's Workbench),
210-215, 277-280
sectors,
174-175
real
files
177-178
creating,
editing,
178-179
jumping
to definitions,
program
list
setting,
mode, 461
register addressing
599
179-180
command, 26
Register
loading, 181
192,
176-177
600
registers,
26
32-bit,
471-472
AX, 26-27
Q-R
BP, 423
QBasic language, 88
byte,
BX, 26-27
RCL instruction,
READ_BYTE procedure,
34
CL, 74
CS, 30, 141-142
57, 73
638
428, 499,
529, 532
memory
pseudo-ops,
CX,
DH, 34
DI, 130
mode,
Index
26
displaying,
ROM
DL, 34
DS, 142, 193-194
DX,
ROM_DISKETTE_INT variable,
449
34
26,
EBX, 473
ES, 142,392
root directories,
running programs, 50
into,
47-50
passing information
to,
172
171-172
171-172
SAVE_REAL_CURSOR
131-132
SAVE_SCREEN
segment, 462
setting to zero,
saving
SP, 90
214
relocation,
381-386
RESTORE_REAL_CURSOR
procedure, 294-296, 500, 535
restoring registers, 92,
instruction,
171-172
88-90
addresses
screens
clearing,
244-246, 264-267
w^riting to,
popping, 91
400-403
90
SCROLL_DOWN procedure,
439
returning
581-582
memory, 392
locating, 398-400
return
saving,
276
scan_to_extended procedure,
values,
171-172
return addresses, 90
word, 34-35
RET
procedure, 451,
455
130
status,
RCL
240
routines, display,
modifying, 27
restoring, 92,
see
30-32
moving data
59
instruction
incrementing, 89
SI,
general-purpose, 26
IP,
90
SCROLL_UP procedure,
372-375,
500, 536
460
639
Assembly Language
for the
scrolling
displays,
305
half sectors,
372-375
shifting zeros,
158
sectors,
half
372-375
read/write functions,
reading, 210-215,
directive,
277-280
159
435
381
462
registers,
84
SHL
84
code, 144
sign bits,
20
Sign Flag, 69
signed numbers, 16
mode,
small
189-194
430, 433
memory-model programs,
189
source
memory
Source Index,
models, 431
392-394
Windows
selector
creating, 102,
numbers, 463
see SI register
CodeView, 361-365
set_cursor procedure,
365
procedure, 197,
557
Set_mouse_position procedure,
SP
register,
SS
register, 90,
90
585
142
see
SS
starting addresses, 14
starting sectors,
590
159
setting
status,
lists,
176-177
registers to zero,
shift
register
144-146
program
count, 74
105-106
SEND_CRLF
files,
548, 554
file,
programs,
467-471
SegSize(
123
SOCHALIB.INC
overrides,
53
single-stepping, 58
grouping, 189
size,
640
instruction,
skeletons, program,
data, 144,
shifts, arithmetic,
single-step
SEGMENT directive,
segment
74
SI register, 130
606-607
SEG
SHR instruction
SHR instruction, 74
dumping, 197
scrolling,
SHL instruction
131-132
68
CY, 56
NC, 56
NG, 69
Index
NV,69
TEST.C
file,
416
NZ, 68
OV,69
READ_KEY procedure,
PL, 69
>XaiITE_STRING
status register,
214
STOSB
TEST_SEG.ASM
instruction
strings, character,
SUB
procedure,
422
ZR, 68
STOre
429
instruction,
33
program, 142
TEST_WRITE_DECIMAL
procedure, 131
TEST_WR1TE_HEX procedure,
122
testing
procedures, 95
READ_BYTE procedure,
supersets,
314-316
WRITE_CHAR procedure,
switches
WRITE_HEX_DIGIT
/CODEVIEW,
text editors,
365, 369
/v,
/Zi,
/zi,
02
102
TEXTEQU directive,
362
437
365
switching
procedure, 122
362, 365
/PL, 181
122
memory
models, 438
Trace command, 3 1 42
,
tracing over
INT
tracking bugs,
Trap
tables
Flag,
instruction,
63
358-360
153
truth tables, 75
descriptor,
463-464
GDT, 463
LDT, 463
truth,
75
TEST.ASM
325-326
file,
166, 315-316,
a
Unassemble command, 45
unassembling
WRITESTR.COM
program, 108
641
Assembly Language
for the
underscores (_) in
procedures,
defining,
DISK_DRIVE_NO,
SCREEN_X, 403
SCREEN_Y, 403
417
Undocumented DOS: A
Programmer's Guide
to
Reserved
215-216
251
ROM_DISKEri E_INT,
484
valid,
vectors, interrupt,
585, 589
153-154
verifying conversions,
43
unsigned numbers, 16
VERR instruction,
UPDATE_REAL_CURSOR
449
466
465
119-121,
file,
'
UPDATE_VIRTUAL_CURSOR
404
402
upper
INIT_WRITE_CHAR
134
bytes,
nibbles, isolating,
73-75
338-339
WRITE Al'lRlBU TE
TIMF.S
542
WRITE_CHAR procedure.
valid variable,
466
196,261-262,401-404,501,
540
WRITE_CHAR_N_TIMES
472-473
ValidOfifset(
function,
ValidPtr RinctionC
ValidReadPtr(
values, return,
f\inction,
476
477
428-429, 439
global
501,
538
procedure, 501, 539
WRITE_PATTERN
C/C++, 439
in-line assembly,
reading,
local,
WRITE_HEX procedure,
WRITE_HEX_DIGIT
variables
in
WRITE_DECIMAL procedure.
467-468
function, 473,
ValidWritePtr(
),
475-476
441-443
434
94
memory, 248
M
m
1'
procedure.
227-228,501,543
WRITE_STRING
procedure,
254,501,538
viewing ASCII conversions, 83
CURRENT_SECTOR_NO,
251
642
Index
WRITE_PATTERN
227-228,231-232, 501,543
Windows 3. 1: A
Developer's Guide,
484
procedure,
programs, 465
32-bit registers,
471-472
472-473
WRITE_PHANTOM
procedure,
WRITE_PROMPT_LINE
procedure, 271, 276-277, 497,
518
WRITE_SECTOR procedure,
352-354, 497, 509
segments, 467-471
registers,
34-35
word-multiply instruction, 36
words, 12, 19
WR1TE_STRING
procedure,
statement,
WRITE_TO_MEMORY
procedure, 308, 498, 521
WRITE_TO_SCREEN
bytes
424
procedure,
451,456
lower, 134
upper, 134
popping, 91-94
WRITE_TOP_HEX_NUMBERS
procedure, 232-233, 497, 515
WRITESTR.ASM
program,
pushing, 91-94
Write command, 49
WRITE_ATTRIBUTE_N_TIMES
procedure, 296, 405, 500, 542
WRITE_CHAR procedure,
195-196, 260, 400-404, 501, 540
2nd
version,
assembling, 106
WRITESTR.COM program,
49,
108
writestr.exe program,
383-384
writing
C/C++
260-264
122
WRITE_CHAR_N_TIMES
procedure, 172, 224-226, 501,
436-438
542
WRITE_DECIMAL procedure,
252-255
headers,
in-line assembly,
128-129, 133-135,501,541
WRITE_HEADER procedure,
to disk,
352-354
247,252-253,266,497,514
440-441
procedures, 88-90
to screen
memory, 400-403
122,501,539
643
Assembly Language
for the
x-z
XOR instruction,
Zero
Flag, 68,
131
466
zeros
setting registers to,
shifting,
ZR status,
644
74
68
131-132
DISK REPLACEMENT
the event that the disk
In
bound
fill
in to this
book
is
Computer Publishing
print clearly.
BOOK TITLE
ISBN
NAME
.PHONE
COMPANY
TITLE
ADDRESS
STATE
CITY
ZIP
LIMITED
In
Please
BOOK
fill
In
in
IN 46032.
must be on
file
with
PHCP within
thirty
days ot purchase.
ISBN
TITLE
PHONE NUMBER
NAME
).
ADDRESS
STATE
CITY
COMPUTER BRAND
&
MODEL
this
ZIP
MEMORY
DOS VERSION
product?
.PHONE NUMBER
DEALER NAME?
ADDRESS
STATE
CITY
PURCHASE DATE
How
this
STORE DISPLAY
OTHER
How
HOME
ADVERTISEMENT.
owned
MONTHS TO A YEAR
BUSINESS
Where
MAGAZINE ARTICLE
(Please explain)
is
SALESPERSON
ZIP
PURCHASE PRICE
did
is
will
send
charge.
out the information below and return this card to the address listed below with your original
Please
disk.
of
ORDER FORM
PERSONAL
EDUCATION
OTHER
(Please explain)
OFFICE
SCHOOL
OTHER
(Please explain).
OVER
YEAR
-j
PUT
FIRST
CLASS
STAMP
HERE
Computer Publishing
11711 N. College Avenue
Carmel, IN 46032
Prentice Hall
Attn:
Order Department
If
/4-inch disks...
While most personal computers use 3 1/2-inch disks to store information, some computers use 5 1/4-inch disks for information storage. If your computer uses 5 1/4-inch
disks, you can return this form to Brady to obtain a 5 1/4-inch disk to use with this
book. Simply fill out the remainder of this form and mail to:
Assembly Language
for the PC
Disk Exchange
Brady
11711 N. College Ave., Suite 140
Carmel, IN 46032
We will
then send you, free of charge, the 5 1/4-inch version of the book
software.
Name
Phone
Company
Tide
Address _
City
St.
ZIP
II
Assembl)Mfeucige/Programming/IBM
All
LevelsS^
A Bum^^Block Tutorial
PC, you
get:
version
,..
an ad\ancec
a powerful
programs
You
alst
more than 30 assembly routines for C/C+programming that pro\'ide mouse support,
writing to your screen, some keyboard input
routines, and much; much more.
get
$49.95
37.60
DSKPATCH,
the
$39.95 U.S.
to simplify their
many techniques
programmers use
in-line
(incl.
CAN
VAT) Net UK
3.1