📄 gwcom.asm
字号:
CSWAIT:
CALL GetComUnitID ;[AL]=Com Unit ID(DI)
MOV AH,AL ;[AH]=Com Unit ID(DI)
CALL B$RECCOM ;[AL]=input byte (if data is ready)
PUSHF
CALL CKCMER ;check for Com Error
POPF
JNZ CSGOT1 ;wait if none ready to be read
CALL B$BREAK_CHK ;allow ^Break to break in
JMP SHORT CSWAIT
CSGOT1:
PUSH AX ;save registers...
PUSH DI
CALL GetComDCB ;get DCB in DI
DEC [DI].CD_CMEVT ;one less char in input queue
POP DI ;restore registers
POP AX
CMP AL,EOFCHR ;check for CTL-Z
JNE CMNEOF ;branch if not
TEST [SI].FD_FLAGS,FL_BIN ; binary file?
JNZ CMNEOF ;CTL-Z is not EOF for Binary files
STC ;CTL-z is EOF for ASCII files
AND [SI].FD_FLAGS,NOT FL_NEOF ;flag as eof
JMP SHORT CMSINX ;restore registers and exit
CMNEOF:
CLC ;clear carry (no eof)
CMSINX:
RET
;COM_SOUT - Sequential Output.
; Entry - SI points to File-Data-Block.
; [DI] = device offset (2=COMD, 4=SCRN, etc.)
; [AL] = byte to be output.
; Exit - SI, DI can be changed.
; All other registers preserved
; This routine keeps track of column position,
; expands tabs, and forces a carriage return when line width
; is exceeded.
COM_SOUT:
PUSH AX
CALL GetComDCB ;DI points to COMx DCB
POP AX
TEST [DI].CD_CMFLG,CF_CMCOD ;did user explicity specifiy BIN/ASC?
JZ NOTBIN ;No
TEST [SI].FD_FLAGS,FL_BIN
JNZ CMROUT ;if binary, branch to Raw-Output routine
NOTBIN:
PUSH DX ;NOT binary
MOV DL,[SI].FD_WIDTH ;[DL]=device width (from FDB)
MOV DH,[DI].CD_CMPOS ;[DH]=current column (from DCB)
CALL XTABCR ;Expand tabs, force CR, do output, etc.
MOV [DI].CD_CMPOS,DH ;save new column position
POP DX
RET11:
RET
;CLRCRF - Clear <CR> flag and output character
;CMROUT - Raw output routine
; Exit - All registers preserved
CLRCRF:
AND [DI].CD_CMFLG,NOT CF_CMCRF ;clear CR flag
CMROUT: ;output character/raw output routine
MOV AH,[DI].CD_DEVID ;[AH]=device ID
CALL B$SNDCOM ;output [AL] to COM
JMP CKCMER ;check for successful transmit and rtn
;XTABCR expand tabs,force <CR> if EOL
;entry-> [AL] = Char to be output
; [DX] = [current column,file width]
; [DI] = device offset
;exit -> [DH] = new column
; all other regesters preserved
XTABCR:
INC DH ; send character and then check
;if beyond width specified
CMP AL,ASCSP ;Is it printable
JB OTHERS ;No - start checking alternatives
CALL CLRCRF ;Yes - print it
CMP DH,DL ;Are we in range?
JB INRANG ;YES
CMP DL,0FFh ;NO, but do we care?
JE INRANG ;We dont care so pretend were in range
MOV AL,ASCCR ; and print a
CALL TRYCR ; carriage return
AND [DI].CD_CMFLG,NOT CF_CMCRF ;clear CR flag
INRANG:
RET
OTHERS:
DEC DH
TRYTAB:
CMP AL,ASCHT ;is it a tab
JNE TRYCR ;no so try <CR>
TEST [DI].CD_CMFLG,CF_CMCOD ;test if IBM mode
JZ CMROUT ;if so, just output tab
MOV AL,ASCSP ;expand to spaces
MORSPC:
CALL XTABCR
TEST DH,7 ;Are we on a multiple of 8?
JNZ MORSPC ;Nope, try again
MOV AL,ASCHT ;Restore AL
RET ;and return
TRYCR:
CMP AL,ASCCR ;is it a <CR>?
JNE TRYLF ;No - see if its a line feed
CALL CMROUT ;Yes - put it out
XOR DH,DH ; and update pos.
TEST [DI].CD_CMFLG,CF_CMCLF ; add an <LF>?
JZ SETCRF ; no
MOV AL,ASCLF ; yes, so put one out
CALL CMROUT
MOV AL,ASCCR ; restore AL
SETCRF:
OR [DI].CD_CMFLG,CF_CMCRF ;set CR flag
RET
TRYLF:
CMP AL, ASCLF ;Is it an <LF>
JNE TRYBS ;No - try a <BS>
TEST [DI].CD_CMFLG,CF_CMCRF ;look to see this follows CR
JZ CMROUT ;not preceded by a <CR>
AND [DI].CD_CMFLG,NOT CF_CMCRF ;pred by CR - ignore LF, clear flag
TEST [DI].CD_CMFLG,CF_CMCOD ;test if IBM mode
JZ CMROUT ;if so, no LF suppression
RET ; and return
TRYBS:
CMP AL,ASCBS ;is it a <BS>
JNE CLRCRF ;no - write it out
DEC DH ;back up pos
JNC CLRCRF ;send it out unless pos backed up past 0
INC DH
JMP CLRCRF
;COM_GPOS - return current file position.
; Entry - SI points to File-Data-Block.
; [DI] = device offset (2=COMD, 4=SCRN, etc.)
; Exit - [AH] = current file column. (0-relative)
; All other registers preserved
COM_GPOS:
PUSH AX ;save contents of AL
CALL GetComDCB ;DI points to Device Control Block
POP AX ;restore contents of AL
MOV AH,[DI].CD_CMPOS
RET
;COM_GWID - get device width
; Entry - SI points to File-Data-Block.
; [DI] = device offset (2=COMD, 4=SCRN, etc.)
; Exit - [AH] = device width as set by xxxSWD
COM_GWID:
MOV AH,[SI].FD_WIDTH ;get current width
RET
;COM_SCW - set device comma width ****Apparently not used by Bascom****
; Entry - [BX] = new device comma width
; SI points to File-Data-Block.
; [DI] = device offset (2=COMD, 4=SCRN, etc.)
; Exit - SI, DI can be changed.
; All other registers preserved
;
;COM_SCW:
; RET
;COM_GCW - get device comma width ****Apparantly not used by Bascom****
; Entry - SI points to File-Data-Block.
; [DI] = device offset (2=COMD, 4=SCRN, etc.)
; Exit - [BX] = device comma width as set by xxxSCW
; All other registers preserved
;
;COM_GCW:
; RET
;** com_blkin - block input
;** com_blkout - block output --DMA support for BLOAD
; NOT IMPLEMENTED
; Entry [bx] = offset of destination
; [cx] = maximum number of bytes to read
; [dx] = DS of destination
; [di] = device number
; [si] -> FDB of file to be loaded
; exit ? (This routine is provided to allow the user
; to trash himself beyond all recognition!
; Exit [bx] = 1 past last byte read
; CF set if EOF encountered
; Uses AX
com_blkin equ B$ERR_FC
com_blkout equ B$ERR_FC
;***
; GetComDCB - get pointer to COM Device Control Block
;
; Purpose:
; To compute the offset the device control block (DCB) of
; the communications device ID given. The number of the
; device is also given (0-relative).
; Entry:
; DI = -2 * device ID (positive value)
; Exit:
; DI = offset to the device control block
; AX = 0 for COM1, 1 for COM2, ...
; Modifies:
; None.
; Exceptions:
; None.
;*****************************************************************************
GetComDCB:
CALL GetComUnitId ;[AX]=unit id (0..n)
MOV DI,OFFSET DGROUP:B$CM1DCB ;assume COM1: first
OR AX,AX ;test if really first device
JZ GetComDCBDone ;if so, then jump
ADD DI,SIZE COMDCB ;add to get start of DCB for COM2:
GetComDCBDone:
RET
;***
; GetComUnitID - get communications unit ID
;
; Purpose:
; To get the zero-relative unit identification number from
; the device ID.
; Entry:
; DI = -2 * device ID (positive number)
; Exit:
; AX = 0 for COM1:, 1 for COM2:,...
; Modifies:
; None.
; Exceptions:
; None.
;***************************************************************************
GetComUnitID:
MOV AX,DI
ADD AX,2*DN_COM1
SHR AX,1 ;[AX]=0, 1. for COM1, COM2, ...
ERRRET:
RET
; Check for COM I/O error and output COM Error Message if error occured.
; Entry - [AH] = non-zero if error occured
CKCMER:
OR AH,AH
JZ ERRRET ;branch if no COM I/O error detected
MOV BL,AH
XOR BH,BH ;[BX]=error code 1..n
MOV DI,OFFSET DGROUP:CMERRT ;DI has dipatch table for error routines
CMP BL,5
JBE ERROK
XOR BX,BX ;use default error
ERROK:
SHL BX,1 ;convert error to word offset
JMP [DI+BX] ;Handle error
;***
;B$CommSave - Save communications state
;
;Purpose:
; This routine will be called whenever a process is going to
; be shelled. The communications ports, if opened, are
; disabled, but their DCB's and opened status are kept for
; subsequent reopening in B$CommRestore. Note that
; interrupt handlers will not have to be terminated.
;
; This is a DOS only routine.
;
;Entry:
; None.
;
;Exit:
; None.
;
;Uses:
; Per Convention
;
;Preserves:
; AX, BX, CX, DX
;
;Exceptions:
; None.
;********************************************************************
cProc B$CommSave,<PUBLIC,NEAR>,<AX,BX,CX,DX,SI,DI>
cBegin
DbAssertRelB <[b$COFlag]>,E,0,DV_TEXT,<b$COFlag non-zero in B$CommSave> ;
MOV CX,b$ComPort ;get value of I/O port for COM1
MOV COMSAV,CX ;put into save area
JCXZ NoActCOM1 ;if no active COM1, then jump
MOV DI,OFFSET DGROUP:b$COM_DCB ;get offset to COM1 DCB
; CX must be non-zero so DTR and RTS are unaffected (DOS 3 only)
MOV AH,0 ; AH = 0 indicates COM1
CALL B$TRMCOM ;[3]terminate COM1 device
CALL B$ComDealloc ;and dellocate the COM1 buffer
NoActCOM1:
MOV CX,b$ComPort+2 ;get value of I/O port for COM2
MOV COMSAV+2,CX ;put into save area
JCXZ NoActCOM2 ;if no active COM2, then jump
MOV DI,OFFSET DGROUP:b$COM_DCB+SIZE COMDCB ;offset to COM2 DCB
; CX must be non-zero so DTR and RTS are unaffected (DOS 3 only)
MOV AH,1 ; AH = 1 indicates COM2
CALL B$TRMCOM ;[3]terminate COM2 device
CALL B$ComDealloc ;and dellocate the COM2 buffer
NoActCOM2:
cEnd
;***
;B$CommRestore - Restore communications state
;
;Purpose:
; This routine will be called when a shelled process returns.
; The communications ports disabled in B$CommSave are
; reopened with their preSHELL values. Note that interrupt
; handlers will not have to be restarted.
;
; This is a DOS only routine.
;
;Entry:
; None.
;
;Exit:
; None.
;
;Uses:
; Per Convention
;
;Preserves:
; AX, BX, CX, DX
;
;Exceptions:
; None.
;********************************************************************
cProc B$CommRestore,<PUBLIC,NEAR>,<AX,BX,CX,DX,SI,DI>
cBegin
DbAssertRelB <[b$COFlag]>,E,0,DV_TEXT,<b$COFlag non-zero in B$CommRestore> ;
MOV CX,COMSAV ;get saved I/O port for COM1
JCXZ NoRestCOM1 ;if none, the skip over restore
MOV DI,OFFSET DGROUP:b$COM_DCB ;get offset to COM1 DCB
CALL B$ComAlloc ;allocate the COM1 buffer
MOV BX,DI ;move DCB address to BX
CALL B$INICOM ;[3]initialize COM1 device
NoRestCOM1:
MOV CX,COMSAV+2 ;get saved I/O port for COM2
JCXZ NoRestCOM2 ;if none, then skip over restore
MOV DI,OFFSET DGROUP:b$COM_DCB+SIZE COMDCB ;offset to COM2 DCB
CALL B$ComAlloc ;allocate the COM2 buffer
MOV BX,DI ;move DCB address to BX
CALL B$INICOM ;[3]initialize COM2 device
NoRestCOM2:
cEnd
sEnd DV_TEXT
END
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -