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

  1. ;-----------------------------------------------------------------------
  2. ;    Amstrad PCW8000 Overlay for ZMP (Z-Modem Program)  Jul 6, 89
  3. ;
  4. ;    Name    ZMO-PW05.Z80
  5. ;
  6. ;    Dated Jul 6, 1989
  7. ;
  8. ;    Modified from ZMP-BLNK.Z80 by Nigel Dallard
  9. ;
  10. ;    NOTE:    As supplied in the ZMP15.LBR library, ZMP-BLNK.Z80
  11. ;    would not assemble with M80. M80 objected to the hyphen in the
  12. ;    filename, and to the labels WAITHLS and WAITHLMS which it
  13. ;    thought were the same label. To enable M80 to assemble the file
  14. ;    the name should be changed. The offending labels have been changed
  15. ;    to WAITSHL and WAITMSHL.
  16. ;    The conditional assembly portion at the end of the file was also
  17. ;    removed since it included a call to a non-existant label. This
  18. ;    does not affect the program assuming the code is within the
  19. ;    specified size limitation.
  20. ;    The code as supplied did not initialise the serial port on entry.
  21. ;    The routine USERIN is used to call the INIT routine part way
  22. ;    through to cure this.
  23. ;
  24. ;     * EXPLANATORY NOTE: this file uses BDOS calls to access the PCW
  25. ;       hardware. Amstrad CP/M-80 version 1.4 (current) is said to have
  26. ;       interrupt buffering which helps to overcome the "lost character"
  27. ;       problem at 2400 baud. Apparently Amstrad did this without much
  28. ;       if any publicity.....  Up-grade to 1.4 if you can find a copy.
  29. ;       The direct command "ESC-0" can be used to disable the status 
  30. ;       line; this also speeds up screen handling....  Try it.
  31. ;       The overlay also handles split baud rates as used in UK;
  32. ;       1200 RX 75 TX or vice-versa. Ignore if you don't need this.
  33. ;       Sorry; this file does NOT work on the CPC 6128 machine, (why ?)
  34. ;                          John Crux 17 March 1990 *
  35. ;
  36. ;-----------------------------------------------------------------------
  37. ;
  38. ;    System-dependent code overlay for ZMODEM
  39. ;
  40. ; Assemble as follows:
  41. ;
  42. ;    M80 =ZMOPW05 
  43. ;    RELHEX ZMOPW05 
  44. ;    MLOAD ZMP.COM=ZMPX.COM,ZMOPW05.HEX
  45. ;  * or ZASM ZMO-PW05 HEX; MLOAD as before  (Cromemco ZASM works OK) *
  46. ;  * or ZSM ZMO-PW05; MLOAD as before * 
  47. ; (Don't use L80 without changing the source  for  assembly  as  a  CSEG
  48. ; file.)
  49. ;
  50. ;-----------------------------------------------------------------------
  51. ;
  52. ; Notes on modifying this file:
  53. ;
  54. ;    C    requires  that functions do not change either index register (IX
  55. ; or IY). If your overlay requires either of these to be changed, ensure
  56. ; they are restored to the original values on return.
  57. ;
  58. ; An  inline print routine is provided for printing strings in the usual
  59. ; way, usage is:
  60. ;
  61. ;              CALL    PRINT
  62. ;              DB    'required string',0
  63. ;
  64. ;-----------------------------------------------------------------------
  65. ;
  66. ;    Don't forget to set your clock speed at the clkspd variable.
  67. ;
  68. ;-----------------------------------------------------------------------
  69. ;
  70. NO    EQU    0
  71. YES    EQU    NOT NO
  72. ;
  73. ;
  74. ; User-set variables:
  75. ;
  76. CLKSPD    EQU    4        ; Processor clock speed in MHz
  77. DEBUG    EQU    NO        ; To allow debugging of overlay with
  78. ;                ; Z8E etc.
  79. ;
  80. ;
  81. ; Set the following two equates to the drive and user area which will
  82. ; contain ZMP's .OVR files, .CFG file, .FON file and .HLP file.  Set
  83. ; both to zero (null) to locate them on the drive from which ZMP was
  84. ; invoked.
  85. ;
  86. OVERDRIVE EQU    0        ; Drive to find overlay files on ('A'-'P')
  87. OVERUSER EQU    0        ; User area to find files
  88. ;
  89. ;-----------------------------------------------------------------------
  90. ;
  91. ; NOT user-set variables
  92. ;
  93. USERDEF    EQU    0145H        ; Origin of this overlay.  This address
  94. ;                ;   should not change with subsequent
  95. ;                ;   revisions.
  96. MSPEED    EQU    03CH        ; Location of current baud rate
  97. OVSIZE    EQU    0400H        ; Maximum size of this overlay
  98. ;
  99. ;    .Z80            ; Use Z80 code (for M80)
  100. ;
  101. ;    ASEG            ; Absolute     (for M80)
  102. ;
  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. ESC    EQU    1BH
  111. CTRLQ    EQU    11H
  112. CR    EQU    0DH
  113. LF    EQU    0AH
  114. BDOS    EQU    5
  115. ;
  116. ;-----------------------------------------------------------------------
  117. ;
  118. ;Jump table for the overlay: do NOT change this
  119. ;
  120. JUMPTAB:JP    SCRNPR        ; Screen print
  121.     JP    MRD        ; Modem read with timeout
  122.     JP    MCHIN        ; Get a character from modem
  123.     JP    MCHOUT        ; Send a character to the modem
  124.     JP    MORDY        ; Test for tx buffer empty
  125.     JP    MIRDY        ; Test for character received
  126.     JP    SNDBRK        ; Send break
  127.     JP    CURSADD        ; Cursor addressing
  128.     JP    CLS        ; Clear screen
  129.     JP    INVON        ; Inverse video on
  130.     JP    INVOFF        ; Inverse video off
  131.     JP    HIDE        ; Hide cursor
  132.     JP    SHOW        ; Show cursor
  133.     JP    SAVECU        ; Save cursor position
  134.     JP    RESCU        ; Restore cursor position
  135.     JP    MINT        ; Service modem interrupt
  136.     JP    INVEC        ; Initialise interrupt vectors
  137.     JP    DINVEC        ; De-initialise interrupt vectors
  138.     JP    MDMERR        ; Test uart flags for error
  139.     JP    DTRON        ; Turn DTR on
  140.     JP    DTROFF        ; Turn DTR OFF
  141.     JP    INIT        ; Initialise uart
  142.     JP    WAIT        ; Wait seconds
  143.     JP    MSWAIT        ; Wait milliseconds
  144.     JP    USERIN        ; User-defined entry routine
  145.     JP    USEROUT        ; User-defined exit routine
  146.     JP    GETVARS        ; Get system variables
  147.     JP    SETPORT        ; Set the modem port being used
  148. ;
  149. ; Spare jumps for compatibility with future versions
  150. ;
  151.     JP    SPARE        ; Spare for later use
  152.     JP    SPARE        ; Spare for later use
  153.     JP    SPARE        ; Spare for later use
  154.     JP    SPARE        ; Spare for later use
  155.     JP    SPARE        ; Spare for later use
  156.     JP    SPARE        ; Spare for later use
  157. ;
  158. ;-----------------------------------------------------------------------
  159. ;
  160. ; Main code starts here
  161. ;
  162. ; Screen print function
  163. ;
  164. SCRNPR:    PUSH    AF        ; save registers
  165.     PUSH    BC
  166.     PUSH    DE
  167.     PUSH    HL
  168.         CALL    PRINT        ; print message
  169.     DB    CR,LF,'Press <EXTRA>+<PTR> for a screen dump.',CR,LF,0
  170.     POP    HL        ; restore registers
  171.     POP    DE
  172.     POP    BC
  173.     POP    AF
  174. ;
  175. SPARE:    RET
  176. ;
  177. ; User-defined entry routine: used by ND to initialise UART on entry
  178. ;
  179. USERIN:    CALL    INIT2
  180.     RET
  181. ;
  182. ; User-defined exit routine: leave empty if not needed
  183. ;
  184. USEROUT:RET
  185. ;
  186. ; Get a character from the modem: return in HL
  187. ;
  188. MCHIN:    PUSH    BC
  189. ;
  190. ; <== Start of user-defined code
  191. ;
  192.     PUSH    DE        ; save all unused registers
  193.     PUSH    IX
  194.     PUSH    IY
  195.     LD    C,3        ; use BDOS to get a character from AUXIN:
  196.     CALL    BDOS        ;   and put it in A
  197.     POP    IY        ; restore registers
  198.     POP    IX
  199.     POP    DE
  200. ;
  201. ; <== End of user-defined code
  202. ;
  203.     LD    L,A        ; Put in HL
  204.     LD    H,0
  205.     OR    A        ; Set/clear Z
  206.     POP    BC
  207.     RET
  208. ;
  209. ; Send a character to the modem
  210. ;
  211. MCHOUT:    LD    HL,2        ; Get the character
  212.     ADD    HL,SP
  213.     LD    A,(HL)
  214. ;
  215. ; <== Start of user-defined code
  216. ;
  217.     PUSH    BC        ; save unused registers
  218.     PUSH    DE
  219.     PUSH    IX
  220.     PUSH    IY
  221.     LD    E,A        ; move character to E
  222.     LD    C,4        ; let BDOS pass the character to AUXOUT:
  223.     CALL    BDOS
  224.     POP    IY        ; restore registers
  225.     POP    IX
  226.     POP    DE
  227.     POP    BC
  228. ;
  229. ; <== End of user-defined code
  230. ;
  231.     RET            ; Done
  232. ;
  233. ; Test for output ready: return TRUE (1) in HL if ok
  234. ;
  235. MORDY:    DS    0
  236. ;
  237. ; <== Start of user-defined code
  238. ;
  239.     PUSH    BC        ; save registers
  240.     PUSH    DE
  241.     PUSH    IX
  242.     PUSH    IY
  243.     LD    C,8        ; ask BDOS if AUXOUT: is ready
  244.     CALL    BDOS        ; BDOS returns with A=FFh if so
  245.     LD    H,0        ; set HL accordingly
  246.     AND    1
  247.     LD    L,A
  248.     POP    IY        ;restore registers
  249.     POP    IX
  250.     POP    DE
  251.     POP    BC
  252. ;
  253. ; <== End of user-defined code
  254. ;                ; NB next 2 lines commented out by ND 6/7/89
  255.     LD    A,L        ; Set/clear Z
  256.     OR    A
  257.     RET
  258. ;
  259. ; Test for character at modem: return TRUE (1) in HL if so
  260. ;
  261. MIRDY:    DS    0
  262. ;
  263. ; <== Start of user-defined code
  264. ;
  265.     PUSH    BC        ; save registers
  266.     PUSH    DE
  267.     PUSH    IX
  268.     PUSH    IY
  269.     LD    C,7        ; ask BDOS if AUXIN: is ready
  270.     CALL    BDOS        ; BDOS returns A=FFh if so
  271.     LD    H,0        ; set HL accordingly
  272.     AND    1
  273.     LD    L,A
  274.     POP    IY        ; restore registers
  275.     POP    IX
  276.     POP    DE
  277.     POP    BC
  278. ;
  279. ; <== End of user-defined code
  280. ;                ; NB next 2 lines commented out by ND 6/7/89
  281.     LD    A,L        ; Set/clear Z
  282.     OR    A
  283.     RET
  284. ;
  285. ; Send a break to the modem: leave empty if your system can't do it
  286. ;
  287. SNDBRK:    DS    0
  288. ;
  289. ; <== Start of user-defined code
  290. ;
  291. ;    The PCW BDOS/BIOS doesn't allow you to send a BREAK.
  292. ;       (except by directly driving the hardware....)
  293. ; <== End of user-defined code
  294. ;
  295.     RET
  296. ;
  297. ; Test UART flags for error: return TRUE (1) in HL if error.
  298. ;
  299. MDMERR:    DS    0
  300. ;
  301. ; <== Start of user-defined code
  302. ;
  303.     LD    HL,0        ; Serial errors are dealt with by BDOS
  304. ;
  305. ; <== End of user-defined code
  306. ;
  307.     LD    A,L        ; Set/clear Z
  308.     OR    A
  309.     RET
  310. ;
  311. ;
  312. ; Turn DTR ON
  313. ;
  314. DTRON:    DS    0
  315. ;
  316. ; <== Start of user-defined code
  317. ;
  318.     PUSH    AF        ; save registers
  319.     PUSH    BC
  320.     PUSH    DE
  321.     PUSH    HL
  322.     PUSH    IX
  323.     PUSH    IY
  324.     LD    A,80H        ; ask the BIOS to drop DTR
  325.     CALL    SIOSET
  326.     POP    IY        ; restore registers
  327.     POP    IX
  328.     POP    HL
  329.     POP    DE
  330.     POP    BC
  331.     POP    AF
  332. ;
  333. ; <== End of user-defined code
  334. ;
  335.     RET
  336. ;
  337. ;
  338. ; Turn DTR OFF
  339. ;
  340. DTROFF:    DS    0
  341. ;
  342. ; <== Start of user-defined code
  343. ;
  344.     PUSH    AF        ; save registers
  345.     PUSH    BC
  346.     PUSH    DE
  347.     PUSH    HL
  348.     PUSH    IX
  349.     PUSH    IY
  350.     LD    A,7FH        ; ask BIOS to raise DTR
  351.     CALL    SIOSET
  352.     POP    IY        ; restore registers
  353.     POP    IX
  354.     POP    HL
  355.     POP    DE
  356.     POP    BC
  357.     POP    AF
  358. ;
  359. ; <== End of user-defined code
  360. ;
  361.     RET
  362. ;
  363. ; Initialise the uart
  364. ;
  365. INIT:    LD    HL,2        ; Get parameters
  366.     ADD    HL,SP
  367.     EX    DE,HL
  368.     CALL    GETPARM        ; In HL
  369.     LD    (BRATE),HL    ; Baud rate
  370.     CALL    GETPARM
  371.     LD    (PARITY),HL    ; Parity
  372.     CALL    GETPARM
  373.     LD    (DATA),HL    ; Data bits (BINARY 7 or 8)
  374.     CALL    GETPARM
  375.     LD    (STOP),HL    ; Stop bits (BINARY 1 or 2)
  376. ;
  377. ; <== Start of user-defined code
  378. ;
  379. ;    LD    (MSPEED),A    ; Don't forget to load mspeed with the
  380. ;                ;   Current BRATE value if the new rate
  381. ;                ;   is valid.  See table of values below.
  382. ;
  383. INIT2:    PUSH    AF        ; save registers
  384.     PUSH    BC
  385.     PUSH    DE
  386.     PUSH    HL
  387.     PUSH    IX
  388.     PUSH    IY
  389.  
  390.     LD    HL,(1)        ; get address of WBOOT entry in BIOS jump table
  391.     LD    DE,87        ; calculate the address of the USERF entry
  392.     ADD    HL,DE
  393.     LD    (PARMS+1),HL    ; modify the jump instruction at PARMS
  394.  
  395.     LD    HL,(BRATE)    ; HL = baud-rate code
  396.     ADD    HL,HL        ; double it
  397.     LD    BC,BRTBL    ; BC = base of baud-rate look-up table
  398.     ADD    HL,BC        ; HL points to entry in look-up table
  399.     LD    E,(HL)        ; E = encoded tx baud rate
  400.     INC    HL
  401.     LD    D,(HL)        ; D = encoded rx baud rate
  402.     LD    A,E        ; encoded tx baud rate of 0 => not supported
  403.     OR    A
  404.     JR    NZ,SETBD    ; if not supported, print message & leave
  405.     CALL    PRINT        ;   baud rate set as present.
  406.     DB    'Baud Rate not supported.',CR,LF,0
  407.     JR    CHKPAR
  408. SETBD:    EX    DE,HL        ; HL = encoded baud-rates
  409.     CALL    BAUD        ; let BIOS set the baud-rate
  410.     LD    A,(BRATE)    ; adjust the ZMP modem speed variable
  411.     LD    (MSPEED),A
  412.     JR    CHKPAR        ; go on to set the rest of the uart parameters
  413.  
  414. BRTBL:    DB    03H,03H        ; 110 baud
  415.     DB    06H,06H        ; 300 baud
  416.     DB    08H,02H        ; 450 baud [ actually used for 7512 ]
  417.     DB    07H,07H        ; 600 baud
  418.     DB    02H,08H        ; 710 baud [ actually used for 1275 ]
  419.     DB    08H,08H        ; 1200 baud
  420.     DB    0AH,0AH        ; 2400 baud
  421.     DB    0CH,0CH        ; 4800 baud
  422.     DB    0EH,0EH        ; 9600 baud
  423.     DB    0FH,0FH        ; 19200 baud
  424.     DB    00H,00H        ; 38400 baud
  425.     DB    00H,00H        ; 57600 baud
  426.     DB    00H,00H        ; 76800 baud
  427.  
  428. CHKPAR:    LD    A,(PARITY)    ; A = parity value
  429.     CP    'N'
  430.     JR    NZ,NOTNONE
  431.     LD    E,0        ; no parity => E = 0
  432.     JR    CHKDATA
  433. NOTNONE:CP    'O'
  434.     JR    NZ,NOTODD
  435.     LD    E,1        ; odd parity => E = 1
  436.     JR    CHKDATA
  437. NOTODD:    LD    E,2        ; even parity => E = 2
  438.  
  439. CHKDATA:LD    A,(DATA)    ; A = number of data bits
  440.     LD    H,A        ; H = rx data bits
  441.     LD    L,A        ; L = tx data bits
  442.  
  443.     LD    A,(STOP)    ; A = number of stop bits
  444.     CP    1
  445.     JR    NZ,STOP2
  446.     LD    D,0        ; 1 stop bit => D = 0
  447.     JR    SETSIO
  448. STOP2:    LD    D,2        ; 2 stop bits => D = 2
  449.  
  450. SETSIO:    LD    A,0FEH        ; sio mode = interrupt, no handshake
  451.     CALL    SIOSET        ; let BIOS set up the sio port
  452.  
  453.     POP    IY        ; restore registers
  454.     POP    IX
  455.     POP    HL
  456.     POP    DE
  457.     POP    BC
  458.     POP    AF
  459.     RET
  460.  
  461. BAUD:    CALL    PARMS        ; set the baud rate
  462.     DW    00B9H        ;   via extended BIOS function B9h
  463.     RET
  464.  
  465. SIOSET:    CALL    PARMS        ; set the sio parameters
  466.     DW    00B6H        ;   via extended BIOS function B6h
  467.     RET
  468.  
  469. PARMS:    JP    0        ; BIOS entry point to set sio parameters
  470.                 ;  and baud rate. The code self-modifies
  471.                 ;  itself to provide the correct address.
  472. ;
  473. ; <== End of user-defined code
  474. ;                ; NB the next line was commented out by ND 6/7/89
  475. ;    RET
  476. ;
  477. ;-----------------------------------------------------------------------
  478. ;
  479. STOP:    DW    1        ; Stop bits
  480. PARITY:    DW    'N'        ; Parity
  481. DATA:    DW    8        ; Data bits
  482. BRATE:    DW    6        ; Baud rate:
  483. ;
  484. ;-----------------------------------------------------------------------
  485. ;
  486. ; Values of BRATE for each baud rate
  487. ;
  488. ; baud rate    BRATE
  489. ;
  490. ;   110      0
  491. ;   300      1
  492. ;   450      2
  493. ;   600      3
  494. ;   710      4
  495. ;  1200      5
  496. ;  2400      6
  497. ;  4800      7
  498. ;  9600      8
  499. ; 19200      9
  500. ; 38400     10
  501. ; 57600     11
  502. ; 76800     12
  503. ;
  504. ;-----------------------------------------------------------------------
  505. ;
  506. ; Set the port. ZMP supplies either 0 or 1 as a parameter. If you only
  507. ; have one UART port, or if you don't want to go through all the hassles
  508. ; just have this routine returning with no changes made. Note that ZMP
  509. ; calls this routine twice -- once for each port value -- on
  510. ; initialisation.
  511. ;
  512. SETPORT:LD    HL,2        ; Get port number
  513.     ADD    HL,SP
  514.     EX    DE,HL
  515.     CALL    GETPARM        ; In HL (values are 0 and 1)
  516. ;
  517. ;  <== Start of user defined code
  518. ;
  519. ;    Only one serial port on the PCW.
  520. ;
  521. ;  <== End of user defined code
  522. ;
  523.     RET
  524. ;
  525. PORT:    DS    1
  526. ;-----------------------------------------------------------------------
  527. ;
  528. ; Video terminal sequences: these are for Amstrad PCW8000 series
  529. ;
  530. ; Cursor addressing:
  531. ;
  532. CURSADD:LD    HL,2        ; Get parameters
  533.     ADD    HL,SP
  534.     EX    DE,HL
  535.     CALL    GETPARM        ; In HL
  536.     LD    (ROW),HL    ; Row
  537.     CALL    GETPARM
  538.     LD    (COL),HL    ; Column
  539. ;
  540. ; <== Start of user-defined code
  541. ;
  542.     CALL    PRINT
  543.     DB    ESC,'Y',0    ; leadin
  544.     LD    A,(ROW)        ; Row first
  545.     ADD    A,' '        ; Add offset
  546.     CALL    COUT
  547.     LD    A,(COL)        ; Same for column
  548.     ADD    A,' '
  549.     CALL    COUT
  550. ;
  551. ; <== End of user-defined code
  552. ;
  553.     RET
  554. ;
  555. ROW:    DS    2        ; Row
  556. COL:    DS    2        ; Column
  557. ;
  558. ; Clear screen
  559. ;
  560. CLS:    CALL    PRINT
  561.     DB    ESC,'E',ESC,'H',0
  562.     RET
  563. ;
  564. ; Inverse video on
  565. ;
  566. INVON:    CALL    PRINT
  567.     DB    ESC,'p',0
  568.     RET
  569. ;
  570. ; Inverse video off
  571. ;
  572. INVOFF:    CALL    PRINT
  573.     DB    ESC,'q',0
  574.     RET
  575. ;
  576. ;Turn off cursor
  577. ;
  578. HIDE:    CALL    PRINT
  579.     DB    ESC,'f',0
  580.     RET
  581. ;
  582. ; Turn on cursor
  583. ;
  584. SHOW:    CALL    PRINT
  585.     DB    ESC,'e',0
  586.     RET
  587. ;
  588. ; Save cursor position
  589. ;
  590. SAVECU:    CALL    PRINT
  591.     DB    ESC,'j',0
  592.     RET
  593. ;
  594. ; Restore cursor position
  595. ;
  596. RESCU:    CALL    PRINT
  597.     DB    ESC,'k',0
  598.     RET
  599. ;
  600. ;-----------------------------------------------------------------------
  601. ;
  602. ; Service modem interrupt
  603. ;
  604. MINT:    RET            ; My system doesn't need this
  605. ;
  606. ; Initialise interrupt vectors
  607. ;
  608. INVEC:    RET            ; Ditto
  609. ;
  610. ; De-initialise interrupt vectors
  611. ;
  612. DINVEC:    RET            ; Ditto
  613. ;
  614. ;------------------ end of user-defined code ---------------------------
  615. ;        do not change anything below here
  616. ;
  617. ; Modem character test for 100 ms
  618. ;
  619. MRD:    PUSH    BC        ; Save BC
  620.     LD    BC,100        ; Set limit
  621. ;
  622. MRD1:    CALL    MIRDY        ; Char at modem?
  623.     JR    NZ,MRD2        ; Yes, exit
  624.     LD    HL,1        ; Else wait 1ms
  625.     CALL    WAITMSHL
  626.     DEC    BC        ; Loop till done
  627.     LD    A,B
  628.     OR    C
  629.     JR    NZ,MRD1
  630.     LD    HL,0        ; None there, result=0
  631.     XOR    A
  632. ;
  633. MRD2:    POP    BC
  634.     RET
  635. ;
  636. ; Inline print routine: destroys A and HL
  637. ;
  638. PRINT:    EX    (SP),HL        ; Get address of string
  639. ;
  640. PLOOP:    LD    A,(HL)        ; Get next
  641.     INC    HL        ; Bump pointer
  642.     OR    A        ; Done if zero
  643.     JR    Z,PDONE
  644.     CALL    COUT        ; Else print
  645.     JR    PLOOP        ; And loop
  646. ;
  647. PDONE:    EX    (SP),HL        ; Restore return address
  648.     RET            ; And quit
  649. ;
  650. ; Output a character in A to the console
  651. ;
  652. COUT:    PUSH    BC        ; Save registers
  653.     PUSH    DE
  654.     PUSH    HL
  655.     LD    E,A        ; Character to E
  656.     LD    C,2
  657.     CALL    BDOS        ; Print it
  658.     POP    HL
  659.     POP    DE
  660.     POP    BC
  661.     RET
  662. ;
  663. ; Wait(seconds)
  664. ;
  665. WAIT:    LD    HL,2
  666.     ADD    HL,SP
  667.     EX    DE,HL        ; Get delay size
  668.     CALL    GETPARM
  669. ;                ; Fall thru to..
  670. ;Wait seconds in HL
  671. ;
  672. WAITSHL:PUSH    BC        ; Save BC
  673.     PUSH    DE        ; DE
  674.     PUSH    IX        ; And IX
  675.     LD    IX,0        ; Then point IX to 0
  676.                 ; So we don't upset memory-mapped I/O
  677. ;
  678. ; Calculate values for loop constants. Need to have two loops to avoid
  679. ; 16-bit overflow with clock speeds above 9 MHz.
  680. ;
  681. OUTERVAL EQU    (CLKSPD/10)+1
  682. INNERVAL EQU    (6667/OUTERVAL)*CLKSPD
  683. ;
  684. WAIT10:    LD    B,OUTERVAL
  685. ;
  686. WAIT11:    LD    DE,INNERVAL
  687. ;
  688. WAIT12:    BIT    0,(IX)        ; Time-wasters
  689.     BIT    0,(IX)
  690.     BIT    0,(IX)        ; 20 T-states each
  691.     BIT    0,(IX)
  692.     BIT    0,(IX)
  693.     BIT    0,(IX)
  694.     DEC    DE
  695.     LD    A,E
  696.     LD    A,D
  697.     OR    E
  698.     JR    NZ,WAIT12    ; 150 T-states per inner loop
  699.     DJNZ    WAIT11        ; Decrement outer loop
  700.     DEC    HL        ; Ok, decrement count in hl
  701.     LD    A,H
  702.     OR    L
  703.     JR    NZ,WAIT10
  704.     POP    IX        ; Done -- restore ix
  705.     POP    DE        ; De
  706.     POP    BC        ; And bc
  707.     RET
  708. ;
  709. ; Wait milliseconds
  710. ;
  711. MSWAIT:    LD    HL,2
  712.     ADD    HL,SP
  713.     EX    DE,HL        ; Get delay size
  714.     CALL    GETPARM
  715. ;                ; Fall thru to..
  716. ; Wait milliseconds in HL
  717. ;
  718. WAITMSHL:PUSH    DE
  719. ;
  720. W1MS0:    LD    DE,39*CLKSPD
  721. ;
  722. W1MS1:    DEC    DE
  723.     LD    A,D
  724.     OR    E
  725.     JR    NZ,W1MS1
  726.     DEC    HL
  727.     LD    A,H
  728.     OR    L
  729.     JR    NZ,W1MS0
  730.     POP    DE
  731.     RET
  732. ;
  733. ; Get next parameter from (DE) into HL
  734. ;
  735. GETPARM:EX    DE,HL        ; Get address into HL
  736.     LD    E,(HL)        ; Get LOW
  737.     INC    HL
  738.     LD    D,(HL)        ; Then HIGH
  739.     INC    HL        ; Bump for next
  740.     EX    DE,HL        ; Result in hl, address still in de
  741.     RET
  742. ;
  743. ; Get address of user-defined variables
  744. ;
  745. GETVARS:LD    HL,USERVARS
  746.     RET
  747. ;
  748. USERVARS:
  749.     DW    OVERDRIVE    ; OVR etc. drive/user
  750.     DW    OVERUSER
  751. ;
  752. ;
  753.     END
  754. L
  755.     JR    NZ,WAIT10
  756.     POP    IX        ; Done -- restore ix
  757.     POP    DE        ; De
  758.     POP    BC        ; And bc
  759.     RET
  760. ;
  761. ; Wait milli