Vous êtes sur la page 1sur 261

AT BIOS KIT

The Comprehensive Guide


to Creating an AT Bios in C
" .
. . _
A Complete Description of the Bios
Including Source Code on Diskette
John O. Foster & John P. ChQisser
Annabooki
I SBN 0-929392-02-7
AT BIOS KIT
The Comprehensive Guide
to Creating an AT Bios in C
John O. Foster & John P. Choisser
AT BiosKit
by JohnO. Foster and John P. Choisser
PUBLISHED BY
Annabooks
12145 Alta Carmel Court, Suite 250-262
San Diego, CA. 92128
Copyright (C) Annabooks 1988, 1989
Copyright (C) FOSCO 1988, 1989
All Rights Reserved. No part of the contents of this book may be reproduced or transmitted in any
form or by any means without the written permission of the publisher, except for the inclusion of brief
quotations in a review.
Object Code produced from the Source Code mes may be reproduced only in accordance with the
terms of the license agreement.
November 1989
Printed in the U oited States of America
ISBN 0-929392-02-7
This book is designed to provide information about a Basic Input Output System (BIOS) for an AT
type computer. No warranty of suitability, purpose, or fitness is implied. The information contained
within as supplied on an "as-is" basis. The authors and publishers shall have neither liability nor respon-
sibility to any person or entity with respect to any loss or damage, real or claimed, in connection with or
arising from any information contained in this book.
Dedication
John O. Foster
This Book is dedicated especially to Patricia, and to the rest of the family for all
their help and support.
John P. Choisser
This Book is dedicated to Coleen for her loving support during my career change.
Preface
What started as a diversion has turned into a gratifying nuisance. Publishing the XT-
AT Handbook and the XT Bioskit was an exercise in "Is anyone interested?" The
Handbook proved there were some people out there, and the XT BiosKit indicated
there were a lot of people out there. "Do you publish an AT Bios Book?" was often
asked. When we at Annabooks tallied up the interest, the next move was obvious.
More and more system designers are moving from 8088 based systems to 286 and
386 based systems. And the fascinating thing we heard was the variety of uses to
which the PC architecture was being put. ..
We heard from those who are involved in automation, robotics, research, education,
avionics, consumer and office products, energy management and control, and
industries and applications too numerous to mention, both in the U.S. and around
the world. Product volumes involved ranged from 5 and 10 per year, to thousands
per month.
We even heard that because of the BiosKit, projects that were designed for 286
based systems could be changed to 8088 based systems. Being able to use the
BiosKit was important enough to justify changing the product.
For all you who asked for an AT BiosKit, we are happy to present this latest volume
in an exciting series which will cover a variety of topics, always in the form of a
"working" book.
John O. Foster
Hidden Meadows, California
November 1988
Table of Contents
SECTION A "ABOUT THE BIOS"
One Introduction
Two Audience
Three About the Programs
Four Tools Required
Five Ownership, License, and Warranty
Six Overview
SECTIONB 'THE C UTILITY PROGAMS"
One The Biossum File
Two The Biosdate File
Three The Biostype File
Four The Biosgen File
SECTIONC 'THE BUILD PROGRAMS"
One The Make File
Two The Link File
Three The Cut.inp File
SECTIOND 'THE ASM PROGRAMS"
One The Prfx.inc File
Two The Top File
Three The Pad File
Four The Fill File
Five The Data File
Six The Virt File
SECTIONE 'THE CPROGRAMS"
One The Kit.h File
Two The Misc File
Three The Pod Module
Four The Equipment Driver
Five The Memory Size Driver
Six The Keyboard Driver
Seven The Video Driver
Eight The Floppy Disk Driver
Nine The Hard Disk Driver
Ten The Boot File
Eleven The Cassette Driver
Twelve The Parallel Printer Driver
Thirteen The Comm Driver
Fourteen The Timer Interrupt
Fifteen The Time of Day Function
Sixteen The Print Screen Function
Seventeen The Sys Vue File
SECTIONF "ODDS AND ENDS"
One Loading Static Ram
Two The Indent Program
Three The Hilite Program
Four The Parens Program
Five The Bin2Hex Filter
Six The Splitbin Program
Seven The Mergebin Program
Eight The Patch.asm File
NOTES
SECTION A
About the Bios
This section introduces the Bios, lists some reasons for creating your own
customized Bios, explains Ownership and License information, and provides an
Overview of the structure of the Bios.
Introduction AII
ONE
Introduction
Unseen and unnoticed, the Bios (Basic input/output system) of a personal computer
takes control when power is switched on, setting up the hardware devices, running
tests, and booting up the operating system from disk. Without a Bios the machine is
an unusable, non-operating collection of hardware components. Yet the Bios is a
mysterious component for the majority of users. The Bios is a collection of programs
stored on a read-only memory chip and is usually considered to be part of the
hardware set, but these routines are like any other software. They can -be analyzed,
understood, modified and re-created as desired.
This Book
This book is a guide to analyzing and understanding what a Bios is, how it works,
and how one goes about creating a Bios. The descriptions of the Bios functions are
augmented with listings of the programs required to perform those functions. The
auxiliary tools and utility programs which are used to create the Bios are also
included with an explanation of their purpose and function.
What is the Bios?
Bios is an acronym for Basic input/output system. It is a set of programs that reside
in non-volatile memory (often called firmware; programs that are implemented in
hardware memory chip(s) and are not lost when power is turned ofO. The Bios
includes the power-on diagnostics, a boot-up program, and device drivers for the
keyboard, disk, display, serial ports, printer port, and miscellaneous functions. A
Bios is usually written in assembly language, but the BiosKit is done in the C
language wherever possible. Some low-level operations require assembly language
for memory allocation reasons and some operations are done in assembly language
for efficiency. But by providing the bulk of the BiosKit in C, it is much easier to
understand, modify, and maintain the code.
Why do your own Bios?
You may want special features, such as special interface card support, Sys Vue
capability, faster bootup, equipment status displays, and so forth. Some of these
features are difficult to implement with a supplied Bios since you do not have the
capability to modify it. Additionally, a standard Bios may not have the compatibility
that you desire. You may also wish to upgrade your machine to newer capabilities
that are included in later generations of compatible computers.
If you are a manufacturer or systems integrator, you may have found that your own
Bios requires expensive long-term commitments to a Bios vendor that may not be
able to respond to your needs in a timely manner. Once you have control of your
Bios in your own hands, you will be able to modify and maintain your Bios at your
own discretion.
If you are a manufacturer of systems for use in government or commercial
applications which require delivery of source code for all software included in a
system, BiosKit allows you to easily meet these requirements without cumbersome
Al2 Introduction
escrow agreements or additional payment to a Bios Supplier to obtain source code.
By including BiosKit Documentation as part of your product, you may satisfy your
project requirements. If your project requires special verification or certification
activities, Bioskit not only gives you access to source code, it also allows you to
configure it as you desire.
A Type BiosKit
Audience A21
TWO
Audience
This book is intended for various groups of people:
* Those who have an unsatisfied curiosity about the internal workings of their
personal computer.
* Those who are involved in the hardware and system design details of PC's and
need to understand the workings of a Bios.
* Those who are creating special applications of PC systems and find that the typical
PC Bios may have some shortcomings or omissions.
* Those who just want to make their own Bios so they can enjoy the satisfaction of
having done it.
* And especially for those people that are in more than one just one of the above
groups.
More Notes
About The Programs A31
THREE
About the Programs
This book and the magnetic media included with it provide you with the source code
and explanations needed for you to customize your own Bios for an AT type
compatible computer. The majority of the source code is in the C language with
supporting routines in assembly language. C was chosen for a variety of reasons,
including:
* It is well suited to systems level programs because it permits access to machine
features.
* It is widely used, understood, and a de-facto standard among system level
programmers.
* There are many publications available for reference, tutorials, as well as periodical
publications for alternate information.
* It is supported by a variety of affordable compilers.
* Its architecture and structure encourage good programming practices which help
to minimize the frustrating aspects of debugging and error-correction.
Because of some restrictive aspects of a Bios program, some of the programs are
written in assembly language, as you might expect with systems-level C programs.
This is required because:
* Certain locations in the completed program need to be fIXed at absolute memory
locations (the reset jump).
* Constants need to reside in read-only memory and be allocated to the code
segment in fIXed locations.
* Some operations such as block moves (used in CRT scrolling, for instance) are
much faster than the C counterparts.
Things To Do
Tools Required A-4-1
FOUR
Tools Required
Building and customizing the Bios requires some tools. Knowledge is the basic tool.
Then you will need the physical tools; the hardware and software described below.
Knowledge Tools
Readers should have or be prepared to acquire some degree of skill in the following
areas to comprehend and become proficient in the creation and enhancement of a
Bios:
* operation of DOS
* operation of a text editor
* assembly language understanding
* understanding of the C language
* understanding of the AT architecture
There are many excellent publications available on these subjects in addition to the
manuals that are supplied with the software tools listed below. By visiting your
library and book store, and by reading computer periodicals, and especially by
talking to computer-interested acquaintances, you will find ways to augment your
knowledge. For those who may be apprehensive about tackling a Bios project,
remember that knowledge is acquired by bits and pieces. Curiosity, patience, and a
positive attitude will be your best ally.
Software Tools
To build the Bios you will need the following tools:
* C Compiler
Recommended - Microsoft V 5.1 or later
Other Compilers may require some modification of
the Source Code.
* Macro-Assembler - Microsoft V 5.1 or later
* Linker - Microsoft (included with MASM or Compiler)
* Debug program (included with MASM)
* A Make Utility (included with MASM or Compiler)
* An Archive or backup utility is also recommended.
You may chose alternate tools, but they may require some modification of the
source code to build and execute successfully.
Hardware Tools
Your development computer should be an XT / AT compatible with 640K of ram, a
hard disk, and a printer. Either a color or monochrome monitor is sufficient.
To program Eproms for your computer you will need a Prom programmer. The
Sunshine (brand name) programmer (approximately $125.00) is suggested.
To erase Proms, a Walling Datarase UVProm Eraser is suggested ($35 to $55).
A42 Tools Required
Target Tools
The programs in this book were designed for use with an AT compatible hardware
set. This means that the original AT or the truly compatible "clone/compatibles" will
require little or no Bios modification to operate successfully. There are some areas
of difference, however, that may affect your Bios details. Some of these are
described below.
Prom/Rom chip types - Some high volume AT's use masked Rom chips for the Bios.
These chips mayor may not have the same electrical characteristics and pinout as
the Prom chips you would normally use for your Bios. You should verifY that the
pinout of the original Bios chip you intend to replace is compatible with the chip you
will be using. If it is not pin compatible, you may be able to replace it by using an
appropriate adapter.
The next consideration is the addressing capability of the original Bios Socket(s) in
your target system. Depending on the original design, the address mapping may be
hard-wired or jumper (or decoding device) selectable to accommodate the Bios
Proms you create. You should have the range of FOOOO-FFFFF available for your
Bios. This will probably require two Proms, one for even bytes and one for odd bytes
in your target system.
Turbo machines generally interpret a special combination of keystrokes to
enter/leave the turbo mode. This decoding may be added to the keyboard handler
(Bioskb.c ) in the scan code conversion section of the hardware interrupt service
routine. Turbo-AT's may use one of the spare output pins of the 8042 keyboard
controller chip to change the CPU clock speed. To determine if this method is used,
you may manually toggle these bits using Sysvue (Port In and Out commands) to see
if this scheme is used to control the Turbo switching. If you include a Turbo
switching feature and subsequently have floppy disk failures, the DMA clock speed
is to be suspected. Some Turbo motherboards switch the DMA clock to high speed
along with the CPU clock. It may be necessary to include an "Unturbo" and
"Returbo" sequence in the floppy disk module (Biosdisk.c) to insure that the DMA
is operated at the slow clock speed during disk transfers. To do this, save the state of
the signal used to implement the speed switch upon entry to the Disk_io handler,
and restore it to its previous condition upon exit. A Turbo machine may have a
A-Type BiosKit
Tools Required A 43
"Turbo" mode display (typically an LED) to show when it is in turbo mode. This
indicator is usually driven from the same speed switch signal that controls the clock.
One method of investigating compatibility is to attempt to run the standard version
of DOS on a computer. If a given computer operates only with its customized
version of DOS, some hardware incompatibility might be expected.
SysVue
Bonus - BiosKit includes the source code for Sys Vue, a Prom resident program that
provides many of the features of disk resident Debug programs. Sys Vue is always
available with a keystroke sequence. It is extremely handy for checking custom
features of your Bios.
Once you have successfully built the standard version of the BiosKit, you will be
ready to consider special versions for your particular application.
Section A: About the Bios
Things I Should Do Soon
Ownership, License, Warranty A51
FIVE
Ownership, License, and Warranty
The following paragraphs explain the ownership (right of title) of the Source Code
and of the Binary Code generated from it, the license granted to you to duplicate
the object code, and the warranty of this published information. This information is
important to you. Please read it carefully.
Ownership oj Source Code
The Source Code for BiosKit is an intellectual work covered under the copyright
laws of the United States and other countries. Title to ownership is retained by
FOSCO. Your purchase of the BiosKit includes a license to use the Source Code,
but does not convey right of title of said Source Code to you. You may use the
Source Code in accordance with the License Agreement as described in the
following paragraph.
License to Duplicate
With the purchase of the BiosKit, FOSCO and Annabooks have waived the $4.00
per copy license fee for the first ten (10) copies of the BiosKit Binary code for your
own use, or for sale in your product.
You are responsible for remitting to Annabooks the fee of $4.00 per copy for
additional copies. This fee remittance should be made payable to Annabooks and
annotated as "AT Bioskit License Fee". It should be made on not less than a
quarter-year basis and must be payable in U.S. (US$) funds.
Payments should be sent to the following address:
Annabooks
12145 Alta Carmel Court, Suite 250-262
San Diego, CA. 92128
Please abide by the license fee requirements to avoid the need for legal recourse on
the part of Annabooks and FOSCO to insure compliance with these requirements.
During the build/ customization phases, you may program an unlimited number of
Proms until you have completed the Bios. Once you place the Proms in a computer
used to run programs, the Proms are included in the ten (10) quantity covered by
this license to duplicate.
Any Bios built from the BiosKit must include the FOSCO copyright information
included with the original source code. You may add additional information, but you
may not delete any copyright information included in the standard BiosKit.
A52 Ownership, License, Warranty
DISCLAIMER AND LIMITED WARRANTY
The information contained in this book and on the diskette is believed to be factual
and accurate; however, no claim of such, nor of fitness to purchaser's intended use,
is implied. Although the programs described in this book (and contained on the
diskette) are believed to be compatible in function and operation with the normal
operation of an AT type computer, no warranty as to the completeness of
compatibility to any other Bios is implied or expressed. Prudence dictates that the
user must verify fitness, correctness, and applicability of the information contained
in this publication. The diskette(s) are warranted to be readable when installed in a
compatible computer. Warranty is limited to the replacement of unreadable
diskette(s) within 90 days of purchase. The Diskette(s) are not copy-protected and
should be used only to make working copies, and then archived for backup
purposes. Liability under this warranty is limited to the replacement of the
diskette(s) even if claims otherwise have been made by purchaser or any user of the
information contained in this publication. This statement of warranty constitutes the
full and complete agreement between seller and buyer. and may not be modified by
oral representation or written instrument without the permission of FOSCO and
Annabooks.
A Type BiosKit
Overview A61
SIX
Overview
This chapter is intended to acquaint you with the major functions and parts of the
Bios. To do this, we will follow the flow of the Bios from the power-on hardware
reset point and summarize what happens as the computer is turned on. Descriptions
of detailed operations will follow in later sections and be correlated with the Source
Code Listings.
Power On -
The 80286 processors start operation at segment:offset address FFFFF:OOOO. This
means that program execution begins at the last paragraph (16 bytes) at the top of
address space. This location normally will have a far jump to a lower address where
the Bios will start to initialize and check-out hardware features of the system.
Diagnostics -
This usually starts at a label called 'reset' and includes checking of the CPU chip
registers, tests and initialization of the peripheral chips, and ends up by invoking a
bootstrap routine.
Bootstrap -
The function of the bootstrap routine is to load DOS from a floppy disk. If you have
a hard disk in the system, a failure to boot from a floppy is usually followed by an
attempt to boot from the hard disk. If no disk is available, you may wish to default to
Sys Vue or some other Prom resident program you may elect.
Drivers -
The Bios contains the low-level drivers for a variety of devices. DOS normally
assumes these drivers are present in the Bios and makes calls to them to perform
peripheral access. The drivers correspond to the Bios Interrupts documented in
various publications about PC's and DOS. To fully support DOS, these drivers must
be included, and their devices initialized by the Bios.
Bios Structure
This description of the Bios structure IS intended to clarify. some of the
characteristics of the Bios.
The 80286 processor starts executing code (from a power-up reset) at the highest
paragraph in the memory map. This is at Segment:Offset FFFFF:OOOO. To properly
respond to the hardware reset, valid executable code must be stored at this location
in the Bios Prom. To insure that the instruction intended for this location is
assembled and linked correctly, the final module of the Bios is manipulated in such
a way that the normal linker utilities (such as Microsoft's Linker which links
programs in an ascending address sequence), can achieve this result. The top
module of the Bios is written in Assembly language, so that programmer control is
maintained over the location of certain instructions. Additionally, the top module
A 6 2 Overview
provides a place to include various table structures and assembly language
subroutines, which are C functions.
From the power-on reset, a jump is executed (at FFFFF:OOOO) to an assembly
language initialization code sequence which initializes the DMA controller, the
Ram Refresh, and the first 64 Kbytes of System Ram. Once this has been
accomplished, the C language POD (Power On Diagnostic) module is executed.
This module continues the power-up and diagnostic checks of the system, and also
calls setup (initialization) routines in the various device driver modules. When the
system has been completely initialized, the bootstrap function is called.
The POD process includes:
loading the interrupt vector locations,
initializing the display adapter,
determining the size of the system Ram,
testing the system Ram,
reading the equipment configuration CMOS Ram,
performing a checksum test on the Bios prom,
identifying and initializing COM and LPT ports,
calling any executable Rom option modules,
initializing the floppy disk drive(s),
and finally calling the bootstrap procedure.
Why Link is Done Twice
During the linking process when the Bios, a trial link is performed. This
trial link determines how far short the BIOS falls of filling a complete segment (64
Kbytes). This shortfall in length is calculated, and a filler module is built which will
compensate for the shortfall. The Bios is then linked again with the filler module to
produce a Bios in the required locations are fIXed at the correct addresses.
This file is then converted from an .EXE format file to a .BIN binary image file
suitable for transfer to a Prom programmer.
How to develop and test a Bios
The simplest way, of course, is to build a Bios, program a Prom, install the Prom in
the system, and see how the system runs. This method is time consuming and
debugging can be difficult, particularly if the system doesn't run at all. The preferred
method is to install a Static Ram Adapter Card residing above the video ram area,
and away from any rom-scan devices such as EGA Video and Hard Disk Adapters
that might be installed in your target system. Recommended location is segment
DOOO. The Test Bios is then loaded into the Ram area and a Jump instruction is
executed to start executing the Test Bios. The Load-and-Jump can be performed
using a Debug Batch file as shown in Section F. To effectively integrate the Bios,
you should have (or should add) a pushbutton reset switch to your target system.
This allows you to easily reset and restart your system with its prom-based Bios if
your Test Bios should lock up or run away due to modifications which you are
testing.
An additional aid to testing is to add debug mode display statements to track the
activity of the Bios. These may be included in your C modules by using the
write_string("text") statement. Hexadecimal byte and word values may be dumped
A-Type BiosKit
Overview A 63
using the lbyte(value) and lword(value) statements. By referring to the BiosVue.c
module, you may examine examples of the usage of these statements.
When you have verified the operation of your modified Bios, the debug-mode
statements may be removed, and the Bios rebuilt.
Driver Structure
By examining the structure of the Driver modules, you will see that they are
essentially self-contained. They may call common assembly language functions in
BiosTop.asm and common C functions in BiosMisc.c, but they seldom will call other
modules except through the Interrupt structure. This helps to isolate interaction and
serves to make testing easier.
Drivers have the general structure of a Setup routine followed by the Driver itself.
Some drivers may also have a service routine for its associated hardware interrupt.
The Setup routines are called from BiosPod to initialize the drivers during the
Power-On-Diagnostics.
Programming Style
As you work with the source code, you will begin to apply your particular style of
to re-writes, additions, and changes. This is normal and it is a sign of
your increasIng of the programs. Don't be afraid to analyze the
program structure and expenment. There are at least as many ways to code a
function as there are programmers! Since this book deals with each topic only once,
we had to present each example in a particular manner. You have a different
perspective and style, and you will probably see it in a slightly different manner.
Remember there are many right ways to code a function. It is sometimes difficult to
find one of those right ways; it is usually easier to find one of the wrong ways!
Section A: About the Bios
Things I Should Avoid Doing
SECTIONB.
The C Utility Programs
These programs are used during the building process to add the date-stamp,
calculate the checksum, install the CPU type identification, and to fix some
locations at absolute addresses.
The Biossum File B-l-1
ONE
The Biossum File
The Biossum.c file is used during the Bios Build process to calculate the additive
checksum of the Bios and to insert the checksum value into the last byte of the Bios.
It looks for the first non-FF location and treats it as the start of the block. If the Bios
is padded with FF's at the front of the file, the program will scan forward every 2K
bytes to look for the start. This allows you to reserve space in 2 Kbyte blocks at the
front for your own special programs. The Rom-Scan routine will determine where
the Bios starts and scan up to that point.

*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: Bios checksum calculator
*
* Version: 1.00
*
* Author: FOSCO
*
* Date: 1-5-89
*
*
* Functional Description:
*
: This program calculates a checksum and inserts it into the last byte location of the Bios.
* Argunents:
* Filename
*
* Return:
* None
*
: Version History:
*
***************************************************************************************************/
/* INC L U D E F I L E S */
#include <stdio.h>
/* FUN C T ION PRO TOT Y PES */
/* G LOB A L V A R I A B L E S */
uns i gned numread i'
char
FILE *stream;
/* G LOB A L CON S TAN T S */
/* L 0 CAL D E FIN I T ION S */
/* L 0 CAL CON S TAN T S */
/* PRO G RAM */
main(argc,argv)
int argc;
char *argv[];
{
if (argc <2)
(
}
printf("Not enough parameters on COlllll8nd line\n");
exit(O);
if stream = fopen(argv[1] ,"r+b" == NULL) printf(IICould not open fi le for reading\n
ll
);
else
(
sum=O'
numread = freadchar *)buffer,sizeof(char),32768,stream);
}
Bl2 The Biossum File
/*
** Scan for the first non -ff- cell at 2k boundaries to mark the start of the bios code.
** Reserve the prior cells for rom module integration later when customizing the bios prom
** with extensions.
*/
for (i=O;(i < numread) && (buffer[i] == Oxff); i += 2048);
/* i is advanced to beginning of actual bios code */
for (;i<numread;i++) sum += buffer[i];
numread = freadchar *)buffer,sizeof(char),32767,stream);
for (i=O;i<numread;i++) sum += buffer[i];
sum = O.-sum;
buffer[l] = sum;
fseek(stream
l
-1L,SEEK END);
fwrite(&sum,1,1,stream);
fclose(stream);
}
A Type BiosKit
The Biosdate File B-2-1
TWO
The Biosdate File
The Biosdate.c file is the program which inserts the current date value as the date-
stamp in the Bios module. This date is determined from the current date in your
development machine. It will obviously affect the overall checksum of the Bios
module, if you re-build on different days.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: bios date routine
*
* Version: 1.00
*
* Author: FOSCO
*
* Date: 1-05-89
*
* Filename: Biosdate.c
*
* Functional Description:
*
* Insert date string into bios binary file. This program inserts the current date information
* into the date field in the Bios at location FFF5
*
*
*
* Fllename
*
* Return:
* Writes date field in bios.bin file
*
* Version History:
* 1-5-89 font revision
*
***************************************************************************************************/
/* INC L U 0 E F I L E S */
#include <stdio.h>
/* FUN C T ION PRO TOT Y PES */
/* G LOB A L V A R I A B L E S */
FILE *stream;
char date_buffer[9];
/* G LOB A L CON S TAN T S */
/* L 0 CAL 0 E FIN I T ION S */
/* PRO G RAM */
main(argc,argv)
int argc;
char *argv [] ;
{
}
if (argc <2)
(
}
printf("Not enough parameters on conmand l ine\n");
exiteO);
if stream = fopen(argv[1],lIr+b" == NULL) printf("Could not open file for reading\n");
else
(
fseek(stream,-11,SEEK END); /* find date field */
strdate(date buffer);
Twritechar -)date buffer,sizeof(char),8,stream);
} -
fclose(stream) ;
Things Someone Else Should Do
The Biostype File B-3-1
THREE
The Biostype File
The Biostype.c file is used to insert a byte identifying the type of system in which the
Bios is installed. The type identification may be used by some applications (or the
Bios if so desired) to determine operational characteristics of the system hardware
and/ or software. This byte is located at the next- to-last location of the Bios. In an
AT Bios, there is also another identification function; Interrupt 15, Function code
CO, which returns system configuration parameters. This parameter block provides
additional type information.
/**************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
: Module Name: Bios type
* Version: 1.00
*
* Author: FOSCO
*
* Date: 5-5-88
*
* Filename: biostype.c
*
: Functional Description:
* Insert CPU Type byte into bios binary file. This program inserts a machine identification byte
* at location FFFE 1n the Bios. Because of an Assembler quirk, if we try to define this in the
* Source file, the assembler increments the offset counter and believes that the segment becomes
: larger than 64K bytes, which it considers an error condition.
*
*
* b10stype filespec [typel
* where type is pc,xt,at,jr,xt640
* if type is omitted, then default is xt
*
* Return:
: Writes type byte in bios.bin file 'filespec'
* Version History:
*
*
***************************************************************************************************/
/* INC L U 0 E F I L E S */
#include <stdio.h>
#include <string.h>
/* FUN C T ION PRO TOT Y PES */
/* G LOB A L V A R I A B L E S */
FILE *stream:
char type_buffer[2l;
/* G LOB ALe a N S TAN T S */
/* LaC A L 0 E FIN I T ION S */
#define at Oxfc /* these are the standard defined types */
#def i ne xt Oxfe
#define pc Oxff
#def i ne j r Oxfd
#define xt640 Oxfb
/* PRO G RAM */
main(argc,argv) /* bios.bin */
int argci
char *argv [] ;
{
char cpu_type = xt; /* default to XT type byte */
B32 The Biostype File
if (argc <2)
{
}
printf("Not enough parameters on conmand line\n
ll
);
exi teO);
if (argc > 2)
{
if == 0) cpu_type = at;
i f IIxtlf) == 0) cpu_type = xt;
if == 0) cpu_type = f?C;
if ,lfjrlf) == 0) cpu_type = Jr;
if ,lIxt640") == 0) cpu_type = xt640;
}
if stream = fopen(argv[1] ,"r+b
ll
== NULL) printf("Could not open file for reading\n");
else .
{
fseek(stream
6
-2,SEEK END); /* find type field */
type buffer[ ] = cpu-type; .
fwritechar *)type_6uffer,sizeof(char),1,stream);
}
fclose(stream);
}
A Type BiosKit
The Biosgen File B-4-1
FOUR
The Biosgen File
The Biosgen.c file is used during the build process to sense the size of the Bios code
and calculate a value which will be used to upward justify the Biostop module so
that it resides in the highest portion of the Bios segment. This is required to insure
that when a power-on hardware reset occurs there is an instruction present to be
executed.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: Bios filler generator
*
* Version: 2.00
*
* Author: FOSCO
*
* Date: 12-01-88
*
* Filename: biosgen.c
*
: Functional Description:
* This program reads the map file (bios.map) and calculates how far short it falls from ending at
* the top of the segment. Then it builds a biosfill.inc file that pads out enough to complete the
* segment (64k bytes). The .inc file is used in a second linking of the .obj files. This produces
: a full 64k byte file with the power-on reset jumps fixed at offset FFFO in the binary image file.
* Ar!iJl.II1ents:
: bl0sgen bios.map biosfill.inc
* Return:
* Creates a biosfill. inc file
*
* Version History: 2.00 9/12/88
* The method of determining the file length was changed to operate with 5.1 tools. This program
* now looks at the .MAP and searches for the ORG EOOO label. If it finds the label, it looks at
* the offset value associated with it, and calcuTates the fill value from that. If it does not
* find the label, it prints an Abort Message. If the . m a ~ file shows that the Bios is too large,
* it prints a message indicating that the Bios will not fit into the segment.
*
* Notes:
* This file normally compiles with two Warning Messages. They maybe disabled by changing the
* message level switch in the make file. The program will execute OK even with the warnings.
*
***************************************************************************************************/
/* INC L U 0 E F I L E S */
#include <stdio.h>
#include <string.h>
/* FUN C T ION PRO TOT Y PES */
unsigned int hval(unsigned char);
/* G LOB A L V A R I A B L E S */
FILE *stream
int radix = ~ O ;
char first[20],second[20],third[20];
char *p;
unsigned int it
unsigned int dlff;
unsigned int find; /* find/no find flag */
unsigned int find string;
unsigned long int-numread;
unsigned char line[255], *result;
/* G LOB A L CON S TAN T S */
/* L 0 CAL 0 E FIN I T ION S *1
/* PRO G RAM */
B42 The Biosgen File
main(argc,argv) 1* sourcefile.map,destfile.inc *1
int argc;
char *argv[];
{
/* this is the label we will search for */
char *estring = "_ORG_EOOOII;
/* this is where we move the offset value of the label*1
char *vstring = 110000";
if (argc <3)
(
}
printf("Not enough parameters on comnand l ine\n");
exi t(O);
if stream = fopen(argv[ll ,"r+b" == NULL) printf("Could not open file for reading\n");
else
{
find = 0;
/* check each line of the .map file for the wanted label*1
do
(
ifresult = fgets(line,255,stream != NULL);
(
/* check for the label */
if (strstr(result,estring) 1= NULL)
(
find string = OxeOoo;
strnepy(vstring,&line[6],4);
diff = O(
for(i=O;1<4;i++)
{
diff = (diff 4) + hval(vstring[i]);
}
find = 1;
}
}
}
while result != NULL) && (find == 0;
fclose(stream);
if (find == 0) 1* no find */
(
printf("Could not find ORG FOOO label in .MAP file\n\r");
printf("Aborting operation7\n\r")i
printf(" 1. Check comnand line argunent speci fies .MAP file\n\r");
printf(1I 2. Check .MAP file for proper labels.\n\r")i
}
else
(
printf(1I File size = XSu\n\r
tl
,diff+(Ox10000-find string;
if (diff >= find_string) -
{
printf(".EXE file is to large to process - aborting fill generation\n\r")i
}
else
(
}
numread = find_string - diffi /* num to write */
printf(1I Free Space = XSu\n\r",numread);
/* now build the text line for the biosfill.inc file */
strcpy(first II cI:) II).

strcpy(third," dup(Offh)")i
strcat(first,second)i
strcat(first,third)i
if stream = fopen(argv[2] ,"Wlt == NULL) printf("Could not open file for wdting\n")i
else
(
fwritechar *)first,sizeof(char),strlen(first),stream);
}
fclose(stream);
}
}
}
/* convert hex ascii to val */
unsigned hval(unsigned char cval) {
A Type BiosKit
unsigned val;
cval -: '0'
if (cval > ~ ) cval -: 7;
val: cval;
return(val);
} .
The Biosgen File B-4-3
Section B: The C Utility Proauams
Things I keep Forgetting
SECTIONC
The Build Programs
These programs are used to assemble, compile and link the Bios modules. The
process is automated to permit a complete build with just a few keystrokes.
The Make File Cll
ONE
The Make File
The Make File is the top level file used in building a Bios. It includes all the
operations needed to compile and assemble the source files, to link them into a
code module, and to convert the code module into a binary image file for Prom
programming. This file will also build the utility programs needed for the build
process. Using the MAKE utility simplifies the operation and allows the building of
the Bios with just a few keystrokes.
#***********************************************************************************-***************
#
# Copyright (c) 1988, 1989 FOSCO - All Rights Reserved'
#
# Module Name: atbios.make
#
# Version: 1.00
#
# Author: FOSCO
#
# Date: 1-5-89
#
# Filename: at
#
# Functional Description:
#
#" This is the Make file to build the AT Bios
# To Build the Bios, type 'make bios' <enter>
#
# Version History:
#
#
#***************************************************************************************************
#--- inference rules - see description of MAKE utility ---
.asm.obi: atprfx.inc
masm $ IW1/Z1/z;
.obj.exe:
link $*;
.c.obj: atkit.h
cl IZp1 IJ IWO IG2 Ic IZl IZi lAS lOx S*.c
#-------------- list of files to build -------------------
#--- These are utility routines used to build the Bios ----
# routine to fi II up to top module
biosgen.exe: S*.c
cl IWO lOx IZi S*.c Ilink ICo
# routine to place date in binary file
biosdate.exe: S*.e
cl IWO lOx IZi S*.c Ilink ICo
# routine to place type byte in binary file
biostype.exe: S*.e
cl IWO lOx IZi S*.e Ilink ICo
# routine to checksum binary file
biossum.exe: S*.c
cl IWD lOx IZi S*.c Ilink ICo
# routine to display parenthesized text
parens.exe: $*.c
Cl2 The Make File
cl IWO lOx Ili S*.c Ilink ICo
# routine to indent according to {}
indent.exe: S*.c
cl IWO lOx Ili S*.c Ilink ICo
, routine to display comments
hilite.exe: $*.c
cl IWO lOx Ili $*.c Ilink ICo
, routine to split out even/odd bytes
splitbin.exe: $*.c
cl IWO lOx Ili $*.c Ilink ICo
, routine to merge in evenlodd bytes (for test purposes)
mergebin.exe: $*.c
cl IWO lOx Ili $*.c Ilink ICo
bin2hex.exe: $*.asm
masm $*.
link $*;
# binary image to Intel hexadecimal filter
,---------- These are the Bios Modules --------------
, routine to pad the front of the Bios
atpad.asm:
atpad.obj:
atdata.asm:
atdata.obj:
atprsc.obj:
atmem.obj:
atmisc.obj:
atboot.obj:
atvue.obj:
atcomn.obj:
atlcb.obj:
atdisk.obj:
athard.obj:
atlpt.obj:
, the data declaration module for biosvue
, print screen driver
, memory size driver
, misc drivers in 'c'
# bootstrap routine
, sys vue
# COllIn driver
, keyboard driver
# floppy disk driver
, hard disk driver
# lpt ddver
, crt driver
A Type BiosKit
atcrt.obj:
attmr.obj:
attod.obj:
atequi.obj:
atcass.obj:
atpod.obj:
atvirt.asm:
atvirt.obj:
attop.asm:
attop.obj:
'II timer driver
'II time of day driver
'II equipment driver
'II cassette driver
'II power on diagnostics
'II virtual mode driver
'II absolutized high location module
'11---------- This is the linking process -----------
'II make binary file of bios
at.bin: \
atdisk.obi atlink atkb.Obj atvue.Obj \
atcomm.ObJ atlpt.Obj atcrt.Obj atcut.inp \
atPOd.obj atpad.Obj atdata.Obj atvirt.Obj \
atboot.obj atcass.Obj atequi.ObJ attmr.Obj \
atmisc.obJ attop.Obj at \
attod.obj atprsc.Obj atmem.Obj athard.Obj \
biostype.exe biosdate.exe biossurn.exe biosgen.exe
copy atblank.inc atfill.inc
masm atf ill
link Cilatlink
biosgen at.map atfill.inc
masm atf ill;
link ICo Cilatl ink
debug <atcut.inp
biosdate at.bin
biostype at.bin at
biossurn at.bin
spl itbin at
The Make File Cl3
Section C: The Build Pro&rams
Things I Forgot
The Link File C-2-1
TWO
The Link File
The Link File is an indirect file used by the linker to convert the group of bios---.obj
files into an executable (.EXE) file module. The EXE module will then be
converted to a binary image file for loading a prom programmer.
atpad+
atdata+
atpod+
atboot+
atconm+
atkb+
atdisk+
athard+
atlpt+
atcrt+
atequi+
atmem+
attmr+
attod+
atprsc+
atcass+
atmisc+
atvue+
atvirt+
atfill+
attop,
at,
at/m;
Things I Remember
The Cut.inp File C31
THREE
The Cut.inp File
The Cut.inp is used after the second link to transform the .EXE file, which is output
by the linker, to a .BIN (binary image file). This type of operation is usually done by
using the DOS Utility "EXE2BIN", but "EXE2BIN" cannot handle a full segment
.exe file.
****************************************************************************************************
*
* Copyright ec) FOSCO 1988, 1989 - All Rights Reserved
*
: Module Name: Cut of bios after second linking
* Version: 2.00
*
* Author: FOSCO
*
* Date: 1-5-89
*
: Filename: atcut.inp
: Functional Description:
*
*
*
*
*
This input file is used to perfonm an exe -> bin load of the bios.exe file. Because it
is a 64K file, the traditional exe2bin program overflows. This file directs that a
64 Kbyte output file (bios.bin) be written. This output file will be the binary image
used for prom programming.
* Argll1lents:
*
* Return:
*
* Version History:
*
***************************************************************************************************
nat.exe
l
rbx
1
rex
o
nat.bin
w cs:O
q
Things Someone Should Tell Me
SECTION:D
The ASM Programs
These programs are used to include assembly language functions, tables, virtual
memory support, and initial start-up code for the Bios.
The Prfx.inc File Dll
ONE
The Prfx.inc File
The Prfx.inc is the include file used for the assembly (.ASM) modules. It specifies
the memory model, macro definitions, segment loading order for the linker, and
required absolute offset locations for various data and code.
page 55,132
.*************************************************************************************************** ,
Copyright (c) FOSCO 1988 - All Rights Reserved
Module Name: AT Bios assembly module prefix
Version: 2.01
Author: FOSCO
Date: 01-01-89
Filename: biosprfx.inc
Functional Description:
This include file is used for the standard definitions for assembly language modules of the bios.
It is used to define the segment names, the segment loading sequence, assorted macros, and
location assignments.
Version History:
2.01 - Font revision
,
.************************************************************************************************** ,
.286p
seq
-
text segment word public 'code'
text ends
-
data segment word public 'data'
:data ends
const segment word public 'const'
const ends
bss segment word public 'bss'
:bss ends
fill segment word public 'fill'
:fill ends
-
stack segment word stack 'stack'
stack ends
-
atext segment word publ i c 'acode'
:atext ends
.model small,e
dgroup group _text,_data,const, bss,_fill,_atext
assume cs:dgroup,di:dgroup
ok
error
delay
.xl ist
equ
equ
o
-1
macros for Bios generation
macro
Jq)
J ~
enan
$+2
$+2
D12 The Prfx.inc File
write cmos
macro
push
mov
out
delay
out

- push
push
call
add
enan
read cmos macro
- push
call
add
enan
true
false
equ
equ
ax
al,20h
20n,al
OaOh,al
ax
macro address, value
value
address
out cmos
sp,4
address
address
incmos
sp,2
-1
o
;---- stack swappers for interrupt routines ------
int header
- p'ush
Jf11)
enan
macro dest
offset dest
interrupt_shell
( this 8088 version emulates the push
1 nt header 88 macro dest
inmediate opcode
; this is the 8088 version
- Push ax
push bp
mov bp,sp
; this saves ax on the stack
; save bp while we access the stack
; use bp for a pointer
mov ax, offset dest
xchg ax, [bp+21
pop bx
jmp interrupt shell
i ax = dest
restore ax and put the dest on the stack
; restore bp, leaving the dest
enan -
;-------- required by MS C Compiler ---------
; This definition is by the C Compiler.
; The value was determined by looking the standard C libraries.
_acrtused equ 9876h
Bios Equates
ana equ 00
0 equ 040h
equ 041h
equ 042h
pi equ 043h
a equ 060h
equ 061h
plo.J>Ort c equ 062h
equ 063h
segment 00
segment:OO
segment at 0
ends
icomment /* rom bios data area */
segment 40
conm l iit dw 4 dup(?)
lpt_Tist dw 3 duP(?)
org 67h
voffset dw
vsegment dw ?
vflag db
org 078h
lpt timeout list db 4 dup(?)
corrm timeout list db 4 dup(?)
segment_40 inds
segment at 40h
?
?
;--------- macros used to indicate org conflicts
free=O
slop=O
A Type BiosKit
cina chamel 0 addr reg port addr
8255 port a addr
8255 port b addr
8255 port c addr
The Prfx.inc File Dl3
macro arg
ifdef teql
romorg
tetJ1)=$
i f1
if ($ le (arg-OeOOOh)
@out - ,(arg-OeOOOh)-S, bytes free
free=free+arg-$
else
@out - ,S-(arg-OeOOOh), bytes TOO LONG
%out

endif
endif
else

endif
if1
@OUt ,arg, ORIGIN OF &arg
endif
org arg-OeOOOh
endn
@out macro arg1,arg2,arg3
.radix 16
@Qout
@Qout arg1,%(arg2),arg3
.radix 10
endn
macro
%out
endn
arg1,arg2,arg3
arg1 arg2 arg3
i------------------------------------------------------
Rom entry points
Unfortunately, these entry points need to be enforced since many users assl.llle these to be fixed.
Even though lt violates the PC rules, we have to live with it.
_copyright
reset
-nmi
Coot
-conm table
-conm-io
-keybOard io
-keyboaraisr
-disk io -equ
-disk-isr equ
-diskj)arms
:printer io
video io equ
:videojlarms
_mem_slZe equ
equlpment
-cassette io
-video font
-time of day
-timer int
-vector
- dll1lny i ret
:J>rinCscreen
nard reset
-date-st8ll1;)

.list
.data
code
equ OeOOOh
equ OeOSbh
equ Oe2c3h
equ 0e6f2h

Oe729h
equ Oe82eh
equ Oe987h
OecS9h
OefS7h
equ Oefc7h

Oefd2h

OfOa4h
equ Of84dh
equ Of8S9h
equ Ofa6eh
equ Ofe6eh
equ OfeaSh
equ Ofef3h
equ OffS3h
equ OffS4h
equ OfffOh power on start
equ OfffSh date stamp of bios
equ Offfeh hardware 10 byte
Section D: The ASM ProlUams
Things I Should Tell Someone
The Top File D21
TWO
The Top File
The Top.asm File is an assembly language file which is linked so as to reside in the
top portion of the Bios segment. It is the module which responds to the power-on
hardware reset of the system. This module is where the execution of code starts, and
is used to reset critical peripheral functions and start Ram Refresh. A minimum
block of Ram is assigned to allow the use of a stack and then control is transferred
to the POD (Power On Diagnostics) routine. This module also contains the
assembly language support functions used by the Bios. The Bios ID and Copyright
ASCII text information, the CPU type byte, the Bios date-stamp, and the Bios
checksum byte are also in this module .
*************************************************************************************************** ,
; Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
; Module Name: AT Bios top of the'segment assembly module
; Version: 1.02
; Author: FOSCO
;
; Date: 10-18-89
Filename: attop.asm
Language MS MASM 5.1
Functional Description:
This module serves these purposes;
1. It provides the power-on jump at location FFFFO.
2. It starts the Ram refresh.
3. It allocates a stack.
4. It transfers flow to the power-on diagnostic module.
5. It holds assembly language functions
This module is linked as the final module in order for
power-on jump.
Version History:
1.01
it to respond to the hardware reset
In the sense program for test bios' at 0000 or EOOO, changed the lines (2 places) from:
cmp byte ptr ds:[DI+2],SOh
to the following:
byte ds:[2],SOh
because the inclusion of the DI index was lnI8nted. DI mayor may not be = 0000
1.02
Deleted the test for a Bios at Segment EOOO
Added interrupt disable around the insw/outsw for the hard disk
rep in and rep out f'-WICt ions.
Added staCK swap option for function call interrupts to minimize use of
callers stack space (for DOS 4.xx
Updated various modules (see modules for descriptions)
!*************************************************************************************************** ,
include atprfx.inc
extrn biospod:near
extrn boot:near
extrn comm io:near
extrn keybOard io:near
extrn keyboardrisr:near
extrn disk io:near
extrn disk-isr:near
extrn printer io:near
extrn video io:near
extrn mem sTze:near
extrn equTpment:near
extrn cassette_io:near
pod module is a destination
D22 The Top File
extrn
extrn
extrn
extrn
extrn
extrn
extrn
extrn
extrn
time of day:near
timer int:near
print-screen:near
watch:flag:word
syserror:far
restart2:near
restart5:near
restart9:near
restart10:near
;------- public labels --------------
publ ic
publ ic
publ ic
public
publ ic

public
publ ic
public

public
public
public
publ ic
public
public
public
publ ic
ver id
bios id
name-id
owner_id
reset
type byte
date:stanp
conm list
lpt Tist
corriii timeout list
lpt timeout fist
config table
video font
colUlii table
videoj)arms
mode table
hdisK table
_acrtused
public org EOOO
i a correct lTnk may be confirmed by checking this label's location in the file Bios.map
;========== This is Bios Identification ===================
segment
assume cs:dgroup
org_EOOO label byte
i There may be some programs sensitive to what bit pattern resides in this area. If so, this text
; area may be encoded as needed.
bios cOlJ1)8t field label byte
- dO 12 dup(Offh)
db 8ah
db '1BMC'
db 14 dup(Offh)
i========= This is part of the power up sequence =========
remorg reset
reset proc -
reseta
align 16
ver_id label byte
db 'Version 1.02 ',0
bios id label byte
name:id label bYte
db 'Annabooks AT BiosKit ',0
owner id label byte
- db 'Copyright (c) FOSCO 1988,1989 - All Rights Reserved ',0
This ASCII field is intended to show the Copyright and even/odd identification when you are
using 2 Proms to hold the Bios. If you examlne the indiv;c:iual Proms, you wi II see a
clear message, and will be able to discern whether lt is the even or odd prom.
align
db
db
db
align
db
al ign
Programmers Note:
16
'CCooppyyrriigghhtt cc 11998888
ff
11998899'
, FFOOSSCCOO -- AATT--BBIIOOSSKK TT '
,-- AAllll RRiigghhttss RReesseerrvveedd ',00
16
'eovdedn ffiieelldd ',00
16
A-Type BiosKit
The Top File D23
We have noticed some reset problems with some CPU boards. If the power-on voltage does not come
up cleanly and strongly, the 286 may not get a good reset. It seems that this sometimes happens
on loaded systems with marginal power supplies.
The reset. signal to the CPU may not delay long enough before it rises through the threshold
voltage to allow the CPU to start. It also may pass through the indeterminate area (can't decide
whether it is a logic "0" or a logic "1") too slowly and break into oscillation.
Another problem area we have also seen is that the crystal or oscillator may not get started
consistently. If these problems are caused by hardware problems, there is lIttle that the
software can do except try to execute some delay loops until thIngs are stable.
If you experience problems in this area, a scope is handy for checking the sequencing of
the "power 90od" signal from the power supply, the oscillator cirCUits, and the waveform of
the reset SIgnal. After that, an emulator may be required to help to pInpoint the problem.
From a software standpoint, inserting delay loops may be about the only thing you can attempt.
If you encounter, and especially if you solve a problem in this area, sharing your information
would be a generous gesture. .
reseta:
cli
cld
mov
out
al,80h
70h,al
disable interrupts
disable nmi's
.----------- check for bios' patched in ----------
; This patch checking sequence is a powerful development tool. You may link to a "test" Bios at
segment 0000. It allows you to modify and test Bios',
; while still retaining an operating Bios at segment FOOO. For more information, see the Chapter
; on liThe Patch.asm file".
If we find a Bios patch (by checking its signature), then we go to it.
check1:
check2:
mov aX,OdOOOh ; check seg dOOO first
mov ds,ax
cmp word ptr ds:[0],OSb1h
jne check2 ; no bios here, continue
cmp byte ptr ds:[2],SOh
jne check2 ; no bios here, continue
mov ax,cs are we checkIng ourselves?
cmp ax, OdOOOh
je check2 yes, skip it
xor cx,cx set 64k count
xor al,al clear checksum
xor si,si clear index
add
inc
loop
or
jne
db
dw
dw
; do a checksum on the test bios
al ,ds: [5 i]
si
check1
al,al
check2
Oeah
00003h
OdOOOh
jump to bios at dOOO
First, we need to check to see if this was a power-on start or a restart from virtual mode.
If it is a power-up start, then we will go through this startup and then go to BiosPod.
If it is a restart we will go to a particular restart routine.
in al,64h look at the 8742 status port
test al,04h test the power on condition flag
jnz CilF jump if not a power on start
put valid restart code in cmos Ofh
mov
a l ~ 8 f h
prepare to clear cmos cell Of
out 70 ,al select the address
delay
al al xor
out 71h,al mark as val id power-up code
xor aX,ax
mov ds,ax
mov word ptr ds:[472h],0 reset warm boot flag
jlJ1) power_en_start
CilCil: ; determine type of restart
Section D: The ASM Pro&rams
Q)Q):
Q)Q):
Q)Q):
Q)Q):
D 24 The Top File
mov
out
delay
in
or
Jnz


jne
mov
out
delay
xor
out


jne
mov
out
delay
xor
out


jne
mov
out
delay
xor
out
jlJ1)

jne
mov
out
delay
xor
out

al/8th
70n,al
al,71h
al,al
prepare to read cmos cell Of
select the address
get the cmos contents
GlF
power_on_start
al,02
GlF
al/8th
70n,al
al,al
71h,al
restart2
al,OS
GlF
al/8th
70n,al
al al

restartS
al,09
GlF
al/8fh
70n,al
al al
71tal
restart9
al,10
iF
al,8th
70h,al
al al

restart10
reset the restart code to itO"
memory test return
reset the restart code to "0"
dword with interrupt
reset the restart code to "0"
block move return
reset the restart code to .. a ..
dword without interrupt
; unsupported restart code
i-- save the restart code in case we want to display an invalid code
power_on_start:
;- .......... start the refresh timer ............. -
mov
out
mov
out
mov
out
al,74h
pit-POrt_cmnd,al
al, f8
pit-port_' ,al
al,o-
pit.J)Ort_1,al
; start the ram refresh timer
save the wanm boot flag while we clear the lower 64k
xor ax,ax
mov es,ax
mov bp,es:[472h]
make sure all repeats are in forward direction
cld
cycle the ram memory to pre-charge the rams
xor ax, ax
mov di ,0
mov cx,32768
rep stosw
mov ax -1
mov di :0
mov cx,32768
rep stosw
A-Type BiosKit
store zeroes
store ones
xor ax,ax
rnov di,O
rnov cx,32768
rep stosw
rnov ax -1
rnov di ;0
rnov cx,32768
rep stosw
do a quick ram test on the lower 64k
copy the bios to low ram
rnov si,OOOOh
rnov di,OOOOh
store zeroes
store ones
rnov cx, 32768
rep movs word ptr es:[di],word ptr cs:[si]
comp bios to low ram
rnov si,OOOOh
rnov di,OOOOh
rnov cx, 32768
The Top File D 25
repz c.
rnov sp,cx
word ptr es: [di],word ptr es:[si]
; save cx - cx = 0 = ok, else ram compare error
now do a ram clear on 64k - then proceed
xor ax,ax
mov cx, 32768
xor di ,di
rep stosw
mov es:[472h],bp ; restore the warm boot flag in its place
mov es:[415h],sp; save the low ram test indicator
;-- now we can use 'e' because we can have a stack IIII
;--- set up the local stack - now we can use real calls
xor ax,ax
cli
mov ss,ax
mov sp,ax ; top of the sys_seg
;/* from here on we can use
'e'
because we have a stack */
;- .
- - - - - - - - - - - - -
push cs
P.OP
ds ; 'e' wants ds = cs
~
biospod
reset
;=-=-=-:-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
; The NMI routine may be expanded as desired. It resets the parity toggles and returns to
; the interrupted program.
romorg
label
push
xor
out
in
or
out
and
out
P.OP
Het
nmi
6yte
ax
al al
Oa6h
1
al
al,61h
al,30h
61h al
al/bcfh
61n,al
ax
disable nmi interrupts
reset the nmi toggles
This is where the hard disk table can reside. There is room for 60-70 entries as needed. You
may modify these entries to support the disk types you desire.
hd tbl struc struc
hdTive-cyls dw ?
hdrive-heads db ?
- dw 0
hdrive-precomp dw ?
db 0
hdrive contrl db ?
- db 0
db 0
Section D: The ASM ProlUams
D26 The Top File
db
hdrive lndng dw ?
hdrive-sectors db ?
- db
hd_tbl_struc ends
drive type macro a1,a2,83 a4 a5,86,a7
- hd tbl struc
era.. -
al ign 16
hdisk_table label byte
drive type 1, 306, 4,128,0, 305,17
drive-type 2, 615, 4,300,0, 615,17
drive-type 3, 615, 6,300,0, 615,17
drive-type 4, 940, 8,512,0, 940,17
drive-type 5, 940, 6,512,0, 940,17
drive-type 6, 615, 4, -1,0, 615,17
drive-type 7, 462, 8,256,0, 511,17
dr!ve:type 8, 733, 5, -1,0, 733,17
drlve type 9
L
900,15, -1,8, 901,17
dr!ve:type 1u,820, 3, -1,0, 820,17
dr!ve_type 11,855, 5, -1,0, 855,17
drlve type 12,855, 7, -1,0, 855,17
drive-type 13,306,8,128,0,319,17
drive-type 14,733, 7, -1,0, 733,17
drive-type 15, 0, 0, 0,0, 0,
drive-type 16,612, 4, 0,0, 663,17
drive-type 17,977, 5,300,0, 977,17
drive-type 18,977, 7, -1,0, 977,17
drive-type
drive-type 20,733, 5,300,0, 732,17
drive-type 21,733, 7,300,0, 733,17
drive-type 22,733, 5,300,0, 733,17
drive-type 23,306, 4, 0,0, 336,17
dr!ve:type 24,612, 4,305,0, 663,17
drlve type 25,306, 4, -1,0, 340,17
drive-type 26,612, 4, -1,0, 670,17
drive-type 27,698, 7,300,0, 732,17
drive-type 28,976, 5,488,0, 977,17
drive-type 29,306, 4, 0,0, 340,17
drive-type 30,611, 4,306,0, 663,17
dr!ve:type 31,732 7,300,0, 732,17
dr!ve_type -1,0,1023,17
drlve_type 33,306, 2, -1,0, 305,17
The SysVue "TYPES" Conmand looks for this following
entry to sense the end of the hard drive parameter table.
drive_type -1,-1,-1,-1,-1,-1,-1 ; end of table
; this function is used to reset the parity logic
enables proc uses ax
in- al,61h ; reset the nmi toggles
or aL
l
30h
out 61n aL
and al
l
6cfh
out 61n,aL
ret
endp
romorg

boot
Soot
; This is the table referenced by the Int 15, Function CO
; get system configuration parameters caLL.
config tabLe LabeL
- dw
db
db
db
db
db

Ofch
01h

70h
4 dup(O);
Length of tabLe in bytes
model byte
sub modeL byte
bios leveL
; DNA 3,cascede 8259, rtc clock
spares
romorg comm tabLe
comn table label byte -
'- dw 1047,768,384,192,96,48,24,12
romorg

romorg
comm io
comm_To
_keyboard_fo
A-Type BiosKit
jmp keyboard_io
romorg keyboard isr
jmp Keyboard_Tsr
romorg disk io
int_header- - disk_io
romorg
jmp
disk isr
aisk_Tsr
The Top File D 2 7
disk uses own stack
This is the default disk parameter table. The Biosdisk.c Module actually uses its own set
of enhanced parameters to support the additional drive types available.
romorg _disk-P8nms
fdisk table label byte
- db Odfh,2,2Sh,2,Ofh,1bh,Offh,54h,Of6h,Ofh,8
romorg
jmp

prlnter_l0
video uses own stack
romorg
label
db
db
db
db

byte
38h,40,2dh,10,1fh,6,19h,1ch,2,7,6,7,0,0,0,0
71h,80,Sah,10,1fh,6,19h,1ch,2,7,6,7,0,0,0,0

, ,0,0
The length tabel is not used by biosert.c
we include it in case some user thinks it exists.
length table label byte
- dw 2048,4096,16384,16384
coll.l1n table label byte
- db 40,40,80,80,40,40,80,80
mode table label byte
- db 2ch,28h,2dh,29h,2ah,2eh,1eh,29h
;==== this large area is used for the asm routines ======
; This is used by the hard disk driver for data-in xfers
proc
mov
mov
mov
mov
pushf
cl i
cld
rep
popf
ret
endp
uses es di cx dx,tseg:word,toff:word,port:word,count:word
dx,port
es,tseg
di,toff
cx,count
save flags while disabling
insw
; This is used by the hard disk driver for data-out xfers
rep_out proc
mov
mov
mov
mov
pushf
cli
cld
rep
popf
ret
uses ds S1 ex dx,tseg:word,toff:word,port:word,count:word
dx,port
ds,tseg
si,toff
cx,count
save flags while disabling
outsw
rep_out endp
; --------- this is the ram test called by 'e' ------
; This test is used in real-mode only.
;unsigned int ram_test(unsigned base,unsigned length)
returns ok = 1
returns error = 0
Section D: The ASM Pro&rams
D-2-8 The Top File
ram_test proc uses
mov
mov
push
~
mov
xor
rep
mov
xor
mov
repe
jcxz
mov
jo., short
ram test10:
- mov
ram test20:
- xor
mov
xor
rep
mov
ret
ram_test endp
; write and read bios pattern into 64k
cx ds si es di,test_base:word,test_length:word
cx,test lengtn
es, testE>ase
cs -
ds
si ,OOOOh
di ,di
movsw
si,OOOOh
di ,di
cx,test_length
cn.,sw
ram test10
si ,error
ram_test20
si ,ok
di ,di
cx,test length
ax,ax -
stosw
ax,si
set di = 0
set di = 0
set di = 0
clear the block
return the condition in ax
; This routine is used to re-locate the Bios-system-segment from the top of the 1st 64k segment
; (at power-on time) to the top of the System Ram at run-time.
move system segment proc uses ax cx dx ds si es di c to seg:word,seg size:word
- cTi ; disable lnterrupts because
( of moving the stack
moves, to_seg ; destinatlon segment
mov cx, seg size ; ca l c the base segment address
shr cx,4-
mov aX,1000h
sub ax,cx
mov ds,ax
mov cx,seg size ; move I'YVY1 bytes
xor si,si -
xor di,di set di = 0
rep movs byte ptr es:[di],byte ptr ds:[si]
mov
mov
and
mov
mov
mov
xor
mov
xor
rep
mov
mov
mov
sti
ret
ax,es
dx,ax
aX,OfOOOh
ss,ax
ax,ds
es,ax
di ,di
cx,seg_size
ax,ax
stosb
ax,40h
ds,ax
ds: [Oeh] , dx
move_system_segment endp
; reset the stack segment
; save dest segment for 40:e
stack is top of 641c segment
now clear the old segment
set di = 0
clear the old block
set new sys seg ptr
; re-enable interrupts
;------- this is the rom scan checksum called by 'e' -----
; unsigned int checlcsum(unsigned segment,unsigned length)
checksum proc uses bx cx ds,segptr:word,length arg:word
mov ds,segptr ; get Sase address
mov cx,length_arg ; get count
xor ax,ax
xor bx,bx
QlGl: add al ,ds: [bx]
inc bx point to next byte
loop Q8
ret
checksum endp
A-Type BiosKit
;-- this is the far call routine called by 'C' rom scan ---
i void far _call (l.I'\signed int segment,lW'Isigned int address)
far call proc segptr:word,addr:word
LOCXL offset:word
-...... j5ushf _ ...... -
push a
push ds
push es
push segptr get segment
pop teRJ) segment
push addr- get offset
pop temp offset
call dwora ptr [temp_offset]
pop es
pop ds
=
ret
far_call endp
;-- this jump to boot passes the drive' in dl --
i boot_jump(seg,off,drive);
boot jump proc segptr:word, addr:word,drive: word
locaT temp_segment:word,temp_offset:word
push
=h
pop
mov
jfl1)
boot_jump endp
segptr get segment
teRJ) segment
addr - i get offset
temp offset
dx,drive
dwOrd ptr [temp_offset]
i------------ beep routine ----------------
i void beep(void);
beep proc uses ax bx cx dx
mov bx,128
mov dx,pio-POrt b
in al,dx -
mov ah,al
and al,Ofch
out dx,al
mov cx,64
loop alB
or al,2
out dx,al
mov cx,64
beep 1 0:
GlGl:
@Gl:
128 cycles last about 1/12 sec.
save the 8255 port byte
turn the beeper off
make the duty cycle 50X
i turn the beeper on
leave it on = to the off time
The Top File D-2-9
loop Q8
dec bx
jnz
mov al,ah
out dx,al
; COU"lt the major cycles down
get the original port byte
restore the 8255 to previous
ret
beep encIp
i----------_---------------------------_--------
seg_40_constant dw 40h
i void setds_system_segment(void)i
setds system segment proc
- mov dS,cs:seg 40 constant
mov ds, ds: [Oen] -
ret
setds_system_segment endp
i-- this is used to set the DS to a specified value --
i void setds(unsigned ptr);
setds proc seg-ptr:word
push seg-ptr
pop ds
ret
setds endp
i-- get the current stack segment value --
i unsigned get_ss(void)i
Section D: The ASM Pro&rams
D210 The Top File
proc
mov
ret
encfp
ax,ss
;-- test the specified watch flag bits
; return true if set, false if not
; unsigned watch(unsigned)i
watch proc uses ds,bits:word
call setds system segment
mov ax, bits -
test ds:watch flag,ax
mov ax, false-
jz iF
mov ax, true
iilGI: ret
watch encfp
;-- this can be used to force a break while debugging --
trap proc ; this can be used for hard breakpointing
int 18h ; goes to SysYue
ret
trap endp
; check to see if any key at console device --
i returns true if a key waltlng ,
kbhit proc
mov
int
mov
jz
mov
; returns true if any key hit
ret
aX,0100h
16h
ax, false
iF
ax, true
kbhi t encfp
;=========== Console In Routine ===============
ci
ci
char ci (void);
proc
mov
int
ret
endp
;*========- block checksum routine ==============*/
; unsigned checksum bios block(void)
extrn bios_start:near
checksum bios block proc uses bx ds,seg addr:word,off addr:word
- pusn cs - -
pop ds ; set ds = cs to el iminate need for CS: overide
xor ax,ax ; clear accumulator
mov bx,offset bios start
iilGI: add al,[bx] -
inc bx exit at end of segment
jnz CilB
ret
checksum_bios_block endp
i*=========== Console OUt Routine =============*/
; console out routine
; co(char);
co proc uses ax bx1char:byte
mov ah,Oen
mov al,char
mov bx,O
int 10h
ret
co endp
;--- calc the hdisk size - this uses some long unsigneds
unsigned
returns a va l ue 1 n ax 1 n megabytes
By doing this in ASH, the C Lib ft.n:tion is not needed.
proc uses dx'si,cyls:word,heads:word,sectors:word
A Type BiosKit
xor
mov
mov
nul
mov
nul
mov
div
ret
calcJ,disk_size
dx,dx
ax,cyls
si ,heads
si
si,sec:tors
si
si,2000
si
endp
i---.-.-----------------------------------------
; this is used by the timer interrupt to chain to a user
timer chain
- push
P.OP
1nt
ret
timer_chain
proc uses ds
40h
ds
1ch
endp
; this chains the hard -> floppy disk without extra
; stack usage
fdisk chain
- mov
pop
pop
pope
1nt
retf 2
fdisk_chain
proc
sp,bp
es
ds
40h
endp
discard the callers return address
The Top File D211
long integer as an unsigned in ax
; unsigned hi_regs(unsigned long)
proc low arg:word,high arg:word
mov aX,nigh_arg -
ret
hi_regs endp
;--------long multiply for setting tod clock
; unsigned long lnul(unsigned long,unsigned)
lnul proc
mov
mov
mov
nul
ret
enctp
uses bx,ax_arg:word,dx_arg:word,bx_arg:word
dx,dx_arg
convert binary
- mov
mov
shr
and
aad
xor
ret
convert_binary
ax,ax arg
bX,bx-arg
bx -
proc
ax,arg
ah,al
ah,4
al,Ofh
ah,ah
endp
arg:word
; void bin2dec:(value,return array[S]);
; the output array is in os:
ax di si dx,value:word,array-ptr:word
di,array..p.tr
bin2dec proc uses
mov
mov
mov
mov
mov
mov
mov
byte ptr as: [di+O],' ,
byte ptr ds:[di+1],' ,
byte ptr ds:[di+2],'
byte ptr ds:[di+3],'
byte ptr ds:[di+4),'0'
byte ptr ds:[di+S),O string tenminator char
add di ,4
mov si,10
mov ax, value
iilQ): mov
div Sl
add
mov ds: [d1] ,dl
dec di
or aX,ax
Section D: The ASM Pro&rams
D212 The Top File
jnz
ret
bin2dec endp
i-----------------------.-.-------------------
; unsigned dec2bin(unsigned decval):
; the arg is max of 9999 decimal - ok for up to 8192k of extended memory
; the binary value is returned in ax
dec2bin proc uses dx di cx,decval:word
mov dx,O ; clear accumulator
@Q):
mov ax,O
mov di,10
mov cx,4
I1IJl di
rol decval,4
mov bx, decva l
and bx,OOOfh
add ax,bx
loop iil8
ret
dec2bin endp
load I1IJltiplier
i load loop count
; I1IJl by ten
get next digit
load to bx
save only wanted digit
add to accumulated nuJi)er
; do for all four digits
;------ move string routine for alpha mode crt scrolling
; void move_row(unsigned segment,unsigned from_offset,unsigned to_offset, unsigned count)
move_row proc uses
mov
mov
mov
mov
mov
cld
jcxz
rep
@Q): ret
move_row endp
cx si di es ds,segptr:word,from:word,to:word,count
ds,segptr ; segment
es,segptr
si,from
di, to
cx,count
GilF
movsw
from
to
count
;------ clear row routine for alpha mode crt scrolling
i void clear_row(unsigned segment, unsigned address,unsigned count, unsigned fill)
clear_row proc uses ax cx di es,segptr:word,addr:word,count:word,filler:word
!nOv es, segpt r ; segment .
!nOv d i , addr ; address
!nOv cx , count ; CO\.l\t
mov ax,filler ; fill
cld
jcxz QF
rep stosw
QGl: ret
clear_rowendp
;-- move string routine for graphics mode crt scrolling
move graph i cs row proc uses cx dx s i
- mov- dx,O
move_graphics_r0w5:
mov
GlG1:
@Q):
mov
mov
mov
mov
cld
add
add
jcxz
rep
mov
mov
add
add
mov
cld
add
add
jcxz
rep
add
i ~
ds,segptr
es,segptr
si,from
di,to
cx,count
si,dx
di ,dx
QF
movsw
s i , [ ~ ]
di, [bI)+8]
si,2000h
di ,2000h
cx, [bp+10]
si,dx
di ,dx
QF
A-Type BiosKit
from_offset, to_offset, count)
di es ds,segptr:word, from:wordf. to:word,count:word
: use dX to move Tour lines each
segment
from
to
count
from
to
add for odd row
add for odd row
count
ret
move_graphics_row endp
;------ clear row routine for alpha mode crt scrolling
; void clear_graphics_row(segment, address, count, fill)
The Top File D-2-13
clear graphics row proc uses ax ex dx di
- mov - dx,O
es,segptr:word,addr:word,count:word,filler:word
; use dx to clear four lines each
clear_graphics_rowS:
mov es,segptr
Q)Q):
mov di,addr
mov cx,count
mov ax,filler
cld
add
jcxz
di ,dx
CilF
segment
address
count
fill
address
rep
mov
add
mov
mov
add
cld
stosw
di, [bp+61
di ,2000h
cx, [ ~ 8 1
ax, [bp+101
di ,dx
add for odd row
cOU"St
fill
jcxz iF
rep stosw
add dx,80
c"1l dx, 320
jb clear_graphics_rowS
ret
clear_graphics_row endp
; ---- low level routines for 'e' ---------
.========================================================
; this version assumes the regs are in the system segment. note that it also requires a
; slightly different regs structure than int86 or int86x because it always passes es and ds.
axoff equ 4
cxoff equ 6
dxoff equ 8
sioff equ 10
dioff equ 12
bpoff equ 14
bxoff equ 16
dsoff 18
esoff equequ 20
floff equ 22
Jmp_off equ 24
J mp seg equ 26
coCe_string_location equ 28
; void sys_int(char number, reg_block);
code string proc far
- lds bX,cs:[bx+bxoff]
int 0
number offset = $-code string-1
- ret -
code string length = $-code string
code:string- endp-
sys_int proc uses si di ax bx cx dx es ds, number:word,regs_block:word
mov bx,regs_block
move the code string image
; get cOU"St of bytes to move
mov cx,code string length
; point-to org-of code string
mov si offset code string -
; ~ i l d ptr to-destination
mov di ,bx
add di,offset code string location
; set segment Tor destination
push ds
pop es
; now do the copy
rep movs byte ptr es:[dil, byte ptr cs:[sil
; load the correct interrupt number
mov ax, number
mov [bx+code_string_location+number_offsetl,al
Section D: The ASM Pro&rams
D214 The Top File
mov
add
mov
; load the j ~ vector
word ptr [bx+jmp off],code string location
[bx+Jmp off],bx - --
mov
mov
mov
mov
mov
mov
[bx+ JII1(seg] ,ds
; load the registers
ax, [bx+axoff]
cx, [bx+cxof f]
dx, [bx+dxoff]
si,[bx+sioff]
di, [bx+dioff]
es, [bx+esoff]
push
mov
push
push
call
~ s a v e the real bp for the implied LEAVE instruction
bP, [bx+bpoff]
ds
bx
dword ptr ds:[bx+jmp_off]
now we have to swap out ds:bx with the stack-saved ones
push
push
push
mov
lds
bx save returned ds:bx
ds
bp save bp - will be used as ptr
bP,sp
bx, [bp+6] re-load myblock ds:bx
pop
pop
pop
ds:[bx+bpoff] ; restore returned bp
ds: [bx+dsoff]
ds: [bx+bxoffl
pop
pop
:;
; discard old ds:bx slots
i without affecting flags
pop
mov
mov
mov
mov
mov
mov
pushf
pop
ret
sys_int endp
~ bp is now pre-interrupt value
; store the registers
[bx+esoff] , es
[bx+axoff],ax
[bx+cxoff],cx
[bx+dxoff],dx
[bx+s i off] , s i
[bx+di off] ,di
; save flags
[bx+floff]
; SysErr routine ~ t s an error code in ax, then goes to sysvue -- This is an expansion feature
; you may wish to implement.
sys_err proc
mov
pushf
call
ret
sys_err endp
uses ax,error_code:word
ax, error_code
syserror
;---------------------------------------------------
get vector returns the selected vector in OX:AX.
This routine is done in assenClr language because a 'e'
routine would need the library eng shift function to
build the seg:off into DX:AX.
unsigned long get_vector(char number);
get vector proc uses bx es,number:word
- xor bx,bx
mov es,bx
mov bx,number
xor bh,bh
shl bx,1
shl bx,1
cl i
mov dX,es:[bx]+2
mov aX,es:[bx]
sti
ret
get_vector endp
getds proc
A Type BiosKit
int #I
rul by 4
getds
mov
ret
endp
The Top File D 215
ax,ds
return the bios code segment value in AX.
This function is coded this way so the Bios may be operated at segments other than FOOO.
unsigned bios_cs(void);
bios_cs proc
mov
ret
bios_cs endp
ax,cs
Disable interrupts
void disable(void);
disable proc
cU
ret
disable endp
Enable interrupts
void enable(void);
enable proc
sti
ret
enable endp
void delay(unsigned res,unsigned count);
res == 0 - delay in useconcfs
res 1= 0 - use as milliseconds resolution
count = count
delay_call proc uses ax cx dx ds,res:word,count:word
cmp res 0
jnz mil[i_delay
micro delay:
- mov
iiIi:
xor
mov
div
add
mov
in
and
cmp
je
mov
loop
ret
milli delay:
- mov
milli major:
- push
mov
iiIi: call
loop
~
ret
delay_call
read timer ccx.nt
- xor
out
Jmp
iiIi: Jmp
iiIi: ~ m p
iiIi: 1n
mov
Jmp
iiIi: ~ m p
iiIi: Jmp
GlQl: 1n
xchg
ax, count
dX,dx
cx,15
cx
ax,2
cx,ax
al,61h
al,10h
ah,al
Q8
ah,al
Q)8
CX,COU'lt
cx
micro seconds delay
this has 15 usec resolution
each toggle of the refresh bit is 15 usecs
now cx = count/15
make sure we have at least 15-30 usecs min.
cx will be a loop count
get port b refresh bit
save only the bit we want
now use current state
wait n times
th1
'S' ; ~ e s argument = # of millis resolution
1S major loop
cx res
delay a milli
Q)8 --
this is minor loop
wait for resolution counts
cx
mill i_major
endp
proc
al,al
43h,al
GlF
QF
QF
al,40h
ah,el
CilF
GlF
CilF
al,40h
ah,al
repeat major loop for total counts
each COU'lt = .8 usecs
latch timer 0 count into storage register
: delay for 8253 response
delay for 8253 response
Section D: The ASM Proauams
D216 The Top File
ret
read_timer_count endp
; return count in ax
; Note: Remember that the counters in the 8253/8254 are down counters,
; so that we have to subtract the desi red count from the current count.
delay a mi II i
- - call
call
mov
sub

mov
not
@GI: call
cq)
jae
ret
delay_a_milli
proc uses cx
read timer count
reaa-timer-count
cx,ax -
cx,1250
cx,ax
GlF
cx,ax
cx
read timer count
ax,cx -
Gl8
endp
delay 1 milli second
do a double read
since count rate is 1.19 Mhz, about
1250 timer counts = 1 millisecond
delay count> current count, no rollover
use delay based from zero if rollover
delay until current count >= calced count
get offset
- pop
push
ret
get_offset
proc
ax
ax
this function is used to retrun the callers offset
it pops the callers address into ax
puts it back so it can be used for the ret instruct i on
endp
;--- These are additional peek and poke functions
; unsigned peek40(unsigned offset);
peek40 proc uses bx eS,offptr:word
mov bx,40h
mov es,bx
mov bx,offptr
mov aX,es:[bx]
ret
peek40 endp
; char peekb40(unsigned offset);
peekb40 proc uses bx esfoffptr:word
mov bX,ltOh
mov es,bx
mov bx,offptr
mov al,es:[bx]
xor ah,ah
ret
peekb40 endp
; char peekbcs(unsigned offset);
peekbcs proc uses
mov Dx,offptr
mov al,cs:[bx]
xor ah,ah
ret
peekbcs endp
; unsigned peekcs(unsigned offset);
peekcs proc uses bx,offptr:word
mov bx,offptr
mov ax,cs:[bx]
ret
peekcs endp
peeks in segment 40h
; void pokeb40(unsigned offset, char value);
pokeb40 proc uses ax bx eS,offptr:word,value:word
mov bX,40h
mov es,bx
moV bx,offptr
mov ax, value
mov es:[bx],al
ret
pokeb40 endp
; void poke40(unsigned offset, unsigned value);
poke40 proc uses ax bx esloffptr:word,value:word
mov bx,40n
mov es,bx
mov bX,offptr
mov ax, value
A-Type BiosKit
mov
ret
poke40 endp
es:[bx],ax
; void andb40(unsigned offset, char value);
andb40 proc uses
mov
mov
mov
mov
and
ret
ax bxes,offptr:word,value:word
bX,40h
es,bx
bx,offptr
ax, value
es:[bx],al
andb40 endp
; void and40(unsigned offset, unsigned value);
and40
and40
proc
mov
mov
mov
mov
and
ret
endp
uses ax bx es,offptr:word,value;word
bX,40h
es,bx
bx,offptr
ax, value
es:[bx],ax
; void orb40(unsigned offset, char value);
orb40
orb40
proc
mov
mov
mov
mov
or
ret
endp
uses ax bx es,offptr:word,value:word
bX,40h
es,bx
bx,offptr
ax, value
es:[bx],al
; void xorb40(unsigned offset, char value);
xorb40 proc uses ax bx es,offptr:word,value:word
mov bx,40n
mov es,bx
mov bx,offptr
mov ax, value
xor es:[bx],al
ret
xorb40 endp
;--- These are the standard peeks, pokes, ins, and outs
; unsigned peek(unsigned segment, unsigned offset)
peek proc uses bx es,segptr:word,offptr:word
mov es,segptr
mov bX,offptr
mov aX,es:[bx]
ret
peek endp
; void poke(segment, offset, value);
poke proc uses ax bx es,segptr:word,offptr:word,value:word
mov es,segptr
mov bx,offptr
mov ax, value
mov es:[bx],ax
ret
poke endp
; char peekb(unsigned segment,unsigned offset);
peekb proc uses bx es,segptr:word,offptr:word
mov es,segptr
mov bx,offptr
mov al ,es: [bx]
xor ah,ah
ret
peekb endp
; void pokeb(unsigned segment, unsigned offset, char value);
pokeb proc uses ax bx es,segptr:word,offptr:word,value:word
mov es, segpt r
mov bx,offptr
mov ax, value
mov es:[bx],al
The Top File D217
Section D: The ASM Pro&rams
D218 The Top File
ret
pokeb endp
; unsigned inport(unsigned port);
inport proc uses dx,port:word
mov dx,port
in ax,dx
ret
inport endp
; void outport(unsigned port, unsigned value);
outport proc uses dx ax,port:word,value:word
mov dx,port
mov ax, value
out dx,ax
ret
outport endp
; char inportb(unsigned port);
inportb proc uses dx,port:word
mov dx,port
in al,dx
xor ah,ah
ret
inportb endp
; void outportb(unsigned port, char value);
outportb proc uses ax dx,port:word,value:word
mov dx,port
mov ax, value
out dx,al
ret
outportb endp
cstods
cstods
proc
push
pop
ret
endp
SdLIIIIIY i sr proc
- send eoi
iret-
Sdllll11Y _ i sr endp
Siret proc
lret
Siret endp
; set ds = to cs
cs
ds
Stack swapper for interrupt routines - (see int_header macro) ---
Typically code written in C may use more stack space then
tweaked assembly language code. Intennediate varlables created
br using "for" and "while" loops mar be assigned to the stack.
A so the use of the "Interrupt" dec aration for Interrupt
service routines causes all the registers to be pushed on the
stack. Normally this does not cause problems, beCause user or
appl ication declared stacks are usually large encxJh to be safe.
However, there are some instances where a program 1 gnores the user
declared stack (PC-DOS 3.xx VDISK) or system software (PC/MS 4.xx
IO.SYS) sets a very tight stack, which will run with most (but not all)
BIOS' written in assembr.' (The more curious among us may have
already discovered the rase "may run on some PC and XT machines",
in the DOS 4.xx manuals
Starting with DOS 3.xx, the IIstacks=n,yt' conmand has been included
for CONFIG.SYS use to set up a stack ~ l for swapping stacks on
the hardware (caused through the 8259 interrupt controller(s interrupts.
This alleviated some stack overflow problems encountered when
running true IBM PC-DOS on true IBM hardware. So it wasn't an error
committed either by the 3rd party clone or BIOS creators. It simply
was a result of the programmlng style used in writing the DOS.
Microsoft is currently the most prominent "bender" of the rules
(previously IBM possessed the leverage) and we (as well as Intel)
are forced to conform. The code below implements a stack swapping
mechanism for use by Function Call Interrupts by creating a stack
in the system segment ram area for the des ired funct i on ca Lt.
The swap occurs before the Interrupt Service Routine is called,
allowing all the user registers to be pushed onto the new staCK.
This limits user stack usage and seems to solve the problems.
A-Type BiosKit
The Top File D219
Example of usage:
A non-swapped interrupt -
Vector ---------> cdecl far interrupt sample(interrupt_registers)
<-----------.
A swapped interrupt -
Vector ---------> push dest
jmp interrupt_shell
(swap to system stack)
----> cdecl far interrupt sample(interrupt_registers)
.
. <----------.
(restore to callers stack)
<-----------.
The code below is entered with destination address on the stack
push dest
jmp interrupt_shell
extrn bx save:word,ds save:word,dest save:word
extrn ss:save:word,sp:save:word,length mark:word
extrn current_open: word, end_block:wordr
size_requested equ 256 default standard size
interrupt_shell proc
push
push
mov
mov
mov
pop
pop
pop
mov
pushf
add
j ~
popf
rJ
Sh
ds
ret
QlQ:
mov
add
popf
mov
mov
mov
mov
mov
mov
pushf
push
push
rJ:h
ret
continue:
push
push
mov
mov
mov
pop
pop
pushf
sub
popf
ds
bx
entered with interrupts disabled as a
result of the previous Int xx opcode.
bx,O
ds,bx
ds,ds: [040ehl
bx save
ds-save
deit save
bx, cur rent _open
bx,size requested
bx,end Slock
ilF -
dest save
get system segment
sys:xx
; sys:xx+2
sys:xx+4
; save callers flag state
check for space available
j ~ if enough space
use current stack, jump to isr service
bx,dWord ptr ds:[bx_savel restore ds:bxto callers values
bx,current oper:\
current_open,size_requested
get base address of block
mark the block "in use"
ds:[bx+length markl,size requested
ds:[bx+ss savil,ss ; save the caller stack pointers
ds:[bx+sp:savel,sp in the allocated stack block
sp,ds
ss,sp
sp,dS: [current_open] set sp at top of new block
cs
offset continue ; set up ~ o n y interrupt call
dest save ; set destination address
bx,dWord ptr ds:[bx_savel ; restore ds:bx to callers values
go to dest with phnoy call
bx
ds
bx,O
ds,bx
ds,ds: [40ehl
ds save
bx:save
ds:[current_openl,size_requested
Section D: The ASM ProlD"ams
D220 The Top File
mov bx,current open
mov ss,ds:[bx+ss save] ; get the callers stack description
mov sp,ds:[bx+sp-save]
mov ds:[bx+length mark],O mark the block as free
lds bx,dword ptr as: [bx_save]
retf
interrupt_shell
2
endp
return with cuurent flags
;============== end of the asm routines ===================
romorg
jnp
romorg
jnp
mem size
iiie"Lsize
equipment
iquipment
romorg cassette io
int_header- -cassette_io
romorg vi deo font
cassette uses own stack
video font label byte -
; - These are the bit-mapped characters for the graphics mode. They must be here
; because some user software uses these for generating characters in graphics mode.
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
db
OOOh,OOOh,OOOh,OOOh,OOOh,OOOh,OOOh,OOOh
07eh,081h,Oash,081h,Obdh,099h,081h,07eh
07eh,Offh,Odbh,Offh,Oc3h,Oe7h,Offh,07eh
06ch,Ofeh,Ofeh,Ofeh,07ch,038h,010h,OOOh
010h,038h,07ch,Ofeh,07ch,038h,010h,OOOh
038h,07ch,03Bh,Ofeh,Ofeh,07ch,038h,07ch
010h,010h,03Bh,07ch,Ofeh,07ch,038h,07ch
000h,000h,01Bh,03ch,03ch,01Bh,OOOh,000h
Offh,Offh,Oe7h,Oc3h,0c3h,Oe7h,Offh,Offh
000h,03ch,066h,042h,042h,066h,03ch,000h
Offh,Oc3h,099h,Obdh,Obdh,099h,Oc3h,Offh
OOfh,007h,00fh,07dh,Occh,Occh,Occh,078h
03ch,066h 066h 066h 03ch 01Bh 07eh 01Bh
03fh,033h:03fh:030h:030h:070h:OfOh:OeOh
07fh,063h,07fh,063h,06eh,067h,0e6h,OcOh
099h,05ah,03ch,Oe7h,Oe7h,03ch,05ah,099h
080h,OeOh,OfBh,Ofeh,OfBh,OeOh,08Oh,OOOh
002h,00eh,03eh,Ofeh,03eh,OOeh,002h,OOOh
018h,03ch,07eh,018h,018h,07eh,03ch,01Bh
066h,066h,066h,066h,066h,000h,066h,OOOh
07fh,Odbh,Odbh,07bh,01bh,01bh,01bh,OOOh
03eh,063h,038h,06ch,06ch,038h,Occh,078h
000h,000h,000h,000h,07eh,07eh,07eh,000h
018h,03ch,07eh,018h,07eh,03ch,01Bh,Offh
01Bh,03ch,07eh,01Bh,01Bh,01Bh,01Bh,000h
01Bh,01Bh,01Bh,01Bh,07eh,03ch,01Bh,000h
000h,01Bh,00ch,Ofeh,00ch,01Bh,000h,OOOh
000h,030h,06Oh,Ofeh,06Oh,030h,000h,000h
OOOh,OOOh,OcOh,OcOh,OcOh,Ofeh,OOOh,OOOh
000h,024h,066h,Offh,066h,024h,000h,000h
000h,01Bh,03ch,07eh,Offh,Offh,000h,OOOh
OOOh,Offh Offh 07eh 03ch 01Bh OOOh OOOh
OOOh,OOOh:OOOh:OOOh:OOOh:OOOh:OOOh:OOOh
030h,078h,078h,030h,030h,OOOh,030h,OOOh
06ch,06ch,06ch,OOOh,OOOh,OOOh,OOOh,OOOh
06ch,06ch,Ofeh,06ch,Ofeh,06ch,06ch,000h
030h,07ch,OcOh,078h,00ch,OfBh,030h,000h
000h,Oc6h,Occh,01Bh,030h,066h,Oc6h,000h
038h,06ch,038h,076h,Odch,Occh,076h,000h
O6Oh,06Oh,OcOh,OOOh,OOOh,OOOh,OOOh,OOOh
018h,030h,06Oh,06Oh,06Oh,030h,01Bh,000h
O6Oh,030h,01Bh,01Bh,018h,030h,06Oh,000h
000h,066h,03ch,Offh,03ch,066h,000h,000h
OOOh, 030h, 030h,Ofch, 030h ,030h ,000h,000h
000h,000h,00Oh,000h,000h,030h,030h,060h
OOOh,OOOh,OOOh,Ofch,OOOh,OOOh,OOOh,OOOh
000h,000h,OOOh,000h,OOOh,030h,030h,000h
006h,00ch,01Bh, 030h, O6Oh , OcOh ,000h,000h
07ch,Oc6h,Oceh,0deh,Of6h,0e6h,07ch,000h
030h,070h,030h,030h,030h,030h,Ofch,000h
078h,Occh,00ch,038h,06Oh,Occh,Ofch,000h
07Bh,Occh,00ch,038h,00ch,Occh,078h,000h
01ch,03ch,06ch,Occh,Ofeh,00ch,01eh,000h
Ofch,OcOh,OfBh,OOch,OOch,Occh,078h,OOOh
03Bh,06Oh,OcOh,OfBh,Occh,Occh,078h,OOOh
Ofch,Occh,00ch,01Bh,030h,030h,030h,000h
078h,Occh,Occh,07Bh,Occh,Occh,078h,OOOh
078h,Occh,Occh,07ch,00ch,01Bh,070h,OOOh
000h,030h,03Oh,000h,000h,030h,030h,000h
000h,030h,030h,000h,000h,030h,030h,06Oh
01Bh,030h,06Oh,OcOh,06Oh,030h,01Bh,000h
A-Type BiosKit
00 - nul
01 - "A
02 - "B
03 - "C
04 - "0
05 - "E
06 - "F
07 - "G
08 - "H
09-- "I
OA - "J
08 - "I(
OC - "L
00 - "M
OE - "N
OF - "0
10 _ "p
11 - "Q
12 - "R
13 - "s
14 - "T
1S - "U
16 - "V
17 - "y
18 - "X
19 - "y
1A - "Z
18 - "r
1C - "\
1D - "]
1E - "6
1F - "-
20 - spc
21 - I
22 - "
23 - 1#
24 - S
25 - X
26 - &
27 - I
28 - (
29 - )
2A - *
28 - +
2C - ,
2D - -
2E -
2F - I
30 - 0
31 - 1
32 - 2
33 - 3
34 - 4
35 - 5
36 - 6
37 - 7
38 - 8
39 - 9
3A -
38 - ;
3C - <
The Top File D221
db OOOh,OOOh,Ofch,OOOh,OOOh,Ofch,OOOh,OOOh 30-
=
db 060h,030h,01Sh,OOch,01Sh,030h,06Oh,OOOh 3E - >
db 078h,Occh,OOch,01Sh,030h,OOOh,030h,OOOh 3F
- ?
db 07ch,Oc6h,0deh,Odeh,Odeh,OcOh,07Sh,OOOh 40 - Q
db 030h,07Sh,Occh,Occh,Ofch,Occh,Occh,000h 41
- A
db Ofch,066h,066h,07ch,066h,066h,Ofch,OOOh 42 - B
db 03ch,066h,OcOh,OcOh,OcOh,066h,03ch,OOOh 43 - C
db OfSh,06ch,066h,066h,066h,06ch,OfSh,OOOh
44 - 0
db Ofeh,062h,068h,07Sh,068h,062h,Ofeh,000h 45 - E
db Ofeh,062h,068h,07Sh,068h,06Oh,OfOh,OOOh 46 - F
db 03ch,066h,OcOh,OcOh,Oceh,066h,03eh,OOOh 47 - G
db Occh,Occh,Occh,Ofch,Occh,Occh,Occh,OOOh 48 - H
db 078h,030h,030h,030h,030h,030h,078h,OOOh 49 - I
db 01eh,OOch,OOch,OOch,Occh,Occh,078h,OOOh 4A - J
db Oe6h,066h,06ch,078h,06ch,066h,Oe6h,OOOh
48 - K
db OfOh,06Oh,06Oh,06Oh,062h,066h,Ofeh,000h 4C - L
db Oc6h,Oeeh,Ofeh,Ofeh,Od6h,Oc6h,Oc6h,OOOh
40 - M
db Oc6h,Oe6h,Of6h,Odeh,Oceh,Oc6h,Oc6h,OOOh 4E - N
db 038h,06ch,Oc6h,Oc6h,Oc6h,06ch,038h,OOOh 4F - 0
db Ofch,066h,066h,07ch,06Oh,06Oh,OfOh,OOOh 50 - p
db 07Sh,Occh,Occh,Occh,Odch,078h,01ch,OOOh 51 - Q
db Ofch,066h,066h,07ch,06ch,066h,0e6h,OOOh 52 - R
db 078h,Occh,OeOh,070h,01ch,Occh,078h,OOOh 53 - S
db Ofch,Ob4h,030h,030h,030h,030h,078h,OOOh 54 - T
db Occh,Occh,Occh,Occh,Occh,Occh,Ofch,OOOh 55 - U
db Occh,Occh,Occh,Occh,Occh,078h,030h,OOOh 56 - V
db Oc6h,Oc6h,Oc6h,Od6h,Ofeh,Oeeh,Oc6h,OOOh 57 - W
db Oc6h,Oc6h,06ch,038h,038h,06ch,Oc6h,OOOh 58 - X
db Occh,Occh,Occh,078h,030h,030h,078h,OOOh 59 - Y
db Ofeh,Oc6h,08ch,018h,032h,066h,Ofeh,OOOh SA - Z
db 078h,060h,06Oh,06Oh,06Oh,06Oh,078h,000h 58 - [
db OcOh,06Oh,030h,018h,00ch,006h,002h,OOOh 5C - \
db 07Sh,01Sh,01Sh,018h,01Sh,01Sh,078h,000h 50 - ]
db 010h 038h 06ch Oc6h OOOh OOOh OOOh,OOOh 5E - A
db OOOh:OOOh:OOOh:OOOh:OOOh:OOOh:OOOh,Offh SF -
db 030h,030h,01Sh,000h,OOOh,OOOh,OOOh,OOOh 60
_ T
db OOOh,000h,078h,00ch,07ch,Occh,076h,000h 61 - a
db OeOh,06Oh,06Oh,07ch,066h,066h,Odch,000h 62 - b
db OOOh,00Oh,07Sh,Occh,OcOh,Occh,078h,OOOh 63 - c
db 01ch,OOch,00ch,07ch,Occh,Occh,076h,000h 64 - d
db OOOh,OOOh,078h,Occh,Ofch,OcOh,078h,OOOh 65 - e
db 038h,06ch,06Oh,OfOh,06Oh,06Oh,OfOh,000h 66 - f
db 000h,OOOh,076h,Occh,Occh,07ch,OOch,OfSh
67 - 9
db OeOh 060h 06ch 076h 066h 066h 0e6h OOOh 68 - h
db 030h:OOOh:070h:030h:030h:030h:07Sh:000h 69 - i
db 00ch,OOOh,00ch,00ch,00ch,Occh,Occh,07Sh
6A
db OeOh,06Oh,066h,06ch,078h,06ch,Oe6h,OOOh 68 : ~
db 070h,030h,030h,030h,030h,030h,078h,OOOh 6C - l
db OOOh,OOOh,Occh,Ofeh,Ofeh,Od6h,Oc6h,OOOh 60
- m
db OOOh,OOOh,OfSh,Occh,Occh,Occh,Occh,OOOh 6E
- n
db OOOh,OOOh,078h,Occh,Occh,Occh,078h,OOOh 6F
- 0
db 00Oh,OOOh,Odch,066h,066h,07ch,06Oh,OfOh 70 -
P
db 000h,000h,076h,Occh,Occh,07ch,00ch,01eh 71 - q
db OOOh,00Oh,Odch,076h,066h,06Oh,OfOh,00Oh n- r
db 00Oh,000h,07ch,OcOh,078h,00ch,OfSh,OOOh 73 - s
db 010h,030h,07ch,030h,030h,034h,01Sh,000h 74 - t
db 000h,OOOh,Occh,Occh,Occh,Occh,076h,000h 75- u
db 00Oh,000h,Occh,Occh,Occh,078h,030h,OOOh
76 -
v
db OOOh,OOOh,Oc6h,Od6h,Ofeh,Ofeh,06ch,OOOh n- w
db OOOh,OOOh,Oc6h,06ch,038h,06ch,Oc6h,OOOh
78 -
x
db OOOh,000h,Occh,Occh,Occh,07ch,00ch,OfSh 79- y
db OOOh,00Oh,Ofch,098h,030h,064h,Ofch,000h 7A - z
db 01ch,030h,030h,OeOh,030h,030h,01ch,000h 78- {
db 01Sh,01Sh,01Sh,000h,01Sh,01Sh,01Sh,000h 7C -
! db OeOh,030h,03Oh,01ch,030h,030h,OeOh,000h 70-
db 076h,Odch,000h,OOOh,000h,OOOh,000h,000h 7E
db 000h,01Oh,038h,06ch,Oc6h,Oc6h,Ofeh,000h
7F -
~ o m o r g time of day
J..., time_of_may
~ o m o r g timer int
J..., timer_Tnt
romorg dumIy iret
iret
- -
romorg -print screen
int_header print:screen
print screen uses own stack
abort string label byte
- db 13,10,'WARNING - This program cannot be executed under 00S.',13,10,'$'
abort:
push
pop
; if this program is started by dos, we display a message and abort
cs
ds
Section D: The ASM Pro&rams
D222 The Top File
mov
mov
int
mov
int
dx,offset abort string
ax 0900h -
21h print string
ax,4cOOh
21" exit to DOS
i=== This is the hardware entry point after a reset ===
romorg

db
dw
dw
Oeah
OeOSbh
OfOOOh
i=== This is the standard location for the date-stamp ===
romorg date stamp
date_stamp label byte -
db '--1--1--',0
i These locations are loaded with the current date by bfosdate during the buHd process.
i======== This is the CPU type byte ===========
type byte label byte
- db 0
i This location is loaded with the type byte value by biostype during the bui ld process.
i=== This is where the Bios checksum value is stored =====
db 0
i This location is loaded with the calculated checksum by biossum during the build process.
_atext ends
end abort
A- BiosKit
The Pad File D31
THREE
The Pad File
The Pad.asm File is an assembly language file used to assign the starting offset of
the Bios to a location greater than 0000 in the segment. If it is desired to reserve
space at the beginning of the Bios segment for optional rom-scan modules, or to
reduce the size of the Bios to less than 64 Kbytes in order to use a smaller-size
prom, the hiospad module is used to declare the Bios starting offset. A signature is
placed at the beginning of this module to facilitate the detection of secondary and
test Bios'. The signature is a representation of the word "bios" expressed by the
hexadecimal characters "bI05" .
. ***************************************************************************************************
I
; Copyright (c) FOSCO 1988 - All Rights Reserved
Module Name: AT Bios pad out the front of the bios
Version: 1.00
Author: FOSCO
Date: 12-01-88
Filename: atpad.asm
Functional Description:
This module is used to fill out the front of the bios prom when a less than 64k bios is desired.
The linker always generates a 64k binary image module. The unused locations are preset to all
ones (FF) so that prom pr09rammers may skip over these locations. This leaves them unused
and avai lable for merging 1n optional rom-scan modules for an extended custom Bios.
Version History:
!**************************************************************************************************
I
include atprfx.inc
code
extrn reset:near
bios start proc
- dw
db
j ~
bios_start endp
end
OSb1h
BOh
reset
this is a Bios signature
Things I Should Forget
The Fill File D41
FOUR
The Fill File
The Fill.asm File is an assembly language file used during the linking process to
upwardly justify the biostop module so that it resides at the end of the Bios segment.
.*************************************************************************************************** ,
Copyright (c) FOSCO 1988 - All Rights Reserved
Module Name: Bios fill at link time
Version: 1.00
Author: FOSCO
Date: 5-12-88
Filename: atfill.asm
Functional Description:
Uses biosfill.inc (generated by BIOSGEN) to fill out area so the biostop module will
be positioned correctly at the top of the bios.
Version History:
;**************************************************************************************************/
include atprfx. inc
-
fi II segment
include atfill.inc
fill ends
-
end
Meetings I Should Go To
The Data File D51
FIVE
The Data File
The Data.asm File is an assembly language file used to declare the variables
assigned to the system scratch Ram segment and those used by the Sys Vue program.
These variables will be assigned to the top 2 Kbytes of space in the system Ram
Memory map by the power-up (POD) routine.
The memory block pool definitions also reside in this file. The acquire_block and
release_block operations (in Biosmisc.c) are used to assign memory for use as
variables to limit use of the stack by Bios function call routines .
************************************************************************************************** ,
Copyright (c) FOSCO 1988 - All Rights Reserved
Module Name: AT Bios system data definition
Version: 1.00
Author: FOSCO
Date: 12-01-88
Fi lename: atdata.asm
Language: MS MASH 5.1
Functional Description:
This module is used to declare the variables in the system ram segment. Most of these variables
are used by biosvue.
A stack is assigned at the top of the module for use by the POD routines.
Version History:
;**************************************************************************************************/
include atprfx.inc
the data section to declare the system ram for biosvue
publ ic
publ ic

Public
publ ic
public
public
publ ic
public
public
publ ic
public
public
public
publ ic
public
public
publ ic
public
public
public
public
public
public
public
publ i c
publ ic
publ ic
public
publ ic
public
Public
publ ic
mode size
mode-type
sysvUe busy
inchar-
buffer
exit flag
buffer index
reg saves
inreg saves
out reg saves
token index
token-value
cc -
token buffer
conmafid index
flag ir&x
token fUlt)er
list index
last-del im
breai flag
last start seg

lnt seg
int-off
reg-index
break chain
trace-chain
trap_Chain
present
sl.l1l
enter_seg, enter_off
char count
record_type
D5 2 The Data File
~ l i c
~ l i c
public
~ l i c
public
publ ic
publ ic
trace COll1t
watch-flag
watch-selection
u found
jJ
redirect flag
dec_array
;=== definition of system scratch object ===
scratch segment at 0
aid dw
; sysvue variables
sysvue busy dw 1
mode sTze dw
mode-type dw
inchir dw 1
?
?
?
buffer dw 80 dup(1)
exit flag dw ?
buf fir index dw 1
- align 16
reg saves label word
- dw 16 dup (1)
inreg saves label word
- dw 16 dup(1)
out reg saves label word
- dw 16 dup(1)
token index dw 1
token-value dw 8 dup(1)
cc - dw 1
token buffer dw 16 dup(1)
conrnaiid index dw ?
flag inC!ex dw
token number dw 1
lis t T ndex dw 1
last-delim dw 1
breaK flag dw 1
last a ~ start seg dw 1
last-dump-start-off dw 1
int seg Ow - 1
int-off dw 1
reg-index dw ?
break chain dd 1
trace-chain dd 1
trap_Chain dd ?
present dw
trace count
sum - dw
enter seg dw
enter-off dw
char count dw
record type dw ?
watch flag
watch-selection
u found dw
H. dw
redlrect flag
dec_array ci)
?
dw
?
1
?
1
dw
dw
?
1
dw
6 dup(1)
?
?
?
?
?
Object Structure Definitions
optional id field = 5aa5 to be valid
load this field if you need to locate
this object in an expanded system.
line input buffer
; -1 = exit from sysvue
ptr for DUffer
i these are normal saves
these are used for INT command
these are used for I NT command
ptr for token string
token string
gotten from _token_index
nr. of match i ng i tern
i last delimiter found
;============== variables for functions ============
:------ reserved space for protected mode tables -------
;----- pointer to parent bios
parent
org
publ ic
dw
48h
parent
1
;------ reserved space for protected mode tables
al ign 16
pUblic GOT block
GOT_block label byte -
dq 7 dup(1)
publ ic
lOT_block dq
al ign
publ ic
lOT block
o -
16
psuedo _LI OT
A Type BiosKit
psuedo_LIDT
align
PUblic
psuedo_LGO'r
align
publ i c
virtual block
- db
df 0
8
~ u e d o LGDT
df - 0
16
virtual block
label byte
256 dup(7)
block space for allocating
public start block
public current open
Publi c end blOCk
public blOCk beg
public block:end
The Data File D-5-3
The following area is a block-pool, from which blocks can be allocated by the functions:
acquire_block
release block
These allow dynamic allocation for recursive functions while minimizing stack space used.
public ds save,bx save,dest save, length mark
public sp:save,ss:save - -
align 16
start block dw 7
current ~ dw ?
end_blOCk dw 7
bx save dw 7
ds-save dw 7
deit_save dw 7
align 16
block beg label word
- dw 1024 dup(7)
block_end label word
;===================================================
scratch ends
; This structure is used to save the old stack pointer in the new
; stack block, It is used to switch back to the callers stack
; after a swapping interrupt.
swap_seg segment at 0
length_mark dw
dw
dw
dw
sp_save
ss save
swap_seg ends
end
7
7
7
7
also user 10 field
save of callers ss:sp
Section D: The ASM Pro&rams
Meetings I Should Avoid
The Virt File D-6-1
SIX
The Virt File
. The Virt.asm File contains the virtual mode routines.
Three major items are handled by the virtual routines:
1. Sizing and testing any extended ram
2. Block move routine which supports Virtual Ram Disks.
3. Switching machine operation to virtual mode.
Default descriptor tables are built for ram test and for the block move. The user
needs to build the tables when switching to virtual mode. The test and the move
routines have their own restart sequences, so that the CPU may be restarted back in
real mode, and continue operation.
A restart consists of saving a restart code in the CMOS RAM at location OF. An
error code may be returned in DMA page register port 80. The values are used to
determine what action to take. An optional argument may be saved in port 88. A
signal is then sent to the 8042 keyboard controller which pulses the reset line to the
CPU. The CPU then restarts in the default real-mode and the restart-code value is
checked to see if it is other than a power-up or a normal reset switch sequence. If a
valid restart code value is found in port 80, the Biostop.asm module code diverts to
the specific restart sequence. This restart sequence then restores the machine state
(registers) and returns control to the program which caused the CPU to go to virtual
mode.
The 286 CPU normally starts operation in the real-mode upon power-up. It may be
switched to virtual mode by setting the protection enable (PE) bit in the machine
status word (MSW). Because of a quirk in the original design of the 286 CPU, the
only way to switch back to the real-mode, (which is the normal mode for DOS), is by
actually causing a hardware reset of the CPU chip. To permit this, the 8042 output
port has an output line which connects to the 286' s reset input line. A command may
be sent to the 8042 to pulse this reset line.
The 386 has provision for switching to and from the virtual mode internally by
modifying the machine status register (MSW) by a 386-specific instruction (MOV to
Control Register). This enhancement of the 386 negates the need for the
complicated restart handling of the 286.
One item about the 286 which is of interest is that there is a Interrupt Descriptor
Table Register (IDTR) which provides the base address of the interrupt vectors.
Upon a hardware reset, this register is set to a value of 0000, so that the base
address of the interrupt vector segment is at zero. When switching to virtual mode,
this register is changed to point to an Interrupt Descriptor Table (IDT). This
permits the interrupt vector segment to be re-Iocated without changing the contents
of the vector locations. This basing register is also active in the real-mode (since it
defaults to 0000, we are not aware of its existence in real-mode) and can be used to
relocate or substitute multiple sets of interrupt vectors. In standard DOS practice,
however, this option is not exercised.
D6 2 The Virt File
Why the DMA page register is used to save parameters - During the restart
sequence, there are usually some values that need to be passed from the virtual-
mode program back to the real-mode program. These could be saved in the CMOS
RAM, or somewhere in system memory. A very convenient spot that was originally
used on the AT type machines, is the DMA page register chip. In the earlier PC and
XT type of machines, the was a write only device, which handled the four
standard DMA channels. ThIs chip held the high four bits of the memory address
during a DMA transfer, as the 8237 DMA chip only has 16-bit internal repsters.
The AT type of machines have an additional 8237 DMA controller for 16-bJt wide
data transfers. Now there was a need for 8 page registers (one for each of the 8
DMA channels). Instead of using two of the XT type chips (74670), a newer chip
was selected. This is the 74612 type of chip. This contains 16 8-bit registers, 8 of
which are used for the DMA channels.
These registers are both read/write, so two of these are used for passing parameters
by the AT BiosKit. The basic restart-type code is passed in location OF of the
CMOS-RAM, but an error-descriptive value is passed in the page register port at 80,
and a second argument may be passed in register port 88.
Notes for potential 386/376 users - The 386, as mentioned previously, has an
enhanced mechanism for switching between real and virtual modes, while the 376
assumes the virtual mode of operation from reset, since it does not have the real-
mode capability. .
.*************************************************************************************************** ,
; Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
Module Name: AT BiosKit Virtual memory support
Version: 1.02
; Author: FOSCO
; Date: 10-20-89
: Filename: atvirt.asm
; Language MS MASM 5.1
; Functional Description:
; Version History:
; 1.01
; Deleted some extraneous code (GOT structures)
; 1.02
; Corrected block move errors
; Changed restart from 8042 to double fault shutdown sequence
; Added sucoort for restart 5 and 10
; Changed ")/11) myself" loop after shutdown to a HLT to keep busses quiet
!*************************************************************************************************** ,
include atprfx.inc
extrn
extrn
extrn .
extrn
extrn
extrn
extrn

publ ic
public
err'-port equ
arg-.POrt equ
port a
porto
i ntalJO
inta01
out cmos : near
GOT block!near
IDTolock:near
psuido LGOT: near
psuedo:LIDT:near
co:near
lword:near
restartS
restart9
restart10
080h
088h
equ
equ
equ
equ
; save stuff in page register chip
for saving aux. data on restarts
061h
020h
021h
A-Type BiosKit
intbOO equ
intb01 equ
status-POrt equ
input DUffer full equ
restart cell- equ
restart-command equ Ofeh
OaOh
Oa1h
064h
02h
08fh
cmos-POrt equ 070h
equ OOch
equ Of3h
parlty_error equ OcOh
build 24bit address macro arg1,arg2
- PUsh arg2
push
call bulld 24
add sp,4 -
enan
build_descriptor macro arg1,arg2
push arg2
push
call bulld descriptor routine
add sp,4 - -
enan
These are macros to enable or disable A20, added 5-12-89 <BG>
active
inactive equ
Odfh
change_number = 0 Number of change_a20 call
empty_8042 macro
local empty_loop
empty_number = empty _nc.Jlt)er +
xor cx,cx
empty_loop;
1n
and
loopnz
mov
encin
al,64h
al,02h
loop
al,
Inc number of empty call
change a20 macro arg ;; Odfh = enable, Oddh = disable
- local error check,exit change
empty_number = 0-; Start ofT with empty number = 0
change number = change number + 10h
- 8042 -
jnz - error check
mov a l ,Od'lh
out 64h,al
8042
jnz - error check
mov al,arg
out 60h,al
efI1)ty 8042
error check: -
- clc
jz exit_change
stc
add al,change_number
exit change:
- enan
i End of new macros <BG>
i==== definitions for virtual modes =====
i==== (test_ram and move_block) ====
i------ Code/Data Descriptor definitions ----------------
desc struc
lim 15 0 dw
bas-15-0 dw
bas-23-16 db
access-
limit (15-0)
base (15-0)
base (23-16)
The Virt File D-6-3
irsv
desc ends
o
o
o
db
dw
o
o
; access rights
; intel 386 reserved next 2 bytes
trap/interrupt gate definition
tigdesc struc
code offset
code:select
dw
dw
db
?
?
o
offset to routine
selector to routine
always zero
Section D: The ASM Pro&rams
D-6-4 The Virt File
hb_arb
tigdesc ends
db
dw
len_desc equ 8
?
o
high base and access rights
reserved for 386
;========== Global Descriptor Table structures ==========
0 _______ the GOT for the block move organization ------
; This structure order is determined by the function call format.
; Do not alter it I
; We also use this structure for the extended memory testing
move struc
move any dq 0
move :gdt c:Jq 0
move ds
move-es
move-cs
move-ss
move-idt dq 0
move-ends
fdt
fdt
ide
struc
ends
dqO
i 00
; 08
10
18
20
28
30 - this exists for both move and mem-test
; 00
i---------- the GOT for virtual mode function call --------
i This structure order fs determined by the function call format.
; Do not alter it I
mode struc
mode_any dq
mode sdt dq
mode -1 dt c:Jq
mode-ds dq
mode:es dq
mode ss dq
mode - cs c:Jq
modecios dq
mode-ends
o
o
o
o
o
o
o
o
00 - unusable
08 - GOT
10 - lOT
18 - data
20 - extra
28 - stack
30 - code
38 - bios
i----------------------------------------------------- ----
;----------- the gdt segment for the POD and the move ----
gdt segment segment at 0
gdt:start label byte
desc <>
desc <>
desc <>
desc <>
desc <>
desc <>
desc <>
gdt end label byte
gdt-len = gdt end-gdt start
gdt:segment ends -
idt segment segment at 0
idt:start label byte
desc <>
idt_segment ends
virtual_enable equ 1
null_idt: desc<>
table 0 not usable
08 - GOT
10 - temp for ds
18 - temp for es
20 - temp for ss
28 - temp for cs
30 - lOT - created for move
ram idt descriptor
;========== end of definitions ============
i this module includes all the code for accesssing the virtual memory and running in protected mode
i----------------------------------------------------- -----
code
;-------- move virtual block - function code 15h ----------
virtual move proc uses ds,word count:word,global segment:word,global offset:word
- cli - - ; disable interrupts/execeptions
cld
xor al,al
out err-POrt,al
change a20 acllve
jnc - iF
change a20 inactive
mov - aX,0300h
ret
A-Type BiosKit
; clear the error bucket
enable full range addressing <8G>
i no carry says A20 ok
disable 1t again <8G>
mark A20 error, return to caller
; quiCK return when A20 error
ii)Q:
pusha
push
push
push
pop
assune
mov
mov
mov
mov
ds
es
40h
ds
ds:segment_40
ax,ss
vsegment,ax
ax,sp
voffset,ax
write_cmos restart_cell,9
build_descriptor es,si
mov
mov
mov
cx,word_count
ax,40h
The Virt File D-6-S
save return pointers in low ram
save stack description in low ram
set restart type 9
get and save the move count
es,ax
es, word ptr es:[Oeh] mov get system seg
19dt fword ptr es:psuedo_LGOT; point the gdt-reg to the block
Udt fword ptr es:psuedo_LIOT ; lOT's are built
mov
lmsw
delay
db
aX,virtual enable
ax -
Oeah
go into protected mode
this jump to clear queue
dw
jmp far ptr into cs: selector to
; set access rights
cont i nue execut i ng 2 lines be l ow
continue:
ii)Q:
ii)Q:
dw
nap
mov
mov
mov
mov
mov
mov
sub
sub
~ e p
1n
test
jz
xchg
xchg
mov
out
in
delay
or
out
delay
and
out
aX,move_ss
sS,ax
aX,move ds
ds,ax -
aX,move_es
eS,ax
di ,di
si ,si
movsw
al,port b
al,parity error
GlF -
ds: [di] ,ax
ds: [di] ,ax
al,1
err,J)Ort,al
al,port_D
al,disable-psrity
port_b,al
al,enable-psrity
port_b,al
change a20 inactive
jnc - GlF
in al,err,J)Ort
or al,al
jnz GlF
mov al,3
out err,J)Ort,al
set up selectors
; word count is already in ex
; this does the actual move
see if a parity error on move
jump if no error
re-write the bad word
set parity error code in bucket
reset parity
were there any previous errors?
test for non-zero
no - set A20 error code
i fndef SLOW RESET Shutdown may not work on some ch i p s ~ t s <BG>
; try causing i shutdown
else
<BG>
endif
lidt fword ptr cs:null idt
int 3 -
mov
out
hlt
al,restart command
status,J)Ort,al
Use keyboard controller to reset if shutdown won't work
this causes restart
End of alternate reset code <BG>
stop cpu to quiet the busses
i- This is where the restart from the block moves comes in -
restart9: ; proc
mov
mov
assune
ax,40h
ds,ax
ds:segment_40
Section D: The ASM ProlUams
D66 The Virt File
cli
mov
mov
mov
mov
pop
pop
pope
1n
mov
xor
ret
ax,vsegment
ss,ax
ax,voffset
sp,ax
es
ds
al,errJ)Ort
ah,al
al,al
restore the original real stack
; get.returning error code
return with error code in AH
virtual_move endp
..... switch to virtual mode ........
; Int 15
c
function 89
void vlrtual mode(bhbltseV,off)
called with 5h = 8259 .1 lndex
called with bl = 8259 #2 index
called with es = segment of ~ i n t e r to global desc. table
called with si = offset of pointer to globel desc. table
returns with ax = 0 = ok, else not zero = error
all other registers destroyed IIII
vi rtua l mode proc bhbl : word,desc_seg: word, desc_off: word
- cl i
@G):
lOT
change a20 active
jnc - iF
mov ax,-1 ; set error, quick return to caller
ret
mov
mov
19dt
l idt
es,desc seg
si,desc-off
fword pfr es:[si].mode_gdt
fword ptr es:[sil.mode_idt
reload the 8259 interrupt controllers because we have changed the base address of the
( the interrupt vectors).
mov
out
delay
mov
xchg
out
delay
mov
out
delay
mov
out
delay
mov
out
al,11h
intaOO,al
ax,bhbl
ah,al
inta01,al
al,04h
inta01,al
al,01h
inta01,al
al,Offh
inta01,al
al,11h
intbOO,al
ax,bhbl
intb01,al
al,2
intb01,al
al,1
intb01,al
this is penn from caller
this is penn from caller
mov
out
delay
mov
out
mov
delay
out
delay
IIIOV
out
delay
IIIOV al,Offh
out intb01,al
build our own CS: as the bas 23 16 value for the descriptor table, This way we can execute from
a secondary or a test bios, it other than segment FOOO.
IIIOV
shr
IIIOV
mov
IIIOY
IIIOY
IIIOY
moY
lmsw
ax,cs
ax,12
A-Type BiosKit
; now looks as 32-16 value
delay
mov
mov
mov
mov
mov
mov
The Virt File D6 7
this jump to clear queue

ax,mode_ds
ds,ax
ax,mode_es
es,ax
ax,mode ss
ss,ax -
bx
sp,4
get the return address off the stack
need to adjust this II!!
we may have to back up through the call
into the Int 15 function to return
push
push
retf
virtual_mode endp
mode cs
bx -
to the real caller. 7111
push cs selector on stack
push return on stack
return to user
These are the "continue" points for returning from virtual mode to
real mode, when using the switch to virtual mode function above
The User MUST disable both interrupts and NMl
f
and load V OFFSET and
V SEGMENT with a valid continuation address. hen the user must
load the restart code (5d or 10d (OSh or Oah in CMOS location
xx, then cause a double fault exception to force a CPU reset. Not many
users get involved in this.
Programmers Opinion: If you really want to operate in virtual mode,
get a 386 mach i ne.
restart5:
restart10:
in
mov
out
mov
mov
j"l)
al,60h
al
/
20h
20n,al
ax,40h
ds,ax
dword ptr voffset
i=============================
idt descriptor label byte
- dw rom idt len
purge the keyboard buffer
send an EOI to the interrupt controller
to purge pending timer interrupts
voffset is in segment 40:
dw offset rom_idt
db Ofh,O resident idt table is in bios_cs
idt descriptor length = S-idt_descriptor'
rom-idt: -
- tigdesc <exc OO,move cs,,81h>
tigdesc <exc-01,move-cs,,81h>
tigdesc <exc-02,move-cs,,81h>
tigdesc <exc-03,move-cs,,81h>
tigdesc <exc-04,move-cs,,81h>
tigdesc <exc-OS,move-cs,,81h>
tigdesc <exc-06,move-cs,,81h>
tigdesc <exc-07,move-cs,,87h>
tigdesc <exc-08,move-cs,,87h>
tigdesc <exc-09,move-cs,,87h>
tigdesc <exc-10,move-cs,,87h>
tigdesc <exc-11,move-cs,,87h>
tigdesc <exc-12,move-cs,,81h>
tigdesc <exc-13,move-cs,,81h>
tigdesc <exc-14,move-cs,,87h>
tigdesc <exc-15,move-cs,,81h>
tigdesc <exc-16,move-cs,,87h>
tigdesc <exc-17,move-cs,,81h>
tigdesc <exc-18,move-cs,,81h>
tigdesc <exc-19,move-cs,,81h>
tigdesc <exc-20,move-cs,,87h>
tigdesc <exc-21,move-cs,,81h>
tigdesc <exc-22,move-cs,,87h>
tigdesc <exc-23,move-cs,,87h>
tigdesc <exc-24,move-cs,,87h>
tigdesc <exc-2S,move-cs,,81h>
tigdesc <exc-26,move-cs,,81h>
tigdesc <exc-27,move-cs,,81h>
tigdesc <exc-28,move-cs,,87h>
tigdesc <exc-29,move-cs,,87h>
tigdesc
tigdesc
rom_idt_len equ S-rom_Tdt -
;--------------------------------
ex_int:
Q)Q):
mov
out
mov
out
hlt
al,2

al,restart command

exception interrupts for move
error code = 2 = excep. into error
Section D: The ASM ProlUams
D68 The Virt File
restore idt label fword
- dw 3ffh
dw 0
dw 0
i ret addr label word
- i ret
lim 15 0
basi -
; this sets up an all inclusive exception table. if we get an exception while we are in
virtual mode, we want to process and report it.
sys idt offsets
- - dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
dw
label word
offset exc 00
offset exc-01
offset exc-02
offset exc-03
offset exc-04
offset exc -05
offset exc-06
offset exc-07
offset exc-08
offset exc-09
offset exc-10
offset exc-11
offset exc-12
offset exc-13
offset exc-14
offset exc-15
offset exc-16
offset exc-17
offset exc-18
offset exc-19
offset exc-20
offset exc-21
offset exc-22
offset exc-23
offset exc-24
offset exc-25
offset exc-26
offset exc-27
offset exc -28
offset exc-29
offset exc'""30
offset exc::J1
00 = divide error
01 = step
02 = l'1IIi
03 = trap
04 = into detect
05 = bounds check
06 = inval id opcode
07 = NPX not available
08 = double fault
09 = NPX segment error
10 = invalid tss
11 = cs, ds, es not present
12 = SS: not present
13 = general prot error
14 =
15 =
16 = NPX error
17 =
18 =
19 =
20 =
21 =
22 =
23 =
24 =
25 =
26 =
27 =
28 =
29=
30 =
31 =
;----- this is the canned gdt for the pod routines ---------
gdt data start
- - desc
label word
<0,0,0,0> ; 00
08 - the GOT desc
desc
desc
desc
desc
desc
<gdt len(,offset GOT olock,0,93h>
<-1,0000 ,Ofh,93h> -; 10 - temp for ds
<-1,0000h,10h,93h> ; 18 - temp for es
<-1,0000h,00h,93h> ; 20 - temp for cs
<-1,0000h 00h,93h> ; 28 - temp for ss
<rom idt (en,rom idt,0,93h> ; 30 - the IDT
word - - - gdt_data_end label
---------------.------------------_._--.-._--------
exc_OO: mov al,O ; load al with exception ruar
jmp test exc
exc_01: mov al,1-
jmp test exc
exc_02: mov al,2-
jmp test exc
exc_03: mov al,3-
jmp test exc
exc_04: mov al,4-
jmp test_exc
exc_05: push
mov
mov
sub
mov
mov
pop
mov
jnp
exc_06: mov
jnp
exc_07: mov
es this is a bounds check
ax,move es
es,ax -
di ,di
word ptr es:[di] 0
word ptr
es
al,5
test_exc
al,6
test exc
al,r
A Type BiosKit
j ~ test exe
exc_08: mov al,8-
j ~ test exc
exc_09: mov al,9-
jlJ1) test exe
exc_10: mov al,10
jlJ1) test exe
exc_11: mov al,1T
jlJ1) test exc
exc_12: mov al,12
jlJ1) test exe
exc_13: mov al,13
jlJ1) test exc
exc_14: mov a l, 17;
jlJ1) test exc
exc_15: mov al,1)
jlJ1) test exe
exc_16: mov a l , 11)
jlJ1) test exe
exc_17: mov al,17
j ~ test exc
exc_18: mov al,18
j ~ test exc
exc_19: mov al,19
j ~ test exc
exc_20: mov al,20
j ~ test exe
exc_21: mov al,2T
jlJ1) test exc
exc_22: mov al,22
jlJ1) test exe
exc_23: mov al,23
j ~ test exe
exc_24: mov al,27;
jlJ1) test exe
exc_25: mov al,2)
jlJ1) test exe
exc_26: mov al,21)
j ~ test exc
exc_27: mov al,27
jlJ1) test exc
exc_28: mov al,28
jlJ1) test exc
exc_29: mov al,29
jlJ1) test exe
exc_30: mov al,30
jlJ1) test exc
exc_31 : mov al,3T
jlJ1) test_exe
; if we got an exception, process it so we can return an
; exception code.
test_exc:
add
out
iret
al,80h
errJ)Ort,al
add SOh to these exceptions
;------- build a descriptor table in the system ram segment
we do this for both the block move and the mem-test
t seV:t off ~ i n t s to the template to build
wi wlll-fill in some dynamic values
it will be buil t in system:segment:GDT_block
;------- build the global descriptor tables ---------------
; These are built with current CS: in case we are in test mode
build_deseriptor_routfne proc t_seg:word,t_off:word
i-- ds:si ~ seg:off of the template
mov
mov
ds,t seg
si,t:off
i-- es:di = location in system segment to build the descriptor
mov di,offset GOT_block
mov ax,40h
mov es,ax
moves, word ptr es:[Oeh]
i-- cx = length of the template
The Virt File D69
mov cx,24 template is 48 bytes long
Section D: The ASM Prolfams
D610 The Virt File
push
rep
pop
di
movsw
di
i-- build a dynamic GOT descriptor
build 24bit address es,<offset GOT block>
mov - es:[dil.move gdt.lim 15 O,38h
mov es:[dil.move-gdt.bas-15-0
J
ax
mov es:[dil.move-gdt.bas-23-10 dl
mov es:[dil.move-gdt.access;93h
mov es:[dil.move:gdt.irsv,O
i-- build a dynamic CS: descriptor
build 24bit address cs,O
moy - es:[dil.move cs.lim 15 0,-1
mov es:[dil.move-cs.bas-15-0 ax
moy es:[dil.move-cs.bas-23-1A,dl
moy es:[dil.move-cs.access;9bh
moy es:[dil.move:cs.irsv,O
i-- build a dynamic SS: descriptor
build 24bit address ss,O
moy - es:[dil.move ss.lim 15 0,-1
moy es:[dil.move-ss.bas-15-0,ax
moy es:[dil.move-ss.bas-23-16 dl
mov es:[dil.move-ss.access;93h
mov es:[dil.move:ss.irsv,O
i-- build a dynamic lOT descriptor
build 24bit address es,<offset lOT block>
mov - es:[dil.move idt.lim 15 U,6
mov es:[dil.moye-idt.bas-15-0
J
ax
mov es:[dil.move-idt.bas-23-10 dl
mov es:[dil.move-idt.access;93h
mov es:[dil.move:idt.irsv,O
i-- now build the lOT descriptor
build 24bit address cs,<offset rom idt>
mov - dT,offset lOT block -
mov es:[dil.idt.Tim 15 0,6
mov es:[dil.idt-.bas-15-0
J
ax
mov es:[dil.idt-.bas-23-10 dl
mov es:[dil.idt-.access;93h
mov es:[dil.idt:.irsv,O
;-- now build the psuedo GOT- qescriptor
build 24bit address es,<offset GOT block>
mov - dT,offset psUedo LGOT -
mov word ptr es:[di+U01,56
mov es:[di+02],ax
mov es: [di+04],dx
i-- now bui ld the psuedo lOT descriptor
build 24bit address es,<offset lOT block>
mov - dT,offset psUedO LIOT -
mov word ptr es:[di+UO],256
mov es:[di+02],ax
mov es: [di+04],dx
ret
build_descriptor_routine endp
save base address of GOT table
;---------------------------------------------------_.--
; returns a 24 bit address in OX:AX
bui ld_24 proc
xor
mov
mov
shr
shl
add
adc
ret
bui ld_24 endp
xseg:word, xoff:word
dx,dx
ax,xseg build 24-bit address from seg:off
dl,ah
dl,4
ax,4
ax,xoff
dl,O
Test Ram - size, test, and clear
A Type BiosKit
returns ok/error code in AX - size in cmos(30 and 31)
note: this are all near procs, since they can be
called from the Bios CS: only. After we do a restart,
we are also in the Bios CS:, so we automatically connect
with the right return address.
The ram test is a combination of a block-move (Bios ->
test area) followed by a block compare.
CJIlSg: db 13,10,"A20 error on entry",O
test ext mem proc
- - cl i
cld
al,Offh
21n,al
mov
out
pusha
push ds
push es
write cmos 30h,0 ;
write:cmos 31h(0 ;
xor al,a
out err-POrt,al
disable interrupts/execeptions
mask the 8259
save all the reggies
clear the r e ~ r t i n g cells
for ext mem size
; clear the error reporting cell
The Virt File D611
Note: Interesting point:
It takes the 8042 a discrete amount of time to actually enable the A20 address line after
this command is given. It is given in some publications as > 20 useconds. If the extended
mem tests cuase a system crash 'it may be because A20 has not switched yet, and < 1Mb ram
is getting trashed. See the delay routines in the wrap enable/disable functions.
@GI:
change_a20 active ; enable full range addressing <BG>
; Error numbers 51
6
,52,53 <BG>
; no carry says A2 OK jnc .F
mov ah,al
change_a20 inactive ;
mov al,ah
out err-POrt,al
pop es
pop ds
popa
mov
sti
ret
aX,0300h
40h
save nuar of "efI1)tyl that failed <8G>
<8G>
retrieve nuar of "8q)tyl that failed <8G>
mark A20 error, return to caller
; re-enable interrupts
; quick return when A20 error
push
pop
assl.me
ds
ds:segment_40
save return pointers in low ram
mov
mov
mov
mov
ax,ss
vsegment,ax
ax sp
voJfset,ax
save stack description in low ram
write_cmos restart_cell,2 ; set restart type 2
build a complete GOT table set
Once we do this, we can't do any interrupts, because the LIOT changes the interrput vector table
base. Since we set it up for exceptions, we won't be able to do video interrupts.
next:
build_descriptor cs,<offset GOT_data_start>
mov
mov
mov
19dt
lidt
mov
lmsw
delay
db
dw
dw
delay
mov
mov
ax,40h
eS,ax
es, word ptr es:[Oeh] get system seg
fword ptr es:psuedo_LGDT; point the gdt-reg to the block
fword ptr es:psuedo_LIOT lOT's are built
ax,virtual_enable
ax
Oeah
ax, offset move_ss
ss,ax
goto virtual mode
this jump to clear queue
jmp far ptr into cs: selector
to set access rights
Section D: The ASM ProlUams
D612 The Virt File
mov
mov
assune
start loc equ
end loc
ax, offset move gdt
ds,ax -
ds:gdt segment
OOfh -
equ Ofeh
- mov
mov
mem check:
dl,start loe start at 1 Mb - 64K
ds:move_es.bas_15_0,6 ; set es: segment = xxOOOO
- inc
c ~
jae
mov
dl
dl,end loe ; > 15 Mb bou1dary ?
mem exit
ds:move_es.bas_23_16,dl ; set es: segment
cld
mov
mov
sub
sub
mov
; make sure direct is forward
~ ~
sub
mov
ax,move_es
es,ax
di ,di
s i ,si
cX,8000h ; move 64k
this preloads the block
movs word ptr es:[dii,word ptr cs:[si]
di ,di
si,si
repe
jcxz
j ~
cX,8000h ; compare 64k
this does the actual test
crops word ptr cs:[sii,word ptr es:[di]
mem ok ; it's OK
mem_ok:
mem_exit:
sub
mov
xor
rep
j ~
mem:exit exit
di ,di
cX,BOOOh
ax,ax
stosw
mem_check
. ; now clear the block
clea.r 64K
check the next block
xor cI1,cfI
dec dl ; ~ dl down to last good segment
sub dx,start loc ; rejustify to "0000"
shl dx,6 - ; eX8q)le Z56K = 100h
; just return tested OK size - pod can display findings
wr1te_cmos 30h(dx ; write the cmos
GlGl:
xchg dh d
write_cmos 3ih,dx
change a20 inactive;
jnc - QF
mov ah,al
in al,err-POrt
or al,al
jnz GlF
mov al,ah
out errJlOrt,al
ifndef NO SHUTDOWN
~ t y numbers 71,72,73 <BG>
save number of tlemptY" that fai led <8G>
were there any previous errors ?
test for non-zero
no - set A20 exit error code to
number of fai led "emptY" <8G>
Shutdown may not work on some chipsets <8G>
; try causing a shutdown
lidt fword ptr cs:null idt
int 3 -
else
<BG>
endif
mov
out
hlt
test_ext_mem endp
al,restart command
status-POrt,al
; Use keyboard controller to reset if shutdown won't work
End of alternate reset code <8G>
stop the CPU to qui et the busses
; This is the real return from the ext mem test
restart2 proc
mov
mov
assune
mov
mov
mov
mov
pop
pop
GlGl:
f?OP8
1n
or
jnz
mov
sti
ret
aX,40h
ds,ax
ds: segment 40
ax,vsegment
ss,ax
ax,voffset
sp,ax
es
ds
al, err -port
al,al
QlF
ax,ok
A Type BiosKit
restore the original real stack
now pop the registers
iet returning error code
1f non-zero, return "error"
return(ok);
mov
sti
ret
restart2 endp
ax, error
; return(error);
; ________________________________________________________ e.
end
The Virt File D613
Section D: The ASM Pro&rams
Meetings I Should Call
The C Programs
These are the modules of the Bios which are in C. They include the Function Calls
and the Interrupt Service Routines.
The Kit.h File Ell
ONE
The Kit.h File
The Kit.h file is the 'c' header file used for all the Bios modules. The 'c' language
utilities used in the build process use normal .h files since they run from normal
Ram. Because the Bios is a prom-resident it has its own special
requirements in the use of the CPU's segment regIsters. Declarations to provide
interrupt routine support are also in this file. A special simplified interrupt sequence
is provided in order to save and restore registers when either calling interrupt
routines, or in defining a function to act as an interrupt routine. Because of these
features included in the bioskit.h file, interrupt service routines are written as
regular functions, with the machine register state being declared as unsigned integer
parameters on the stack.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: AT Bios h file of standard definitons
*
* Version: 1.02
*
* Author: FOSCO
*
* Date: 11-01-89
*
* Filename: atkit.h
*
* Language MSC 5.1
*
: Functional Description:
* This file is used for the standard header for bios 'C' programs. It is the only header file
: that should be #defined in the Bios modules. Other headers may contain conflicting definitions.
*
*
*
*
*
The Bios does not use any standard library for two main reasons:
1. The linker attempts to place library routines at the top of the segment,
which Rl.lSt contain some fixed code.
2. The standard libraries assume that the program is running under DOS (which is
not the case for Bios), and may make DOS references.
*
*
*
*
The file Biostop.asm contains the assembly-language functions required for the Bios.
* Version History:
* 1.01
: Font revi s i on - content t.n:hanged
* 1.02
* Defined casts for low ram variables
*
***************************************************************************************************/
unsigned peek(unsigned,unsigned);
unsigned peek40(unsigned)i
unsigned peekcs(unsigned)i
void poke(unsigned,unsigned,unsigned)i
void poke40(unsigned,unsigned);
unsigned char peekb(unsigned,unsigned)i
unsigned char peekb40(unsigned)i
unsigned char peekbcs(unsigned)i
unsigned peekcs(unsigned);
void pokeb(unsigned,unsigned,unsigned char);
void pokeb40(unsigned,unsigned char);
void beep(void);
void
void andb40(unslgned,unslgned char)i
void
void orb40(unslgned,unslgned char);
void xor40(unsigned,unsigned)i
El 2 The Kit.h File
void xorb40(unsigned,unsigned char);
unsigned inport(unsigned)i
unsigned char inportb(unslgned);
void
void outportb(unslgned,unslgned char);
unsigned bios cs(void):
void set vector(unsigned,unsigned,unsigned *):
void lbyfe(unsigned char):
void lword(unsigned):
void write string(unsiqned *):
void bios_Unsigned(unSlgned,unsigned *,unsigned *);
void outcmos(unsigned,unsigned char);
unsigned char incmos(unsigned);
unsigned acquire scratch block(unsigned,unsigned,unsigned,struct callers far *);
void release bloek(unsigned):
unsigned loni set timeout count(unsigned);
void snapshot in(Unsiqnedr, struct callers far *):
void snapshot:out(unslgned, struct callers far *):
#define true 1
#define false 0
#define yes true
#define no false
#define ok 0
#define error -1
#define at Oxfc
#define xt Oxfe
1* error codes may be 0001-ffff *1
1/ type byte definition
1/ type bYte definition
#define cr 13
#define If 10
#def i ne bspace 8
#define sys_seg_size 4096
#define BIT15 Ox8000
#define BIT14 Ox4000
#define BIT13 Ox2000
#define BIT12 Ox1000
#define BIT11 Ox0800
#define BIT10 Ox0400
#define BIT9 Ox0200
#define BIT8 Ox0100
#define BIT7 Ox0080
#define BIT6 Ox0040
#define BITS Ox0020
#define BIT4 Ox0010
#def i ne B I T3 Ox0008
#def i ne B I T2 Ox0004
#define BIT1 Ox0002
#define BITO Ox0001
II Define the watch bits
II size of the system segment
II These bits are also used by the block acquire/release
II function as the owners 10 codes. This is for future enhancements.
#define VIDEO BITO
#define VUE BIT1
#define CASSETTE BIT2
#def i ne EQU I PMENT B I T3
#define MEMORY BIT4
#define LPT BITS
#define COM BIT6
#define FLOPPY BIT7
#define HARD BIT8
#define TOO BIT9
#define BOOT BIT10
#define TIMER BIT11
#define KEYBOARD BIT12
#define PRSC BIT13
#define POO BIT14
1/ define the devices subject to watching - exclude some I
#define WATCH MASK CASSETTEIEOUIPMENTIMEMORYICOMIFLOPPYIHARDITOOIBOOT
#define carry-bit Ox0001
#define zero_Sit Ox0040
#define interrupt registers \
uns i gMa es, uns i gned ds, uns i gned d i, uns i gned s i , uns i gned l?P, uns i gned sp, \
uns i gned bx, uns i gned dx, uns i gned cx, uns i gned ax, uns i gned i p, uns i gned cs, uns i gned flags
A Type BiosKit
The Kit.h File El3
II This definition is the same as above except for the semi-colons in place of the commas.
II It is used for snapshots.
#define snap registers \
lI"'Isigned eS;lI"'ISigned ds; unsigned di; lI"'Isigned si;lI"'Isigned t?P; unsigned sPi \
lI"'Isigned bX;lI"'Isigned dx; lI"'Isigned cx; lI"'ISigned aX;lI"'Isigned ip; lI'lsigned cs; lI'lsigned
flags;
II This is the structure of the callers save registers on the stack
/1 after an into function entry
struct callers
{
uns i gned es;
uns i gned ds;
unsigned di;
unsigned si;
unsigned bpi
unsigned sp:
uns i gned bx:
uns i gned dx:
uns i gned cx:
uns i gned ax;
uns i gned i P:
uns i gned cs;
unsigned flags:
} ;
II This definition provides a siq)llfied means to set the interrupt vector to the service routine.
#define link_interrupt(level,name) set_vector(level,bios_cs(),name)
//--------------------------------------------------------------------------------------------------
#define variables typedef struct {\
lI"'Isigned length tag: \
unsigned user ia:\
unsigned ax:\-
lI"'IS i gned cx; \
unsigned dx:\
lI"'Isigned si;\
lI"'ISigned di:\
lI"'Isigned bp:\
unsigned bx: /* this is so we can do LDS ax *1 \
unsigned ds:\
unsigned es:\
unsigned flags;\
uns!gned Jq)_off;\
unslgned J ~ seg:\
unsigned coOe_string[18]i 1* reserved for code string *1 \
#define end_variables lI"'ISigned char size; }
II This definition sizes the block acquire to include the variables specified
II in the variable declaration
#define acquire block(id) acquire scratch block(id, \
(&myblock->size-- &myblock->lengtn tag) +-\
(16-&myblock->size - &myblock->lingth_tag) X 16)
11---------------------------------------------------- --
II definitions of variables in data segment segment 40h
#clef ne VECTOR(nr) (*lI"'ISigned long far *)
#def ne VECTOR 00 (*lI"'ISigned long far *)
#def ne VECTOR-OO OFFSET (*lI"'ISigned far *)
#def ne VECTOR:OO:SEGMENT (*lI"'Isigned far *)
#clef ne VECTOR 00 (*lI"'ISigned long far *)
#clef ne VECTOR-OO OFFSET (*lI"'ISigned far *)
#clef ne VECTOR:OO:SEGMENT (*lI"'ISigned far *)
#def ne VECTOR 00 (*l6Isigned long far *)
#def ne VECTOR-OO OFFSET (*lI"'ISigned far *)
#def ne VECTOR:OO:SEGMENT (*lI"'ISigned far *)
#clef ne VECTOR 13 (*l6Isigned long far *)
#clef ne VECTOR-13 OFFSET (*lI"'ISigned far *)
#clef ne VECTOR:13:SEGMENT (*lI"'ISigned far *)
#def ne VECTOR 40 (*unsigned long far *)
#def ne VECTOR-40 OFFSET (*l6Isigned far *)
#def ne VECTOR:40:SEGMENT (*unsigned far *)
4 * nr
OxOOOO
OxOOOO
OxOOOO
Ox004c
Ox0100
OxOOOO
Ox0002
OxOOOO
Ox0002
OxOOOO
Ox0002
Ox004c
Ox004e
Ox0100
Ox0102
Section E: The C Pro&rams
El4 The Kit.h File
#define SYSTEM SEGMENT PTR (*unsigned far *) Ox40e
#define SWITCH-BYTE (*t(unsigned char far *) Ox410
#define EQUIP 1LAG (*unsi9ned far *) Ox410
#define MEMORY SIZE (*unslgned far *) Ox413
#define KB FLAn (*unsigned char far *) Ox417
#define KB-FLAG 1 (*unsigned char far *) Ox418
#define ALT INPUT (*unsigned char far *) Ox419
#define BUF'ER HEAD (*unsigned far *) Ox41a
#define BUFFER-TAIL (*unsigned far *) Ox41c
#define KB BUF1ER (*unsigned far *) Ox41e
#define SEK STATUS (*unsi9ned char far *) Ox43e
#define MOTel STATUS (*unSlgned char far *) Ox43f
#define MOTOR-COUNT (*unsigned char far *) Ox440
#define DISK !TATUS (*unsigned char far *) Ox441
#define CRT RODE (*unsigned char far *) Ox449
#define CRT-COLS (*unsigned far *) Ox44a
#define CRT-LENGTH (*unsigned far *) Ox44c
#define CRT-START (*unsigned far *) Ox44e
#define CUR!OR POSN (*unsigned far *) Ox450
#define CURSOR-NOOE (*unsigned far *) Ox460
#define ACTIVE-PAGE (*unsigned char far *) Ox462
#define ADOR 6845 (*unsigned far *) Ox463
#define CRT AooE SET (*unsigned char far *) Ox465
#define CRT-PALL!TTE (*unsigned char far *) Ox466
#define V 01FSET far *) Ox467
#define V-SEGMENT (*unSlgned far *) Ox469
#define V-FLAG (*unsigned char far *) Ox46b
#define TTMER LOW far *) Ox46c
#define TIMER-HIGH (*unSlgned far *). Ox46e
#define TIMER-LONG (*unsigned long far *) Ox46c
#define TIMER-LONG MAX Ox1800bO f* 24 hour count *f
#define TIMER-OFL char far *) Ox470
#define BIOS IREAK (*unstgned char far *) Ox471
#define RESET FLAG (*unsigned far *) Ox472
#define HO (*unsigned char far *) Ox474
#define HO-NUN (*unsigned char far *) Ox475
#define HO-CONTROL (*(Cunsigned char far *) Ox476
#define LPT TIMEOUT LIST char far *) Ox478
#define cOMR TIMEOUT LIST (*unstgned char far *) Ox47c
#define BUFF!R START-(*(Cunsigned far *) Ox480
#define BUFFER-eNO (*unsigned far *) Ox482
#define ROWS C-unsigned char far *) Ox484
#define POINTS (*unsigned far *) Ox485
#define INFO (*unsigned char far *) Ox487
#define INFO 3 (*(Cunsigned char far *) Ox488
#define HO STATUS (*unsigned char far *) Ox48c
#define HO-ERROR C*CCunsigned char far *) Ox48d
#define HO-INT FLAG (*unsigned char far *) Ox48e
#define HF-CNTIL (*unsigned char far *) Ox48f
/* 490-493-are floppy disk drive and media type bytes */
/* 494-497 are floppy disk drive current track positions */
/* kb flags 2 and 3 must be re-located if using more than 2 floppy drives */
#define KB FLAG 3 (*unsigned char far *) Ox496 .
#define KB-FLAG-2 (*C(unsigned char far *) Ox497
#define USR (*C(unsigned far *) Ox498
#define USER-FLAG SEG (*(Cunsigned far *) Ox49a
#define RTC (OW far *) Ox49c
#define RTe-HIGH (*unstgned far *) Ox4ge
#define RTC-WAIT FLAG (*unsigned char far *) Ox4AO
#define BUSY (*unsigned char far *) Ox500
#define aooT:AREA (*C(unsigned char far *) Ox7cOO
f*=====================.== end of bfoskft.h ==================================*/
A-Type BiosKit
The Mise File E21
TWO
The Mise File
The Misc.c file contains functions which are used by various modules. Many of the
functions used by the Setup and Watch commands in Sysvue reside in this file. The
register snapshot routines are in here, as well as most of the support functions for
the 8042 keyboard controller chip.
1***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: AT Bios misc. functions
*
* Version: 1.02
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: atmisc.c
*
* Language: MS C 5.1
*
* Functional Description:
* This module includes miscellaneous functions used by vadous modules.
*
* Arguments:
*
* Return:
*
* Version History:
* 1.01
* Changed the IIcurrent video" peekb40 from Ox13 (mem size) to Ox10 (switch byte)
* 1.02
: Added 8253 timer-based timeout support
***************************************************************************************************1
1* INC L U D E F I L E S *1
#include lIatkit.h"
1* FUN C T ION PRO TOT Y PES */
void eoi_sequence();
extern unsigned char type byte;
extern unsigned char dec irray[6];
extern const unsigned chir hdlSk table;
void pause(void); -
unsigned get video(void);
unsigned sena 8042(unsigned);
unsigned sena-8042 data(unsigned);
unsigned wait-to rx 8042(void);
unsigned wait:to:send_8042(voio)i
1* L 0 CAL CON S TAN T S */
1/ these are the text words for the setup program
const display list[] =
( -
II EGA"
"CGA to x 25"
"CGA 80 x 25";
IIMonochrome",
}i
1* PRO G RAM S *1
1*=========== Send EOI to Interrupt Controller ==========*/
void eoi_sequence() { outportb(Ox20,Ox20)i }
1*======== Dump hex word on Console ==============*/
E 22 The Mise File
void lword(w) {lbyte(w 8)i lbyte(w)i}
1*======== Dump hex byte on Console ==============*1
void lbyte(outchar)
{
}
unsigned char c;
c = (outchar 4) & OxOfi
if (c > 9) c+= 7;
co(c + '0');
c = outchar & OxOf;
if (c > 9) c+= 7;
co(c + '0');
1*======== Check for 0-9, a-f, A-F character =====*1
unsigned ishex(c) 1* returns true or false *1
{
}
if c >= '0') && (c <= '9' return (true);
if c >= 'a') && (c <= 'f' return (true);
if c >= 'A') && (c <= 'F' return (true);
return(false)i
1*======== Check for a-z character ==============*1
unsigned islower(c) 1* returns true or false *1
{
}
if c >= 'a') && (c <= 'Z/ return (true)i
return(false)i
1*======== Check for a-z, A-Z character =======*1
unsigned isalpha(c) 1* returns true or false *1
{
}
if c >= 'a') && (c <= 'Z' return (true);
if c >= 'A') && (c <= 'Z' return (true);
return(false);
1*======== Write String on Console ==============*1
void write string(loc)
{ -
while (peekb(bios cs(),loc) != 0) ( co(peekb(bios_cs(),loc++i )
} -
1*======== Set Interrupt Vector =============*1
void set vector(int number,seg,off)
( - -
}
disableC);
poke(OxOO,int number * 4 off)
poke(OxOO,(int_number * ~ ) + ~ , s e g ) ;
enableC);
1*======== Read CMOS Ram ============*1
unsigned char incmos(unsigned address)
(
outportb(Ox70,address I Ox80); return(inportb(Ox71;
}
1*======== Write CMOS Ram ============*1
void outcmos(unsigned address,unsigned char value)
(
outportb(Ox70,address I OxSO); outportb(Ox71,value);
}
1*======= return true if (type == ar9) =======*1
/I If you wish to dynamically deternl1ne the kind of machine, then these functions will check
II the type byte.
/I To determine CPU type, expand this f\J'lCtion with CPU testing.
II check for motherboard type
unsigned type(unsigned int arg)
(
ifarg == at) II (arg == xt
(
if arg == xt) && (peekbcs(&type_byte) == xt\
return(true);
if arg == at) && (peekbcs(&type_byte) == at\
return(true);
A-lYRe BiosKit
}
ifarg == 86) I I (arg == 186) II
(arg == 286) II (arg == 38611 check for cpu type
(
return(false);
}
return(false);
}
11=========================================================
#define swapped 1 II in myblock->status, this tells if stack is swapped
extern unsigned start block;
extern unsigned current open;
extern unsigned end block;
extern unsigned watCh_flag;
variables
end_variables pool regs;
1/ block size is passed as nunber of bytes needed.
unsigned acquire scratch block(unsigned id,unsigned block_size)
( --
poolregs *block-ptr;
setds system segment();
disabTe(); -
if current open + block size) < end_block)
( - -
}
II this open space is allocatable
blocK-ptr = current
current open += block size
blocK-ptr -> length tig = block size;
blocK-ptr -> user_ia = id; -
enable();
ifid & (watch flag & (WATCH MASK) 1= 0)
( - -
write string("\n\rAcquire Block II); lword(blocKJ)tr);
if(ia== FLOPPY) write string(1I Floppyll);
if(id == HARD) write string(" DisK");
if(id == BOOT) write-string(" Boot");
if( id == CASSETTE) write string(" Cass
ll
);
if(id == EQUIPMENT) writi string(" Equi");
if(id == MEMORY) write string(" Mem
ll
);
if( id == LPT) write string(" Lpt");
if(id == CC1) write-string(" CornU);
if(id == TOD) write-string(" Tod")
if(id == KEYBOARD) write string(" Kb
ll
);
} -
return(blocK-ptr);
II acquire the start block so we can flag system error
current = start blocK
sys errtOx1111); II this is an arbitrary code
ena6leO;
return(current open); II this is an error condition
} -
void release block(poolregs *block ntr)
(_ ...r
->user_id & WATCH_MASK) & watch_flag 1= 0)
write string("\n\rRelease Block II); lword(blocKJ)tr);
if(blOcKjptr -> user id == FLOPPY)
write strlng(" Floppy")
if(blOcKJ)tr -> user id'== HARD) write string(" DisK");
if(blocKJ)tr -> user-id == BOOT) write-string(" Boot");
if(blocKjptr -> user-id == CASSETTE) -
write strlng(" Cass"J
if(blOcK-ptr -> user td == EQUIPMENT)
write string(" EquillJ.
if(blOcKJ)tr -> user td == MEMORY) write string(" Mem
ll
);
if(blocKJ)tr -> user-id == LPT) write string(" Lpt");
if(blocKJ)tr -> user-id == CC1) write-string(" Com");
if(blockJ)tr -> user-id == TOD) write-string(" Tod");
if(blocKJ)tr -> user:id == KEYBOARD) write_string(1I Kb
ll
);
The Mise File E23
}
disable();
II If you wish to zero out the released blocK, then a clear blocK function could be 'created here.
Section E: The C Pro&rams
)
E 24 The Mise File
II clear_block(block-ptr,blocK-ptr .> length_tag);
blocK-ptr .> length tag = 0;
current open = blocK-ptr;
enable(J';
11-_- register snapshots . _ . -._--.--
/I this will execute if the "watch
lt
bit for the specified device is set
void snapshot in(unsigned device, struct callers far * frame)
( -
)
if(watch(device
(
write string("\n\rax="); lword(frame->ax);
write-string(" bx=It); lword(frame->bx);
write-string(" cx=") lword(frame->cx);
write-string(" lword(frame->dx)i
wri te-string(" Sp=II) lword(frame>sp);
write-string(" bt?="): lword(frame->bj?)"
write-string(" Si=II)! lword(frame->si)!
write:string(" di="); lword(frame->di);
write string(lI\n\rds="); lword(frame->ds);
write-string(" es="); lword(frame->es)i
write-string(" ss="); lword(&frame->es + 1); /I this = old ss
write-string(" cs="); lword(frame->cs);
wr!te:str!ng(" ip=II); lword(frame->ip);
wrlte strlng(" II).
if(device == FLoppy)'write string(" FLOPPY II);
if(device == HARD) write st'ring(" DISK II);
if(device == BOOT) write-string(" BOOT II);
if(device == CASSETTE) write string(" CASS II);
if(device == EQUIPMENT) write string(" EQUI II);
if(device == MEMORY) write string(" MEM II);
if(device == LPT) write string(1I LPT II);
if(device == COM) write-string(" COM II);
if(device == TOO) write-string(It TOO II);
if(device == KEYBOARD) write string(It KB It);
) -
void snapshot out(unsigned device,struct callers far *frame)
( -
)
if(watch(device
(
write string(It\n\rax="); lword(frame->ax);
write-string(It bx="); lword(frame->bx);
write-string(It cx="); lword(frame->cx);
wri te-stri{'lg(It dx=") lword(frame->dx)
write-string(It Sp=II)! lword(frame>sp)!
write-string(" bt:>=")! lword(frame->bj?)!
write-string(It si=")! lword(frame->si)!
write:string(" di="); lword(frame->di);
write string("\n\rds=II); lword(frame->ds);
write-string(" es=") lword(frame->es)"
write-string(" ss="); lword(&frame->es'+ 1>;
write-string(" cs=") lword(frame->cs)"
write-string(" ip=It)! lword(frame->ip)!
write-string(" lword(frame->hags & Ox01>;
) -
void watch string(unsigned device,unsigned msg)
( -
if(watch(device write string(ms9)i
) -
void watch word(unsigned device, unsigned msg)
( -
if(watch(device lword(msg)i
) .
void watch byte(unsigned device, unsigned msg)
( -
if(watch(device lbyte(msg);
)
void watch char(unsigned device, unsigned msg)
( -
if(watch(device co(msg);
)
11==================================================
A-Type BiosKit
II these will execute only in the cold-boot condition
II they will not execute for wanm-boot
void cold string(unsigned msg)
( -
if(cold( write string(msg);
} -
void cold word(unsigned msg)
( -
if(cold( lword(msg);
}
void cold byte(unsigned msg)
( -
if(cold( lbyte(msg);
}
void cold char(unsigned msg)
( -
if(cold( co(msg);
}
11============ set the timer counter on boot up ============
#define seconds 0
#define minutes 2
#def i ne hours 4
#define counts sec 18
#define counts-min 1092
#define counts:hr 60 * counts_min
uns i gned long llllJ l (uns i gned long, uns i gned) ;
unsigned convert_binary(unsigned char);
unsigned set count(void)
{ -
}
unsigned char temp;
unsigned long count, long_temp;
if temp = incmos(hours > Ox23) return(error);
long_temp = convert_binary(temp);
count = llllJl(long_temp,counts_hr)i
if temp = incmos(minutes > Ox59) return(error)i
long_temp = convert_binary(temp)(
count += lmul(long_temp,counts_mln)i
if temp = incmos(seconds > Ox59) return(error);
long_temp = convert_binary(temp);
count +=lmul(long_temp,counts_sec);
TIMER LONG = count;
retur;;(ok);
1*===================================================
Return the drive type for a specified drive.
drive 00-03 = floppy
drive 80-81 = hard
----------------------------------------------------*1
unsigned char cmos drive type(unsigned char drive nr)
( - - -
switch(drive nr)
( -
case 0: return(incmos(Ox10) 4):
case 1: return(incmos(Ox10) & OxOf);
case 2: return(incmos(Ox11) 4):
case 3: return(incmos(Ox11) & OxOf);
case Ox80:
ifincmos(Ox12) 4) == 15) return(incmos(Ox19;
return(incmos(Ox12) 4);
case Ox81:
ifincmos(Ox12) & 15) == 15) return(incmos(Ox1a;
return(incmos(Ox12) & OxOf);
}
returneO);
}
11========== return the cmos system memory size =====
The Mise File E-2-S
Section E: The C ProlUams
E26 The Mise File
unsigned cmos mem()
{ -
}
uns i gned teq');
temp = incmos(Ox16);
temp = 8;
temp 1= incmos(Ox15);

11========== return the cmos extended memory size =====
unsigned cmos ext()
{ -
}
unsigned
temp = incmos(Ox18);
temp = 8;
temp 1= incmos(Ox17);
return( ;
1/==== return the cmos extended found memory size =====
unsigned cmos ext found()
{ - -
}
uns i gned teq')i
temp = incmos(Ox31);
temp = temp 8;
temp 1= incmos(0x30)i

// ---- display the time -----------
variables
end_variables timevars;
void display time(void)
{ -
timevars *myblock;
myblock = acqui re block(VUE);
myblock ->ax = Ox0200;
sys int(Ox1a,myblock)
co({(myblock->cx & OxOf) I '0');
co(myblock->cx 8) & OxOf) 1 '0');
co(':')
4) & OxOf) I '0');
co(myblock->cx ) & OxOf) '0');
co(':')
12) & OxOf) I '0');
co(myblock->dx 8) & OxOf) I '0');
}
// ---- display the date -----------
variables
end_variables datevars;
void display date(void)
{ -
datevars *myblock;
myblock = acquire block(VUE);
myblock ->ax = OX0400i
sys_int(Ox1a,myblock)i
}
co(myblock->dx 12) & OxOf) I '0');
co(myblock->dx 8) & OxOf) I '0');
co('/')
4) & OxOf) I '0');
co(myblock->dx ) & OxOf) '0');
co(' /').
cO(mYblock->cx 12) & OxOf) I '0');
co(myblock->cx 8) & OxOf) I '0');
co(myblock->cx 4) & OxOf) '0');
co(myblock->cx ) & OxOf) '0');
// this is the text list for the floppy drive types
const drive list[] =
{ -
"No Drive",
"360k",
"1.2MII,
"nOk",
"1.44M
II
,
"Unknown", /* "2.88M could go here if ill1llemented */
"Unknown",
A Type BiosKit
"Unknown
ll
,
};
11------- display the disk drive configuration ------
void display drives(void)
( -
unsigned next hard = 'C';
II the letter-code of the next hard drive
II find the number of floppy drives
ifincmos(Ox14) & Ox01) 1= 0)
{
}
if (cmos drive type(O) 1= 0)
( - -
write string("\n\r Drive A: II).
}write:string(peek(biOS_CS(),&driVe_l1sttcmos_drive_type(0)];
if(incmos(Ox14) 6) & Ox03) > 0)
{
}
if (cmos drive type(1) 1= 0)
( - -
write string("\n\r Drive B: II).
}write:string(peek(biOS_CS(),&drive_lfsttcmos_drive_type(1)];
if(incmos(Ox14) 6) & Ox03) > 1)
{
}
if (cmos drive type(2) != 0)
( - -
write string("\n\r Drive C: II).
write-string(peek(bios cs(),&drive l1sttcmos drive type(2)];
} - - - --
if(incmos(Ox14) 6) & Ox03) > 2)
{
}
if (cmos drive type(3) 1= 0)
( - -
write string("\n\r Drive D: II).
}write:string(peek(biOS_CS(),&driVe_l1sttcmos_drive_type(3)]));
The Mise File E2 7
II The letters used for the disk drives can change depending on the number of floppy drives in the
II system. Find the number of floppy drives
}
ifincmos(Ox14) & Ox01) 1= 0)
(
if(incmos(Ox14) 6) & Ox03) > 1) next hard++;
if(incmos(Ox14) 6) & Ox03) > 2)
} -
if (cmos_drive_type(OxSO) 1= 0)
(
write string("\nV Drive II); co(next_hard);
write:string(": Type II);
II this should be printed in decimal II
lbyte(cmos drive type(OxSO;
} --
if (cmos_drive_type(Ox81) 1= 0)
(
write string("\n\r Drive II); co(next_hard+1);
write:string(": Type II);
1/ this should be printed in decimal II
lbyte(cmos drive type(Ox81;
} --
1*--------- display video type ------------*1
void display video(void)
( -
write string("\n\r Default Video: II);
write:string(peek(bios_cs(),&display_listCget_video()];
wrHe string("\n\rExpected Video: II);
write:string(peek(bios_cs(),&display_listC(incmos(Ox14) 4) & Ox03];
write_string("\n\r Current Video: II);
Section E: The C ProlUams
E28 The Mise File
/*--------- calculate cmos checksum -------------*/
unsigned calc cmos(void)
( -
}
unsigned j,x sum = 0;
x = (incmos(6x2e) 8) I incmos(Ox2f)i
for(j=Ox10ij<=Ox2d;j++) sum += incmos(J):
8);
outcmos(Ox2f,sum);
return(x);
/*----------- display sys mem size -----------*/
display sys mem()
( --
bin2dec(cmos mem(),&dec array);
co(dec arraylO]); -
co(dec-array[1]);
co(dec-array[2]);
co(dec-array[3]):
co(dec-array[4]);
} -
/*----------- display ext mem size -----------*/
display ext mem()
( --
bin2dec(cmos ext(),&dec array);
co(dec arraylO]): -
co(dec-array[1]);
co(dec-array[2]):
co(dec-array[3]):
co(dec-array[4]);
} -
/*----------- set sys mem size -----------*/
set sys mem(unsigned sys size)
( - - -
outcmos(Ox15,sys size);
outcmos(Ox16,sys:size 8);
calc cmos 0 ;
} -
/*----------- set ext mem size -----------*/
set ext mem(unsigned ext size)
( - - -
outcmos(Ox17,ext size);
outcmos(Ox18,ext:size 8);
calc cmosO;
} -
/*== return the number of floppy drives in the system ==*/
unsigned number of floppies(void)
( - -
}
if incmos(Ox14) & Ox01) == 0) return(O):
returnincmos(Ox14) 6) + 1);
/*==== display hard disk table parameters ====*/
void display hdisk types(void)
( --
unsiened qq,jk cyls,heads,sectors approx size:
// llSt the ta6le entries, calc approximate disk size
// use the sectors/track to accomodate the RLL drives
/I format is:
// type, cyls, heads, sectors, size
write_string(ItType Cyl inders Heads Sectors Size\n\rlt):
jk = 0: qq=1
while(peek(btos cs(),jk+&hdisk table) 1= -1)
( - -
// display drive type
bin2dec(qq,&dec array):
co(dec array[2]1;
co(dec:array[3]):

wrlte_strlng(11 II):
A-Type BiosKit
II display cylinders
cyls = peek(bios_cs(),jk+&hdisk_table);
bln2dec(cyls,&dec_array);
co(dec array[O]);
co(dec-array[1]);
co(dec-array[2]);
co(dec-array[3]);
co(dec-array[4]);
wrHe_itring(1I II);
/I display heads
heads = peekb(bios cs(),jk+2+&hdisk table);
bin2dec(headS
6
&dec:array); -
co(dec array[ ]);
co(dec-array[1]);
co(dec-array[2]);
co(dec-array[3]);
co(dec:array[4]);
write_string(1I II);
/1 display sectors
sectors = peekb(bios csO,jk+14+&hdisk table);
bin2dec(sectors,&dec-array); -
co(dec array[O]); -
co(dec-array[1]);
co(dec-array[2]);
co(dec-array[3]);
co(dec:array[4]);
write_string(1I II);
II display size (cyls*heads*sectors) in Mbytes
approx_size = calc_hdisk_size(cyls,heads,sectors);
bin2dec(approx size,&dec array);
co(dec_array[Or); -
co(dec_array[1]);
co(dec array[2]);
co(dec-array[3]);
co(dec:array[4])i
write_string(lI\n\r");
~ + .
JK =' jk + 16 1/ look to next table entry
ifqq & Ox060f) == 0)
(
pause()i
write string("Type Cylinders Heads Sectors Size\n\r");
} -
}
}
1*---------- pause and wait for key ---------*/
void pause(void)
{
while(kbhit({ci()i}; /1 get any ~ i n g keys
write string(" ---- hit any key for more ----\n\r")i
while{lkbhit({};
}
1*--------- display NPX status -----------*/
void display npx(void)
( -
write string("Exp4]!Cted: II).
ifincmos(Ox14) & Ox02) = ~ 0)
(
write string(INo")
} - ,
else
(
write string(IIYes
ll
).
} - ,
write string(" FoU'ld: II).
ifSOITCH BYTE & Ox02) == 6)
( -
write string("No")
} - ,
else
(
write string(IIYes
ll
).
} - ,
The Mise File E29
Section E: The C ProlUams
E210 The Mise File
}
11-------- return a long timeout count -----------
II - returns a long TIMER LONG + count( corrects for 24 hour rollover
II - if rollover near, then delay unti rollover, then return count
unsigned long get current timer(void)
( --
return(TIMER LONG);
} -
unsigned long set timeout count(l.I1signed COU'lt)
( --
whileget_current_t!mer() + count) > TIMER_LONG_MAX);
return(get current tlmer() + count);
} - -
11---------- keyboard controller support -------
/*=================================================1
The 8042 keyboard controller uses ports Ox60 and Ox64.
Ox60 = data in and out
Ox64 = status in.
The status bits are:
Bit Description
7 Parity error 0 = odd (no error), 1 = even
6 rx timeout 1 = error
5 tx timeout 1 = error
4 inhibit 0/1 = inhibit/not inhibited
3 datalcommand port 60 = datalcommand
2 system flag 0= powerup, 1= reset
1 inp bfr full 0/1 = empty/full
o out bfr full 0/1 = empty/full
8042 commands (to port 64):
Ox60 write next byte (Ox64) to controller: (use Ox4S)
Bit Description
7 always 0
6 1 = PC mode
5 1 = PC moc:Ie
4 1 = disable keyboard
3 1 = inhibit override
2 0 = reset system flag
1 always 0
o 1 = enable out bfr full into (IRQ1)
Oxaa self test 8042
returns Ox55 in out bfr (Ox6O) if OK .
xOcO read 8042 port into out bfr (Ox60)
bit Description of input port
7 0/1 = keylock switch locked/not locked
6 0/1 = CGA/MOA vidoe
5 0/1 Mfg Jumper present/absent
4 0/1 system ram = 512/256 K
Oxd1 write next byte (Ox64) to controller
bit Description
7 kb data out line
6 kb clock out line
1 Gate A20
o 1 = reset system
/==================================================*1
11------- reset the 8042
unsigned reset 8042()
( -
unsigned stat = ok;
/1 mask out interrupts in case they are still enabled
outportb(Ox21inportb(Ox21) I Ox02);
II purge the 0042's output bUffer
inportb(Ox60)
1/ reset the A042
if(wait to send 8042() == error) stat = error;
== error) stat = error;
if(wait-to rx 8042() == error) stat = error;
if(inportbtOx!O) != Ox55) stat = error;
/1 configure 8042
if(wait to send 8042() == error) stat = error;
== error) stat = error;
A Type BiosKit
}
outportb(Ox60,Ox45);
outportb(Ox21,inportb(Ox21) & -Ox02);
return(stat)i
//----- this gets the video jumper byte from the 8042 ----
// returns 2 = CGA, 3 = MDA
unsigned get video()
( -
}
unsigned t ~ = OJ
outportb(Ox21
L
inportb(Ox21) I Ox02);
wait to send o042();
senc:r8Q7;2(OxCO)i /I read the jumper conmand
wait-to rx 8042();
temp-= TnpOrtb(Ox60)"
outportb(Ox21,inportb(Ox21) & -Ox02)i
if temp & Ox40) == 0) return(2)i
// return CGA index value, else
return(3)i // return MDA index value
1/---- wait until 8042 ready to accept another byte ----
unsigned wait to send 8042()
{ - - -
unsigned long jj = set_timeout_count(20)i // 1 second delay
The Mise File E-2-11
do ( ifinportb(Ox64) & Ox02) == 0) return(ok); } while (TIMER_LONG < jj);
return(error);
}
1/--- wait for 8042 output buffer to be loaded ----
unsigned wait to rx 8042()
( - - -
unsigned long jj = set_timeout_count(20); /1 1 second delay
do ( ifinportb(Ox64) & Ox01) != 0) return(ok)i } while (TIMER_LONG < jj);
return(error);
}
11--- send a conmand and wait until accepted ---
unsigned send 8042(value)
( -
outportb(Ox64,value); return(wait to send 8042(i
} - - -
11--- check buffer ready and send data
unsigned send 8042 data(value)
{ --
unsigned trys = 10;
while (trys-- > 0)
(
if(wait to send 8042() == ok) { outportb(Ox60,value)i return(ok)i }
} - - -
return(error);
}
Section E: The C Pro&rams
Things Worth Making A Note Of
The Pod File E31
THREE
The Pod File
The Pod.c (Power On Diagnostics )file contains power-up diagnostics and initializing
routines. This file inits some of the peripherals and also calls the setups for most of
the other function calls. A general convention to develop (it has been implemented
for some cases) is to examine the status returned from a function call setup routine.
to determine the degree of success in initializing a device (such as video, disk,
keyboard, etc.) This returned status can then be used to display' an enhanced
message during the POD.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988 - All Rights Reserved
: Module Name: AT bios power on diagnostics
* Version: 1.01
*
* Author: FOSCO
*
* Date: 12-31-88
*
: Filename: biospod.c
* Language: MS C 5.1
*
: Functional Description:
* This module does the power on diagnostics and initialization. When it finishes, it does
: a bootstrap to load the system.
* Argunents:
*
* Return:
*
* Version History:
: Added NMI disable bit to the read_swtiches function.
***************************************************************************************************/
/* INC L U D E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
void biospod(void);
unsigned comm setup(void);
unsigned lpt setup(void);
void biospOdfvoid);
unsigned xchg(unsigned,unsigned,unsigned);
unsigned ram test(unsigned segment,unsigned length);
void move system segment(unsigned,unsigned);
unsigned Char reid switches(void);
unsigned rom checkfunsigned);
void cout(unsigned char);
unsigned checksum(unsigned,unsigned,unsigned);
unsigned cold(void)i
/* G LOB A L V A R I A B L E S */
extern unsigned start block;
extern unsigned current open;
extern unsigned end block;
extern unsigned blOCk beg;
extern unsigned block:end;
variables
end_variables podregs;
/* G LOB A L CON S TAN T S */
extern Siret;
E32 The Pod File
extern isr;
extern divide;
extern bios id;
extern date-stamp;
extern bios:start;
1* L 0 CAL D E FIN I T ION S *1
#define b Ox61
#define default equip OxOO6d
#define boot retrys 6
#define dna OxOO
#define inta01 Ox21
#define timer controlJ)Ort Ox43
#define timer-counter-o-POrt Ox40
#define timer-counter-2-POrt Ox42
#define port 5 Ox61 -
#define cr - 13
#define escape 27
#define carry_bit Ox0001
1* PRO G RAM *1
II Biostop module already has found 64k of ram to operate with.
void biospod(void)
{
podregs *myblock;
unsigned ext mem size = 0;
uns i gned duIiiiy, -
rom scan end, 1* end segment value for rom scan *1
i,r; -
cs, 1* save for code segment value *1
error code; 1* temp save for returned error codes *1
uns i gfied cnar checksun;
unsigned video status; II returned from video setup
equipment_status; II returned from equip setup
cs = bl0S_CS()i
1* use top of 1st 64k for system segment *1
SYSTEM_SEGMENT_PTR = Ox1000(sys_seg_size 4);
1* set pool delimiters *1
setds system segment();
= current open = &block beg;
end_bTock = &block_ena; -
1* set the equipment switch flag *1
SWITCH_BYTE = read_switches()i
1* load default interrupt vectors */'
for(i=0,j=0;i<31;i++,j+=4)
{
poke(OxOOOO,j,&Siret); /* load software defaults */
1* override hardware defaults */
}
if i >= 8) && (i <= 16 poke(OxOOOO,j,&Sdummy isr);
poke(OxOOOO,j+2,cs); -
/* load default interrupt vectors for 8259 #2 */
for(i=0,j=Ox70*4;i<8;i++,j+=4)
{
}
poke(OxOOOO,i,&Sdummy isr);
poke(OxOOOO,J+2,cs); -
/* div by zero */
poke(OxOOOO,OxOOOO,&divide);
/* .. setup the 8255 if one exists .. */
outportb(Ox63,Ox99) /* set the control register */
outportb(port_b,Ox76)i /* disable the parity checkers */
1* setup the dma controllers ... _ .. _*/
#define DNA1 OxOO
#def i ne DNA2 OxcO
outportb(DMA1+8 Ox04); // disable dma #1
outportb(DMA2+1&,Ox04); // disable dma #2
outportb(DMA1+13,OxOO); // master clear
outportb(DMA2+26,OxOO);
A-Type BiosKit
outportb(DMA1+8 OxOO); // now do dma setup
outportb(DMA2+1A,OxOO);
outportb(DMA1+11,Ox40); // set the channel defaults
outportb(DMA2+22,OxcO);
outportb(DMA1+11,Ox41);
outportb(DMA2+22,Ox41);
outportb(DMA1+11,Ox42);
outportb(DMA2+22,Ox42);
outportb(DMA1+11,Ox43);
outportb(DMA2+22,Ox43);
outportb(DMA2+20,OxOO); // enable cascade of chI 0
/*------- setup the 8259 interrupt controller -------*/
outportb(Ox20,Ox11); // icw1
outportb(Ox21,Ox08); // icw2
outportb(Ox21,Ox04); // icw3
outportb(Ox21,Ox01)i // icw4
outportb(Ox21,Oxff); // disable all interrupts
outportb(OxaO,Ox11); // icw1
outportb(Oxa1,Ox70); // icw2
outportb(Oxa1,Ox02); // icw3
outportb(Oxa1,Ox01)i // icw4
outportb(Oxa1,Oxff); // disable all interrupts
/* allow any stray interrupts to be reset */
enableO;
/*------- setup adapters and peripherals ------------*/
equipment status=equipment setup();
video_status=video_setup();
write string("\n\r
ll
);
write-string(&bios id);
write:string(&date:stamp);
The Pod File E-3-3
// If a restart sequence is generated which we do not recognize, we abort to a regular re-boot,
// and display the unknown restart code.
if(incmos(OxOf) != 0) // invalid restart code
(
write string("\n\rlnvalid Restart Code -");lbyte(incmos(OxOf;
} -
cold string("\n\rBios at "); cold word(bios cs(;
colastring("\n\rLow 641C Ram Test 11); - -
if(peek(OxOO,Ox412) == 0) // check low-ram error flag
(
cold_string(IIOIC
II
);
}
else
(
cold_string(IIErro,.II);
}
cold string("\n\rVideo FU'1Ction ");
colastring(IIQlCII).
colastring("\n\rEquipment FU'1Ction 11);
colastring(IIQICII);
colastring(lI\n\rlCeyboard FliM:t i on 11);
if(kiyboard setup() == ok)
( -
cold_string(IIQlCII);
}
else
(
cold_stri ng(IIErrorl');
}
enableO
c
cold strlng("\n\rSysVue 11); sysvue_setupO;
colastring(IIQlCII);
colastring("\n\rMemory Size Function "); mem_size_setupOi
colastring("OICII)i
colastring("\n\rTimer Function "); timer setupO;
colastring(IIQlCII). -
colastring(lI\n\rTime of Day Function
II
); time of day setupO;
if(sit count() == ok) // set the timer counter- - -
( -
cold_string(1I01C
1I
);
}
else
{
Section E: The C ProlUams
E34 The Pod File
cold_string(IIError");
}
cold string("\n\rPrint Screen "); print_screen_setupO;
colastring(II01(II); .
colastring("\n\rCassette FlI1Ct1on "); cassette_setupO;
colastri ng(IIOI(II).
colastring(ll\n\rBootstrap F\.I"lCtion "); boot_setupO;
colc(string(II01(II);
1* enable speaker */
outportb(pio-POrt_b,inportb(pio-POrt_b) & -Ox03);
1*---------- setup timer 0 for the rtc ----------*/
outportb(timer control-PQrt,Ox36);
outportb(timer-counter-O-POrt,Oxff);
outportb(timer-counter-O-POrt,Oxff);
outportb(Ox21,lnportb(OxZ1) & -Ox01); 1* enable the rtc */
1*---------- setup timer 2 for the beeper ----------*1
outportb(timer control-POrt,Oxb6)'

outportb(timer:counter:2-POrt ,OxOS);
/*-----------------------------------------------------
Si ze and Test Ram - from 64K up to 640K
-------------------------------------------------------*/
cold_string(lI\nll);
for (i = 64; (i < 640) && (ram test(i 6,32768) == ok); MEMORY_SIZE = += 64);
( -
cold string("\rRam Test at 1I);cold word(i 6);
colc(string(11 - OK II); -
}
/1 Now reset the sys segment to the top of ram. The function will copy the Of80h block to
// the system segment then reset the stack segment register to it, then do a return.
MEMORY SIZE = (i = MEMORY SIZE - sys seg size/1024);
move system segment(i seg slze);
colc(string'flt\n\rSystem Segment at7 .... );cold_word(i6);
1*-------------- now test ram above 1Meg --------------*/
II extended mem test returns ok/error
// if ok - size is in cmos(30 and 31)
':iri te_string( II\n");
1f (test ext mem() == ok)
( --
ext mem size = incmos(Ox31) 8 I incmos(0x30);
if(ixt mem size == 0)
( --
cold string("\rExtended Ram Not Found");
} -
else
{
for (i = O;i <= ext mem size;; +=64)
( - -
cold string("\rExt Ram at 1I);cold wordi 4) + Ox1000);
colastring("O")' -
colastring(11 - OK II).
} - ,
}
}
else
(
}
if(inportb(OxSO) < Ox80)
(
cold string("\rError on AZO Control ");
} -
else
(
cold Error 11);
cold[byte(lnportb(OxSO) & -OxSO);
} -
/*-------- do a checksum on the rom bios prom ----------*/
cold string("\n\rRom checksum ");
checKsum = checksum_bios_block();
A-Type BiosKit
if (checlesll1l == 0) cold stdng(IIOK");
else -
(
write string("Error II);
lbytercheclesll1l);
}
1* enable timer and kb interrupts *1
outportb(Ox21,inportb(Ox21) & Oxfc);
1*--------- setup the comm and lpt ports --------------*1
cold string("\n\rCOM Function
II
); cOllln_setup();
colcCstring(IIOKII);
cold string("\n\rLPT Function
II
); If)t_setup();
colcCstring(IIOK");
1*-------- check for game port ------------*1
if inportb(Ox0201) & OxOf) == 0 ) EQUIP_FLAG 1= Ox1000;
1*----------------------------------------------------
setup the floppy disk controller
-----------------------------------------------------*I
cold string("\n\rFloppy Disk ");
if (Tdisk setup() == ok)
( -
cold_string(IIOKII);
}
else
(
cold string(IOK")'
} - ,
1*--------------------------------------------------------
setup the hard disk controller
;----------------------------------------------------- --*1
cold string("\n\rHard Disle Check ");
iferror code = hdisk setup( == ok)
( - -
cold string(" OK");
} -
else
(
cold word(error code);
} - -
I * - - - - - - - - - - - - - - - - - - - - - - - - - - ~ - - - - - - - - - - - - - - - - - - - - - - - - - -
The Pod File E35
Check for optional rom modules from c8000 -> beginning of bios in 2k increments.
A valid module has'55aa' in the first 2 locations, length indicator (length/512) in the
3rd location, and test/init. code starting in the 4th location. These modules may adjust
the mem size downward to reserve scratch ram memory.
------------------------------------------------------ --*1
rom scan end = &bios start;
rom:scan:end = (rom_scan_end 4) 1 OxfOOO;
cold string("\n\rScan Rom from II);
colaword(Oxc800); cold stdng(1I to II);
colcCword(rom_scan_end); cold_string("\n\r");
I I for debuggi ng f I
Ilrom scan end = OxdOOO; II keeps from re-loading ourself
II rom-scan logic has problem with >= 64k blocks I!
for (i=Oxc800;i<rom_scan_end ;i = rom_check(i;
cold_string("\n\rRom scan cCll11llete")i
1*------------------------------------------------------*/
1* re-enable the rtc in case scan module disabled it */
outportb(Ox21,inportb(Ox21) & -Ox01);
1*=-=-=-=-=-= now do the boot =-=-=-=-=-=-=-=-=*1
Section E: The C ProlUams
E36 The Pod File
cold_string("\n\r>-------- Booting System -----------<\n\r\n");
myblock = acquire_block(POO);
while (0==0) // stay in this loop forever
(
/* make sure kb interrupt is enabled */
outportb(Ox21,inportb(Ox21) & -Ox02);
enableO;
beep();
write_string("\n\r");
sys int(Ox19,myblock)i // try boot from boot module
sys-int(Ox18,myblock); // try booting to SysVue
} -
release_block(myblock)i
}
/*=====================================================*/
unsigned xchg(unsigned segment,
unsigned address,unsigned value)
(
}
register i,j;
i = peek(segment,address);
poke(segment, address, value);
j = peek(segment,address);
poke(segment,address,i);
return (j);
/*----- read the cmos dipswitch -------------*/
char read switches()
( -
outportb(Ox70,Ox94);
return(inportb(Ox71;
}
/*-------------------------------------------------------*/
unsigned rom check( address)
( -
unsigned length,next address;
/* if not a modUle return next address */
if(peek(address,O) 1= Oxaa55) return(address + OxSO);
1* get length to checksum */
length = peekb(address,2)*512; // blocks are 512 bytes
next_address = address + (length 4);
if (checksum(address,length) == 0)
(
}
if(address 1= bios cs( /1 don't call ourselves III
( -
cold string("\n\rRom Signature found at : II); cold_word(address)i
far call(address,3)i
} -
return(next address);
} -
unsigned warm(void)
{
}
if (RESET FLAG == Ox1234) return(true);
return(faTse)i
unsigned cold(void)
{
}
if (RESET FLAG 1= Ox1234) return(true);
return(faTse)i
A-Type BiosKit
The Equipment Driver E41
FOUR
The Equipment Driver
The Equipment Configuration Driver is an Interrupt Function Call (Ox!!) that is
used by DOS and other programs to determine the options which are present in a
system. It is called with no input parameters and returns a value in the AX register
describing the system options. The POD reads the configuration dipswitch and
stores this value along with an adapter configuration byte into the word at
0040:0010.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
: Module Name: AT Bios equipment function
* Version: 1.01
*
* Author: FOSCO
*
* Date: 10-20-89
*
: Filename: biosequi.c
* Language MS C 5.1
*
: Functional Description:
* Interrupt Ox11 - get equipment, configuration
*
: This function call returns an equipment configuration word.
: The equip_flag variable is set during the power on.
: Returns the Equipment Word in AX:
* Bit Description
* 15,14 number of printers attached
* 13 = 0
* 12 = 1 = game port attached
* 11,10,9 number of rs232 cards attached
* 8 = 0
* 7 6 number of diskette drives
* 00=1, 01=2, 10=3, 11=4 only if bit 0 = 1
* 5 4 initial video mode
* 60 - no video adapter
* 01 - 40x25 bw using color card
* 10 - 80x25 bw using color card
* 11 - 80x25 bw using bw card
* 3,2 not used
* 1 0/1 = no 8087/8087
: 0 0/1 = boot from int 18/floppy disk
* Argunents:
* None
*
* Return:
: Equi pment word in AX
* Version History:
* 1.01
: Replaced peeks and pokes with casts
***************************************************************************************************/
/* INC L U D E F I L E S */
#include "atki t.h"
unsigned equipment setup(void)i
void interrupt cdecl far equipment(interrupt_registers)i
/* G LOB A L S */
extern _equipment;
E4 2 The Equipment Driver
/* L 0 CAL 0 E FIN I T ION S */
/* PRO G RAM */
unsigned equipment setup()
{ -
}
link_interrupt(Ox11,&_equipment)i
return(ok)i
void interrupt cdecl far equipment(interrupt_registers)
{
ax = EQUIP FLAGi
} -
A Type BiosKit
The Memory Size Driver E-5-1
FIVE
The Memory Size Driver
The Memory Size Driver is an Interrupt (Ox12) Function Call that is used by various
programs (including DOS) to determine how much RAM is in the system.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: AT Bios memory size function
*
* Version: 1.01
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: atmem.c
*
* Language: MS C 5.1
*
: Functional Description:
* Interrupt 12h - get memory size
*
* This function call returns the amount of System RAM in AX.
* The value indicates the number of 1024 byte blocks of RAM.
*
* Arguments:
* None
*
* Return:
* Mem size in AX
*
* Version History:
* 1.01
: Replaced peeks and pokes with casts
***************************************************************************************************1
1* INC L U D E F I L E S *1
#include "atkit.h"
1* FUN C T ION PRO TOT Y PES *1
unsigned mem size setup(void)i /1 called by pod to set the interrupt vector to the service routine
void interrupt cdicl far mem_size(interrupt_registers)i /1 returns the mem size in 1kbyte blocks
/* G LOB A l S *1
extern _mem_sizei
1* 0 E FIN I T ION S */
1* PRO G RAM *1
unsigned mem size setup()
{ --
}
link_interrupt(Ox12,&_mem_size)i
return(ok)i
void interrupt cdecl far mem_size(interrupt_registers)
{
ax = MEMORY SIZEi
} -
Things Not Worth Writing Down
The Keyboard Driver E61
SIX
The Keyboard Driver
The Keyboard Driver is used to obtain keyboard input from the keyboard.
If a non-standard keyboard or alternate input device is being used, it is suggested
that the keyboard function call structure be retained. The application will then be
independent of the hardware characteristics of the actual input device, and may be
exercised in a development environment with the standard keyboard input device.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
: Module Name: AT Bios keyboard driver
* Version: 1.06
*
* Author: FOSCO
*
* Date: 11-01-89
*
* Filename: atkb.c
*
* Language: MS C 5.1
*
: Functional Description:
* Argunents:
*
* Return:
*
* Version History:
* 1.01
: Added an nmi disable (out 70 with 8x) for re-boots (ctrl-alt_del).
* 1.02
* Modified buffer store to discard newest key on overrun.
*
* 1.03
* Iq>roved nuneric keypad handl ing.
*
* 1.04
* On "check for key in buffer", zeroed out only the zero bit rather than all the flag bits.
: Disabled interrupts during the "check for" sequence to insure correct key code was returned.*
* 1.05
: Added F 11 and F 12 support
* 1.06
: Replaced peeks and pokes with casts
*********************************!*****************************************************************/
/* INC L U D e F I L e S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
unsigned keyboard setup(void);
void interrupt cdicl far keyboard io(interrupt registers);
void interrupt cdecl far -
unsigned translate from column(uniigned char);
void reset(void)i - -
void int1b(void);
void update leds(void)i
void disabli keyboard(void)i
void enable ieyboard(void)i
unsigned seOd_8042_data(unsigned)i
/* G LOB A L V A R I A B L E S */
/* G LOB A L CON S TAN T S */
E6 2 The Keyboard Driver
extern keyboard io;
extern :keyboard[isri
/* L 0 CAL D E FIN I T ION S */
#define pio-port a Ox60
#define pio-POrtlb Ox61
#define s t a t u s ~ r t Ox64
#define in bfr full Ox02
lI#define Suffer head Ox1a
//#define buffer-tail Ox1c
#define buffer oegin Ox1e
lI#define buffer start Ox80
//#define buffer-end Ox82
#define wait for-key OxOO
#define checK for key in buffer Ox01
#define get_fTags-Ox02 -
#define break code Ox80 /* add to key to get break code *1
#define tab key 15
#define ctl-key 29
#define left key 42
#define riht key 54
#define prlnt-screen 55
#define alt key 56
#def i ne caPi key 58
#define f1 59
#define f2 60
#define f3 61
#def i ne f4 62
#define f5 63
#def i ne f6 64
#define f7 65
#define f8 66
#define f9 67
#define f10 68
#define f11 87
#define f12 88
#def i ne nun key 69
#define scroll key 70
#def i ne nun 0 !2
#def i ne nun -1 79
#define nun-2 80
#define nun' 81
#define nun-4 75
#def i ne nun, 76
#define nun-6 n
#def i ne nun, 71
#define nun-8 72
#def i ne nun:9 73
#define minus key 74
#define plus Key 78
#def i ne ins Key 82
#define del-key 83
#define sys:key 84
#define ack code Oxfa
#define resind_code Oxfe
#define ins state Ox80
#define caPS state Ox40
#define nun state Ox20
#define scroll state Ox10
#define al t shTft Ox08
#define ctl-shift Ox04
#define left shift Ox02
#define right_shift Ox01
#define ins shift Ox80
#define caps shift Ox40
#define nun Shift Ox20
#define scroll shift Ox10
#define hold_state Ox08
#define alt column 3
#define ctl-column 2
#define shift column 1
#define base_column 0
/* L 0 CAL CON S TAN T S */
/*======== This is the keyboard table ====================*/
const unsigned char kb_table[89] [4] ={
A Type BiosKit
1* This table covers all keys.
** Some keys are pre-checked for special handling.
** Some special keys are padded out in this table.
** The format is: base,upper,ctrl,alt cases.
** The alt cases are handled as extended codes.
*1
(a ,0 ,0 ,0), 1* base a padding for indexing*1
{27 ,27 ,27 ,-1 }, 1* key 1 - Escape key*1
('1','I',-1 120) 1* key 2 - '1'*1
('2' 'Q' 0 :121); 1* key 3 - '2' - special handling *1
('3';'#';-1 ,122 ), 1* key 4 - '3'*1
('4' '$' -1 ,123 ), 1* key 5 - '4'*1
('5':'X';-1 ,124 ), /* key 6 - '5'*/
{'6','A',30 ,125 ),1* key 7 - '6'*1
{'7','&',-1 ,126),1* key 8 - '7'*1
{'8' ,'*',-1 ,127),1* key 9 - '8'*1
{'9' ,'(',-1 ,128),1* key 10 - '9'*1
{'O',')',-1 ,129),1* key 11 - '0'*1
{'-','_',31 ,130),1* key 12 - '-'*1
{'=','+',-1 ,131 }, 1* key 13 - '='*1
{8 ,8 ,127, -1 }, 1* key 14 - backspace*1
{9 ,-1 ,-1 , -1 }, 1* key 15 - tab*1
{'q' ,'Q',17 16),1* key 16 - 'Q'*I
{'w' 17),1* key 17 -
{'e','E',S 18}, 1* key 18 - 'E'*I
{'r' ,'R',18 19}, 1* key 19 - 'R'*I
{'t' ,'T' ,20 20}, 1* key 20 - 'T'*I
{/y',/Y',25 21),1* key 21 - 'Y/*I
{/U
/
,/U',21 22}, 1* key 22 - 'U'*I
{'i','I',9 23}, 1* key 23 - '1'*/
{'o/,'O',15 24}, 1* key 24 - '0'*1
{'p',/P',16 25),1* key 25 - 'P/*I
(/[/,/{',27, -1) 1* key 26 - 1[1*1
{'l' '}' 29 , -1 S, 1* key 27 - 'l'*1
{13 ,10 , -1 }, 1* key 28 - CR*I
{-1 ,-1 ,-1 -1}, /* key 29 - control shift *1
{'a','A',1 30 }, 1* key 30 - 'A'*I
{/s','S',19 31}, 1* key 31 - 'S'*I
{'d','D',4 32 }, 1* key 32 - 'D'*I
{'f','F',6 33}, 1* key 33 - 'F/*I
{/g','G',7 34}, 1* key 34 - 'G'*I
{'h','H',8 35}, 1* key 35 - 'H'*I
{'j','J',10 36}, 1* key 36 - 'J'*I
('k','K',11 37), /* key 37 - 'K'*/
{'l' ,'L',12 38}, 1* key 38 - 'L'*I
{/',':',-1 -1}, 1* key 39 - ';'*1
, '"' , -1 -1}, 1* key 40 " '*1
{'\' '-' -1 -1} 1* key 41 - "'*1
{-1 :-1 '-1 ; -1 }: 1* key 42 - left shift *1
-1}, 1* key 43 - '\'*1
{'z', Z',26 , 44 }, 1* key 44 - 'Z'*I
{'x','X',24 45}, 1* key 45 - 'X'*I
{'c' 'C' 3 46} 1* key 46 - 'C'*I
{'v':'V';22 , 47 }; 1* key 47 - 'V'*I
{'b','B',2 48}, 1* key 48 - 'B'*I
{'n','N',14 49}, 1* key 49 - 'N'*I
{'m','M',13 50}, 1* key 50 - 'M'*I
{',' ,'<',-1 -1),1* key 51 - ','*1
{'.','>',-1 -1}, /* key 52 '.'*1
('I' ", -1 -1) 1* key 53 - '1'*1
{-1 :-i '-1 ; -1 }: 1* key 54 - right shift - *1
{'*' -1 -1} 1* key 55 - prt-scr - *1
{-1 '-1' -1' -1}' 1* key 56 Alt - *1
{32 :32 ;32', 32 }; 1* key 57 - space bar*1
{-1 ,-1 ,-1, -1}, 1* key 58' - caps-lock - *1
/* funct10n key cases*1
{59,84,94,104 }, 1* key 59 - F1*1
{60,85,95,105 }, 1* key 60 - F2*1
{61,86,96,106 }, 1* key 61 F3*1
{62,87,97,107 }, 1* key 62 - F4*1
{63,88,98,108 }, 1* key 63 - F5*1
{64,89,99 109 }, 1* key 64 - F6*1
{65,90,106,110 }, 1* key 65 - F7*1
{66,91,101,111 }, /* key 66 - F8*1
{67,92,102,112 }, /* key 67 - F9*1
{68,93,103,113 }, /* key 68 - F10*1
{-1,-1,-1,-1 }, 1* key 69 - num-lock - *1
{-1,-1,-1,-1 }, 1* key 70 - scroll-lock - *1
1* num key pad - cases are base,upper,ctrl,alt*1
{71,'7',119,-1 }, 1* key 71 - home*1
{72,'8',-1 -1} 1* key 72 - cursor up*1
S, 1* key 73 -
{'-','-' -1,-1 }, 1* key 74 - m1nus slgn*1
}, 1* key 75 - cursor left*1
{-1,/5',-1 -1} 1* key 76 - center key*1
S, 1* key 77 - cursor r1ght*1
The Keyboard Driver E63
Section E: The C Pro&rams
E64 The Keyboard Driver
('+','+' -1,-1 ), 1* key 78 - plus sign*1
(79,'1',117,-1 ), 1* key 79 - end*1
(80,'2',-1 -1 ), 1* key 80 - cursor down*1
(81,'3',11A,-1), 1* key 81 -.page down*1
{82,'O',-1,-1 }, 1* key 82 - lnsert *1
{83,'.',-1,-1 }, 1* key 83 - delete */
{-1, -1,-1,-1 }, 1* key 84 - sys key */
{-t, -1,-1,-1 }, /* key 85 */
{-1 -1 -1 -1} /* key 86 */
}, /* key 87 - F11 */
{134,136,138,140 }, 1* key 88 - F12 *1
};
1* PRO G RAM */
1*==========================================*/
1*==========================================*1
1* Interrupt 16h - Keyboard function call */
1*==========================================*1
1*==========================================*1
1*==========================================*/
unsigned keyboard setup(void)
( -
}
unsigned status = ok'
link interrupt(Ox16,1 keyboard 10):
link-interrupt(Ox09,&-keyboardrisr);
if(reset 8042() == error) status = error;
BUFFER HAD = buffer begin;
BUFFER-TAIL =
BUFFER-START = buffer begin:
BUFFER-END = buffer bigin + 32:
outportb(Ox21,inportb(Ox21) & -Ox02);
enable keyboard(); ,
1 OxcO);
1* reset the port *7
II & -Ox80);
KB FLAG = 0: // reset the flags
KB-FLAG 1 = 0; 1/ reset the flags
KB-FLAG-2 : 0; 1/ reset the flags
= 0: II reset the flags
return(it&tus):
/*==========================================*/
void interrupt cdecl far keyboard_io(interrupt_registers)
(
enable 0;
switch(ax 8)
{
}
}
case wait for key:
while (BU1FER-HEAD == BUFFER TAIL)
{ - -
enableO;
disableO;
}:
ax = peek40(BUFFER HEAD): BUFFER HEAD +: 2:
if (BUFFER HEAD >=-BUFFER END) SOFFER HEAD = BUFFER START;
enable(); - - - -
break;
case check for key in buffer:
disable();- - --
flags &= -zero bit; II clear only the zero bit in the flags
ax = peek40(BU1FER HEAD);
if (BUFFER HEAD ==-BUFFER TAIL) flags 1= zero_bit;
enable(); - -
break;
case get flags:
ax = (ax-& OxffOO) I KB_FLAG;
break;
1*======================================================*1
1* ==== keyboard hardware interrupt service routine ==== *1
variables
unsigned char scan code,scan_byte,col:
unsigned scan wordr,temp:
end_variables-kb_regs:
A JYpe BiosKit
The Keyboard Driver E65
void interrupt cdecl far keyboard isr(interrupt registers)
{ --
kb regs *myblock:
mySlock = acquire_block(KEYBOARD);
enable(); .
disable keyboard();
/* get ican code from input port */
myblock->scan_code =
myblock->scan_word = -1; /* preset scan word to default no-load */
switch (myblock->scan code)
{ -
/* first do all the special handling keys */
case ack code:
KB FLAG 2 1= Ox10;
briak; -
case resend code:
KB FLAG 2 1= Ox20;
briak; -
case sys key:
break; -
case tab key:
ifKB F[AG & (left shift I right shift 1= 0)
mybloc1(->scan_word = 15*256; -
else
myblock->scan_word = 15*256+9;
break;
case ctl key:
KB_FLAG T= ctl_shift;
break:
case break code+ctl key:
KB FLAG &=--ctl shift;
briak; -
case left key:
KB FLAG 1= left shift;
briak; -
case break code+left key:
KB FLAG &=--left shift;
briak; -
case right key:
KB FLAG I=-right shift;
briak; -
case break code+right key:
KB FLAG &=--right shift;
briak; -
case print screen:
ifKB & ctl shift) 1= 0)
myblocK->scan_wora = 114*256;
else
{
ifKB FLAG & (left shift 1 right shift 1= 0)
srs_int(OX05,myblOCK); -
e se
myblock->scan word = 55*256+'*'
} - ,
break;
case break code+print screen: /* print screen break */
break; - -
case alt key:
KB FLAG I= alt shift;
/*-ifK FLAG-& alt shift) == 0) */
ALT INPUT-= 0; -
break;
case break code+alt key:
KB FLAG &=--alt shift
iffALT INPUT !=-O) myblock->scan word = ALT INPUT;
breaic;- --
case caps key:
if KB F[AG 1 & caps shift) == 0)
/* if kiy not depressid */
Section E: The C ProlUams
{
}
E66 The Keyboard Driver
KB FLAG 1 1= caps shift;
KB:FLAG-
A
= caps_state;
break;
case break code+caps key:
KB_FLAG_1 1= -caps_snift;
break;
case nun key:
if KB rLAG 1 & num shift) == 0)
1* if key not depressed *1
{
KB_FLAG_1 1= nun_shift;
KB FLAG A= nun state;
} - --
ifKB FLAG & ctl shift) 1= 0)
1* do Pause mode wI
(
KB FLAG 1 1= hold state;
iff CRT t= 7)-
( -
outportb(Ox3d8,CRT MODE SET);
} - -
eoi sequence();
ena6le keyboard();
while (K8 FLAG 1 & hold state) 1=0) ()
} - - -
break;
case break code+nun key:
K8 FLAG 1 I- -nun snift;
break; - -
case scroll key:
if K8 FLAU 1 & scroll shift) == 0)
1* if key not depressedi*1
{
}
KB FLAG 1 1= scroll shift;
& (ctT_shift I alt_shift == 0)
1/ don't change state if ctrl or alt keys down
KB FLAG A= scroll state;
) - -
ifK8 FLAG & ctl shift) 1= 0)
(- -
eoi sequence();
ena6le keyboard();
ifKB-FLAG & alt shift) t= 0)
(- -
sys int(Ox18,myblock);
} -
else /* break condition */
(
BIOS 8REAK = Ox80;
sys Tnt(Ox1b,myblock);
} -
}
break;
case break code+scroll key:
K8 FLAG 1 1= -scroll snift;
break; - -
case ins key:
if K8 rLAG & alt shift) 1= 0)
(- -
assemble alt numeric(myblock->scan code);
} - - -
else
{
if K8 FLAG & ins shift) == 0)
{- -
KB FLAG A= ins state; 1* toggle insert state */
KB-FLAG 1 1= ins shift;
} - - -
// If in either nun state or shift state, but not bithe, code = '0'
II else code = 0 - -
ifK8 FLAG & nun state) == 0)
{- -
if K8 FLAG & ( left shift I right shift == 0)
mybloci->scan word =-ins key*2S6; -
else - -
A-Type BiosKit
}
myblock->scan word = ins keY*256+'0';
} - -
else
(
if KB FLAG & (left shift I right shift 1= 0)
mybloci->scan_word :: ins_key*256;-
else
myblock->scan word = ins keY*256+'0';
} - -
break;
case break code+ins key:
KB FLAG 1 1= -ins snifti
break; - -
case minus key:
myblock->scan_word = 74*256+'-';
break;
case plus key:
myblock->scan word = 78*256+'+';
break; -
The Keyboard Driver E-6-7
case del key:
& (ctl_shift I alt_shift == (ctl_shift I alt_shift
if KB FLAG & (left shift I right shift == 0)
(- - -
RESET FLAG = Ox1234; /* warm boot */
) -
else
(
RESET FLAG = 0; /* cold boot */
) -
disableO
incmos(Ox60); // set NMI mask
far call(bios cs(),&reset);
} - -
else
(
}
ifC(KB FLAG & nun state) 1= 0)
(- -
ifKB FLAG & (left shift I right shift == 0)
mvbloci->scan_word :: 83*256+' .'; -
else
myblock->scan word = 83*256;
} -
else
(
ifC(KB FLAG &
(left shift I right shift 1= 0)
mvbloek->scan_word:: 83*256+'.';
else
myblock->scan word = 83*256;
} -
break;
case break code+del key:
break; - -
default: /* not a special handling key */
if CCmyblock->scan code & Ox80) == 0)
/* do only the makes for these * /
(
myblock->scan_code &= Ox7f; /* clear the break bit */
/* release the hold state if it is active */
iflCCKB_FLAG_' & hold_state) 1= 0) KB_FlAG_1 &= -hold_state;
e se
(
switch (myblock->scan code)
( -
case nun 0:
case nun-':
case nun-2:
case nun':
case nun-4:
case nun-S:
case num-6:
case nun,:
case nun-8:
case nun-9:
if & alt_shift) 1= 0)
Section E: The C ProlUams
}
}
E68 The Keyboard Driver
assemble_alt_numeric(myblock->scan_code);
else
{
myblock->col = 0t" 1* BASE = 0 (all extended codes) *1
if KB FLAG & a t shift) 1= 0 )
- - = alt column; 1* ALT = 3 (all suppressed) */
else if KB FLAG & ctl shtft) 1= 0) -
- - myblock->col = ctl_column; 1* CTRL = 2 (all extended codes *1
if KB FLAG & (num state 1= 0)
myblocK->scan peekbcs(&kb table[myblock->scan code] [1]);
else - - -
myblock->scan_word = peekbcs(&kb_table[myblock->scan_code] [myblock->coll)8;
}
break:
case f1:
case f2:
case f3:
case f4:
case f5:
case f6:
case f7:
case f8:
case f9:
case f10:
case f11:
case f12:
myblock->scan word = translate from column(myblock->scan code):
if myblock->scan word & OxffUO) == 0) -
myblock->scan_word 8:
break;
default:
mvblock->scan word = translate from column(myblock->scan code):
j'-if not an extended code return *7 -
}
ifmyblock->scan word & OxffOO) == 0)
( -
mvblock->scan byte = myblock->scan word;
j'-caps lock correction */ -
ifKB FLAG & caps state) 1= 0)
{- -
if (myblock->scan byte >= 'A') &&
(myblock->scan byte-<= 'Z/ II
=
( lock->scan byte >= 'a/) &&
( lock->scan 6yte <= 'Z')
lock->scan pyte A= Ox20;
} -
myblock->scan_word = (myblock->scan_code 8) I myblock->scan_byte:
}
break:
}
break;
if(myblock->scan word 1= -1) /* load scan word into buffer */
{ -
//-------------------------------------------------
/I increment the tail pointer
myblock->temp = BUFFER TAIL + 2;
// check for wrap-around and reset to start if needed
if (myblock->temp == BUFFER END) mvblock->temp = BUFFER START;
/1 if overwrite wfll not then store the scan word
}
if (myblock->temp 1= BUFFER EAD)
( -

II now update the tatl
BUFFER TAIL = myblock->temp;
} -
else
(
beep();
}
11-------------------------------------------------
1* read the in service register to see if eoi is needed *1
outportb(Ox20,OxOb):
ifinportb(Ox20) & Ox02) 1= 0)
(
outportb(Ox20,Ox20);
enable keyboard();
} -
update_ledsO;
A Type BiosKit
release block(myblock):
} -
1*========== end of keyboard isr routine ===========*1
unsigned translate from column(unsigned char scan code)
< - - -
unsigned char col = 0,
if KB FLAG & alt sh,ft) 1= 0 )
relturn(peekbcS(&kb:table[Scan_code] [alt_column]) 8);
e se
<
if KB FLAG & ctl shift) != 0) col = ctl column,' 1* 2 *1
else - - -
<
if KB FLAG & (left shift 1 right shift 1= 0)
col = snift column: 7* 1 *1 -
} -
}
return (peekbcs(&kb table[scan code] [col]:
} --
1*---------------------------------------------*1
assemble alt numeric(unsigned char scan code)
( - - -
unsigned char code;
code = peekbcs(&kb table[scan code] [1]):
if code >= '0') 1& (code <=-'9'
(ALT INPUT *= 10) + (code & OxOf):'
} -
1*-- update the keyboard leds if state has changed --*1
void update leds(void)
( -
}
& Ox70) 4) 1= (KB_FLAG_2 & Ox07
}
II check update busy bit
if KB FLAG 2 & Ox40) == 0)
< --
eoi
ena5le keyboard():
KB 2 l= Ox40; II set update busy
i ffsenaao 2 data(Oxed) == ok) II send the led conmand
< --
}
delay call(0,10000): II wait about 10 millisecs
KB FLXG 2 &= Oxf8: II build new led bits
KB:FLAG:2 1= & Ox70) 4:
eOl sequence();
ena5le keyboard(): .
I I sena the led code
if(send 8042 data(KB FLAG 2 & Ox07) 1= ok)
( - - --
II send enable if we had a tx error
send 8042 data(Oxf4);
} - -
KB FLAG 2 &= -Ox40: II clear update busy
} - -
enable():
void disable keyboard()
( -
send 8042(Oxad);
} -
void enable keyboardO
( -
send 8042(Oxae):
} -
1*=======================================================*1
The Keyboard Driver E69
Section E: The C Pro&rams
The Video Driver E71
SEVEN
The Video Driver
The Video Driver is used to operate the CRT display.
If a video adapter is not installed in a system, it is wise to retain the video function,
and internally modify it to direct output to an alternate device. This permits
character oriented video output (such as the "write_tty" command) to retain PC
compatibility during the development phases. As an example, the video driver might
relay characters to a serial channel output routine, but the application could be
exercised on a system with a video device installed.
Note: Screen flickering - some early generation video adapters do not have clean
memory-write/refresh-read timing and flickering may be observed when updating
the screen. Most of the currently available adapters, in our experience, seem to
minimize this flickering effect. If you observe flickering, the general method to
pursue to minimize this is to sample the horizontal re-trace status, (usually bit 0 of
the status port, 3BA or 3DA), and write into display memory only when the adapter
is in retrace (moving the blanked beam from right to left to start a new line). The
vertical sync time can also be used for writing.
Note: 24 line scrolling - The standard Write-TIY function scrolls all 25 lines. A 24
line scroll may be a desirable option in order to maintain a "status" line at the
bottom of the screen. This may be accomplished by modifying the Write-TIY
function to either always scroll 24 (or 25) or to sense a flag (or variable) to
determine how many lines should be scrolled.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: AT Bios crt driver
*
* Version: 1.03
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: atcrt.c
*
: Language: MSC 5.1
: Functional Description:
: This driver manages the video display.
* Argunents:
*
* Return:
*
* Version History:
* 1.01
* Corrected some get cursor ~ s i t i o n statements; added active page index to the
* peekb40(cursor-POsn+(peekb40(active-psge)1 uses active page # as word index
* into cursor co-ordinates table in segment 40:50-5f.
* 1.02
* Added some graphics in.,rovements
* 1.03
: Used typecast segment 40: variables
**************************************************************************************************/
/* INC L U D E F I L E S */
E72 The Video Driver
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
void $iret(void);
unsigned video setup(void)c
void interrupt-cdecl far vldeo_io(interrupt_registers);
extern void move row
extern void clear row (unslgned,unsigned,unslgned,unslgned)i
extern void move-graphics row (
unsigned,unsigned;unsignedr,unsigned);
extern void clear graphics row (

unsigned check mode(vold);
void load char);
void
unsigned expana byte(unslgned char,unslgned char);
void set the cursor to loc(unsigned);
void store
unsigned fTnd-PQSltion(void);
void scroll end(void);
uns igned swi{)(uns i gned);
unsigned char,unsigned char);
unsigned rom check(unslgned)i
unsigned fina-P8ge-POsitionCunsigned char);
/* G L 0 8 A L V A R I A 8 L E S */
extern unsigned redirect_flag;
/* G L 0 8 ALe 0 N S TAN T S */
extern _video_io;
/* L 0 CAL D E FIN I T ION S */
#define cursor-POsn Ox50
#define 0
#define dOwn 1
#define is graphics Ox01
#define is:alpha Ox02
#define bell Ox07
#define backspace OxOS
#define carriage return OxOd
#define l ine_fiea OxOa
#define VIDEO_IO Ox10
#define color address Ox03d4
#define mono iddress Ox03b4
#define ega_address Ox03cO
/*=== command equates ===*/
#def i ne set mode 0
#define set-cursor shape
#define set-cursor:Position 2
#define resa cursor-PQsition 3
#define 4
#define set ictlVe-PBge 5
#define scroll
#define scroll-dOwn 7
#def i ne read ae current 8
#define write ac current 9
#define write-c current 10 /* OA */
#define set color 11 /* 08 */
#define write...{)ixel 12 /* OC */
#define readJ)1xel 13 /* OD */
#define write tty 14 /* OE */
#define return VIdeO state 15 /* OF */
#define write_string- 19 /* 13 */
/* L 0 CAL CON S TAN T S */
/*------ constants ----------*/
extern const unsigned char video font [128] [8];
extern const unsigned char mode table[8]
extern const unsigned char column tabletS]
extern const unsigned char
A-Type BiosKit
The Video Driver E 73
II We do not use the length table in biostop.asm because it only has four entries.
const unsigned length table[8] =
{ -
2048,2048,4096,4096,16384,16384,16384,4096
};
1* PRO G RAM *1
1*------------- video setup ---------------------*1
variables
end_variables video_setup_regs;
unsigned video setup(void)
( -
*myblock;
myblock = acqulre_block(VIDEO);
1* reset any video cards *1
outportb(color_address + 4, 0);
outportb(mono address + 4, 1);
inportb(mono address + 6);
inportb(color address + 6);
outportb(ega_address, 0);
1* load vector for this routine *1
link video io);
set_vector(Ox1d,bios_cs(),&video-Parms[0]);
II set default address to cOlor board
II this is done in ease we have an EGA
ADDR_6845 = color_address;
}
1* determine type of video *1
switch (EQUIP FLAG & Ox0030)
( -
}
case 0x30: 1* monochrome *1
ADDR 6845 = mono address;
myblOck -> ax = Ux0002;
sys_int(Ox10,myblock);
break;
ease OxOO: 1* none - assume color */
case Ox20: 1* cga 80 *1
myblock -> ax = Ox0003;
sys int(Ox10,myblock);
break;
case Ox10: /* cga 40 *1
myblock -> ax = Ox0001;
sys_int(Ox10,myblock);
break;
rom_check(OxcOOO);
release_block(myblock);
return(ok);
1*===
1*===
1*===
MAIN VIDEO ROUTINE
variables
uns i gned i, j, reg index, video segment
unsigned perm segment,parm olfset,fi{l word;
uns i gned row, co l , line CCU'lt'; -
unsigned char outchar;
unsigned temp,temp cursor,fill length;
end_variables videO_regs; -
===*1
===*1
===*1
void interrupt cdecl far video io(interrupt registers)
( --
video regs *myblock;
enabli();
myblock = acquire_block(VIDEO);
if (ADDR 6845 1= 0)
{ -
if (ADDR 6845 == mono address)
{- -
myblock->video segment = OxbOOO; 1* mono card *1
} -
Section E: The C Pro&rams
E 7 -4 The Video Driver
else
{
myblock->video segment = OxbBOO;
} -
switch (ax 8)
{
/* color card */
/*=============================================*/
/*=== ===*/
/*=== AH = 0 = set mode ===*/
/*=== AL = mode to be selected (0-9) ===*/
/*=== ===*/
/*=============================================*/
case set_mode:
if SWITCH BYTE & Ox30) == OxlO)
{ -
CRT MODE = 7; /* if mono, force mode 7 */
ADDf 6845 = mono address;
mybleck->video segment = OxbOOO;
} -
else
{
}
ADDR 6845 = color address
mybleck->video_segment = 6xbBOO;
if ax & Oxff) 1= 7)
CRT MODE = ax; /* if color, use selected mode */
else
{
if SWITCH BYTE & OxlO) == Ox20) CRT MODE = 0; else CRT_MODE = 2;
} - -
CRT MODE SET = table[CRT MODE]);
outportb{(ADDR_6845) + 4, CRT_MODE_SET1;
myblock->panm offset = peek(OxOO,Ox74);
myblock->panm:segment = peek(OxOO,Ox76)i
if (CRT MODE >=2) myblock->parm offset += 16; /* 16 */
if (CRT-MODE >=4) myblock->panm-offset += 16; /* 16+16 */
if (CRTJMOOE ==7) myblock->panm:offset += 16; /* 16+16+16 */
CURSOR_MODE = swap(peek(myblock->parm_segment,(myblock->panm_offset+10);
for (myblock->reg index=O;myblock->reg index < 16;myblock->reg index++)
( - - -
6845_byte(myblock->reg_index,peekb(myblock->parm_segment,myblock->parm_offset+myblock-
>reg 1 ncleX;
}-
CRT START = 0;
ACTTVE_PAGE = 0; /* set active page to zero */
/* enable video and correct port setting */
outportbADDR_6845) + 4,peekbcs(&mode_table[CRT_MODE];
CRT_MODE_SET = peekbcs(&mode_table[CRT_MODE]);
CRT_COLS = peekbcs(&column_table[CRT_MODE]);
CRT_LENGTH = peekcs(&length_table[CRT_MODE]);
for. (myblock->i = 0; myblock->i < 8;
poke40(cursor-POsn + myblock->i, 0); / clear all cursor positions */
if (CRT MODE == 6) /* set paLlette register */
( -
outportbADDR 6845) + 5,Oxlf);
CRT PALLETTE =-Oxlf;
} -
else
(
outportbADDR 6845) + 5,OxlO);
CRT PALLETTE =-Ox30;
} -
if (check mode() == is graphics)
mvblock->Till_word = 0;
else
myblock->fill_word = Ox0720;
myblock->fill_length = 2 * CRT_LENGTH;
A-Type BiosKit
The Video Driver E-7-S
CURSOR_MODE = Ox0607;
for (myblock->i = 0; myblock->i < myblock->fill_length; myblock->i += 2) 1* clear the screen */
(
poke(myblock->video_segment, myblock->i, myblock->fill_word);
)
break;
1*===========================================*/
1*=== ===*/
/*=== AH = 1 = set the cursor shape ===*/
/*=== ===*/
/*=== CH = start line ===*/
/*=== CL = stop line ===*/
1*=== ===*/
/*===========================================*/
case set_cursor_shape:
CURSOR_MODE = cx; load_6845_word(10,cx);
break;
/*=====================================*/
1*=== ===*/
1*=== AH = 2 = set cursor position ===*/
/*=== ===*/
/*=== OH = row ===*/
/*=== OL = column ===*/
./*=== BH = page ===*/
/*=== ===*/
/*=====================================*/
case set_cursor-POsitfon:
poke40(cursor-POsn+ bx 8) 1), dx);
if (ACTIVE_PAGE == (bx 8
load 6845 word(14 CRT START) +
- T(dx A) * cRT_COLS) + (dx & Oxff) ) 1) 1 ;
break;
/*=============================================*/
/*=== ===*/
1*=== AH = 3 = read cursor position ===*/
1*=== ===*/
/*=== BH = page I OH = row ===*/
/*=== I OL =column ===*/
1*=== CX = cursor mode ===*/
/*=== ===*/
1*=============================================*/
case read_cursor-POsition:
cx = CURSOR_MODE; dx = CURSOR_POSN + bx 8) 1);
break;
/*=============================================*/
/*=== ===*/
/*=== AH = 4 = read light pen position ===*/
/*=== ===*/
/*=== AN = 0 = no info ===*/
/*=== AN = 1 = info ===*/
/*=== ON = row ===*/
1*=== OL = column ===*/
/*=== CN = raster line ===*/
/*=== BX = horz. position ===*/
/*=== ===*/
/*=============================================*/
case
ax = ax & OxOOff; /* set no light pen return code */
break;
/*==========================================*/
/*=== ===*/
/*=== AN = 5 = set active page ===*/
1*=== ===*/
/*=== AL = active page # ===*/
/*=== ===*/
Section E: The C Pro&rams
E 76 The Video Driver
/*==========================================*/
case set_active-P8ge:
ACTIVE PAGE = ax;
CRT = CRT LENGTH * (ax & OxOOff);
dx = peek40(eursor-POsn+ax & OxOOff) 1;
load 6845 START / 2);
START +
ax -8) * CRT COL! ) + (dx & Oxff) ) 1)
1 ; -
break;
/*=============================================*/
/*=== ===*/
/*=== AH = 6 = scroll up ===*/
/*=== ===*/
/*=== AL = # rows to scroll (0 = blank) ===*/
/*=== cx = row,col of left corner ===*/
/*=== ox = row,col of lower right corner ===*/
/*=== 8H = attribute for blanked line ===*/
/*=== ===*/
/*=============================================*/
case scroll up:
if (check mOde() == is_graphics)
{ -
if ax & Oxff) == 0) /* blank the field */
{
myblock->i = (dx 8) - (ex 8)';
for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line_count++)
{ - -
for (myblock->row = (ex 8); myblock->row <= (dx 8); myblock->row++)
{
}
clear graphics row(myblock->video segment,
mybTock->row-* 320) + (ex & OxfT,
(dx & Oxff) - (ex & Oxff) + 1,0);
}
}
else /* scroll the field */
{
/* i will = the # of rows to scroll */
myblock->i = ax & Oxff;
for (myblock->line count = O;myblock->line count < myblock->iimyblock->line eount++)
{ - - -
}
}
}
for (myblock->row = (ex 8); myblock->row < (dx 8); myblock->row++)
{
}
move graphics_row(myblock->video_segment,
mY6lock->row + 1) * 320) + (ex & Oxff),
(mybloek->row * 320) + (ex & Oxff),
(dx & Oxff) - (ex & Oxff)+1);
myblock->row = dx 8
clear graphics row(myb[ock->video segment,
(myblOck->row 320) + (cx & Oxffl,
(dx & Oxff). - (ex & Oxff) + 1,0);
else /* alpha mode scroll */
{
if ax & Oxff) == 0) /* blank the field */
{
myblock->i = (dx 8) - (ex 8);
for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line eount++)
{ - - -
for (myblock->row = (cx 8); myblock->row <= (dx 8); myblock->row++)
{
}
clear row(myblock->video segment,
mybTock->row * CRT COL!) + (cx & Oxff * 2,
(dx & Oxff) - (cx & Uxff) + 1,
(bx & OxffOO) I Ox20);
}
}
else /* scroll the field */
{
myblock->i = ax & Oxff;
for (myblock->line count = 0; myblock->line_count < myblock->i; myblock->line_count++)
{ -
for (myblock->row = (ex 8); myblock->row < (dx 8); myblock->row++)
{
move_row(myblock->video_segment,
A-Type BiosKit
}
}
}
}
(myblock->row + 1) * CRT_COLS)+(cx & Oxff*2,
myblock->row * CRT COLS)+(cx & Oxff*2,
(dx & Oxff)-(cx & Oxlf)+1);
mvblock->row = dx 8;
clear row(myblock->video segment,
mybTock->row * CRT & Oxff*2,
(dx & Oxff)-(cx & Oxif)+1,
bx & OxffOO) I Ox20;
break;
/*===================================================*/
/*=== AH = 1 = scroll down ===*/
/*=== ===*/
/*=== AL = # rows to scroll (0 = blank window) ===*/
/*=== cx = row, col of upper left corner ===*/
/*=== ox = row, col of lower right corner ===*/
/*=== BH = attribute for blanked line ===*/
/*=== ===*/
/*===================================================*/
case scroll_down:
if (check mode() -- is_graphics)
{ -
if ax & Oxff) == 0) /* blank the field */
{
The Video Driver E 7-7
myblock->i = (dx 8) - (cx 8);
for (myblock->line count = 0; myblock->line count <= myblock->i; myblock->line count++)
{ - - -
for (myblock->row = (cx 8); myblock->row <= (dx 8); myblock->row++)
<
}
}
}
clear graphics row(myblock->video segment,
mybTock->rowW)20)+(cx & Oxff,-
(dx & Oxff)-(cx & Oxff)+1,0);
else /* scroll the field */
<
for (mvblock->line count = 0; myblock->line_count < (ax & Oxff);
myblock->line count++)
< -
for (myblock->row = (dx 8); myblock->row > (cx 8); myblock->row--)
<
}
}
}
move graphics row(myblock->video segment,
my6lock->row - 1) * 320) + (cx-& Oxff),
(myblock->row * 320) + (cx & Oxff),
(dx & Oxff)-(cx & Oxff)+1); .
mvblock->row = cx 8"
clear graphics row(myb{ock->video segment,
(myblOck->row w 320) + (cx & Oxffl,
(dx & Oxff)-(cx & Oxff)+1,0);
}
else
<
if ax & Oxff) == 0) /* blank the field */
<
for (myblock->row = (dx 8); myblock->row < (cx 8); myblock->row--)
<
for (myblock->col=(cx & Oxff); myblock->col< (dx & Oxff); myblock->col++)
}
}
<
pokeb(myblock->video segment,
(myblock->row * CRT COLS) + myblock->col)*2),Ox20);
} -
else /* scroll the field */
<
for (mvblock->line count = 0; myblock->line_count < (ax & Oxff);
myblock->line count++)
< -
for (myblock->row = (dx 8); myblock->row > (cx 8); myblock->row--)
<
}
move row(myblock->video segment,
(mYblock->row - 1) * COLS)+(cx & Oxff*2,
myblock->row * CRT COLS)+(cx & Oxff*2,
(dx & Oxff)-(cx & Oxlf)+1);
Section E: The C ProlUams
E 78 The Video Driver
myblock->row = cx 8;
clear row(myblock->video segment
mybTock->row * CRT COL! + (cx & Oxff*2),
(dx & Oxff)-(cx & OXTf)+1,
}
}
}
bx & OxffOO) I Ox20;
break;
1*=============================================*/
1*=== ===*/
/*=== AH = 8 = read attr and char at cursor ===*/
/*=== ===*/
/*=== BH = page # I AL = char ===*/
1*=== for alpha only AH = attrib ===*/
1*=============================================*/
case read_ac_current:
if (check_mode() == is_graphics)
(
for (myblock->j = 0; myblock->j < 128; myblock->j++)
(
myblock->temp = true;
for (myblock->i=O; myblock->i <= 7; myblock->i++)
(
/* if mode is 640 x 200 */
if(CRT MODE == 6)
( -
}
segment
(myblock->row * 320) + t(mybloc'->i & Oxfe) * 40) + myblock->col +
mvblock->i & 1) * Ox2000 1= peekbcs(&video_font[ax & Ox007f] [myblock->i]
myblock->temp = false;
else /* 320 x 200 mode *1
(
segment,
(myblock->row * 320) +-myblock->i & Oxfe) * 40) + (myblock->col * 2) + myblock->i
Ox2000 1=
}
}
byte(peekbcs(&video_font[ax & Ox007f] [myblock->i]),3
mybloci->temp = false;
if (myblock->temp == true)
(
ax = (ax & OxffOO) I mvblock->j;
break; /* get out with the find */
}
}
}
else /* --- alpha read --- */
(
ax = peek(myblock->video segment,find-P8ge nnsition(bx 8; } _ -r-
break;
/*==============================================*/
1*=== ===*/
/*=== AH = 9 z write attr and char at cursor ===*/
1*=== ===*/
1*=== BH = page # ===*/
1*=== for only ===*/
1*=== CX = # write ===*/
1*=== AL = character ===*/
/*=== BL = attribute ===*/
/*=== ===*/
/*==============================================*/
case write_ac_current:
if(check mode() == is graphics)
(- -
myblock->row = peekb40(cursor-PQsn+bx 8) 1) +1);
myblock->col = peekb40(cursor-PQsn+bx 8) 1;
for (myblock->i=O; myblock->i <= 7; myblock->i++)
(
1* if the mode is 640 x 200 */
if(CRT MODE == 6)
( -
pokeb(mvblock->video segment
(myblock->row * 320)-+ myb(ock->i & Oxfe) * 40) +
myblock->col +
A-Type BiosKit
& 1) *
}
myblock->i & 1) * Ox2000)
peekbcs(&video font[ax & Ox607f] [myblock->i));
} -
else
<
}
/* if the mode is 320 x 200 */
poke(myblock->video segment
(myblock->row * 320J + myblock->i & Oxfe) * 40) +
(myblock->col * 2) +
myblock->i & 1) * Ox2000)
& Ox007f] [myblock->i]),
bx & Ox83;
}
else
(
myblock->temp = 8);
for (myblOCK->; = 0; myblOCK->i < cx; myblock->i++)
(
The Video Driver E-7-9
poke(myblock->video segment,myblock->temp+(2 * myblock->i),bx 8) I (ax & Oxff);
} -
}
break;
/*===============================================*/
/*=== . ===*/
/*=== AH = 10 = write char at cursor position ===*/
/*=== ===*/
/*=== BH = page ===*/
/*=== for alpha onlyl ===*/
/*=== CX = to write ===*/
/*=== AL = character ===*/
/*=== ===*/
/*===============================================*/
case write_c_current:
if(check mode() == is graphics)
< - -
myblock->row = peekb40(cursor-POsn+bx 8) 1)+1);
myblock->col = 8) 1;
for (myblock->i=O; myblock->i <= 7; myblock->i++)
<
/* if the mode is 640 x 200 */
if(CRT MODE == 6)
< -
pokeb(myblock->video segment-
(myblock->row * 320)-+ myb[ock->i & Oxfe) * 40) +
myblock->col +
myblock->i & 1) * Ox2000)
peekbcs(&video font[ax & Ox607f] [myblock->i));
} -
else
<
/* if the mode is 320 x 200 */
poke(myblock->video segment
(myblock->row * 320J + myblock->i & Oxfe) * 40) +
(myblock->col * 2) +
myblock->i & 1) * Ox2000)
expand byte(peekbcs(&video font[ax & Ox007f] [myblock->i]),3;
} - -
}
}
else
<
myblock->temp = 8);
for (myblock->i = 0; myblock->i < cx; myblock->i++)
{
pokeb(myblock->video segment,myblock->temp + (2 * myblock->i),ax);
} -
}
break;
/*==============================================*/
/*=== ===*/
/*=== AH = 11 = set color for MRES graphics ===*/
/*=== ===*/
/*=== BH = 0 ===*/
/*=== Bl = background color ===*/
Section E: The C Proerams
E 7 10 The Video Driver
1*=== ===*1
1*=== BH = 1 ===*1
1*=== BL = pallette select ===*1
1*=== ===*1
1*==============================================*1
case set color:
1* get current ~ l l e t t e value *1
ifbx 8) == 0) 1* this is color 0 *1
{
1* turn off low 5 bits of current color */
CRT PALLETTE &= OxeO-
CRT-PALLETTE 1= (bx 1 Ox1f);
1* turn off hlgh three bits of input *1
}
else 1* select pallette */
(
CRT PALLETTE &= Oxdf; 1* turn off pallete select bit *1
ifC{bx & Ox01) 1= 0)
CRT PALLETTE 1= Ox20; 1* turn on pallette select bit */
} -
outportbADOR 6845) + S,CRT PALLETTE);
break; - -
1*===========================================*1
1*=== ===*1
1*=== AH = 12 = write pixel ===*1
1*=== ===*/
1*=== OX = row 0-199 ===*1
1*=== CX = column 0-639 ===*/
1*=== AL = pixel value (1 or 2 bits) ===*1
1*=== bit 7 = 1 = XOR lower bits ===*/
1*=== ===*1
1*===========================================*1
case write-pixel:
1* calc row address for even/odd */
myblock->row = dx * 40 + dx & 1) * (Ox2000-40:
if(CRT MODE == 6) 1* write one 1 bit *1
{ -
1* col variable is used for bit mask *1
myblock->col = 1 (ex X 8);
}
1* calc address for 1 bit in 8 *1
myblock->row += ex I 8;
pokeb(myblock->video_segment,myblock->row,peekb(myblock->video_segment,myblock->row)
& -myblock->col) I
ax & Ox0001) (cx X 8;
else 1* write 2 bits *1
{
1* col variable is used for bit mask *1
myblock->col = 3 (cx X 4):
1* calc address for 2 bits in 8 */
myblock->row += cx/4;
r
keb(myblOCk->video_segment,myblock->row,C(peekbCmyblock->video_Segment,myblock->row)
-myt)lock->col) I
ax & Ox0003) (cx X 4;
}
break;
1*==========================================*1
1*=== ===*1
1*=== AH 13 read pixel ==.*1
1*= ===*1
1*=== OX = row 0-199 I AL = pixel ===*1
1*=== CX = column 0-639 ===*1
1*=== ===*1
1*==========================================*1
case read-pixel:
1* calc row address for even/odd *1
myblock->row = dx * 40 + dx & 1) * (Ox2000-40;
if(CRT MODE == 6)
{ -
1* read one 1 bit *1
1* calc address for 1 bit in8 *1
A-1Jpe BiosKit
myblock->row += cx/8;
ax :I (ax & OxffOO) I
peekb(myblock->video_segment,myblock->row) (ex X 8 & 1);
)
else
{
1* read 2 bits */
)
1* calc address for 2 bits in 8 *1
myblock->row += cx/4;
ax = (ax & OxffOO) I
peekb(myblock->video_segment,myblock->row) (cx X 4 & 3);
break;
/*=========================================*/
/*=== ===*/
1*=== AH = 14 = write tty ===*/
/*=== ===*/
/*=== Al = character to write ===*1
/*=== Bl = fground color in graphics ===*1
1*=== use active page ===*1
/*=========================================*1
case write_tty:
if(redirect flag 1= 0)
( -
myblock -> ax = ax & OxOOff;
myblock -> dx :I 0;
sys int(Ox17,myblock);
} -
1* get current cursor *1
myblock->row = peekb40(cursor-POsn + (ACTIVE PAGE 1)+1);
myblock->col = peekb40(cursor-POsn + (ACTIVE:PAGE 1;
switch (ax & OxOOff)
(
case bell:
beep();
break;
case backspace:
if (myblock->col !=O) myblock->col--;
break;
case carriage return:
myblock->col = 0;
break;
case line feed:
if (mybloek->row == 24)
(
/* find the fill attribute *1
myblock -> ax = Ox0800;
II set bh to active page
myblock -> bx = ACTIVE PAGE"
myblock -> bx = myblOCK -> ~ x 8;
sys int(VIDEO IO,myblock);
II set bh to Slank line attribute
myblock -> bx = (myblock -> ax & OxffOO);
myblock -> ax = Ox0601; 1* scroll call */
myblock -> cx = 0"
myblock -> dx = ( ~ 4 8) I (CRT_COlS - 1);
sys int(VIDEO IO,myblock);
} - -
else
{
myblock->row++;
}
break;
default: /* any other character */
myblock -> ax = (write c current 8) I (ax & OxOOff);
myblock -> bx = ACTIVE-PXGE"
myblock -> bx = myblocK -> ~ x 8;
myblock -> ex = 1;
sys_int(VIDEO_IO,myblock);
The Video Driver E 7 11
Section E: The C Pro&rams
E 7 12 The Video Driver
myblock->col++;
if (myblock->col >= CRT_COLS)
{
)
)
myblock->col = 0;
if (myblock->row == 24)
(
/* find the fill attribute */
myblock -> ax = Ox0800;
myblock -> bx = ACTIVE PAGE
myblock -> bx = myblOCK -> bX 8;
sys int(VIOEO_IO,myblock);
mybTock -> bx = (myblock -> ax & OxffOO);
myblock -> ax = Ox0601;
myblock -> cx = O
myblock -> dx = (24 8) I (CRT_COlS - 1);
sys int(VIOEO IO,myblock);
) - _. .
else
{
myblock->row++;
}
break;
myblock->temp = (myblock->row 8) I (myblock->col & OxOOff);
poke40(cursor-PQsn+ACTIVE_PAGE) 1),myblock->temp);
load 6845 word(14,(CRT START +
* CRT_CDLS) + myblocx->col ) 1) 1 );
break;
/*===========================================*/
/*=== ===*/
/*=== AH = 15 = return video state ===*/
/*=== ===*/
/*=== AH = # of cols ===*/
/*=== AL = mode ===*/
/*=== BH = page ===*/
/*=== ===*/
/*===========================================*/
case return_video_state:
ax = (CRT COLS 8) I CRT MODE;
bx = (bx 'OxOOff) I (ACTIVE_PAGE 8);
break;

/*=== ===*/
/*=== AH = 19 = write string ===*/
/*=== ===*/
/*=== ES:BP = pointer to string ===*/
/*=== CX = length of string ===*/
/*=== OX = cursor position ===*/
/*=== BH = page # ===*/
/*=== ===*/
/*=== AL = 0 = write string - don't move cursor ===*/
/*=== BL = attribute ===*/
/*=== AL = 1 = write string - move cursor ===*/
/*=== BL = attribute ===*/
/*=== AL = 2 = write char and attribute ===*/
/*=== - don't move cursor ===*/
/*=== AL = 3 = write char and attribute ===*/
/*=== - move cursor ===*/
/*=== ===*/
/*====================================================*/
case write_string:
/* if count> 0 and 0-3 */
if cx != 0) && ax & OxOOff) <= 3
(
/* save current cursor for this page */
myblock->temp_cursor = peek40(cursor-PQsn+(bx 8)1);
/* set cursor to callers position */
myblock -> ax = (set cursor-PQsition 8);
myblock -> dx = dx; -
myblock -> bx = bXi
sys int(VIOEO IO,mvblock);
mybTock->row = myblock -> dx 8
myblock->col = myblock ->dx & Ox06ff;
A Type BiosKit
}
}
}
for (myblock->i = 0i myblock->i < cx; myblock->i++)
(
myblock->outchar = peekb(es,bp+myblock->i);
}
if myblock->outchar == backspace) II
(myblock->outchar == carriage return) II
(myblock->outchar == line feea
{ -
myblock -> ax = (write tty 8) I myblock->outchari
myblock -> bx = bXi -
sys int(VIDEO IO,myblock)i
mybTock->row = (peek40(cursorJPOsn+(bx 8)1 8;
myblock->col = peek40(cursor-PQsn+(bx 8)1);
}
else
{
myblock -> cx = 1;
myblock -> bx = bx
if (ax & OxOOff > ~ )
(
}
myblock -> bx = peekb(es,bp);
bp++;
myblock -> ax = (write ac current 8) I myblock->outchar;
sys int(VIDEO IO,mybloek);
mybTock->col++;
if (myblock->col (CRT COlS
{ -
myblock->row++;
if (myblock->row >=25)
{
}
}
myblock->col = 0i
myblock -> ax = (write tty 8) I line_feed;
sys int(VIDEO_IO,mybloek);
mybTock->row--;
1* update cursor */
myblock -> ax = (set cursorJPOsition 8);
myblock -> dx = (mybTock->row 8) I myblock->col;
sys int(VIDEO IO,myblock)i
} - -
1* restore original cursor *1
if ax & 1) == 0)
(
poke40cursorJPOsn + CCbx 8) 1,mvblock->temp cursor);
myblock -> ax = (set cursorJPOsition 8); -
myblock -> dx = myblOck->temp cursor; .
sys int(VIDEO IO,myblock); -
} - -
break;
1*===========================================*1
1*=== ===*1
1*=== default case for invalid opcodes ===*1
1*=== ===*1
/*===========================================*/
release blockCmyblock);
} -
1*=============================================*1
/*=== ===*1
1*=== SUPPORTING FUNCTIONS ===*1
1*=== ===*1
1*=============================================*/
/1 find position - returns offset page*row*col
unsigned findJPOsi tionO
(
}returnCfind-P8geJPOsitionCACTIVE_PAGE;
unsigned find-P8geJPOsition(unsigned char page)
(
unsigned temp, length
unsigned char row,col;
temp = peek40(cursorJPOsn + Cpage 1;
row = temp 8;
col = temp;
The Video Driver E-7 -13
Section E: The C Pro&rams
E714 The Video Driver
length = CRT lENGTH;
teq:> = length *
return(teq:> + position(row,col;
}
/*---
**--- calc buffer address of character at AX = row,col
**--- returns ax offset of character in buffer
*/
unsigned position(unsigned char row,unsigned char col)
(
return(row * CRT COlS)+col)1);
} -
/*---
**--- scroll end
*/
void scroll end()
{ -
if (CRT MODE != 7) outportb(Ox3d8,CRT MODE SET);
} - - -
/*---
**---
convert cursor position to buffer offset
*/
unsigned cursor to offset()
( - -
return(peek40(cursor-POsn) 8) * CRT_COlS * 4) + CURSOR_POSN & OxOff);
}
/*---
**--- convert input row-col to buffer offset
*/
/* input is row, col position */
unsigned calc offset(unsigned input)
( -
return(input 8) * CRT COlS * 4) + input & OxOff);
} -
/*---
**---
*/
return alpha or graphics mode flag
unsigned check mode()
{ -
if CRT MODE >= 4) && (CRT MODE <= 6 return(is_graphics);
return(ii alpha); -
} -
/*---
**---
**---
*/
expand the byte for mediun res.
double the input byte to an output integer
unsigned expand byte(unsigned char the byte,
{- -
register = O
unsigned char mask = Ox80;
while (mask != 0)
{
}
= temp 2;
if the bYte & mask) != 0)
ifcolor & Ox80) == 0)
else
temp 1= (color & Ox03);
A= (color & Ox03);
mask = mask 1;
unsigned char color)
return(temp 8) & OxOOff) 1 temp 8 ) & OxffOO;
}
/*---------------------------------------------------*/
/*--- ---*/
/*--- load a word into the 6845 reg 'n' and 'n'+1 --*/
/*--- ---*/
/*---------------------------------------------------*/
void load 6845 word (unsigned address,l.I1Signed value)
( --
load 6845 value 8);
load:6845!byte(address + 1, value);
} - -
A-Type BiosKit
/*------------------------------------------------*/
/*--- ---*/
/*--- load a byte into the 6845 reg 'n' ---*/
/*--- . ---*/
/*------------------------------------------------*/
void load 6845 byte(unsigned address,unsigned char value)
( --
outportb(ADDR 6845 address);
outportb(AOaR 6845) + 1),value);
} -
unsigned swap(unsigned aword)
(
returnaword 8) I (aword 8;
}
The Video Driver E 7 15
Section E: The C Pro&rams
The Floppy Disk Driver E81
EIGHT
The Floppy Disk Driver
The Floppy Disk Driver is used to operate the floppy disk.
This driver structure has been organized to support up to four (4) floppy disk drives.
The normal AT style disk controller does not provide the motor and select logic to
do so. Two possible options are to:
1. Install a second controller at an alternate address and sense which port address
should be referenced for each drive. This would entail declaring a "port" variable
which would be used on the inport and outport commands.
2. Install a controller which does support four drive configurations. If such a
controller is not commercially available, one may design and construct such a
device by duplicating the standard functions and adding the required motor and
select logic. Since newer LSI based floppy disk controllers (such as the Intel 82072)
simplify this task, one may wish to consider this alternative.
Presuming that the new perpendicular-recording 4 Mbyte floppy disk drives will
become desired options, the disk parameter tables are organized for easy expansion.
By inspecting the defined tables in the source file, one will observe that some entries
are already included for the 4 Mb drives. Take note that these drive parameters
(and the 4Mb drives) have not been installed or tested on the Bios development
system, so that some additional development work will be required to implement
the 4 Mb drive type.
The standard location in the CMOS RAM for storing the drive types for Drive A:
and B: is cell 10 hex. We have chosen the "reserved" cell 11 hex for storing the type
byte for floppy Drives C: and D:.- If these should conflict with some other use, they
may be re-assigned as you wish.
For those of you who are creating diskless systems, our Annabooks PromKit
publication provides additional information on how the standard floppy disk driver
may be replaced / chained / enhanced so a different physical device may be used
for a logical floppy disk.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
: Module Name: AT Bios enhanced floppy disk driver
* Version: 1.02
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: atdisk.c
*
: Functional Description:
* Argunents:
*
* Return:
*
* Version History:
* 1.01
E8 2 The Floppy Disk Driver
* Moved misplaced perm table entry for 720k drive from index 2 to index 3
* 1.02
* Replaced peeks and pokes with casts
: Moved variables to myblock
***************************************************************************************************/
/* INC L U 0 E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
void fdisk setup(void);
void interrupt cdecl far disk io(void);
void interrupt cdecl far disk:isr(void);
unsigned char send fdc(unsigned char);
void send rate(unsTgned);
unsigned retry(unsigned);
unsigned char med change(unsigned);
unsigned char calc sectors(unsigned);
unsigned char cmos-type(unsigned char);
unsigned char char);
unsigned char wait int(void);
unsigned recal(unsTgned);
unsigned char seek(unsigned);
void wait for head(unsigned);
uns i gned Char-read i d( uns i gned) ;
unsigned char get Tdc status(unsigned);
unsigned char reaa dSKchng(unsigned);
unsigned char resuTts(void)c
unsigned char chk stat 2(VOld);
vo id send spec i fy - conmind( uns i gned) ;
void FOC reset(uniigned);
void delay call(unsigned,unsigned)i
unsigned cnar dma setup(unsigned,unsigned,unsigned);
void purge fdc(voTd)c
unsigned cnar fdc_inlt(unsigned);
/* G LOB A L CON S TAN T S */
extern disk io;
extern :disk:isr;
/* G LOB A L V A R I A B L E S */
/* L 0 CAL 0 E FIN I T ION S */
#define FOC STATUS Ox42
#define olsf 10 Ox90 /* drive/media type */
#define LAST:TRACK Ox94 /* 94-97 holds last track number */
#define RATE 500 OxOO
#define Ox01
#define RATE-2S0 Ox02
#define RATE-1000 Ox03
#define INT 'LAG BIT7
#define MOTOR_WAIT Ox25
#def i ne BAD CtI) Ox01
#define BAD-ADOR MARK Ox02
#define WRITE PROTECT Ox03
#define RECORD' NOT FNO Ox04
#define MEDIA Ox06
#def i ne BAD oRA OxOS
#def i ne OMA-BOONOARY Ox09
#define MEO-NOT FND OxOc
#define BAD-CRC- Ox10
#define BAD-FOC Ox20
#define BAD-SEEK Ox40
#define OxSO
/* function code definitions */
#define RESET OxOO
#define READ STATUS Ox01
#define READ-SECTORS Ox02
#def i ne WR I SECTORS Ox03
#define VERIFY SECTORS Ox04
#define FORMAT-TRACK OxOS
#define DISK PXRMS Ox08
#define Ox1S
#define DISK-CHANGE Ox16
#define FORMXT SET Ox17
#define SET_MED'IA Ox18
A Type BiosKit
#define BAD_FUNCTION Ox19
#define TRY Oxff
/* FOC port definitions */
#define OOR PORT Oxlf2
#define NSR-PORT Oxlf4
#define PORT OxlfS
#define DIR Ox3f7
#define ORR:PORT Ox3f7
#define RQM BIT7
#define 010 BIT6
#define BUSY BIT4
#define OSKCHANGE_BIT BIT7
/* DNA port definitions */
#def i ne OMA MASK OxOa
#def i ne DMA -..oDE OxOb
#define OMA-FLFF OxOc
#define OMA-ADR Ox04
#define DMA-BASE OxOS
#define DMA:PAGE Ox81
/* OMA literal definitions */
#def i ne OMA ON Ox02
#define OMA-OFF Ox06
#def i ne OMA -RX MOOE Ox46
#define DMA-TX-MODE Ox4a
#def i ne OMA -VRrt MODE Ox42
#define TX Ux01
#define RX:PIR OxOO
/* FOC commands */
#def i ne FOC READ Oxe6
#define FDC-WRITE OxcS
#def i ne FDC-FORMA T Ox4d
#define FDC:READID Ox4a
!*=== These are the floppy disk parameter tables =====
The Floppy Disk Driver E83
* The tables are organized as an Array of up to 8 Drive types, each supporting up to 8 media types.
* Each i tam is 16 bytes long
*
*/
/* DISK TABLE indexes */
#define OT SPEC1 0 /I specify cornmand 1
#define OT-SPEC2 1 /I specify cornmand 2
#define DT-OFF TIM 2 // motor off count
#define OT-BYT-SEC 3 // bytes/sector
#define DT-SEC-TRK 4 // sectors/track
#define DT-GAP) // gap
#define DT-oTL 6 // dtl
#def i ne DT-GAP3 7 // gap 3 for format cornmand
#define OT-FIL BYT 8 /I fi II byte for format cornmand
#define OT-HD TIM 9 // head settle time
#define OT-STI TIM 10 // motor start time
#define DT1NAx-TRK 11 // max , of tracks for drive
#def i ne DT-RA T! 12 // data rate
#define DT-TYPE // drive and media type (not used)
#define DT:STEP 14 /1 double step flag
#define drive established Ox08
#define drive-field Ox07
#define drive-none 00
#define 01
#define drive-12 02
#define 03
#define drive-14 04
#define drive:28 05
#define media established Ox80
#define media-field Ox70
#define media-none OxOO
#define Ox10
#define media-12 Ox20
#define OxlO
#define media-14 Ox40
#define media-28 OxSO
// media definitions for transition table
Section E: The C Pro&rams
E84 The Floppy Disk Driver
#def i ne m none OxO
#define Ox1
#define m-12 Ox2
#def i ne m f20 0x3
#define m-14 Ox4
#define m:28 OxS
#define m_wait Ox2S
1* L 0 CAL CON S TAN T S *1
const unsigned char transition table[8] [4]= {
II This table covers the of media type to try for
II each drive type in establishing the media in the drive.
II The media is defaulted to the first item in this table
II for a particular drive type. When we attempt retries, we
II step through the possible media types until we come
II to "none" marking the end of the table.
1* drive type 0 (None) *1 {m none,m_none,m_none,m_none},
1* drive type 1 ( 360) *1 m none,m_none,m_none},
1* drive type 2 ( 1.2) *1 {m 126 m_none,m_none},
1* drive type 3 ( 720) *1 , m none,m none,m none},
1* drive type 4 (1.44) *1 {m-14, mf20, m-none,m-none},
1* drive type 5 (2.88) *1 {m:28, m:14, m:none},
1* drive type 6 unused *1 {m_none,m_none,m_none,m_none},
1* drive type 7 unused *1 {m_none,m_none,m_none,m_none},
}i
const unsigned char fdisk table [8] [8] [16]= {
1* this entry is for compatibility with the XT disk driver *1
{
1* ---- drive type 0 = None (Default to 360) ----*1
{OxOaf,2,m_wait
6
2
6
9
6
0x2a,-1
6
0xSO,OxOf6,15,8,39,RATE_25O,drive_36OImedia_36O,0,0},
{O,O,O,O,O,O,O, , , ,0,0,0, ,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
1* ---- drive type 1 = 360 ----*1
1* 0 = no media in 360 kb drive *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
1* 1 = 360 kb media in 360 kb drive *1
{OxOaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,.39,RATE_250,drive_36OImedia_36O,0,O},
1* 2-7 not used *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
1* ---- drive type 2 = 1.2 ------*1
1* 0 = no media in 1.2 mb drive *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
1* 1 = 360 kb media in 1.2 mb drive *1
{Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,39,RATE_300 ,drive_12Imedia_36O,1,O},
1* 2 = 1.2 mb media in 1.2 mb drive *1
{Oxaf,2,m_wait,2,15,Ox1b,-1,Ox54,OxOf6,15,8,79,RATE_500 ,drive_12Imedia_12,O,0},
1* 3-7 = not used *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
1* ---- drive type 3 = 720 ------ *1
A-Type BiosKit
/* = no media in 720 kb drive */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
/* 1-2 = not used *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
The Floppy Disk Driver E85
/* 3 = 720 kb media in 720 kb drive *1
{OxOaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_720Imedia_720,O,O},
/* 4-7 = not used */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
/* ---- drive type 4 = 1.44 ------*/
/* = no media in 1.44 mb drive *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
/* 1-2 = not used *1
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
1* 3 = 720 kb media in 1.44 mb drive *1
{Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_14Imedia_720,O,0},
/* 4 = 1.44 kb media in 1.44 mb drive */
{Oxaf,2,m_wait,2,18,Ox1b,-1,Ox6c,OxOf6,15,8,79,RATE_500 ,drive_14Imedia_14,O,O},
/* 5-7 = not used */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
/*---- drive type 5 = 2.88 ------*/
// The 2.88 Meg drives have not been tested.
// These tables are included as a help to integrating 2.88 drives into your system.
II The correct parameters must be determined in conjunction with the drlve manufacturers
II specifications.
/* = no media in 2.88 mb drive */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
/* 1-2 not used */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
/* 3 = 720 kb media in 2.88 mb drive */
{Oxaf,2,m_wait,2,9,Ox2a,-1,Ox50,OxOf6,15,8,79,RATE_250 ,drive_28Imedia_720,O,0},
/* 4 = 1.44 kb media in 2.88 mb drive */
{Oxaf,2,m_wait,2,18,Ox1b,-1,Ox6c,OxOf6,15,8,79,RATE_500 ,drive_28Imedia_14,O,O},
/* 5 = 2.88 kb media in 2.88 mb drive */
{Oxaf,2,m_wait,2,36,Ox1b,-1,Ox53,OxOf6,15,8,79,RATE_100O,drive_28Imedia_28,O,O},
/* 6-7 not used */
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
1*---- drive type 6 = reserved ------*/
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
{O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O},
},
{
1*---- drive type 7 = reserved ------*/
Section E: The C Pro&rams
E86 The Floppy Disk Driver
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),

(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0),
},
};
/* PRO G RAM */
/*********************************************************
*
: FOSCO Enhanced Floppy Disk Driver
: Copyright FOSCO 1988, 1989
**********************************************************1
/*
This driver uses a drive/media id byte as follows:
bit 7 0/1 = media not established I established
bit 6-4 media
000 = no establlshed media
001 = 360 (40/SO track)
010 = 1.2 (SO track)
011 = 720 (SO track)
100 = 1.4 (SO track)
101 = 2.8 (SO track)
110 - 111 reserved
bit 3 = 0/1 = drive not established I established
bit 2-0 Drive type
000 no established drive type
001 = 360 (40 track)
010 = 1.2 (SO track)
011 = 720 (SO track)
100 = 1.4 (SO track)
101 = 2.8 (SO track)
110 - 111 reserved
The drive/media bytes are located at 40:90-93 for up to four drives.*1
1*======================================================*1
1*=================== START OF CODE ====================*1
1*======================================================*1
variables
unsigned char fd drive type;
unsigned char fastate;
uns i gned char fa fdc comnand;
unsigned char fadna-comnand
unsigned char fasector
unsigned char famedia type;
unsigned char fafcode;
unsigned char fadrive;
unsigned char fanr sectors;
unsigned char fdrheid;
unsigned char fasector;
unsigned char fatrack;
unsigned fd max track;
unsigned famax-sectors;
unsigned fai; -
unsigned fatry count;
unsigned fameOi'a index;
unsigned char ena-track,end head,end sector,num sectors,sectors track;
unsigned dma address; - - - -
unsigned loni lcheck;
unsigned nibble, upper byte, lower byte, length;
unsigned char error byte, time out flag;
end_variables fdisk:regs; - -
1*-------------- setup the controller -----------*1
void fdisk setup ()
( -
fdisk regs *myblock
mybloek = acquire_b(ock(FLOPPY);
link_interrupt(Ox13,&_disk_io);
A-Type BiosKit
link interrupt(OxOe,& disk isr)
set_vector(Ox1e,bios_cs(),lfdisk_tableCO] [0] [0]);
outportb(Ox21,inportb(Ox21) & -BIT6); II unmask
SEEK STATUS = 0; 1* clear seek status *1
COUNT = O 1* clear motor count *1
MOTOR-STATUS = 0; 1* clear motor status *1
= 0; 1* clear disk status *1
HF CNTRL 1= 1;
WAIT 1= 1

pokeb40(DISK-ID+1,0);
pokeb40(DISK-ID+2,0);

1* clear drive 0 state *1
1* clear drive 1 state *1
1* clear drive 2 state *1
1* clear drive 3 state *1
pokeb40(DISK ID+O,cmos type(O;
pokeb40(DISK-ID+1,cmos-type(1;
pokeb40(DISK:ID+2,cmos:type(2;
pokeb40(DISK_ID+3,cmos_type(3;
int's
RTC WAIT FLAG &= Oxfe; 1* allow for rtc wait *1
= get-PBrm(myblock,2); 1* set motor count */
myblock -> dx = OxOOOO;
myblock -> ax = OxOOOO; 1* reset the FDC *1
sys_int(Ox13,myblock);
release blocK(myblock);
) -
1*========================================================*1
1*========================================================*1
1*========================================================*1
1*======== BEGINNING OF MAIN ROUTINES ===================*1
1*========================================================*/
/*========================================================*1
1*========================================================*/
1* handle the floppy disk function service call *1
void interrupt cdecl far disk io(interrupt registers)
( --
The Floppy Disk Driver E8 7
fdisk regs *myblock;
/1 disible(); II some XT type disk controllers will pre-enable
myblock = acquire_block(FLOPPV);
1/ enableO;
snapshot_in(FLOPPV,&es);
myblock->fd fcode = ax 8
myblock->fdrdrive = dx & OxOOff;
myblock->fdrnr sectors = ax & OxOOff;
myblock->fdrheid = dx 8
myblock->fdrsector = cx & OxOOff;
= cx 8;
flags &= -Ox0001; /* clear the carry flag for returns *1
DISK_STATUS = 0; 1* clear status *1
if (ax 8) 1= 0) && dx & OxOOff) > 3
{ II bad function code because of drive number
DISK STATUS = BAD CMO; ax = (BAD CMO 8) 1 (ax & Oxff);
flags 1= 1; 1* sit return error-flag *1
)
else
(
1* make sure any residual status is unloaded */
purge fdc();
/* set the data rate register to a default value *1
outportb(DRR_PORT,RATE_250);
switch (myblock->fd fcode)
( -
case RESET: 1* reset the disk controller */
watch string(FLOPPV,"Reset");
Foe reset(myblock);
ax = (DISK STATUS 8) Il (ax & Oxff);
if ax & UxffOO) != 0) fags 1= 1;
break;
case READ STATUS:
watch strTng(FLOPPV,"Read Status");
ax = STATUS 8
if ax &-OxffOO) != 0) flags 1= 1;
break;
Section E: The C Pro&rams
E88 The Floppy Disk Driver
case READ SECTORS: /* read sectors */
watch strTng(FLOPPY,"Read sectors");
MOTOR-STATUS &= -INT FLAG;
rnybloek->fd fde comnind = FDC READ;
myblock->fdrdma-command = OMA-RX MODE;
goto read_write:verify; --
case WRITE SECTORS:
watch stri;lg(FLOPPY6"Write sectors");
MOTOR-STATUS /= Ox8 ;
mybloek->fd fde command = FDC WRI!!i
myblock->fdrdma-command = DMA-TX JlllWE;
goto read_write:verify; --
case VERIFY SECTORS:
watch strinj(FLOPPY,"Verify sectors");
MOTOR-STATUS &= -INT FLAG;
rnybloek->fd fde_commind = FDC_READ;
rnyblock->fdrctna command = DMA VRFY MODE;
goto read_write:verify; --
read_write_verify:
// if a media change sensed, then de-establish media
if (med change(myblock) == error)
( -
andb40(DISK ID+myblock->fd drive,OxOf);
myblock->fdrmedia index = U;
} --
rnyblock->fd try count = 3-
do // this-is the major loop, try the major operation 3 times
(
watch_string(FLOPPY,"\n\rMajor Loop");
// if media not established, then set media type = drive type
// set media_index = 0, set media type by index
if peekb40(DISK ID+myblock->fd drive) & media established) == 0)
( - - -
// set the media index for the first possible type of media
myblock->fd_drive_type = & Ox07i
II set the DISK to with the first media type to try
pokeb40(DISK ID+myblock->fd drive,(peekb40(DISK ID+myblock->fd drive) &
-media field) I - - -
- (peeibcs(&transition table[myblock->fd drive type] [0]) 4;
// set the media type according to the drive type [iriaex = U]
}myblOCk->fd_media_type = (peekb40(OISK_ID+myblock->fd_drive) 4) & Ox07i
do II this is the minor loop
/1 do I.I1ti l we rim out of retrys
(
watch string(FLOPPY," Minor Loop II);
purge:fde()i 1* make sure any residual status is unloaded */
/I set drive and media indexes before doing the dna setup,
/I which needs to know how many bytes per sector for calcing xfr length
myblock->fd drive type = peekb40(DISK tD+myblock->fd drive) & Ox07i
myblock->fdrmedia-tYDe = (peekb40(DISf ID+myblock->fa drive) 4) & Ox07;
watch strinj(FLOPJSY:h Disk to byte = Ill; -
watch:Pvte(FlOPPY,peekb40(OISK_ID+myblock->fd_drive;
if (ana setup(myblock,es,bx) == ok)
( -
/* send the specify command *1
send fde(3);
sena-fde(get-P8rm(myblock,Oi

send_rate(myblock)i
if (fde init(myblock) == ok)
{ -
if (send fdc(rnyblock->fd track) == ok)
{- -
if (send fdc(rnyblock->fd head) == ok)
{- -
if (send fdc(myblock->fd sector) == ok)
{- -
if (send fdc(get narm(myblock,3 == ok)
{ _ ..r-
if (send fde(get narm(myblock,4 == ok)
( _ ..r-
if (send_fde(get,J)8rm(myblock,S == ok)
A-Type BiosKit
The Floppy Disk Driver E89
(
if (send_fdc(get-P8rm(myblock,6 == ok)
(
if(get fdc status(myblock) == ok)
( --
operation
orb40(DISK_ID+myblock->fd_drive,media_established); break; II get out with good
}
}
}
}
}
}
}
}
}
}
}
while (retry(myblock) == error);
watch string(FLOPPY,"\n\rDISK STATUS = 1I);watch byte(FLOPPY,DISK STATUS);
} - --
while --myblock->fd try count> 0) &&
peekb40(DISK-ID+ffiyblock->fd drive) & media established) == 0) &&
DTSK STATUS & TIRE OUT) 1= TIME-OUT;
ax = (DISK STATUS 8) T (calc sectors(myblock; -
if ax & OxffOO) != 0) flags 1= 1;
break;
case FORMAT TRACK: 1* format track *1
watch string(FLOPPY,"Format trackll)t"
mybloek->fd fdc_command = FDC_FORMA ;
myblock->fdd'na command = DMA TX MODE;
II if media-not-established then set media t'(Pe = drive type
if peekb40(DISK ID+myblock->fd drive) & medla established) == 0)
ID+myblock->ld drive -
(piekb40(DISK ID+mMblock->fd drive) & Ox07) 1
piekb40(DISK_ID+ffiyblock->fd_drive) & Ox07) 4;
MOTOR STATUS 1= Ox80; /* indicate write operation *1
if (mid change(myblock) == ok) 1* check for media change */
( -
watch string(FLOPPY,"\n\rNo media chan2ell);
send ldc(3); /* send specify command /
sendfdc(get.J)8rm(myblock,O;

watcn strlnglFLOPPY,"\n\rSpeclfy Command Sent");
send rate(myblock);
if (ams setup(myblock,es,bx) == ok)
( -
}
}
watch string(FLOPPY,"\n\rDma Setup Ok");
if (fac init(myblocK) == ok)
( -
}
watch string(FLOPPY,"\n\rFDC Init Ok");
if (send fdc(get nArm(myblock,3 == OK)
( - .....-
watch string(FLOPPY,"\n\rSent parm 3
11
);
if (send fdc(get nArm(myblock,4 == OK)
( - .....-
watch string(FLOPPY,"\n\rSent parm 4
11
);
if (send fdc(get nArm(myblock,7 == OK)
( _ ..r-
}
}
}
watch_string(FLOPPY,"\n\rSent parm 7");
send 1* send command *1
watcn_strmglFLOPPY,"\n\rFDC Commands all sent");
get fdc status(myblock);
watCh_string(FLOPPY,"\n\rFDC status rx'd");
ax = DISK STATUS 8-
if ax &-OxffOO) != 6) flags 1= 1;
break;
case DISK PARMS : 1* read drive parameters */
watch strTng(FLOPPY,"Read disk parms
ll
);
ax = Ex = cx = dx = es = 0i 1* reset all registers *1
if (myblock->fd drive> OxeO)
{ -
lax = (ax & Oxff) 1 (BAD_CHO 8); flags 1= 1; 1* set return error flag *1
Section E: The C ProlUams
E810 The Floppy Disk Driver
else
{
if EQUIP FLAG & Ox01) 1= 0) 1* there are drives present */
{ -
di = dx; II save old dx temporarily
dx = EQUIP FLAG 6;
1* return J of drives in dx */
if (di > dx) 1* called for a non-existent drive *1
di = 0; 1* return with null parameters *1
else
{
di = 0;
if (cmos type(myblock->fd drive) 1= 0) 1* get parms for this type */
(- -
myblock->fd_drive_type = myblock->fd_media_type = cmos_type(myblock->fd_drive) & Ox07;
di = &fdisk table[myblock->fd drive type] [myblock->fd media [0];
track = peikbcs(Ifdisk type] [myblock-
>fd medi a type] [DT-SEC TRf]); - --
- = peekbcs(&fdisk table[myblock->fd drive type] [myblock-
>fd media - --
- cx-= myblOck->fd max track 8) & OxffOO) / (myblock->fd sector track & Ox3f);
dx = (1 8) I dx':' - - -
bx = cmos type(myb(ock->fd drive) & Ox07;
es = bios-cs(); II nieds to be our code segment
) -
)
)
)
break;
case DISK TYPE: 1* read disk type *1
watch_strTng(FLOPPY,"Read disk type");
ax &= OxOOff; 1* no drive */
peekb40(DISK_ID+myblock->fd_drive) & drive_field) 1= drive_none)
if peekb40(DISK_ID+mblock->fd_drive) & drive_field) .= drive_36O)
(
ax /= Ox0100; 1* 40 track, no change line */
)
else
(
)
ax /= Ox0200; /* 80 track, change line */
)
break;
case DISK CHANGE: /* return change line condition */
watch strTn\J(FLOPPY,"Read disk change line");
1* if-no dr1ve - then return a timeout condition */
if peekb40(DISK ID+myblock->fd drive) & drive field) == drive_none. )
( - - -
DISK STATUS /= TIME OUT;
) - -
else
{
/* if 360 k drive - always return disk change */
if peekb40(DISK ID+myblock->fd drive) & drive field) == drive 360)
DISK STATUS = MEDTA CHANGE; - - -
else- -
1* if 720, 1.4, or 2.8 drive - read the change line */
if (read dskchng(myblock) f. 0 )
DISK STATUs. MEDIA CHANGE;
) - -
ax = (DISK STATUS 8) I (ax & Oxff);
if ax & UxffOO) 1= 0) flags /= 1;
break;
case FORMAT SET : /* set disk type */
watch_stri"g(FLOPPY,"Set disk type");
1* set drive to requested format/media */
myblock->fd_drive_type = peekb40(DISK_ID+myblock->fd_drive) & Ox07;
switch (ax & OxOOff) /* use requested type for switch */
(
case 1: /* 360/360 */
if(mvblock->fd drive type == drive 360)
pokeb40(DISK drive,fmedia 360 drive_360 / media_established;
break; - - -
case 2: /* 360/1.2 */
if(mvblock->fd drive type == drive 12)
drive_12 / media_established;
A-Type BiosKit
The Floppy Disk Driver E81I
break;
case 3: /* 1.2/1.2 */
if(mvblock->fd drive type == drive 12)
drive_12 1 media_established;
break;
case 4: /* 720/720 */
if(mvblock->fd drive type == drive 720)
drive_720 1 media_established;
break;
default:
DISK STATUS = BAD CMO; /* bad conmand * /
breai; -
}
ax = (DISK STATUS 8) I (ax & Oxff);
if ax & UxffOO) 1= 0) flags 1= 1;
break;
case SET MEDIA : /* set media type */
watch st'Fing(FLOPPY,IISet media type");
// get the max tracKS called for
myblock->fd max track = (cx 8) 1 cx 2) & 0x300);
// get the max sectors called for
myblock->fd max sectors = cx & Ox003f;
if (cmos type(myblock->fd drive) 1= 0)
(- -
myblock->fd drive = cmos type(myblock->fd drive) & Ox07;
watch string(FLOP'Y, '\n\rDrive 1S ")iwatch byte(FLOPPY,myblock->fd drive);
watch-string(FLOPPY,"\n\rDrive type 1S ");watch_byte(FLOPPY,mybloci->fd drive type);
// -myblock->fd drive type = peekb40(DISK ID+ffiyblock->fd drive)& Ox07; -
// use the transition tible for this drive - -
for (myblock->fd i= O;peekbcs(&transition table[myblock->fd drive type] [myblock->fd il) 1=
Omyblock->fd i++) - - - - -
, ( -
myblock->fd media tvce = peekbcs(&transition table[myblock->fd drive type] [myblock->fd ill;
watch_stri"g(FLOPPV:"\n\rMedia type is ");watch_byte(FLOPPY,my6lock->fd_media_type); -
if myblock->fd max sectors == peekbcs(&fdisk table[myblock->fd drive type] [myblock-
>fd medi a typel [DT SEC TRfJ && \ - --
- - - (ffiyblock->fd_max_track == peekbcs(&fdisk_table[myblock->fd_drive_typel [myblock-
>fd media typel [DT MAX TRK])
-{ - - - .
// return the disk perms ptr to the caller
di = &fdisk_table[myblock->fd_drive_typel [myblock->fd_media_typel [0];
es = b10S cso-
// set the id to the established supported media
pokeb40(DISK drive type 1 (myblock->fd_media_type 4)
drive established I media established); - -
watch-string(FLOPPi',"\n\rAedia established, drive byte is: II);
ID+myblock->fd drive;
1/ need a break to say OK here-III -
goto set media exit;
} --
}
if (peekbcs(&transition table[myblock->fd drive typel [myblock->fd i]) == 0)
DISK STATUS = MED NOT FlO; - - -
} - - -
set media exit:
ax = (DISf STATUS 8) I (ax & Oxff);
if ax & UxffOO) 1= 0) flags 1= 1;
break;
default: /* invalid function code - return bad code */
watch string(FLOPPY,"Bad COIIEnd");
DISK !TATUS = BAD CMO;
ax =-(BAD CMO 8) I (ax & Oxff);
flags 1= T; /* set return error flag */
} /* end of switch */
}
snapshot_out(FLOPPY,&es);
MOTOR_COUNT = get-P8rm(myblock,2); /* set motor count */
release_block(mybTock);
} /* end of disk_io */
/*=======================================================*/
/*=======================================================*/
Section E: The C Pro&rams
E812 The Floppy Disk Driver
1* reset the disk system *1
void FOC reset(fdisk regs *myblock)
(- -
unsigned i
unsigned status;
disable();
status = (MOTOR STATUS 4) 1 8;
II if a motor is on, set the drive select bits accordingly
switch (status & OxfO)
{
1* motor 2 on *1
case Ox20: status 1= Ox01; break;
1* motor 3 on */
case Ox40: status 1= Ox02: break;
1* motor 4 on */
case Ox80: status /= Ox03; break;
}
outportb (OCR PORT,status): 1* reset disk controller */
SEEK STATUS =-0;
outpOrtb (OCR PORT,status 1 Ox04); 1/ reset the reset bit
enable(); 7* enable interrupts */
/* wait for interrupt */
if (wait int() == error) { DISK STATUS 1= BAD FOC; return; }
for (i =-0; i < 4: i++) /* number of drives-*I
(
1* send command *1
if (send_fdc(8) == error) { DISK_STATUS /= BAD_FOC; return; }
1* check results *1
if (results() 1= ok) { DISK STATUS 1= BAD FOC; return }
}if (peekb40(FOC_STATUS) 1= {i / OxcO { 1= BAD_FOC; return; }
send specify command(myblock);
} - -
1*========================================================
When the hardware occurs from the floppy disk,
this function sets bit 7 1n the seek status flag and sends
an endof-interrupt command to the 8259.
----_._--_._._----------_ _------_ _._--_. __ ._---*/
void interrupt cdecl far disk isr (void)
{ -
SEEK STATUS 1= INT FLAG: outportb (Ox20,Ox20); /* send eoi */
} - -
1*===:================::=======================:===========
Return the drive type for a specified drive.
--_ .. _-_._-.--.- .. __ ._._------.---_._----_._--._---_.-_._*/
unsigned char cmos (unsigned char drive nr)
{ - -
unsigned char drive type = 0;
switch(drive nr) -
( -
case 0: drive type = incmos(Ox10) 4 break;
case 1: drive-type = incmos(Ox10) & Ox6f; break:
case 2: drive-type = incmos(Ox11) 4 Dreak;
case 3: drive-type = incmos(Ox11) & Ox6f: break:
} -
if (drive_type 1= 0) drive_type 1= drive_established;
return(drlve type):
} -
1*========================================================
Send a byte to the Foe.
---------------------------_._.-_._---------------------*/
uns i gned char send fdc( uns i gned char pann)
{ -
unsigned long i = set_timeout_count(5):
do
{
if inportb(MSR PORT) & OxcO) == RQM)
{ -
A-Type BiosKit
/1 wait at least 1 sec
The Floppy Disk Driver E813
}
}
}
outportb(DATA PORT,parm);
delay_call(O,;O); 1* delay at least 50 useconds *1
return (ok);
while CTIMER LONG < i);
DISK_STATUS T= TIME_OUT;
return (error);
1*==========================================================
Get the indexed value from the disk parameter table.
--------------------------------------------------------*1
(nsigned char getJ)8rm(fdisk_regs char index)
}returnCpeekbcS(&fdisk_table[myblock->fd_drive_type) [myblock->fd_media_type] [index];
1*==========================================================
Send the specify command to the FDC.
------------------------------------------------------ --*1
void send specify command (fdisk regs *myblock)
( - - -
send fdc(3);
sendrfdc(getJ)8rm(myblock,O;
sendrfdc(get nArm(myblock,1; 1* send command *1
} _ -r-
1*=======================================================*1
1*=======================================================*1
1*=======================================================*1
1*======================================================
Turn motor on and wait for motor start up time if this is a
write operation. Proceed inmediately if a read operation.
1. save the last state of the motor.
2. turn on the selected motor.
3. if not a write, exit inmediately.
3. if a write, if the same motor was already on, exit, else wait for the delay.
------------------------------------------------------ --*1
void motor on(fdisk regs *myblock)
( - -
}
unsigned char this_motor, last_motor, wait;
disable();
MOTOR COUNT = Oxff;
1* hit' timer with max on-ccx.nt *1
last motor = MOTOR STATUS & OxOf;
wait-= MOTOR STATUI & Ox80;
MOTOR STATUS-= this motor = (1 drive);
outportb(DOR_PORT,(this_motor 4) I OxOc I ffiybLock->fd_drive);
enable();
iflast motor != this motor) && (wait != 0
(- -
II delay for a write and a motor start
II force a delay in 1/8 seconds
II delay = (resolution,ccx.nt) in milliseconds *1
delay_cal l (125
6
getJ)8rm(myblOCk, 10;
MOTOR COUNT = xff;
1* hit' timer with max on-ccx.nt */
watch string(FLOPPY,"\n\rMotor on Delay = II);
watch:hYte(FLOPPY,get nArm(myblock,10; } _ -r-
1*========================================================
Wait for the hardware interrupt to occur. Time-out and return
if no interrupt.
------------------------------------------------------ --*1
unsigned char wait int (void)
( -
1* this time out should be 3 secs *1
unsigned long i = set_timeout_ccx.nt(3 * 20);
Section E: The C ProlUams
}
E814 The Floppy Disk Driver
disable()
outportb(6x21,inportb(Ox21) & -BIT6):
enable(); .;
do
(
}ifSEEK_STATUS & INT_FLAG) 1= 0) { SEEK_STATUS &= -INT_FLAG: return (ok): }
while (TIMER LONG < i);
DISK_STATUS T= TIME_OUT: SEEK_STATUS &= -INT_FLAG;
return (error);

Send the data-transfer-rate command to controller
--------------------------------------------------------*/
void send rate(fdisk regs *myblock)
( - -
outportb(DRR PORT,peekbcs(&fdisk ID+mvblock->fd drive) & Ox07]
[(peekb40(DI!K_ID+inyblock->fd_drTve) 4) & Ox07] tIfT_RAtE]: -
}
1*================================:=:::==:=::::=::::=====
Process the interrupt received after recalibrate or seek.
--------------------------------------------------------*/
unsigned char chk stat 2 (void)
{ - -
if (wait int() == error) return (error):
if (sena-fdc(8) == error) return (error):
if (resuTts() == error) return (error):
if peekb40(FDC STATUS) & Ox60) == Ox60) /* normal termination */
( -
watch string(FLOPPY,It\n\rSeek Error, fdc status was - It):
STATUS:
DISK_STATUS 1= BAD_SEEK; -
return (error);
}
return (ok);
}
/*======:::==:=============================================
Initialize dma controller for read, write, verify operations.
---------------------------------------------------------*/
unsigned char dma setup(fdisk regs *myblock,unsigned es,unsigned bx)
( - -
disable(); /* disable interrupts */
outportb(DMA FLFF,OxOO) /* set the first/last ff */
outportb(DMA]tASK,DMA_OFF): /* disable chamel whi le loading */
outportb(DMA MOOE ,myblock->fd dna cocmw.d); /* output mode byte * /
if (myblock->fd dma command =- DNX VRFY MOOE) /* ana verify command? */
{ /* yes */- - - -
myblock->dma address = 0;
myblock->lowir byte = 0;
= 0;
myblock->nibbli = 0:
}
else
{
myblock->dma address = es + (bx 4);
myblock->nib6le = myblock->ana address 12;
myblock->upper byte = myblock->dna address 4
= (myblock->dmi address 4) 1 (bx & OxOOOf);
} - -
myblock->length = myblock->fd nr sectors * 128) get-P8rm(myblock,3 - 1;
watch_string(FLOPPY,"\n\rTransfir Tength = II);
watch word(FLOPPY,myblock->length);
outportb(DMA ADR,myblock->lower byte); /* output low address */
/* output high address */
outportb(DMA-PAGE,myblock->nibbTe) /* output page address */
outportb(DMA-BASE,myblock->length 1 Oxff); // output low byte length
outportb(DMA-BASE,mvblock->length 8): // output high byte length
enable(): -/* enable interrupts */
outportb(DMA_MASK,DMA_ON); /* init disk channel */
A-Type BiosKit
The Floppy Disk Driver E81S
myblock->lcheck = 0;
myblock->lcheck = myblock->upper byte & Oxtt) 8) I (myblock->lower byte & Oxtt);
myblock->lcheck = myblock->lcheck + (unsigned long) myblock->lengthi -
if (myblock->lcheck & OxffffOOOO) /* test for overflow */
( /* overflow */ .
}
DISK STATUS = DMA BOUNDARY;
watcn overflow"):
return (error):
return (ok);
}
/*==========================================================
Move the head to the selected track.
--------------------------------------------------------*/
unsigned char seek(fdisk regs *myblock)
{ -
//unsigned char drive type,media
if SEEK STATUS & (T mybloci->fd drive == 0) /* need recal */
{- -
SEEK_STATUS 1= (1 myblock->fd_drive): /* mark recal will be done *1
/* try 2 attemps at recalibrate, then if failed, return error *1
if (recal(myblock) == error)
(
DISK STATUS = 0;
if (recal(myblock) == error) return (error);
}
pokeb40(LAST TRACK+(myblock->fd drive)eO): 1* clear track number *1
/* if we want track zero, then just walt for head and exit *1
if (myblock->fd track == 0) ( wait for head(myblock): return (ok): }
} - - -
if (peekbcs(&fdisk table [myblock->fd_drive_type] [myblock->fd_media_type] [DT_STEP]) 1= 0)
myblock->rd track *= 2;
if (peekb40(LAST drive) == myblock->fd track)
}
return{ok)t - -
1* new POSitlon *1
pokeb40(LAST TRACK+myblock->fd drive,myblock->fd track);
if (send fde{OxOf) == error) return (error): -
if drive) == error) return (error);
if == error) return (error):
if (chk stat 2() == error) return (error):
wait for heaa(myblock):
return ('ok):
/*=========================================================
Recalibrate the drive.
-------------------------------------------------------*1
unsigned recal(fdisk regs *myblock)
{ -
}
if (send fde(7) == error) return (error);
if drive) == error) return (error);
/* send comnand *1 -
if (chk stat 2() == error) return (error);
/* return with error *1
return (ok): 1* return with no error *1
1*===========================================================
Determine whether a retry is necessary.
Returning an OK says don't retry any more
Returning an ERROR says retry again
------------------------------------------------------ ---*1
unsigned retry(fdisk regs *myblock)
{ -
unsigned char media
1* if operation timed out - say no retry *1
if DISK STATUS & TIME OUT ) == TIME OUT) return (ok):
1* if media is establisned - say no retry *1
if peekb40(DISK_ID+myblock->fd_drive) & media_established) 1= 0) return (ok):
1* we have to step through the media *1
II the next possible media type for this drive type
medla_type = peekbcs(&transition_table[myblock->fd_drive_typel [++myblock->fd_media_indexl);
Section E: The C ProlUams
E816 The Floppy Disk Driver
if (media type == media none) II then at end of possibles
(- -
}
II dis-establish media
I I return - no more
andb40(OISK_IO+myblock->fd_drive,-(media_established 1 media_field;
return(ok); .
II insert the new media type into the DISK ID and return saying try again
& -media_field)
(medta_type 4;
DISK STATUS = 0;
poke640(FOC STATUS,O);
return(error); 1* return saying retry *1
}
1*=======================================================
Read anything from the controller following an interrupt.
This may include up to seven bytes of status.
--------------------------------------------------------*/
unsigned char results (void)
{
}
unsigned long i;
unsigned char count, flag;
for (count = 0; count < 7; COU'lt++) . I I get up to seven bytes
(
flag = error;
i = set_timeout_cOU'lt(2); II set delay to 50-100 ms.
do
{
if inportb(MSR PORT) & OxcO) =- OxcO) 1* data available from FOC */
( -
}
pokeb40(FOC STATUS+cOU'lt,inportb(OATA PORT; 1* save status *1
delay call(U,100); 1* at least 100 us-for the FOC */
flag =- ok;
/* check busy bit *1
if inportb(MSR PORT) & BUSY) == 0) return (ok);
} -
while (TIMER LONG < i)
if (flag == error) ( DiSK STATUS 1= TIME OUT; return (error); )
} --
DISK_STATUS 1= BAD_FOC; 1* too many bytes *1
return (error);
/*========================================================
Purge the Foe of any status it is waiting to send.
--------------------------------------------------------*/
void purge fdc (void)
{ -
}
while inportb(MSR PORT) & OxcO) == OxcO)
( -
inportb(OATA PORT); /* read status */
delay call(O;SO); 1* at least 50 us for the FOe */
} -
/*=======================================================
Read the state of the disk change line.
--------------------------------------------------------*/
unsigned char read dskchng(fdisk regs *myblock)
( - -
motor on(myblock); /* turn motor on *1
return (inportb(OIR PORT) & DSKCHANGE BIT);
} - -
1*=======================================================
Execute the FOe read id command.
------------------------------------------------------ --*1
unsigned char read_id (fdisk_regs *myblock)
A-Type BiosKit
The Floppy Disk Driver E-8-17
{
if (send fde(FDC READID) == error) return(error);
if (sena-fde(mybTock->fd head 2 I myblock->fd_drive) == error) return (error);
return (get fde status(myblock;
}-
/*======================================================
Wait for the head to settle after a seek.
-------------------------------------------------------*/
void wait for head(fdisk regs *myblock)
( - - -
unsigned char wait;
wait = /* get head settle */
if MOTOR STATUS & Ox8 ) 1= 0) // if write
{ /* yes */
if (wait == 0) /* wait zero? */
{ /* yes */
if ID+(myblock->fd drive 4) & Ox07)
wait = Ox14; /*-default 360 heaa time */
else
wait = OxOf; /* default others head time */
}
}
else
{
if (wait == 0) /* is wait zero? */
return; /* yes, return */
}
delay call(1,wait); /* delay n miLLiseconds */
} -
/*=========================================================
Checks for a media change, reset media changes and check
media changes.
Returns:
ok = medi a not changed, error = medi a changed
-------------------------------------------------------*/
unsigned char med change(fdisk regs *mybLock)
{ - -
}
if (read dskchng(mybLock) == 0) return (ok);
/* clear-media estabLished and media type */
andb40(DISK_ID+mybLock->fd_drive,-media_estabLished);
disabLe();
MOTOR STATUS &= -(1 myblock->fd drive);
/* turn off motor status */ -
enable();
motor_on(mybLock)i
FDC reset(mybLock);
mybTock->fd track = 0;
seek(mybloci) ;
mybLock->fd track = 1;
seek(mybLoci);
DISK STATUS = MEDIA CHANGE;
if (read_dskchng(mYSlock) 1= 0) DISK_STATUS = TIME_OUT;
return (error);
/*========================================================
Seek to the requested track and initialize the controller
--------------------------------------------------------*/
unsigned char fde init(fdisk regs *myblock)
( --
motor on(myblock);
if (seek(myblock) == error) return (error);
if (send fdc(myblock->fd fde command) == error) return(error)i
if (send[fde(myblock->Td_head 2) & 81T2) I myblock->fd_drlve) == error)
return(error);
}
return (ok);
/*=======================================================
Wait untiL an operation is compLete, then accept the status
from the controller.
Section E: The C ProlD"ams
E818 The Floppy Disk Driver
--------------------------------------------------------*/
unsigned char get_fdc_status(fdisk_regs *myblock)
(
}
myblock->time out flag = wait int();
if (results()-== error) return (error);
if (myblock->time_out_flag == error)
{
if (DISK STATUS == 0) return(ok); else return(error);
} -
if peekb40(FDC STATUS) & OxcO) == 0)
{ -
if (DISK STATUS == 0) return(ok); else return(error);
} -
if peekb40(FDC_STATUS) & OxcO) 1= Ox40) { DISK_STATUS 1= BAD_FDC; return(error); }
mvblock->error byte = peekb40(FDC STATUS + 1);
j*-get controlTer status */ -
if myblock->error byte & BIT7) 1= 0) {DISK STATUS = RECORD NOT FND;}
else if myblock->error:pyte & BIT5) 1= 0) {DISK-STATUS = BAD CRfi} -
else if & BIT4) 1= 0) = BADiDMA;)
else if myblock->error]bYte & BIT2) 1= 0) = RECaRD NOT FNOi)
else if & BIT1) 1= 0) a WRITE
else if myblock->error:pyte & BITO) 1= 0) {DISK-STATUS =
else (DISK STATUS 1= FDC;) -
if (DISK STATUs 1= 0) return(error);
return( OK);
/*=======================================================
calculate number of sectors that were actually transferred_
returns:
number of sectors transferred
--------------------------------------------------------*/
unsigned char calc sectors (fdisk regs *myblock)
{ - -
if (DISK_STATUS 1= 0) return (0);
myblock->sectors_track = get-PBnm(myblock,4);
myblock->end track = STATUS + 3);
myblock->endrhead = peekb40(FOC tTATUS + 4)-
myblock->end'sector = STATUS +
myblock->num-sectors = 0; -
if (myblock->end track 1= myblock->fd track)
myblOCK->num sectors += mybTock->sectors track;
if (myblock->end head T= myblock->fd head) -
myblocK->num_sectors += mv6lock->sectors track;
myblock->num_sectors += (myblock->end_sector - mybTock->fd_sector);
return(myblock->num sectors);
} - .
/*====================================================*/
A Type BiosKit
The Hard Disk Driver E91
NINE
The Hard Disk Driver
The Hard Disk Driver is used to operate an optional hard disk drive. This driver
supports the standard AT type of hard disk controller. Other disk interfaces such as
SCSI, ESDI, and SMD may require drastically different hardware level interaction,
but the Bios register interface will remain the same as in this driver. If you are
developing any of these drivers, this module may be used as a starting point, since
the functional requirements at the Bios function call interface remain the same.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: AT Bios hard disk driver
*
* Version: 1.04
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: athard.c
*
* Language MSC 5.1
*
: Functional Description:
* Interrupt 13h - hard disk driver
*
* AH = 0 - do a reset on the controller, set recal needed
*
* AH = 1 - read the last operation status into AL
*
:--------------- for the following operations -------------
* DL = drive number (Ox80-0x81)
* DH = head number
* CH = track number
* CL = sector number (except for Format)
* AL = number of sectors (except for Format)
: ES:BX - data buffer address (except for F o ~ t )
*
* AH = 2 - read sectors
*
* AH = 3 - write sectors
*
* AH = 4 - verify sectors
*
* The above commands return in AL the # of sectors succesfull
*
* AH = 5 - format track
* ES:BX points to (4 sector bytes) * # of sectors
* Each field (1 per sector) =
* C = Cylinder (track) number
* H = head number
* R = sector number
* N = number of bytes per sector encoded as:
* 00 = 128 bytes per sector
* 01 = 256 bytes per sector
* 02 = 512 bytes per sector
: 03 = 1024 bytes per sector
* AH = 6 - not used
*
* AH = 7 - not used
*
* AH = 8 - Return the Drive Parameters
*
: AH = 9 - Initialize the drive pair
* AH = 10 - Read Long
*
* AH = 11 - Write Long
*
* AH = 12 - Seek
E9 2 The Hard Disk Driver
*
* AH = 13 - Alternate disk reset
*
* AH = 14 - not used
*
* AH = 15 - not used
*
* AH = 16 -
test drive ready
*
* AH = 17 - Reca librate
*
* AH = 18 -
not used
*
* AH = 19 - not used
*
* AH
*
= 20 -
controller diagnostic
* AH = 21 - read drive type
*
*
* Returns:
* Carry Flag Clear = operation - AH a 0
* Carry Flag Set = Fallure - AH = failure code
*
* Argunents:
*
* Return:
*
* Version History:
* 1.01
* DMA overrun check was being called with the cx register instead of the ax register. Changed
* calls to pass ax.
* 1.02
* Corrected previous error in check overrun
c
(test for nr sectors = Ox7f).
* Corrected error in check error byte functlon
* 1.03 - -
* Changed init routine to check for any disks present before linking
* vector 40h.
* 1.04
* Replaced and pokes with casts
* Moved varlables to
* Changed setup to skip vectoring if no hard disks present
* Changed most function calls to pass only myblock pointer for argunents
* Corrected error in FORMAT case (using wrong block index)
*
***************************************************************************************************1
1* INC L U D E F I L E S *1
#include lIatkit.hll
1* FUN C T ION PRO TOT Y PES *1
1*================ function prototypes ===================*1
unsigned hdisk setup(void);
void interrupt-cdecl far hdisk io(interrupt registers);
void interrupt cdecl far hdisk:isr (void); -
unsigned char calc hsectors(unsigned char,unsigned char,unsigned char);
unsigned wait for Tnt(void)i
unsigned not 5usyfvoid);
unsigned cheek overrun(unsigned,unsigned,unsigned);
unsigned wait for data(void);
unsigned checi hdrstatus(void);
unsigned check-stitus byte(void);
unsigned check-error
unsigned load comnana(unsigned);
unsigned hi_rigs(unsigned long);
1* G lOB A l V A R I A B l E S */
1* G lOB A L CON S TAN T S *1
extern canst unsigned char hdisk_table;
1* L 0 CAL D E FIN I T ION S */
#def i ne OOTPUT REQ BIT OxOS
#define ecc_mOae oi02
#define sencCconmand load_con.nd(myblock)
11--------- bios ram usage definitions ----------
#define bad_bat OxSO
A-Type BiosKit
#define bad_chksm Ox40
11--------- error code definitions ------------
#def i ne NO ERROR OxOO
#define BAD' CMO Ox01
#define BAD-ADDRESS Ox02
#define BAD-SECTOR Ox04
#define BAD-RESET OxOS
#define BAD-PARMS Ox07
#define BAD\)MA Ox09
#define BAD-SECTOR FLAG OxOa
#define OxOb
#define -BAD-FORMAT OxOd
#define BAD-CONTROL OxOe
#def i ne BAD -DMA ARB OxOf
#define BAD-ECC- Ox10
#define BAD-ECC OK Ox11
#define BAD-HDC- Ox20
#define BAD-SEEK Ox40
#def i ne T I ooT Ox80
#define NOT IEADY Oxaa
#def i ne ERR Oxbb
#define BAD WIITE Oxcc
#define BAD-STATUS OxeC
#define BAo:SENSE Oxff
11--------- function code definitions ---------
#define RESET OxOO
#define READ STATUS Ox01
#define READ-SECTORS Ox02
#define SECTORS Ox03
#def i ne VER I FY SECTORS Ox04
#define FORMAT-TRACK OxOS
#define BAD FuRcTION Ox06
#define GET-PARAMETERS OxOS
#define INIT DRIVE Ox09
#define READ-LONG OxOa
#define WRITr LONG OxOb
#define SEEK OxOc
#define ALT RESET OxOd
#define TEST DRIVE READY Ox10
#define RECAtIBRATr Ox11
#define DIAGNOSTIC Ox14
#define GET DISK TYPE Ox1S
#define PARr HEAD'S Ox19
#define FORMiT UNIT Ox1a
#define BAD_COMMAND Ox1b
#define, TRY Oxff
11----------- I/O port definitions -----------
#define Ho_PORT Ox1fO
II controller task register file (ports) (frame)
II for a port write -
/1 0 - write data
1/ 1 - pre-ceq)
1/ 2 - sector count
// 3 - sector number
1/ 4 - low cyl
1/ S - high cyl
// 6 - size/drive/head
// 7 - command register
// for a port read
// 0 - read data
// 1 - error register
1/ 2 - sector count
II 3 - sector number
1/ 4 - low cyl
1/ S - high cyl
// 6 - size/drive/head
// 7 - status register
#define Ho_REG_PORT 0x3f6
//----- controller internal command codes ------------
#def ne HOC RECAL Ox10
#def ne HOC-READ Ox20
#def ne HDC:READ_LONG Ox22
The Hard Disk Driver E93
Section E: The C Proerams
E;.94 The Hard Disk Driver
#def i ne HDC WR I TE 0x30
#define LONG Ox32
#define HDC-VERIFT Ox40
#define HDC-FORMAT Ox50
#define HDC-INIT Ox60
#define HDC-SEEK' Ox70
#define HDC-oIAG Ox90
#define HDC:SET_PARM Ox91
/* L 0 CAL CON S TAN T S */
//const char ndisk_table[1] [1] [16]:
/* PRO G RAM */
variables
unsigned char hd frame[8]:
unsigned hd tabli seg:
unsigned hdrtable-off:
/* The comnand block is bui l t in this frame */
/* pointers to drive parameter table */
unsigned hdxfr seg:
unsigned hdrxfr-off:
/* pointers to the transfer area */
end_variables haregs:
/*-------------- setup the controller -----------*/
unsigned hdisk setup()
( -
unsigned error code = ok:
hdregs *mybloci;
unsigned char drive type:
myblock = acquire_bTock(HARD):
HD NUM = 0: /* clear number of drives */
HD-CONTROL = 0:/* clear control byte */
HD:STATUS1 = 0:/* clear disk status */
if (incmos(Ox8e) & (bad bat I bad chksm) 1= 0)
( --
outcmos(Ox8e,incmos(Ox8e) & -Ox10): = error:
}
else
(
/* get disk type for drive 1 from cmos */
drive type = incmos(Ox12) 4:
if (drive type 1= 0) /* there are 1 or more drives */
( -
VECTOR_40 = VECTOR_13: /* move floppy vector to interrupt 40 */
link_interrupt(Ox13,hdisk_io): /* link 13 for functions and 76 (IRQ14) for isr */
link_interrupt(Ox76,hdisk_isr):
set vector(Ox41,bios cs(),&hdisk table): /* set default table addresses to type 0 */
set:vector(Ox46,bios:cs(),&hdisk:table);
outportb(Oxa1,inportb(Oxa1) & -Ox40): /* enable IRQ 14 */
outportb(Ox21,inportb(Ox21) & -Ox05): /* enable IRQ 2 in slave mode */
if(drive_type == 15) drive_type = incmos(Ox19): /* get extended type */
/* set pointer to table[typel into int 41 vector */
poke(OxOO.Ox41 * 4,&hdisk table+drive type-1)*16:
HD_NUM = 1: // say there 1S one drive -
drive type = incmos(Ox12) & OxOf:
if (drive type 1= 0) /* there are 1 or more drives */
( -
if(drive_type == 15) drive_type = incmos(Ox1a): /* get extended type */
/* set pointer to table[typel into int 46 vector */
poke(OxOO
L
Ox46 * 4,&hdisk_table+drive_t ype-1)*16:
HD NUM = /1 say there are two drlves
} -
/* test the hard disk controller */
myblock->dx = Ox0080:
myblock->ax = DIAGNOSTIC 8;
sys int(Ox13,myblock):
if r(myblock->flags & carry bit) != 0)
{ -
error code = Ox1782: /* return error code */
} -
/* do a reset on the drive(s) */
A Type BiosKit
}
}
}
myblock->dx = OX0080i
myblock->ax = RESET 8:
sys int(Ox13,myblock);
if f(myblock->flags & carry bit) != 0)
{ -
error code = Ox1790i /* returnerror code */
} -
release block(myblock):
return(error_code)i
The Hard Disk Driver E95
/*=================================================*/
/*======== BEGINNING OF MAIN ROUTINES ============*/
/*=================================================*/
/* handle the floppy disk function service call */
void interrupt cdecl far hdisk io (interrupt registers)
( --
hdregs *myblocki
ifdx & Ox0080) == 0) /* if dl <= 7f, then divert to floppy disk */
(
// fdisk chain is an assembly language routine which
// unstacks the pushed registers, then executes an int 40
// to the floppy driver. This prevents the stack from
// becoming too deep. DOS has a problem with its stack
// being too short to support many nested, interrupts.
fdisk chain(): /1 does not return here !!I
} -
enableO:
myblock = acquire_block(HARD):
snapshot_in(HARD,&es)i
flags &= -Ox0001: 1* clear the carry flag for returns */
HD_STATUS1 = 0; 1* clear status */
// set - varies for drive zero or one III
if dx & Oxff) > Ox81) ax = BAD_COMMAND 8: /* bad drive number *1
if(HD_NUM == 0) ax = BAD_COMMAND 8; /* no hard drives */
ifdx & Ox7f) > (HD_NUM - 1 ax = BAD_COMMAND 8; /* bad drive number */
if dx & Ox01) == 0) II drive 0:
(
myblock->hd table seg = peek(OxOO,Ox0106);
myblock->hdrtable-off = peek(OxOO,Ox0104);
} --
else // drive 1:
(
myblock->hd table seg = peek(OxOO,Ox011a);
= peek(OxOO,Ox0118);
} - - .
// set the control byte .
HD CONTROL = (HD CONTROL & OxcO) I peekb(myblock->hd table seg,myblock->hd table off+8);
"-set the register port - - --
outportb(HD REG PORT,peekb(myblock->hd table seg, myblock->hd table off+8;
" build the frime - - --
myblock->hd frame[1] = table seg, myblock->hd table off+5) 2;
= ax & OxOOff: - - 1/ sector ccUit -
= cx & Ox3f; " sector number
= cx 8; 1/ cyl low
myblock->hdrframe[5] = (cx 6) & Ox03" // cyl high
= dx & Ox01) ,) dx 8) & OxOf) I OxaO;
myblock->hd[frame[71 = 0; // pre-clear item
/1 normalize es:bx to xfr seg:xfr off = xxxx:OOOx
myblock->hd xfr seg = es + (bx -4);
myblock->hd[xfr:off = bx & OxOOOf;
/* now execute the CASE for the selected function */
switch (ax 8)
(
case RESET: /* reset the disk controller */
watch string(HARD,"RESET");
mybloek->ax =_01 II do a reset on the Floppy controller first
sys int(Ox40 myglock)i
if f(dx & Ox60ff) > Ox81) // not legal drive'
{
ax = myblock->ax; // pass results back to caller
Section E: The C Pro&rams
E-9-6 The Hard Disk Driver
flags = myblock->flags;
}
else II do the hard drive too
(
/1 enable the IRQ
outportb(Oxa1,inportb(Oxa1) & Oxbf);
// reset the controller
outportb(HD_REG_PORT, 4);
II DELAY 5-10 USECS
delay_call(0,10);
II set the head, and clear the reset bit
outportb(HD REG PORT,HD CONTROL & OxOf);
if(not busyr) == error)-
( -
HD STATUS1 = BAD RESET;
watch string(HARD',"NOT BUSY BAD RESET");
} -
else
(
watch string(HARDt"Not busy was 0K");
if(inportb(HD POR +1) 1= Ox01)
( -
HD STATUS1 = BAD RESET;
watch string(HARD',"Port 1 not = 01 bad reset");
} -
else
(
watch string(HARDt"Init and Recal the drives
ll
);
myblock->ax = INI DRIVE 8;
myblock->dx = Ox0080; .
sys_int(Ox13,myblock);
myblock->ax = RECALIBRATE 8;
myblock->dx = OxOO8O;
sys int(Ox13
c
myblock);
/ I Tf two drlVes, do the next one
if (HD NUM > 1)
( -
myblock->ax = INIT DRIVE 8;
mYblock->dx = OxOO!1;
sys_int(Ox13,myblock);
myblock->ax = RECALIBRATE 8;
myblock->dx = Ox0081
sys int(Ox13,myblock);
} -
HD STATUS1 = 0; 1/ clear the error bits
watch string(HARD,"Gooci reset");
} -
HD STATUS1 = 0; II clear the error bits
watch string(HARD,"Gooc:I reset");
} -
}
break;
case READ STATUS:
watch strTng(HARD,"READ STATUS");
ax = fax & OxffOO) I HD-STATUS1;
break; -
case READ SECTORS:
watch strTng(HARD,"READ SECTORS");
mybLock->hd frame[n = IlDc READ;
if(myblock->hd_frame[21 ==-0) < HD_STATUS1 z BAD_CMD; break; }
watch string(HARD,"\n\rChecking OVerrt.rl")
if(Chick_OVerrt.rl(myblOCk->hd_frame[21,myb[OCk->hd_xfr_off,myblOCk->hd_frame[n) == ok)
watch_string(HARD,"\n\rOverrt.rl ok");
if(send command == ok)
( -
watch string(HARD,II\n\rSent command");
// ~ t commands
II do thTs loop for each sector
do
(
if(wait for int() == ok)
II wait-for-data ready interrupt
(
watch_string(HARD,"\n\rReady for data
ll
);
1/ do the sector transfer
rep in(myblock->hd xfr seg, myblock->hd xfr off,HD PORT,256);
mybTock->hd_xfr_ofr +=;12; - - -
A-Type BiosKit
The Hard Disk Driver E9 7
(
}
}
watch string(HARD,"\n\rXFR done
ll
);
if (cneck hd status() == error) break;
watch strTng(HARD,"\n\rStatus was OK");
} -
while( - -myblock->hd frame [2] 1= 0);
} -
break;
case WRITE SECTORS:
watch striiig(HARD,IIWRITE SECTORSII);
mybloC'k->hd_frame[n = HD'C_WRITE;
if(myblock->hd_frame[2] == 0) ( HD_STATUS1 = BAD_CHO; break; )
II check for transfer overrun

watch string(HARD,"\n\rOVerrun okll);
if(sefid command == ok)
( -
watch_string(HARD,II\n\rSent command
ll
);
II wait for data request
if(wait for data() == ok)
( --
watch string(HARDt"\n\rReady for data
ll
);
II dO this loop Tor each sector
do
(
1/ do the sector transfer
rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256);
mybTock->hd xfr off-+= ;12; - - -
watch string(HAR'D,"\n\rXFR done
ll
);
if(waTt for int() t= ok) break, 1/ wait for completion
watch string(HARO,II\n\rCompletlon Interrupt rx'd");
if (cneck hd status() == error) break;
watch strTng(HARD,II\n\rStatus was OK");
} -
while(HO STATUS & OXOS) 1= 0) && (--myblock->hd frame[2] t= 0;
if(inportb(HD_PORT+2) t= 0) -
watch_string(HARD,"\n\rXfer Aborted = original error code = II);
watch word(HARD,HD STATUS1);
HD_STXTUS1 = UNDEF:ERR;
}
}
)
}
break;
case VERIFY SECTORS:
watch string(HARD,"VERIFY SECTORS");
mybloC'k->hd frame[n = HOe VERIFY;
if(send command == ok) -
{ -
if (wait for int() == ok)
( --
check hd status();
) --
}
break;
case FORMAT TRACK:
watch string(HARD,IIFORMAT TRACK");
mybloek->hd frame[n = HDe FORMAT;
= peeKb(myblock->hd table seg, myblock->hd_table_off+14);
i f(send command == ok) - -
( -
watch_string(HARD,"\n\rSent conmand");
// wait for data request interrupt
if(wait for data() == ok)
( --
watch string(HARD,"\n\rReady for .t .. );
// do-this loop for each sector
do
(
II do the sector transfer
rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256);
mybTock->hd xfr off-+= ;12; - - -
watch string(HAR'D,"\n\rXFR done");
if(waTt for int() != ok) break, 1/ wait for completion
watch_string(HARD,"\n\rCompletlon Interrupt rx'd");
== ok)
Section E: The C ProlUams
}
E98 The Hard Disk Driver
if (check hd status() == error) break;
watch strTngl'HARD,II\n\rStatus was OKII);
} -
while(HD STATUS & Ox08) 1= 0) && (--myblock->hd frame[2] 1= 0;
II if the controller is still asking for more dati, then it is an error
}if(inportb(HD_PORT+2) 1= 0) HD_STATUS1 = UNDEF_ERRi
break;
case GET PARAMETERS:
wateh_string(HARD,IIGET_PARAMETERSII);
II build ch = max cyls, cl = max sectors
II get lower 8 bits of max cyls .
ax = peek(myblock->hd_table_seg,myblock->hd_table_off)-1;
ex = ax 8;
ex 1= ax 2) & OxOOcO);
II max sectors
ex 1= (peekb(myblock->hd_table_seg,myblock->hd_table_off+14;
I I bui ld ell = max heads, dl = tI drives
dx = (peekb(myblock->hd table seg,myblock->hd table off+2)-1) 8;
dx 1= HD_NUM; - - --
ax = 0;
break;
case INIT DRIVE:
watch strTng(HARD,IIINIT DRIVE")i
myblock->hd frame[7] = RDc SET
I I set max neads --
myblock->hd_frame[61 = (myblock->hd frame[6] & OxfO) 1 \
(peekb(myblock->hd table_seg,mybloci->hd_table_off+2)-1);
II set sector count
= peekb(myblock->hd_table_seg,myblock->hd_table_off+14);
II set low cyllnder = 0
myblock->hd frame[4] 0;
II set high-cylinder = 0
myblock->hd_frame[5] = 0;
if(send command == ok)
{ -
}
if(not busy() == ok)
{ -
check hd status();
} --
break;
case READ LONG:
watch strTng(HARD, "READ LONG"?!
mybloek->hd_frame[7] = RDC_REAU_LONG;
if(myblock->hd_frame[2] == 0) { HD_STATUS1 = BAD_CMD; break; }
II check for transfer overrun
1/ watch string(HARD lI\n\rCheckfng OVerrun")
if(check-overrun(myb(ock->hd frame[2],myblock->hd xfr off,myblock->hd frame[7]) == ok)
{- - - - -
1/ watch strfng(HARO,"\n\l"OVerrun okll);
1/ commandlphase
if(send command == ok)
{ -
// watch_string(HARD,"\n\rSent command");
1/ ouput commands
// do thTs loop for each sector
do
{
if(wait for int() == ok)
1/ wait-for-data ready interrupt
{
watch_string(HARD,"\n\rReady for data");
/1 do the sector transfer
rep in(myblock->hd xfr seg,myblock->hd xfr off,HD PORT,256);
mybTock->hd_xfr_ofT +=;12; - - -
}
// read the 4 extra bytes
pokeb(myblock->hd xfr seg,myblock->hd xfr off++, nportb(HD PORT
pokeb(myblock->hdrxfr-seg,myblock->hdrxfr-off++,
pokeb(myblock->hdrxfr-seg,myblock->hdrxfr-off++, nportb(HD:PORT
nportb(HD_PORT
A Type BiosKit
The Hard Disk Driver E99
}
/I watch string(HARD,"\n\rXFR done");
if (check hd status() == error) break;
/I watcfCstring(HARD,"\n\rStatus was 0K");
}
while(--myblock->hd frame[2] > 0);
} -
break;
case WRITE LONG:
watch striiig(HARO, "WRITE LONG")i
myblock->hd_frame[7] =
if(myblock->hd_frame[2] == 0) < HO_STATUS1 = BAD_CMD; break; }
II check for transfer overrun
if(check overrun(myblock->hd frame[2],myblock->hd xfr off,myblock->hd frame[7]) == ok)
< - - - - -
watch string(HARD,"\n\rOVerrun Ok");
if(send command == ok)
< -
watch_string(HARD,"\n\rSent command");
II wait for data request interrupt
if(wait for data() == ok)
< --
watch string(HARD,"\n\rReady for data");
II do-this loop for each sector
do
<
II do the sector transfer
rep out(mvblock->hd xfr seg,myblock->hd xfr off,HD PORT,256);
mybTock->hd_xfr_off-+= ;12[__ - - -
II ecc mode - sind 4 more oytes
outportb(HO PORT,peek(myblock->hd xfr seg,myblock->hd xfr off++
outportb(HO-PORT,peek(myblock->hdrxfr-seg,myblock->hdrxfr-off++
outportb(HO-PORT,peek(myblock->hdrxfr-seg,myblock->hdrxfr-off++

watch strlng(HARD,"\n\rXFR done");
if(waTt for int() 1= ok) breaki II wait for completion
watch string(HARD,"\n\rCompletlon Interrupt rx'd");
if (cneck hd status() == error) break;
watch strTng"(HARD,"\n\rStatus was OK");
} -
while(HD STATUS & Ox08) 1= 0) && (--myblock->hd frame[2] 1= 0;
II if the controller still asking for more then an error.
if(inportb(HD PORT+2) 1= 0) HD STATUS1 = UNDEF ERR;
} - - -
}
}
break;
case SEEK:
watch string(HARO,ISEEK");
myblock->hd frame[7] = HOC SEEK;
if(send command == ok) -
< -
if(wait for int() == ok) check hd status();
if(HD == BAD SEEK) HD = 0;
} - --
break;
case ALT RESET:
watch string(HARO,"ALT RESET");
break; -
case TEST DRIVE READY:
watch strTng(HAIfD,"TEST DRIVE READYIl);
if(not busy() == ok) - -
< -
outportb(HD PORT+6,myblock->hd frame[6]);
check hd status(); -
} --
break;
case RECALIBRATE:
watch string(HARD,"RECALIBRATE");
mybloek->hd frame[7] = HOC RECAL;
if(send command == ok) -
< -
if(wait for int() == ok)
< --
check hd status();
} --
Section E: The C ProlUams
)
E910 The Hard Disk Driver
else
(
if(wait for int() == ok)
check ha stitus();
) --
if(HO STATUS1 == BAD SEEK) HO STATUS1 = 0;
break; --
case DIAGNOSTIC:
watch string(HARO,"OIAGNOSTIC");
/* maKe sure interrupts are disabled when changing the interrupt mask */
disableOo
outportb(6xa1,lnportb(Oxa1) & - Ox40);
outportb(Ox21,inportb(Ox21) & - Ox20);
enableO; .
if(not bUsy() == ok) /* ok to start diag */
( -
outportb(HO PORT+7,HOC OIAG);
if (not busy() == ok) - /* wait for completion */
{ -
if HO ERROR = inportb(HO PORT+1 1= 1)
(- -
HO STATUS1 = BAD HOC;
) - -
)
else
(
HO STATUS1 = TIME_OUT;
) -
)
break;
case GET DISK TYPE:
watch stFing(IARO,"GET DISK TYPE");
1/ cyTs = peek(hd tible ieg,hd table off)
/1 heads = peekb(ha table seg,ha table off+2)
// sectors = peekb(hdCtable:seg,hdCtable:off+14)
cx = hi table seg,mvblock->hd table off)-1) *
peekb(myblock->hd table seg,mY6lock->hd table off+2)-* -
peekb(myblock->hdCtable:seg,mVblock->hdCtable:off+14;
dx = (peek(mvblock->hd table seg,mvblock->hd table off)-1) *
peekb(myblock->hd table seg,ffiyblock->hd table off+2) *
peekb(myblock->hdCtable:seg,mVblock->hd[table:off+14);
ax = Ox0300;
break;
default: /* invalid function code - return bad code */
HO STATUS1 = BAD CMD10
ax-= (BAD CMD -8) (ax & Oxff>;
break; -
) /* end of switch *1
ax = (ax & OxOOff) I (HO STATUS1 8);
ifax & OxffOO) != 0) fTags 1= 1;
if (watch( HARD
(
}
/1 display port ins
write stringC"\n\rPort ins 1f1 = ");lbyte(inportb(HO PORT+1;
write-stringC" 1f2 = II); lbyteCinportb(HO PORT+2; -
write-stringC" 1f3 = II); lbyte(inportbCHO-PORT+3;
write-stringC" 1f4 = II); lbYte(inportb(HO-PORT+4;
write-stringC" 1f5 = II); lbyte(inportbCHO-PORT+5;
wri te-stringCIt 1f6 = II); lbyteC inportbCHO-PORT+6;
wr!te:str!ngc" 1f7 II II); lbYteCinportbCHO:PORT+7;
wrlte_strlngc"\n\r");
snapshot out(HARD(&eS);
release 6lock(myb ock);
) -
/*====================================================*/
/* check for the controller not busy */
unsigned not busy(void)
( -
/* current count and add 5 secs to it */
unslgned long delay_count = set_timeout_count(5 * 20);
enable();
A-Type BiosKit
}
// clear status byte
HD_STATUS1 = NO_ERROR;
do
{ if inportb(HD PORT+1) & OxSO) == 0) return(ok); }
while (TIMER_LONG-< delay_count);
// set time out error
HD_STATUS1 = TIME_OUT;
// return error condition to caller
return(error)i /* time out */
1*====================================================*/
void interrupt cdecl far hdisk isr (void)
( -
}
HD INT FLAG = -1'

outportb(Ox20,Ox20)i 1* send eo; *1
1*======================================================
Wait for the hardware interrupt to occur. Timeout and
return if no interrupt
.................................. *I
unsigned wait for int (void)
( - -
/* this time out should be 3 secs */
unsigned long delay_count = set_timeout_count(3 * 20);
enable();
do
The Hard Disk Driver E911
( if(HD INT FLAG 1= 0) { HD INT FLAG = 0; HD_STATUS1 = 0; return (ok); } }
while LONG < delay count-
HD INT FLAG =-0; HD STATUsT 1= TIME OUT;
return(error); - -
}
1*======================================================
Wait for the data request. Timeout and
return if no request
............................................. *I
unsigned wait for data (void)
( - -
unsigned long delay_count = set_timeout_count(2 * 20);
enable();
/* this time out should be 2 sees */
do
( ifinportb(HD PORT+1) & OUTPUT REQ BIT) != 0) { return(ok)i } }
while (TIMER < delay count)i- -
HD STATUS1 =-TIME OUT; -
return (error); -
)
1*=========================================================
recalibrate the drive.
.. .... .. .... ...*1
1/
unsigned check hd status()
( - -
if(check status byte() == error) return(error);
ifinportb(HD & Ox01) == 0) return(ok);
return(check error byte(;
} --
II
II This is a reminder of what is in the tables
Ilconst char status mask[S]={Ox80,Ox20,Ox40,Ox10,OxQ4}
Ilconst char status:err [S]={OxOO,Oxcc,Oxaa,Ox40,Ox11}
Ilconst char status_key [S]={OxOO,OxOO,Ox40,Ox10,OxOO}
unsigned check_status_byte()
Section E: The C Pro&rams
(
}
E912 The Hard Disk Driver
unsigned i
unsigned tempi
HO STATUS1 = 0; // start with a clear
temp = HO STATUS = inportb(HO PORT+7);
if(watch(RARO -
( write string("\n\rHO STATUS = II); lbyte(temp)i write_string("\n\r")i }
iftemp & Ox80)-'= 0) return(oi);
iftemp & Ox20) t= 0) ( HO STATUS1 = OXCCi return(error) }
iftemp & Ox40) == 0) ( HO-STATUS1 = Oxaa; return(error) }
iftemp & Ox10) == 0) ( HO-STATUS1 = Ox40; return(error) }
iftemp & Ox04) != 0) ( HO-STATUS1 = Ox11; )
return(ok); -
//-----------------------------------------------------
const unsigned char error table[8] = \
( -
BAD SECTOR, /* OxSO - bad block */
BAD-ECC! /* Ox40 - bad data ecc */
UNDE'F EKR /* Ox20 - not used * /
BAD SE'CTOR, /* Ox10 - id not found */
UNOE'F ERR, /* Ox08 - not used */
BAD cRo, /* Ox04 - aborted comnand * /
BAO-SEEK
L
/* Ox02 - trk 0 not found on recalibrate */
BAD:ADORI:SS, /* Ox01 - data address mark not found */
);
unsigned check error byte()
( --
)
unsigned i = 0, temp = O
temp = HO ERROR = inportb(HD PORT+1);
watch from 1F1 ="); watch_byte(HARO,temp)i
whilef(temp & OxfT) t= 0)
(
iftemp & OxSO) != 0)
(
}
HO STATUS1 = peekb(bios cs(),&error table[i])i
watch_string(HARD,"\n\rError Byte returned ="); watch_byte(HARO,HD_STATUS1)i
return(error);
temp = 1; i++;
}.
error detected");
return (ok)i
//---------------------------------------------------------
1/ check for transfer overrun
// if ecc mode than use 7f04 as max, else use SOOO
unsigned check overrun(nr sectors,xfr off,ecc char)
{ - - -
)
if (nr_sectors < Ox7f) return(ok); 1/ always ok
ifecc char & ecc mode) 1= 0)
(- -
if nr sectors == Ox7f) && (xfr off < 4 return(ok);
) - -
else
(
if(nr sectors == Ox7f) return(ok)
ifnr sectors == OxSO) && (xfr == 0 return(ok);
) - -
HO STATUS1 = BAD OMA;
return(error)i -
//----------------------------------------------------
uns i gned load comnand( hdregs *myparm)
( -
unsigned count = 10000;
I I hdregs *myparm;
1/ myparm = arg;
/ I check for time out on drive being ready
1/ watch string(HARO,"Load comnand entry\n\r");
do -
(
1/ check for controller and drive ready
if (not busy() == ok)
( -
1/ watch string(HARO,"not busy DK\n\r");
// select drive -
outportb(HO_PORT+6,myparm->hd_frame[6]);
A Type BiosKit
}
}
}
if (check status byte() == ok)
( - -
}
1/ watch string(HARD,"status byte was ok\n\r")i
// reset the interrupt flag byte
HD_INT_FLAG = 0; .
// enable the interrupts
disableO
outportb(6xa1,inportb(Oxa1) & Oxbf)i
outportb(Ox21,inportb(Ox21) & Oxfb);
enableO;
/1 check for retries
ifHD CONTROL & OxcO) != 0)
( -
if(myparm->hd frame[7] & OxfO) >= Ox20) && \
myparm->hd frame[7] & OxfO) <= Ox40 .
myparm- >hd frame [7] 1= Ox01;
} -
if (watch (HARD
(
}
I / output the conmands
write string("\n\rPort outs 1f1 = II);
frame[1])
wrlte string(" 112 = II); lbyte(myparm->hd frame [2] )
write-string(" 113 = II); lbyte(myparm->haframe[3])
write-string(1I 1f4 = II); lbyte(myparm->haframe[4])
write-string(" 1f5 = II); lbyte(myparm->haframe[5])
write-string(1I 1f6 = II): lbyte(myparm->haframe[6])
write-string(" 1f7 = II); lbyte(myparm->haframe[7])
write:string(lI\n\r
ll
); -
outportb(HD PORT+1,myparm->hd frame[1]);
outportb(HD:PORT+2,myparm->haframe[2]);
outportb(HD PORT+3,myparm->haframe[3]);
outportb(HD-PORT+4,myparm->haframe[4]);
outportb(HD-PORT+5,myparm->haframe[5]);
outportb(HD:PORT+6,myparm->haframe[6]);
outportb(HD_PORT+7,myparm->hd[frame[7]):
return(ok);
while(count-- > 0);
return(error);
1*====================================================*1
1*====================================================*1
1*====================================================*1
The Hard Disk Driver E-9-13
Section E: The C Pro&rams
The Boot File EI01
TEN
The Boot File
The Boot.c File is the bootstrap function call routine which is used to load DOS
from a floppy disk device. The boot routine attempts to read the boot sector of the
specified drive and if successful transfers control to the loaded routine (which in
tum loads the remainder of the operating system).
To allow flexibility in the way the system attempts to boot, there is a "boot_list" in
the boot program which defines the drives which will be used in the boot process.
This list may specify the hard or floppy drives in any order.
If your Boot requirements are non-standard or specific to a dedicated application,
you may wish to modify the standard boot routine. All the standard system
initialization has been done by the POD when the boot routine is finally called. A
specialized boot program may load an operating system or start executing an
application directly. If one is not using an operating system to support an
application, one must not design and code the application so that it makes reference
to non-existent operating system features!
The boot routine should exit if the boot process is not completed. This will allow the
POD routine to attempt an alternate path, such as defaulting to SysVue.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988 - All Rights Reserved
*
: Module Name: AT Bios bootstrap routine
* Version: 1.00
*
* Author: FOSCO
*
* Date: 12-01-88
*
* Filename: atbootoc
*
* Language: MS C 501
*
: Functional Description:
: This module does the bootstrap load to get DOS loaded and running.
* We look at the boot list to determine what drives should be used for the boot atten.,ts.
* The boot sector is loaded into 0000:7cOO and control is transferred to that address.
: If the boot cannot be performed, then we exi t.
* Argunents:
*
* Return:
*
: Version History:
***************************************************************************************************/
/* INC L U D E F I L E S */
#include "atkitoh"
/* FUN C T ION PRO TOT Y PES */
unsigned boot setup(void)
void interrupt cdecl far boot(void)i
void boot_jump(unsigned,unsigned,unsigned)i
/* G LOB A L V A R I A B L E S */
EI02 The Boot File
1* G lOB A l CON S TAN T S */
// this is the list of possible boot deviceS
r
in the order in which they should be tried.
// If all the named drives are tried and fai , then exit
1/ The list is terminated bY a -1
const unsigned boot_list[] ={OxOO,Ox80,Ox01,Ox81,-1,};
IIThis example shows the boot preference order to be:
II Drives A:, C:, B:, and 0:
II Programmers Caution:
/I Some versions of DOS may not allow booting from B: or D: due to DOS internal programs
1/ defaulting to A: or C:, regardless of the drive number being passed in the Dl register
II to the DOS boot sector routine.
II Programmers Note:
II This version of boot checks for a particular signature in the last two (2) bytes of the boot
II sector. This seems to be an IBM or Microsoft convention on their boot records. Boot records of
II operating systems other than IBM or MS may not have this signature. If you wish to modify the
II boot module to accept any value for the slgnature, you may delete the slgnature comparison logic
/I accordingly.
1* l 0 CAL 0 E FIN I T ION S *1
#define boot retrys 2
#define reset flag Ox72
#define switcn_byte Ox10
/* PRO G RAM *1
unsigned boot setup(void)
( -
}
link interrupt(Ox19,boot);
return(ok);
11----------- The boot routine ------------------
variables
end_variables bootregs;
void interrupt cdecl far boot(interrupt registers)
( -
unsigned i,break flag,boot_drive,boot_index;
bootregs *myblocK;
myblock = acquire block(800T);
snapshot_in(BOOT,les);
//write_string("----------- Booting ------------\n\r");
II clear the boot area
for (i = Ox7cOO; i < Ox7eOO; pokeb(OxOOOO,i++,O;
for(boot index = 0; peekcs(&boot list[boot index]) 1= -1; boot_index++)
{- --
for (i=O;i < boot retrys; i++)
( -
boot_drive = peekcs(&boot_list[boot_index]);
watch string(BOOT ,"\n\rBooting from Drive II II);
watch:hYte(BOOT boot drive);
watch-string(BOOT!"\n\rAtt8q)t II II);
watchJbyte(800T,iJ;
myblock -> ax = OxOOOO; /1 try a reset
myblock -> dx = boot drive;
SYS int(Ox13,myblockJ;
IW 1f no carry returned on reset then try booting *1
ifmyblock -> flags & carry bit) == 0)
( -
myblock -> ax = Ox0201; 1* try to read boot sector *1
myblock -> bx = Ox7cOO;
myblock -> es = OxOOOO;
myblock -> dx = boot drive;
myblock -> cx = OXOOa1i
sys int(Ox13,myblock)
ifmyblock -> flags 1 carry bit) == 0)
1* no carry returned on readi*1
(
1* check for boot sector signature *1
1* See programmers note above *1
if (peek(OxOOOO,Ox7dfe) == Oxaa55)
{
A-Type BiosKit
}
}
RESET FLAG = 0; /* clear reset flag */
enabli()"
release
watch string(BOOT,"\n\rJlJ'I1ling to boot sector\n\r");
/* go-and don't return */
boot_jlJ'l1l(OxOOOO,Ox7cOO,boot_drive);
else
(
watch string(BOOT,"\n\rSignature was II);
watch-word(BOOT,peek(OxOOOO,Ox7dfe;
} -
else
(
// check for a timeout on the disk controller
ifmyblock->ax & Ox8000) 1= 0) i = boot retrys + 1;
watch string(BOOT,"\n\rCarry returneC! on Read");
} -
}
}
}
else
(
watch string(BOOT ,"\n\rCarry returned on Reset");
} -
watch string(BOOT,"\n\rRetrys exhausted
ll
);
snapsnot out(BOOT(&eS);
release 6lock(myb ock);
} -
/*=======================================================*/
The Boot File EI03
Section E: The C ProK1"ams
The Cassette Driver E-ll-l
ELEVEN
The Cassette Driver
Although an AT Type machine does not have a cassette interface, a driver is
provided in the event a program makes a cassette function call. The function call
returns a cassette error condition to the caller. The A-Type machines use an
extended set of functions codes for AT specific functions for joystick input, virtual
mode control, multi-tasking hooks, sys-request functions, etc.
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ~ * * * * * * * * * * * * * * * *
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: AT Bios cassette function
*
* Version: 1.01
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: atcass.c
*
* Functional Description:
* This module returns an error condition in AX in the event a user program calls this function.
*
* Version History:
* 1.01
: Replaced peeks and pokes with casts
***************************************************************************************************/
/* INC L U D E F I L E S */
#include lIatldt.h"
void interrupt cdecl far cassette_io(interrupt_registers);
/* G LOB A L S */
extern unsigned char config table;
extern _cassette_io; -
/* L 0 CAL D E FIN T ION S */
#define OPEN DEVICE Ox80
#define CLOS DEVICE Ox81
#define PROGRXM TERMINATE Ox82
#define EVENT WXIT Ox83
#define JOYSTTCK SUPPORT Ox84
#define SYS REQ fEY Ox8S
#define WAIT Ox!6
#define MOVE BLOCK Ox87
#define GET EXTENDED MEMORY SIZE Ox88
#define SWITcH TO PROTECTED-MODE Ox89
#define DEVICE-BU!Y Ox90 -
#define INTERRUPT COMPLETE Ox91
#define RETURN_SY!TEM_CONFIG_PARAMETERS OxCO
#define rtc_wait_flag OxaO
/* PRO G RAM */
//-------------------------------------------------------
unsigned cassette setup()
( -
link interrupt(Ox1S,& cassette io); return(ok);
} - --
//-------------------------------------------------------
void interrupt cdecl far cassette io(interrupt registers)
{ --
enable();
setds_system_segment();
Ell2 The Cassette Driver
snapshot_in(CASSETTE,&es);
swi tch (ax 8)
(
case OPEN DEVICE:
watch strTng(CASSETTE,tlOpen Device
tl
);
break;
case CLOSE DEVICE:
watch_string(CASSETTE,tlClose Device");
break;
case PROGRAM TERMINATE:
watch_stri ng1'CASSETTE, "Program Terminate");
break;
case EVENT WAIT:
watch striiig(CASSETTE,"Event Waittl);
ifRTC WAIT FLAG & Ox01) 1= 0)
( --
flags /= carry_bit;
)
else
(
outportb(Oxa1,inportb(Oxa1) & Oxfe);
USER FLAG SEG = es;
USER-FLAG-= bx;
RTC row = cx;
RTC-HIGH = dx;
RTCIWAIT FLAG = 1;
II enabli PIE in cmos chip
outcmos(OxOb,(incmos(OxOb) & Ox7f) / Ox40);
}
break;
case JOYSTICK SUPPORT:
watch
break;
case SYS REQ KEY:
watch_string1'CASSETTE,"Sys Req Key");
break;
case WAIT:
watch string(CASSETTE,"Wait")-
ifRTC WAIT FLAG & Ox01) 1= 6) flags /= carry_bit;
else - -
(
disableO-
outportb(6xa1,inportb(Oxa1) & Oxfe);
USER FLAG SEG = ds(
USER-FLAG-= rtc_walt_flag;
RTC RIGH = cx;
RTC-LOW = dx;
RTC-WAIT FLAG = 1;
II enable PIE in cmos chip
outcmos(OxOb,(incmos(OxOb) & Ox7f) / Ox40);
enable();
do ( ) whileRTC WAIT FLAG & OxSO) == 0);
RTC WAIT FLAG = 0; -
} - -
break;
case MOVE BLOCK:
watch strTng(CASSETTE,"Move Block");
II format = virtual move(word count,global segment,global offset)
ax = virtual move(ci,es,si); - - -
if (ax 1= O)-flags 1= carry_bit;
break;
case GET EXTENDED MEMORY SIZE:
watch string(CASSlTTE,"Get Ext Mem Size");
ax = Tncmos(0x31);
ax :I ax 8;
ax 1= incmos(0x30);
break;
case SWITCH TO PROTECTED MODE:
watch stri"g(CXSSETTE,"Switch to Virtual
tl
);
II format = virtual mOde(index,global segment,global offset);
ax = virtual_mode(bi,es,si); - -
break;
case DEVICE_BUSY:
A-Type BiosKit
}
watch string(CASSETTE,"Device Busyll);
flags-&= -Ox0001;
break;
case INTERRUPT COMPLETE:
CCIq)lete");
break;
case RETURN SYSTEM CONFIG PARAMETERS:
watch string(CASSETTE,"Opin Device
ll
);
es = 6ios cs();
bx = &conlig table;
flags &= -carry bit;
ax &= OxOOff; -
break;
default:
watch string(CASSETTE6"Defaultl);
ax = fax & OxOOff) 1 x8600;
flags 1= carry bit;
break; -
snapshot out(CASSETTE,&es);
) -
The Cassette Driver Ell3
Section E: The C ProlUams
The Parallel Printer Driver E-12-1
TWELVE
The Parallel Printer Driver
The Parallel Printer Driver is an Interrupt (Ox17) function call that is used to
communicate with the printer. A parallel printer is one which has a "Centronics"
interface and is referred to as LPTl, 2, or 3. The printer driver provides simple
commands to initialize the printer or send a character to the printer.
Although a hardware interrupt line (IRQ7) is normally assigned for the parallel
printer port, interrupt operation is not supported by the standard Bios driver. The
typical printer adapter has logic to support the use of the interrupt, but it is not clear
how the interrupt would be used if there is more than one printer port installed.
Some print spooling programs may possibly use the interrupt, but we are not aware
of it. There may also be logic in some printer adapters to disable the output data
latch, thereby allowing a bi-directional data capability. The control logic to use such
a feature is not a standard Bios function.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: AT Bios LPT driver
*
* Version: 1.02
*
* Author: FOSCO
*
* Date: 2-25-89
*
: Filename: atlpt.c
* Language: MS C 5.1
*
: Functional Description:
: Int Ox17 - parallel printer driver
: Input:
* AH = 0 print the character in AL
* on return, ah = 1 if character could not be printed
* (t i me out). '
* Other bits set as on normal status call
*
* AH = 1 initialize the printer port
: returns with AH set with printer status
* AH = 2 read the printer status into (ah)
* 76543210
* I I I +-- time out
* +------ unused
* +---------- unused
* +-------------- 1 = i/o error
* +------------------ 1 = selected
* +---------------------- 1 = out of paper
* +-------------------------- 1 = acknowledge
: +------------------------------ 1 = not busy
: OX = printer to be used (0,1,2)
*
* Argunents:
*
* Return:
*
* Version History:
* 1.01
* Chnaged the time out loop and pre-cleared (AH) to insure returning status was clean.
* 1.02
: Pre-cleared the port list before scanning to prevent phamtoms LPT's being assumed.
***************************************************************************************************/
E122 The Parallel Printer Driver
/* INC L U D E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES *1
unsigned lpt setup(void);
void scan lpt(unsigned);
void interrupt cdecl far printer_io(interrupt_registers):
1* G LOB A L V A R I A B L E S *1
extern unsigned lpt list[41:
extern unsigned char lpt_timeout_list[41;
/* G LOB ALe 0 N S TAN T S *1
extern -printer_io;
1* L 0 C AL D E FIN I T ION S *1
#define print the character 0
#define init the-Port 1
#define status 2
#define equipment Ox10
1* PRO G RAM *1
unsigned lpt setup()
( -
}
unsigned i;
link io):
for Ti=0;i<3ii++) poki40(&lpt:list[il,0): 1/ pre-clear the list
scan lpt(Ox3oc);
scan-lpt(0x37S):
scan-lpt(Ox27S);
for Ti=Oii<3;i++) pokeb40(&lpt_timeout_list[il,Ox14):
return(oK):
void scan lpt(unsigned port)
( -
l.I'Isigned i:
outPQrtb(port,Ox55):
if (inportb(port) == Ox55)
{
EQUIP FLAG += Ox4000:
for (1 = 0: i < 3) && (peek40(&lpt list[il) 1= 0; i++)i
poke40(&lpt list[i],port); -
.} -
}
/1=======================================================================
void interrupt cdecl far printer io(interrupt registers)
( --
unsigned port,i,j:
setds system segment():
snapsnot_in([PT,&es);
if (dx <= 2) 1* valid lpt number ? *1
(
port = peek40(&lpt list[dx]); 1* get port number */
switch (ax S ) t 1* test.for valid commands *1
case print the character:
ax = ax & UxOOrf;
watch string(LPT,"Print Char"):
outportb (port,ax); 1* output character to port *1
II see if the printer is busy
for (j = (peekb40(&lpt timeout list[dxl) & Oxff): > 0: j--
{ --
for (i= 1000; i > 0; i--)
(
if inportb(port+1) & OxSO) 1= 0) break: 1* if not busy *1
}
if inportb(port+1) & OxSO) 1= 0) break: 1* if not busy *1
} .
if inportb(port+1) & OxSO) 1= 0) 1* if not busy *1
{
outportb (port+2, OxOd): 1* set strobe high *1
outportb (port+2, OxOc); 1* set strobe low *1
A Type BiosKit
}
The Parallel Printer Driver E123
ax = (inportb(port+1) & Oxf8) A Ox48) 8) I (ax & Oxff);
} .
else II port was busy, so device not available
{
ax = (ax I Ox0100 ) & Oxf9ff) A Ox48); 1* printer timed-out *1
}
break;
case init t h e ~ r t :
ax = ax &-OxOOff;
watch_string(LPT,lIlnit Port");
outportb (port+2, Ox08); 1* set init line low *1
1* delay for reset to take place *1
for (;=0; i <= 4000; i++);
outportb (port+2, OxOc); 1* set init line high *1
goto read_status;
case read the status :
ax = ax &-OxOOff;
watch_string(LPT,IIRead Status");
read status:
ax =-(inportb(port+1) & Oxf8) A Ox48) 8) I ax;
}
snapshot out(LPT,&es)i
} -
1*==============================================================================================*1
Section E: The C Pro&rams
The Comm Driver E-13-1
THIRTEEN
The Comm Driver
The Comm Driver is an Interrupt (Ox14) Function Call that is used to communicate
with the serial port adapters.
Note - The most common problem involved with serial devices on the Com ports is
the incorrect use of the control signals, CTS, R TS, DTR, and DSR. If you
experience problems in communication, try jumpering CTS to RTS, and DSR to
DTR.
This may help to localize and correct the problem.
The extended function calls available on some PS/2 machines are not included in
this standard driver. These are relatively simple to add if you wish to enhance your
Com Driver.
Note - The standard serial port Bios driver does not support interrupt driven
operation. Most tele-communication software packages will replace the Bios driver
with their own driver.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
: Module Name: AT Bios com port driver
* Version: 1.02
*
* Author: FOSCO
*
* Date: 2-25-89
*
* Filename: atcomm.c
*
* Language: MS C 5.1
*
* Functional Description:
: Interrupt Ox14 -- Serial Port Driver
* Provides a function call for initializing, sending data, receiving data, and reading the status
: of an asynchronous adapter.
: Upon Entry:
: OX = Logical Async device' (0,1,2,3) for COM1,2,3,4
* Initialize the port:
* AH = OOh
: AL = initialization parameters:
* Bit Meaning
* -----
-----------
* Bits 7,6,5
* 000 110 Baud
* 001 150
* 010 300
* 011 600
* 100 1200
* 101 2400
* 1 1 0 4800
* 1 1 1 9600
*
* Bits 4,3
* o 0 No parity
* o 1 Odd parity
* 1 0 No parity
* 1 1 Even parlty
*
* Bit 2
E132 The Comm Driver
*
*
*
* Bits
*
*
*
*
*
* Send
* AH
* AL
*
0 One stop bit
1 Two stop bi ts
1,0
o 0 5 bits/char
o 1 6 bits/char
1 0 7 bits/char
1 1 8 bits/char
a character:
= 01h
= the character to send
* Receive a character:
* AH = 02h
*
* Read the port status:
* AH = 03h
*
: Upon Exit:
* For
* AH
* Bit
* ---
* 7
* 6
* 5
* 4
* 3
* 2
* 1
* 0
*
* AL
* Bit
* ---
* 7
* 6
* 5
* 4
* 3
* 2
* 1
* 0
*
'Initialize the port' (AH=O):
= Line status
Meaning if = 1
Time out
Tx ElJ1)ty (TEMT)
Tx Holdlng Register ElJ1)ty (THRE)
Break Interrupt (BI) .
Framing Error (FE)
Parity Error (PE)
OVerr"" Error (OE)
Data Ready (DR)
= Modem status
Meaning if = 1
Data Carrier Detect (DCD)
Ring Indicator (RI)
Data Set Ready (DSR)
Clear To Send (CTS)
Delta Data Carrier Detect (DDCO)
Trailing Edge Ring Indicator (TERI)
Delta Data Set Ready (DOSR)
Delta Clear To Send (OCTS)
* For 'Send a character (AH = 1):
* AL = unchanged (character that was sent)
* AH = Completion code
* 1XXX XXXX - Time out, char not sent
* OYYY YYYY - Tx Successful, Bits 6 - 0 = Line status
*
* For 'Receive a character (AH = 2):
* AL = The received char, if successful
* AH = Completion code
* 1XXX XXXX - Time out, no char received
* OOOY YYYO - Data received, but error detected
* See Line status Bit Definitions
*
* For 'Get port status' (AH=3):
* AH = Line status (see above)
* AL = Modem status (see above)
*
* Global Variables:
*
: Asyne_adapter-PQrt_list (word * 4):
* Word 0 = adapter address of COM1
* Word 1 = adapter address of COM2
* Word 2 = adapter address of C0M3
: Word 3 = adapter address of C0M4
* These four words contain the hardware port addresses of the asyne adapters. Four asyne
: adapters can be supported al though the operating system may only recognize COM 1,2.
: Async_time_out_ccx.nt (byte * 4):
* Byte 0 = time out count value for COM1
* Byte 1 = time out ccx.nt value for COM2
* Byte 2 = time out count value for COM3
: Byte 3 = time out count value for C0M4
: The time outs for no response use the contents of these cells for a COU1t.
* Registers Modified:
* AX is modified
A Type BiosKit
The Comm Driver E133
*
* Argunents:
*
* Return:
*
* Version History:
* 1.01
* Get divisor corrected by using a peek to reference the baud rate table
* - 1.02
: Pre-cleared comm list before scanning to insure no phantoms present.
***************************************************************************************************1
1* INC L U D E F I L E S *1
#include "atkit.h"
1* FUN C T ION PRO TOT Y PES *1
unsigned comm setup(void);
void scan comm(unsigned);
void interrupt cdecl far comm_io(interrupt_registers);
1* G LOB A L V A R I A B L E S *1
extern unsigned comm list [41;
extern unsigned char-comm_timeout_list [41;
1* G LOB A L CON S TAN T S *1
const unsigned baud table[81=<1047,768,384,192,96,48,24,12};
extern _comm_io; -
1* L 0 CAL D E FIN I T ION S *1
1* 8250/16450 register offsets from base address *1
#def i ne tx data reg OxOO
#define rx-data-reg OxOO
#define div lsb-reg OxOO
#define div-msb-reg Ox01
#define int-enb-reg Ox01
#define int-id reg Ox02
#define line ctrl reg Ox03
#define modeiii ctrT reg Ox04
#define line itat reg Ox05
#define modeiii_staf_reg Ox06
1* 8250/16450 register bit definitions *1
#def i ne txrdy Ox60
#define rxrdy Ox01
#define dsr bit Ox20
#define Ox01
#define Ox10
#define rts:bit Ox02
1* opcode definitions *1
#define initialize OxOO
#define send character Ox01
#define rx cnaracter Ox02
#define reid_status Ox03
#define equipment Ox10
#define tlmeout_bit Ox8000
1* PRO G RAM *1
II SCAN Com Ports -
II This routine is called to detenmine how many serial ports are in the system
unsigned comm setup(void)
{ -
unsigned i;
link interrupt(Ox14,& comm io);
for Ti=0;i<4ii++) poki40(&comm_list[i1,0); II insure list is clear before scanning
scan
scan:comm(Ox2f8);
}
scan comm(Ox3e8);
scan-comm(Ox2e8);
for Ti=0;i<4ii++) pokeb40(&comm_timeout_list[i1,Ox01);
return(oK);
void scan_comm(unsigned port)
Section E: The C ProlUams
(
}
E134 The Comm Driver
unsigned i;
outportb(port+3,Ox55);
if (inportb(port+3) == Ox55)
{
EQUIP FLAG += Ox0200
for (1 = O;i < 4) 1& (peek40(&comm list[i]) 1= O;i++);
poke40(&comm list[i],port); -
} -
void interrupt cdecl far comm_io(interrupt_registers)
(
unsigned port address,divisor;
unsigned time-out;
unsigned long-timeout counter;
setds_sys t em_segment (1;
snapshot_in(COM,&es);
if (dx > 3) '* check for OX out of range */
(
watch string(COM,"Bad Port");
} -
else
(
/* get the time out parameter *'
time_out = peekb40(&comm_timeout_list[dx]);
/* scale to use as a major loop counter */
time_out *= 10; '* figure 1 count = 500 millisec = 10 clock ticks
/* get the port address for the (OX) specified device *'
port_address = peek40(&comm_list[dxl);
'* if no serial port for this logical device *'
if (port address == 0)
{ -
/* return with a time-out error */
ax 1= timeout bit;
} -
else
{
switch (ax 8)
(
case initialize: /* INITIALIZE THE PORT *'
ax &= OxOOff;
watch string(COM,"lnit Port");
/* set divisor latch enable */
outportb(port address+line ctrl reg,Ox80)i
/* the divisor */ - -
divlsor = peekcs(&baud table[(ax 5) &OxOOO7]);
/* load the baud rate aivisor into the 8250 */
outportb(port address+div lsb reg,divisor);
outportb(port-address+div-msb-reg,(divisor 8;
/* set */
outportb(port address+line ctrl reg,(ax & Ox1f;
/* set OTR ana RTS lines *7 -
outportb(port address+modem ctrl reg,(OxOS 1 dtr bit rts_bit;
ax = inportb(port address+l1ne stat reg); -
ax = (ax 8) 1 1nportb(port_iddreis+moaem_stat_reg)i
break;
case send character: /* SEND A CHARACTER */
watch_strTng(COM,"Send Char");
/* start with clean return status */
ax &= OxOOff;
/* set dtr and rts */
outportb(port address+modem ctrl reg, inportb(port address+modem ctrl reg) dtr_bit 1 rts_bit)i
/* check dsr ind cts */ - - - --
timeout_counter = set_timeout_count(time_out);
("ile(inportb(port_address+modem_stat_reg) & (dsr_bit 1 cts_bit 1= (dsr_bit cts_bit)
if (TIMER LONG >= timeout counter) {ax 1= timeout bit; break;}
} - - -
if ax & OxffOO) == 0) /* OK - no timeout */
(
timeout_counter = set_timeout_count(time_out)i
whileinportb(port address+line stat reg) & txrdy) 1= txrdy)
{ - --
A Type BiosKit
The Comm Driver E135
if (TIMER_LONG >= timeout_counter) {ax 1= timeout_bit; break;}
}
if ax & OxffOO) == 0) /* OK - no timeout */
(
/* send the character */
outportb(port address+tx data reg, ax);
/* return the-status in XH */-
ax = (ax & OxOOff) 1 (inportb(port address+line stat reg) 8);
} - --
}
break;
case rx character: /* RECEIVE A CHARACTER */
watch_striiig(COM,"Rx Char"):
/* start with clean return status */
ax &= OxOOff;
/* set OTR out */
outportb(port_address+modem_ctrl_reg, inportb(port_address+modem_ctrl_reg) I dtr_bit)i
/* check OSR */
timeout counter = set timeout count(time out)
1 dsr_bit) 1= dsr_bit
}
}
}
if (TIMER LONG >= timeout counter) {ax 1= timeout bit, break;}
} - - -
if ax & OxffOO) == 0) /* OK - no timeout */
(
/* check for data ready */
timeout counter = set timeout count(time out):
whilefinportb(port address+Tine stat reg) & rxrdy) 1= rxrdy
{ - --
if (TIMER LONG >= timeout counter) {ax 1= timeout bit: break:}
} - - -
if ax & OxffOO) == 0) /* OK - no timeout */
(
}
ax = inportb(port_address+line_stat_reg) & Ox1e) 8) 1 inportb(port_address+rx_data_reg);
}
break;
case read status: 1* READ THE STATUS */
watch_strTng(COM,"Read Status"):
ax = inportb(port address+line stat reg):
ax = (ax 8) 1 Tnportb(port_address+modem_stat_reg)i
break;
default:
watch string(COM,"Bad Comnandll)i
ax I=-timeout_bit:
snapshot out(COM,&es);
} -
/*======================================================*/
Section E: The C Pro&rams
The Timer Interrupt E141
FOURTEEN
The Timer Interrupt
The Timer Interrupt is called by the hardware real-time clock every 53 milliseconds
to increment the time count. This count is used by DOS to calculate the time of day.
Note - A user supplied routine may be linked to the timer interrupt routine, using
interrupt IC. This user routine should be of minimal execution time, since other
interrupts are disabled while it is running. If it retains control too long, other
interrupts may be missed.
/***************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: AT Bios real time clock service routine
*
* Version: 1.01
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: attmr.c
*
* Language: MS C 5.1
*
: Functional Description:
* Interrupt Ox08
: This routine services the real time clock interrupt.
* Arguments:
*
* Return:
*
* Version History:
* 1.01
: Replaced peeks and pokes with casts
***************************************************************************************************/
/* INC L U D E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
void interrupt cdecl far timer_int(interrupt_registers);
/* G LOB A L S */
extern _timer_inti
/* CON S TAN T S */
/* D E FIN E S */
/* PRO G RAM */
unsigned timer setup()
{ -
link interrupt(Ox08,& timer int); return(ok);
} - --
//===============================================
void interrupt cdecl far timer int(interrupt registers)
{ --
/* increment timer COU'lt check for 24 hour value */
if(++TIMER_LONG >= TIMER_LONG_MAX) { TIMER_LONG = 0; TIMER_OFL = 1; }
if(--MOTOR_COUNT == 0)
(
}
E14 2 The Timer Interrupt
MOTOR STATUS &= OxfO; /* turn off motor running bits */
outportb(0x3f2,OxOc); /* turn off any FD motors */
timer chain();
eoi siquence()i
} -
A-Type BiosKit
The Time of Day Function E-15-1
FIFTEEN
The Time of Day Function
The Time of Day Function is used to read and set the timer counter, which IS
incremented by the timer interrupt.
1***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: AT Bios time of day function
*
* Version: 1.03
*
* Author: FOSCO
*
* Date: 10-20-89
*
* Filename: attod.c
*
* Language: MS C 5.1
*
: Functional Description:
* Interrupt Ox1A - Time of Day function call -
* readlset the clock
*
*
* I n.terrupt 1AH - Time of Day funct i on ca II
* readlset the internal clock or the 6818 clock chip
*
* AH = 0 read the clock.
* returns:
* CX = high word of count
* OX = low word of count
* AL = 0 if no 24 hour rollover since last read
*
* AH = 1 set the clock
* CX = high word of count
* OX = low word of count
*
* AH = 2 read the time from the 6818 clock
* returns:
* CH = BCD hours
* CL = BCD minutes
* DH = BCD seconds
* CY flag if 6818 not running
*
* AH = 3 set the time to the 6818 clock
* CH = BCD hours
* CL = BCD mi nutes
* DH = BCD seconds
* DL = 0/1 = normal/daylight time
*
* AH = 4 read the date from the 6818 clock
* returns:
* CH = BCD century
* CL = BCD year
* DH = BCD month
* DL = BCD day
* CY flag if 6818 not ruming
*
* AH = 5 set the date to the 6818 clock
* CH = BCD century
* CL = BCD year
* DH = BCD month
: DL = BCD day
* AH = 6 set the 6818 alarm
* CH = BCD hours f rom set time
* CL = BCD minutes from set time
* DH = BCD seconds from set time
* returns:
* CY flag if alarm already set
* NOTE: function 6 is hooked through Int. 4ah, user replaceable.
*
*
* AH = 7 reset the 6818 alarm off
E152 The Time of Day Function
*
* Version History
* 1.01
* Added enable(): coming into ISR. Fixed Proconm Exiting hangup problem
* 1.02
* Changed outcmos(32 to outcmos(0x32 for setting century byte
* 1.03
: Replaced peeks and pokes w.ith casts
***************************************************************************************************/
/* INC l U 0 E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
unsigned time of day setup():
void interrupt caecl-far time of day(interrupt registers):
unsigned in-progress(voidl: -
unsigned initiaTize_status(void):
/* G LOB A L S */
extern _time_of_day:
/* L 0 CAL 0 E FIN I T ION S */
#define READ CURRENT CLOCK OxOO
#define SET Ox01
#define REAa RTC OxU2
#define SET JTC Ox03
#define REAa OATE Ox04
#define SET OxOS
#define SET-ALARM Ox06
#define RESrT_ALARM Ox07
/* PRO G RAM */
uns i gned time of day setup()
( - - -
}
link_interrupt(Ox1a,&_time_of_day):
return(ok):
void interrupt cdecl far time_of_day(interrupt_registers)
(
enable():
setds system segment():
snapsnot in(TOO,&es):
switch(ai 8)
(
case READ CURRENT CLOCK:
watch strTngCTOIl.c.1fRead Current Clock"):
ax = fax & oxffuu) 1 TIMER OFL:
dx = TIMER_LOW: -
ex = TIMER HIGH:
TIMER OFL = 0:
break;
case SET CURRENT CLOCK:
watch stringCTOO;"Set Current Clock
ll
):
TIMER:LOW = dx:
TIMER HIGH :II ex:
TIMER:OFL = 0:
break:
case READ RTC:
watch strTng(TOO/'Read Time"):
flags-&:II -carry Dit:
if (update in nrogress() == error)
{ - ...,..
flags 1= carry bit:
} -
else
(
dx = incmos(O):
dx = dx 8
ex =
cx = (ex 8) 1 incmos(2):
}
break:
case SET RTC:
watch stri",(TOO,"Set Time
ll
):
if (update_,n-progress() == error)
A Type BiosKit
The Time of Day Function E153
(
initialize status();
} -
outcmos(OxOO,dx 8);
outcmos(Ox02,cx);
outcmos(Ox04,cx 8)"
outcmos(OxOb,(incmos(6xOb) & Ox30) 1 (dx & Ox0001) 1 2);
break;
case READ DATE:
watch strTng(TOO,"Read Date");
flags-&= -carry bit;
if (update in nrogress() == error)
{ _ .or
flags 1= carry bit;
} -
else
{
cx = incmos(Ox32)i
cx = (cx 8) 1 1ncmos(9);
dx = incmos(8);
dx = (dx 8) 1 incmos(7);
}
break;
case SET DATE:
watch stri"Q(TOO,"Set Date");
if (update 1n nrogress() == error)
( _ .or
initialize status();
} -
outcmos(6,0) "
out cmos (7 ,dx);
outcmos(8,dx 8);
outcmos(9,cx);
outcmos(0x32,cx 8)"
outcmos(OxOb,(incmos(6xOb) & Ox7f;
break;
case SET ALARM:
}
watch string(TOO,"Set Alarmll);
flags-&= -carry Dit"
ifincmos(OxObJ & 6x20) 1= 0)
{
ax = 0"
flags 1= carry bit;
} -
else
(
}
if(update in nrogress() == error)
( _ .or
initialize status();
} -
outcmos(1,dx 8);
outcmos(3,cx);
outcmos(S cx 8);
outportb(6xa1,inportb(Oxa1) I OXfe)l"
outcmos(OxOb,(incmos(OxOb) & Ox7f) Ox20);
break;
case RESET ALARM:
watchstriiig(TOO,"Reset Alarm");"
outcmOs(OxOb,incmos(OxOb) & OxSr);
break;
default:
watch_string(TOOc"Bad Conmand");
flags 1= carry_b1t;
break;
snapshot out(TOO,&es);
} -
//--------------------------------------------------
unsigned update in nrogress(void) ( _ .or
unsiined j;
for(J = 0; j < 600; j++)
(
if incmos(OxOa) & Ox80) == 0) return(ok);
}
return(error);
Section E: The C Pro&rams
E154 The Time of Day Function
)
unsigned initialize status(void)
( -.
)
outcmos(OxOa,26);
outcmos(OxOb,82);
incmos(OxOC)i
i ncmos (OxOel) ;
A-Type BiosKit
The Print Screen Function E-16-1
SIXTEEN
The Print Screen Function
The Print Screen Function is used to print the screen contents to LPTl.
Some additions and enhancements could be:
* Creating an "active_printer" flag (in system ram) which could be used to direct
screen prints to LPT2 or LPT3.
* Providing a screen print function to output on a serial channel. .
* Using this module as a guideline for creating a print-screen to disk-file
applications program.
There are various public-domain print-screen functions which support video
adapters other than MDA and CGA. An EGA print-screen routine for instance, has
been circulated on various Bulletin Board Systems. The logic of one of these could
be adapted to replace the standard print screen function, if desired.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
: Module Name: AT Bios print screen function
* Version: 1.01
*
* Author: FOSCO
*
* Date: 10-20-89
*
: Filename: atprsc.c
* Language: MSC 5.1
*
: Functional Description:
* Interrupt OxOS .
: This module copies the contents of the screen buffer to the printer.
* Argunents:
* None
*
* Return:
* None
*
* Version History:
* 1.01
: replaced peeks and pokes with casts
***************************************************************************************************/
/* INC L U D E F I L E S */
#include "atkit.h"
/* FUN C T ION PRO TOT Y PES */
void interrupt cdecl far print screen(interrupt registers);
void print_screen_service(struet prscregs *); -
/* G LOB A L S *./
extern -print_screen;
/* PRO G RAM */
void print screen setup()
{ --
link_interrupt(Ox05,&-print_screen)i
}
variables
E16 2 The Print Screen Function
unsigned line,old cursor, current
unsigned char row, coT, current-char; -
end_variables prscregs; -
void interrupt cdecl far print_screen(interrupt_registers)
(
prscregs *myblock;
unsigned prlnt error = false!
myblock = acquTre block(PRSC);
if (PRSC BUSY 1= T) 1* check status byte *1
( -
}
PRSC BUSY = 1; 1* set status = busy *1
myblock->ax = OxOfOOi
SYS int(Ox10,myblock);
I
W
get current screen mode *1
= myblock->ax 8;
myblock->ax = OxOOOd;
myblock->dx = O
sys
mybTock->ax =""OxOOOa;
myblock->dx = O
sys_int(Ox17,mYblock);
myblock->ax = Ox0300;
SYS int(Ox10,myblock);
I
W
read and save old cursor position *1
myblock->old cursor = myblock->dx;
myblock->row-= myblock->col = 0;
for (myblock->row = 0;
(myblock->row < 25) & Iprint error;
myblock->row++) -
(
for (myblock->col = 0;
(myblock->col < line) & Iprint_error;
{
myblock->col++) -
II set cursor position
myblock->ax = Ox0200;
myblock->dx = (mvblock->row 8) myblock->col;
sys_int(Ox10,myblock);
II read character at cursor
myblock->ax = Ox0800;
myblock->bx = o
sys_int(Ox10,mYblock);
II print character
myblock->current char = myblock->ax;
if (myblock->current_char==O) myblock->current_char = Ox20;
myblock->dx = 0;
myblock->ax = myblock->current char & OxOOff;
sys int(Ox17,myblock)' -
ifamyblock->ax & 1= 0) print error = true;
} -
II do the cr-lf at end of columns
myblock->ax = OxOOOd;
myblock->dx = o
sys
mybTock->ax =""OxOOOa;
myblock->dx = o
sys int(Ox17,mYblock);
if(rmyblock->ax & Ox0100) 1= 0) print_error = true;
}
myblock->ax = Ox0200; II reset cursor to original position
myblock->dx = myblOCK->old cursor;
sys int(Ox10 myblock); -
PRSC BUSY = 6; 1* clear status = not busy *1
} -
A-Type BiosKit
The Vue File E171
SEVENTEEN
The Vue File
The Vue.c file is the source code for Sys Vue, the resident monitor/debugger
program. SysVue allows the user to gain access to the system features from any
program. If the bootstrap operation is unsuccessful, program control is automatically
transferred to Sys Vue.
SysVue has some Watch features built-in to assist in development/debugging. The
"select" command is used to set and clear specific bits in the watch_selection
variable. These bits are checked when "watch" is "on" and display commands
imbedded in the various function routines ~ r e enabled. These display commands
are:
"watch_string( device, "string");
"watch_ word( device, word_value);
"watch_ byte ( device,byte_ value);
These watch commands check to see if the corresponding "device" bit is set in the
watch_flag variable. H so, the command is executed. When developing and
debugging code, this feature is extremely handy. For a final version, one may wish to
delete the "watch_xxxxO" calls to save space and increase speed.
The SysVue "SI" command is used to display pertinent data about the Bios and the
system. It is especially handy for tech support communications, allowing the user to
use the "SI" command to display and convey commonly requested information to the
technically oriented person. Since it also shows configuration information, it permits
a quick peek at the current system configuration.
The system Setup is accomplished by the use of the:
"Time" and "Date" commands to s.et the clock\calendar
"Drive" to set the number and type of floppy and hard drives
"Video" to set the type of video adapter
"Mem" to set the size of system and extended memory
"Npx" to declare the presence of the numeric processor
"Types" to display the hard disk types in the resident type table
"Cmos" to display the checksum value of the CMOS RAM
The redirection command "> ","> con"," > lpt" are used to copy the screen output to a
printing device. This allows generating audit trails when involved in debugging, and
with "watch" enabled, can provide a wealth of data concerning internal Bios
operation. Since one can re-compile the Bios with additional "watch_xxxO"
commands, debugging aids can easily be placed where desired.
The "Trace" and "e" (for execute) commands allow a detailed single-step trail to be
generated when required. Once a problem area is located with "watch" features, this
single stepping can provide lowest level tracing of system action. Single stepping
does NOT sense when the stack-segment or stack-pointers are changed, so
unpredictable results may occur when these registers are changed.
E172 The Vue File
The "Int" command allows the execution of an interrupt, using the register values set
with the "Rxx" commands. This permits specialized execution of bios functions from
within sysvue. With the watch function enabled, this is a handy debugging aid.
SysVue may also be expanded with new commands as desired.
An easy way for you to generate documentation of your version of Sys Vue is to use
the" > LPT" command to provide hard copy of the various screens and menus. These
printouts may then be integrated into the user documentation you create.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988 - All Rights Reserved
*
* Module Name: AT Bios SysVue
*
* Version: 1.00
*
* Author: FOSCO
*
* Date: 12-01-88
*
* Filename: atvue.c
*
* Functional Description:
*
* This is the SysVue module which is a Bios-resident debug/monitor program.
*
* NOTE:
: Entry to SysVue is by CTRL-ALT-BREAK.
* Argunents:
*
* Return:
*
* Version History:
*
***************************************************************************************************/
/* INC L U D E F I L E S */
#include lIatkit .h"
/* FUN C T ION PRO TOT Y PES */
unsigned sysvue setup();
void interrupt cdecl far sysvue(void);
void cdecl far sysbreak(voia);
char ci (void);
void co(char);
unsigned ishex(char);
unsigned islower(char)i
unsigned isalDha(char)i
unsigned isdelim(char);
void lword(unsigned)i
void pword(unsigned);
void lbyte(char)i
void pbyte(char),
char get byte(vold);
unsignedrget word(void),
void poked(liisigned,unslgned long int);
void set system segment (void);
void syntax error(void)i
void write itring(unsigned);
unsigned get token(void);
unsigned get-token number(unsigned *)i
void find next list item(void);
void get Tine /* erg is line. terminator char */
token velue( ;
unsigned loni get Timits();
void set vector(cnar,unsigned,unsigned)i
unsignedilong get vector(char);
unsigned console Dreak(void)i
void far call(uniigned,unsigned);
unsignedivalue-present(char);
void display regs(unsi9ned)i
void display:flags(unslgned)i
/* G lOB A L V A R I A B L E S */
A Type BiosKit
1*------ external data (variables) declarations
extern reset:
extern unsigned comm list[]:
extern l.I1signed lpt_Tist[]:
/* variables are in system scratch segment of RAM *1
extern char sysvue busy; 1* 0/1 = not busy/busy *1
extern unsigned long break chain:
extern l.I1signed long trace-chain:
extern unsigned long Chain:
extern char
extern char eXlt flag
extern char buffer[SOi:
extern unsigned buffer index,token index:
extern list index, token number; -
extern unsigned
extern unsigned token value[Si:
extern unsigned cc; -
extern char present:
extern unsigned last start seg:
extern unsigned last-dumP-start-off:
extern l.I1signed enter seg;enter-off:
extern char inchar; - -
extern unsigned int seg,int off:
extern unsigned reg-index: -
extern unsigned reg-saves[15]
extern unsigned inreg
extern unsigned outreg saves[15 ;
extern unsigned trace count:
extern char break flag:
extern char
extern char last aelim:
extern char record type"
extern l.I1signed watch flag:
extern unsigned watch-selection:
extern unsigned u found:
extern unsigned jj;
extern unsigned redirect flag:
extern char dec_array[61;
1* G LOB ALe 0 N S TAN T S *1
1*------ external data (constants) declarations ---------*1
1* constants are in Bios ROM *1
extern bios id:
extern ver Td;
extern bioi name:
extern owner_id:
extern date_stamp:
1* L 0 CAL 0 E FIN I T ION S *1
#define byte 1
#def i ne word 2
#define dword 4
#define ascii 1
#def i ne hex 2
#def i ne data record 0
#define end of file record 1
#define extended adaress record 2
#define start_adaress_reeord 3
1* this are the delimiters for biosvue command strings *1
#def i ne space 32
#def i ne comma 44
#define colon 5S
#def i ne semi co l on 59
#define leftparen 40
#define rightparen 41
#def i ne per i od 46
#def i ne 63
#def i ne tab 9
#define quote 34
#define slash 47
1*------------ enumeration lists ------------*1
1* This list MUST be in the same order as the command token list.
** The enumerated values for the commands are assigned by this list.
** These values are used by the case operator in the main body of SysVue.
The Vue File E173
Section E: The C ProlUams
E174 The Vue File
** For each entry in this list, there rust be a corresponding entry in the Comnand Token List.
** The token list is searched and the number of the find is used as the comnand switch value.
*/
enllll cOllEnd
{
cOIIEnd NUL, /* Nul value = no find */
cOllEnc:f'C /* * /
COIIEnc:f'CA, /* ascii */
COIIEndrCB, /* byte */
cOIIEndrCW, /* word */
COIIEnc:f'CD, /* compare double */
cOIIEndrCHK, /* checksllll */
commandrCLS /* clear screen */
cOIIEndrCOL6 BOOT, /* cold boot */
cOIIEndrCMOS-; /* display cmos contents and checksl.tll */
cOIIEndrDATE, /* set date */
cOIIEndrD /* */
COIIEndrDA, /* dump ascii */
commanc:f'DB, /* byte */
cOIIEndrDW, /* word * /
cOIIEndrDD /* dumP double word */
COIIEndrDRfVE, /* set number and type of drives */
COllEnc:f'E, /* enter or execute */
cOIIEndrEA, /* enter ascii */
cOIIEndrEB, /* enter byte * /
commandrEW, /* enter word */
commandrED /* enter double */
commandrExh, /* exit from SysVue */
commandrF /* fill */ .
cOllEndrFA, /* fill ascii */
commanc:f'FB, /* fill byte */
cOllEndrFW, /* fill word * /
commandrFD, /* fill double */
commandrH, /* hex add and subtract */
commandrHARD BOOT, /* hard boot */
commandrHELP;
cOllEndrl /* i port * /
cOllEndrl6, /* input byte */
commanc:f'IW /* word */
cOllEndrlNt, /* interrupt */
cOllEndiM /* move */
cOIIEndiMEM, /* set/display mem sizes */
cOIIEnc:f'NPX, /* select NPX present or not */
/* output port * /
cOIIEndrUII, /* output byte */
cOIIEndrOW, /* output word * /
COIIEnc:f'QUIT, /* exit from SysVue */
.. /* display registers */
comnanc:f'KAA, /* register ax */
cOIIEndrRBX, /* register bx */
commandrRCX, /* register cx */
cOllEndrRDX, /* register dx */
cOIIEndrRSP, /* register sp */
cOllEndrRBP, /* register bP */
COIIEnc:f'RSI, /* register si */
cOIIEndrRDI, /* register di */
cOIIEncf"RDS, /* register ds */
cOIIEndrRES, /* register es */
cOIIEnc:f'RSS, /* register ss */
cOIIEndrRCS, /* register cs */
commandrRIP, /* revister ip */
cOIIEndrRF, /* reglster flags */
cOllEnc:f'RHEX, /* read Intel hex */
cOllEndrSI, /* display info */
cOIIEndrSELECT, /* select watch parameters */
cOIIEndrS, /* search */
cOllEnc:f'SA, /* search ascii */
cOIIEnc:f'SB, /* search byte */
cOllEnciSW, /* search word */
cOIIEndrSO, /* search double */
cOIIEnc:f'TIME, /* set time */
cOllEndrT /* single step */
commandrTRACE, /* single step */
commandrTYPES, /* list hard drive types on table */
commanc:f'VIDEO, /* set/display video adapters */
commandrWATCHL_L* watch bios */
commandrWARM /* warm boot */
commandrWHEX-; /* write Intel hex */
commanciTO LPT, /* di rect output to lpt * /
commandrTO-CON /* di rect output to conso l e * /
commandrBAeK TO CON, /* defaul t back to console */
>; - --
/* this enumeration list is used for the register
** display cOllEnds.
A Type BiosKit
*/
enun order
{
nulreg,
axsave,bxsave,cxsave,dxsave,spsave,
bpsave,sisave,disave,dssave,essave,
sssave,cssave,ipsave,pswsave,
}i
1* l 0 CAL CON S TAN T S */
The Vue File E175
II this is a list of the command tokens for biosvue, it MUST agree with the enumeration list
const command_token_list[]=
(
"C", 1* cOfl1)8re */
"CA", 1* cOfl1)8re ascii *1
"CB" , /* cOfl1)8re byte * /
"CW", /* cOfl1)8re word */
"CD" , /* cCJl11l8re doubl e * /
"CHK" , /* checksun *1
"ClS", 1* clear screen */
"COLO" /* cold boot */
"CMOS"; /* display cmos contnets and checksun */
"DATE", /* set date */
"Oil 1* ~ */
"DAI" /* dUJ1) asci i * /
"DB", /* dUJ1) byte * /
"DW", /* dUJ1) word */
"00", 1* dll'l1? double */
"DRIVE" /* d1splay or set drives *1
liE II /' enter */
ilEAl, , 1* enter asc ii * /
"EB", 1* enter byte */
"EW", /* enter word */
"EO" /* enter double */
"ExItI, /* exi t from SysVue * /
"F", 1* fill */
"FA", /* fill ascii */
"FB" /* fi II byte */
"FWII; 1* f ill word * /
"FO", /* fill double *1
"H" /* hex add and subtract * /
II HARD II /* hard boot */
IIHELP"; / ~ display help */
"I", /* 1I)PUt port *1
II I B" /* lnput byte */
"IW"' /* input word */
II INTI, , /* interrupt */
"M'I 1* move * /
IIMENU, 1* set/display meory sizes */
"NPX", /* select NPX present or not */
"0", 1* output port */
"OB", /* output byte * /
"OW" /* output word * /
IlQUIf" /* exit form SysVue */
"R" i* display registers */
II RAX II /* register ax */
"RBX'" /* register bx */
"RCX"' /* register cx */
"ROX'" 1* register dx */
"RSP'" /* register sp */
"RBP" , /* register b{) */
"RSI'" /* register Sl */
"ROI'" /* register di */
"ROS'" /* register ds */
"RES'" /* register es */
"RSS'" /* register ss */
"RCS'" /* register cs */
"RIP"; /* r e ~ i s t e r ip */
"RF", /* reg1ster flags */
"RHEX" /* read Intel hex */
"SI", '1* display id */
"SELECT", /* select watch parameters */
"S" /* search */
"SAl" /* search ascii */
"SB", /* search byte */
"SW", 1* search word */
"SO" 1* search double */
"TIME", /* set time */
"Til,
"TRACE",
"TYPES", /* list hard drive types on table *1
"VIDEO" /* set/display video adpaters */
"WATCHII; /* watch bios */
Section E: The C ProlUams
E176 The Vue File
"WARM", /* warm boot */
"WHEX", /* write Intel hex */
">LPT",
">CON",
">"
8-1: /* list terminator */
};
// the register token list is searched to determine the switch value for the register commands.
const register_token_list[]=
{
II AX II , "BX" , "CX" , "DX" , "Spil , "BP" , liS I II, liD I ", "DSII , liES" , "55" , "CS" , II I P" , -1 ,
};
// the flag token list is used for the flag register command
const flag token list[]=
{ --
"NC" , "Cyll, 11 __ 11," __ " , II PO " ,"PEII," .. II ," .. 11 ,"NA" , "AC" ,11 11 ,11 11 , "NZ" ,"ZR" ,11 11,11 11,
"PLII, "NG", liD I II, liE I II ,"UP", "DN", "NV", "OV", 11 11,11 11,11 11,11 11, II . 11,11 11, II .. ", 11 11,1,
};
// the flag display token list is used for the flag register command
const flag display token list[16] [2]=
{ - - -
"NC", "Cyll, 11 .. 11, .1 11, IlPO", IIPE", 11 11, II. _I', II NAil , "AC" ," .. 11, 11 11, "NZ", "ZR", 1' 11, 11 11,
"PL II, "NG", "0 I", liE I", "UP", "DNII, "NV", "OV", I _I', 11 11, 11 11, 1' 11, 11 11, 11 11, 11 11 , II .. 11 ,
};
// This is a list of the delimiter characters to be accepted when parsing command lines.
// A zero value marks the end of the list.
const char delim list[]=
{ -
space,comma,colon,semicolon,leftparen,rightparen,period,ques,tab,quote,slash,D
};
/* PRO G RAM */
/*========= SysVue Setup Routine ==========*/
// This routine is called by the POD to effect the installation of SysVue by patching Interrupt 18.
unsigned sysvue setup()
( -
}
link_interrupt(Ox18,sysvue):
return(ok);
/*==============================================*/
/*==============================================*/
/*======= SysVue Main Routine ==================*/
/*==============================================*/
/*==============================================*/
variables
end_variables vueregs;
// these are arbitrary identifiers so the main routine will know how it was entered
#define trap oriein 5
#define trace orlein 6
#define boot origln 7
#define diviae origin 8
#define syserr:origin 9
void sysmain():
void interrupt cdecl far Divide(interrupt_registers)
(
sysmain(divide origin);
} -
void interrupt cdecl far SysError(interrupt_registers)
(
sysmain(syserr origin):
} -
void interrupt cdecl far Sysvue(interrupt registers)
( -
sysmain(boot origin):
} -
A-Type BiosKit
void interrupt cdecl far Systrap(interrupt_registers)
(
sysmain(trap origin);
} -.
void interrupt cdecl far Systrace(interrupt_registers)
(
sysmain(trace origin);
} -
void sysmain(unsigned origin, interrupt registers)
( -
vue regs *myblock;
enableO;
mvblock = acquire block(VUE);
j'-variables referenced in sys seg *1
exit_flag = 0;
iforigin == boot origin) && (sysvue_busy 1= 0
( -
write string("\n\rSysVue Busyll);
} -
else
(
sysYUe_busyz1;
The Vue File E177
II chain the break vector through sysvue logic: if the break flag is set by the sysbreak isr,
II return a true from the csts routine to abort the op in progress. when exiting sysvue:
II de-chain the vector back to the original state for normal operation.
break chain = get vector(Ox1b);
link_Tnterrupt(Oxlb,sysbreak);
II move the stacked registers into the saves so we know where we came from
reg saves[axsave] = ax;
reg-saves[bxsave] = bXi
reg-saves[cxsave] = cx;
reg-saves[dxsave] = dx;
reg-saves[sisave] = si;
reg:saves[disave] = di;
reg saves[essave] = es;
reg:saves[dssave] = dsi
reg_saves[spsavel = SPi
reg saves[sssave] = get sse);
reg:saves[eswsave] =.fligs;
reg_saves[lpsave] = lp;
reg_saves[cssave] = CSi
if(origin == trace_origin) II de-chain trace vector
(
set_vector(Ox1,trace_chain 16,trace_chain)i
II if(peek(Ox26a,Ox316) == OxObeb)
II{
II place for option of silent trace until condition
II trace_count = 1i
display regs(&reg saves);
wdte sfring("\n\;: II).
lwordfcs);write string(":II)ilword(ip)iWrite string(" II);
lbyte(peeKb(cs,Tpi -
wrlte string(" II).

II}
if(--trace count 1= 0)
( -
if(console break(
{ -
exit flag=Oi
trace cOl.l'lt=1;
} -
else
{
I I check for any key
if (kbhitO)
{
exit flag=O;
trace count=1;
} -
else
Section E: The C Pro&rams
E178 The Vue File
}
(
exit flag=1;
reg savesCpswsave] /= Ox0100; // set trace bit
// chain-in the trace vector
trace chain = get vector(Ox1);
link Tnterrupt(Oxl,Systrace);
} -
}
}
if(origin == trap origin) // de-chain trap vector
{ -
}
// restore the trapped locations and decrement the pc value
// clear the trap saves and stuff
if(origin == boot origin)
{ -
trace COU'lt = 1;
// restore the trapped locations and decrement the
// pc value
// clear the trap saves and stuff
}
mode size = byte: /* default to byte presentation mode */
mode-type = hex: /* default to hex (not ascii) */
if(origin == boot origin)
( -
write string("\nVSysVue Copyright (c) FOSCO 1988, 1989 - All Rights Reserved."):
} -
if(origin == divide origin)
( -
write string("\n\roivide Overflow at location - II):
lwordfcs): write string(":");lword(ip);
} -
if(origin == syserr origin)
( -
write string("\n\rSystem Error, Type - II): lword(ax):
} -
while Cexit flag ==0)
( -
wrhe string(lI\n\rSysVue>II);
get_lTne_inputCcr):
/* move pas t lead i ng spaces * /
while(buffer[buffer_index] == , I) buffer_index++:
ifCget tokenC) == true) /* if there is a command */
( -
/* get the token number for the
** command from the token list
*/
command_index = get_token_numberC&command_token_list):
/* get the rest of the arguments on the command line */
get_valuesC):
/* execute the command */
switch Ccommand index)
( . -
defaul t: /* conmand not fOU"ld */
syntax errorC):
break:-
/*============ COMPARE COMMAND =======*/
case command CA:
mode_type = ascii; mode_size = byte: goto compare_case;
case command CB:
mode_type = "ex; mode_size = byte; goto compare_case:
case command CW:
mode_type = "ex; mode_size = word; goto compare_case;
case command CD:
mode_type = "ex: mode_size = dword; goto compare_case:
case command_C:
A-Type BiosKit
The Vue File E179
cClq)Sre case:
do -
(
if (peekb(token_vaLueCO],token_vaLueC1]) 1= peekb(token_vaLueC4],token_vaLueCS]
co(13): co(10)-
Lword(token vatueCO])i CO(':')i
lword(token-vaLue[1])i
co(' '): cof'>'): co(' ')-
Lbyte(peekb(token_vaLueCOi,token_vaLueC1]:
co(' '): co(' '):
Lbyte(peekb(token_vaLueC4],token_vaLueCS]:
co(' '): cO('<'): co(' '):
Lword(token value[4])i co(':'):
Lword(token-valueCS])i
} -
if(consoLe break( breaki
token vaLueC1]++: token vaLue[S]++;
} - -
whiLe token vaLueC1] < token_vaLueC3]) &&
(token_va lue [T] != 0:
break:
/*======= CLear Screen Command ===========*/
case command CLS:
/I read current video mode
mybLock->ax = OxOfOO;
sys int(Ox10,mybLock);
// reset video mode (cLears screen)
mybLock->ax = myblock->ax & OxOOffi
sys_int(Ox10,mybLock)i
break:
/*=========== CMOS Command ================*/
case command_CMOS:
// this wouLd be a great pLace to have a dump of the CMOS contents_
write string("CaLcuLated CMOS checksun: II);
token-vaLueC1]=0-
foretoken vaLuec6] = Ox10: token value[O] < Ox2e:
token vaLue[O]++) -
( -
token vaLue[1] += incmos(token vaLue[O]);
} - -
lword(token_value[1]);
write string("\nV ActuaL CMOS checksun: II);
lword(incmos(Ox2e) 8) I incmos(Ox2fi
break;
/*============ 0 Commands =================*/
case command OA:
mode_size = 6yte; mode_type = ascii; goto dump_case:
case command OB:
mode_size = 6ytei mode_type = hex; goto dump_case;
case command OW:
mode_size = word; mode_type = hex; goto dump_case;
case command 00:
mode_size = aword; mode_type = hex; goto dump_case;
case command 0:
dump_case: -
cc = 2S6; /* defauLt ~ Length in characters */
if (mode_type == ascii) cc = 1024;
if present & OxSO) == 0)
(
token value[1] = last dump start off + CCi
}token:value[O] = last:dump:start:seg;
if (token_value[3] == 0)
(
token vaLue[3] = token vaLue[1] + cC;
) - -
last_dump_start_seg = token_value[O];
Section E: The C Pro&rams
E1710 The Vue File
last_dump_start_off = token_value[1];
do
(
co(cr); co(lf); lword(token value[O]);
co(':');lword(token_value[1T); co(' ');
if (mode type == ascii)
{ -
do
(
}
cc = peekb(token value[0]6token value[1]++) & Ox7f;
if cc < Ox20) TI (cc> x7e-cc = '.';
co(cc);
while token value[1] X 64) 1= 0);
} -
mode_type == hex) II (mode_type == 0
if mode size == byte) II (mode size == 0
{- -
do
(
co(' ');
lbyte(peekb(token value[O],token value[1]++;
/* print extra spice every four Characters */
if token value[1] X 4) == 0) co(' ');
} - .
while token value[1] X 16) 1= 0);
} -
if (mode size == word)
{ -
do
{
co(' ');
lword(peek(token value[O],token value[1];
token value[1] += 2; -
if ftoken value[1] & Oxfffe) X 4) == 0) co(' ');
} -
while (token value[1] & Oxfffe) X 16) 1= 0);
} -
if (mode size == dword)
{ -
do
(
co(' ');
lword(peek(token_value[0],token_value[1]+2;
co(':'); .
lword(peek(token value[O],token value[1];
token value[1] += 4 -
if ftoken value[1i & Oxfffc) X 4) == 0) co(' ');
} -
while (token value[1] & Oxfffc) X 16) != 0);
} -
/* print the ascii char for the hex dump */
co(' ');
token value[1] -= 16;
do -
(
}
cc = peekb(token value[0]6token value[1]++) & Ox7f;
if cc < Ox20) TI (cc> x7e-cc = '.';
co(cc);
while token value[1] X 16) 1= 0);
} -
if (console break( break;
} -
while token value[1] < token value[3]) && (token value[1] 1= 0;
break; - - -
/*=========== Exit Commands ============*/
case command EXIT:
case
exit flag=1;-
breaK;
/*=========== Enter Commands ============*/
case command EA:
mode_size = 5yte; mode_type = ascii; goto enter_case;
A Type BiosKit
case command EB:
mode_size = 6yte; mode_type = hex; goto enter_case;
case command EW:
mode_size = word; mode_type = hex; goto enter_case;
case command ED:
mode_size = aword; mode_type = hex; goto enter_case;
case command_E:
II if e<enter> then it is execute else it is enter
if (value-present(1) == 0) 1/ e<enter> is execute
<
}
exi t flag=1;
trace count = -1;
reg sives[pswsavel 1= Ox0100; II set trace bit
II Chain-in the trace vector
trace chain = get vector(Ox1);
link Tnterrupt(Oxl,Systrace);
breaK;
enter_case:
1* if there is a command line input, just store it *1
if(value-present(3) == true)'
<
The Vue File E1711
if(mode size == byte) pokeb(token value[O],token value[1],token value[3]);
if(mode-size == word) poke(token value[O],token value[1],token value[3]);
if(mode-size == dword) - - -
< -
poke(token value[O],token value[1],token value[3])
poke(token-value[0],token-value[1]+2,tokin value[2i);
} - - -
}
else
<
lword(token_value[O]); co(':'); lword(token_value[1]);
1* solicit input *1
enter seg = token value [0] ;
enter:off = token:value[1];
inchar = , ,.
while (inchar == , ')
<
co(' ').
if(mode'size==byte) lbyte(peekb(enter seg,enter off;
if(mode-size==word) lword(peek(enter seg,enter off;
if(mode-size==dword) --
< -
lword(peek(enter_seg,enter_off+2;
co(':');
lword(peek(enter seg,enter off;
} --
co('-')
get line input(' ').
1* terminate this on a space or a cr *1
vet valuesC);
If(value-present(1))
<
if(mode size==byte) pokeb(enter seg,enter off,token value[1]);
if(mode-size==word) poke(enter seg,enter off,token value[1]);
}
}
if(mode-size==dword) - - -
< -
poke(enter_seg,enter_off,token_value[1]);
poke(enter seg,enter off+2,token value[O]);
} - - -
enter off = enter off + mode size;
if (Center off X 8) == 0) -
< -
co(cr); co(lf);
lword(enter seg); co(':'); lword(enter_off);
} -
}
break;
1*========== Fill Commands ============*1
Section E: The C ProlUams
E1712 The Vue File
case comnand FB:
mode_size = 6yte; mode_type = hex; goto fill_case;
case comnand FW:
mode_size = word; mode_type = hex; goto fill_case;
case comnand FO:
mode_size = award; mode_type = hex; goto fill_case;
case conmand F:
fill case: -
do -
(
if(mode size == byte) pokeb(token value[O],token value[1],token valuerS]);
if(mode-size == word) poke(token value[O],token value[1],token value[S]):
if(mode-size == dword) - - -
( -
poke(token value[O],token value[1],token valuerS])
poke(token:value[0],token:value[1]+2,token_value[4i);
)
if(console break( break;
token value[1] += mode size;
) - -
while (Ctoken value[1] < token value[3]) &&
(token value[T] 1= 0; -
break;-
1*======= Int Conmand =================*1
II This command invokes the interrupt selected. It uses the sys int registers and the
II sys_int conmand. The user has to confirm the command with an-X to eXecute it.
II this command should use a separate set of registers 1111
case command_I NT:
1* get the interrupt runber from the conmand line */
1* print the vector value *1
if Ctoken value[1] < 256)
( -
write_stringC"lnterrupt is at II);
int off = peek(OxOO,token value[1] * 4)
int:seg = peekCOxOO,ctoken_value[1] * 4) +2);
lwordCint_seg); co(':'); lword(int_off); co(' ');
write_stringC"Press X to confirm eXecution");
1* wait for confirmation *1
cc = ciO;
if CCcc == 'X') II Ccc == 'x'
(
)
write stringC"\n\r"); /1 do a cr If for a clean line
mybloek ->ax = reg saves[axsave];
myblock ->bx = reg:saves [bxsave] ;
myblock ->cx = reg saves[cxsave];
myblock ->dx = reg-saves [dxsave];
myblock ->si = reg-saves[sisave];
myblock ->di = reg-saves[disave];
myblock ->ds = reg-saves [dssave] ;
myblock ->es = reg:saves[essave];
sys_intCtoken_value[1J,myblock);
outreg saves[axsave] = myblock ->ax;
outreg-saves[bxsavel = mYblock ->bx;
outreg-saves[cxsavel = mYblock ->cx;
out reg-saves [dxsavel = mYblock ->dx
outreg-saves[sisave] = mYblock ->si;
outreg-saves[disave] = mYblock ->di;
outreg-saves[essave] = myblock ->es;
outreg-saves[dssave] = myblock ->ds
outreg:saves[pswsavel = myblock ->f{ags;
1* display the register upon return */
display regsC&outreg saves);
) - -
else write_stringC"Value Out of Range II);
break;
A-Type BiosKit
/*============= HELP =============*/
case command HELP:
write string("C <range> <address> -
write-string("CLS - Clear Screen\n\r
ll
);
write-string("CHIC <range> - checksun\n\r")
write-string("COLD - cold boot to cwrent Bios\nv");
wr!te:str!ng("CMOS - display the CMOS checksun\nV");
wrlte strlng("D[type] - memory\n\rll);
wr!te:str!ng("DRIVE [0-3 I A:-F:] [type] dlsplay/set drives\n\r");
wrlte strlng("DATE [xx/xxlxxxx] Display or Set Date\nV");
write-string("E - execute single until any key hit\n\r");
write-string(IIE[type] <address> [<list>] - enter\n\r");
write-string("EXIT - exit from SysVue\n\r");
write-string("F[type] <range> <llst> - fi II \n\r
ll
);
write-stringCIIH <value> <value> - hex add/sub\n\r")i
wr!te:str!ng("HARD - re-boot to primary Bios\nV")i
wr!te_stqngC"HELP - help screen\n\r")i
wr!te_str!ngC"I[type] <address> - In port\n\r")i
wr! te_stqng(IIINT <value> - Interrupt\n\r")i
wrlte strlngC"M <range> <address> - move\nV");
write-stringCIIMEM [sys,ext] - display/set memory sizes\nV");
pause'f);
wr i te s t r i ngC "NPX [0111 - No NPX/Yes NPX\n\r");
wr!te:str!ngC"O[typel <value> OUt port\n\r");
wrlte strlngC"QUIT - eXlt from SysVue\n\r");
write-stringC"R[<reg>] <value> - register\n\r");
write-string("RHEX <range> - read Intel hex\nV");
write-stringC"S[type] <range> <key> <mask> - search\n\r");
write-stringC"SELECT - Select Watch Parameters\n\r
ll
);
The Vue File E17 13
write-stringC"SI - Display System Information\n\r")i
write-string("TIME [xx:xx:xx] - Display or Set Time\n\r");
write-stringC"TRACE [ccx.nt] - Trace ccx.nt steps or untH anykey hit\nV")i
write-string(IITYPES - Display hard disk parameters\n\r");
write-string("VIDEO [type] - display/set vldeO type\n\r");
write-stringC"WARM - warm boot to current Bios\n\r")i
write-string("WATCH - Toggle watch on/off\nV");
write-string("WHEX <range> - write Intel hex\nV")i
write:stringC">[CON I LPT] - redirect console output\n\r");
breaki
/*========== Calculator Command =========*/
case command H:
write string{"Sun is: II); lwordctoken value[1]+token value[3])i
write:stringc" Difference is: II); lwardCtoken_valuelll-token_value[3]);
break;
/*===== Sys Info Command ===========*/
case command_SI:
wdte string("\n\r Current Time: II); <:iisplay timeO;
write:stringc"\n\r Current Date: ");dlsplayjlateO;
write_stringC"\n\r Bios Name: II); write_string(&bios_id);
write_stringC"\nV Bios Version: II); write_string(&ver_id);
write_string("\n\r Bios Date: II); write_string(&date_st8ll1l);
write_stringc"\nV Copyright: II); write_string(&owner_id);
write_stdng("\n\r Bios Size: 64k At Segment: II); lword(bios_csO);
write string("\n\r CPU: II).
I! a cpu type sensing routine could added here
wr!te_str!ng(I80286");
wrl te_strlng("\n\r NPX: II); display_npxO;
write string("\n\r Com Ports: II);
for (cc = 0-
CCcc < 4) i1 Cpeek40C&comm list[cc]) != O;cc++)
( -
lwordCpeek40(&comm list[cc]; co(' ');
} -
write string("\n\r LPT Ports: II);
for (cc = O
cc < 3) i1 (peek40C&lpt list(cc]) != O;cc++)
( -
lword(peek40(&lpt list[cc]; co(' ');
} -
// display the disk drives in the system
Section E: The C Pro&rams
E1714 The Vue File
display_drives();
display_video();
write string(lI\n\rMemory Size
write-string("\n\r Expected:
sys_mem();
wrl te sirlllg("
display ext mem();
II);
System
II) ;
Extended");
write sirini("\n\r Fot.nd: II).
bin2dic(peek40(Ox13) + (sys seg array);
co(dec array[O]); - - -
co(dec-array[1]);
co(dec-array[2]);
co(dec-array[3]);
co(dec:array[4]);
write string(" II).
bin2dic(cmos ext found(),&dec array):
co(dec arrayTO]); -
co(dec:array[1]):
co(dec_array[2]);
co(dec array[3]);
co(dec:array[4]):
#if(O==1)
write string(lt\n\rCMOS Values are:
It
);
write-string(lt\n\rOiagnostic 'I): lbYte( ncmos(OxOe
wri te-string(lt\n\rRestart 'I): lbYte( ncmos(OxOf
write-string(lt\n\rFloppy Disks 'I); lbYte( ncmos(Ox10
write-string('I\n\rHard Disks II): lbyte( ncmos(Ox12
write-string("\n\rEquipnent 'I): lbYte( ncmos(Ox14
#endi'
break;
/*------- set time -------------*/
case command TIME:
i f (va l ue..,preient (0 /I i f anyth i ng entered
{
myblock->cx = token_value[O]:
myblock->cx = (mvblock->cx 8) I token_value[1]:
myblock->dx = token valueD];
myblock->dx = 8;
myblock->ax = Ox0300;
sys int(Ox1a,mvblock);
if(!myblock->flags & carry bit) 1= 0)
write string("Error settini time"):
} - .
write_string("Current Time is - It);display_time():
break: . .
/*------- set date -------------*/
case conmand DATE:
if(value..,preient(O /I if anything entered
{
myblock->dx = token value[O]:
myblock->dx = (mvblOck->dx 8) I token value[1]:
myblock->cx = token value[3]: -
myblock->ax = Ox0500;
sys int(Ox1a,mvblock):
if(!myblock->flags & carry bit) 1= 0)
write string("Error settini date'I):
} -
write_string("Current Date is- 'I):display_date()i
break;
/*------- set drives -----------*/
case command_DRIVE:
// if value - a-f, then set type of drive in system
iftoken value[O] >= OxOa) && (token value[O] <= OxOf
(- -
// a and b are easy, c,d,e,f have to count drives
/I A: is floppy
if(nuttler of floppiesO > 0)
( - -
if(token value[O] == OxOa)
( -
outcmos(Ox10,(incmos(Ox10) & OxOf) I token_value[1] & Ox0007) 4:
}
A-Type BiosKit
)
II B: is floppr
if(number_of_f oppies() > 1)
(
if(token value[O] == OxOb)
( -
The Vue File E1715
outcmos(Ox10,(incmos(Ox10) & OxfO) (token_value[1] & Ox0007i
)
)
II C: is flOppr
if(number_of_f oppies() > 2)
(
if(token value[O] == OxOc)
( -
)
)
outcmos(Ox11,(incmos(Ox11) & OxOf) I token_value[1] & Ox0007) 4;
II 0: is floppr
if(number_of_f oppies() > 3)
(
if(token value[O] == OxOd)
( -
outcmos(Ox11,(incmos(Ox11) & OxfO) I (token_value[1] & Ox0007;
)
)
11------- these are for hard disks ---------
if(number of floppies() <= 2)
II C: ana-O:-are hard drives
(
if(token value[O] == OxOc)
{ -
if (token value[1] < 14) II use primary cell
( -
outcmos(Ox12,(incmos(Ox12) & OxOf) I token value[1] & OxOOOf) 4;
) -
}
else II use secondary cell
(
outcmos(Ox12,incmos(Ox12) 1 OxfO);
outcmos(Ox19,token value[1 )i
) -
if(token value[O] == OxOd)
{ -
if (token value[1] < 14) II use primary cell
( -
outcmos(Ox12,(incmos(Ox12) & OxfO) I (token value[1] & OxOOOf;
) -
)
}
else II use secondary cell
(
outcmos(Ox12,incmos(Ox12) 1 OxOf);
outcmos(Ox1a,token value[1 )i
} -
if(number of floppies() == 3)
II 0: ana-E:-are hard drives
(
if(token value[O] == OxOd)
{ -
if (token value[1] < 14) II use primary cell
( -
outcmos(Ox12,(incmos(Ox12) & OxOf) I token value[1] & OxOOOf) 4;
) -
}
else II use secondary cell
(
outcmos(Ox12,incmos(Ox12) I OxfO);
outcmos(Ox19,token value[11);
} -
if(token value[O] == OxOe)
{ -
if (token value[1] < 14) II use primary cell
( -
outcmos(Ox12,(incmos(Ox12) & OxfO) I (token value[1] & OxOOOfi
) -
}
)
else II use secondary cell
(
outcmos(Ox12,incmos(Ox12) I OxOf);
outcmos(Ox1a,token value[11);
) -
if(number of floppies() == 4)
II E: ana-F:-are hard drives
(
if(token_value[O] == OxOe)
Section E: The C ProlP"ams
E1716 The Vue File
}
{
if (token value[1] < 14) // use primary cell
( -
outcmos(Ox12,(incmos(Ox12) & OxOf) I token_value[1] & OxOOOf) 4;
} .
else // use secondary cell
(
outcmos(Ox12,incmos(Ox12) 1 OxfO);
outcmos(Ox19,token value[1 )i
} -
} .
if(token value[O] == OxOf)
{ -
}
if (token value[1] < 14) // use primary cell
( -
}outcmoS(Ox12,(incmoS(OX12) & OxfO) I (token_value[1] & OxOOOf;
else // use secondary cell
{
outcmos(Ox12,incmos(Ox12) 1 OxOf);
outcmos(Ox1a,token value[1 );
} -
calc cmos(); // recalc checksum
} -
else
(
if(value-present(1 // if anything entered
{
// if value = 0-4, then' of drives in system
if(token value[1] <= 4)
( -
)
if(token value[1] == 0) // set no-drives in system
( -
outcmos(Ox14,incmos(Ox14) & -Ox01);
calc cmosC);
} -
else // there are drives in system
(
outcmos(Ox14,incmos(Ox14) I Ox01)!
outcmos(Ox14,(incmos(Ox14) & Ox3f} I \
token value[1]-1) 6;
calc cmOSC)i
} -
}
}
write string("Qptions are\n\r");
write-string("0-4 = , of floppy drives\n\r");
write-string("A:n - F:n = set drive type\n\rll).
write-string("For Floppy drives:\n\r"); ,
write-string(" 0 = no drive\n\r");
write-string(" 1 = 360k drive\n\r");
wri te-string(" 2 = 102M drive\n\r");
write-string(" 3 = nOk drive\n\r");
write-string(" 4 = 1.44M drive\n\r");
write-string("For Hard drives:");
write-string(" n = drive type\n\r");
write-string("For list of hard drive types, enter IIiITypesllllll);
display_drives();
break;
/*------ list drive types fro. hdisk table ----*/
case command TYPES:
display_hdisK_typeS();
break;
/*------- set memory sizes ----------*/
case command_MEM:
if(value-present(1 /1 if anything entered
{
set sys mem(dec2bin(token value[1];
} - - -
if(value-present(3 // if anything entered
{
set ext mem(dec2bin(token value[3];
} - - -
wr!te_str!ng(" System Memory Size !S - .");displ!y_sys_mem();
wr1te_str1ng("\n\rExtended Memory S1Ze lS - 1I);d1splay_ext_mem();
break;
A Type BiosKit
1*--- select NPX present/not present ----*1
case command NPX:
if(value"present(1
( .
iftoken value[1] & Ox01) == 0)
( -
outcmos(Ox14,incmos(Ox14) & -Ox02);
}
else
(
outcmos(Ox14,incmos(Ox14) I Ox02);
}
calc cmos();
} -
write_string("Options are: 0 = No, 1 = Yes\n\r");
wrl te strlng("NPX II).
displiy npx(); ,
break; -
1*------- set video type ----------*1
case command VIDEO:
The Vue File E1717
write string'f"Options are\n\rO=EGA\n\r1=CGA 40x2S\n\r2=CGA 8Ox2S\n\r3=Monochrome");
if(vaTue"present(1 II if anything entered
(
II chekc for argument validity
iftoken value[1] >= 0) && (token value[1] <= 3
(- -
II this is where we set the video bits
outcmos(Ox14,(incmos(Ox14) & Oxcf) I token value[1] & Ox0003) 4;
calc cmos(); -
} -
else
(
write string("\n\rVideo type argunent IIlJst be between 0-3
11
);
beip();
}
}
else
(
write string("\n\rTo change Expected Video, type IIIIVIDEO n <enter>"II\n\r");
) -
display video();
break; -
1*======== Input from port Command ======*/
case command_IB: mode_size = byte; lbyte( inportb(token_value[1]; break;
case command_IW: mode_size = word; lword(inport(token_value[1]; break;
case command I:
switch (mode-size)
( -
case byte: lbyte(inportb(token value[1]; break;
case word: lword(inport(token value[1]; break;
} -
break;
1*========= OUtput from Port Commands =========*/
case command_OS: mode_size = byte; outportb(token_value[1],token_value[3]); break;
case command_OW: mode_size = word; outport(token_value[1],token_value[3]); break;
case command 0:
switch (mode-size)
( -
case byte: outportb(token value[1],token value[3]); break;
case word: outport(token-value[1],token-value[3]); break;
} --
break;
1*=== Move Command ===*1
case command_M:
do
(
pokeb(token value[4],token value[S)++,

if(console 6reak( Dreak;-
} -
Section E: The C ProlUams
E1718 The Vue File
while token value[1] < token value[3]) &&
(token value[T] 1= 0; -
break;-
/*=== Register Display Command ===*/
case command R: /* display all the registers */
display_regs(&reg_saves);
break;
/*=== Register Display and Change Commands ===*/
case command_RAX: reg_index = axsave; goto r_display;
case command_RBX: reg_index = bxsave; goto r_display;
case command_RCX: reg_index = cxsave; goto r_display;
case command_RDX: reg_index = dxsave; goto r_display;
case command_RSP: reg_index = spsavei goto r_displaYi
case command_RBP: reg_index = bpsavei goto r_display;
case command_RSI: reg_index = sisavei goto r_displaYi
case command_RDI: reg_index = disavei goto r_displaYi
case command_RDS: reg_index = dssavei goto r_display;
case command_RES: reg_index = essave; goto r_displaYi
case command_RSS: reg_index = sssave; goto r_displaYi
case command_RCS: reg_index = cssavei goto r_displaYi
case command_RIP: reg_index = i psave; goto r_displaYi
r_display:
/* if there is a commend line input, just store it */
if(value-present(1) == true)
<
reg saves[reg index] = token value[1];
} - - -
else
<
}
write string(peek(bios cs(),&register token list[reg index-1];
co( I T). - - - -
lword(res saves[reg index])i
co(cr)i co(lf)i cO(T:')i
/* solicit input for register */
get_line_input(cr);
~ e t values()i
If(value-present(1))
<
reg saves[reg index] = token_value[1]i
} - -
breaki
/*-------- Flag Register Command ---------*/
case command_RF:
/* we have to look at comnand line for flag alpha1s */
/* if there is a comnand line input, just store it */
command_index = get_token_number(&flag_token_list)i
if(commend index == 0) // solicit input
< -
display flags();
write sYring(" II).
get_lTne_input(Cr)i'
get token();
command index = get token number(&flag token list);
} - - - --
if (commend index 1=.0)
< -
commend index--i // rebase to zero
lword(cOmmand_index)i
A Type BiosKit
if command index & 1) == 0)
{ -
1* even number - clear bit */
reg saves[pswsave] &= -(1 (command index/2;
} - -
else
{
/* odd number - set bit *1
} reg_saves [pswsave] 1= (1 (command_index/2;
)
break;
/*========= Read Intel Hex =================*/
case command_RHEX:
/* start looking for record marker */
do
(
while(inchar = ci() 1= ':') {}
Sllll = 0;
char count = get byte();
token value[1] =-get word();
recora_type = get_byle();
switch (record type)
{ -
case data record:
if (char count == 0)
{ -
record type = end of file record;
break;- - - -
}
while (char count> 0)
{ -
pokeb(token value[O],token value[1],get byte(i
} - - -
get byte()i
1f {Sllll 1= 0) record type = end of file record;
break; - - - -
case end of file record:
/* return to sysYue main *1
break;
case extended address record:
/* set load aadress sigment *1
token value[O] = get word();
get cyte()i -
if {Sllll 1= 0) record type = end of file record;
break; - - - -
case start address record:
/* set cs:Tp of reg set */
reg saves[cssave] = get word();
reg-saves[ipsave] = get-word();
getlbyte()i -
if {Sllll 1= 0) record type = end of file record,"
break" - - - -
} ,
}
while (record type 1= end_of_file_record);
break; -
/*========= Write Intel Hex =================*/
case command_WHEX:
/* disregard if range = nul */
if token value[1] II token value[3]) != 0)
(- -
/* write extended address record for segment *1
write_string(lI\r\n:
II
);
Sllll = 0i
pbyte(2)ipword(O);pbyte(2);
pword(toKen_value[O])i
PbYte( Sllll) ;
do
{
write string(lI\r\n:
lI
)i
if token value[3] - token value[1]) > 16)
{- -
char count = 16;
} -
The Vue File E1719
Section E: The C Prolaams
E-17-20 The Vue File
else
(
char count = token value[3] - token_value[1];
) - -
sum = o .
pbyte(Char count); /* record count */
pword(token value[1]); /* address */
pbyte(O); /- data mode_type record */
whlle (cnar count> 0)
( -
pbyte(peekb(token_value[0],token_vaLue[1];
token vaLue[1]++;
char_count--;
}-
PbYte(sun);
if (console break( break;
} -
while token value[1] < token value[3]) &&
(token_value[T] 1= 0; -
/* write start address record */
if token value[4] II token value[5]) 1= 0)
(- -
}
write string(II\r\n:II);
sun =-0-
pbyte(4);pword(0);pbyte(4);
pword(toKen vaLue[4]);
pword(token-vaLue[S]);
pbyte(sun);-
write string("\r\n:00000001FF");
} -
break;
/*========= Search Commands =================*/
case command_SA: mode_size = byte; mode_type = ascii; goto search_case;
case command_S8: mode_size = byte; mode_type = hex; goto search_case;
case command_SW: mode_size = word; mode_type = hex; goto search_case;
case command_SO: mode_size = dword; mode_type = hex; goto search_case;
case command_S:
search_case:
/* if no mask entered, then aLL bits significant */
iftoken vaLue[6] I token value[7] ) == 0)
(- -
token value[6] = -token value[6];
token-value[7] = -token-value [7] ;
) - -
if (mode size == byte)
/* clear-un-needed bits from mask */
(
token value[6] = 0-
token-value[7] &= 6xOOff;
) -
if (mode size == word)
/* cLear-un-needed bits from mask */
(
token value[6] = 0;
) -
do
(
ifpeek(token value[O],token value[1]) & token value[7]) ==
(token value[5] ,; token value [7] I &&
(peek(token value[Or,token value[1]+2) & token value[6]) ==
- (toien_value[4] & token:value[6]
(
co(13); co(10) /* cr-lf */
l word( token_va {ue [0.] ) ;
co(':');
lword(token_vaLue[1])i
co(' ');
if (mode size == byte)
( -
Lbyte(peekb(token value[O],token value[1];
} - -
A Type BiosKit
if (mode size == word)
{ -
lword(peek(token value[O],token value[1]i
} - -
if (mode size == dword)
( -
lword(peek(token_value[0],token_value[1]+2i
cO('-')i
lword(peek(token value[O],token value[1];
} - -
}
if(console break( break;
token value[1] ++;
} -
while token value[1] < token value[3) &&
(token value[l] 1= 0; - .
breaki-
1*========= Checksum Command ===========*1
case command CHK:
sum = 0; -
do
{
sum += peekb(token value[O],token value[1]++)i
if (console break(J) break; -
} -
while token value[1] < token value[3]) &&
(token value[l] 1= 0; . -
1* the last byte *1
sum += peekb(token value[O],token value[1])i
write string("ChecKsum = II); -
lbytefsum);
break;
1*========== Re-Boot Commands ===========*1
case command COLD BOOT:
RESET FLAG =-0; I
W
reset the wanm boot flag *1
disabTeO" incmos(OxOO); II set NMI mask
far call(bios cs(),&reset)i
breik; -
case command WARM BOOT:
1* reset flag *1
RESET FLAG = Ox1234;
disabTe()" incmos(OxOO);
far call(bios cs(),&reset);
breik; -
II set NMI mask
case command HARD BOOT: 1* forces cs: to fOOO *1
RESET FLAG =-0; I
W
reset the warm boot flag *1 .
diSabTe()6" incmos(OxOO)i II set NMI mask
far_call( xfOOO,OxfffO);
breaki
1*========== Trace Commands ===========*1
case command T:
case
trace count = token value[1];
if(trice count == OJ trace count = 1;
exit flag=1; -
reg iaves[pswsave] 1= Ox0100; II set trace bit
II Chain-in the trace vector
trace chain = get vector(Ox1);
link Tnterrupt(Oxl,Systrace);
breaK;
1*======= Select Watch parms command =======*1
case command SELECT:
if (value-present(1
{
II modi fr parms
watch se ection = token value[1];
} - -
write string(1I0ptions are (the OR) as follows:\n\r");
lworCVIDEO); write string(1I = Video\n\rll);
lword(VUE)i write itring(1I = SysVue\n\r");
lword(CASSETTE); wrTte string(1I = Cassette\n\r");
lword(EQUIPMENT); write string(" = Equip\n\r");
lword(MEMORY); write stringCII = Mem\n\r")i
lword(LPT); write stringC" = Lpt\n\r");
lword(COM); write:string(" = Com\n\rll)i
The Vue File E1721
Section E: The C ProlUams
}
};
E,17 22 The Vue File
lword(FLOPPY); write string(1I = Floppy\n\r");
lword(HARD); write string(" = Hard\n\r");
lword(TOO); write itring(1I = Tod\n\r");
lword(BOOT); write_string(1I = Boot\n\r");
write string("Current Watch Selections are: II);
watcn selection &= WATCH MASK;
if(watCh selection == 0) write string("None");
ifwatcn selection & VIDEO) 1= 0) write string("Vic::leo II);
ifwatch-selection & VUE) 1= 0) write string("SysVue II);
ifwatch-selection & CASSETTE) 1= 0) write string("Cass II);
ifwatch-selection & EQUIPMENT)I= 0) write-string("Equip II);
ifwatch-selection & MEMORY) 1= 0) write string("MeII II);
ifwatch-selection & LPT) 1= 0) write string("Lpt II);
ifwatch-selection & COM) 1= 0) write-string("Com II);
ifwatch-selection & FLOPPy) 1= 0) wrTte string("Floppy II);
ifwatch-selection & HARD) 1= 0) write string("Hard II);
ifwatch-selection & TOO) 1= 0) write itring("Tod II).
i fwatch-selection & BOOT) ! = 0) wrf.ti string("Boot II);
ifwatch-selection & TIMER) 1= 0) write string("Tmr II).
i fwatch:selection & KEYBOARD) 1 = 0) wrTte_string(IIKb II);
write string("\n\rWatch is currently II);
if(watch flag == 0) .
( -
write_string("Off");
}
else
(
write string(IOn")
} - ,
break;
/*=========== Watch command ==============*/
case command WATCH:
1/ toggle watch flag
if (watch flag 1= 0)
( -
watch flaV = 0;
Write:Strlng(" Off");
}
else
(
Write String(" 0n")
watch-flag = watch selection;
if(reairect flag 1= 0) watch flag &= -LPT;
} - -
break;
/*=========== Re-direction commands ==============*/
case command TO CON:
case commandrBACK TO CON:
redirect flag = 0; -
break; -
}
case command TO LPT:
redirect flag =-1;
// If you are watching the printer driver, it must not be copying screen output to the printer.
// An lnsidious recursion results, blowing the system away
ifwatch_flag & LPT) 1= 0) watch_flag &= -LPT;
break:
ax = reg_saves[axsave];
bx = reg_saves[bxsave];
cx = reg saves[cxsave];
dx = reg-saves[dxsave];
si = reg-saves[sisave];
di = reg:saves[disave];
ds = reg saves[dssave];
es = reg-saves[essave];
flags = reg_saves[pswsave]:
cs = reg saves[cssave]i
ip = reg:saves[ipsave];
// If tracing, we should link the trace vector here
// If trapping (breakpointing), we should link the trap vector here.
set_vector(Ox1b,break_chain 16,break_chain):
A Type BiosKit
The Vue File E1723
sysvue busy = 0; /* release Sysvue */
) -
release block(myblock);
) -
/******************************************************/
1*=========== Console Status Routines ============*/
unsigned console break()
1* returns true Tor abort operation */
{
)
if (break flag == 0) return(false);
break_ fl a9 = 0;
return(true);
1*-------------------------------------------------*/
1* dump byte and word functions *1
void pword(w) /* print word, accumulate checksum */
(
pbyte(w 8); pbyte(w);
)
void pbyte(outchar) /* print byte, accumulate checksum */
(
}
sum -= outchar; /* build checksum for whex conmand */
lbyte(outchar);
1* dunny rvni interrupt rout i ne * /
void rvni intO
{ -
}'
1*--------- supporting functions -------------*/
/I This fooction displays the register set. It is used by the 'R' Conmand and the' INT' Conmand.
void display regs(unsigned *reg saves)
(- -
co(cr); co( If);
for (token index = O;token index < 13;token index++)
(- - -
write string(peek(bios cs(),&register token list[token index];
CO(,=T). - - - -
lword(reg saves[token index+1]);
co(' '). co(' '); -
if (token index == 7) ( co(cr); co(lf); )
) -
co(' '); co(' ');
display flags(reg saves);
) - -
void display flags(unsigned *reg saves)
{- -
)
unsigned even odd;
int scan index;
/* displiy the flag conditions */
for (scan index = 15; scan index> -1; scan_index--)
{- -
)
even_odd = (reg_saves[pswsave] scan_index) & 1;
~ f (peekb(bios_cs(),peek(bios_cs(),&flag_display_token_list[scan_index] [even_odd]
write string(peek(bios cs(),&flag display token list[scan index] [even odd];
co(' T); - - - - - -
)
1*------- get a byte for rhex ---------*/
char get_byte()
(
char cc,d;
cc = ci() - '0'
if (cc > 9) cc ~ = 7
g = ci() - '0'; ,
1f Cd > 9) d -= 7;
cc = CC 4 I d;
1= '-')
Section E: The C ProlUams
E1724 The Vue File
sun += cc
return (d);
)
1*------- get a word for rhex ---------*1
unsigned get warde)
( -
)return get_byte() 8) I get_byte(;
unsigned isdelim(char c) 1* returns true or false *1
(
)
int q=O;
char cc;
1* write string("\n\rIsdelim II). ')*1
for (;(cc-= peekb(bios cs(),&deltm l1st[q++] 1= 6;)
{ --
(* lbyte(cc)cO(' ');*1
1f (cc == (c & 6xff return(true);
}i
return(false);
uns i gned get tokenC)
{ -
)
II this gets the next token from the line input buffer and puts it into the token buffer
I I It uses the buffer index and advances until end of data.
/I It returns true iTa token was found and false if no token found
if buffer[buffer index] == 0) II (bufter[buffer index] == cr return(false);
1* move from butfer to token buffer *1 -
for (token index=O; (isdelim(buffer[buffer index]) == false) && (buffer[buffer index] 1= 0)
token buffer[token index++]=buffer[buffer index++]); -
= 0; -
1* put in end of string marker *1
last delim = buffer[buffer index];
buffer_index++; 1* index over delimiter *1
return (true);
1* *1
void syntax error(void)
( -
write string(lI\n\rSyntax Error");
} -
II Get Line Input is the normal It always terminates on a cr OR on the char
II specified on the callers argo If the caller wants only a CR then he calls with CR
1/ as the argo
void get line input(term) /*---- get the input line ----*/
{ --
bufter index = 0;
do -
(
itinchar = ci( == bspace)
(
)
it (buffer index 1= 0)
( -
buffer index--
co(bspice); I
co(' ');
co(bspace) ;
buffer[buffer index] = 0;
) -
else 1* not a backspace *1
{
1* lower to upper case *1
if inchar >= 'a') && (inchar <= 'z' inchar A= Ox20;
co(inchar); 1* echo character */
ifinchar 1= term) && (inchar 1= cr
1* if a regular character */
(
buffer[buffer index] = inchar;
buffer index++;
) -
else 1* a cr or a term char *1
(
butfer[buffer index] = 0;
buffer[bufter-index+1] = 0;
it (inchar ==-cr) co(lf);
A-Ifpe BiosKit
}
)
}
while inchar != term) && (inchar != cr;
buffer index = 0;
} -
1*--- get the value specified by this token ---*1
unsigned get token value()
( --
}
char cc;
unsigned token value;
token value = 0; 1* pre-clear token value cell *1
token-index = 0;
token-number = get token number(&register token list);
if (token number == 0) I" it is a value, not a token -I
( 1* determine value *1
token index = 0;
while-(token buffer[token index] != 0)
( - -
cc = token buffer[token index];
if (ishex(cc) == true) -
(
if (isalpha(cc) == true) cc += 9;
cc &= OxOf; 1* now it is a nibble *1
1* merge it into token *1
token value = (token value 4) Icc;
} - -
token index++;
) -
return(token value);
} -
else
II if there is a token I, then get the value of that token
(
return(reg saves[token number-1]);
) - -
1*---------------------------------------------------*I
The Vue File E17 25
II search the specified token list against the token buffer and return the token number if a find -
II no find - return token_number = 0
unsigned get_token_number(unsigned *token_listJltr)
{
unsigned token index,list index=O,token number=1;
1* points to current string being checkid *1
unsigned list item;
unsigned item:index=Oi
while
list item = peek(bios cs(), &token list ntr[list index++] != -1)
{- - - ~ -
for (token index = O,item index = O
token buTfer[token index] 1= 0) i1 (peekb(bios cs(),list item+item index) != 0) &&
(token 6uffer[token Tndex] == peekb(bios cs(), lTst item+item index)});
1* co(peekb(bios cs(),list item+list indix,-I - -
token_index++,item_index++}; -
II If they are both at the end of string, then they matched.
~ f token_buffer[token_index] == 0) && (peekb(bios_cs(),list_item+item_index) == 0
1*
** write string("\n\rToken is II); lword(token_number);
*1 -
return(token number);
} -
1* count the tokens *1
token number++;
1* -
** write_string("\n\rToken I II);
** lword(token number),
** write strinij("\n\rLlst index II);
** lword(list lndeX);
** write string("\n\rList pointer II);
** lword(list_item);
*1
).
I ~ co(peekb(bios cs(),list item+list index;
*1 - - -
return(O);
Section E: The C ProlUams
E1726 The Vue File
}
1*--------------------------------------------------*1
1* The sysbreak. routine is invoked by the CTRL-BREAK or CTRL-C keys and sets the break flag.
** This 1S checked by the CSTS routine to see if an operation should be aborted. It is linked
** upon entry to SysVue and de-linked upon exit.
*1
void interrupt cdecl far sysbreakCinterrupt registers)
( -
cstodsC); II do this because it is assumed that cs = ds
setds system segmentC)
1* alT varia5les will be referenced in sys seg *1
break flag = 1;
} -
1* This function evaluates the arguments on the command line and gets the values associated with
** the args and places their values into the token_value array.
** The values are arranged:
** seg:off - seg:off - seg:off - seg:off
** The corresponding present bit is set in the 'present' char to indicate if a an arg was
** present for that value. -
*1
get valuesO
( -
unsigned i; 1* i is a local variable used for the index *1
1* clear tne token value array *1
for (i=O; i< 8;token value[i++] = 0)( present = 0; i = 0;
1* write stringc"\n\rEntering get va ues II);
*1 - -
do
(
}
ifCget tokenC) == true) /* there is a token - *1
( -
token value[i+1] = get token valueC);
present 1= COx80 (i+1); -
if (Clast delim == ':') II (last delim == 'I'
1* the tOKen is a register token-*I
(
}
}
token value[i] = token value[i+1];
present 1= COx80 i)l
present &= -(Ox80 (1+1;;
token value[i+1] = 0;
ifCget token() == true) 1* there is a token - *1
( -
}
token value[i+1] = get token valueC);
present 1= COx80 (i+1; -
i += 2;
}
while (i < 8);
1*
**wri te stringC"\n\rExi ting get values");
*1 - -
1* Value present looks at the present bit for token_values 0-7 and returns a true if the bit is
** set, indicating a value was entered
*1
unsigned value-presentCindex)
(
}
if (present index) & Ox80) 1= 0) return(true);
return(false);
A-Type BiosKit
SECTIONF
Odds and Ends
This section includes tips on loading a Test Bios into Static Ram by using Debug
Batch files, and other assorted subjects.
Loading Test Ram Fll
ONE
Loading Bios Test Ram
The following example shows how a Static Ram Adapter card installed in a target
system can be loaded with the Bios image to test the Bios without programming
Eproms. This example assumes the target machine has 64 Kbytes of static Ram at
segment 0000. Note that the Adapter uses static rather than dynamic Ram and that
the Ram is located in the high memory map area, rather than in the System Ram
area (0 - 640 K). The low Ram area is cleared when a Bios starts, so the Bios image
must be outside the 0-640 K range. Dynamic Ram Refresh is re-initialized during
the Bios Power-up, so Static Ram is required for the Test-Bios to remain intact.
Create a file named loadat.inp file (as shown below) to provide input to the debug
program. It will be used to automate the copying of the Bios image from the DOS
transient area to the static Ram location. Note that the transfer is done in 4000 byte
portions, as the debug program treats the length argument (4000) as a signed
integer. A value of 8000 would be unreliable. Following the copying commands, a
Go command starts executing the Bios at its reset label. By inspecting the Bios.map
file, the offset for the label reset may be verified.
nbios.bin
I
m cs:OOOO I 4000 dOOO:OOOO
m cs:4000 I 4000 dOOO:4000
m cs:8000 I 4000 dOOO:8000
m cs:cOOO 14000 dOOO:cOOO
g = dOOO:e05b
To perform this loading procedure, enter debug < loadat.inp
N ext, to avoid typing the full command debug < loadat.inp every time you want to
load the Ram, create a file such as load.bat which contains the one line as shown
below:
debug < loadat.inp
Now all that is required to perform the complete copy, load, and go procedure is to
enter load and allow the batch file to invoke the process.
A sample schematic is included for a static ram adapter which you may wish to use
as a design guideline in case you decide to construct your own adapter. This
schematic shows the general philosophy you can use in your design. Fosco and
Annabooks have not constructed an adapter from this schematic, but have used the
same design approach in the past. The functions shown in the programmable logic
device (16L8) can be duplicated with discrete logic, but a PAL approach is the
F 12 Loading Test Ram
simplest. PAL's are a specific family of programmable devices by MMI, and PAL is
a registered trademark of MMI. An adapter of this type will also accommodate the
Dallas Semiconducterbattery backed ram modules, so a non-volatile ram board can
be configured.
A Type BiosKit
+ v
'({RITE PROTECT
SWITCH
EQUATIONS.
BWRI = WRI ... 511
1 OJ<
RES.
RAMO / = 1 C3 / ... A T 8/ * X ... 'of A f 5/ ... A f 4 /
RAM T I = A T C3 I * A f 8 I ... X * 'of .. A t 5 I ... At 4
R AM21 = At C31 ... At 81 ... X ... Y ... A t 5 ... At 41
R AM3 I = At 9 I ... A t a I ... X ... Y A 15 A 14
, c
R( I
'w'U
WRITE PROTECT
RAM SELECTS
f6L8

DENB/ = ROI ... RAMOI DATA ENABLE FOR DATA BUFFER
ROI ... RAMt I
+ ROI ... RAM21
+ ROI ... RAM31 DEN U
I RAM31
RAM21 20 I
NOTES.
QAMtL 20 I
I
FOR SEGMENT 0000:
X=A171
Y = At6
I_ ,..-....... __ '-I
06
FOR SGMENT 000 .
X=A17
Y = A16/
28-P IN SOCKETS 'vi ILL ACCEPT
62256 RAM's
DALLAS T 235 RAM's
o AT A LINES SHOULD 8E BUFFERED THROUGH
A 245 IN ORDER TO DRIVE THE BUS.
ADORESS LINE BUFFER INO IS OPT ION AL
DECODER IS MMI t 6L8 PAL.
TH IS SCHEM AT IC IS FOR EX AMPLE ONLY.
:. 245 05
04
-I 03
-I 02
0 t
.... 1-1 DO
OE/'
AOO
AO t
A02
..... AO!
A04
AOS
-!!o'Q A06
A07
A08
ACC3
FOSCO &. ANN A80CJ<SM AJ<E NO REPRESENT AT ION
AS TO THE CORRECTNESS OF THE EXAMPLE.
AtO
..... A IT
At 2
At 3
__ ....... 4 ----41 A 14
B\YRJ II 'WEI
I
20 I
I
-
BiosKit Static Ram Board
FOSCO
28035 MOUNT A IN ME ACC'H' RC .AD
ESCONO 100. CA. 92026
619+144-8086
The Indent Program F 21
TWO
The Indent Program
The Indent program is used to indent the lines of a source file according to the
nesting of the left and right bracket characters ({ and }) to ease the readability of
the code. Some editors have built-in features to do this automatically for you, so this
Indent program may not be needed. Hyou are using an ordinary editor, you will find
this program useful.
/**************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: Indent
*
* Version: 1.01
*
* Author:FOSCO
*
* Date: 10-10-89
*
* Filename: Indent.c
*
* Functional Description:
* This program is a utility which is used to indent C source code lines according to the nesting
* level of the left and right bracket characters ( { } ). It improves readability of the souce
* file, but does not affect the logic flow. It is useful when a general purpose editor is being
: used to prepare source files.
*
* Flle name
* Return:
*
* Version History:
* 1.01
* Updated under QuickC 2 for convenience.
* General clean-up and simplification.
***************************************************************************************************/
/* INC L U D E F I L E S */
#include <stdio.h>
/* G LOB A L V A R I A B L E S */
FILE *instream;
FILE *outstream;
int length,i,numread,numwritten, tab = 0;
#deflne blen 512
char instring[blen],outstring[blen],buffer[16384l;
#deflne true -1
#define false 0
unsigned write_ok = true;
/* L 0 CAL D E FIN I T ION S */
#define tabchar 9
#define rt brace 125
#def i ne l fcrace 123
#define inCIent_level 1 /* # of colums to indent */
/* PRO G RAM */
/* indent c programs according to {} characters */
main(int argc, char *argv[])
(
printf("FOSCO/Annabooks Indent Source Util ity V1.01\n\r");
if (argc <2) ( printf("Not enough argunents on COlllll8nd line\n"); exit(O); }
if instream = fopen(argv[ll,lr" == NULL)
printf("Could not open file for reading\n");
else
(
length = filelength(fileno(instream;
}
F 2 2 The Indent Program
if (length == -1) printf(1I8ad Length on input file\n");
else
{
if outstream = fopen("Sid.SSS" "W" == NULL)
printf("Could not open file for writing\n");
else
(
}
tab=O
while'Cfgets(instring,blen,instream) f= 0)
{
}
II skip over leading spaces
i =0 wh it e (i ns t ring [ i ++] == , ') i - -
II check for right brace here so We de!indent the current line
if instrinv[i] == rt brace) && (tab >= indent level
tab -= lndent_levil; -
/I pad front of output string with required # of spaces
strnset(outstring,' ',tab);outstring[tab] = 0;
II now copy instring[i] to outstring[tab]
strcat(&oUtstring[tab],&instring[i]);
II write to the temp file and mark any errors
if(fputs(outstring,outstream) 1= 0) write ok = false;,
/I check for left craces here so we indent the follOWIng line
if (instring[i] == lf brace)
( -
}
tab += indent level;
II check for closing brace on same line
fore; i<strlen(instring)ii++) .
{
if instring[i] == rt brace) && (tab >= indent_level
( -
tab -= indent level:
break; -
)
}
}
fclose(instream)
fclose(outstream):
if(lwrite ok)
( -
}
printf(lI\n\rError in writing fi le, processing aborted. II);
printfC"Original file Xs remains unchanged.\n\r
U
,argv[1]);
else
{
II now copy the Sid.SSS to the original file
if Cinstream = fopenC"Sid.SSS",lIr+b
ll
1= NULL) &&
outstream=fopenCargv[ll ,1Iw+b
ll
f= NULL
{
do
(
}
numread = freadCCchar *)buffer sizeofCchar) 16384,instream):
numwritten = fwritechar *)buJfer,
if (numwritten 1= numread)
(
printf("Transfer error on fi le Xs. Use SID.SSS as recovery fi le./n",argv[1]);
write ok = false;
} -
whi le (nunread > 0);
fclose(instream);
fclose(outstream)i
if(write ok)
iTnunread = remove (IISid.SSS" f= 0)
}
}
}
printf("\n\rError deleting temp file SID.SSS\n\r"):
A Type BiosKit
The Uilite Program F 31
THREE
The Hilite Program
The Hilite program is used to display program comments in intensified video on the
display. It scans the source file and looks for pairs of comment delimiters ( /* and
* / ), and intensifies the video between these marks. It is useful for detecting
incorrect comment delimiter pairs, which may comment out wanted source code
statements. When strange errors show up in the compilation of a 'slightly' edited
program, comment delimiter errors may cause drastic errors. If a program compiles
properly but operation changes radically, a comment check with Hilite may
help in determirung the cause(s).
/**************************************************************************************************
*
: Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
* Module Name: Hilite
*
* Version: 1.00
*
* Author: FOSCO
*
* Date: 1-1-89
*
* Filename: hilite.c
*
* Functional Description:
* This program is used to hilite the comments in a C source program as it is displayed on
* the screen.
*
* Arglnents:
* Fi le name
* Return:
*
* Version History:
*
***************************************************************************************************/
/* INC L U D E F I L E S */
/* FUN C T ION PRO TOT Y PES */
/* G LOB A L V A R I A B L E S */
/* G LOB A L CON S TAN T S */
/* L 0 CAL D E FIN I T ION S */
/* L 0 CAL CON S TAN T S */
/* PRO G RAM */
/* highlight c programs according to / * * / characters */
#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#define cr 13
#define lf 10
#def i ne space 32
#define on 1
#def i ne off 0
#define star ,*,
#define slash 47
#def i ne bspace 8;
FILE *instream;
unsigned int length;
unsigned int i;
unsigned char char;
unsigned char buffer[16304]; -
union REGS regs;
main(argc,argv)
int argc;
F32 The HiIite Program
char *argv [] ;
{
)
if (argc <2)
(
)
printf("Not enough parameters on conmand l ine\n");
exi t(O):
if instream = fopen(argv[1] ,lIr+b" == NULL) printf("Could not open file for reading\n
ll
);
else
(
length = filelength(fileno(instream;
for (i=O; i<length && ch = getc(instream 1= EOF); i++)
{
if last_char == slash) && (ch == star
(
comment = on; /* backspace and turn on last slash */
regs.h.ah = OxOe:
regs.h.al = bspace:
regs.h.bh = 0:
int86(Ox10,&regs,&regs);
regs.h.bl = OxOfi
regs.h.ah = Ox09i /* write attribute at cursor */
regs.h.al = Ox20: /* display without highlight */
regs.h.bh = OxOO
regs.x.cx = Ox0061:
int86(Ox10,&regs,&regs):
regs.h.ah = OxOe
regs.h.al = slash:
regs.h.bh = 0:
int86(Ox10,&regs,&regs):
regs.h.bl = OxOf:
} .
if (comment == on)
{
regs.h.bl = OxOf;
}
else
{
regs.h.bl = Ox07:
}
regs.h.ah = Ox09: /* write attribute at cursor */
regs.h.al = Ox20: /* display without highlight */
regs.h.bh = OxOO'
regs.x.cx = Ox0061:
if (isprint(ch int86(Ox10,&regs,&regs):
regs.h.ah = OxOe: /* write tty */
regs.h.al = ch'
regs.h.bh = Ox6o:
int86(Ox10,&regs,&regs):
if last char == star) && (ch == slash comment = off:
last char-= chi
} -
fclose(instream)i
}
A Type BiosKit
The Parens Program F 41
FOUR
The Parens Program
The Parens program is used to display parenthesized text in intensified video on the
display. It scans the source file and looks for parentheses characters and intensifies
the video between these marks. It is useful for detecting incorrect parenthesizing.
/***************************************************************************************************
*
* Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
*
* Module Name: Parens
*
* Version: 1.00
*
* Author: FOSCO
*
* Oate: 1-5-89
*
: Fi lename: parens.c
* Functional Description:
: This progam is used to display parenthesized text on the screen in itensified video.
*
* Flle name
*
* Return:
*
: Version History:
***************************************************************************************************/
/* INC L U D E F I L E S */
/* FUN C T ION PRO TOT Y PES */
/* G LOB A L V A R I A B L E S */
/* G LOB A L CON S TAN T S */
/* LaC A L D E FIN I T ION S */
/* LaC A L CON S TAN T S */
/* PRO G RAM */
/* highlight c programs according to () characters */
#include <stdio.h>
#include <dos.h>
#include <ctype.h>
#define cr 13
#define l f 10
#def i ne space 32
#define on 1
#define off 0
#def i ne l paren 40
#def i ne rparen 41
FILE *instream;
unsigned int length;
uns i gned i nt i;
unsigned char ch,depth:
unsigned char buffer[163841;
union REGS regs;
main(argc,argv)
int argc;
char *argv [] ;
{
if (argc <2)
(
printf("Not enough parameters on conmand l ine\n");
exit(O);
)
if instream = fopen(argv[ll ,"r+b" == NULL) printf("Could not open file for reading\n");
else .
}
(
F 4 2 The Parens Program
length = filelength(fileno(instream;
depth = 0;
for (i=O; i<length && ch = getc(instream 1= EOF); i++)
{ .
if (ch == lparen) depth++;
if (depth 1= 0)
{
regs.h.bl = OxOf;
}
else
{
regs.h.bl = Ox07;
}
regs.h.ah = Ox09; /* write attribute at cursor */
regs.h.al = Ox20; /* display without highlight */
regs.h.bh = OxOO .
regs.x.ex = Ox0061;
if (isprint(eh int86(Ox10,&regs,&regs);
regs.h.ah = OxOe: /* write tty */
regs.h.al = eh
6

regs.h.bh = Ox 0;
int86(Ox10,&regs,&regs);
if (eh == rparen) depth--;
}
fclose(instream);
}
A-Type BiosKit
The Bin2Hex Filter F51
FIVE
The Bin2Hex Filter
The Bin2Hex filter is used to convert a binary image file into Intel Hexadecimal
Format. This is a common format used by many prom programmers such as Data
I/O, etc. Since this is a filter, the output may be directed to a file, an output port, or
the screen .
. *************************************************************************************************** ,
Copyright (c) FOSCO 1988, 1989 - All Rights Reserved
Module Name: Binary to Intel hexadecimal filter
Version: 1.00
Author: FOSCO
Date: 1-5-89
Filename: bin2hex.asm
Functional Description:
This program converts the contents of a file to Intel hexadecimal format. Since many Prom
Progranmers wi II accept an Intel Hex download format( .BIN fi les may be converted.
Fil ter outputs can be di rected as shown in the ex..., es below.
Argunents:
bin2hex <infile.bin >outfile.hex
bin2hex <infile.bin >COM1
bin2hex <infile.bin >CON
Return:
Version History:
1-5-89 - font revision
!*************************************************************************************************** ,
PRO G RAM
.model CQq)8ct
stack
stack
segment word stack 'stack'
ends
stdin
stdout
equ
equ
.data
ibuff db
obuff db
line count dw
char-count db
checKsun db
ochar db
eof db
code
assl.llle
bin2hex proc
mov
mov
mov
$$001 :
mov
mov
mov
mov
int
JC $$EN1
o
1
16 dup(O)
32 dup(O)
o
o
o
o
13,10,':00000001FF'
ax,_data
ds,ax
l ine_count,O
bx,stdin
cx,16
dx,offset ibuff
ah,3fh
21n
get stdin
F 52 The Bin2hex Filter
or ax,ax
JZ SSEN1
mov char count,al
call write line
JMP SHORT SS001 .-
$$EN1 :
call
mov
int
bin2hex endp
wri te_l ine proc
mov
mov
xor
mov
call
mov
call
mov
call
mov
sub
call
mov
mov
sub
call
mov
sub
call
mov
sub
call
add
mov
$$005:
lodsb
write eof
ax, 4cOOh
21"
checksl.ln,O
cl,char count
ch,ch -
al,13
~ t c
al,10
~ t c
al,":"
~ t c
al,char cOUtt
checksl.iii,al
convert
ax, line cOUtt
al,ah -
checksl.lll,al
convert
ax, line cOUtt
checksl.iii,al
convert
al,OO
checksl.lll,al
convert
line COU'1t ( 16
Si,offset 1buff
sub checksum,al
call convert
LOOP $$OOS
mov al , checksl.lll
call convert
ret
wri te_line endp
convert proc
push ax
push ax
shr al, 1
shr al,1
shr al,1
shr al,1
and al,Ofh
add al '0'
clJ1) al: '9'
JNA SSlF7
SSIF7:
add al,7
call putc
pop ax
ana al,Ofh
add al,'O'
clJ1) al,'9'
JNA SSIf9
S$IF9:
add al,7
call putc
pop ax
ret
convert endp
putc proc
push ax
push bx
push cx
push dx
mov ochar,al
mov bx,stdout
mov cx,1
mov dx,offset ochar
mov
a h ~ 4 0 h
int 21
pop dx
pop cx
pop bx
A-JYpe BiosKit
done
write eof
return to dos
; carriage return
l fne feed
The Bin2Hex Filter F 53
pop ax
ret
pute endp
write eof proc
- push ax
push bx
push ex
push dx
moy bx,stdout
moy ex,13
moy dx,offset eof
moy
ah(,40h
int 21
pop dx
pop ex
pop bx
pop ax
ret
wri te_eof endp
end bin2hex
Section F: Odds and Ends
The Split bin Program F 61
SIX
The Splitbin Program
The Splitbin Program is used to Split the at.bin file into an at.evn and at.odd file for
programming the two Proms normally needed for an AT Bios.
Some of the newer Chipsets used in AT clones may allow you to use a 64k x 8 prom
for the complete Bios. These Chipsets are based on the idea that the Bios would be
moved to Shadow Ram which usually operates with fewer wait states than Prom,
allowing higher performance operation. This may provide you with a design
advantage if you are designing your own CPU board. Check with the VISI chipset
vendor for more information on this possible feature, and what additional software
that might be required. IT your AT motherboard has this feature, then the Splitbin
won't be needed.
The Splitbin command line argument is the filename without the extension ("at" not
"at.bin"). Splitbin adds the ".bin" to the input filename argument and the ".evn" and
".odd" extensions to the output files.
/********.****.***.***** * *.* * * *

: Copyright (c) FOSCO 1989 - All Rights Reserved
: Module Name: Bin file splitter to even/odd
Version: 1.00
*
* Author: FOSCO

Date: 10-1-89
*
: Filename: Splitbin.c
* Language: MS C 5.1
*
* Functional Description:
* This program reads the .bin file specified by the argument,
: and splits it into an .evn and a .odd file.
*
* Version History:
*
** ** * * /
/. INC L U D E F I L E S ./
#include <stdio.h>
/. G LOB A L V A R I A B L E S ./
#define blen 8192
FILE instreamc*evenstream Oddstreami
unsigned char lnbuffer[2bten], evenbuffer[blen]J oddbuffer[blen]i
unsigned char inname[16], oddn8me[16],evenname[1o]i
unsigned numread,i,ji
/* PRO G RAM ./
unsigned main(int argc, char argv[])
(
printf("\n\rFOSCO/Amabooks Spl it xx.bin to xx.evn and xx.odd files Uti lity\n\r")i
i f(argc == 2)
(
strcpy(inname,argv[ll)i strcat(inname,".bin")i
strcpy(evemame,argv[1])i strcat(evemame,".evn")i
strcpy(oddname,argv[1])i strcat(oddname,".odd")i
i f instream = fopen( imame, "rb" I = NULL)
}
F62 The Split bin Program
i f evenst ream = fopenCevenname, "wb" I = NULL)
i f C ( odds t ream = fopenC oddname, "wb" ! = NULL)
{
whi leC
(
(numread = freadCCchar *)inbuffer,sizeof(char),2*blen,instream
!= NULL)
for(i=O,j=Oi j < numread; i++,j+=2)
(
evenbuffer[il = inbuffer[j1i
oddbuffer[il = inbuffer[j+lli
)
fwritechar *)evenbuffer,sizeofCchar),numread/2,evenstream)i
, fwriteC(char *)oddbuffer,sizeofCchar),numread/2,Oddstream)i
}
)
}
else
{
printfC"No .bin fi Le specified in conmand l ine\n\r")i
}
returnCO)i
A-Type BiosKit
The Mergebin Program F 71
SEVEN
The Mergebin Program
The Mergebin Program is the companion to the Splitbin Program and may be ;used
to combine ".evn" and ".odd" files to a ".bin" file. The command line argument,is the
filename (without extension). Mergebin looks for the ".evn" and ".odd" files" ,and
creates a ".bin" file. Mergebin is handy if you want to read Bios proms alld
create a complete image, as well as providing a means to venfy the evenl99d
conversion process (Splitbin) by merging a split and comparing results. , ';;, .. ' -.
. -:
1**********************************************************************
*
* Copyright (c) FOSCO 1989 - All Rights Reserved
*
* Module Name: Merge evn/odd files to a bin file
*
* Version: 1.00
*
* Author: FOSCO
*
* Date: 10-1-89
*
* Filename: Mergebin.c
*
* Language: MS C 5.1
*
* Functional Description:
: This program merges the .evn and .odd file into a combined .bin file.
* Version History:
*
**********************************************************************/
/* INC L U D E F I L E S */
#include <stdio.h>
1* G LOB A L V A R I A B L E S *1
#define blen 8192
FILE *outstream,*evenstream *Oddstreami
unsigned char outbuffer[2*btenl, evenbuffer[blenl, oddbuffer[blenli
unsigned char outname[16], oddname[161,evenname[161i
unsigned numread,i,ji
1* PRO G RAM */
unsigned main(int argc, char *argv[])
(
printf("\n\rFOSCO/Annabooks Merge xx.evn and xx.odd to xx.bin fi les Uti l ity\n\rll)i
if(argc == 2)
(
}
st rcpy(outname, argv [1] ) ( strcat(outname, II. bi nil) i
st rcpy(evemame, argv [1] J i strcat( evemame, ". evn") i
strcpy(oddname,argv[1])i strcat(oddname,".odd")i
ifoutstream = 1= NULL)
ifevenstream = fopen(evemame,"rb" 1= NULL)
ifOddstream = fopen(oddname,llrb" 1= NULL)
(
}
whi lee
numread = freadchar *)evenbuffer,sizeof(char),blen,evenstream 1= NULL) &&
numread = freadchar *)oddbuffer,sizeof(char),Dlen,Oddstream 1= NULL)
)
(
for(i=O,j=Oi i < numreadi i++,j+=2)
(
outbuffer[il = evenbuffer[i]i
outbuffer[J+1] = oddbuffer[i]i
)
fwritechar
}
. . .
}
F'2 The Mergebin Program
else
{
printf("No .bin file specified in conmand line\n\r")i
}
return(O)i
A-Type BiosKit
The Patch.asm File F 81
EIGHT
The Patch.asm File
If you have a problem with the initial installation of the generic version of the AT
BiosKit, this chapter may be of interest to you. Normally the generic Bios image
"at.bin" that is supplied on the distribution diskette will run on almost all AT system
boards, so that is where most readers start. If you are planning to make
modifications of the BiosKit, read this chapter anyway, as it will give you some ideas
on how to speed up checkout (also refer to the Chapter on "Loading Static Ram") by
eliminating the Prom Erase/Program cycle for your Bios Under Test. The contents
of the patch.asm program are a normal feature of the BiosKit, so the material in this
Chapter may help you to appreciate the BiosKit methodology.
This patch procedure may be useful to you if you are modifying the standard AT
Bioskit to you particular hardware configuration and you have access to a previously
configured Bios from another source. Its purpose is to provide a method to sense the
existence of a "test" copy of Bios in Ram, and transfer control to the "test" copy. This
patch will permit control to the transferred before any significant checks or
initialization is done by the other Bios.
This patch program was created during the early days of testing the AT Bios in static
ram. We were using a system with "another" Bios chip, and loading and running the
development Bios in Ram as described in Chapter F-l. The typical AT Bios has the
restart routines locked into the se$ment at FOOO, because they do not check for rom-
scan or secondary Bios until well Into the Bios. In order to wrest control away from
the primary Bios residing at segment FOOO immediately upon a hardware reset
signal, it was necessary to intercept the control flow at the very beginning of the
code. To provide for this, the patch sequence in this file was created. It is intended
to be loaded into a modified "other" Bios.
The typical Bios will have a reset control flow similar to the example shown below:
FOOO:FFFO Jmp Far FOOO:E05B
FOOO:E05B Jmp Near - reset_code
FOOO:reset_code Cll
mov
Out
xxx
xxx
al,8F
70,al
; disable interrupts
; disable NMI's
; write to CMOS
; and so on
The patch is intended to be patched in between the jump at FOOO:E05B and the
reset_code, so it looks like the example shown below:
FOOO:FFFO Jmp Far FOOO:E05B
FOOO:E05B Jmp Near - patch
FOOO:patch ; patch program in this file
; checks for test Bios and
" ~ ~ . . . f
F 82 The Patch.asm File
; transfers control if valid
Jmp reset_code
.. code CU
mov
Out
xxx
xxx
al,8F
70,al
; disable interrupts
; disable NMI's
; write to CMOS
; and so on
To install the patch, make a binary image copy of the "other" Bios using Debug. This
can ;be done by the :following
sequence:
Debug <enter>
nother.bin <enter>
rcs <enter>
xxxx
rcs xxyx < enter>
(call up debug)
(name the file to be created)
(examine the CS register)
(displays current value)
(xxyx = xxxx + 10)
m fOOO:OOOO I 4000 cs:OOOO < enter>
m fOOO:4000 I 4000 cs:4000 < enter>
m fOOO:8000 I 4000 cs:8000 < enter>
m fOOO:.cOOO I 4000 cs:cOOO < enter>
rbx 1 < enter>
rex 0 < enter>
w cs:O < enter>
q <enter>
(this copies the bios to ram)
(this sets the length of the file)
(this writes the file on disk)
(this exits debug)
Now that you have an image of the "other" bios on disk, you may reload it (using
Debug), and find an unused area large enough to accommodate the patch program.
When a space has been found, the patch program may be inserted by using the
"asm" command and the code. Replace the old jump at EOSB with a jump to
the patch, and use that origtnal destination for the jump out of the patch.
After carefully checking that the patch is entered and linked correctly, use the "w"
command to rewrite the file to disk.
The modified file will need its checksum corrected. The Biossum program may be
used to calculate a new checksum. First though, you need to check the size of the
bios. Remember, we wrote a full 64k file for the binary file. Reload it using debug
and determine where code starts. If it is a typical assembly language version Bios,
the code will start at location 8000. Fill the area from 0000 to 7FFF' with "FF" using
the debug "fill" command. The Biossum program will skip over "fr bytes, until it
finds a non-"fr byte and assume that checksumming should then begin. After you
have performed this fill (if required), then calculate a new checksum with the
following command:
Biossum other. bin < enter>
Finally, if two proms are required (even and odd bytes), run "Evenodd other" to
produce the two binary images required. Program a set of modified proms (we
A Type BiosKit
: ..,;.;.,,.;.,<>, .. ,"
The Patch.asm File F 83
strongly recommend you retain the original unaltered proms) and install and test
them in you machine.
This modified bios will then adhere to the standard Annabooks conventions for
secondary and test Bios', and you may proceed with developing arid testiof' yoUr
personalized version of the AT BiosKit. ,
The patch file below is intended to provide you with' a guide to creating the patching
code you will' need, not necessarily an executable .EXE file. By assembling file with
a "MASM patch,,; <enter> " command, the listing file generated will illustrate the _,
object required. The actual is most easily by
command In the DOS Debug as descnbed above. Therefore this module 'IS
for reference only. ' : ,.',
.******************************************************** ,
Copyright (c) FOSCO 1988 - All Rights Reserved
,
Module Name: Patch for "other" bios' for system checkout
; Version: 1.00
i
; Author: FOSCO
i
; Date: 12-01-88
, Fi lename: patch.asm
Language MS MASM S. 1
Functional Description:
Th i s patch is intended to be patched into a non
AnnabOoks Bios to allow the secondary bios feature to
be used. The Annabooks Bios U'lder deve l may then
be loaded into and executed from High-Ram in the 0000
segment. The order of priority for selection
is:
1. 0000 segment - test (usually Ram, may be Prom)
2. FOOO segment - primary (Prom)
; . .
; Verslon Hlstory:
,
.model
code
small
i----------- check for bios' patched in ----------
If we find a Bios patch (by checking its signature),
then we go to it.
patch a at FOOO:EOSB to to "patch"
patch:
aX,OdOOOh i check seg dOOO
ds ax
si;si ; check for bios signature
word ptr ds:[si],OSb1h
mov
mov
xor
cJl1)
jne check2 ; jumps if bad signature
_ithen check for length count
byte ptr ds: [si+2]
check1:
Cq)
jne
xor
xor
add
inc
loop
or
jne
db
dw
dw
check2 ; iJ bad length count
cx, cx ; set 64k count
al,al ; clear checksum register
al ,ds: [si] ; bui ld checksum for 641C bytes
si
check1
al,al
check2
Oeah
OfffOh
OdOOOh
i zero = good
i jumps i f bad checksum
; to bios at dOOO
, ... '.,;;., ....
" .. .. ..
'.
4 ":' .
", " . :'-
. }:c,.
. " i 0 1,::;-!
.;" 'l
;, ..
i"'k ",,' f' .. i. L ' ; :
:.; .'
.]) "..'
"'}:)!Ib01Cc
,', ,','I; ;.' ;,.; Pf. A
Section F: Odds ;'alid'EndS
F 84 The. Patch.asm File
check2:
1234h jump to EOSB's original destination
; you RUSt determine this location I
end
p 'A-llJe BiosKit

Vous aimerez peut-être aussi