我无法理解msdos源代码,IOFUNC程序。在MOV CX,(DEVRD SHL 8)或DRDWRHL

时间:2018-03-21 13:26:05

标签: assembly

    ;
    ; Device call routines for MSDOS
    ;

    INCLUDE DOSSEG.ASM

    IFNDEF  KANJI
    KANJI   EQU     0       ;FALSE
    ENDIF

    CODE    SEGMENT BYTE PUBLIC  'CODE'
        ASSUME  SS:DOSGROUP,CS:DOSGROUP

    .xlist
    .xcref
    INCLUDE DOSSYM.ASM
    INCLUDE DEVSYM.ASM
    .cref
    .list

    TITLE   DEV - Device call routines
    NAME    Dev

        i_need  IOXAD,DWORD
        i_need  IOSCNT,WORD
        i_need  DEVIOBUF,4
        i_need  IOCALL,BYTE
        i_need  IOMED,BYTE
        i_need  IORCHR,BYTE
        i_need  CALLSCNT,WORD
        i_need  DMAAdd,DWORD
        i_need  NullDevPt,DWORD
        i_need  CallDevAd,DWORD
        i_need  Attrib,BYTE
        i_need  NULDEV,DWORD
        i_need  Name1,BYTE
        i_need  DevPt,DWORD
        i_need  DPBHead,DWORD
        i_need  NumIO,BYTE
        i_need  ThisDPB,DWORD
        i_need  DevCall,DWORD
        i_need  VerFlg,BYTE

    SUBTTL IOFUNC -- DO FUNCTION 1-12 I/O
    PAGE
    IOFUNC_RETRY:
    ASSUME  DS:NOTHING,ES:NOTHING
        invoke  restore_world

        procedure   IOFUNC,NEAR
    ASSUME  DS:NOTHING,ES:NOTHING

    ; Inputs:
    ;       DS:SI Points to FCB
    ;       AH is function code
    ;               = 0 Input
    ;               = 1 Input Status
    ;               = 2 Output
    ;               = 3 Output Status
    ;               = 4 Flush
    ;       AL = character if output
    ; Function:
    ;       Perform indicated I/O to device or file
    ; Outputs:
    ;       AL is character if input
    ;       If a status call
    ;               zero set if not ready
    ;               zero reset if ready (character in AL for input. 
    status)
    ; For regular files:
    ;       Input Status
    ;               Gets character but restores fcb_RR field
    ;               Zero set on EOF
    ;       Input
    ;               Gets character advances fcb_RR field
    ;               Returns ^Z on EOF
    ;       Output Status
    ;               Always ready
    ; AX altered, all other registers preserved

        MOV     WORD PTR [IOXAD+2],SS
        MOV     WORD PTR [IOXAD],OFFSET. 
    DOSGROUP:DEVIOBUF
        MOV     WORD PTR [IOSCNT],1
        MOV     WORD PTR [DEVIOBUF],AX

    IOFUNC2:
        TEST    [SI.fcb_DEVID],080H
        JNZ     IOTODEV
        JMP     IOTOFILE

    IOTODEV:
        invoke  save_world
        PUSH    DS
        PUSH    SS
        POP     ES
        PUSH    SS
        POP     DS
    ASSUME  DS:DOSGROUP
        XOR     BX,BX
        MOV     [IOCALL.REQSTAT],BX
        MOV     BYTE PTR [IOMED],BL

        MOV     BX,OFFSET DOSGROUP:IOCALL

        MOV     CX,(DEVRD SHL 8) OR DRDWRHL
        OR      AH,AH
        JZ      DCALLR
        MOV     CX,(DEVRDND SHL 8) OR DRDNDHL
        DEC     AH
        JZ      DCALLR
        MOV     CX,(DEVWRT SHL 8) OR DRDWRHL
        DEC     AH
        JZ      DCALLO
        MOV     CX,(DEVOST SHL 8) OR DSTATHL
        DEC     AH
        JZ      DCALLO
    DFLUSH:
        MOV     CX,(DEVIFL SHL 8) OR DFLSHL
    DCALLR:
        MOV     AH,86H
    DCALL:
        MOV     [IOCALL.REQLEN],CL
        MOV     [IOCALL.REQFUNC],CH
        MOV     CL,AH
        POP     DS
    ASSUME  DS:NOTHING
        CALL    DEVIOCALL
        MOV     DI,[IOCALL.REQSTAT]
        TEST    DI,STERR
        JZ      OKDEVIO
        MOV     AH,CL
        invoke  CHARHARD
        CMP     AL,1
        JZ      IOFUNC_RETRY
    ;Know user must have wanted ignore. Make sure device. 
    shows ready so
    ;that DOS doesn't get caught in a status loop when user. 
    simply wants
    ;to ignore the error.
        AND     BYTE PTR [IOCALL.REQSTAT+1], NOT (STBUI. 
    SHR 8)
    OKDEVIO:
        PUSH    SS
        POP     DS
    ASSUME  DS:DOSGROUP
        CMP     CH,DEVRDND
        JNZ     DNODRD
        MOV     AL,BYTE PTR [IORCHR]
        MOV     [DEVIOBUF],AL

    DNODRD: MOV     AH,BYTE PTR [IOCALL.REQSTAT+1]
        NOT     AH                      ; Zero = busy, not zero = ready
        AND     AH,STBUI SHR 8

        invoke  restore_world
    ASSUME  DS:NOTHING
        MOV     AX,WORD PTR [DEVIOBUF]
        return

    DCALLO:
        MOV     AH,87H
        JMP     SHORT DCALL

    IOTOFILE:
    ASSUME  DS:NOTHING
        OR      AH,AH
        JZ      IOIN
        DEC     AH
        JZ      IOIST
        DEC     AH
        JZ      IOUT
        return                  ; NON ZERO FLAG FOR OUTPUT. 
    STATUS

    IOIST:
        PUSH    WORD PTR [SI.fcb_RR]        ; Save position
        PUSH    WORD PTR [SI.fcb_RR+2]
        CALL    IOIN
        POP     WORD PTR [SI.fcb_RR+2]      ; Restore position
        POP     WORD PTR [SI.fcb_RR]
        return

    IOUT:
        CALL    SETXADDR
        invoke  STORE
        invoke  FINNOSAV
        CALL    RESTXADDR       ; If you change this into a jmp. 
    don't come
        return                  ; crying to me when things don't work 
    ARR

    IOIN:
        CALL    SETXADDR
        invoke  LOAD
        PUSH    CX
        invoke  FINNOSAV
        POP     CX
        OR      CX,CX           ; Check EOF
        CALL    RESTXADDR
        MOV     AL,[DEVIOBUF]   ; Get byte from trans addr
        retnz
        MOV     AL,1AH          ; ^Z if EOF
        return

    SETXADDR:
        POP     WORD PTR [CALLSCNT]     ; Return address
        invoke  save_world
        PUSH    WORD PTR [DMAADD]       ; Save Disk trans.   
    addr
        PUSH    WORD PTR [DMAADD+2]
        PUSH    DS
        PUSH    SS
        POP     DS
    ASSUME  DS:DOSGROUP
        MOV     CX,WORD PTR [IOXAD+2]
        MOV     WORD PTR [DMAADD+2],CX
        MOV     CX,WORD PTR [IOXAD]
        MOV     WORD PTR [DMAADD],CX    ; Set byte trans. 
    addr
        MOV     CX,[IOSCNT]             ; ioscnt specifies length of 
    buffer
        POP     DS
    ASSUME  DS:NOTHING
        MOV     [SI.fcb_RECSIZ],1           ; One byte per record
        MOV     DX,SI                   ; FCB to DS:DX
        invoke  GETRRPOS
        JMP     SHORT RESTRET           ; RETURN ADDRESS

    RESTXADDR:
        POP     WORD PTR [CALLSCNT]     ; Return address
        POP     WORD PTR [DMAADD+2]     ; Restore Disk trans 
    addr
        POP     WORD PTR [DMAADD]
        invoke  restore_world
    RESTRET:JMP     WORD PTR [CALLSCNT]      ; Return 
    address
    IOFUNC  ENDP

    SUBTTL DEVIOCALL, DEVIOCALL2 - CALL A DEVICE
    PAGE
        procedure   DEVIOCALL,NEAR
    ASSUME  DS:NOTHING,ES:NOTHING

    ; Inputs:
    ;       DS:SI Points to device FCB
    ;       ES:BX Points to request data
    ; Function:
    ;       Call the device
    ; Outputs:
    ;       None
    ; DS:SI,AX destroyed, others preserved

        LDS     SI,DWORD PTR [SI.fcb_FIRCLUS]

       entry   DEVIOCALL2
    ; As above only DS:SI points to device header on entry, 
    and DS:SI is preserved
        MOV     AX,[SI.SDEVSTRAT]
        MOV     WORD PTR [CALLDEVAD],AX
        MOV     WORD PTR [CALLDEVAD+2],DS
        CALL    DWORD PTR [CALLDEVAD]
        MOV     AX,[SI.SDEVINT]
        MOV     WORD PTR [CALLDEVAD],AX
        CALL    DWORD PTR [CALLDEVAD]
        return
    DEVIOCALL   ENDP

    SUBTTL DEVNAME - LOOK FOR NAME OF DEVICE
    PAGE
        procedure   DEVNAME,NEAR
    ASSUME  DS:DOSGROUP,ES:DOSGROUP

    ; Inputs:
    ;       DS,ES:DOSGROUP
    ;       Filename in NAME1
    ; Function:
    ;       Determine if file is in list of I/O drivers
    ; Outputs:
    ;       Carry set if name not found
    ;       ELSE
    ;       Zero flag set
    ;       BH = Bit 7,6 = 1, bit 5 = 0 (cooked mode)
    ;            bits 0-4 set from low byte of attribute word
    ;       DEVPT = DWORD pointer to Device header of device
    ; Registers BX destroyed

        PUSH    SI
        PUSH    DI
        PUSH    CX

        IF      KANJI
        PUSH    WORD PTR [NAME1]
        CMP     [NAME1],5
        JNZ     NOKTR
        MOV     [NAME1],0E5H
    NOKTR:
        ENDIF

        TEST    BYTE PTR [ATTRIB],attr_volume_id ; If looking 
    for VOL id don't find devs
        JNZ     RET31
        MOV     SI,OFFSET DOSGROUP:NULDEV
    LOOKIO:
    ASSUME  DS:NOTHING
        TEST    [SI.SDEVATT],DEVTYP
        JZ      SKIPDEV                 ; Skip block devices
        PUSH    SI
        ADD     SI,SDEVNAME
        MOV     DI,OFFSET DOSGROUP:NAME1
        MOV     CX,4                    ; All devices are 8 letters
        REPE    CMPSW                   ; Check for name in list
        POP     SI
        JZ      IOCHK                   ; Found it?
    SKIPDEV:
        LDS     SI,DWORD PTR [SI]       ; Get address of next 
    device
        CMP     SI,-1                   ; At end of list?
        JNZ     LOOKIO
    RET31:  STC                             ; Not found
    RETNV:  PUSH    SS
        POP     DS
    ASSUME  DS:DOSGROUP

        IF      KANJI
        POP     WORD PTR [NAME1]
        ENDIF

        POP     CX
        POP     DI
        POP     SI
        RET

    IOCHK:
    ASSUME  DS:NOTHING
        MOV     WORD PTR [DEVPT+2],DS         ; Save pointer to 
    device
        MOV     BH,BYTE PTR [SI.SDEVATT]
        OR      BH,0C0H
        AND     BH,NOT 020H             ;Clears Carry
        MOV     WORD PTR [DEVPT],SI
        JMP     RETNV
    DevName ENDP

        procedure   GetBP,NEAR
    ASSUME  DS:DOSGROUP,ES:NOTHING

    ; Inputs:
    ;       AL = Logical unit number (A = 0)
    ; Function:
    ;       Find Drive Parameter Block
    ; Outputs:
    ;       ES:BP points to DPB
    ;       [THISDPB] = ES:BP
    ;       Carry set if unit number bad
    ; No other registers altered

        LES     BP,[DPBHEAD]    ; Just in case drive isn't valid
        AND     AL,3FH          ; Mask out dirty and device bits
        CMP     AL,BYTE PTR [NUMIO]
        CMC
        JC      GOTDPB          ; Get drive A
    FNDDPB:
        CMP     AL,ES:[BP.dpb_drive]
        JZ      GOTDPB          ; Carry is clear if jump executed
        LES     BP,ES:[BP.dpb_next_dpb]
        JMP     SHORT FNDDPB
    GOTDPB:
        MOV     WORD PTR [THISDPB],BP
        MOV     WORD PTR [THISDPB+2],ES
        RET
    GetBP   ENDP

    SUBTTL SETREAD, SETWRITE -- SET UP HEADER BLOCK
    PAGE
        procedure   SETREAD,NEAR
    ASSUME  DS:NOTHING,ES:NOTHING

    ; Inputs:
    ;       DS:BX = Transfer Address
    ;       CX = Record Count
    ;       DX = Starting Record
    ;       AH = Media Byte
    ;       AL = Unit Code
    ; Function:
    ;       Set up the device call header at DEVCALL
    ; Output:
    ;       ES:BX Points to DEVCALL
    ; No other registers effected

        PUSH    DI
        PUSH    CX
        PUSH    AX
        MOV     CL,DEVRD
