home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / a / cpxbee.asm < prev    next >
Assembly Source File  |  2020-01-01  |  21KB  |  997 lines

  1. IF NOT lasm
  2. .printx * CPXBEE.ASM *
  3. ENDIF    ;NOT lasm
  4. ;       KERMIT - (Celtic for "FREE")
  5. ;
  6. ;       This is the CP/M-80 implementation of the Columbia University
  7. ;       KERMIT file transfer protocol.
  8. ;
  9. ;       Version 4.09
  10. ;
  11. ;       Copyright June 1981,1982,1983,1984,1985
  12. ;       Columbia University
  13. ;
  14. ; Originally written by Bill Catchings of the Columbia University Center for
  15. ; Computing Activities, 612 W. 115th St., New York, NY 10025.
  16. ;
  17. ; Contributions by Frank da Cruz, Daphne Tzoar, Bernie Eiben,
  18. ; Bruce Tanner, Nick Bush, Greg Small, Kimmo Laaksonen, Jeff Damens, and many
  19. ; others.
  20. ;
  21. ;
  22. ;
  23. ; revision history:
  24. ;
  25. ; edit 1,  1st September 1990 
  26. ;    Original version by Russell Lang <rjl@monu1.cc.monash.edu.au>
  27. ;       The 'microbee' is designed and manufactured in Australia
  28. ;       by Microbee Systems Ltd (previously Applied Technology).
  29. ;    The microprocessor is a Z80 at 3.375MHz.
  30. ;    The video screen is memory mapped from 0F000h to 0F7FFh, 
  31. ;    with Programmable Characters 80-FF from 0F800h to 0FFFFh.  
  32. ;    The serial and parallel ports are implemented using a Z80 PIO.
  33. ;    The early model microbees were ROM-Basic computers with up
  34. ;    to 32k of battery backed RAM.  Later models dropped the
  35. ;    ROM-Basic and added disk drives and CP/M.  The disk systems
  36. ;    include the 56k (64k) APC (5.25" drives), 64k Computer-In-A-Book 
  37. ;    (3.5"), 128k Dynamic (5.25" or 3.5"), 256TC (3.5").
  38. ;    
  39. ;    This version of kermit was developed on a 56k APC.
  40. ;    It has been tested on 56k, 64k, 128k and 256k Microbees.
  41. ;
  42. ;     The serial port is implemented in software NOT hardware.
  43. ;    A special transmit routine allows simultaneous receiving
  44. ;    for all speeds except 75/1200, 1200/75, 4800, 9600.
  45. ;    The receive routine is interrupt driven with a 2 kbyte buffer.
  46. ;    The 9600 bit/s speed is marginal on receive - if the transmitter
  47. ;    is slightly fast (more than about 1%), the serial routine will 
  48. ;    not have enough time to put the character in the buffer before 
  49. ;    the next character arrives.
  50.  
  51.  
  52. ;
  53. ;         *** MAIN CODE START ***
  54. ;
  55. ;
  56. ; Keep module name, edit number, and last revision date in memory.
  57.  
  58. sysedt: db      'CPXSYS.ASM (35) 01-Dec-86$'
  59. family: db    'CPXBEE.ASM (1)  01-Sep-90$'
  60.  
  61.  
  62. ; Assembly time message announcing which version we're building
  63.  
  64. .printx * Assembling Microbee Kermit-80 *
  65.  
  66. z80    EQU    TRUE    ; They all use Z80s
  67.  
  68. defesc  EQU     ']'-100O        ;The default escape character for Microbee
  69.  
  70. vtval    EQU    0    ; use default emulation which is adm3a superset
  71.  
  72. ;
  73. sysxin:        ;continuation of system initialisation code
  74.     ; set up baud rate
  75.     lxi    h,t300
  76.     shld    speed
  77.     xchg
  78.     call    setbaud
  79.     ; change the interrupt vector so that we intercept rs232 input
  80.     db    0EDh,57h    ;ld    a,i    ;get old interrupt reg
  81.     sta    oldint
  82.     mvi    a,int        ;new value
  83.     db    0EDh,47h    ;ld    i,a
  84.         ret                     ; return from system-dependent routine
  85.  
  86.  
  87. ;
  88. ; sysexit - System-dependent termination processing
  89. ;         if we've changed anything, this is our last
  90. ;        chance to put it back.
  91. ;
  92. sysexit:
  93.     lda    oldint          ;restore old interrupt reg
  94.     db    0EDh,47h    ;ld    i,a
  95.         ret
  96.  
  97. ;
  98. ; syscon - System-dependent processing for start
  99. ;       of CONNECT command.
  100. ;
  101. syscon:
  102.     lxi    d,conmsg
  103.     call    prtstr
  104.         ret
  105.  
  106. conmsg:         ; Messages printed when entering transparent (CONNECT) mode:
  107.     db    cr,lf,'$'
  108. ;
  109. ; syscls - system-dependent close routine
  110. ;          called when exiting transparent session.
  111. ;
  112. syscls:
  113.         ret
  114. ;
  115. ; sysinh - help for system-dependent special functions.
  116. ;          called in response to <escape>?, after listing
  117. ;          all the system-independent escape sequences.
  118. ;
  119. sysinh:
  120.         lxi     d,inhlps        ; we got options...
  121.         call    prtstr          ; print them.
  122.         ret
  123.  
  124.  
  125. ; additional, system-dependent help for transparent mode
  126. ; (two-character escape sequences)
  127. inhlps:
  128.         db      cr,lf,'B  Transmit a BREAK (0.3s)'
  129.     db    cr,lf,'L  Transmit a LONG BREAK (1.8s)'
  130.     db    cr,lf,'W  Wipe screen clear'
  131.     db    '$'
  132.  
  133. ; sysint - system dependent special functions
  134. ;          called when transparent escape character has been typed;
  135. ;          the second character of the sequence is in A (and in B).
  136. ;          returns:-
  137. ;                non-skip: sequence has been processed
  138. ;                skip    : sequence was not recognized
  139. ;
  140. sysint: ani     137O            ; convert lower case to upper, for testing...
  141.         cpi     'B'             ; send break ?
  142.         jz      sendbr          ; then jump to send break routine
  143.     cpi    'L'        ; long break ?
  144.     jz    longbr        ; then jump to long break routine
  145.     cpi    'W'        ; clear screen ?
  146.     jz    clrtop        ; then jump to clear screen routine
  147.         jmp     rskp            ; take skip return - command not recognized.
  148.  
  149. ;
  150. ; Break routines
  151. ;
  152. longbr:
  153.     mvi    e,180        ; time for long break is 1800 ms
  154.     jmp    setbit
  155.  
  156. sendbr:
  157.     mvi    e,30        ; time for break is 300 ms
  158.  
  159. setbit:    
  160.     in    portb
  161.     ani    0dfh        ; mask with tx bit
  162.     out     portb
  163. ;
  164. ;       Now, delay for duration of hangup or break
  165.         mov     a,e        ; delay count
  166.         call    delay
  167. ;
  168. ;       Time's up. Put transmitter back in normal state and return.
  169.     in    portb
  170.     ori    20h        ; mask with tx bit
  171.     out     portb
  172.         ret                     ; done.
  173.  
  174. ; sysflt - system-dependent filter
  175. ;          called with character in E.
  176. ;          if this character should not be printed, return with A = zero.
  177. ;          preserves bc, de, hl.
  178. ;          note: <xon>,<xoff>,<del>, and <nul> are always discarded.
  179. ;
  180. sysflt:
  181.         mov     a,e             ; get character for testing
  182.     ret
  183.  
  184. ;
  185. ; sysbye - system-dependent processing for BYE command.
  186. ;
  187. sysbye:
  188.         ret
  189.  
  190. ;
  191. ; This is the system-dependent command to change the baud rate.
  192. ; DE contains the two-byte value from the baud rate table; this
  193. ; value is also stored in 'speed'.
  194. ;
  195. sysspd:
  196.     call    setbaud
  197.     ret
  198.  
  199. ;
  200. ;       Speed tables
  201. ; (Note that speed tables MUST be in alphabetical order for later
  202. ; lookup procedures, and must begin with a value showing the total
  203. ; number of entries.  The speed help tables are just for us poor
  204. ; humans.
  205.  
  206. ;       db      string length,string,divisor (2 identical bytes or 1 word)
  207. ; [Toad Hall]
  208.  
  209. spdtbl:    db    11            ;11 entries
  210.     db    03h,'110$'
  211.     dw    t110
  212.     db    04h,'1200$'
  213.     dw    t1200
  214.     db    07h,'1200/75$'
  215.     dw    t1275
  216.     db    03h,'150$'
  217.     dw    t150
  218.     db    04h,'2400$'
  219.     dw    t2400
  220.     db    03h,'300$'
  221.     dw    t300
  222.     db    04h,'4800$'
  223.     dw    t4800
  224.     db    03h,'600$'
  225.     dw    t600
  226.     db    02h,'75$'
  227.     dw    t75
  228.     db    07h,'75/1200$'
  229.     dw    t7512
  230.     db    04h,'9600$'
  231.     dw    t9600
  232.  
  233. sphtbl:    db    cr,lf,'75  75/1200  110  150  300  600  1200  1200/75'
  234.     db    ' 2400 4800 9600$'
  235.  
  236.  
  237. ;
  238. ;    This is the system-dependent SET PORT command.
  239. sysprt:
  240.     ret
  241.  
  242. prttbl    equ    0        ; SET PORT is not supported
  243. prhtbl    equ    0
  244.  
  245.  
  246. ;
  247. ; selmdm - select modem port
  248. ; selcon - select console port
  249. ; selmdm is called before using inpmdm or outmdm;
  250. ; selcon is called before using inpcon or outcon.
  251. ; preserves BC, DE, HL.
  252. ;
  253. selmdm:
  254. selcon:
  255.         ret
  256. ;
  257. ; Get character from console, or return zero.
  258. ; result is returned in A.  destroys bc, de, hl.
  259. ;
  260. inpcon:
  261.         mvi     c,dconio        ;Direct console I/O BDOS call.
  262.         mvi     e,0FFH          ;Input.
  263.         call    BDOS
  264.         ret
  265. ;
  266. ;
  267. ;       Output character in E to the console.
  268. ;       destroys bc, de, hl
  269. ;
  270. outcon:
  271.  
  272.         mvi     c,dconio        ;Console output bdos call.
  273.         call    bdos            ;Output the char to the console.
  274.         ret
  275.  
  276.  
  277.  
  278. ;
  279. ;
  280. ;       outmdm - output a char from E to the modem.
  281. ;               the parity bit has been set as necessary.
  282. ;       returns nonskip; bc, de, hl preserved.
  283. outmdm:
  284. ;
  285.     push    psw
  286.     push    b
  287.     push    d
  288.     push    h
  289.     mov    a,e
  290.     lxi    h,outm2    ; return address
  291.     push    h
  292.     lhld    txcall
  293.     pchl        ; send to rs232 port
  294. outm2:    pop    h
  295.     pop    d
  296.     pop    b
  297.     pop    psw
  298.     ret
  299.  
  300.  
  301. ;
  302. ;       get character from modem; return zero if none available.
  303. ;       bc, de, hl preserved.
  304. inpmdm:
  305.     call    rsin    ; get char if available
  306.     ret            ; return with character in A
  307.  
  308.  
  309. ;
  310. ;       flsmdm - flush comm line.
  311. ;       Modem is selected.
  312. ;       Currently, just gets characters until none are available.
  313. flsmdm: call    inpmdm          ; Try to get a character
  314.         ora     a               ; Got one?
  315.         jnz     flsmdm          ; If so, try for another
  316.         ret                     ; Receiver is drained.  Return.
  317.  
  318. ;
  319. ;       lptstat - get the printer status. Return a=0 if ok, or 0ffh if not.
  320. lptstat:
  321.     lda    pflag
  322.         ret
  323.  
  324. ;
  325. ;       outlpt - output character in E to printer
  326. ;       console is selected.
  327. ;       preserves de.
  328. outlpt:
  329.         push    d               ; save DE in either case
  330.         ana     a               ; if A = 0 do nothing,
  331.         jz      outlp1          ; [30] if a=0 do nothing
  332.     mov    a,e
  333.     call    parout
  334. outlp1: pop     d               ; restore saved register pair
  335.         ret
  336.  
  337.  
  338. ;
  339. ;
  340. ;       Screen manipulation routines
  341. ;       csrpos - move to row B, column C
  342. ;
  343. ;       csrpos for terminals that use a leadin sequence followed
  344. ;        by (row + 31.) and (column + 31.)
  345. ;
  346. csrpos: push    b               ; save coordinates
  347.         lxi     d,curldn        ; get cursor leadin sequence
  348.         call    prtstr          ; print it
  349.         pop     h               ; restore coordinates
  350.         mov     a,h             ; get row
  351.         adi     (' '-1)         ; space is row one
  352.         mov     e,a
  353.         push    h
  354.         call    outcon          ; output row
  355.         pop     h
  356.         mov     a,l             ; get column
  357.         adi     (' '-1)         ; space is column one
  358.         mov     e,a
  359.         jmp     outcon          ; output it and return
  360.  
  361. ;
  362. ; delchr - make delete look like a backspace.  Unless delete is a
  363. ;          printing character, we just need to print a backspace
  364. ;          (we'll output clrsp afterwards)
  365. delchr:
  366.         lxi     d,delstr
  367.         jmp     prtstr
  368.  
  369.  
  370. ; erase the character at the current cursor position
  371. clrspc: mvi     e,' '
  372.         call    outcon
  373.         mvi     e,bs            ;get a backspace
  374.         jmp     outcon
  375.  
  376. ; erase the current line
  377. clrlin: lxi     d,eralin
  378.         jmp     prtstr
  379.  
  380. ; erase the whole screen, and go home
  381. clrtop: lxi     d,erascr
  382.         jmp     prtstr
  383.  
  384.  
  385. sysver:    db    'Microbee$'
  386. outlin:    db    1AH,cr,lf,tab,'$'    ;(Clear screen, home cursor)
  387. erascr:    db    1AH,'$'            ;Clear screen and go home.
  388. eralin:    db    cr,esc,'T$'        ;Clear line.
  389. delstr:    db    bs,'$'            ; Adjust for delete
  390. curldn:    db    esc,'=$'        ;Cursor lead-in
  391. ttab:                    ;Table start location.
  392. ta:    db    ('K'-100O),'$',0,0    ;Cursor up.
  393. tb:    db    12O,'$',0,0        ;Cursor down.
  394. tc:    db    ('L'-100O),'$',0,0    ;Cursor right.
  395. td:    db    bs,'$',0,0        ;Cursor left.
  396. te:    db    subt,'$',0,0        ;Clear screen.
  397. tf:    db    '$',0,0,0        ;(can't) Enter graphics mode
  398. tg:    db    '$',0,0,0        ;(can't) Exit graphics mode
  399. th:    db    ('^'-100O),'$',0,0    ;Cursor home.
  400. ti:    db    ('K'-100O),'$',0,0    ;Reverse linefeed.
  401. tj:    db    esc,'Y$',0        ;Clear to end of screen.
  402. tk:    db    esc,'T$',0        ;Clear to end of line.
  403.  
  404.  
  405. ;Microbee software serial port routines
  406. porta    equ    0
  407. portb    equ    2
  408.  
  409.  
  410. ; interrupt vectors
  411. ; We change the Z80 Interrupt register to point to these vectors.
  412. ; Instead of trying to identify a particular Microbee system, 
  413. ; we just put vectors here for all systems.
  414. ;
  415. ; known vectors are:
  416. ;  48h : 56k (64k apc) - tested 19-Jun-1990
  417. ;  48k : 64k           - tested 01-Sep-1990
  418. ;  50h : dreamdisk (3rd party disk for Microbee)
  419. ;  e0h : 128k          - tested 19-Jun-1990
  420. ;  e0h : 256k          - tested 01-Sep-1990
  421.  
  422.     org    ($ and 0ff00h) + 100h
  423. int    equ    $/256    ; byte for interrupt register
  424.  
  425.     dw    inta    ; printer vector
  426.     dw    intb    ; rs232 vector
  427.     dw    inta
  428.     dw    intb
  429.     dw    inta
  430.     dw    intb
  431.     dw    inta
  432.     dw    intb
  433.     dw    inta
  434.     dw    intb
  435.     dw    inta
  436.     dw    intb
  437.     dw    inta
  438.     dw    intb
  439.     dw    inta
  440.     dw    intb
  441.     dw    inta
  442.     dw    intb
  443.     dw    inta
  444.     dw    intb
  445.     dw    inta
  446.     dw    intb
  447.     dw    inta
  448.     dw    intb
  449.     dw    inta
  450.     dw    intb
  451.     dw    inta
  452.     dw    intb
  453.     dw    inta
  454.     dw    intb
  455.     dw    inta
  456.     dw    intb
  457.     dw    inta
  458.     dw    intb
  459.     dw    inta
  460.     dw    intb
  461.     dw    inta
  462.     dw    intb
  463.     dw    inta
  464.     dw    intb
  465.     dw    inta
  466.     dw    intb
  467.     dw    inta
  468.     dw    intb
  469.     dw    inta
  470.     dw    intb
  471.     dw    inta
  472.     dw    intb
  473.     dw    inta
  474.     dw    intb
  475.     dw    inta
  476.     dw    intb
  477.     dw    inta
  478.     dw    intb
  479.     dw    inta
  480.     dw    intb
  481.     dw    inta
  482.     dw    intb
  483.     dw    inta
  484.     dw    intb
  485.     dw    inta
  486.     dw    intb
  487.     dw    inta
  488.     dw    intb
  489.     dw    inta
  490.     dw    intb
  491.     dw    inta
  492.     dw    intb
  493.     dw    inta
  494.     dw    intb
  495.     dw    inta
  496.     dw    intb
  497.     dw    inta
  498.     dw    intb
  499.     dw    inta
  500.     dw    intb
  501.     dw    inta
  502.     dw    intb
  503.     dw    inta
  504.     dw    intb
  505.     dw    inta
  506.     dw    intb
  507.     dw    inta
  508.     dw    intb
  509.     dw    inta
  510.     dw    intb
  511.     dw    inta
  512.     dw    intb
  513.     dw    inta
  514.     dw    intb
  515.     dw    inta
  516.     dw    intb
  517.     dw    inta
  518.     dw    intb
  519.     dw    inta
  520.     dw    intb
  521.     dw    inta
  522.     dw    intb
  523.     dw    inta
  524.     dw    intb
  525.     dw    inta
  526.     dw    intb
  527.     dw    inta
  528.     dw    intb
  529.     dw    inta
  530.     dw    intb
  531.     dw    inta
  532.     dw    intb
  533.     dw    inta
  534.     dw    intb
  535.     dw    inta
  536.     dw    intb
  537.     dw    inta
  538.     dw    intb
  539.     dw    inta
  540.     dw    intb
  541.     dw    inta
  542.     dw    intb
  543.     dw    inta
  544.     dw    intb
  545.     dw    inta
  546.     dw    intb
  547.     dw    inta
  548.     dw    intb
  549.     dw    inta
  550.     dw    intb
  551.     dw    inta
  552.     dw    intb
  553.     
  554.  
  555. ; tables for baud rates
  556. t75:    db    124,13    ; full delay
  557.     db    55,7    ; semi delay
  558.     db    168,255    ; txrx delay
  559.     dw    trout    ; address of subroutine to transmit char
  560. t7512:    db    124,13    ; 75R/1200T
  561.     db    55,7
  562.     db    194,1    ; txout delay
  563.     dw    txout
  564. t110:    db    129,9
  565.     db    55,5
  566.     db    5,217    
  567.     dw    trout
  568. t150:    db    59,7
  569.     db    23,4
  570.     db    2,158
  571.     dw    trout
  572. t300:    db    26,4
  573.     db    134,2
  574.     db    3,75
  575.     dw    trout
  576. t600:    db    139,2
  577.     db    191,1
  578.     db    2,34
  579.     dw    trout
  580. t1200:    db    195,1
  581.     db    90,1
  582.     db    3,13
  583.     dw    trout
  584. t1275:    db    195,1    ; 1200R/75T
  585.     db    90,1
  586.     db    124,13
  587.     dw    txout
  588. t2400:    db    94,1
  589.     db    40,1
  590.     db    2,3
  591.     dw    trout
  592. t4800:    db    44,1
  593.     db    15,1
  594.     db    44,1
  595.     dw    txout
  596. t9600:    db    19,1
  597.     db    1,1
  598.     db    19,1
  599.     dw    txout
  600.  
  601.  
  602. ; copy table entries to locations used by serial routines
  603. setbaud:
  604.     lxi    h,fulldel
  605.     mvi    b,8
  606. setb2:    ldax    d
  607.     mov    m,a
  608.     inx    h
  609.     inx    d
  610.     dcr    b
  611.     jnz    setb2
  612.     ret
  613.  
  614.  
  615. ;transmit character in E
  616. ; destroys all regs
  617. txout:    mvi    b,ntotal    ;total number of bits to send
  618.     di
  619.     in    portb        ;c = portb with tx bit zeroed
  620.     ani    0dfh
  621.     mov    c,a
  622.     ora    a        ;carry=0 (start bit)
  623. txout2:    mov    a,c        ; 4T
  624.     jnc    txout4        ;10T skip if space
  625.     ori    20h        ; 3T (average)   set mark
  626. txout4:    out    portb        ;11T
  627.     lhld    txrxdel        ;16T
  628. txout6:    dcr    l        ;delay
  629.     jnz    txout6
  630.     dcr    h
  631.     jnz    txout6        ;  14*L + 14*H + 3584*(H-1)
  632.     stc            ; 4T carry=1 (stop bit)
  633.     mov    a,e        ; 4T shift next bit to carry
  634.     rar            ; 4T
  635.     mov    e,a        ; 4T
  636.     dcr    b        ; 4T
  637.     jnz    txout2        ;10T
  638.                 ;loop = 74T + (delay loop)
  639.     ei
  640.     ret
  641.  
  642.     
  643. ;
  644. ;transmit character in E
  645. ;simultaneous receive char if necessary
  646. trout:    mov    a,e
  647.     mvi    b,ndata
  648.     lxi    h,0
  649. tro2:    rrc        ;shift tx char to hl
  650.     mov    c,a
  651.     mov    a,l
  652.     ral
  653.     mov    l,a
  654.     mov    a,h
  655.     ral
  656.     mov    h,a
  657.     mov    a,c    ;recover
  658.     dcr    b
  659.     jnz    tro2
  660. tro10:    mvi    b,tqfudge ;adjust char in hl to align with
  661.               ;tx bit of portb
  662. tro12:    stc        ; pad out
  663.     mov    a,l
  664.     ral
  665.     mov    l,a
  666.     mov    a,h
  667.     ral
  668.     mov    h,a
  669.     dcr    b
  670.     jnz    tro12
  671.     mvi    a,0ffh    ;flag to say we are not receiving
  672.     sta    trtemp    ;save it
  673.     mvi    d,tqbit    ;total number of qtr bits to send
  674.     in    portb    ;b = portb with tx bit zeroed
  675.     ani    0dfh
  676.     mov    b,a
  677.     mvi    e,0    ;we are not receiving yet
  678. tro14:    in    portb
  679.     ori    8h    ;test CTS
  680.     jz    tro14    ;loop till Clear To Send
  681.     out    09h    ;Color Wait OFF
  682.     di
  683.     call    qbit
  684.     lda    trtemp    ;are we receiving
  685.     ora    a
  686.     jnz    tro22    ;skip if not
  687.     in    portb    ;is last bit a mark?
  688.     ori    10h
  689.     jz    tro18    ;skip if mark (don't wait for stop)
  690.     lhld    fulldel ;delay to stop bit
  691. tro16:    dcr    l
  692.     jnz    tro16
  693.     dcr    h
  694.     jnz    tro16
  695. tro18:    lhld    wptr        ; check buffer
  696.     xchg
  697.     lhld    rptr
  698.     dcx    d        ; decrement queue pointer
  699.     mov    a,d
  700.     ora    e
  701.     jnz    tro20        ; skip if no queue wrap around
  702.     lxi    d,maxque-1    ; wrap around
  703. tro20:    mov    a,l        ; sub hl,de
  704.     sub    e
  705.     mov    l,a
  706.     mov    a,h
  707.     sbb    d
  708.     mov    h,a
  709.     ora    l        ; check for zero
  710.     jz    tro22        ; skip if buffer full
  711.     xchg
  712.     shld    wptr        ; update queue
  713.     lxi     d,rqueue
  714.     dad    d
  715.     mov    m,c        ; put char in queue
  716. tro22:    ei
  717.     ret            ;ret
  718.  
  719.  
  720. ; routine for quarter bit timing
  721. ; for transmit and simultaneous receive
  722. ; total execution time is 223T + L*14T + H*34T
  723. qbit:    call    txrx    ;17T + 162T
  724.     lda    txrxdel    ;13T
  725. qbit2:    dcr    a    ; 4T
  726.     jnz    qbit2    ;10T
  727.     lda   txrxdel+1 ;13T
  728. qbit4:    dcr    a    ; 4T
  729.     nop        ; 4T
  730.     nop        ; 4T
  731.     nop        ; 4T
  732.     nop        ; 4T
  733.     nop        ; 4T
  734.     jnz    qbit4    ;10T
  735.     mov    a,d    ; 4T Check if still sending or receiving
  736.     ora    e    ; 4T
  737.     jnz    qbit    ;10T
  738.     ret
  739.  
  740.  
  741. ;simultaneous transmit/receive
  742. ;do next quarter bit
  743. ; regs: b = portb with tx bit zeroed
  744. ;    c = character being received
  745. ;    d = number of qtr bits remaining to send
  746. ;    e = number of qtr bits remaining to receive (0 if not receiving)
  747. ;    hl = character being transmitted
  748. ;this subroutine always executes in 162T (or 163T)
  749. txrx:    mov    a,d    ; 4T qtr bits remaining to send
  750.     ora    a    ; 4T
  751.     jz    txrx12    ;10T skip if no bits remaining (may be receiving)
  752.     ani    03h    ; 7T a complete bit?
  753.     jnz    txrx10    ;10T skip if not
  754.     dad    h    ;11T shift tx bit to bit 5 of h
  755.     mov    a,h    ; 4T
  756.     ani    20h    ; 7T extract tx bit
  757.     ora    b    ; 4T combine with portb
  758.     out    portb    ;11T send it
  759. txrx2:    dcr    d    ; 4T one less qtr bit to send
  760.             ;76T total
  761. ;now receive part
  762. txrx4:    mov    a,e    ; 4T qtr bits remaining to receive
  763.     ora    a    ; 4T
  764.     jz    txrx16    ;10T skip if not receiving
  765.     ani    3h    ; 7T a complete bit?
  766.     jnz    txrx14    ;10T skip if not
  767.     in    portb    ;11T get input
  768.     ani    10h    ; 7T extract rx bit
  769.     sui    1    ; 7T bit to carry
  770.     mov    a,c    ; 4T bit to c
  771.     rar        ; 4T
  772.     mov    c,a    ; 4T
  773. txrx6:    dcr    e    ; 4T one less qtr bit to receive
  774. txrx8:    ret        ;10T
  775.             ;86T total
  776.  
  777. ;come here if transmitting, but not a complete bit
  778. ;delay to match up execution times
  779. txrx10:
  780.     ora    a    ; 4T
  781.     ora    a    ; 4T
  782.     ora    a    ; 4T
  783.     ora    a    ; 4T
  784.     ora    a    ; 4T
  785.     ori    00h    ; 7T
  786.     jmp    txrx2    ;10T
  787.  
  788. ;come here if not sending (but still receiving)
  789. ;delay to match up execution times
  790. txrx12:    ora    a    ; 4T
  791.     ora    a    ; 4T
  792.     ora    a    ; 4T
  793.     ora    a    ; 4T
  794.     ora    a    ; 4T
  795.     ora    a    ; 4T
  796.     ora    a    ; 4T
  797.     ora    a    ; 4T
  798.     ora    a    ; 4T
  799.     ora    a    ; 4T
  800.     ora    a    ; 4T
  801.     ora    a    ; 4T
  802.     jmp    txrx4    ;10T
  803.  
  804. ;come here if receiving (but not a complete bit)
  805. ;delay to match up execution time
  806. txrx14:    ora    a    ; 4T
  807.     ora    a    ; 4T
  808.     ora    a    ; 4T
  809.     ora    a    ; 4T
  810.     ora    a    ; 4T
  811.     ori    00h    ; 7T
  812.     jmp    txrx6    ;10T
  813.  
  814. ;come here if not receiving
  815. txrx16:    in    portb    ;11T check if start bit
  816.     ani    10h    ; 7T
  817.     jz    txrx18    ;10T skip if mark
  818.     mvi    e,rqbit ; 7T get quarter bit count for receive
  819.     xra    a    ; 4T
  820.     sta    trtemp    ;13T store flag to say we are receiving
  821.     ori    a    ; 7T delay (should be 6T)
  822.     ret        ;10T
  823.     
  824. txrx18:    ora    a    ; 4T
  825.     ora    a    ; 4T
  826.     ora    a    ; 4T
  827.     ora    a    ; 4T
  828.     ora    a    ; 4T
  829.     jmp    txrx8    ;10T
  830.  
  831.  
  832.  
  833.  
  834. ; RS232 input interrupt routine
  835. ; stores received character in queue
  836. ;                ;semi delay starts here
  837. intb:                ;20T (approx.) for interrupt
  838.     push    psw        ;11T
  839.     push    b        ;11T
  840.     push    d        ;11T
  841.     push    h        ;11T
  842.     in    portb        ;11T
  843.     ani    10h        ; 7T test input for start bit
  844.     jz    intb16        ;10T skip if no start bit.
  845.     out    09h        ;11T
  846.     lhld    semidel        ;16T half bit delay
  847. intb2:    dcr    l        ; 4T
  848.     jnz    intb2        ;10T  inner loop 14T*L
  849.     dcr    h        ; 4T
  850.     jnz    intb2        ;10T  outer loop (14*H + 256*14*(H-1))T
  851.     mvi    e,8        ; 6T number of data bits
  852.                 ;semi delay ends here (125T + delay loop)
  853.                 ;full delay starts here
  854. intb4:    lhld    fulldel        ;16T  full bit delay
  855. intb6:    dcr    l
  856.     jnz    intb6
  857.     dcr    h
  858.     jnz    intb6        ;  14*L + 14*H + 3584*(H-1)
  859.     in    portb        ;11T test input
  860.     ani    10h        ; 7T
  861.     sui    1        ; 7T input bit to carry
  862.     mov    a,c        ; 4T
  863.     rar            ; 4T
  864.     mov    c,a        ; 4T and then to C
  865.     dcr    e        ; 4T bit count
  866.     jnz    intb4        ;10T  loop till all data bits collected
  867.                 ;full delay ends here (67T + delay loop)
  868.     in    portb
  869.     ani    10h
  870.     jz    intb12        ; skip if mark
  871.     lhld    fulldel        ; wait for stop bit
  872. intb10:    dcr    l
  873.     jnz    intb10
  874.     dcr    h
  875.     jnz    intb10
  876. intb12:    lhld    wptr        ; check buffer
  877.     xchg
  878.     lhld    rptr
  879.     dcx    d        ; decrement queue pointer
  880.     mov    a,d
  881.     ora    e
  882.     jnz    intb14        ; skip if no queue wrap around
  883.     lxi    d,maxque-1    ; wrap around
  884. intb14:    mov    a,l        ; sub hl,de
  885.     sub    e
  886.     mov    l,a
  887.     mov    a,h
  888.     sbb    d
  889.     mov    h,a
  890.     ora    l        ; check for zero
  891.     jz    intb16        ; skip if buffer full
  892.     xchg
  893.     shld    wptr        ; update queue
  894.     lxi    d,rqueue
  895.     dad    d
  896.     mov    m,c        ; put char in queue
  897. intb16:    pop    h
  898.     pop    d
  899.     pop    b
  900.     pop    psw
  901.     ei
  902.     db    0EDh,4Dh    ;reti
  903.  
  904. ;
  905. ; get char from serial port buffer.
  906. ; exit:  A=char  or  Z if no char
  907. rsin:    push    d
  908.     push    h
  909.     lhld    rptr
  910.     xchg
  911.     lhld    wptr
  912.     mov    a,l        ;sub hl,de
  913.     sub    e
  914.     mov    l,a
  915.     mov    a,h
  916.     sbb    d
  917.     mov    h,a
  918.     ora    l        ;check for zero
  919.     jnz    rsi4        ;get char
  920. rsi2:    pop    h
  921.     pop    d
  922.     ret
  923.  
  924. rsi4:    push    psw
  925.      dcx    d        ; decrement queue pointer
  926.     mov    a,d
  927.     ora    e
  928.     jnz    rsi6        ; skip if no queue wrap around
  929.     lxi    d,maxque-1    ; wrap around
  930. rsi6:    pop    psw
  931.     xchg
  932.     shld    rptr
  933.     lxi    d,rqueue
  934.     dad    d
  935.     mov    e,m    ;get char from queue
  936.     ori    0ffh    ;set NZ
  937.     mov    a,e
  938.     jmp    rsi2
  939.  
  940. ; printer routines
  941.  
  942. inta:    sta    ptemp
  943.     mvi    a,0
  944.     sta    pflag
  945.     lda    ptemp
  946.     ei
  947.     db    0EDh,4Dh    ;reti
  948.  
  949. parout:    push    h
  950.     lxi    h,pflag
  951. par2:    db    0CBh,46h    ;bit    0,(hl)
  952.     jnz    par2
  953.     mvi    m,0ffh
  954.     out    porta
  955.     pop    h
  956.     ret
  957.  
  958. ; data storage
  959.  
  960. oldint:        db    0    ; storage for old i reg
  961. trtemp:        db    0
  962. ptemp:        db    0    ;temp storage used by inta interrupt
  963. pflag:        db    0    ;0ffh if waiting for printer. 00h if ready
  964.  
  965. ;receive queue pointers
  966. maxque        equ    2048    ; receiver queue size
  967. rptr:        dw    maxque-1
  968. wptr:        dw    maxque-1
  969.  
  970. ;transmit
  971. ndata    equ    8    ; 8 data bits
  972. nstrt    equ    1    ; 1 start bit
  973. nstop    equ    1    ; 1 stop bit
  974. ntotal    equ    nstrt+ndata+nstop
  975. rqbit    equ    4*(nstrt+ndata)        ;number of quarter bits to receive
  976. tqbit    equ    4*(nstrt+ndata+nstop)    ;number of quarter bits to transmit
  977. tqfudge    equ    13-nstrt-ndata
  978.  
  979. ;H=0 or L=0 behave as 256
  980. ;receive delays.
  981. fulldel:    dw    0    ; 3584(H-1) + 14H + 14L + 67 cycles
  982. semidel:    dw    0    ; 3584(H-1) + 14H + 14L + 125 cycles
  983. ;1/4 bit transmit and simultaneous tx/rx delay  34H + 14L + 223 cycles
  984. ;or full bit delay  3584(H-1) + 14H + 14L + 74 cycles
  985. txrxdel:    dw    0    ;
  986. txcall:        dw    trout    ; address of subroutine to transmit char
  987.  
  988. ; receiver queue
  989. rqueue:        ds    maxque
  990.  
  991.  
  992. ovlend    equ    $    ; End of overlay
  993.  
  994. IF lasm
  995.     END
  996. ENDIF
  997.