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-BW05.Z80 < prev    next >
Text File  |  1991-02-02  |  17KB  |  835 lines

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