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

316 lines
7.8 KiB
Plaintext
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

; *** 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