You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

406 lines
9.7 KiB

;===============================================================================
; Talk - Bare minimum terminal interface
;
; Console talks to designated character device.
;
;===============================================================================
;
; Author: Wayne Warthen (wwarthen@gmail.com)
;_______________________________________________________________________________
;
; Usage:
; TALK TTY:|CRT:|BAT:|UC1:
;_______________________________________________________________________________
;
; Change Log:
;_______________________________________________________________________________
;
; ToDo:
; 1) Handle ZCPR devices somehow
;_______________________________________________________________________________
;
;===============================================================================
; Definitions
;===============================================================================
;
stksiz .equ $40 ; Working stack size
;
restart .equ $0000 ; CP/M restart vector
bdos .equ $0005 ; BDOS invocation vector
iobyte .equ $0003 ; IOBYTE address
;
const .equ $06 ; CBIOS CONST function dispatch table offset
conin .equ $09 ; CBIOS CONIN function dispatch table offset
conout .equ $0C ; CBIOS CONOUT function dispatch table offset
;
;===============================================================================
; Code Section
;===============================================================================
;
.org $100
;
; setup stack (save old value)
ld (stksav),sp ; save stack
ld sp,stack ; set new stack
;
; initialization
call init ; initialize
jr nz,exit ; abort if init fails
;
ld de,msghel ; hello message
call prtstr ; print it
;
; save active iobyte (console)
ld a,(iobyte) ; get active IOBYTE
ld (iobcon),a ; save it to iobcon
;
; parse command line
call parse ; parse command line
jr nz,exit ; abort if parse fails
;
; startup message
;
ld de,msgtlk1 ; message prefix
call prtstr ; print it
call prtstrz ; print dev name at HL
ld de,msgtlk2 ; message suffix
call prtstr ; print it
;
; do the real work
call talk ; do the real work
;
; restore original iobyte
ld a,(iobcon) ; load original iobyte
ld (iobyte),a
;
ld de,msgbye ; goodbye message
call prtstr ; print it
;
exit: ; clean up and return to command processor
;
call crlf ; formatting
;
ld sp,(stksav) ; restore stack
ret ; return to CP/M w/o reset
;
; Initialization
;
init:
; add check for RomWBW?
;
; locate cbios function table address
ld hl,(restart+1) ; load address of CP/M restart vector
ld de,-3 ; adjustment for start of table
add hl,de ; HL now has start of table
ld (cbftbl),hl ; save it
; return success
xor a
ret
;
; Parse command line
; If success, Z set and HL points to device name string (zero terminated)
; ... else NZ set.
;
parse:
;
ld hl,$81 ; point to start of command tail (after length byte)
call nonblank ; skip blanks
jp z,erruse ; no parms
;
ld c,0 ; current table entry
ex de,hl ; point to parm with de
ld hl,devtbl ; point to device table with hl
;
parse0: ; compare loop
push bc
push de
push hl
call strcmp ; compare strings
pop hl
pop de
pop bc
jr z,parse1 ; if Z, we have a match
inc c ; increment table entry
ld a,5 ; bump hl by
call addhl ; ... table entry size
ld a,c ; get the table entry num to A
cp 4 ; past end of table?
jr nz,parse0 ; loop till done
jp errprm ; handle parm error
;
parse1: ; handle match
ld a,c ; device num to A
ld (iobcom),a ; save as com device iobyte
; return success
xor a ; signal error
ret ; and return
;
; Main routine
;
talk: ; CON: --> UC1:
;
ld a,(iobcon) ; setup iobyte to read from CON:
ld (iobyte),a
;
call cbios ; check for char pending using cbios
.db const ; ... const function
or a ; set flags
jr z,next ; no char ready
call cbios ; read char using cbios
.db conin ; ... conin function
cp $1A ; check for exit request (ctrl+z)
ret z ; if so, bail out
;
push af ; save the char we read
ld a,(iobcom) ; setup iobyte to read from UC1:
ld (iobyte),a
pop af ; recover the character
;
ld c,a ; move it to C
call cbios ; write char using cbios
.db conout ; ... conout function
;
next: ; UC1: --> CON:
;
ld a,(iobcom) ; setup iobyte to read from com device
ld (iobyte),a
;
call cbios ; check for char pending using cbios
.db const ; ... const function
or a ; set flags
jr z,talk ; no char ready
call cbios ; read char using cbios
.db conin ; ... conin function
;
push af ; save the char we read
ld a,(iobcon) ; setup iobyte to read from CON:
ld (iobyte),a
pop af ; recover the character
;
ld c,a ; move it to C
call cbios ; write char using cbios
.db conout ; ... conout function
;
jr talk ; loop
;
;
; Print character in A without destroying any registers
;
prtchr:
push bc ; save registers
push de
push hl
ld e,a ; character to print in E
ld c,$02 ; BDOS function to output a character
call bdos ; do it
pop hl ; restore registers
pop de
pop bc
ret
;
; Print a '$' terminated string at (DE) without destroying any registers
;
prtstr:
push bc ; save registers
push de
push hl
ld c,$09 ; BDOS function to output a '$' terminated string
call bdos ; do it
pop hl ; restore registers
pop de
pop bc
ret
;
; Print a zero terminated string at (HL) without destroying any registers
;
prtstrz:
push hl
;
prtstrz1:
ld a,(hl) ; get next char
or a
jr z,prtstrz2
call prtchr
inc hl
jr prtstrz1
;
prtstrz2:
pop hl ; restore registers
ret
;
; Print the value in A in hex without destroying any registers
;
prthex:
push af ; save AF
push de ; save DE
call hexascii ; convert value in A to hex chars in DE
ld a,d ; get the high order hex char
call prtchr ; print it
ld a,e ; get the low order hex char
call prtchr ; print it
pop de ; restore DE
pop af ; restore AF
ret ; done
;
; Convert binary value in A to ascii hex characters in DE
;
hexascii:
ld d,a ; save A in D
call hexconv ; convert low nibble of A to hex
ld e,a ; save it in E
ld a,d ; get original value back
rlca ; rotate high order nibble to low bits
rlca
rlca
rlca
call hexconv ; convert nibble
ld d,a ; save it in D
ret ; done
;
; Convert low nibble of A to ascii hex
;
hexconv:
and $0F ; low nibble only
add a,$90
daa
adc a,$40
daa
ret
;
; Start a new line
;
crlf:
ld a,13 ; <CR>
call prtchr ; print it
ld a,10 ; <LF>
jr prtchr ; print it
;
; Get the next non-blank character from (HL).
;
nonblank:
ld a,(hl) ; load next character
or a ; string ends with a null
ret z ; if null, return pointing to null
cp ' ' ; check for blank
ret nz ; return if not blank
inc hl ; if blank, increment character pointer
jr nonblank ; and loop
;
; Check character at (DE) for delimiter.
;
delim: or a
ret z
cp ' ' ; blank
ret z
jr c,delim1 ; handle control characters
cp '=' ; equal
ret z
cp '_' ; underscore
ret z
cp '.' ; period
ret z
cp ':' ; colon
ret z
cp $3b ; semicolon
ret z
cp '<' ; less than
ret z
cp '>' ; greater than
ret
delim1:
; treat control chars as delimiters
xor a ; set Z
ret ; return
;
; Compare $ terminated strings at HL & DE
; If equal return with Z set, else NZ
;
strcmp:
;
ld a,(de) ; get current source char
cp (hl) ; compare to current dest char
ret nz ; compare failed, return with NZ
or a ; set flags
ret z ; end of string, match, return with Z set
inc de ; point to next char in source
inc hl ; point to next char in dest
jr strcmp ; loop till done
;
; Invoke CBIOS function
; The CBIOS function offset must be stored in the byte
; following the call instruction. ex:
; call cbios
; .db $0C ; offset of CONOUT CBIOS function
;
cbios:
ex (sp),hl
ld a,(hl) ; get the function offset
inc hl ; point past value following call instruction
ex (sp),hl ; put address back at top of stack and recover HL
ld hl,(cbftbl) ; address of CBIOS function table to HL
call addhl ; determine specific function address
jp (hl) ; invoke CBIOS
;
; Add the value in A to HL (HL := HL + A)
;
addhl:
add a,l ; A := A + L
ld l,a ; Put result back in L
ret nc ; if no carry, we are done
inc h ; if carry, increment H
ret ; and return
;
; Errors
;
erruse: ; command usage error (syntax)
ld de,msguse
jr err
errprm: ; command parameter error (syntax)
ld de,msgprm
jr err
err: ; print error string and return error signal
call crlf ; print newline
call prtstr ; print error string
or $FF ; signal error
ret ; done
errdos: ; handle BDOS errors
push af ; save return code
call crlf ; newline
ld de,msgdos ; load
call prtstr ; and print error string
pop af ; recover return code
call prthex ; print error code
or $FF ; signal error
ret ; done
;
;===============================================================================
; Storage Section
;===============================================================================
;
cbftbl .dw 0 ; address of CBIOS function table
;
iobcon .db 0 ; iobyte value for console
iobcom .db 0 ; iobyte value for com device
;
devtbl: ; device table
.db "TTY:",0
.db "CRT:",0
.db "BAT:",0
.db "UC1:",0
;
stksav .dw 0 ; stack pointer saved at start
.fill stksiz,0 ; stack
stack .equ $ ; stack top
;
; Messages
;
msghel .db 13,10,"Talk v1.0",13,10,"$"
msgbye .db 13,10,13,10,"*** Finished talking ***","$"
msgtlk1 .db 13,10,"Talking on device $"
msgtlk2 .db " (press <Ctrl+Z> to exit)...",13,10,13,10,"$"
msguse .db "Usage: TALK TTY:|CRT:|BAT:|UC1:$"
msgprm .db "Parameter error$"
msgdos .db "DOS error, return code=0x$"
;
.end