home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / unix / volume9 / zmac / part02 / serial.z < prev    next >
Text File  |  1987-03-11  |  19KB  |  748 lines

  1.  
  2. ; SCCS flags:        serial.z    1.8    9/21/82
  3.  
  4.  
  5. ;
  6. ; This program is a quick and dirty controller program
  7. ; for the simple Z80 serial interface card for the Red
  8. ; display controller.
  9. ;
  10. ; It uses two 256 byte buffers to buffer data to and from the
  11. ; host. This helps make up for the obnoxiously slow rs232.
  12. ;
  13. ; History:
  14. ; jrp    3-18-82    v1.0 Initial version by John Providenza.
  15. ;
  16. ; jrp    3-22-82    v1.1 Added code to send a Xon (Cntrlq) at reset
  17. ;        if the dip switch is set to Xon/Xoff mode.
  18. ;
  19. ; jrp    4-20-82    v1.2 Added SCCS flags as comment in header and
  20. ;        as a "ascii" block after a reset jmp.
  21. ;
  22. ; jrp    4-20-82    v1.3 Changed crt modem flags to RLSD = Out Buf Full,
  23. ;        RI = In Buf Full.
  24. ;
  25. ; jrp    4-21-82    v1.4 Added diagnostic code to test ram, switches, and
  26. ;        uart.
  27. ;
  28. ; jrp    4-30-82    v1.5 Cleaned up some code, added some more comments.
  29. ;
  30. ; jrp    5-27-82    v1.6 Fixed bug that caused output buffer to overflow
  31. ;        in Hex mode.
  32. ;
  33. ; jrp    6-22-82    v1.7 Added 'end of message' command in hex mode.
  34. ;        This is active only in hex mode and only if a
  35. ;        non 0 byte count is specified (0 is default)
  36. ;        'l' is used to specify byte count, 'm' specifies
  37. ;        the eom char. Both expect 2 hex digits following
  38. ;        to specify the apropriate parameter.
  39. ;
  40. ; jrp    8-23-82    v1.8 Added code to allow send/recv in different modes.
  41. ;        Thus the host can send in raw mode and receive in hex
  42. ;        mode, allowing CntrlS/Q flow control.
  43. ;        Also added 's' command in 'hex' mode to reset the SWTCH
  44. ;        settings.
  45. ;        Also added break detect to reset the mode/baud to the
  46. ;        switch settings.
  47. ;            switch    dIN    dOUT    Flow Control.
  48. ;            7 6 5
  49. ;            0 0 0    raw    raw    No flow control.
  50. ;            0 0 1    raw    hex    Xon/Xoff sent to host.
  51. ;            0 1 0    hex    raw    Xon/Xoff received from host.
  52. ;            0 1 1    hex    hex    Full Xon/Xoff.
  53. ;            1 0 0    raw    raw    Full modem flow control.
  54. ;            1 0 1    raw    hex    Full modem flow control.
  55. ;            1 1 0    hex    raw    Full modem flow control.
  56. ;            1 1 1    hex    hex    Full modem flow control.
  57. ;
  58. ; SCCS flags:    serial.z 1.8 9/21/82
  59.     eject    1
  60. ; Serial port equates.
  61. Serial    equ    00H    ; base address of 8250 controller.
  62. Ier    equ    01H    ; Interrupt Enable Reg
  63. Iir    equ    02H    ; Interrupt Ident Reg
  64. Lcr    equ    03H    ; Line Control Reg
  65. Mcr    equ    04H    ; Modem Control Reg
  66. Lsr    equ    05H    ; Line Status Reg
  67. Msr    equ    06H    ; Modem Status Reg
  68.  
  69. ; These equates define bits in the Msr.
  70. DsrIn    equ    05    ; Data Set Ready input
  71. CtsIn    equ    04    ; Clear to Send input
  72. InMt    equ    06    ; No data from display controller = 1 (Ring In)
  73. OutMt    equ    07    ; Crt ready for next byte = 1 (Rcvd Line Signal Detct)
  74.  
  75. ; These equates define bits in the Lsr
  76. DataRdy    equ    00    ; Input data ready.
  77. Break    equ    04    ; Break condition.
  78. XmitMt    equ    05    ; Xmitter buffer empty.
  79.  
  80. ; These equates define bits in the Mcr
  81. DtrOut    equ    00    ; Data terminal ready output.
  82. RtsOut    equ    01    ; Request to send output.
  83.  
  84. ; Misc definitions.
  85. Crt    equ    80H    ; Parallel port to display controller.
  86. Baud    equ    40H    ; Switches port.
  87. Stack    equ    0FFFFH
  88.  
  89. ; Mailbox equates.
  90. Head    equ    0
  91. Tail    equ    1
  92. Count    equ    2
  93. Base    equ    3
  94. Status    equ    4
  95. UnChar    equ    5    ; Should be used only for CntrlS and CntrlQ
  96.  
  97. ; Equates for the Queue status byte
  98. XmitOff    equ    00        ; xmitter is disabled.
  99.  
  100. ; Baud/Switch equates.
  101. Bmask    equ    0FH
  102. Rawout    equ    020H
  103. RObit    equ    5
  104. Rawin    equ    040H
  105. RIbit    equ    6
  106. Xon    equ    080H
  107. Xonbit    equ    7
  108.  
  109. ; Some ASCII character equates.
  110. CntrlS    equ    19        ; Xoff
  111. CntrlQ    equ    17        ; Xon
  112. Cr    equ    13        ; Carriage return.
  113.     eject    1
  114.     ORG    0FC00H
  115. RAM_START:
  116. ; Variable declarations
  117. ; Ram is in the top 1K of memory.
  118.  
  119. ; Queues.
  120. ; These are the actual data buffers. The only routine that should use
  121. ; these labels re INIT_V to set the mailbox data pointers up.
  122. ; All I/O is via GETQ and PUTQ routines.
  123. INBUF:    block    256        ; input buffer q.
  124. OUTBUF:    block    256        ; output buffer q.
  125.  
  126. UNUSED:    block    256        ; unused ram
  127.  
  128. ; Now the ram for variables and stack.
  129.  
  130. SWTCH:    block    1        ; Current baud/switches
  131.  
  132. ; Variable for the H_to_Q routine
  133. ; It holds the upper nibble of hex until the lower one arrives.
  134. ; Bit 0 = 1 for empty, 0 for upper nibble full.
  135. H_to_QV:    block    1
  136.  
  137. ; End of message variables.
  138. MESS_LEN:    block    1    ; How long messages are.
  139. MESS_CNT:    block    1    ; Number of chars in current message.
  140. EOM_CHAR:    block    1    ; The end of message char.
  141.  
  142.  
  143. ; In and Out queues variables.
  144. INBOX:    block    6
  145. OUTBOX:    block    6
  146.     eject    1
  147. ; Mainline loop.
  148.     ORG    0
  149.     JP    RESET        ; Jmp to the code
  150.                 ; Put in ID string
  151.     ascii    'serial.z 1.8'
  152. RESET:
  153.     LD    SP, Stack
  154.     CALL    CHECK        ; Check the hardware out.
  155.     CALL    INIT_HW        ; Init the hardware devices.
  156.     CALL    INIT_V        ; Init the variables.
  157.  
  158.     LD    IX,OUTBOX    ; Point to the outbox.
  159.     LD    A,(SWTCH)    ; Check if we're in Xon/Xoff mode.
  160.     AND    Xon
  161.     LD    A,Cntrlq    ; Send a Xon to host if we're in that mode
  162.     CALL    NZ,PUTQ
  163.  
  164. ; Now loop checking for data available from host or display controller.
  165. ; Also check if we can send data to them.
  166. LOOP:
  167.     IN    A,(Lsr)        ; Get the line status.
  168.     LD    C,A
  169.     IN    A,(Msr)        ; Get the modem status.
  170.     LD    B,A        ; and save it
  171.                 ; B = Msr, C = Lsr.
  172. ; Check for break condition.
  173.     BIT    Break,C        ; test the bit in the Lsr
  174.     JR    Z,LOOP1
  175.     CALL    SETBAUD        ; reset the SWTCH variable.
  176.     CALL    INIT_V        ; reset all the variables
  177.     JR    LOOP
  178. LOOP1:
  179.     CALL    HOST_IN
  180.     CALL    DISP_IN
  181.     CALL    DISP_OUT
  182.     CALL    HOST_OUT
  183.     JR    LOOP
  184.     eject    1
  185. ; Check if data is ready from host.
  186. HOST_IN:
  187.     BIT    DataRdy,C    ; Data ready?
  188.     RET    Z        ; Ret if no.
  189.                 ; Handle a byte from the Host.
  190.     LD    IX,INBOX    ; data will go into the Input Q.
  191.     LD    A,(SWTCH)    ; check for Raw or encoded mode.
  192.     LD    H,A
  193.     AND    Rawin        ; NZ for Raw mode
  194.     IN    A,(Serial)    ; get the data byte.
  195.     JR    Z,HEX_IN    ; Jmp if hex data in.
  196. RAW_IN:                ; Process Raw data
  197.     CALL    PUTQ
  198.     JP    STOP_IN        ; stop the input if needed.
  199. HEX_IN:
  200.     AND    7FH        ; Kill any parity bit.
  201.     CP    ' '        ; Printable ASCII?
  202.     JR    NC,PRINT    ; Jmp if yes
  203. ; Control character.
  204.     CP    Cr        ; Carriage Ret?
  205.     JR    NZ,IN_FLOW    ; Jp if no.
  206.     LD    A,1        ; Set the H_to_Q variable to empty.
  207.     LD    (H_to_QV),A    ; This flushes any partially assembled byte.
  208.     RET            ; Done
  209. ; Test for Xon/Xoff commands.
  210. IN_FLOW:
  211.     BIT    Xonbit,H    ; Are we sensitive to them?
  212.     RET    Z        ; Ret if no.
  213.     LD    HL,OUTBOX+Status    ; Get a pointer to our outbox status.
  214.     CP    CntrlS        ; Xoff our transmitter?
  215.     JR    NZ,NOT_XOFF    ; Jmp if no.
  216. OFF:
  217.     SET    XmitOff,(HL)
  218.     RET
  219. NOT_XOFF:
  220.     CP    CntrlQ        ; Xon our xmitter?
  221.     RET    NZ        ; ret if no.
  222. ON:
  223.     RES    XmitOff,(HL)
  224.     RET
  225. ; Printable char received from host.
  226. PRINT:                ; Printable character received in hex mode.
  227.     SET    5,A        ; Convert to lower case.
  228.     CP    'l'        ; Message length command?
  229.     JR    NZ,PRINT1    ; Jmp if no.
  230.     CALL    GET_HEX        ; Get byte from UART
  231.     LD    (MESS_LEN),A    ; Set the message length.
  232.     LD    (MESS_CNT),A    ; Reset the number of chars sent so far.
  233.     RET
  234. PRINT1:
  235.     CP    'm'        ; EOM char set command?
  236.     JR    NZ,PRINT2
  237.     CALL    GET_HEX        ; Get byte from UART
  238.     LD    (EOM_CHAR),A
  239.     RET
  240. PRINT2:
  241.     CP    's'        ; change SWTCH command?
  242.     JR    NZ,PRINT3
  243.     CALL    GET_HEX        ; Get byte from UART
  244.     CPL            ; Toggle them.
  245.     LD    (SWTCH),A
  246.     RET
  247. PRINT3:
  248.     CALL    H_to_Q        ; Pack the encoded data into bytes.
  249.     JP    STOP_IN        ; stop the input if needed.
  250.     eject    1
  251. ; Data ready from controller?
  252. DISP_IN:
  253.     BIT    InMt,B        ; data from controller?
  254.     RET    NZ        ; ret if no.
  255.     LD    IX,OUTBOX
  256.     LD    A,(IX+Count)    ; Get the Q count.
  257.     ADD    A,3        ; Check if Q has room for 3 more bytes.
  258.     RET    C        ; ret if no
  259.     LD    A,(SWTCH)    ; check if we need to encode the data.
  260.     AND    Rawout
  261.     IN    A,(Crt)        ; get the data from the crt.
  262.     JP    NZ,PUTQ        ; send the raw data and return.
  263. ; hex data out to host.
  264.     CALL    B_to_H        ; convert byte to hex format and stick in Q.
  265.                 ; Check if we need to stick an EOM char in.
  266.     LD    A,(MESS_LEN)    ; Get the length.
  267.     AND    A
  268.     RET    Z        ; Zero means no EOM character to be sent.
  269.     LD    HL,MESS_CNT    ; Point to the counter.
  270.     DEC    (HL)        ; Time to send a EOM char?
  271.     RET    NZ        ; Ret if no.
  272.     LD    (HL),A        ; reset the length.
  273.     LD    A,(EOM_CHAR)    ; Get the char and stick it in the Q.
  274.     JP    PUTQ        ; and return when done
  275.     eject    1
  276. ; Controller ready for data?
  277. DISP_OUT:
  278.     BIT    OutMt,B        ; controller ready for data?
  279.     RET    Z        ; Jmp if no
  280.     LD    IX,INBOX
  281.     CALL    GETQ        ; get a byte for controller.
  282.     RET    C        ; ret if no byte available.
  283.     OUT    (Crt),A        ; send char to display.
  284.     JP    STRT_IN        ; re-enable host xmitter if needed.
  285.     eject    1
  286. ; Host ready for data?
  287. HOST_OUT:
  288.     BIT    XmitMt,C    ; Uart xmitter empty?
  289.     RET    Z        ; ret if no.
  290.     LD    IX,OUTBOX    ; Get OutBox pointer.
  291.     LD    A,(SWTCH)    ; Check for Xon mode
  292.     AND    Xon
  293.     JR    NZ,H_O_Xon    ; Jp if Xon mode.
  294.     BIT    CtsIn,B        ; Clear to send?
  295.     RET    Z        ; ret if no.
  296.     JR    H_O_Send    ; We are clear to send.
  297. H_O_Xon:
  298.     LD    A,(OUTBOX+UnChar)
  299.     AND    A
  300.     JR    NZ,H_O_Send    ; Always send an 'UnChar'
  301.     BIT    XmitOff,(IX+Status)
  302.     RET    NZ        ; ret if xmitter is disabled.
  303. H_O_Send:
  304.     CALL    GETQ
  305.     RET    C        ; Ret if no character available.
  306.     OUT    (Serial),A
  307.     RET
  308.     eject    1
  309. ; Check the hardware out.
  310. ; Call this routine only after a external reset!!!!
  311.  
  312. CHECK:
  313. ; Check the baud switch (really crude).
  314.     IN    A,(BAUD)    ; Get the baud switch.
  315.     LD    B,A        ; Save it.
  316.     IN    A,(BAUD)
  317.     CP    B        ; Same as last time?
  318. BAD_B:    ; Switch ERROR - Can't read switches twice in a row.
  319.     JR    NZ,BAD_B    ; Loop if no.
  320. ; Check the ram.
  321. ; Write the complement of the low byte of address out to all ram,
  322. ; then check if it stayed the same.
  323. ; Note that this destroys all ram contents.
  324.     POP    DE        ; Save the return address in a register.
  325.     LD    HL,RAM_START    ; Get the first address of ram.
  326.     LD    B, NOT [RAM_START & 0FFH]
  327.     LD    C,B        ; Get complement of low address byte.
  328.                 ; Load the ram with the pattern.
  329. RAM1:
  330.     LD    (HL),B
  331.     DEC    B
  332.     INC    HL
  333.     LD    A,H        ; Test for done.
  334.     OR    L
  335.     JR    NZ,RAM1        ; Loop till all locations written.
  336.     LD    HL,RAM_START    ; Get the first address of ram.
  337. ; Check if ram agrees with what should be there.
  338. RAM2:
  339.     LD    A,(HL)        ; Get the byte.
  340.     XOR    C        ; Same as its low address byte?
  341.     JR    Z,RAM6        ; Jmp if yes.
  342. ; Ram error. We have three loops: low bad, high bad, both bad.
  343.     LD    B,A        ; Save the symptom.
  344.     AND    0FH        ; Low nibble bad?
  345. RAM3:    ; Ram ERROR - bad high nibble.
  346.     JR    Z,RAM3        ; Jmp if no.
  347.     LD    A,B        ; get the symptom back.
  348.     AND    0F0H        ; High nibble bad too?
  349. RAM4:    ; Ram ERROR - bad low nibble.
  350.     JR    Z,RAM4        ; Loop if error.
  351. RAM5:    ; Ram ERROR - both nibbles bad.
  352.     JR    RAM5
  353. RAM6:
  354.     DEC    C
  355.     INC    HL
  356.     LD    A,H        ; Done?
  357.     OR    L
  358.     JR    NZ,RAM2        ; Jmp if no.
  359.     PUSH    DE        ; Fix the stack back up.
  360. ; Check out the National Semi INS8250 Uart.
  361. ; Since we were reset, Lcr should be zero.
  362.     IN    A,(Lcr)        ; Get the Line Control reg
  363.     AND    A
  364. U0:    ; Uart ERROR - Lcr not reset properly.
  365.     JR    NZ,U0        ; Loop if error.
  366.     LD    A,80H
  367.     OUT    (Lcr),A        ; And set the Divisor access bit.
  368.     IN    A,(Lcr)        ; Check that it got set.
  369.     CP    80H        ; Still set?
  370. U1:    ; Uart ERROR - Lcr won't hold divisor access bit.
  371.     JR    NZ,U1        ; Loop if error.
  372.     LD    A,3        ; Try to set 38.4K baud
  373.     OUT    (Serial),A    ; Ld the divisor.
  374.     IN    A,(Serial)    ; Test that it loaded OK.
  375.     SUB    3        ; Check if same (also set A to zero)
  376. U2:    ; Uart ERROR - unexpected low divisor.
  377.     JR    NZ,U2        ; Loop if error.
  378.     OUT    (Ier),A        ; Set high byte to zero
  379.     IN    A,(Ier)
  380.     AND    A        ; Still zero?
  381. U3:    ; Uart ERROR - unexpected high divisor.
  382.     JR    NZ,U3        ; Loop if no (ie, error).
  383.     IN    A,(Lcr)        ; Get the Line reg back.
  384.     SUB    80H        ; Is it the same as before?
  385. U4:    ; Uart ERROR - unexpected Lcr value after setting divisor.
  386.     JR    NZ,U4        ; loop if error.
  387.     OUT    (Lcr),A        ; Turn off divisor access bit.
  388.     IN    A,(Lcr)        ; Check it.
  389.     AND    A
  390. U5:    ; Uart ERROR - Lcr won't reset after setting divisor.
  391.     JR    NZ,U5
  392.     LD    A,7
  393.     OUT    (Lcr),A        ; 8 bits, no parity, 2 stop bits
  394.     IN    A,(Lcr)
  395.     SUB    7        ; Test if the same (also set A to zero)
  396. U6:    ; Uart ERROR - Can't set proper operating Lcr.
  397.     JR    NZ,U6        ; If we succeed, assume Lcr is Ok.
  398.     OUT    (Ier),A        ; Disable all 8250 interrupt conditions (set to 0).
  399.     IN    A,(Ier)
  400.     AND    A
  401. U7:    ; Uart ERROR - Can't reset Ier.
  402.     JR    NZ,U7
  403.     RET
  404.     eject    1
  405. ; Init the hardware.
  406. INIT_HW:
  407.     CALL    SETBAUD        ; Set the Uart baud
  408.     LD    A,7
  409.     OUT    (Lcr),A        ; 8 bits, no parity, 2 stop bits
  410.     XOR    A        ; Disable all 8250 interrupt conditions.
  411.     OUT    (Ier),A
  412.     LD    A,3        ; Dtr, Rts on.
  413.     OUT    (Mcr),A
  414.  
  415. ; Perform the I/O diagnostic with the controller.
  416. ; Wait for data from controller, then echo it back.
  417. INITH1:
  418.     IN    A,(Msr)        ; Check if controller data ready.
  419.     BIT    InMt,A        ; Ready?
  420.     JR    NZ,INITH1    ; Jmp if no.
  421.     IN    A,(Crt)        ; Get the data.
  422.     OUT    (Crt),A        ; And send it back to controller.
  423.     RET
  424.  
  425.  
  426. ; Init the variables.
  427. INIT_V:
  428.     XOR    A        ; zero A
  429.  
  430. ; Init the Q's
  431.     LD    IX,INBOX    ; Init the inbox.
  432.     LD    (IX + Head),A
  433.     LD    (IX + Tail),A
  434.     LD    (IX + Count),A
  435.     LD    HL,INBUF
  436.     LD    (IX + Base),H
  437.     LD    (IX + Status),A
  438.     LD    (IX + UnChar),A
  439.  
  440.     LD    IX,OUTBOX    ; Init the outbox.
  441.     LD    (IX + Head),A
  442.     LD    (IX + Tail),A
  443.     LD    (IX + Count),A
  444.     LD    HL,OUTBUF
  445.     LD    (IX + Base),H
  446.     LD    (IX + Status),A
  447.     LD    (IX + UnChar),A
  448.  
  449. ; Init the H_to_Q variable.
  450.     LD    A,1
  451.     LD    (H_to_QV),A
  452.  
  453. ; init the 'end of message' stuff
  454.     LD    A,Cr        ; default r is a carriage return.
  455.     LD    (EOM_CHAR),A
  456.     XOR    A
  457.     LD    (MESS_LEN),A
  458.     LD    (MESS_CNT),A
  459.     RET
  460.     eject    1
  461. ; These routines handle the input and output queues.
  462. ; The Q pointer is passed in IX, result/source in A.
  463. ; Queues must be 256 bytes long. We use only 8 bit
  464. ; arithmetic for Q manipulation.
  465. ; A Q is defined as 6 bytes of status:
  466. ;    Tail    Offset for getting next char
  467. ;    Head    Offset for putting next char
  468. ;    Count    Number of chars in q
  469. ;    Base    High byte of the q origin
  470. ;    Status    Status of Q
  471. ;    UnChar    The 'un_get' char if non-zero
  472. ; and 256 bytes of storage.
  473. ;
  474.  
  475. GETQ:
  476. ; Get an element from the Q.
  477. ; entry    ix = Q pointer
  478. ; exit    a  = result
  479. ;    ca = set for empty Q, cleared for full Q.
  480. ;    bc & de are unchanged.
  481. ;    hl = garbage
  482. ;
  483.     LD    A,(IX + UnChar) ; Get the unget char
  484.     LD    (IX + UnChar),0    ; Set the byte to 0 (empty).
  485.     AND    A
  486.     RET    NZ        ; Ret if we got an unget char.
  487.                 ; A == 0 here.
  488.     CP    (IX + Count)    ; Get the q count
  489.     SCF
  490.     RET    Z        ; empty Q return (Count == 0).
  491.     DEC    (IX + Count)    ; one less item in the Q.
  492.     LD    L,(IX + Tail)    ; get a pointer to the element in the Q.
  493.     LD    H,(IX + Base)
  494.     INC    (IX + Tail)    ; bump the pointer to the next char.
  495.     OR    (HL)        ; Get the element, and clear the carry.
  496.     RET
  497.  
  498.  
  499. PUTQ:
  500. ; Routine to put a char in a Q.
  501. ;entry    ix = pointer to Q structure.
  502. ;    a = char to put.
  503. ;exit    hl = garbage
  504. ;    a, bc & de unchanged.
  505. ;    Ca = 1 for Q full, character discarded.
  506. ;
  507.     INC    (IX + Count)    ; Bump the Q count.
  508. QPUT_ERR:
  509.     JR    Z,QPUT_ERR
  510. QPUT1:
  511.     LD    H,(IX + Base)
  512.     LD    L,(IX + Head)
  513.     LD    (HL),A        ; Put the char in the Q
  514.     INC    (IX + Head)
  515.     AND    A        ; Clear the carry bit
  516.     RET
  517.     eject    1
  518. ; These routines pack and unpack bytes into Hex
  519. ; suitable for sending as ASCII over a serial line.
  520. ; H_to_Q takes Hex characters
  521. ; and packs them into 8 bit bytes to send to the display.
  522. ; B_to_H takes bytes from the display and converts them into
  523. ; the Hex character stream.
  524. ;
  525. ; Both routines use Q calls. IX must be set up with the proper
  526. ; Q address.
  527. ;
  528. ;
  529.  
  530.  
  531.  
  532. H_to_Q:
  533. ;
  534. ; entry    A    = Ascii Hex char (0-9, a-f)
  535. ;    IX    = Q pointer
  536. ; exit    A, Hl    = Garbage
  537. ;    bc, de    = unchanged.
  538. ;    Ca    = 1 if Q too full.
  539. ;
  540.     CALL    H_to_B        ; convert the character to binary.
  541.     LD    HL,H_to_QV    ; Point hl to our variable
  542.     BIT    0,(HL)        ; check if the upper nibble is full.
  543.     JR    Z,H_SEND    ; Jmp if yes.
  544.     ADD    A,A        ; Move the nibble to the high 4 bits.
  545.     ADD    A,A
  546.     ADD    A,A
  547.     ADD    A,A
  548.     LD    (HL),A        ; Save away the high nibble with low nibble = 0.
  549.     RET
  550. H_SEND:
  551.     OR    (HL)        ; Merge in the upper nibble from ram.
  552.     LD    (HL),1        ; Set the variable to empty.
  553.     JP    PUTQ        ; Send the byte and return.
  554.     eject    1
  555.  
  556.  
  557.  
  558. B_to_H:
  559. ; B_to_H takes the byte in A and splits it into two hex characters
  560. ; to be sent to the Q specified in IX.
  561. ;
  562. ; Entry    A    = byte of data to convert to Hex.
  563. ;    IX    = Q address.
  564. ; Exit    A E Hl    = garbage
  565. ;    D Bc Ix    = unchanged.
  566. ;
  567.  
  568.     LD    E,A        ; Save the byte
  569.     RRA            ; Move the upper nibble to low nibble.
  570.     RRA
  571.     RRA
  572.     RRA
  573.     AND    0Fh        ; Get only the upper nibble.
  574.     CP    10        ; 0 thru 9?
  575.     JR    C,B_to_H1    ; Jmp if yes.
  576.     ADD    A,'A'-'0'-10
  577. B_to_H1:
  578.     ADD    A,'0'
  579.     CALL    PUTQ
  580.     LD    A,E        ; Get the byte back
  581.     AND    0Fh        ; Mask for only low nibble.
  582.     CP    10        ; 0 thru 9?
  583.     JR    C,B_to_H2    ; Jmp if yes.
  584.     ADD    A,'A'-'0'-10
  585. B_to_H2:
  586.     ADD    A,'0'
  587.     JP    PUTQ        ; Send and return.
  588.     eject    1
  589. GET_HEX:
  590. ; This routine gets two hex characters from the UART and
  591. ; munches them into a byte in A.
  592. ; Entry:    No Params.
  593. ; Exit:     A=byte    H = trash
  594. ;        all others unchanged (except for flags)
  595.     IN    A,(Lsr)        ; Get the line status
  596.     BIT    DataRdy,A    ; Data ready from host?
  597.     JR    Z,GET_HEX    ; Jmp if no.
  598.     IN    A,(Serial)    ; get the data.
  599.     CALL    H_to_B        ; convert to binary.
  600.     ADD    A,A        ; Shift up 4 bits
  601.     ADD    A,A
  602.     ADD    A,A
  603.     ADD    A,A
  604.     LD    H,A        ; Save in B
  605. GET_HX1:
  606.     IN    A,(Lsr)        ; Get the line status
  607.     BIT    DataRdy,A    ; Data ready from host?
  608.     JR    Z,GET_HX1    ; Jmp if no.
  609.     IN    A,(Serial)    ; get the data.
  610.     CALL    H_to_B        ; convert to binary.
  611.     OR    H
  612.     RET            ; A = 2 input chars munched together.
  613.  
  614. ; Convert hex char to binary.
  615. H_to_B:
  616.     SET    5,A        ; convert to lower case.
  617.     SUB    '0'        ; less than 0?
  618.     JR    C,HB_ERR    ; Jmp if out of bounds.
  619.     CP    10        ; bigger than 9?
  620.     RET    C        ; Ret if no (0..9)
  621.     SUB    'a'-'0'-10    ; try to make it range 10-15
  622.     CP    10
  623.     JR    C,HB_ERR    ; Jmp if out of bounds.
  624.     CP    16
  625.     RET    C        ; Ret if hex.
  626. HB_ERR:
  627.     XOR    A        ; Set to zero.
  628.     RET
  629.  
  630.     eject    1
  631. SETBAUD:
  632. ; This routine reads the BAUD switches and looks the code
  633. ; up in the BTABLE to set the baudrate of the 8250 serial chip.
  634. ;
  635. ; Entry    No parameters
  636. ; exit    A Hl De    = garbage.
  637.     IN    A,(Lcr)    ; Set the divisor access bit on
  638.     OR    80H
  639.     OUT    (Lcr),A
  640.     IN    A,(Baud)    ; Get the baud rate code
  641.     LD    (SWTCH),A
  642.     AND    Bmask        ; Get only the baud specifier bits.
  643.     ADD    A,A        ; Double it to index into table.
  644.     LD    HL,BTABLE    ; Index into table to get the divisor
  645.     LD    E,A
  646.     LD    D,0
  647.     ADD    HL,DE
  648.     LD    A,(HL)        ; Get the low order divisor byte
  649.     OUT    (Serial),A
  650.     INC    HL
  651.     LD    A,(HL)        ; Get the high divisor byte
  652.     OUT    (Serial+1),A
  653.     IN    A,(Lcr)    ; Set the divisor access bit off
  654.     AND    7FH
  655.     OUT    (Lcr),A
  656.     RET
  657.  
  658. ; Baud rate look up table
  659. ; Only allow 16 entries.
  660. BTABLE:
  661.     WORD    5    ; 38.4 Kbaud
  662.     WORD    10    ; 19.2
  663.     WORD    20    ; 9600
  664.     WORD    27    ; 7200
  665.     WORD    40    ; 4800
  666.     WORD    53    ; 3600
  667.     WORD    80    ; 2400
  668.     WORD    107    ; 1800
  669.     WORD    160    ; 1200
  670.     WORD    320    ; 600
  671.     WORD    640    ; 300
  672.     WORD    1280    ; 150
  673.     WORD    1428    ; 134.5
  674.     WORD    1745    ; 110
  675.     WORD    2560    ; 75
  676.     WORD    3840    ; 50
  677.     eject    1
  678. ; STRT_IN and STOP_IN are called when the Input Q is may be too full/empty.
  679. ; They check and enable/disable the host xmitter apropriately.
  680. ;
  681.  
  682. STRT_IN:
  683. ; Entry    No registers set.
  684. ; Exit    A Ix Hl    = garbage.
  685. ;    Bc De    = unchanged.
  686. ;
  687.     LD    IX,INBOX    ; Point to the Q.
  688.     BIT    XmitOff,(IX + Status)    ; Is it off?
  689.     RET    Z        ; ret if no.
  690.     LD    A,40        ; Check if we've gone below low water mark.
  691.     CP    (IX + Count)
  692.     RET    C        ; Ret if no, Q still too full.
  693.     LD    A,(SWTCH)    ; get the switch settings.
  694.     BIT    Xonbit,A
  695.     JR    Z,STRT_DTR    ; Jmp if rs232 modem mode flow control.
  696. ; Try to use Xon/Xoff control flow methods.
  697.     BIT    RObit,A        ; Raw Output mode?
  698.     RET    NZ        ; No way to start/stop host xmitter.
  699.     LD    HL,OUTBOX+UnChar
  700.     LD    A,(HL)        ; Anything in unget spot?
  701.     AND    A
  702.     RET    NZ        ; Ret if yes.
  703.     LD    (HL),CntrlQ    ; 'unget' a control Q.
  704.     JR    STRT_END
  705. ; Set DTR bit on.
  706. STRT_DTR:
  707.     IN    A,(Mcr)        ; get the modem controls.
  708.     SET    DtrOut,A
  709.     OUT    (Mcr),A
  710. STRT_END:
  711.     RES    XmitOff,(IX + Status)    ; Mark as enabled.
  712.     RET
  713.  
  714.  
  715. STOP_IN:
  716. ; Entry    No registers set.
  717. ; Exit    A Ix Hl    = garbage.
  718. ;    Bc De    = unchanged.
  719. ;
  720.     LD    IX,INBOX    ; Point to the Q.
  721.     BIT    XmitOff,(IX + Status)    ; Already disabled?
  722.     RET    NZ        ; ret if yes.
  723.     LD    A,256-40    ; Check if we've gone above high water mark.
  724.     CP    (IX + Count)
  725.     RET    NC        ; Ret if no, Q still too empty.
  726.     LD    A,(SWTCH)
  727.     BIT    Xonbit,A    ; test for Xon/Xoff vs. modem flow cntrl.
  728.     JR    Z,STP_DTR    ; jmp if rs232 modem mode
  729. ; try to send an Xoff to the host.
  730.     BIT    RObit,A        ; Are we in raw out?
  731.     RET    NZ        ; Can't control the host xmitter.
  732.     LD    HL,OUTBOX+UnChar
  733.     LD    A,(HL)        ; Anything in unget spot?
  734.     AND    A
  735.     RET    NZ        ; Ret if yes.
  736.     LD    (HL),CntrlS    ; 'unget' a control S.
  737.     JR    STP_END
  738. ; Modem mode flow control, set DTR bit off.
  739. STP_DTR:
  740.     IN    A,(Mcr)        ; get the modem controls.
  741.     RES    DtrOut,A
  742.     OUT    (Mcr),A
  743. STP_END:
  744.     SET    XmitOff,(IX + Status)    ; Mark as disabled.
  745.     RET
  746.  
  747.     END
  748.