;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; ; ; ; M R S I O S O U R C E ; ; ; Copyright 1983 OCCO inc. ; ; ; ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ;****************************************************************************** ; ;****************************************************************************** ;****************************************************************************** ; ; ; M R S I O C O N S T A N T V A L U E S ; ; ;****************************************************************************** ;****************************************************************************** ; ; ; ; ; ; ;****************************************************************************** ; ; B O O T A N D R E S E T C O N S T A N T S ; ;****************************************************************************** ; ; IOSTRT: EQU 0F000H ;STARTING ADDRESS OF MRSIO PRMREG: EQU 0A0H ;ADDRESS OF THE PROM CONTROL REGISTER COLDBT: EQU 0003H ;ADDRESS OF COLD BOOT ROUTINE IN PROM MRSBGN: EQU 0E000H ;STARTING ADDRESS OF MRS ; ; ;****************************************************************************** ; ; C O N S O L E A N D P R I N T E R C O N S T A N T S ; ;****************************************************************************** ; ; RECSTA: EQU 01H ;RECEIVER STATUS REGISTER ADDRESS RECMSK: EQU 02H ;RECEIVER BUFFER FULL STATUS MASK RECDAT: EQU 00H ;RECEIVER DATA REGISTER ADDRESS TRNSTA: EQU 01H ;TRANSMITTER STATUS REGISTER ADDRESS TRNMSK: EQU 01H ;TRANSMITTER BUFFER EMPTY STATUS MASK TRNDAT: EQU 00H ;TRANSMITTER DATA REGISTER ADDRESS PTRSTA: EQU 30H ;PRINTER STATUS REGISTER ADDRESS PTRMSK: EQU 02H ;PRINTER BUFFER STATUS MASK PTRDAT: EQU 30H ;PRINTER DATA REGISTER ADDRESS ; ; ; ;****************************************************************************** ; ; D I S K C O N T R O L L E R C O N S T A N T S ; ;****************************************************************************** ; ; STATUS: EQU 50H ;DISK CONTROLLER STATUS REGISTER ADDRESS CMDREG: EQU 50H ;DISK CONTROLLER COMMAND REGISTER ADDRESS TRKREG: EQU 51H ;DISK CONTROLLER TRACK REGISTER SCTREG: EQU 52H ;DISK CONTROLLER SECTOR REGISTER DATREG: EQU 53H ;DISK CONTROLLER DATA REGISTER ADDRESS DSKREG: EQU 60H ;DISK CONTROLLER ID REGISTER DMAREG: EQU 70H ;DMA REGISTER ADDRESS HOMCMD: EQU 0CH ;HOME HEAD COMMAND SEKCMD: EQU 1CH ;SEEK TRACK COMMAND RDACMD: EQU 0C4H ;READ ADDRESS COMMAND RDCMD: EQU 84H ;READ SECTOR COMMAND WRTCMD: EQU 0A4H ;WRITE SECTOR COMMAND BSYMSK: EQU 01H ;DISK CONTROLLER BUSY MASK RDYMSK: EQU 80H ;DISK DRIVE READY MASK ERRMSK: EQU 18H ;RECORD NOT FOUND OR CRC ERROR MASK WREMSK: EQU 5CH ;WRITE ERROR CONDITIONS MASK RDEMSK: EQU 1CH ;READ ERROR CONDITIONS MASK SKEMSK: EQU 18H ;SEEK ERROR CONDITIONS MASK WRPROT: EQU 40H ;DISK WRITE PROTECTED MASK ; ;****************************************************************************** ; ; D I S K I / O S U B S Y S T E M C O N S T A N T S ; ;****************************************************************************** ; ; RETRYS: EQU 10 ;RETRY THINGS 10 TIMES BEFORE GIVING UP DIDOS: EQU 0 ;DISK DATA ARRAY OFFSET TO ID CHARACTER FLAGOS: EQU 1 ;DISK DATA ARRAY OFFSET TO FLAG BYTE TRAKOS: EQU 2 ;DISK DATA ARRAY OFFSET TO TRACK NUMBER SCTROS: EQU 3 ;DISK DATA ARRAY OFFSET TO SECTOR NUMBER SIZEOS: EQU 4 ;DISK DATA ARRAY OFFSET TO SECTOR SIZE HEADOS: EQU 5 ;DISK DATA ARRAY OFFSET TO HEAD POSITION DPHLOS: EQU 6 ;DISK DATA ARRAY OFFSET TO LSB OF DPH ADDRESS DPHHOS: EQU 7 ;DISK DATA ARRAY OFFSET TO MSB OF DPH ADDRESS ATRKOS: EQU 0 ;ADDRESS ID FIELD OFFSET TO TRACK NUMBER ASIZOS: EQU 3 ;ADDRESS ID FIELD OFFSET TO SECTOR SIZE RDALGT: EQU 13 ;LENGTH OF READ ADDRESS DMA TABLE DABDMA: EQU 83H ;DISABLE DMA COMMAND MNTMSK: EQU 01H ;MOUNTED DISK MASK FIVMSK: EQU 40H ;FIVE INCH DISK DRIVE MASK WRPMSK: EQU 0FDH ;WRITE PENDING MASK WRPBIT: EQU 02H ;WRITE PENDING BIT SCNMSK: EQU 01H ;FIRST SECTOR NUMBER ON TRACK MASK STDSIZ: EQU 128 ;SIZE OF A STANDARD SECTOR TMDLAY: EQU 1AH ;TIME DELAY CONSTANT MTDLAY: EQU 0FFH ;MOTOR DELAY TIME CONSTANT DMALGT: EQU 15 ;LENGTH OF THE DMA TABLES DBFLSB: EQU 2 ;DMA TABLES OFFSET TO LSB OF BUFFER ADDRESS DBFMSB: EQU 3 ;DMA TABLES OFFSET TO MSB OF BUFFER ADDRESS DSZLSB: EQU 4 ;DMA TABLES OFFSET TO LSB OF XFER SIZE DSZMSB: EQU 5 ;DMA TABLES OFFSET TO MSB OF XFER SIZE SIZ256: EQU 1 ;SIZE INDICATOR FOR A 256 BYTE SECTOR SIZ512: EQU 2 ;SIZE INDICATOR FOR A 512 BYTE SECTOR ; ; ; ; ORG IOSTRT ; ; MRSIO: EQU $ ; ; ;****************************************************************************** ; ; M R S I O J U M P T A B L E ; ; used exclusively by MRS to access the I/O routines ; ;****************************************************************************** ; ; CBOOT: JP MPROM ;COLD BOOT TO PROM WBOOT: JP RESET ;SYSTEM RESET CSTAT: JP CONSTA ;INPUT CONSOLE STATUS (RETURNED IN 'A') CIN: JP CONIN ;GET CONSOLE CHARACTER (RETURNED IN 'A') COUT: JP CONOUT ;WRITE TO CONSOLE (FROM 'C') LOUT: JP PRNTOT ;PRINTER OUTPUT (FROM 'C') POUT: JP PNCHOT ;PUNCH OUTPUT (FROM 'C') RIN: JP READIN ;READER INPUT (RETURNED IN 'A') HOME: JP DSKHOM ;HOME DRIVE HEAD SETDSK: JP SELDSK ;SELECT DISK (FROM 'C') SETTRK: JP SELTRK ;SELECT TRACK (FROM 'C') SETSEC: JP SELSEC ;SELECT SECTOR (FROM 'C') SETBUF: JP SELBUF ;SELECT DMA BUFFER (FROM 'BC') READ: JP RDDSK ;READ FROM DISK WRITE: JP WRDSK ;WRITE TO DISK TSTLST: JP LISTST ;TEST LIST DEVICE STATUS TRNSCT: JP SCTRAN ;SECTOR TRANSLATE ; ; ; ; ; ;****************************************************************************** ; ; M P R O M ( C O L D B O O T P R O C E D U R E ) ; ; turn on the prom ; jump to the monitor cold boot routine ; ;****************************************************************************** ; ; MPROM: IN A,(PRMREG) ;ENABLE THE PROM BY READING THE PROM REGISTER JP COLDBT ;JUMP TO THE COLD BOOT ROUTINE IN PROM ; ; ;****************************************************************************** ; ; R E S E T ; ; jump to the starting address of MRS ; ;****************************************************************************** ; ; RESET: LD C,0 ;CLEAR THE C REGISTER JP MRSBGN ;JUMP TO THE START OF MRS ; ; ; ;****************************************************************************** ; ; M R S I O - C O N S O L E & P R I N T E R ; ; ; The following routines were written for the 8251 serial I/O chip. ; MRSIO assumes that the interface and it's baud rate have been ; initialized by the computer PROM or ROM before MRS was started. ; These devices exist in the I/O space of the processor. If your ; computer has it's I/O in the memory space, then you will need to ; rewrite the I/O routines. Under most circumstances however, the ; only changes that will be needed are at the front of this listing ; (the EQUates). You will need to know the addresses of the I/O ; data and status ports as well as the specific bit configuration ; of the status register (the receiver full and transmitter empty ; status bits). ; ; ;****************************************************************************** ; ; P N C H O T ; ; return (there is no punch output) ; ;****************************************************************************** ; ; PNCHOT: RET ;NO PUNCH OUTPUT ;****************************************************************************** ; ; R E A D I N ; ; return (there is no card reader input) ; ;****************************************************************************** ; ; READIN: RET ;NO READER INPUT ; ;****************************************************************************** ; ; C O N S T A ; ; get the console receiver status bit ; IF:(receiver is empty) ; THEN: ; return with register A=0 ; ELSE: ; return with register A=-1 (FF hex) ; IF END: ; ;****************************************************************************** ; ; CONSTA: IN A,(RECSTA) ;GET RECEIVER STATUS AND A,RECMSK ;TEST STATUS BIT JR Z,CONSTE ;NO CHARACTER PRESENT LD A,0FFH ;CHARACTER WAITING CONSTE: RET ; ; ;****************************************************************************** ; ; C O N I N ; ; DO UNTIL:(a character is entered) ; get the console input status, check for character entered ; DO END: ; get the character from the console receiver data register ; mask off the MSB of the character ; return ; ;****************************************************************************** ; ; CONIN: CALL CONSTA ;GET RECEIVER STATUS JR Z,CONIN ;WAIT FOR CHARACTER IN A,(RECDAT) ;GET CHARACTER AND A,7FH ;REMOVE MSB RET ; ; ;****************************************************************************** ; ; C O N O U T ; ; DO UNTIL:(transmit buffer empty) ; get the console status, examine the transmit buffer status ; DO END: ; transmit the character contained in register C ; return ; ;****************************************************************************** ; ; CONOUT: IN A,(TRNSTA) ;GET XMITTER STATUS AND A,TRNMSK ;TEST STATUS BIT JR Z,CONOUT ;LOOP TILL BUFFER EMPTY LD A,C ;GET CHARACTER OUT (TRNDAT),A ;SEND CHARACTER RET ; ; ;****************************************************************************** ; ; P R N T O T ; ; DO UNTIL:(printer buffer not full) ; get the printer status ; mask off all but the printer busy bit ; DO END: ; output the character contained in register C to the printer ; return ; ;****************************************************************************** ; ; PRNTOT: IN A,(PTRSTA) ;GET XMITTER STATUS AND A,PTRMSK ;TEST STATUS BIT JR NZ,PRNTOT ;WAIT FOR PRINTER NOT BUSY LD A,C ;GET CHARACTER OUT (PTRDAT),A ;SEND DATA RET ; ; ;****************************************************************************** ; ; L I S T S T ; ; get the list device status ; IF:(list status not zero) ; THEN: ; set accumulator to -1 (FF hex) ; IF END: ; return ; ;****************************************************************************** ; ; LISTST: IN A,(PTRSTA) ;GET THE LIST DEVICE STATUS JR Z,LISTSE ;EXIT IF PRINTER NOT READY LD A,-1 ;RETURN A -1 IF IT IS LISTSE: RET ; ; ; ;****************************************************************************** ; ; ; MRSIO - DISK I/O ROUTINES ; ; ; The following routines are written for the 2793 disk controller ; which is software compatable with the 1793 controller. None of the ; routines require interrupt service from the CPU. The data transfers ; are all handled by a Z80 DMA chip. Any delays or other timing loops ; are written for a 4 Mhz Z80 central processor. ; ; In the disk I/O routines that follow, the disk drive status array ; is used extensively. The array contains the drive id#, a flag byte ; containing a write pending flag and bit indicating the first sector ; number on a track (i.e.: 0 or 1 ), the track # of the next or previous ; disk access, the desired sector # (MRS standard 128 byte sectors), ; the size of a physical sector on the disk, the current head position ; of the drive, and a pointer to the Disk Parameter Header (DPH) for ; the drive. Since the calls to set the track and sector number do ; not reference a disk in the call parameters, MRSIO assumes a disk. ; This disk is selected by the routine "SELDSK" which puts the address ; of the selected drive data array in "CURDSK". MRS will ALWAYS select ; the disk before setting the track or sector numbers. If you write any ; software which directly interfaces to MRSIO, BE CAREFUL to follow the ; same order in the disk I/O calls as MRS. ; ;****************************************************************************** ; ; ; ;****************************************************************************** ; ; D S K H O M ; ; make sure the disk controller isn't busy ; select the current disk drive ; see if a diskette is in the selected drive ; IF:(a diskette is in the drive) ; THEN: ; See if a write is pending for this drive ; IF:(a write is pending) ; THEN: ; perform the actual write to the disk ; IF END: ; home the head on the drive ; wait for the disk controller status to be valid ; store the new head position in the disk data array ; IF END: ; return ; ;****************************************************************************** ; ; DSKHOM: CALL DSNBSY ;WAIT UNTIL THE DISK CONTROLLER ISN'T BUSY LD IX,(CURDSK) ;ADDRESS OF CURRENT DISK ARRAY LD A,(IX+DIDOS) ;CURRENT DISK ID # OUT (DSKREG),A ;SELECT THE CURRENT DISK LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSKRDY ;SEE IF A DISKETTE IS IN THE DRIVE JR NZ,DSKHOE ;SKIP THE HOME COMMAND IF NO DISKETTE LD A,(IX+FLAGOS) ;GET THE FLAG BYTE AND A,WRPBIT ;MASK OFF ALL BUT THE WRITE PENDING BIT JR Z,DSKHO1 ;SKIP THE NEXT COMMAND IF NO WRITE PENDING CALL WRTBUF ;WRITE THE CONTENTS OF THE BUFFER TO DISK DSKHO1: LD A,HOMCMD ;GET THE HOME HEAD COMMAND OUT (CMDREG),A ;OUTPUT THE COMMAND TO THE CONTROLLER LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR CONTROLLER STATUS REGISTER VALID LD (IX+TRAKOS),0 ;TRACK 0 LD (IX+HEADOS),0 ;HEAD POSITIONED AT TRACK 0 DSKHOE: RET ; ;****************************************************************************** ; ; S E L B U F ; ; save the address contained in register BC at location "DMAADR" ; ;****************************************************************************** ; ; SELBUF: LD (DMAADR),BC ;STORE IN DISK CONTROLLER RET ; ;****************************************************************************** ; ; S E L T R K ; ; save the track # contained in register C in the Track Byte ; of the current disk data array ; ;****************************************************************************** ; ; SELTRK: LD IX,(CURDSK) ;ADDRESS OF CURRENT DISK ARRAY LD (IX+TRAKOS),C ;GIVE TRACK# NEW VALUE RET ; ;****************************************************************************** ; ; S E L S E C ; ; save the sector # contained in register C in the Sector Byte ; of the current disk data array. ; ;****************************************************************************** ; ; SELSEC: LD IX,(CURDSK) ;ADDRESS OF CURRENT DISK ARRAY LD (IX+SCTROS),C ;GIVE SECTOR# NEW VALUE RET ; ;****************************************************************************** ; ; S E L D S K ; ; set a pointer to the disk data array for the disk indicated in C ; save the pointer in "CURDSK" and register IX ; IF:(the LSB of register E is ZERO) ; THEN: ; mount the disk ; IF END: ; IF:(the disk drive exists) ; THEN: ; put the drive's current DPH address in register HL ; ELSE: ; clear regsiter HL ; IF END: ; return ; ;****************************************************************************** ; ; SELDSK: LD HL,DSKA ;ARRAY BASE ADDRESS SLA C ;OFFSET=DISK# * 8 LD D,C ;SAVE AS THE OFFSET INTO THE DISK ID ARRAY SLA C SLA C LD B,0 ;SETUP OFFSET AS 16 BITS ADD HL,BC ;NEW ADDRESS OF CURRENT DISK LD (CURDSK),HL ;SAVE IT LD IX,(CURDSK) ;AND KEEP A COPY IN IX LD A,E ;MOVE THE E REGISTER TO THE ACCUMULATOR AND A,MNTMSK ;MASK OFF ALL BUT THE DISK MOUNTED BIT JR NZ,SELDS0 ;DON'T BOTHER REMOUNTING IT IF ALREADY DONE CALL MNTDSK ;MOUNT THE DISK ON THE DRIVE JR NZ,SELDS1 ;JUMP IF NO DISK DRIVE SELDS0: LD L,(IX+DPHLOS) ;LEAST SIGNIFICANT BYTE OF DPH ADDRESS LD H,(IX+DPHHOS) ;MOST SIGNIFICANT BYTE OF DPH ADDRESS JR SELDSE ;SKIP THE NEXT INSTRUCTION SELDS1: LD HL,0 ;CLEAR THE HL REGISTER IF NO DRIVE OR DISK SELDSE: RET ; ;****************************************************************************** ; ; M N T D S K ; ; set a pointer in register HL to the single density disk ID character ; for the indicated drive ; try to read an address ID field from the disk ; IF:(we couldn't read an ID field) ; THEN: ; move the pointer to the double density disk ID character ; try to read an address ID field from the disk in double density ; IF END: ; IF:(we managed to read an address ID one way or the other) ; THEN: ; put appropriate disk ID character in the disk data array ; extract the size of the sector from the address ID field and ; store it in the disk data array size byte ; extract the track # from the address ID field and save it as ; the current track # and head position in the disk data array ; get the # of the first sector on a track for this disk format ; and save it in the flag word of the disk data array ; set a pointer in the DPH for this drive to the appropriate ; DPB for this disk density and format ; set a pointer in the DPH for this drive to the appropriate ; sector translate table for this disk density and format ; clear the data buffer if it points to this disk drive ; clear the accumulator ; IF END: ; return ; ;****************************************************************************** ; ; MNTDSK: LD HL,DSKIDS ;DISK DRIVE ID CHARACTER ARRAY LD E,D ;MOVE THE DISK ID ARRAY OFFSET INTO E LD D,0 ;SET UP AS A 16 BIT VALUE ADD HL,DE ;POINTER TO SINGLE DENSITY DRIVE ID CHARACTER CALL RDADDR ;TRY TO READ AN ADDRESS FIELD FROM THE DISK JR Z,MNTDS0 ;DON'T NEED TO CHECK FOR DD IF IT WAS SINGLE INC HL ;POINT TO THE DOUBLE DENSITY DRIVE ID CHARACTER INC E ;INCREMENT THE OFFSET AS WELL CALL RDADDR ;TRY TO READ THE ADDRESS FIELD FROM THE DISK JR NZ,MNTDSE ;ERROR IF WE COULDN'T READ DD EITHER MNTDS0: LD A,(HL) ;GET THE DRIVE ID CHARACTER LD (IX+DIDOS),A ;SAVE THE DISK ID CHARACTER LD IY,ADRBUF ;ADDRESS OF THE ADDRESS BUFFER LD A,(IY+ASIZOS) ;GET THE SIZE OF THE SECTOR FROM THE ADDR FIELD LD (IX+SIZEOS),A ;AND SAVE IT IN THE DISK DATA TABLE LD A,(IY+ATRKOS) ;GET THE TRACK NUMBER FROM THE ID FIELD LD (IX+TRAKOS),A ;SAVE IT AS THE CURRENT TRACK NUMBER LD (IX+HEADOS),A ;AND THE CURRENT HEAD POSITION LD HL,FSTSCT ;POINTER TO THE FIRST SECTOR NUMBER TABLE ADD HL,DE ;ADD THE OFFSET TO THE TABLE POINTER LD A,(HL) ;GET THE FIRST SECTOR NUMBER ON THE TRACK LD (IX+FLAGOS),A ;SAVE THE NUMBER IN THE DISK DATA TABLE LD L,(IX+DPHLOS) ;LEAST SIGNIFICANT BYTE OF THE DPH ADDRESS LD H,(IX+DPHHOS) ;MOST SIGNIFICANT BYTE OF THE DPH ADDRESS LD BC,10 ;OFFSET IN DPH TO THE DPB ADDRESS ADD HL,BC ;POINTER TO THE DPB ADDRESS WORD IN THE DPH SLA E ;DOUBLE THE TABLE OFFSET VALUE PUSH DE ;SAVE THE NEW OFFSET ON THE STACK PUSH HL ;SAVE THE ADDRESS TEMPORARILY ON THE STACK LD HL,DPBTBL ;ADDRESS OF THE DISK PARAMETER BLOCK TABLE ADD HL,DE ;ADD THE NEW OFFSET TO THE BASE ADDRESS POP DE ;RECOVER THE POINTER INTO THE DPH LD BC,2 ;NUMBER OF BYTES TO BE TRANSFERRED LDIR ;TRANSFER THE ADDRESS TO THE DPH POP DE ;RECOVER THE OFFSET LD HL,XLTTBL ;GET THE ADDRESS OF THE XLATE VECTOR TABLE ADD HL,DE ;ADD THE OFFSET TO THE BASE ADDRESS LD E,(IX+DPHLOS) ;PUT THE DISK PARAMETER HEADER ADDRESS IN DE LD D,(IX+DPHHOS) LD BC,2 ;NUMBER OF BYTES TO TRANSFER IN BC LDIR ;PUT THE XLATE VECTOR ADDRESS IN THE DPH CALL CLRBUF ;CLEAR DATA BUFFER IF IT POINTS TO THIS DISK XOR A,A ;SET THE ZERO FLAG MNTDSE: RET ; ; ;****************************************************************************** ; ; R D A D D R ; select the current disk drive ; IF:(a disk is present in the drive) ; THEN: ; initialize the DMA chip to transfer an address ID field from ; the disk controller ; give the disk controller a READ ADDRESS command ; wait for the disk controller status to be valid ; wait for the disk controller to finish the command ; read the disk controller status regsiter ; mask off all but the pertinent error condition bits ; IF END: ; return ; ;****************************************************************************** ; ; RDADDR: PUSH HL ;SAVE THE HL REGISTER PAIR CALL SELDRV ;SELECT THE INDICATED DRIVE JR NZ,RDADDE ;EXIT THIS ROUTINE IF NO DISK IN DRIVE LD HL,RDATBL ;POINTER TO THE READ ADDRESS DMA TABLE LD C,DMAREG ;ADDRESS OF THE DMA CHIP LD B,RDALGT ;LENGTH OF THE READ ADDRESS DMA TABLE OTIR ;INITIALIZE THE DMA CHIP LD A,RDACMD ;GET THE READ ADDRESS COMMAND OUT (CMDREG),A ;AND OUTPUT IT TO THE DISK CONTROLLER LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSNBSY ;WAIT FOR DISK CONTROLLER TO BE NOT BUSY LD A,DABDMA ;GET THE DISABLE DMA COMMAND OUT (DMAREG),A ;AND SEND IT TO THE DMA CONTROLLER IN A,(STATUS) ;GET THE FINAL DISK CONTROLLER STATUS AND A,(ERRMSK) ;MASK OFF ALL BUT THE RECORD NOT FOUND BIT RDADDE: POP HL ;RESTORE THE CONTENTS OF HL RET ; ; ;****************************************************************************** ; ; C L R B U F ; ; IF:(write pending flag is set) ; THEN: ; write the data buffer contents out to disk ; IF END: ; IF:(the data in the buffer is from the current disk) ; THEN: ; clear the buffered disk address word ; IF END: ; return ; ;****************************************************************************** ; ; CLRBUF: LD A,(WRTFLG) ;GET THE WRITE PENDING FLAG AND A,A ;SEE IF IT IS SET JR Z,CLRBU0 ;SKIP THE NEXT INSTRUCTION IF NO WRITE PENDING CALL WRTBUF ;WRITE THE BUFFER OUT TO DISK CLRBU0: LD HL,(BUFDSK) ;GET THE DATA ARRAY ADDRESS FOR BUFFERED DATA LD DE,(CURDSK) ;GET THE DATA ARRAY ADDRESS FOR THIS DISK SBC HL,DE ;COMPARE THE TWO ADDRESSES JR NZ,CLRBUE ;RETURN IF THEY ARE NOT THE SAME LD (BUFDSK),HL ;CLEAR THE BUFFERED DISK ADDRESS WORD CLRBUE: RET ; ; ;****************************************************************************** ; ; R D D S K ; set a pointer to the current disk data array ; check the size of a sector on the current disk ; IF:(the current disk has a sector size greater than 128 bytes) ; THEN: ; get a pointer to the indicated data in the data buffer ; IF:(no error occurred in getting the data pointer) ; THEN: ; transfer the data into the user buffer ; IF END: ; ELSE: ; set a pointer in register DE to the user buffer space ; put the desired track # in "SKTRAK" ; put the desired sector # in register B ; read the sector from the disk ; IF END: ; return ; ;****************************************************************************** ; ; RDDSK: LD IX,(CURDSK) ;POINT TO THE CURRENT DISK ARRAY LD A,(IX+SIZEOS) ;GET THE SECTOR SIZE CHARACTER AND A,A ;TEST FOR ZERO JR Z,RDDSK0 ;JUST READ THE SECTOR IF IT IS 128 BYTES LONG CALL GETPTR ;GET A POINTER TO START OF 128 BYTE SECTOR JR NZ,RDDSKE ;EXIT IF THERE WAS AN ERROR LD DE,(DMAADR) ;POINTER TO THE USER BUFFER LD BC,STDSIZ ;STANDARD SECTOR SIZE (128 BYTES) LDIR ;TRANSFER THE DATA TO THE USER BUFFER JR RDDSKE ;ALL FINISHED RDDSK0: LD DE,(DMAADR) ;POINT TO THE USER BUFFER SPACE LD A,(IX+TRAKOS) ;GET THE # OF THE TRACK TO BE READ LD (SKTRAK),A ;SAVE IT IN THE SEEK TRACK POINTER WORD LD B,(IX+SCTROS) ;PUT THE SECTOR NUMBER IN B CALL DSKRD ;READ IN A 128 BYTE SECTOR TO USER BUFFER RDDSKE: RET ; ; ;****************************************************************************** ; ; W R D S K ; set a pointer in register IX to the current disk data array ; check the size of the sectors on the disk ; IF:(sector size is greater than 128 bytes) ; THEN: ; get a pointer to the data block to be written in the ; data buffer ; IF:(no error occurred in getting the data pointer) ; THEN: ; transfer the data from the user buffer to the data buffer ; set the write pending bit in the current disk data array ; ;and the disk data buffer ; IF END: ; ELSE: ; set a pointer in register DE to the user data buffer ; get the desired track # and save it in "SKTRAK" ; get the desired sector # and put it in register B ; set a pointer in register HL in the current disk data array ; write the user buffer out to the indicated sector on the disk ; IF END: ; return ; ;****************************************************************************** ; ; WRDSK: LD IX,(CURDSK) ;POINT TO THE CURRENT DISK ARRAY LD A,(IX+SIZEOS) ;GET THE SECTOR SIZE CHARACTER AND A,A ;TEST FOR ZERO JR Z,WRDSK0 ;JUST WRITE THE SECTOR IF IT IS 128 BYTES LONG CALL GETPTR ;GET A POINTER TO START OF 128 BYTE SECTOR JR NZ,WRDSKE ;EXIT IF THERE WAS AN ERROR PUSH HL ;PUT THE BUFFER POINTER ON THE STACK POP DE ;AND MOVE IT INTO DE LD HL,(DMAADR) ;POINTER TO THE USER BUFFER LD BC,STDSIZ ;STANDARD SECTOR SIZE (128 BYTES) LDIR ;TRANSFER THE DATA TO THE USER BUFFER LD A,WRPBIT ;GET THE WRITE PENDING BIT LD (WRTFLG),A ;AND SAVE IT IN THE WRITE FLAG WORD OR A,(IX+FLAGOS) ;GET THE FLAG WORD FROM THE DISK DATA ARRAY LD (IX+FLAGOS),A ;SAVE THE FLAG WORD BACK IN THE DATA ARRAY XOR A,A ;CLEAR THE ACCUMULATOR JR WRDSKE ;ALL FINISHED WRDSK0: LD DE,(DMAADR) ;POINTER TO THE USER BUFFER SPACE LD A,(IX+TRAKOS) ;GET THE # OF THE TRACK TO BE WRITTEN LD (SKTRAK),A ;SAVE IT IN THE SEEK TRACK POINTER WORD LD B,(IX+SCTROS) ;PUT THE SECTOR NUMBER IN B LD HL,(CURDSK) ;SET A POINTER TO THE CURRENT DISK DATA ARRAY CALL DSKWRT ;WRITE THE 128 BYTE USER BUFFER TO DISK WRDSKE: RET ; ; ;****************************************************************************** ; ; G E T P T R ; ; convert the MRS 128 byte sector # to a disk sector # ; compare the sector #, track #, and disk with those for the data ; currently buffered in the disk data buffer ; IF:(the desired sector is not already buffered) ; THEN: ; see if the buffered data has a write pending ; IF:(a write is pending on the data buffer) ; THEN: ; write the buffer out to the appropriate disk ; IF END: ; IF:(no error has occurred yet) ; THEN: ; fill the disk data buffer with the desired sector from the ; current disk ; IF END: ; IF END: ; IF:(no error has occurred) ; THEN: ; set a pointer in HL to the start of the disk data array ; adjust the pointer by 128 bytes for every unit of count in ; register C which contains the block offset value ; IF END: ; return ; ;****************************************************************************** ; ; GETPTR: CALL CONVRT ;CONVERT TO A DISK SECTOR NUMBER LD A,(SCTNBR) ;GET THE CURRENTLY BUFFERED SECTOR NUMBER CP A,B ;COMPARE WITH THE CURRENTLY BUFFERED SECTOR JR NZ,GETPT0 ;DIFFERENT SECTOR GO TAKE CARE OF IT LD A,(TRKNBR) ;GET THE TRACK NUMBER OF CURRENT BUFFER SECTOR CP A,(IX+TRAKOS) ;COMPARE IT WITH THE ONE WE WANT JR NZ,GETPT0 ;DIFFERENT SECTOR GO TAKE CARE OF IT LD HL,(CURDSK) ;GET THE CURRENT DISK POINTER LD DE,(BUFDSK) ;GET THE BUFFERED DISK POINTER SBC HL,DE ;SUBTRACT DE FROM HL JR Z,GETPT2 ;JUMP IF WE HAVE THE RIGHT SECTOR BUFFERED GETPT0: LD A,(WRTFLG) ;SEE IF A WRITE IS PENDING ON BUFFERED SECTOR AND A,A ;TEST FLAG JR Z,GETPT1 ;NO WRITE PENDING CALL WRTBUF ;WRITE THE BUFFER OUT TO DISK JR NZ,GETPTE ;EXIT IF THERE WAS A WRITE ERROR GETPT1: CALL FILLBF ;READ THE SPECIFIED SECTOR INTO THE BUFFER JR NZ,GETPTE ;EXIT IF THERE WAS A READ ERROR GETPT2: LD HL,DATBUF ;POINTER TO START OF DATA BUFFER LD DE,STDSIZ ;SIZE OF A STANDARD SECTOR LD A,C ;GET THE OFFSET FROM START OF BUFFER AND A,A ;TEST THE OFFSET FOR ZERO JR Z,GETPTE ;EXIT IF THE OFFSET COUNT IS ZERO GETPT3: ADD HL,DE ;ADD A SECTOR OFFSET TO HL DEC A ;DECREMENT THE OFFSET COUNTER JR NZ,GETPT3 ;LOOP IF THERE IS STILL MORE OFFSET TO ADD GETPTE: RET ; ; ;****************************************************************************** ; ; C O N V R T ; ; initially set the sector number adjustment factor to 0 (register B) ; extract from the current disk data array the first sector number ; on a track ; IF:(first sector number is 1) ; THEN: ; DO CASE: ; WHEN:(the sector is 256 bytes long) ; put a sector number adjustment factor of 1 in register B ; WHEN:(the sector is 512 bytes long) ; put a sector number adjustment factor of 3 in regsiter B ; WHEN:(the sector is 1024 bytes long) ; put a sector number adjustment factor of 7 in register B ; CASE END: ; IF END: ; get the MRS sector number from the current disk data array ; add the adjustement factor to the sector number ; physical sector # = adjusted MRS sector # / (2 * sector size #) ; buffer offset = remainder from physical sector # calculation ; return ; ;****************************************************************************** ; ; CONVRT: LD D,A ;PUT THE SECTOR SIZE INTO D LD B,0 ;CLEAR THE B REGISTER FOR NOW LD A,(IX+FLAGOS) ;GET THE FLAG WORD FROM DISK DATA TABLE AND A,SCNMSK ;MASK OFF ALL BUT THE FIRST SECTOR NUMBER BIT JR Z,CONVR3 ;SKIP THE ADDRESS ADJUSTMENT IF 1ST # IS 0 LD A,D ;GET THE SECTOR SIZE NUMBER CP A,SIZ256 ;IF THE SECTOR IS NOT 256 BYTES JR NZ,CONVR1 ;THEN SEE IF IT IS 512 BYTES LD B,1 ;ELSE SECTOR NUMBER GETS ADJUSTED BY 1 JR CONVR3 ;SKIP THE OTHER CASES CONVR1: CP A,SIZ512 ;IF THE SECTOR IS NOT 512 BYTES JR NZ,CONVR2 ;THEN IT MUST BE 1024 BYTES LONG LD B,3 ;ELSE SECTOR NUBER GETS ADJUSTED BY 3 JR CONVR3 ;SKIP THE 1024 BYTE CASE CONVR2: LD B,7 ;1024 BYTES ADJUST SECTOR # BY 7 CONVR3: LD A,(IX+SCTROS) ;GET THE SECTOR NUMBER ADD A,B ;ADD THE ADJUSTMENT FACTOR TO A LD B,A ;PUT THE ADJUSTED SECTOR NUMBER IN B LD C,1 ;SET THE LEAST SIGNIFICANT BIT OF C XOR A,A ;CLEAR THE ACCUMULATOR CONVR0: SRA B ;DIVIDE THE RECORD NUMBER BY 2 JR NC,CONVR4 ;SKIP NEXT INSTRUCTION IF NO CARRY GENERATED ADD A,C ;ADD THE CARRY VALUE TO A CONVR4: SLA C ;DOUBLE THE VALUE OF THE NEXT CARRY DEC D ;DECREMENT THE SIZE COUNTER JR NZ,CONVR0 ;LOOP IF WE STILL HAVE EXCESS SIZE LD C,A ;PUT THE REMAINDER IN C FOR OFFSET CALCULATION RET ; ; ;****************************************************************************** ; ; W R T B U F ; ; set a pointer in register DE to the disk data buffer ; put the desired track # in "SKTRAK" ; put the desired sector # in register B ; set a pointer in register HL to the disk data array for the buffered ; sector ; also set the same pointer in register IY ; write the buffered data out to the indicated disk ; IF:(no error occurred on the disk write) ; THEN: ; clear the write pending flags in the disk data array and the ; disk data buffer ; clear the accumulator ; IF END: ; return ; ;****************************************************************************** ; ; WRTBUF: PUSH BC ;SAVE THE SECTOR NUMBER AND OFFSET PUSH IX ;SAVE THE POINTER TO THE CURRENT DISK ARRAY LD DE,DATBUF ;POINTER TO THE DATA BUFFER LD A,(TRKNBR) ;GET THE # OF THE TRACK TO BE WRITTEN LD (SKTRAK),A ;AND SAVE IT IN THE SEEK TRACK POINTER WORD LD A,(SCTNBR) ;GET THE SECTOR NUMBER OF THE BUFFER DATA LD B,A ;AND PUT IT IN B TO PASS TO DSKWRT LD HL,(BUFDSK) ;POINTER TO DISK DATA ARRAY FOR BUFFERED DRIVE LD IX,(BUFDSK) ;POINTER TO DISK DATA ARRAY FOR BUFFERED DATA CALL DSKWRT ;ACTUAL WRITE TO DISK JR NZ,WRTBUE ;EXIT IF ERROR DURING WRITE LD (WRTFLG),A ;CLEAR THE WRITE PENDING FLAG LD A,(IX+FLAGOS) ;GET THE DISK DATA ARRAY FLAG WORD AND A,WRPMSK ;CLEAR THE WRITE PENDING FLAG BIT LD (IX+FLAGOS),A ;AND WRITE IT BACK TO MEMORY XOR A,A ;CLEAR THE ACCUMULATOR WRTBUE: POP IX ;RESTORE THE POINTER TO THE CURRENT DISK ARRAY POP BC ;RESTORE THE SECTOR NUMBER AND OFFSET RET ; ; ;****************************************************************************** ; ; D S K W R T ; ; select the disk drive pointed to by register HL ; IF:(no error occurred) ; THEN: ; seek the track indicated in the disk data array ; IF:(no error coourred) ; THEN: ; initialize the retry counter in "RTRYCT" ; DO UNTIL:(write successful or retry count equals zero) ; output the desired sector # to the disk controller ; initialize the DMA chip to perform the desired write ; output the write sector command to the disk controller ; wait for the disk controller status to be valid ; wait for the disk controller to finish the command ; output a disable DMA command to the DMA controller ; input the disk controller final status ; mask off all but the pertinent error bits in the status word ; IF:(an error occurred in the write operation) ; THEN: ; retry count = retry count -1 ; ELSE: ; the write was successful ; IF END: ; DO END: ; IF END: ; IF END: ; set or clear the error flag as appropriate ; return ; ;****************************************************************************** ; ; DSKWRT: CALL SELDRV ;SELECT THE INDICATED DRIVE FOR I/O JR NZ,DSKWRE ;ERROR EXIT IF NO DISKETTE IN THE DRIVE CALL SEEK ;SEEK THE INDICATED TRACK JR NZ,DSKWRE ;ERROR EXIT IF WE COULDN'T FIND IT LD A,RETRYS ;WRITE RETRY COUNTER DSKWR0: LD (RTRYCT),A ;SAVE THE RETRY COUNTER LD A,B ;GET THE SECTOR NUMBER OUT (SCTREG),A ;AND PUT IT IN THE DISK CONTROLLER LD HL,DMAWRT ;POINTER TO THE DMA WRITE INITIALIZATION TABLE CALL INIDMA ;INITIALIZE THE DMA CHIP LD A,WRTCMD ;WRITE SECTOR COMMAND OUT (CMDREG),A ;TO THE DISK CONTROLLER LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSNBSY ;WAIT FOR DISK CONTROLLER NOT BUSY LD A,DABDMA ;DISABLE DMA COMMAND OUT (DMAREG),A ;TO THE DMA CONTROLLER IN A,(STATUS) ;GET THE FINAL DISK CONTROLLER STATUS AND A,WREMSK ;WRITE ERRORS MASK JR Z,DSKWRE ;EXIT IF THE WRITE WAS SUCCESSFUL LD A,(RTRYCT) ;GET THE RETRY COUNTER DEC A ;DECREMENT THE RETRY COUNTER JR NZ,DSKWR0 ;TRY AGAIN IF RETRYS NOT ALL USED LD A,0FFH ;ERROR FLAG DSKWRE: AND A,A ;SET OR CLEAR THE ZERO FLAG RET ; ; ;****************************************************************************** ; ; F I L L B F ; ; set a pointer in register DE to the disk data buffer ; put the desired track # in "SKTRAK" ; read the indicated sector from the dis to the disk data buffer ; IF:(no error occurred on the read from disk) ; THEN: ; save the buffered sector # in "SCTNBR" ; save the buffered track # in "TRKNBR" ; save a pointer to the current disk data array in "BUFDSK" ; clear the error flag in the accumulator ; IF END: ; return ; ;****************************************************************************** ; ; FILLBF: LD DE,DATBUF ;POINTER TO THE DATA BUFFER LD A,(IX+TRAKOS) ;GET THE # OF THE TRACK TO BE READ LD (SKTRAK),A ;AND SAVE IT IN THE SEEK TRACK POINTER WORD CALL DSKRD ;ACTUAL READ FROM DISK JR NZ,FILLBE ;EXIT IF ERROR OCCURRDED ON READ LD A,B ;GET THE SECTOR NUMBER LD (SCTNBR),A ;SAVE IT AS THE SECTOR NUMBER IN THE BUFFER LD A,(IX+TRAKOS) ;GET THE TRACK NUMBER LD (TRKNBR),A ;SAVE IT AS THE TRACK OF SECTOR IN BUFFER LD HL,(CURDSK) ;ADDRESS OF THE CURRENT DISK DATA ARRAY LD (BUFDSK),HL ;SAVE IT AS THE BUFFERED DISK XOR A,A ;CLEAR THE ACCUMULATOR FILLBE: RET ; ; ;****************************************************************************** ; ; D S K R D ; ; set a pointer in HL to the current disk data array ; select the indicated disk drive ; IF:(no error occurred in selecting the drive) ; THEN: ; seek the track indicated in the current disk data array ; IF:(no error occurred in seeking the desired track) ; THEN: ; initialize the retry counter in "RTRYCT" ; DO UNTIL:(read is successful or retry count is equal to zero) ; read the indicated sector from the disk ; IF:(an error occurred trying to read the disk) ; THEN: ; retry count = retry count - 1 ; IF END: ; DO END: ; IF END: ; IF END: ; set or clear the error flag as appropriate ; return ; ;****************************************************************************** ; ; DSKRD: LD HL,(CURDSK) ;POINTER TO THE CURRENT DISK DATA ARRAY CALL SELDRV ;SELECT THE INDICATED DRIVE FOR I/O JR NZ,DSKRDE ;ERROR EXIT IF NO DISK IN DRIVE CALL SEEK ;SEEK THE PROPER TRACK JR NZ,DSKRDE ;ERROR EXIT IF WE COULDN'T FIND IT LD A,RETRYS ;PUT THE RETRY COUNT IN D DSKRD0: LD (RTRYCT),A ;SAVE THE RETRY COUNTER CALL SCTRRD ;TRY TO READ THE SECTOR JR Z,DSKRDE ;EXIT DSKRD1: LD A,(RTRYCT) ;GET THE RETRY COUNTER DEC A ;DECREMENT IT JR NZ,DSKRD0 ;TRY AGAIN IF ALL OUR RETRYS NOT USED UP LD A,0FFH ;ERROR FLAG DSKRDE: AND A,A ;SET OR CLEAR THE ZERO FLAG RET ; ; ;****************************************************************************** ; ; S C T R R D ; ; get the sector # from register B and output it to the disk controller ; initialize the DMA chip for a sector read operation ; output a read sector command to the disk controller ; wait for disk controller status ready ; wait for the disk controller to complete execution of the command ; output a disable DMA command to the DMA controller ; input the final status from the disk controller and mask off all ; but the pertinent error bits ; return ; ;****************************************************************************** ; ; SCTRRD: LD A,B ;GET THE SECTOR NUMBER OUT (SCTREG),A ;OUTPUT THE SECTOR NUMBER TO THE CONTROLLER LD HL,DMARD ;POINT TO THE DMA READ TABLE CALL INIDMA ;INITIALIZE THE DMA CHIP FOR THE READ LD A,RDCMD ;READ SECTOR COMMAND OUT (CMDREG),A ;TO THE DISK CONTROLLER COMMAND REGISTER LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSNBSY ;WAIT FOR DISK CONTROLLER NOT BUSY LD A,DABDMA ;DISABLE DMA COMMAND OUT (DMAREG),A ;TO THE DMA CHIP IN A,(STATUS) ;GET THE FINAL DISK CONTROLLER STATUS AND A,RDEMSK ;READ ERRORS MASK RET ; ; ;****************************************************************************** ; ; S E E K ; ; initialize register D with the retry count ; get the current head position from the current disk data array ; output the head position to the disk controller track register ; DO UNTIL:(seek is successful or retry count equals zero) ; get the desired track # from "SKTRAK" ; output the desired track # to the disk controller data register ; output a "SEEK TRACK" command to the disk controller ; wait for the disk controller data register to be valid ; wait for the disk controller to finish executing the command ; input the final status from the disk controller ; mask off all but the pertinent error bits ; IF:(an error occurred seeking the desired track) ; THEN: ; output a "HOME HEAD" command to the disk controller ; wait for the disk controller status register to be valid ; wait for the disk controller to finish executing the command ; decrement the retry counter in register D ; IF:(retry count is equal to zero) ; THEN: ; set the error return code in the accumulator ; IF END: ; IF END: ; DO END: ; put the current head position in the disk data array ; return ; ;****************************************************************************** ; ; SEEK: PUSH DE ;SAVE THE DE REGISTER PAIR LD D,RETRYS ;ERROR RETRY COUNTER LD A,(SKTRAK) ;GET THE # OF THE TRACK WE DESIRE LD E,A ;STORE IT IN REGISTER E LD A,(IX+HEADOS) ;CURRENT HEAD POSITION OUT (TRKREG),A ;OUTPUT CURRENT HEAD POSITION TO TRACK REGISTER CP A,E ;COMPARE WITH THE DESIRED TRACK JR Z,SEEKE ;NO NEED TO SEEK IF WE ARE ALREADY THERE SEEK0: LD A,E ;MOVE THE DESIRED TRACK # TO THE ACCUMULATOR OUT (DATREG),A ;TO THE DISK CONTROLLER DATA REGISTER LD A,SEKCMD ;SEEK TRACK COMMAND WITH VERIFY OUT (CMDREG),A ;TO THE DISK CONTROLLER LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSNBSY ;WAIT FOR DISK CONTROLLER NOT BUSY IN A,(STATUS) ;GET THE FINAL DISK CONTROLLER STATUS AND A,(SKEMSK) ;SEEK ERROR MASK JR Z,SEEKE ;EXIT IF NO SEEK ERROR LD A,HOMCMD ;HOME HEAD COMMAND OUT (CMDREG),A ;HOME THE HEAD TO START FROM SCRATCH LD A,TMDLAY ;SHORT TIME DELAY CONSTANT CALL WTSTAT ;WAIT FOR DISK CONTROLLER STATUS VALID CALL DSNBSY ;WAIT FOR DISK CONTROLLER NOT BUSY DEC D ;DECREMENT THE RETRY COUNTER JR NZ,SEEK0 ;TRY AGAIN LD A,0FFH ;ERROR FLAG AND A,A ;CLEAR THE ZERO FLAG SEEKE: PUSH AF ;SAVE THE ACCUMULATOR AND FLAGS IN A,(TRKREG) ;GET THE CURRENT HEAD POSITION LD (IX+HEADOS),A ;AND SAVE IT IN THE DISK DATA ARRAY POP AF ;RESTORE THE ACCUMULATOR AND FLAGS POP DE ;RESTORE THE DE REGISTER PAIR RET ; ; ;****************************************************************************** ; ; I N I D M A ; ; move the DMA table address to register IY ; put the address of the DMA data buffer in the DMA initialization table ; DO CASE: ; WHEN:(sector size equals 128 bytes) ; load the BC register with 127 (sector size - 1) ; WHEN:(sector size equals 256 bytes) ; load the BC register with 255 (sector size - 1) ; WHEN:(secotr size equals 512 bytes) ; load the BC register with 511 (sector size - 1) ; WHEN:(sector size equals 1024 bytes) ; load the BC register with 1023 (sector size - 1) ; CASE END: ; move the transfer size from the BC register to the DMA initialization ; table ; initialize the DMA chip with the contents of the indicated DMA ; initialization table ; return ; ;****************************************************************************** ; ; INIDMA: PUSH BC ;SAVE THE BC REGISTER PAIR PUSH HL ;PUT THE DMA TABLE ADDRESS ON THE STACK POP IY ;AND MOVE IT INTO THE Y INDEX REGISTER LD (IY+DBFLSB),E ;SAVE THE LSB OF THE DATA BUFFER LD (IY+DBFMSB),D ;SAVE THE MSB OF THE DATA BUFFER LD A,(IX+SIZEOS) ;GET THE SIZE OF THE BLOCK TO TRANSFER CP A,0 ;IS IT A 128 BYTE SECTOR? JR NZ,INIDM1 ;NO LD BC,127 ;SIZE OF SECTOR MINUS 1 JR INIDM4 ;SKIP THE REST OF THE CASES INIDM1: CP A,1 ;IS IT A 256 BYTE SECTOR? JR NZ,INIDM2 ;NO LD BC,255 ;SIZE OF SECTOR MINUS 1 JR INIDM4 ;SKIP THE REST OF THE CASES INIDM2: CP A,2 ;IS IT A 512 BYTE SECTOR JR NZ,INIDM3 ;NO LD BC,511 ;SIZE OF THE SECTOR MINUS 1 JR INIDM4 ;SKIP THE LAST CASE INIDM3: LD BC,1023 ;MUST BE A 1024 BYTE SECTOR INIDM4: LD (IY+DSZLSB),C ;PUT LSB OF SIZE IN DMA INITIALIZATION TABLE LD (IY+DSZMSB),B ;PUT MSB OF SIZE IN DMA INITIALIZATION TABLE LD C,DMAREG ;ADDRESS OF THE DMA REGISTERS LD B,DMALGT ;LENGTH OF THE DMA INITIALIZATION TABLE OTIR ;INITIALIZE THE DMA CHIP POP BC ;RESTORE THE BC REGISTER PAIR RET ; ; ;****************************************************************************** ; ; S C T R A N ; move the logical sector # from register BC to register HL ; check for a zero translate table address ; IF:(translate table address is not equal to zero) ; THEN: ; move the translate table address into register HL ; add the logical sector # to the table address ; load the HL register with the sector # pointed to by HL ; IF END: ; return ; ;****************************************************************************** ; ; SCTRAN: LD H,B ;MOVE THE SECTOR NUMBER INTO HL LD L,C LD A,D ;CHECK THE XLATE TABLE ADDRESS FOR ZERO OR A,E JR Z,SCTRAE ;EXIT IF THE XLATE TABLE ADDRESS IS ZERO EX DE,HL ;MOVE THE TABLE ADDRESS INTO HL ADD HL,BC ;ADD THE SECTOR NUMBER AS AN OFFSET LD L,(HL) ;GET THE INDICATED SECTOR NUMBER LD H,0 ;CLEAR THE MSB OF THE SECTOR NUMBER SCTRAE: RET ; ; ; ;****************************************************************************** ; ; D S K R D Y ; ; input the contents of the disk controller status register ; mask off all but the "drive not ready" status bit ; return ; ;****************************************************************************** ; ; DSKRDY: IN A,(STATUS) ;GET CONTROLLER STATUS REGISTER AND A,RDYMSK ;MASK OFF ALL BUT THE READY BIT RET ; ;****************************************************************************** ; ; D S N B S Y ; ; DO UNTIL:(disk controller busy equal zero) ; input the disk controller status register ; mask off all but the disk controller busy status bit ; DO END: ; return ; ;****************************************************************************** ; ; DSNBSY: IN A,(STATUS) ;GET CONTROLLER STATUS REGISTER AND A,BSYMSK ;TEST BUSY BIT JR NZ,DSNBSY ;LOOP IF THE CONTROLLER IS STILL BUSY RET ; ; ;****************************************************************************** ; ; W T S T A T ; ; DO UNTIL:(contents of the A register equals zero) ; decrement the A register ; DO END: ; return ; ;****************************************************************************** ; ; WTSTAT: DEC A ;DECREMENT THE DELAY COUNTER JR NZ,WTSTAT ;LOOP IF DELAY NOT EXPIRED RET ; ; ;****************************************************************************** ; ; S E L D R V ; ; wait for the disk controller to be not busy ; get the disk ID character pointed to by register HL ; output the disk ID character to the disk drive select register ; IF:(the drive being selected is a 5.25" drive) ; THEN: ; get a long time delay constant to allow for motor spin up ; ELSE: ; a short delay will do to allow for disk controller status valid ; IF END: ; wait for the specified time delay ; see if a diskette is in the selected drive ; return ; ;****************************************************************************** ; ; SELDRV: CALL DSNBSY ;MAKE SURE THE DISK CONTROLLER ISN'T BUSY LD A,(HL) ;GET THE DISK ID CHARACTER OUT (DSKREG),A ;OUTPUT IT TO THE DISK CONTROLLER AND A,FIVMSK ;IS THIS A 5.25" DRIVE? JR Z,SELDR0 ;NO-SET A SHORT DELAY FOR THE DISK CONTROLLER LD A,MTDLAY ;YES-SET A LONG DELAY FOR THE MOTOR JR SELDR1 ;SKIP THE NEXT INSTRUCTION SELDR0: LD A,TMDLAY ;SHORT DELAY CONSTANT SELDR1: CALL WTSTAT ;WAIT FOR THINGS TO STABILIZE CALL DSKRDY ;SEE IF THE DISK CONTROLLER IS READY RET ; ; ;------------------------------------------------------------------------------ ; ; D I S K I / O S Y S T E M D A T A ; ;------------------------------------------------------------------------------ ; ; RTRYCT: DB 0 ;DISK I/O RETRY COUNTER SKTRAK: DB 0 ;SEEK TRACK POINTER WORD DMAADR: DW 00080H ;DISK BUFFER ADDRESS CURDSK: DW DSKA ;CURRENT DISK POINTER ; ;------------------------------------------------------------------------------ ; ; D I S K D A T A A R R A Y S ; ;------------------------------------------------------------------------------ ; ; DSKA: DB 0 ;DISK A ID# DB 0 ;FLAGS DB 0 ;TRACK# DB 0 ;SECTOR# DB 0 ;PHYSICAL SECTOR SIZE DB 0 ;CURRENT HEAD POSITION DW DPHA ;DISK PARAMETER HEADER ADDRESS ; DSKB: DB 0 ;DISK B ID# DB 0 ;FLAGS DB 0 ;TRACK# DB 0 ;SECTOR# DB 0 ;PHYSICAL SECTOR SIZE DB 0 ;CURRENT HEAD POSITION DW DPHB ;DISK PARAMETER HEADER ADDRESS ; DSKC: DB 0 ;DISK C ID# DB 0 ;FLAGS DB 0 ;TRACK# DB 0 ;SECTOR# DB 0 ;PHYSICAL SECTOR SIZE DB 0 ;CURRENT HEAD POSITION DW DPHC ;DISK PARAMETER HEADER ADDRESS ; DSKD: DS 8 ;DISK D DSKE: DS 8 ;DISK E DSKF: DS 8 ;DISK F DSKG: DS 8 ;DISK G DSKH: DS 8 ;DISK H DSKI: DS 8 ;DISK I DSKJ: DS 8 ;DISK J DSKK: DS 8 ;DISK K DSKL: DS 8 ;DISK L DSKM: DS 8 ;DISK M DSKN: DS 8 ;DISK N DSKO: DS 8 ;DISK O DSKP: DS 8 ;DISK P ; ;------------------------------------------------------------------------------ ; ; D M A I N I T I A L I Z A T I O N T A B L E ; ;------------------------------------------------------------------------------ ; ; READ ADDRESS DMA INITIALIZATION TABLE ; RDATBL: DB 0C3H ;RESET DMA CHIP DB 79H ;WRG0 BASE REG, B>A DW ADRBUF ;DESITNATION BUFFER ADDRESS DB 05H ;# OF BYTES TO XFER-1 DB 00H ;MSB OF # OF BYTES TO XFER DB 14H ;WRG1 BASE REG, A IS MEMORY-INCREMENT DB 28H ;WRG2 BASE REG, B IS I/O-FIXED DB 0C5H ;WRG4 BASE REG, BURST MODE DB DATREG ;PORT B ADDRESS DB 8AH ;WRG5 BASE REG, STOP AT END, READY ACTIVE HIGH DB 0CFH ;LOAD DB 87H ;ENABLE DMA ; ; READ SECTOR DMA INITIALIZATION TABLE ; DMARD: DB 0C3H ;RESET DMA CHIP DB 79H ;WRG0 BASE REG, B>A DW DATBUF ;DESITNATION BUFFER ADDRESS DB 7FH ;# OF BYTES TO XFER-1 DB 00H ;MSB OF # OF BYTES TO XFER DB 14H ;WRG1 BASE REG, A IS MEMORY-INCREMENT DB 28H ;WRG2 BASE REG, B IS I/O-FIXED DB 0C5H ;WRG4 BASE REG, BURST MODE DB DATREG ;PORT B ADDRESS DB 8AH ;WRG5 BASE REG, STOP AT END, READY ACTIVE HIGH DB 0CFH ;LOAD DB 0BBH ;WRG6 READ MASK FOLLOWS DB 7FH ;READ MASK DB 87H ;ENABLE DMA ; ; WRITE SECTOR DMA INITIALIZATION TABLE ; DMAWRT: DB 0C3H ;RESET DMA CHIP DB 79H ;WRG0 BASE REG, B>A DW DATBUF ;DESITNATION BUFFER ADDRESS DB 7FH ;# OF BYTES TO XFER-1 DB 00H ;MSB OF # OF BYTES TO XFER DB 14H ;WRG1 BASE REG, A IS MEMORY-INCREMENT DB 28H ;WRG2 BASE REG, B IS I/O-FIXED DB 0C5H ;WRG4 BASE REG, BURST MODE DB DATREG ;PORT B ADDRESS DB 8AH ;WRG5 BASE REG, STOP AT END, READY ACTIVE HIGH DB 0CFH ;LOAD DB 05H ;WRG0 PORT A IS SOURCE DB 0CFH ;LOAD SOURCE ADDRESS, CLEAR COUNTER DB 87H ;ENABLE DMA ; ; ADDRESS ID DATA BUFFER ; ADRBUF: DS 6 ;ADDRESS ID FIELD BUFFER ; ; ;------------------------------------------------------------------------------ ; ; D I S K I D C H A R A C T E R T A B L E ; ;------------------------------------------------------------------------------ ; DSKIDS: DB 0B1H ;DRIVE A SSSD DB 31H ;DRIVE A SSDD DB 0B2H ;DRIVE B SSSD DB 32H ;DRIVE B SSDD DB 0D4H ;DRIVE C SSSD (5.25" DRIVE) DB 54H ;DRIVE C SSDD (5.25" DRIVE) DW 0 ;DRIVE D DW 0 ;DRIVE E DW 0 ;DRIVE F DW 0 ;DRIVE G DW 0 ;DRIVE H DW 0 ;DRIVE I DW 0 ;DRIVE J DW 0 ;DRIVE K DW 0 ;DRIVE L DW 0 ;DRIVE M DW 0 ;DRIVE N DW 0 ;DRIVE O DW 0 ;DRIVE P ; ; ;------------------------------------------------------------------------------ ; ; F I R S T S E C T O R N U M B E R O N T R A C K T A B L E ; ;------------------------------------------------------------------------------ ; ; FSTSCT: DB 01 ;DRIVE A 8" SSSD DB 01 ;DRIVE A 8" SSDD DB 01 ;DRIVE B 8" SSSD DB 01 ;DRIVE B 8" SSDD DB 01 ;DRIVE C 5.25" SSSD DB 00 ;DRIVE C 5.25" SSDD ; ; ;------------------------------------------------------------------------------ ; ; D I S K P A R A M E T E R H E A D E R S ; ;------------------------------------------------------------------------------ ; DPHA: DW XLATE1 ;TRANSLATION VECTOR DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW DIRBUF ;DIRECTORY BUFFER DW 0 ;DPB ADDRESS DW 0 ;CHECK VECTOR DW ALLOCA ;ALLOCATION VECTOR ; DPHB: DW XLATE1 ;TRANSLATION VECTOR DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW DIRBUF ;DIRECTORY BUFFER DW 0 ;DPB ADDRESS DW 0 ;CHECK VECTOR DW ALLOCB ;ALLOCATION VECTOR ; DPHC: DW 0 ;TRANSLATION VECTOR DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW 0 ;SCRATCH AREA DW DIRBUF ;DIRECTORY BUFFER DW 0 ;DPB ADDRESS DW 0 ;CHECK VECTOR DW ALLOCC ;ALLOCATION VECTOR ; ; ;------------------------------------------------------------------------------ ; ; S E C T O R T R A N S L A T I O N V E C T O R S ; ;------------------------------------------------------------------------------ ; ; SECTOR TRANSLATION VECTOR REFERENCE TABLE ; XLTTBL: DW XLATE1 ;XLATE VECTOR FOR 8" SSSD DW XLATE3 ;XLATE VECTOR FOR 8" SSDD DW XLATE1 ;XLATE VECTOR FOR 8" SSSD DW XLATE3 ;XLATE VECTOR FOR 8" SSDD DW XLATE2 ;XLATE VECTOR FOR 5.25" SSSD DW 0 ;XLATE VECTOR FOR 5.25" SSDD ; ; 8" SINGLE SIDED SINGLE DENSITY SECTOR TRANSLATION VECTOR ; XLATE1: DB 01,07,13,19,25,05,11,17,23,03,09,15,21 DB 02,08,14,20,26,06,12,18,24,04,10,16,22 ; ; 5.25" SINGLE SIDED SINGLE DENSITY SECTOR TRANSLATION VECTOR ; XLATE2: DB 01,07,13,02,08,14,03,09,15 DB 04,10,16,05,11,17,06,12,18 ; ; 8" SINGLE SIDED DOUBLE DENSITY SECTOR TRANSLATION VECTOR ; XLATE3: DB 01,02,13,14,25,26,37,38,49,50,09,10 DB 21,22,33,34,45,46,05,06,17,18,29,30 DB 41,42,03,04,15,16,27,28,39,40,51,52 DB 11,12,23,24,35,36,47,48,07,08,19,20 DB 31,32,43,44 ; ;------------------------------------------------------------------------------ ; ; D I S K P A R A M E T E R B L O C K S ; ;------------------------------------------------------------------------------ ; ; DISK PARAMETER BLOCK REFERENCE TABLE ; DPBTBL: DW SSSD8 ;DATA PARAMETER BLOCK FOR 8" SSSD DW SSDD8 ;DATA PARAMETER BLOCK FOR 8" SSDD DW SSSD8 ;DATA PARAMETER BLOCK FOR 8" SSSD DW SSDD8 ;DATA PARAMETER BLOCK FOR 8" SSDD DW SSSD5 ;DATA PARAMETER BLOCK FOR 5.25" SSSD DW SSDD5 ;DATA PARAMETER BLOCK FOR 5.25" SSDD ; ; 8" SINGLE SIDED SINGLE DENSITY DISK PARAMETER BLOCK ; SSSD8: DW 26 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 242 ;DISK SIZE -1 DW 63 ;DIRECTORY MAXIMUM DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 2 ;OFFSET ; ; 8" SINGLE SIDED DOUBLE DENSITY DISK PARAMETER BLOCK ; SSDD8: DW 52 ;SECTORS PER TRACK DB 4 ;BLOCK SHIFT DB 15 ;BLOCK MASK DB 1 ;EXTENT MASK DW 242 ;DISK SIZE-1 DW 127 ;DIRECTORY MAXIMUM DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 32 ;CHECK SIZE DW 2 ;OFFSET ; ; 5.25" SINGLE SIDED SINGLE DENSITY DISK PARAMETER BLOCK ; SSSD5: DW 18 ;SEC PER TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 71 ;DISK SIZE-1 DW 63 ;DIRECTORY MAXIMUM DB 192 ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 3 ;OFFSET ; ; 5.25" SINGLE SIDED DOUBLE DENSITY DISK PARAMETER BLOCK ; SSDD5: DW 40 ;SECTORS PER TRACK DB 3 ;BLOCK SHIFT DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 194 ;DISK SIZE-1 DW 63 ;DIRECTORY MAXIMUM DB 0C0H ;ALLOC0 DB 0 ;ALLOC1 DW 16 ;CHECK SIZE DW 1 ;OFFSET ; ;------------------------------------------------------------------------------ ; ; D I S K B U F F E R S ; ;------------------------------------------------------------------------------ ; ; DISK DATA BUFFER INFORMATION REGISTERS ; SCTNBR: DB 0 TRKNBR: DB 0 WRTFLG: DB 0 BUFDSK: DW 0 ; ; A L L O C A T I O N V E C T O R S ; ALLOCA: DS 32 ALLOCB: DS 32 ALLOCC: DS 32 ; ; D I R E C T O R Y B U F F E R ; DIRBUF: DS 128 ;DIRECTORY BUFFER ; ; D I S K D A T A B U F F E R ; DATBUF: DS 512 ;DATA BUFFER ; ; END MRSIO