home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / BEEHIVE / COMMS / ZMP-OV16.ARC / ZMO-CP05.Z80 < prev    next >
Text File  |  1991-02-02  |  17KB  |  751 lines

  1. ;-----------------------------------------------------------------------------
  2. ;
  3. ;    Name    ZMO-CP05.Z80
  4. ;
  5. ;    Dated Sep 14, 1988
  6. ;
  7. ;    Written by -
  8. ;      Ron Murray, c/o Z-Node 62, 061-9-450-0200, Perth, Western Australia.
  9. ;
  10. ;    Modified to ZMP v1.2 standard rjm 15/9/88
  11. ;    Modified to ZMP v1.3 standard rjm 11/10/88
  12. ;    Modified to ZMP v1.4 standard rjm 20/11/88
  13. ;    Modified to ZMP v1.5 standard rjm 25/3/89
  14. ;
  15. ;    This overlay is set up for an Amstrad CPC6128 under CPM Plus, with a
  16. ;      Zenith Z19/Z29 terminal emulation and a Z80SIO and 8253 counter.
  17. ;
  18. ;-----------------------------------------------------------------------------
  19. ;
  20. ;    System-dependent code overlay for ZMODEM
  21. ;
  22. ;
  23. ;    Insert your own code as necessary in this file. Code contained herein
  24. ; has been written in Z80 code for use with M80 or SLR. Assemble as follows:
  25. ;
  26. ;    SLR ZMO-xx01/h
  27. ;    MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX
  28. ; or
  29. ;    M80 =ZMO-xx01.Z80
  30. ;    RELHEX ZMO-xx01
  31. ;    MLOAD ZMP.COM=ZMODEM.COM,ZMO-xx01.HEX
  32. ;
  33. ;
  34. ;       (Don't use L80 without changing the source for assembly as a
  35. ;         cseg file.)
  36. ;
  37. ;-----------------------------------------------------------------------------
  38. ;
  39. ;
  40. ; Notes on modifying this file:
  41. ;
  42. ;    C requires that functions do not change either index register (IX or IY).
  43. ; If your overlay requires either of these to be changed, ensure they are
  44. ; restored to the original values on return.
  45. ;    Since collecting parameters from C functions can be tricky, only change
  46. ; the parts marked 'Insert your own code here'. Do NOT modify the jump
  47. ; table at the start. Do NOT modify the entry/exit sections of each
  48. ; function. Do NOT pass 'GO'. Do NOT collect $200.
  49. ;    Apart from defining modem functions, this file also defines terminal
  50. ; characteristics. Examples provided are for ADM-3A (with a few of my own
  51. ; additions). Modify to suit your own terminal. An inline print routine
  52. ; is provided for printing strings in the usual way: usage is
  53. ;
  54. ;    call    print
  55. ;    db    'required string',0
  56. ;
  57. ;-----------------------------------------------------------------------------
  58. ;
  59. ;
  60. ;    Don't forget to set your clock speed at the clkspd variable.
  61. ;
  62. ;
  63. ;    If you find your overlay exceeds the maximum size (currently 0400h),
  64. ; you will have to contact me for another version. If too many people need 
  65. ; to do it, we haven't allowed enough room.
  66. ;
  67. ; Ron Murray 15/8/88
  68. ;
  69. ;
  70. ;
  71. ;---------------------------------------------------------------------------
  72.  
  73. false    equ    0
  74. true    equ    not false
  75.  
  76. ;------------------------------------------------------------------------------
  77.  
  78. ; User-set variables: 
  79.  
  80. clkspd    equ    4        ; Processor clock speed in MHz
  81. debug    equ    false        ; to allow debugging of overlay with Z8E etc.
  82.  
  83. ;Set the following two equates to the drive and user area which will contain
  84. ;   ZMP's .OVR files, .CFG file, .FON file and .HLP file. Set both to zero
  85. ;   (null) to locate them on the drive from which ZMP was invoked.
  86.  
  87. overdrive    equ    'A'    ; Drive to find overlay files on ('A'-'P')
  88. overuser    equ    0    ; User area to find files
  89.  
  90. ;------------------------------------------------------------------------------
  91.  
  92.  
  93. ; NOT user-set variables
  94.  
  95. userdef    equ    0145h        ; origin of this overlay
  96.                 ; This address should not change with
  97.                 ; subsequent revisions.
  98. mspeed    equ    03ch        ; location of current baud rate. 
  99. ovsize    equ    0400h        ; max size of this overlay
  100.  
  101.     .z80            ; use z80 code
  102.     aseg            ; absolute
  103.  
  104.      if    debug
  105.     org    100h        ; so you can debug it with cebug, zsid, etc
  106.      else
  107.     org    userdef
  108.      endif
  109.  
  110.  
  111. esc    equ    1bh
  112. ctrlq    equ    11h
  113. cr    equ    0dh
  114. lf    equ    0ah
  115. bdos    equ    5
  116. ;--------------------------------------------------------------------
  117. mdata    equ    0FADCH        ; data port  \_A port
  118. mstat    equ    0FADDH        ; status port/
  119.  
  120. mdatab    equ    0FADEH        ; data port  \_B port
  121. mstatb    equ    0FADFH        ; status port/
  122.  
  123. rda    equ    0        ; Received data available
  124. tbe    equ    2        ; Tx ready
  125. error    equ    70h
  126. break    equ    0F8h
  127.  
  128. ; 8253 Counter equates
  129.  
  130. ctcont    equ    0FBDFH        ; Control register of the 8253
  131.  
  132. ctc0    equ    0FBDCH        ; Counter #0 of the 8253\_A port 
  133. ctc1    equ    0FBDDH        ; Counter #1 '   '   '  /
  134.  
  135. ctc2    equ    0FBDEH        ; Conuter #2 '   '   ' ---B port
  136. ;------------------------------------------------------
  137. codebgn    equ    $
  138.  
  139. ;Jump table for the overlay: do NOT change this
  140. jump_tab:
  141.     jp    scrnpr        ; screen print
  142.     jp    mrd        ; modem read with timeout
  143.     jp    mchin        ; get a character from modem
  144.     jp    mchout        ; send a character to the modem
  145.     jp    mordy        ; test for tx buffer empty
  146.     jp    mirdy        ; test for character received
  147.     jp    sndbrk        ; send break
  148.     jp    cursadd        ; cursor addressing
  149.     jp    cls        ; clear screen
  150.     jp    invon        ; inverse video on
  151.     jp    invoff        ; inverse video off
  152.     jp    hide        ; hide cursor
  153.     jp    show        ; show cursor
  154.     jp    savecu        ; save cursor position
  155.     jp    rescu        ; restore cursor position
  156.     jp    mint        ; service modem interrupt
  157.     jp    invec        ; initialise interrupt vectors
  158.     jp    dinvec        ; de-initialise interrupt vectors
  159.     jp    mdmerr        ; test uart flags for error
  160.     jp    dtron        ; turn DTR on
  161.     jp    dtroff        ; turn DTR OFF
  162.     jp    init        ; initialise uart
  163.     jp    wait        ; wait seconds
  164.     jp    mswait        ; wait milliseconds
  165.     jp    userin        ; user-defined entry routine
  166.     jp    userout        ; user-defined exit routine
  167.     jp    getvars        ; get system variables
  168.     jp    setport        ; set port (1 or 2)
  169.  
  170. ; Spare jumps for compatibility with future versions
  171.     jp    spare        ; spare for later use
  172.     jp    spare        ; spare for later use
  173.     jp    spare        ; spare for later use
  174.     jp    spare        ; spare for later use
  175.     jp    spare        ; spare for later use
  176.     jp    spare        ; spare for later use
  177.  
  178. ;
  179. ; Main code starts here
  180. ;
  181. ;Screen print function
  182. scrnpr:
  183.                 ; <== Insert your own code here
  184.     call    print
  185.     db    'This function not supported.',cr,lf,0
  186.                 ; <== End of your own code
  187. spare:
  188.     ret
  189.  
  190. ; User-defined entry routine: leave empty if not needed
  191. userin:
  192.     ret
  193.  
  194. ; User-defined exit routine: leave empty if not needed
  195. userout:
  196.     ret
  197.  
  198.  
  199. ;Get a character from the modem: return in HL
  200. mchin:    push    bc
  201.                 ; <== Insert your own code here
  202.     ld    bc,(status)
  203. mchin2:    in    a,(c)        ; check for byte waiting
  204.     bit    rda,a
  205.     jr    z,mchin2
  206.     ld    bc,(portadd)
  207.     in    a,(c)        ; read in the byte
  208.  
  209.                 ; <== End of your own code
  210.     ld    l,a        ; put in HL
  211.     ld    h,0
  212.     or    a        ; set/clear Z
  213.     pop    bc
  214.     ret
  215.  
  216. ;Send a character to the modem
  217. mchout:
  218.     ld    hl,2        ; get the character
  219.     add    hl,sp
  220.     ld    a,(hl)
  221.                 ; <== Insert your own code here
  222.     push    bc
  223.     ld    bc,(status)
  224. mchout2:in    e,(c)        ; check for uart ready
  225.     bit    tbe,e
  226.     jr    z,mchout2
  227.     ld    bc,(portadd)
  228.     out    (c),a        ; send it
  229.     pop    bc
  230.                 ; <== End of your own code
  231.  
  232.     ret            ; done
  233.  
  234. ;Test for output ready: return TRUE (1) in HL if ok
  235. mordy:
  236.                 ; <== Insert your own code here
  237.     push    bc
  238.     ld    bc,(status)
  239.     ld    hl,0
  240.     in    a,(c)
  241.     bit    tbe,a        ; transmit buffer empty
  242.     jr    z,mordy1
  243.     inc    hl
  244. mordy1:    pop    bc
  245.                 ; <== End of your own code
  246.  
  247.     ld    a,l        ; set/clear Z
  248.     or    a
  249.     ret
  250.  
  251. ;Test for character at modem: return TRUE (1) in HL if so
  252. mirdy:
  253.                 ; <== Insert your own code here
  254.     push    bc
  255.     ld    bc,(status)
  256.     ld    hl,0
  257.     in    a,(c)
  258.     bit    rda,a        ; received data available
  259.     jr    z,mirdy1
  260.     inc    hl
  261. mirdy1:    pop    bc
  262.                 ; <== End of your own code
  263.  
  264.     ld    a,l        ; set/clear Z
  265.     or    a
  266.     ret
  267.  
  268. ;Send a break to the modem: leave empty if your system can't do it
  269. sndbrk:
  270.                 ; <== Insert your own code here
  271.  
  272.     ld    hl,300        ; wait 300 mS
  273.     call    waithlms
  274.  
  275.                 ; <== End of your own code
  276.     ret
  277. ;
  278. ;Test UART flags for error: return TRUE (1) in HL if error.
  279. mdmerr:
  280.                 ; <== Insert your own code here
  281.     push    bc
  282.     ld    bc,(status)
  283.     ld    hl,0
  284.     in    a,(c)
  285.        and    a,error
  286.     jr    z,mdmer2
  287.     inc    hl
  288. mdmer2:    pop    bc
  289.                 ; <== End of your own code
  290.  
  291.     ld    a,l        ; set/clear Z
  292.     or    a
  293.     ret
  294.  
  295.  
  296. ;Turn DTR ON
  297. dtron:
  298.             ; <== Insert your own code here
  299.     push    bc
  300.     ld    bc,(status)
  301.     ld    a,5
  302.     out    (c),a
  303.     ld    a,(combyt)    ; get the value of byte
  304.     set    7,a        ; set bit 7
  305.     out    (c),a        ; go
  306.     pop    bc        ;
  307.  
  308.                 ; <== End of your own code
  309.     ret
  310.  
  311. ;Turn DTR OFF
  312. dtroff:
  313.                 ; <== Insert your own code here
  314.     push    bc
  315.     ld    bc,(status)
  316.     ld    a,5
  317.     out    (c),a
  318.     ld    a,(combyt)    ; get the one we used last time
  319.     res    7,a        ; clear bit 7
  320.     out    (c),a        ; go
  321.     pop    bc
  322.                 ; <== End of your own code
  323.     ret
  324.  
  325. ;Initialise the SIO +++
  326. ; The SIO is set up in four steps:
  327. ;     1)  Reset
  328. ;       2)  Reg 4 - clock, stop bits, parity
  329. ;    3)  Reg 5 - dtr, Tx bits, Brk, TxEn, rts
  330. ;    4)  Reg 3 - Rx bits, RxEn
  331.  
  332. init:    ld    hl,2        ; get parameters
  333.     add    hl,sp
  334.     ex    de,hl
  335.     call    getparm        ; in HL
  336.     ld    (brate),hl    ; baud rate
  337.     call    getparm
  338.     ld    (parity),hl    ; parity
  339.     call    getparm
  340.     ld    (data),hl    ; data bits (BINARY 7 or 8)
  341.     call    getparm
  342.     ld    (stop),hl    ; stop bits (BINARY 1 or 2)
  343.  
  344.                 ; <== Insert your own code here
  345.     push    bc
  346.     push    ix
  347.     ld    bc,(status)
  348.     ld    a,0
  349.     out    (c),a        ; point to reg 0
  350.     ld    a,18h        ; reset
  351.     out    (c),a        ;                *** step 1
  352.  
  353.     ld    a,4        ; point to wrt reg 4
  354.     out    (c),a
  355.     ld    e,44H        ; assume  x16, 1 stop, No parity
  356.     ld    a,(stop)    ; set stop bits
  357.     cp    2        ; set 2 if required
  358.     jr    nz,setpar
  359.     ld    a,08h        ; 0000 1000
  360.     or    e
  361.     ld    e,a
  362. setpar:    ld    a,(parity)    ; set parity bits
  363.     cp    'O'
  364.     jr    nz,setpa2
  365.     ld    d,01h        ; 0000 0001    ODD
  366.     jr    setpa3
  367. setpa2:    cp    'E'
  368.     jr    nz,setpa4
  369.     ld    d,03h        ; 0000 0011    EVEN
  370. setpa3:    ld    a,e
  371.     or    a,d
  372.     ld    e,a
  373. setpa4:    ld    a,e
  374.     out    (c),a        ;                *** step 2
  375.  
  376.     ld    a,5        ; point to wrt reg 5 - dtr, Tx bits, etc
  377.     out    (c),a
  378.     ld    e,0EAH        ; assume dtr, TX 8 bits, TxEn, rts 1110 1010
  379.     ld    a,(data)
  380.     cp    7
  381.     jr    nz,setbi2
  382.     ld    d,0AAH        ; 1010 1010    7 bits
  383. setbi2:    ld    a,e
  384.     out    (c),a
  385.     ld    (combyt),a    ; This byte used for DTR on/off *** step 3
  386.  
  387.     ld    a,3        ; point to wrt reg 3
  388.     out    (c),a
  389.     ld    e,0C1H        ; assume 8 bits 1100 0001
  390.     ld    a,(data)
  391.     cp    7
  392.     jr    nz,setbi3
  393.     ld    d,041H        ; 7 bits 0100 0001
  394. setbi3:    ld    a,e
  395.     out    (c),a        ;                *** step 4
  396.  
  397. setbrate:
  398.     ld    de,(brate)    ; get baud rate value (0-10)
  399.     ld    ix,brval
  400.     add    ix,de
  401.     add    ix,de        ; ix now points to the 2-byte value
  402.     ld    a,(ix)        ; if zero,
  403.     or    (ix+1)
  404.     jr    z,setbrx    ; it's not valid
  405.  
  406.     ld    a,(port)    ; check to see which port to be setup
  407.     cp    1
  408.     jr    z,setupb
  409.  
  410.     ld    bc,ctcont
  411.     ld    a,36h
  412.     out    (c),a
  413.     ld    bc,ctc0
  414.     ld    a,(ix)
  415.     out    (c),a        ; lo byte
  416.     ld    a,(ix+1) 
  417.     out    (c),a        ; hi byte
  418.     ld    bc,ctcont
  419.     ld    a,76h
  420.     out    (c),a
  421.     ld    bc,ctc1
  422.     ld    a,(ix)
  423.     out    (c),a        ; lo byte
  424.     ld    a,(ix+1)
  425.     out    (c),a        ; hi byte
  426.     ld    a,(brate)    ; tell zmp it's valid
  427.  
  428.                 ; Using values below
  429.     ld    (mspeed),a    ; don't forget to load mspeed with the
  430.                 ; current brate value if the new rate is
  431.                 ; valid. See table of values below.
  432. setbrx:    pop    ix
  433.     pop    bc
  434.     ret
  435.  
  436. setupb:    ld    bc,ctcont
  437.     ld    a,0B6H
  438.     out    (c),a
  439.     ld    bc,ctc2
  440.     ld    a,(ix)
  441.     out    (c),a        ; lo byte
  442.     ld    a,(ix+1) 
  443.     out    (c),a        ; hi byte
  444.     ld    a,(brate)    ; tell zmp it's valid
  445.  
  446.                 ; Using values below
  447.     ld    (mspeed),a    ; don't forget to load mspeed with the
  448.                 ; current brate value if the new rate is
  449.                 ; valid. See table of values below.
  450.     pop    ix
  451.     pop    bc
  452.                 ; <== End of your own code
  453.     ret
  454. ;--------------------------------------------------------------------------
  455. ; ZMP will default to the values here, when assembled
  456. ;
  457. brate:    dw    5        ; baud rate
  458. parity:    dw    'N'        ; parity
  459. data:    dw    8        ; data bits
  460. stop:    dw    1        ; stop bits
  461. combyt    ds    1        ; used for DTR on/off
  462.  
  463. ;Values for 8253 control reg for each baud rate: 0 if invalid
  464.  
  465. brval:    dw    470H    ;   110        0
  466.     dw    1A1H    ;   300        1
  467.     dw    116H    ;   450        2
  468.     dw    0D0H    ;   600        3
  469.     dw    0B0H    ;   710        4
  470.     dw    068H    ;  1200        5
  471.     dw    034H    ;  2400        6
  472.     dw    01AH    ;  4800        7
  473.     dw    00DH    ;  9600        8
  474.     dw    007H    ; 19200        9 
  475.     dw    003H    ; 38400        10
  476.     dw    0    ; 57600        11
  477.     dw    0    ; 76800        12
  478. ;-----------------------------------------------------------------------
  479. ; Set the port. ZMP supplies either 0 or 1 as a parameter. You're on your
  480. ; own here -- your system is bound to be different from any other! You may
  481. ; implement a software switch on all the modem-dependent routines, or perhaps
  482. ; you can have one or two centralised routines for accessing the UARTs and
  483. ; modify the code from this routine to select one or the other. (Who said
  484. ; there was anything wrong with self-modifying code?). If you have only one
  485. ; UART port, or if you don't want to go through all the hassles, just have
  486. ; this routine returning with no changes made. Note that ZMP calls this
  487. ; routine with both values for the port on initialisation.
  488. ;
  489. setport:
  490.     ld    hl,2        ; get port number
  491.     add    hl,sp
  492.     ex    de,hl
  493.     call    getparm        ; in HL (values are 0 and 1)
  494.  
  495.                 ; <== Insert your own code here
  496.     ld    a,l
  497.     ld    (port),a
  498.     cp    1
  499.     jr    z,setb
  500.  
  501.     ld    hl,mdata
  502.     ld    (portadd),hl
  503.     inc    hl
  504.     ld    (status),hl
  505.     ret
  506.  
  507. setb:    ld    hl,mdatab
  508.     ld    (portadd),hl
  509.     inc    hl
  510.     ld    (status),hl
  511.  
  512.                 ; <== End of your own code
  513.     ret
  514.  
  515. port:    ds    1
  516. portadd:ds    2        ; Store address of SIO data address
  517. status:    ds    2        ; Store address of SIO status address
  518.  
  519. ;****************************************************************************
  520. ;Video terminal sequences: these are for Heath/Zenith Z19/Z29:
  521. ; Modify as you wish
  522.  
  523. ;Cursor addressing:
  524.  
  525. cursadd:
  526.     ld    hl,2        ; get parameters
  527.     add    hl,sp
  528.     ex    de,hl
  529.     call    getparm        ; in HL
  530.     ld    (row),hl    ; row
  531.     call    getparm
  532.     ld    (col),hl    ; column
  533.                 ; <== Insert your own code here
  534.  
  535.     call    print
  536.     db    esc,'Y',0    ; leadin
  537.     ld    a,(row)        ; row first
  538.     add    a,' '        ; add offset
  539.     call    cout
  540.     ld    a,(col)        ; sane for column
  541.     add    a,' '
  542.     call    cout
  543.                 ; <== end of your own code
  544.     ret
  545.  
  546. row:    ds    2        ; row
  547. col:    ds    2        ; column
  548.  
  549.  
  550. ;Clear screen:
  551. cls:    call    print
  552.     db    esc,'E',esc,'H',0
  553.     ret
  554.  
  555. ;Inverse video on:
  556. invon:    call    print
  557.     db    esc,'p',0
  558.     ret
  559.  
  560. ;Inverse video off:
  561. invoff:    call    print
  562.     db    esc,'q',0
  563.     ret
  564.  
  565. ;Turn off cursor:
  566. hide:    call    print
  567.     db    esc,'f',0
  568.     ret
  569.  
  570. ;Turn on cursor:
  571. show:    call    print
  572.     db    esc,'e',0
  573.     ret
  574.  
  575. ;Save cursor position:
  576. savecu:    call    print
  577.     db    esc,'j',0
  578.     ret
  579.  
  580. ;Restore cursor position:
  581. rescu:    call    print
  582.     db    esc,'k',0
  583.     ret
  584.  
  585. ;****************************************************************************
  586.  
  587. ;Service modem interrupt:
  588. mint:
  589.     ret            ; my system doesn't need this
  590.  
  591. ;Initialise interrupt vectors:
  592. invec:
  593.     ret            ; ditto
  594.  
  595. ;De-initialise interrupt vectors:
  596. dinvec:
  597.     ret            ; ditto
  598.  
  599. ;****************** End of user-defined code ********************************
  600. ;        Do not change anything below here.
  601.  
  602. ;Modem character test for 100 ms
  603. mrd:
  604.     push    bc        ; save bc
  605.     ld    bc,100        ; set limit
  606. mrd1:
  607.     call    mirdy        ; char at modem?
  608.     jr    nz,mrd2        ; yes, exit
  609.     ld    hl,1        ; else wait 1ms
  610.     call    waithlms
  611.     dec    bc        ; loop till done
  612.     ld    a,b
  613.     or    c
  614.     jr    nz,mrd1
  615.     ld    hl,0        ; none there, result=0
  616.     xor    a
  617. mrd2:
  618.     pop    bc
  619.     ret
  620.  
  621. ; Inline print routine: destroys A and HL
  622.  
  623. print:
  624.     ex    (sp),hl        ; get address of string
  625. ploop:
  626.     ld    a,(hl)        ; get next
  627.     inc    hl        ; bump pointer
  628.     or    a        ; done if zero
  629.     jr    z,pdone
  630.     call    cout        ; else print
  631.     jr    ploop        ; and loop
  632. pdone:
  633.     ex    (sp),hl        ; restore return address
  634.     ret            ; and quit
  635.  
  636. ;
  637. ;Output a character in A to the console
  638. ;
  639. cout:
  640.     push    bc        ; save regs
  641.     push    de
  642.     push    hl
  643.     ld    e,a        ; character to E
  644.     ld    c,2
  645.     call    bdos        ; print it
  646.     pop    hl
  647.     pop    de
  648.     pop    bc
  649.     ret
  650.  
  651. ;Wait(seconds)
  652. wait:
  653.     ld    hl,2
  654.     add    hl,sp
  655.     ex    de,hl        ; get delay size
  656.     call    getparm
  657.                 ; fall thru to..
  658. ;Wait seconds in HL
  659. waithls:
  660.     push    bc        ; save bc
  661.     push    de        ; de
  662.     push    ix        ; and ix
  663.     ld    ix,0        ; then point ix to 0
  664.                 ; so we don't upset memory-mapped i/o
  665.  
  666. ;Calculate values for loop constants. Need to have two loops to avoid
  667. ;   16-bit overflow with clock speeds above 9 MHz.
  668.  
  669. outerval    equ    (clkspd / 10) + 1
  670. innerval    equ    (6667 / outerval) * clkspd
  671.  
  672. wait10:
  673.     ld    b,outerval
  674.  
  675. wait11:
  676.     ld    de,innerval
  677.  
  678. wait12:
  679.     bit    0,(ix)        ; time-wasters
  680.     bit    0,(ix)
  681.     bit    0,(ix)        ; 20 T-states each
  682.     bit    0,(ix)
  683.     bit    0,(ix)
  684.     bit    0,(ix)
  685.     dec    de
  686.     ld    a,e
  687.     ld    a,d
  688.     or    e
  689.     jr    nz,wait12    ; 150 T-states per inner loop
  690.     djnz    wait11        ; decrement outer loop
  691.     dec    hl        ; ok, decrement count in hl
  692.     ld    a,h
  693.     or    l
  694.     jr    nz,wait10
  695.     pop    ix        ; done -- restore ix
  696.     pop    de        ; de
  697.     pop    bc        ; and bc
  698.     ret
  699.  
  700. ;Wait milliseconds
  701. mswait:
  702.     ld    hl,2
  703.     add    hl,sp
  704.     ex    de,hl        ; get delay size
  705.     call    getparm
  706.                 ; fall thru to..
  707. ;Wait milliseconds in HL
  708. waithlms:
  709.     push    de
  710. w1ms0:
  711.     ld    de,39 * clkspd
  712. w1ms1:
  713.     dec    de
  714.     ld    a,d
  715.     or    e
  716.     jr    nz,w1ms1
  717.     dec    hl
  718.     ld    a,h
  719.     or    l
  720.     jr    nz,w1ms0
  721.     pop    de
  722.     ret
  723.  
  724. ;Get next parameter from (de) into hl
  725. getparm:
  726.     ex    de,hl        ; get address into hl
  727.     ld    e,(hl)        ; get lo
  728.     inc    hl
  729.     ld    d,(hl)        ; then hi
  730.     inc    hl        ; bump for next
  731.     ex    de,hl        ; result in hl, address still in de
  732.     ret
  733.  
  734. ;Get address of user-defined variables
  735.  
  736. getvars:
  737.     ld    hl,uservars
  738.     ret
  739.  
  740. uservars:
  741.     dw    overdrive    ; .OVR etc. drive/user
  742.     dw    overuser
  743.  
  744.  
  745.      if    ($ - codebgn) gt ovsize
  746. toobig:    jp    errval        ; Overlay too large!
  747.      endif
  748.  
  749.     end
  750.