Professional Documents
Culture Documents
CH02
CH02
CH02
2.1 INTRODUCTION
Basically, Assembly language is used today for two very important reasons.
The first reason is that only in Assembly Language do we have access to all
the power that is built into the computer. Evidence of that power will be
demonstrated shortly in the next section with some functions that control the
computer's cursor. Right now you have no capability with your high-level
language to alter the size of the cursor, turn the cursor off and back on. Yet
you know from certain application programs that such a capability must
exist. With Assembly language you can have that very control.
Yes, it is true, this chapter is not much fun. You are aching to get on the
stick and do some serious graphics, but patience is needed. A few tools
need to be prepared to build our foundation for future knowledge.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
What comes to the rescue are Registers. Registers are special memory
locations that are housed inside the microprocessor. These nearby
locations allow quick access, and the registers have special abilities that
regular memory does not have. Think of registers as a temporary scratch
pad of memory locations that aid the microprocessor in performing certain
specialized tasks.
The registers are titled AX, BX, CX and DX. Each register has two bytes
and is shown with sixteen spaces for each bit. Assembly Language does
not deal much with binary machine code, and information is usually
represented in base 16, or hexadecimal. Since each hexadecimal (hex)
digit is represented by four bits the registers are usually shown as follows:
╔═════╤═════╦═════╤═════╗
║ 1 │ 2 ║ 3 │ 4 ║ AX register
╚═════╧═════╩═════╧═════╝
AH register AL register
The registers are also divided in a high and a low section, each occupying
a byte. For the AX register, these sections are called AH, storing 12 (hex)
and AL, storing 34 (hex) in the example above. A similar logic follows for
the other three registers and from now on you can assume that values
discussed in this chapter will be in hex.
The AX, BX, CX and DX registers are the memory work horses of the
microprocessor. Besides functioning as a scratch pad of temporary memory
to speed up arithmetic logic, these registers also work with various BIOS
functions to control special operations. We are particularly interested with
the operations that pertain to video output. After all, this book is about
graphics, and video output is very much on our mind.
In the next section, we will write some short Assembly Language programs.
Do not let that frighten you. It was mentioned in the introduction, which you
probably skipped, that certain students seem to have program capabilities
with graphics that are quite startling and far superior to the rather mundane
graphics of most students and teachers.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
Your DOS operating system has a convenient way to tinker with Assembly
Language. Hidden in your DOS subdirectory is an obscure program called
DEBUG. It is appropriately named and allows some powerful low level
debugging and alteration of programs. With DEBUG you can see inside a
program and understand what is or isn't happening. An added benefit is that
you can also write short Assembly Language programs with a minimum
amount of fuzz.
There are special DEBUG editing commands that will only get some brief
comments. The intent of this section is to demonstrate several Assembly
Language features that take control of the computer in a way that you might
not have been able to do before. The real purpose follows in the next
section where you will see how this type of knowledge can also be used
inside C++ programs without much difficulty.
You can tell you are in DEBUG when you no longer see the regular DOS
prompt but only a small dash.
The MOV DL,41 command assigns 41 HEX (65 DEC) to the DL register.
The ASCII code for A is 65. The DL register is used to store the ASCII code
(in HEX) of character to be displayed.
The MOV AH,02 command assigns 02 HEX to the AH register. This register
is reserved for special functions. Function number 02H is the Display
Output function.
INT 21 is one of many INT instructions, short for INTerrupt, which calls a
routine based on the number following INT. INT 21 calls a DOS routine that
in this case, prints a character.
The following is a list of the DEBUG commands. You may not notice all of
these in the following programs. It is not particularly important to remember
these commands unless you want to become proficient with DEBUG. The
commands are listed here primarily to allow you to experiment, if you have
the desire to do so.
This brief page hardly makes you a DEBUG commands expert, but it does
list all the main commands in one convenient location. Play around, you will
find that working in DEBUG is not so bad.
─────────────────────────────────────────────────────────────────────────
╔═══════════════════════════════════════════╗
C:\>DEBUG ║ <-- Execute DEBUG from DOS prompt ║
-A100 ║ <-- Start entering at address 100 ║
14D9:0100 MOV AX,0100 ║ <-- Place 0100 (HEX) in the AX register ║
14D9:0103 MOV CX,2000 ║ <-- Place 2000 (HEX) in the CX register ║
14D9:0106 INT 10 ║ <-- Call the DOS interrupt 10H (Video) ║
14D9:0108 INT 20 ║ <-- Call the DOS interrupt 20H ║
14D9:010A ║ <-- Press <CR> to leave memory entering ║
-G ║ <-- Execute the program with G (Go) ║
║ <-- Output of the program (No Cursor) ║
Program terminated normally ║ <-- Message provided by Debug ║
-NCURSOROF.COM ║ <-- Name the program CURSOROF.COM ║
-RBX ║ <-- Check the contents of the BX register ║
BX 0000 ║ <-- Contents of BX register are 0000 ║
: ║ <-- Press <CR> do not change BX ║
-RCX ║ <-- Check contents of the CX register ║
CX 0000 ║ <-- Contents of CX register are 0000 ║
:A ║ <-- Enter A for size of program ║
-W ║ <-- Save program with Write command ║
Writing 000A bytes ║ <-- Message indicating A bytes saved ║
-Q ║ <-- Quit DEBUG mode, return to DOS ║
C:\>CURSOROF ║ <-- Execute program from DOS ║
C:\> ║ <-- DOS prompt ║
╚═══════════════════════════════════════════╝
─────────────────────────────────────────────────────────────────────────
This program introduced several new features, and the use of several new
registers. It is not important to give a detailed discussion of the functions
that each register can perform. It is far more important to observe how
special capabilities can be accessed by manipulating the registers. This
type of manipulation will be done soon to take control of the computer's
graphics capabilities.
You realize the following: the cursor size is controlled by the CX register. A
value of 2000H turns the cursor off. A value of 0607H is the normal cursor
size. This program uses Interrupt 10, the video interrupt, which is the most
Saving a DEBUG program is a little tricky. First, you need to give the
program a name with the N command. Then, you need to make sure that
the BX register is 0000. Follow this by storing the size of the program in the
CX register. The size of the program can be determined by the address
location listed to the left of the program. Finish by saving the program to
disk by typing W to Write or save the program.
We will now demonstrate one more DEBUG program to turn the cursor back
on. All the steps involved in saving the program will be repeated so that you
can see the pattern necessary for saving a program.
─────────────────────────────────────────────────────────────────────────
╔═══════════════════════════════════════════╗
C:\>DEBUG ║ <-- Execute DEBUG from DOS prompt ║
-A100 ║ <-- Start entering at address 100 ║
14D9:0100 MOV AX,0100 ║ <-- Place 0100 (HEX) in the AX register ║
14D9:0103 MOV CX,0607 ║ <-- Place 0607 (HEX) in the CX register ║
14D9:0106 INT 10 ║ <-- Call the DOS interrupt 10H (Video) ║
14D9:0108 INT 20 ║ <-- Call the DOS interrupt 20H ║
14D9:010A ║ <-- Press <CR> to leave memory entering ║
-G ║ <-- Execute the program with G (Go) ║
║ <-- Output of the program (No Cursor) ║
Program terminated normally ║ <-- Message provided by Debug ║
-NCURSORON.COM ║ <-- Name the program CURSORON.COM ║
-RBX ║ <-- Check the contents of the BX register ║
BX 0000 ║ <-- Contents of BX register are 0000 ║
: ║ <-- Press <CR> do not change BX ║
-RCX ║ <-- Check contents of the CX register ║
CX 0000 ║ <-- Contents of CX register are 0000 ║
:A ║ <-- Enter A for size of program ║
-W ║ <-- Save program with Write command ║
Writing 000A bytes ║ <-- Message indicating A bytes saved ║
-Q ║ <-- Quit DEBUG mode, return to DOS ║
C:\>CURSORON ║ <-- Execute program from DOS ║
C:\> ║ <-- DOS prompt ║
╚═══════════════════════════════════════════╝
─────────────────────────────────────────────────────────────────────────
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄
After the brief Assembly Language introduction with DEBUG, we will now
look at C++ programs that do the same thing. The C++ DOS library
(accessed with #include <dos.h>) does not come with a pre-defined type
called registers, as in Pascal. This delclaration, however, must be user
defined.
─────────────────────────────────────────────────────────────────────────
struct Registers
{
unsigned char al,ah,bl,bh,cl,ch,dl,dh;
unsigned ax,bx,cx,dx,bp,si,di,ds,es,flags;
}; // End struct registers.
─────────────────────────────────────────────────────────────────────────
The Registers structure includes some registers that were not previously
mentioned, and you don't need to be concerned about. They are shown
here to view the actual definition of the Registers type, but we will only be
using the AX,BX,CX,DX full (two bytes) registers or the
AL,AH,BL,BH,CL,CH,DL,DH half (1 byte) registers. We will now proceed to
write the CursorOff and CursorOn programs in C++ by manipulating the
appropriate registers. Keep in mind that a 0x in front of a number, like 0x10,
means that it is a base 16 (HEX) number, meaning that 0x10 is equal to 16
in base 10.
─────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH02_01.CPP turns the text cursor off completely. ***/
/**********************************************************************/
#include <dos.h>
#include <conio.h>
void main()
{
clrscr();
_AX = 0x0100; // Int 0x10, function 0x0100 ? set cursor.
_CX = 0x2000; // Set cx to 0x2000 (turn cursor off).
geninterrupt(0x10); // Call interrupt 0x10.
getch();
} // End main program CH02_01.CPP
─────────────────────────────────────────────────────────────────────────
We must include the dos.h library statement to have access to the internal
registers. In the dos.h library, all the CPU registers have been pre-defined.
With the same kind of logic, we can write a program that turns the cursor on.
You may find it useful to place these two short routines in some utility library
that you use with regular programming. There are times when keyboard
input should not be prompted with a cursor, and you prefer to turn the cursor
off.
─────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH02_02.CPP turns the text cursor on to the ***/
/*** conventional cursor size at the bottom of the text character ***/
/*** position. ***/
/**********************************************************************/
#include <dos.h>
#include <conio.h>
void main()
{
clrscr();
_AX = 0x0100; // Int 0x10, function 0x0100 ? set cursor.
_CX = 0x0607; // Ch = 0x06, cl = 0x07; set cursor width.
// Upper bound at 6, lower bound at 7.
geninterrupt(0x10); // Call interrupt 0x10.
getch();
} // End main program CH02_02.CPP
─────────────────────────────────────────────────────────────────────────
We will now go one step further and make a cursor program more general to
allow us to pick the type of cursor size that we want. The value 0x0607 is
the cursor size that you normally see. Value 0x0707 is the skinniest cursor,
and 0x0107 is the fattest cursor with other cursor sizes fluctuating in-
between. The next program allows keyboard input to indicate the starting
and ending values of the cursor.
#include <iostream.h>
#include <dos.h>
#include <conio.h>
void main()
{
Byte Pos1,Pos2; // Start and end limits of cursor.
clrscr();
cout << "Enter cursor start [1..7] ???> ";
cin >> Pos1;
cout << "Enter cursor end [1..7] ???> ";
cin >> Pos2;
CursorSize(Pos1,Pos2);
getch();
} // End main program CH02_03.CPP.
▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