Option ROM / Expansion Card BIOS Information
Information Contained Herein:
This information
gives the basics of how to use an 8-bit expansion card with on-board option
ROM for your use. The procedure for using a 16-bit expansion card with
two ROMs is similar, but there is the added complication of merging the
two ROMs into one file, rewriting the code, and then breaking the file
into two parts (Even/Odd) again.
This 5-step procedure is
not too complicated. However, you must have access to an EPROM programmer
in order to do this stuff. The software used with the programmer must be
able to do a checksum on the loaded file, and it is good if it has a binary
editor as well. DEBUG.EXE, which comes standard with DOS and Win, is used
for making code changes. For Win95, you should be able to find DEBUG.EXE
in the C:\WINDOWS\COMMAND directory.
Note: DEBUG uses numbers
in hexadecimal form!
Procedure:
1) Remove the
EPROM chip from the board. Read the chip using a programmer and its software.
Save the buffer to disk as CARDROM.BIN. Also, note that the last two digits
of the checksum are zeros. This is important. (Code and data are stored
in the binary file as numbers. A checksum is the sum of all those numbers.
If the last two digits of the checksum are zeros, then the file is considered
to be valid.)
2) Unless you like to take
chances or want to read in the chip a second or third time, you should
make a backup copy of your file in case you mess it up in the following
steps.
3) Use Debug to make the
changes. First, use Debug to look the start of the data in the file – that
is, do a data dump. Note that Debug starts the file at an address offset
of 0100h. All numbers are in hexadecimal. Here's what I got.
C:\>debug cardrom.bin
-d
2B6F:0100 55 AA 10 EB 03 E9 2A 08-E9 7F 00 28 43 29 20 43 U.....*....(C)
C
2B6F:0110 6F 70 79 72 69 67 68 74-20 31 39 38 34 20 57 65 opyright 1984
We
2B6F:0120 73 74 65 72 6E 20 44 69-67 69 74 61 6C 20 43 6F stern Digital
Co
2B6F:0130 72 70 6F 72 61 74 69 6F-6E CF 02 25 02 08 2A FF rporation..%..*.
2B6F:0140 50 F6 19 04 64 02 04 65-02 65 02 0B 05 64 02 00 P...d..e.e...d..
2B6F:0150 00 00 00 00 64 02 02 80-00 80 00 0B 05 64 02 00 ....d........d..
2B6F:0160 00 00 00 00 64 02 04 65-02 80 00 0B 05 64 02 00 ....d..e.....d..
2B6F:0170 00 00 00 00 32 01 04 32-01 00 00 0B 05 32 01 00 ....2..2.....2..
-
Note the first two bytes, "55
AA." They tell the main BIOS that the expansion card has a startup
routine that it also needs to run, and that the main BIOS needs to give
control to the expansion card.
The third byte ("10"
in this case) tells the main BIOS the length of the address space that
is taken by the expansion card. The value of the third byte is the number
of 512-byte blocks of address space that the card takes up. Here, the amount
is (10h) * (512 bytes) = 8 kilobytes. Also, a double-check can be made
by noting that the chip itself is a 2764 EPROM. Thus, it is (64 kilobits)
/ (8 bits/byte) = 8 kilobtyes.
The code starts with the
fourth byte. Let's take a look at it using Debug.
-u 103 2B6F:0103 EB03 2B6F:0105 E92A08 2B6F:0108 E97F00 2B6F:010B 284329 2B6F:010E 20436F 2B6F:0111 7079 2B6F:0113 7269 2B6F:0115 67 2B6F:0116 68 2B6F:0117 7420 2B6F:0119 3139 2B6F:011B 3834 2B6F:011D 205765 2B6F:0120 7374 2B6F:0122 65 - |
JMP JMP JMP SUB AND JO JB DB DB JZ XOR CMP AND JNB DB |
0108 0932 018A [BP+DI+29],AL [BP+DI+6F],AL 018C 017E 67 68 0139 [BX+DI],DI [SI],DH [BX+65],DL 0196 65 |
The
first instruction says to jump to the instruction at address 0108h. Note
that the opcode for this instruction is "EB03", shown in the
second column. This shows that the instruction, "JMP 0108," actually
performs a relative jump – that is, a jump is performed based upon the
address of the current instruction rather than any certain absolute address.
Relative jumps pose no difficulty in Debug, but absolute jumps must be
analyzed with care. If a jump statement starts with "EA" then
it is an absolute jump and the absolute address is given as the destination.
Looking at this address in Debug will not yield the correct result except
the case of a wild fluke.
Well, the instruction at
0108h says to jump to the instruction at 018Ah. If you wish, enter "u
018a" in order to see the instructions starting there.
Here's something to try
in order to illustrate something important.
-u 0100 2B6F:0100 55 2B6F:0101 AA 2B6F:0102 10EB 2B6F:0104 03E9 2B6F:0106 2A08 2B6F:0108 E97F00 2B6F:010B 284329 2B6F:010E 20436F 2B6F:0111 7079 2B6F:0113 7269 2B6F:0115 67 2B6F:0116 68 2B6F:0117 7420 2B6F:0119 3139 2B6F:011B 3834 2B6F:011D 205765 - |
PUSH STOSB ADC ADD SUB JMP SUB AND JO JB DB DB JZ XOR CMP AND |
BP BL,CH BP,CX CL,[BX+SI] 018A [BP+DI+29],AL [BP+DI+6F],AL 018C 017E 67 68 0139 [BX+DI],DI [SI],DH [BX+65],DL |
Well,
now, that doesn't look anything like the instructions we had before. In
fact, unlike the previous listing, there is no instruction starting at
0103h in this listing. The reason is that no instructions start at 0100h,
but we asked Debug to generate instructions starting there. It did its
best. If there were instructions starting at 0100h, it would have given
them to us. Instead, it gave us garbage since it tried to interpret data
as code. Remember that there is a data byte at 0100h, not an instruction.
In fact, the first three bytes are data (55 AA 10); that is why we have
to look at code starting at 0103h, the fourth byte.
While we're at it, look at the original code listing which started at 0103h.
Look at the code at 010Bh and following. Kind of strange-looking code.
Well, if you look at the data dump that we did right at the beginning,
you'll see the Western Digital copyright message starts right there at
010Bh. That's why the code looks so strange – it's not code at all.
The moral is that if it looks like you are getting a bunch of garbage code,
then you may need to start disassembly at a different instruction (unless
you are starting the disassembly at an address that was specifically given
in a jump statement, etc.).
Well, now what are we going
to do with this stuff? Let's use Debug to make a change or two for our
own personal edification. We can write our own assembly code starting at
0103h. Enter "a 103" in order to start writing your code. Type
the first instruction and hit <ENTER>. The next address will automatically
be given, and you can keep going until you are done. When you are finished,
just hit <ENTER> without typing any code.
-a 103
2B70:0103 mov bx,0
2B70:0106 mov ax,0e0d
2B70:0109 int 10
2B70:010B mov ax,0e48
2B70:010E int 10
2B70:0110 mov ax,0e69
2B70:0113 int 10
2B70:0115 mov ax,0e21
2B70:0118 int 10
2B70:011A mov ax,0e0d
2B70:011D int 10
2B70:011F retf
2B70:0120
-
In
this case, the code will display a message on the screen. Since I am using
a monochrome/text-only display, I set BX=0 before calling Int 10h. A carriage
return/line feed is executed followed by "Hi!" and then another
CR/LF. This is done by putting the appropriate ASCII codes in AL, putting
"0e" in AH, and then calling Int 10h. You can do basically anything
you want to do. You may want to clear the screen, send a control byte to
an output port for a computer-controlled project, or whatever. If you can
do it in assembly language, then you can do it here.
Finally, the computer comes to the "retf" command. This returns
control back to the main BIOS.
That's pretty simple, but
you get the idea. Make a note of the next unused address. In this case,
it is 0120h. Next, we need to write the file to disk. Just type "w"
and <ENTER> at the Debug prompt to save the file.
-w
Writing 02000 bytes
-
It
saved the file, the length of which is 2000h bytes (8k). Quit Debug by
entering "q". Incidentally, you can get a summary of the Debug
commands by entering "?" at the Debug prompt.
4) The only problem we have
now is that the lower two digits of the checksum are probably not "00"
any longer. Thus, you must load the new file into the buffer of your EPROM
programmer software. It should tell you the checksum. Using your software,
you can change that file in order to obtain the necessary checksum. Change
any of the numbers that are after the address of your last instruction.
In this case, I can change the data at addresses 0120h and following in
order to get zeroes in the last two checksum digits. Of course, you only
need to change on byte in order to obtain a valid checksum of zeros in
the last two digits.
5) Once accomplished, you
can program a chip (must be the same type as the chip you removed) and
put it in the expansion card. Power up the computer and see what happens.
The computer should run through its regular startup routine before it runs
your code. I use an old 80286 computer for testing this sort of thing,
just in case something were to go horribly wrong.
For testing, I would suggest that you boot up off drive A: so that the
screen with your message will definitely not be erased before you have
a chance to see it. If the computer hangs up or does some strange beeping,
then you may not have created a valid checksum. Maybe you forgot the last
instruction, "retf." Maybe you started at an address other than
0103h.