; ZMP180B3.Z80 -- SB180 computer overlay file for ZMP -- 10/15/88
;
; This file adapts ZMP13 to the SB180/FX computer; HD64180 ASCII port 0.
;
; Assemble with ZAS or SLR180
;
;
; vB.3  Added fixes outlined in ZMP-OVL.UPD for ZMP13  10/15/88  John Fort
;
; vB.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
;
; vB.1  Beta-test version 1                     09/24/88  Bill Biersdorf
;       -- works with 9 MHz SB180-FX
;       -- no provisions for stop bit, word length, or parity change
;
;
; System-dependent installation overlay for ZMP
; Author: Ron Murray
;
;    Insert your own code as necessary in this file. Code contained herein
; has been written in HD64180 code for use with ZAS.  Assemble with the h
; option to create a .HEX file, and use MLOAD to overlay it over the main
; ZMPX.COM file to produce your very own ZMP.COM.
;
; Notes on modifying this file:
;    Hi-Tech C requires that functions do not change either index register
; (IX or IY). If your overlay requires either of these to be changed, ensure
; they are restored to their original values on return.
;    Since collecting parameters from C functions can be tricky, only change
; the parts marked 'Insert your own code here'. Do NOT modify the jump
; table at the start. Do NOT modify the entry/exit sections of each
; function. Do NOT pass 'GO'. Do NOT collect $200.
;    Apart from defining modem functions, this file also defines terminal
; characteristics. Most have been set up for ADM-3A (with a few of my own
; additions). Modify to suit your own terminal. An inline print routine
; is provided for printing strings in the usual way: usage is
;
;       call    print
;       db      'required string',0
;
;    Don't forget to set your clock speed at the Select-a-speed section.
; Set only one of cpu12, cpu9, or cpu6 to true.  Set 'dtrfx' to true for
; your SB180-FX for proper DTR operation.
;
;    If you find your overlay exceeds the maximum size (currently 0400h),
; you will have to re-compile the whole thing. Good luck. You might try
; informing us if you need to do this: if too many people need to do it, we
; haven't allowed enough room.
;
; Ron Murray 15/8/88
;

;Some fundamental truths

false   equ     00h
true    equ     not false

;Select-a-speed                 ; NOTE: set only ONE of the following to true

cpu12   equ     false           ; 12.288 MHz HD64180
cpu9    equ     true            ; 9.216 MHz HD64180
cpu6    equ     false           ; 6.144 MHz HD64180

;Control latch dtr

dtrfx   equ     false           ; 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

mspeed  equ     003ch           ; Current baud rate: as used by BYE etc
                               ; This MUST be the same as Mspeed in
                               ; ZMP.H

userdef equ     0145h           ; origin of this overlay: get this value
                               ; from the .SYM file produced when ZMP.COM
                               ; is linked
ovsize  equ     0400h           ; max size of this overlay


       .hd64                   ; use HD64180 code
;;      aseg                    ; absolute

       org     userdef

esc     equ     1bh
ctrlq   equ     11h
cr      equ     0dh
lf      equ     0ah
bdos    equ     5


;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           ; 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
; Spare jumps for compatiblity with future versions.
       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

;
; Main code starts here
;
codebgn equ     $

;
;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:
userin:
userout:
       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 TRUE (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 TRUE (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

                               ; <== 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
                               ; to 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 TRUE (1) in HL if error
mdmerr:
                               ; <== Insert your own code here

       xor     a               ; 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

;Initialise the UART
init:
       ld      hl,2            ; get parameters
       add     hl,sp
       ex      de,hl
       call    getparm         ; in HL
       ld      (brate),hl      ; baud rate
       ld      a,l             ; only 1 byte
       ld      (mspeed),a      ; save for future use
       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


initsio:                        ; using values below
       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
       ret

sbexit:
       call    print
       db      'That rate not supported by this system.',cr,lf,0
       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


;               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
;;
;;                              ; assume one
;;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

       ret


                               ; <== 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)


;****************************************************************************
; Video terminal sequences: these are for Televideo 950 -- 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)         ; same 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      01ah,0
       ret

;Highlight on:
invon:
       call    print
       db      esc,')',0
       ret

;Highlight off:
invoff:
       call    print
       db      esc,'(',0
       ret

;Turn off cursor:
hide:
       call    print
       db      esc,'.0',0
       ret

;Turn on cursor:
show:
       call    print
       db      esc,'.1',0
       ret

;Save cursor position:
savecu:
       ret

;Restore cursor position:
rescu:
       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 ********************************
; Don't change anything below this point.  We needed some assembly language
; stuff for speed, and this seemed like a good place to put it.

;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

outerval        equ     [clkspd / 10] + 10
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 loop
       djnz    wait11          ; decrement outer loop
       dec     hl
       ld      a,h
       or      l
       jr      nz,wait10
       pop     ix
       pop     de
       pop     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

        if     [$ - codebgn] gt ovsize
toobig: jp      errval          ; Overlay too large!
        endif

       end
lt in hl, address still in de
       ret

        if     [$ - codebgn] gt ovsize
toobig: jp      errval          ; Overlay too large!
        en