CH02

You might also like

Download as rtf, pdf, or txt
Download as rtf, pdf, or txt
You are on page 1of 11

II ASSEMBLY LANGUAGE BASICS

2.1 INTRODUCTION

A brief introduction into Assembly Language is essential to understand and


appreciate the graphics routines explained in this book. Many of the strange
looking features revolve around low-level language concepts that are based
on Assembly Language. If you are familiar with Assembly Language jump
ahead to Chapter III and plunge into the actual graphics routines. On the
other hand, if your experience is only with high level languages, such as C+
+ and Pascal, it will be beneficial to study this Assembly Language chapter.

"Why Use Assembly Language?" is a very logical question. It has been


many years since we advanced from the tedious programming in machine
code and in Assembly Language (which is barely a step above machine
code). Thanks to such wonderful people like Grace Hopper we have had
high-level programming languages for four decades now. "Besides, isn't
Assembly Language for programmers who create compilers like Turbo C+
+"?

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.

The second reason is speed. Compilers are becoming more sophisticated


all the time, but for pure speed, it is hard to beat the low-level programming
done by an intelligent human being.

Chapter II Assembly Language Basics -2.1-


Do not be concerned that advanced graphics requires writing programs in
Assembly Language. Complete Assembly Language programs are tedious
and not necessary. There exists a good compromise by writing code in a
high-level language, C++ in our case, and mixing in Assembly Language
where it is beneficial. First, you will learn a little about Assembly Language,
and then we will show how you can use Assembly Language in a C++
program.

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.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

2.2 ASSEMBLY REGISTERS

The greater majority of computer information is stored in computer memory.


The computer microprocessor accesses information stored in ROM and
RAM, and it handles millions of operations in a very short period of time.
But computer users are always searching for ways to speed up the process.
Short as the distance may seem between processor and memory chips, the
distance traveled adds up when multiplied billions of times. Furthermore,
much information is of a temporary nature and can be quickly discarded, like
the intermediate values that are computed during certain mathematical
operations.

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.

There are thirteen registers in the microprocessor, but we will only be


concerned with the four main registers. Symbolically, these four registers
appear as follows:

Chapter II Assembly Language Basics -2.2-


╔══╤══╤══╤══╤══╤══╤══╤══╦══╤══╤══╤══╤══╤══╤══╤══╗
║ │ │ │ │ │ │ │ ║ │ │ │ │ │ │ │ ║ AX
╚══╧══╧══╧══╧══╧══╧══╧══╩══╧══╧══╧══╧══╧══╧══╧══╝
╔══╤══╤══╤══╤══╤══╤══╤══╦══╤══╤══╤══╤══╤══╤══╤══╗
║ │ │ │ │ │ │ │ ║ │ │ │ │ │ │ │ ║ BX
╚══╧══╧══╧══╧══╧══╧══╧══╩══╧══╧══╧══╧══╧══╧══╧══╝
╔══╤══╤══╤══╤══╤══╤══╤══╦══╤══╤══╤══╤══╤══╤══╤══╗
║ │ │ │ │ │ │ │ ║ │ │ │ │ │ │ │ ║ CX
╚══╧══╧══╧══╧══╧══╧══╧══╩══╧══╧══╧══╧══╧══╧══╧══╝
╔══╤══╤══╤══╤══╤══╤══╤══╦══╤══╤══╤══╤══╤══╤══╤══╗
║ │ │ │ │ │ │ │ ║ │ │ │ │ │ │ │ ║ DX
╚══╧══╧══╧══╧══╧══╧══╧══╩══╧══╧══╧══╧══╧══╧══╧══╝

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 drawing shows that 1234 is stored in the AX register, which is


equivalent to 0001 0010 0011 0100. Normally only the hex code is used.

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.

Chapter II Assembly Language Basics -2.3-


Here is the first secret revealed: Power with graphics comes from using a
certain amount of Assembly Language, but not full-blown, jump-right-into-
the-microprocessor-and-do-not-leave type of Assembly Language. Yet, you
do take advantage of taking control of the computer in a way that is only
possible with some low-level language programming. You will find that a
rather small amount of Assembly Language knowledge will perform a rather
large amount of graphics processing.

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

2.3 USING DEBUG

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.

Let us start by writing a small program that displays an A on the monitor.


You will probably be totally unimpressed by the amount of work required to
display a modest single letter, but nobody ever said that Assembly Language
programs were short on code. This is precisely why early computer science
pioneers like Grace Hopper decided it made sense to develop programs like
interpreters and compilers to make programming simpler. You need to type
in the program exactly as it is shown below, but keep in mind that the
memory addresses are automatically displayed by DEBUG and should not
be typed as part of the program.

Chapter II Assembly Language Basics -2.4-


