[net.micro.6809] Debugged Newdisk source code

ingoldsby@calgary.UUCP (Terry Ingoldsby) (05/27/86)

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%  The following is a modified (debugged) version of the  %
%  Color Computer OS9 Disk Driver by Dave Lewis.  The     %
%  modifications were made by Terrance Ingoldsby in May   %
%  of 1986 and he accepts the credit or blame associated  %
%  with the mods.  Enjoy.  P.S.  Thanks Dave!             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
From: dml@loral.UUCP (Dave Lewis)
-------------------------------
  Before I am buried in E-mail (short pause to spit out some stray bits)
here is NewDisk.

  Assemble this source using the Microware OS-9 assembler. Ensure that the
files OS9Defs, RBFDefs, SCFDefs and DEFSFile are present in the DEFS directory
(DEFSFile says essentially, USE OS9Defs, USE RBFDefs, USE SCFDefs, USE SYSType)
SYSType is not necessary because NewDisk doesn't reference any of the symbols
defined there.

  Invoke it as: asm newdisk o=newdisk.obj #16k

  Then the fun begins. You must remove the existing CCDisk module from your
OS9Boot file and insert NewDisk. This means making a new system disk.
BIG PROBLEM: The system disk must be single-sided. OS9Gen and Cobbler are
both unable to cope with double-sided disks. If you make one, OS-9 won't mind
but YOU CAN'T BOOT IT UP. 

  This is obviously a major problem, and it severely limits the usefulness of
the NewDisk module. I'm rewriting OS9Gen to automatically handle both single
and double sided disks. It's Friday now and I hope to have it done by Monday.
I hoped to have it done by last Monday, too.

  Despite this, NewDisk can and will read just about any format once installed.
If you set up all your disks as 35-track single siders and stick in a 40-track
double, NewDisk will happily read and write it all day long. The only limit
is the performance of your disk drives. I run a system with /D0 = 40T DS,
/D1 and /D2 = 80T DS. Total storage: 1.8 Megabytes.

  I recommend that even after you have double-sided boot disks, you keep one
35-track single sided system master around for compatibility. It won't limit
your system's performance but it is certain to run on ANYTHING.

  Also, your disk descriptors will control how your disks get formatted. If
the descriptor says single-sided, you will format single-sided disks in that
drive. You may choose to use different descriptors on your drives so you can
format disks several ways without rebooting or using Debug.

  Over the next several days I will be posting a disk descriptor, improved
Dump utility, 80-column directory command, and reposting Separate, my bootfile
breaking utility.

  I'm pleased to see all the interest out there. It tells me OS-9 is alive and
well, despite (or is it because of) its `lack' of me-too IBM compatability.
And now, a word from the sponsor. If anyone out there likes these programs
enough, some $$$ would be much appreciated. I think NewDisk is worth about $5,
the others less because I put less work into them. (Dump took about 5 hours)
For $10 I'll send a disk with all the programs mentioned here, plus some
procedure files and documentation for installing them on several different
system configurations. If you think your system is really unique, tell me what
you've got and I'll make sure it's covered.

  And now ... heeeeere's  NewDisk!!   (groan)
-------------------------------
		Dave Lewis    Loral Instrumentation   San Diego

    sdcc6 ---\     gould9 --\
    ihnp4 ---->-->!sdcc3 ---->--->!loral!dml  (uucp)
    sdcrdcf -/     sdcsvax -/

 Stupidity got us into this mess -- why can't it get us out of it?
-------------------------------
%  Remove everything above and including this line for assembly %

         NAM NewDisk
         TTL Improved OS-9 disk device driver module
*
*  Copyright 1985 by Dave Lewis
*                4417 Idaho apt. 4
*                San Diego, CA 92116
*  Released to public domain January, 1986
*
 IFP1
         USE /D0/DEFS/DEFSFile
 ENDC
*
REV      EQU 1
TYPE     EQU DRIVR+OBJCT
ATTR     EQU REENT+REV
*
N.DRIVES EQU 3 Number of drives supported
DISKRUN  EQU $70 Disk run time after access
NMIVECT  EQU $109 NMI jump vector in RAM
COMDREG  EQU $FF48 1793 Command register (write)
STATREG  EQU $FF48 1793 Status register (read)
TRAKREG  EQU $FF49 1793 Track register
SECTREG  EQU $FF4A 1793 Sector register
DATAREG  EQU $FF4B 1793 Data register
*
         MOD SIZE,NAME,TYPE,ATTR,EXEC,STORG
         FCB $FF Mode byte -- all modes
NAME     FCS 'CCDisk' Still the same module name
         FCB 4 Version number
*
         RMB DRVBEG Storage common to all drives
TABL.ORG RMB DRVMEM Drive 0 parameter table
         RMB DRVMEM Drive 1 parameter table
         RMB DRVMEM Drive 2 parameter table
DRV.ACT  RMB 2 Active drive's table origin
DPRT.IMG RMB 1 Drive control port image byte
DRVS.RDY RMB 1 Drive ready flags
Q.SEEK   RMB 1 Same drive/track flag
STORG    EQU . Total storage required
*
*  Function dispatch vectors
*
EXEC     LBRA INIT Initialize variables
         LBRA READ Read one sector
         LBRA WRITE Write one sector
         LBRA RETNOERR GETSTA call is not used
         LBRA SETSTA Two oddball calls
         LBRA RETNOERR TERM call is not used
*
INIT     CLR >D.DSKTMR Zero disk rundown timer
         LDA #$D0 `Force interrupt' command
         STA >COMDREG
         LDA #$FF
         LDB #N.DRIVES Number of drives
         STB V.NDRV,U
         LEAX TABL.ORG,U Origin of first drive table
