; name ('CLCPM') ; title CLCPM - CP/M Dependent Communications I/O for Local ;;; polygon associates, inc. ; ; R. W. Vornberg 81/10/08 v3.0 ; B. W. Baebler 82/03/31 v3.1 ;;; Copyright (c) 1981, 1982, Polygon Associates, Incorporated. ; ; Reproduction or publication in any form or format prohibited. ; This unpublished program is the property of Polygon Associates, ; Inc. ; ; Current licensees of Polygon Associates, Inc. software which ; requires customization are hereby granted permission to modify ; the source code supplied with the software, and merge it into ; the binary code provided by Polygon, for the purpose of enabling ; Polygon software to execute on the Licensee's computer or CPU ; registered with Polygon Associates, Inc. Any other use is ; prohibited. ; poly-, and poly-XFR are trademarks of Polygon Associates, Inc. ; CP/M is a registered trademark of Digital Research. ;;; CLCPM - CP/M Dependent Communications I/O for XFRLOC. ; ; This module defines the following C Callable functions: ; ; ; TEXT *comini(spd, siz) Initialize Communications ; VOID comend() End communications ; BOOL inpsts() Get input status ; TEXT inpchr() Get input data ; VOID inflsh() Flush any input ; BOOL outsts() Get output status ; VOID outchr(chr) Send character ; COUNT bufin(ptxt,ltxt) Get input buffer ; VOID bufout(ptxt,ltxt) Send character buffer ; COUNT boutin(otxt,olen,itxt,ilen) Send/rcv buffer ; ; where: ; typedef unsigned char TEXT; ; typedef int BOOL, VOID; ; typedef short COUNT; ;; The Interface Conditions. ; ; This module interfaces to "C" language routines. The parameter ; passing conventions are those of the Whitesmiths Ltd. C compiler. ; Parameters are pushed onto the stack as sixteen bit values, from ; left to right in the function call. ; ; All registers except the DE pair are available for use. If DE must ; be used, it must be restored upon exit. Additionally, the stack ; pointer must be the same on exit. (i.e. the parameters, or ; placeholders, still on the stack.) The register pair bc is used to ; return the function value, if any. ; ; The largest program (XFR) uses approximately 10k bytes of code. The ; stack pointer is set to the top of the CP/M TPA, so ample stack space ; is available. ; ; All programs are built so a single assembly of this communications ; module can be merged into the binary image. All routines are routed ; through a transfer vector located at a common communications base ; address. (At polygon, we actually link object modules, rather than ; merging .HEX files, but the end result is the same.) The symbol ; "cbase" defined below contains the proper value, and "clength" gives ; the maximum module size allowed. ; ; The standard for all poly-XFR locals is 8 data bits, no parity, and ; 1 stop bit. If 7 level only transfer is possible, the value "parm1$" ; should be given a value of NO, and MASKD changed to MASK7. "parm2$" ; is an internal buffer size value that should not be changed for CP/M. ;;;; External Entry Points. ; public comini,comend ; public inpsts,inpchr,inflsh ; public outsts,outchr ; public bufin$,bufout,boutin ; External Symbols. ; public loops$,parm1$,parm2$ ;;;; ;;;; Symbol Definitions. cbase equ 01A5h ; Module base address clength equ 0200h ; Maximum module length (in bytes) NULL equ 0 ; Null value pointer NO equ 0 ; C logical false YES equ not NO ; C logical true MASK7 equ 07Fh ; 7 level logical mask MASK8 equ 0FFh ; 8 level logical mask MASKD equ MASK8 ; Default condition ;; Device Definitions. ; This is a special version defined for the 2651 devices. devbas equ 0C8h ; Device base dro equ 0 ; Read offset dwo equ 4 ; Write offset rdat equ devbas+dro+00 ; Read data rsts equ devbas+dro+01 ; Read status rmde equ devbas+dro+02 ; Read mode registers 1 and 2 rcmd equ devbas+dro+03 ; Read command wdat equ devbas+dwo+00 ; Write data wmde equ devbas+dwo+02 ; Write mode registers 1 and 2 wcmd equ devbas+dwo+03 ; Write command SRXRDY equ 001h ; Transmitter Ready SRRRDY equ 002h ; Receiver Ready SRXEMP equ 004h ; Transmitter empty or Data set change SRPE equ 008h ; Parity Error SROE equ 010h ; Overrun Error SRFE equ 020h ; Frame Error SRDCD equ 040h ; Data carrier detect SRDSR equ 080h ; Data Set Ready (CC) SRERR equ SRPE or SROE or SRFE ; Any error CRTXEN equ 001h ; Transmitter interrupt enable CRDTR equ 002h ; Data Terminal Ready (CD) CRRXEN equ 004h ; Receiver enable CRSBRK equ 008h ; Send break CRERST equ 010h ; Error Reset CRRTS equ 020h ; Request to Send (CA) STSDLY equ 10 ; Device not ready delay count MR1 equ 04Eh ; Mode reg 1, 1 stop, no parity, 8 data, 16x MR2 equ 030h ; Mode reg 2, select internal rates ;;;; ;;;; Beginning of position dependent code. ; cseg org cbase ; Base of communications area. ;; Dispatch Vectors. comini: jmp cini ; Initialize comend: jmp cend ; Terminate inpsts: jmp ists ; Input status inpchr: jmp ichr ; Input data inflsh: jmp ifsh ; Flush input outsts: jmp osts ; Output status outchr: jmp ochr ; Output character bufin$: jmp ibuf ; Input buffer bufout: jmp obuf ; Output buffer boutin: jmp oibf ; Output/Input buffer ; Global constants. loops$: dw 65000 ; Timeout loop counter parm1$: dw YES ; Binary transfers parm2$: dw 15 ; Maximum buffer size (128) ;;;; End of position dependent code. ;;; CINI - Initialize Communications Interface. ; ; TEXT *comini(spd, siz) ; int spd; ; Communciations speed ordinal (a value ; between 0 and 16. If 0, no change in speed ; is requested, otherwise an index into a ; speed table. ; int siz; ; Logical character data width. If a value ; of 8, then full bytes. Otherwise the low ; 7 bits of each byte. ; Exit: bc = NULL - If no error in initialization. ; = pointer to an error message otherwise. ; Uses: a, bc, hl, initfg. ; Calls: setspd. cini: lda initfg ora a ; Initialized? jnz cin10 ; If so inr a sta initfg ; Set initialized ; Process desired speed if present. pop h ; Return address pop b ; Requested baud rate push b push h mov a,c ora a jz cin10 ; If no speed desired ; Initialize the 2651. mvi a,CRDTR or CRERST ; Disable transmitter and receiver out wcmd in rcmd ; Reset internal sequencer to mode register 1 mvi a,mr1 ; Mode register 1 out wmde mov a,c call setspd ; If not current default cin10: mvi a,CRRTS or CRDTR or CRRXEN or CRTXEN or CRERST out wcmd ; Check for 7 or 8 level transfers. pop h ; Return address pop b ; Requested baud rate pop b ; Transfer level push b ; Restore stack push b mov a,c cpi 8 mvi a,MASK8 ; Assume 8 level jz cin15 mvi a,MASK7 ; Set mask for seven level code cin15: sta ichra sta ichrb sta ochra sta ochrb lxi b,NULL ; Indicate success pchl ; Return ;;; CEND - Terminate communications. ; ; VOID comend() ; ; CEND waits until the communications device is idle ; and performs any required termination duties. cend: in rsts ; Read the status ani SRXEMP ; All sent? jz cend ; If not mvi a,CRDTR ; Drop RTS to the modem, if any out wcmd ret ; Exit ;;; ISTS - Return communications input status. ; ; BOOL inpsts() ; ; ISTS checks whether a character is available from the ; communications device. ; ; Entry: none. ; Exit: bc = YES ( <> 0) if a character is ready. ; = NO ( = 0) otherwise. ; Uses: ; Calls: none. ists: in rsts ; Read status ani SRRRDY ; Mask bit mov c,a ; Return mvi b,0 ; it to caller rnz ; If input is available (YES) ; The device is not ready, delay a small period. ; ; A small delay loop is necessary to get the proper time ; out values on incomplete transfers. For the terminal ; emulator, change the above RNZ to a RET with DDT during ; installation. mvi a,STSDLY ists5: dcr a jnz ists5 ret ; Exit ;;; ICHR - Return communications input. ; ; TEXT inpchr() ; ; ICHR returns the last data byte received by the serial interface. ; It is assumed in the programs that "inpsts" will have been previously ; called and indicated a character present. ; ; Exit: bc = character read. ; Uses: a, bc. ; Calls: none. ichr: in rdat ; Get data ani MASKD ; Keep the significant bits. ichra equ $-1 ; ** Reference label from initialization mov c,a ; Return character mvi b,0 ; to caller ret ; Exit ;;; IFSH - Flush any pending input. ; ; VOID inflsh() ; ; IFSH throws away any pending characters. It is used during ; error recovery processing. ; ; Exit: none. ; Uses: a. ; Calls: none. ifsh: in rsts ; Read status ani SRRRDY rz ; Until no characters are present in rdat ; Flush the character jp ifsh ;;; OSTS - Return status of communications output. ; ; BOOL outsts() ; ; OSTS checks whether a character can be sent to the ; communications device. ; ; Entry: none. ; Exit: bc = YES ( <> 0) if a character may be sent. ; = NO ( = 0) otherwise. ; Uses: a, bc. ; Calls: none. osts: in rsts ; Read status ani SRXRDY ; Mask bit mov c,a ; Return mvi b,0 ; it to caller ( depends on ready being ret ; Exit non-zero) ;;; OCHR - Send communications output. ; ; VOID outchr(chr) ; ; TEXT chr; ; character to transmit ; ; OCHR transmits a character out the serial interface. ; It is assumed in the programs that "outsts" will have been previously ; called and indicated a character could be sent. ; ; Exit: none. ; Uses: a, bc, hl. ; Calls: none. ochr: pop h ; Pick up return address pop b ; Pick up data push b ; Maintain sp mov a,c ; Set data ani MASKD ochra equ $-1 out wdat ; Send pchl ; Exit ;;; IBUF - Get input buffer. ; ; COUNT bufin(ptxt, ltxt) ; TEXT *ptxt ; ; Pointer to an input buffer ; COUNT ltxt ; ; Byte count ; ; IBUF is called to receive a buffer of data from the communication ; line. The first parameter is a pointer to (the address of) an ; input buffer. The second is the size of the read expected. ; The function returns the number of bytes read before any timeout ; period expired, so if the returned value does not match the input ; length "ltxt", a timeout or error occurred. A delay loop is used ; within the read to allow for a five to six second timeout. ; ; Exit: bc = number of characters read into buffer. ; Uses: a, bc, hl, cnt. ; Calls: none. ibuf: lxi h,0 ; Initialize shld cnt ; number read pop h ; get return pc pop b ; get buffer pointer xthl ; save return pc, get length ibf5: mov a,h ; End ora l ; of buffer? jz ibf20 ; If yes dcx h ; Count down remaining push h ; Save remaining length lhld loops$ ; Get loop counter ibf10: in rsts ; Read status ani SRRRDY ; Mask bit jz ibf15 ; If not ready in rdat ; Read data ani MASKD ichrb equ $-1 stax b ; Store inx b ; Advance pointer lhld cnt ; Count inx h ; the input shld cnt ; byte pop h ; Get remaining length jmp ibf5 ; Continue ibf15: dcx h ; Count down mov a,h ; Timed ora l ; out? jnz ibf10 ; If not pop h ; Clean stack ibf20: lhld cnt ; Get count mov b,h ; Put in mov c,l ; return register xthl ; Get return pc push b ; Restore stack pchl ; Exit ;;; OBUF - Send character buffer. ; ; COUNT bufout(ptxt, ltxt) ; TEXT *ptxt ; ; Pointer to an output buffer ; COUNT ltxt ; ; Byte count ; ; OBUF is called to send a buffer of data to the communication ; line. The first parameter is a pointer to (the address of) the ; output buffer. The second is the size of the buffer. ; The function returns the number of bytes sent before any error ; occurred, so if the returned value does not match the output ; length "ltxt", an error occurred. ; ; Exit: bc = number of characters sent from the buffer. ; Uses: a, bc, hl. ; Calls: none. obuf: pop h ; get return pc pop b ; get buffer pointer xthl ; save return pc, get length obf5: mov a,h ; End ora l ; of buffer? jz obf15 ; If yes obf10: in rsts ; Read status ani SRXRDY ; Mask bit jz obf10 ; If not ready ldax b ; Get input inx b ; Advance pointer ani MASKD ochrb equ $-1 out wdat ; Write data dcx h ; Count down remaining jmp obf5 ; Continue obf15: xthl ; Get return pc push b ; Restore stack pchl ; Exit ;;; OIBF - Output/Input buffer. ; ; COUNT boutin(otxt, olen, itxt, ilen) ; TEXT *otxt ; ; Pointer to the output buffer ; COUNT olen ; ; Byte count of output buffer ; TEXT *itxt ; ; Pointer to an input buffer ; COUNT ilen ; ; Byte count ; ; OIBF is called to send and then receive a buffer as one operation. ; ; Exit: bc = returned value of IBUF. ; Uses: hlsav. ; Calls: ibuf, obuf. oibf: pop h ; Save caller's shld hlsav ; return pc call obuf ; Send output buffer pop psw ; Remove output buffer pointer pop psw ; Remove output buffer length call ibuf ; Get input buffer push psw ; Restore push psw ; stack lhld hlsav ; Return pchl ; to caller ;; Local subroutines. ;; setspd - Set device baud rate. ; ; The speed ordinal represents a index into the table below. ; and is the value + 1. (i.e. upon entry a value of 2 will ; use the second [spdtbl+1] table entry or 75 baud.) When ; implementing for other hardware, if the requested speed is ; not available, we do not change the speed. ; ; Entry: c = Requested speed ordinal. ; Exit: speed set. ; Uses: b, c, h, l. ; Calls: None. setspd: mov b,0 lxi h,spdtbl-1 dad b ; Index into table mov a,m ; Get control out wmde ; Write mode reqister 2 ret spdtbl: db mr2+00h ; 1 50 db mr2+01h ; 2 75 db mr2+02h ; 3 110 db mr2+03h ; 4 134.5 db mr2+04h ; 5 150 db mr2+05h ; 6 300 db mr2+06h ; 7 600 db mr2+07h ; 8 1200 db mr2+08h ; 9 1800 db mr2+09h ; 10 2000 db mr2+0Ah ; 11 2400 db mr2+0Bh ; 12 3600 db mr2+0Ch ; 13 4800 db mr2+0Dh ; 14 7200 db mr2+0Eh ; 15 9600 db mr2+0Fh ; 16 19200 db 00 ; 17 EXTERNAL ;; Local Data. ; dseg cnt: dw 0 ; Byte counter hlsav: dw 0 ; Save area initfg: db 0 ; Initialized (if <> 0) if (cbase+clength-$) and 8000h error - module is too long endif freesp equ cbase+clength-$ ; Reserve space for expansion ds freesp end