                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Module: Command_Driver
;>
;>      This module controls the way in which commands received by
;>      the Host are executed. It's main responsibility is to determine
;>      whether a command string is protected by a check byte ( the
;>      original Profile commands are not ) and then decode the command
;>      and pass control over to the correct driver routine to
;>      execute the command. All exception handling at this level is
;>      controlled by the individual command routines.
;>
;>      PROCEDURE Start_Command
;>      PROCEDURE Pro_Read
;>      FUNCTION Read_Common : BOOOEAN
;>
;>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Start_Command
;>      Inputs   : Assumes a command string in external memory; the
;>                 command byte must be in location $0000 (external )
;>
;>      Algorithm:
;>
;>      BEGIN
;>       Initialize internal and external stack ptrs
;>       ZeroHeader
;>       Excpt_Stat.Buf_Damage := False
;>       Excpt_Stat.Nzero_Stat := False
;>       IF ( Cache_Index >= Cache_Length )
;>        THEN Cache_Index := 0
;>       OpCode := ExtMem[ 0 ]
;>       IF OpCode.CommandType is FreeProcess type
;>        THEN goto Strt_FreeProcess
;>       IF OpCode.CommandType is protected by a checkbyte
;>        THEN
;>         IF NOT( Check_Command_String )
;>          THEN Abort( Cmnd_Driver_Exception,
;>                       Start_Command, CheckByte_Mismatch )
;>       IF ( OpCode.Instruction >
;>              CommandLimit[ CommandType ] )
;>        THEN Abort( Cmnd_Driver_Exception
;>                      Start_Command, IllegalOpCode, OpCode )
;>       JMP @Command^[ CommandType ]. RoutineTable[ Instruction ]
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Start_Command:
                Srp     #Wrk_Sys ;get into a reasonable state
                Clr     Sph
                Ld      Spl,#Stack_Top
                
                Ld      !r2,#.HIBYTE. StackPtr ;init external stack
                Ld      !r3,#.LOWBYTE. StackPtr
                Ld      !r0,#.HIBYTE. TopOfStack
                Lde     @!!r2,!r0
                Incw    !!r2
                Ld      !r0,#.LOWBYTE. TopOfStack
                Lde     @!!r2,!r0
                
                Cp      Cache_Index,#CacheLength
                Jr      Lt,St_Load_Cmnd
                
                Clr     Cache_Index
                
St_Load_Cmnd:    Ld     !r2,#.HIBYTE. Cmnd_Ptr
                 Ld     !r3,#.LOWBYTE. Cmnd_Ptr
                 Ld     !rE,#.HIBYTE. CStatus4
                 Ld     !rF,#.LOWBYTE. CStatus4
                 Ld     !r1,#8 ;move 8 bytes
St_L_Lp:        Lde     !r0,@!!r2
                Lde     @!!rE,!r0
                Incw    !!r2
                Incw    !!rE
                Djnz    !r1,St_L_Lp

Strt_ZH:        Ld      !rE,#.HIBYTE. CStatus4
                Ld      !rF,#.LOWBYTE. CStatus4
                Lde     !r4,@!!rE
                
                Ld      !r6,!r4
                And     !r6,#CmndType
                Cp      !r6,#$F0 ;check for 'free bus command'
                Jr      Nz,Strt_ChkDiag
                
                 Ld     !r2,#.HIBYTE. Strt_FreeProcess
                 Ld     !r3,#.LOWBYTE. Strt_FreeProcess
                Call    Bank_Call

Strt_ChkDiag:   Cp      !r6,#$10 ;check for diagnostic command
                Jr      Nz,Strt_Swap
                
                 Ld     !r2,#.HIBYTE. Set_SeekNeeded
                 Ld     !r3,#.LOWBYTE. Set_SeekNeeded
                Call    Bank_Call
                
                Ld      Seek_Type,#Access_Offset