INI.TBL  STA DD.TOT+1,X Make total sectors nonzero
         STA V.TRAK,X Force first seek to track 0
         CLR DD.FMT,X Make it see a 1-sided disk
         LEAX DRVMEM,X Go to next drive table
         DECB Test for last table done
         BNE INI.TBL Loop if not finished
         LEAX NMI.SVC,PCR Get address of NMI routine
         STX >NMIVECT+1 NMI Jump vector operand
         LDA #$7E Jump opcode
         STA >NMIVECT NMI Jump vector opcode
         LDA >STATREG Clear interrupt condition
RETNOERR CLRB
         RTS
*
ERR.WPRT COMB Set carry flag
         LDB #E$WP Set error code
         RTS
ERR.SEEK COMB Set carry flag
         LDB #E$SEEK Set error code
         RTS
ERR.CRC  COMB Set carry flag
         LDB #E$CRC Set error code
         RTS
ERR.READ COMB Set carry flag
         LDB #E$READ Set error code
         RTS
*
* All disk controller commands exit via NMI. The service routine
*   returns control to the address on top of stack after registers
*   have been dumped off.
*
NMI.SVC  LEAS R$SIZE,S Dump registers off stack
         LDA >STATREG Get status condition
STAT.TST LSLA Test status register bit 7
         LBCS ERR.NRDY Status = Not Ready if set
         LSLA Test bit 6
         BCS ERR.WPRT Status = Write Protect if set
         LSLA Test bit 5
         LBCS ERR.WRT Status = Write Fault if set
         LSLA Test bit 4
         BCS ERR.SEEK Status = Record Not Found
         LSLA Test bit 3
         BCS ERR.CRC Status = CRC Error if set
         LSLA Test bit 2
         BCS ERR.READ Status = Lost Data if set
         CLRB No error if all 0
RETURN1  RTS
*
READ     TSTB If LSN is greater than 65,536
         BNE ERR.SECT   return a sector error
         LDA #$A4 Set retry control byte
         CMPX #0 Is it sector 0?
         BNE READ2 If not, just read the data
         BSR READ2 If sector 0, read it and
         BCS RETURN1   update drive table
         PSHS Y,X Save X and Y
         LDX PD.BUF,Y Point to data buffer
         LDY DRV.ACT,U Point to active drive's table
         LDB #DD.RES+1 Counter and offset pointer
SEC0LOOP LDA B,X Get byte from buffer
         STA B,Y Store in drive table
         DECB Decrement loop index
         BPL SEC0LOOP Loop until B < 0
         CLRB No error
         PULS X,Y,PC Pull and return
*
WRITE    TSTB If LSN is greater than 65,536
         BNE ERR.SECT   return a sector error
         LDA #$A4 Set retry control byte
         PSHS X,A,CC Save registers
         LBSR DSKSTART Start and select drive
         BCS EXIT.ERR Exit if error
