WO1992002873A1 - Data emulation and encoding apparatus - Google Patents

Data emulation and encoding apparatus Download PDF

Info

Publication number
WO1992002873A1
WO1992002873A1 PCT/US1991/005527 US9105527W WO9202873A1 WO 1992002873 A1 WO1992002873 A1 WO 1992002873A1 US 9105527 W US9105527 W US 9105527W WO 9202873 A1 WO9202873 A1 WO 9202873A1
Authority
WO
WIPO (PCT)
Prior art keywords
mov
data
scsicontrol
segment
diagled
Prior art date
Application number
PCT/US1991/005527
Other languages
French (fr)
Inventor
William E. Thacker
Original Assignee
Pbt Technologies
Priority date (The priority date is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the date listed.)
Filing date
Publication date
Application filed by Pbt Technologies filed Critical Pbt Technologies
Publication of WO1992002873A1 publication Critical patent/WO1992002873A1/en

Links

Classifications

    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F3/0601Interfaces specially adapted for storage systems
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F2003/0697Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers device management, e.g. handlers, drivers, I/O schedulers
    • GPHYSICS
    • G06COMPUTING; CALCULATING OR COUNTING
    • G06FELECTRIC DIGITAL DATA PROCESSING
    • G06F3/00Input arrangements for transferring data to be processed into a form capable of being handled by the computer; Output arrangements for transferring data from processing unit to output unit, e.g. interface arrangements
    • G06F3/06Digital input from, or digital output to, record carriers, e.g. RAID, emulated record carriers or networked record carriers
    • G06F3/0601Interfaces specially adapted for storage systems
    • G06F3/0628Interfaces specially adapted for storage systems making use of a particular technique
    • G06F3/0662Virtualisation aspects
    • G06F3/0664Virtualisation aspects at device level, e.g. emulation of a storage device or system