Strt_Swap:      Swap    !r6                     ;r6 := CommandType
                Jr      Z,Chk_Inst             ;jump if no check byte in string
                
                Ld      !r8,!r4
                And     !r8,#$0F ;get length of command string
                Incw    !!rE ;get opcode
                Lde     !r4,@!!rE
                 Ld     !rE,#.HIBYTE. Cmnd_Ptr
                 Ld     !rF,#.LOWBYTE. Cmnd_Ptr
                Call    Chk_Chk_Byte
                Jr      Z,Chk_Inst
                
                Call    Abort
                
Chk_Inst:       Cp      !r6,#Max_Cmnd_Types     ;check for illegal type
                Jr      Gt,Inst_Abort

                Or      SlfTst_Result,SlfTst_Result ;check if we're not healthy
                Jr      Z,Chk_Limits
                
                Cp      !r6,#01 ;only allow diagnostic commands
                Jr      Z,Chk_Limits
                
                Call    Abort
                
Chk_Limits:     Ld      !rE,#.HIBYTE. Cmnd_Limits
                Ld      !rF,#.LOWBYTE. Cmnd_Limits
                Add     !rF,!r6                 ;get offset into table
                Adc     !rE,#0
                Ldc     !r0,@!!rE               ;get limit
                Ld      !r1,!r4                 ;get instruction
                Cp      !r1,!r0
                Jr      Le,Ok_Inst              ;jump if legal instruction

Inst_Abort:     Call    Abort
                
Ok_Inst:        Ld      !rE,#.HIBYTE. Cmnd_Ptrs
                Ld      !rF,#.LOWBYTE. Cmnd_Ptrs
                Rl      !r6
                Add     !rF,!r6                 ;get offset into table
                Adc     !rE,#0
                Ldc     !rC,@!!rE               ;get inst routine ptr
                Incw    !!rE
                Ldc     !rD,@!!rE
                Rl      !r1
                Add     !rD,!r1                 ;get offset into table
                Adc     !rC,#0
                Ldc     !rE,@!!rC               ;get address to routine
                Incw    !!rC
                Ldc     !rF,@!!rC
                Jp      @!rE                    ;jump to routine

                .Page

;>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Command Routine Tables
;>
;>>>>>>>>>>>>>>>>>>>>>>>>

Cmnd_Limits:    .DB     Pro_Cmnds
                .DB     Diag_Cmnds
                .DB     Sys_Cmnds

Cmnd_Ptrs:      .DW     Pro_Inst
                .DW     Diag_Inst
                .DW     Sys_Inst

Pro_Inst:       .DW     Pro_Read
                .DW     Pro_Write
                .DW     Pro_WrVer
                
Diag_Inst:      .DW     D_Read_ID               ;cmnd 0
                .DW     Read_CStatus            ;cmnd 1
                .DW     Read_SStatus            ;cmnd 2
                .DW     Send_ServoCmnd          ;cmnd 3
                .DW     Send_Seek               ;cmnd 4
                .DW     Send_Restore            ;cmnd 5
                .DW     Set_Recovery            ;cmnd 6
                .DW     $000C ;Soft_Reset       ;cmnd 7
                .DW     Send_Park               ;cmnd 8
                .DW     D_Read                  ;cmnd 9
                .DW     D_ReadHdr               ;cmnd A
                .DW     D_Write                 ;cmnd B
                .DW     Store_Map               ;cmnd C
                .DW     D_Read_SprTbl           ;cmnd D
                .DW     Wr_SprTbl               ;cmnd E  + password
                .DW     Format                  ;cmnd F  + password
                .DW     D_InitSprTbl            ;cmnd 10 + password
                .DW     Read_Abort              ;cmnd 11
                .DW     D_RstSrvo               ;cmnd 12
                .DW     Scan_Vector             ;cmnd 13
                
Sys_Inst:       .DW     Sys_Read
                .DW     Sys_Write
                .DW     Sys_WrV

                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Procedure: Pro_Read     { Profile Read }
