CMD
.Page
;++
;
; Cmd
;
; Cmd is the commmand interpreter; it looks at the Iob Gobyte and evaluates the
; command to be done. If an interrupt is pending, '81' command will be
; aborted. All commands are checked for the validity of their parameters by
; the "Validate" routine.
;
; REGISTERS
; All = Destroyed
;
; CALLS
; Validate Validates the parameters of the Iob
; Rwts Handles all commands related to the disk
; Seek Moves the heads to Drive/Side/Track
; Call Will call routine
; ClrIst Clears the Interrupt Status Bye
; SetIMsk Enables drives for interrupts using mask byte
; ClrIMsk Disables drives for interrupts using mask byte
; WaitROM Waits for particular GoByte sequence before Cold Restart
; ESAD Will only access ROM; loops forever on until reset
;++
.Page
;++
; For x:=IobSize Downto 0 do Transfer Iob into internal copy
; iiob,x := iob,x;
; "A" reg will be left containing GoByte
;--
Cmd .Equ * ; Entry point for Cmd
Ldy CmdX
Ldx #IobSize ; Move only the eight bytes that are passed
Cmd1 Lda Iob,x ; Fetch
Sta IIob,x ; And deposit
Sta @SaveL,y ; for posterity
Dey
Dex ; Count down
Bpl Cmd1
Sty Cmdx
Iny
Bne $32
Ldy #CmdLeng
Sty CmdX
; If IIob.Gobyte = 81 then
; Goto Rwts
$32 Cmp #RwtsCmd ; Rwts command?
Beq Rwts ; Yes & let Rts from Rwts return to Loop
; Else
; Begin
; In not (IIob.GoByte in [Valid IIob.GoByte]) then
; begin
; Iob.GoByte := 001; Invalid command
; Carry := Clear Command completed
; Return
; end;
; Validate
Cmp #NullCmd ; If null command then exit
Beq CmdNoErr
Sec
Sbc #LwCmdNo ; Subtract lowest command number
Bcc Cmd3 ; Oooops! Not a valid GoByte command
Cmp #CmdNumb+1 ; Number of commands in range
Bcc Cmd5 ; Skip if valid GoByte command
Cmd3 Lda #GErrCmd ; Else signal invalid GoByte
Bne CmdClnUp ; Cleanup & exit
Cmd5 Tax ; Index to command already in A-reg!
Sta HoldInx ; Save index fro the moment
Lda TestGoB,x ; Fetch Parsing for GoByte Commands
Jsr Validate ; And validate it
Bcs CmdClnUp ; Not a valid command
Lda HoldInx ; Get back the index to the command
; If Valid then
; case GoByte of
; 83: Seek Seek to track
; 84: Call Call 6504 address
; 85: ClrIst Clear Ist (Interrupt Status) bits
; 86: SetIMsk Set (enable) bits in IMsk (Interrupt Mask)
; 87: ClrIMsk Clear (disable) bits in Imsk (Interrupt Mask)
; 88: WaitRom Wait in Rom (used by 68K ram test)
; 89: ESAD Jump to self in Rom and never return
; End; {case}
; End;
Asl A ; To index into word table
Tax ; Use command number as index
Jsr Cmd6
Lda HoldInx ; Fetch the index (0..6)
Beq CmdRts ; Skip if comand was a "Seek" command
Cmp #01 ; Also skip if it was a "Call" command
Beq CmdRts
CmdNoErr .Equ *
Lda #0 ; Signal no error
CmdClnUp Sta Iob+ErrStat ; Common error reporting code for Cmd and Rwts
Lda #00
Sta Iob+GoByte ; Allow host to process error (if any)
CmdRts Rts ; And exit
;--
;
; Cmd Jump Table Dispatcher
;
Cmd6 Lda CmdJmp+1,x ; Fetch th ehigh byte
Pha ; Put it on the stack
Lda CmdJmp,x ; Then the low byte
Pha
Rts ; and jump indirect top of stack
CmdJmp .Word Seek-1,Call-1,ClrIst-1,SetIMsk-1,ClrIMsk-1
.Word WaitRom-1,ESAD-1
.Page
;++
;
; Rwts
;
; Rwts (Read Write Track Sector) is the routine that parses and dispatches
; all commands that affect the disk ( except Seek). If no interrupts are
; pending and all parameters are valid, then the memory will be disabled to
; access by the 68K and the proper routine will be called.
;
; REGISTER
; IN
; A = IIob+GoByte
;
; OUT
; All == Destroyed
;
; CALLS
; Validate Validates parameters for Cmd, driven by TestTbl
; Init Set up Global conditions used by most commands
; Read Reads Drive/Side/Track/Sector
; Write Writes Drive/Side/Track/Sector
; Unclamp Unclamps the disk in Drive
; Format Formats the disk in Drive starting at Side/Track
; Verify Reads the disk in Drive starting at Side/Track
; FormTrack Formats single Track on Disk in Drive
; VerTrack Read single Track on Disk in Drive
; ReadBF Read Drive/Side/Track/Sector w/o checksum verify
; WriteBF Writes Drive/Side/Track/Sector w/o checksum creation
; ClpEnty Will clamp disk in drive
;
;++
.Page
Rwts .Equ * ; Entry point for Rwts
; Validate IIob.Command;
; if not valid then
; begin
; Iob.GoByte := Command error
; Carry := Clear
; return from Rwts
; end
; Validate;
; if not valid then return from rwts
; else
; begin
; lock memory
; init
; call command
; Ist := R/W command done
; UpdInt
; end
; end
; return from rwts
;++
Lda OkToGo ; If <> 0 then interrupt is pending
Beq AOk
Lda #GeErrIntr ; Pending interrupt error
NotAOk Jsr CmdClnUp ; Report error
Beq Rw400 ; Send an interrupt back to host
AOk Ldx IIob+Command ; Fetch the command number
Cpx #MaxCmd+1 ; compare against maximum command
Bcc Rwts4 ; Skip if valid
Lda #GeErrCmd ; Signal a command error
Bne NotAOk ; Local error exit handler
Rwts4 Lda TestTbl,X ; Fetch bit mask of parameters to check
Jsr Validate ; Validate return carry clear if OK
Jsr CmdClnUp ; Will clear GoByte and return error code
Bcs Rw400 ; If error the return FDirH
Rwts40 Jsr Init ; Set up global conditions used by most commands
Lda IIob+Command ; Load with command byte
Asl A ; Mult by two to address word entry
Tax ; Put into index register
Jsr Rwts7 ; Push return address on stack and execute cmd
Sta DisL ; Unlock memory
Sta BootH ; Tell 68K that memory is available
Bcc Rwts5 ; If carry clear then no error
Sta Iob+ErrStat ; If error then report this to host
Rw400 .Equ *
Ldy CmdX ; And save for posterity
Cpy #CmdLeng
Bne $10
Ldy #6
Bne $20
$10 Tya
Clc
Adc #7 ; Point at "Speed" byte
Tay
$20 Lda Iob+ErrStat
Sta @SaveL,y
Rwts5 Lda #040 ; Use drive 80
Ora Ist ; Set bit in interrupt status
Sta Ist
Jmp UpdInt
;--
;
; Rwts command dispatcher
Rwts7 Lda RwtsJmp+1,x ; Fetch the high byte of the routine
Pha ; Push it
Lda RwtsJmp,x ; Fetch the low byte of the address
Pha ; Push it to the stack
Sta BootL ; Tell the 68K that memory is disabled
Sta DisH ; Disable address al last possible moment
Rts ; Pop address and jump to it
RwtsJmp .Word Read-1,Write-1,UnClamp-1
.Word Format-1,Verify-1,FormTrak-1,VerTrack-1
.Word ReadBF-1,WriteBf-1,ClpEnty-1
.Page
;++
;
; Validate
;
; Validates the Iob parameters passed from the 68K depending on the
; bit pattern in the A-reg.
;
; REGISTERS
; IN
; A = Parameters in the Iob to be tested:
;
; Bit Contents
; --- --------
; 0 (LSb) Drive and a clamped disk
; 1 Side #
; 2 Sector #
; 3 Track #
; 4 Mask
; 5 Confirmation byte
; 6 Write Protection
; 7 (MSb) Format/Verify parameters
;
; X = Any value
; Y = Any value
;
; OUT
; A = Destroyed
; X = Destroyed
; Y = Destroyed
;
; CALLS
; EnblTest Test for drive being enabled for interrupts
; TrkClss Returns w/ "Y" = class of Track
; ReadDWP Tests for write protected disk
;---
.Page
Validate .Equ * ; Entry point for validate
Sta Temp1 ; Save "A" here during validation
Beq VldNoTst ; If zero then no testing required
Ldx #0E ; Test bits 7-0, use 14. to index word array
Valid1 Lsr Temp1 ; Shift and test the carry bit
Bcc Valid20 ; Bit not set; skip this test
Stx Temp2 ; Save the "X" couinter value
Lda ValJmp+1,x ; Pick up the high byte
Pha ; Put it on the stack
Lda ValJmp,x ; Pick up the low byte
Pha ; Put it too on the stack
Rts ; Jmp to the test
; This is the return point after a successful test
Valid2 Ldx Temp2 ; Restore "X" counter value
Valid20 Dex ; Loop count -2 = next test address index
Dex
Bpl Valid1 ; Will loop until index is negative
VldNoTst Lda #0
Clc ; Signal no errors
Rts
; This the return point after a failed test
Valid3 Sec ; Something went wrong
Rts
;--
;
; Test drive number, if the drive is enabled and for a clamped disk
ValidDr Lda IIob+Drive
Cmp #80 ; Must use 'Lower' drive value
Bne $28
Lda Clamped
Bne $57 ; Yes, there is a clamped disk
$28 Lda #GeErrClm ; No disk in drive error
Bne $57 ; Always taken
$57 Jsr EnblTest ; Test if the drive is enabled
Bcs Valid2 ; Yes, the drive is enabled
Lda #GeErrNA ; Drive not enabled
Bne Valid3 ; Always taken
;--
;
; Test side number
ValidSI Lda #GeErrSid ; Assume error
Ldy IIob+Side
Beq Valid2 ; side 0 is always good
Cpy #01 ; now see if side 1
Bne Valid3 ; Not side 1 either
Ldy #02
Cpy Iob+NoSides ; Will range from 0 to 2 -- must be 2 for dual sided
Bne Valid3 ; Not a dual sided drive
Beq Valid2
;--
;
; Test sector number
ValidSe Jsr TrkClss ; Find track class
Lda IIob+Sector ; New sector number
Cmp SecPrTrk,y ; Compare against max sectors per track class
Bcc Valid2 ; Ok, within limits
Lda #GeErrSec ; Oops, to many
Bne Valid3 ; Always taken
;--
;
; Test track number
ValidTr Lda IIob+Track ; Fetch the track
Cmp #MaxTrack+1 ; And test against the maximum track number
Bcc Valid2 ; Ok, nothing wrong so far
Lda #GeErrTrk ; Track number i too high, signal error
Bne Valid3 ; Always taken
;--
;
; Test mask
ValidCF Inc Iob+FmtCnfM ; If correct byte, this will inc to zero
Beq Valid2 ; Ok, byte was = FF
Lda #GeErrFmPr ; Wrong byte
Bne Valid3 ; Always taken
;--
;
; Test for write protection
ValidWP Jsr ReadWP ; Test for a write protected disk
Bcs Valid2 ; Carry = 1 ==> not protected
Lda #SErrProt ; Write protection error constant
Bne Valid3 ; Always taken
;--
;
; Test for format and verify parameters
ValidFV Lda IIob+Track
Ora IIob+Side ; Must have Trk/Side = 0
Beq Valid2 ; Params are Ok-continue
Lda #GeErrFmPr ; Track/Side <> 0 error
Bne Valid3 ; Always taken
;--
;
; Validation jump table
; Table must be in this order -- Drive must be validated and selected
; prior to checking for write protection
ValJmp .Word ValidFV-1,ValidWP-1,ValidCF-1,ValidMA-1,ValidTr-1
.Word ValidSe-1,ValidSi-1,ValidDr-1
.Page
;++
;
; EnblTest
;
; Test IMsk against X-reg to find out if the drive indexed by x is enabled.
;
;--
;
; REGISTERS
; IN
; A = Any Value
; X = =0, Drive 0; =2, Drive 80
; Y = Any value
; OUT
; A= Destroyed
; X = Unchanged
; Y = Unchanged
; Carry = =Clear, drive not enabled; =Set drive enabled
;
;--
EnblTest .Equ * ; Entry point for EnblTest
Lda #080 ; Drive 80
EnblTst1 And IMsk ; Test against interrupt mask
Adc #0F8 ; Cause overflow if 008 or larger
Rts
.Page
;++
;
; Init
;
; Set up global conditions used by most Rwts commands
;
; REGISTERS
; IN
; A = Any value
; X = Any value
; Y = Any value
;
; OUT
; A = Destroyed
; X = Destroyed
; Y = Unchanged
;
;++
;
; RetryCnt := MaxRetry;
; RecalCnt := MaxRecal;
; Error counters := 0;
Init .Equ * ; Entry point for Init
Lda MaxRetry
Sta RetryCnt
Lda MaxRecal
Sta RecalCnt
Lda MaxDDly ; Motor off delay time
Sta WthHih
Lda IIob+Side
Beq $09
Lda #20 ; If side 1 then set only bit 5
Sta IIob+Side
$09 Lda #00
Sta WtLow ; Reset 3 byte counter
Sta WtMid
Sta RtyFlg ; When = 2 then abort read or write operation
Ldx #ErrLen ; Number of error counters
$12 Sta StSlp,x ; Zero the counter
Dex
Bpl $12 ; Zero based index
Rts
.Page
;++
;
; Call
;
; Calls a routine in the Rom or Ram as specified by the address in AdrL, AdrH.
; This is mostly used by diagnostics. You can always return from the call by
; Executing an Rts.
;
;
; REGISTERS
; IN
; A = Any value
; X = Any value
; Y = Any value
;
; OUT
; A = Destroyed
; X = Destroyed
; Y = Destroyed
;
;++
; First make sure that the motors are off
; then jump off into the blue
Call .Equ * ; Entry point for call
Jsr PrkClr0 ; Park heads, turn off motors & clear GoByte
Jmp @IIob+Adrl ; Jump indirect on the address in the IIob
.Page
;++
;
; ClrIst
;
; Clears selected bits in the Ist (Interrupt Status) and then checks if FDir
; should still be high. Mask should contain a 1 for the bits in Ist to
; be switched off
;
; REGISTERS
; IN
; A = Any value
; X = Any value
; Y = Any value
; OUT
; A = Destroyed
; X = Unchanged
; Y = Unchanged
;
; CALLS
; UpdInt Updates FDir depending in Ist
;
;++
ClrIst .Equ * ; Entry point for ClrIst
Lda IIob+Mask ; Fetch the mask
Eor #0FF ; Ones complement
And Ist ; And with Ist to switch off selected bits
Sta Ist ; Save new Ist
ClrExit Jmp UpdInt ; Calculate new status of FDir
.Page
;++
;
; SetIMsk
;
; Sets (Enables) the interrupt mask fro drive 0 and drive 80 and computes the
; new status if FDir.
;
; REGISTERS
; IN
; A = Any value
; X = Any value
; Y = Any value
; OUT
; A = Destroyed
; X = Unchanged
; Y = Unchanged
;
; CALLS
; UpdInt Update FDir status
;
; Imsk := $88
; Call UpdInt -- will return from UpdInt to caller
;++
SetImsk .Equ * ; Entry point for SetIMsk
Lda IIob+Mask
Ora IMsk
Sta IMsk ; Save the new IMsk value
Jmp UpdInt ; Calculate the new status of FDir
.Page
;++
;
; ClrImsk
;
; Clears (Disables) then IMsk (Interrupt Status) selectivly. Computes new status
; of the FDir.
;
; REGISTERS
; IN
; A = Any value
; X = Any value
; Y = Any value
; OUT
; A = Destroyed
; X = Unchanged
; Y = Unchanged
;
; CALLS
; UpdInt Update FDir
;
; Call UpdInt -- Will return from UpdInt to caller
;++
ClrIMsk .Equ * ; Entry point for ClrIMsk
Lda IIob+Mask
Eor #0FF
And IMsk
Sta IMsk ; Save new IMsk value
Jmp UpdInt ; Calculate new status of FDir