Tuesday, November 20, 2007

IBM PC Assembly Language Tutorial 8

IBM PC Assembly Language Tutorial 8

A final example

I leave you with a more substantial example of code which illustrates

some good elementary techniques; I won't claim its style is perfect,

but I think it is adequate. I think this is a much more useful example

than what you will get with the assembler:

TITLE SETSCRN -- Establish correct monitor use at boot time;

This program is a variation on many which toggle the equipment

flags to support the use of either video option (monochrome or

color).

The thing about this one is it prompts the user in such a way that he

can select the use of the monitor he is currently looking at (or which

is currently connected or turned on) without really having to know

which is which. SETSCRN is a good program to put first in an

AUTOEXEC.BAT file.

This program is highly dependent on the hardware and BIOS of the

IBMPC and is hardly portable, except to very exact clones. For this

reason, BIOS calls are used in lieu of DOS function calls where both

provide equal function.

OK. That's the first page of the program. Notice the PAGE

statement,which you can use to tell the assembler how to format the

listing. You give it lines per page and characters per line. I have

mine setup to print on the host lineprinter; I routinely upload my

listings at 9600 baud and print them on the host; it is faster than

using the PC printer.

There is also a TITLE statement. This simply provides a nice title for

each page of your listing. Now for the second page:

SUBTTL -- Provide .COM type environment and Data

PAGE

First, describe the one BIOS byte we are interested in

BIOSDATA SEGMENT AT 40H ;Describe where BIOS keeps his

data ORG 10H ;Skip parts we are not interested in

EQUIP DB ? ;Equipment flag location

MONO EQU 00110000B ;These bits on if monochrome

COLOR EQU 11101111B ;Mask to make BIOS think of the color

board BIOSDATA ENDS ;End of interesting part

Next, describe some values for interrupts and functions

DOS EQU 21H ;DOS Function Handler INT code

PRTMSG EQU 09H ;Function code to print a message

KBD EQU 16H ;BIOS keyboard services INT code

GETKEY EQU 00H ;Function code to read a character

SCREEN EQU 10H ;BIOS Screen services INT code

MONOINIT EQU 02H ;Value to initialize monochrome screen

COLORINIT EQU 03H ;Value to initialize color screen (80x25)

COLORINIT EQU 01H ;Value to initialize color screen (40X25)

Now, describe our own segment

SETSCRN SEGMENT ;Set operating segment for CODE and

DATA

ASSUME

CS:SETSCRN,DS:SETSCRN,ES:SETSCRN,SS:SETSCRN ;All

segments

ORG 100H ;Begin assembly at standard .COM offset

MAIN PROC NEAR ;COM files use NEAR linkage

JMP BEGIN ;And, it is helpful to put the data first, but then you must

branch around it.

Data used in SETSCRN

CHANGELOC DD EQUIP ;Location of the EQUIP, recorded as far

pointer

MONOPROMPT DB 'Please press the plus ( + ) key.$' ;User sees

on mono

COLORPROMPT DB 'Please press the minus ( - ) key.$' ;User sees

on color

Several things are illustrated on this page. First, in addition to titles,

the assembler supports subtitles: hence the SUBTTL pseudo-op.

Second, the PAGE pseudo-op can be used to go to a new page in

the listing. You see an example here of the DSECT-style segment in

the "SEGMENT AT 40H". Here, our our interest is in correctly

describing the location of some data in the BIOS work area which

really is located at segment 40H.

You will also see illustrated the EQU instruction, which just gives a

symbolic name to a number. I don't make a fetish of giving a name

to every single number in a program. I do feel strongly, though, that

interrupts and function codes, where the number is arbitrary and the

function being performed is the thing of interest, should always be

given symbolic names.

One last new element in this section is the define doubleword (DD)

instruction. A doubleword constant can refer, as in this case, to a

location in another segment. The assembler will be happy to use

information at its disposal to properly assemble it. In this case, the

assembler knows that EQUIP is offset 10 in the segment

BIOSDATA which is at 40H.

SUBTTL -- Perform function

PAGE

BEGIN: CALL MONOON ;Turn on mono display

MOV DX,OFFSET MONOPROMPT ;GET MONO PROMPT

MOV AH,PRTMSG ;ISSUE

INT DOS ;IT

CALL COLORON ;Turn on color display

MOV DX,OFFSET COLORPROMPT ;GET COLOR PROMPT

MOV AH,PRTMSG ;ISSUE

INT DOS ;IT

MOV AH,GETKEY ;Obtain user response

INT KBD

CMP AL,'+' ;Does he want MONO?

JNZ NOMONO

CALL MONOON ;yes. give it to him

NOMONO: RET

MAIN ENDP

The main code section makes use of subroutines to keep the basic

flow simple. About all that's new to you in this section is the use of

the BIOS interrupt KBD to read a character from the keyboard.

Now for the subroutines, MONOON and COLORON:

SUBTTL -- Routines to turn monitors on

PAGE

MONOON PROC NEAR ;Turn mono on

LES DI,CHANGELOC ;Get location to change

ASSUME ES:BIOSDATA ;TELL ASSEMBLER ABOUT CHANGE

TO ES OR EQUIP,MONO

MOV AX,MONOINIT ;Get screen initialization value

INT SCREEN ;Initialize screen

RET

MONOON ENDP

COLORON PROC NEAR ;Turn color on

LES DI,CHANGELOC ;Get location to change

ASSUME ES:BIOSDATA ;TELL ASSEMBLER ABOUT CHANGE

TO ES AND EQUIP,COLOR

MOV AX,COLORINIT ;Get screen initialization value

INT SCREEN ;Initialize screen

RET

COLORON ENDP

SETSCRN ENDS ;End of segment

END MAIN ;End of assembly; execution at MAIN

The instructions LES and LDS are useful ones for dealing with

doubleword addresses. The offset is loaded into the operand

register and the segment into ES (for LES) or DS (for LDS). By

telling the assembler, with an ASSUME, that ES now addresses the

BIOSDATA segment, it is able to correctly assemble the OR and

AND instructions which refer to the EQUIP byte. An ES segment

prefix is added.

To understand the action here, you simply need to know that flags in

that particular byte control how the BIOS screen service initializes

the adapters. BIOS will only work with one adapter at a time; by

setting the equipment flags to show one or the other as installed and

calling BIOS screen initialization, we achieve the desired effect.


No comments: