.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