Mercurial > hg > Members > kono > nitros9-code
view 3rdparty/drivers/burke/xtos9.src @ 1015:08fcfa9b150a
The gfx module is now in a seperate file
author | roug |
---|---|
date | Tue, 04 Mar 2003 20:07:34 +0000 |
parents | c10820aa211b |
children | 892188818514 |
line wrap: on
line source
******************************************* *** *** *** COPYRIGHT 1990 BURKE & BURKE *** *** ALL RIGHTS RESERVED *** *** *** *** COPYRIGHT 1992 BURKE & BURKE *** *** ALL RIGHTS RESERVED *** *** *** ******************************************* * * CoCo XT Hard Disk Driver Version 2.0 * * For Western Digital WD1002-WX1 (or 27X) Controller. * * The controller can only handle 512 bytes per sector, * so these routines must synthesize 2 logical 256 byte * sectors from each physical 512 byte sector. This * increases the time it takes to read or write a sector. * * To counteract this, the 2nd half of each "even" sector * is retained during a read. If the next read accesses the * "odd" half, the sector contents is read from the "verify" * buffer instead of the hard disk. * * This version can be optimized for a single ST-225 hard disk, * via conditional assembly. Several other parameters can also * be controlled by conditional assembly. * * Conditional assembly control: * * Drives ;Number of drives supported (1-2) * * irqflg ;non-zero to mask IRQ during disk access. * fmtflg ;non-zero if hard formatting supported * fstflg ;non-zero if fast transfers supported * cchflg ;non-zero if read cache supported * vrfflg ;non-zero if write verification supported * tboflg ;non-zero if jump to 2 MHz for block moves * errflg ;non-zero for good error messages * icdflg ;non-zero to ignore C/D status bit * trsflg ;non-zero if optimized for 32 SPT, 4 hd disks * sysram ;non-zero to use system RAM for verf buffer * sizflg ;non-zero if drives may be different sizes * * XLEVEL ;Special level 2 flag -- to use L1 assembler * * Chris Burke Schaumburg, IL 10/14/87 * * Modification History * -------------------- * * Date Who Description * -------- --- ------------------------------------- * 11/20/87 CJB Fixed bug in PARK. * 12/23/87 CJB Corrected table size and location * equates for L2 compatibility. * Deleted support for Level 1, Version * 1.X OS9. * 12/27/87 CJB Added code to grab parameters from * device descriptor if not obtained * by INIT. * 01/28/88 CJB Added support for any slot. * 02/07/88 CJB Changed FORMAT to reset drive parameters * Added speedy read cache algorithm. * Eliminated DIVA, DIVY, etc. * 02/23/88 CJB Recoded for TRSFLG * 03/03/88 CJB Changed module names to BBhdisk etc. * 04/17/88 cjb Modified INIT to call WaitIdl before * shutting off controller interrupts & DMA * Fixed bugs in INIT which confused path * descriptor and device descriptor pointers * 04/21/88 cjb Added code to disable I/O retries after * formatting hard drive. * 06/12/88 cjb Changed to call WaitId2 instead of WaitIdl * 07/01/88 cjb Changed revision from 2 to 3 * 10/10/88 cjb Modified for format error recovery * 05/18/90 cjb Modified copyright * Added support for up to 4 drives * 07/07/91 cjb Rev 2.5 (allow disabling of recalibration) * 04/15/92 cjb Rev 2.6 (speed-ups, bug fix for DBLRDD) * page * * Equates * ifp1 use defsfile use wx2.equ endc * Index into device descriptor (using PD.XXX) DD.BASE equ M$DTYP-PD.OPT DD.HDSK equ $25 ;Start of extra hard disk stuff * Multi-PAK Addresses MPAK equ $FF7F * * Bogus equates for Level 2 * D.DMARq2 equ $008A ;Bogus Level 2 D.DMAReq D.PROC2 equ $0050 ;Bogus Level 2 D.PROC DRVMEM2 equ $26 ;Level 2 drive table size DRVBEG2 equ $0F ;Level 2 start of drive tables * * Bogus equates for Level 1 * D.DMARq1 equ $006A ;Bogus Level 1 D.DMAReq D.PROC1 equ $004B ;Bogus Level 1 D.PROC DRVMEM1 equ $18 ;Level 1 drive table size DRVBEG1 equ $07 ;Level 1 start of drive tables ifne XLEVEL-1 DMASEM set D.DMARq2 ;Level 2 DMA stuff (multi-pak) DPROC set D.PROC2 ;Level 2 process control stuff XDrvBeg set DRVBEG2 XDrvMen set DRVMEM2 else DMASEM set D.DMARq1 ;Level 1 DMA stuff (multi-pak) DPROC set D.PROC1 ;Level 1 process control stuff XDrvBeg set DRVBEG1 XDrvMen set DRVMEM1 endc page * * Module Header * verson equ 2 mod cchend,cchnam,drivr+objct,reent+verson,JmpTbl,endmem fcb DIR.+SHARE.+PEXEC.+PREAD.+PWRIT.+EXEC.+READ.+WRITE. * Dynamic module name generation cchnam equ * ifeq testing fcc "BB" ; (normal name) else fcc "BK" ; (special name) endc ifeq (XLEVEL-1) ;If level 1, ifne irqflg ;If Level 1, Version 1 OS9 fcc /X/ else ;If Level 1, Version 2 OS9 fcc /1/ endc endc ifne fmtflg ;If this driver can format hard disk, fcc /F/ endc ifne tboflg ;If 2MHz transfers supported, fcc /T/ endc ifne trsflg ;If "terse" version fcs /hd/ ;NOTE -- set MSB of last byte else ;If "normal" version fcs /hdisk/ ;NOTE -- set MSB of last byte endc fcb $06 ;revision - 2.6 * Copyright notice fcc /COPR. 1992 BURKE & BURKE/ page * * Static Storage * use hdvars.src page * * Jump table * JmpTbl lbra INIT lbra READ lbra WRITE lbra GETSTA lbra SETSTA lbra TERM ifne sizflg ;If drives may be different sizes, page * * Post-initialization for drives. * * If we ever call a driver routine (other than INIT) * with PARK LSN = 0, we know this drive has not been * initialized. * * Enter w/ Reg-Y = path descriptor pointer, * Reg-U = static storage * * Must save A and B:X as well as Y, U. * * Returns carry set if error initializing drive * PostIni pshs Y,X,D ldb PD.DRV,Y lbsr GOBPtr ;Point Y to extra variables clrb ;Force no carry (success) ldb (PRKLSN-OBSTART+0),Y orb (PRKLSN-OBSTART+1),Y bne PSTI0 ; (branch if OK) * Perform drive info and controller intialization ldy 4,S ;Get path pointer ldy PD.DEV,Y ; get device table pointer ldy V$DESC,Y ; get device descriptor pointer lbsr CtlInit ;Call routine to init. controller * Done initiailizing this drive. PSTI0 puls D,X,Y,PC endc page * * Initialize driver routines * * Reg-Y points to device descriptor * INIT pshs y * This section calls routines that expect a *PATH* descriptor * pointer in Reg-Y leay DD.BASE,Y ;Make Y look like path descriptor to get slot lbsr Semfor ;Wait, then select HD controller. sta >HDRSET ;Reset controller lbsr WaitId2 ;Sleep -- wait for controller to reset *** Extra call to give WD1004 time to reset lbsr WaitId2 ;Sleep -- wait for controller to reset *** ENDK ldy ,S ;Restore y -> device descriptor * Set up controller for non-interrupt, non-DMA operation clr >HDMASK ;Turn off controller interrupts and DMA * Set # of drives we can handle lda #Drives sta V.NDRV,U * Set up drive switching info ifne (Drives-1) ldd #$FFFF std prvdrv,u ; (set PRVDRV unknown, DRVSEM for new drive) std actdrv,u ;Pointer to active drive table else lda #$FF sta DRVSEM,U endc * Enable hardware I/O retries. These will be disabled by a FORMAT * setstat, and will be re-enabled by an INIT call or a reboot. * The main use of this is to disable retries during disk formatting. clr RetryEn,U ;Enable hardware retries * Program controller w/ drive parameters. * Y points to device descriptor. bsr CtlInit ; (also clears BFRFLG,U and changes Y) bcs INIT9 ; (abort if error) * Initialize the drive tables for all drives ldd #(-1) ;Current track is unknown stb XDrvBeg+V.TRAK,U std XDrvBeg+DD.TOT,U ;Set total sectors non-zero to allow LSN0 ifne (Drives-1) stb XDrvBeg+XDrvMen*1+V.TRAK,U ; (do all drives) std XDrvBeg+XDrvMen*1+DD.TOT,U ifge (Drives-3) stb XDrvBeg+XDrvMen*2+V.TRAK,U ; (do all drives) std XDrvBeg+XDrvMen*2+DD.TOT,U endc ifge (Drives-4) stb XDrvBeg+XDrvMen*3+V.TRAK,U ; (do all drives) std XDrvBeg+XDrvMen*3+DD.TOT,U endc endc * Reg-Y points to bogus path descriptor (courtesy of CtlInit). * Wait for drive to be ready. * * Note that WaiDrv returns Reg-B=0 and carry clear to OK, * else reg-B = E$NotRdy and carry set. bsr WaiDrv ;Note: WaiDrv requires *PATH* descriptor * Error hook INIT9 puls Y ;restore saved Y register (DD pointer) bra HDXIT * Generic error-free exit OKXIT clrb * * Generic exit. Restore MULTI-PAK to * slot #4 so floppy disk works, and release semaphore * * Preserves CC and B * * RELEASE also clears the V.WAKE flag. * HDXIT lbsr Release rts * * Wait for drive ready * Assumes reg-Y points to real or bogus path * descriptor (for drive # and step rate) * WaiDrv pshs y,x,a,b clr ,-s ;Time out WaiDr2 lda #WX$TST ;Test drive ready ifne (Drives-1) ;If more than 1 drive ldb PD.DRV,Y ;get drive # endc lbsr DrvCmd bcc WaiDr3 ; (branch if drive ready) dec ,s ;Decrement timeout beq WaiDr4 ; (branch if timeout) lbsr Snooze ;Give drive some time bra WaiDr2 ; then retry. * Timeout WaiDr4 comb ldb #E$NotRdy ;Drive not ready stb 1+1,S * Carry clear if ready, else carry set WaiDr3 leas 1,S ;Discard counter puls a,b,x,y,pc * * Get extra bytes from this drive's descriptor. * Send them to the controller. * * Enter w/ * Reg-Y = Dev Desc pointer, and * Reg-U = static storage pointer. * * Note that if there is a 2nd drive with different * parameters, they must be obtained in a different * manner. * * Modifies Reg-Y to make it look like a bogus *PATH* * descriptor * CtlInit equ * ifne cchflg ;If read cache, clr BFRFLG,U ;Buffer contents invalid endc bsr GetXtra ;Call subroutine DDPTR in Y. * Send drive parameters to controller. Reg-Y points to device * descriptor, but we adjust it to look like a path descriptor. leay DD.BASE,Y ;Make Y look like path descriptor lda #WX$INI ;Command to send drive parameters ifne (Drives-1) ;If more than 1 drive ldb PD.DRV,Y ;get drive # endc lbsr DrvCmd ;Set up drive parameters rts page * * Copy precomp cylinder and park LSN from descriptor * (also gives max. tracks!) * GetXtra ldd DD.HDSK+(PCCYL-OBSTART),Y ;get prec, MSB of park LSN ldx DD.HDSK+(PRKLSN+1-OBSTART),Y ;get rest of park LSN ifne (Drives-1) ; If 2 drives, ifne sizflg ; of different sizes, pshs Y,X,D ldb DD.BASE+PD.DRV,Y ;get drive # lbsr GOBPtr ;get dest. pointer to Y puls D,X std (PCCYL-OBSTART),Y stx (PRKLSN+1-OBSTART),Y puls Y,PC ;Recover DD ptr and exit else ; of same size, std PCCYL,U stx (PRKLSN+1),U ;set up both tables at once std (PCCYL+OBSIZE),U stx (PRKLSN+1+OBSIZE),U rts endc else ; If 1 drive, std PCCYL,U stx (PRKLSN+1),U rts endc page * * Terminate hard disk processing * TERM lbsr Semfor ;Wait on semaphore, select controller bra OKXIT ;Clear semaphore and successful exit * * Dummy routine for GETSTA * GETSTA comb ;Set carry ldb #E$UnkSVC rts page * * Read a sector from disk * * LSN in B:X. If it is 1+OLDLSN, * and the drive # is right, and the * read cache is full, don't even bother * doing address computations * * There are always an even number of sectors * per track, so if the new LSN is the old LSN * with MSB set, we have a winner! We always * store the old LSN with MSB set. * READ equ * ifne cchflg ;If read cache, pshs X,B ;Save LSN lbsr SavSlt ;Save old slot #, but don't change yet tst BFRFLG,U ;Is buffer valid? beq READXX ; (branch if no luck) ifne (Drives-1) lda PD.DRV,Y cmpa PRVDRV,U bne READXX ; (branch if drive different) endc puls B,X cmpx OLDLSN+1,U bne READXY cmpb OLDLSN+0,U bne READXY * Use verify buffer for sector data -- no read necessary! * The OLDLSN and PRVDRV variables are already set right. pshs u,y,x ldb #128 ldx PD.BUF,Y ;Get destination pointer leay vrfbuf,U ;Get source pointer DR0 ldu ,y++ stu ,x++ decb bne DR0 puls x,y,u bra OKXIT3 ;Successful exit * Not a cache read. Restore LSN READXX puls B,X * Save LSN in case we can do a cache read next time. * We always set the LSB of the saved LSN; the BFRFLG * will be set only if the actual LSB is 0! READXY clr BFRFLG,U ;Assume future cache read invalid stb OLDLSN+0,U ;Save LSN for next time pshs B tfr X,D bitb #%00000001 ;If LSB is 0, cache read valid next time bne READXZ com BFRFLG,U ; (cache read next time) READXZ orb #%00000001 ; (always set LSB in possible match) std OLDLSN+1,U puls B endc * Perform normal read -- LSN in B:X lbsr Semfor ;Wait, select hard disk controller slot ifne sizflg ;If drives can be different sizes, lbsr PostIni bcs HDXIT3 endc * Check for LSN0 cmpx #0 ;Check for LSN 0 -- SPECIAL bne NotLS0 tstb bne NotLS0 ** Wants to read LSN 0. ** See if LSN 0 has already been read once. ** ** We must use PD.DTB,Y instead of ACTDRV,U because ** SELDRV has not been called yet. ** ** Actually, we still read -- we just don't update ** the drive table * * pshs X,B ;Save LSN * ifne (Drives-1) ;If 2 drives, * ldx PD.DTB,Y ;Point to drive table * else * leax DRVTBL,U ;Point to drive table * endc * ldd DD.TOT,x ;Get total sectors * cmpd #-1 ; -1 is a special value set by INIT routine * puls B,X ;Restore LSN (always $000000) * bne NotLS0 ;If not -1, LSN 0 already read; no special stuff * Special treatment for LSN0 -- refresh drive table when done bsr DoRead bcs HDXIT3 ldx PD.BUF,y ;Get buffer address pshs Y,X ;Save old buffer and device descriptor ptrs * Note that the SELDRV routine, called by DOREAD, sets up * the drive table pointer in actdrv,U if there are 2 drives. ifne (Drives-1) ;If 2 drives, ldy actdrv,u else leay DRVTBL,U endc ldb #DD.SIZ-1 * Update drive table from buffer RCPY1 lda b,x sta b,y decb bpl RCPY1 puls y,x bra OKXIT3 * Read (not LSN0) NotLS0 bsr DoRead HDXIT3 lbcs HDXIT OKXIT3 lbra OKXIT page * * Utility to read a sector * DoRead lbsr SETUP bcs DORXIT * Entry point for VERIFY VrfRdd ldx PD.BUF,Y ;Get buffer address * General read sector GetSec lda #WX$RDD ;Create "READ SINGLE SECTOR" command lbsr CMEXEC DORXIT rts page * * Write a sector to disk. * * This routine must pre-read the sector in order to * pack 2 logical sectors into 1 physical sector. * This invalidates any data that might have been pre-read * into the verify buffer. * WRITE lbsr Semfor ;Wait, then select HD controller ifne sizflg ;If drives can be different sizes, lbsr PostIni bcs HDXIT3 endc * Pre-read the "other" half of the sector to the verify buffer pshs X,B ;Save LSN lbsr SETUP ;Set up head, track, sector #'s bsr flphlf ;flip LSB of SECNUM ifne cchflg ;If read cache supported clr BFRFLG,u ;2nd half of sector should not be saved endc leax vrfbuf,U ;Use verify buffer bsr GetSec ; (re-use code) puls X,B bcs HDXIT3 ; branch to abort if pre-read fails bsr flphlf ;fix up sector # * Perform the write. The "other" half of the physical sector * has been pre-read into the verify buffer. pshs x,b ;save LSN bsr DoWrit puls x,b bcs HDXIT3 ifne vrfflg ;If verify enabled, tst PD.VFY,Y ;Verify writes? bne OKXIT3 * Verify the write bsr VERIFY bcc OKXIT3 * Verify failed; carry set ldb #E$Write bra HDXIT3 else bra OKXIT3 endc * * Flip LSB of SECNUM. This is used to pre-read the half of the sector * that should not be changed by a write. * flphlf lda secnum,u EORA #1 sta secnum,u rts page * * Utility to write a sector * DoWRIT lbsr SETUP bcs DOWXIT ldx PD.BUF,Y ;Get buffer pointer lda #WX$WRT ;Create "WRITE SINGLE SECTOR" command lbsr CMEXEC DOWXIT rts ifne vrfflg ;If verify supported, * * Verify last sector written * * Don't copy unused part of sector to verify buffer * VERIFY pshs x,b,a ldx PD.BUF,y ;Save buffer pointer pshs x leax vrfbuf,U stx PD.BUF,y ;Force dummy buffer pointer ldx 4,s ;Recover LSN lbsr setup bcs VF1 ifne cchflg ;If read cache supported, clr BFRFLG,u ;Mark don't save 2nd half of sector endc lbsr VrfRdd ;Actual read done here VF1 puls x stx PD.BUF,y ;Restore buffer pointer bcs VRFXIT * Look only at every 8th byte to speed up the verify lda #(256/8) ;Iteration count pshs u,y,a leay vrfbuf,U ;Point at sector buffer tfr x,u * Compare the data read back to the data written VRF1 ldx ,u cmpx ,y bne VRFERR leau 8,u ;next byte leay 8,y dec ,s bne VRF1 bra VRFOK * Error exit VRFERR orcc #$01 * Deallocate temporaries VRFOK puls u,y,a * Generic verify exit VRFXIT puls a,b,x,PC endc page * * Set Status. * * Reg-Y has path descriptor, and Reg-A has status code. * SETSTA lbsr Semfor ;Wait, then select HD controller ifne sizflg ;If drives can be different sizes, lbsr PostIni lbcs HDXIT endc lbsr SELDRV ldx PD.RGS,y ;Point at register stack ldb R$B,x ;Recover service code cmpb #SS.Reset bne SS1 lbsr SEEKT0 bra SSXIT SS1 equ * ifne fmtflg ;If hard formatting supported, cmpb #SS.WTrk bne SS2 bsr FmtTrk bra SSXIT endc SS2 cmpb #SS.SQD bne SS9 bsr PwrDwn bra SSXIT * Error - unrecognized SETSTA code SS9 comb ldb #E$UnkSvc * Generic exit. Return error if carry set. SSXIT lbcs HDXIT lbra OKXIT page * * Power-down (park) disk * PwrDwn equ * * Get park LSN to B:X ifne (Drives-1) ;If 2 drives, lbsr GtPkLSN ;Call routine to get park LSN to B:X else ldb PRKLSN+0,U ldx PRKLSN+1,U endc * Seek to this LSN PwrDn2 lbsr SETUP lbsr SEEK ;Park head at last track rts ifne fmtflg ;If hard format supported * * Format a track. * * Now we format one track at a time. * * At entry Reg-X points to the register packet, * and Reg-Y points to the path descriptor * FmtTrk lda #$80 ;Disable hardware retries sta RetryEn,U ldd R$U,x ;Get track number -- must be zero. cmpd #0 bne FMTXIT ldd R$Y,x ;Check side/density -- MSB must be zero cmpa #0 beq FMT1 * Ignore repeated calls, returning success FMTXIT clrb rts * Perform the format if not write protected FMT1 pshs u,y,x * Proceed, disk not write protected FMT11 equ * * Set up reduced drive characteristics (only legal tracks) lda #WX$XIN ;Bogus command to init. special parameters lbsr CmExec bcs FMTERR * Initialize sector buffer lda #WX$WBF lbsr CmExec bcs FMTERR * Begin formatting at track 0 ldd #$C0FF ;Set initial cylinder to (-1) std ERRHCYL,u * Set up starting track for format FMT2 ldd ERRHCYL,u ;Use last good cylinder anda #%11000000 incb bne FMT3 adda #%01000000 FMT3 std hicyl,U ; (set track number, sector 0) * clr lowcyl,u ;Clear LOWCYL * clr hicyl,u ;Clear HICYL (and sector #) ifne (Drives-1) ;If multiple drives, lda PD.DRV,Y ;Set up drive # ldb #32 mul stb sdhreg,u ;Select correct drive, clear head number else clr sdhreg,u endc lda PD.ILV,Y ;Set interleave factor lsra ; / 2 since physical sectors are 2X sta seccnt,u lda #WX$FMT ;Command to FORMAT ENTIRE DRIVE * lda #WX$FTK ;Command to FORMAT TRACK lbsr CmExec bcs FMT2 ;Try next track if error * Return error code in B, C set or no error, C clear FMTERR pshs b,cc ;Stack error status * Set up correct drive characteristics (park track allowed) lda #WX$INI ;Init. original parameters lbsr CmExec * Get back error status puls cc,b * End of format routine FMTEND puls x,y,u,PC endc * * End of main line of XTOS9.SRC. * "USE" files follow. * page * * Include routines to issue command to controller * and return completion status. * use hdcmd.src page * * Include routines to translate LSN & drive # * to a controller task file. * use hdmath.src page * * Include utility routines. * use hdutil3.src emod cchend equ * end