REWRITE  LDX 2,S Get LSN off stack
         LBSR SEEK Position head at sector
         BCS RETRY.WR Try again if seek error
         BSR WRITE2 Write the sector
         BCS RETRY.WR Try again if write error
         TST PD.VFY,Y Check verify flag
         BNE EXIT.NER Exit without verify if off
         BSR VERIFY Verify sector just written
         BCC EXIT.NER Exit if no error
RETRY.WR LDA 1,S Get retry control byte
         LSRA Indicate another try
         STA 1,S Put updated byte back
         BEQ EXIT.ERR If zero, no more chances
         BCC REWRITE If bit 0 was 0, don't home
         BSR HOME Home and start all over
         BCC REWRITE If it homed OK, try again
EXIT.ERR PULS CC Restore interrupt masks
         COMA Set carry for error
         BRA CCDEXIT Finish exit
*
EXIT.NER PULS CC Restore interrupt masks
         CLRB Clear carry -- no error
CCDEXIT  LDA #8 Spindle motor control bit
         STA >DPORT Deselect disk drive
         PULS A,X,PC Pull and return
*
ERR.SECT COMB Set carry flag for error
         LDB #E$SECT Set error code
         RTS
*
READ2    PSHS X,A,CC CC is on top of stack
         LBSR DSKSTART Start drives and test
         BCS EXIT.ERR Abort if not ready
REREAD   LDX 2,S Recover LSN from stack
         LBSR SEEK Position head at sector
         BCS RETRY.RD Try again if seek error
         BSR READ3 Read the sector
         BCC EXIT.NER Read OK, return data
RETRY.RD LDA 1,S Get retry control byte
         LSRA Indicate another try
         STA 1,S Put updated byte back
         BEQ EXIT.ERR If it was all 0, quit
         BCC REREAD If bit 0 was 0, don't home
         BSR HOME Home and start all over
         BCC REREAD If it won't home, quit now
         BRA EXIT.ERR Exit with an error
*
WRITE2   LDA #$A2 `Write sector' command
         BSR RWPREP
WTENTRY  STA >COMDREG Execute command.  This is also an
*                     entry point for the Write Track


WAITWDRQ  STB >DPORT Wait until WD1793 ready for data
*
WRTLOOP  LDA ,X+ Get byte from data buffer
         STA >DATAREG Put it in data register
         STB >DPORT Activate DRQ halt function
         BRA WRTLOOP Loop until interrupted
*
VERIFY   LDA #$82 `Read sector' command
         BSR RWPREP
         STA >COMDREG
WAITVDRQ STB >DPORT
         NOP Give the HALT time to take effect
*
VFYLOOP  LDA >DATAREG Get read data byte
         STB >DPORT Activate DRQ halt function
         CMPA ,X+ Compare to source data
         BEQ VFYLOOP Loop until interrupt if equal
*
         ANDB #$7F Mask off DRQ halt bit
         STB >DPORT Disable DRQ halt function
         LBSR KILLCOMD Abort read command
ERR.WRT  COMB Set carry flag
         LDB #E$WRITE Set error code
         RTS
*
SS.HOME  PSHS X,A,CC Set up stack for exit
         BSR HOME Home drive
         BRA SS.EXIT Skip to empty-stack exit
SS.EXIT4 LEAS 2,S Exit w/4 bytes on stack
SS.EXIT2 LEAS 2,S Exit w/2 bytes on stack
SS.EXIT  BCS EXIT.ERR Exit with error
         BRA EXIT.NER Exit with no error
*
HOME     LBSR DSKSTART Start and select drive
         BCS RETURN2 Return if error
         LDX DRV.ACT,U Point to active drive's table
         CLR V.TRAK,X Set track number to zero
         LDD #$43C Home, verify, allow 3 seconds
         LBSR STEPEX Execute stepping command
RETURN2  RTS
*
SETSTA   LDX PD.RGS,Y Point to caller's stack
         LDB R$B,X Get stacked B register
         CMPB #SS.RESET `Home' call
         BEQ SS.HOME Execute Home sequence
         CMPB #SS.WTRK `Write track' call, used by
         BEQ WRT.TRAK   the Format utility
         COMB If not one of those, it's an
         LDB #E$UNKSVC   illegal setsta call
         RTS
*
READ3    LDA #$82 Read sector command
         BSR RWPREP
         STA >COMDREG
WAITRDRQ STB >DPORT Wait for DRQ before proceeding
         NOP Give the Halt a chance to take effect
