home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
hamradio
/
rtty3.lbr
/
MORSE2.AZM
/
MORSE2.ASM
Wrap
Assembly Source File
|
1987-02-21
|
25KB
|
974 lines
; MORSE2.ASM Version 2.0 By G.F.Reding 05 Jun 86
;
;
; Morse Program for 8008
; Typed from BYTE Magazine Oct 1976 Page 57
; By R.J.S. on 2/2/79
;
; (RJS may have also done the conversion to 8080 code. <GFR>)
;
; (RJS, you neglected to give credit to original author. <GFR>)
;
;--------------------------------------------------------------
;
; Original source code by: Bruce Filgate
; Components Application Engineering
; 01/29/76 Digital Equipment Corporation
; Marlbough, Massachusetts
;
; --- for their logic products MPS product line.
;
;--------------------------------------------------------------
;
; The disk copy of the source code didn't contain the comments
; as was in the original source shown in Byte Magazine, so the
; magazine article was obtained from a university's microfilm
; library, then the comments were typed back in. If you refer
; to the original article, you may notice that I may have made
; some changes/improvements which I will also try to document.
; <GFR>
;--------------------------------------------------------------
;
; Commands available:
;
; <ESC> Return to normal keyboard mode (exit)
; <ESC> L Load message buffer - until <ESC> L
; <ESC> P Print the message buffer contents
; <ESC> S Send message buffer, as Morse code
; <ESC> T Test - do <ESC> S - until <ESC> typed
; <ESC> W WPM speed change. Next char is speed
; (See table/notes re speed character)
; <Delete> In load mode, remove previous chars
; back to the beginning of the buffer
;
;--------------------------------------------------------------
;
; Weighting is 1 dash to 3 dots.
;
; Buffers (stacks) use the first byte as a "character count".
;
; The terminal bell will ring whenever a buffer over is caused
; by the user, and the character which caused such overflow is
; discarded.
;
; Normally the keyboard data is transmitted out translated but
; the command mode, as shown in the list, may change this for
; for other functions/effects.
;
; Delete key is used to edit buffer, and represents the error
; code in the immediate mode.
;
; Originally, the lsb of the input byte from I/O channel 2 was
; reserved to the sense line for code input. The byte on I/O
; channel 4 was used for code output. The key sense for code
; input and output was ground for key down condition and logic
; high for the key up condition.
;
;--------------------------------------------------------------
;
FALSE EQU 0 ; For conditional assembly
TRUE EQU NOT FALSE
;
IMSAI EQU FALSE ; Using imsai with lights
IMSPT EQU 0FFH ; Addr for imsai lights
;
;--------------------------------------------------------------
;
; Machine specific
;
; The following are your console/terminal DATA and STATUS ports
; which your terminal is connected to. (If your console is not
; on a serial port, but is memory mapped, you will have to add
; your own appropriate routines. In the latter case, please do
; make such an addition an assembly conditional, as is now the
; option for an IMSAI's lights, and bump version number of this
; program.)
;
CDATA EQU 60H ; Console data port
CSTAT EQU 61H ; Console status port
CRBF EQU 01H ; Receive buffer full
CTBE EQU 04H ; Transmit buffer empty mask
;
; The following are the interface unit DATA ports you will use.
; The interface is your user built CW modulator/demodulator, or
; commercial unit such as Heathkit Terminal Interface, HD-3030.
;
MORINP EQU 70H ;62H ; Morse input data port
MOROUT EQU 70H ;62H ; Morse output data port
;
;
; Buffer sizes
;
MSGSZ EQU 0FFH ; Msg holding buffer
BUFOUT EQU 30H ; Code output buffer
BUFSKY EQU 0FFH ; Keyboard buffer
BUFSPN EQU 30H ; Printer buffer
;
;
; Other constants
;
WIDTH EQU 80 ; Printer width
CR EQU 0DH ; Carriage return
LF EQU 0AH ; Linefeed
ERCHAR EQU 7 ; Error char (bell)
ESC EQU 1BH ; Enter cmd mode char (escape)
ESCSYM EQU 24H ; Echo "$" for esc char
QUEST EQU '?' ; Bad cmd char (question mark)
DELETE EQU 7FH ; Delete char
DELSYM EQU 5CH ; Printable char for delete
ETX EQU 3 ; Control c exit to strt
UPARRO EQU 5EH ; Ascii ^ for control chars
BLANK EQU 20H ; Space
;
EXCHAR EQU 'X'-40H ; Quit program char (ctrl x)
;
;
;--------------------------------------------------------------
;
; Beginning of the program.
;
;
ORG 100H
;
STRT: LXI H,MSSGBF ; Clear the msg buffer
MOV M,A
LXI H,BAUD ; Set output baud
MVI M,0FFH
CALL INCLH ; Same with input baud
MVI M,0FFH
;
;
; Restart for ^C and clear reg A.
;
STRT1: XRA A ; Zero
LXI H,KYFIFO ; Clear keyboard char count
MOV M,A
LXI H,OTFIFO ; Clear output buffer count
MOV M,A
LXI H,CMMND ; Initialize the mode byte
MOV M,A
CALL INCLH ; Initialize char count
MOV M,A ; Set for crlf initialization
LXI H,PNFIFO ; Clear printer char count
MOV M,A ; To clear tone and other bits
OUT MOROUT ; Output to morse data port
IF IMSAI
CMA
OUT 0FFH
CMA
ENDIF
;
;
; Monitor entry and supervisor main task
;
RESTRT: CALL INPEND ; Try code input line
CALL KYBD ; Try the keyboard task
CALL PNTR ; Try the printer task
LXI H,CMMND ; Point to mode byte
XRA A ; Zero the reg and flags
ADD M ; Add mode byte to reg a
JNZ CMMNDR ; Enter command mode
CALL IDLE ; Non-command char feedthrough
CALL OTPUT ; Anything morse to output
JMP RESTRT ; And loop
;
;
; Exit to cp/m system
;
EXIT: JMP 0 ; Do warmboot to the system
;
;
; ASCII TABLE
;
ASCTAB: DB 'ABCDE' ; A
DB 'FGHIJ' ; To
DB 'KLMNO' ; Z
DB 'PQRST'
DB 'UVWXYZ'
;
; NUMERALS
;
DB '12345' ; 1 to 9
DB '6789'
;
; SPECIAL CHARACTERS
;
DB 30H ; Zero
DB 2DH ; Minus
DB 2EH ; Period
DB 2CH ; Comma
DB 3FH ; Question mark
DB 2FH ; Slash
DB 3AH ; Colon
DB 28H ; (
DB 29H ; )
DB 27H ; '
DB 22H ; *
DB 0AH ; End of message cr/lf
DB 0AH ; End of work (cr/lf)
;
ASCEND: DB 3BH ; Semicolon
;
;
; MORSE TABLE
;
MORTAB: DB 60H ; A
DB 88H ; B
DB 0A8H ; C
DB 90H ; D
DB 40H ; E
DB 28H ; F
DB 0D0H ; G
DB 08H ; H
DB 20H ; H
DB 78H ; J
DB 0B0H ; K
DB 48H ; L
DB 0E0H ; M
DB 0A0H ; N
DB 0F0H ; O
DB 68H ; P
DB 0D8H ; Q
DB 50H ; R
DB 10H ; S
DB 0C0H ; T
DB 30H ; U
DB 18H ; V
DB 70H ; W
DB 98H ; X
DB 0B8H ; Y
DB 0C8H ; Z
DB 7CH ; 1
DB 3CH ; 2
DB 1CH ; 3
DB 0CH ; 4
DB 04H ; 5
DB 84H ; 6
DB 0C4H ; 7
DB 0E4H ; 8
DB 0F4H ; 9
DB 0FCH ; 0
DB 86H ; -
DB 56H ;
DB 0CEH ; ,
DB 32H ; ?
DB 94H ; /
DB 0E2H ; :
DB 0B6H ; (
DB 0B6H ; )
DB 7AH ; '
DB 4AH ; *
DB 54H ; Eom cr/lf
DB 16H ; Eow cr/lf
;
MOREND: DB 0AAH ; ;
;
;
; Subroutine to put data in a general stack
; This stack pointer in HL, data in B, buffer size in C
; Returns A = zero if no error else A = erchar if error
;
ENTPAK: MOV A,M ; Char count to a
DCR C ; Decr size
CMP C ; Test for zero
JZ ERROFL ; Jump if full
ADI 1 ; Else bump the count
MOV M,A ; Put back into memory
ADD L ; Add low pointer to a
MOV L,A ; Put new value back into l
JNC OK ; If a carry, fix the h
INR H ; Fix h reg
;
OK: MOV M,B ; Char to memory
XRA A ; Clear the a reg
RET ; Done
;
ERROFL: ADI 1 ; Set a to non zero err return
RET ; System err, system must fix..
;
;
; Pop subroutine. Entered with pointer in HL, size in B
;
PXP: MOV A,M ; Get counter to a
SUI 1 ; Decrement
MOV M,A ; Restore the new counter
JMP PXPY ; Get into poplop loop
;
;
; Loop for pop
;
PXPLOP: CALL INCLH ; Point at char to pop
MOV C,M ; Get char to c
CALL DCRLH ; Point to new location
MOV M,C ; Put char in memory
MOV A,B ; Put b into a
SUI 1 ; Subtract 1
;
PXPY: RZ ; Done?
MOV B,A ; Restore reg b
CALL INCLH ; Recover from decrmt position
JMP PXPLOP ; Next pair pop
;
;
; Subroutine to increment the HL regs
;
INCLH: INR L ; Bump the l
RNZ ; Return if no carry
INR H ; Bump the h on carry
RET ; Done
;
;
; Subroutine to decrement the HL regs
;
DCRLH: MOV A,L ; Reg l to a
SUI 1 ; Decrement the a
MOV L,A ; Restore a to l
RNC ; Return if no borrow
DCR H ; Fix the h after a borrow
RET ; Done
;
;
; Subroutine to wait a unit code time.
; Destroys A,B, and C.
;
TICK: LXI H,BAUD ; Point at constant
MVI C,28H ; Multiplier constant
;
WAIT2: MOV B,M ; Constant to b
;
WAIT1: DCR B ; Count it down delay
JNZ WAIT1
DCR C ; Multiply it
JNZ WAIT2
CALL KYBD ; Overlap with keyboard input
CALL PNTR ; Same with the printer
RET ; Delay over...
;
;
; Delay. Used for 8 slice decoding of input code.
;
TICKI: LXI H,BAUDI ; Point at constant
MVI C,05H ; 8 times faster than tick
JMP WAIT2 ; Finish this in tick routine
;
;
; Subroutine to generate a dot and post space.
; Destroys A,B,C, and HL.
;
DOT: MVI A,0FFH ; Set all bits (turn on - down)
OUT MOROUT ; Output to morse data port
IF IMSAI
CMA
OUT 0FFH
CMA
ENDIF
JMP FINDOT ; Finish dot in dash routine
;
;
; Subroutine generates dash its post space.
; Destroys A,B,C, and HL.
;
DASH: MVI A,0FFH ; Set all bits (turn on - down)
OUT MOROUT ; Output to morse data port
IF IMSAI
CMA
OUT 0FFH
CMA
ENDIF
CALL TICK ; Dash
CALL TICK ; Dash
;
;
FINDOT: CALL TICK ; Entered here to finish a dot
XRA A ; Clear all bits (turn off - up)
OUT MOROUT ; Output to morse data port
IF IMSAI
CMA
OUT 0FFH
CMA
ENDIF
CALL TICK
RET
;
;
; Monitor task subroutine for handling commands from keyboard.
;
CMMNDR: CALL UNPAK ; Get char from keyboard
JZ CMMNDR ; If nothing, then wait
CPI ESC ; Another cmd mode char (esc)?
JZ CLRMD ; If so, exit
CPI 'L' ; Was it a load?
JZ LDNXT ; If so, go load a message
CPI 'P' ; Was it a print?
JZ PRT ; If so, go print msg buffer
CPI 'S' ; Was it a send of buffer?
JZ SNDNX ; If so, send the message
CPI 'T' ; Was it a test?
JZ TEST ; If so, send the buffer
; Until an esc is typed
CPI 'W' ; Was it a new wpm constant?
JZ WPM ; If so, load next char/constant
;
; If here a bad command
;
MVI B,QUEST ; Bad cmd char (question mark)
CALL PPAK ; To the printer fifo
JMP CMMNDR ; Try for a valid cmd char
;
;
; Routine to load the message buffer.
;
LDNXT: LXI H,MSSGBF ; Point at current char pointer
MVI M,0 ; Zero the count
;
LDNXT1: CALL UNPAK ; Get keyboard char
JZ LDNXT1 ; If nothing then wait
CPI ESC ; End of the input message?
JZ CLRMD ; Then exit, end of message
MOV B,A ; Char to b for entpak
LXI H,MSSGBF ; Point at the message buffer
CPI DELETE ; Delete command?
JNZ LDNXT2 ; If no
XRA A ; If yes, clear reg a and flags
ADD M ; Get count to a and flags
JZ LDNXT1 ; Buffer empty, a no-no
SBI 1 ; Decrement counter
MOV M,A ; Restore it to memory
JMP LDNXT1 ; Loop
;
LDNXT2: MVI C,MSGSZ ; Get buffer size
CALL ENTPAK ; Char to buffer
; Test if full
CNZ WHOOP ; If full, tell user
JMP LDNXT1 ; Loop until esc
;
;
; Subroutine for user error indication
;
WHOOP: IN CSTAT ; Get status
ANI CTBE ; Transmit buffer empty mask
JZ WHOOP ; If not, then loop
MVI A,ERCHAR ; Error char (bell)
OUT CDATA ; Send it
RET
;
;
; Routine to print the message buffer
;
PRT: LXI H,SOH ; Set up print submode
MVI M,0 ; Zero
CALL DMPSUB ; Print the message buffer
JMP CLRMD ; Exit to the supervisor
;
;
; Subroutine to move the message buffer contents to location
; defined by the SOH location. 0 = Printer 1 = Sender.
;
DMPSUB: LXI H,MSSCNT ; Point at temp char pointer
MVI M,0 ; Clear the pointer
;
PRT1: CALL PNTR ; Try to finish printing
CALL KYBD ; Try to finish keyboard input
CALL OTPUT ; Try to finish transmission
LXI H,MSSGBF ; Get char counter, check for 0
XRA A ; Clear reg a and flags
ADD M ; Add in the char count
RZ ; If no message, exit
LXI H,MSSCNT ; Check count on xfer chars
CMP M ; Is it all transfered?
RZ ; If so, then exit
MOV B,M ; Else get char count to b
INR B ; Bump the count
MOV M,B ; Restore it to memory
;
;
; Fetch the char from the message buffer
;
PR4: MVI A,MSSGBF AND 0FFH ; Compute pointers
ADD M ; By adding in buffer offset
MOV L,A ; Set up the l, h yet to go
MVI H,MSSGBF/256 ; H is set if no carry from l
JNC PR2 ; No carry
INR H ; Fix for the l carry
;
PR2: MOV B,M ; Char to b
XRA A ; Clear reg a
LXI H,SOH ; Get the submode
ADD M ; Submode in reg a and flags
JNZ SOH1 ; Send submode
CALL PPAK ; Print submode
JMP PR3
;
SOH1: LXI H,OTFIFO ; Point at output buffer
MVI C,BUFOUT ; Size to c
CALL ENTPAK ; Xfer to the buffer
;
PR3: JZ PRT1 ; Loop if no error
CALL PNTR ; Yes, overlay the i/o
CALL KYBD ; Try to finish keyboard input
CALL OTPUT ; Try to finish transmission
LXI H,MSSCNT ; Reset h for error recovery
JMP PR4 ; Try the char again
;
;
; Routine to ship out the buffer in code
;
SNDNX: LXI H,SOH ; Set up send mode
MVI M,1 ; For dmpsub routine
CALL DMPSUB ; Send the message buffer
JMP CLRMD ; Exit
;
;
; Routine to test output, ship until escape is typed
;
TEST: LXI H,SOH ; Set up for send mode
MVI M,1
CALL DMPSUB ; Send the buffer
CALL UNPAK ; Char from keyboard
JZ TEST ; Nothing yet, do it again
CPI ESC ; Cmd mode char (escape)?
JZ CLRMD ; If yes, exit
;
TEST1: MVI B,QUEST ; Else illegal char for this
CALL PPAK ; Notify the user
JNZ TEST1 ; If overflow, try again
JMP TEST ; And loop
;
;
; Code to load a new wpm constant into baud
;
WPM: CALL UNPAK ; Get char from keyboard
JZ WPM ; If nothing, then wait
ANI 1FH ; Mask for 5 valid bits
RLC ; Mult by 2
RLC ; Again (*4)
RLC ; Again (*8)
ORI 07H ; Set the lsb
LXI H,BAUD ; Point at baud location
MOV M,A ; Store it in memory
;
;
; Clear the flags and exit to supervisor
;
CLRMD: LXI H,CMMND ; Point to mode byte
MVI M,0 ; Zero it
JMP RESTRT ; To supervisor
;
;
; Routine to get char from keyboard fifo.
; Returns with char in reg A, else A = 0 if no char.
;
UNPAK: CALL PNTR ; Try finish pending printing
CALL KYBD ; Keyboard happy?
CALL OTPUT ; Overlay the code output
LXI H,KYFIFO ; Point at keyboard stack
XRA A ; Clear reg a
ADD M ; Char count to a
RZ ; If empty, return a = 0
CALL INCLH ; Point at char
MOV E,M ; Get char to reg e (temp)
CALL DCRLH ; Point at keyboard fifo
CALL PXP ; Out of fifo, returns a = 0
ADD E ; Char to reg a and flags
RET ; Return with reg a = char
;
;
; Subroutine to wait for the transmit buffer empty flag
;
WAITMT: IN CSTAT ; Get status
ANI CTBE ; Transmit buffer empty mask
JZ WAITMT ; Loop until empty
RET ; Okay, have empty flag
;
;
; Keyboard handler subroutine
;
KYBD: IN CSTAT ; Get status
ANI CRBF ; Receive buffer full mask
RZ ; If nothing, next task
;
; Put keyboard char in keyboard fifo
;
IN CDATA ; Serial input
ANI 7FH ; Strip parity
CPI EXCHAR ; Exit to system?
JZ EXIT ; If yes, then quit
CPI ETX ; Control c?
JNZ NETX ; No, skip over
XRA A ; Clear all bits (turn off - up)
OUT MOROUT ; Output to morse data port
IF IMSAI
CMA
OUT 0FFH
CMA
ENDIF
CALL WAITMT ; Wait for buffer empty
MVI A,UPARRO ; Ascii ^ for control chars
OUT CDATA ; Send it
CALL WAITMT ; Wait for buffer empty
MVI A,'C' ; Ascii c
OUT CDATA ; Send it
CALL WAITMT ; Wait for buffer empty
JMP STRT1 ; Then restart from almost 0
;
NETX: LXI H,KYFIFO ; Point at keyboard fifo
MOV B,A ; Char to reg b
MVI C,BUFSKY ; Get buffer size
CALL ENTPAK ; Put char in buffer
CNZ WHOOP ; If overflow, tell user
; Fall thru and return in next
;
; Put char in printer fifo from B reg
;
PPAK: LXI H,PNFIFO ; Point at printer fifo
MVI C,BUFSPN ; Get buffer size
CALL ENTPAK ; Put char in buffer
RET
;
; End of the keyboard handler task
;
;
; Printer handler subroutine task
;
PNTR: IN CSTAT ; Get status
ANI CTBE ; Transmit buffer empty mask
RZ ; If busy, try something else
;
LXI H,TWIDTH ; Find print position
XRA A ; Clear reg a and flags
ADD M ; Count to reg a and flags
JNZ PRT2 ; No line overflow
MVI A,CR ; Line overflow, fix it
;
OUT CDATA ; Send a c/r
CALL WAITMT ; Wait until buffer empty
;
MVI A,LF ; And lf
OUT CDATA
;
MVI M,WIDTH ; Reset print position count
RET
;
PRT2: LXI H,PNFIFO ; Point at char count
XRA A ; Clear reg a and flags
ADD M ; Count to reg a and flags
RZ ; Nothing to print, next task
;
;
; If here there is printing to be done.
; Point at char to print and print it
;
CALL INCLH
NXTPNT: MOV E,M ; Char to reg e (temp)
LXI H,PNFIFO ; Point at char count
CALL PXP ; Ripple the fifo
LXI H,TWIDTH ; Update print position
MOV B,M ; Count to b
DCR B ; Decrement it
MOV M,B ; Restore to memory
MOV A,E ; Char back to a
CPI LF ; Is it linefeed?
JZ INCRLF ; If yes, insert a crlf
CPI CR ; Is it a c/r?
JZ INCRLF ; If yes, insert a crlf
CPI DELETE ; Is it a delete char?
JZ DEL ; Yes, insert a back slash
CPI ESC ; Is it cmd mode char (esc)?
JNZ PNT1 ; No
MVI A,ESCSYM ; Else substitute "$" for esc
;
PNT1: OUT CDATA ; Print the char
RET ; Done, printed a char
;
INCRLF: MVI M,0 ; Set for crlf next
RET
;
DEL: MVI A,DELSYM ; Substitute char for delete
OUT CDATA ; Print the char
RET
;
; End of the printer task
;
;
; This subroutine translates A reg to output mode.
; Compute the displacement in asctab.
;
XLATER: LXI H,ASCTAB ; Point at asctab
;
THISIT: CMP M ; Is this the char?
JZ CONVT ; Yes, go convert the char
CALL INCLH ; No, try the next
MOV B,A ; Save tha char in b (temp)
MVI A,ASCEND/256 ; Get high limit to a for
CMP H ; Compare - past table end?
JC NTFUND ; If past and no match
MVI A,ASCEND AND 0FFH ; Else get low limit to a for
CMP L ; Compare - past table end?
JC NTFUND ; If past and no match
; If still in table, try again
MOV A,B ; Return char to a
JMP THISIT ; And loop for next check
;
CONVT: MVI A,MORTAB AND 0FFH ; Compute rel displacement low
SUI ASCTAB AND 0FFH
JNC OK1
DCR H ; Handle the borrow
;
OK1: ADD L ; Add in the low pointer
JNC OK2
INR H ; Handle the carry
;
OK2: MOV L,A ; L now points in output tbl
MVI A,MORTAB/256 ; Compute rel displacement high
SBI ASCTAB/256
ADD H ; Add in the high pointer
MOV H,A ; H now points in output tbl
MOV A,M ; Replacement char to a
RET ; Return with char in a
;
NTFUND: MVI A,80H ; Set char not found error
RET ; Error return
;
;
; This subroutine translates A reg to print mode
;
XLAT: CPI 0FFH ; Set c flag (guard bit)
RAL ; Rotate
JNC $-1 ; If no left guard, loop
;
; If reg A contains a 000, error char was seen
;
CPI 0 ; Set flags
JNZ XLAT1 ; Not error, translate
MVI A,DELSYM ; Substitute delete char
RET ; Exit
;
XLAT1: LXI H,MORTAB ; Point at mortab
;
THIS: CMP M ; Is this the char?
JZ MCONVT ; If yes, convert the char
CALL INCLH ; Else try next char
MOV B,A ; Save char in b (temp)
MVI A,MOREND/256 ; Get high limit to a for
CMP H ; Compare - past table end?
JC NTFND ; Yes, with no match
MVI A,MOREND AND 0FFH ; Get low limit to a for
CMP L ; Compare - past table end?
JC NTFND ; Yes, with no match
;
; If here, still in table, try contents again
;
MOV A,B ; Return char to a
JMP THIS ; Loop for next check
;
MCONVT: MVI A,ASCTAB AND 0FFH ; Compute rel displacement low
SUI MORTAB AND 0FFH
JC MOK1
DCR H ; Handle the borrow
;
MOK1: ADD L ; Add in the low pointer
JNC MOK2
INR H ; Handle the carry
;
MOK2: MOV L,A ; L now points in output tbl
MVI A,ASCTAB/256 ; Compute rel displacement high
SBI MORTAB/256
ADD H ; Add in the high pointer
MOV H,A ; H now points in output tbl
MOV A,M ; Ascii code to reg a
RET ; Return with char in a
;
NTFND: MVI A,BLANK ; Not found, ret with space
RET ; Error return
;
;
; Subroutine task to output code
;
OTPUT: LXI H,OTFIFO ; Point at stack
XRA A ; Clear reg a
ADD M ; Count to a and flags
RZ ; If nothing, then next task
CALL INCLH ; Else point at the data
MOV A,M ; Get char
CPI DELETE ; Error char?
JNZ OTPUT1 ; No, go translate
MVI D,7 ; Yes, do 8 dots
;
OTERR: CALL DOT ; One dot
DCR D ; Count -1
JNZ OTERR ; Not done... do it again
JMP OUTEND ; Done, pop and exit
;
OTPUT1: CALL XLATER ; Translate
MOV D,A ; Save the char in d
CPI 80H ; Is it a bad char (or space)?
JNZ GOODCH ; Char ok, so do it up right
MVI D,6 ; Set 7 units delay (units-1)
;
SPACE: CALL TICK ; Wait one unit
DCR D ; Decrement unit counter
JNZ SPACE ; Loop until done
JMP OUTEND
;
GOODCH: CPI 80H ; If a=80h then done
JZ OUTEND ; Done
JNC DSH ; Dot or dash?
CALL DOT ; Yes a dot, so key it
JMP OTLOOP ; Next symbol
;
DSH: CALL DASH ; Must be a dash, so key it
;
OTLOOP: MOV A,D ; Get char back to a
ANI 7FH ; Throw out the used bit
RLC ; Rotate in an unused bit
MOV D,A ; Save the new image in d
JMP GOODCH ; Loop for other symbols
;
OUTEND: CALL TICK ; Inter-letter space
CALL TICK
LXI H,OTFIFO ; Point at stack
CALL PXP ; Pop the stack
RET ; Next task
;
;
; Keyboard decoder for non command mode
;
IDLE: LXI H,KYFIFO ; Point at char count
XRA A ; Clear reg a and flags
ADD M ; Count to a
RZ ; If empty, try something else
CALL INCLH ; Else point at char
MOV E,M ; Save char in reg e (temp)
CALL DCRLH ; Point at start of buffer
CALL PXP ; Pop the char off the buffer
MOV A,E ; Restore char to a
CPI ESC ; Is it cmd mode char (esc)?
JZ IDLE1 ; Yes
; Output in code
LXI H,OTFIFO ; Set up for entpak
MOV B,A ; Data to reg b
MVI C,BUFOUT AND 0FFH ; Get buffer size
CALL ENTPAK
CNZ WHOOP ; If buffer full, tell user
RET ; Done
;
IDLE1: LXI H,CMMND ; Set for command mode
MVI M,1 ; Mode = 1
RET
;
;
; Subroutine to service morse code input
;
INPEND: IN MORINP ; Get morse input data
ANI 1 ; We use the lsb
RNZ ; If nothing pending, exit
LXI H,INCHAR ; Point at holding reg
MVI M,1 ; Set up to shift in morse
;
INTIME: LXI H,TIMER ; Point at timer reg
MVI M,0 ; Initialize time = 0
;
INSENS: CALL TICKI ; Wait for part of a baud (1/8)
LXI H,TIMER ; Update timer
MOV B,M ; To b
INR B ; Increment it
MOV M,B ; Restore to memory
IN MORINP ; Get morse input data
ANI 1 ; Is key down?
JZ INSENS ; Wait for key up
;
; If here, key is now up
;
MVI E,0 ; E=0 for dot fix later if dash
MOV A,B ; Timer to a (8 * # of baud)
CPI 10H
JNC INDASH ; If dash, service dash
;
; See if clock much too slow for dot
;
CPI 6 ; Should be 10 ideal
JNC INPOK ; Clock is good enough
LXI H,BAUDI ; Not good enough fix wpm const
MOV A,M ; Wpm to a
CPI 2 ; Is wpm too low to track?
JC INPOK ; Dont try fix already too fast
SBI 1 ; Decrement it
MOV M,A ; Restore new to memory
JMP INPOK
;
; If here, symbol is dash, update baudi for tracking
;
INDASH: LXI H,BAUDI ; Point at input wpm
MOV A,B ; Timer to reg a, again
CPI 1CH ; Clock too fast?
JC OKDASH ; No
MOV A,M ; Yes
CPI 0FEH ; Timer really too slow?
JNC OKDASH ; Yes, bail out
ADI 1 ; Else increment it
MOV M,A ; Restore new to memory
;
OKDASH: MVI E,1 ; Set e = 1 for dash
;
INPOK: LXI H,INCHAR ; Point at char holding reg
MOV A,M ; Partial char to a
RAL ; Shift up one bit
ANI 0FEH ; Junk the old carry bit
ORA E ; Bring in new symbol from e
MOV M,A ; Restore new partial char
;
; Time the interspace to find what type it is.
;
LXI H,TIMER ; Reset the timer
MVI M,0 ; Timer reset
;
UPTIME: CALL TICKI ; Delay 1/8 of a baud time
IN MORINP ; Get morse input data
ANI 1 ; Is key down?
JZ INTIME ; Yes, get the next symbol
LXI H,TIMER ; Update the time
MOV B,M ; To b
INR B ; Increment it
MOV M,B ; Restore to memory
MOV A,B ; Get timer to a for compare
CPI 0FFH ; End of message?
JNZ NOTEOM ; Keep looping
MVI B,LF ; End of message, cr-lf-cr-lf
CALL PPAK
CALL PPAK
RET ; Exit to mainline
;
NOTEOM: CPI 30H ; End of word?
JNZ ENDLET ; No
MVI A,1 ; Yes, output a space
JMP MPAK ; Do it out right
;
ENDLET: CPI 14H ; End of letter?
JNZ UPTIME ; No, keep timing the up time
LXI H,INCHAR ; Point at holding reg
MOV A,M ; Morse from holding reg to a
MVI M,1 ; Reset hold reg for next char
;
MPAK: CALL XLAT ; Ascii to a equiv of morse
MOV B,A ; Set up for ppak
CALL PPAK ; Print the char
JMP UPTIME ; Keep timing the up time
;
;
CMMND DS 1 ; 0 = normal, else command mode
TWIDTH DS 1 ; When byte is 0 generate cr/lf
MSSCNT DS 1 ; Temp char count forr msg dump
SOH DS 1 ; Dmpsub submode 0=print 1=send
BAUD DS 1 ; Wpm constant (see notes)
BAUDI DS 1 ; Input wpm val (gets modified)
TIMER DS 1 ; Time baud * 8 counter
INCHAR DS 1 ; Input char holding reg
KYFIFO EQU $ ; Keyboard input buffer
PNFIFO EQU KYFIFO+BUFSKY ; Printer buffer
OTFIFO EQU PNFIFO+BUFSPN ; Output buffer
MSSGBF EQU OTFIFO+BUFOUT ; Message buffer
;
END