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:
Post a Comment