þ a‹R þ w Qþ mP9     þ hý	 oP    þ nSystem-wide$PAGEWIDTH(96)
     NAME     DISKIO
;
;     DISKIO.ASM
;

;
;
;These assembly language routines should be called
;with the following PLM LARGE calls:
;          
;
;     DataOut : PROCEDURE (data);
;        DCL data BYTE;
;     END;
;
;     DataIn : PROCEDURE (location);
;        DCL location POINTER;
;     END;
;
;     SelectDrive : PROCEDURE (driveNo,SelectBit);
;        DCL driveNo BYTE;
;        DCL SelectBit BYTE;
;     END;
;
;     SetUpDMA: PROCEDURE (command,pBuffer,length);
;        DCL command WORD;
;        DCL pBuffer POINTER;
;        DCL length  WORD;
;     END;
;
;     WaitForDMADone: PROCEDURE WORD;
;     END;
;
;     FastRead: PROCEDURE (pCommand,pBuffer) WORD;
;        DCL pCommand POINTER;
;        DCL pBuffer POINTER;
;     END;
;

CGROUP     GROUP     CODE
DGROUP     GROUP     DATA


DATA     SEGMENT     PUBLIC     'DATA'
DATA     ENDS

          



CONST SEGMENT PUBLIC 'CONST'

;DMA register addresses

WriteTab  DW   LoDMASrc0, HiDMASrc0
ReadTab   DW   LoDMADest0, HiDMADest0
          DW   LoDMASrc0, HiDMASrc0

CONST ENDS






CODE     SEGMENT     PUBLIC     'CODE'

     PUBLIC     DataIn
     PUBLIC     DataOut
     PUBLIC     SelectDrive
     PUBLIC     SetUpDMA
     PUBLIC     WaitForDMADone
     PUBLIC     FastRead


DSA    STRUC        ; DEFINE CALL PARAMETER STRUCTURE
OldBP    DW    ?    ; old BP marker
OldDS    DW    ?    ; old DS
RetIP    DW    ?    ; return IP
RetCS    DW    ?    ; return CS
DLen     DW    ?    ; return CS
Buffr    DD    ?    ; pointer to data buffer
Command  DW    ?    ; read or write
DSA      ENDS


DSB    STRUC        ; DEFINE CALL PARAMETER STRUCTURE
OBP      DW    ?    ; old BP marker
RIP      DW    ?    ; return IP
RCS      DW    ?    ; return CS
pBuffr   DD    ?    ; pointer to data buffer
pCmd     DD    ?    ; pointer to command block
DSB      ENDS


PerBusSeg           EQU    0d000h
PerBusBoxAddr       EQU    100h
PerBusDataREAD      EQU    206h
PerBusDataWRITE     EQU    206H
PerBusStatus        EQU    202H
PerBusSelect        EQU    200H
PerBusHi            EQU    000DH
STOPDMA             EQU    04h

REQMSK             EQU     020H


PTSET              EQU     0FFH           ; POSITIVE TRUE SET VALUE
PTCLR              EQU     000H           ; POSITIVE TRUE CLEAR VALUE
NTSET              EQU     PTCLR          ; NEGATIVE TRUE SET VALUE
NTCLR              EQU     PTSET          ; NEGATIVE TRUE CLEAR VALUE
ONE                EQU     001H



;
;DMA decodes
;
DMACont0           EQU    0FFCAH
HiDMADest0         EQU    0FFC6H
LoDMADest0         EQU    0FFC4H
HiDMASrc0          EQU    0FFC2H  
LoDMASrc0          EQU    0FFC0H
DMATC0             EQU    0FFC8H

EnDMAWrit0         EQU    097A6H
EnDMARead0         EQU    0B366H
DoneMsk            EQU    0002H
RidSeg             EQU    0FFF0H
;
;Other decodes
;
TimeoutValue       EQU    0FFFH
ddRead             EQU    4
eReqTimeOut        EQU    253
DMALength          EQU    2202h    ; 8.5k + two status bytes


     ASSUME     CS:CGROUP, DS:DGROUP, SS:DGROUP
     



                   


SetUpDMA  PROC    FAR;

    PUSH   DS         ; DATA SEGMENT POINTER
    PUSH   BP         ; PLM PROCEDURE PROLOGUE
    MOV    BP,SP      ; SAVE STACK MARKER

    MOV    AX, SEG WriteTab     ;set up DMA register address segment
    MOV    ES,AX

;  now get the buffer pointer from
;  the stack and place the lower 16 bits
;  in AX and the upper 4 bits in the lsb's
;  of CL

    LDS    BX,[BP].BUFFR      ;put buffer addr in BX

    MOV    AX,DS              ;get upper 4 address
    MOV    CL,4               ;bits in lsb's of AX
    ROL    AX,CL
    MOV    CL,AL              ;save upper 4 bits

    AND    AX,RidSeg          ;mask out upper 4 
    ADD    AX,BX              ;bits and get lower
                              ;16 bits
    ADC    CL,00              ;if there was a carry
                              ;add 1 to the upper
                              ;bits

    CMP    [BP].Command,ddread   ;decide if read or write
    JE     SetUpRead

SetUpWrite:

    MOV    SI, OFFSET WriteTab   ;get correct table
    MOV    BX, EnDMAWrit0        ;save correct command
    JMP    OutputSetUp


