home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / cpm / hamradio / rtty3.lbr / MORSE2.AZM / MORSE2.ASM
Assembly Source File  |  1987-02-21  |  25KB  |  974 lines

  1. ; MORSE2.ASM    Version 2.0    By G.F.Reding    05 Jun 86
  2. ;
  3. ;
  4. ; Morse Program for 8008
  5. ; Typed from BYTE Magazine Oct 1976 Page 57
  6. ; By R.J.S. on    2/2/79
  7. ;
  8. ; (RJS may have also done the conversion to 8080 code.     <GFR>)
  9. ;
  10. ; (RJS, you neglected to give credit to original author. <GFR>)
  11. ;
  12. ;--------------------------------------------------------------
  13. ;
  14. ; Original source code by:  Bruce Filgate
  15. ;                Components Application Engineering
  16. ;    01/29/76        Digital Equipment Corporation
  17. ;                Marlbough, Massachusetts
  18. ;
  19. ;    --- for their logic products MPS product line.
  20. ;
  21. ;--------------------------------------------------------------
  22. ;
  23. ; The disk copy of the source code didn't contain the comments
  24. ; as was in the original source shown in Byte Magazine, so the
  25. ; magazine article was obtained  from a university's microfilm
  26. ; library, then the comments were typed back in.  If you refer
  27. ; to the original article, you may notice that I may have made
  28. ; some changes/improvements which I will also try to document.
  29. ;                        <GFR>
  30. ;--------------------------------------------------------------
  31. ;
  32. ; Commands available:
  33. ;
  34. ;    <ESC>        Return to normal keyboard mode (exit)
  35. ;    <ESC> L     Load message buffer - until <ESC> L
  36. ;    <ESC> P     Print the message buffer contents
  37. ;    <ESC> S     Send message buffer, as Morse code
  38. ;    <ESC> T     Test - do <ESC> S - until <ESC> typed
  39. ;    <ESC> W     WPM speed change.  Next char is speed
  40. ;              (See table/notes re speed character)
  41. ;    <Delete>    In load mode, remove previous chars
  42. ;              back to the beginning of the buffer
  43. ;
  44. ;--------------------------------------------------------------
  45. ;
  46. ; Weighting is 1 dash to 3 dots.
  47. ;
  48. ; Buffers (stacks) use the first byte as a "character count".
  49. ;
  50. ; The terminal bell will ring whenever a buffer over is caused
  51. ; by the user, and the character which caused such overflow is
  52. ; discarded.
  53. ;
  54. ; Normally the keyboard data is transmitted out translated but
  55. ; the command mode, as shown in the list,  may change this for
  56. ; for other functions/effects.
  57. ;
  58. ; Delete key is used to edit buffer, and  represents the error
  59. ; code in the immediate mode.
  60. ;
  61. ; Originally, the lsb of the input byte from I/O channel 2 was
  62. ; reserved to the sense line for code input.   The byte on I/O
  63. ; channel 4 was used for code output.    The key sense for code
  64. ; input and output was ground for key down condition and logic
  65. ; high for the key up condition.
  66. ;
  67. ;--------------------------------------------------------------
  68. ;
  69. FALSE    EQU    0        ; For conditional assembly
  70. TRUE    EQU    NOT FALSE
  71. ;
  72. IMSAI    EQU    FALSE        ; Using imsai with lights
  73. IMSPT    EQU    0FFH        ; Addr for imsai lights
  74. ;
  75. ;--------------------------------------------------------------
  76. ;
  77. ; Machine specific
  78. ;
  79. ; The following are your console/terminal DATA and STATUS ports
  80. ; which your terminal is connected to.  (If your console is not
  81. ; on a serial port, but is memory mapped,  you will have to add
  82. ; your own appropriate routines.  In the latter case, please do
  83. ; make such an addition an assembly conditional,  as is now the
  84. ; option for an IMSAI's lights, and bump version number of this
  85. ; program.)
  86. ;
  87. CDATA    EQU    60H        ; Console data port
  88. CSTAT    EQU    61H        ; Console status port
  89. CRBF    EQU    01H        ; Receive buffer full
  90. CTBE    EQU    04H        ; Transmit buffer empty mask
  91. ;
  92. ; The following are the interface unit DATA ports you will use.
  93. ; The interface is your user built CW modulator/demodulator, or
  94. ; commercial unit such as Heathkit Terminal Interface, HD-3030.
  95. ;
  96. MORINP    EQU    70H    ;62H        ; Morse input  data port
  97. MOROUT    EQU    70H    ;62H        ; Morse output data port
  98. ;
  99. ;
  100. ; Buffer sizes
  101. ;
  102. MSGSZ    EQU    0FFH        ; Msg holding buffer
  103. BUFOUT    EQU    30H        ; Code output buffer
  104. BUFSKY    EQU    0FFH        ; Keyboard buffer
  105. BUFSPN    EQU    30H        ; Printer buffer
  106. ;
  107. ;
  108. ; Other constants
  109. ;
  110. WIDTH    EQU    80        ; Printer width
  111. CR    EQU    0DH        ; Carriage return
  112. LF    EQU    0AH        ; Linefeed
  113. ERCHAR    EQU    7        ; Error char (bell)
  114. ESC    EQU    1BH        ; Enter cmd mode char (escape)
  115. ESCSYM    EQU    24H        ; Echo "$" for esc char
  116. QUEST    EQU    '?'        ; Bad cmd char (question mark)
  117. DELETE    EQU    7FH        ; Delete char
  118. DELSYM    EQU    5CH        ; Printable char for delete
  119. ETX    EQU    3        ; Control c exit to strt
  120. UPARRO    EQU    5EH        ; Ascii ^ for control chars
  121. BLANK    EQU    20H        ; Space
  122. ;
  123. EXCHAR    EQU    'X'-40H        ; Quit program char (ctrl x)
  124. ;
  125. ;
  126. ;--------------------------------------------------------------
  127. ;
  128. ; Beginning of the program.
  129. ;
  130. ;
  131.     ORG    100H
  132. ;
  133. STRT:    LXI    H,MSSGBF    ; Clear the msg buffer
  134.     MOV    M,A
  135.     LXI    H,BAUD        ; Set output baud
  136.     MVI    M,0FFH
  137.     CALL    INCLH        ; Same with input baud
  138.     MVI    M,0FFH
  139. ;
  140. ;
  141. ; Restart for ^C and clear reg A.
  142. ;
  143. STRT1:    XRA    A        ; Zero
  144.     LXI    H,KYFIFO    ; Clear keyboard char count
  145.     MOV    M,A
  146.     LXI    H,OTFIFO    ; Clear output buffer count
  147.     MOV    M,A
  148.     LXI    H,CMMND        ; Initialize the mode byte
  149.     MOV    M,A
  150.     CALL    INCLH        ; Initialize char count
  151.     MOV    M,A        ; Set for crlf initialization
  152.     LXI    H,PNFIFO    ; Clear printer char count
  153.     MOV    M,A        ; To clear tone and other bits
  154.     OUT    MOROUT        ; Output to morse data port
  155.      IF    IMSAI
  156.     CMA
  157.     OUT    0FFH
  158.     CMA
  159.      ENDIF
  160. ;
  161. ;
  162. ; Monitor entry and supervisor main task
  163. ;
  164. RESTRT:    CALL    INPEND        ; Try code input line
  165.     CALL    KYBD        ; Try the keyboard task
  166.     CALL    PNTR        ; Try the printer task
  167.     LXI    H,CMMND        ; Point to mode byte
  168.     XRA    A        ; Zero the reg and flags
  169.     ADD    M        ; Add mode byte to reg a
  170.     JNZ    CMMNDR        ; Enter command mode
  171.     CALL    IDLE        ; Non-command char feedthrough
  172.     CALL    OTPUT        ; Anything morse to output
  173.     JMP    RESTRT        ; And loop
  174. ;
  175. ;
  176. ; Exit to cp/m system
  177. ;
  178. EXIT:    JMP    0        ; Do warmboot to the system
  179. ;
  180. ;
  181. ; ASCII TABLE
  182. ;
  183. ASCTAB:    DB    'ABCDE'        ; A
  184.     DB    'FGHIJ'        ; To
  185.     DB    'KLMNO'        ; Z
  186.     DB    'PQRST'
  187.     DB    'UVWXYZ'
  188. ;
  189. ; NUMERALS
  190. ;
  191.     DB    '12345'        ; 1 to 9
  192.     DB    '6789'
  193. ;
  194. ; SPECIAL CHARACTERS
  195. ;
  196.     DB    30H        ; Zero
  197.     DB    2DH        ; Minus
  198.     DB    2EH        ; Period
  199.     DB    2CH        ; Comma
  200.     DB    3FH        ; Question mark
  201.     DB    2FH        ; Slash
  202.     DB    3AH        ; Colon
  203.     DB    28H        ; (
  204.     DB    29H        ; )
  205.     DB    27H        ; '
  206.     DB    22H        ; *
  207.     DB    0AH        ; End of message  cr/lf
  208.     DB    0AH        ; End of work (cr/lf)
  209. ;
  210. ASCEND:    DB    3BH        ; Semicolon
  211. ;
  212. ;
  213. ; MORSE TABLE
  214. ;
  215. MORTAB:    DB    60H        ; A
  216.     DB    88H        ; B
  217.     DB    0A8H        ; C
  218.     DB    90H        ; D
  219.     DB    40H        ; E
  220.     DB    28H        ; F
  221.     DB    0D0H        ; G
  222.     DB    08H        ; H
  223.     DB    20H        ; H
  224.     DB    78H        ; J
  225.     DB    0B0H        ; K
  226.     DB    48H        ; L
  227.     DB    0E0H        ; M
  228.     DB    0A0H        ; N
  229.     DB    0F0H        ; O
  230.     DB    68H        ; P
  231.     DB    0D8H        ; Q
  232.     DB    50H        ; R
  233.     DB    10H        ; S
  234.     DB    0C0H        ; T
  235.     DB    30H        ; U
  236.     DB    18H        ; V
  237.     DB    70H        ; W
  238.     DB    98H        ; X
  239.     DB    0B8H        ; Y
  240.     DB    0C8H        ; Z
  241.     DB    7CH        ; 1
  242.     DB    3CH        ; 2
  243.     DB    1CH        ; 3
  244.     DB    0CH        ; 4
  245.     DB    04H        ; 5
  246.     DB    84H        ; 6
  247.     DB    0C4H        ; 7
  248.     DB    0E4H        ; 8
  249.     DB    0F4H        ; 9
  250.     DB    0FCH        ; 0
  251.     DB    86H        ; -
  252.     DB    56H        ;
  253.     DB    0CEH        ; ,
  254.     DB    32H        ; ?
  255.     DB    94H        ; /
  256.     DB    0E2H        ; :
  257.     DB    0B6H        ; (
  258.     DB    0B6H        ; )
  259.     DB    7AH        ; '
  260.     DB    4AH        ; *
  261.     DB    54H        ; Eom cr/lf
  262.     DB    16H        ; Eow cr/lf
  263. ;
  264. MOREND:    DB    0AAH        ; ;
  265. ;
  266. ;
  267. ; Subroutine to put data in a general stack
  268. ; This stack pointer in HL, data in B, buffer size in C
  269. ; Returns A = zero if no error else A = erchar if error
  270. ;
  271. ENTPAK:    MOV    A,M        ; Char count to a
  272.     DCR    C        ; Decr size
  273.     CMP    C        ; Test for zero
  274.     JZ    ERROFL        ; Jump if full
  275.     ADI    1        ; Else bump the count
  276.     MOV    M,A        ; Put back into memory
  277.     ADD    L        ; Add low pointer to a
  278.     MOV    L,A        ; Put new value back into l
  279.     JNC    OK        ; If a carry, fix the h
  280.     INR    H        ; Fix h reg
  281. ;
  282. OK:    MOV    M,B        ; Char to memory
  283.     XRA    A        ; Clear the a reg
  284.     RET            ; Done
  285. ;
  286. ERROFL:    ADI    1        ; Set a to non zero err return
  287.     RET            ; System err, system must fix..
  288. ;
  289. ;
  290. ; Pop subroutine.  Entered with pointer in HL, size in B
  291. ;
  292. PXP:    MOV    A,M        ; Get counter to a
  293.     SUI    1        ; Decrement
  294.     MOV    M,A        ; Restore the new counter
  295.     JMP    PXPY        ; Get into poplop loop
  296. ;
  297. ;
  298. ; Loop for pop
  299. ;
  300. PXPLOP:    CALL    INCLH        ; Point at char to pop
  301.     MOV    C,M        ; Get char to c
  302.     CALL    DCRLH        ; Point to new location
  303.     MOV    M,C        ; Put char in memory
  304.     MOV    A,B        ; Put b into a
  305.     SUI    1        ; Subtract 1
  306. ;
  307. PXPY:    RZ            ; Done?
  308.     MOV    B,A        ; Restore reg b
  309.     CALL    INCLH        ; Recover from decrmt position
  310.     JMP    PXPLOP        ; Next pair pop
  311. ;
  312. ;
  313. ; Subroutine to increment the HL regs
  314. ;
  315. INCLH:    INR    L        ; Bump the l
  316.     RNZ            ; Return if no carry
  317.     INR    H        ; Bump the h on carry
  318.     RET            ; Done
  319. ;
  320. ;
  321. ; Subroutine to decrement the HL regs
  322. ;
  323. DCRLH:    MOV    A,L        ; Reg l to a
  324.     SUI    1        ; Decrement the a
  325.     MOV    L,A        ; Restore a to l
  326.     RNC            ; Return if no borrow
  327.     DCR    H        ; Fix the h after a borrow
  328.     RET            ; Done
  329. ;
  330. ;
  331. ; Subroutine to wait a unit code time.
  332. ; Destroys A,B, and C.
  333. ;
  334. TICK:    LXI    H,BAUD        ; Point at constant
  335.     MVI    C,28H        ; Multiplier constant
  336. ;
  337. WAIT2:    MOV    B,M        ; Constant to b
  338. ;
  339. WAIT1:    DCR    B        ; Count it down delay
  340.     JNZ    WAIT1
  341.     DCR    C        ; Multiply it
  342.     JNZ    WAIT2
  343.     CALL    KYBD        ; Overlap with keyboard input
  344.     CALL    PNTR        ; Same with the printer
  345.     RET            ; Delay over...
  346. ;
  347. ;
  348. ; Delay.  Used for 8 slice decoding of input code.
  349. ;
  350. TICKI:    LXI    H,BAUDI        ; Point at constant
  351.     MVI    C,05H        ; 8 times faster than tick
  352.     JMP    WAIT2        ; Finish this in tick routine
  353. ;
  354. ;
  355. ; Subroutine to generate a dot and post space.
  356. ; Destroys A,B,C, and HL.
  357. ;
  358. DOT:    MVI    A,0FFH        ; Set all bits (turn on - down)
  359.     OUT    MOROUT        ; Output to morse data port
  360.      IF    IMSAI
  361.     CMA
  362.     OUT    0FFH
  363.     CMA
  364.      ENDIF
  365.     JMP    FINDOT        ; Finish dot in dash routine
  366. ;
  367. ;
  368. ; Subroutine generates dash its post space.
  369. ; Destroys A,B,C, and HL.
  370. ;
  371. DASH:    MVI    A,0FFH        ; Set all bits (turn on - down)
  372.     OUT    MOROUT        ; Output to morse data port
  373.      IF    IMSAI
  374.     CMA
  375.     OUT    0FFH
  376.     CMA
  377.      ENDIF
  378.     CALL    TICK        ; Dash
  379.     CALL    TICK        ; Dash
  380. ;
  381. ;
  382. FINDOT:    CALL    TICK        ; Entered here to finish a dot
  383.     XRA    A        ; Clear all bits (turn off - up)
  384.     OUT    MOROUT        ; Output to morse data port
  385.      IF    IMSAI
  386.     CMA
  387.     OUT    0FFH
  388.     CMA
  389.      ENDIF
  390.     CALL    TICK
  391.     RET
  392. ;
  393. ;
  394. ; Monitor task subroutine for handling commands from keyboard.
  395. ;
  396. CMMNDR:    CALL    UNPAK        ; Get char from keyboard
  397.     JZ    CMMNDR        ; If nothing, then wait
  398.     CPI    ESC        ; Another cmd mode char (esc)?
  399.     JZ    CLRMD        ; If so, exit
  400.     CPI    'L'        ; Was it a load?
  401.     JZ    LDNXT        ; If so, go load a message
  402.     CPI    'P'        ; Was it a print?
  403.     JZ    PRT        ; If so, go print msg buffer
  404.     CPI    'S'        ; Was it a send of buffer?
  405.     JZ    SNDNX        ; If so, send the message
  406.     CPI    'T'        ; Was it a test?
  407.     JZ    TEST        ; If so, send the buffer
  408.                 ; Until an esc is typed
  409.     CPI    'W'        ; Was it a new wpm constant?
  410.     JZ    WPM        ; If so, load next char/constant
  411. ;
  412. ; If here a bad command
  413. ;
  414.     MVI    B,QUEST        ; Bad cmd char (question mark)
  415.     CALL    PPAK        ; To the printer fifo
  416.     JMP    CMMNDR        ; Try for a valid cmd char
  417. ;
  418. ;
  419. ; Routine to load the message buffer.
  420. ;
  421. LDNXT:    LXI    H,MSSGBF    ; Point at current char pointer
  422.     MVI    M,0        ; Zero the count
  423. ;
  424. LDNXT1:    CALL    UNPAK        ; Get keyboard char
  425.     JZ    LDNXT1        ; If nothing then wait
  426.     CPI    ESC        ; End of the input message?
  427.     JZ    CLRMD        ; Then exit, end of message
  428.     MOV    B,A        ; Char to b for entpak
  429.     LXI    H,MSSGBF    ; Point at the message buffer
  430.     CPI    DELETE        ; Delete command?
  431.     JNZ    LDNXT2        ; If no
  432.     XRA    A        ; If yes, clear reg a and flags
  433.     ADD    M        ; Get count to a and flags
  434.     JZ    LDNXT1        ; Buffer empty, a no-no
  435.     SBI    1        ; Decrement counter
  436.     MOV    M,A        ; Restore it to memory
  437.     JMP    LDNXT1        ; Loop
  438. ;
  439. LDNXT2:    MVI    C,MSGSZ        ; Get buffer size
  440.     CALL    ENTPAK        ; Char to buffer
  441.                 ; Test if full
  442.     CNZ    WHOOP        ; If full, tell user
  443.     JMP    LDNXT1        ; Loop until esc
  444. ;
  445. ;
  446. ; Subroutine for user error indication
  447. ;
  448. WHOOP:    IN    CSTAT        ; Get status
  449.     ANI    CTBE        ; Transmit buffer empty mask
  450.     JZ    WHOOP        ; If not, then loop
  451.     MVI    A,ERCHAR    ; Error char (bell)
  452.     OUT    CDATA        ; Send it
  453.     RET
  454. ;
  455. ;
  456. ; Routine to print the message buffer
  457. ;
  458. PRT:    LXI    H,SOH        ; Set up print submode
  459.     MVI    M,0        ; Zero
  460.     CALL    DMPSUB        ; Print the message buffer
  461.     JMP    CLRMD        ; Exit to the supervisor
  462. ;
  463. ;
  464. ; Subroutine to move the message buffer contents to location
  465. ; defined by the SOH location.    0 = Printer 1 = Sender.
  466. ;
  467. DMPSUB:    LXI    H,MSSCNT    ; Point at temp char pointer
  468.     MVI    M,0        ; Clear the pointer
  469. ;
  470. PRT1:    CALL    PNTR        ; Try to finish printing
  471.     CALL    KYBD        ; Try to finish keyboard input
  472.     CALL    OTPUT        ; Try to finish transmission
  473.     LXI    H,MSSGBF    ; Get char counter, check for 0
  474.     XRA    A        ; Clear reg a and flags
  475.     ADD    M        ; Add in the char count
  476.     RZ            ; If no message, exit
  477.     LXI    H,MSSCNT    ; Check count on xfer chars
  478.     CMP    M        ; Is it all transfered?
  479.     RZ            ; If so, then exit
  480.     MOV    B,M        ; Else get char count to b
  481.     INR    B        ; Bump the count
  482.     MOV    M,B        ; Restore it to memory
  483. ;
  484. ;
  485. ; Fetch the char from the message buffer
  486. ;
  487. PR4:    MVI    A,MSSGBF AND 0FFH ; Compute pointers
  488.     ADD    M        ; By adding in buffer offset
  489.     MOV    L,A        ; Set up the l, h yet to go
  490.     MVI    H,MSSGBF/256    ; H is set if no carry from l
  491.     JNC    PR2        ; No carry
  492.     INR    H        ; Fix for the l carry
  493. ;
  494. PR2:    MOV    B,M        ; Char to b
  495.     XRA    A        ; Clear reg a
  496.     LXI    H,SOH        ; Get the submode
  497.     ADD    M        ; Submode in reg a and flags
  498.     JNZ    SOH1        ; Send submode
  499.     CALL    PPAK        ; Print submode
  500.     JMP    PR3
  501. ;
  502. SOH1:    LXI    H,OTFIFO    ; Point at output buffer
  503.     MVI    C,BUFOUT    ; Size to c
  504.     CALL    ENTPAK        ; Xfer to the buffer
  505. ;
  506. PR3:    JZ    PRT1        ; Loop if no error
  507.     CALL    PNTR        ; Yes, overlay the i/o
  508.     CALL    KYBD        ; Try to finish keyboard input
  509.     CALL    OTPUT        ; Try to finish transmission
  510.     LXI    H,MSSCNT    ; Reset h for error recovery
  511.     JMP    PR4        ; Try the char again
  512. ;
  513. ;
  514. ; Routine to ship out the buffer in code
  515. ;
  516. SNDNX:    LXI    H,SOH        ; Set up send mode
  517.     MVI    M,1        ; For dmpsub routine
  518.     CALL    DMPSUB        ; Send the message buffer
  519.     JMP    CLRMD        ; Exit
  520. ;
  521. ;
  522. ; Routine to test output, ship until escape is typed
  523. ;
  524. TEST:    LXI    H,SOH        ; Set up for send mode
  525.     MVI    M,1
  526.     CALL    DMPSUB        ; Send the buffer
  527.     CALL    UNPAK        ; Char from keyboard
  528.     JZ    TEST        ; Nothing yet, do it again
  529.     CPI    ESC        ; Cmd mode char (escape)?
  530.     JZ    CLRMD        ; If yes, exit
  531. ;
  532. TEST1:    MVI    B,QUEST        ; Else illegal char for this
  533.     CALL    PPAK        ; Notify the user
  534.     JNZ    TEST1        ; If overflow, try again
  535.     JMP    TEST        ; And loop
  536. ;
  537. ;
  538. ; Code to load a new wpm constant into baud
  539. ;
  540. WPM:    CALL    UNPAK        ; Get char from keyboard
  541.     JZ    WPM        ; If nothing, then wait
  542.     ANI    1FH        ; Mask for 5 valid bits
  543.     RLC            ; Mult by 2
  544.     RLC            ; Again (*4)
  545.     RLC            ; Again (*8)
  546.     ORI    07H        ; Set the lsb
  547.     LXI    H,BAUD        ; Point at baud location
  548.     MOV    M,A        ; Store it in memory
  549. ;
  550. ;
  551. ; Clear the flags and exit to supervisor
  552. ;
  553. CLRMD:    LXI    H,CMMND        ; Point to mode byte
  554.     MVI    M,0        ; Zero it
  555.     JMP    RESTRT        ; To supervisor
  556. ;
  557. ;
  558. ; Routine to get char from keyboard fifo.
  559. ; Returns with char in reg A, else A = 0 if no char.
  560. ;
  561. UNPAK:    CALL    PNTR        ; Try finish pending printing
  562.     CALL    KYBD        ; Keyboard happy?
  563.     CALL    OTPUT        ; Overlay the code output
  564.     LXI    H,KYFIFO    ; Point at keyboard stack
  565.     XRA    A        ; Clear reg a
  566.     ADD    M        ; Char count to a
  567.     RZ            ; If empty, return a = 0
  568.     CALL    INCLH        ; Point at char
  569.     MOV    E,M        ; Get char to reg e (temp)
  570.     CALL    DCRLH        ; Point at keyboard fifo
  571.     CALL    PXP        ; Out of fifo, returns a = 0
  572.     ADD    E        ; Char to reg a and flags
  573.     RET            ; Return with reg a = char
  574. ;
  575. ;
  576. ; Subroutine to wait for the transmit buffer empty flag
  577. ;
  578. WAITMT:    IN    CSTAT        ; Get status
  579.     ANI    CTBE        ; Transmit buffer empty mask
  580.     JZ    WAITMT        ; Loop until empty
  581.     RET            ; Okay, have empty flag
  582. ;
  583. ;
  584. ; Keyboard handler subroutine
  585. ;
  586. KYBD:    IN    CSTAT        ; Get status
  587.     ANI    CRBF        ; Receive buffer full mask
  588.     RZ            ; If nothing, next task
  589. ;
  590. ; Put keyboard char in keyboard fifo
  591. ;
  592.     IN    CDATA        ; Serial input
  593.     ANI    7FH        ; Strip parity
  594.     CPI    EXCHAR        ; Exit to system?
  595.     JZ    EXIT        ; If yes, then quit
  596.     CPI    ETX        ; Control c?
  597.     JNZ    NETX        ; No, skip over
  598.     XRA    A        ; Clear all bits (turn off - up)
  599.     OUT    MOROUT        ; Output to morse data port
  600.  
  601.      IF    IMSAI
  602.     CMA
  603.     OUT    0FFH
  604.     CMA
  605.      ENDIF
  606.  
  607.     CALL    WAITMT        ; Wait for buffer empty
  608.     MVI    A,UPARRO    ; Ascii ^ for control chars
  609.     OUT    CDATA        ; Send it
  610.     CALL    WAITMT        ; Wait for buffer empty
  611.     MVI    A,'C'        ; Ascii c
  612.     OUT    CDATA        ; Send it
  613.     CALL    WAITMT        ; Wait for buffer empty
  614.     JMP    STRT1        ; Then restart from almost 0
  615. ;
  616. NETX:    LXI    H,KYFIFO    ; Point at keyboard fifo
  617.     MOV    B,A        ; Char to reg b
  618.     MVI    C,BUFSKY    ; Get buffer size
  619.     CALL    ENTPAK        ; Put char in buffer
  620.     CNZ    WHOOP        ; If overflow, tell user
  621.                 ; Fall thru and return in next
  622. ;
  623. ; Put char in printer fifo from B reg
  624. ;
  625. PPAK:    LXI    H,PNFIFO    ; Point at printer fifo
  626.     MVI    C,BUFSPN    ; Get buffer size
  627.     CALL    ENTPAK        ; Put char in buffer
  628.     RET
  629. ;
  630. ; End of the keyboard handler task
  631. ;
  632. ;
  633. ; Printer handler subroutine task
  634. ;
  635. PNTR:    IN    CSTAT        ; Get status
  636.     ANI    CTBE        ; Transmit buffer empty mask
  637.     RZ            ; If busy, try something else
  638. ;
  639.     LXI    H,TWIDTH    ; Find print position
  640.     XRA    A        ; Clear reg a and flags
  641.     ADD    M        ; Count to reg a and flags
  642.     JNZ    PRT2        ; No line overflow
  643.     MVI    A,CR        ; Line overflow, fix it
  644. ;
  645.     OUT    CDATA        ; Send a c/r
  646.     CALL    WAITMT        ; Wait until buffer empty
  647. ;
  648.     MVI    A,LF        ; And lf
  649.     OUT    CDATA
  650. ;
  651.     MVI    M,WIDTH        ; Reset print position count
  652.     RET
  653. ;
  654. PRT2:    LXI    H,PNFIFO    ; Point at char count
  655.     XRA    A        ; Clear reg a and flags
  656.     ADD    M        ; Count to reg a and flags
  657.     RZ            ; Nothing to print, next task
  658. ;
  659. ;
  660. ; If here there is printing to be done.
  661. ; Point at char to print and print it
  662. ;
  663.     CALL    INCLH
  664. NXTPNT:    MOV    E,M        ; Char to reg e (temp)
  665.     LXI    H,PNFIFO    ; Point at char count
  666.     CALL    PXP        ; Ripple the fifo
  667.     LXI    H,TWIDTH    ; Update print position
  668.     MOV    B,M        ; Count to b
  669.     DCR    B        ; Decrement it
  670.     MOV    M,B        ; Restore to memory
  671.     MOV    A,E        ; Char back to a
  672.     CPI    LF        ; Is it linefeed?
  673.     JZ    INCRLF        ; If yes, insert a crlf
  674.     CPI    CR        ; Is it a c/r?
  675.     JZ    INCRLF        ; If yes, insert a crlf
  676.     CPI    DELETE        ; Is it a delete char?
  677.     JZ    DEL        ; Yes, insert a back slash
  678.     CPI    ESC        ; Is it cmd mode char (esc)?
  679.     JNZ    PNT1        ; No
  680.     MVI    A,ESCSYM    ; Else substitute "$" for esc
  681. ;
  682. PNT1:    OUT    CDATA        ; Print the char
  683.     RET            ; Done, printed a char
  684. ;
  685. INCRLF:    MVI    M,0        ; Set for crlf next
  686.     RET
  687. ;
  688. DEL:    MVI    A,DELSYM    ; Substitute char for delete
  689.     OUT    CDATA        ; Print the char
  690.     RET
  691. ;
  692. ; End of the printer task
  693. ;
  694. ;
  695. ; This subroutine translates A reg to output mode.
  696. ; Compute the displacement in asctab.
  697. ;
  698. XLATER:    LXI    H,ASCTAB    ; Point at asctab
  699. ;
  700. THISIT:    CMP    M        ; Is this the char?
  701.     JZ    CONVT        ; Yes, go convert the char
  702.     CALL    INCLH        ; No, try the next
  703.     MOV    B,A        ; Save tha char in b (temp)
  704.     MVI    A,ASCEND/256    ; Get high limit to a for
  705.     CMP    H        ; Compare - past table end?
  706.     JC    NTFUND        ; If past and no match
  707.     MVI    A,ASCEND AND 0FFH ; Else get low limit to a for
  708.     CMP    L        ; Compare - past table end?
  709.     JC    NTFUND        ; If past and no match
  710.                 ; If still in table, try again
  711.     MOV    A,B        ; Return char to a
  712.     JMP    THISIT        ; And loop for next check
  713. ;
  714. CONVT:    MVI    A,MORTAB AND 0FFH ; Compute rel displacement low
  715.     SUI    ASCTAB AND 0FFH
  716.     JNC    OK1
  717.     DCR    H        ; Handle the borrow
  718. ;
  719. OK1:    ADD    L        ; Add in the low pointer
  720.     JNC    OK2
  721.     INR    H        ; Handle the carry
  722. ;
  723. OK2:    MOV    L,A        ; L now points in output tbl
  724.     MVI    A,MORTAB/256    ; Compute rel displacement high
  725.     SBI    ASCTAB/256
  726.     ADD    H        ; Add in the high pointer
  727.     MOV    H,A        ; H now points in output tbl
  728.     MOV    A,M        ; Replacement char to a
  729.     RET            ; Return with char in a
  730. ;
  731. NTFUND:    MVI    A,80H        ; Set char not found error
  732.     RET            ; Error return
  733. ;
  734. ;
  735. ; This subroutine translates A reg to print mode
  736. ;
  737. XLAT:    CPI    0FFH        ; Set c flag (guard bit)
  738.     RAL            ; Rotate
  739.     JNC    $-1        ; If no left guard, loop
  740. ;
  741. ; If reg A contains a 000, error char was seen
  742. ;
  743.     CPI    0        ; Set flags
  744.     JNZ    XLAT1        ; Not error, translate
  745.     MVI    A,DELSYM    ; Substitute delete char
  746.     RET            ; Exit
  747. ;
  748. XLAT1:    LXI    H,MORTAB    ; Point at mortab
  749. ;
  750. THIS:    CMP    M        ; Is this the char?
  751.     JZ    MCONVT        ; If yes, convert the char
  752.     CALL    INCLH        ; Else try next char
  753.     MOV    B,A        ; Save char in b (temp)
  754.     MVI    A,MOREND/256    ; Get high limit to a for
  755.     CMP    H        ; Compare - past table end?
  756.     JC    NTFND        ; Yes, with no match
  757.     MVI    A,MOREND AND 0FFH ; Get low limit to a for
  758.     CMP    L        ; Compare - past table end?
  759.     JC    NTFND        ; Yes, with no match
  760. ;
  761. ; If here, still in table, try contents again
  762. ;
  763.     MOV    A,B        ; Return char to a
  764.     JMP    THIS        ; Loop for next check
  765. ;
  766. MCONVT:    MVI    A,ASCTAB AND 0FFH ; Compute rel displacement low
  767.     SUI    MORTAB AND 0FFH
  768.     JC    MOK1
  769.     DCR    H        ; Handle the borrow
  770. ;
  771. MOK1:    ADD    L        ; Add in the low pointer
  772.     JNC    MOK2
  773.     INR    H        ; Handle the carry
  774. ;
  775. MOK2:    MOV    L,A        ; L now points in output tbl
  776.     MVI    A,ASCTAB/256    ; Compute rel displacement high
  777.     SBI    MORTAB/256
  778.     ADD    H        ; Add in the high pointer
  779.     MOV    H,A        ; H now points in output tbl
  780.     MOV    A,M        ; Ascii code to reg a
  781.     RET            ; Return with char in a
  782. ;
  783. NTFND:    MVI    A,BLANK        ; Not found, ret with space
  784.     RET            ; Error return
  785. ;
  786. ;
  787. ; Subroutine task to output code
  788. ;
  789. OTPUT:    LXI    H,OTFIFO    ; Point at stack
  790.     XRA    A        ; Clear reg a
  791.     ADD    M        ; Count to a and flags
  792.     RZ            ; If nothing, then next task
  793.     CALL    INCLH        ; Else point at the data
  794.     MOV    A,M        ; Get char
  795.     CPI    DELETE        ; Error char?
  796.     JNZ    OTPUT1        ; No, go translate
  797.     MVI    D,7        ; Yes, do 8 dots
  798. ;
  799. OTERR:    CALL    DOT        ; One dot
  800.     DCR    D        ; Count -1
  801.     JNZ    OTERR        ; Not done... do it again
  802.     JMP    OUTEND        ; Done, pop and exit
  803. ;
  804. OTPUT1:    CALL    XLATER        ; Translate
  805.     MOV    D,A        ; Save the char in d
  806.     CPI    80H        ; Is it a bad char (or space)?
  807.     JNZ    GOODCH        ; Char ok, so do it up right
  808.     MVI    D,6        ; Set 7 units delay (units-1)
  809. ;
  810. SPACE:    CALL    TICK        ; Wait one unit
  811.     DCR    D        ; Decrement unit counter
  812.     JNZ    SPACE        ; Loop until done
  813.     JMP    OUTEND
  814. ;
  815. GOODCH:    CPI    80H        ; If a=80h then done
  816.     JZ    OUTEND        ; Done
  817.     JNC    DSH        ; Dot or dash?
  818.     CALL    DOT        ; Yes a dot, so key it
  819.     JMP    OTLOOP        ; Next symbol
  820. ;
  821. DSH:    CALL    DASH        ; Must be a dash, so key it
  822. ;
  823. OTLOOP:    MOV    A,D        ; Get char back to a
  824.     ANI    7FH        ; Throw out the used bit
  825.     RLC            ; Rotate in an unused bit
  826.     MOV    D,A        ; Save the new image in d
  827.     JMP    GOODCH        ; Loop for other symbols
  828. ;
  829. OUTEND:    CALL    TICK        ; Inter-letter space
  830.     CALL    TICK
  831.     LXI    H,OTFIFO    ; Point at stack
  832.     CALL    PXP        ; Pop the stack
  833.     RET            ; Next task
  834. ;
  835. ;
  836. ; Keyboard decoder for non command mode
  837. ;
  838. IDLE:    LXI    H,KYFIFO    ; Point at char count
  839.     XRA    A        ; Clear reg a and flags
  840.     ADD    M        ; Count to a
  841.     RZ            ; If empty, try something else
  842.     CALL    INCLH        ; Else point at char
  843.     MOV    E,M        ; Save char in reg e (temp)
  844.     CALL    DCRLH        ; Point at start of buffer
  845.     CALL    PXP        ; Pop the char off the buffer
  846.     MOV    A,E        ; Restore char to a
  847.     CPI    ESC        ; Is it cmd mode char (esc)?
  848.     JZ    IDLE1        ; Yes
  849.                 ; Output in code
  850.     LXI    H,OTFIFO    ; Set up for entpak
  851.     MOV    B,A        ; Data to reg b
  852.     MVI    C,BUFOUT AND 0FFH ; Get buffer size
  853.     CALL    ENTPAK
  854.     CNZ    WHOOP        ; If buffer full, tell user
  855.     RET            ; Done
  856. ;
  857. IDLE1:    LXI    H,CMMND        ; Set for command mode
  858.     MVI    M,1        ; Mode = 1
  859.     RET
  860. ;
  861. ;
  862. ; Subroutine to service morse code input
  863. ;
  864. INPEND:    IN    MORINP        ; Get morse input data
  865.     ANI    1        ; We use the lsb
  866.     RNZ            ; If nothing pending, exit
  867.     LXI    H,INCHAR    ; Point at holding reg
  868.     MVI    M,1        ; Set up to shift in morse
  869. ;
  870. INTIME:    LXI    H,TIMER        ; Point at timer reg
  871.     MVI    M,0        ; Initialize time = 0
  872. ;
  873. INSENS:    CALL    TICKI        ; Wait for part of a baud (1/8)
  874.     LXI    H,TIMER        ; Update timer
  875.     MOV    B,M        ; To b
  876.     INR    B        ; Increment it
  877.     MOV    M,B        ; Restore to memory
  878.     IN    MORINP        ; Get morse input data
  879.     ANI    1        ; Is key down?
  880.     JZ    INSENS        ; Wait for key up
  881. ;
  882. ; If here, key is now up
  883. ;
  884.     MVI    E,0        ; E=0 for dot fix later if dash
  885.     MOV    A,B        ; Timer to a (8 * # of baud)
  886.     CPI    10H
  887.     JNC    INDASH        ; If dash, service dash
  888. ;
  889. ; See if clock much too slow for dot
  890. ;
  891.     CPI    6        ; Should be 10 ideal
  892.     JNC    INPOK        ; Clock is good enough
  893.     LXI    H,BAUDI        ; Not good enough fix wpm const
  894.     MOV    A,M        ; Wpm to a
  895.     CPI    2        ; Is wpm too low to track?
  896.     JC    INPOK        ; Dont try fix already too fast
  897.     SBI    1        ; Decrement it
  898.     MOV    M,A        ; Restore new to memory
  899.     JMP    INPOK
  900. ;
  901. ; If here, symbol is dash, update baudi for tracking
  902. ;
  903. INDASH:    LXI    H,BAUDI        ; Point at input wpm
  904.     MOV    A,B        ; Timer to reg a, again
  905.     CPI    1CH        ; Clock too fast?
  906.     JC    OKDASH        ; No
  907.     MOV    A,M        ; Yes
  908.     CPI    0FEH        ; Timer really too slow?
  909.     JNC    OKDASH        ; Yes, bail out
  910.     ADI    1        ; Else increment it
  911.     MOV    M,A        ; Restore new to memory
  912. ;
  913. OKDASH:    MVI    E,1        ; Set e = 1 for dash
  914. ;
  915. INPOK:    LXI    H,INCHAR    ; Point at char holding reg
  916.     MOV    A,M        ; Partial char to a
  917.     RAL            ; Shift up one bit
  918.     ANI    0FEH        ; Junk the old carry bit
  919.     ORA    E        ; Bring in new symbol from e
  920.     MOV    M,A        ; Restore new partial char
  921. ;
  922. ; Time the interspace to find what type it is.
  923. ;
  924.     LXI    H,TIMER        ; Reset the timer
  925.     MVI    M,0        ; Timer reset
  926. ;
  927. UPTIME:    CALL    TICKI        ; Delay 1/8 of a baud time
  928.     IN    MORINP        ; Get morse input data
  929.     ANI    1        ; Is key down?
  930.     JZ    INTIME        ; Yes, get the next symbol
  931.     LXI    H,TIMER        ; Update the time
  932.     MOV    B,M        ; To b
  933.     INR    B        ; Increment it
  934.     MOV    M,B        ; Restore to memory
  935.     MOV    A,B        ; Get timer to a for compare
  936.     CPI    0FFH        ; End of message?
  937.     JNZ    NOTEOM        ; Keep looping
  938.     MVI    B,LF        ; End of message, cr-lf-cr-lf
  939.     CALL    PPAK
  940.     CALL    PPAK
  941.     RET            ; Exit to mainline
  942. ;
  943. NOTEOM:    CPI    30H        ; End of word?
  944.     JNZ    ENDLET        ; No
  945.     MVI    A,1        ; Yes, output a space
  946.     JMP    MPAK        ; Do it out right
  947. ;
  948. ENDLET:    CPI    14H        ; End of letter?
  949.     JNZ    UPTIME        ; No, keep timing the up time
  950.     LXI    H,INCHAR    ; Point at holding reg
  951.     MOV    A,M        ; Morse from holding reg to a
  952.     MVI    M,1        ; Reset hold reg for next char
  953. ;
  954. MPAK:    CALL    XLAT        ; Ascii to a equiv of morse
  955.     MOV    B,A        ; Set up for ppak
  956.     CALL    PPAK        ; Print the char
  957.     JMP    UPTIME        ; Keep timing the up time
  958. ;
  959. ;
  960. CMMND    DS    1        ; 0 = normal, else command mode
  961. TWIDTH    DS    1        ; When byte is 0 generate cr/lf
  962. MSSCNT    DS    1        ; Temp char count forr msg dump
  963. SOH    DS    1        ; Dmpsub submode 0=print 1=send
  964. BAUD    DS    1        ; Wpm constant (see notes)
  965. BAUDI    DS    1        ; Input wpm val (gets modified)
  966. TIMER    DS    1        ; Time baud * 8  counter
  967. INCHAR    DS    1        ; Input char holding reg
  968. KYFIFO    EQU    $        ; Keyboard input buffer
  969. PNFIFO    EQU    KYFIFO+BUFSKY    ; Printer buffer
  970. OTFIFO    EQU    PNFIFO+BUFSPN    ; Output buffer
  971. MSSGBF    EQU    OTFIFO+BUFOUT    ; Message buffer
  972. ;
  973.     END
  974.