home *** CD-ROM | disk | FTP | other *** search
- ;CONNECT.A86 - Connect current Virtual console to another virtual
- ; console. FOR MCDOS only.
-
- ; Written only for the sake of learning about MCDOS
- ; so could be full of bugs.
- ;
- ; Author : Alex Soya - Nov. 1984
- ;
- ; Type a Control-Z to get out of Connect.
- ;
-
- ;CCPM function calls
-
-
- P_TERMCPM equ 0 ; Terminate and release all resources
- C_READ equ 1 ; Read a character from the Default Console
- C_WRITE equ 2 ; Write a character to the Default Console
- C_RAWIO equ 6 ; Direct Console I/O with Default Console
- C_WRITESTR equ 9 ; Print ASCII string to default console
- C_STAT equ 11 ; Obtain Status of Default Console
- DEV_WAITFLAG equ 132 ; Wait for a System Flag
- DEV_SETFLAG equ 133 ; Set a system Flag
- Q_OPEN equ 135 ; Open A system queue
- Q_WRITE equ 139 ; Write a message to a System Queue
- S_SYSDAT equ 154 ; Return address of System Data Segment
- P_PDADR equ 156 ; Return address of the process descriptor
-
-
-
- cr equ 13
- lf equ 10
- cntrl_Z equ 'Z'-40h
-
- OPTION equ 05dh ; Command line Option can be found here.
- BASEFLAG equ 40h ; BaseFlag + console # used for qbuffer
- QDEPTH equ 40 ; # of bytes in output Circular Que buffer
-
-
- ; Sysdat Offsets:
- ;
- ;
- SUPENTR equ 0h ; Supervisor entry offset
- XIOSSYS equ 28h ; Offset to Xios vector
-
-
- CSEG
-
- connect:
- pushf ! pop bx ; No interrupts during stack switches
- cli
- mov ax,ds
- mov ss,ax
- mov sp, offset stack
- push bx ! popf ; Now we have our own stack.
-
- mov cs:Word Ptr DSKEEP,DS ; Keep the Data Segment here
-
- call makesys ; make us a system process.
- call gtarg ; Get target console number
- jz valcon ; If Console NOT valid then
- mov dx, offset invmsg ; Write error message.
- mov cl, C_WRITESTR
- int 224
- jmps qexit ; and terminate
-
- valcon: mov Byte Ptr TCON, al ; Save the Target console #
- mov Word Ptr VQNAM, dx ; Make proper Queue name
- mov dx, offset VINQPB ; open VINQ que for target console
- mov cl, Q_OPEN
- int 224
- cmp ax,0h ; If Not Open then
- jz qopnd
- mov dx, offset nopmsg ; Write an error message
- mov cl, C_WRITESTR
- int 224
- jmps qexit ; and terminate
- ; endif
- qopnd: call ovlxios ; overlay the xios jump vectors
-
- mainloop:
- call tready ;repeat main loop:
- jz local ; if (target = ready) then
- call tget ; get target character
- call lput ; put character to local console
- ; endif
- local: call lready
- jz mainloop ; if (local = ready) then
- call lget ; get local character
- cmp al,cntrl_Z ; check for abort
- jz exit ; if abort then exit
- call tput ; put character to target console
- jmps mainloop ;until abort
-
- exit: call restxios ; restore xios vectors
- qexit: call makeus ; make us a user process again
- mov cl,P_TERMCPM ; and terminate us
- int 224
-
- DSKEEP dw 2
-
- ;-----------------------------------------------------------------------;
- ; makesys: Set the current process as a systems process in PD flag ;
- ; field. ;
- ; ;
- ; Entry -> None ;
- ; Return <- none ;
- ; ;
- ; Regs used: ax, bx, cx, es ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- makesys:
- mov cl,P_PDADR ; Obtain process descriptor address
- int 224
- mov bx,ax ; bx := offset(PD); es := segment(PD)
- or es:word ptr 6[bx],1 ; PD.FLAG := PD.FLAG or SYSTEM
- ret ;end makesys
-
-
-
- ;-----------------------------------------------------------------------;
- ; makeus: Reset the system attribute in PD flag ;
- ; ;
- ; Entry -> None ;
- ; Return <- None ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- makeus: mov cl,P_PDADR ; Obtain PD address
- int 224
- mov bx,ax ; bx:= offset(PD); es:= segment(PD)
- and es:Word Ptr 6[bx],0feh ; mask PD.FLAG.System
- ret
-
-
-
-
- ;-----------------------------------------------------------------------;
- ;gtarg Get console number as option from command tail ;
- ; ;
- ; entry -> none ;
- ; ;
- ; Return <- DX = 2 byte ASCII value from buffer ( 0 - 99) ;
- ; AL = Integer 0 - 99 ;
- ; FLAG = Z if valid Option, NZ if Invalid option ;
- ; ;
- ; Regs used : AX,DX,CX ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- gtarg: cmp Byte Ptr .OPTION,' ' ; If No Tail then No Option
- je nooption ;else
- mov dx, word ptr .OPTION ; DX := Option
- mov ax,dx ; AX := Option (in Ascii)
- sub al,'0' ; Convert AX to binary in AL
- cmp ah,'0'
- jb no_tens ; If second digit then
- cmp ah,'9'
- ja no_tens ; adjust
- sub ah,'0'
- mov ch,ah
- mov cl,10
- mul cl ; make first digit the tens
- add al,ch ; AL = binary(DX)
- no_tens: ; end if
- cmp al,0 ; is option in range
- jb nooption ; Nope, so no option found
- cmp al,99
- jg nooption
-
- xor ah,ah ; set flag
- ret
- nooption:
- or ah,0ffh
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; ovlxios: Overlays the XIOS jump vectors in SYSDAT with that of ;
- ; xiosintcpt, Keeps the old XIOS jump vector at XIOS and ;
- ; fills in the SUPVSR segment. ;
- ; ;
- ; Entry -> None ;
- ; Return <- Fills in: XIOS, SYSDAT, SUPVSR (segment) and ;
- ; SYSDAT SEGMENT XIOS VECTOR ;
- ; ;
- ; Regs used: ax,bx,cx,ex
- ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- ovlxios:
- mov cl,S_SYSDAT ; Get Sysdat Segment to ES
- int 224
- pushf ; No interrupts while messing
- cli ; with Sysdat vectors
- mov ax,es:.XIOSSYS ; Get current Xios Offset
- mov cs:XIOS,ax ; and keep it here
- mov ax,es:.XIOSSYS+2 ; get segment of real xios
- mov XIOS+2,ax
- mov ax, offset xiosintcpt ; overlay xios interceptor offset
- mov es:.XIOSSYS,ax ; to Sysdat Xios vector offset
- mov ax,cs ; overlay xios interceptor segment
- mov es:.XIOSSYS+2,ax ; to Sysdat Xios vector segment
-
- mov ax,es:.SUPENTR+2 ; Get Segment of Supervisor
- mov SUPVSR+2,ax ; and keep it for us
- popf ; Interrupts OK again.
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; tready: See if a character from the target console is ready, ie ;
- ; is a character in the circular queue buffer. ;
- ; ;
- ; Entry -> nothing ;
- ; ;
- ; Return <- Flag = NZ if char is ready, Z if not ;
- ; AL = FFh if char is ready, 0 if not ;
- ; ;
- ; Regs used: None ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- tready: mov si, offset OUTQUE ; Here is our Que
- call qempt
- pushf
- jnz treadr ; If Writer waiting then
- cmp Byte Ptr BFULL,0ffh
- jne treadr
- mov Byte Ptr BFULL,0h ; Set Flag to indicate que empty
- mov dl, BASEFLAG ; Compute Flag for this console
- add dl, Byte Ptr TCON ; and set it.
- mov cl, DEV_SETFLAG
- int 224
- treadr: popf
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; tget: Get the target character, i.e. Take it out of the Queue buffer ;
- ; ;
- ; Entry -> None ;
- ; Return <- AL = Character ;
- ; ;
- ; Regs used: AX, SI, BX ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- tget: mov si, offset OUTQUE ; This is the Que Buffer
- call qdel ; Go get the char
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; lput: Send a character to local console ;
- ; ;
- ; Entry -> AL = Character ;
- ; Return <- none ;
- ; ;
- ; Regs used: AX, CX, DX ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- lput: mov dl,al ; Character to send to DL
- mov cl, C_WRITE ; Use System C_Write function
- int 224
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; lready: Obtain status of local console ;
- ; ;
- ; Entry -> none ;
- ; Return <- AL = 01h if Char ready, 00h if not ready ;
- ; Flag = Z if not ready, NZ if ready ;
- ; ;
- ; Regs used: AX, BX, CX ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- lready: mov cl,C_STAT ; Use System C_stat function
- int 224
- or al,al ; Set Return Flag
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; lget: Get a character from the local console ;
- ; ;
- ; Entry -> None ;
- ; Return <- AL = character ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- lget: mov cl,C_RAWIO
- mov dl,0fdh
- int 224
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; tput: Send a character to target console. Does this by writing the ;
- ; character to the target consoles VINQn System Queuq. ;
- ; ;
- ; Entry -> AL = Character to send ;
- ; Return <- AX = AX on entry. ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- tput: push ax
- mov ah,0 ; Null the High Byte
- mov Word Ptr Qbuf,AX ; Put the character into Queue buffer
- mov dx, offset VINQPB ; DX := Queue Parameter Block offset
- mov cl, Q_WRITE
- int 224 ; and send a message
- pop ax
- ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; restxios: Restore the original XIOS jump vectors in SYSDAT page ;
- ; ;
- ; Entry -> Assumes original XIOS vectors stored at XIOS in Code ;
- ; Segment. ;
- ; Return <- None ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- restxios:
- mov cl,S_SYSDAT ; Get Sysdat segment to ES
- int 224
- pushf ; No interupts while messing
- cli ; With SYSDAT values
- mov ax,cs:XIOS ; Get Xios offset
- mov es:.XIOSSYS,ax ; and restore it in SYSDAT
- mov ax,cs:XIOS+2 ; Get Segment for Xios
- mov es:.XIOSSYS+2,ax ; and restore it too.
- popf ; Interrupts are ok again
- ret ; back to caller.
-
-
-
-
- ;-----------------------------------------------------------------------;
- ; xiosintcpt: Intercept call to XIOS and handle IO_CONOUT function ;
- ; for target console locally. ;
- ; ;
- ; Entry -> AL = XIOS function number ;
- ; CL = Character to send ;
- ; DL = Virtual console to send to ;
- ; ;
- ; Return <- Jumps to XIOS with all registers preserved ;
- ; Except Flag, which is not used by XIOS ;
- ; functions. ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- xiosintcpt:
-
- push ds
- mov ds, Word Ptr DSKEEP ; Get this Data Segment
- cmp al,2 ; if XIOS function = 2 (Console Output)
- jne jxios ; and
- cmp dl, Byte Ptr TCON ; Console = Target Console
- jne jxios ; then
- call qinsert ; Insert char in queue
- jxios: pop ds
- jmpf cs:Dword Ptr XIOS ; Goto realxios
-
-
- ;-----------------------------------------------------------------------;
- ; qinsert: Insert a character into the que. If Que is full, wait until ;
- ; Some space has been made. Uses System Flags to wait for ;
- ; empty queue. ;
- ; ;
- ; Entry -> CL = Character ;
- ; Return <- none ;
- ; ;
- ; Regs used: All Registers preserved except flag Reg ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- ;
- qinsert:
- push ax
- push bx ; Save'm
- push cx
- push dx
- push si
- push di
- push bp
- mov si, offset OUTQUE ; Get Circular Que offset
- call qfull ; If Que is full then
- jnz insrt ; Wait for empty queue flag
- push si
- push cx
- mov Byte Ptr BFULL,0ffh ; Tell Reader to set Flag when empty
- mov dl,BASEFLAG ; Compute flag for this console
- add dl, Byte Ptr TCON ; flag := BaseFlag + Console #
- mov cl, DEV_WAITFLAG ; lets wait for the flag
- call supif ; direct supervisor call
- pop cx
- pop si ; end if
-
- insrt: mov al,cl ; Character to send in al
- call queins ; insert Character into que
- pop bp
- pop di
- pop si
- pop dx
- pop cx
- pop bx ; restore them
- pop ax
- ret
-
-
-
-
-
- ;-----------------------------------------------------------------------;
- ; qempt: Check to see if Que is empty ;
- ; ;
- ; entry -> si = que offset ;
- ; ;
- ; return -> Que empty: al = 0, Z is Set ;
- ; Char in que: al = FF, Z not set ;
- ;-----------------------------------------------------------------------;
-
-
- qempt: push bx ; lets not destroy anything other than al
- mov bx,word ptr 2[si] ; get rear of que
- cmp word ptr[si],bx ; if front = rear then
- mov al, 0
- je qstat ; que := empty
- mov al, 0ffh ; else que:= not empty
- qstat: pop bx
- or al,al
- ret
-
- ;-----------------------------------------------------------------------;
- ; qfull: test if que is full. ;
- ; ;
- ; entry -> si = que offset ;
- ; ;
- ; return -> NZ = ok, Z = que FULL ;
- ; ;
- ;-----------------------------------------------------------------------;
-
- qfull: mov bx,word ptr[si] ; if front + 1 = rear then
- call incqptr ; que=full
- cmp bx,word ptr 2[si]
- ret ; Z = full, NZ = ok
-
-
- ;-----------------------------------------------------------------------;
- ; incqptr: Increment the Que pointer. Takes care of wrap arround ;
- ; if end of que area is reached ;
- ; entry -> BX = pointer ;
- ; return -> BX = pointer + 1 increment ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- incqptr:inc bx ; point to next que offset
- cmp bx,qdepth ; end of que area reached ?
- jne incd ; if not we are done
- xor bx,bx ; yeap... lets wrap
- incd: ret
-
-
-
- ;-----------------------------------------------------------------------;
- ; queins: insert a character into que. If que is full the character ;
- ; is just droped. ;
- ; ;
- ; entry -> al = character ;
- ; si = que offset ;
- ; ;
- ; return -> none ;
- ;-----------------------------------------------------------------------;
-
- queins: push ax
- call qfull ; find out if the que is full
- pop ax ; Z -> ok, NZ -> full
- je qind ; if que is full then loos data
- mov bx, word ptr[si] ; else que[front]=item
- mov byte ptr 4[si+bx],al
- call incqptr ; front = front + 1
- mov word ptr[si],bx
- qind: ret
-
-
- ;-----------------------------------------------------------------------;
- ; qdel: delete a character from que ;
- ; ;
- ; entry -> si = que offset ;
- ; ;
- ; return -> al = character ;
- ;-----------------------------------------------------------------------;
-
-
- qdel: call qempt ; anything in the que ?
- je qdeld ; nope, so nothing we can get out...
- mov bx,word ptr 2[si] ; al = que[rear]
- mov al,byte ptr 4[si+bx]
- call incqptr ; rear = rear+1
- mov word ptr 2[si],bx
- qdeld: ret
-
-
-
-
- ;-----------------------------------------------------------------------;
-
- ; supif: Call CCP/M Supervisor ;
- ; ;
- ; Entry -> CX = System call number ;
- ; DX = Parameter ;
- ; DS = Segment address if DX is an offset into a structure ;
- ; ES = User Data Area ;
- ; ;
- ; Return -> AX = BX = Return ;
- ; CX = Error Code ;
- ; ES = UDA Segment (as on Entry) ;
- ; ;
- ; Regs Used: DX, SI, DI, BP are NOT preserved.. ;
- ; ;
- ;-----------------------------------------------------------------------;
- ;
- ;
- supif: mov ch,0 ; Clear High byte of function number
- push es
- push ds
- mov ds, Word Ptr Sysdat
- mov si,.68h
- mov es,ds:10h[si] ; Get UDA of current process
- callf cs:dword ptr SUPVSR
- pop ds
- pop es
- ret
-
-
-
- XIOS dw 0 ; Offset address of XIOS
- SYSDAT dw 0 ; Segment of XIOS and System Data Segment
-
- SUPVSR dw 3 ; Entry to supervisor, offset = 3
- dw 0 ; Segment filled in later
-
- DSEG
-
- Org 100h
-
-
- TCON db 0 ; Target Console Number
- BFULL db 0 ; Flag indicating buffer is full
- OUTQUE dw 0 ; front of que
- dw 0 ; rear of que
- rb qdepth ; here is the que area.
-
- INVMSG db ' Invalid Virtual Console Number.',cr,lf
- db ' usage: CONNECT nn',cr,lf
- db ' nn - Virtual Console number',cr,lf,'$'
-
- NOPMSG db ' Unable to open Input Queue.',cr,lf,'$'
-
- VINQPB dw 0,0,0 ; VINQnn Parameter Block
- dw offset Qbuf
- db 'VINQ' ; Primary Queue name
- VQNAM db ' ' ; Secondary Queue name (Console number)
-
- QBUF db 40h * 2 ; can have 40 messages times 2 bytes each
-
- rw 31
- stack dw 0