*
READLOOP LDA >DATAREG Get data from controller
         STA ,X+ Store in sector buffer
         STB >DPORT Activate DRQ halt function
         BRA READLOOP Loop until interrupted
*
RWPREP   LDX PD.BUF,Y
         LDB DPRT.IMG,U
         BITB #$40
         BEQ RWPREP1
         ORA #8
RWPREP1  LDB #$A8 Set up DRQ halt function
         ORB DPRT.IMG,U  OR in the select bits
         RTS
*
* Write an entire track -- used by Format
*
WRT.TRAK PSHS X,A,CC Set up stack for exit
         LDA R$U+1,X Get track number
         LDB R$Y+1,X Get side select bit
         LDX R$X,X Get track buffer address
         PSHS X,D Save 'em
         LBSR DSKSTART Start and select drive
         BCS SS.EXIT4 Exit if error
         PULS D Get track number and side
         LDX DRV.ACT,U Get drive table address
         BSR SID.PCMP Get drive ready to go
         TST Q.SEEK,U Different drive/track?
         BNE WRT.TRK2 If not, no need to seek
         LDD #$103C Seek, allow 3 seconds
         LBSR STEPEX Execute stepping command
         BCS SS.EXIT2 Exit if error
WRT.TRK2 PULS X Retrieve track buffer address
         LDA #$F0 `Write track' command
         LDB #$A8 Set upt DRQ Halt function
         ORB DPRT.IMG,U OR in the drive select bits
         LBSR WTENTRY Just like a Write Sector
         LBRA SS.EXIT Return to caller
*
SID.PCMP LSRB Bit 0 of B is set for
         BCC SIDE.ONE   side 2 of disk
         LDB DPRT.IMG,U Get drive control image byte
         ORB #$40 Side 2 select bit
         STB DPRT.IMG,U Activate side 2 select
SIDE.ONE CMPA PD.CYL+1,Y If track number exceeds #
         LBHI ERR.SECT   of tracks, return error
SD.PCMP2 LDB PD.DNS,Y Check track density of drive
         LSRB Shift bit 1 (TPI bit) into
         LSRB   carry flag (1 = 96 TPI)
         LDB #20 Precomp starts at track 21
         BCC FORTYTKS   on 48 TPI drives, track 41
         LSLB   on 96 TPI drives
FORTYTKS PSHS B Put B where it can be used
         CMPA ,S+ Does it need precomp?
         BLS NOPRECMP No, skip next step
         LDB DPRT.IMG,U Get drive control image byte
         ORB #$10 Write precompensation bit
         STB DPRT.IMG,U Activate precompensation
NOPRECMP LDB V.TRAK,X Get current track number
         STB >TRAKREG Update disk controller
         CMPA V.TRAK,X Same track as last access?
         BEQ SAMETRAK If so, leave flag set
         CLR Q.SEEK,U Clear same drive/track flag
SAMETRAK STA V.TRAK,X Update track number
         STA >DATAREG Set destination track
         LDB DPRT.IMG,U Get disk control byte
         STB >DPORT Update control port
         RTS
*
* Translate logical sector number (LSN) to physical side, track
*   and sector, activate write precompensation if necessary,
*   and execute seek command. If any error occurs, return error
*   number to calling routine.
*
SEEK     LDD PD.SCT,Y Get #sectors per track
         PSHS X,D Put LSN and sec/trk on stack
         LDD 2,S Get LSN off stack
         CLR 2,S Set up track counter
FINDTRAK INC 2,S Increment track counter
         SUBD ,S Subtract sectors in one track
         BPL FINDTRAK Loop if LSN still positive
         ADDD ,S++ Restore sector number
         INCB Sector numbers start at 1
         STB 1,S Save sector number
         PULS A Get track number
         DECA Compensate for extra count
         LDX DRV.ACT,U Get active table address
         LDB DD.FMT,X See if disk is double sided
         BITB #1 Test #sides bit
         BEQ SEEK2 If one-sided, skip next step
         LSRA Divide track number by 2
         ROLB Put remainder in B bit 0
SEEK2    BSR SID.PCMP Set up precomp and side sel
         PULS B Get sector number
         STB >SECTREG Set destination sector
         TST Q.SEEK,U Same drive/track?
         BNE COMDEXIT If so, no need to seek
         LDD #$143C Seek with verify, allow 3 sec