;>
;>      This procedure emulates a Profile read operation.
;>
;>      Inputs: { none }
;>
;>      Outputs: { none }
;>
;>      Local Variables:
;>              BlockStatus : BYTE { !r4 }
;>              BlockNumber : 3 BYTES { !rC:E }
;>
;>      Global Variables Changed:
;>              LogicalBlockNumber
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ClearStatus
;>       LogicalBlockNumber := Command.LogicalBlockNumber
;>       Ack_Read( Pro_Read_Response )
;>       BlockType, BlockNumber := Get_Type( Profile )
;>       Seek_Type := Access { Seek without Auto-Offset }
;>       SearchStatus, Element.Ptr := OverLappedSeek( Read, BlockType,
;>                                                    BlockNumber, 0 )
;>       IF NOT( Read_Common )
;>        THEN Data_Ex_Handler( Read_Common.ErrorType )
;>        ELSE
;>         IF ( BlkStat.SprCode = Bad_Block )
;>          THEN
;>              BlockMove( Buf2Array, RDummy )
;>              Data_Ex_Handler( SpareBlock )
;>       Move4( StatusArray, Status )
;>       Clr_Bsy( StatusArray )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Pro_Read:
                 Ld     Wrk_Io+$A,#Read_Response
                Call    Ack_Read
                
                Call    ClrNormStat
                
                 Ld     !r0,#Pro_Log_Offset
                Call    Ld_LgclBlk;LogicalBlockNumber := ...
                
                 Ld     !r8,#Profile
                 Ld     !r2,#.HIBYTE. Get_Type
                 Ld     !r3,#.LOWBYTE. Get_Type
                Call    Bank_Call
                
                Cp      !r8,#SprTbl_Type
                Jp      Z,Read_SprTbl
                Cp      !r8,#ID_Type
                Jp      Z,Read_ID
                
                Ld      Seek_Type,#Access
                Ld      Data_Type,#User_Type
                And     DiskStat,#$FF-Wr_Op-Seq_CachSrch
                
                 Ld     !r2,#.HIBYTE. OverLap
                 Ld     !r3,#.LOWBYTE. OverLap
                Call    Bank_Call
                
                Call    Read_Common
Pro_Rd_Exit:    Jr      Z,ProRd_Err
                
                Tm      BlkStat,#B_Block ;check if block read was a bad block
                Jr      Z,Rd_Leave
                
                Call    Pro_Rd_BB
ProRd_Err:      Call    Data_Ex_Handler
                
Rd_Leave:       Ld      Wrk_Io+$A,#Init_Response
                Clr     Wrk_Io+$B ;Cmnd_Pending, IBsy := False
                
Rd_Leave2:      Call    Ld_Stand_Stat

Rd_Leave1:       Ld     Wrk_Io+$C,#.HIBYTE. StatusArray
                 Ld     Wrk_Io+$D,#.LOWBYTE. StatusArray
                Jp      Clr_Bsy

Pro_Rd_BB:       Ld     !r2,#.HIBYTE. RBuf_To_Buf2
                 Ld     !r3,#.LOWBYTE. RBuf_To_Buf2
                Call    Bank_Call
                Call    Rd_SprBlock
                Ret
                
                
