; PROGRAM: ZMO-TV05.Z80 ; AUTHOR: Michael Evenson ; VERSION: 1.5 ; DATE: 10 Nov, 1988 ;----------------------------------------------------------------------- ; This overlay is set up for Televideo TS80x(H) using modem port. ; Uses a Z80SIO AND A Z80CTC. ; flags must be set for Televideo TS806, TS816, or TS802(H) ; currently does not support TS803 (STI) or TS804 (MPM system) ;----------------------------------------------------------------------- ; 89/04/12 - Modified to ZMP v1.5 - George Conover ; 89/03/15 - Removed the beginning remarks to make the file ; smaller. If you need the remarks there are in the ; file ZMP-BLNK.Z80 - George Conover ; 89/03/14 - Modified to ZMP v1.4 - George Conover ; 88/11/10 - First version of this file - Michael Evenson ; ; Written by - ; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. ;----------------------------------------------------------------------- NO EQU 0 YES EQU NOT NO ; User-set variables: *********** CLKSPD EQU 4 ; Processor clock speed in MHz DEBUG EQU NO ;Set the following two equates to the drive and user area which will contain ; ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero ; (null) to locate them on the drive from which ZMP was invoked. OVERDRIVE EQU 'A' ; Drive to find overlay files on ('A'-'P') OVERUSER EQU 0 ; User area to find files ;------------------------------------------------------------------------------ ; NOT user-set variables USERDEF EQU 00145H ; origin of this overlay ; This address should remain constant ; with subsequent revisions. MSPEED EQU 003CH ; current baud rate id OVSIZE EQU 0400H ; max size of this overlay .Z80 ; use z80 code ASEG ; absolute IF DEBUG ORG 100H ; so you can debug it with cebug, zsid, etc ELSE ORG USERDEF ENDIF ; be sure to set the correct system and port identifier here ; (only one of each please) TS802 EQU YES TS806 EQU NO TS816 EQU NO MODEMP EQU YES PRINTP EQU NO ; ESC EQU 1BH CTRLQ EQU 11H CR EQU 0DH LF EQU 0AH BDOS EQU 5 ; Televideo specific equates ****************************************** IF TS802 IF MODEMP MDATA EQU 020H MSTAT EQU 022H CTC EQU 08H ELSE MDATA EQU 021H MSTAT EQU 023H CTC EQU 09H ENDIF ELSE IF TS806 IF MODEMP MDATA EQU 050H MSTAT EQU 052H CTC EQU 80H ELSE MDATA EQU 051H MSTAT EQU 053H CTC EQU 81H ENDIF ELSE IF TS816 IF MODEMP MDATA EQU 059H ; channel B MSTAT EQU 05BH CTC EQU C1H ; CTC 1 ELSE MDATA EQU 058H ; channel A MSTAT EQU 05AH CTC EQU C0H ; CTC 0 ENDIF ENDIF ENDIF ENDIF RDA EQU 0 TBE EQU 2 MODE EQU 47H ONHOOK EQU 7FH ONLINE EQU 80H ERROR EQU 70H BREAK EQU 0F8H RESET EQU 30H ; ****************************************** ; Main code starts here CODEBGN EQU $ ;Jump table for the overlay: do NOT change this JUMP_TAB: JP SCRNPR ; screen print JP MRD ; modem read with timeout JP MCHIN ; get a character from modem JP MCHOUT ; send a character to the modem JP MORDY ; test for tx buffer empty JP MIRDY ; test for character received JP SNDBRK ; send break JP CURSADD ; cursor addressing JP CLS ; clear screen JP INVON ; inverse video on JP INVOFF ; inverse video off JP HIDE ; hide cursor JP SHOW ; show cursor JP SAVECU ; save cursor position JP RESCU ; restore cursor position JP MINT ; service modem interrupt JP INVEC ; initialise interrupt vectors JP DINVEC ; de-initialise interrupt vectors JP MDMERR ; test uart flags for error JP DTRON ; turn DTR on JP DTROFF ; turn DTR OFF JP INIT ; initialise uart JP WAIT ; wait seconds JP MSWAIT ; wait milliseconds JP USERIN ; user-defined entry routine JP USEROUT ; user-defined exit routine JP GETVARS ; get system variables JP SETPORT ; Set port (0 or 1) ; ; Spare jumps for compatibility with future versions ; JP SPARE ; spare for later use JP SPARE ; spares for later use JP SPARE ; spares for later use JP SPARE ; spares for later use JP SPARE ; spares for later use JP SPARE ; spares for later use SPARE: RET ;------------------------------------------------------------------------- ;Screen print function SCRNPR: ; <== Insert your own code here CALL PRINT DB 'This function not supported.',CR,LF,0 ; <== End of your own code RET ;Get a character from the modem: return in HL MCHIN: PUSH BC ; <== Insert your own code here MCHIN2: IN A,(MSTAT) ; check for char waiting BIT RDA,A JR Z,MCHIN2 IN A,(MDATA) ; read the char ; <== End of your own code LD L,A ; put in HL LD H,0 OR A ; set/clear Z POP BC RET ;Send a character to the modem MCHOUT: LD HL,2 ; get the character ADD HL,SP LD A,(HL) ; <== Insert your own code here PUSH BC LD B,A ; save the char MCHOUT2: IN A,(MSTAT) ; check for uart ready BIT TBE,A JR Z,MCHOUT2 LD A,B ; char in a OUT (MDATA),A ; send it POP BC ; <== End of your own code RET ; done ;Test for output ready: return TRUE (1) in HL if ok MORDY: ; <== Insert your own code here LD HL,0 IN A,(MSTAT) BIT TBE,A ; transmit buffer empty JR Z,MORDY1 INC HL MORDY1: ; <== End of your own code LD A,L ; set/clear Z OR A RET ;Test for character at modem: return TRUE (1) in HL if so MIRDY: ; <== Insert your own code here LD HL,0 IN A,(MSTAT) BIT RDA,A ; received data available JR Z,MIRDY1 INC HL MIRDY1: ; <== End of your own code LD A,L ; set/clear Z OR A RET ;Send a break to the modem: leave empty if your system can't do it SNDBRK: ; <== Insert your own code here LD A,5 OUT (MSTAT),A LD A,BREAK ; F8 OUT (MSTAT),A LD HL,300 ; wait 300 mS CALL WAITHLMS LD A,5 OUT (MSTAT),A LD A,ONLINE ; 68 OUT (MSTAT),A LD A,3 OUT (MSTAT),A LD A,0E1H OUT (MSTAT),A ; E1 ; <== End of your own code RET ; ;Test UART flags for error: return TRUE (1) in HL if error. MDMERR: ; <== Insert your own code here LD HL,0 IN A,(MSTAT) AND ERROR JR Z,MDMER2 INC HL MDMER2: ; <== End of your own code LD A,L ; set/clear Z OR A RET ;Turn DTR ON DTRON: ; <== Insert your own code here LD A,5 OUT (MSTAT),A LD A,(COMBYT) ; get the one we used last time OR ONLINE ; 80h - set bit 7 high LD (COMBYT),A ; save it for next time OUT (MSTAT),A ; go ; <== End of your own code RET ;Turn DTR OFF DTROFF: ; <== Insert your own code here LD A,5 OUT (MSTAT),A LD A,(COMBYT) ; get the one we used last time AND ONHOOK ; 7Fh - clear bit 7 LD (COMBYT),A ; save it for next time OUT (MSTAT),A ; go ; <== End of your own code RET ;Initialise the SIO +++ ; The SIO is set up in four steps: ; 1) Reset ; 2) Reg 4 - clock, stop bits, parity ; 3) Reg 5 - dtr, Tx bits, Brk, TxEn, rts ; 4) Reg 3 - Rx bits, RxEn INIT: LD HL,2 ; get parameters ADD HL,SP EX DE,HL CALL GETPARM ; in HL LD (BRATE),HL ; baud rate CALL GETPARM LD (PARITY),HL ; parity CALL GETPARM LD (DATA),HL ; data bits CALL GETPARM LD (STOP),HL ; stop bits ; <== Insert your own code here ; using values below PUSH BC LD A,0 OUT (MSTAT),A ; point to reg 0 LD A,18H ; reset OUT (MSTAT),A ; *** step 1 LD A,4 ; point to wrt reg 4 OUT (MSTAT),A LD E,44H ; assume x16, 1 stop, No parity LD A,(STOP) ; set stop bits CP 2 ; set 2 if required JR NZ,SETPAR SET 3,E SETPAR: LD A,(PARITY) ; set parity bits CP 'O' JR NZ,SETPA2 SET 0,E ; ODD JR SETPA3 SETPA2: CP 'E' JR NZ,SETPA3 SET 0,E SET 1,E ; EVEN SETPA3: LD A,E OUT (MSTAT),A ; *** step 2 LD A,5 ; point to wrt reg 5 - dtr, Tx bits, etc OUT (MSTAT),A LD E,0EAH ; assume dtr, TX 8 bits, TxEn, rts LD A,(DATA) CP 7 JR NZ,SETBI2 RES 6,E ; 7 bits SETBI2: LD A,E OUT (MSTAT),A ; *** step 3 LD A,3 ; point to wrt reg 3 OUT (MSTAT),A LD E,0C1H ; assume 8 bits LD A,(DATA) CP 7 JR NZ,SETBI3 RES 7,E ; 7 bits SETBI3: LD A,E OUT (MSTAT),A ; *** step 4 SETBRATE: LD DE,(BRATE) ; get baud rate value (0-10) LD HL,BRVAL ADD HL,DE LD A,(HL) ; get value from table OR A ; 0 = not valid JR Z,SETBRX ; so quit LD A,MODE ; 47h OUT (CTC),A ; select the correct timer and mode of the CTC LD A,(HL) ; then get value back OUT (CTC),A ; do it LD A,(BRATE) LD (MSPEED),A ; tell zmp it's ok SETBRX: POP BC RET BRATE: DW 7 ; baud rate: PARITY: DW 'N' ; parity DATA: DW 8 ; data bits STOP: DW 1 ; stop bits COMBYT: DB 0EAH ; save it here ;Values for Z80CTC control reg for each baud rate: 0 if invalid BRVAL: DB 0 ; 110 0 DB 80H ; 300 1 DB 0 ; 450 2 DB 40H ; 600 3 DB 0 ; 710 4 DB 20H ; 1200 5 DB 10H ; 2400 6 DB 08H ; 4800 7 DB 04H ; 9600 8 DB 02H ; 19200 9 DB 0 ; 38400 10 DB 0 ; 57600 11 DB 0 ; 76800 12 ; ; Set the port. ZMP supplies either 0 or 1 as a parameter. ; setport: ld hl,2 ; get port number add hl,sp ex de,hl call getparm ; in HL (values are 0 and 1) ; <== Insert your own code here ; <== End of your own code ret ;**************************************************************************** ;Video terminal sequences: these are for Televideo TS950: Modify as you wish ;Cursor addressing: CURSADD: LD HL,2 ; get parameters ADD HL,SP EX DE,HL CALL GETPARM ; in HL LD (ROW),HL ; row CALL GETPARM LD (COL),HL ; column ; <== Insert your own code here ; using values in row and col CALL PRINT DB ESC,'=',0 ; ADM-3A leadin LD A,(ROW) ; row first ADD A,' ' ; add offset CALL COUT LD A,(COL) ; sane for column ADD A,' ' CALL COUT ; <== end of your own code RET ROW: DS 2 ; row COL: DS 2 ; column ;Clear screen: CLS: CALL PRINT DB ESC,'*',0 RET ;Inverse video on: INVON: CALL PRINT DB ESC,'G4',0 RET ;Inverse video off: INVOFF: CALL PRINT DB ESC,'G0',0 RET ;Turn off cursor: HIDE: CALL PRINT DB ESC,'.1',0 RET ;Turn on cursor: SHOW: CALL PRINT DB ESC,'.2',0 RET ;Save cursor position: SAVECU: RET ;Restore cursor position: RESCU: RET ;User-defined entry routine: leave empty if not used USERIN: RET ;User-defined exit routine: leave empty if not used USEROUT: RET ;**************************************************************************** ;Service modem interrupt: MINT: RET ; my system doesn't need this ;Initialise interrupt vectors: INVEC: RET ; ditto ;De-initialise interrupt vectors: DINVEC: RET ; ditto ;****************** End of user-defined code ******************************** ; Do not change anything below here. ;Modem character test for 100 ms MRD: PUSH BC ; save bc LD BC,100 ; set limit MRD1: CALL MIRDY ; char at modem? JR NZ,MRD2 ; yes, exit LD HL,1 ; else wait 1ms CALL WAITHLMS DEC BC ; loop till done LD A,B OR C JR NZ,MRD1 LD HL,0 ; none there, result=0 XOR A MRD2: POP BC RET ; Inline print routine: destroys A and HL PRINT: EX (SP),HL ; get address of string PLOOP: LD A,(HL) ; get next INC HL ; bump pointer OR A ; done if zero JR Z,PDONE CALL COUT ; else print JR PLOOP ; and loop PDONE: EX (SP),HL ; restore return address RET ; and quit ; ;Output a character in A to the console ; COUT: PUSH BC ; save regs PUSH DE PUSH HL LD E,A ; character to E LD C,2 CALL BDOS ; print it POP HL POP DE POP BC RET ;Wait(seconds) WAIT: LD HL,2 ADD HL,SP EX DE,HL ; get delay size CALL GETPARM ; fall thru to.. ;Wait seconds in HL WAITHLS: PUSH BC ; save bc PUSH DE ; de PUSH IX ; and ix LD IX,0 ; then point ix to 0 ; so we don't upset memory-mapped i/o ;Calculate values for loop constants. Need to have two loops to avoid ; 16-bit overflow with clock speeds above 9 MHz. OUTERVAL EQU (CLKSPD / 10) + 1 INNERVAL EQU (6667 / OUTERVAL) * CLKSPD WAIT10: LD B,OUTERVAL WAIT11: LD DE,INNERVAL WAIT12: BIT 0,(IX) ; time-wasters BIT 0,(IX) BIT 0,(IX) ; 20 T-states each BIT 0,(IX) BIT 0,(IX) BIT 0,(IX) DEC DE LD A,E LD A,D OR E JR NZ,WAIT12 ; 150 T-states per inner loop DJNZ WAIT11 ; decrement outer loop DEC HL ; ok, decrement count in hl LD A,H OR L JR NZ,WAIT10 POP IX ; done -- restore ix POP DE ; de POP BC ; and bc RET ;Wait milliseconds MSWAIT: LD HL,2 ADD HL,SP EX DE,HL ; get delay size CALL GETPARM ; fall thru to.. ;Wait milliseconds in HL WAITHLMS: PUSH DE W1MS0: LD DE,39 * CLKSPD W1MS1: DEC DE LD A,D OR E JR NZ,W1MS1 DEC HL LD A,H OR L JR NZ,W1MS0 POP DE RET ;Get next parameter from (de) into hl GETPARM: EX DE,HL ; get address into hl LD E,(HL) ; get lo INC HL LD D,(HL) ; then hi INC HL ; bump for next EX DE,HL ; result in hl, address still in de RET ; ;Get address of user-defined variables ; GETVARS: LD HL,USERVARS RET USERVARS: DW OVERDRIVE ; .OVR etc. drive/user DW OVERUSER IF ($ - CODEBGN) GT OVSIZE TOOBIG: JP ERRVAL ; Overlay too large! ENDIF END