home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / cpm86 / c86xfu.a86 < prev    next >
Text File  |  2020-01-01  |  28KB  |  1,038 lines

  1. ; STARTSYSDEP    ; This is so:
  2. ;               ;     PIP LISTING=86KERMIT.LST[WSSTARTSYSDEP^ZQENDxSYSDEP^Z]
  3. ;               ; will work.
  4. ;
  5. ;
  6. ; **************************************************************************
  7. ;
  8. ; This is the i/o support module for the Future Computers FX20/FX30
  9. ; Running CP/M-86 or Concurrent CP/M.
  10. ;
  11. ;  Tony Chabot, University of Birmingham, UK   October 1985
  12. ;  (Based on the version for the Honeywell MSE by Mark Hewitt).
  13. ;
  14. ;  This module checks which type of CP/M system it is running under,
  15. ;  and alters its performance accordingly. No separate assembly is
  16. ;  required for CP/M-86 and Concurrent.
  17. ;  It is preferable to use the KERUTL from Concurrent implementations
  18. ;  as that will work with both types of CP/M, whereas the standard
  19. ;  version of KERUTL (for CP/M-86) will not work fully with Concurrent.
  20. ;
  21. ;  This implementation allows only the modem port to be used.
  22. ;  This is because the printer port does not have its rx interrupt request
  23. ;  line connected to the 8259 interrupt controller.
  24. ;
  25. ;  The modem port uses a 7201 Multi Protocol Serial Controller, situated
  26. ;  at address C120-C123, with the relevant addresses for the modem part
  27. ;  of it being C121 & C123.(Note - the FX20/FX30 manual incorrectly gives
  28. ;  the addresses as C122 and C123).
  29. ;  The baud rate generator is an 8253-5, timer 1.
  30. ;  The range of addresses for this device is C060-C063. The generator
  31. ;  has a 4MHz clock input (gleaned from a scope, so this is not too accurate,
  32. ;  but a frequency meter seemed to think the frequency was 1MHz +- 10% !).
  33. ;  The 7201 is programmed to divide by 16, so the baud rate divider is given
  34. ;  by
  35. ;  divider = 4000000/(16*baudrate)
  36. ;
  37. ;  The 8259 interrupt controller is programmed (by CP/M) to base its vectors
  38. ;  at 100. The relationship between the 8259 IR lines and the requesting device
  39. ;  is:
  40. ;
  41. ;    IR0    ?
  42. ;    IR1    PIT (out0)
  43. ;    IR2    7201
  44. ;    IR3    ?
  45. ;    IR4    ?
  46. ;    IR5    Keyboard 8251 RxRdy
  47. ;    IR6    Printer  8251 TxRdy
  48. ;    IR7    Pulled up.
  49. ;
  50. ;  Only IR0, IR1 and IR5 have useful interrupt service routines, as well
  51. ;  as the predefined vectors and CP/M system call vectors. All other
  52. ;  vectors point, via some register saving code, to an illegal interrupt
  53. ;  routine. It is thus simple to patch the vector for the 7201 (at 108-10B)
  54. ;  to point to our ISR.
  55. ;
  56. ;  ** W A R N I N G **
  57. ;
  58. ;  The 7201 also handles the LAN, so if you have lan software running, it
  59. ;  is likely that this code will cause problems.
  60. ;
  61. ;
  62. ; **************************************************************************
  63.     CSEG $
  64.  
  65. ; Port base definitions
  66.  
  67. bgen    equ    0C060h        ; Baud Rate Generator            (8253-5)
  68. ictrl    equ    0C000h        ; Interrupt Controller           (8259A)
  69.  
  70. ; And the I/O ports themselves
  71.  
  72. bgcmd    equ    bgen+3        ; Baud rate generator command port
  73.  
  74. iccmd    equ    ictrl+0        ; Interrupt controller command port
  75. icmask    equ    ictrl+1        ; Interrupt controller mask register port
  76.  
  77. mdmcmd    equ    0C123h        ; modem command port
  78. mdmbg    equ    bgen+1        ; Baud rate countdown value for modem port
  79. mdmio    equ    0C121h        ;modem data io port (Note-FX30 manual is wrong)
  80. ptrcmd    equ    0C122h
  81. ;
  82. ;
  83. ;    Port selection
  84. ;
  85. pmdm    equ    0
  86. ;
  87. ; Interrupt vectors in page 0
  88. ;
  89. mdmvec    equ    0108h        ; Interrupt vector for modem.
  90. ;
  91. ; Interrupt masks
  92. ;
  93. immdm    equ    04h        ; Mask for modem port.
  94. ;
  95. ;  Baud rate generator command words
  96. ;
  97. mdmbsel    equ    76h        ; Select modem baud rate register
  98. ;
  99. ;  Interrupt controller commands
  100. ;
  101. iceoi    equ    20h        ; end of interrupt
  102. ;
  103. ;  I/O register bits:
  104. ;
  105. ;  For 7201 'Multiprotocol Serial Communications Controller' ( a name
  106. ;  worthy of IBM !).
  107. ;
  108. ccreg0    equ    00h        ; Control instruction - select register 0
  109. ccreg1    equ    01h        ; Control instruction - select register 1
  110. ccreg2    equ    02h        ; Control instruction - select register 2
  111. ccreg3    equ    03h        ; Control instruction - select register 3
  112. ccreg4    equ    04h        ; Control instruction - select register 4
  113. ccreg5    equ    05h        ; Control instruction - select register 5
  114. ccreg6    equ    06h        ; Control instruction - select register 6
  115. ccreg7    equ    07h        ; Control instruction - select register 7
  116.  
  117. c0null    equ    00h        ; Register 0 - null command
  118. c0abort    equ    08h        ; Register 0 - send abort
  119. c0resi    equ    10h        ; Register 0 - reset ext. status ints.
  120. c0chrst    equ    18h        ; Register 0 - channel reset
  121. c0eninc    equ    20h        ; Register 0 - enable int. on next character
  122. c0rpti    equ    28h        ; Register 0 - reset pending tx int./DMA req.
  123. c0errst    equ    30h        ; Register 0 - error reset
  124. c0eoi    equ    38h        ; Register 0 - end of interrupt
  125. c0rxcrc    equ    40h        ; Register 0 - reset rx CRC checker
  126. c0txcrc    equ    80h        ; Register 0 - reset tx CRC generator
  127. c0ricrc    equ    0C0h        ; Register 0 - reset idle/CRC latch
  128.  
  129. c1stien    equ    01h        ; Register 1 - external/status int enable
  130. c1txien    equ    02h        ; Register 1 - transmitter interrupt enable
  131. c1cav    equ    03h        ; Register 1 - condition affects vector
  132. c1noi    equ    00h        ; Register 1 - no rx or DMA interrupts
  133. c1i1st    equ    08h        ; Register 1 - int. on 1st received character
  134. c1iall    equ    10h        ; Register 1 - int. on all received characters
  135. c1ialp    equ    18h        ; Register 1 - int on all rx'd chars, no parity
  136. c1wrxtx    equ    20h        ; Register 1 - WAIT on rx/tx
  137. c1txbcm    equ    40h        ; Register 1 - TX byte count mode enbable
  138. c1wten    equ    80h        ; Register 1 - WAIT function enable
  139. ;
  140. ;  and some useful abbreviations
  141. ;
  142. c1norm    equ    c1ialp
  143. ;
  144. c2dma0    equ    00h        ; Register 2 - No DMA
  145. c2dma1    equ    01h        ; Register 2 - DMA mode 1
  146. c2dma2    equ    02h        ; Register 2 - DMA mode 2
  147. c2dma3    equ    03h        ; Register 2 - DMA mode 3
  148. c2pri    equ    04h        ; Register 2 - Set DMA priority
  149. c2ack0    equ    00h        ; Register 2 - Int Ack mode 0 (NV,D432)
  150. c2ack1    equ    08h        ; Register 2 - Int Ack mode 1 (NV, D432)
  151. c2ack2    equ    10h        ; Register 2 - Int Ack mode 2 (NV, D210)
  152. c2ack4    equ    20h        ; Register 2 - Int Ack mode 4 (8085 master)
  153. c2ack5    equ    28h        ; Register 2 - Int Ack mode 5 (8085 slave)
  154. c2ack6    equ    30h        ; Register 2 - Int Ack mode 6 (8086)
  155. c2ack7    equ    38h        ; Register 2 - Int Ack mode 7(8085/8259A slave)
  156. c2rxim    equ    40h        ; Register 2 - rx interrupt mask
  157. c2syncb    equ    80h        ; Register 2 - pin 10 ~RTSB or ~SYNCB
  158.  
  159. c3rxen    equ    01h        ; Register 3 - receive enable
  160. c3scli    equ    02h        ; Register 3 - sync character load inhibit
  161. c3asm    equ    04h        ; Register 3 - address search mode
  162. c3rxcrc    equ    08h        ; Register 3 - receiver CRC enable
  163. c3hunt    equ    10h        ; Register 3 - enter hunt phase
  164. c3aen    equ    20h        ; Register 3 - auto enables on DCD/CTS
  165. c3r5bit equ    00h        ; Register 3 - 5 bit data
  166. c3r6bit equ    40h        ; Register 3 - 6 bit data
  167. c3r7bit equ    80h        ; Register 3 - 7 bit data
  168. c3r8bit equ    0C0h        ; Register 3 - 8 bit data
  169. ;
  170. ;  and some useful abbreviations
  171. ;
  172. c3norm    equ    c3rxen+c3r8bit
  173. ;
  174. c4pen    equ    01h        ; Register 4 - parity enable
  175. c4ep    equ    02h        ; Register 4 - even parity
  176. c41stp    equ    04h        ; Register 4 - 1 stop bit
  177. c415stp    equ    08h        ; Register 4 - 1.5 stop bits
  178. c42stp    equ    0C0h        ; Register 4 - 2 stop bits
  179. c48syn    equ    00h        ; Register 4 - 8 bit internal sync (monosync)
  180. c416syn    equ    10h        ; Register 4 - 16 bit internal sync (bisync)
  181. c4sdlc    equ    20h        ; Register 4 - SDLC
  182. c4exts    equ    30h        ; Register 4 - External sync
  183. c41clk    equ    00h        ; Register 4 - 1x clock rate
  184. c416clk    equ    40h        ; Register 4 - 16x clock rate
  185. c432clk    equ    80h        ; Register 4 - 32x clock rate
  186. c464clk    equ    0C0h        ; Register 4 - 64x clock rate
  187. ;
  188. ;  and some useful abbreviations
  189. ;
  190. c4norm    equ    c41stp+c416clk
  191. ;
  192. c5txcrc    equ    01h        ; Register 5 - transmitter CRC enable
  193. c5rts    equ    02h        ; Register 5 - request to send
  194. c5poly    equ    04h        ; Register 5 - CRC polynomial select
  195. c5txen    equ    08h        ; Register 5 - transmitter enable
  196. c5sbrk    equ    10h        ; Register 5 - send break
  197. c5t5bit    equ    00h        ; Register 5 - transmit 5 bit data
  198. c5t6bit    equ    20h        ; Register 5 - transmit 6 bit data
  199. c5t7bit    equ    40h        ; Register 5 - transmit 7 bit data
  200. c5t8bit    equ    60h        ; Register 5 - transmit 8 bit data
  201. c5dtr    equ    80h        ; Register 5 - data terminal ready
  202. ;
  203. ;  and some useful abbreviations
  204. ;
  205. c5norm    equ    c5rts+c5txen+c5t8bit+c5dtr
  206. ;
  207. cs0rxr    equ    01h        ; Status register 0 - received char ready
  208. cs0ip    equ    02h        ; Status register 0 - interrupt pending
  209. cs0tbe    equ    04h        ; Status register 0 - tx buffer empty
  210. cs0dcd    equ    08h        ; Status register 0 - data carrier detect
  211. cs0sync    equ    10h        ; Status register 0 - sync status
  212. cs0cts    equ    20h        ; Status register 0 - clear to send
  213. cs0idle    equ    40h        ; Status register 0 - idle CRC latch status
  214. cs0brk    equ    80h        ; Status register 0 - break detect
  215.  
  216. cs1sent    equ    01h        ; Status register 1 - all sent
  217. cs1sdlc    equ    0Eh        ; Status register 1 - SDLC residue code
  218. cs1pe    equ    10h        ; Status register 1 - parity error
  219. cs1oe    equ    20h        ; Status register 1 - overrun error
  220. cs1fe    equ    40h        ; Status register 1 - framing error
  221. cs1eosf    equ    80h        ; Status register 1 - end of SDLC frame
  222.  
  223.  
  224. ;    System call defs for concurrent version.
  225. p_dispatch    equ    8Eh    ; Reschedule.
  226. f_errmode    equ    2Dh    ; Set BDOS error mode.
  227.  
  228. ;
  229. ; Clock rate *10 for timing loops    ;[19g]
  230. ;
  231. clckrt    equ    80            ;[19g]  8.0 Mhz
  232. ;
  233. ;  Maximum number of examinations of output port to be ready before
  234. ;  rescheduling.
  235. ;
  236. outlmt    equ    1000h
  237.  
  238. ;
  239. ;  The executable code starts here
  240. ;
  241. ;
  242. ; ===========================================================================
  243. ;
  244. ;                        INITIALISATION ROUTINES
  245. ;
  246. ; ===========================================================================
  247. ;
  248. ; INTERFACE ROUTINE SERINI - Initialisation code
  249. ;
  250. serini:    cmp    mninit, true    ; Ensure that we only initialise once
  251.     je    serin2
  252.     mov    mninit, true
  253.  
  254. ;    Get type of CP/M system.
  255. ;
  256.     mov    cl,0ch
  257.     int    bdos
  258.     mov    cpmtyp, bh
  259.  
  260. ;
  261. ;  Initialise the screen
  262. ;
  263.     call    clrscr        ; Clear the screen.
  264. ;
  265. ;  Disable I/O interrupts, and save the old interrupt mask.
  266. ;
  267.     mov    dx, icmask    ; read the current interrupt mask
  268.     in    al, dx
  269.     mov    oldmsk, al    ; and save it
  270.     or    al, immdm    ; mask off i/o interrupts
  271.     out    dx, al        ; and reprogram interrupt controller
  272. ;
  273. ;  Save the system i/o interrupt vectors
  274. ;
  275.     mov    ax, ds        ; save the data segment in code segment
  276.     mov    cs:mndseg, ax    ;   for use by interrupt handler
  277.  
  278.     mov    ax, 0        ; point to zero page and save both the
  279.     mov    es, ax        ;   system's i/o interrupt vectors
  280.     mov    ax,es:.mdmvec+0    ;     for the modem channel
  281.     mov    vscoff, ax
  282.     mov    ax, es:.mdmvec+2
  283.     mov    vscseg, ax
  284.  
  285. ;  Configure the default port
  286. ;
  287.     mov    ax, 0        ; point to zero page and set the interrupt
  288.     mov    es, ax        ;   vector for the modem/printer channel to my
  289.                 ;     interrupt service routine
  290.     mov    ax, offset isr    ; set offset address
  291.     mov    es:.mdmvec+0, ax
  292.     mov    ax, cs        ; set segment address
  293.     mov    es:.mdmvec+2, ax
  294.  
  295.     call    setmode        ; set UART mode for current port
  296.     call    setbaud        ; set the baud rate for the current port
  297.     call    mnflush        ; flush and enable the current port
  298.     call    inton        ; turn interrupts on for current port
  299.  
  300. ;    If concurrent, set BDOS error mode.
  301. ;
  302.     cmp    cpmtyp, 14h
  303.     jne    serin2
  304.     mov    cl, f_errmode
  305.     mov    dl, 0FEh    ; Set err mode to display and return.
  306.     int    bdos
  307.  
  308. serin2:    ret            ; initialisation over
  309.  
  310. ;
  311. ; INTERFACE ROUTINE SERFIN - restore environment (as far as possible)
  312. ;                            to that which existed before we played with it
  313. ;
  314. serfin:    cmp    mninit, true    ; only deinitialise if necessary
  315.     jne    serfn2
  316.     mov    mninit, false
  317. ;
  318. ;  Disable i/o interrupt while we reset the vectors
  319. ;
  320.     mov    dx, icmask    ; get present interrupt mask
  321.     in    al, dx        ; and turn off all i/o interrupts
  322.     or    al, immdm    ;   from the modem channel
  323.     out    dx, al        ; reprogram the interrupt controller
  324. ;
  325. ;  Reset the i/o interrupt vectors
  326. ;
  327.     mov    ax, 0        ; point at page 0 and reset the int. vectors
  328.     mov    es, ax
  329.     mov    ax, vscoff    ;   for the modem/printer port
  330.     mov    es:.mdmvec+0, ax
  331.     mov    ax, vscseg
  332.     mov    es:.mdmvec+2, ax
  333. ;
  334. ; turn interrupts back on (or off...)
  335. ;
  336.     mov    al, oldmsk    ; restore original interrupt mask
  337.     out    dx, al
  338. ;
  339. ;  Reset screen modes
  340. ;
  341.     call    clrscr        ; Be tidy - clear the screen.
  342.  
  343. serfn2:    ret            ; deinitialisation over
  344.  
  345. ;
  346. ;
  347. ; INTERNAL ROUTINE SETMODE - set the operating mode for current port's UART.
  348. ;
  349. setmode:
  350.     push    ax
  351.     push    dx        ; we'll need this
  352.  
  353.     mov    dx, mdmcmd    ; Command port adrs.
  354.  
  355.     mov    al, c0chrst    ; reset the port
  356.     out    dx, al
  357.     mov    al, c0resi+ccreg4 ; select register 4
  358.     out    dx, al
  359.     mov    al, c4norm    ; 16x Clock, 1 stop bit, no parity
  360.     out    dx, al
  361.     mov    al, c0resi+ccreg3 ; Select register 3
  362.     out    dx, al
  363.     mov    al, c3norm    ; 8 bits/character, RX enable
  364.     out    dx, al
  365.     mov    al, c0resi+ccreg5 ; select register 5
  366.     out    dx, al
  367.     mov    al, c5norm    ; 8 bits/character, TX enable RTS and DTR
  368.     out    dx, al
  369.     mov    al, c0resi+ccreg1 ; select register 1
  370.     out    dx, al
  371.     mov    al, c1norm    ; Interrupt enable
  372.     out    dx, al
  373.     
  374.     pop    dx        ; modes now set, restore regs. and return
  375.     pop    ax
  376.     ret
  377.  
  378. ;
  379. ;  INTERNAL ROUTINE SETBAUD - set the baud rate of a current port.
  380. ;                             port number in cport.
  381. ;                             timer countdown table offset in cbaud.
  382. ;
  383. setbaud:
  384.     push    bx        ; we'll be using this
  385.     push    dx        ; and this
  386.     push    ax        ; and this too
  387.  
  388.     mov    al, bdtab    ; check that rate is legal
  389.     dec    al        ; pick up number of valid rates from BDTAB
  390.     cmp    cbaud, al    ;  0 <= cbaud <= [bdtab]-1
  391.     ja    setbd2        ; just return if not legal
  392.  
  393.     mov    bx, offset bdtct; get timer value
  394.     mov    al, cbaud    ; from timer countdown table
  395.     mov    ah, 0
  396.     add    al, al        ; word offset
  397.     add    bx, ax        ; bx now points to correct value
  398.  
  399.     mov    dx, bgcmd    ; dx is now baud rate generator command port
  400.  
  401.     cmp    cport, pmdm    ; is it the modem port?
  402.     jne    setbd2        ; just return if not
  403.  
  404.     mov    al, mdmbsel    ; set baud rate for modem port
  405.     out    dx, al
  406.     mov    dx, mdmbg
  407.     jmp    setbd3
  408.  
  409. setbd3:    mov    ax, [bx]    ; set the countdown value
  410.     out    dx, al
  411.     mov    al, ah
  412.     out    dx, al
  413.  
  414. setbd2:    pop    ax        ; baud rate set, retore regs. and return
  415.     pop    dx
  416.     pop    bx
  417.     ret
  418.  
  419. ;
  420. ;  INTERNAL ROUTINE MNFLUSH - enable and flush current port.
  421. ;                             Port in cport.
  422. ;
  423. mnflush:
  424.     push    ax        ; preserve registers
  425.     push    dx
  426.  
  427.     mov    dx, mdmio    ; Modem data port adrs.
  428.     in    al, dx        ; flush the port
  429.     in    al, dx
  430.     in    al, dx
  431.     mov    dx, mdmcmd    ; reset any pending interrupts
  432.     mov    al, c0errst
  433.     out    dx, al
  434.     mov    al, c0resi
  435.     out    dx, al
  436.  
  437.     pop    dx        ; port flushed, retore regs. and return
  438.     pop    ax
  439.     ret
  440.  
  441. ;
  442. ; INTERNAL ROUTINE INTON - enable interrupts for the selected port
  443. ;               (This version simply enables the modem port!)
  444. ;                          Ensure that the port selected is enabled, and
  445. ;                          that all other ports are as the system would
  446. ;                          wish them!
  447. inton:    
  448.     push    ax
  449.     push    dx
  450.  
  451.     mov    dx, icmask
  452.     in    al,dx        ; Read current interrupt mask.
  453.     and    al, not immdm    ; Enable modem interrupts.
  454.     out    dx, al
  455.  
  456. inton2:    pop    dx
  457.     pop    ax        ; interrupts now enabled - restore regs.
  458.     ret            ;   and return
  459.  
  460.     DSEG $            ; Data used by initialisation/deinitialisation
  461.  
  462. mninit    db    false        ; flag set when initialised
  463. oldmsk    rb    1        ; Old interrupt mask
  464. cpmtyp    db    0        ; CP/M type (0 = CP/M-86, 14h = concurrent).
  465. ;
  466.  
  467. ;  Current port status
  468. ;
  469. cport    db    pmdm        ; current port number - default to modem
  470. cbaud    db    8        ; current baud rate - default to 4800
  471. ciop    dw    mdmio        ; current i/o port - default to modem
  472. ccmdp    dw    mdmcmd        ; current command/status port - default modem
  473. ;
  474. ;  Storage for system interrupt vectors
  475. ;
  476. vscoff    rw    1        ; offset for system v.24/printer int. vector
  477. vscseg    rw    1        ; seg. address for system v.24/printer int. vec
  478. ;
  479. ;  Baud rate timer countdown table
  480. ;  (The accuracy of these is uncertain as the baud rate generator clock
  481. ;  frequency was measured with a scope).
  482. ;
  483. bdtct    dw    5000        ;    50 baud, code  0
  484.     dw    3333        ;    75
  485.     dw    2273        ;   110
  486.     dw    1667        ;   150
  487.     dw    833        ;   300
  488.     dw    417        ;   600
  489.     dw    208        ;  1200
  490.     dw    104        ;  2400
  491.     dw    52        ;  4800
  492.     dw    26        ;  9600
  493.     dw    13        ; 19200
  494.  
  495.     CSEG $
  496.  
  497. ; ===========================================================================
  498. ;
  499. ;                             SET COMMANDS
  500. ;
  501. ; ===========================================================================
  502. ;
  503. ;  INTERFACE ROUTINE BDSET - set baud rate for current port (cport).
  504. ;                            save current baud rate in cbaud.
  505. ;
  506. bdset:    mov    dx, offset bdtab    ; table of valid baud rates
  507.     mov    bx, offset bdhlp    ; help information for SET BAUD
  508.     mov    ah, cmkey        ; Command parser - KEYWORD lookup
  509.     call    comnd
  510.       jmp    r            ; error return
  511.     mov    settmp, bx        ; Normal return - save value
  512.     mov    ah, cmcfm        ; Command parser - CONFIRM
  513.     call comnd
  514.       jmp    r
  515.     mov    bx, settmp
  516.     mov    cbaud, bl        ; save the baud rate
  517.     call    setbaud            ; and set it for the current port
  518.     jmp    rskp            ; end of parsing SET BAUD command
  519.  
  520.     DSEG $
  521.  
  522. settmp    rw    1            ; temporary storage for baud rate
  523.  
  524.     CSEG $
  525. ;
  526. ;  INTERFACE ROUTINE PRTSET - set the current port.
  527. ;
  528. prtset:    mov    dx, offset potab    ; table of valid port names
  529.     mov    bx, offset pohlp    ; help information for SET PORT
  530.     mov    ah, cmkey        ; Command parser - KEYWORD lookup
  531.     call    comnd
  532.       jmp    r            ; error return
  533.  
  534.     mov    settmp, bx        ; Normal return - save value
  535.  
  536.     mov    ah, cmcfm        ; Command parser - CONFIRM
  537.     call comnd
  538.       jmp    r
  539.     jmp    rskp            ; end of parsing SET PORT command
  540. ;
  541. ;  Data required by the SET commands
  542. ;
  543.     DSEG $                ; SET command data
  544. ;
  545. ;  Baud rate table
  546. ;
  547. bdtab    db    11            ; number of entries
  548.     db    3, '110$'        ; size of entry, and the keyword$
  549.     dw    02            ; value returned
  550.     db    3, '150$'
  551.     dw    03
  552.     db    4, '1200$'
  553.     dw    06
  554.     db    5, '19200$'
  555.     dw    10
  556.     db    4, '2400$'
  557.     dw    07
  558.     db    3, '300$'
  559.     dw    04
  560.     db    4, '4800$'
  561.     dw    8
  562.     db    2, '50$'
  563.     dw    00
  564.     db    3, '600$'
  565.     dw    05
  566.     db    2, '75$'
  567.     dw    01
  568.     db    4, '9600$'
  569.     dw    09
  570. ;
  571. ;  Help table for baud rate setting
  572. ;
  573. bdhlp    db    cr, lf, '    50     75    110    150    300    600'
  574.     db    cr, lf, '  1200   2400   4800   9600  19200'
  575.     db    '$'
  576. ;
  577. ;  Port table
  578. ;
  579. potab    db    1
  580.     db    5, 'MODEM$'
  581.     dw    pmdm
  582. ;
  583. ;  Help table for port selection
  584. ;
  585. pohlp    db    cr, lf, 'MODEM$'
  586.  
  587.     CSEG $
  588.  
  589. ; ===========================================================================
  590. ;
  591. ;                              SHOW COMMANDS
  592. ;
  593. ; ===========================================================================
  594.  
  595. ;
  596. ;  INTERFACE ROUTINE SHOBD - display the currently set baud rate within
  597. ;                            the SHOW command.
  598. ;
  599. shobd:    mov    dx, offset bdst    ;Baud rate string.
  600.     call    tcrmsg
  601.     mov    al, cbaud    ;Print the keyword corresponding to the
  602.     mov    bx, offset bdtab; current value of mnbaud.
  603.     call    tabprt
  604.     ret
  605.  
  606. ;
  607. ;  INTERFACE ROUTINE SHOPRT - display the currently selected communication
  608. ;                             port within the SHOW command.
  609. ;
  610. shoprt:    mov    dx, offset prtst    ; Port name string
  611.     call    tcrmsg
  612.     mov    al, cport        ; current port code
  613.     mov    bx, offset potab    ; and print the corresponding
  614.     call    tabprt            ;   textual description
  615.     mov    dx, offset prtst2
  616.     call    tmsg
  617.     ret
  618.  
  619.     DSEG $
  620.  
  621. prtst    db    'Communicating via $'
  622. prtst2    db    ' port$'
  623.  
  624.     CSEG $
  625.  
  626. ; ===========================================================================
  627. ;
  628. ;                                I/O ROUTINES
  629. ;
  630. ; ===========================================================================
  631. ;
  632. ;  INTERNAL ROUTINE ISR - Interrupt service routine for modem port.
  633. ;
  634.  
  635. isr:    
  636.     cli                ; disable intrerupts
  637.     mov    cs:mnax, ax        ; save ax - we will need a register
  638.     mov    ax, sp
  639.     mov    cs:mnsp, ax        ; save current stack pointer
  640.     mov    ax, ss
  641.     mov    cs:mnsseg, ax        ; Save current stack segment
  642.     mov    ax, cs:mndseg        ; Switch to my stack
  643.     mov    ss, ax
  644.     mov    sp, offset mnstk
  645.     push    ds            ; Save registers
  646.     push    es
  647.     push    bp
  648.     push    di
  649.     push    si
  650.     push    dx
  651.     push    cx
  652.     push    bx
  653.     mov    ds, ax            ; set our data segment address
  654. ;
  655. ;  That's the housekeeping out of the way - now we can start
  656. ;
  657.  
  658.     mov    dx, mdmcmd        ; see if char. ready at default port
  659.     in    al, dx
  660.     test    al, cs0rxr        ; is there a character for us?
  661.     jz    iprt3            ; no - clear interrupt, and return
  662.  
  663. iprt2:    mov    dx, mdmio        ; Fetch the character
  664.     in    al, dx
  665.     call    iproc            ; Process the character in AL
  666.  
  667. iprt3:    mov    dx, iccmd        ; Signal end of interrupt to
  668.     mov    al, iceoi        ;   interrupt controller
  669.     out    dx, al
  670.  
  671.     mov    dx, ptrcmd        ; Clear interrupt status at
  672.     mov    al, c0eoi        ;   7201
  673.     out    dx, al            ;    (note we use the A channel).
  674.  
  675.     pop    bx            ; Restore registers
  676.     pop    cx
  677.     pop    dx
  678.     pop    si
  679.     pop    di
  680.     pop    bp
  681.     pop    es
  682.     pop    ds
  683.     mov    ax, cs:mnsp        ; restore interrupt stack
  684.     mov    sp, ax
  685.     mov    ax, cs:mnsseg        ; restore original stack segment
  686.     mov    ss, ax
  687.     mov    ax, cs:mnax        ; restore original AX
  688.     iret                ; all over - return
  689.  
  690. ;
  691. ;  CSEG data required by interrupt service routine
  692. ;
  693. mnax    dw    0        ; temp. copy of AX
  694. mnsp    dw    0        ; interrupt stack pointer
  695. mnsseg    dw    0        ; interrupt stack segment
  696. mndseg    dw    0        ; location of our data segment
  697.  
  698. ;
  699. ; INTERNAL ROUTINE IPROC - process incoming character from Rx interrupt
  700. ;                          Character in AL
  701. ;
  702.  
  703. iproc:    cmp    floctl, floxon    ;are we doing flow-control ?    [19a] start
  704.     jne    ipr2b        ;no - go on
  705.     cmp    al, xoff    ;is it an XOFF?
  706.     jne    ipr2a        ;no - go on
  707.     mov    xofrcv, true    ;set the flag
  708.     ret
  709.  
  710. ipr2a:    cmp    al, xon        ;an XON?
  711.     jne    ipr2b        ;no
  712.     mov    xofrcv, false    ;clear the flag
  713.     ret            ;                [19a] end
  714.  
  715. ipr2b:    cmp    mnchrn,mnchnd    ;Is the buffer full?
  716.     je    iperr        ;If so, take care of the error.
  717.     inc    mnchrn        ;Increment the character count.
  718.     mov    bx,mnchip    ;Get the buffer input pointer.
  719.     inc    bx        ;Increment it.
  720.     cmp    bx,offset mnchrs+mnchnd ;Past the end?
  721.     jb    ipro3
  722.     mov    bx, offset mnchrs ;Yes, point to the start again.
  723. ipro3:    mov    mnchip,bx    ;Save the pointer.
  724.     mov    [bx],al        ;Put the character in the buffer.
  725.     cmp    floctl, floxon    ;do flow-control?        [19a] start
  726.     je    ipro4        ;If yes jump
  727.     ret
  728.  
  729. ipro4:    cmp    xofsnt, true    ;Have we sent an XOFF
  730.     jnz    ipro5
  731.     ret            ;return if we have
  732.  
  733. ipro5:    cmp    mnchrn, mntrg2    ;Past the High trigger point?
  734.     ja    ipro6        ;yes - jump
  735.     ret
  736.  
  737. ipro6:    mov    al, xoff
  738.     call    prtout        ;send an XOFF
  739.     mov    xofsnt, true    ;set the flag
  740.     ret            ;                [19a] End
  741.  
  742. iperr:    ret            ; just return on error for now
  743.  
  744. ;
  745. ;  INTERFACE ROUTINE CFIBF - Clear serial port input buffer
  746. ;
  747. cfibf:    mov    mnchrn, 0    ;Say no characters in the buffer.
  748.     mov    mnchip, OFFSET mnchrs-1+mnchnd ;Reset input pointer.
  749.     mov    mnchop, OFFSET mnchrs-1+mnchnd ;Reset output pointer.
  750.     ret
  751.  
  752. ;
  753. ;  INTERFACE ROUTINE PRTOUT - send character in AL to current port.
  754. ;
  755. prtout:    call    dopar        ; set parity if necessary
  756.     push    dx
  757.     push    cx
  758.  
  759.     mov    cx, outlmt
  760. prtou2:    call    outwait        ; wait for port to be free, or timeout
  761.       loop    prtou2
  762.       nop
  763.     call    outchr        ; output the character
  764.     pop    cx
  765.     pop    dx
  766.     ret
  767.  
  768. ;
  769. ; INTERNAL ROUTINE OUTWAIT - test if port ready for next char to be sent.
  770. ;                            returns RSKP if ready.
  771. ;
  772. outwait:
  773.     cmp    floctl, floxon
  774.     jne    outwt1
  775.     cmp    xofrcv, true
  776.     je    outwt3
  777. outwt1:
  778.     push    ax
  779.     mov    dx, mdmcmd
  780.     in    al, dx
  781.     test    al, cs0tbe
  782.     jnz    outwt4
  783.     pop    ax
  784. outwt3:    
  785.     cmp    cpmtyp, 14h    ; Concurrent?
  786.     jne    outwt35        ; No.
  787.     call    dispatch    ; Yes - redispatch the processor.
  788. outwt35:
  789.     ret
  790.  
  791. outwt4:    pop    ax
  792.     jmp    rskp
  793. ;
  794. ;  INTERNAL ROUTINE OUTCHR - send data to a port
  795. ;
  796. outchr:    mov    dx, mdmio
  797.     out    dx, al
  798.     ret
  799.  
  800. ;
  801. ; INTERFACE ROUTINE INSTAT - determine if there is any data to receive.
  802. ;
  803. instat:    cmp    mnchrn, 0        ; any characters in buffer?
  804.     jne    inst2
  805.     ret
  806. inst2:    jmp    rskp
  807.  
  808. ;
  809. ;  INTERFACE ROUTINE INCHR - read a character from a port
  810. ;
  811. inchr:    push    bx
  812.     cli            ;Disable interrupts while were are playing.
  813.     dec    mnchrn        ;Decrement the number of chars in the buffer.
  814.     mov    bx,mnchop    ;Get the pointer into the buffer.
  815.     inc    bx        ;Increment to the next char.
  816.     cmp    bx,offset mnchrs+mnchnd ;Past the end?
  817.     jb    inchr2
  818.     mov    bx, offset mnchrs ;If so wrap around to the start.
  819. inchr2:    mov    mnchop,bx    ;Save the updated pointer.
  820.     mov    al,[bx]        ;Get the character.
  821.     sti            ;All done, we can restore interrupts.
  822.     pop    bx
  823.     cmp    parflg,parnon    ;[par] no parity?
  824.     je    inchr3        ;[par] yup, don't bother stripping
  825.     and    al,7fh        ;[par] checking parity, strip off
  826. inchr3:    cmp    floctl, floxon    ;do flow-control?        [19a] start
  827.     je    inchr4        ;If yes jump
  828.     ret
  829. inchr4:    cmp    xofsnt, true    ;Have we sent an XOFF
  830.     je    inchr5        ;Jump if yes
  831.     ret
  832. inchr5:    cmp    mnchrn, mntrg1    ;Under the low trigger point?
  833.     jb    inchr6        ;yes - jump
  834.     ret
  835. inchr6:    push    ax        ;save current character
  836.     mov    al, xon
  837.     call    prtout        ;send an XON
  838.     mov    xofsnt, false    ;turn off the flag
  839.     pop    ax        ;get back character
  840.     ret            ;                [19a] end
  841.  
  842. ;
  843. ;  INTERFACE ROUTINE PRTBRK - Send a BREAK sequence to the default port
  844. ;
  845. prtbrk:    mov    dx, mdmcmd        ; Modem port cmd byte.
  846.     cmp    cport, pmdm        ; is it modem port?
  847.     jne    brka            ; must be an error - just return
  848.  
  849. brkc:
  850.     mov    al, c0resi+ccreg5    ; Break to modem port.
  851.     out    dx, al            ; Select register 5
  852.     mov    al, c5norm+c5sbrk    ; 8 bits, TX enable, Break, RTS & DTR
  853.     out    dx, al
  854.     mov    ax, 275            ; for 275 mS
  855.     call    mswait
  856.     mov    al, c0resi+ccreg5    ; select register 5
  857.     out    dx, al
  858.     mov    al, c5norm        ; 8 bits, TX enable, RTS & DTR
  859.     out    dx, al
  860.     ret
  861.  
  862. brka:    ret
  863.  
  864.     DSEG $
  865. ;
  866. ;  Input character queue
  867. ;
  868. mnchnd    equ    512        ;Size of circular buffer.
  869. mnchrs    rb    mnchnd        ;Circular character buffer for input.
  870. mnchip    dw    mnchrs-1+mnchnd    ;Input pointer into character buffer.
  871. mnchop    dw    mnchrs-1+mnchnd    ;Output pointer into character buffer.
  872. mnchrn    dw    0        ;Number of chars in the buffer.
  873.  
  874. mntrg1    equ    128        ;[19a] Low trigger point for Auto XON/XOFF
  875. mntrg2    equ    384        ;[19a] High trigger point for Auto XON/XOFF
  876.  
  877. floctl    db    1        ;[19a] If floctl=floxon do Auto XON/XOFF logic
  878. xofsnt    db    0        ;[19a] set if XOFF was sent
  879. xofrcv    db    0        ;[19a] set if XOFF was recieved
  880. ;
  881. ;  a small stack for interrupt handling
  882. ;
  883.     rw    64        ;Interrupt stack        ;[28e]
  884. mnstk    dw    0        ;bottom of stack        ;[28e]
  885.  
  886.     CSEG $
  887.  
  888. ; ===========================================================================
  889. ;
  890. ;                             UTILITY ROUTINES
  891. ;
  892. ; ===========================================================================
  893. ;
  894. ; INTERNAL ROUTINE MSWAIT - Delay for AL milliseconds
  895. ;
  896. mswait:                ;                [34] start
  897.     mov    cx,5*clckrt    ; inner loop count for 1 millisec.
  898. mswai1:
  899.     sub    cx,1        ;** inner loop takes 20 clock cycles
  900.     jnz    mswai1        ;**
  901.     dec    ax        ; outer loop counter
  902.     jnz    mswait        ; wait another millisecond
  903.     ret            ;                [34] end
  904.  
  905.  
  906. ;
  907. ; INTERNAL ROUTINE DISPATCH
  908. ;
  909. ;    Function    Redispatch processor.
  910. ;
  911. ;    Inputs        None.
  912. ;
  913. ;    Outputs        None.
  914. ;
  915. ;    Side effects    Processor is redispatched.
  916. ;            All registers preserved.
  917. ;
  918. dispatch:
  919.     push    ax
  920.     push    bx
  921.     push    cx
  922.     mov    cl, p_dispatch
  923.     int    bdos
  924.     pop    cx
  925.     pop    bx
  926.     pop    ax
  927.     ret
  928.  
  929.  
  930. ; ===========================================================================
  931. ;
  932. ;                        SCREEN CONTROL ROUTINES
  933. ;
  934. ; ===========================================================================
  935. ;
  936. ; INTERFACE ROUTINE POSCUR - positions cursor to row and col (each 1 byte)
  937. ;                            pointed to by dx.
  938. ;
  939.  
  940. poscur:    
  941.     mov    bx, dx        ;Do cursor positioning.
  942.     mov    dx, offset scrpos    ;Print cursor positioning string.
  943.     call    tmsg
  944.     mov    al, [bx]    ;Get row value
  945.     add    ax, 1Fh        ;Convert to ASCII
  946.     mov    dl,al
  947.     push    bx        ;(Gets clobbered by bout)
  948.     call    bout
  949.     pop    bx
  950.     mov    al, 1[bx]    ;Do same for column value
  951.     add    ax, 1Fh
  952.     mov    dl,al
  953.     call    bout
  954.     ret
  955.  
  956. ;
  957. ; INTERFACE ROUTINE CLRSCR - homes cursor and clears screen.
  958. ;
  959.  
  960. clrscr:    mov    dx, offset scrcls
  961.     call    tmsg
  962.     ret
  963. ;
  964. ; INTERFACE ROUTINE CLRLIN - clears line.
  965. ;
  966.  
  967. clrlin:    mov    dl, cr        ;Go to beginning of line
  968.     call    bout
  969. ;
  970. ;    ...FALL THROUGH
  971. ;
  972. ;  INTERFACE ROUTINE CLREOL - clear to end of line
  973. ;
  974.  
  975. clreol:    mov    dx, offset scrclr ;Clear from cursor to end of line
  976.     call    tmsg
  977.     ret
  978.  
  979. ;
  980. ; INTERFACE ROUTINE REVON - turns on reverse video display
  981. ;
  982.  
  983. revon:    mov    dx, offset scrron
  984.     call    tmsg
  985.     ret
  986.  
  987. ;
  988. ; INTERFACE ROUTINE REVOFF - turns off reverse video display
  989. ;
  990.  
  991. revoff:    mov    dx, offset scrrof
  992.     call    tmsg
  993.     ret
  994. ;
  995. ; INTERFACE ROUTINE BLDON - turns on bold (highlighted) display
  996. ;
  997.  
  998. bldon:    mov    dx, offset scrbon
  999.     call    tmsg
  1000.     ret
  1001. ;
  1002. ; INTERFACE ROUTINE BLDOFF - turns off bold (highlighted) display
  1003. ;
  1004.  
  1005. bldoff:    mov    dx, offset scrbof
  1006.     call    tmsg
  1007.     ret
  1008.  
  1009.  
  1010.     DSEG $
  1011.  
  1012. scrpos    db    esc, 'Y$'    ;Position cursor to row and column
  1013. scrcls    db    esc, 'E$'    ;Home cursor and clear screen
  1014. scrclr    db    esc, 'K$'    ;Clear from cursor to end of line
  1015. scrron    db    esc, 'p$'    ;Turn on reverse video
  1016. scrrof    db    esc, 'q$'    ;Turn off reverse video
  1017. scrbon    db    esc, 'm$'    ; Bold on (Actually underline).
  1018. scrbof    db    esc, 'n$'    ; Bold off
  1019.  
  1020.     CSEG $
  1021. ;
  1022. ; INTERFACE ROUTINE DOTAB - do tab expansion if necessary
  1023. ;
  1024. dotab:    jmp    rskp        ; assume h/w does it for now
  1025.  
  1026. ;
  1027. ;  Assorted textual constants required as part of the machine interface
  1028. ;
  1029.     DSEG $
  1030.  
  1031. delstr  db    esc,'D ',esc,'D$'    ;Delete string.
  1032. system    db    '  Future Computers FX20/FX30 (TC - Oct 85)$'
  1033.  
  1034.     CSEG $
  1035. ;
  1036. ; ENDSYSDEP
  1037. ;
  1038.