home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / modem / com_pkg3.arc / COM_PKG3.ASM
Assembly Source File  |  1986-06-01  |  42KB  |  1,056 lines

  1. 30-May-86 01:03:08-PDT,41855;000000000001
  2. Return-Path: <milne@ICSE.UCI.EDU>
  3. Received: FROM ICSE.UCI.EDU BY USC-ISIB.ARPA WITH TCP ; 30 May 86 00:57:05 PDT
  4. Received: from localhost by ICSE.UCI.EDU id a007132; 29 May 86 22:54 PDT
  5. To: info-ibmpc@usc-isib.arpa
  6. Subject: ComPackage version for UCSD p-System
  7. Date: Thu, 29 May 86 22:54:20 -0800
  8. From: Alastair Milne <milne@ICSE.UCI.EDU>
  9.  
  10.  
  11.  
  12.    Here is my adaptation of the simpler version of ComPackage for the UCSD
  13.    p-System.  There are 5 or 6 separate source files, mostly because of
  14.    limitations of the p-System assembler.  They are delimited by <<<<< marks.
  15.  
  16.    I have placed on each file the documentation header we use at work, to
  17.    explain it and give its relations to the other files.  I hope they will be
  18.    adequate: this is the first time I've sent them to a non-p-System
  19.    installation.
  20.  
  21.    Several of the names exported to Pascal have been changed (lengthened).  
  22.    This was done to make them clearer, and in particular to avoid confusion 
  23.    with names from other units trying to serve the same purpose.  I trust 
  24.    it will not result in too much confusion.
  25.  
  26.    The bug fix I reported is in the interrupt service routine, whose file is
  27.    still called COM.PKG1.TEXT.
  28.  
  29.    I hope you will not find restoring this to MASM conventions overly
  30.    difficult.  If questions arise about what I've done, I'll be happy to help.
  31.  
  32.  
  33.    Thank you,
  34.    Alastair Milne
  35.    
  36. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  37. ;{% global equates and macro definitions for ComPackage
  38. ;File Name : COM.EQU.TEXT  Code Name : <none>
  39. ;
  40. ;Assembly context.  
  41. ;  Files included :  none
  42. ;
  43. ;%}
  44. rsize   .equ     2048            ; size of receive buffer
  45. tsize   .equ     256             ; size of transmit buffer
  46. base    .equ     3F0H            ; base of address of aux. port registers
  47. aux_int .equ     0CH             ; interrupt number for aux port
  48. int_off .equ     aux_int*4       ; offset of interrupt vector
  49. datreg  .equ     base + 8H       ; data register
  50. dll     .equ     base + 8H       ; low divisor latcH
  51. dlh     .equ     base + 9H       ; high divisor latch
  52. ier     .equ     base + 9H       ; interrupt enable register
  53. iir     .equ     base + 0AH      ; interrupt identification register
  54. lcr     .equ     base + 0BH      ; line control register
  55. mcr     .equ     base + 0CH      ; modem control register
  56. lsr     .equ     base + 0DH      ; line status register
  57. msr     .equ     base + 0EH      ; modem status register
  58. dla     .equ     80H             ; divisor latch access
  59. mode    .equ     03H             ; 8-bits, no parity
  60. dtr     .equ     0BH             ; bits to set dtr line
  61. dtr_of  .equ     00H             ; turn off dtr, rts, and tHe interupt driver
  62. thre    .equ     20H             ; mask to find status of xmit holding register
  63. rxint   .equ     01H             ; enable data available interrupt
  64. txint   .equ     02H             ; enable tx holding register empty interrupt
  65. tcheck  .equ     20H             ; mask for checking tx reg status on interrupt
  66. rcheck  .equ     01H             ; mask for checking rx reg status on interrupt
  67. imr     .equ     21H             ; interuprt mask register
  68. int_mask .equ    0EFH            ; mask to clear bit 4
  69. int_pend .equ    01H             ; there is an interrupt pending
  70. mstat   .equ     00H             ; modem status interrupt
  71. wr      .equ     02H             ; ready to xmit data
  72. rd      .equ     04H             ; received data interrupt
  73. lstat   .equ     06H             ; line status interrupt
  74. ack     .equ     244             ; acknowledge symbol
  75. parity  .equ     7FH             ; bits to mask off parity
  76. ocw2    .equ     20H             ; operational control word on 8259
  77. eoi     .equ     64H             ; specific end of interrupt 4
  78. brkbit  .equ     40H             ; bits to cause break
  79. true    .equ     1               ; truth
  80. false   .equ     0               ; falsehood
  81. XOn     .equ     17              ; ASCII Transmit On code, for XOn/XOff protocl
  82. XOff    .equ     19              ; ASCII Transmit Off code,  "    "        "
  83.         
  84. ; assumes the parameter is the first word of an IP:CS pair, 
  85. ;    places the current CS into the CS half, and does an 
  86. ;    indirect long call to the routine pointed to.
  87. ;    NOTE: destroys bx
  88. .macro  CallRel
  89.         lea     bx, cs:%1
  90.         mov     cs:(bx+2), cs
  91.         calll   cs:(%1)
  92. .endm
  93.  
  94. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  95.         .title   "COM.PKG"
  96. ;{% interrupt handler, installer, and remover for ComPackage
  97. ;File Name : COM.PKG1.TEXT   Code Name :  COM.PKG1.CODE
  98. ;
  99. ;History:
  100. ; (Adapted from code for MS-Pascal by John Romkey and Jerry Saltzer of MIT
  101. ;  by Richard Gillmann (GILLMANN@ISIB), 1983.  Taken from COM_PKG1.ASM
  102. ;  from the INFO-IBMPC repository at the University of Southern California.)
  103. ;Date           Coder           Modification
  104. ; winter, 1986  Alastair Milne    Adapted to p-System assembler syntax,
  105. ;                                 and p-System calling conventions.
  106. ;                                 - clearing of serial port (i.e. forced break)
  107. ;                                   moved from init. of interrupt handler
  108. ;                                   to user-callable routine.
  109. ;                                 - XOn/XOff protocol (input & output) added to
  110. ;                                   intrpt handler.
  111. ;                                 - bug fix: transmit-ready interrupt is raised
  112. ;                                      before transmit shift register is ready.
  113. ;                                      Caused strings to be sent as garbage.
  114. ;                                      Added loop to wait for the shift reg.
  115. ;                                         before sending.
  116. ;
  117. ;Assembly context.  
  118. ;  Files included :  COM.EQU.TEXT
  119. ;
  120. ;Linked to : COM.PKG.P.CODE    to obtain : COM.PKG.CODE
  121. ;
  122. ;Important Additional Info: 
  123. ;    All this code expects to use serial port 1 on the IBM PC or compatibles.
  124. ;       No allowance is made for machines with no serial port installed.
  125. ;
  126. ;%}
  127. ;
  128.  
  129. .include        com.equ.text
  130.  
  131. ;
  132. ; int_hndlr - handles interrupts generated by the remote serial port
  133. ;
  134. .PROC   int_hndlr    ; *WARNING* - this routine MUST NOT be .REL
  135. .def    dataseg, ivecofst, int_segment, start_tdata, end_tdata, size_tdata
  136. .def    tdata, rdata, start_rdata, end_rdata, size_rdata
  137. .def    handleraddr
  138.         push    bp
  139.         push    ds
  140.         push    es
  141.         push    di
  142.         push    ax
  143.         push    bx
  144.         push    cx
  145.         push    dx
  146.  
  147. ; set up data segment
  148.         mov     ax,cs:dataseg
  149.         mov     ds,ax
  150.         mov     es,ax
  151.  
  152. ; find out where interrupt came from and jump to routine to handle it
  153.         mov     dx,iir
  154.         in      al,dx
  155.         cmp     al,rd
  156.         jz      rcv_chk          ; if it's from the receiver
  157.         cmp     al,wr
  158.         jz      tmit_chk          ; if it's from the transmitter
  159.         cmp     al,lstat
  160.         jz      lstat_int       ; interrupt becuase of line status
  161.         cmp     al,mstat
  162.         jz      mstat_int       ; interrupt because of modem status
  163.         jmp     int_end ; interrupt when no interrupt pending, go away
  164.  
  165. lstat_int:
  166.         mov     dx,lsr          ; clear interrupt
  167.         in      al,dx
  168.         jmp     repoll          ; see if any more interrupts
  169.  
  170. mstat_int:
  171.         mov     dx,msr          ; clear interrupt
  172.         in      al,dx
  173.         jmp     repoll          ; see if any more interrupts
  174.  
  175. tmit_chk:
  176.         mov     dx,lsr
  177.         in      al,dx
  178.         and     al,tcheck
  179.         jz      repoll          ; transmitter not yet ready, 
  180.                                 ;    so see if any more interrupts
  181.  
  182. .public SndSuspended
  183. goodtx: test    ss:SndSuspended, 1
  184.         jnz     $1
  185.         cmp     size_tdata,0    ; see if any more data to send
  186.         jne     have_data       ; if not equal then there is data to send
  187.  
  188. ; if no data to send, or host sent XOff, then reset tx interrupt and return
  189. $1      call    StopWriting
  190.         jmp     repoll
  191.  
  192. have_data:
  193. TSRReadyFlag    .equ    01000000T   ; the LSR bit indicating the Transmitter
  194.                                     ;   Shift Register is ready.
  195.         xor     cx, cx          ; prepare to leave loop eventually no matter what
  196.         mov     dx, lsr
  197. $1      in      al, dx          ; repeatedly obtain the line status
  198.         test    al, TSRReadyFlag
  199.         jnz     $2              ; until the xmit shift register shows ready.
  200.         loop    $1              ;   (or 65536 iterations done: more than enough)
  201.  
  202. $2      mov     bx,start_tdata  ; bx points to next char. to be sent
  203.         mov     dx,datreg       ; dx equals port to send data to
  204.         mov     al,tdata(bx)    ; get data from buffer
  205.         out     dx,al           ; send data
  206.         inc     bx              ; increment start_tdata
  207.         cmp     bx,tsize        ; see if gone past end
  208.         jl      ntadj           ; if not then skip
  209.         sub     bx,tsize        ; reset to beginning
  210. ntadj:  mov     start_tdata,bx  ; save start_tdata
  211.         dec     size_tdata      ; one less character in x-mit buffer
  212.         jmp     repoll
  213.  
  214. rcv_chk:
  215.         mov     dx,lsr          ; check and see if read is real
  216.         in      al,dx
  217.         and     al,rcheck       ; look at receive data bit
  218.         jnz     good_rx         ; real, go get byte
  219.         jmp     repoll          ; go look for other interrupts
  220.  
  221. good_rx:
  222.         mov     dx,datreg
  223.         in      al,dx           ; get data
  224.         call    CtrlCheck       ; check that data is not flow control
  225.         jz      repoll          ; if it is, don't add it to the queue
  226.         cmp     size_rdata,rsize        ; see if any room
  227.         jge     repoll          ; if no room then look for more interrupts
  228.         mov     bx,end_rdata    ; bx points to free space
  229.         mov     rdata(bx),al    ; send data to buffer
  230.         inc     size_rdata      ; got one more character
  231.         inc     bx              ; increment end_rdata pointer
  232.         cmp     bx,rsize        ; see if gone past end
  233.         jl      nradj           ; if not then skip
  234.         sub     bx,rsize        ; else adjust to beginning
  235. nradj:  mov     end_rdata,bx    ; save value
  236.         call    SizeCheck
  237.  
  238. repoll:
  239.         mov     dx,lsr          ; we always expect receive data, so
  240.         in      al,dx           ; check status to see if any is ready.
  241.         and     al,rcheck       ; get received data bit
  242.         jnz     good_rx         ; yes, go accept the byte
  243.  
  244.         mov     dx,ier          ; look at transmit condition
  245.         in      al,dx           ; to see if we are enabled to send data
  246.         and     al,txint
  247.         jz      int_end         ; not enabled, so go away
  248.         mov     dx,lsr          ; we are enabled, so look for tx condition
  249.         in      al,dx
  250.         and     al,tcheck
  251.         jz      int_end
  252.         jmp     goodtx          ; transmitter is finished, go get more data
  253.  
  254. int_end:
  255.         mov     dx,ocw2         ; tell the 8259 that I'm done
  256.         mov     al,eoi
  257.         out     dx,al
  258.  
  259.         pop     dx
  260.         pop     cx
  261.         pop     bx
  262.         pop     ax
  263.         pop     di
  264.         pop     es
  265.         pop     ds
  266.         pop     bp
  267.         iret
  268.  
  269. ; StopWriting - disables the xmitter-ready interrupt
  270. StopWriting:
  271.         mov     dx,ier
  272.         mov     al,rxint
  273.         out     dx,al
  274.         ret
  275.  
  276. SizeCheck:
  277.      ; check whether receive buffer is now more than 1/4 full:
  278.         cmp     size_rdata, rsize//4
  279.         jle     rdfinished
  280.      ; if it is, and XOn/XOff is being used, and XOff hasn't been sent yet,
  281.      ;     send an XOff to the char-write routine, and set RcvSuspended TRUE
  282.         .ref    WrAppender      ; use the char-write routine to send XOff
  283.         .public ISendXOnXOff, RcvSuspended
  284.         mov     bl, ss:ISendXOnXOff
  285.         mov     dl, ss:RcvSuspended
  286.         not     dl
  287.         and     bl, dl
  288.         and     bl, 1           ; read only bit 0
  289.         jz      rdfinished        ; if XOff has been sent, don't resend
  290.         mov     ax, XOff        ; passing conventions use whole word
  291.         push    ax
  292.         CallRel WrAppender
  293.         mov     ss:RcvSuspended, TRUE
  294. rdfinished:
  295.         ret
  296.         
  297. ;  CtrlCheck - checks if character now in al is flow control character.
  298. ;              returns with ZF reset if it is not.
  299. CtrlCheck:
  300.         .public IHnrXOnXOff, SndSuspended
  301.         test    ss:IHnrXOnXOff, 1       ; if honouring incoming Xon/XOff,
  302.         jnz     CharCheck               ;    check for particular code
  303.         mov     bl, al                  ; otherwise force reset of zero flag,
  304.         not     bl                      ;    and return
  305.         cmp     bl, al
  306.         ret
  307. CharCheck:
  308.         cmp     al, XOn                 ; if incoming is XOn, kill any suspension
  309.         jne     XOffCheck
  310.         mov     ss:SndSuspended, FALSE
  311.         mov     dx,ier                  ;    and restore xmit-ready interrupt
  312.         mov     al,rxint .or txint
  313.         out     dx,al
  314.         ret
  315. XOffCheck:
  316.         cmp     al, XOff
  317.         jne     checkdone
  318.         mov     ss:SndSuspended, TRUE
  319. CheckDone:
  320.         ret
  321.  
  322. handleraddr     .word   int_hndlr
  323. dataseg         .word      0
  324. ivecofst        .word      0       ; the original interrupt offset
  325. int_segment     .word      0       ; the original interrupt segment
  326. start_tdata     .word      0       ; index to first character in x-mit buffer
  327. end_tdata       .word      0       ; index to first free space in x-mit buffer
  328. size_tdata      .word      0       ; number of characters in x-mit buffer
  329. start_rdata     .word      0       ; index to first character in rec. buffer
  330. end_rdata       .word      0       ; index to first free space in rec. buffer
  331. size_rdata      .word      0       ; number of characters in rec. buffer
  332. tdata           .block     tsize ; dup(?)    ; transmit buffer
  333. rdata           .block     rsize ; dup(?)    ; receive buffr
  334.  
  335. ;
  336. ; init_rem
  337. ; initialize the Intel 8250 and set up interrupt vector to int_hndlr
  338. ;
  339. .relproc        InitRem
  340. .ref    handleraddr, dataseg, intsegment, ivecofst
  341.         push    bp
  342.         mov     bp,sp
  343.         cli              ; make sure no interrupts during int.vec change
  344.  
  345.         mov     ax,ds
  346.         mov     cs:dataseg,ax
  347.  
  348.         mov     dx,lsr          ; reset line status condition
  349.         in      al,dx
  350.         mov     dx,datreg       ; reset receive data condition
  351.         in      al,dx
  352.         mov     dx,msr          ; reset modem deltas and conditions
  353.         in      al,dx
  354.  
  355. ; set interrupt vector
  356.    ;save current DS, and reset it to address from 0:0
  357.         push    ds
  358.         xor     ax, ax
  359.         mov     ds,ax
  360.    ;save the pointer at int_off in cx and bx:
  361.         mov     bx,ds:int_off
  362.         mov     cx,ds:int_off+2
  363.         mov     ax, cs:handleraddr
  364.    ; prevent any interrupts, and set the routine pointer to cs:<handler>
  365.         cli
  366.         movm    ds:<int_off+0>, ax
  367.         movm    ds:<int_off+2>,cs
  368.         pop     ds
  369.     ; save the recovered pointer in the handler's data area:
  370.         mov     ivecofst,bx
  371.         mov     int_segment,cx
  372.  
  373. ; enable interrupts on 8259 and 8250
  374.         in      al,imr          ; set enable bit on 8259
  375.         and     al,int_mask
  376.         out     imr,al
  377.         mov     dx,ier          ; enable interrupts on 8250
  378.         mov     al,rxint
  379.         out     dx,al
  380.         mov     dx,mcr          ; set dtr and enable int driver
  381.         mov     al,dtr
  382.         out     dx,al
  383.  
  384.         sti
  385.         pop     bp
  386.         retl
  387.  
  388. ;
  389. ; TurnOffSerial - turns off serial interrupt raising at the serial port
  390. ;                 and the interrupt controller.
  391. ;
  392. .relproc  TurnOffSerial
  393. ; turn off 8250
  394.         mov     dx,ier
  395.         mov     al,0
  396.         out     dx,al
  397.  
  398. ; turn off 8259
  399.         mov     dx,imr
  400.         in      al,dx
  401.         or      ax, .not int_mask
  402.         out     dx,al
  403.         retl
  404.         
  405. ;
  406. ; RemoveHandler - unlinks ComPackages interrupt handler from
  407. ;                 the interrupt vector, returning to it
  408. ;                 whatever was there when the package initialised.
  409. ;
  410. .relproc  RemoveHandler
  411. .ref    int_segment, ivecofst
  412. ; reset interrupt vector
  413.         cli
  414.         mov     bx,ivecofst
  415.         mov     cx,int_segment
  416.         push    ds
  417.         xor     ax, ax
  418.         mov     ds, ax
  419.         movm    ds:<int_off+0>,bx
  420.         movm    ds:<int_off+2>,cx
  421.         pop     ds
  422.         sti
  423.         retl
  424.         
  425. .end
  426. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  427. ;{% 8088/6 routines to set communications parameters for ComPackage.
  428. ;File Name : COM.STNG   Code Name :  COM.STNG     (i.e. COM.SeTtiNGs)
  429. ;
  430. ;History:
  431. ; (Adapted from code for MS-Pascal by John Romkey and Jerry Saltzer of MIT
  432. ;  by Richard Gillmann (GILLMANN@ISIB), 1983.  Taken from COM_PKG1.ASM
  433. ;  from the INFO-IBMPC repository at the University of Southern California.)
  434. ;Date           Coder           Modification
  435. ;  Jan-April 86   Alastair Milne   Adapted to p-System conventions,
  436. ;                                  added setting of word length, stop bits,
  437. ;                                  and parity;
  438. ;                                  added FlushAll to clear I/O queues.
  439. ;                                  separated baud rate setting into own routine.
  440. ;                                  collapsed DTR_on and DTR_off into SetDTR.
  441. ;Assembly context.  
  442. ;  Files included :  COM.EQU>TEXT
  443. ;
  444. ;Linked to : COM.PKG.P.CODE   to obtain : COM.PKG.CODE
  445. ;
  446. ;%}
  447. .include com.equ.text
  448.  
  449. .RELPROC  SetBaudDivisor, 1
  450. ; Place the passed argument in the baud rate divisor latch.
  451.         mov     bp, sp
  452.         mov     dx,lcr
  453.         in      al, dx
  454.         or      al, dla         ; set 8th bit of LnCtrlReg on,
  455.                                 ;   so that 3F8H addresses divisor latch.
  456.         out     dx,al
  457.         mov     dx,dll
  458.         mov     al,(bp+4)       ; low byte of passed argument
  459.         out     dx,al
  460.         mov     dx,dlh
  461.         mov     al,(bp+5)       ; high byte of passed argument
  462.         out     dx,al
  463.         mov     dx, lcr
  464.         in      al, dx
  465.         and     al, 7FH         ; turn off 8th bit again,
  466.                                 ;   so 3F8H addresses Xmit/Recv buffer.
  467.         out     al, dx
  468.         retl    2
  469.  
  470. .RELPROC   SetWordLength, 1
  471. ; Sets the Line Control Register to use a word length of the value
  472. ;    of the passed argument, either 7 or 8.  Any other value is ignored.
  473. SevenDataBits   .equ    10T
  474. EightDataBits   .equ    11T
  475.         mov     bp, sp
  476.         cmp     (bp+4), 7
  477.         jl      ResetDone       ; don't do anything if new length < 7
  478.         mov     ah, SevenDataBits       ; in case new length = 7
  479.         cmp     (bp+4), 8
  480.         jg      ResetDone       ; don't do anything if new length > 8
  481.         jne     SetBits         ; given length = 7 bits, use crnt pattern
  482.         mov     ah, EightDataBits       ; given length = 8, get 8 bit pattern
  483. SetBits:
  484.         mov     dx, lcr         ; get crnt line ctrl settings, 
  485.         in      al, dx
  486.         and     al, 11111100T   ;   and clear word length bits for new setting.
  487.         or      al, ah          ; put in new word length setting
  488.         out     al, dx          ;   and send it back out.
  489. ResetDone:
  490.         retl    2
  491.         
  492. .RELPROC  SetStopBits, 1
  493. ;  Sets the Line Control Register to use either 1 or 2 stop bits,
  494. ;    depending on the parameter.  Anything but 1 or 2 is ignored.
  495.         mov     bp, sp
  496.         mov     dx, lcr         ; get crnt line ctrl settings
  497.         in      al, dx
  498.         cmp     (bp+4), 1       ; if new number of stop bits = 1, 
  499.         jne     Try2
  500.         and     al, 11111011T   ;    set stop-bit switch 0
  501.         jmp     Reset
  502. Try2:   cmp     (bp+4), 2       ; else if it's 2, 
  503.         jne     NoChange
  504.         or      al, 00000100T   ;    set stop-bit switch 1
  505. Reset:  out     al, dx
  506. NoChange:
  507.         retl    2
  508.         
  509. .RELPROC    SetParity, 1
  510. ; Sets the Line Control Register to use the parity indicated
  511. ;   by the passed argument.  Allowed values are the 5 listed below.
  512. ;   Any other is ignored.
  513. NoParity        .equ    0
  514. EvenParity      .equ    1
  515. OddParity       .equ    2
  516. SpaceParity     .equ    3
  517. MarkParity      .equ    4
  518.         mov     bp, sp
  519.         mov     cx, (bp+4)
  520.         mov     dx, lcr         ; get crnt line ctrl settings
  521.         in      al, dx
  522.         cmp     cl, NoParity
  523.         jne     TryEven
  524.         and     al, 11000111T   ; suppress all parity switches.
  525.         jmp     Reset
  526. TryEven:
  527.         or      al, 00001000T   ; enable parity switch for all other settings.
  528.         cmp     cl, EvenParity  ; if new parity is even, 
  529.         jne     TryOdd
  530.         or      al, 00010000T   ;    suppress break, and stick-parity switch.
  531.         jmp     Reset
  532. TryOdd: cmp     cl, OddParity   ; if new parity is odd,
  533.         jne     TrySpace
  534.         and     al, 11001111T   ;    suppress stick- and even-parity.
  535.         jmp     Reset
  536. TrySpace:
  537.         or      al, 00100000T   ; turn on the stick-parity switch for the rest.
  538.         cmp     cl, SpaceParity
  539.         jne     TryMark
  540.         or      al, 00111000T   ; turn on stick-, even-, and enable switches.
  541.         jmp     Reset
  542. TryMark:
  543.         cmp     cl, MarkParity
  544.         jne     NoChange
  545.         and     al, 11101111T ; turn off even-par switch.
  546. Reset:  out     al, dx
  547. NoChange:
  548.         retl    2
  549.         
  550.  
  551. ;
  552. ; SetDTR  - turns off dtr to tell modems that the terminal has gone away
  553. ;           and to hang up the phone
  554. ;
  555. .relproc        SetDTR, 1       ; bit 0 of parameter is new DTR setting
  556.         mov     dx,mcr
  557.         mov     bp, sp
  558.         test    (bp+4), 1       ; check whether bit 0 is 1
  559.         jnz     $1
  560.         mov     al,dtr_of       ; if not, set up DTR-off mask 
  561.         jmp     $2
  562. $1      mov     al, dtr         ; if so, set up DTR-on mask
  563. $2      out     dx, al          ; set modem ctrl reg to new mask
  564.         retl    2
  565.  
  566. ;
  567. ; Break - causes a break to be sent out on the line
  568. ;
  569. .relproc        Break
  570.         mov     dx,lcr          ; save the line control register
  571.         in      al,dx
  572.         mov     bl,al
  573.                 
  574.         or      al,brkbit       ; set break condition
  575.         out     dx,al
  576.  
  577.         mov     cx,500          ; delay a while
  578. delay:  loop    delay
  579.  
  580.         mov     al,bl           ; restore the line control register
  581.         out     dx,al
  582.         retl
  583.  
  584. ; FlushAll  -  resets all queue pointers to zero, dropping any contents.
  585. ;              Doesn't affect interrupt servicing.
  586. ;
  587. .RELPROC    FlushAll
  588.         .ref    start_tdata, end_tdata, size_tdata
  589.         .ref    start_rdata, end_rdata, size_rdata
  590.         xor     ax, ax
  591.         mov     start_tdata, ax
  592.         mov     end_tdata, ax
  593.         mov     size_tdata, ax
  594.         mov     start_rdata, ax
  595.         mov     end_rdata, ax
  596.         mov     size_rdata, ax
  597.         retl
  598. .END
  599.  
  600. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  601. ;{% remote serial output management routines for ComPackage
  602. ;File Name : COM.WRT.TEXT    Code Name :  COM.WRT.CODE
  603. ;
  604. ;History:
  605. ; (Adapted from code for MS-Pascal by John Romkey and Jerry Saltzer of MIT
  606. ;  by Richard Gillmann (GILLMANN@ISIB), 1983.  Taken from COM_PKG1.ASM
  607. ;  from the INFO-IBMPC repository at the University of Southern California.)
  608. ;Date           Coder           Modification
  609. ;  Jan-April 86   Alastair Milne    Adapted to p-System conventions.
  610. ;                                   Added SendStr for string-oriented output.
  611. ;                                   Interrupts cleared for char-add and 
  612. ;                                      string-add so handler won't try to send
  613. ;                                      during routines' execution.
  614. ;Assembly context.  
  615. ;  Files included :  COM.EQU.TEXT
  616. ;
  617. ;Linked to : COM.PKG.P.CODE   to obtain : COM.PKG.CODE
  618. ;
  619. ;Important Additional Info: 
  620. ;  Neither write routine (string or character) checks whether there is room
  621. ;     left in the output queue for what they will add.  If there is none, 
  622. ;     they will overwrite the existing contents.  The function RemWrtSpace 
  623. ;     is exported to permit the user to make this check if desired.
  624. ;%}
  625. .include com.equ.text
  626. ;
  627. ; RemWrtSpace - returns the amount of free space remaining in the transmit buffer
  628. ;
  629. .relfunc        RemWrtSpace
  630.         .ref    size_tdata
  631.         push    bp
  632.         mov     bp, sp
  633.         mov     ax,tsize        ; get the size of the x-mit buffer
  634.         sub     ax,size_tdata   ; subtract the number of bytes used
  635.         mov     (bp+6), ax
  636.         pop     bp
  637.         retl
  638. ;
  639. ; SendCh(ch:byte) - the passed character is put in the transmit buffer
  640. ;       *WARNING*  does not check that there is room to hold the character.
  641. .relproc        SendCh, 1
  642.         .ref    end_tdata, tdata, size_tdata
  643.         .def    IntrAddr, WrAppender
  644.         push    bp
  645.         cli             ; keep intrpt handler out while adding the char.
  646.         mov     bp,sp
  647.         mov     bx,end_tdata    ; bx points to free space
  648.         mov     al,(bp+6)       ; move data from stack to x-mit buffer
  649.         mov     tdata(bx),al
  650.         inc     bx              ; increment end_tdata to point to free space
  651.         cmp     bx,tsize        ; see if past end
  652.         jl      L4              ; if not then skip
  653.         sub     bx,tsize        ; adjust to beginning
  654. L4:     mov     end_tdata,bx    ; save new end_tdata
  655.         inc     size_tdata      ; one more character in x-mit buffer
  656.         call    IntrOn
  657. L44:    sti
  658.         pop     bp
  659.         retl    2
  660.         
  661. IntrOn:
  662.         mov     dx,ier          ; see if tx interrupts are enabled
  663.         in      al,dx
  664.         and     al,txint
  665.         or      al,al
  666.         jnz     $1
  667.         mov     al,rxint+txint  ; if not then set them
  668.         out     dx,al
  669. $1      ret
  670. IntrAddr        .word   IntrOn
  671. WrAppender      .word   SendCh, CS       ; the intersegment address of this 
  672.                                         ;    relproc.
  673.                                         ; second word must be set to current CS
  674.                                         ;   at runtime, BEFORE any indirect 
  675.                                         ;   calls to this routine.
  676.  
  677. ;
  678. ; SendStr(var Out: string);
  679. ;       *WARNING*  does NOT check that the buffer has room for the string.
  680. .relproc SendStr, 1             ; parameter points to byte 0 of string in SS.
  681. OutStrPtr       .equ    4
  682.         .ref    end_tdata, tdata, size_tdata, IntrAddr, WrAppender
  683.         mov     bp, sp
  684.         cld                     ; make sure str instructions move ahead in mem.
  685.     ;put length byte into cl, move si to string[1], and zero ch:
  686.         mov     si, (bp+OutStrPtr)
  687.         mov     cl, ss:(si)
  688.         inc     si
  689.         xor     ch, ch
  690.         jcxz    finished        ; if the string is empty, send is finished
  691.         push    cx              ; save the length (loop will zero cx)
  692.         mov     di, end_tdata   ; di now indexes (NOT pointing) last buffer pos.
  693.         cli     ; keep intrpt handler out while adding the string.
  694. ; append cx characters from the string to the buffer:
  695. nextchar:
  696.         seg ss  lodsb           ; al <= new char, si <= si + 1
  697.         mov     es:tdata(di), al        ; buffer[di] <= new char
  698.         inc     di
  699.         cmp     di, tsize       ; has buffer index reached buffer end?
  700.         jl      moveup          ; no: go for next character.
  701.         xor     di, di          ; yes: wrap it to start of buffer.
  702. moveup:
  703.         loop    nextchar
  704.         pop     cx              ; recover the string's length, 
  705.         add     cs:size_tdata, cx       ; and augment the queue size by it.
  706.         mov     cs:end_tdata, di        ; adjust permanent buffer index.
  707.         sti
  708.         call    cs:(IntrAddr)   ; make sure transmitter-ready intrpt is on.
  709. finished:
  710.         retl    2
  711. ;
  712. ; wlocal(ch:byte) - writes a character to the input buffer
  713. ;
  714. .relproc        wlocal, 1
  715.         .ref    size_rdata, end_rdata, rdata
  716.         push    bp
  717.         mov     bp,sp
  718.         cli
  719.  
  720.         cmp     size_rdata,rsize        ; see if any room
  721.         jge     L14             ; if no room then quit
  722.         mov     bx,end_rdata    ; bx points to free space
  723.         mov     al,(bp+6)       ; get data
  724.         mov     rdata(bx),al    ; send data to buffer
  725.         inc     size_rdata      ; got one more character
  726.         inc     bx              ; increment end_rdata pointer
  727.         cmp     bx,rsize        ; see if gone past end
  728.         jl      L13             ; if not then skip
  729.         sub     bx,rsize        ; else adjust to beginning
  730. L13:    mov     end_rdata,bx    ; save value
  731.  
  732. L14:    sti
  733.         pop     bp
  734.         retl    2
  735. .end
  736. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  737. ;{% the remote serial input management routines of ComPackage.
  738. ;File Name : COM.READ.TEXT   Code Name : COM.READ.CODE
  739. ;
  740. ;History:
  741. ; (Adapted from code for MS-Pascal by John Romkey and Jerry Saltzer of MIT
  742. ;  by Richard Gillmann (GILLMANN@ISIB), 1983.  Taken from COM_PKG1.ASM
  743. ;  from the INFO-IBMPC repository at the University of Southern California.)
  744. ;Date           Coder           Modification
  745. ;  Jan-April 86  Alastair Milne   Adapted existing char read and char count
  746. ;                                   routines to p-System.
  747. ;                                 Added routine to return string of chars.
  748. ;                                   from input queue.
  749. ;Assembly context.  
  750. ;  Files included :  COM.EQU.TEXT
  751. ;
  752. ;Linked to : COM.PKG.P.CODE   to obtain : COM.PKG.CODE
  753. ;
  754. ;%}
  755. .include com.equ.text
  756. ;
  757. ; RemReadCount - returns number of bytes in the receive buffer
  758. ;
  759. .relfunc        RemReadCount
  760.         .ref    size_rdata
  761.         push    bp
  762.         mov     bp, sp
  763.         mov     ax,size_rdata   ; get number of bytes used
  764.         mov     (bp+6), ax
  765.         pop     bp
  766.         retl
  767. ;
  768. ; RemChRead - returns the next character from the receive buffer and
  769. ;         removes it from the buffer
  770. ;
  771. .relfunc        RemChRead
  772.         .ref    start_rdata, rdata, size_rdata
  773.         mov     bx,start_rdata  ; set bx to index the front of the read queue
  774.         mov     al,rdata(bx)    ; put the char to read in low byte and zero high
  775.         xor     ah, ah
  776.         mov     bp, sp          ; put ax on the stack as function result
  777.         mov     (bp+4), ax
  778.         inc     bx              ; bump start_rdata so it points at next char
  779.         cmp     bx,rsize        ; see if past end
  780.         jl      $1              ; if not then skip
  781.         sub     bx,rsize        ; adjust to beginning
  782. $1:     mov     start_rdata,bx  ; save the new start_rdata value
  783.         dec     size_rdata      ; one less character
  784.         jnz     $2
  785.         call    Restore         ; if buffer now empty, make sure further input
  786.                                 ;    not prevented by XOff
  787. $2:     retl
  788.         
  789. Restore:
  790. ; assumes the read buffer is now empty, or almost.  If UsingXOnXOff and 
  791. ;    Suspended are set, sends an XOn, and resets Suspended
  792.         .public ISendXOnXOff, RcvSuspended
  793.         .def    RestoreAddr
  794.         .ref    WrAppender      ; export my own address in WrAppender
  795.    ; if lowest bit of (ISendXOnXOff AND RcvSuspended) is set ...
  796.         mov     bl, ss:ISendXOnXOff
  797.         mov     dl, ss:RcvSuspended
  798.         and     bl, dl
  799.         and     bl, 1
  800.         jz      $1
  801.         mov     ax, XOn                 ; pass XOn to the public SendCh routine
  802.         push    ax
  803.         CallRel WrAppender
  804.         mov     ss:RcvSuspended, FALSE  ; indicate reception is now suspended.
  805. $1      ret
  806. RestoreAddr     .word   Restore
  807.  
  808.         
  809. ; RemStrRead - moves the characters at the head of the remote input queue
  810. ;       into a Pascal string, adjusting the queue pointers and size 
  811. ;       indicator accordingly.
  812. .relproc        RemStrRead, 2   ; first parameter is pointer to string
  813.                                 ;   length byte
  814.                                 ; second is maximum length to be read.
  815. OutStr          .equ    6
  816. MaxLength       .equ    4
  817.         .ref    start_rdata, rdata, size_rdata
  818.         mov     bp, sp
  819.      ; set si to index of first char. to read from buffer:
  820.         mov     si, cs:start_rdata
  821.      ; point es:di to zero'th byte of parameter string:
  822.         mov     di, (bp+OutStr)
  823.         push    ss
  824.         pop     es
  825.      ; set cx to lesser of: number of chars. in buffer; or max. length
  826.         mov     cx, size_rdata
  827.         cmp     cx, (bp+MaxLength)
  828.         jle     $1
  829.         mov     cx, (bp+MaxLength)
  830. $1:     cld
  831.      ; store the length count into the string's length byte (ie. string[0])
  832.         mov     al, cl
  833.         stosb
  834.      ; if the string is empty, just return
  835.         jcxz    retstr
  836.         push    cx              ; save count, for subtraction after loop
  837. ; run si along the queue, appending cx characters to the parameter string:
  838. nextchar:
  839.         mov     al, rdata(si)   ; get each byte from the buffer,
  840.         inc     si
  841.         stosb                   ;    and append it to the string.
  842.         cmp     si, rsize       ; if si now at end of buffer area,
  843.         jl      $2
  844.         xor     si, si          ;    wrap it around to the beginning
  845. $2:     loop    nextchar        ; if more left to read, do another pass
  846.         pop     cx              ; recover original count (loop has 0'd it)
  847.         sub     size_rdata, cx  ;    and reduce current queue size by it.
  848. retstr: mov     start_rdata, si         ; update reading pointer to new start.
  849.         or      size_rdata, 0   ; if no more left in incoming queue,
  850.         jnz     $1
  851.         .ref    RestoreAddr 
  852.         call    cs:(RestoreAddr)    ;   make sure XOff isn't suppressing it.
  853. $1      retl    4
  854. .end
  855. <<<<<<<<<<<<<<<<<<<<<<<<<<<
  856. {% UCSD Pascal library UNIT to service remote serial interrupts.
  857. File Name : COM.PKG.P.TEXT               Code Name:  COM.PKG.P.CODE
  858.  
  859. History:
  860. Date            Coder           Modification
  861.  Jan-Apr 86   Alastair Milne    Creation of Pascal interface for assembly
  862.                    routines:
  863.                 - string and character write routines
  864.                 - string and character read routines
  865.                 - report of chars. to read and space for write
  866.                 - routines to change communications params.
  867.                 - routines to set DTR and send break signal
  868.                 - routine to flush I/O queues
  869.                 - flags to set or reset XOn/XOff flow control
  870.                 Automatic initialisation installs handler
  871.                   and enables serial interrupts.
  872.                 Automatic termination restores original 
  873.                   interrupt vector entry and disables
  874.                   serial interrupts.
  875.  
  876. Compilation context:     Prefix for Compilation: None
  877.    Units used : None
  878.    Files included : None
  879.    Linked to : COM.READ.CODE
  880.            COM.WRT.CODE
  881.            COM.STNG.CODE
  882.            COM.PKG1.CODE
  883.    
  884.    To obtain : COM.PKG.CODE
  885.  
  886. Files used at execution:  None
  887.  
  888. Important Additional Info:  does NOT handle incoming tabs (ASCII 9).
  889.  
  890. %}
  891. unit ComPackage;
  892.  
  893.   interface
  894.     
  895.     type  cpWrdLngRange = 7 .. 8;
  896.           cpStpBtRange = 1 .. 2;
  897.           StrRange = 0 .. 255;   {the range of lengths a UCSD Pascal
  898.                       string can have.}
  899.           cpBaudRates = (cpBaud110, cpBaud300, cpBaud1200, cpBaud2400, 
  900.                          cpBaud4800, cpBaud7200, cpBaud9600);
  901.           cpParityTypes = (cpNoParity, cpEvenParity, cpOddParity,
  902.                            cpSpaceParity, cpMarkParity);
  903.     
  904.     var  ISendXOnXOff: boolean;  {set this TRUE if ComPackage is to 
  905.                                   control incoming flow with XOn/XOff
  906.                                   protocol.  Initially FALSE. }
  907.          IHnrXOnXOff: boolean;  {set this TRUE if ComPackage is to
  908.                                  honour XOn/XOff protocol use by other host.  
  909.                                  Initially FALSE. }
  910.     
  911.     
  912.     function RemReadCount: integer;
  913.        { Returns number of characters waiting to be read 
  914.          from serial port. }
  915.     function RemChRead: char;
  916.        { Returns character now at front of queue from serial port.}
  917.     procedure RemStrRead(var StrFromRem: string; MaxLength: StrRange);
  918.        { Returns all the characters now available from the serial port,
  919.          or the first MaxLength of them, whichever is less.  StrFromRem
  920.          is returned empty if no characters are available. }
  921.     
  922.     function RemWrtSpace: integer;
  923.        { Returns the number of bytes still available to the write buffer.}
  924.     procedure RemChWrite(ch: char);
  925.        { Writes Ch into the output serial buffer. }
  926.     procedure RemStrWrite(str: string);
  927.        { Moves Str into the output serial buffer, and makes sure 
  928.          the serial interrupts are set to transmit it.}
  929.     
  930.     procedure InWrite(ch: char);
  931.        { Writes the Ch to the serial input buffer (debugging). }
  932.     
  933.     procedure SetBaudRate(NewRate: cpBaudRates);
  934.     procedure SetWordLength(BitsInWord: cpWrdLngRange);
  935.     procedure SetStopBits(BitsToStop: cpStpBtRange);
  936.     procedure SetParity(NewParity: cpParityTypes);
  937.     
  938.     procedure SetDTR(DTRSetting: BOOLEAN);
  939.        { Sets the RS-232C DTR (Data Terminal Ready) pin to DTRSetting. }
  940.     
  941.     procedure FlushAll;
  942.        { Empties the input and output remote serial buffers,
  943.          but leaves interrupt servicing available. }
  944.     procedure Break;
  945.        { Sends the break signal. }
  946.     procedure CloseRemote;
  947.        { Closes down the remote serial port and suppresses 
  948.          serial interrupts.  Doesn't affect input or output buffer.}
  949.   
  950.   implementation
  951.           
  952.     var  (*WARNING: the xxxSuspended flags are global to give them 
  953.                     a permanent lifetime, and to permit them to be communicated
  954.                     among the interrupt servicer, reading, and writing routines.
  955.                     They must NOT be modified by any other routine, or errors
  956.                     in flow control (including possible infinite loops) may 
  957.                     result. *)
  958.          RcvSuspended,  {TRUE <==> I have sent XOff to suspend host sending}
  959.          SndSuspended:  {TRUE <==> host has sent XOff to suspend my sending}
  960.                     boolean;
  961.          Divisor: array[cpBaudRates] of integer;
  962.     
  963.     procedure IntHndlr;  external;  {This is the interrupt handler,
  964.                                      to which the hardware interrupt vector
  965.                                      points.
  966.                                      MUST NOT BE CALLED DIRECTLY
  967.                                      BY PASCAL. }
  968.  
  969.  {Routines to initialise and terminate serial interrupt servicing: }
  970.     procedure InitRem;  external;  {Install interrupt handler, 
  971.                     and enable serial interrupts}
  972.     procedure TurnOffSerial;  external;  {disable serial interrupts}
  973.     procedure RemoveHandler;  external;  {restore original interrupt vector
  974.                       entry}
  975.     procedure FlushAll;  external;
  976.     
  977.  {Routines to manage incoming characters:}
  978.     function RemReadCount (*: integer*);  external; 
  979.     function RemChRead (*: char*);  external;
  980.     procedure RemStrRead(*var FromRem: string; MaxLength: StrRange*);  external;
  981.     
  982.  {Routines to manage outgoing characters:}
  983.     function RemWrtSpace (*: integer*); external;
  984.     procedure SendCh(ch: char); external;  {add ch to output queue}
  985.     procedure SendStr(var OutStr: string); external;  {add outstr to 
  986.                                                         output queue}
  987.     
  988.  {Debugging routine to append characters to input queue:}
  989.     procedure WLocal(ch: char);  external;
  990.     
  991.  {Routines to control transmission parameters: }
  992.     procedure SetBaudDivisor(Divisor: integer); external;
  993.     procedure SetWordLength(*BitsInWord: cpWrdLngRange*); external;
  994.     procedure SetStopBits(*BitsToStop: cpStpBtRange*); external;
  995.     procedure SetParity(*NewParity: cpParityTypes*); external;
  996.     procedure SetDTR(*DTRSetting: BOOLEAN*);  external;
  997.     procedure Break;  external;
  998.     
  999.     procedure SetBaudRate(*NewRate: cpBaudRates*);
  1000.       begin
  1001.         SetBaudDivisor(Divisor[NewRate]);
  1002.       end;
  1003.   
  1004.     procedure CloseRemote;
  1005.       begin
  1006.         TurnOffSerial;
  1007.         RemoveHandler;
  1008.       end;
  1009.     
  1010.     procedure RemChWrite(*ch: char*);
  1011.       begin
  1012.         while RemWrtSpace < 5 do;    {make sure serial output queue 
  1013.                                 has enough space: wait until some is dumped. }
  1014.         SendCh(ch);
  1015.       end;
  1016.  
  1017.     procedure RemStrWrite(*Str: string*);
  1018.       begin
  1019.         while RemWrtSpace < length(Str) do;  {wait until the hardware
  1020.                                         has dumped enough of the buffer
  1021.                                         to admit the new string.}
  1022.         SendStr(Str);
  1023.       end;
  1024.     
  1025.     procedure InWrite(*ch: char*);
  1026.       begin
  1027.         WLocal(ch);
  1028.       end;
  1029.       
  1030.  begin
  1031.  {automatic initialisation: 
  1032.      set baud rate divisors (taken from table);
  1033.     NOTE: these values should work for most IBM PC compatibles,
  1034.           but they WON'T work for the PC jr, which uses different divisors.
  1035.      set flags for no flow control;
  1036.      install handler and enable serial interrupts.}
  1037.    Divisor[cpBaud110] := 1047;
  1038.    Divisor[cpBaud300] := 384;
  1039.    Divisor[cpBaud1200] := 96;
  1040.    Divisor[cpBaud2400] := 48;
  1041.    Divisor[cpBaud4800] := 24;
  1042.    Divisor[cpBaud7200] := 16;
  1043.    Divisor[cpBaud9600] := 12;
  1044.    ISendXOnXOff := false;  RcvSuspended := false;  
  1045.    IHnrXOnXOff := false;   SndSuspended := false;
  1046.    InitRem;
  1047.  {automatic termination:
  1048.    turn off serial interrupts and restore the original 
  1049.      interrupt vector entry: }
  1050.    ***;
  1051.    TurnOffSerial;
  1052.    RemoveHandler;
  1053.  end.
  1054.