Definitions

  • the invention concerns data archiving systems, and more particularly, systems which emulate one form of archiving medium with another.
  • Archival storage media have undergone significant increases in density as various technologies have developed over the years. This not only permits storage of much more data in a smaller physical space at a lower cost, but also minimizes the number of times that media must be mounted or dismounted during the storage or retrieval of data.
  • 9-track magnetic tapes typically store on the order of 30 megabytes of data on each reel, whereas an optical disk can store as much as 5 gigabytes of data per disk or more.
  • an optical disk can store as much as 5 gigabytes of data per disk or more.
  • a controller is provider for interfacing a high density medium to a host computer system adapted originally for a lower density medium.
  • the controller includes an emulator, the input of which connects directly to the existing computer system archive port, an interface for coupling data to a higher density medium, and formatting apparatus for reformatting and/or remapping the data as it is transmitted in one direction or the other.
  • Means are provided for uniquely identifying each block of data on the higher density medium, corresponding to individual units of the lower density medium.
  • the identifier is in a natural form, including, for example, the date on which the data is written to the archive.
  • the user can then simply enter the date on which the data was archived, as well as any other identifying information necessary to select a unique block of archive data.
  • the addressing of the data within the selected block by the host therefore corresponds to the addressing of a unit of the lower density medium on which the user would previously have hand-written the same identification markings.
  • Fig. 1 is a block diagram of a controller according to the invention.
  • Fig. 2 is a flow chart describing the firmware operation of the controller of Fig. 1.
  • the lower density medium which is emulated is 9-track magnetic tape and the higher density medium which is actually used is writable optical disk. No change in the computersystem's software is necessary. Since 9-track tape media can be approximately 5 times more expensive than optical media per byte of archive data, this controller significantly reduces operation costs.
  • the controller interfaces with the computer system via two 50-pin connectors identical to the connectors on 9-track tape drives.
  • the host system sees the same signals as the 9-track drive, thus emulating its operation.
  • ports are provided both for connection to the computer system and for connection to an existing 9-track drive.
  • the user can enable either the optical disk medium or the 9-track drive, so that data previously archived on 9-track tape can still be restored without the expense of a conversion to the optical format.
  • Every record written on an optical disk includes a date stamp, so for fast data retrieval, MONTH, DAY, YEAR and LOCK buttons are located on the controller front panel with an LED readout of the current date selected.
  • the controller By depressing the LOCK button, the controller automatically positions itself at the first occurrence of a matching date stamp on the optical disk.
  • the associated "pseudo" tape is then considered mounted, as far as the host is concerned, and available for fast data retrieval.
  • the controller always keep track of the current date, so operator action is usually not required for LOCK operation.
  • Data on the archive device which can be optical or magnetic disks as well as alternative tape storage devices such, as digital audio tape (DAT) systems, is divided into “blocks" of 64k bytes in length. These blocks can be grouped into “segments,” which define multiple blocks. Segments are re-mapped via a lookup table when the archive device has "write once" capability and the input data is to be rewritten.
  • the archive reserves the first 0.2% of the medium for segment remap tables.
  • a segment remap table is 64k bytes in length where the segment remapped address consists of a 4-byte integer. These tables are written in sequence whenever a new entry is assigned to the remap table; therefore, the last remap table written is the "valid" remap table for the medium.
  • a segment can be defined as one block or multiple blocks, depending on the size of the archive medium. The segment size is written within each block.
  • Bytes 8 thru 1023 contain the "file mark" table. This is a sequential list of file marks detected from the input data stream. Each file mark is a 4 byte long integer value.
  • Bytes 1024 thru 2047 contain the "record" table. This is a sequential list of record marks detected from the input data stream. Each record mark is a 4 byte long integer value.
  • the optical disk drive useable with the controller can be, for example, the Toshiba VM-S500 12-inch optical disk drive, with a storage capacity of 5 gigabytes. This is equivalent to 167 typical 9-track tapes.
  • the controller emulates the tape drive and stores the archive data on the optical disk.
  • An LED readout is provided, enabling the operator to date stamp the archived data to insure fast, accurate retrieval. Additionally, the percent disk remaining and the tape number is also displayed on the front panel.
  • lockstatus Indicates lock mode (lock current date)
  • displaymode - Is either percentage (0) mode or tape
  • databuffer0 databufferl are twin 4 Kbyte
  • CommandBuffer is utilized to pass SCSI command data
  • drivecommandbytes is the number of command bytes to transfer
  • stat i c int SCSIcontrol 0 ⁇ 180;
  • This code includes
  • setLEDstatus() /* Pass, set LED display * / readdate (0 ⁇ a);
  • f0 diskcurrentblock * 4096. ;
  • diskblock i4 + 0 ⁇ 100001*i5;
  • i5 SCSIdatabuffer[5] + 256*SCSIdatabuffer[4]:
  • writeiow (keyswitch 0 ⁇ 7) /* Take tape drive OFFLINE * / readiow (tapecontrol &i2) /* Get current tape control */
  • LEDbuffer[c0] LEDoff; /* Load with blanks */
  • LEDbuf fer [1] two.
  • LEDbuffer[1] f ive
  • LEDbuffer[1] six;
  • LEDbuf fer[1] eight;
  • LEDbuf f er [4] zero; /* set 1st year digit */
  • LEDbuf f er [5] zero, /* set 2nd year digit */
  • LEDbuf fer [5] eight;
  • LEDbuffer[7] three;
  • LEDbuf fer [7] six:
  • LEDbuf fer[7] eight;
  • LEDflash() Function that turns LEO display on/off every 2 seconds. Invoked if unlocked
  • LEDbuffer[c3] LEDoff; /* Set LED displays to OFF */ c3++;
  • altdate[1] (altdate[1] & 0 ⁇ f0) + 0 ⁇ 9;
  • altdate[1] altdate[1] - 0 ⁇ 10;
  • altdate[2] (altdate[2] & 0 ⁇ f0) + c2, if ((altdate[2] & 0 ⁇ f) > 9)
  • LEDbuffer maps as f ol lows
  • diagLED diagLED & 0 ⁇ bfff /* Set shift clock high */ writeiow (LEDcontrol, diagLED),
  • diagLED diagLED ⁇ 0 ⁇ c000 /* Set shift clock low */ writeiow (LEDcontro diagLED)
  • diagLED diagLED & 0 ⁇ bfff, /* Set shift clock high */ writeiow (LEDcontrol, diagLED)
  • diagLED diagLED ! 0 ⁇ c000 /* Set shift clock IO ⁇ . *, writeiow (LEDcontrol, diagLED,
  • diagLED diagLED & 0 ⁇ bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
  • diagLED diagLED ! 0 ⁇ c000, /* Set shift clock low * / writeiow (LEDcontrol, diagLED);
  • diagLED (diagLED & 0 ⁇ 1f00) + 0 ⁇ 60ff /* Set for 1st load */
  • diagLED diagLED & 0 ⁇ bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
  • diagLED diagLED
  • diagLED diagLED ! 0 ⁇ 8000; /* Set for shift */
  • diagLED diagLED & 0 ⁇ bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
  • diagLED diagLED
  • diagLED (diagLED & 0 ⁇ lf0O) + 0 ⁇ 60ff; /* Set for 1st load * /
  • diagLED diagLED i 0 ⁇ 8000; /* Set for shift */
  • diagLED diagLED & 0 ⁇ bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
  • diagLED diagLED ⁇ 0 ⁇ c000; /* Set shift clock low */ writeiow (LEDcontrol. diagLED);
  • diagLED diagLED & 0 ⁇ bfff; /* Set shift c1ock high * / writeiow (LEDcontrol, diagLED):
  • diagLED diagLED & 0 ⁇ fdff, /* Turn on LED */
  • diagLED diagLED ⁇ 0 ⁇ 100
  • Th i s function reads a value from the Date/Time
  • This function writes a value to the Date/Time
  • regnumber regnumber * 2, /* Scale Register number */ writeiob ((datecontrol + regnumber) c0), /* Read register */
  • This function sets the DATE and TIME in tne
  • lockstatus 1; /* Set for keyflow */
  • tapestatus tapestatus & 0 ⁇ ffdc
  • tapeblkprevptr tapeblklastptr
  • tapefmprevptr tapefmlastptr
  • tapeblklastptr tapeblkpointer
  • tapefmlastptr tapefmpoint er
  • tapebufferblkptr 0 ⁇ 200;
  • tapebuf ferfmptr 0 ⁇ 8;
  • tapebufferblkptr 0 ⁇ 200 + 8*f0;
  • tapebuf ferfmptr 0 ⁇ 8 + 8*f0;
  • f0 tapefmpo inter - tapefmlastptr
  • tapebufferfmptr 0 ⁇ 8 + 8*f0;
  • rdbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), tapebuf ferfmptr+2,&i2); rdbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), tapebufferfmptr+4,&i3);
  • i1 i1 & 0 ⁇ ff;
  • i2 i2 & 0 ⁇ ff;
  • i3 i3 & 0 ⁇ ff;
  • i4 i4 & 0 ⁇ ff;
  • tapebufferblkptr 0 ⁇ 200 + 8*f0
  • i3 i3 & 0 ⁇ ff;
  • tapebufferfmptr 0 ⁇ 8 + 8*f0
  • f1 f0 / 256 ;
  • f2 f1 / 256 ;
  • wrtbuff (((tapebufferflag*0 ⁇ 1000) +0 ⁇ 1000),tapebufferfmptr i1); wrtbuff (((tapebufferflag*0 ⁇ 1000) +0 ⁇ 1000),tapebufferfmptr+2, ⁇ 2); wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000),tapebuffertmptr+4 ⁇ 3); wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000;,tapebuf fer fmpt r+6 ⁇ 4); ⁇
  • f2 fl / 256 , .
  • wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000; tapebufferblkptr i1); wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000) tapebuf ferblkpt r+2, ⁇ 2); wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), tapebuf ferblkptr+4 ⁇ 3); wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000). tapebuf ferblkpt r+6, ⁇ 4); tapestart()
  • tapebufferstatus ;
  • wrtbuff (((tapebuf ferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ 8, 0); /* 0 fm array */ wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ a, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ c, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ e, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ 200, 0); /* 0 gap array */ wrtbuff (((tapebufferflag*0 ⁇ 1000) + 0 ⁇ 1000), 0 ⁇ 202
  • tapestatus tapestatus ⁇ 0 ⁇ 481;
  • tapestatus tapestatus , 0 ⁇ 20;
  • tapebufferstop (10 . tapepointer) + tapebufferpointer;
  • readfilefw (tapebufferf lag, &tapebufferpointer, tapebufferstop);
  • tapebufferstop 0 ⁇ fffe
  • t apestatus tapestatus ⁇ 0 ⁇ 20;
  • t apebuf ferstop tapebuf ferpointer - (tapepointer - 10;
  • tapebuf ferstop 0 ⁇ 400;
  • tapepointer tapepointer - tapebuf ferpointer + 0 ⁇ 400
  • tapebufferstop tapebuf ferpointer
  • tapepo i nt e r tapepointer + (tapebutferpointer - tapebufferstop) tapeblkpointer++;
  • tapestatus tapestatus ! 0 ⁇ 20;
  • tapestatus tapestatus & 0 ⁇ fbff; /* Turn off load point */ ⁇
  • tapebutferpointer tapebutferpointer + (10 - I1);
  • tapestatus tapestatus ⁇ 0 ⁇ 20; tapefmpointer++;
  • tapebuf ferpo int er tapebuf ferpointer • (10 • II;

Landscapes

  • Engineering & Computer Science (AREA)
  • Theoretical Computer Science (AREA)
  • Human Computer Interaction (AREA)
  • Physics & Mathematics (AREA)
  • General Engineering & Computer Science (AREA)
  • General Physics & Mathematics (AREA)
  • Signal Processing For Digital Recording And Reproducing (AREA)

Abstract

A controller for interfacing a high-density archive medium with a low-density host computer archive port includes a date generator and display. Information being written to the archive medium is reformatted appropriately for the higher density medium and date stamped before writing. In order to retrieve data, the user enters the date on which the data was written, potentially together with some other identifying information, in order to uniquely identify a block or segment of data on the higher density medium. Each such block or segment corresponds to a separate 'pseudo' one of the units of the lower density medium.

Description

DATA EMULATION AND ENCODING APPARATUS
A portion of the disclosure of this patent document contains material which is subject to copyright protection. The copyright owner has no objection to the facsimile reproduction by anyone of the patent document or the patent disclosure, as it appears in the Patent and Trademark Office patent file or records, but otherwise reserves all copyright rights whatsoever.
BACKGROUND OF THE INVENTION
1. Field of the Invention
The invention concerns data archiving systems, and more particularly, systems which emulate one form of archiving medium with another.
2. Description of Related Art
For many types of businesses which store data via computer, it is important to write large blocks of such data onto a bulk storage medium for archival purposes. Archival storage media have undergone significant increases in density as various technologies have developed over the years. This not only permits storage of much more data in a smaller physical space at a lower cost, but also minimizes the number of times that media must be mounted or dismounted during the storage or retrieval of data.
For example, 9-track magnetic tapes typically store on the order of 30 megabytes of data on each reel, whereas an optical disk can store as much as 5 gigabytes of data per disk or more. Thus, the same amount of data can be stored in a far smaller amount of shelf space on optical disk, and far less operator intervention is required to mount and dismount the disks.
Because the technology has improved so quickly, many computer installations have not been able to keep pace. Many installations, therefore, are still using the older, more bulky archive media, even though newer, faster and much denser media are available. There is, therefore, a need to make higher density archive media available for use with computer installations which have previously used lower density archive media. There is a further need that this be accomplished with little or no alterations in the host computer system's software.
SUMMARY OF THE INVENTION
According to the invention, a controller is provider for interfacing a high density medium to a host computer system adapted originally for a lower density medium. The controller includes an emulator, the input of which connects directly to the existing computer system archive port, an interface for coupling data to a higher density medium, and formatting apparatus for reformatting and/or remapping the data as it is transmitted in one direction or the other. Means are provided for uniquely identifying each block of data on the higher density medium, corresponding to individual units of the lower density medium.
Advantageously, the identifier is in a natural form, including, for example, the date on which the data is written to the archive. For retrieval purposes, the user can then simply enter the date on which the data was archived, as well as any other identifying information necessary to select a unique block of archive data. The addressing of the data within the selected block by the host therefore corresponds to the addressing of a unit of the lower density medium on which the user would previously have hand-written the same identification markings.
BRIEF DESCRIPTION OF THE DRAWINGS
The invention will be described with respect to particular embodiments thereof, and reference will be made to the drawings, in which:
Fig. 1 is a block diagram of a controller according to the invention; and
Fig. 2 is a flow chart describing the firmware operation of the controller of Fig. 1.
DETAILED DESCRlPTION
In the preferred embodiment, the lower density medium which is emulated is 9-track magnetic tape and the higher density medium which is actually used is writable optical disk. No change in the computersystem's software is necessary. Since 9-track tape media can be approximately 5 times more expensive than optical media per byte of archive data, this controller significantly reduces operation costs.
The controller interfaces with the computer system via two 50-pin connectors identical to the connectors on 9-track tape drives. The host system sees the same signals as the 9-track drive, thus emulating its operation. As shown in Fig. 1, ports are provided both for connection to the computer system and for connection to an existing 9-track drive. Thus, the user can enable either the optical disk medium or the 9-track drive, so that data previously archived on 9-track tape can still be restored without the expense of a conversion to the optical format.
Every record written on an optical disk includes a date stamp, so for fast data retrieval, MONTH, DAY, YEAR and LOCK buttons are located on the controller front panel with an LED readout of the current date selected. By depressing the LOCK button, the controller automatically positions itself at the first occurrence of a matching date stamp on the optical disk. The associated "pseudo" tape is then considered mounted, as far as the host is concerned, and available for fast data retrieval. The controller always keep track of the current date, so operator action is usually not required for LOCK operation.
The data format at the computer system interface is in accordance with ANSI standards X3.39-1973 and X3.32- 1973, both of which are set forth in industry standard documents and both of which are incorporated by reference herein. These standards specify the existence of "records" and "files". Each record or file is marked by unique data patterns specified in the ANSI specification.
Data on the archive device, which can be optical or magnetic disks as well as alternative tape storage devices such, as digital audio tape (DAT) systems, is divided into "blocks" of 64k bytes in length. These blocks can be grouped into "segments," which define multiple blocks. Segments are re-mapped via a lookup table when the archive device has "write once" capability and the input data is to be rewritten. The archive reserves the first 0.2% of the medium for segment remap tables.
A segment remap table is 64k bytes in length where the segment remapped address consists of a 4-byte integer. These tables are written in sequence whenever a new entry is assigned to the remap table; therefore, the last remap table written is the "valid" remap table for the medium.
A segment can be defined as one block or multiple blocks, depending on the size of the archive medium. The segment size is written within each block.
The block data specification is as follows. Each block begins with the following eight byte header:
Byte 0 Month (in BCD)
Byte 1 Day (in BCD)
Byte 2 Year (in BCD)
Byte 3 Hour (in BCD)
Byte 4 Minute (in BCD)
Byte 5 Seconds (in BCD)
Byte 6 Sequence Number (in Hex)
Byte 7 Segment Size (in Hex)
Every time a block is written, the current date and time is also written for data retrieval purposes.
Bytes 8 thru 1023 contain the "file mark" table. This is a sequential list of file marks detected from the input data stream. Each file mark is a 4 byte long integer value.
Bytes 1024 thru 2047 contain the "record" table. This is a sequential list of record marks detected from the input data stream. Each record mark is a 4 byte long integer value.
Bytes 2048 thru 65535 contain the data itself.
The optical disk drive useable with the controller can be, for example, the Toshiba VM-S500 12-inch optical disk drive, with a storage capacity of 5 gigabytes. This is equivalent to 167 typical 9-track tapes. When the operator executes an archive to tape command from the host computer system, the controller emulates the tape drive and stores the archive data on the optical disk. An LED readout is provided, enabling the operator to date stamp the archived data to insure fast, accurate retrieval. Additionally, the percent disk remaining and the tape number is also displayed on the front panel.
The firmware for operating the system in Fig. 1 in accordance with the flow chart of Fig. 2 is set forth below in C language and assembly language source code.
The invention has been described with respect to particular embodiments thereof, and it will be understood that numerous variations and modifications are possible within its scope.
Controller MAIN FIRMWARE ROUTINE and FUNCTIONS
Copyright 1990 PBT Technologies
/***********************************************************************
STATIC VARIABLES
***********************************************************************/
/***********************************************************************
Interupt flags: tapeintr - 9 track tape command present
scsiintr - SCSI controller service request
**************************************************************************/ static int tapeintr = 0;
static int scsiintr = 0;
/***********************************************************************
Variable declartions.
dragpass . Non-zero if diagnostics pass
fatalerror . Non-recoverable error
configuration - Tape Drive Configuration
diagLED - Map of on board LEDs
percentage - BCD value for 7,8 LED display digit
lockstatus - Indicates lock mode (lock current date)
keystatus • Map of key switch register loaded by
interupt routine
flashsec - Copy of old seconds value used to flash
LED display in unlocked mode
flashstatus - whether LED display is blank (10) or
unblanked (1)
displaymode - Is either percentage (0) mode or tape
number (1) mode
SCSImode - Is either Target (0) or Initator (1)
on SCSI bus
***********************************************************************/ static int diagpass = 0;
static int fatalerror = 0;
static int configuration = 0;
static int diagLED = 0×FF00;
static int percentage = 0;
static int lockstatus = 0;
static int keystatus = 0×ff;
static char flashsec = 0;
static char flashvalue = 0;
static int flashstatus = 0;
static int displaymode = 0;
static int SCSImode = 0;
static int dayIight = 0×3;
static int tapebufferpointer =0×400;
static int tapebufferstop = 0;
static unsigned long tapepointer = 01;
static unsigned long tapeblkpointer = 01;
static unsigned long tapefmpointer = 01;
static unsigned long tapeblklastptr = 01;
static unsigned long tapeblkprevptr = 01;
static unsigned long tapefmlastptr = 01;
static unsigned long tapefmprevptr = 01;
static int tapeprevcommand = 0;
static int tapebuf ferblkptr = 0;
static int tapebuf ferfmpt r = 0;
static int tapenumber = 1;
static int tapedensity = 0;
static int tapebufferflag - 0;
static int SCSIbufferflag = 0;
static int SCSIpresent = 1;
static int tapebufferstatus = 0;
static int diskbufferstatus = 0;
static long tapesize = 01;
static long diskblock = 01;
static long diskblocksize = 01;
static long diskcurrentblock = 01;
static long diskwriteptr = 01;
static long diskreadptr = 01;
static long diskpointer = 01;
static long disktapebot = 01;
static int disklogical = 01;
static int diskiogicalmax = 01;
static int diskreadyflag = 0;
static int diskdone = 0;
static int datacurrent = 0;
/*********************************************************************** altdate - Alternate Date code when not in lock
mode This is what is used instead of
CMOS ram if unlocked Charectors are BCD encoded***********************************************************************/ static unsigned char altdate[4]
/***********************************************************************
Data buffer declarations
databuffer0 databufferl are twin 4 Kbyte
buffers utilized by the SCSI controller
under DMA control, and by the 9-track
interface under program I/O
CommandBuffer is utilized to pass SCSI command data
drivecommand contains the current SCSI coinmand initiated
drivecommandbytes is the number of command bytes to transfer
SCSIerror is non zero if SCSI error ocurs
***********************************************************************/ static char SCSIdatabuffer [64];
static char CommandBuffer [16];
static char driveselect;
static int drivecommandbytes;
static int SCSIerror = 0;
static int buffersize;
/ ***********************************************************************
Offset definitions for control registers.
(To be used by readio, writeio routines)
tapecontrol - Tape control register
LEDdisplay - Seven segment LED register
tapedata - Tape data register
SCSIcontrol - SCSI controller
serial - RS-232 port controller
datecontrol - Date, Time controller
keyswitch - Keyswitch status register static int tapecontrol =0×0;
static int LEDcontrol =0×80;
static int tapedata = 0x100;
stat i c int SCSIcontrol = 0×180;
static int serial = 0×200;
static int datecontrol = 0×280;
s t at i c int keyswi t ch =0×300;
/*********************************************************************** Misc. variables used
***********************************************************************/ static unsigned int tapestatus;
static long 10, 11, 12, 13, 14, 15, 16, 17;
static unsigned int i0, i1, i2, i3 i4, i 5, i6, i7;
static unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
static float f0, f1, f2, f3, f4, f5, f6, f7;
/***********************************************************************
LEObuffer defines - These initial values represent
charector decoding for the LED
display - to be used with the
array for loading LEDs.
***********************************************************************/ static int LEDbuffer[10];
static int zero = 0×3f; /* LED Map */ static int one = 0×06; /* * / static int two = 0×5b, /* a * / static int three - 0×4 f; /* f b * / static int four = 0×66; /* g * / static int f ive = 0×6d; /* e c * / stat ic int six = 0×7d; /* d * / stat ic int seven = 0×07; /* LEDcontrol * / static int eight = 0×7f, /* Register Definition * / stat ic int nine = 0×67, /* Bits 6 5 4 3 2 1 0 * / static int LEDoff = 0×00, /* g f e d c b a * /
/***************************************************************************
External reference for readio and writeio
***************************************************************************/ extern readiow(),
extern wr i teιow(),
extern readiob();
extern writeiob():
extern readfilerev(),
extern readfiIefw(),
extern writetape(),
extern dmaread();
extern dmawrt(),
extern dmastatus();
/***************************************************************************
Start of main function (assembly language startup program
jumps here upon completion)
***************************************************************************/
#ιnclude <stdιo. h>
maιn()
{
/************************************************************************** The initial section of code is executing only from power
up or fatal error conditions - This code includes
a) Initialization of LED display . diagnostic LEDs
SCSI, tape emulation, CMOS RAM timer, Read Configuration b) Run diagnostics if configuration bit 15 is set including
1) i 186 Memory test (Disk-Tape data buffers)
2) CMOS RAM-timer check
3) SCSI test
4) Tape emulation verify
5) Serial port test
c) Set LED display to current date perentage mode
d) Find the last data entry on drive by looking for
last entry Start with entry found in CMOS RAM (updated each write)
e) Continue to main service loop
*****************************************************************************/ powerup:
initialize(); /* Initialize hardware */
SCSIreset();
if (configuration & 0×8000 = 0×8000) diagnost ics(); /* Run diagnostics */ setaltdate(); /* Copy current date to alternate * / displaymode = 0; /* Percentage mode * /
setLEDstatus(): /* Pass, set LED display * / readdate (0×a);
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false * / readdate (0×0);
flashvalue = c0;
/***************************************************************************
Main program loop:
a) Flashes LED display if in unlocked mode
b) Checks for tape drive coπinand and processes
c) Checks for SCSI command and processes
d) Checks for date changes
e) Checks for keyswitch input and processes
f) Checks for serial port status
***************************************************************************/ while (fatalerror = 0)
{
readiow (tapedata, ficonf igurat ion); /* get configuration */
if (lockstatus != 0) LEDflash(); /* Not locked - Flash LED display * / if (lockstatus = 0) setLEDstatus();
if (tapeintr = 0)
{
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false * / writedate (0×e, 0);
}
if (tapeintr != 0) tapeflow(); /* Tape command present - process */ if (scsiintr != 0) scsiflow(); /* SCSI command present - process */ if ((keystatus & 0×42) = 0) setdatet ime(); /* Date change - process * / if ((scsiintr < 2) & (SCSIpresent = 1))
{
toshιbaready();
if (SCSIerror != 0) SCSIpresent = 0;
if (SCSIpresent =0) c1 = 1;
if (c1 = 0)
{
if (diskreadyflag = 0)
{
d isk logi cal = 0:
diskcurrentblock = 1024.
f0 = diskcurrentblock * 4096. ;
disktapebot = f0;
diskreadptr = f0;
diskwriteptr = f0;
diskpointer = f0;
drtycln();
toshibareadcapacity();
i4 = SCSIdatabuffer[3] + 256*SCSI databuf fer [2],
i5 = SCSIdatabuffer[1] + 256*SCSIdatabuffer[0].
diskblock = i4 + 0×100001*i5;
i4 = SCSIdatabuffer[7] + 256*SCSIdatabuffer [6];
i5 = SCSIdatabuffer[5] + 256*SCSIdatabuffer[4]:
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false * / writedate (0×f.l); /* Tape number = 1 * / diskblocksize - ι4 + 0×100001 * 15.
diskreadyflag = 1,
tapeintr = 1,
tapebufferini t (),
scsiintr = 1,
}
else
{
f1 = diskwr iteptr
(2 = diskblock,
(3 = diskblocksize
f0 = (1 ■ (fl/(f2*f3)))*100 ,
10 = f0
if (10 > 9E) 10 = 99
percentage = 10
c1 = 10/10
c0 = c1 * 10
c1 = c1 * 16
c0 = 10 - c0,
c7 = c1 + c0,
c0 = 0×80,
while (c0 = 0×80) readdate (0×a) /* Wait for update to be false */ writedate (0×e c7)
}
writeiow (keyswitch 0×7) /* Take tape drive OFFLINE * / readiow (tapecontrol &i2) /* Get current tape control */
diagLED = diagLED ¦ 0×200 /* Turn drive ONLINE LED off */ diagLED = diagLED & 0×feff /* Set ONLINE LED * /
writeiow (tapecontrol i2 | 0×c1) /* Load tape with ONLINE */
)
else
{
tapeoffIιne()
tapeintr = 0
diskreadyflag = 0
datacurrent = 0
}
}
keyflow() /* Keyswitch was depressed * / serialport() /* Check serial port */
}
/*************************************************************************** If a fatalerror has been flagged try to recover - if all
is lost re-powerup and hope ! ! !
***************************************************************************/ errorrecover (), /* Try recovering error - re-boot * / goto powerup
}
/*************************************************************************** initlalize()
Function that initializes hardware by
taking tape emulator off I ine
b) blank LED display
c) turn diagnostic LEDs off (prior ro diagnosticsd) Initialize based on configuration
1) SCSI adapter for drive type
2) Tape emulation for tape drive type
***************************************************************************/ i n i t i a l i ze ()
{
tapeoffline();
readiow (tapedata, &configuration); /* get configuration */ if ((configuration & 0×38) = 0)
{
f0 = 2400*12*1600; /* For 2400 ft 1600 BPI * / tapesize = f0;
tapedensity = 1;
}
it ((configuration & 0×38) = 0×8)
{
(0 = 2400*12*800 /* For 2400 ft 800 BPI*/ tapesize = f0;
tapedensi ty = 0:
}
if ((configuration & 0×38) =0×10)
{
f0 = 2400*12*3200; /* For 2400 ft 3200 BPI */ tapesize = f0;
tapedensity = 2;
}
if ((configuration & 0×38) = 0×18)
{
f0 = 2400*12*6250; /* For 2400 ft 6250 BPI */ tapesize = f0;
tapedensi ty = 3;
}
c0 = 0: /* Fill LED buffer */
while (c0 < 8)
{
LEDbuffer[c0] = LEDoff; /* Load with blanks */
c0++;
}
setLED(); /* Write LED display */ readdate (0×d):
if ((c0 & 0×80) = 0) setdatetime(); /* Check for VRT bit */
}
/*************************************************************************** setLEDstatus() . Function that reads date-month-year as well
as percentage/or tape number data all stored in battery back up RAM locations or from alternate date location if not in lock mode. This routine assumes the CMOS ram is correct before executing ***************************************************************************/ setLEDstatus()
{
if (lockstatus = 0)
{
c0 = 0×80:
while (c0 = 0×80) readdate (0×a); /* Wait for valid */ readdate (0×8); /* Get month (in BCD) */
}
else c0 = al tdate[0];
LEDbuffer[0] = zero, /* set 1st month digit */ if ((c0 & 0×f0) = 0×10) LEDbuf fer [0] = one.
LEDbuffer[l] = zero; /* set 2nd month digit */ if ((c0 & 0×f) = 0×1) LEDbuffer[1] = one;
if ((c0 & 0×f) = 0×2) LEDbuf fer [1] = two.
if ((c0 & 0×f) = 0×3) LEDbuf fer[1] = three; if ((c0 & 0×f) = 0×4) LEDbuffer[1] = four;
if ((c0 & 0×f) = 0×5) LEDbuffer[1] = f ive;
if ((c0 & 0×f) = 0×6) LEDbuffer[1]= six;
if ((c0 & 0×f) = 0×7) LEDbufftr[1] = seven;
if ((c0 & 0×f) = 0×8) LEDbuf fer[1] = eight;
if ((c0 & 0×f) = 0×9) LEDbuffer[1] = nine;,
if (lockstatus = 0)
c0 = 0×80,
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×7);
)
else c0 = altdate[1],
LEDbuf fer [2] = zero, /* set 1st day digit */ if ((c0 & 0×f0) = 0×10) LEDbuf fer [2] = one
if ((c0 & 0×f0) = 0×20) LEDbuf fer[2] = two
if ((c0 & 0×f0) = 0×30) LEDbuf fer [2] = three
LEDbuf fer [3] = zero, /* set 2nd day digit */ if ((c0 & 0×f) = 0×l) LEDbuffer [3] = one;
if ((c0 & 0×f) = 0×2) LEDbuffer [3] = two;
if ((c0 & 0×f) = 0×3) LEDbuffer[3] = three;
if ((c0 & 0×f) = 0×4) LEDbuf fer [3] = four;
if ((c0 & 0×f) = 0×5) LEDbuffer [3] = five;
if ((c0 & 0×f) = 0×6) LEDbuffer [3] = six;
if ((c0 & 0×f) = 0×7) LEDbuffer [3] = seven;
if ((c0 & 0×f) = 0×8; LEDbuffer [3] = eight;
if ((c0 & 0×f) = 0×9) LEDbuffer [3] = nine; if (lockstatus = 0)
{
c0 = 0×80,
while (c0 = 0×80) readdate (0×a) /* Wait for update to be false */ readdate(0×9), /* Get Year in BCD */
}
else c0 = altdate[2]:
LEDbuf f er [4] = zero; /* set 1st year digit */
if ((c0 & 0×f0) = 0×10) LEDbuf fer [4] = one;
if ((c0 & 0×f0) = 0×20) LEDbuf fer [4] = two;
if ((c0 & 0×f0) = 0×30) LEDbuf fer [4] = three;
if ((c0 & 0×f0) = 0×40) LEDbuf fer [4] = four;
if ((c0 & 0×f0) = 0×50) LEDbuf fer[4] = five;
if ((c0 & 0×f0) = 0×60) LEDbuf fer[4] = six;
if ((c0 & 0×f0) = 0×70) LEDbuf fer[4] = seven;
if ((c0 & 0×f0) = 0×80) LEDbuf fer [4] = eight;
if ((c0 & 0×f0) = 0×90) LEDbuf fer [4] = nine;
LEDbuf f er [5] = zero, /* set 2nd year digit */
if ((c0 & 0×f) = 0×1) LEDbuf fer [5] = one;
if ((c0 & 0×f) = 0×2) LEDbuf fer [5] = two;
if ((c0 & 0×f) = 0×3) LEDbuf fer [5] = three;
if ((c0 & 0×f) = 0×4) LEDbuf fer [5] = four;
if ((c0 & 0×f) = 0×5) LEDbuf f er[5] = five;
if ((c0 & 0×f) = 0×6) LEDbuf fer[5] = six;
if ((c0 & 0×f) = 0×7) LEDbuf f er [δ] = seven;
if ((c0 & 0×f) = 0×8) LEDbuf fer [5] = eight;
if ((c0 & 0×f) = 0×9) LEDbuf fer [5] - nine;
if (lockstatus = 0)
{
c0 = 0×80
while (c0 = 0×80) readdate (0×a) /* Wait for update to be false */ readdate (0×e), /* Get status (in BCD) */ i f (c0 = 0)
{
LEDbuf fer[6] = LEDoff.
LEDbuf fer[7] = LEDoff;
}
}
else c0 = al tdate[3];
if ((c0 & 0×f0) = 0×10) LEDbuf fer[6] = one;
if ((c0 & 0×f0) = 0×20) LEDbuffer[6] = two;
if ((c0 & 0×f0) = 0×30) LEDbuffer.[6] = three;
if ((c0 & 0×to) = 0×40) LEDbuffer[6] = four;
if ((c0 & 0×f0) = 0×50) LEDbuffer[6] = five;
if ((c0 & 0×f0) = 0×60) LEDbuf fer[6] = six;
if ((c0 & 0×f0) = 0×70) LEDbuf fer [6] = seven;
if ((c0 & 0×f0) = 0×80) LEDbuffer [6] = eight;
if ((c0 & 0×f0) = 0×90) LEDbuffer[6] = nine.
if ((c0 & 0×f) = 0×l) LEDbuffer[7] = one;
if ((c0 & 0×f) = 0×2) LEDbuf fer [7] = two;
if ((c0 & 0×f) = 0×3) LEDbuffer[7] = three;
it ((c0 & 0×f) = 0×4) LEDbuf fer [7] = four;
if ((c0 & 0×f) = 0×5) LEDbuffer [7] = five;
if ((c0 & 0×f) = 0×6) LEDbuf fer [7] = six:
i f ((c0 & 0×f) = 0×7) LEDbuffer[7] = seven;
if ((c0 & 0×f) = 0×8) LEDbuf fer[7] = eight;
if ((c0 & 0×f) = 0×9) LEDbuf fer [7] = nine;
setLED(); /* output to d i sp l ay */
/*************************************************************************** setaltdate () - Function that copies the current date into the alternate date array This function assumes CMOS RAM is functioning
****************************************************************************/ setaltdate()
{
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */' readdate (0×8);
altdate[0] = c0; /* Set alternate date */
c0 = 0×80,
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false * / readdate (0×7);
altdate[l] = c0; /* Update alternate date */ c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false * / readdate (0×9);
altdate[2] = c0;
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for upoate to be false * / readdate (0×e):
altdate[3] = c0; /* Update alternate date * /
}
/***************************************************************************
LEDflash() - Function that turns LEO display on/off every 2 seconds. Invoked if unlocked
***************************************************************************/ LEDflash()
{ readdate (0×a);
whi le (c0 = 0×80) readdate (0×a), /* Wait for update to be false */ readdate (0×0);
flashsec = c0;
if (f lashsec != f lashvalue)
{
readdate (0×a);
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×0);
(lashvalue = c0;
i0 x- flashstatus;
if (i0 = 0)
{
c3 = 0,
whi le (c3 < 10)
{
LEDbuffer[c3] = LEDoff; /* Set LED displays to OFF */ c3++;
}
setLED();
flashstatus = 1,
}
if (i0 = 1)
(
setLEDstatus(),
flashstatus = 0;
}
}
}
/*************************************************************************** keytlow() - Function that tests for keyswitch input
***************************************************************************/ keyflow()
{
readiow (keyswitch, &c0);
i f (keystatus != c0)
{
keystatus = c0;
if ((c0 & 1) = 0)
{
if (lockstatus = 0)
{
if (c0 = 0×fc) lockstatus = 1;
}
else
{
if (c0 = 0×fc) lockstatus = 0;
if ((c0 & 4) = 0)
{
c2 = altdate[2].
c2 = c2 & 0×f;
c2 = c2 - 1
c2 = c2 & 0×f,
altdate [2] = (alloate [2] & 0×f0) + c2
if ((altdate[2] & 0×f; > 10;
{
altdate[2] = (altdate[2] & 0×f0) + 0×9
altdate[2] = a 11 date [2] - 0×10
if ((altdate[2] & 0×f0 > 0×90) altdate[2] = 0×99.
}
} if ((c0 & 0×10) = 0)
{
c2 =altdate[1];
c2 = c2 & 0×f;
c2 = c2 - 1;
c2 = c2 & 0×f;
altdate[1] = (altdate[1] & 0×f0) + c2;
if ((altdate[1] & 0×f) > 9)
{
altdate[1] = (altdate[1] & 0×f0) + 0×9; altdate[1] = altdate[1] - 0×10;
if ((altdate[1] & 0×f0) > 0×30) altdate[1] = 0×39.
}
i f ( (c0 & 0×40) = 0)
{
c2 = altdate[3];
c2 = c2 & 0×f;
c2 = c2 + 1;
c2 = c2 & 0×f;
altdate[3] = (altdate[3] & 0×f0) + c2;
if ((altdate[3] & 0×f) > 9) altdate[3] = 0×1;
}
if ((c0 & 8) = 0)
{
c2 = altdate[2];
c2 = c2 & 0×f;
c2 = c2 + 1:
c2 = c2 & 0×f;
altdate[2] = (altdate[2] & 0×f0) + c2, if ((altdate[2] & 0×f) > 9)
{
altdate[2] = altdatef2] & 0×f0; altdate[2] = altdate[2] + 0×10;
if ((altdate[2] & 0×f0) > 0×90) altdate[2] = 0×0* }
}
if ((c0 & 0×20) = 0)
{
c2 = altdate[1];
c2 = c2 & 0×f;
c2 = c2 + 1;
c2 = c2 & 0×f;
altdate[1] = (altdate[1] & 0×f0) + c2;
if ((altdate[1] & 0×f) > 9)
{
altdate[1] = altdate[1] & 0×f0; altdate[1] = altdate[1] + 0×10;
if ((altdate[1] & 0×f0) > 0×30) altdate[1] = 0×0; }
}
if ((c0 & 0×80) = 0)
{
c2 = altdate[0];
c2 = c2 & 0×f;
c2 = c2 + 1;
c2 = c2 & 0×f;
altdate[0] = (altdate[0] & 0×f0) + c2,
if ((altdate[0] & 0×f) > 9)
{
altdate[0] = altdate[0] & 0×f0: altdate[0] = altdate[0] + 0×10;
if ((altdate[0] & 0×f0) > 0×10) altdate[0] = 0×0; }
}
} }
}
}
/********************************************************************** setLED()
Function that loads the 7 segment LEDs
uses LEDbuffer which should be lo-aded utilizing
the variables zero, one , two etc which are decoded
with the seven segments
LEDbuffer maps as f ol lows
LEDbuf fer[0] 1st Month digit
LEDbuf fer[1] 2nd Month digit
LEDbuf fer[2] 1st Day digit
LEDbuf fer[3] 2nd Day digit
LEDbuf fer [4] 1st Year digit
LEDbuf fer[5] 2nd Year digit
LEDbuff er[6] 1st Variable digit
LEDbuf fer[7] 2nd Variable digit
LEDbuf fer [8] 1st Expansion digit
LEDbuf fer[9] 2nd Expansion digit
***************************************************************************/ setLED ()
{
diagLED = (diagLED & 0×1f00) + 0×40ff /* Set for 1st load */ writeiow (LEDcontrol, diagLED) /* Load shift register */ writeiow (LEDcontrol, diagLED) /* Do twice to insure load diagLED = diagLED ¦ 0×8000, /* Set for shift */
writeiow (LEDcontrol, di agLED) /* Do twi ce to insure load c0 = 0 /* Set variable */
whi le (c0 < 1)
{
diagLED = diagLED & 0×bfff /* Set shift clock high */ writeiow (LEDcontrol, diagLED),
diagLED = diagLED ¦ 0×c000 /* Set shift clock low */ writeiow (LEDcontro diagLED)
c0++,
}
c1 =4
whi e (c1 <= 7)
{
ι2 = LEDbuffer [c1] & 0×ff, /* Set for subsequent loads */ diagLED = (diagLED & 0×lf0O) + 0×4000 + ι2 /* Set for subsequent loads */ writeiow (LEDcontrol, diagLED), /* Load shift register */ writeiow (LEDcontrol diagLED) /* Load shi ft register */ diagLED = diagLED ¦ 0×8000, /* Set for shift */
writeiow (LEDcontrol, diagLED) /* Do twice to insure load */ c0 = 0,
whi le (c0 < 7)
{
diagLED = diagLED & 0×bfff, /* Set shift clock high */ writeiow (LEDcontrol, diagLED)
diagLED = diagLED ! 0×c000 /* Set shift clock IOΪ. *, writeiow (LEDcontrol, diagLED,
c0++,
}
c1++,
}
diagLED =(diagLED & 0×lf0O) + 0×40ff /* Set for 1st load */ writeiow (LEDcontrol diagLED) /* Load shift register */ writeiow (LEDcontrol diagLED; /* Do twice to insure load */ diagLED = diagLED ! 0×8000; /* Set for shift */
writeiow (LEDcontrol, diagLED); /* Do twice to insure load * / c0 = 0; /* Set variable */
while (c0 < 6)
{
diagLED = diagLED & 0×bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
diagLED = diagLED ! 0×c000, /* Set shift clock low * / writeiow (LEDcontrol, diagLED);
c0++;
}
diagLED = (diagLED & 0×1f00) + 0×60ff /* Set for 1st load */
writeiow (LEDcontrol.diagLED): /* Load shift register */ writeiow (LEDcontrol. diagLED): /* Load shift register */ diagLED = diagLED ¦ 0×8000; /* Set for shift */
writeiow (LEDcontrol, diagLED); /* Do twice to insure load */ c0 m 0;
while (c0 < 1 )
{
diagLED = diagLED & 0×bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
diagLED = diagLED | 0×c000; /* Set shift clock low */ writeiow (LEDcontrol, diagLED);
c0++;
}
c1 = 0;
while ( c1 <= 3)
{
i2 = LEDbufferfd] & Qxff, /* Set for subsequent loads */ diagLED = (diagLED & 0×lf0O) 0×6000 + i2 /* Set for subsequent loads */' writeiow (LEDcontrol, diagLED), /* Load shift register */
writeiow (LEDcontrol, diagLED); /* Load shift register */
diagLED = diagLED ! 0×8000; /* Set for shift */
writeiow (LEDcontrol, diagLED): /* Do twice to insure load */ c0 = 0;
whi le (c0 < 7)
{
diagLED = diagLED & 0×bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
diagLED = diagLED | 0×c0OO; /* Set shift c1ock low * / writeiow (LEDcontrol, diagLED);
c0++;
}
c1++;
}
diagLED = (diagLED & 0×lf0O) + 0×60ff; /* Set for 1st load * /
writeiow (LEDcontrol, diagLED); /* Load shift register * /
writeiow (LEDcontrol, diagLED); /* Load shift register */
diagLED = diagLED i 0×8000; /* Set for shift */
writeiow (LEDcontrol. diagLED); /* Do twice to insure load */ c0 = 0,
while (c0 < 6 )
{
diagLED = diagLED & 0×bfff; /* Set shift clock high */ writeiow (LEDcontrol, diagLED);
diagLED = diagLED ¦ 0×c000; /* Set shift clock low */ writeiow (LEDcontrol. diagLED);
c0++;
}
diagLED = diagLED & 0×bfff; /* Set shift c1ock high * / writeiow (LEDcontrol, diagLED):
}
/*************************************************************************** tapeoffline - function sets tape emulation hardware to
offline status: allows existing tape drive
to coinmunication with host
*******************************************************************************/ tapeoffIιne()
{
diagLED = diagLED & 0×fdff, /* Turn on LED */
diagLED = diagLED ¦ 0×100,
writeiow (tapecontrol, 0×0), /* tape controls OFF */
writeiow (tapedata, 0×0). /* tape data OFF */
writeiow (keyswitch 0×0), /* tape address to 0 */
} /********************************************************************************* readdate (regnumber, value)
Th i s function reads a value from the Date/Time
chip and rearranges the address and data
************************************************************************/ readdate (regnumber)
int regnumber
{
regnumber = regnumber * 2 /* Scale Register number readiob ((datecontrol + regnumber) &c0) /* Read register */ c1 = c0 & 0×1; /* Re-arrange data */ c1 = c1 * 0×80;
c0 = c0 & 0×fe,;
c0 = c0 / 2,
c0 = c0 + c1,
}
/************************************************************************ writedate (regnumber. value)
This function writes a value to the Date/Time
chip and rearranges the address and data
***********************************************************************/ writedate (regnumber, value;
int regnumber,
unsigned char value,
{
c0 = value
c1 = c0 & 0×80; /* Re-arrange data */ c1 = c1 / 0×80;
c0 = c0 & 0×7f;
c0 = c0 * 2;
c0 = c0 + c1;
regnumber = regnumber * 2, /* Scale Register number */ writeiob ((datecontrol + regnumber) c0), /* Read register */
}
/************************************************************************ setdatet ιme()
This function sets the DATE and TIME in tne
dat/time chip
* **********************************************************************/ setdatetime()
{
lockstatus = 1; /* Set for keyflow */
if ((configuration & 0×40000) != 0) daylight = 0×2;
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×8); /* Read current month */ altdate[0] = c0;
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×7); /* Read current Day */ altdate[1] = c0:
c0 = 0×80;
wh i l e (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×9): /* Read current Year */ altdate[2] = c0;
altdate[3] = 0: /* Load percent with 0 (unused) while (lockstatus = 1)
{
LEDflash(); /* Flash display * / keyflow(); /* Get key input * /
}
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ writedate (0×b, daylight ¦ 0×80); /* Set change bit */ writedate (0×8, altdate[0]); /* Write changed values */ writedate (0×7, altdate[1]);
writedate (0×9, al tdat e[2]);
writedate (0×b, daylight); /* Set change bit */
lockstatus = 1;
altdate[0] = 0; /* Set month to 0 (unused) */ c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×4), /* Get current hour */ altdate[1] = c0;
c0 = 0×80;
while (c0 m-ι 0×80) readdate (0×a); /* Wait for update to be false * / r eaddat e (0×2); /* Get current minute */ altdate[2] = c0;
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×6); /* Get current day of week */ altdatef3] = c0;
while (lockstatus = 1)
{
LEDflash(); /* Flash display * / keytlow(); / Get key input */
}
c0 = 0×80:
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */' writedate (0×b, daylight ¦ 0×80); /* Set change bit "*/
writedate (0×4. altdate[1]); /* Write changed values */ writedate (0×2, altdate[2]);
writedate (0×6, al tdatef3]);
writedate (0×0,0); /* fni t ial ize seconds to 0 */ writedate (0×1,0); /* Initialize second alarm to 0 * / writedate (0×3.0); /* Initialize minute alarm to 0 * / writedate (0×5,1). /* Initialize hour alarm tc 0 */ writedate (0×a,0): /* Set for 4MHz operation */ writedate (0×b. daylight); /* Set BCD, 24 hour format, */ writedate (0×f, tapenumber); /* Tape number */ readdate (0×d); /* Ini t ial ize for new disk * / c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×8): /* Read current month */ altdate[0] = c0,
c0 =0×80
while (c0 = 0×80) readdate (0×a), /* Wait for update to be false */ readdate (0×7), /* Read current Day * /
altdate[1] - c0,
c0 = 0×80,
while (c0 =0×80) readdate (0×a) /* Wait for update to be false */ readdate (0×9), /* Read current Year */
altdate[2] = c0,
altdatef3] = 1, /* Load percent with 0 (.unused) */}
/* ***************************************************************************** tapeflow() . function that handles the tape emulation
***************************************************************************/ tapef low()
{
r ead i ow (tapecont rol &tapestatus) /* Get tape status */
if ((tapes t atus & 0×40) = 0) taperewind() /* Rewind ?? */
if ((tapest atus & 0×1) != 0) /* Is a command present ? */
{
writelow (tapecontrol, tapestatu 0×c3)
readiow LEDcontro &ι3),
if ((i3 & 0×e0c0) = 0×0) tapereadforward();
if ((i3 & 0×e0c0) = 0×2000) tapereadreverse();
if ((i3 & 0×e0c0) = 0×2040) tapereadreverse();
if ((i3 & 0×e0c0) = 0×4000) tapewrιte();
if ((i3 & 0×e0c0) = 0×4040) tapewrite();
if ((i3 & 0×e0c0) = 0×c000) tapewritefm();
if ((i3 & 0×e0c0) = 0×4080) tapeerasevari();
if ((i3 & 0×e0c0) = 0×c080) tapeerasefixed();
if ((i3 & 0×e0c0) = 0×e0c0) tapeerasesecure();
if ((i3 & 0×e0c0) = 0×0080) tapespaceforward();
if ((i3 & 0×e0c0) = 0×2080) tapespacereverse();
if ((i3 & 0×e0c0) = 0×8000) tapefileforward();
if ((i3 & 0×e0c0) = 0×8080) tapefileforwardi();
if ((i3 & 0×e0c0) = 0×a000) tapefilereverse();
if((i3 & 0×e0c0) = 0×a080) tapefilereversei ();
if ((i3 & 0×e0c0) = 0×c0) tapewritesync();
if ((i3 & 0×e0c0) = 0×a0c0) tapehidens();
if ((i3 & 0×e0c0) = 0×40c0) tapestddens();
if (tapeintr = 1)
{
wr i t e i ow (tapecontrol, tapestatus)
writeiow (tapecontrol (tapestatus & 0×fffc));
tapestatus = tapestatus & 0×ffdc
writeiow (tapecontrol, tapestatus)
writelow (tapecontrol (tapestatus ! 0×c1));
}
}
}
/******************************************************************
Tape Emulat ion Fund ions
Memory Buffer . only LSB is available due to SCSI DMA
Memory Buffer Map
Address Contents
0 Month
2 Day 4 Year
6 Tape Number
8 thru 0×lfe File Mark Array (long values)
0×200 thru 0×3fe Inter Record Gap Array (long values)
400 thru 0×fffe data
*******************************************************************/ tapebuffer init()
{
c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×8); /* Read current month */ i0 = c0:
wrtbuff (((tapebufferf Iag*0×1000) + 0×1000), 0×0, i0); /* load values */ c0 = 0×80:
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×7); /* Read current Day */ i0 = c0 ; /* Load word into i0 * / wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×2, i0); /* load values */ c0 = 0×80;
while (c0 == 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×9); /* Read current Year */ i0 = c0;
wrtbuff (((tapebufferfIag=*0×1000) + 0×1000), 0×4, i0); /* load values */ c0 = 0×80;
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×f); /* Read tape number */ i0 = c0;
wrtbuff (((tapebufferflag*0×1000) + 0×1000). 0×6, i0), /* load values */ tapebuf ferpointer = 0×400;
tapeblkprevptr = tapeblklastptr;
tapefmprevptr = tapefmlastptr;
tapeblklastptr = tapeblkpointer;
tapefmlastptr = tapefmpoint er;
}
tapefwptr()
{
tapebufferblkptr = 0×200;
tapebuf ferfmptr = 0×8;
}
taperevptr()
{
f0 = tapeblkprevptr;
tapebufferblkptr = 0×200 + 8*f0;
to = tapeblkprevptr;
tapebuf ferfmptr = 0×8 + 8*f0;
}
taperdfmptr()
{
f0 = tapefmpo inter - tapefmlastptr;
tapebufferfmptr = 0×8 + 8*f0;
rdbuff (((tapebufferflag*0×1000) x- 0×1000), tapebuf ferfmptr, &i1);
rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebuf ferfmptr+2,&i2); rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebufferfmptr+4,&i3);
rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebufferfmptr+6,&i4);
i1 = i1 & 0×ff;
i2 = i2 & 0×ff;
i3 = i3 & 0×ff;
i4 = i4 & 0×ff;
10 = 14*0×10000001 + i3*0×100001 + i2*0×1001 + i1;
} taperdblkptr()
{
f0 = tapeblkpointer . tapeblklastptr;
tapebufferblkptr = 0×200 + 8*f0,
rdbuff (((tapebufferf Iag*0×1000) + 0×1000), tapebufferblkptr, &il); rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebufferblkpt r+2, &ι2); rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebufferblkptr+4, &ι3); rdbuff (((tapebufferflag*0×1000) + 0×1000), tapebufferblkpt r-t-6. & 14); i1 = i1 & 0×ff;
ι2 = i2 & 0×ff;
i3 = i3 & 0×ff;
i4 = ι4 & 0×ff;
10 = 14*0×10000001 + ϊ 3*0×100001 + 12*0×1001 + i1;
}
tapewrt fmptr()
{
f0 = tapefmpointer . tapefmlastptr,
tapebufferfmptr = 0×8 + 8*f0,
f0 = tapepointer;
f1 = f0 / 256 ;
f2 = f1 / 256 ;
f3 = (2 / 256 ;
10 = f0;
i1 = f1;
i2 = f2;,
i3 = f3,;
i1 = 10 & 0×000000ff1;
ι2 = I1 & 0×000000ff1;
ι3 = I2 & 0×000000ff1;
i4 m I3 & 0×000000ff1;,
wrtbuff (((tapebufferflag*0×1000) +0×1000),tapebufferfmptr i1); wrtbuff (((tapebufferflag*0×1000) +0×1000),tapebufferfmptr+2,ι2); wrtbuff (((tapebufferflag*0×1000) + 0×1000),tapebuffertmptr+4 ι3); wrtbuff (((tapebufferflag*0×1000) + 0×1000;,tapebuf fer fmpt r+6 ι4);}
tapewrtblkptr()
{
f0 = tapleblkpointer - tapeblklastptr,
tapebuf f erblkptr = 0×i !00 + 8«f0
f0 m taplepointer.
fl = f0 / 256 .
f2 = fl / 256 , .
f3 = f2 / 256 ,
10 = f0,
11 = fl
12 «- f2,
13 - f3.
il = 10 & 0×000000ffl,
ι2 = 11 & 0×000000ffl,
ι3 = 12 & 0×000000ffl,
ι4 = 13 & 0×000000ffl
wrtbuff (((tapebufferflag*0×1000) + 0×1000; tapebufferblkptr i1); wrtbuff (((tapebufferflag*0×1000) + 0×1000) tapebuf ferblkpt r+2,ι2); wrtbuff (((tapebufferflag*0×1000) + 0×1000), tapebuf ferblkptr+4 ι3); wrtbuff (((tapebufferflag*0×1000) + 0×1000). tapebuf ferblkpt r+6, ι4); tapestart()
{
tapeblklastptr = 0;
tapefmlastptr = 0;
tapebufferstatus = ;
tapeblkpointer = 01;
tapefmpointer = 01; tapebufferflag = 0;
wrtbuff (((tapebuf ferflag*0×1000) + 0×1000), 0×8, 0); /* 0 fm array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×a, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×c, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×e, 0); /* 00 fm array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×200, 0); /* 0 gap array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×202, 0); /* 0 gap array */ wrtbuff (((tapebufferflag*0×1000) + O0×x1000), 0×204, 0);/* 0 gap array */ wrtbuff (((tapebufferflag*0×1000) + 0×1000), 0×206, 0);/* 0 gap array */ tapebufferinit();
tapefwptr();
}
taperewind()
{
if ((tapeintr = 1) & (scsiintr = 1))
{
tapestart();
scsiintr = 30;
tapeintr = 2;
}
if ((tapeintr = 2) & (scsiintr = 1))
{
tapeintr = 1;
if (tapepointer > 0×Offfcl ) datacurrent = 0,
tapepointer = 01; /* 0 tape pointer */ tapestatus = tapestatus & 0×ffbf;
tapestatus = tapestatus ¦ 0×481;
writeiow (tapecontrol, tapestatus); /* Set load point and ready tapestatus = tapestatus ¦ 0×41;
writeiow (tapecontrol, tapestatus); /* Set load point and ready readiow (tapecontrol, &tapestatus); /* Get tape status */ }
}
tapereadforward()
{
if (datacurrent = 0) tapeintr = 2;
tape status = tapestatus & 0× fb f f ; /* Turn o f f l oad po i nt */ if (tapefmpointer = 0) tapefmpointer++;
taperdfmptr();
if(I 0 = tapepointer)
{
tapestatus = tapestatus , 0×20;
tapefmpointer++;
tapeintr = 1;
}
else
if (((tapeintr = 1) ¦ (tapeintr = 2)) & (datacurrent = 1))
{
tapeblkpointer++;
taperdblkptr();
if (10 != 01)
{
tapebufferstop = (10 . tapepointer) + tapebufferpointer;
readfilefw (tapebufferf lag, &tapebufferpointer, tapebufferstop);
tapepointer = 10.
tapeintr = 1
}
else
{
tapebufferstop = 0×fffe;
tapeblkpointer- -;
t apepo i nt er = tapepointer + (0×100001 - tapebuf ferpointer + 0×400); readf i lefw (tapebuf ferflag, &tapebuf ferpointer, tapebufferstop); if (tapebufferf lag = 0) tapebijfferflag = 1;
else tapebufferfl ag =0;
datacurrent = 0;
tapeintr = 2;
tapebufferinit();
tapefwptr();
}
}
if ((tapeintr = 2) & (scsiintr = 1) & (datacurrent = 0) ) s cs i i nt r = 10;
}
}
tapereadreverse()
{
if (datacurrent = 0) tapeintr = 2;
if (tapeblkpointer = 01) tapestart ();
else
{
i f (tapefmpo inter 0) tapefmpointer++;
t aperdfmptr();
i f ( 10 = t apepo i nt e r )
{
t apestatus = tapestatus ¦ 0×20;
tapefrnpointer- -;
}
e l s
{
if (( (tapeintr = 1) ¦ (tapeintr = 2)) & (datacurrent = 1))
{
if (tapebufferblkptr > 0×200;
{
tapeblkpointer- -;
taperdblkptr();
t apebuf ferstop = tapebuf ferpointer - (tapepointer - 10;
readfilerev (tapebuf fer flag, &t apebufferpointer tapebufferstop) tapepointer = I0;
tapeintr = 1;
}
els
{
tapebuf ferstop = 0×400;
tapepointer = tapepointer - tapebuf ferpointer + 0×400
readfilerev (tapebuf ferf lag. &tapebufferpoιnter, tapebufferstop; i f (tapebufferflag = 0) tapebufferflag - 1.
e Ise tapebufferflag = 0;
datacurrent = 0;
tapeintr = 2;
tapebuf f erini t ();
t aperevptr();
}
}
}
}
tapestatus = tapestatus & 0×fbff /* Turn off load point */ if ((tapeintr = 2) & (scsiintr = 1) & (datacurrent = 0)) scsiintr = 11; }
tapewrιte()
{
if ((tapeintr = 1 ) & (datacurrent = 0;) datacurrent = 1;
if (((tapeintr = 1) ! (tapeintr = 2)) & (datacurrent = 1))
{
tapebufferstop = tapebuf ferpointer;
wr netape (tapebufferf lag. &tapebufferpo inter);
if (tapebuf ferpointer =0)
{ tapeblkpointer++;
17 = tapepointer;
tapepointer = 01;
tapewrtblkptr();
tapeblkpointer- -;
tapepointer = 17;
tapepointer = tapepointer + (0×100001 . tapebufferstop + 0×400); if (tapebufferflag =0) tapebufferflag=1;
else tapebufferflag = 0;
tapebufferinit();
tapefwptr();
datacurrent = 0;
tapeintr = 2:
}
else
{
tapepo i nt e r = tapepointer + (tapebutferpointer - tapebufferstop) tapeblkpointer++;
tapewrtblkptr();
tapeintr = 1;
}
}
if ((tapeintr = 2) & (scsiintr = 1) & (datacurrent = 0)) scsiintr = 20; tapestatus = tapestatus & 0×fbff; /* Turn off load point */
)
tapewritefm()
{
tapefmpointer++,
tapewrtfmptr();
tapestatus = tapestatus ! 0×20;
tapestatus = tapestatus & 0×fbff; /* Turn off load point */}
tapeerasevari()
{
}
tapeerasefixed()
{
}
tapeerasesecure()
{
}
tapespaceforward()
{
if ((tapeintr = 1) & (scsiintr = 1))
{
taperdblkptr():
I1 = 10;
if (tapefmpointer =- 0) tapefmpoi nter-t-+;
tapeblkpointer++; /* Increment tape pointer */ taperdblkptr(),
if ((tapebutferpointer + (10 - I1)) > 0×100001)
{
tapebufferinit();
tapefwptr();
datacurrent = 0:
}
else tapebutferpointer = tapebutferpointer + (10 - I1);
taperdfmptr():
if(I0 = tapepointer)
{
tapestatus = tapestatus ¦ 0×20; tapefmpointer++;
}
tapestatus = tapestatus & 0×fbff; /* Turn off load point */ scsiintr = 40,
tapeintr = 2;
}
if ((tapeintr = 2) & (scsiintr = 1)) tapeintr = 1;
}
tapespacereverse()
{
if ((tapeintr = 1) & (scsiintr = 1))
{
taperdblkptr();
I1 = 10,
if (tapeblkpointer != 0)
{
tapeblkpointer- -, /* Decrement tape pointer */
taperdblkptr(),
if ((tapebutferpointer • (II . 10)) < 0×4001)
{
tapebuf fer ini t ();
taperevptr();
datacurrent = 0;
}
else tapebuf ferpo int er = tapebuf ferpointer • (10 • II;,
i f (tapefmpointer != 0)
{
taperdfmptr (),
i f(10 = tapepointer)
{
tapestatus = tapestatus ¦ 0×20;
tapefmpointerr -;
}
}
}
if (tapeblkpointer = 0) tapestart ();
scsiintr = 41;
tapeintr = 2;
}
if ((tapeintr = 2) & (scsiintr = 1)) tapeintr =1; tapef 11 eforward()
{
if (datacurrent = 0) tapeintr = 2;
tapestatus = tapestatus & 0×fbff, /* Turn off load point */ if (tapefmpointer = 0) tapefmpoιnter++
taperdfmptr (),
if (10 != tapepointer)
{
if (((tapeintr = 1; ¦ (tapeintr = 2)) & (datacurrent = 1))
f
tapeblkpoιnter++
taperdblkptr().
if ((10 - tapepointer) < (0×100001 - tapebutferpointer + 0×400))
{
tapebufferstop = (10 - tapepointer) + 0×400
readfilefw (tapebuf ferf lag, &tapebuf ferpointer tapebufferstop); tapepointer = 10;
tapeintr = 1
}
else
{
tapebufferstop = 0×fffe
tapepointer = tapepointer + (0×100001 - tapebufferpointer + 0×400) readfiIefw (tapebufferflag, (tapebufferpointer, tapebufferstop);
tapeintr = 2;
tapebuffer init();
tapefwptr();
}
}
tapestatus = tapestatus ¦ 0×20;
}
if ((tapeintr = 2) & (scsiintr = 1) & (datacurrent = 0)) scsiintr = 10; }
tapef i leforwardi ()
{
if ((tapeintr = 1) & (scsiintr = 1))
{
taperdfmptr();
I1 = 10;
tapefmpointer++;
taperdfmptr();
if ((tapebufferpointer + (10 - I1)) > 0×100001)
{
tapebutferpointer = 0×400;
datacurrent = 0;
}
else tapebutferpointer = tapebutferpointer + (10 - I1);
tapepointer = 10;
tapestatus = tapestatus & 0×fbff; /* Turn off load point */ tapestatus = tapestatus ' 0×20;
scsiintr = 40;
tapeintr = 2;
}
if ((tapeintr = 2) & (scsiintr = 1)) tapeintr = 1;
}
tapefilereverse()
{
if (datacurrent = 0) tapeintr = 2;
if (tapeblkpointer =0) tapestart();
else
{
if (tapefmpointer != 0)
{
taperdfmptr();
if (10 != tapepointer)
{
if (((tapeintr = 1) | (tapeintr = 2)) & (datacurrent = 1))
{
tapeblkpointer--;
taperdblkptr();
if (tapepointer - 10 < tapebutferpointer - 0×400)
{
tapebufferstop = tapebutferpointer - (tapepointer - 10);
readfilerev (tapebufferf Iag. &tapebuf ferpointer, tapebufferstop): tapepointer = 10;
tapeintr = 1;
}
else
{
tapebufferstop = 0:
tapepointer = tapepointer - tapebutferpointer + 0×400; readfilerev (tapebufferflag, &tapebufferpointer, tapebufferstop), if (tapebufferf lag = 0) tapebufferf lag = 1;
else tapebufferflag = 0,
datacurrent = 0;
tape i nt r=2;
tapebufferinit(); taperevptr(),
}
}
else if (tapeintr = 1) tapestatus = tapestatus ¦ 0×20,
}
}
tapestatus = tapestatus & 0×fbff, /* Turn off load point */ if ((tapeintr = 2) & (scsiintr = 1) & (datacurrent = 0)) scsiintr =11; }
}
tapefilereversei ()
{
if ((tapeintr = 1) & (scsiintr = 1))
{
taperdfmptr(),
II = 10,
if (tapefmpointer != 0)
{
if (tapeintr = 1) tapepointer « 10,
tapestatus = tapestatus J 0×20,
tapefmpointer- -,
taperdfmptr(),
if ((tapebutferpointer • (I1 - 10)) < 0×41)
{
tapebuf ferinit(),
taperevptr(),
datacurrent = 0,
}
else tapebutferpointer = tapebutferpointer - (I1 - 10)
}
tapeintr = 2;
scsi intr = 41,
}
if ((tapeintr = 2) & (scsiintr = 1)) tapeintr = 1,
}
tapewr itesync()
{
}
tapehidens()
{
}
tapestddens()
{
}
/***************************************************************************
SCSI reset ()
Function that resets SCSI bus (as initiator)
**************************************************************************/
SCSI reset ()
{
writeiob (SCSIcontrol + 0×2, 0×80),
i0 = 0.
whi le (i0 < 0×8)
{
writeiob (SCSIcontrol + i 0*2. 0×0),
i0++.
} i0 = 0;
readdate (0×0);
c7 = c0;
while (i0 < 10)
{
readdate (0×a);
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×0);
if (c7 != c0) i0++;
c7 = c0,
}
/***************************************************************************
SCSIcommand()
Function that initiates SCSI coininand (as initiator)
SCSI coinmand is located in drivecommand variable
Command buffer located in CommandBuffer array
Number of command bytes in dr ivecoinmandbytes variable
***************************************************************************/ SCSI command ()
{
writeiob (SCSIcontrol + 0×4, 0×4);
writeiob (SCSIcontrol +0×6, 0×2);
i0 = 0;
while (i0 != dr ivecoinmandbytes) /* While bytes to do */
{
readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8, &c0); /* WAIT */ readiob (SCSIcontrol + 0×a, &c0); /* Read BSR for phase match */ if ((c0 & 0×8) = 0)
{
SCSIerror = 1; /* test for phase error */
goto scexit;
}
writeiob (SCSIcontrol, CominandBuf fer [i0]); /* load in cominand */ writeiob (SCSIcontrol + 0×2, 0×l); /* set ACK in ICR bit 4 */ writeiob (SCSIcontrol + 0×2, 0×ll); /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) != 0) readiob (SCSIcontrol + 0×8, &c0); /* WAIT */ writeiob (SCStcontrol + 0×2, 0×0); /* clear ACK in ICR bit 4 */ i0++,
}
scexit:
return;
}
/***************************************************************************
SCSImessageout()
Function that initiates SCSI message (as initiator)
SCSI message is in cl
***************************************************************************/
SCSImessageout ()
{
writeiob (SCSIcontrol + 0×4, 0×4);
writeiob (SCSIcontrol +0×6, 0×6);
i0 = 0;
readiob (SCSIcontrol + 0×8, &c0); while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8, ic0); /* WAIT */ readiob (SCSIcontrol + 0×a, &c0); /* Read BSR for phase match */ it ((c0 & 0×8) = 0)
{
SCSIerror = 1; /* test for phase error */
goto smoexit,
}
writeiob (SCSIcontrol, c1); /* load in command */
writeiob (SCSIcontrol + 0×2, 0×l); /* set ACK in ICR bit 4 */ writeiob (SCSIcontrol + 0×2, 0×13), /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) '= 0) readiob (SCSIcontrol + 0×8, &c0) /* WAIT */ writeiob (SCSIcontrol + 0×2. 0×0), /* clear ACK in ICR bit 4 "/ smoexit;
return;,
}
/**************************************************************************
SCSImessagein()
**************************************************************************/
SCSImessagein ()
{
writeiob (SCSIcontrol + 0×4. 0×4)
writeiob (SCSIcontrol + 0×6 0×7),
i0 = 0,
readiob (SCSIcontrol + 0×8, &c0),
while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8. &c0), /* WAIT */ readiob (SCSIcontrol + 0×a, &c0), /* Read BSR for phase match */ if ((c0 & 0×8) = 0)
{
SCSIerror = 1, /* test for phase error */
goto smiexit,
}
readiob (SCSIcontrol, &c5)* /* load in command »/
writeiob (SCSIcontrol + 0×2, 0×10), /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0),
while ((c0 & 0×20) '= 0) readiob (SCSIcontrol + 0×8, &c0) /* WAIT */ writeiob (SCSIcontrol + 0×4, 0×0);
writeiob (SCSIcontrol + 0×2, 0×0), /* clear ACK in ICR bit 4 */ writeiob (SCSIcontrol + 0×6, 0×0), /* clear ACK in ICR bit 4 */ writeiob (SCSIcontrol + 0×8, 0×0); /* clear ACK in ICR bit 4 */ smiexi t
return,
}
/************************************************************************** SCSistatus()
* *************************************************************************/
SCSistatus()
{
writeiob (SCSIcontrol + 0×4 0×4);
writeiob (SCSIcontrol + 0×6 0×3);
i0 = 0
readiob (SCSIcontrol + 0×8, &c0); while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8, &c0); /* WAIT */ readiob (SCSIcontrol + 0×a, &c0); /* Read BSR for phase match * / if ((c0 & 0×8) = 0)
{
SCSIerror = 1; /* test for phase error /
goto ssexit;
}
readiob (SCSIcontrol, &c1); /* load in command */
writeiob (SCSIcontrol + 0×2, 0×10); /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0); •
while ((c0 & 0×20) != 0) readiob (SCSIcontrol + 0×8, &c0); /* WAIT */ writeiob (SCSIcontrol + 0×2, 0×0): /* clear ACK in ICR bit 4 */ ssexit;
return;
)
/**************************************************************************
SCSIselect()
Function provides arbitration and reseletion of SCSI device
***************************************************************************/
SCS I se l ect()
{
s0:
c3 = 0;
writeiob (SCSIcontrol, 0×80); /* own SCSI ID */
writeiob (SCSIcontrol + 0×4, 0×l); /* Set bit 0 */
readiob (SCSIcontrol + 0×2, &c0); /* read bus status */ while ((c0 & 0×40) = 0) readiob (SCSIcontrol + 0×2, &c0); /* Bus Free */ readiob (SCSIcontrol + 0×2, &c0); /* read bus status */ if ((c0 & 0×20) !** 0)
{
writeiob (SCSIcontrol + 0×4, 0×0); /* Set bit 0 */
c3 = 1;
goto sO;
}
readiob (SCSIcontrol, &c4); /* Get SCSI ID */
if ((c4 & 0×7f) != 0)
{
c3 = 1;
writeiob (SCSIcontrol -t 0×4, 0×0), /* clear bit 0 */
goto s0;
}
readiob (SCSIcontrol + 0×2, &c0);
c0 = c0 & 0×1f;
writeiob (SCSIcontrol, (0×81)); /* load in drive select * / writeiob (SCSIcontrol +0×2. 0×7) /* set dbus & sel */
writeiob (SCSIcontrol + 0×8. 0×0) /* clear SER */
writeiob (SCSIcontrol + 0×4, 0×0); /* c1ear bit 0 */
readdate (0×a);
while (c0 = 0×80) readdate (0×a): /* Wait tor update to be false */ readdate (0×0).
c7 = c0;
readiob (SCSIcontrol + 0×8, &c0); /* read bus status */ i0 = 0:
whi le ((c0 & 0×40) = 0×0)
{
readdate (0×a);
while (c0 = 0×80) readdate (0×a); /* Wait for update to be false */ readdate (0×0);
if (c0 != c7) i0++;
c7 = c0.
if (i0 > 10) break; readiob (SCSIcontrol + 0×8, 4c0); /* tst BSY */
}
if (i0 < 10)
{
SCSIpresent = 1,
writeiob (SCSIcontrol + 0×2, 0×2), /* reset dbus, sel*/
}
if (i0 > 10)
{
SCSIpresent = 0,
i1 = 0,
while (il < 0×8)
{
writeiob (SCSIcontrol + ιl*2, 0×0),
ι1++,
}
}
}
/**************************************************************************
SCSI reselect ()
Function provides reseletion of SCSI device
**************************************************************************/
SCSI resel ect ()
{
writeiob (SCSIcontrol + 0×8, 0×80), /* set ID for reseletion */ writeiob (SCSIcontrol + 0×6, 0×l), /* set I/O bit for phase match */ readiob (SCSIcontrol + 0×8, &c1),
while ((c1 & 0×46) ι= 6) readiob (SCSIcontrol + 0×8, &c1)
writeiob (SCSIcontrol + 0×2 0×8) /* reset dbus sel*/
writeiob (SCSIcontrol +0×8, 0×0), /* set ID for reseletion */ readiob (SCSIcontrol + 0×8, &c0),
while ((c0 & 0×2) = 0×2) readiob (SCSIcontrol + 0×8, &c0),
writeiob (SCSIcontrol + 0×2, 0×0), /* reset dbus sel*/
SCSImessagein(),
SCSistatus(),
SCSImessagein()
}
/***************************************************************************
SCSIread()
Function that reads a specified number of bytes from
the target via programed I/O SCSIDataBuf fer is used
to store the data
Number of command bytes in dr ivecommandbytes variable
**************************************************************************/ SCSIread ()
{
writeiob (SCSIcontrol + 0×4 0×4),
writeiob (SCSIcontrol + 0×6 0×l)
i0 = 0
while (i0 ι= dr ivecommandbytes) /* While bytes to do */
{
readiob (SCSIcontrol + 0×8 &c0)
while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8 &c0) /* WAIT */ readiob (SCSIcontrol + 0×a &c0) /* Read BSR for phase match */ if ((c0 & 0×8) = 0)
{ SCSIerror = 1; /* test for phase error */
goto srexit;
}
readiob (SCSIcontrol, &SCSIdatabuffer[i0]); /* load in cominand */ writeiob (SCSIcontrol + 0×2, 0×10); /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) != 0) readiob (SCSIcontrol + 0×8, &c0); /* WAIT */ writeiob (SCSIcontrol + 0×2, 0×0); /* c1ear ACK in ICR bit 4 */ i0++;
}
srexit:
return;
}
/***************************************************************************
SCSIwrite()
Function that writes a specified number of bytes from
the target via programed I/O. SCSIDataBuffer is used
to store the data.
Number of command bytes in dr ivecommandbytes variable
**************************************************************************/
SCSIwrite ()
{
writeiob (SCSIcontrol + 0×4, 0×4):
writeiob (SCSIcontrol + 0×6, 0×0),
i0 = 0;
while (i0 != dr ivecommandbytes) /* While bytes to do */
{
readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8. &c0): /* WAIT * / readiob (SCSIcontrol + 0×a, &c0); /* Read BSR for phase match */ if ((c0 & 0×8) = 0)
{
SCSIerror = 1; /* test for phase error * /
goto swexit;
)
writeiob (SCSIcontrol, SCSIdatabuf fer[i0]); /* load in command */ writeiob (SCSIcontrol + 0×2, 0×l); /* set ACK in ICR bit 4 * / writeiob (SCSIcontrol + 0×2, 0×ll); /* set ACK in ICR bit 4 */ readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) != 0) readiob (SCSIcontrol + 0×8, &c0), /* WAIT */ writeiob (SCSIcontrol + 0×2, 0×0); /* clear ACK in ICR bit 4 -I
Ϊ0++;
}
swexit:
return;
}
SCSIdmaend ()
{
writeiob (SCSIcontrol + 0×4, 0×4);
readiob (SCSIcontrol + 0×8, &c0);
while ((c0 & 0×20) = 0) readiob (SCSIcontrol + 0×8, &c0): I* WAIT */ writeiob (SCSIcontrol + 0×2, 0×0); /* clear ACK in ICR bit 4 */
}
SCSIdmareadstart ()
{
dmaread (tapebuf ferf lag, buffersize);
writeiob (SCSIcontrol + 0×2, 0×0);
writeiob (SCSIcontrol + 0×6, 0×0); writeiob (SCSIcontrol + 0×4, 0×6); writeiob (SCSIcontrol + 0×e, 0×0), }
SCSIdmawri testart ()
{
dmawrt (tapebuf ferf lag, buffersize); writeiob (SCSIcontrol + 0×2, 0×1); writeiob (SCSIcontrol + 0×6, 0×0); writeiob (SCSIcontrol + 0×4, 0×6); writeiob (SCSIcontrol + 0×a, 0×0); }
toshibareadcapaci ty()
{
dr ivecommandbytes = 10;
CommandBuffer[0] = 0×25;
CommandBuffer [1] = 0×0;
CommandBuffer[2] = 0×0;
CommandBuffer [3] = 0×0;
CommandBuff er [4] = 0×0;
CommandBuffer [5] = 0×0;
CommandBuffer [6] = 0×0;
CommandBuffer [7] = 0×0;
CommandBuffer[8] = 0×0;
CommandBuffer [9] = 0×0;
SCSIerror = 0;
SCSIselect();
c1 = 0×80
SCSImessageout();
SCSI commando;
dr ivecommandbytes = 8;
SCSIread();
SCS i st at us();
SCS Imessagein();
}
toshιbastart()
{
dr ivecommandbytes = 6;
CommandBuffer [0] = 0×1b;
CommandBuffer [1] = 0×1;
CommandBuffer[2] = 0×0;
CommandBuffer [3] = 0×0;
CommandBuffer [4] - 0×l;
CoinmandBuffer[5] = 0×0;
SCSIerror = 0;
SCSIselect();
c1 m 0×80;
SCSImessageout();
SCSI commando;
SCSistatus();
SCSImessagein();
}
toshιbastop()
{
drivecommandbytes = 6;
CommandBuffer [0] = 0×1b;
CommandBuffer [1] = 0×1;
CommandBuffer[2] = 0×0.;
CommandBuffer [3] = 0×0;
CommandBuffer [4] = 0×0;
CommandBuffer [5] = 0×0;
SCSIerror = 0
SCSIselect() c1 = 0×80;
SCS Imessageout();
SCS I command() ;
SCSistatus();
SCS Imessage i n();
}
toshibaready()
{
dr ivecommandbytes = 6;
CommandBuffer [0] = 0×0;
CommandBuffer[1] = 0×0;
CommandBuffer[2] = 0×0;
CommandBuf fer [3] = 0×0;
ConτnandBuffer[4] = 0×0;
CommandBuffer[5] = 0×0;
SCSIerror = 0;
SCSIselect():
if (SCSIpresent = 1)
{
c1 = 0×80;
SCSImessageout();
SCSI command();
SCSistatus();
SCSImessagein();
}
}
toshibaread()
{
diskdone = 1;
}
toshibawr i te()
{
diskdone = 1;
}
scsirwend()
{
SCSIdmaend();
SCSistatus();
SCSImessagein();
scsi int r = 1.
}
scsirdmacheck()
{
dmastatus (&i0);
if ((i0 & 0×2) = 0) scsiintr = 3; )
scsiwdmacheck()
{
dmastatus (&i0);
if ((i0 & 0×2) = 0) scsiintr = 5; }
scsiseek()
{
10 = diskcurrentblock;
c1 = I0 & 0×ff;
11 = I0 / 2561;
c2 = I1 & 0×ff;
12 = I1 / 2561;
c3 = 12 & 0×ff, 13 = 12 / 2561;
c4 = 13 & 0×ff,
drivecommandbytes = 10;
CoπinandBuffer [0] = 0×2b;
CommandBuffer[1] = 0×0;
CommandBuffer [2] = c4;
CoirinandBuf fer [3] = c3;
CommandBuffer [4] = c2;
CommandBuffer [5] = c1;
CommandBuffer [6] = 0×0;
CommandBuffer [7] = 0×0;
CommandBuffer [8] = 0×0;, CommandBuffer[9] = 0×0;
SCSIerror = 0;
SCSIselect();
c1 = 0×c0,
SCSImessageout();
SCSIcommand();
SCSImessagein();
SCSI reseIect ();
}
scsireadbufstrt ()
{
buffersize = 0×8000.
dr ivecommandbytes = 10;
CommandBuffer [0] = 0×3c;
CommandBuffer[1] = 0×1
CommandBuffer[2] = SCSIbufferflag CommandBuffer[3] = 0×0;
CommandBuffer[4] = 0×0;
CommandBuf fer[5] = 0×0;
CommandBuf fer [6] = 0×0;
CommandBuf fer [7] = 0×80;
CommandBuf fer [8] = 0×0;
CommandBuf fer [9] = 0×0;
SCSIerror = 0;
SCSIselect();
c1 = 0×80,
SCSImessageout();
SCSIcommand();
SCSIdmareadstart();
scsiintr = 2,
}
scsiwrtbufstrt ()
{
buffersize = 0×8000;
dr iveconriandbytes = 10;
CommandBuffer [0] = 0×3b;
CommandBuffer [1] = 0×1
CommandBuffer[2] = SCSIbufferflag
CommandBuffer[3] = 0×0;
CommandBuffer [4] = 0×0;
CommandBuffer [5] = 0×0;
CommandBuffer [6] = 0×0;
CommandBuffer [7] = 0×80;
CommandBuffer [8] = 0×0;
CommandBuffer [9] = 0×0;
SCSIerror = 0;
SCSIselect();
c1 = 0×80;
SCSImessageout();
SCSIcommand();
SCSIdmawritestart ()
scsiintr = 4; }
scsif low()
{
if (scsiintr = 4) scsiwdmacheck();
if (scsiintr = 5)
{
scsirwend();
if (diskdone = 0) toshibawr i te();
datacurrent = 1;
}
if (scsiintr = 3)
{
scsirwend();
datacurrent = 1;
)
if (scsiintr =2) scsi rdmacheck();
if (scsiintr = 10)
{
/* if (diskdone = 0) toshibaread();
it (diskdone χ= 1) scsireadbufstrt(); * /
disklogical++;
drtychk ((dιsklogical*2), &i0);
diskcurrentblock = (i0 * 32) + (((tapenumber - l)*tapesιze)/131072); diskreadptr - diskreadptr + 0×200001;
diskpointer = diskpointer + 0×200001;
scsiseek();
tapebuf ferinit();
datacurrent = 1;
scsi int r = 1;
}
i f (scsi intr = II)
{
/* if (diskdone = 0) toshibaread();
if (diskdone == 1) scsi readbufst rt (); */
disklogical--;
drtychk ((disklogical*2), &10);
diskcurrentblock = (i0 * 32) + (((tapenumber - l)*tapesize)/131072), diskreadptr = diskreadptr - 0×200001;
diskpointer = diskpointer - 0×200001;
scsiseek();
tapebuf fer init();
datacurrent = 1;
scsi intr = 1;
}
if (scsiintr = 20)
{
disklogical++;
i0 = diskwriteptr/131072;
if (diskpointer < diskwri teptr) drtyload ((disklogical*2), i0); drtychk ((disklogical*2), &i0);
diskcurrentblock = (i0 * 32) + (((tapenumber - 1)*tapesize)/131072), diskwriteptr = diskwriteptr + 0×200001;
diskpointer = diskpointer + 0×200001;
/* scsiwrtbufstrt(); */
scsiseek();
tapeprevcommand = 0;
datacurrent = 1;
scsi intr = 1;
}
if (scsiintr = 30)
{
f0 = ((tapenumber - l)*tapesize)/131072. :
disklogical = f0:
f1 = 1024.;
f2 = 4096.: f3 - disklogical,
f4 = 131072 ,
f0 m (f3*f4) + (fl«f2);
diskcurrentblock = (0/4096 ;
diskreadptr - f0,
diskpointer = f0;
/* scsiwrtbufstrt(), */
scsiseek(),
scsiint r = 1;
}
if (scsi intr = 40)
{
diskpointer = diskpointer + 0×200001;
/* scsiwrtbufstrt(), */
scsi intr -= 1
if (scsi intr -=- 41)
{
diskpointer = diskpointer - 0×200001
scsi intr = 1,
}
}
diagnost ιcs()
{ serialport()
{ errorrecover ()
{ findlastdate()
{
} ************************************************************************ ;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; START-UP MODULE for Controller FIRMWARE
;
; Copyright 1990 PBT Technologies
;
;
; Designed for CC8086 C Cross Compiler SMALL MODEL
; This module must be the FIRST ONE to be linked
;
;************************ IMPORTANT NOTICE ********************************** ; **** In order to provide three symbols (MAIN lOCALL and lODATA); **" necessary for terminal I/O operations to DBI86, the start-up; **** module MUST be assembled always with Is option
; i.e. as i86 /s-u cbox i86
; ****************************************************************************
TRUE equ 1
FALSE equ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; ROMABLE
; if TRUE, initializes all uninitialized variables (C variables ; without initializer; e.g. "unsigned char a;") to
; zeros at execution time,
; ; if FALSE, uninitialized C variables are set to zeros at load time. ROMABLE equ TRUE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; MEMORY_FUNCS USED
; if TRUE, activates definitions of memory allocation variables ; referenced by memory allocation functions (calloc
; free, ma 11 oc functions)
; if FALSE, deactives definitions of memory allocation variables ; ( moat, base, allocp. free).
MEMORY_FUNCS_USED equ FALSE
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; PROGRAM_RUN_MODE
; if AADEBUGGER_RUN, activates terminal (console) I/O via RS232 link when ; running in an AA emulator for use by sscanf, print f .
; qprintf etc.
; if PRODUCT ION_RUN, deactivates terminal (console) I/O used for debugging ; purpose.
AADEBUGGER_RUN equ
PRODUCTION_RUN equ
PROGRAM_RUN_MODE equ AADEBUGGER_RUN
; *************************************************************************** ; S E GM E N T S
; ***************************************************************************
_BSS segment word public 'bss'
_BSS ends
BSS_ND segment word publ ic 'bss'
BSS_ END ends
_ DATA segment word public 'data'
_DATA ends
DATA_END segment word public 'data'
DATA_END ends
FAR_BSS segment word public 'data'
FAR_BSS ends
FAR_DATA segment word public 'data'
FAR_DATA ends
STACK segment word publ ic 'stack'
STACK ends
STACK_END segment word public 'stack'
STACK END ends
_ TEXT segment word publ ic 'code'
_TEXT ends
CONST segment word publ ic 'cnst '
CONST ends INITIAL segment word public 'init'
INITIAL ends
dgroup group _BSS, BSS_END,_DATA, DATA_END, FAR_BSS, FAR_ATA, STACK, STACK_END cgroup group _TEXT, CONST, INITIAL
assume cs: cgroup, ds: dgroup, ss: dgroup
; *************************************************************************** ; _ B S S S E GM E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; The _BSS segment defines the 64k RAM space
;
_BSS segment public 'bss '
_bss dw ?
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;AA Debugger Interface variables
; lODATA is used to transmit a tunction and a data byte to Emu later
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
IF (PROGRAM_RUN_MODE EQ AADEBUGGER_RUN)
public IODATA
lODATA dw 1 dup (*) ,used as mailbox to lOCALL function ENDIF
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;Float/double software stack
; each entry is 12 bytes long
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public _fstk
_fstk db 240 dup (') ; sufficient for 20 entries
_fstkz db ?
_BSS ends
. ***************************************************************************
; B S S _ E N D S E G M E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; The BSS_END is used to indicate the end of the BSS segment
; The segment must be linked immediately after the BSS segment
;
BSS_END segment publ ic 'bss'
_bssz dw ?
BSS_END ends
; ***************************************************************************
; _D A T A S E GM E N T
; The _DATA segment is the template ot data memory for initialized
; variables and constants
;
_DATA segment publ ic data'
_ data dw ?
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Float/double arithmetic variables
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _ fsp
_ fsp dw 1 dup (?) contains TOS address of float/double stacr; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;Storage Allocator variables - used by malloc, free calloc etc
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; IF (MEMORY_FUNCS_USED)
publ ic _moat _base, _allocp, _free
_moat dw 1 dup (?) ; minimum separation between stack and heap _base dw 2 dup (?) ; empty list to get started
_al locp dw 1 dup (?) ; last al located block
_free dw 1 dup (?) ;where heap allocation may begin
ENDIF
_ DATA ends
; *************************************************************************** ; D AT A_ E N D S E GM E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; DATA_END points to the end od _DATA segment and is used along with
; INITIAL to move initialized data from INITIAL segment to _DATA
; segment. Segment DATA_END must be linked immediately attϊr the
; _DATA segment.
DATA_END segment public 'data'
_dataz dw ?
DATA_END ends
;*************************************************************************** ; F A R_ D A T A S E G M E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -; The FAR_DATA segment defines the far data space
;
FAR_DATA segment public 'data'
_ fardata dw ?
FAR_DATA ends
; ***************************************************************************; I N I T I A L S E GM E NT
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -; The INITIAL segment contains the values used to initialize the
; _DATA segment.
;
INITIAL segment public 'init'
_init dw ?
dw _fstkz ;_fsp - initial value
IF (MEMORY_FUNCS_USED)
dw 1000 ;_moat - size of moat between heap and stack dw 0 ;_base - initial value
dw 0 ;_base+2 - initial value
dw 0 ;_allocp - initial value
dw _heap ;_free
ENDIF
N1TIAL ends
IF (MEMORY_FUNCS_USED)
; ***************************************************************************; H E AP S E GMENT
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -; The HEAP segment is used to initialize "_free" indicating the beginning ; of available heap space. The maximum amount of space available for heap; is defined by the area between _heap and (actual sp minus jnoat).
; _moat is the amount of minimum separation between heap and stack.
;
segment HEAP. WORD, DATA
_heap dw ?
ENDIF
; ***************************************************************************; S T A C K S E G M E N T
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; The STACK segment is used to def ine the stack space ; Note that this origin is the top of the stack
;
STACK segment public 'stack'
public SP
_SP dw 1024 dup (?)
STACK ends
; *************************************************************************** ; S T A C K_E N D S E GM E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; The STACK_END segment is used to initialize the SP register
; Note that~thιs origin is the bottom of the stack and the stack will ; grow to LOWER memory locations Therefore there must be sufficient ; amount of memory allowed for possible stack growth
;
STACK_END segment public 'stack
public _SPZ
_SP2 dw
STACK_END ends
; *************************************************************************** ; T E X T S E G M E N T
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ; , The _TEXT segment de f i nes t he code spac e i n ROM
_TEXT s egment pub l i c ' code ' ; *************************************************************************** ; Initialize UMCS for 80C186 with 3 wait states
; RDY ignored since this is PROM we are accessing
; Must do this before processor recognizes
; the rest of the startup code
;*************************************************************************** org 0fff0h
publiC PWRON
PWRON proc near
mov dx.OffaOh
mov ax, Of03fh Set up EPROM for 3 wait states
out dx, ax
; *************************************************************************** ; Jump to MAIN routine for power-up diagnostics and
; setting MCS. PCSO thru 5 etc
+;*************************************************************************** imp far ptr MAIN
PWRON endp
; ***************************************************************************; Reset internal program counter
; *************************************************************************** org Oh
public MAIN
extrn _ main near .reference to compiler-generated main function
MAIN proc near
;*************************************************************************** ; Set LCS for 2S6K window DO NOT set MCS
; Also set for all 7 PCS lines mapped into ; MEMORY space
; *************************************************************************** mov dx,0ffa2h
mov ax,03f(Eh ; use ready input (0 wait states)
out dx, ax
; ***************************************************************************
; Set MCS start at 0 segment (DRAM always mapped
; to 0000:0000
; *************************************************************************** mov dx, 0f fa8h
mov ax, 01ffh; set MCS2 to start at c000 segment
out dx, ax ; set MCS size to 1024, this means mov dx, 0ffa6h ; MCS2 is mapped to c1000
mov ax, 0c1ffh
out dx, ax
; ***************************************************************************; Set MDRAM and CDRAM registers to begin DRAM
; refresh. Since we are using 1 MBit DRAMs we need
; to generate a refresh cyc1e every 15 usec. This
; relates to the main system clock (§16MHz. ) as
; 120 CLKOUT cycles for 10 MHz. system one needs 74
; CLKOUT cycles.
; *************************************************************************** mov dx, 0ffe0h
mov ax, 0h
out dx, ax
mov dx, 0ffe2h ; set number of CLKOUT cycles
mov ax, 04ah ; 4ah for 10MHz: 78h for 16Mhz.
out dx, ax
mov dx, 0ffe4h
mov ax, 080001 ; set memory size
out -dx, ax
; ***************************************************************************; Set PCS to start at segment 8000. Also set
; for 1 wait state operation RDY ignored
;*************************************************************************** mov dx,0ffa4h
mov ax, 0803fh
out dx, ax
; ***************************************************************************; Set LED status for PO diagnostics (01h)
; ********************************** **************************************** push ds
push di
mov ax,08000h ; get segment for Cajche Box 1/0
mov ds, ax
mov ax, 080h ; get LED offset
mov di, ax
mov ax.0le00h ; a 0 turns LED on
mov ds: [di], ax ; write LED
;***************************************************************************; Access DRAM 10 times to insure proper P0 sequence
; *************************************************************************** ax, 0h going to use 0 segment mov ds, ax
mov di, ax ; 0 index as wel 1
mov ax.ds: [di] ; access mult iple times before
mov ax, ds: [di] ; starting test
mov ax.ds: [di]
mov ax.ds: [di]
mov ax, ds: [di]
mov ax, ds: [di]
mov ax, ds: [di]
mov ax, ds: [di]
mov ax, ds. [di]
mov ax, ds:[di]
;************************************************************************** ; Begin DRAM test Write AAAA to Segment 0
;**************************************************************************** mov ax Oh ; 0 segment again
mov ds, ax
mov ax, Oh ; 0 offset
mov di, ax
mov ax.Oaaaah ; ax contains memory values
mov bx.Oaaaah ; bx used for comparison
r t s t lI mov ds: [d i ] , ax , write memory
inc di
inc di ; increment index
cmp di, Oh ; at end of segment?
jne rtstl ; no keep going
r t st 2 mov ax, ds [di] ; at end begin verification
cmp ax. bx
jne rerr1 ; error then loop forever
inc di
inc di ; increment index
cmp di.0h ; are we f inished*
jne rtst2 ; no
jmp rtst 3 ; yes
r e r r l push ds; ; we failed set 2 LEDs on
push di ; store off bad segment, offset
mov ax,08000h ; get Cafche Box I/O segment
mov ds, ax
mov ax, 080h ; get offset for LED
mov di, ax
mov ax.Ofc0Oh ; set 2 LEDs on
mov ds. [di], ax
pop di ; restore bad segment, offset
pop ds
rell mov ax, ds: [di] ; loop forever (for use of scope!) jmp rell
*****
; ***********************************************************************; Continue DRAM test Write 5555 to Segment 0
;**************************************************************************** rts13 mov ax, 0h ; 0 segement to be used
mov ds, ax
mov ax, 0h ; 0 offset as welI
mov di,ax
mov ax.05555h ; ax used for memory transfers
mov bx 05555h ; bx as compare value
rts14 mov ds;[dι].ax ; load memory
inc di
inc di ; increment index
cmp di. 0h ; done?
jne rtst4 ; no loop
rtst5 mov ax, ds [di] ; fetch value
cmp ax, bx ; does it compare? jne rerr2 ; no error
inc di
inc di ; increment index
cmp di, Oh ; are we done?
jne rtst5 ; no loop
jmp rtst6 ; yes cont inue
rerr2: push ds ; we have an error, save bad segment push di ; and bad offset
mov ax,08000h ; fetch Cajche Box I/O segment
mov ds, ax
mov ax,080h ; get LED offset
mov di, ax
mov ax.0f800h ; turn on 3 LEDs now
mov ds: [di], ax
pop di ; restore bad segment, offset
pop ds
rel2: mov ax, ds: [di] ; loop forever (for scope)
jmp rel2
rtst6; nop
; **************************************************************************** ; DRAM passes bit pattern test, lets try to boot
; main C program
; ****************************************************************************;
; Initialize sp (stack pointer) and bp (stack frame pointer)
;
mov ax, seg dgroup ; get segment register for stack
mov ss, ax
mov ds.ax ; data and stack are same group
mov es, ax
mov ax, offset dgroup: SPZ ; stack offset
mov sp, ax ; stack pointer
mov bp, ax ; aIso stack frame pointer
Set up initialized variables (e.g. int i =4;)
by moving the contents of segment INIT IAL(ROM) to segment DATA(RAM) mov di , offset dgroup:_data
mov si, offset cgroup:_init
push ds
mov ax, seg _init
mov ds, ax
mov bx, offset dgroup: dataz ; end of initted data area sub bx, di ; now ex contains the number of bytes shr bx.1
je ibyte
rep movsw
ibyte:
jne istop
movsb
istop:
pop ds restore ds
IF (ROMABLE)
;
; Clear all uninitialized variables to zero (e.g. int i;)
;
xor al.al
mov ex, offset dgroup:_bssz
mov di, offset dgroup:_bss
sub ex, di
rep stosb
ENDIF
;
; Call main() function ;
call near ptr main ; call compiler generated code
jmp short exit ; normal program termination
MAIN endp
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;_abort - Do in abnormal termination to the AA Debugger
;
; INPUT - input argument registers are as follows
; register bx contains the address'Of string to be outputted to terminal ;
; OUTPUT - does not return. It ¦umps to EXIT function
;
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public _abort
_abort proc near
IF (PROGRAM_RUN_MODE EQ AADEBUGGER_RUN)
mov al.lyte ptr cgroup: [bx] ;get char
cmp a 1.0
|e _abortend ; end of string
push ax , char to output
xor cx, cx ; terminal output code
push cx
call near ptr _bdos
add sp, 4
inc bx
imp short _abort ; loop back
_abortend
imp short exit
ELSE
; user must place his own abort code here
ret
END I F
_abort endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; _exιt - Return to American Automation Debugger
;
; INPUT - None
; OUTPUT - Does not return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public _exit
_exit proc near
IF (PROGRAM_RUN_MODE EQ AADEBUGGER_RUN)
mov ax, 0ffffh ; t e rmi nat i on code
mov word ptr dgroup: lODATA. ax , load terminator code FF imp short lOCALL
ENDIF
_aaexιt. imp short _aaexit
exit endp
IF (PROGRAM_RUN_MODE EQ AADEBUGGERJUN)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; _ungetc - Ungetch a char
;
; INPUT - argument contains the char to ungetch
; OUTPUT - return
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public _ungetc
_ungetc proc rfear
push bp mov bp, sp
mov al.byte ptr [bp+4]
mov byte ptr dgroup: I0DATA+1, a
mov sp.bp
pop bp
ret
_ungetc endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;; bdos? Interface to AA Emulation Executive (DB 186) from I/O routines
;
; sypnosis:
; int bdos ( int function code, int data);
;
; descr ipt ion:
; Library functions such as printt(), scant () , putc(), get c(), etc
; call bdos?() in order to perform terminal I/0.
;
; Within the AA Emulation Executive (DBI86), there is a mechanism
; called Run I/O, which actually performs the I/0 to the screen.
; Run I/O uses the Conditional Break facility in order to simulate
; character I/O from the target, across the RS232, to the screen on
; the host computer.
;
; Run I/O makes use ot two uppercase symbols, lOCALL and lODATA, which
; are defined in the BSI86S.S module. lOCALL specifies an address
; and lODATA specifies the function code and data.
;
; When the emulator detects the lOCALL address on the bus.
; a Conditional Break address-stop occurs. At this point. Run I/O
; looks for a function code at lODATA, and depending on the function
; code, it may also look for data at IODATA+1. After Run I/O
; completes its character I/O operation, the code in the library
; function resumes executing.
;
; input:
; the function code in the first argument is to be placed in lODATA.
; 0 = put a character to the console
; 1 = get a character from the console and echo it
; 2 = get a character from the console without echo
; 3 = check the console for recent keystroke
; 10 - set column cursor position
; 11 = set row cursor position
; 12 = c1ear screen
; 13 = enable erase to the end of line
; 14. = set color mode
; 15 = scrolI the screen
; 255 = exit to debugger control
;
; the data in the second argument is to be placed in IODATA+1,
; if the function code is 0 (put a character).
;
; output:
; returns fetched char in register al
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public bdos
bdos proc near
push bp
mov bp, sp
mov al, [bp+4] ; fund ion code
mov ah, [bp+6] ; data
mov byte ptr dgroup: lODATA, al
cmp a 1 , 0
jne bdos_ssip bdos_out;
mov byte ptr dgroup; 10DATA+1, ah
jmp short lOCALL
bdos_skip:
cmp al, 9 ; test for output
¦a bdos_out
bdos_in; ; do getch or getche
cmp byte ptr dgroup. IODATA+1, 0 ; see if any ungot data je I0CALL ; do io
bdos_rtn:
mov al, byte ptr dgroup: IODATA+1 ; return char in AX xor ah, ah
mov byte ptr dgroup IODATA+1, ah ;clear
pop bp
ret
_bdos endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; lOCALL - terminal I/0 call
;
; INPUT parameters are in
; (lODATA) is request code where
; 0 = put a character to the console
; 1 = get a character from the console and echo it
; 2 = get a character from the console without echo ; 3 = check the console for recent keystroke
; 10 = set column cursor position
; 11 = set row cursor position
; 12 = clear screen
; 13 = enable erase to the end of line
; 14 = set color mode
; 15 = scrolI the screen
; 255 m exit to debugger control
; (IODATA+1) contains a char to be outputted
;
; OUTPUT returns inputted char in (IODATA+1)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; nop ;guard against pre-fetch
nop
nop
nop
IOCALL proc near
nop
jmp short bdos_rtn
nop ;guard against pre-fetch
nop
nop
lOCALL endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; PBT Technologies driver routines
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; _writeiow (Register Offset, Value Written)
; Function to write the CA$CHE BOX I/O locations
; with word writes
;
;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _writelow
_writelow proc near push bp ; save segment and pointer push ds
mov bp, sp ; get stack pointer mov bx, word ptr [bp+6] ; get register offset mov ax, 80001) ; load Cajche Box I/0 segment mov ds, ax
mov ax, word ptr [bp+8] ; get value to be written mov ds: [bx], ax ; write value
mov sp. bp ; restore stack, segment pop ds
pop bp
ret return
_writeiow endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;
; readiow (Register Offset, {.Variable)
; Function to read the CA$CHE BOX I/O locations
; wi th word reads
;
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public_readiow
_readiow proc near
push bp save segment, stack pointers push ds
mov bp, sp
mov bx.word ptr [bp+6] ; get register offset mov ax.8000h ; load Ca$che Box I/0 segment mov ds, ax
mov ax, ds: [bx] ; read value
mov bx.word ptr [bp+8] ; fetch pointer to variable mov sp, bp
pop ds ; restore segment first mov ds: [bx], ax ; load value read
pop bp
ret ; return to caller
_ readiow endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; _writeiob (Register Offset, Value Written)
; Function to write the CA$CHE BOX I/0 locations
; with byte wr i tes
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public_writeiob
_writeiob proc near
push bp ; save stack, segment poinnters push ds
mov bp, sp
mov bx.word ptr [bp+6] ; get register offset mov ax, 80001) ; load Cajche Box I/0 segment mov ds. ax
mov al, byte ptr [bp+8] ; get value to write mov ds: [bx], al ; write value
mov sp. bp ; restore stack, segment pointers pop ds
pop bp
ret ; return to cal ler
_writeiob endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; _readiob (Register Offset, &Variable)
; Function to read the CAJCHE BOX I/0 locations
; with word reads
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public_ readiob _readiob proc near
push bp ; save stack, segment pointers push ds
mov bp. sp
mov bx.word ptr [bp+6] ; get register offset mov ax, 8000h ; load Cajche Box I/0 segment mov ds, ax
mov al, ds. [bx] ; read value
mov bx.word ptr [bp+8] ; get pointer to variable mov sp, bp
pop ds ; restore segement first mov ds [bx] al ; load read value into variable pop bp
ret ; return to caller
_readiob endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; wrtbuff (segment address offset value;
; Routine that writes into non-mapped 80186
; memory
;
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public _wrtbuff
_wrtbuff proc near
push bp ; save segment stack p push ds
mov bp, sp
mov ax, word ptr [bp+6] ; get segment
mov ds, ax
mov bx.word ptr [bp+8] ; get offset
mov ax, word ptr [bp+10] ; get data value
mov ds [bx], ax ; write data value mov sp, bp and segments
pop es
pop ds
mov ds [bx] ax ; write new tapepointer pop bp
ret ; return to cal ler
_writetape endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;
; _readf i lefw (buf f ersegment, &t apepo inter, tapefm[])
; Function to read data from specified buffer segment
; handshake then write data to the tape controller
; tapepointer is used as pointer into the 64K
; buffer tape(m[] as the stop value, le read data until
; tapepointer = tapefm[] Data is read in the forward
; direction (increment tapepointer)
;
;';;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; public_readfilefw
_readfilefw proc near
push bp ; save base pointer mov bp, sp ; save stack pointer mov bx.word ptr [bp+10] ; load tapepointer pointer mov dι,ds [bx] ; save in index pointer push ds ; save segments
push es
mov ax, 8000h ; get Catcne Box I/0 segment mov es, ax ; load in es
mov bx.word ptr [bp-ι-8] ; get buffer segment mov ax.bx
mov ds, ax ; load in ds
rf3 mov bx, 100h ; get tape data offset
mov ax, ds [di] ; read data from buffer mov es [bx] ax ; write data to tape controller inc di ; increment buffer pointer inc di
mov bx.0h ; get tape control offset mov ax, es: [bx] ; read old tape control
or ax,80c3h ul ine, read strobe
mov es: [bx], ax ; set read strobe
and ax,07fffh ; clear read strobe
mov es: [bx], ax ; output to tape control mov bx.word ptr [bp+12] ; load in stop value
cmp bx, di ; compare to current pointer je rf4 ; equal - must be done
jmp rf3 ; not equal get more data f4: mov ax, di ; done get ready to store tapepointer mov bx.word ptr [bp+10] ; get tapepointer pointer inov sp, bp ; restore stack pointer
pop es ; restore segments
pop ds
mov ds: [bx], ax ; load tapepointer variable pop bp
_ ret ; return to cal ler
readfilefw endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; _readfilerev (buf fersegment, &t apepointer, tapefm[])
; Function to read data from specified buffer segment,
; handshake, then write data to the tape controller.
; tapepointer is used as pointer into the 64K
; buffer. tapefm[] as the stop value, ie read data until
; tapepointer = tapefm[]. Data is read in the reverse
; direction (decrement tapepointer)
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _readfilerev
_readfilerev proc near
push bp ; save base pointer
mov bp.sp ; load stack pointer
mov bx.word ptr [bp+10] ; get tapepointer pointer mov di.ds: [bx] ; load tapepointer value into index push ds ; save segments
push es
mov ax,8000h ; get Cajche Box I/O segment
mov es. ax ; load into es
inov bx.word ptr [bp+8] ; get buffer segment
mov ax, bx
mov ds, ax ; load into ds
rfr3: mov bx, 100h ; get tape data offset
mov ax, ds: [di] ; read from the buffer
mov es: [bx], ax ; write to tape data
dec di ; decrement pointer
dec di
mov bx.Oh ; get tape control offset mov ax, es: [bx] ; read old tape control
or ax,80c3h ; c nl ine, read strobe
mov es: [bx], ax ; write out
and ax.07fffl> ; clear read strobe
mov es: [bx], ax ; write to tape control
mov bx.word ptr [bp+12] ; get stop value
cmp bx, di ; are they equal?
je rfr4 ; yes exit
imp rfr3 ; no get more data
rfr4: inov ax, di ; save tapepointer value mov bx.word ptr [bp+10] ; get tapepointer pointer mov sp, bp ; restore stack, segments pop es
pop ds
mov ds: [bx], ax ; write tapepointer pop bp
ret return to caller
_readfilerev endp
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; _dmaread (buffersegment, tranfer count)
; Function set up dma controller 0 to read from SCSI
; with byte reads and write into buffer specified by
; buffersegment. The transfer count refers to number
; of bytes to read. This routine sets up the DMA transfer
; and returns. DMA occurs transparent to CPU execution
; SCSI always at seg c000
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public_dmaread
_dmaread proc near
push bp ; save segment stack pointers push ds
mov bp, sp
mov bx.word ptr [bp+6] ; fetch buffersegment only upper mov ax, bx ; digit used for DMA
shr ax, 8 ; shift right 8 (get upper digit) and ax, 3h ; mask all but LS 2 bits
mov dx 0ffc6h ; DMA destination MSW address register out dx. ax ; load it
mov dx,0ffc4h ; DMA destination LSW address register mov ax, 0h ; always 0
out dx, ax ; load it
mov bx.word ptr [bp+8] ; get transfer count
mov ax, bx ; prepare to load it
mov dx.0ffc8h ; transfer count register out dx, ax ; load it
mov ax, 0ch ; Load a "Ch" for SCSI chip mov dx,0ffc2h ; DMA- source MSW address register out dx, ax ; load it
mov ax.01000h ; Offset for MCS2 (SCSI DMA ACK) mov dx, 0ffc0h ; DMA source LSW address register out dx, ax ; load it
mov ax,0be67h ; set source sync etc in DMA csr mov dx.0ffcah ; DMA CSR address
out dx, ax ; load it
mov sp, bp ; restore stack
pop ds ; restore segment
pop bp
ret ; return to cal ler
_dmaread endp
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; _dmawrιte (buffersegment, tranfer count)
; Function set up dma controller 0 to write to SCSI
; with byte writes and read from th buffer specified by
; buffersegment. The transfer count refers to number
; of bytes to write This routine sets up the DMA transfer
; and returns DMA occurs transparent to CPU execution
; SCSI always at seg c000
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
public _dmawrt
_dmawrt proc near
push bp ; save segment stack pointers push ds
mov bp sp
mov bx.word ptr [bp+6] ; letch buffersegment only upper mov ax. bx ; digit used for DMA
shr ax, 8 ; shift right 8 (get upper digit) and ax,3h ; mask all but LS 2 bits mov dx,0 f f c2h ; DMA source MSW address out dx, ax ; load it
inov dx.0ffc0h ; DMA source LSW address mov ax, 0h ; always 0
out dx, ax ; load it
mov bx.word ptr fbp+8] ; get transfer count
mov ax, bx ; prepare to load if
mov dx, 0ffcSh ; DMA transfer count register out dx, ax ; load it
mov ax.Och ; get a "Ch" for SCSI mov dx.Otfcδh ; DMA destination MSW address out dx, ax ; load it
mov ax.01000h ; SCSI offset for MCS2 (DMA ACK) mov dx,0ffc4h ; DMA destination LSW address out dx, ax ; load it
mov ax, 0f6a7h ; set destination sync etc. in CSR mov dx,0ffcah ; DMA CSR
out dx, ax ; load it
mov sp, bp ; restore stack
pop ds ; restore segment
P op bp
ret ; return to cal ler
_
dmawrt endp
; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; _dmastatus (&DMA Control Value Read)
; Function to read the 80186 DMA control l oca t i ons
; wi th word reads
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
publ ic _dmastatus
_ dmastatus proc near
push bp save stack, segment pointers push ds
push dx
mov bp, sp
mov bx,word ptr [bp+8] get variable address mov dx,0ffcah DMA CSR register
in ax, dx read status
mov sp, bp restore stack
pop dx
pop ds restore segement
inov ds:[bx],ax load variable
pop bp
ret return to cal ler
_dmastatus endp ;
; drtyc1n()
; This function c1ears the dirty block map
;
public _drtycln
_drtycln proc near
push bp
push ds
inov ax, 30001)
inov ds, ax
mov di, 0
mov ax, 0
dt1: mov ds:[di],ax
inc di
inc di
inc ax
cmp di.0 jne dt1
pop ds
pop 1bp
ret
_drtycln endp ;
; drtychk (logical block in, logical block out); Function that returns the remapped dirty block ; This returns the remapped pointer (if any); the output is 0 if no match made
;
public_drtychk
_drtychk p r oc near
push bp
push ds
mov bp, sp
mov ax, 3000h
mov ds, ax
mov bx, word ptr [bp+6]
mov ax, ds [bx]
mov di, word ptr [bp+8]
mov sp. bp
pop ds
mov ds: [[di]],,ax
pop bp
ret
_drtychk endp
;
; drtyload (logical block in, logical block out); Function that enters the remapped dirty block; in the dirty block table
;
public_drtyload
_drtyload proc near
push bp
push ds
mov bp, sp
mov ax, 03000h
mov ds, ax
mov bx.word ptr [bp+6]
mov ax, word ptr [bp+8]
mov ds: [bx],ax
mov bx, ax
mov ds: [bx], 0h
dtd4: mov sp, bp
pop ds
pop bp
ret
_drtyload endp ;
; drtysave ()
; Function that copies the dirty block table; into buffer 0 and 1
;
public_drtysave
_drtysave proc near
push ds
push es
mov di,0h mov ax, 030001)
mov ds, ax
dsst: mov ax.01000h
mov es, ax
mov bx. ds: [di]
mov es: [di], ax
mov bx, 02000h
mov es, bx
and ax, 0ff00h
inov ex, 8
shr ax, c1
mov es: [di], ax
inc di
inc di
cmp di, 0h
ie dse
jmp dsst
Ise: pop es
pop ds
ret
_drtysave endp
ENDI F
_ TEXT ends
; **************************************************************************** ; I NT E R RU P T I N T E R F ACE
; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -;- ; 1) INTERRUPT VECTORS
;
; The interrupt vector address belonging to one of possible interrupt; types (a value from 0 thru 255) must be initialized to the entry point; address of the interrupt interface routine. One 64k area of memory; contains pointers to the routines that handle interrupts and it begins; at absolute address 0. The address for the routine appropriate to; each interrupt type must reside at the address 4 times that type.
; For example, the interrupt handler address for non-maskable interrupt; type 2 must be stored at absolute location 8. The first 32 interrupt ; types (0-31) are defined or reserved by Intel for present and future; uses and the rest are user-interrupt types (32-255).
;
; 2) INTERRUPT INTERFACE
;
; This routine merely pushes hardware registers and then calls
; a C-written interrupt handler function and then upon return,
; pops into appropriate registers and executes an IRET instruction.
; Registers BP and DI are preserved by the C interrupt handler.
;
; An assembly source file "vectors, s" which contains both the
; interrupt vector table and interrupt interface routines is
; as follows:
;
; INT_VECTORS segment public 'ivect'
; INT_VECTORS ends
; INT_INTERFACE segment public " iint'
; INT_INTERFACE ends
; igroup group INT_VECTORS, INTJNTERFACE
; assume cs: igroup
;
; extrn _ DEVICE1: far ; 'near' if smalI model
; extrn _DEVICE2: far ; 'near' if small model
;
; INT_VECTORS segment public 'ivect'
; org 80h ; 32*4 is 80h
; dd DEVICE 1 ; interrupt type 32 ; dd DEVICE_2 ;interrupt type 33 ; org 400h ; 256=4 is 400h; INT_VECTORS ends
;
; INT_INTERFACE segment public 'lint'
; DEVICE_1 proc
; push si
; push dx
; push cX
; push bx
; push ax
; call _DEVICE1 ; cal I C-written handler ; pop ax
; pop bx
; pop cX
; pop dx
; pop si
; iret
; DEVICE_1 endp
;
; DEVICE_2 proc
; push si
; push dx
; push cx
; push bx
; push ax
; call _DEVICE2 ; cal I C-wr i tten handler ; pop aχ
; pop bx
; pop cx
; pop dx
; pop si
; iret
; DEVICE_2 endp
;
; INT_NTERFACE ends
; end
;
; 3) INTERRUPT HANDLER routine written in C
;
; The interrupt handler routine written entirely in C is; called from the interrupt interface routine as described; above This method is necessary to properly maintain the ; stack and also to execute an IRET instruction
;
; C-written interrupt handler functions for two devices are ;
; DEVICE1() {
; .....
; .....
; }
; DEVICE2() {
; .....
; .....
; }
;
end

Claims

1. Apparatus for interfacing a first storage medium with a host system port adapted for use with a storage medium of lower density than said first storage medium, comprising:
identifier generating means for generating a unique identifier for an individual storage block on a unit of said first storage medium;
means for reformatting data from said host system port for writing on said unit of said first storage medium; and
means for writing said reformatted data in correspondence with said unique identifier on said unit of said first storage medium.
2. Apparatus according to claim 1, wherein said unique identifier includes the date on which said reformatted data and unique identifier is written on said unit of said first storage medium.
3. Apparatus according to claim 1, further comprising:
input means for entering a desired one of said unique identifiers; and
means for retreiving data corresponding to said desired one of said identifiers from said unit of said first storage medium to said host system port in response to request signals from said host system port.
4. Apparatus according to claim 1, wherein said first storage medium is a write-once medium, wherein said individual storage block already exists on said unit of said first storage medium, and wherein said means for reformatting includes means for remapping said individual storage block to a new portion of said unit of said first storage medium, earlier written copies of said individual storage block subsequently being considered invalid.
PCT/US1991/005527 1990-08-03 1991-08-02 Data emulation and encoding apparatus WO1992002873A1 (en)

Applications Claiming Priority (2)

Application Number Priority Date Filing Date Title
US56239490A 1990-08-03 1990-08-03
US562,394 1990-08-03

Publications (1)

Publication Number Publication Date
WO1992002873A1 true WO1992002873A1 (en) 1992-02-20

Family

ID=24246118

Family Applications (1)

Application Number Title Priority Date Filing Date
PCT/US1991/005527 WO1992002873A1 (en) 1990-08-03 1991-08-02 Data emulation and encoding apparatus

Country Status (2)

Country Link
AU (1) AU8432591A (en)
WO (1) WO1992002873A1 (en)

Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US4947367A (en) * 1988-03-28 1990-08-07 Emc Corporation System for converting digital data from magnetic tape format apparatus and method for converting a sequentially accessible magnetic tape data format to directly accessible write-once disk data format to worm optical disk format
US4953122A (en) * 1986-10-31 1990-08-28 Laserdrive Ltd. Pseudo-erasable and rewritable write-once optical disk memory system
US4987533A (en) * 1988-05-05 1991-01-22 International Business Machines Corporation Method of managing data in a data storage hierarchy and a data storage hierarchy therefor with removal of the least recently mounted medium

Patent Citations (3)

* Cited by examiner, † Cited by third party
Publication number Priority date Publication date Assignee Title
US4953122A (en) * 1986-10-31 1990-08-28 Laserdrive Ltd. Pseudo-erasable and rewritable write-once optical disk memory system
US4947367A (en) * 1988-03-28 1990-08-07 Emc Corporation System for converting digital data from magnetic tape format apparatus and method for converting a sequentially accessible magnetic tape data format to directly accessible write-once disk data format to worm optical disk format
US4987533A (en) * 1988-05-05 1991-01-22 International Business Machines Corporation Method of managing data in a data storage hierarchy and a data storage hierarchy therefor with removal of the least recently mounted medium

Also Published As

Publication number Publication date
AU8432591A (en) 1992-03-02

Similar Documents

Publication Publication Date Title
US5455926A (en) Virtual addressing of optical storage media as magnetic tape equivalents
Case et al. Architecture of the IBM System/370
US4792896A (en) Storage controller emulator providing transparent resource sharing in a computer system
US6237091B1 (en) Method of updating firmware without affecting initialization information
US20080209420A1 (en) Processing system, storage device, and method for performing series of processes in given order
JPH0738202B2 (en) Full event trace gatherer for logic simulation machines
KR930010981A (en) Storage device using flash memory
KR880000793B1 (en) Disc stroage controller
US6393492B1 (en) Method and arrangement for operating a mass memory storage peripheral computer device connected to a host computer
AU619990B2 (en) Data transmission method and data processing system using the same
US5717956A (en) System for batch processing of commands by emulating command string and record format if the string detector detects command is of a specified command string
KR890000100B1 (en) Register control processing system
US3911402A (en) Diagnostic circuit for data processing system
CN101073066A (en) Method, system, and program for generating parity data
JP2761289B2 (en) Disk track emulation method
CN108334453B (en) File debugging method and device, terminal equipment and storage medium
WO1992002873A1 (en) Data emulation and encoding apparatus
US5379389A (en) Method for transmitting commands excluded from a predefined command set
CN114546292A (en) Method and system for managing bad blocks of nand flash
US20040193812A1 (en) Method for improving the performance of read/write testing in a hard drive
EP0080878A2 (en) Cache memory and method of control for use with magnetic disks
CN101551802B (en) File access method used for management system
CN100435112C (en) Method for setting breakpoint of user software program of SCM development system
WO1991008536A1 (en) Data record move apparatus for a virtual memory system
WO1991008537A1 (en) Data record copy apparatus for a virtual memory system

Legal Events

Date Code Title Description
AK Designated states

Kind code of ref document: A1

Designated state(s): AU CA GB JP

AL Designated countries for regional patents

Kind code of ref document: A1

Designated state(s): AT BE CH DE DK ES FR GB GR IT LU NL SE

NENP Non-entry into the national phase

Ref country code: CA