This is only a preview of the January 1994 issue of Silicon Chip. You can view 29 of the 96 pages in the full issue, including the advertisments. For full access, purchase the issue for $10.00 or subscribe for access to the latest issues. Articles in this series:
Articles in this series:
Items relevant to "40V 3A Variable Power Supply; Pt.1":
Items relevant to "A Switching Regulator For Solar Panels":
Items relevant to "Printer Status Indicator For PCs":
Items relevant to "Simple Low-Voltage Speed Controller":
Items relevant to "Computer Bits":
Articles in this series:
Items relevant to "Control Stepper Motors With Your PC":
|
COMPUTER BITS
BY DARREN YATES
Even more experiments for
your games card
In the November 1993 issue, we used some
simple programming so that the games card
could function as an analog interface. Now
we take a look at how to obtain higher speed
interfacing using some simple assembly
language routines.
If you read the last instalment of
this series, you’ll probably think that
using straight MS-DOS QBasic is just
too slow and, in most cases, you’re
right. Any language which is designat
ed as an “interpreter” can usually be
regarded as “slow”.
However, one of the forgotten
programming languages is Assembly
Language which is faster than any
compiler you could lay your hands
on. What’s more, you have access to
it through QBasic!
Now most people, even competent
programmers, seem to baulk at the
idea of using assembler code as either
being “old-fashioned” or “too hard
to use”. But if you can program in
BASIC, there’s no reason why, with a
little care, you can’t do likewise with
Assembler.
Those of you who go back far
enough will remember the DREAM
6800 and ETI-660 microcomputers
which came onto the scene before the
days of the TRS80s and Commodore
64s. Programming on the former was
done by a form of machine code and
by just following simple steps, even
yours truly, as a 9-year old, could write
simple software on them.
By the way, if you still use a TRS80
or Commodore 64, then there’s no
reason why you can’t keep using them
for years to come. OK, so they may be
pushing 20 years old, but if you’re a
hobbyist who wants to interface your
own projects with them, then they’re
ideal.
The main benefit the IBM PC compatible has in this area is just the sheer
volume of information that is available
on the internals - information which is
hard to get on other machines.
BIOS & DOS interrupts
Getting back to machine code, Microsoft have taken most of the hard
work out of writing assembler or
“machine code” routines by supplying
many routines as part of your machine’s disc operating system (DOS).
Other routines are supplied as part of
the built-in operating system (BIOS)
which comes in one or two ROMs on
the motherboard.
These two sets of routines allow
you to get at the hardware of your
machine without having to worry
about the bulk of the programming.
For example, you can set the time
and date directly, check to see if
your motherboard has a co-processor,
check the number of printer ports
or what’s on the printer ports, and
so on. You can even display a message about the motherboard from its
manufacturer. The list goes on and
on. However, at this point, we’ll just
look at those routines that pertain to
the games card.
Clock speed
Back in the first article on using the
games card (SILICON CHIP, January
1992), we looked at the circuitry of
the games card to see how it was able
to translate the joystick position into
an 8-bit count. Recounting briefly, the
games card contains a 558 quad timer
IC which is wired as four monostables.
Each x- and y-section of the joystick
is a separate variable resistor which is
connected up with one section of the
558 to form a monostable.
To read back the digital count, the
computer triggers the monostable and
at the same time starts an 8-bit count.
When the monostable falls low again,
the count is stopped. Now this method
is obviously going to be slow, particularly if it has to count to 256 on each
scan and, as a result, the frequency of
scanning is around 800Hz.
When you couple this with QBasic’s
relatively low speed, you can now
see why the simple analog interface
we built last time could only handle
40 samples per second. However, by
using a small amount of machine code,
we can increase this by about 10-fold.
QBASIC & machine code
Those of you who aren’t familiar
with QBASIC will be surprised at its
easy-to-use interface compared with
GWBASIC. There have been a couple
of small changes in the language,
particularly with respect to using
machine code.
QBASIC gives the user direct control
of the PC via a command called CALL
January 1994 65
Fig.1: Games Card Finder Program
‘ Games card finder program
‘ Copyright 1993 Silicon Chip Publications
‘ Written by Darren Yates B.Sc.
‘ This program prints a message indicating whether or not
‘ a games card is installed.
‘ It uses a machine-language program stored in an array
‘ to get the information from the operating system.
DEFINT A-Z
DIM Asmprog(1 TO 7)
‘ The machine-language program stored as data to read into
‘ the array.
AsmBytes:
DATA &H55
: ‘PUSH BP
Save base pointer.
DATA &H8B, &HEC
: ‘MOV BP,SP
Get our own.
DATA &HCD, &H11
: ‘INT 11H
Make the ROM-BIOS call.
DATA &H8B, &H5E, &H06 : ‘MOV BX,[BP+6] Get argument address.
DATA &H89, &H07
: ‘MOV [BX],AX
Save list in argument.
DATA &H5D
: ‘POP BP
Restore base pointer.
DATA &HCA, &H02, &H00 : ‘RET 2
Pop argument off stack
‘
and make far return.
‘ Get the starting offset of the array.
start = VARPTR(Asmprog(1))
‘ Poke the machine-language program into the array.
DEF SEG = VARSEG(Asmprog(1))’ Change the segment.
RESTORE AsmBytes
FOR index = 0 TO 13
READ byte
POKE (start + index), byte
NEXT index
‘ Execute the program. The program expects a single integer argument.
start = VARPTR(Asmprog(1))
CALL ABSOLUTE(status%, start)
DEF SEG ‘ Restore the segment.
‘ status% now contains bit-encoded equipment list returned by DOS.
‘ Mask off all but the games card bit (bit 12).
game = status% AND &HC000
‘ Print the appropriate message.
IF game = 16384 THEN
PRINT “Games Card present.”
ELSE
PRINT “No Games Card.”
END IF
END
ABSOLUTE() which transfers control
to machine code elsewhere in the
program. A simple example of this is
found in GAMECARD.BAS in Fig.1.
This program checks the hardware of
your computer to see whether it has a
games card connected.
If you’re writing your own programs
to use a games card, you can use this
routine to check if one exists in the
computer before going further. This is
a good idea because it saves the user
66 Silicon Chip
the frustration of not knowing why the
program won’t work.
Looking at the program, the machine code is stored away in an integer array called ASMPROG. If you
count through the data statements,
there are 14 bytes of instructions but
since an integer variable consists of
two bytes, we only need seven to store
away the program.
Looking at the machine code bytes,
each line contains the bytes required
to execute that function – some require
only one byte while others need three.
The first line saves the current base
pointer and puts it on the stack.
The base pointer is a pointer to the
current address of the last instruction
and the reason we need to save this
is that when we run or “call” this
routine, we are effectively transferring
control from one language to another.
The base pointer performs the task of
a “bookmark” – showing us where to
go back to after we’ve finished.
Next, we have to transfer our current base pointer of this program area,
which is the array ASMPROG, into the
BP register. This is to make sure that
we use the correct area of memory.
The next line performs an interrupt, which tells the computer to stop
everything and run the routine which
is designated 11 in the BIOS ROM.
This returns a value to the AX register
which contains the information shown
in Table 1.
The AX register is 16-bits wide and
each bit is used to indicate which parts
of the hardware are present or absent.
Bit 0 shows whether or not there is a
floppy drive. Few computers don’t
have a floppy drive of some kind so
this will invariably be ‘1’. Bit 1 shows
if a co-processor is installed; bit 2
shows if you have a mouse installed;
bits 4 and 5 show which video mode
you’re in; bits 6 and 7 how many
floppy drives you have minus one;
bits 9-B how many RS-232 cards you
have; bit C if you have a games card;
and bits E and F how many printer
ports you have.
Now we want the machine code
program to return this value of AX
back to the variable STATUS%. To do
this, we need to know the address of
this variable and this is what the 4th
line does.
It uses “indirect addressing” to load
into register BX not the value of BP+6
but the address of this position. The
next line loads the contents of AX, not
into BX but the address of the contents
of BX, which in our case is the address
of variable STATUS%.
This sounds pretty long winded but
it is a powerful way of using only a
small number of registers to access a
wide area of memory.
Now that we’ve completed what
we set out to do, we must restore
everything and leave the stack the
way we found it and that requires us
to ‘pop’ the contents of the original
Table 1: Bit Meanings
F E D C B A 9 8 7 6 5 4 3 2 1 0 Meaning of bits
x x
x
0
1
x x x
x
0
0
1
1
0
1
0
1
0 1
1 0
1 1
0
0
1
1
0
1
0
1
base pointer from the stack and put
it back into register BP. The last line
does what’s called a ‘far return’ which
means that it re
turns control from
the machine code program back to
the next instruction of the QBASIC
program, wherever in the memory
that may be.
This machine code is loaded in via
a FOR..NEXT loop using the POKE
command. Before this happens, there
are two commands carried out to make
sure that these bytes go in exactly the
right spot and these involve the commands VARPTR and VARSEG.
Since the PC memory is divided
Number of printers attached
Not used
Game adapter not installed
Game adapter installed
Number of serial cards attached
Not used
1 disc drive attached (if bit 0 = 1)
2 disc drives attached (if bit 0 = 1)
3 disc drives attached (if bit 0 = 1)
4 disc drives attached (if bit 0 = 1)
Initial video mode = 40 x 25 BW/colour card
Initial video mode = 80 x 25 BW/colour card
Initial video mode = 80 x 25 BW/mono card
16K system board RAM
48K system board RAM
32K system board RAM
64K system board RAM
1
Math coprocessor installed
0 No disc drives installed (bits 6-7 insignificant)
1 Disc drives installed (bits 6-7 significant)
into 64Kb segments, we have to know
which of these segments the array
ASMPROG is sitting in. This is carried
out by the VARSEG command which
sets the current segment pointer to
this segment.
Next, we have to know where in
that segment this array is and this
is done by the VARPTR command
which puts the location of the first
array element of ASMPROG into the
variable START.
The command which calls the machine code is CALL ABSOLUTE(STAT
US%, START) with STATUS% the
variable we want the infor
mation
returned in, while START tells the
computer which memory address
to begin the machine code program.
Once it’s carried out, control is return
to the next line of the program, which
restores the segment back to the QBASIC program.
Next up, variable GAME is used to
store the single bit of information we
need and we get this by ANDing the
STATUS value with the hexadecimal
number 8000. The end result of this is
that if the computer has a games card,
then GAME will equal ‘16384’ and ‘0’
otherwise. We simply use it in this
case to print the appropriate message
on screen.
This program will run under
QBASIC in either DOS 5 or DOS 6,
as well as QuickBASIC 4.5. All of
the programs mentioned so far in
this games card series, including
GAMECARD.BAS and .EXE versions,
are available from SILICON CHIP for
$10 including postage and packaging. Please specify either a 5.25-inch
3.5-inch disc as required. You can
call (02) 979 5644 with your credit
card details or send them via fax to
(02) 979 6503.
Next time, we’ll continue by looking
at the games port address and how it
can be used.
References
(1) Using Assembly Language; 2nd
edition, Allen L. Wyatt, Que Corporation 1990.
(2) The Programmer’s PC Source
book; 2nd edition, Thom Hogan,
SC
Microsoft Press 1991.
January 1994 67
|