SetUpRead:

    MOV    SI, OFFSET ReadTab   ;get correct table
    MOV    BX, EnDMARead0        ;save correct command

OutputSetUp:

    MOV    DX,ES:[SI]       ;output lower 16 bits of pointer
    INC    SI
    INC    SI
    OUT    DX,AX

    MOV    AL,CL            ;output upper 4 bits of pointer
    MOV    DX,ES:[SI]       
    INC    SI
    INC    SI
    OUT    DX,AX

    MOV    DX,ES:[SI]       ;output low per bus address
    INC    SI
    INC    SI
    MOV    AX,PerBusDataRead
    OUT    DX,AX

    MOV    DX,ES:[SI]       ;output high per bus address
    MOV    AX,PerBusHi
    OUT    DX,AX

    MOV    DX,DMATC0        ;set up TC register
    MOV    AX,[BP].DLen
    OUT    DX,AX

    MOV    DX,DMACont0      ;enable DMA with saved command
    MOV    AX,BX
    OUT    DX,AX

    POP    BP
    POP    DS
    RET    8

SetUpDMA    ENDP




WaitForDMADone  PROC  FAR;


    MOV    DX,DMACont0
    MOV    CX,0

WaitDMA:

    IN     AX,DX
    AND    AX,DoneMsk
    JZ     DMADone
    LOOP   WaitDMA

    MOV    DX,DMACont0      ; disable DMA
    MOV    AX,STOPDMA
    OUT    DX,AX
    MOV    AX,eReqTimeOut
    JMP    WaitDone

DMADone:

    XOR    AX, AX            ; clear errorcode    

WaitDone:

    RET

WaitForDMADone   ENDP





SelectDrive     PROC     FAR

     PUSH    BP
     MOV     BP,SP
     MOV     BX,[BP+6]                    ; SELECT DATABYTE
     MOV     AX,[BP+8]                    ; BOX NUMBER
     NOT     AL                           ; invert box number

     MOV     CX,PerBusSeg
     MOV     ES,CX
   
     MOV     ES:BYTE PTR PerBusBoxAddr,AL
     
     MOV     ES:BYTE PTR PerBusSelect,BL
  
     POP     BP
     RET     4
     
SELECTDRIVE       ENDP



DATAIN     PROC     FAR

     
     PUSH    BP
     PUSH    DS
     MOV     BP,SP
     LDS     DI,DWORD PTR [BP+8]          ; Get Data Buffer

     MOV     AX,PerBusSeg
     MOV     ES,AX

LOOPRI:

     MOV     AL,ES: BYTE PTR PerBusStatus
     AND     AL,REQMSK
     JZ      LOOPRI
 
     MOV     AL,ES: BYTE PTR PerBusDataREAD

     MOV     DS:[DI],AL                     ; Store data byte


     POP     DS
     POP     BP
     RET     4

DATAIN       ENDP

          



DATAOUT     PROC     FAR

     PUSH    BP
     MOV     BP,SP
     MOV     BX,[BP+6]                    ; DATABYTE TO OUTPUT in BL
     
     PUSH    ES
     MOV     AX,PerBusSeg
     MOV     ES,AX

LOOPRO:

     MOV     AL,ES: BYTE PTR PerBusStatus
     AND     AL,REQMSK
     JZ      LOOPRO
 
     MOV     ES: BYTE PTR PerBusDataWRITE,BL
     
     POP     ES
     POP     BP
     RET     2

DATAOUT      ENDP


CMDOUT   PROC   NEAR

     PUSH    ES
     MOV     AX,PerBusSeg
     MOV     ES,AX

LOOCO:

     MOV     AL,ES: BYTE PTR PerBusStatus
     AND     AL,REQMSK
     JZ      LOOCO
 
     MOV     ES: BYTE PTR PerBusDataWRITE,BL
     
     POP     ES
     RET     

CMDOUT      ENDP


FastRead  PROC FAR    ;

    PUSH   BP         ; PLM PROCEDURE PROLOGUE
    MOV    BP,SP      ; SAVE STACK MARKER


;  now get the command buffer pointer from
;  the stack and output the Peripheral bus commands

    LES    SI,[BP].pCmd   ;put buffer addr in BX
    
    MOV    BL,ES:[SI]         ;output Command
    CALL   CMDOut
    INC    SI
    MOV    BL,ES:[SI]         ;output LUN + Uaddr
    CALL   CMDOut
    INC    SI
    MOV    BL,ES:[SI]         ;output MAddr
    CALL   CMDOut
    INC    SI
    MOV    BL,ES:[SI]         ;output lAddr
    CALL   CMDOut
    INC    SI
    MOV    BL,ES:[SI]         ;output # of blocks
    CALL   CMDOut           
    INC    SI
    MOV    BL,ES:[SI]         ;output Control word
    CALL   CMDOut
;
;   Setup DMA for 8.5 k Read
;
    

    MOV    AX,ddRead          ; Read command to DMA
    PUSH   AX
    LES    SI,[BP].pBuffr     ; get data buffer address
    PUSH   ES
    PUSH   SI
    MOV    AX,DMALength       ; DMA xfer length
    PUSH   AX

    CALL   SetupDMA

;
; Wait for DMA to be completed
;

    HLT
    
    MOV    AX,0h
;
;   Error word already in AX
;

    POP    BP
    RET    8

FastRead    ENDP




     CODE  ENDS
     END    