.TITLE 'ZMP Overlay for Hitachi HD64180 version 1.0' NAME SB180 ; PROGRAM: ZMO-1805.Z80 ; AUTHOR: Bill Biersdorf ; VERSION: 1.5 ; DATE: 14 Sept, 1988 ;----------------------------------------------------------------------- ; This overlay is set up for a SB180-FX computer ; HD64180 ASCII port 0. ; This file is a BETA-TEST version, known only to work on 9 MHz 'FX. ; Assemble with ZAS. ;----------------------------------------------------------------------- ; 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/02 - Modified to ZMP v1.4 - George Conover ; 88/10/10 - Modified to ZMP v1.3 - Ron Murray ; 88/09/15 - Modified to ZMP v1.2 - Ron Murray ; 88/10/13 - First version of this file - Bill Biersdorf ; ; Written by - ; Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia. ;----------------------------------------------------------------------- ; B.2.4 Beta-test version 2 03/02/89 George Conover ; -- Updated to ZMP14 ; -- Tested with Micromint SB180 cpu speed 6.1 Mhz ; ; Modified to v1.3 standard Ron Murray 13/10/88 ; ; B.2 Beta-test version 2 09/27/88 Bill Biersdorf ; -- added conditionals for clock speeds ; -- added equate 'dtrfx' for latch DTR on the 'FX ; -- character framing may work on non-FX, not sure ; ; B.1 Beta-test version 1 09/24/88 Bill Biersdorf ; -- works with 9 MHz SB180-FX ; -- no provisions for stop bit, word length, or paity change ; ;----------------------------------------------------------------------- NO DEFL 0 YES DEFL NOT NO ; ; This file is assembled with ZAS .XLIST ; .SALL ; Suppress macro listing .HD64 ; Use HD64180 opcodes MACLIB Z3BASE ; ZCPR3 equates .LIST ; ; ; Select-a-speed ; NOTE: set only ONE of the following ; ; to YES ; CPU12 DEFL NO ; 12.288 MHz HD64180 CPU9 DEFL NO ; 9.216 MHz HD64180 CPU6 DEFL YES ; 6.144 MHz HD64180 ; ; Control latch DTR ; DTRFX DEFL NO ; Otherwise just use RTS code ; ; User-set variables: ; IPORT EQU 08H ; MODEM data in port OPORT EQU 06H ; MODEM data out port CPORT EQU 00H ; MODEM control port MSTAT EQU 04H ; MODEM status port BPORT EQU 02H ; MODEM baudrate port MDRCV EQU 80H ; Receive ready bit MDSND EQU 02H ; Send ready bit ; IF CPU12 CLKSPD EQU 12 ENDIF ; IF CPU9 CLKSPD EQU 9 ENDIF ; IF CPU6 CLKSPD EQU 6 ; Processor clock speed in MHz ENDIF ; ;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 0 ; Drive to find overlay files on ('A'-'P') OVERUSER EQU 0 ; User area to find files ;------------------------------------------------------------------------------ ; NOT user-set variables USERDEF EQU 0145H ; origin of this overlay ; This address should not change with ; subsequent revisions. MSPEED EQU 03CH ; location of current baud rate. OVSIZE EQU 0400H ; Max size of this overlay ; ; ESC EQU 1BH CR EQU 0DH LF EQU 0AH BDOS EQU 5 ORG USERDEF ; ;Jump table for the overlay: do NOT change this ; JUMPTAB: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 ; Highlight (inverse video) on JP INVOFF ; Highlight (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 (and RTS) ON JP DTROFF ; Turn DTR (and RTS) 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 ; spare for later use JP SPARE ; spare for later use JP SPARE ; spare for later use JP SPARE ; spare for later use JP SPARE ; spare for later use ; ; Main code starts here ; ; ; Main code starts here ; CODEBGN; ; ; Screen print function ; SCRNPR: ; ; <== Insert your own code here ; CALL PRINT DB CR,LF DB 'Screen-print function not supported.',CR,LF,LF DB 0 ; ; <== End of your own code ; SPARE: RET ; Disable and Enable PUBLIC ZRDOS directories ; Set the Z3ENV equate to the address of your environment ; descriptor, then set the relevant bits in PUBDRV and PUBDIR ; in accordance with this table: ; drive byte (126) user byte (127) ; ---------------- --------------- ; bit: 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 ; | | | | | | | | | | | | | | | | ; drive: H G F E D C B A user #: 8 7 6 5 4 3 2 1 ;Z3ENV EQU 0FE00H ; adjust as required PUBDRV EQU 00000001B ; drive A set PUBLIC PUBDIR EQU 00000111B ; users 1, 2, and 3 set PUBLIC ; User-defined entry routine: leave empty if not needed USERIN: LD HL,Z3ENV+126 ; point HL at PUBLIC assignment buffer XOR A ; zero accumulator LD (HL),A ; store zero to first byte of buffer INC HL ; point to second byte of buffer LD (HL),A ; zero it too RET ; User-defined exit routine: leave empty if not needed USEROUT: LD HL,Z3ENV+126 ; point HL at PUBLIC assignment buffer LD A,PUBDRV ; get drive code in A LD (HL),A ; set first byte to PUBLIC drive INC HL ; point to second byte of buffer LD A,PUBDIR ; get user code in A LD (HL),A ; set second byte to PUBLIC user RET ; ; Get a character from the modem: return in HL ; It is not necessary to test for status ; MCHIN: PUSH BC ; ; <== Insert your own code here ; IN0 A,(IPORT) ; To get the character in A ; ; <== 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) ; In A ; ; <== Insert your own code here ; OUT0 (OPORT),A ; ; <== End of your own code ; RET ; Done ; ; Test for output ready: return YES (1) in HL if ok ; MORDY: ; ; <== Insert your own code here ; LD HL,00H ; Assume not ready for now IN0 A,(MSTAT) IN0 A,(MSTAT) ; Do twice for valid DCD AND MDSND JR Z,MORDY1 ; Still not ready INC HL ; Ready, so set HL ; MORDY1: ; ; <== End of your own code ; LD A,L ; Set/clear Z OR A RET ; ; Test for character at modem: return YES (1) in HL if so ; MIRDY: ; ; <== Insert your own code here ; LD HL,00H ; Assume not ready for now IN0 A,(MSTAT) IN0 A,(MSTAT) ; Do twice for valid DCD AND MDRCV JR Z,MIRDY1 ; Still not ready INC HL ; Ready, so set 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, tTo go to 'break' level ; ; <== End of your own code ; LD HL,300 CALL WAITHLMS ; Wait 300 ms ; ; <== Insert your own code here, to restore ; ; <== End of your own code ; RET ; ; Test UART flags for error: return YES (1) in HL if error ; MDMERR: ; ; <== Insert your own code here ; LD HL,00H ; Not yet implemented ; ; <== End of your own code ; LD A,L ; Set/clear Z OR A RET ; ; Turn DTR (and RTS) ON. (reset) ; DTRON: ; ; <== Insert your own code here ; IN0 A,(CPORT) AND 0EFH ; RTS on OUT0 (CPORT),A ; IF DTRFX CALL DTRSTAT ; Pull control latch LD A,10111111B ; Mask off DTR bit AND B ; And it out LD B,A LD A,0FFH ; Set up for write LD HL,(1) ; Get address of BIOS LD L,3FH ; Add offset for control latch LD DE,DTRDONE PUSH DE ; Save return vector JP (HL) ; Go to the latch routine ENDIF ; IF NOT DTRFX ; RET ENDIF ; ; <== End of your own code ; ; Turn DTR (and RTS) OFF. (set) ; DTROFF: ; ; <== Insert your own code here ; IN0 A,(CPORT) OR 10H ; RTS off OUT0 (CPORT),A ; IF DTRFX CALL DTRSTAT ; Pull control latch LD A,01000000B ; Mask off DTR bit OR B ; Or it in LD B,A LD A,0FFH ; Set up for write LD HL,(1) ; Get address of BIOS LD L,3FH ; Add offset for control latch LD DE,DTRDONE PUSH DE ; Save return vector JP (HL) ; Go to the latch routine ENDIF ; IF NOT DTRFX ; RET ENDIF ; ; <== End of your own code ; DTRDONE:RET ; ; Needed to prevent changes to other control latch registers. ; IF DTRFX DTRSTAT:XOR A LD HL,(1) ; Get address of BIOS LD L,3FH ; Add offset of control latch JP (HL) ; Go get status ENDIF ; ; Initializ the UART ; 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 ; CALL INITSIO CALL SETBAUD ; Go set baud ;; CALL SETPRTY ; " " parity ;; CALL SETSTOP ; " " stop bits ;; CALL WLENGTH ; " " word length ; CALL PRINT DB CR,LF,0 RET ; Continue ; ; Using values below ; INITSIO: IN0 A,(CPORT) AND 0EFH ; RTS on OR 68H ; Enable xmit, receive; clear errors OUT0 (CPORT),A RET ; SETBAUD:LD A,(BRATE) ; Get BRATE into A LD E,A ; And DE LD D,0 LD HL,DIVISORS ; Get offset into baudrate divisor table ADD HL,DE LD A,(HL) ; Fetch code OR A ; 00h means upsupported code JR Z,SBEXIT ; Exit if bad OUT0 (BPORT),A ; Else set baud LD A,(BRATE) ; Tell zmp it's ok LD (MSPEED),A ; SBEXIT: RET ; DIVISORS: ; IF CPU12 ; 12.288 MHz clock DB 00H,0EH,00H ; 0 = 110 baud 1 = 300 baud 2 = 450 baud DB 0DH,00H,06H ; 3 = 600 baud 4 = 710 baud 5 = 1200 baud DB 05H,04H,03H ; 6 = 2400 baud 7 = 4800 baud 8 = 9600 baud DB 02H ; 9 = 19200 baud ENDIF ; IF CPU9 ; 9.216 MHz clock DB 00H,26H,00H ; 0 = 110 baud 1 = 300 baud 2 = 450 baud DB 25H,00H,24H ; 3 = 600 baud 4 = 710 baud 5 = 1200 baud DB 23H,22H,21H ; 6 = 2400 baud 7 = 4800 baud 8 = 9600 baud DB 20H ; 9 = 19200 baud ENDIF ; IF CPU6 ; 6.144 MHz clock DB 00H,0DH,00H ; 0 = 110 baud 1 = 300 baud 2 = 450 baud DB 06H,00H,05H ; 3 = 600 baud 4 = 710 baud 5 = 1200 baud DB 04H,03H,02H ; 6 = 2400 baud 7 = 4800 baud 8 = 9600 baud DB 01H ; 9 = 19200 baud ENDIF ; DB 0,0,0 ; 10 = 38400 baud 11 = 57600 baud ; ; 12 = 76800 baud ; ; Parity is controlled by bit 1 of CPORT and bit 4 of BPORT as follows: ; ; BPORT CPORT ; Parity Bit 4 Bit 1 ; Off - 0 ; Odd 1 1 ; Even 0 1 ; SETPRTY: ;; ld a,(parity) ; get parity into A ;; cp 'E' ;; jr z,prevn ; even ;; cp 'O' ;; jr z,prodd ; odd ;; ;; ; else assume none ;;proff: in0 a,(cport) ;; and 0fdh ; reset bit 1 ;; push af ; save ;; in0 a,(bport) ;; jr prnxt ;; ;;prevn: in0 a,(cport) ;; or 02h ; set bit 1 ;; push af ; save ;; in0 a,(bport) ;; and 0efh ; reset bit 4 ;; jr prnxt ;; ;;prodd: in0 a,(cport) ;; or 02h ; set bit 1 ;; push af ; save ;; in0 a,(bport) ;; or 10h ; set bit 4 ;; ;;prnxt: ;; out0 (bport),a ; set for (even) or (odd) ;; pop af ;; out0 (cport),a ; set for (even/odd) or (none) ;; call initsio ; reset the UART RET ; The number of stop bits is controlled by bit ; 0 of CPORT, as follows: ; ; Stop bits Bit 0 ; 1 0 ; 2 1 ; ;;;SETSTOP: ;;; LD A,(STOP) ; get stopbits into A ;;; CP 2 ;;; JR Z,STOP2 ; two ; ;;;STOP1: IN0 A,(CPORT) ;;; AND 0FEH ; reset bit 0 ;;; JR SSNXT ; ;;;STOP2: IN0 A,(CPORT) ;;; OR 01H ; set bit 0 ; ;;;SSNXT: OUT0 (CPORT),A ;;; CALL INITSIO ; reset the UART ; RET ; ; The number of bits per character is controlled by bit 2 of CPORT as ; follows: ; ; BPC Bit 2 ; 7 0 ; 8 1 ; ;;;WLENGTH: ;;; LD A,(DATA) ; get word length ;;; CP 7 ;;; JR Z,WLEN7 ; 7 ; ; assume 8 ;;;WLEN8: IN0 A,(CPORT) ;;; OR 04H ; set bit 2 ;;; JR WLNXT ; ;;;WLEN7: IN0 A,(CPORT) ;;; AND 0FBH ; reset bit 2 ; ;;;WLNXT: OUT0 (CPORT),A ;;; CALL INITSIO ; reset the UART ; ; <== End of your own code ; RET ; BRATE: DS 2 ; Baud rate: ; 0 = 110 baud 1 = 300 baud 2 = 450 baud ; 3 = 600 baud 4 = 710 baud 5 = 1200 baud ; 6 = 2400 baud 7 = 4800 baud 8 = 9600 baud ; 9 = 19200 baud PARITY: DS 2 ; Parity (will be 'N', 'E' or 'O') DATA: DS 2 ; Data bits (will be 7 or 8) STOP: DS 2 ; Stop bits (will be 1 or 2) ; ; 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 VT-100 -- Modify as you ; wish ; ;Cursor addressing: ; CURSADD: LD HL,2 ; Get parameters ADD HL,SP EX DE,HL CALL GETPARM ; In HL INC HL LD (ROW),HL ; Row CALL GETPARM INC HL LD (COL),HL ; Column ; ; <== Insert your own code here, Using values in row and col ; CALL PRINT DB ESC,'[',0 ; Cursor leadin LD HL,(ROW) ; Row first CALL NOUT ; output in decimal LD A,';' ; follow with semicolon CALL COUT ; print it LD HL,(COL) ; Same for column CALL NOUT LD A,'H' ; terminate with 'move cursor' command CALL COUT ; print it ; ; <== end of your own code ; RET ; ROW: DS 2 ; Row COL: DS 2 ; Column ; ; Clear screen: ; CLS: CALL PRINT DB ESC,'[2J' ;clear whole screen DB ESC,'[H',0 ;HOME RET ; ; Highlight on: ; INVON: CALL PRINT DB ESC,'[0;1m',0 RET ; ; Highlight off: ; INVOFF: CALL PRINT DB ESC,'[0m',0 RET ; ; Turn off cursor: ; HIDE: RET ; ; Turn on cursor: ; SHOW: RET ; ; Save cursor position: ; SAVECU: CALL PRINT DB ESC,'7',0 RET ; ; Restore cursor position: ; RESCU: CALL PRINT DB ESC,'8',0 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 ; ; This routine prints the number in HL on the screen in decimal. ; Uses all ACs. NOUT: LD BC,-10 ; Get some useful constants. NOUT1: LD DE,-1 NOUT2: ADD HL,BC ; Subtract as many 10s as possible. INC DE ; Count them. JP C,NOUT2 ; If some left keep going. PUSH HL ; Save remainder - 10 EX DE,HL ; Swap the remainder and the quotient. LD A,H ; Get the number of 10s found. OR L ; Check for quotient non zero CALL NZ,NOUT1 ; If non zero, recurse. POP HL ; Get the remainder - 10 LD A,L ; In a ADD A,'0'+10 ; Make the number printable and add the 10 back JP COUT ; output the digit and return ; ; 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 registers 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 ; ; 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 low INC HL LD D,(HL) ; Then hihi 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 is too large ENDIF ; END