💾 Archived View for mirrors.apple2.org.za › archive › www.textfiles.com › apple › ANATOMY › rwtsdrvr… captured on 2024-08-19 at 03:02:38.
View Raw
More Information
⬅️ Previous capture (2023-01-29)
-=-=-=-=-=-=-
- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*
- *
- RWTSDRVR using WRITE *
- *
- ----------------------------------------------------------------*
- *
- Just as the file manager is used to manipulate entire *
- files at once, RWTS reads or writes disk data one sector at a *
- time. The software interface between these two levels of DOS *
- management is represented by the RWTS driver routines *
- (RWTSDRVR, $B052 and RWTSDRV1, $B058). RWTSDRVR is called any *
- time the file manager wants to seek a given track or read or *
- write a sector of disk data. This routine is always entered *
- with the accumulator containing the RWTS opcode ($00=seek, *
- $01=read, $03=write) and the x- and y-registers housing the *
- target track and sector values. Although RWTSDRV1 is only *
- directly called via the INIT function handler (with the *
- accumlator containing the format ($04) opcode), execution *
- falls into RWTSDRV1 from RWTSDRVR. The driver routines check *
- to see if data are to be output to the disk and condition the *
- carry flag accordingly. The carry is set if the format or *
- write opcodes are detected. After setting up RWTS's parameter *
- list (also known as an input/output block, IOB), the driver *
- calls ENTERWTS ($B7B5). *
- ENTERWTS preserves the conditioned carry flag by pushing *
- the status register on the stack. Next the interrupt disable *
- flag is set to prevent any maskable interrupts from interfer- *
- ring with the real-time subroutines employed by RWTS. *
- Finally, ENTERWTS calls RWTS proper ($BD00) to do the desired *
- function. *
- RWTS selects the appropriate drive and moves the disk arm *
- to the desired track position. Next the opcode is checked to *
- determine what function is to be performed (BEGINCMD, $BDAB). *
- When a write opcode ($02) is detected, the carry flag is *
- cleared and saved on the stack. Execution then fall into the *
- WASWRITE routine ($BDB9). WASWRITE pre-nibbles the data. The *
- source memory bytes are converted to 342 six-and-two encoded *
- bytes and stored in the primary and secondary RWTS buffers. *
- (RWTSBUF1 holds the six-encoded nibbles whereas RWTSBUF2 *
- houses the two-encoded nibbles.) *
- The RDADDR routine ($BF94) is called to locate the addr *
- header of the sector wanted. (If the disk is flawed or *
- "protected" with altered header or checksum bytes, 772 attempts*
- are made to locate the correct address prologue before a *
- re-read is attempted. Simlarly, up to 48 attempts to read the *
- entire address header are allowed between recalibrations. Two *
- recalibrations are permitted before a I/O error message is *
- generated.) Once an address header is successfully read, the *
- volume, track and sector numbers of the address header are *
- compared to the values wanted. If the volume number found *
- does not correspond to the volume number wanted, the write *
- function is aborted with a volume-mismatch error message. *
- Failure to find the expected track or sector numbers causes *
- another attempt to locate the desired address header. If the *
- track numbers did not match, a re-seek is performed before the *
- next read is attempted. *
- Once the correct address header is located, the WRITESEC *
- routine ($B824) is called to write a new data field. First a *
- five-sync gap (gap type 2) is written after the addr epilogue. *
- Next, a new data prologue ("D5 AA AD") is laid down. The *
- encoded data in the RWTS buffers are then EORed together in a *
- weird pattern which is described in the disassembly given *
- below. Each resulting EOR value is used to index a table of *
- disk bytes (DSKNBTBL, $BA29). The disk bytes are taken from *
- the table and written to the disk. After all the data are *
- written, a checksum byte is laid down. The checksum byte is *
- followed by the data epilogue ("DE AA EB") and a single sync *
- byte. After the read mode is selected and the motor is turned *
- off, RWTS exits back into the ENTERWTS routine at at $B7BA. *
- After the saved status byte is thrown off the stack, the *
- carry flag is cleared or set (depending on whether or not RWTS *
- encountered an error). Execution then returns to the caller *
- of ENTERWTS. *
- After updating the last-used volume value in the FM *
- parameter list, the RWTSDRV1 routine checks the carry flag to *
- see if RWTS detected an error. If an error was encountered, *
- the carry is reset and execution returns to the calling *
- routine via ERRWTSDR ($B0A1). If no error was detected, the *
- "BCS ERRWTSDR" instruction at $B09E is skipped and execution *
- returns to the caller of the driving routine with the carry *
- clear. *
- Note that ENTERWTS is the one and only DIRECT caller of *
- RWTS. THE DOS MANUAL recommends the following procedure be *
- employed to call RWTS from an assembly language program: *
- 1) Set up the IOB and DCT tables accordingly. *
- 2) Load the y-register and accumulator with the low and *
- high bytes (respectively) of the address of the IOB. *
- 3) JSR to $3D9. (The instruction at $3D9 normally *
- contains a jump to ENTERWTS.) *
- The execution pattern of RWTS and its associated sub- *
- routines is long, but not particularly complex. On the one *
- hand RWTS is rather simple because it can only perform four *
- types of functions (seek, read, write or format). However, *
- many people find RWTS difficult to understand because: *
- 1) It is the only portion of DOS that uses time-critical *
- code. *
- 2) Two different methods are used to encode information *
- on the disk. *
- 3) The actual method by which the read/write head is *
- moved to different track positions on the disk is not *
- well publicized. *
- Time-critical code and data encoding information are only *
- briefly described below. However, these concepts are clearly *
- explained in chapter 3 of BENEATH APPLE DOS. (When reading *
- this reference, you may find it elcudiating to keep in mind *
- that some protected disks (such as LOCKSMITH by ALPHA LOGIC *
- BUSINESS SYSTEMS ) modify the read/write routines to EOR each *
- sector of data with its sector number.) *
- The positioning of the read/write head is the sole *
- responsibility of the SEEKIT routine ($BE6B). This routine is *
- highly commented in the disassembly given below. The follow- *
- ing comments are applicable to the SEEKIT routine and RWTS in *
- general: *
- - Data are written on the disk in 35 circular paths or *
- concentric circles called tracks. Track $00 is located at *
- the outer edge of the disk, whereas track $22 (#34) is *
- represented by the innermost concentric circle. Each track *
- is divided into 16 segments ($00 to $0F) called sectors. *
- - A disk controller card can be used in any peripheral slot *
- except slot $00. Each of the remaining seven slots ($01 to *
- $07) can contain a controller card. Two different drives *
- can be operated from one controller card. Therefore, you *
- can hang up to 14 different drives from a single Apple II, *
- II+ or IIe machine. *
- - The disk controller ROM is relocatable and is copied into *
- the computer's memory at $Cs00 to $CsFF (where s = slot *
- number). All drive functions are performed by indirectly *
- referencing base addrs $C000 to $C00F. The motor-on-off, *
- drive selection and read-write switches are indexed with an *
- offset equal to slot * 16. The four different stepper motor *
- magnets are all referenced via the $C080 base addr. The *
- index used = (slot*16)+bits0 & 1 of halftrack# + carry. The *
- slot & bit portions of the index are used to select the *
- desired magnet. The added carry is used to make the *
- effective addr even or odd in order to turn the magnet off *
- or on. The EFFECTIVE addresses for all drive functions are *
- shown below: *
- MAG0FF = $C0s0 ;Turn stepper motor magnet 0 off. *
- MAG0N = $C0s1 ;Turn stepper motor magnet 0 on. *
- MAG1OFF = $C0s2 ;Turn stepper motor magnet 1 off. *
- MAG1ON = $C0s3 ;Turn stepper motor magnet 1 on. *
- MAG2OFF = $C0s4 ;Turn stepper motor magnet 2 off. *
- MAG2ON = $C0s5 ;Turn stepper motor magnet 2 on. *
- MAG3OFF = $C0s6 ;Turn stepper motor magnet 3 off. *
- MAG3ON = $C0s7 ;Turn stepper motor magnet 3 on. *
- MTR0FF = $C0s8 ;Wake up controller and spin disk. *
- ;This switch must be thrown before a *
- ;specific drive (1 or 2) is selected. *
- MTR0N = $C0s9 ;Turn disk drive motor off. *
- SELDRV1 = $C0sA ;Select drive number 1. *
- SELDRV2 = $C0sB ;Select drive number 2. *
- The following addresses are used to read or write data *
- bytes or to check the status of the write protect switch. *
- As shown below, they are always used in specific combinations *
- to evoke a certain range of responses from the controller *
- card. The firmware affected on the controller card is called *
- a logic state sequencer. It is a nibble-based language that *
- only contains six different instructions and is transparent to *
- the monitor ROM disassembler. (See UNDERSTANDING THE APPLE II *
- by Jim Sather for further explaination.) *
- Q6L = $C0sC ;Shift byte in or out of data latch. *
- Q6H = $C0sD ;Load latch from data bus. *
- Q7L = $C0sE ;Prepare to read. *
- Q7H = $C0sF ;Prepare to write. *
- When used in combinations: *
- Q7L plus Q6L = select read sequence and then read a byte. *
- Q6H plus Q7L = check write protect switch and select write *
- sequence. *
- Q7H plus Q6H = select write sequence and load data register *
- with output byte. *
- Q6H plus Q6L = load latch from data bus and write byte. *
- (Must have previously selected Q7H.) *
- - Each disk drive contains two motors. One motor (usually *
- referred to as the "drive motor") spins the disk at a *
- constant speed. (When the drive motor is first turned on, a *
- delay is used to wait for the drive to come up to speed *
- before attempting to read or write disk bytes.) Another *
- motor (called a "stepper motor") moves the read/write head *
- across the disk to position the head at different track *
- positions. *
- - The stepper motor can be envisioned as containing a central *
- magnet on a rotatable shaft and a circle of four fixed *
- magnets (magnets 0 to 3) surrounding the shaft. Each time a *
- peripheral magnet is enegized, the central shaft is rotated *
- until its magnet is in line with the energized peripheral *
- magnet. By turning the fixed peripheral magnets on and off *
- in sequence, we can spin the shaft of the stepper motor. *
- Movement of this shaft causes the read/write head to "step" *
- across the disk. Each time the next magnet in sequence is *
- turned on, the shaft is rotated one quarter turn. One *
- quarter turn of the shaft moves the read/write head half a *
- track width. *
- - Normally, DOS only writes data at even magnet positions *
- because the drive head does not have good enough resolution *
- to distinguish information in adjacent half-track positions. *
- The drive head is stepped to a higher track position as the *
- magnets are turned on and off in ascending order. *
- Similarly, a descending reference to the magnets causes *
- movement to a lower track position. Each time a magnet is *
- turned on or off, a delay is used to give the shaft magnet *
- time to properly align with a peripheral magnet. The amount *
- of delay used is inversely proportional to the acceleration *
- of the motor. An example of the on/delay/off sequence used *
- to step the head from track $02 to track $04 is shown below: *
- 1on - delay - 0off - delay - 2on - delay - 1off - delay - *
- 3on - delay - 2off - delay - 0on - delay - 3off - delay - *
- 0off - delay. *
- Similarly, moving the head from track $04 to track $02 *
- requires the following sequence: *
- 3on - delay - 0off - delay - 2on - delay - 3off - delay - *
- 1on - delay - 2off - delay - 0on - delay - 1off - delay - *
- 0off. *
- Note that the last-energized magnet is always turned off. *
- This is done as a safety measure because magnet-1-on is *
- hard wired into the write protect switch. (The boot process *
- is an exception to this rule. The controller ROM leaves *
- magnet0 energized.) *
- - Some protected programs modify DOS to skip entire tracks or *
- write data at odd-numbered magnet positions. However, *
- because the controller ROM always uses track $00 and because *
- crosstalk occurs when data is less than one full track width *
- apart, the data is actually written on a half-track disk at *
- the following track positions: 0, 1+1/2, 2+1/2, 3+1/2, ..., *
- 31+1/2, 32+1/2, 33+1/2. For instance, if you wanted to move *
- the head from track $02 to track $04+1/2, you could add the *
- following sequence to that described above: *
- - delay - 1on - delay - 0off - 1 off -delay. *
- - Data can even be written on quarter track positions (that *
- is, tracks 0, 1+1/4, 2+1/4, ..., 31+1/4, 32+1/4, 33+1/4) by *
- turning on two adjacent magnets almost simultaneously in *
- order to position the head between the two magnets. For *
- instance, if you wanted to move from track $02 to track *
- $04+1/4, you could patch DOS to automatically add the *
- following instructions to the normal sequence described *
- above: - 1on - no delay - 0on - very short delay - 1off - *
- no delay - 0off - delay. *
- *
- ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*
(B052)
RWTSDRVR STX IBTRK ;Enter with (x) = trk wntd.
STY IBSECT ; (y) = sector wntd.
RWTSDRV1 STA IBCMD ; (a) = opcode for RWTS.
(B058) ;RWTSDRV1 is the entry point used by the
;Init function handler.
(B05B) CMP #2 ;Is cmd a write?
(B05D) BNE SKPWRSET ;No, so branch. Note: "CMP" conditions:
; (c)=0 if seek ($00) or read ($01).
; (c)=1 if write ($02) or format ($03).
(B05F) ORA UPDATFLG ;Condition UPDATFLG to designate that
(B062) STA UPDATFLG ;last operation was a write for next
;time around.
- Finish setting up RWTS's
- input/output block (IOB).
(B065)
SKPWRSET LDA VOLWA ;Put complimented vol in IOB.
EOR #$FF
STA IBVOL
LDA SLOT16WA ;Put slot*16 in IOB.
STA IBSLOT
LDA DRVWA ;Put drive in IOB.
STA IBDRVN
LDA SECSIZWA ;Put sector length in IOB
STA IBSECSZ ;(standard size of dec. 256
LDA SECSIZWA+1 ;or hex $0100 bytes).
STA IBSECSZ+1
LDA #1 ;ALWAYS designate table type as 1.
STA IBTYPE
LDY ADRIOB ;Set (y) & (a) to point
LDA ADRIOB+1 ;at RWTS's IOB.
(B090) JSR ENTERWTS ;Go call RWTS.
* Route execution to RWTS.
* (Normally entry route to RWTS for custom
* assembly language programs. See preamble
* for required entry conditions.)
(B7B5)
ENTERWTS PHP ;Save status reg (with conditioned carry) on stk.
;(c) = 0 if seek ($00) or read ($01).
;(c) = 1 if write ($02) or format ($03).
(B7B6) SEI ;Set interrupt disable flag to prevent
(B7B7) JSR RWTS ;any further maskable interrupts
;when doing real-time programming.
* Read/Write Track/Sector (RWTS).
* Enter with (y)/(a) pointing at
* RWTS's input/output block (IOB).
(BD00)
RWTS STY PTR2IOB ;Set up a zero page
STA PTR2IOB+1 ;pointer to RWTS's IOB.
LDY #2 ;Initialize cntr for max of 2 recalibs.
STY RECLBCNT
LDY #4 ;Initialize cntr for # or re-seeks betwn recalibs.
STY RSEEKCNT
LDY #1 ;Get slot*16 from IOB & put it
LDA (PTR2IOB),Y ;in (x) so can use it to index
(BD12) TAX ;base addresses for drive functions.
* Check if wntd slot*16 = last slot*16.
(BD13) LDY #15 ;Index to get val of last slot used.
CMP (PTR2IOB),Y ;Compare wanted vs last.
(BD17) BEQ SAMESLOT ;Take branch if using same slot.
* Want to use different slot so reset (x)
* back to index old slot so can test old motor.
(BD19) TXA ;Save slot*16 wanted on stk.
PHA
LDA (PTR2IOB),Y ;Get old slot*16 back and
TAX ;stick it in (x) to index base addrs.
PLA ;Get slot*16 wanted into (a) from stk
PHA ;and keep it saved on stk.
(BD20) STA (PTR2IOB),Y ;Update last-used slot*16 for next time.
* Check to see if last-used drive assoc with last-
* used slot is still spinning. If it is, wait for
* it to stop.
(BD22) LDA Q7L,X ;Prep latch for input.
CKSPIN LDY #8 ;Set cntr to insure at least 8 chks.
LDA Q6L,X ;Strobe latch to read.
CHKCHNG CMP Q6L,X ;Read again & cmp to last read.
BNE CKSPIN ;Data changed, so still spinning.
DEY ;No change, so chk with some
(BD30) BNE CHKCHNG ;delays just to make sure.
* Get index for slot wanted.
(BD32) PLA ;Get slot*16 back off stk
(BD33) TAX ;and put it in (x).
* Chk to see if a drive assoc with slot wanted
* is still spinning. (As soon as get a change then
* know it's spinning. If no change, chk at least
* 8 times to be certain it is off.)
(BD34)
SAMESLOT LDA Q7L,X ;Set read mode.
LDA Q6L,X ;Strobe latch to read.
LDY #8 ;Set cntr for 8 chks if needed.
STRBAGN LDA Q6L,X ;Strobe latch again.
PHA ;Delay 14 machine cycles.
PLA
PHA
PLA
STX SLOTPG5 ;Save slot*16 wntd in page 5.
CMP Q6L,X ;Has data changed yet?
BNE DONETEST ;Yes - data changed, so disk spinning.
DEY ;No - no change, see if chkd enough times.
BNE STRBAGN ;Chk at least 8 times.
DONETEST PHP ;Save test results on stk so can later
(BD4E) ;chk if need extra delay or not.
* Turn motor on in a drive assoc with slot wanted
* (just in case it wasn't already spinning).
* Note: This uses drive with same # as last
* drive used. This may or may not be the
* specific drive # we want. However, we must use
* this instruction to send power via the controller.
* Once this switch is thrown, we can later re-route
* that power to whichever drive we want by throwing
* another switch to select drive1 or drive2.
(BD4F) LDA MTRON,X ;Turn motor on.
* Establish z-page pointers to device characteristic
* table (DCT) and RWTS's I/O buffer (so can use z-page
* indirect addressing modes).
* IBDCTP ---> PTR2DCT (3C,3D)
* IBBUFP ---> PTR2BUF (3E,3F)
(BD52) LDY #6 ;Get ptrs from RWTS's IOB
MOVPTRS LDA (PTR2IOB),Y ;and put them in z-page.
(BD56) STA: PTR2DCT-6,Y ;(Note: ":" used to force
;a 3-byte instruction.)
(BD59) INY
CPY #10 ;4 bytes to copy (6 to 9).
(BD5C) BNE MOVPTRS
* Check drive status.
(BD5E) LDY #3 ;Save hi byte of motor-on-time
LDA (PTR2DCT),Y ;count in z-page.
STA MTRTIME+1
LDY #2 ;Get drive # wanted.
LDA (PTR2IOB),Y
LDY #16 ;Set (y) = index to last-used drive.
CMP (PTR2IOB),Y ;Drv wanted vs drv last used.
BEQ SAMEDRV
(BD6E) STA (PTR2IOB),Y ;Designate drv wntd as old drv
;for next time around.
(BD70) PLP ;Get status back off stk.
(BD71) LDY #0 ;Reset status (z-flag off) to signal that
;SPECIFIC DRIVE # we want in SPECIFIC SLOT
;wanted was not originally spinning.
(BD73) PHP ;Push updated status back on stk.
SAMEDRV ROR ;Put low bit of drv wanted in carry.
BCC USEDRV2 ;Branch if want drive 2.
LDA SELDRV1,X ;Route power to select drive 1.
BCS USEDRV1 ;ALWAYS.
USEDRV2 LDA SELDRV2,X ;Route power to select drive 2.
USEDRV1 ROR DRVZPG ;Put sign bit for which drive
(BD7F) ;using in z-page: neg = drive1.
; pos = drive2.
* Chk to see if a specific drive wanted in
* specific slot wanted was originally on or not.
(BD81) PLP ;Get previous test result.
PHP ;Put it back on stk for later use.
(BD83) BNE WASON ;Orig drv in orig slot was on.
* Specific drive wanted in specific slot
* wanted was ORIGINALLY OFF, so delay a
* bit to avoid positioning head during
* the period of heavy current flow that
* occurs when motor is turned on. (That
* is, give line/capacitor time to
* bleed down cause motor on/off switch
* requires more current than stepper motor.)
*
* (Amount of delay is not constant cause
* it depends on what is in accum & we don't
* know cause we were just accessing hardware.)
(BD85) LDY #7
WAIT4MTR JSR DELAY ;Stall.
(BD87)
* Main delay routine in DOS.
* (Amt of delay = 100 * (a) microsecs.)
(BA00)
DELAY LDX #17
DLY1 DEX
BNE DLY1
INC MTRTIME
BNE DLY2
INC MTRTIME+1
DLY2 SEC
SBC #1
BNE DELAY
(BA10) RTS
(BD8A) DEY
BNE WAIT4MTR ;Go stall some more.
(BD8D) LDX SLOTPG5 ;Restore (x) = slot*16.
(BD90)
WASON LDY #4 ;Get trk wanted.
LDA (PTR2IOB),Y
(BD94) JSR SEEKTRK ;Go move arm to desired trk.
(BE5A)
SEEKTRK PHA ;Save # of trk wntd on stk.
LDY #1 ;Get drive type (1- or 2-phase)
(BE5D) LDA (PTR2DCT),Y ;from DCT. (P.S. the "II" in the
;"DISK II" logo stamped on Apple's
;disk drive denotes a two-phase
;stepper motor.)
(BE5F) ROR ;Put low byte of drive type in carry.
PLA ;Get trk# wanted back in (a).
(BE61) BCC SEEKIT ;Not using standard DRIVEII, using a
;one-phase drive instead, ther4 skip
;doubling of trk # & use SEEKIT as part
;of routine instead of a subroutine.
* Using a two-phase drive.
(BE63) ASL ;Double trk # wanted to get
;number of 1/2 trk wanted.
(BE64) JSR SEEKIT ;Move disk arm to desired track.
(BE6B)
SEEKIT .
.
.
---------------------------------------------
l * Routine/subroutine to move drive arm
l * to a specific trk position.
l * Used as a subroutine when using Apple's
l * disk drive II. Note when SEEKIT is used as a
l * subroutine, DESTRK, PRESTRK, TRK4DRV1, TRK4DRV2,
l * STPSDONE and HOLDPRES are all expressed in half
l * tracks:
l * DESTRK = destination half-track position.
l * PRESTRK = present half-track position.
l * HOLDPRES = present half-track position.
l * TRK4DRV1 = base addr (when indexed by slot*16) pts
l * at the addr that contains the last half-
l * track # that drive 1 was aligned on.
l * TRK4DRV2 = base addr (when indexed by slot*16) pts
l * at the addr that contains the last half-
l * track # that drive 2 was aligned on.
l * STPSDONE = number of half tracks moved so far.
l * If not using a II-phase drive, change all
l * comments that read "half tracks" to read
l * "full tracks".
l (BE6B)
l SEEKIT STA DESTRK ;(a) = 2*trk # wanted.
l ; = # of halftrk wanted.
l (BE6D) JSR SLOTX2Y ;Set (y) = slot.
l
l * Convert slot*16 from
l * (x) to slot in (y).
l (BE8E)
l SLOTX2Y TXA ;Get slot*16 from (x).
l LSR ;Divide it by 16.
l LSR
l LSR
l LSR
l TAY ;Put slot # in (y).
l (BE94) RTS
l
l (BE70) LDA TRK4DRV1,Y ;Pres halftrk# assoc with drv1.
l (BE73) BIT DRVZPG ;Contains: neg = drive 1.
l ; pos = drive 2.
l (BE75) BMI SETPRSTK ;Branch if using drive 1.
l LDA TRK4DRV2,Y ;Using drv 2 so get pres 1/2trk#.
l SETPRSTK STA PRESTRK ;Save present halftrk#.
l (BE7A)
l
l * Designate halftrk we are about to seek
l * as present halftrk for next time around.
l * (Put halftrk info in slot dependent locations.)
l (BE7D) LDA DESTRK
l BIT DRVZPG ;Chk to see which drive we are using.
l BMI DRV1USG ;Branch if using drive 1.
l STA TRK4DRV2,Y ;Using drv2 -store halftrk 4 next time.
l BPL DRV2USG ;ALWAYS.
l DRV1USG STA TRK4DRV1,Y ;Using drv1 -store halftrk 4 next time.
l DRV2USG JMP SEEKABS
l (BE8B) -----------
l
l * Move disk arm to a given halftrk position.
l * On entry: (x) = slot *16.
l * (a) = destination halftrack pos'n.
l * PRESTRK = current halftrack pos'n.
l
l (B9A0)
l SEEKABS STX SLT16ZPG ;Save slot*16 in z-page.
l STA DESTRK ;Save destin halftrk #.
l CMP PRESTRK ;Dest halftrk = pres halftrk?
l BEQ ARRIVED ;Yes - we are already there, so exit.
l LDA #0 ;Init counter 4 # of halftrks moved.
l (B9AB) STA STPSDONE
l
l * Save current halftrk pos'n & calc
l * number of halftrks need to move minus 1.
l (B9AD)
l SAVCURTK LDA PRESTRK ;Save current halftrk pos'n.
l STA HOLDPRES
l SEC ;Calc (PRESTRK - DESTRK).
l SBC DESTRK
l BEQ ATDESTN ;At destin halftrk so go shutdown.
l (B9B7) BCS MOVDWN ;Pres halftrk > destin halftrk so
l ;want to move to lower trk.
l
l * Want to move to a higher halftrk #
l * (PRESTRK - DESTRK = neg result).
l
l (B9B9) EOR #$FF ;Convert neg to pos.
l (B9BB) INC PRESTRK ;Moving up, so inc current 1/2
l ;trk pos'n for next time around.
l (B9BE) BCC CKDLYNDX ;ALWAYS.
l ------------
l
l * Want to move to lower halftrk #
l * (PRESTRK - DESTRK = pos result).
l (B9C0)
l MOVDOWN ADC #$FE ;Simulate a subtract of 1. Actually
l ;adding minus 1 (#$FF) cause carry
l ;set. Want (a) to equal 1 less than
l ;number of halftrks to move.
l (B9C2) DEC PRESTRK ;Moving down so reduce pres 1/2
l ;trk number for next time around.
l
l * Check to see which index to use to
l * access the delay table. IF WE ARE
l * WITHIN 12 STEPS of the destination
l * or start positions, then use closest
l * distance to start or end pos'n to
l * index delay tables. Delay tables are
l * only 12 bytes long, so if more than 12
l * steps away from both start & destination,
l * then use last index (y=12) to access table.
l
l * Check if closer to destination or start pos'n.
l (B9C5)
l CKDLYNDX CMP STPSDONE ;Compare # of halftrks moved
l ;to # of halftrks need to move.
l (B9C7) BCC CLSR2ND ;Branch if closer to destn than start posn.
l
l * Closer to start.
l (B9C9) LDA STPSDONE ;Set (a) = dist from start pos'n.
l CLSR2ND CMP #12 ;Are we within 12 steps of start
l ;or destination pos'n?
l (B9CD) BCS TURNON ;We are at or beyond 12 steps from
l ;start or destn pos'n so use old
l ;index to access delay table.
l (B9CF)
l PRESNDX TAY ;Use present distance to index delay table.
l TURNON SEC ;Set carry so get odd index to base addr so
l (B9D0) ;magnet will be turned ON.
l (B9D1) JSR ONOROFF ;Turn magnet ON to suck stepper motor
l ;to correct halftrack pos'n.
l
l (B9EE)
l ONOROFF LDA PRESTRK ;Use lwr 2 bits of
l ENTRYOFF AND #%00000011 ;1/2 trk pos'n to
l ;index magnet.
l (B9F3) ROL ;2*halftrack+(c).
l ;If carry set,
l ;result is odd &
l ;magnet is energized.
l (B9F4) ORA SLT16ZPG ;Merge index to magnet
l ;with slot #.
l (B9F6) TAX ;Use (x) for indexing.
l (B9F7) LDA MAG0FF,X ;Use magnet0 off as
l ;base address.
l (B9FA) LDX SLT16ZPG ;Restore (x)=slot*16.
l ARRIVED RTS
l (B9FC)
l
l (B9D4) LDA ONTABLE,Y ;Get time 2 leave magnet on from tbl.
l (B9D7) JSR DELAY ;Delay to give drive time to act before
l ;magnet is turned off again cause computer
l ;too fast 4 peripheral & want smooth mov't.
l
l * Main delay routine in DOS.
l * (Amt of delay = 100 * (a) microsecs.)
l (BA00)
l DELAY LDY #17
l DLY1 DEX
l BNE DLY1
l INC MTRTIME
l BNE DLY2
l INC MTRTIME+1
l DLY2 SEC
l SBC #1
l BNE DELAY
l (BA10) RTS
l
l (B9DA) LDA HOLDPRES ;Get last halftrk pos'n in (a).
l (B9DE) CLC ;Clr carry so index will come out even
l ;and there4 magnet will be turned OFF.
l (B9DD) JSR ENTRYOFF ;Turn magnet assoc with prev pos'n off.
l
l (B9F1)
l ENTRYOFF AND #%00000011 ;Halftrk pos'n to
l ;index magnet.
l (B9F3) ROL ;2*halftrack+(c).
l ;If carry set,
l ;result is odd &
l ;magnet is energized.
l (B9F4) ORA SLT16ZPG ;Merge index to magnet
l ;with slot #.
l (B9F6) TAX ;Use (x) for indexing.
l (B9F7) LDA MAG0FF,X ;Use magnet0 off as
l ;base address.
l (B9FA) LDX SLT16ZPG ;Restore (x)=slot*16.
l ARRIVED RTS
l (B9FC)
l
l (B9E0) LDA OFFTABLE,Y ;Get time 2 leave magnet off from table.
l (B9E3) JSR DELAY ;Leave magnet off for a while to give
l ;arm time to be properly aligned.
l ;(Need time to suck it over & also to
l ;decrease bounce or over-shoot.)
l
l * Main delay routine in DOS.
l * (Amt of delay = 100 * (a) microsecs.)
l (BA00)
l DELAY LDY #17
l DLY1 DEX
l BNE DLY1
l INC MTRTIME
l BNE DLY2
l INC MTRTIME+1
l DLY2 SEC
l SBC #1
l BNE DELAY
l (BA10) RTS
l
l (B9E6) INC STPSDONE
l (B9E8) BNE SAVCURTK ;ALWAYS.
l ------------
l
l * Arrived at destination halftrack.
l (B9EA)
l ATDESTN JSR DELAY ;Wait for peripheral again.
l
l * Main delay routine in DOS.
l * (Amt of delay = 100 * (a) microsecs.)
l (BA00)
l DELAY LDY #17
l DLY1 DEX
l BNE DLY1
l INC MTRTIME
l BNE DLY2
l INC MTRTIME+1
l DLY2 SEC
l SBC #1
l BNE DELAY
l (BA10) RTS
l
l * Turn last-used magnet off so exit
l * with all phases (ie. magnets) off
l * because MAG1ON is wired into the
l * write-protect switch.
l (B9ED) CLC ;Turn magnet OFF.
l
l * Turn magnet on or off.
l (B9EE)
l ONOROFF LDA PRESTRK ;Use halftrk pos'n 2 index magnet.
l ENTRYOFF AND #%00000011 ;Only keep lwr 2 bits of halftrk#
l (B9F1) ;cause only 4 magents (0,1,2, & 3).
l (B9F3) ROL ;Multiply halftrk# * 2 and add (c).
l ;If (c)=1, result even, magnet off.
l ;If (c)=0, result odd, magnet on.
l (B9F4) ORA SLT16ZPG ;Merge index to magnet with slot #.
l TAX ;Use (x) for indexing.
l LDA MAG0FF,X ;Use magnet-0-off as base addr.
l LDX SLT16ZPG ;Restore slot*16 in (x).
l ARRIVED RTS
l (B9FC)
l--------------------------------------------
.
.
.
-----------------------
l
l
(BE67) LSR PRESTRK ;Calc present whole trk #
;(ie. pres halftrk# / 2).
(BE6A) RTS
* Check to see if motor was originally on.
(BD97) PLP ;Get prev motor test result off stack.
BNE BEGINCMD ;Branch if motor was originally on.
(BD9A) LDY MTRTIME+1 ;Motor wasn't originally on.
;However, we have since turned it on.
;Now check if it has been in long enough.
(BD9C) BPL BEGINCMD ;Motor was on long enough. No need
;to wait any longer.
* Although motor was turned on, it hasn't
* been on long enough to do accurate
* reading of bytes. There4, delay until
* motor on time is 1 second (at which time
* MTRTIME count is zero). (Part of time was
* taken up to seek track.)
(BD9E)
TIME1 LDY #18
TIME2 DEY
BNE TIME2
INC MTRTIME
BNE TIME1
INC MTRTIME+1
(BDA9) BNE TIME1
* Motor is up to speed so now process command.
* (Seek=00, Read=01, Write=02, Format=04.)
* Counters:
* READCNTR = allow up to 48 times to find correct
* addr prologue between re-seeking.
* RSEEKCNT = allow up to 4 re-seeks btwn recalibrations.
* RECLBCNT = allow up to 2 recalibrations.
* (There4, if necessary, allow up to 384
* attempts to find correct prologue addr.)
* Begin RWTS command processing.
(BDAB)
BEGINCMD LDY #12 ;Get cmd from IOB.
LDA (PTR2IOB),Y
BEQ WASEEK ;Branch if cmd was "seek".
CMP #4 ;Was cmd "format"?
(BDB3) BEQ FORMDSK ;Branch if command was "format".
* Command was READ or WRITE
* (opcodes $01 or $02).
(BDB5) ROR ;SET CARRY IF READ CMD (opcode $01).
;CLR CARRY IF WRITE CMD (opcode $02).
(BDB6) PHP ;Save carry denoting cmd on stack.
(BDB7) BCS RESETCNT ;Branch if doing a read.
* Command was a WRITE.
(BDB9)
WASWRITE JSR PRENIBL ;Not applicable to read cmd.
* Prenibble data ($B800-$B829).
* Convert 256 memory bytes into 342
* six-bit nibbles as shown below:
* RWTSBUF1
* BB00: 0 0 00-7 00-6 00-5 00-5 00-3 00-2
* BB01: 0 0 01-7 01-6 01-5 01-4 01-3 01-2
* BB02: 0 0 02-7 02-6 02-5 02-4 02-3 02-2
* . . . . . . . . .
* . . . . . . . . .
* . . . . . . . . .
* BBFF: 0 0 FF-7 FF-6 FF-5 FF-4 FF-3 FF-2
*
* RWTSBUF2
* BC00: 0 0 01-0 01-1 AB-0 AB-1 55-0 55-1
* BB01: 0 0 00-0 00-1 AA-0 AA-1 54-0 54-1
* BB02: 0 0 FF-0 FF-1 A9-0 A9-1 53-0 53-1
* . . . . . . . . .
* . . . . . . . . .
* . . . . . . . . .
* BC54: 0 0 AD-0 AD-1 57-0 57-1 01-0 01-1
* BC55: 0 0 AC-0 AC-1 56-0 56-1 00-0 00-1
*
* Where AC-0 = bit 0 of memory byte which
* is offset #$AC bytes into
* the data sector.
* The following bits are duplicated in
* $BC00 - $BC01 & $BC54 - $BC55 but are
* ignored in $BC00 - $BC01:
* 01-0, 01-1, 00-0, 00-1.
(B800)
PRENIBL LDX #0
LDY #2
PRENIB1 DEY
LDA (PTR2BUF),Y ;Get byte from "data" buffer.
LSR ;Put its lwr 2 bits into RWTSBUF1.
ROL RWTSBUF2,X
LSR
ROL RWTSBUF2,X
STA RWTSBUF1,Y ;Put remaining 6 bits in RWTSBUF1.
INX
CPX #$56
BCC PRENIB1
LDX #0
TYA
BNE PRENIB1 ;Repeat until @ byte of RWTSBUF2 has 6 bits.
LDX #$55 ;Make sure bits 6 & 7 of RWTSBUF2
PRENIB2 LDA RWTSBUF2,X ;are zeroes.
AND #%00111111
STA RWTSBUF2,X
DEX
BPL PRENIB2
(B829) RTS
* Common to READ or WRITE.
(BDBC)
RESETCNT LDY #48 ;Init counter for reading addr header.
STY READCNTR
SETXSLT LDX SLOT5PG ;Set (x) = slot*16.
(BDC4) JSR RDADDR ;Go read addr header to find sector
;that we want to read or write.
* Read the address header.
(B944)
RDADDR LDY #$FC ;Designate 772 chances (#$FCFC to #$10000)
;to find the correct address prologue.
(B946) STY PROSCRTH
KICKNTR INY
BNE TRYD5
INC PROSCRTH
(B94D) BEQ ERRTN ;Error - can't find prologue.
* Look for address prologue ("D5 AA 96").
(B94F)
TRYD5 LDA Q5L,X
BPL TRYD5 ;Wait for a full byte.
VERSUSD5 CMP #$D5 ;Was it a "D5"?
BNE KICKNTR ;No - try again.
NOP ;Wait 2 cycles.
TRYAA LDA Q6L,X
BPL TRYAA ;Wait for full byte.
CMP #$AA ;Was it an "AA"?
BNE VERSUSD5 ;No - retry sequence.
(B962) LDY #3 ;Set (y) for later reading of
;vol, trk, sec, checksum info
;from address field.
(B964)
TRY96 LDA Q6L,X
BPL TRY96 ;Wait for full byte.
CMP #$96 ;Was it a "96"?
(B96B) BNE VERSUSD5 ;No - retry sequence.
* Read odd-even encoded volume, track,
* sector and checksum values from the
* address field. (When reading,
* calculate a running checksum.)
* From: byte1: 1 b7 1 b5 1 b3 1 b1
* byte2: b6 1 b4 1 b2 1 b0 1
* -------------------------------
* To: byte: b7 b6 b5 b4 b3 b2 b1 b0
(B96D) LDA #0 ;Initialize running checksum val.
CALCK STA CKSUMCAL
GETHDR LDA Q6L,X ;Get odd-encoded byte.
BPL GETHDR ;Wait for a full byte.
(B976) ROL ;Shift bits & put set
;carry in bit0 pos'n.
(B977) STA PROSCRTH ;Save shifted version.
RDHDR LDA Q6L,X ;Get even-encoded byte.
BPL RDHDR ;Wait for full byte.
AND PROSCRTH ;Merge to generate normal memory byte.
(B980) STA: CKSUMDSK,Y ;Store info read from addr
;field in zero page:
;$2F = vol found, $2E = trk found,
;$2D = sec found, $2C = checksum found.
;(Use ":" to force 3-byte instruction.)
(B983) EOR CKSUMCAL ;Update running checksum.
DEY
BPL CALCK
TAY ;Put checksum found in (y).
(B989) BNE ERRTN ;If checksum found < > 0, then error.
* Read first 2 bytes (only) of
* the address epilogue ("DE AA").
(B98B)
TRYEPIDE LDA Q6L,X ;Get first byte.
BPL TRYEPIDE ;Wait for a full byte.
CMP #$DE ;Was it a "DE"?
BNE ERRTN ;No - try again.
NOP ;Stall 2 cycles.
TRYEPIAA LDA Q6L,X ;Get second byte.
BPL TRYEPIAA ;Wait for a full byte.
CMP #$AA ;Was it an "AA"?
BNE ERRTN ;No - retry sequence.
GOODRTN CLC ;Signal good read.
(B99F) RTS
============
(B942)
ERRTN SEC ;Signal bad read.
(B943) RTS
============
(BDC7) BCC RDRIGHT ;Addr read was good.
* Bad address (or data) read.
(BDC9)
REDUCERD DEC READCNTR ;Reduce read counter.
(BDCC) BPL SETXSLT ;Try again.
* Do a recalibration cause exhausted
* all attempts to get a good read.
(BDCE)
DORECALB LDA PRESTRK ;Save trk wanted on stack.
PHA
(BDD2) LDA #96 ;Pretend presently on trk 96
;so force head against stop.
(BDD4) JSR SETTRK ;Go select drive & put trk wanted in
;memory location specific to drive.
(BE95)
SETTRK PHA ;Save present trk on stack.
LDY #2 ;Get drive # wanted from IOB.
LDA (PTR2IOB),Y
(B9EA) ROR ;Condition carry:
; clr=drv1, set=drv2.
(B9EB) ROR DRVZPG ;Condition zero-page loc:
; neg=drv1, pos=drv2.
(BE9D) JSR SLOTX2Y ;Set (y) = slot.
* Convert slot*16 from (x)
* to slot in (y).
(BE8E)
SLOTX2Y TXA ;Get slot*16 from (x).
LSR ;Divide it by 16.
LSR
LSR
LSR
TAY ;(y) = slot.
(BE94) RTS
(BEA0) PLA ;Get trk wanted off stk.
ASL ;Times 2 for half track.
BIT DRVZPG ;Check which drive to use.
BMI STORDRV1 ;Branch if using drive 1.
STA TRK4DRV2,Y ;Save halftrack wanted for drv2.
BPL RTNSETRK ;ALWAYS.
STORDRV1 STA TRK4DRV1,Y ;Save halftrack wanted for drv1.
RTNSETRK RTS
(BEAE)
(BDD7) DEC RECLBCNT ;Reduce recalibration counter.
BEQ DRVERR ;Error - exhausted recalib attempts.
LDA #4 ;Indicate 4 chances to reseek track
STA RSEEKCNT ;between recalibrations.
LDA #0 ;Seek track 0.
(BDE3) JSR SEEKTRK
(BE5A)
SEEKTRK .
.
(See dis'mbly above.)
.
.
(RTS)
(BDE6) PLA ;Get trk wanted from stack.
RESEEK JSR SEEKTRK ;Seek trk wanted.
(BE5A)
SEEKTRK .
.
(See dis'mbly above.)
.
.
(RTS)
(BDEA) JMP RESETCNT ;Go back to try & read again.
------------
* Got a good read.
(BDED)
RDRIGHT LDY TRKDSK ;(y)=trk# found in header.
CPY PRESTRK ;Trk found = trk wanted?
(BDF2) BEQ RTTRK ;Yes - seeked to correct trk.
* Bad seek (or some kind of protection scheme)
* because track wanted < > track found.
(BDF4) LDA PRESTRK ;Save trk wanted on stack.
PHA
TYA ;Set (a) = present trk = trk found.
(BDF9) JSR SETTRK ;Go select drive & put track wanted in
;memory location specific to drive.
(BE95)
SETTRK .
.
(See dis'mbly above.)
.
.
(RTS)
(BDFC) PLA ;Get trk wanted back off stack.
(BDFD) DEC RSEEKCNT ;Allow 4 attempts between recalibrations
;to find the correct trk.
(BE00) BNE RESEEK ;More attempts left to find track.
(BE02) BEQ DORECALB ;ALWAYS - go do a recalibration.
------------
* Got a drive error.
(BE04)
DRVERR PLA
LDA #$40 ;Error code for bad drive.
TOERRWTS PLP
(BE08) JMP RWTSERR
-----------
* Command was seek (null).
(BE0B)
WASEEK BEQ RWTSEXIT ;Not applicable when writing.
-----------
* Command was format ($04).
(BE0D)
FORMDSK JMP FORMAT ;Not applicable when writing.
----------
* Found the correct track for
* the READ or WRITE opcodes.
(BE10)
RTTRK LDY #3 ;Get vol wanted from IOB.
LDA (PTR2IOB),Y
PHA ;Save it on the stack.
LDA VOLDSK ;Get volume found and
LDY #14 ;save it on the IOB.
STA (PTR2IOB),Y
PLA ;Retrieve vol wanted off stk.
BEQ CRCTVOL ;Volume 0 good for all.
CMP VOLDSK ;Vol wanted = vol found?
(BE20) BEQ CRCTVOL ;Yes - got correct vol #.
* Got a volume mismatch.
(BE22) LDA #$20 ;Set code for vol mismatch.
(BE24) BNE TOERRWTS ;ALWAYS.
------------
* Found correct volume, so now
* check if sector is also correct.
(BE26)
CRCTVOL LDY #5 ;Get logical sector # wanted.
LDA (PTR2IOB),Y
TAY ;Set (y) = logical sector # wanted.
LDA PHYSECTR,Y ;Get # of physical sector wanted.
CMP SECDSK ;Phys sec wanted = phys sec found?
BNE REDUCERD ;No - go try again.
(BE32) PLP ;PULL OPERATION FROM STACK.
;Clr carry = write, set carry = read.
(BE33) BCC WRITE ;Branch if command was a write.
* Write data sector.
(BE51)
WRITE JSR WRITESEC
* Write sector to disk ($B82A-$B8B7).
* On entry: (x) = slot *16.
* On exit: if (c) = 1, write-protect error.
* if no error (c) = 0,
* (a) = ?
* (x) = slot*16
* (y) = #$00
(B82A)
WRITESEC SEC ;(c) = 1, assume write-protect error
;as default condition.
(B82B) STX FRMTSLOT ;Save slot*16 in pages 0 and 6.
STX SLOTPG6
LDA Q6H,X ;Chk if disk is write protected.
LDA Q7L,X
BMI PROTECTD ;Branch if write protected.
LDA RWTSBUF2 ;Get first 2-encoded byte & save
(B83B) STA HOLDNIBL ;it for later use.
* Write a 5-sync gap between address
* epilogue and data prologue.
(B83D) LDA #$FF ;(a) = sync byte.
STA Q7H,X ;Write 1 sync byte.
ORA Q6L,X
PHA ;(3 cyc)
PLA ;(4 cyc)
NOP ;(2 cyc)
LDY #4 ;Write 4 more syns (2 cyc).
WRITE4FF PHA ;(3 cyc)
PLA ;(4 cyc)
(B84C) JSR WRITE2 ;(12 cyc before, 6 after.)
(B8B9)
WRITE2 PHA ;(3 cyc)
PLA ;(4 cyc)
WRITE3 STA Q6H,X ;(5 cyc - shift)
ORA Q6L,X ;(4 cyc - strobe)
(B8C1) RTS ;(6 cyc)
(B84F) DEY ;(2 cyc)
(B850) BNE WRITE4FF ;(2 or 3 cyc)
* Write data prologue ("D5 AA AD").
(B852) LDA #$D5 ;(2 cyc)
JSR WRITE1 ;(14 cyc before, 6 after)
(B8B8)
WRITE1 CLC ;(2 cyc)
WRITE2 PHA ;(3 cyc)
PLA ;(4 cyc)
WRITE3 STA Q6H,X ;(5 cyc - shift)
ORA Q6L,X ;(4 cyc - strobe)
(B8C1) RTS ;(6 cyc)
(B857) LDA #$AA ;(2 cyc)
(B859) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
(B85C) LDA #$AD ;(2 cyc)
(B85E) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
* Convert & write contents of
* RWTS buffers to disk.
* Convert & write 2-encoded
* nibbles from RWTSBUF2.
* (EOR to calc (x) & then use (x)
* as index to table of disk bytes.)
*
* #0 EOR $BC55 = (x)
* $BC55 EOR $BC54 = (x)
* $BC54 EOR $BC53 = (X)
* . .
* . .
* . .
* $BC01 EOR $BC00 = (x)
(B861) TYA ;(a) = 0.
LDY #$56 ;(decimal 86)
BNE DOEOR ;Always.
GETNIBL LDA RWTSBUF2,Y
DOEOR EOR RWTSBUF2-1,Y
TAX ;Index to disk byte.
LDA DSKNBTBL,X ;Get disk byte.
LDX FRMTSLOT ;(x) = slot*16.
STA Q6H,X ;Write byte.
LDA Q6L,X
DEY ;(y) = $56 --> $00.
(B879) BNE GETNIBL ;(Write $56 or dec #86 bytes.)
* Convert & write 6-encoded
* nibbles from RWTSBUF1.
*
* $BC00 EOR $BB00 = (x)
* $BB00 EOR $BB01 = (x)
* $BB01 EOR $BB02 = (x)
* . .
* . .
* . .
* $BBFE EOR $BBFF = (x)
(B87B) LDA HOLDNIBL ;Normally = contents of $BC00.
NOP
SCNDEOR EOR RWTSBUF1,Y
TAX ;Index to disk byte.
LDA DSKNBTBL,X ;Get disk byte to write.
LDX SLOTPG6 ;(x) = slot*16.
STA Q6H,X ;Write 87th --> 341st bytes.
LDA Q6L,X
LDA RWTSBUF1,Y
INY ;(y) = #$00 --> #$FF.
(B892) BNE SCNDEOR
* Convert & write data checksum.
* (342nd byte, $BBFF ------> (x).)
(B894) TAX ;Index to table of disk bytes.
LDA DSKNBTBL,X ;Get disk byte to write.
LDX FRMTSLOT ;(x) = slot*16.
(B89A) JSR WRITE3 ;(5 cyc before, 6 after)
(B8BB)
WRITE3 STA Q6H,X ;(5 cyc - shift)
ORA Q6L,X ;(4 cyc - strobe)
(B8C1) RTS ;(6 cyc)
* Write data epilogue ("DE AA EB").
(B89D) LDA #$DE ;(2 cyc)
(B89F) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
(B8A2) LDA #$AA ;(2 cyc)
(B8A4) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
(B8A7) LDA #$EB ;(2 cyc)
(B8A9) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
* Write a sync byte.
(B8AC) LDA #$FF ;(2 cyc)
(B8AE) JSR WRITE1 ;(14 cyc before, 6 after)
;(See dis'mbly above.)
(B8B1) LDA Q7L,X ;Set READ mode.
PROTECTD LDA Q6L,X
(B8B7) RTS
(BE54) BCC RWTSEXIT ;Good write - go exit.
LDA #$10 ;Write protected error code.
(BE58) BCS RWTSERR
-----------
* Signal success or failure & then shut down.
* NOTE: Some references erroneously state that
* the return code is set to zero if no errors
* occur. However, the seek operation always
* sets the return code to zero. Even if a read
* or write operation was successful, the IOB
* return byte will hold a random number (as a
* result of referencing a hardware switch).
(BE46)
RWTSEXIT CLC ;Clr carry to signal successful operation.
HEX 24 ;"BIT $38" to skip "SEC" instruc below.
RWTSERR SEC ;Set carry to signal unsuccessful operation.
LDY #13 ;Store return code in IOB.
STA (PTR2IOB),Y
LDA MTROFF,X ;Turn motor off.
(BE50) RTS
(B7BA) BCS ERRENTER ;Branch if operation unsuccessful.
PLP ;Throw status off stk.
CLC ;Signal successful.
(B7BE) RTS
============
(B7BF)
ERRENTER PLP ;Throw status off stk.
SEC ;Signal UNsuccessful.
(B7C1) RTS
============
(B093) LDA IBSMOD ;Get vol found from IOB
STA VOLFM ;& put it in Fm parm list.
LDA #$FF ;Designate vol wanted in
(B09B) STA IBVOL ;IOB as 255 for next time.
;(Actually using 0 cause FF EOR FF = 0.)
(B09E) BCS ERRWTSDR ;Branch if UNsuccessful operation.
(B0A0) RTS
=============
- Operation was NOT successful.
(B0A1)
ERRWTSDR LDA IBSTAT ;Get RWTS'S error code.
- Translate IOB error code (a) to
- FM error code (y). DOS later
- employs the FM error code in the
- routine used to print error messages.
(B0A4) LDY #7 ;Set (y) for FM error code.
CMP #$20 ;Vol mismatch?
BEQ SETFMERR ;Yes.
LDY #$04 ;No.
CMP #$10 ;Write protected?
BEQ SETFMERR ;Yes.
LDY #8 ;Must have been other, so
SETFMERR TYA ;designate as general I/O error.
(B0B3) JMP BADFMXIT ;Go handler error.
------------
(B385)
BADFMXIT SEC ;(c) = 1 to signal UNsuccessful.
FMEXIT PHP ;Preserve success of operation on stk.
STA RTNCODFM ;Put appropriate return code in FM parm list.
LDA #0 ;Avoid that infamous $48 bug.
STA STATUS
(B38E) JSR CPYFMWA
(AE7E)
CPYFMWA JSR SELWKBUF
* Point the A4L/H pointer at the DOS work buffer (chain).
(AF08)
SELWKBUF LDX #0 ;Designate work area buffer.
(AF0A) BEQ PT2FMBUF ;ALWAYS.
(AF12)
PT2FMBUF LDA WRKBUFFM,X ;Get addr of DOS's work buffer
STA A4L ;(chain) from FM parm list and put
LDA WRKBUFFM+1,X ;it in the A4L/H pointer.
STA A4L+1
(AF1C) RTS
* Copy work area buffer (non-chain)
* to DOS work buffer (chain).
(AE81) LDY #0
STORWRK LDA FMWKAREA,Y
STA (A4L),Y
INY
CPY #45
BNE STORWRK
(AE8D) RTS
(B391) PLP ;Exit with (c) conditioned accordingly.
LDX STKSAV ;Reset the stack pointer so execution will
TXS ;return to the caller of the function.
(B396) RTS ;(Normally returns to AFTRFUNC (A6AB)
============ ;located in the FMDRIVER routine ($A6A8).