;=============================================================================== ; 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 ; call prtchr ; print it ld a,10 ; 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 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