Digital Research
This commit is contained in:
2020-11-06 18:50:37 +01:00
parent 621ed8ccaf
commit 31738079c4
8481 changed files with 1888323 additions and 0 deletions

View File

@@ -0,0 +1,316 @@
; *** SEROUT.RSP ***
; A Concurrent CP/M-86
; Resident System Process for
; Queue Driven Serial Character Output
; Oct 19, 1983 Dean Ballard
; This program reads the serial out queue and sends those
; characters to the asynchronous communications port. It
; is interrupt driven in that it performs a flag-wait any
; time that the async port is not ready to transmit chars.
; Setting up the actual interrupt routine is the respons-
; ibility of the companion Serial Input routine.
; First the hardware independent equate values.
; These have to do with the queue management, and generally
; pertain to the application program side of things.
q_mes_size equ 17 ; byte count plus 16 characters
out_q_num equ 2 ; number of out queue messages
bdos equ 0E0h ; bdos interrupt number
c_detach equ 93h ; detach console
dev_flag_wait equ 84h ; wait for a flag
dev_flag_set equ 85h ; release a flag
p_delay equ 8Dh ; delay dx ticks
p_term equ 8Fh ; terminate process
q_make equ 86h ; create queue code
q_open equ 87h ; open queue code
q_read equ 89h ; read queue code
q_write equ 8Bh ; write queue code
; RSP origin equates
rsp_header equ 00h ; start of data seg
rsp_pd equ 10h ; process descriptor offset
rsp_uda equ 40h ; user data area offset
rsp_stack_top equ 13Ah ; UDA stack
rsp_data_end equ 140h ; end of rsp stuff
; Data structure for information shared with interrupt routine
t_wait equ byte ptr 0 ; flag wait semaphore
t_count equ byte ptr 1 ; chars left in message
t_ptr_off equ word ptr 2 ; offset of trans message
t_ptr_seg equ word ptr 4 ; segment of trans message
rec_prot equ byte ptr 6 ; receive protocol code
tran_prot equ byte ptr 7 ; transmit protocol code
; Now the hardware specific equates
; These have to do with the I/O port and interrupt management,
; and are, for the most part, specific to the IBM PC
; async port bit patterns
dr equ 01h ; data ready
tbe equ 20h ; xmit buf empty
r_t_mask equ 03h ; rec/trans int en
modem_mask equ 0Bh ; dtr, cts, en int
; **************************
; *** Code begins here ***
; **************************
cseg
org 00h ; small model
serial_out:
call which_port ; are we port 0 or port 1 ?
call is_it_there ; if the port is not present
jnz terminate_out ; then terminate the process
call open_out ; open the output queue
call get_t_block ; copy address to local mem
out_loop:
call read_q ; wait for queue to fill
call send_chars ; transmit queue message
jmps out_loop ; go forever
terminate_out:
mov pd_flag,0 ; turn off the keep flag
mov cl,p_term
mov dl,0
int bdos ; back to bdos
; ***************************
; *** Setup Subroutines ***
; ***************************
; see which port we are, and adjust params if necessary
which_port:
mov al,ncp ; get copy number
cmp al,0 ; if port = 0
jz which_port_done ; then leave params alone
add al,'0' ; change port number to ascii
mov qpb_out_p,al ; and update queue name
mov si,offset port1_params ; now adjust parameters
mov di,offset port0_params
mov cx,port_param_size
cld
rep movsb ; copy port1 over port0
which_port_done:
ret
; check to see if the port is present
; exit: zf set if port is present
is_it_there:
mov dx,port_int_id ; interrupt ident port
in al,dx
test al,0F8h ; should be zero if present
ret
; Open the output queue
; If the open fails, it is because the companion Serial Input
; routine has not yet made the queue. Wait here until it does.
open_out:
mov cl,q_open
mov dx,offset qpb_out ; output queue param block
int bdos ; open it
test ax,ax ; if not successful
jnz open_out ; then try again
ret
; copy t_block address to local memory
; this address is passed by the companion Serial In routine
get_t_block:
mov cl,q_read
mov dx,offset qpb_out ; output queue param block
int bdos ; read shared data pointer
les di,dword ptr msg_out ; get segment and offset
mov t_block_o,di
mov t_block_s,es ; save for wait loop
mov es:t_ptr_seg[di],ds ; tell int where to find
ret ; our trans message
; **************************
; *** Loop Subroutines ***
; **************************
; read one message from the queue
; return only valid data messages
read_q:
mov cl,q_read
mov dx,offset qpb_out ; output queue param block
int bdos ; wait here until ready
mov ax,word ptr msg_out ; al = count, ah = 1st byte
cmp al,q_mes_size ; check message count
jb read_q_done ; return if valid data msg
les di,t_block ; point to shared data
cmp al,0FEh ; recieve protocol code
jnz read_q1
mov es:rec_prot[di],ah ; set receive protocol
read_q1:
cmp al,0FFh ; trans protocol code
jnz read_q
mov es:tran_prot[di],ah ; set transmit protocol
jmps read_q ; go back for another
read_q_done:
ret ; return when ready to send
; send a new queue message to the interrupt routine
send_chars:
les di,t_block ; point to shared data
mov si,offset msg_out
lodsb ; get message count
mov es:t_ptr_off[di],si ; save the message pointer
mov es:t_count[di],al ; and the message count
send_again:
les di,t_block ; point to shared data
mov es:t_wait[di],0FFh ; tell int we're waiting
call fake_int ; and fake an interrupt
mov cl,dev_flag_wait
mov dl,t_flag ; transmit flag
int bdos ; wait here for int done
les di,t_block ; point to shared data
cmp es:t_count[di],0 ; if whole message sent
jz send_done ; then we're done
mov cl,p_delay ; if not, there must be
mov dx,2 ; some protocol hang up
int bdos ; so, wait a bit
jmps send_again ; and try again
send_done:
ret
; Interrupt entries to kick off a transmit burst
fake_int0:
int 12 ; port 0 interrupt
ret
fake_int1:
int 11 ; port 1 interrupt
ret
; *****************************
; *** RSP header, pd, uda ***
; *****************************
dseg
org rsp_header ; header start
dw 0,0
ncp db 1,0 ; one copy
dw 0,0,0
dw 0,0
org rsp_pd ; process descriptor
dw 0,0 ; link, thread
db 0 ; ready to run
db 181 ; priority better than PIN's
pd_flag dw 2 ; process flag "keep"
db 'SerOut ' ; process name
dw rsp_uda/10h ; uda segment
dw 0,0 ; disk, user, reserved
dw 1 ; for shared code
dw 0,0,0 ; and a mess of zeros
dw 0,0,0
dw 0,0,0
dw 0,0,0
org rsp_uda ; user data area
dw 0,0,0,0,0,0 ; no dma buffer
dw 0,0,0,0,0,0
dw 0,0,0,0,0,0
dw 0,0,0,0,0,0
dw 0,0,rsp_stack_top,0,0,0
dw 0,0,0,0,0,0
dw 0,0,0,0,0,0
dw 0,0,0,0,0,0
db 1,0,0,0,0,0 ; don't switch from UDA
; stack at SUP entry
org rsp_stack_top
dw offset serial_out ; code start
dw 0 ; code seg (genccpm)
dw 0 ; flags (genccpm)
; ******************************
; *** Our data begins here ***
; ******************************
org rsp_data_end ; above the rsp stuff
; first we have parameters for port 0
port0_params rb 0
p0_base equ 03F8h ; port base address
port_int_id dw p0_base + 2 ; ro int ident
fake_int dw fake_int0 ; port 0's interrupt
t_flag db 09h ; XIOS transmit flag
; if using port 1, these values are copied over port 0's
port1_params rb 0
p1_base equ 02F8h ; port base address
dw p1_base + 2 ; ro int ident
dw fake_int1 ; port 1's int
db 0Bh ; xmit flag
port_param_size equ offset $ - offset port1_params
t_block_o rw 1 ; address of interrupt
t_block_s rw 1 ; shared data block
t_block equ dword ptr t_block_o
qpb_out dw 0,0,0,msg_out
db 'SerOut'
qpb_out_p db '0 '
msg_out rb q_mes_size
db 00 ; pad
end