home *** CD-ROM | disk | FTP | other *** search
/ CP/M / CPM_CDROM.iso / simtel / sigm / vols000 / vol054 / i-o-cap.asm < prev    next >
Assembly Source File  |  1984-04-29  |  19KB  |  745 lines

  1. ;       I/O-CAP.ASM Version 1.0 as of September 13, 1981
  2. ;                  By: Kelly Smith, CP/M-Net
  3. ;
  4. ; Version 1.0: Initial release by Kelly Smith
  5. ;
  6. ;      Note:  Please  append  any  changes to I/O-CAP  with  a 
  7. ; 'Version  Log' and change comments (your name would be  nice 
  8. ; too) top-down from the initial Version 1.0 release.
  9. ;  
  10. ;      Running  I/O-CAP  (the  first time) will  relocate  the 
  11. ; CONIN,  and CONOUT jump vectors to high memory and then  ALL 
  12. ; subsequent   input  or  output  (depending  on   conditional 
  13. ; assembly  switches)  will  be  buffered  (16  sectors)   for  
  14. ; eventual  output  to  disk with a filename and type   called  
  15. ; USER.LOG.  This file will then be updated as long as I/O-CAP 
  16. ; is   active  in  the system.   Note:   I/O-CAP may  be  made 
  17. ; inactive  by just type I/O-CAP again,  to toggle it off  (or 
  18. ; on).
  19. ;      I/O-CAP   requires   an  unusually  LARGE   amount   of 
  20. ; relocation  memory,  because it must buffer the entire  CP/M 
  21. ; system image to high memory to save and restore all CCP  and 
  22. ; BDOS pointers as it captures each 16 sector block of console 
  23. ; input or output...crude,  but the ONLY other wait to do this 
  24. ; would  be to  'hot-patch' the CCP and BDOS 'on-the-fly'  and 
  25. ; that  get's  just   a   bit  gruesome  from   a    UNIVERSAL   
  26. ; applications  standpoint...It's much easier to just SYSGEN a 
  27. ; smaller   CP/M  system  than your actual  maximum  available 
  28. ; memory,   and  then have I/O-CAP relocate itself above  your 
  29. ; BIOS.  If  anyone has a better way to do this  WITHOUT  this 
  30. ; relocation  crap,  I  would be eager to see it...I just  got 
  31. ; frustrated  with  trying to figure out what CP/M  was  doing 
  32. ; internally  to pursue it further...local  stacks,  pointers, 
  33. ; etc.,...ARGH...so I took the easy way out.
  34. ;      Thanks  to  Mike Karas for discovering  the  BDOS  CALL 
  35. ; contention  problems  when the BDOS stack was not saved  and 
  36. ; restored when saving the console buffer to disk.
  37. ;                       - Applications -
  38. ; (1)   Don't have a printer,  and want 'Hard Copy' of a  user 
  39. ; dialog  with the system?  Use I/O-CAP to creat it as a  disk 
  40. ; file...for  instance,  when making patches into  'uncertain' 
  41. ; areas of the system with DDT (or SID,  or whatever) you  can 
  42. ; keep  a  running  history on disk of the patches  AND  their 
  43. ; effects.
  44. ; (2)   Need to show example of console dialog for an  article 
  45. ; or book and you don't want to 'hand type' it in? Use I/O-CAP 
  46. ; to creat the examples for you,  and edit the dialog to  suit 
  47. ; your needs.
  48. ; (3)   Need to know all the events in 'history form'  leading 
  49. ; to  some bizarre system blow-up?  Use I/O-CAP to record that 
  50. ; history  for you (but only if the blow-up is recoverable  by 
  51. ; NOT COLD BOOTING the system).
  52. ; (4)   Want  to  (secretly) monitor the activities  of  other 
  53. ; users  of  the system?  Use I/O-CAP to record  user  console 
  54. ; input,  and check in from time-to-time to look at the system 
  55. ; activity.  Used  in  conjunction with BYE on a  remote  CP/M 
  56. ; system,  you can finally figure-out how that 'twit' clobbers 
  57. ; your  system from 3000 miles away...and NOT fill a room full 
  58. ; of  paper by logging all input to your  printer.  Note:  Run 
  59. ; I/O-CAP first,  then BYE.COM to 'grab' the vectors set-up by 
  60. ; the I/O-CAP program.The capture of incoming data will appear 
  61. ; to be transparent to the user,  with a slight pause when  it 
  62. ; updates the USER.LOG file...but this only happens every 2048 
  63. ; character entrys, so it should generally go un-noticed.
  64. ;                      - Using I/O-CAP -
  65. ;      Examine  the various conditional assembly switches  and 
  66. ; set  TRUE or FALSE depending on your requirements with  your 
  67. ; editor  (ED.COM).  Then assemble with ASM.COM (or  MAC.COM), 
  68. ; load it to creat a .COM file and then run.  The  conditional 
  69. ; assembly switches allow the following options:
  70. ; (1)   DEBUG  -  I/O-CAP runs at 8000 Hex...about  right  for 
  71. ; most small applications programs that use memory from 100 to 
  72. ; 7FFF Hex in a 56K CP/M system.  If FALSE, I/O-CAP runs above 
  73. ; a  48K  CP/M  system (C800 Hex),  with  no  restrictions  on 
  74. ; applications programs.
  75. ; (2)  QUIET - If FALSE, rings the console bell just before it 
  76. ; writes 2048 bytes of captured console INPUT or OUTPUT.
  77. ; (3)   ERRDISP - If TRUE,  I/O-CAP will display an  'OOPS...' 
  78. ; message on the console if the disk or directory is full.
  79. ; (4)   INPUT  - If  TRUE,  only  console  keyboard  INPUT  is 
  80. ; captured. Note: OUTPUT must be FALSE if INPUT is TRUE.
  81. ; (5)   OUTPUT  - If  TRUE,  both console keyboard  INPUT  and 
  82. ; OUTPUT will be captured...uses 'gobs' of disk storage if you 
  83. ; let I/O-CAP run for any length of time.  Note: INPUT must be 
  84. ; FALSE if OUTPUT is TRUE.
  85. ; (6) QUIT - If TRUE, when a Control-Z and Carriage Return are 
  86. ; entered  at  the console keyboard,  I/O-CAP will append  the 
  87. ; USER.LOG file with a physical end-of-file (i.e.,  no further 
  88. ; data  will  be  displayed in USER.LOG  although  it  may  be 
  89. ; physically appended to it)...Note: You must type I/O-CAP<cr> 
  90. ; to CLOSE the current USER.LOG,  and reset the disk to normal 
  91. ; R/W  status.  Failure  to  do so will result in a  R/O  BDOS 
  92. ; Error  on  any subsequent attempt to write to  the  disk  by 
  93. ; means other than I/O-CAP.
  94. ; (7) SYSLOG - If TRUE,  creates USER.LOG as a $SYS (invisible 
  95. ; to  directory)  file,  so that 'secrecy' is maintained  when 
  96. ; capturing  user input...be sure and rename USER.LOG to  your 
  97. ; 'private' name, or replace the TYPE command with MLIST.COM.
  98. ;      Please  send any changes,  'bug' reports,  suggestions, 
  99. ; comments,  gripes or bitches to the CP/M-Net  system,  (805) 
  100. ; 527-9321...have  fun with this program.  It's in the  public 
  101. ; domain, but NOT TO BE USED for COMMERCIAL BENEFIT.
  102. ;                                    Best regards,
  103. ;                                    Kelly Smith, CP/M-Net
  104. ;
  105. ;
  106. ; define TRUE/FALSE assembly parameters
  107. ;
  108. true    equ    -1    ; define TRUE
  109. false    equ    not true; define FALSE
  110. debug    equ    true    ; define DEBUG
  111. quiet    equ    false    ; define QUIET (ring BELL, if not true)
  112. errdisp    equ    true    ; define ERRDISP (display errors, if true)
  113. quit    equ    true    ; define QUIT (EOF, if Control-Z found)
  114. syslog    equ    false    ; define SYSLOG (make USER.LOG a $SYS file)
  115. ;
  116. ; >>> Note: only one of the following two assembly switches may be true <<<
  117. ;
  118. input    equ    false    ; define INPUT (I/O-CAP console input)
  119. output    equ    true    ; define OUTPUT (I/O-CAP console output)
  120. ;
  121.     if    DEBUG
  122. dest    equ    08000h    ; running location of code
  123.     endif        ; DEBUG
  124.  
  125.     if    not DEBUG
  126. dest    equ    0c800h    ; running location of code
  127.     endif        ; DEBUG
  128. ;
  129. ; BDOS entry point and function codes
  130. base    equ    0    ; <<-- set to offset of CP/M for your
  131.             ; system, standard systems are 0, some
  132.             ; 'alternate' systems are 4200H
  133. bdos    equ    base+5
  134. resdsk    equ    13    ; reset disk system
  135. offc    equ    15    ; open file
  136. cffc    equ    16    ; close file
  137. dffc    equ    19    ; delete file
  138. rrfc    equ    20    ; read record
  139. wrfc    equ    21    ; write record
  140. mffc    equ    22    ; make file
  141. sdma    equ    26    ; set dma address
  142. ; secondary FCB field definitions
  143. fn    equ    1    ; file name field (rel)
  144. ft    equ    9    ; file type field (rel)
  145. ex    equ    12    ; file extent field (rel)
  146. frc    equ    15    ; file record count (rel)
  147. nr    equ    32    ; next record field (rel)
  148. ; ASCII control characters
  149. cr    equ    0dh    ; carriage return
  150. lf    equ    0ah    ; line feed
  151. bel    equ    07h    ; bell signal
  152. ;
  153. ; This  program runs up in high ram.  It gets there,  by being 
  154. ; moved  there  when 'I/O-CAP'  is typed. Change the following 
  155. ; equate to an area in your high memory where this program may 
  156. ; patch itself in.  Approximate memory requirements:  2k bytes 
  157. ; or more,  depending upon the options selected.  a marker has 
  158. ; been  placed  at  the  end to deliberately  print  an  error 
  159. ; message  during  assembly in order to determine  the  actual 
  160. ; ending  address of the program.  The error message will  not 
  161. ; affect the assembly.  make sure you have memory available up 
  162. ; to the address shown.
  163. ;
  164.     org    base+100h
  165. ;
  166. ; Move 'I/O-CAP' program up to high ram and jump to it
  167. ;
  168.     lxi    h,0    ; save old stack pointer
  169.     dad    sp
  170.     shld    oldstk
  171.     lxi    sp,stack; make a new stack pointer
  172.     lxi    h,tbuf    ; set pointer to tbuf
  173.     shld    ptr
  174.     lxi    h,0    ; set size = 0
  175.     shld    size
  176.     lhld    base+1    ; get BIOS pointer
  177.     lxi    d,5    ; add bias to console status address
  178.     dad    d
  179.     mov    d,m    ; save in [d]
  180.     lhld    newjtbl+1    ; see if vector addresses active
  181.     mov    a,h    ; been patched by previous execution?
  182.     cmp    d
  183.     jz    unpatch    ; un-patch, if so
  184.     lxi    b,pend-start+1        ; number of bytes to move
  185.     lxi    h,dest+pend-start+1    ; end of moved code
  186.     lxi    d,source+pend-start    ; end of source code
  187. ;
  188. mvlp    ldax    d    ; get byte
  189.     dcx    h    ; bump pointers
  190.     mov    m,a    ; new home
  191.     dcx    d
  192.     dcx    b    ; bump byte count
  193.     mov    a,b    ; check if zero
  194.     ora    c
  195.     jnz    mvlp    ; if not, do some more
  196.     pchl        ; do it, to it...
  197. ;
  198. source    equ    $    ; boundary memory marker
  199. ;
  200. offset    equ    dest-source ; relocation amount
  201. ;
  202. ; The following code gets moved to high ram located at "dest", 
  203. ; where it is executed. C A U T I O N :  if modifying anything 
  204. ; in this program from here on: ALL labels must be of the form:
  205. ;
  206. ; label    equ    $+offset        
  207. ;
  208. ; ...in   order   that  the  relocation  to  high   ram   work 
  209. ; successfully.   Forgetting  to specify '$+offset' will cause 
  210. ; the program to jmp into whatever is currently in low memory, 
  211. ; with unpredictable results.  Be careful....        
  212. ;
  213. start    equ    $+offset
  214. ;
  215. ; patch in the new jump table (saving the old)
  216. ;
  217. patch    equ    $+offset
  218.     call    tbladdr        ; calc [hl] =  CP/M jmp table
  219.     lxi    d,vcstat    ; point to save location
  220.     call    move        ; move it
  221. ;
  222. ; now move new jump table to CP/M
  223. ;
  224.     call    tbladdr        ; calc [hl] = CP/M's jmp table
  225.     xchg            ; move to de
  226.     lxi    h,newjtbl    ; point to new
  227.     call    move        ; move it
  228.     lxi    h,active$message
  229.     call    msgout
  230.     lhld    oldstk        ; get old CP/M stack pointer
  231.     sphl
  232.     ret
  233. ;
  234. unpatch equ    $+offset
  235.     call    reset    ; reset disk in case it's R/O
  236.     lxi    h,inactive$message
  237.     call    msgout
  238.     call    tbladdr        ; [hl] = CP/M's jmp table
  239.     xchg            ; move to de
  240.     lxi    h,vcstat    ; get saved table
  241.     call    move        ; move orig back
  242.     lhld    oldstk        ; get old CP/M stack pointer
  243.     sphl
  244.     ret            
  245. ;
  246. ; calculate [hl] = CP/M's jump table, [b] = length
  247. ;
  248. tbladdr equ    $+offset
  249.     lhld    base+1        ; get BIOS pointer
  250.     inx    h        ; ..skip
  251.     inx    h        ; ..to
  252.     inx    h        ; ..console status
  253.     mvi    b,9        ; move console jump vectors
  254.     ret
  255. ;
  256. ; move [hl] to [de], length in [b]
  257. ;
  258. move    equ    $+offset
  259.     mov    a,m        ; get a byte
  260.     stax    d        ; put at new home
  261.     inx    d        ; bump pointers
  262.     inx    h
  263.     dcr    b        ; decrement byte count
  264.     jnz    move        ; if more, do it
  265.     ret            ; if not, return
  266. ;
  267. ; move [hl] to [de], length in [bc]
  268. ;
  269. movecpm    equ    $+offset
  270.     mov    a,m        ; get a byte
  271.     stax    d        ; put at new home
  272.     inx    d        ; bump pointers
  273.     inx    h
  274.     dcx    b        ; decrement byte count
  275.     mov    a,b
  276.     ora    c
  277.     jnz    movecpm        ; if more, do it
  278.     ret            ; if not, return
  279. ;
  280. msgout    equ    $+offset
  281.     mov    a,m        ; get character from message string
  282.     ora    a        ; all of string displayed?
  283.     rz            ; return, if so
  284.     inx    h        ; no, bump pointer for next character
  285.     mov    c,a        ; pass character to 'old' BIOS vector
  286.     call    conout
  287.     jmp    msgout        ; display next character in message string
  288. ;
  289. ; This area is used for vectoring calls to the user's CBIOS, 
  290. ; but saving the registers first in case they are destroyed.
  291. ;
  292. constat equ    $+offset
  293.     push    b
  294.     push    d
  295.     push    h
  296.     call    vcstat
  297.     pop    h
  298.     pop    d
  299.     pop    b
  300.     ret
  301. ;
  302. conin    equ    $+offset
  303.     push    b
  304.     push    d
  305.     push    h
  306.     call    vcin
  307.     pop    h
  308.     pop    d
  309.     pop    b
  310.     ret
  311. ;
  312. conout    equ    $+offset
  313.     push    b
  314.     push    d
  315.     push    h
  316.     call    vcout
  317.     pop    h
  318.     pop    d
  319.     pop    b
  320.     ret
  321. ;
  322. ; This  is  the jump table which is copied on top of  the  one 
  323. ; pointed to by location 1 in CP/M
  324. ;
  325. newjtbl equ    $+offset
  326.     jmp    constat    ; console status test
  327.  
  328.     if    INPUT
  329.     jmp    capture    ; console input I/O-CAP routine
  330.     endif        ; INPUT
  331.  
  332.     if    OUTPUT
  333.     jmp    conin    ; console input routine
  334.     endif        ; OUTPUT
  335.  
  336.     if    INPUT
  337.     jmp    conout    ; console output routine
  338.     endif        ; INPUT
  339.  
  340.     if    OUTPUT
  341.     jmp    capture    ; console I/O-CAP output routine
  342.     endif        ; OUTPUT
  343.  
  344. ;
  345. capture    equ    $+offset
  346.     push    h
  347.     push    d
  348.     push    b
  349.     lxi    h,0    ; save old stack pointer
  350.     dad    sp
  351.     shld    oldstk
  352.     lxi    sp,stack; make a new stack pointer
  353.  
  354.     if    INPUT
  355.     call    vcin    ; get console input
  356.     mov    c,a    ; save in [c] for 'save'
  357.     push    psw    ; and save on the stack
  358.     endif        ; INPUT
  359.  
  360.     call    save    ; save characters in buffer
  361.  
  362.     if    INPUT
  363.     pop    psw    ; get console input of the stack
  364.     endif        ; INPUT
  365.  
  366.     lhld    oldstk    ; get old CP/M stack pointer
  367.     sphl
  368.     pop    b
  369.     pop    d
  370.     pop    h
  371.  
  372.     if    OUTPUT
  373.     jmp    vcout
  374.     endif        ; OUTPUT
  375.  
  376.     if    INPUT
  377.     ret
  378.     endif        ; INPUT
  379.  
  380. save:    equ    $+offset
  381.     lhld    size    ; size = size + 1
  382.     inx    h
  383.     shld    size
  384.     lhld    ptr
  385.     mov    m,c
  386.     inx    h
  387.  
  388.     if    INPUT
  389.     mov    a,c
  390.     cpi    cr    ; carriage return?
  391.     jnz    notcr
  392.     mvi    m,lf    ; yes, so add line feed because CP/M does not
  393.     inx    h    ; bump pointer, for next time thru
  394.     endif        ; INPUT
  395.  
  396. notcr    equ    $+offset; make label for next instruction...
  397.  
  398.     if    QUIT
  399.     mov    a,c
  400.     cpi    'Z'-40h    ; control-Z?
  401.     jz    wtb    ; write buffer, if so
  402.     endif        ; QUIT
  403.  
  404.     shld    ptr
  405.     lxi    d,endmark    ; get 'endmark' for buffer top address
  406.     mov    a,d
  407.     cmp    h    ; getting near the end of buffer yet?
  408.     rnz        ; if not, just return
  409.     mov    a,e    ; very near the top now, final address loaded?
  410.     cmp    l
  411.     rnz        ; if not, just return
  412.  
  413.     if    not QUIET
  414.     mvi    c,bel    ; warn user that we need to write to disk
  415.     call    conout
  416.     endif        ; QUIET
  417.  
  418. ; wtb - write text buffer to disk
  419. wtb:    equ    $+offset
  420.     lhld    base+6    ; get warm boot address for next bias to CCP
  421.     lxi    d,0fffah; make bias to CCP
  422.     dad    d    ; add bias to [hl]
  423.     lxi    b,1600h    ; make quantity to move
  424.     lxi    d,cpmbuf; buffer all of CP/M system
  425.     call    movecpm    ; move it...
  426.     call    reset    ; reset disk in case it's R/O
  427.     call    open    ; attempt to open USER.LOG
  428.     inr    a    ; check CP/M return code
  429.     jnz    makeok    ; USER.LOG already exist?
  430. ;
  431. nolog:    equ    $+offset
  432. ;
  433.     call    make    ; make new file
  434.     inr    a    ; check CP/M return code
  435.     jnz    makeok
  436.  
  437.     if    ERRDISP
  438.     lxi    h,dirful; oops...can't make file, return to CP/M
  439.     call    msgout
  440.     endif        ; ERRDISP
  441.  
  442.     jmp    base
  443. ;
  444. ; USER.LOG exists, so set the FCB entry for next append to file
  445. ;
  446. makeok:    equ    $+offset
  447. ;
  448.     lda    fcb+frc    ; get record count
  449.     sta    fcb+nr    ; make next record
  450.     lhld    size    ; [de] = tbuf size
  451.     xchg
  452.     lxi    h,dbuf    ; top of stack points to dbuf
  453.     push    h
  454.     lxi    h,tbuf    ; [hl] points to tbuf
  455. wtb1:    equ    $+offset
  456.     mvi    c,128    ; disk buffer size
  457. wtb2:    equ    $+offset
  458.     mov    a,m    ; fetch next byte of tbuf
  459.     inx    h
  460.     xthl
  461.     mov    m,a    ; store in dbuf
  462.     inx    h
  463.     xthl
  464.     dcx    d    ; size = size - 1
  465.     mov    a,d    ; exit loop if size = 0
  466.     ora    e
  467.     jz    wtb3
  468.     dcr    c    ; loop until dbuf full
  469.     jnz    wtb2
  470.     call    setdma    ; set dma to dbuf
  471.     call    write    ; write full dbuf to disk
  472.     push    psw    ; save possible error code
  473.     lda    fcb+frc    ; get record count
  474.     sta    fcb+nr    ; make next record
  475.     pop    psw    ; get possible error code
  476.     ora    a    ; check CP/M return code
  477.     jz    nextbuf
  478.  
  479.     if    ERRDISP
  480.     lxi    h,dskful; oops...disk is full
  481.     call    msgout
  482.     endif        ; ERRDISP
  483.  
  484.     jmp    base
  485. ;
  486. nextbuf    equ    $+offset
  487. ;
  488.     xthl        ; top of stack points to dbuf
  489.     lxi    h,dbuf
  490.     xthl
  491.     jmp    wtb1    ; loop until end of tbuf
  492. wtb3:    equ    $+offset
  493.     pop    h    ; [hl] points to current place in dbuf
  494. wtb4:    equ    $+offset
  495.     mvi    m,'Z'-40h ; store eof code
  496.     inx    h
  497.     dcr    c    ; loop thru rest if dbuf
  498.     jnz    wtb4
  499.     call    setdma    ; set dma to dbuf
  500.     call    write    ; write last sector to disk
  501.     push    psw    ; save possible error code
  502.     lda    fcb+frc    ; get record count
  503.     sta    fcb+nr    ; make next record
  504.     pop    psw    ; get possible error code
  505.     ora    a    ; check CP/M return code
  506.     jz    closeup
  507.  
  508.     if    ERRDISP
  509.     lxi    h,dskful; oops...disk is full
  510.     call    msgout
  511.     endif        ; ERRDISP
  512.  
  513.     jmp    base
  514. ;
  515. closeup    equ    $+offset
  516. ;
  517.     call    close    ; clean up act and go home
  518.     lxi    h,tbuf    ; clear text buffer
  519.     shld    ptr
  520.     lxi    h,0
  521.     shld    size
  522. wtb5:    equ    $+offset
  523.     lhld    base+6    ; get warm boot address for next bias to CCP
  524.     lxi    d,0fffah; make bias to CCP
  525.     dad    d    ; add bias to [hl]
  526.     lxi    b,1600h    ; make quantity to move
  527.     lxi    d,cpmbuf; buffer all of CP/M system
  528.     xchg        ; swap
  529.     call    movecpm    ; move it...
  530.     ret
  531. ;  reset - reset disk
  532. ;
  533. reset:    equ    $+offset
  534.     push    h
  535.     push    d
  536.     push    b
  537.     mvi    c,resdsk
  538.     call    bdos
  539.     pop    b
  540.     pop    d
  541.     pop    h
  542.     ret
  543. ; open - open disk file
  544. open:    equ    $+offset
  545.     push    h
  546.     push    d
  547.     push    b
  548.     lxi    d,fcb
  549.     mvi    c,offc
  550.     call    bdos
  551.     pop    b
  552.     pop    d
  553.     pop    h
  554.     ret
  555. ; read - read record from disk file
  556. read:    equ    $+offset
  557.     push    h
  558.     push    d
  559.     push    b
  560.     lxi    d,fcb
  561.     mvi    c,rrfc
  562.     call    bdos
  563.     pop    b
  564.     pop    d
  565.     pop    h
  566.     ret
  567. ; close - close disk file
  568. close:    equ    $+offset
  569.     push    h
  570.     push    d
  571.     push    b
  572.     lxi    d,fcb
  573.     mvi    c,cffc
  574.     call    bdos
  575.     pop    b
  576.     pop    d
  577.     pop    h
  578.     ret
  579. ; delt - delete disk file
  580. delt:    equ    $+offset
  581.     push    h
  582.     push    d
  583.     push    b
  584.     lxi    d,fcb
  585.     mvi    c,dffc
  586.     call    bdos
  587.     pop    b
  588.     pop    d
  589.     pop    h
  590.     ret
  591. ; write - write record to disk
  592. write:    equ    $+offset
  593.     push    h
  594.     push    d
  595.     push    b
  596.     lxi    d,fcb
  597.     mvi    c,wrfc
  598.     call    bdos
  599.     pop    b
  600.     pop    d
  601.     pop    h
  602.     ret
  603. ; make - make new disk file
  604. make:    equ    $+offset
  605.     push    h
  606.     push    d
  607.     push    b
  608.     lxi    d,fcb
  609.     mvi    c,mffc
  610.     call    bdos
  611.     pop    b
  612.     pop    d
  613.     pop    h
  614.     ret
  615. ; setdma - set dma address for disk file
  616. setdma:    equ    $+offset
  617.     push    h
  618.     push    d
  619.     push    b
  620.     lxi    d,dbuf
  621.     mvi    c,sdma
  622.     call    bdos
  623.     pop    b
  624.     pop    d
  625.     pop    h
  626.     ret
  627. ;
  628.  
  629.     if    ERRDISP
  630. dskful:    equ    $+offset
  631.     db    cr,lf,bel,'OOPS...disk is full!',0
  632. ;
  633. dirful:    equ    $+offset
  634.     db    cr,lf,bel,'OOPS...directory is full!',0
  635.     endif        ; ERRDISP
  636.  
  637. ;
  638. active$message    equ    $+offset
  639.     db    '  (Active)',0
  640. ;
  641. inactive$message    equ    $+offset
  642.     db    '  (Inactive)',0
  643. ;
  644. fcb    equ    $+offset
  645.     db    0    ; default drive specifier
  646.  
  647.     if    SYSLOG
  648.     db    'USER    L','O'+80h,'G'
  649.     endif        ; SYSLOG
  650.  
  651.     if    not SYSLOG
  652.     db    'USER    LOG'
  653.     endif        ; SYSLOG
  654.  
  655.     db    0,0,0,0,0,0,0,0,0,0
  656. ;
  657. pend    equ    $+offset; end of relocated code
  658. ;
  659. ; data area
  660.     ds    128    ; 64 level stack
  661. stack    equ    $+offset;local stack
  662. ;
  663. ptr:    equ    $+offset
  664.     ds    2    ; text buffer pointer
  665. ;
  666. size:    equ    $+offset
  667.     ds    2    ; text buffer size
  668. ;
  669. ; Save the CP/M jump table here
  670. ;
  671. vcstat    equ    $+offset
  672.     ds    3
  673. ;
  674. vcin    equ    $+offset
  675.     ds    3
  676. ;
  677. vcout    equ    $+offset
  678.     ds    3
  679. ;
  680. oldstk    equ    $+offset
  681.     ds    2    ; storage for old CP/M stack pointer
  682. ;
  683. cpmbuf    equ    $+offset
  684.     ds    1600h    ; storage CP/M system image
  685. ;
  686. dbuf    equ    $+offset
  687.     ds    128    ; secondary disk buffer address
  688. ;
  689. tbuf:    equ    $+offset
  690.     ds    16*128    ; I/O-CAP storage for 16 sectors (2048 bytes)
  691. ;
  692. endmark    equ    $+offset;! ignore error - this marks end of program
  693. ;
  694.     end
  695.