─────────────────────────────────────────────────────────────────────────
╔═══════════════════════════════════════════╗
C:\>DEBUG ║ <-- Execute DEBUG from DOS prompt ║
-A100 ║ <-- Start entering at address 100 ║
14D9:0100 MOV DL,41 ║ <-- Place 41H (65D) in the DL register ║
14D9:0102 MOV AH,02 ║ <-- Place 02H (02D) in the AH register ║
14D9:0104 INT 21 ║ <-- Call the DOS interrupt 21H ║
14D9:0106 INT 20 ║ <-- Call the DOS interrupt 20H ║
14D9:0108 ║ <-- Press <CR> to leave memory entering ║
-G ║ <-- Execute the program with G (Go) ║
A ║ <-- Output of the program (Letter A) ║
Program terminated normally ║ <-- Message provided by Debug ║
- ║ <-- Debug prompt waiting for commands ║
Q ║ <-- Quits Debug mode ║
C:\> ║ <-- Return to DOS prompt ║
╚═══════════════════════════════════════════╝
─────────────────────────────────────────────────────────────────────────

You can tell you are in DEBUG when you no longer see the regular DOS
prompt but only a small dash.

All DEBUG commands are single-letter commands. In the program above


the A (Address) indicates that information is to be entered at the indicated
address. All DEBUG programs start at memory address 0100. The
segment part of the address (the part before the :) is automatically provided.

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.

INT 20 calls a routine that returns control of the computer to DEBUG.

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.

Chapter II Assembly Language Basics -2.5-


═══════════════════════════════════════════════════════
DEBUG COMMANDS

D Dump Displays values in memory at a given memory address


D100 Displays memory values starting at address 0100

F Fill Fills a part of memory with hex number(s)


F120 14F FF Fills the value FF is each byte of memory starting at
address 0120 and ending at address 014F.

A Address Allows assembly code to be entered at given address


A100 Start writing code at memory address 0100.

U List List program at specified address (exactly Unassemble)


U100,106 List program from address 0100 to address 0106

G Go Executes the program

Q Quit Quits debug and returns to DOS

R Register Allows values to be altered in registers


RAX Displays AX values and waits for new values

N Name Gives a name to an Assembly program


NEXAMPLE.COM Specifies EXAMPLE.COM as name (must use .COM)

W Write Writes (saves) program with number of bytes


specified in the CX register

L Load Load a DEBUG program


LEXAMPLE.COM Loads a program called EXAMPLE.COM
═══════════════════════════════════════════════════════

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.

Chapter II Assembly Language Basics -2.6-


TURNING THE CURSOR OFF

If Assembly language is supposed to give you greater control over the


capabilities of the computer, then displaying the letter A has not exactly left
you wanting more of the same. But this next program allows you to do
something that is not readily available in C++, like turning the cursor off.
At the same time we will introduce how to save the program so that you can
run the program from DOS.

─────────────────────────────────────────────────────────────────────────
╔═══════════════════════════════════════════╗
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

Chapter II Assembly Language Basics -2.7-


important interrupt for graphics programs.

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.

TURNING THE CURSOR ON

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 ║
╚═══════════════════════════════════════════╝
─────────────────────────────────────────────────────────────────────────

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter II Assembly Language Basics -2.8-


2.4 ACCESSING REGISTERS IN C++

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.

The type definition looks as follows:

─────────────────────────────────────────────────────────────────────────
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.

Chapter II Assembly Language Basics -2.9-


Instead of using the Registers structure, explained earlier, to assign values
to the registers, you can use the internal C++ register variables. These
variables names are the same as the register name (like AX, AH, AL), but
the C++ variables are preceeded by an underscore character (_). Assigning
values to these registers is just like assigning values to any other variable.

The statement _AX = 0x0100; stores 0100 (HEX) in a variable that


corresponds to the AX register.
The statement _CX = 0x2000; stores 2000 (HEX) in a variable that
corresponds to the CX register.
The statement geninterrupt(0x10); is the Interrupt 10H video call, which
performs an Assembly Language INT instruction with the above register
values intact.

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.

Chapter II Assembly Language Basics -2.10-


─────────────────────────────────────────────────────────────────────────
/**********************************************************************/
/*** CH02_03.CPP allows the program user to control the ***/
/*** size and the location of the cursor. ***/
/**********************************************************************/

#include <iostream.h>
#include <dos.h>
#include <conio.h>

typedef unsigned short Byte;

void CursorSize(Byte Pos1, Byte Pos2);

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.

void CursorSize(Byte Pos1, Byte Pos2)


{
_AX = 0x0100;
_CH = Pos1; // set upper bound
_CL = Pos2; // set lower bound
geninterrupt(0x10);
} // End void function CursorSize.
─────────────────────────────────────────────────────────────────────────

▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄▄

Chapter II Assembly Language Basics -2.11-

You might also like