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 / CPM / MODEMS / MODEM / TINYTERM.LBR / TINYTERM.MQC / TINYTERM.MAC
Text File  |  2000-06-30  |  14KB  |  428 lines

  1. ;=====================================================
  2. ; tinyterm - a tiny terminal program with XMODEM
  3. ;         file download facility.
  4. ; tinyterm v1.0 (Z-80 version) 3rd June, 1985
  5. ; Written by Michael Brandon.
  6. ; The idea behind tinyterm is that it is a terminal
  7. ; program you can use to download a better terminal
  8. ; program (e.g. MODEM7A or YAM). Tinyterm is small
  9. ; enough to type in by hand (minus the comments of
  10. ; course !) or to download the source code using PIP.
  11. ;=====================================================
  12.     .z80            ; use Zilog mnemonics
  13.     org    100h        ; normal cp/m origin
  14. ;==========================================================
  15. ; You will almost certainly have to change the following -
  16. ;
  17. ; mod_data   - the SIO or UART data port through which the
  18. ;           modem is accessed
  19. ; mod_status - the port from which the status of the SIO
  20. ;           or UART can be read
  21. ;==========================================================
  22. mod_data    equ    40h    ; modem data port
  23. mod_status    equ    41h    ; modem status port
  24. ;==============================================================
  25. ; You may have to change the following -
  26. ;
  27. ; rx_mask   - when ANDed with the SIO or UART status, extracts
  28. ;          the bit (or bits) which tell whether or not the 
  29. ;          SIO or UART has a received a character
  30. ; rx_ready  - the value of 'rx_mask AND status' when a
  31. ;          character has been received
  32. ; tx_mask   - when ANDed with the SIO or UART status, extracts
  33. ;          the bit (or bits) which tell whether or not the 
  34. ;          SIO or UART is ready to transmit a character
  35. ; tx_ready  - the value of 'tx_mask AND status' when the SIO
  36. ;          or UART is ready to transmit a character
  37. ; * note *  : the values for the above four constants as they
  38. ;          stand are correct for a Zilog Z-80 SIO
  39. ; cpu_speed - the speed of the processor in kHz. Not very
  40. ;          critical.
  41. ;==============================================================
  42. rx_mask        equ    00000001b    ; "Rx ready" modem status mask
  43. rx_ready    equ    00000001b    ; value when char is received
  44. tx_mask        equ    00000100b    ; "Tx ready" modem status mask
  45. tx_ready    equ    00000100b    ; value when ready to transmit
  46. cpu_speed    equ    4000d        ; cpu speed in kHz
  47. ;===================================================
  48. ; You might like to change the following -
  49. ;
  50. ; exit_char - when this character is typed, the
  51. ;          program exits to cp/m
  52. ; rx_char   - when this character is typed, a file
  53. ;          is downloaded, using XMODEM protocols
  54. ;===================================================
  55. exit_char    equ    03h        ; <ctrl> C
  56. rx_char        equ    12h        ; <ctrl> R
  57. ;=================================
  58. ; Don't, what ever you do, change
  59. ; the following constants !!!
  60. ;=================================
  61. warm_boot    equ    0000h        ; cp/m warm boot address
  62. bdos        equ    0005h        ; entry into cp/m's bdos
  63. fcb        equ    005ch        ; & (file control block 1)
  64. def_dma        equ    0080h        ; default DMA address
  65. rx_delay    equ    cpu_speed  / 4    ; delay count for a one
  66.                     ; second receive timeout
  67. soh        equ    01h        ; ASCII <soh> char
  68. eot        equ    04h        ; ASCII <eot> char
  69. ack        equ    06h        ; ASCII <ack> char
  70. lf        equ    0ah        ; ASCII <lf> char
  71. cr        equ    0dh        ; ASCII <cr> char
  72. nak        equ    15h        ; ASCII <nak> char
  73. ;=============================================================
  74. ; You shouldn't have to modify any code beyond this point,
  75. ; other than adding code to initialise your SIO or UART
  76. ; between main1 and main2.
  77. ; The only things which will stand modification are -
  78. ; (i)   test_rx - see if a character has been received
  79. ; (ii)  test_tx - see if we can transmit a character
  80. ; (iii) tx_byte - transmit a character
  81. ; (iv)  rx_t1   - receive a character with a 1 second timeout
  82. ; (v)   the line marked (***) after main4
  83. ; but modify them only if necessary.
  84. ;=============================================================
  85. main:
  86.     ld    a,(def_dma)    ; get length of command line tail
  87.     or    a        ; has user just typed "tinyterm" ?
  88.     jr    nz,main1    ; skip if not
  89.     call    print
  90.     defm    'Usage: tinyterm file',cr,lf,0
  91.     jp    warm_boot
  92. main1:
  93. ;===============================================================
  94. ; Put the code to initialise your SIO or UART chip in here. The
  95. ; communications port should be set for 300 baud, 8 data bits,
  96. ; 1 stop bit and no parity. You may not need to do any
  97. ; initialisation at all ...
  98. ;===============================================================
  99. main2:
  100.     ld    c,0bh        ; cp/m "get console status" request
  101.     call    bdos        ; has a character been typed ?
  102.     or    a        ; test return value (00 or ff)
  103.     jr    z,main4        ; skip if no character
  104.     ld    c,06h        ; cp/m "direct console I/O" request
  105.     ld    e,0ffh        ; console input indicator
  106.     call    bdos        ; get the character
  107.     cp    exit_char    ; exit to the operating system ?
  108.     jp    z,warm_boot    ; do a warm boot if so
  109.     cp    rx_char        ; receive a file ?
  110.     jr    nz,main3    ; skip if not
  111.     call    rx_file        ; receive the file, XMODEM style
  112.     jr    main4        ; (don't send the rx_char character)
  113. main3:
  114.     call    tx_byte        ; send the byte out the modem port
  115. main4:
  116.     call    test_rx        ; received a character from the modem ?
  117.     jr    nz,main2    ; keep looping if not
  118.     in    a,(mod_data)    ; get the character (***)
  119.     call    put_char    ; print the character
  120.     jr    main2        ; and keep looping ...
  121.  
  122. ;--------------------------------------------
  123. ; put_char - print a character on the screen
  124. ; Input    : char in a
  125. ; Clobbers : A, B, C, D, E, H, L, flags
  126. ;--------------------------------------------
  127.  
  128. put_char:
  129.     ld    c,02h        ; cp/m "console output" request
  130.     ld    e,a        ; char to print in e
  131.     jp    bdos        ; call bdos & return
  132.  
  133. ;---------------------------------------------
  134. ; print    - print a null-terminated sequence
  135. ;         of characters "in line" i.e.
  136. ;        call    print
  137. ;        defm    'string of chars'
  138. ;        defb    0
  139. ; Clobbers : A, D, E, H, L, flags
  140. ;---------------------------------------------
  141.  
  142. print:
  143.     pop    hl        ; get return address (start of string)
  144.     push    bc        ; save
  145. prin1:
  146.     ld    a,(hl)        ; get char
  147.     inc    hl
  148.     or    a        ; end of string ? (0 byte terminator)
  149.     jr    z,prin2        ; skip if so
  150.     push    hl        ; save ^
  151.     call    put_char    ; print the character
  152.     pop    hl        ; retrieve ^
  153.     jr    prin1        ; keep looping ...
  154. prin2:
  155.     pop    bc        ; retrieve
  156.     jp    (hl)        ; return to the code after the string
  157.  
  158. ;-----------------------------------------------
  159. ; test_rx  - test the modem status port to see
  160. ;         if a character is ready to be read
  161. ; Output   : Z  if modem has a character
  162. ;         NZ if not
  163. ; Clobbers : A
  164. ;-----------------------------------------------
  165.  
  166. test_rx:
  167.     in    a,(mod_status)    ; get the modem status
  168.     and    rx_mask        ; mask out all but the bits we want
  169.     cp    rx_ready    ; modem got a char for us to read ?
  170.     ret            ; return (Z) if ready, (NZ) if not
  171.  
  172. ;-----------------------------------------------
  173. ; test_tx  - test the modem status port to see
  174. ;         if it is ready to send a character
  175. ; Output   : Z  if the modem is ready
  176. ;         NZ if not
  177. ; Clobbers : A
  178. ;-----------------------------------------------
  179.  
  180. test_tx:
  181.     in    a,(mod_status)    ; get the modem status
  182.     and    tx_mask        ; mask out all but the bits we want
  183.     cp    tx_ready    ; modem ready to send a char ?
  184.     ret            ; return (Z) if ready, (NZ) if not
  185.  
  186. ;----------------------------------------------------
  187. ; tx_byte - transmit a byte when the modem is ready
  188. ; Input   : A - byte to transmit
  189. ;----------------------------------------------------
  190.  
  191. tx_byte:
  192.     push    af        ; save byte
  193. tx_b1:
  194.     call    test_tx        ; modem ready to transmit ?
  195.     jr    nz,tx_b1    ; loop until ready
  196.     pop    af        ; get byte back
  197.     out    (mod_data),a    ; send it out the data port
  198.     ret
  199.  
  200. ;------------------------------------------------
  201. ; rx_t1  - wait for a character to be received;
  202. ;       time out after one second
  203. ; Output : Z  if a character was received
  204. ;       NZ if we timed out
  205. ;       A - character received if no time out
  206. ;------------------------------------------------
  207.  
  208. rx_t1:
  209.     push    hl        ; save
  210.     ld    hl,rx_delay    ; delay counter for 1 second timeout
  211. rx_t1a:
  212.     call    test_rx        ; is there a char ready for us ?
  213.     jr    z,rx_t1c    ; jump if so
  214.     xor    a        ; A := 0
  215. rx_t1b:
  216.     dec    a
  217.     jr    nz,rx_t1b    ; wait around a while ...
  218.     dec    hl
  219.     ld    a,h
  220.     or    l        ; timed out ?
  221.     jr    nz,rx_t1a    ; loop if not
  222.     inc    a        ; set flags to NZ
  223.     pop    hl
  224.     ret            ; return (NZ) - timed out
  225. rx_t1c:
  226.     in    a,(mod_data)    ; get the byte from the data port
  227.     pop    hl
  228.     ret            ; return (Z) - got a char
  229.  
  230. ;------------------------------------------------
  231. ; rx_t10 - wait for a character to be received;
  232. ;       time out after ten seconds
  233. ; Output : Z  if a character was received
  234. ;       NZ if we timed out
  235. ;       A - character received if no time out
  236. ;------------------------------------------------
  237.  
  238. rx_t10:
  239.     push    hl        ; save
  240.     ld    hl,rx_delay*10    ; counter for 10 second timeout
  241.     jr    rx_t1a        ; carry on as for 1 second timeout
  242.  
  243. ;---------------------------------------------------------
  244. ; tx_ack - wait until the line is clear (i.e. we time out
  245. ;       while receiving chars), and then send an <ack>
  246. ;---------------------------------------------------------
  247.  
  248. tx_ack:
  249.     push    af        ; save
  250. tx_a1:
  251.     call    rx_t1        ; get a char, with 1 second timeout
  252.     jr    z,tx_a1        ; if no timeout, keep gobbling chars
  253.     ld    a,ack        ; <ack> char
  254.     call    tx_byte        ; send it
  255.     pop    af
  256.     ret
  257.  
  258. ;---------------------------------------------------------
  259. ; tx_nak - wait until the line is clear (i.e. we time out
  260. ;       while receiving chars), and then send a <nak>
  261. ;---------------------------------------------------------
  262.  
  263. tx_nak:
  264.     push    af        ; save
  265. tx_n1:
  266.     call    rx_t1        ; get a char, with 1 second timeout
  267.     jr    z,tx_n1        ; if no timeout, keep gobbling chars
  268.     ld    a,nak        ; <nak> char
  269.     call    tx_byte        ; send it
  270.     pop    af
  271.     ret
  272.  
  273. ;--------------------------------------------------
  274. ; get_block - get a block of data from the modem,
  275. ;          consisting of -
  276. ;          (i)   block number
  277. ;          (ii)  complement of the block number
  278. ;          (iii) 128 data bytes (1 sector), and
  279. ;          (iv)  checksum
  280. ; Output    : Z  if all went o.k.
  281. ;        A - block number of the block
  282. ;          - 128 bytes at *(def_dma)
  283. ;          NZ if an error occurred
  284. ;          - timed out
  285. ;          - block no. <> ~ (~ block no.)
  286. ;          - checksum wrong
  287. ;--------------------------------------------------
  288.  
  289. get_block:
  290.     push    bc
  291.     push    de
  292.     push    hl        ; save
  293.     call    rx_t1        ; get the block no.
  294.     jr    nz,get_2    ; return (NZ) if we timed out
  295.     ld    c,a        ; save the block no.
  296.     call    rx_t1        ; get ~ block no.
  297.     jr    nz,get_2    ; return (NZ) if we timed out
  298.     cpl            ; ~ ~ block no. (we hope)
  299.     cp    c        ; is the block no. right ?
  300.     jr    nz,get_2    ; return (NZ) if block no. wrong
  301.     ld    hl,def_dma    ; put data in the default DMA buffer
  302.     ld    b,128        ; 128 bytes / block
  303.     ld    d,0        ; initial checksum
  304. get_1:
  305.     call    rx_t1        ; get a data byte
  306.     jr    nz,get_2    ; return (NZ) if we timed out
  307.     ld    (hl),a        ; save the byte
  308.     inc    hl
  309.     add    a,d        ; generate a new checksum
  310.     ld    d,a        ; save it
  311.     djnz    get_1        ; do the whole block
  312.     call    rx_t1        ; get checksum
  313.     jr    nz,get_2    ; return (NZ) if we timed out
  314.     cp    d        ; checksums the same ?
  315.     ld    a,c        ; return the block no. in A
  316. get_2:
  317.     pop    hl
  318.     pop    de
  319.     pop    bc
  320.     ret
  321.  
  322. ;----------------------------------------------------------------
  323. ; rx_file  - download a file using the XMODEM file transfer
  324. ;         protocol. Any existing file with the name specified
  325. ;         on the command line will be overwritten (as will
  326. ;         any file previously downloaded in this invocation
  327. ;         of the program).
  328. ; Clobbers : A, B, C, D, E, H, L, flags
  329. ;----------------------------------------------------------------
  330.  
  331. rx_file:
  332.     ld    c,13h        ; cp/m "delete file" request
  333.     ld    de,fcb        ; & (file control block)
  334.     call    bdos        ; delete the file (if it exists !)
  335.     ld    c,16h        ; cp/m "make file" request
  336.     ld    de,fcb        ; & (file control block)
  337.     xor    a        ; a := 0
  338.     ld    (fcb+12),a    ; set things up ...
  339.     ld    (fcb+14),a    ; ... in the file control block
  340.     ld    (fcb+32),a    ; (don't know what it does !)
  341.     call    bdos        ; create the file, and open it
  342.     inc    a        ; error if a = 0ffh after the bdos call
  343.     jr    nz,rx_f1    ; skip if all's well
  344.     call    print        ; print the error message
  345.     defm    'can''t create file',cr,lf,0
  346.     ret
  347. rx_f1:
  348.     ld    c,0        ; initial "previous" block no.
  349.     call    tx_nak        ; send an initital <nak>
  350. rx_f2:
  351.     ld    b,10        ; retry block errors 10 times
  352. rx_f3:
  353.     call    rx_t10        ; look for a <soh> or <eot>
  354.     jr    z,rx_f5        ; skip if we got something
  355.     call    print
  356.     defm    'timeout',cr,lf,0
  357. rx_f4:
  358.     call    tx_nak        ; send a <nak> to signal error
  359.     djnz    rx_f3        ; retry 10 times
  360.     call    print
  361.     defm    'aborted',cr,lf,0
  362.     ld    c,13h        ; cp/m "delete file" request
  363.     ld    de,fcb        ; & (file control block)
  364.     call    bdos        ; delete the file
  365.     ret
  366. rx_f5:
  367.     cp    eot        ; <eot> (end of transmission) ?
  368.     jr    nz,rx_f6    ; skip if not
  369.     call    print
  370.     defm    'file transfer completed',cr,lf,0
  371.     call    tx_ack        ; acknowledge it
  372.     ld    c,10h        ; cp/m "close file" request
  373.     ld    de,fcb        ; & (file control block)
  374.     call    bdos        ; close the file
  375.     inc    a        ; error if a = 0ffh after bdos call
  376.     ret    nz        ; return if o.k.
  377.     call    print
  378.     defm    'can''t close file',cr,lf,0
  379.     ret
  380. rx_f6:
  381.     cp    soh        ; <soh> (start of header) ?
  382.     jr    z,rx_f7        ; skip if so
  383.     call    print
  384.     defm    'no <soh> or <eot>',cr,lf,0
  385.     jp    rx_f4
  386. rx_f7:
  387.     call    get_block    ; get the block
  388.     jr    z,rx_f8        ; skip if no errors
  389.     call    print
  390.     defm    'error in block',cr,lf,0
  391.     jp    rx_f4
  392. rx_f8:
  393.     cp    c        ; resent the old block ?
  394.     jr    nz,rx_f9    ; skip if not
  395.     call    tx_ack        ; acknowledge it
  396.     call    print
  397.     defm    '(repeated block)',cr,lf,0
  398.     jp    rx_f2
  399. rx_f9:
  400.     inc    c        ; next block no.
  401.     cp    c        ; block no.s match ?
  402.     jr    z,rx_f10    ; skip if so
  403.     call    print
  404.     defm    'error in block number',cr,lf,0
  405.     dec    c        ; go back a block
  406.     jp    rx_f4
  407. rx_f10:
  408.     call    print
  409.     defm    'block received',cr,lf,0
  410.     push    bc        ; save the block number
  411.     ld    c,15h        ; cp/m "write sequential" request
  412.     ld    de,fcb        ; & (file control block)
  413.     call    bdos        ; write sector to disc
  414.     pop    bc        ; retrieve the block number
  415.     inc    a        ; error if a = 0ffh after bdos call
  416.     jr    nz,rx_f11    ; skip if write went o.k.
  417.     call    print
  418.     defm    'disc limit reached',cr,lf,0
  419.     ld    c,13h        ; cp/m "delete file" request
  420.     ld    de,fcb        ; & (file control block)
  421.     call    bdos        ; delete the file (if it exists !)
  422.     ret
  423. rx_f11:
  424.     call    tx_ack        ; acknowledge the block
  425.     jp    rx_f2        ; loop for next block
  426.  
  427.     end    main
  428.