SETCALLHEAD:
        MOV     AL,DRDWRHL
        PUSH    SS
        POP     ES
        MOV     DI,OFFSET DOSGROUP:DEVCALL
        STOSB                   ; length
        POP     AX
        STOSB                   ; Unit
        PUSH    AX
        MOV     AL,CL
        STOSB                   ; Command code
        XOR     AX,AX
        STOSW                   ; Status
        ADD     DI,8            ; Skip link fields
        POP     AX
        XCHG    AH,AL
        STOSB                   ; Media byte
        XCHG    AL,AH
        PUSH    AX
        MOV     AX,BX
        STOSW
        MOV     AX,DS
        STOSW                   ; Transfer addr
        POP     CX              ; Real AX
        POP     AX              ; Real CX
        STOSW                   ; Count
        XCHG    AX,DX           ; AX=Real DX, DX=real CX, CX=real AX
        STOSW                   ; Start
        XCHG    AX,CX
        XCHG    DX,CX
        POP     DI
        MOV     BX,OFFSET DOSGROUP:DEVCALL
        RET

        entry   SETWRITE
    ASSUME  DS:NOTHING,ES:NOTHING

    ; Inputs:
    ;       DS:BX = Transfer Address
    ;       CX = Record Count
    ;       DX = Starting Record
    ;       AH = Media Byte
    ;       AL = Unit Code
    ; Function:
    ;       Set up the device call header at DEVCALL
    ; Output:
    ;       ES:BX Points to DEVCALL
    ; No other registers effected

        PUSH    DI
        PUSH    CX
        PUSH    AX
        MOV     CL,DEVWRT
        ADD     CL,[VERFLG]
        JMP     SHORT SETCALLHEAD
    SETREAD ENDP

    do_ext

   CODE    ENDS
    END

1 个答案:

答案 0 :(得分:2)

CX是一个16位寄存器,结合了CH和CL

而不是

mov ch, 0x12
mov cl, 0x78

你可以写

mov cx, 0x1278     ( which is 0x12<<8 or 0x78)

所以

MOV     CX,(DEVRD SHL 8) OR DRDWRHL

正在组合

MOV     CH, DEVRD
MOV     CL, DRDWRHL

成一条指令。 DEVRD和DRDWRHL显然是在其他地方定义的常量