home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol078 / talk1-5.asm < prev    next >
Assembly Source File  |  1984-04-29  |  23KB  |  1,039 lines

  1. .title    'Program to microcommunicate with other computer systems'
  2. .sbttl    '    Version of 10-Jul-81'
  3. .ident    talk
  4. .entry    start
  5. .if1,[ .prntx    'TALK v1.5 - CP/M to host file transfer program']
  6. ;
  7. ;    Simple program that can send and receive characters
  8. ;    from the CP/M console or floppy disk to another
  9. ;    computer/ acoustic modem/ or terminal that is connected
  10. ;    to a Z80 SIO or DART (serial asynchronous interface).
  11. ;
  12. ;    It is my first attempt at writing a program using
  13. ;    interrupts so that I can fully utilise my hardware's
  14. ;    capabilities. (I have a Godbout DISK 1 DMA floppy disk
  15. ;    controller, Wire-wrapped 4 MHz IEEE 696 Z80 CPU with
  16. ;    2x Z80 SIO's, Z80 CTC and Z80 PIO allowing use of Mode 2
  17. ;    vectored interrupts, 64Kbytes RAM and a Fulcrum VIO-X2
  18. ;    intelligent video board).
  19. ;
  20. ;    Sorry the source is in TDL Macro assembly language and
  21. ;    requires Phoenix Software Associates PASM or TDL/Xitan
  22. ;    Macroassembler to assemble. Conversion to ASM should
  23. ;    be straight forward, though you lose all the nice
  24. ;    features of this assembler.
  25. ;
  26. ;    Author:        Anthony Nicholson
  27. ;
  28. ;    Address:    54 Carnley Avenue,
  29. ;            New Lambton, NSW, 2305,
  30. ;            Australia.
  31. ;
  32. ;    Phone:        049-526017
  33. ;
  34. ;    Date written:    20-Dec-1981
  35. ;
  36. ;    Modification history:
  37. ;
  38. ;    * Rev 5  10-Jul-1982
  39. ;            Tidy up and add Z80 processor check
  40. ;            for submission to 'Public Domain'.
  41. ;
  42. ;    * Rev 4  13-Jun-1982
  43. ;            Add log file feature and change
  44. ;            abort character to ^^ (so I can
  45. ;            communicate with a VAX-11/780 which
  46. ;            uses ^Y).
  47. ;
  48. ;    * Rev 3  21-Mar-1982
  49. ;            Add delay to SENDFILE to allow
  50. ;            host computer to catch up when
  51. ;            using fast (2400baud) transmission,
  52. ;            and echo what is sent for testing
  53. ;            (This was found to be necessary when
  54. ;            TALKing to a timesharing host PDP-11/70
  55. ;            which required time to process its
  56. ;            input buffer).
  57. ;
  58. ;    * Rev 2  07-Mar-1982
  59. ;            Implement file send to host.
  60. ;
  61. ;    * Rev 1  27-Jan-1982
  62. ;            Fix GETFCB filename scan. Also
  63. ;            add conditional assembly for use
  64. ;            with the Ferguson Big Board and
  65. ;            for testing using my hardware.
  66. ;
  67. ;    * Rev 0  20-Dec-1981
  68. ;            Initial version for my hardware.
  69. ;
  70. ;
  71. ;
  72. ; C P / M   D E F I N I T I O N S
  73. ;
  74. bdos    ==    5    ;CP/M entry address
  75. base    ==    0    ;CP/M base re-entry address
  76. ;
  77. conwr$    ==    2    ;Console write
  78. dirio$    ==    6    ;Direct console i/o
  79. print$    ==    9    ;Print string
  80. rdbuf$    ==    10    ;Read console buffer
  81. openf$    ==    15    ;Open file
  82. close$    ==    16    ;Close file
  83. delet$    ==    19    ;Delete file
  84. readf$    ==    20    ;Read file
  85. write$    ==    21    ;Write file
  86. creat$    ==    22    ;Create file
  87. sdma$    ==    26    ;Set DMA address
  88. ;
  89. ; G E T   B U F F E R   S I Z E
  90. ;
  91. bufsiz    =\    'File blocking buffer size (must be multiple of 128)'
  92.     .ifn    bufsiz @ 128,[
  93.         .error    '?ILLEGAL BUFFER SIZE' 
  94.         ]
  95. ;
  96. ; C O N T R O L  C H A R A C T E R S
  97. ;
  98.             ; Command characters to
  99. ctrld    ==    04h    ;  - download file
  100. ctrle    ==    05h    ;  - send file
  101. ctrlf    ==    06h    ;  - log file
  102. ctrlq    ==    11h    ;  - XON to host
  103. ctrls    ==    13h    ;  - XOFF to host
  104. ctrly    ==    1eh    ;  - Abort (really ^^)
  105. ctrlz    ==    1ah    ;  - EOF char
  106. ;
  107. lf    ==    0ah
  108. cr    ==    0dh
  109. ;
  110. noparity==    07fh    ;parity bit mask
  111. ;
  112. false    ==    0
  113. true    ==    # false
  114. .opsyn    .ife,.ifnot
  115. .opsyn    .ifn,.if
  116. ;
  117. testing    =\    'Version required (TEST=1, Bigboard=0) '
  118. ;
  119. baudc    =\    'Baud rate for Z80 SIO <Default=300> '
  120. ;
  121. opt.delay=\    'Is a delay required after sending a line (Yes=1, No=0) '
  122. ;
  123. .ifnot    testing,[
  124.     ;
  125.     ; Ferguson BIG BOARD equates
  126.     ;
  127.     bauda    ==    0ch    ;Baud rate generator
  128.                 ; Value output to baud
  129.                 ; rate generator is
  130.                 ; determined below with
  131.                 ; a default of 300baud.
  132.                 ;For other baud rates,
  133.                 ; extend the conditional
  134.                 ; making sure to match
  135.                 ; all parentheses.
  136.     .ife    baudc-2400,[
  137.         baudr   ==      1010b
  138.         ]
  139.         [.ife    baudc-1200,[
  140.         baudr    ==    1000b
  141.         ]
  142.         [.ife    baudc-600,[
  143.             baudr   ==      0110b
  144.             ]
  145.             [
  146.             baudr    ==    0101b
  147.             ]
  148.         ]
  149.         ]
  150.     delcnt    ==    2*1000    ;delay count for 2MHz Z80
  151.     siobc    ==    07h    ;Uses Z80 SIO channel B
  152.     siobd    ==    05h    ; at ports 05 & 07h
  153.     intvec    ==    0ff00h    ; and its associated interrupt
  154.     rx.v    ==    intvec+4; vectors for rx char
  155.     rxe.v    ==    intvec+6; and rx char error
  156. ]
  157. .if    testing,[
  158.     ;
  159.     ; Test equates using my hardware
  160.     ;
  161.     intvec:    .word    ierror    ;I need to set up an
  162.         .word    ierror    ; interrupt vector table
  163.         .word    ierror    ; for the Z80 SIO
  164.         .word    ierror
  165.         .word    ierror
  166.         .word    ierror
  167.         .word    ierror
  168.         .word    ierror
  169.     ;
  170.     ierror:    lxi    d,imsg    ; This routine will
  171.         call    prints    ;handle anything funny
  172.         hlt        ;that may occur by HALTing!!!
  173.         jmpr    ierror
  174.     ;
  175.     imsg:    .ascii    [cr][lf]'?SPURIOUS INTERRUPT$'
  176.     ;
  177.     rx.v    ==    intvec+4;vector assignment for SIO
  178.     rxe.v    ==    intvec+6; channel B
  179.     ctcb    ==    11h    ;CTC controls the baud rate
  180.     .ife    baudc-2400,[
  181.         baudr   ==      00011000b
  182.         ]
  183.         [.ife   baudc-1200,[
  184.         baudr    ==    00110000b
  185.         ]
  186.         [.ife    baudc-600,[
  187.             baudr    ==      01100000b
  188.             ]
  189.             [
  190.             baudr    ==    11000000b
  191.             ]
  192.         ]
  193.         ]
  194.     siobd    ==    01h    ;data register of SIO
  195.     siobc    ==    03h    ;control register of SIO
  196.     delcnt    ==    4*1000    ;delay count for 4MHz Z80
  197. ]
  198. ;
  199. ; B E G I N   P R O G R A M   ' T A L K '
  200. ;
  201. start:    mvi    a,7fH    ;Identify processor
  202.     add    a    ; cause overflow
  203.     jpe    Z80    ; conclusive proof of Z80
  204.     lxi    d,z80msg;Give them the bad news
  205.     call    prints
  206.     jmp    base    ;Return to CP/M
  207. ;
  208. z80msg:    .ascii    '?TALK - This program requires a Z80 processor$'
  209. ;
  210. z80:    lxi    d,signon ;print("TALK V1.n")
  211.     call    prints
  212.     call    rxecho
  213.     call    inisio    ;initialise SIO
  214. ;
  215. next1:    call    getch    ;get a character
  216.     ora    a    ; from console.
  217.     jrnz    proc1    ;if we get one then off we go...
  218.     call    prxch    ;otherwise print any character
  219.     jmp    next1    ; we got down the line.
  220. ;
  221. proc1:    cpi    ctrld    ;if ch="^D" then
  222.     jrz    ..6    ; transfer file to CP/M
  223.     cpi    ctrlf    ;else if ch="^F" then
  224.     jrnz    ..2    ; do log file function
  225.     mvi    a,true    ; by setting log flag
  226.     sta    log.flag
  227.     lxi    d,logmsg; and getting prompt
  228.     jmpr    ..7    ; message ready.
  229. ;    
  230. ..6:    lxi    d,filmsg
  231. ;
  232. ..7:    call    prints    ; print "filename ?"
  233.     call    inputl    ; get filename
  234.     lxi    d,newlin
  235.     call    prints
  236.     lxi    h,conbuf+2
  237.     lxi    d,fcb
  238.     call    getfcb    ; set up file control
  239.             ; block
  240.     jrz    ..1    ;if not ok then
  241. ..0:    lxi    d,fnerrm ; print "filename error"
  242.     call    prints
  243.     jmpr    ..8    ;else
  244. ;
  245. ..1:    call    getfile    ; transfer file
  246. ;
  247. ..8:    mvi    a,false    ;when done, reset
  248.     sta    log.flag; log flag
  249.     jmp    next1
  250. ..2:
  251.     cpi    ctrly    ;if ch="^Y" then 
  252.     jrnz    ..3
  253.  
  254.     lxi    d,byemsg; print "exiting..."
  255.     call    prints
  256.     call    close    ; close files and
  257.     call    rxdint    ; disable host rx interrupts
  258.     jmp    base    ;Return to CP/M
  259. ..3:
  260.     cpi    ctrle    ;if ch="^E" then
  261.     jrnz    ..4
  262.     lxi    d,sndmsg; print "filename to send?"
  263.     call    prints
  264.     call    inputl    ; get filename
  265.     lxi    d,newlin
  266.     call    prints
  267.     lxi    h,conbuf+2
  268.     lxi    d,fcb
  269.     call    getfcb
  270.     jrz    ..5
  271.  
  272.     lxi    d,fnerrm; print "filename error"
  273.     call    prints
  274.     jmp    next1
  275.  
  276. ..5:    call    sendfile
  277.     jmp    next1
  278. ..4:
  279.     call    send    ;send character to host
  280.     jmp    next1
  281. ;
  282. signon:
  283. .ascii    'TALK V1.5 Program to talk to host computer via serial data line'[cr][lf]
  284. .if    testing,[    .ascii    'TESTING VERSION'[cr][lf]]
  285. .ascii    'Command characters are:'[cr][lf][cr][lf]
  286. .ascii    '    ^^    abort current process (returns to CP/M)'[cr][lf]
  287. .ascii    '    ^D    prompt for CP/M filename to receive characters'[cr][lf]
  288. .ascii    '        from host and initiate the transfer (by'[cr][lf]
  289. .ascii    '        sending a <return> to host) (^F logfile)'[cr][lf]
  290. .ascii    '    ^E    prompt for CP/M filename to send to host'[cr][lf]
  291. .ascii    '        and initiate the transfer (assumes host is'[cr][lf]
  292. .ascii    '        ready to receive characters)'[cr][lf]
  293. .ascii    '    ^Z    when in file transfer mode causes the'[cr][lf]
  294. .ascii    '        current operation to terminate'[cr][lf][cr][lf]
  295. .ascii    'You are now talking to the host...'[cr][lf]'$'
  296. ;
  297. filmsg:    .ascii    [cr][lf]'filename to receive?$'
  298. ;
  299. newlin:    .ascii    [cr][lf]'$'
  300. ;
  301. fnerrm:    .ascii    [cr][lf]'filename error, ignoring input...'[cr][lf]'$'
  302. ;
  303. byemsg:    .ascii    [cr][lf]'exiting...$'
  304. ;
  305. sndmsg:    .ascii    [cr][lf]'filename to send?$'
  306. ;
  307. logmsg:    .ascii    [cr][lf]'log filename?$'
  308. ;
  309. ;-----------------------
  310. ;
  311. ; S U B R O U T I N E S
  312. ;
  313. ;-----------------------
  314. ;
  315. ; getch - get a character from console
  316. ;
  317. ;    exit:    character -> a
  318. ;
  319. getch:    mvi    c,dirio$
  320.     mvi    e,0ffh
  321. bdose:    push    b
  322.     push    d
  323.     push    h
  324.     call    bdos
  325.     pop    h
  326.     pop    d
  327.     pop    b
  328.     ret
  329. ;-----------------------
  330. ;
  331. ; prints - print ascii string on console
  332. ;
  333. ;    entry:    de -> address of string
  334. ;
  335. prints:    mvi    c,print$
  336.     jmp    bdose
  337. ;
  338. ; inputl - input line from console
  339. ;
  340. ;    flushes buffer with spaces
  341. ;
  342. inputl:    mvi    b,cbfsiz;initialise console
  343.     lxi    h,conbuf; input buffer CONBUF
  344.     mov    m,b    ; and fill with spaces
  345.     inx    h
  346.     xra    a
  347.     mov    m,a
  348.     inx    h
  349. ..0:    mvi    m,' '
  350.     inx    h
  351.     djnz    ..0
  352.     mvi    c,rdbuf$ ;read chars into buffer
  353.     lxi    d,conbuf
  354.     jmp    bdose
  355. ;-----------------------
  356. ;
  357. ; getfcb - build a CP/M filename from input string
  358. ;
  359. ;    entry:    HL -> ascii filename string
  360. ;        DE -> FCB
  361. ;    exit:    z flag <- 0 if error (A<>0)
  362. ;              1 if ok (A=0)
  363. ;
  364. getfcb:    xra    a    ;Set result status=OK
  365.     sta    ..okfl    ; and get File Control Block
  366.     push    d
  367.     mov    b,m    ;first char might be
  368.     inx    h    ; drivename
  369.     mov    a,m    ;if this is a ":" then we
  370.     cpi    ':'    ; have a drivename
  371.     jrnz    ..nodv
  372.     mov    a,b
  373.     call    ..cpan    ;check alphanumeric drive name
  374.     inx    h    ; point past colon
  375.     ani    7    ; mask drive A to H
  376.     jmpr    ..stdv
  377. ;
  378. ..nodv:    
  379.     dcx    h    ;no drivename so
  380.     xra    a    ; set to default drive
  381. ..stdv:
  382.     stax    d    ;store drivename
  383.     inx    d    ; in first byte of FCB
  384.     mvi    b,8    ;get filename (8 chars)
  385.     call    ..name
  386.     mov    a,m
  387.     cpi    '.'    ;check optional '.'
  388.     jrnz    ..ext
  389.     inx    h
  390. ..ext:    mvi    b,3    ;get extension (3 chars)
  391.     call    ..name
  392.     mvi    b,24    ;clear rest of FCB
  393.     xra    a
  394. ..crst:    stax    d
  395.     inx    d
  396.     djnz    ..crst
  397.     lda    ..okfl    ;Get return status
  398.     ana    a    ; set flag bits
  399.     pop    d    ; and return
  400.     ret
  401. ;
  402. ..okfl:    .byte    0
  403. ;
  404. ..cpan:    cpi    ' '    ;if space or '.' then
  405.     jrz    ..cnok    ; return z bit reset.
  406.     cpi    '.'
  407.     jrz    ..cnok
  408.     cpi    'Z'+1    ;convert lower case
  409.     jrc    ..0    ; alpha to upper case
  410.     sui    020h
  411. ..0:    cpi    '0'    ;check for numeric
  412.     jrc    ..cper
  413.     cpi    '9'+1
  414.     jrc    ..cok
  415.     cpi    'A'    ;check for alpha
  416.     jrc    ..cper
  417.     cpi    'Z'+1
  418.     jrnc    ..cper
  419. ..cok:    cmp    a    ;return with z flag
  420.     ret        ; set if alphanumeric
  421.  
  422.  
  423. ..cper:    push    psw    ;not alphanumeric
  424.     mvi    a,0ffh    ; so set flag to
  425.     sta    ..okfl    ; signify error
  426.     pop    psw
  427. ..cnok:    ori    0ffh    ;reset zero flag
  428.     ret    
  429. ;
  430. ..name:    mov    a,m    ;get char from buffer
  431.     call    ..cpan    ; and check it
  432.     jrnz    ..nr    ;if error change to ' '
  433.     inx    h
  434.     stax    d    ;put it to FCB (we
  435.     inx    d    ; don't check errors
  436.     djnz    ..name    ; 'til end)
  437.     ret
  438. ..nr:    mvi    a,' '
  439.     stax    d
  440.     inx    d
  441.     djnz    ..nr
  442.     ret
  443. ;-----------------------
  444. ;
  445. ; send - send character to host
  446. ;
  447. ;    entry:    A <- character
  448. ;
  449. send:
  450.     push    psw    ;output the character
  451. ..wait:    in    siobc    ; to sio channel B
  452.     ani    00000100b; when the TxRDY bit
  453.     jrz    ..wait    ; is set
  454.     pop    psw
  455.     out    siobd
  456.     ret
  457. ;-----------------------
  458. ;
  459. ; conout - output character to console
  460. ;
  461. ;    entry:    A <- character
  462. ;
  463. conout:    mov    e,a
  464.     mvi    c,conwr$
  465.     jmp    bdose
  466. ;-----------------------
  467. ;
  468. ; inisio - initialise Z80 SIO for interrupt
  469. ;    input from host
  470. ;
  471. inisio:
  472.     di
  473.     lxi    h,intvec;set the interrupt
  474.     mov    a,h    ; vector on the cpu
  475.     stai        ; and store the low
  476.     mov    a,l    ; byte in sio control
  477.     sta    ivec    ; data area
  478.     lxi    h,init$t;point to i/o init table
  479. ..1:    mov    b,m    ; get # bytes,
  480.     inx    h
  481.     mov    c,m    ;  i/o port
  482.     inx    h
  483.     outir        ;  and output
  484.     bit    7,m
  485.     jrz    ..1
  486.  
  487.     lxi    h,rxdvr    ; interrupt vectors
  488.     shld    rx.v    ;  Rx channel B
  489.     lxi    h,rxerra
  490.     shld    rxe.v    ;  Rx error channel B
  491.  
  492.     im2        ;make sure its mode 2
  493.     ei        ; interrupts
  494.  
  495.     ret
  496. ;
  497. ; init$t - Z80 SIO and baud rate initialise
  498. ;       data for Ferguson BIG BOARD
  499. ;
  500. init$t:
  501.     .ifnot    testing,[
  502.     .byte    1    ;Baud rate for
  503.     .byte    bauda    ; channel B on the
  504.     .byte    baudr    ; Big board.
  505. ]
  506.     .if    testing,[
  507.     .byte    2
  508.     .byte    ctcb    ;My system uses a Z80 CTC
  509.     .byte    01000111b; as a clock for the Z80 SIO
  510.     .byte    baudr
  511. ]
  512.     .byte    12    ;SIO channel B
  513.     .byte    siobc            
  514.  
  515.     .byte    0,00011000b ;channel B reset
  516.     .byte    4,01000100b ;16x clock, 1 stopbit, no parity
  517.     .byte    1,00011100b ;Rx interrupt enable
  518.     .byte    3,11000001b ;8bits / Rx character, Rx enable
  519.     .byte    5,11101010b ;8bits / Tx character, DTR, RTS, Tx enable
  520.     .byte    2
  521. ivec:    .byte    0       ;interrupt vector
  522.  
  523.     .byte    -1    ;end of table marker
  524.  
  525. ;-----------------------
  526. ;
  527. ; rxinten - set flag so characters received
  528. ;        from host are buffered
  529. ;
  530. rxinten:
  531.     mvi    a,true
  532.     sta    buf.active
  533.     jmp    sendq
  534. ;-----------------------
  535. ;
  536. ; rxecho - set flag so characters received
  537. ;       from host are echoed
  538. ;
  539. rxecho:    mvi    a,false
  540.     sta    buf.active
  541. sendq:    mvi    a,ctrlq    ;send ^Q to host
  542.     jmp    send
  543. ;-----------------------
  544. ;
  545. ; rxdint - disable host receive
  546. ;       character interrupts
  547. ;
  548. rxdint:    mvi    a,1    ;turn off so that
  549.     out    siobc    ; when we return to
  550.     mvi    a,00000000b; CP/M we won't
  551.     out    siobc    ; bomb out (RXDVR is
  552.     ret        ; overlayed)
  553. ;-----------------------
  554. ;
  555. ; prxch - print the last received character
  556. ;      from the host
  557. ;
  558. prxch:    di        ;let's not get any
  559.     lda    rxchar    ; interruptions while
  560.     mov    c,a    ; we talk a copy of
  561.     xra    a    ; the last character
  562.     sta    rxchar    ; received and clear
  563.     ei        ; it
  564.     mov    a,c    ;has a character been
  565.     ora    a    ; received ?
  566.     rz        ;no
  567.     jmp    conout    ;yes, print it so he
  568.             ; can see that something
  569.             ; is happening.
  570. ;-----------------------
  571. ;
  572. ; rxdvr - receive host character interrupt
  573. ;       driver.
  574. ;
  575. rxdvr:
  576.     push    psw    ;save registers
  577.     push    b
  578.     push    d
  579.     push    h
  580.  
  581. rxdvr2:    lda    buf.active;check for buffered
  582.     ora    a    ; mode
  583.     jrnz    rxbufi    ;yes
  584.     in    siobd    ;no, just get the
  585.     ani    noparity; character and save
  586.     sta    rxchar    ; it
  587.     jmpr    retdvr
  588. rxbufi:
  589.     lhld    free.ptr;buffered mode.
  590.     in    siobd    ;get character
  591.     ani    noparity; mask parity bit
  592.     mov    m,a    ; and store
  593.     sta    rxchar
  594.     inx    h    ;bump pointer
  595.     shld    free.ptr; and store.
  596.     lda    buf.sub    ;get end of buffer
  597.     ora    a    ; address depending
  598.     lxi    d,buf2    ; on buffer subscript
  599.     jrz    ..a
  600.     lxi    d,bufend
  601. ..a:    mov    a,h    ;is the current buffer
  602.     cmp    d    ; full (ie: is free.ptr
  603.     jrnz    ..ret    ; now pointing past
  604.     mov    a,l    ; current buffer) ?
  605.     cmp    e
  606.     jrnz    ..ret    ;no.
  607. ..full:    
  608.     lda    buf.sub    ;swap buffer pointers
  609.     ana    a    ; to other buffer
  610.     jrz    ..0    ; (using buffer
  611.     lxi    h,buf1    ; subscript)
  612.     mvi    a,0
  613.     jmpr    ..1
  614. ..0:    lxi    h,buf2
  615.     mvi    a,1
  616. ..1:    sta    buf.sub    ;record new buffer
  617.     shld    buf.ptr    ; pointers
  618.     shld    free.ptr
  619.  
  620.     mvi    a,true    ;signal that write
  621.     sta    buf.rdy    ; buffer is ready
  622.  
  623. ..ret:    lda    rxchar    ;if character from
  624.     cpi    ctrlz    ; host was a "^Z"
  625.     jrnz    retdvr    ; then also set the
  626.     mvi    a,true    ; end of file flag
  627.     sta    eof.flag
  628.  
  629. retdvr:    pop    h    ;restore registers
  630.     pop    d
  631.     pop    b
  632.     pop    psw
  633.     ei        ; and return
  634.     reti
  635. ;
  636. rxchar:    .byte    0
  637. ;
  638. ;-----------------------
  639. ;
  640. ; rxerra - receive host character error
  641. ;       interrupt driver.
  642. ;
  643. rxerra:
  644.     push    psw    ;if by some means
  645.     push    b    ; a parity or
  646.     push    d    ; framing error is
  647.     push    h    ; detected then
  648.     mvi    a,00010000b
  649.     out    siobc
  650.     mvi    a,00110000b; error reset
  651.     out    siobc
  652.     jmp    rxdvr2    ; and process character
  653. ;-----------------------
  654. ;
  655. ; getfile - get a CP/M file from host computer
  656. ;
  657. ;    entry:    FCB is file to get
  658. ;
  659. getfile:
  660.     lxi    h,buf1    ;initialise buffer pointers
  661.     shld    free.ptr; and subscripts for
  662.     shld    buf.ptr    ; transfer.
  663.     shld    write.ptr
  664.     mvi    a,0
  665.     sta    buf.sub
  666.     sta    wr.sub
  667.     mvi    a,false    ;clear done.flag, eof.flag,
  668.     sta    done.flag; buf.rdy indicator and
  669.     sta    eof.flag;  err.flag
  670.     sta    buf.rdy
  671.     sta    err.flag
  672.     call    make    ;open file
  673.     rnz        ; abort if error
  674.     call    rxinten    ;enable receive buffer interrupts
  675.     lda    log.flag;if log file operation
  676.     ana    a    ; then skip sending a <CR>
  677.     jrnz    ..1
  678.     mvi    a,cr    ;send <CR>
  679.     call    send    
  680. ..1:    lda    buf.rdy    ;if buf.ready.flag set then
  681.     ana    a
  682.     jrz    ..2
  683.     mvi    a,false
  684.     sta    buf.rdy
  685.     call    stopsend; stop host from sending
  686.     call    write    ; write to file
  687.     mvi    a,ctrlq    ; send host resume
  688.     call    send
  689.     jmpr    ..3
  690. ..2:
  691.     lda    eof.flag;else if end.of.file then
  692.     ora    a
  693.     jrz    ..3
  694.     call    stopsend; stop host from sending
  695.     call    puteofch; and put an end of file mark
  696.             ; in the buffer.
  697.     call    write
  698.     call    close
  699.     mvi    a,true    ; set done.flag
  700.     sta    done.flag
  701. ..3:
  702.     lda    done.flag
  703.     ora    a    ;if done.flag set then
  704.     jrnz    getexit; exit
  705.     lda    err.flag;if err.flag set then
  706.     ora    a    ; abort
  707.     jrnz    ..4
  708.     call    prxch
  709.     call    getch    ;get char (if any) from
  710.     ana    a    ; console. Skip the
  711.     jrz    ..1    ; tests if nothing typed
  712.     cpi    ctrly    ;test character and abort
  713.     jrz    ..4    ; if ^Y is struck
  714.     cpi    ctrlz
  715.     jrz    ..9
  716.     push    psw
  717.     lda    log.flag;if log file active
  718.     ana    a    ; then we want to send
  719.     jrnz    ..8    ; characters typed
  720.     pop    psw
  721.     jmpr    ..1
  722. ..8:    pop    psw
  723.     call    send
  724.     jmpr    ..1
  725. ..9:    mvi    a,true
  726.     sta    eof.flag
  727.     jmpr    ..1
  728. ..4:
  729.     call    rxecho
  730.     lxi    d,sabmsg; print "file transfer aborted"
  731.     call    prints    ; and return
  732.     ret
  733. getexit:
  734.     call    rxecho    ;disable host buffer Rx
  735.     lxi    d,sdnmsg;print "file transferred"
  736.     call    prints    ; and return
  737.     ret
  738. ;
  739. sabmsg:    .ascii    [cr][lf]'file transfer aborted'[cr][lf]'$'
  740. ;
  741. sdnmsg:    .ascii    [cr][lf]'file transferred from host'[cr][lf]'$'
  742. ;
  743. ;-----------------------
  744. ;
  745. ; sendfile - send CP/M file to host
  746. ;
  747. sendfile:
  748.     call    open    ;open file
  749.     rnz        ; and return if error
  750.     lxi    d,senmsg;print "sending file
  751.     call    prints    ; to host"
  752.     mvi    a,cr    ;send a <CR> to
  753.     call    send    ; host
  754. ..rdlp:    mvi    c,readf$;read next sector from
  755.     lxi    d,fcb    ; file to RBUF
  756.     call    bdose
  757.     ora    a    ;CP/M end of file?
  758.     jrnz    ..eof    ;yes
  759.     xra    a    ;no, clear newline
  760.     sta    crflag    ; flag so we only send
  761.             ; a <CR> for each <CR><LF>
  762.     lxi    h,rbuf    ;set address and
  763.     mvi    b,128    ; number of bytes
  764.  
  765. ..slp:    lda    crflag    ;was last char a <CR>?
  766.     ora    a
  767.     jrz    ..sn    ;no
  768.     xra    a    ;yes, reset flag
  769.     sta    crflag
  770.     .if    opt.delay,[
  771.         push    h        ;delay 250ms to allow
  772.         lxi     h,250   ; host to process the
  773.         call    delay   ; last line.
  774.         pop     h
  775.     ]
  776.     mov    a,m    ;get next character
  777.     inx    h
  778.     cpi    lf    ;ignore next linefeed
  779.     jrz    ..keep
  780.     jmpr    ..sn2
  781. ..sn:    mov    a,m    ;get next char from
  782.     inx    h    ; read buffer
  783. ..sn2:    cpi    cr    ;if it's a <CR> then
  784.     jrnz    ..sn1    ; set flag
  785.     sta    crflag
  786. ..sn1:    call    send    ; and send it to host
  787.     .if    testing,[
  788.         push    h       ;echo what we send
  789.         push    d       ; to the console.
  790.         push    b
  791.         push    psw
  792.         call    conout
  793.         pop     psw
  794.         pop     b
  795.         pop     d
  796.         pop     h
  797.     ]
  798.     cpi    ctrlz    ;was it a ^Z?
  799.     jrz    ..eof    ;yes
  800. ..keep:    djnz    ..slp    ;no, keep sending...
  801.     call    getch    ;check for ^Y from
  802.     cpi    ctrly    ; console
  803.     jrnz    ..rdlp    ; none, so keep going
  804.     lxi    d,sabmsg;print "file transfer
  805.     call    prints    ; aborted"
  806.     call    close
  807.     ret
  808. ..eof:    call    close    ;close input file
  809.     lxi    d,fstmsg;print "file sent
  810.     call    prints    ; to host successfully"
  811.     ret
  812. ;
  813. senmsg:    .ascii    [cr][lf]'Sending file to host...'[cr][lf]'$'
  814. ;
  815. fstmsg:    .ascii    [cr][lf]'File sent to host successfully'[cr][lf]'$'
  816. ;
  817. ;-----------------------
  818. ;
  819. ; make - create new CP/M file
  820. ;
  821. make:    lxi    d,fcb    ;delete any old
  822.     mvi    c,delet$; file
  823.     call    bdose
  824.     lxi    d,fcb    ; and open a new
  825.     mvi    c,creat$; one
  826.     call    bdose
  827.     cpi    0ffh    ;any errors ?
  828.     jrz    ..0    ;yes
  829.     mvi    a,false    ;no, return status
  830.     ora    a    ; OK
  831.     ret
  832. ..0:    lxi    d,opnmsg;error, print "open failure"
  833.     call    prints
  834.     mvi    a,true    ;and return with status
  835.     ora    a    ; not OK
  836.     ret
  837. ;
  838. opnmsg:    .ascii    [cr][lf]'?CP/M file create failure'[cr][lf]'$'
  839. ;
  840. ;-----------------------
  841. ;
  842. ; open - open file (which must already exist)
  843. ;
  844. open:    mvi    c,sdma$    ;set buffer address
  845.     lxi    d,rbuf    ; for reads
  846.     call    bdose
  847.     mvi    c,openf$
  848.     lxi    d,fcb
  849.     call    bdose
  850.     cpi    0ffh    ;find it?
  851.     jrz    ..opnf
  852.     xra    a
  853.     ret
  854. ..opnf:    lxi    d,opfmsg;no, print "can't find
  855.     call    prints    ; file"
  856.     mvi    a,0ffh
  857.     ora    a
  858.     ret
  859. ;
  860. opfmsg:    .ascii    [cr][lf]"?Can't find CP/M file"[cr][lf]'$'
  861. ;
  862. ;-----------------------
  863. ;
  864. ; close - close file
  865. ;
  866. close:
  867.     lxi    d,fcb
  868.     mvi    c,close$
  869.     jmp    bdose
  870. ;-----------------------
  871. ;
  872. ; stopsend - stop host from sending
  873. ;
  874. stopsend:
  875.     mvi    a,ctrls    ;send ^S
  876.     call    send
  877. ..0:
  878.     lhld    free.ptr; copy free.ptr
  879.     shld    sav.ptr
  880.     lxi    h,1000    ; delay 1 second
  881.     call    delay
  882.     lhld    sav.ptr    ; if free.pointer
  883.     lded    free.ptr;  hasn't moved then
  884.     ana    a    ;  return, else
  885.     dsbc    d    ;  keep waiting
  886.     jrnz    ..0
  887.     ret
  888. ;
  889. sav.ptr:.blkb    2
  890. ;
  891. ;-----------------------
  892. ;
  893. ; write - write buffer to CP/M disk file
  894. ;
  895. write:
  896.     lda    eof.flag;if not end.of.file then
  897.     ora    a    ; write out a whole buffer
  898.     jrz    ..3
  899.     lded    write.ptr; otherwise calculate
  900.     lhld    free.ptr; the number of sectors
  901.     ora    a    ; = ((free.ptr - write.ptr)*2/256)+1
  902.     dsbc    d
  903.     dad    h
  904.     mov    a,h
  905.     inr    a
  906.     jmpr    ..2
  907. ;
  908. ..3:    mvi    a,numsec;set number of sectors
  909. ..2:    sta    ..nsec    ; to write.
  910.  
  911. ..wnxt:
  912.     lded    write.ptr;set disk buffer
  913.     mvi    c,sdma$    ; address
  914.     call    bdose
  915.  
  916.     lxi    d,fcb    ;write next sector
  917.     mvi    c,write$
  918.     call    bdose
  919.     ana    a    ;abort if write error
  920.     jrnz    ..err    ; status returned.
  921.  
  922.     lhld    write.ptr;point to next logical
  923.     lxi    b,128    ; sector
  924.     dad    b
  925.     shld    write.ptr
  926.     lda    ..nsec    ;repeat until all sectors
  927.     dcr    a    ; have been written
  928.     sta    ..nsec
  929.     jrnz    ..wnxt
  930.  
  931.     lda    wr.sub    ;swap write.ptr and
  932.     ora    a    ; wr.sub to the
  933.     jrz    ..4    ; other buffer so
  934.     lxi    h,buf1    ; we write it next
  935.     mvi    a,0    ; time.
  936.     jmpr    ..5
  937. ..4:    lxi    h,buf2
  938.     mvi    a,1
  939. ..5:    sta    wr.sub
  940.     shld    write.ptr
  941.     ret
  942.  
  943. ..err:    lxi    d,wremsg;print "write error"
  944.     call    prints
  945.     call    close    ;close CP/M file
  946.     mvi    a,true    ; and set error flag
  947.     sta    err.flag
  948.     ret
  949. ;
  950. ..nsec:    .byte    0
  951. ;
  952. wremsg:    .ascii    [cr][lf]'?CRITICAL ERROR - Disk full'[cr][lf]'$' 
  953. ;
  954. ;-----------------------
  955. ;
  956. ; puteofch - Put an end-of-file marker (^Z)
  957. ;        at the end of the current buffer.
  958. ;
  959. puteofch:
  960.  
  961.     di
  962.     lhld    free.ptr
  963.     mvi    m,ctrlz
  964.     inx    h
  965.     shld    free.ptr
  966.     ei
  967.  
  968.     ret
  969. ;-----------------------
  970. ;
  971. ; delay - delay the millisecond count
  972. ;      passed in the HL register pair
  973. ;
  974. delay:    mvi    a,delcnt/26
  975. ..0:    dcx    h
  976.     inx    h
  977.     dcr    a
  978.     jnz    ..0
  979.     dcx    h
  980.     mov    a,l
  981.     ora    h
  982.     jnz    delay
  983.     ret
  984. ;
  985. ; G L O B A L   F L A G S
  986. ;
  987. done.flag:
  988.     .byte    0    ;set when transfer complete
  989. eof.flag:
  990.     .byte    0    ;set when ^Z received from host
  991. buf.rdy:
  992.     .byte    0    ;set when rx buffer full
  993. err.flag:
  994.     .byte    0    ;set if a fatal error occurs
  995. buf.active:
  996.     .byte    0    ;set when buffer i/o is active
  997.  
  998. crflag:    .byte    0    ;set to filter <LF> from sent file
  999. log.flag:
  1000.     .byte    0    ;set to store characters received
  1001.             ; in a log file.
  1002. ;
  1003. ; B U F F E R   P O I N T E R S
  1004. ;
  1005. free.ptr:        ;points to next free byte to
  1006.             ; receive a character from
  1007.     .word    buf1    ; the host.
  1008. buf.ptr:        ;points to start of current
  1009.     .word    buf1    ; receive buffer.
  1010. write.ptr:        ;points to start of the next
  1011.     .word    buf1    ; buffer to write to disk.
  1012. buf.sub:        ;subscript into buffer
  1013.     .byte    0    ;( 0=buf1, 1=buf2 )
  1014. wr.sub:    .byte    0
  1015. ;
  1016. ; fcb - CP/M file control block
  1017. ;
  1018. fcb:    .blkb    36
  1019. ;
  1020. ; B U F F E R S
  1021. ;
  1022. ;
  1023. ; conbuf - console input buffer
  1024. ;
  1025. cbfsiz    =    64
  1026. conbuf:    .byte    cbfsiz
  1027. nchrs:    .byte    0
  1028.     .blkb    cbfsiz
  1029. ;
  1030. numsec    ==    bufsiz/128
  1031. ;
  1032. buf1:    .blkb    bufsiz
  1033. buf2:    .blkb    bufsiz
  1034. bufend:
  1035. ;
  1036. rbuf:    .blkb    128    ;CP/M file read buffer
  1037. ;
  1038.     .end    start
  1039.