*   The next instruction is redundant
*        BRA STEPEX Execute stepping command
*
* Execute command in A and wait for it to finish. If it runs
*   normally or aborts with an error it will exit through NMI;
*   if it takes an unreasonable amount of time this routine
*   will abort it and set the carry flag. If the command
*   involves head movement, use STEPEX to set step rate.
* On entry, A contains command code and B contains time limit
*   in 50-millisecond increments.
*
STEPEX   PSHS A Put raw command on stack
         LDA PD.STP,Y Get step rate code
         EORA #3 Convert to 1793's format
         ORA ,S+ Combine with raw command
COMDEX   BSR XWAIT50  Go execute command in A and wait 50 ms
         BCC COMDEXIT Exit if no error
         CMPB #E$NOTRDY Test for the three valid
         BEQ KCEXIT   error codes for a Type 1
         CMPB #E$SEEK   disk controller command --
         BEQ KCEXIT   home, seek or force int-
         CMPB #E$CRC   errupt -- and return the
         BEQ KCEXIT   errors
COMDEXIT CLRB No error, clear carry
         RTS
*
XWAIT50  STA >COMDREG Execute command in A
         CLRA Clear carry flag
WAIT50MS LDX #$15D8 Almost exactly 50 mSec delay
WAITIMER LEAX -1,X Wait specified time for disk
         BNE WAITIMER   controller to issue NMI
         DECB   signaling command completed
         BNE WAIT50MS   or aborted with error
KILLCOMD LDA #$D0 Force interrupt, NMI disabled
         STA >COMDREG Abort command in progress
ERR.NRDY LDB #E$NOTRDY Set error code
KCEXIT   COMA Set carry to flag error
         RTS
*
*
* Get selected drive ready to read or write. If spindle motors are
*   stopped, start them and wait until they're up to operating
*   speed. Check drive number and select drive if number is valid.
*   Monitor index pulses to ensure door is closed, disk inserted
*   and turning, etc. Return appropriate error code if any of
*   these conditions can't be met.
*
DSKSTART TST >D.DSKTMR Are drives already running?
         BNE SPINRDY If so, no need to wait
         CLR DRVS.RDY,U No drives are ready
         LDD #$80B Motor on, wait 550 mSec
         STA >DPORT Start spindle motors
         BSR WAIT50MS Wait for motors to start
SPINRDY  LDA PD.DRV,Y Get drive number
         CMPA V.NDRV,U Test for valid drive #
         BHS ERR.UNIT Return error if not
         LEAX TABL.ORG,U Compute address of active
         LDB #DRVMEM   drive's parameter table
         MUL   TABL.ORG + (D# * tablesize)
         LEAX D,X Add computed offset to origin
         LDA PD.DRV,Y Get drive number again
         LSLA Set corresponding drv select
         BNE NOTDRV0   bit -- 1 for D1, 2 for D2
         INCA Set bit 0 for drive 0
NOTDRV0  TFR A,B Copy select bit
         ORB #$28 Enable double density
         ORCC #INTMASKS Disable IRQ and FIRQ
         STB >DPORT Enable drive
         STB DPRT.IMG,U Set image byte
         CLR Q.SEEK,U Clear same drive/track flag
         CMPX DRV.ACT,U Is this the same drive?
         BNE NEWDRIVE If not, leave flag zeroed
         LDB #$FF Indicate successive accesses
         STB Q.SEEK,U   to the same drive.
NEWDRIVE STX DRV.ACT,U Store table address
         BITA DRVS.RDY,U Has this drive been ready
         BNE DRVRDY   since the motors started?
         PSHS A Save drive select bit
         LDD #$D405 Force int, allow 250 mSec
         BSR COMDEX Look for index pulse
         PSHS CC Save carry flag condition
         BSR KILLCOMD Clear index-pulse NMI state
         PULS CC,A Restore carry flag and A
         BCS RETURN3 Error if no index pulse
DRVRDY   ORA DRVS.RDY,U Set corresponding drive
         STA DRVS.RDY,U   ready flag
         LDA #DISKRUN Restart disk rundown timer
         STA >D.DSKTMR
         LDA >STATREG Clear interrupt condition
         CLRB Return no error
RETURN3  RTS
*
ERR.UNIT COMB Set carry flag
         LDB E$UNIT Set error code
         RTS
*
         EMOD CRC bytes
SIZE     EQU *
         END