home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / archives / krt11.zip / krtkm.mac < prev    next >
Text File  |  1997-10-17  |  42KB  |  1,273 lines

  1.     .title    KRTKM    Kermit-11 RT-11/TSX modem driver
  2.     .ident    "V03.63"
  3.  
  4.     .ASECT
  5. . = 110                    ; for RESORC/V
  6.     .rad50    "V03"            ; handler is for this version
  7.     .word    63.            ; and this revision of Kermit
  8.     .word    0.            ; patch level
  9.     .word    -1            ; terminator
  10.  
  11. ; /63/    27-Sep-97  Billy Youdelman  V03.63
  12. ;
  13. ; Add SPFUNs to support Xmodem compatibly with the TSX CL handler:
  14. ;
  15. ;    CLSET    <250>    Set CL options (binin and binout only)
  16. ;    CLRSET    <251>    Clear CL options (binin and binout only)
  17. ;    CLIPND    <261>    Get number of input chars pending
  18. ;    CLWBYT    <263>    Write with byte count
  19. ;    CLCHAR    <266>    Get CL characteristics (options flags only)
  20. ;
  21. ; Enabling binin or binout does not in itself bypass XOFF flow control
  22. ; processing in the input or output routines here, one must explicitly
  23. ; set RTS/CTS flow control as well, or uncomment the appropriate lines
  24. ; in the kiint (binin) and kmint/koint (binout) routines, below.
  25. ;
  26. ; This driver does not currrently support "no flow control" -- RTS/CTS
  27. ; must be enabled when binin or binout is used.  Flow control may then
  28. ; be ignored if desired by using a cable that doesn't connect pins 4 &
  29. ; 5.
  30. ;
  31. ; Added .br macro for clarity.
  32.  
  33. ; /62/    27-Jul-93  Billy Y..  V03.62-7    (for KRT V03.62-8)
  34. ;
  35. ; KM is a "Kermit Modem" communications handler provided to support
  36. ; TSX-Plus features not otherwise available under RT-11, as well as
  37. ; older releases of TSX that preceded its CL handler.   KM combines
  38. ; the best of both worlds, including the following under RT-11:
  39. ;
  40. ;    o  Works with DL(V), Falcon and PRO serial interfaces
  41. ;    o  Speed may be SET and SHOWn from within Kermit
  42. ;    o  Automatic fallback to the connected speed
  43. ;    o  An eight-bit data path
  44. ;    o  Selectable hardware (RTS/CTS) flow control
  45. ;    o  Emulation of TSX's CLCLR (flush pending I/O)
  46. ;    o  DTR toggling to support Kermit's HANGUP command
  47. ;    o  Usable with RT-11 V4.0 and up, and TSX-Plus V5.0 and up
  48. ;
  49. ; To use KM you must first edit the appropriate conditional assembly
  50. ; files for the serial line interface in your system:
  51. ;
  52. ;    KRTSJ .CND  -  for RT-11FB, RT-11SB, and RT-11SJ
  53. ;    KRTXM .CND  -  for RT-11XB, RT-11XM, RT-11ZB and RT-11ZM
  54. ;    KRTTSX.CND  -  for TSX-Plus
  55. ;
  56. ; Then assemble and link using KRTSYS.COM if being done under RT-11
  57. ; V5.0 or above, or KRTSV4.COM if using any RT-11 V4 release.  This
  58. ; will create KM.SYS, KMX.SYS and KM.TSX, which should be copied to
  59. ; your system device (SY) where they may be INSTALLed and LOADed as
  60. ; needed.  Note that KRTKM.MAC (the handler source file) must be on
  61. ; the default disk for this assembly.  Under TSX you'll have to use
  62. ; TSXMOD to add a definition for KM as shown below, or define it in
  63. ; TSGEN.MAC and rebuild the system.  In either case you must reboot
  64. ; as it only loads handlers when started.  KM may be mapped to save
  65. ; low memory:
  66. ;
  67. ;    DEVDEF    <KM>,MAPH
  68. ;
  69. ; To build KM under RT-11 V5 (KRTSYS.COM):
  70. ; MAC/OBJ:KM KRTSJ.CND+KRTKM
  71. ; LINK/NOBIT/EXE:KM.SYS KM
  72. ; MAC/OBJ:KMX KRTXM.CND+KRTKM
  73. ; LINK/NOBIT/EXE:KMX.SYS KMX
  74. ; MAC/OBJ:KMTSX KRTTSX.CND+KRTKM
  75. ; LINK/NOBIT/EXE:KM.TSX KMTSX
  76. ;
  77. ; To build KM under RT-11 V4 (KRTSV4.COM):
  78. ; MAC/OBJ:KM KRTSJ.CND+KRTKM    ! KRT will only run under RT-11FB if V4
  79. ; LINK/EXE:KM.SYS KM
  80. ; MAC/OBJ:KMTSX KMTSX.CND+KRTKM
  81. ; LINK/EXE:KM.TSX KMTSX
  82. ;
  83. ; Comments must be stripped to run these command files under RT-11.
  84. ;
  85. ; WARNING:   Earlier versions of RT-11 may choke on the "dma=no" in
  86. ; the .drdef macro.  If it causes an error your system doesn't need
  87. ; it and it should be dumped to allow successful assembly.
  88. ;
  89. ; KM supports the following SET commands from the monitor (KMON):
  90. ;
  91. ;    SET KM CSR=oct_address        ! except on the PRO for
  92. ;    SET KM VECTOR=oct_address    ! which these are fixed
  93. ;
  94. ; Hardware flow control REQUIRES pins 4 and 5 be carried through in
  95. ; the modem cable, 4 to 4 (RTS) and 5 to 5 (CTS), DTE (the port) to
  96. ; DCE (the modem), in addition to those otherwise normally present.
  97. ;
  98. ; The port should be set up for 8 data bits and NO parity as Kermit
  99. ; does parity in software.
  100. ;
  101. ; WARNING:  If the interface provides selectable interrupt priority
  102. ; and your max speed will be greater than 4800 you will likely have
  103. ; to use BIRQ 5 to avoid dropping chars.
  104. ;
  105. ; NOTE:  This handler does NOT support VTCOM, nor is it intended to
  106. ; be used with anything other than KRT V03.62 or future releases.
  107. ;
  108. ; WARNING:  Because it's  impossible  to  bomb  an outstanding read
  109. ; completion routine once KM has been assigned the  link  the  only
  110. ; way to deassign KM is to exit Kermit.
  111.  
  112.  
  113.     .sbttl    Interface and operating system defaults
  114.  
  115.     .iif ndf km$dve    km$dve = 0    ; if <> DL(V)-11/E interface
  116.     .iif ndf km$pdt    km$pdt = 0    ; if <> display holds on PDT-11 LEDs
  117.     .iif ndf km$pro    km$pro = 0    ; if <> PRO-series modem interface
  118.     .iif ndf km$sbc    km$sbc = 0    ; if <> Falcon SBC-11 interface
  119.             rte$m =: 0    ; RTEM is not supported here
  120.     .iif ndf tsx$p  tsx$p  = 0    ; if <> support TSX-Plus
  121.     .iif ne  km$dve    km$dve = 1    ; ensure proper assembly
  122.     .iif ne  km$pdt    km$pdt = 1
  123.     .iif ne  km$pro    km$pro = 1
  124.     .iif ne  km$sbc    km$sbc = 1
  125.     .iif ne  tsx$p    mmg$t  = 1    ; the "Plus" is 22-bit addressing
  126.     .iif gt     <km$dve+km$pro+km$sbc-1> .error <; Too many interface types!>
  127.     .iif gt     <km$pdt+km$pro-1> .error <; PDT LEDs don't exist on the PRO!>
  128.  
  129.     .iif ndf km$csr km$csr = 176500    ; default CSR
  130.     .iif ndf km$vec km$vec = 300    ; and its interrupt vector
  131.     .iif ne  km$pro    km$csr = 173300    ; PRO modem port CSR
  132.     .iif ne  km$pro    km$vec = 210    ; and its vector
  133.     .iif ndf km$pri    km$pri = 4    ; default interrupt priority
  134.     .iif ne  km$sbc    km$pri = 5    ; Falcon must use priority 5
  135.     .iif ndf km$spd    km$spd = 9600.      ; default speed
  136.     .iif ndf km$bsz    km$bsz = 256.      ; default input buffer size in bytes
  137.     .iif ndf km$xof    km$xof = km$bsz/4 ; default low water mark, hold I/O
  138.     .iif ndf km$xon    km$xon = km$bsz/4 ; default hi water mark, resume I/O
  139.  
  140.  
  141.     .sbttl    Local macros
  142.  
  143. .macro    .assume    a1 ,cnd ,a2 ,msg
  144. .if cnd <a1>-<a2>
  145. .iff
  146. .error    <; 'a1 is not 'cnd 'a2  'msg>
  147. .endc
  148. .endm    .assume
  149.  
  150. .macro    .br to            ; /63/ added..
  151. .if df    to
  152. .if ne    to-.
  153. .error    <; not at location to;>
  154. .endc
  155. .endc
  156. .endm    .br
  157.  
  158. .macro    df.speed speedval    ; get code for default speed
  159. .if eq speedval-50.        ; not available on Falcon
  160.   .iif eq km$sbc b.code = 0    ; DL(V)-11/E or PRO-series
  161. .endc
  162. .if eq speedval-75.        ; not available on Falcon
  163.   .iif eq km$sbc b.code = 1    ; DL(V)-11/E or PRO-series
  164. .endc
  165. .if eq speedval-110.        ; not available on Falcon
  166.   .iif eq km$sbc b.code = 2    ; DL(V)-11/E or PRO-series
  167. .endc
  168. .if eq speedval-134.        ; not available on Falcon
  169.   .iif eq km$sbc b.code = 3    ; DL(V)-11/E or PRO-series
  170. .endc
  171. .if eq speedval-150.        ; not available on Falcon
  172.   .iif eq km$sbc b.code = 4    ; DL(V)-11/E or PRO-series
  173. .endc
  174. .if eq speedval-300.
  175.   .iif ne km$sbc b.code = 0    ; Falcon
  176.   .iif eq km$sbc b.code = 5    ; DL(V)-11/E or PRO-series
  177. .endc
  178. .if eq speedval-600.
  179.   .iif ne km$sbc b.code = 1    ; Falcon
  180.   .iif eq km$sbc b.code = 6    ; DL(V)-11/E or PRO-series
  181. .endc
  182. .if eq speedval-1200.
  183.   .iif ne km$sbc b.code = 2    ; Falcon
  184.   .iif eq km$sbc b.code = 7    ; DL(V)-11/E or PRO-series
  185. .endc
  186. .if eq speedval-1800.        ; not available on Falcon
  187.   .iif eq km$sbc b.code = 10    ; DL(V)-11/E or PRO-series
  188. .endc
  189. .if eq speedval-2000.        ; not available on Falcon
  190.   .iif eq km$sbc b.code = 11    ; DL(V)-11/E or PRO-series
  191. .endc
  192. .if eq speedval-2400.
  193.   .iif ne km$sbc b.code = 3    ; Falcon
  194.   .iif eq km$sbc b.code = 12    ; DL(V)-11/E or PRO-series
  195. .endc
  196. .if eq speedval-3600.        ; not available on Falcon
  197.   .iif eq km$sbc b.code = 13    ; DL(V)-11/E or PRO-series
  198. .endc
  199. .if eq speedval-4800.
  200.   .iif ne km$sbc b.code = 4    ; Falcon
  201.   .iif eq km$sbc b.code = 14    ; DL(V)-11/E or PRO-series
  202. .endc
  203. .if eq speedval-7200.        ; not available on Falcon
  204.   .iif eq km$sbc b.code = 15    ; DL(V)-11/E or PRO-series
  205. .endc
  206. .if eq speedval-9600.
  207.   .iif ne km$sbc b.code = 5    ; Falcon
  208.   .iif eq km$sbc b.code = 16    ; DL(V)-11/E or PRO-series
  209. .endc
  210. .if eq speedval-19200.
  211.   .iif ne km$sbc b.code = 6    ; Falcon
  212.   .iif eq km$sbc b.code = 17    ; DL(V)-11/E or PRO-series
  213. .endc
  214. .if eq speedval-38400.        ; not available on PRO-series or DL(V)-11/E
  215.   .iif ne km$sbc b.code = 7    ; Falcon
  216. .endc
  217. .if ge b.code            ; speed is ok, set it
  218.   .iif ne km$dve b.deflt = <b.code*10000>!dve.en ; DL(V)-11/E
  219.   .iif ne km$pro b.deflt = <b.code*20>+b.code     ; PRO-series
  220.   .iif ne km$sbc b.deflt = <b.code*10>!sbc.en     ; Falcon SBC-11
  221. .iff
  222. .error    <; default speed ('speedval) isn't supported on interface specified>
  223. .endc
  224. .endm    df.speed
  225.  
  226. .macro    picadr    src    ,dst=r0    ; position independent code addressing
  227.     mov    pc    ,dst    ; where we are now
  228.     add    src-.    ,dst    ; where we want to be
  229. .endm    picadr
  230.  
  231.  
  232.     .sbttl    Define the driver and its parameters
  233.  
  234.     .mcall    .drdef    ,.inten    ,.mtps
  235.  
  236.     .drdef    KM ,57 ,abtio$!hndlr$!spfun$ ,0 ,km$csr ,km$vec    ,dma=no
  237.     q.job    = 30        ; TSX+ queue element job (line) number offset
  238.     q$job    = q.job-4    ; and its offset from Q.BLKN
  239.  
  240.     psw    = 177776    ; processor status word address
  241.     sysptr    = 54        ; location of address of RMON base
  242.         qcomp    = 270    ;  offset to I/O exit routine address
  243.         confg2    = 370    ;  offset to second configuration word
  244.         pros$    = 20000    ;   if <> it's a PRO-series system
  245.  
  246.     b.code    = -1        ; init as speed not settable
  247.     b.deflt = 0        ; init as nothing to set for speed
  248.     sbc.en    = 2        ; Falcon SBC-11 speed enable
  249.     dve.en    = 4000        ; DL(V)-11/E speed enable
  250.  
  251.     ctrlq    = 21        ; ^Q (XON)  flow
  252.     ctrls    = 23        ; ^S (XOFF) control
  253.     lowater    = km$xof    ; hold when this # free bytes remain
  254.     hiwater    = km$bsz-km$xon    ; resume when this # bytes become free
  255.  
  256.                 ; SPFUNs
  257.     clrdrv    = 201        ; flow control reset
  258.     brkdrv    = 202        ; send a break
  259.     srddrv    = 203        ; read at least 1 byte
  260.     stsdrv    = 204        ; short and fast style driver status
  261.         rt.hold    = 2    ; /63/ received flow control hold from remote
  262.         rt.dcd    = 10    ; /63/ dcd
  263.     offdrv    = 205        ; disable interrupts
  264.     dtrdrv    = 206        ; set or clear DTR and RTS
  265.     clset    = 250        ; /63/ set some TSX options
  266.     clrset    = 251        ; /63/ reset some TSX options
  267.     clstat    = 255        ; TSX style modem status
  268.         cl.dcd    = 2    ; /63/ dcd
  269.         cl.dtr    = 4    ; /63/ dtr
  270.         cl.rts    = 10    ; /63/ rts
  271.         cl.cts    = 20    ; /63/ cts
  272.         cl.flow    = 40    ; /63/ <> for rts/cts flow control
  273.     clspeed    = 256        ; get or set speed
  274.     clclr    = 257        ; abort pending I/O
  275.     clipnd    = 261        ; /63/ get number of input chars pending
  276.     clwbyt    = 263        ; /63/ write with byte count
  277.     clchar    = 266        ; /63/ get CL characteristics
  278.         t.form    = 1    ; /63/ transmit form feed
  279.         t.tab    = 2    ; /63/ transmit horizontal tab
  280.         t.lc    = 4    ; /63/ transmit lower case
  281.         lfout    = 10    ; /63/ transmit line feed
  282.         lfin    = 20    ; /63/ receive line feed
  283.         binout    = 100    ; /63/ transmit binary output
  284.         binin    = 200    ; /63/ receive binary input
  285.         t.cr    = 400    ; /63/ transmit carriage return
  286.         t.ctrl    = 1000    ; /63/ transmit control chars
  287.         eightbit= 4000    ; /63/ receive and transmit 8-bit chars
  288.     kmflow    = 277        ; select XOFF/XON or RTS/CTS flow control
  289.  
  290.                 ; DL style serial interface
  291.     in$csr    = 176        ; installation CSR stored here
  292.     rx.dtr    = 2        ; data terminal ready
  293.     rx.rts    = 4        ; request to send
  294.     rx.ie    = 100        ; interrupt enable
  295.     rx.dcd    = 10000        ; data carrier detect
  296.     rx.cts    = 20000        ; clear to send
  297.     tx.br    = 1        ; break
  298.     tx.ie    = 100        ; interrupt enable
  299.  
  300.                 ; PRO serial interface
  301.     ic$buf    = 173200    ; interrupt controller base
  302.     ic$csr    = ic$buf+2    ; and its CSR
  303.         com.ie    = 33    ;   enable comm port interrupts
  304.     km$buf    = km$csr    ; rx/tx data register
  305.     km$csa    = km$csr+2    ; CSR A
  306.         sel.r0    = 0    ;  goto reg 0
  307.         cmd.cr    = 30    ;   reset channel
  308.         cmd.rt    = 50    ;   reset xmit interrupt pending
  309.         cmd.er    = 60    ;   reset error latches
  310.         cmd.ei    = 70    ;   end of interrupt
  311.         cmd.tr    = 300    ;   reset xmit underrun/end of message latch
  312.         sel.r1    = 1    ;  goto reg 1
  313.         w1.tie    = 2    ;   xmit interrupt enable
  314.         w1.rie    = 30    ;   receive interrupt enable
  315.         sel.r2    = 2    ;  goto reg 2
  316.         req.a2    = 0    ;   _required_
  317.         sel.r3    = 3    ;  goto reg 3
  318.         w3.rxe    = 1    ;   receive enable
  319.         rcl.8    = 300    ;   8-bit receive char length
  320.         sel.r4    = 4    ;  goto reg 4
  321.         stp.1    = 4    ;   1 stop bit
  322.         clk.16    = 100    ;   16x rate multiplier
  323.         sel.r5    = 5    ;  goto reg 5
  324.         w5.txe    = 10    ;   transmit enable
  325.         w5.brk    = 20    ;   send a break
  326.         tcl.8    = 140    ;   8-bit xmit char length
  327.     km$csb    = km$csr+6    ; CSR B
  328.         sel.r1    = 1    ;  goto reg 1
  329.         req.b1    = 4    ;   _required_
  330.         sel.r2    = 2    ;  goto reg 2
  331.         req.b2    = 0    ;   _required_
  332.         cmd.re    = 20    ;   reset ext/status interrupts
  333.         r2.imk    = 34    ;   interrupt vector mask
  334.     km$mc0    = km$csr+10    ; modem control 0
  335.         clk.bg    = 0    ;  modem baud rate generator
  336.         m0.rts    = 10    ;  request to send
  337.         m0.dtr    = 20    ;  data terminal ready
  338.     km$mc1    = km$csr+12    ; modem control 1
  339.         m1.dcd    = 20    ;  data carrier detect
  340.         m1.cts    = 40    ;  clear to send
  341.     km$bdr    = km$csr+14    ; speed control
  342.  
  343.     ledcsr    = 177420    ; PDT LEDs display CSR
  344.         led.tx    = 100    ; send hold (LED #1)
  345.         led.rx    = 200    ; received hold (LED #2)
  346.         led.en    = 40000    ; update enable
  347.  
  348.  
  349.     .sbttl    Installation code
  350.  
  351.     .if ne km$pro!km$dve!km$sbc
  352.     df.speed km$spd            ; calculate desired default speed
  353.     .endc
  354.  
  355.     .ASECT
  356. . = 200
  357.     nop                ; boot ept, unused here..
  358.     mov    @#sysptr,r0        ; get RMON base
  359.     bit    #pros$    ,confg2(r0)    ; is this a PRO-series system?
  360.     .if eq km$pro
  361.     bne    o.bad            ; a PRO, but handler not built for it
  362.     .iff
  363.     beq    o.bad            ; built for PRO but not running on one
  364.     .ift
  365.       .if ne km$dve!km$sbc
  366.     mov    in$csr    ,r0        ; recover base (rx$csr) address
  367.     mov    #b.deflt,4(r0)        ; set default speed in tx$csr
  368.       .endc
  369.     .iff
  370.     movb    #b.deflt     ,@#km$bdr    ; set PRO default speed
  371.     mov    #km$csa         ,r0    ; CSR A (reg 0)
  372.     movb    #cmd.cr         ,@r0    ;  reset chan A
  373.     movb    #cmd.tr         ,@r0    ;  reset xmit underrun latch
  374.     movb    #sel.r4         ,@r0    ; goto reg 4
  375.     movb    #clk.16!stp.1,@r0    ;  clock rate 16x, 1 stop bit
  376.     movb    #sel.r3         ,@r0    ; goto reg 3
  377.     movb    #w3.rxe!rcl.8,@r0    ;  receive enable, 8-bit chars
  378.     movb    #sel.r5         ,@r0    ; goto reg 5
  379.     movb    #w5.txe!tcl.8,@r0    ;  xmit enable, 8-bit chars
  380.     movb    #sel.r2         ,@r0    ; goto reg 2
  381.     movb    #req.a2         ,@r0    ;  _required_
  382.     movb    #cmd.re         ,@r0    ;  reset external/status interrupts
  383.     mov    #km$csb         ,r0    ; CSR B (reg 0)
  384.     movb    #cmd.cr         ,@r0    ;  reset chan B
  385.     movb    #sel.r2         ,@r0    ; goto reg 2
  386.     movb    #req.b2         ,@r0    ;  _required_
  387.     movb    #sel.r1         ,@r0    ; goto reg 1
  388.     movb    #req.b1         ,@r0    ;  _required_
  389.     movb    #com.ie         ,@#ic$csr    ; enable comm port interrupts
  390.     movb    #clk.bg         ,@#km$mc0    ; set PRO modem baud rate generator
  391.     .endc    ; eq km$pro
  392.     tst    (pc)+            ; installed OK, clear carry
  393. o.bad:    sec                ; something failed, set carry
  394.     rts    pc
  395.  
  396.     .assume    . le 400 msg=<;*** INSTALL CODE IS TOO LARGE ***>
  397.  
  398.  
  399.     .if eq km$pro            ; these are not settable on PRO-series
  400.     .sbttl    SET CSR and VECTOR    ; Kermit SETs everything else..
  401.  
  402.     .drset    CSR    ,160000    ,o.csr    ,oct    ; SET KM CSR=oct_address
  403.     .drset    VECTOR    ,474    ,o.vec    ,oct    ; SET KM VECTOR=oct_address
  404.  
  405. o.csr:    cmp    r0    ,r3        ; is address ok?
  406.     bcs    o.bad            ; no, out of range..
  407.     bit    #7    ,r0        ; must also be multiple of 10 (octal)
  408.     bne    o.bad            ; it wasn't..
  409.     mov    r0    ,in$csr        ; copy for installation code
  410.     mov    r0    ,rx$csr        ; receive (from modem) CSR address
  411.     add    #2    ,r0
  412.     mov    r0    ,rx$buf        ; receive buffer address
  413.     add    #2    ,r0
  414.     mov    r0    ,tx$csr        ; xmit (to modem) CSR address
  415.     add    #2    ,r0        ; this also clears the carry bit
  416.     mov    r0    ,tx$buf        ; xmit buffer address
  417.     rts    pc
  418.  
  419. o.vec:    bit    #3    ,r0        ; multiple of 4?
  420.     bne    o.bad            ; no, it's no good
  421.     cmp    r3    ,r0        ; ya, but is it within range?
  422.     bcs    o.bad            ; nope..
  423.     mov    r0    ,km$vtb        ; input interrupt vector
  424.     add    #4    ,r0        ; this also clears carry
  425.     mov    r0    ,km$vtb+6    ; output interrupt vector
  426.     rts    pc
  427.     .endc    ; eq km$pro
  428.  
  429.     .assume    . le 1000 msg=<;*** SET CODE IS TOO LARGE ***>
  430.  
  431.  
  432.     .sbttl    Driver entry
  433.  
  434.     .drbeg    KM
  435.     mov    kmcqe    ,r4        ; mon/handler current queue element
  436.     tst    q$blkn(r4)        ; doing I/O to block 0?
  437.     bne    10$            ; no
  438.     clr    kicqe            ; ya, reset the input queue
  439.     clr    kocqe            ; and the output queue
  440. 10$:    .if eq km$pro
  441.     bis    #rx.ie    ,@rx$csr    ; enable receive interrupts
  442.     .iftf
  443.     asr    (pc)+            ; are tx interrupts already enabled?
  444. stsflg: .word    1
  445.     bcc    20$            ; hopefully..
  446.     .ift
  447.     bis    #tx.ie    ,@tx$csr    ; no, turn them on
  448.       .if ne km$pdt
  449.       jsr    pc    ,setled        ; update the PDT-11 lights
  450.       .endc
  451.     .iff
  452.     bis    #w1.rie!w1.tie,sts$r1    ; set tx and rx interrupts enable bits
  453.     mov    #sel.r1          ,@#km$csa    ; goto CSR A reg 1
  454.     mov    sts$r1          ,@#km$csa    ; turn them on
  455.     .iftf                ; /63/
  456. 20$:    movb    q$func(r4),r5        ; check for a SPFUN
  457.     bne    spfun            ; found one..
  458.     asl    q$wcnt(r4)        ; words -> bytes, check & dump hi bit
  459.     .ift                ; /63/ if not PRO branch is in range
  460.     bcc    km$err            ; reads must be via SPFUN 203 only
  461.     .iff                ; /63/ old PRO code + new SPFUN code
  462.     bcs    bwrite            ; /63/ = too far to branch..
  463.     jmp    km$err            ; /63/ reads via SPFUN 203 only
  464.     .iftf                ; /63/
  465. bwrite:    inc    qchflg            ; flag queue is about to be changed
  466.     jsr    r5    ,enqueue    ; place write on internal queue
  467. kocqe:    .word    0            ;  output current queue element
  468. kolqe:    .word    0            ;  output last queue element
  469.     clr    qchflg            ; queue is no longer changing
  470.     .ift                ; /63/
  471.     bis    #tx.ie    ,@tx$csr    ; enable interrupts
  472.     .iff
  473.     jsr    pc    ,txproc        ; try to get a char
  474.     beq    30$            ; nothing there
  475.     movb    r5    ,@#km$buf    ; got one, send it
  476.     .endc    ; eq km$pro
  477. 30$:    rts    pc
  478.  
  479.  
  480.     .sbttl    Registers and vector tables
  481.  
  482.     .if eq km$pro
  483. rx$csr:    .word    km$csr            ; input (rx from modem) status
  484. rx$buf:    .word    km$csr+2        ; input (rx) buffer
  485. tx$csr:    .word    km$csr+4        ; output (tx to modem) status
  486. tx$buf:    .word    km$csr+6        ; output (tx) buffer
  487.     .drvtb    KM,km$vec,kiint        ; input interrupts
  488.     .drvtb    ,km$vec+4,kmint        ; output interrupts
  489.  
  490.     .iff                ; PRO CSR and vector are not settable
  491. sts$r1:    .word    0            ; status reg 1
  492. sts$r5:    .word    w5.txe!tcl.8        ; status reg 5  tx enable, 8-bit chars
  493.     .drvtb    KM,km$vec,kmint        ; for PRO-series kmint
  494.     .drvtb    ,km$vec+4,kmint        ; dispatches everything..
  495.     .endc    ; eq km$pro
  496.  
  497.     .assume    . le kmstrt+1000 msg=<;*** BLOCK 1 CODE IS TOO LARGE ***>
  498.  
  499.  
  500.     .sbttl    Break request        ; here so everything else can branch..
  501.  
  502. s.brk:    tst    q$wcnt(r4)        ; start break or stop break?
  503.     beq    10$            ; stop it
  504.     inc    brkflg            ; start it, flag it's being done
  505.     .if eq km$pro
  506.     bis    #tx.br    ,@tx$csr    ; begin the break
  507.     .iff
  508.     bis    #w5.brk    ,sts$r5        ; set the break enable bit
  509.     mov    #sel.r5    ,@#km$csa    ; goto CSR A reg 5
  510.     mov    sts$r5    ,@#km$csa    ; begin the break
  511.     .iftf
  512.     br    km$fin            ; done
  513. 10$:    .ift
  514.     bic    #tx.br    ,@tx$csr    ; stop the break
  515.     .iff
  516.     bic    #w5.brk    ,sts$r5        ; reset the break enable bit
  517.     mov    #sel.r5    ,@#km$csa    ; goto CSR A reg 5
  518.     mov    sts$r5    ,@#km$csa    ; stop the break
  519.     .iftf
  520.     clr    brkflg            ; no longer doing a break
  521.     .ift
  522.     bis    #tx.ie    ,@tx$csr    ; re-enable output interrupts
  523.     .endc    ; eq km$pro
  524.     br    km$fin            ; done
  525.  
  526.  
  527.     .sbttl    Set CL options        ; /63/ added to support xmodem..
  528.  
  529. ; NOTE:    If you add an option flagged in the hi byte uncomment the appropriate
  530. ;    two lines here and in cl.clr (below).  Doing this will require making
  531. ;    the bcs bwrite/jmp km$err code in the driver entry code unconditional
  532. ;    as km$err will then be too far to branch.  Currently this driver only
  533. ;    checks and uses the binin <000200> and binout <000100> option bits.
  534.  
  535. cl.set:    .if eq mmg$t
  536.     bis    @q$buff(r4),clopts    ; set the desired options
  537.     .iff
  538.     jsr    pc    ,@$gtbyt    ; recover low byte of options word
  539.     bisb    (sp)+    ,clopts        ; set it
  540. ;    jsr    pc    ,@$gtbyt    ; recover hi byte of options word
  541. ;    bisb    (sp)+    ,clopts+1    ; set it
  542.     .endc
  543.     br    km$fin            ; done
  544.  
  545.  
  546.     .sbttl    Clear CL options    ; /63/ added to support xmodem..
  547.  
  548. cl.clr:.if eq mmg$t
  549.     bic    @q$buff(r4),clopts    ; reset the desired options
  550.     .iff
  551.     jsr    pc    ,@$gtbyt    ; recover low byte of options word
  552.     bicb    (sp)+    ,clopts        ; reset it
  553. ;    jsr    pc    ,@$gtbyt    ; recover hi byte of options word
  554. ;    bicb    (sp)+    ,clopts+1    ; reset it
  555.     .endc
  556.     br    km$fin            ; done
  557.  
  558.  
  559.     .sbttl    Get CL options        ; /63/ added to support xmodem..
  560.  
  561. ; NOTE:    Functions which this driver provides by design are returned
  562. ;    as enabled by setting same in the clopts configuration word.
  563. ;    While it's possible to set or clear anything, and then view
  564. ;    the results with this routine, currently only the the binin
  565. ;    and binout bits actually do anything here..
  566.  
  567. clopts:    .word    t.form!t.tab!t.lc!lfout!lfin!t.cr!t.ctrl!eightbit ; "defaults"
  568.  
  569. cl.char:.if eq    mmg$t
  570.     mov    q$buff(r4),r5        ; buffer address
  571.     clr    (r5)+            ; handler status word unsupported here
  572.     mov    clopts    ,(r5)        ; options_status_word_offset = 2
  573.     .iff
  574.     clr    -(sp)            ; handler status word unsupported here
  575.     jsr    pc    ,@$ptwrd    ; first word of data buffer
  576.     mov    clopts    ,-(sp)        ; put the options status word
  577.     jsr    pc    ,@$ptwrd    ; in second word of buffer
  578.     .endc
  579.     br    km$fin            ; only options word is needed here..
  580.  
  581.  
  582.     .sbttl    SPFUN dispatching
  583.     .enabl    lsb
  584.  
  585. spfun:    cmpb    r5    ,#srddrv    ; read at least 1 byte?
  586.     bne    10$            ; no
  587.     jsr    r5    ,enqueue    ; ya, place on the internal queue..
  588. kicqe:    .word    0            ;  input current queue element
  589. kilqe:    .word    0            ;  input last queue element
  590.     jmp    rxproc            ; ..then get whatever is ready now
  591. 10$:    cmpb    r5    ,#clipnd    ; /63/ number of input chars pending?
  592.     bne    20$            ; /63/ no
  593.     mov    #km$bsz    ,r5        ; /63/ size of the input ring buffer
  594.     sub    rxfree    ,r5        ; /63/ - bytes free = chars waiting
  595.     br    s.out            ; return number of chars pending
  596. 20$:    cmpb    r5    ,#stsdrv    ; /63/ moved this forward for speed
  597.     beq    s.stat            ; driver status
  598.     cmpb    r5    ,#clwbyt    ; /63/ write with byte count?
  599.     beq    bwrite            ; /63/ ya..
  600.     cmpb    r5    ,#clrdrv    ; /63/ moved forward
  601.     beq    s.clr            ; flow control reset
  602.     cmpb    r5    ,#clclr        ; emulate TSX+ abort pending I/O?
  603.     bne    30$            ; no
  604.     inc    stsflg            ; ya, force reinit of interrupts
  605.     jmp    abort            ; and go hose the queue
  606. 30$:    cmpb    r5    ,#brkdrv
  607.     beq    s.brk            ; break
  608.     cmpb    r5    ,#dtrdrv
  609.     beq    s.dtr            ; set or clear DTR and RTS
  610.     cmpb    r5    ,#clstat
  611.     beq    cl.stat            ; TSX+ style get modem status
  612.     cmpb    r5    ,#clset
  613.     beq    cl.set            ; /63/ set some TSX+ options
  614.     cmpb    r5    ,#clrset
  615.     beq    cl.clr            ; /63/ reset some TSX+ options
  616.     .if ne km$pro!km$dve!km$sbc
  617.     cmpb    r5    ,#clspeed
  618.     beq    s.speed            ; TSX+ style get/set line speed
  619.     .endc
  620.     cmpb    r5    ,#kmflow    ; selecting flow control type?
  621.     beq    s.flow            ; ya
  622.     cmpb    r5    ,#offdrv    ; disable interrupts?
  623.     bne    km$err            ; /63/ no
  624.     inc    stsflg            ; ya, revert to uninitialized state
  625.     br    km$fin            ; done
  626. km$err:    bis    #hderr$    ,@-(r4)        ; set error bit if none of above cause
  627. km$fin:    .drfin    KM            ; knowing's more important than noping
  628.  
  629.     .dsabl    lsb
  630.  
  631.  
  632.     .sbttl    Set and/or clear flow control
  633.  
  634. s.flow:    mov    q$wcnt(r4),ctsflg    ; set it (0=XOFF,<>=CTS) then clear it
  635. s.clr:    clr    rxhold            ; hose possible received hold
  636.     .if eq km$pro
  637.     bis    #tx.ie    ,@tx$csr    ; ensure output interrupts are on
  638.     .iftf
  639.     tst    ctsflg            ; doing hardware flow control?
  640.     bne    x.dtr            ; ya, go turn it on
  641.     .ift
  642.     mov    #-2    ,txhold        ; set flag to send an XON
  643.       .if ne km$pdt
  644.       jsr    pc    ,setled        ; update the PDT lights
  645.       .endc
  646.     .iff
  647.     clr    txhold            ; xmit XOFF is no longer pending
  648.     movb    #ctrlq    ,@#km$buf    ; send an XON
  649.     .endc    ; eq km$pro
  650.     br    km$fin            ; done
  651.  
  652.     .sbttl    Set or clear DTR and RTS
  653.     .enabl    lsb
  654.  
  655. s.dtr:    tst    q$wcnt(r4)        ; set or clear?
  656.     bne    x.dtr            ; set..
  657.     .if eq km$pro
  658.     bic    #rx.dtr!rx.rts,@rx$csr    ; clear
  659.     .iff
  660.     bicb    #m0.dtr!m0.rts,@#km$mc0    ; clear
  661.     .iftf
  662.     tst    ctsflg            ; doing hardware flow control?
  663.     beq    20$            ; no
  664.     mov    #1    ,txhold        ; flag RTS has been dropped
  665.     br    10$
  666. x.dtr:    .ift
  667.     bis    #rx.dtr!rx.rts,@rx$csr    ; turn them on
  668.     .iff
  669.     bisb    #m0.dtr!m0.rts,@#km$mc0    ; PRO turns them on this way
  670.     .iftf
  671.     tst    ctsflg            ; doing hardware flow control?
  672.     beq    20$            ; no
  673.     clr    txhold            ; ya, xmit hold is no longer pending
  674. 10$:    .ift
  675.       .if ne km$pdt
  676.       jsr    pc    ,setled        ; update the PDT lights
  677.       .endc
  678.     .endc    ; eq km$pro
  679. 20$:    br    km$fin            ; done
  680.  
  681.     .dsabl    lsb
  682.  
  683.  
  684.     .sbttl    RT-11 style status
  685.  
  686. ; NOTE:    This is called by Kermit once every 0.5 second.
  687. ;    Any added extra function(s) should go anywhere but here.
  688.  
  689. s.stat:    clr    r5            ; init
  690.     tst    rxhold            ; has remote asserted flow control?
  691.     beq    10$            ; no
  692.     bis    #rt.hold,r5        ; /63/ ya, set bit 1
  693. 10$:    .if eq km$pro
  694.     bit    #rx.dcd    ,@rx$csr    ; DCD asserted?
  695.     .iff
  696.     bit    #m1.dcd    ,@#km$mc1    ; DCD asserted?
  697.     .endc
  698.     beq    s.out            ; no
  699.     bis    #rt.dcd    ,r5        ; /63/ ya, set bit 3
  700. s.out:    .if eq    mmg$t
  701.     mov    r5    ,@q$buff(r4)    ; return the status word
  702.     .iff
  703.     mov    r5    ,-(sp)        ; pass the status word to
  704.     jsr    pc    ,@$ptwrd    ; the $_put_word subroutine
  705.     .endc
  706.     br    km$fin            ; done
  707.  
  708.  
  709.     .sbttl    TSX style status
  710.  
  711. cl.stat:clr    r5            ; init
  712.     .if eq km$pro
  713.     bit    #rx.dcd    ,@rx$csr    ; DCD asserted?
  714.     .iff
  715.     bit    #m1.dcd    ,@#km$mc1    ; DCD asserted?
  716.     .iftf
  717.     beq    10$            ; no
  718.     bis    #cl.dcd    ,r5        ; /63/ ya, flag it
  719. 10$:    .ift
  720.     bit    #rx.dtr    ,@rx$csr    ; DTR asserted?
  721.     .iff
  722.     bit    #m0.dtr    ,@#km$mc1    ; DTR asserted?
  723.     .iftf
  724.     beq    20$            ; no
  725.     bis    #cl.dtr    ,r5        ; /63/ ya, flag it
  726. 20$:    .ift
  727.     bit    #rx.rts    ,@rx$csr    ; RTS asserted?
  728.     .iff
  729.     bit    #m0.rts    ,@#km$mc0    ; RTS asserted?
  730.     .iftf
  731.     beq    30$            ; no
  732.     bis    #cl.rts    ,r5        ; /63/ ya, flag it
  733. 30$:    .ift
  734.     bit    #rx.cts    ,@rx$csr    ; CTS asserted?
  735.     .iff
  736.     bit    #m1.cts    ,@#km$mc1    ; CTS asserted?
  737.     .endc    ; eq km$pro
  738.     beq    40$            ; no
  739.     bis    #cl.cts    ,r5        ; /63/ ya, flag it
  740. 40$:    tst    ctsflg            ; RTS/CTS flow control?
  741.     beq    s.out            ; no
  742.     bis    #cl.flow,r5        ; /63/ ya, flag it
  743.     br    s.out            ; common code..
  744.  
  745.  
  746.     .if ne km$pro!km$dve!km$sbc
  747.     .sbttl    Set or get speed
  748.  
  749. s.speed:tst    q$wcnt(r4)        ; set it or get it?
  750.     bmi    10$            ; hi bit set flags get speed
  751.       .if eq mmg$t
  752.     mov    @q$buff(r4),r1        ; recover desired set speed value
  753.       .iff
  754.     jsr    pc    ,@$gtbyt    ; recover desired set speed value
  755.     mov    (sp)+    ,r1        ; hi byte here is "undefined"..
  756.       .endc
  757.     bic    #^c<37>    ,r1        ; hose any possible garbage in hi bits
  758.       .if eq km$sbc
  759.     cmp    r1    ,#16.        ; if not a Falcon,
  760.     beq    km$err            ; 38.4k is unavailable
  761.       .endc
  762.     mov    r1    ,curspd        ; save to return speed when asked..
  763.       .if ne km$pro            ; speed = <b.code*20>+b.code
  764.     mov    r1    ,-(sp)        ; save copy of speed code for receive
  765.     asl    r1            ; then shift it into xmit speed bits
  766.     asl    r1
  767.     asl    r1
  768.     asl    r1
  769.     bis    (sp)+    ,r1        ; restore the receive speed bits
  770.     movb    r1    ,@#km$bdr    ; set both tx and rx speeds
  771.       .iff
  772.         .if ne km$dve
  773.     swab    r1            ; speed = <b.code*10000>!dve.en
  774.     asl    r1
  775.     asl    r1
  776.     asl    r1
  777.     asl    r1
  778.     bis    #dve.en    ,r1        ; now set the speed enable bit
  779.         .endc
  780.         .if ne km$sbc        ; speed = <b.code*10>!sbc.en
  781.     picadr    #sbcspd            ; get conversion table pointer
  782.     add    r1    ,r0        ; add speed offset
  783.     movb    (r0)    ,r1        ; copy real speed code from table
  784.     bmi    km$err            ; not a valid SBC-11 speed
  785.         .endc
  786.     mov    r1    ,@tx$csr    ; set the new speed
  787.       .endc    ; ne km$pro
  788.     br    km$fin            ; done
  789.  
  790. 10$:      .if eq mmg$t
  791.     mov    curspd    ,@q$buff(r4)    ; put current speed into user's buffer
  792.       .iff
  793.     mov    curspd    ,-(sp)        ; pass speed value to $_put_word
  794.     jsr    pc    ,@$ptwrd    ; which places it into user's buffer
  795.       .endc
  796.     br    km$fin            ; done
  797.  
  798. curspd:    .word    b.code            ; the current speed, -1 if unsettable
  799.       .if ne  km$sbc        ; Falcon speed translation table
  800. sbcspd:    .byte    -1    ,-1    ,-1    ,-1    ,-1    ,02
  801.     .byte    12    ,22    ,-1    ,-1    ,32    ,-1
  802.     .byte    42    ,-1    ,52    ,62    ,72
  803.     .even
  804.       .endc
  805.     .endc    ; ne km$pro!km$dve!km$sbc
  806.  
  807.  
  808.     .if ne km$pdt
  809.     .sbttl    Display flow control status on PDT-11 lamps
  810.  
  811. setled:    mov    #led.en    ,r5        ; enable with both LEDs preset off
  812.     tst    txhold            ; is a sent XOFF or RTS hold pending?
  813.     ble    10$            ; no
  814.     bis    #led.tx    ,r5        ; ya, illuminate LED #1
  815. 10$:    tst    rxhold            ; received XOFF or CTS hold pending?
  816.     beq    20$            ; no
  817.     bis    #led.rx    ,r5        ; ya, illuminate LED #2
  818. 20$:    mov    r5    ,@#ledcsr    ; send the results to the hardware
  819.     rts    pc
  820.     .endc
  821.  
  822.  
  823.     .sbttl    Driver reset
  824.  
  825. abort:    mov    r0    ,-(sp)
  826.     .if eq km$pro
  827.     bic    #rx.ie    ,@rx$csr    ; disable input interrupts
  828.     .iff
  829.     bic    #w1.rie    ,sts$r1        ; set to disable input interrupts
  830.     mov    #sel.r1    ,@#km$csa    ; goto CSR A reg 1
  831.     mov    sts$r1    ,@#km$csa    ; do it
  832.     .iftf
  833.     jsr    r4    ,delink        ; dump entries
  834.     .word    kicqe-q$link-del.pc    ; from the input queue
  835.     tst    stsflg            ; re-enable interrupts?
  836.     bne    10$            ; no
  837.     .ift
  838.     bis    #rx.ie    ,@rx$csr    ; ya, turn them on
  839.     .iff
  840.     bis    #w1.rie    ,sts$r1        ; set to enable receive interrupts
  841.     mov    #sel.r1    ,@#km$csa    ; goto CSR A reg 1
  842.     mov    sts$r1    ,@#km$csa    ; do it
  843.     .iftf
  844. 10$:    inc    qchflg            ; flag queue is about to be changed
  845.     jsr    r4    ,delink        ; dump entries
  846.     .word    kocqe-q$link-del.pc    ; from the output queue
  847.     clr    qchflg            ; queue is no longer changing
  848.     tst    stsflg            ; re-enable interrupts?
  849.     bne    30$            ; no
  850.     .ift
  851.     bis    #tx.ie    ,@tx$csr    ; ya, turn them on
  852.     .iff
  853.     mov    r5    ,-(sp)
  854.     jsr    pc    ,txproc        ; try to get an ouput char
  855.     beq    20$            ; nothing there
  856.     movb    r5    ,@#km$buf    ; send it
  857. 20$:    mov    (sp)+    ,r5
  858.     .endc    ; eq km$pro
  859. 30$:    mov    (sp)+    ,r0
  860.     tst    kmcqe            ; any data in current queue element?
  861.     bne    40$            ; ya, go unload it
  862.     rts    pc            ; no, done
  863. 40$:    jmp    km$fin
  864.  
  865.  
  866.     .if ne km$pro
  867.     .sbttl    PRO interrupt service dispatcher
  868.  
  869.         br      abort            ; abort entry point
  870. kmint:    jsr    r5    ,@$inptr    ; drop back to the
  871.         .word   ^c<km$pri*40>&340    ; device priority
  872.     mov    #sel.r2    ,@#km$csb    ; goto CSR B reg 2
  873.     mov    @#km$csb,-(sp)        ; recover the interrupt
  874.     bic    #^c<r2.imk>,@sp        ; mask non-relevant data
  875.     asr    @sp            ; word indexing
  876.     add    pc    ,@sp        ; calculate and add the
  877.     add    #inttab-.,@sp        ; top of the table address
  878.     mov    @(sp)+    ,-(sp)        ; entry for this type interrupt
  879.     add    pc    ,@sp        ; calculate its address
  880. intdsp:    jmp    @(sp)+            ; service the interrupt
  881.  
  882. esint:    mov    #cmd.re    ,@#km$csa    ; reset external/status interrupts
  883. xxint:    mov    #cmd.ei    ,@#km$csa    ; end of interrupt
  884.     rts    pc
  885.  
  886. srint:    mov    #cmd.er    ,@#km$csa    ; reset error latches and
  887.     jmp    kiint            ; treat as a rec'd char
  888.  
  889. inttab:    .word    xxint-intdsp        ; unknown interrupts
  890.     .word    xxint-intdsp
  891.     .word    xxint-intdsp
  892.     .word    xxint-intdsp
  893.     .word    koint-intdsp        ; xmit buffer empty
  894.     .word    esint-intdsp        ; external/status interrupts
  895.     .word    kiint-intdsp        ; rec'd char ready
  896.     .word    srint-intdsp        ; special receive interrupt
  897.     .endc    ; ne km$pro
  898.  
  899.  
  900.     .sbttl    Output (to modem) interrupt service
  901.     .enabl    lsb
  902.  
  903.     .if eq km$pro
  904.     br    abort            ; abort entry point
  905.     .iff
  906. koint:    .ift
  907. kmint:    jsr    r5    ,@$inptr    ; drop back to the
  908.     .word    ^c<km$pri*40>&340    ; device priority
  909.     .iftf
  910.     tst    (pc)+            ; if sending a break..
  911. brkflg:    .word    0            ;  <> if break is asserted
  912.     bne    40$            ; ..then output can't be done
  913.     tst    (pc)+            ; flow control status  -2=doRESUME
  914. txhold:    .word    0            ;  -1=doHOLD, 0=RESUMEed, 1=onHOLD
  915.     bpl    20$            ; nothing to do
  916.     tst    (pc)+            ; check flow control type
  917. ctsflg:    .word    0            ; if <> do RTS/CTS flow control
  918.     bne    10$            ; go get CTS status into rxhold
  919. ; /63/ use hardware flow control with binout or uncomment the next 2 lines
  920. ;    bit    #binout    ,clopts        ; /63/ if doing binary output
  921. ;    bne    10$            ; /63/ don't send XOFF or XON chars
  922.     movb    #ctrlq    ,r5        ; preset an XON
  923.     add    #2    ,txhold        ; really need one?
  924.     beq    30$            ; ya
  925.     movb    #ctrls    ,r5        ; no, thus it's an XOFF that's needed
  926.     br    30$
  927. 10$:    clr    rxhold            ; preset to no hold
  928.     .ift
  929.     bit    #rx.cts    ,@rx$csr    ; CTS asserted?
  930.     .iff
  931.     bit    #m1.cts    ,@#km$mc1    ; CTS asserted?
  932.     .iftf
  933.     bne    20$            ; ya
  934.     mov    #1    ,rxhold        ; no, set the hold flag
  935. 20$:    tst    (pc)+            ; is other end ready for more data..?
  936. rxhold:    .word    0            ;  <> if it sent an XOFF or CTS is low
  937.     bne    40$            ; ..not yet
  938.     tst    (pc)+            ; is the queue being changed?
  939. qchflg:    .word    0            ;  <> if queue is being updated
  940.     bne    40$            ; ya, output must wait..
  941.     jsr    pc    ,txproc        ; no, try to get something to output
  942.     beq    40$            ; nothing was there..
  943. 30$:    .ift
  944.     movb    r5    ,@tx$buf    ; something was there, send it
  945.       .if ne km$pdt
  946.       jmp    setled            ; update the PDT lights
  947.       .endc
  948.     rts    pc            ; if not a PRO, done..
  949.     .iff
  950.     movb    r5    ,@#km$buf    ; something was there, send it
  951.     .iftf
  952. 40$:    .ift
  953.     bic    #tx.ie    ,@tx$csr    ; disable xmit interrupts
  954.     .iff
  955.     mov    #cmd.rt    ,@#km$csa    ; reset xmit interrupt pending
  956.     mov    #cmd.ei    ,@#km$csa    ; end of interrupt
  957.     .endc    ; eq km$pro
  958.     rts    pc
  959.  
  960.     .dsabl    lsb
  961.  
  962.  
  963.     .sbttl    Get next output (to modem) character
  964.  
  965. txproc:    mov    kocqe    ,r4        ; pointer to current queue element
  966.     beq    10$            ; nothing is ready
  967.     .if eq mmg$t
  968.     add    #q$wcnt    ,r4        ; where word count lives
  969.     tst    @r4            ; anything left?
  970.     beq    20$            ; no, done
  971.     inc    @r4            ; ya, decrement count
  972.     movb    @-(r4)    ,r5        ; get the char
  973.     inc    @r4            ; point to possible next char
  974.     .iff
  975.     tst    q$wcnt(r4)        ; anything left?
  976.     beq    20$            ; no, done
  977.     inc    q$wcnt(r4)        ; ya, decrement count
  978.     jsr    pc    ,@$gtbyt    ; get the char
  979.     mov    (sp)+    ,r5        ; save a copy
  980.     .endc    ; eq mmg$t
  981.     bic    #^c<377>,r5        ; mask to 8 bits
  982.     bne    10$            ; /63/ not a null, something is left..
  983.     bit    #binout    ,clopts        ; /63/ ignore nulls?
  984.     beq    txproc            ; yes
  985. 10$:    rts    pc
  986.  
  987. 20$:    inc    qchflg            ; flag queue is about to be changed
  988.     .if eq km$pro
  989.     bic    #tx.ie    ,@tx$csr    ; disable xmit interrupts
  990.     .iftf
  991.     mov    kocqe    ,r4        ; point to current queue element
  992.     mov    q$link(r4),kocqe    ; put next element at top of queue
  993.     jsr    pc    ,dequeue    ; give current element to the os
  994.     clr    qchflg            ; queue is no longer changing
  995.     .ift
  996.     bis    #tx.ie    ,@tx$csr    ; re-enable xmit interrupts
  997.     .endc    ; eq km$pro
  998.     br    txproc            ; always return a char if possible
  999.  
  1000.  
  1001.     .sbttl    Input (from modem) interrupt service
  1002.  
  1003.     .if eq km$pro
  1004.     rts    pc            ; abort entry point
  1005.     .iftf
  1006. kiint:    .ift
  1007.     jsr    r5    ,@$inptr    ; drop back to the
  1008.     .word    ^c<km$pri*40>&340    ; device priority
  1009.     movb    @rx$buf    ,r5        ; get a char
  1010.     .iff
  1011.     movb    @#km$buf,r5        ; get a char
  1012.     .iftf
  1013.     bic    #^c<377>,r5        ; mask to 8 bits, dump possible sxt
  1014.     bne    10$            ; /63/ not a null, something is left..
  1015.     bit    #binin    ,clopts        ; /63/ was a null, check disposition
  1016.     beq    30$            ; ignore nulls
  1017. 10$:    tst    ctsflg            ; doing hardware flow control?
  1018.     bne    50$            ; ya, ^Q and ^S are normal chars..
  1019. ; /63/ use hardware flow control with binin or uncomment the following 2 lines
  1020. ;    bit    #binin    ,clopts        ; /63/ or if doing binary input
  1021. ;    bne    50$            ; /63/ they are normal here too
  1022.     cmp    r5    ,#ctrls        ; no, is it an XOFF?
  1023.     bne    40$            ; no
  1024.     mov    #1    ,rxhold        ; ya, flag it
  1025. 20$:    .ift
  1026.       .if ne km$pdt
  1027.       jmp    setled            ; update the PDT lights
  1028.       .endc
  1029.     .iftf
  1030. 30$:    .iff
  1031.     mov    #cmd.ei    ,@#km$csa    ; end of interrupt
  1032.     .iftf
  1033.     rts    pc
  1034.  
  1035. 40$:    cmp    r5    ,#ctrlq        ; is it an XON?
  1036.     bne    50$            ; no
  1037.     clr    rxhold            ; ya, flag it
  1038.     .ift
  1039.     bis    #tx.ie    ,@tx$csr    ; re-enable xmit interrupts
  1040.     .iff
  1041.     clr    txhold            ; flag xmit XOFF is no longer pending
  1042.     movb    #ctrlq    ,@#km$buf    ; because this XON has just been sent
  1043.     .iftf
  1044.     br    20$            ; common code..
  1045.  
  1046. 50$:    tst    rxfree            ; input buffer full?
  1047.     beq    70$            ; ya, go send an XOFF
  1048.     mov    rxputc    ,r4        ; no, point to where char goes in buff
  1049.     add    pc    ,r4        ; calculate and add
  1050.     add    #rxbuff-.,r4        ; the top of the buffer's address
  1051.     movb    r5    ,@r4        ; stuff the char into the buffer
  1052.     dec    rxfree            ; decrement the free byte count
  1053.     inc    rxputc            ; next char goes here
  1054.     cmp    rxputc    ,#km$bsz    ; unless at the end
  1055.     blo    60$            ; not yet..
  1056.     clr    rxputc            ; wrap to top of the buffer
  1057. 60$:    cmp    rxfree    ,#lowater    ; time to put the brakes on yet?
  1058.     bhi    100$            ; no..
  1059.     tst    txhold            ; ya, done an XOFF or dropped RTS yet?
  1060.     bgt    100$            ; ya..
  1061.  
  1062. 70$:    tst    ctsflg            ; no, doing hardware flow control?
  1063.     bne    80$            ; ya
  1064.     .ift
  1065.     mov    #-1    ,txhold        ; no, flag to send an XOFF
  1066.     bis    #tx.ie    ,@tx$csr    ; enable output interrupts
  1067.     br    100$
  1068.     .iff
  1069.     movb    #ctrls    ,@#km$buf    ; send an XOFF
  1070.     br    90$            ; go flag it's been sent
  1071.     .iftf
  1072. 80$:    .ift
  1073.     bic    #rx.rts    ,@rx$csr    ; clear RTS
  1074.     .iff
  1075.     bicb    #m0.rts    ,@#km$mc0    ; clear RTS
  1076.     .iftf
  1077. 90$:    mov    #1    ,txhold        ; flag the hold
  1078.  
  1079. 100$:    tst    kicqe            ; anything in the input queue?
  1080.     beq    20$            ; no
  1081.     .iff
  1082.     mov    #cmd.ei    ,@#km$csa    ; end of interrupt
  1083.     .endc    ; eq km$pro
  1084.     .br    rxproc            ; /63/ fall through to rxproc
  1085.  
  1086.  
  1087.     .sbttl    Process chars from the modem
  1088.  
  1089. rxproc:    inc    rx.proc            ; is this process already running?
  1090.     bne    80$            ; ya..
  1091.     jsr    r0    ,90$        ; no, but save r0-r3, drop pri first
  1092. 10$:    clr    rx.proc            ; flag input is now being processed
  1093.     cmp    rxfree    ,#hiwater    ; enough room to allow more input yet?
  1094.     blo    40$            ; no..
  1095.     tst    txhold            ; ya, has an XON been sent yet?
  1096.     beq    40$            ; ya..
  1097.     tst    ctsflg            ; doing hardware flow control?
  1098.     bne    20$            ; ya
  1099.     .if eq km$pro
  1100.     mov    #-2    ,txhold        ; no, flag to send an XON
  1101.     bis    #tx.ie    ,@tx$csr    ; enable output interrupts
  1102.     br    40$
  1103.     .iff
  1104.     movb    #ctrlq    ,@#km$buf    ; send an XON
  1105.     br    30$
  1106.     .iftf
  1107. 20$:    .ift
  1108.     bis    #rx.rts    ,@rx$csr    ; set RTS
  1109.     .iff
  1110.     bisb    #m0.rts    ,@#km$mc0    ; set RTS
  1111.     .endc    ; eq km$pro
  1112. 30$:    clr    txhold            ; xmit hold is no longer pending
  1113.  
  1114. 40$:    mov    kicqe    ,r4        ; is there input to do?
  1115.     beq    70$            ; no..
  1116.     cmp    rxfree    ,#km$bsz    ; ya, check input ring buffer
  1117.     beq    70$            ; it's empty..
  1118.     mov    rxgetc    ,r5        ; this is the offset to the next char
  1119.     add    pc    ,r5        ; calculate and add
  1120.     add    #rxbuff-.,r5        ; the top of the buffer's address
  1121.     movb    @r5    ,r5        ; get the char
  1122.     inc    rxfree            ; this byte is now free
  1123.     inc    rxgetc            ; next char will be here
  1124.     cmp    rxgetc    ,#km$bsz    ; unless at the end
  1125.     blo    50$            ; not yet..
  1126.     clr    rxgetc            ; wrap to top of the buffer
  1127. 50$:    .if eq mmg$t
  1128.     add    #q$wcnt    ,r4        ; get the word count
  1129.     movb    r5    ,@-(r4)        ; return the char
  1130.     inc    (r4)+            ; next char goes here
  1131.     dec    @r4            ; done?
  1132.     .iff
  1133.     movb    r5    ,-(sp)        ; pass char to
  1134.     jsr    pc    ,@$ptbyt    ; $_put_byte
  1135.     dec    q$wcnt(r4)        ; done?
  1136.     .iftf
  1137.     beq    60$            ; ya..
  1138.     cmp    rxfree    ,#km$bsz    ; no, is there more to do?
  1139.     bne    10$            ; ya..
  1140.     bit    #binin    ,clopts        ; /63/ binary input mode enabled?
  1141.     bne    60$            ; /63/ ya, no need to terminate..
  1142.     mov    kicqe    ,r4        ; no, restore pointer to current entry
  1143.     .ift
  1144.     add    #q$wcnt    ,r4        ; location of next free byte in buffer
  1145.     clrb    @-(r4)            ; null terminate the data
  1146.     .iff
  1147.     clrb    -(sp)            ; pass a null byte to
  1148.     jsr    pc    ,@$ptbyt    ; $_put_byte to terminate the data
  1149.     .endc    ; eq mmg$t
  1150. 60$:    mov    kicqe    ,r4        ; point to current queue element
  1151.     mov    q$link(r4),kicqe    ; put next element at top of queue
  1152.     jsr    pc    ,dequeue    ; give current element to the os
  1153.     br    10$            ; next one..
  1154.  
  1155. 70$:    dec    rx.proc            ; something new to do?
  1156.     bpl    10$            ; ya..
  1157. 80$:    rts    pc            ; see code just below re: r0 vs. pc..
  1158.  
  1159. 90$:    mov    r1    ,-(sp)        ; r0 was just pushed by jsr r0 ,90$
  1160.     mov    r2    ,-(sp)        ; note r0 is NOT preserved here as it
  1161.     mov    r3    ,-(sp)        ; isn't needed in routine following..
  1162.     mov    r0    ,-(sp)        ; save return address on top of stack
  1163.     .mtps    #0            ; drop priority, then
  1164.     jsr    pc    ,@(sp)+        ; go back to the caller after which
  1165.     mov    (sp)+    ,r3        ; we arrive here to pop the regs as
  1166.     mov    (sp)+    ,r2        ; calling routine ends with rts pc
  1167.     mov    (sp)+    ,r1        ;   ..all this saves a few words..
  1168.     mov    (sp)+    ,r0        ; <- pushed by originating jsr r0,90$
  1169.     rts    pc            ; now return from whence we came..
  1170.  
  1171. rx.proc:.word    -1            ; -1=RXPROC is free, =>0 RXPROC is not
  1172. rxbuff:    .blkb    km$bsz            ; receive high speed ring buffer
  1173. rxfree:    .word    km$bsz            ; number of bytes free
  1174. rxputc:    .word    0            ; put_next_char pointer
  1175. rxgetc:    .word    0            ; get_next_char pointer
  1176.  
  1177.  
  1178.     .sbttl    Place an entry on the internal queue
  1179.  
  1180. enqueue:clr    kmcqe            ; this is where it's coming from
  1181.     clr    kmlqe            ; also here, as never more than one..
  1182.     tst    @r5            ; anything in the internal queue?
  1183.     bne    10$            ; ya..
  1184.     mov    r4    ,(r5)+        ; no, so this becomes the first
  1185.     mov    r4    ,(r5)+        ; and the last one too
  1186.     rts    r5
  1187.  
  1188. 10$:    mov    r4    ,-(sp)        ; address of the new element
  1189.     tst    (r5)+            ; get the pointer
  1190.     mov    @r5    ,r4        ; to the last element
  1191.     mov    @sp    ,q$link(r4)    ; link to the one being added
  1192.     mov    (sp)+    ,(r5)+        ; which then becomes the last one..
  1193.     rts    r5
  1194.  
  1195.  
  1196.     .sbttl    Remove internal queue elements to monitor/handler queue
  1197.  
  1198. delink:    mov    (r4)+    ,r5        ; get the queue to check (in or out)
  1199.     mov    r4    ,-(sp)        ; r4 now has return address, save it
  1200.     add    pc    ,r5        ; get queue's actual location
  1201. del.pc    = .                ; with respect to where we are now
  1202.     mov    r5    ,-(sp)        ; and save a copy
  1203. 10$:    mov    q$link(r5),r4        ; get link to next entry
  1204.     beq    40$            ; done
  1205.     .if eq    tsx$p
  1206.     movb    q$jnum(r4),r0        ; recover the RT-11 job number
  1207.     asr    r0
  1208.     asr    r0
  1209.     asr    r0
  1210.     bic    #^c<17>    ,r0        ; got it..
  1211.     .iff
  1212.     movb    q$job(r4),r0        ; support TSX job numbers >16
  1213.     bic    #^c<77>    ,r0        ; but it'll never be >63.
  1214.     .endc    ; eq tsx$p
  1215.     cmp    r0    ,4(sp)        ; does calling job own this entry?
  1216.     beq    20$            ; ya
  1217.     mov    r4    ,r5        ; no, skip it
  1218.     br    10$            ; next..
  1219.  
  1220. 20$:    mov    q$link(r4),q$link(r5)    ; unlink from the internal queue
  1221.     tst    kmcqe            ; any entries in the monitor queue?
  1222.     bne    30$            ; ya, add this at the end
  1223.     mov    r4    ,kmcqe        ; no, make it the first
  1224.     mov    r4    ,kmlqe        ; and thus the last as well
  1225.     br    10$            ; next..
  1226.  
  1227. 30$:    clr    q$link(r4)        ; last entry must link to 0
  1228.     mov    kmlqe    ,r0        ; pointer to last monitor queue entry
  1229.     mov    r4    ,q$link(r0)    ; link in this new one
  1230.     mov    r4    ,kmlqe        ; which is now the last one
  1231.     br    10$            ; next..
  1232.  
  1233. 40$:    mov    (sp)+    ,r4        ; back to top of the queue
  1234.     mov    r5    ,q$link+2(r4)    ; queue now ends here
  1235.     mov    (sp)+    ,r4        ; pop the return address
  1236.     rts    r4
  1237.  
  1238.  
  1239.     .sbttl    Non-exiting delink per RT-11 V5.5 SSM p. 7-22
  1240.  
  1241. dequeue:.mtps    #340            ; disable interrupts
  1242.     tst    kmcqe-4            ;;; need to wait?
  1243.     bpl    10$            ;;; no..
  1244.     mov    @sp    ,-(sp)        ;;; ya, push the return address
  1245.     .if eq mmg$t
  1246.     clr    2(sp)            ;;; and clear the PSW
  1247.     .iff
  1248.     mov    @#psw    ,2(sp)        ;;; under XM just hose
  1249.     bic    #340    ,2(sp)        ;;; priority 7..
  1250.     .iftf
  1251.     .inten    km$pri    ,pic        ;;; goto the device priority
  1252.     .fork    fkblk            ; wait for system stuff to finish
  1253.     .ift
  1254.     .mtps    #340            ; disable interrupts
  1255.     .iff
  1256.     bis    #340    ,@#psw        ; play it safe under XM ..
  1257.     .endc    ; eq mmg$t        ; in case the monitor/handler queue
  1258. 10$:    mov    kmcqe    ,-(sp)        ; has an element, stash a copy then
  1259.     mov    r4    ,kmcqe        ; put the internal queue element
  1260.     mov    r4    ,kmlqe        ; on the monitor/handler queue
  1261.     clr    q$link(r4)        ; now delink from internal queue
  1262.     picadr    #kmcqe    ,r4        ; emulate .drfin except
  1263.     mov    @#sysptr,r5        ; come back after the
  1264.     jsr    pc    ,@qcomp(r5)    ; monitor/handler queue releases it
  1265.     mov    @sp    ,kmcqe        ; recover the current element which is
  1266.     mov    (sp)+    ,kmlqe        ; the first, last (and only) element
  1267.     rts    pc
  1268.  
  1269. fkblk:    .word    0 ,0 ,0 ,0        ; fork queue element
  1270.     .drend    KM
  1271.  
  1272.     .end
  1273.