;****************
Ld_Stand_Stat:   Ld     !r2,#.HIBYTE. CStatus0
                 Ld     !r3,#.LOWBYTE. CStatus0
                 Ld     !rE,#.HIBYTE. StatusArray
                 Ld     !rF,#.LOWBYTE. StatusArray
                Call    Move4_B0
                Ret
                
                .LSTOFF
                .DO     External
                .LSTON
                .Page
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;>
;>      Function: Read_Common
;>
;>      This procedure is responsible for all the common functions
;>      performed by all the read commands.
;>
;>      Inputs: { none }
;>
;>      Outputs:
;>              Read_Common : BOOLEAN { zero flag, true if data exception }
;>              ErrorCode.Error   : BOOLEAN { !r0/Bit 7 }
;>              ErrorCode.Type    : 7 BITS { !r0/Bits 6:0 }
;>
;>      Local Variables:
;>              Retry        : BYTE { !r5 }
;>              ErrorCode    : BYTE { !r4 }
;>
;>      Algorithm:
;>
;>      BEGIN
;>       ErrorCode.Error := False
;>       IF NOT( ReadBlock )
;>        THEN
;>         ErrorCode.Error := True
;>         ErrorCode.Type := Undetermined
;>         IF Recovery
;>            THEN
;>                IF ServoError OR NoHeaderFound
;>                 THEN
;>                   ErrorCode.Error := False
;>                   Retry := 4
;>                   REPEAT
;>                     THEN
;>                           ServoRecovery
;>                           Retry := Retry - 1
;>                   UNTIL NOT( Retry = 0 ) OR ReadBlock
;>                  IF NOT( ReadBlock )
;>                   THEN
;>                       ErrorCode.Error := True
;>                       ErrorCode.Type := Undetermined
;>                  IF ServoError
;>                   THEN
;>                        SetStatus( Byte0, Status_ServoError )
;>                        Abort
;>                  IF NoHeaderFound
;>                   THEN ErrorCode.Type := BadBlock
;>                   ELSE
;>                    IF ( ErrCnt > 0 )
;>                     THEN
;>                          IF ( ReadErrorCount > 2 ) AND
;>                                    ( ReadErrorCount < 10 )
;>                           THEN ErrorType := SpareBlock
;>                           ELSE
;>                                  IF ( ReadErrorCount = 10 )
;>                                   THEN
;>                                    IF Ecc
;>                                     THEN ErrorCode.Type := SpareBlock
;>                                     ELSE ErrorCode.Type := BadBlock
;>                     ELSE ErrorCode.Type := ReadError
;>       Read_Common := NOT( ErrorCode.Error )
;>      END
;>
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .LSTOFF
                .FIN
                .DO     Internal
                .LSTON
                .Page
                .FIN

Read_Common:
                And     DiskStat,#$FF-Wr_Op
                Clr     !r4
                Call    ReadBlock
                Jr      Nz,Rd_Cmn_End
                
                Ld      !r4,#RdError ;ErrorCode := Error, Undetermined
                
                Tm      Excpt_Stat,#Recovery ;IF Recovery THEN ...
                Jr      Z,Rd_Cmn_End
                
                Ld      !r5,#4  ;Retry := 4
                
Rd_Cmn_Lp:      Tm      RdStat,#RdSrvoErr + RdNoHdrFnd
                Jr      Z,Rd_Cmn_Crct
                
                 Ld     !r2,#.HIBYTE. SrvoRcvry
                 Ld     !r3,#.LOWBYTE. SrvoRcvry
                Call    Bank_Call
                
                Call    ReadBlock
                Clr     !r4
                Jr      Nz,Rd_Cmn_End
                
                Djnz    !r5,Rd_Cmn_Lp
                
Rd_Cmn_Servo:   Tm      RdStat,#RdSrvoErr
                Jr      Z,Rd_Cmn_Hdr
                
                 Clr    !r0 ;Byte 0
                 Ld     !r1,#Stat_Srvo
                Call    SetStatus
                Call    Abort
                
Rd_Cmn_Hdr:     Tm      RdStat,#RdNoHdrFnd
                Jr      Z,Rd_Cmn_Crct
                
                Ld      !r4,#Error+Ex_HdrBad
                Jr      Rd_Cmn_End
                 
Rd_Cmn_Crct:    Ld      !r0,RdErrCnt
                And     !r0,#$0F ;mask off unwanted status
                Cp      !r0,#SprThresh
                Jr      Le,Rd_Cmn_RdErr
                Cp      !r0,#10
                Jr      Z,Rd_BadBlock
                
Rd_SprBlock:    Ld      !r4,#Error+Ex_SprBlock
                Jr      Rd_Cmn_End
                
Rd_Cmn_RdErr:   Ld      !r4,#Error+Ex_ReadErr
                Jr      Rd_Cmn_End
                
Rd_BadBlock:    Ld      !r4,#Error+Ex_BadBlock
                
Rd_Cmn_End:     Ld      !r0,!r4
                Tcm     !r0,#RdError
                Jp      Bank_Ret
                
                .LSTOFF

