MOV CX,(DEVRD SHL 8) 或 DRDWRHL 在此设备驱动程序中做什么?为什么要将两种中断类型放入计数寄



我想在我的代码中提到 DEVRD = 0000 0100(即十进制 4 或中断 04h,用于溢出)和 DRDWRHL = 0001 0110(即十进制 22 或中断 16h,用于键盘输入)。 在这里我很困惑,为什么我们要把这里 (0000 0100 SHL 8) 放在 CH 中,(0001 0110)放在 CL 中。 我们试图放置两种中断类型(04H 表示溢出)是什么意思和 16h 用于键盘输入)进入计数器寄存器 CX。什么是计数器寄存器 CX 在这里做什么。

我更具体地提到:这里 DEVRD 代表设备读取,DRDWTHL 代表设备读写标头大小。 提前谢谢。

;
; 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   // I am in trouble here.
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
但我想在我的代码中提到 DEVRD = 0000 0100(即十进制 4 或用于溢出的中断 04h)

和 DRDWRHL = 0001 0110(即十进制 22 或中断 16h,用于键盘输入)。 在这里我很困惑,为什么我们要把这里 (0000 0100 SHL 8) 放在 CH 中,(0001 0110) 放在 CL 中。 我们试图放置两种中断类型是什么意思(04h for溢出和键盘输入 16h)进入计数器寄存器 CX。什么是计数器寄存器 CX 在这里做什么。

此处使用字大小CX寄存器方便地编写较短的代码。
指令

MOV CX,(DEVRD SHL 8) OR DRDWRHL

相当于

MOV CL, DRDWRHL
MOV CH, DEVRD

CX版本需要 3 个字节,CLCH版本需要 4 个字节。
由于该技术重复多次,因此可以节省大量资金。

我们试图将两种中断类型(04H 用于溢出,16h 用于键盘输入)放入计数器寄存器 CX 中是什么意思

事实并非如此。如果你进一步查看程序,你会发现CL存储在变量IOCALL中。雷克伦。一个明确暗示长度的名称。
CL以临时方式使用的进一步证据来自这样一个事实,即在它被AH中的任何值(86h 或 87h)覆盖后不久。

最新更新