Files
Sepp J Morris 31738079c4 Upload
Digital Research
2020-11-06 18:50:37 +01:00

225 lines
5.7 KiB
Plaintext

;****************************************************************
;* *
;* Queue system subroutines: Q System must be owned *
;* before calling any of the following routines *
;* *
;****************************************************************
queverify: ; check QLR for existence of QD address
;--------- ---------------------------------------
; entry: U_WRKSEG:DX = offset of QPB
; exit: CX = 0 if queue is found
; CX = E_NO_QUEUE error code, if not
; BX=SI=QD offset
; ES,DX preserved
push es ;save UDA
mov es,u_wrkseg
mov bx,dx ;ES:BX->QPB
mov bx,es:qpb_qaddr[bx] ;get QD from user's QPB
pop es ;restore UDA
lea si,qlr-q_link
qv_nxt:
mov si,q_link[si] ;SI addresses of valid QDs
test si,si ! jz qv_nqf
cmp bx,si ! jne qv_nxt
xor cx,cx ! ret ;BX=SI=QD offset, return success
qv_nqf:
mov cx,e_no_queue ;couldn't find the queue
ret
getqdaddr:
;----------
; entry: DX = offset of QD in U_WRKSEG
; exit: DI = offset of QD in SYSDAT
;
; If QD address is within SYSDAT use it.
; Else get a QD from QDUL and set QF_TABLE flag.
; If Q_NMSGS=0 in QD then return error.
; If 0 length buffer needed, zero the Q_BUF field.
; If buffer space is within SYSDAT use it. Else get buffer
; from QMAU. Return the QD address within SYSDAT.
push dx ;save QD offset
mov bx,qdlen
call sysdat_chk
jcxz g_qul ;CX=0 if not within SYSDAT
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
mov bx,ds
sub ax,bx ;from SYSDAT
mov cl,4 ! shl ax,cl ;make into # of bytes
pop di ;DI=QD in U_WRKSEG
add di,ax ;make QD relative to SYSDAT
jmps g_qd
g_qul:
mov di,qul ;get QD from QUL
test di,di ;DI=unused QD
jnz g_gotqd
pop dx
mov cx,e_no_qd ;no QD available
ret
g_gotqd:
mov ax,q_link[di]
mov qul,ax
pop si ;SI=QD in U_WRKSEG
push di ;save SYSDAT QD
mov cx,qdlen/2
; ES=UDA, DS=SYSDAT
mov ax,ds
mov ds,u_wrkseg ; DS:SI = QD in U_WRKSEG
push es ! mov es,ax ; ES:DI = QD in SYSDAT
rep movsw ; copy QD into QD in SYSDAT
mov ax,es ! mov ds,ax
pop es ; ES=UDA, DS=SYSDAT
pop di ; SYSDAT:DI -> New QD
or q_flags[di],qf_table ; Set "from table" flag
g_qd: ;DI=QD in SYSDAT
xor cx,cx ;CX=0
cmp q_nmsgs[di],cx ;must have one or more msgs
jne g_buflen ;or illegal queue
mov cx,e_no_qbuf
jmps g_qdfree
g_buflen: ;if MX or buffer length is zero
test q_flags[di],qf_mx ;0 Q_BUF field and return
jnz g_mx ;CX=0 to indicate success
cmp q_msglen[di],cx
jne g_getbuf
g_mx:
mov q_buf[di],cx
ret
g_getbuf: ;non 0 length buffer needed
cmp q_buf[di],0 ;is there a buffer specified?
je g_buf
mov ax,q_msglen[di] ;yes make sure it fits in SYSDAT
mul q_nmsgs[di] ;AX=needed buffer space
mov bx,ax
mov dx,q_buf[di]
call sysdat_chk
jcxz g_buf ;CX=0 not within SYSDAT
mov ax,u_wrkseg ;# of paragraphs to U_WRKSEG
mov bx,ds
sub ax,bx ;from SYSDAT
mov cl,4 ! shl ax,cl ;make into # of bytes
add q_buf[di],ax ;make buffer relative to SYSDAT
xor cx,cx ;indicate success
ret
g_buf: ;allocate buffer space to queue
call qspace
jcxz g_ret
mov cx,e_no_qbuf ;no buffer space
g_qdfree:
mov ax,qul ;error return QD to QUL
mov q_link[di],ax
mov qul,di ;CX = error code
g_ret:
ret
sysdat_chk:
;----------
; entry: DX = offset of data structure to check
; relative to U_WRKSEG
; BX = length of data structure
; exit: CX <> 0 if within SYSDAT
; or wrap around
; CX = 0 if not within SYSDAT
; SI,DI preserved
; Check data structure for being within SYSDAT
; Also check that data structure doesn't wrap
; around at 64K, or 1 megabyte.
add dx,bx ;find end of data structure
jc sc_no ;check for 64K wrap around
add dx,0fh
mov cl,4 ;round up to next paragraph
shr dx,cl ;1st paragraph after struct relative
add dx,u_wrkseg ;to U_WRKSEG
jc sc_no ;next paragraph after struct
;check for 1 MB wrap around
mov ax,sysdat
cmp dx,ax ;check for below SYSDAT
jb sc_no
add ax,1000h ;check for above SYSDAT
cmp ax,endseg ;must be within 64k and ENDSEG
jb sc_end ;(use the smaller of the 2)
mov ax,endseg
sc_end:
cmp dx,ax ;DX=next paragraph,
ja sc_no
mov cl,1 ;indicate within SYSDAT
ret
sc_no:
xor cx,cx
ret
qspace:
;------
; entry: DI = QD address
; exit: CX = 0 if ok else error code
; DI preserved
; Allocate buffer space for QD
; The QMAU describes the Memory Allocation Unit
; for the queues. QMAU is set up by GENCCPM or GENSYS.
mov ax,q_msglen[di] ;compute size of buffer
mul q_nmsgs[di] ;AX=size of request
xor cx,cx
push cx ! push cx ! push ax ;call MALLOC
push ax ! push cx ;with MPB on stack
mov dx,sp ! mov ax,ss
mov ds,ax
mov bx,offset qmau
push di ;save QD
mov cx,f_maualloc ;go through OSIF to
call osif ;get U_WRKSEG=SS
pop di ;DI=QD
mov ds,sysdat
cmp cx,0 ! jne qspace_ret
mov bp,sp
mov ax,mpb_start[bp]
mov q_buf[di],ax ;address of buffer
qspace_ret:
add sp,10 ;pop MPB from stack
ret
remqd:
;-----
; Place QD on queue unused list
; entry: DS:DI = QD address
; exit: none
mov ax,q_flags[di]
and ax,qf_table ! jz rqd_exit
mov ax,qul ! mov q_link[di],ax
mov qul,di
jmps qrelease
rqd_exit:
ret
qrelease:
;--------
; entry: DI = QD address
; exit : none
;
; Release buffer space for QD.
; If the released space is ajacent to another
; free area, they are joined in the SAT table.
; The QMAU describes the Memory Allocation Unit
; for the queues. QMAU is set up by GENCCPM or GENSYS.
mov ax,q_buf[di]
mov cx,offset qmau
push ax ! push ax ! push cx ;MFPB on stack
mov cx,f_maufree
mov dx,sp ! mov ax,ss ! mov ds,ax
call osif
add sp,6 ;pop MFPB from stack
mov ds,cs:sysdat ;DS=SYSDAT
ret