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 / BDOS / Z80DOS10.LBR / Z80DDISK.ZZ0 / Z80DDISK.Z8°
Text File  |  2000-06-30  |  44KB  |  1,524 lines

  1. ; Z80DOS - Z80 Disk Operating System
  2. ;
  3. ; Version 1.0 - 05 Sept. 87 by Carson Wilson
  4. ;
  5.  
  6. ; -------------------------------------------------------------------
  7. ;
  8. ; Z80DDISK.Z80 - Return CP/M Version, Disk Functions
  9. ;
  10. ; -------------------------------------------------------------------
  11.  
  12. ;
  13. ; Return version number
  14. ;
  15. cmnd12:    ld    a,22h            ; Set version number
  16.     jr    cmd25a            ; And exit
  17. ;
  18. ; -----------------------------
  19. ;
  20. ;    Disk functions
  21. ;
  22. ; -----------------------------
  23. ;
  24. ; Reset disk system
  25. ;
  26. cmnd13:    ld    hl,0            ; Load zero
  27.     ld    (login),hl        ; All drives logged out
  28.     ld    (dskro),hl        ; All drives read/write
  29.     xor    a
  30.     ld    (diff),a        ; Disk changed flag
  31.     ld    hl,RamLow+00080h    ; Set up DMA address
  32.     ld    (DMA),hl        ; And save it
  33.     call    stDMA            ; Do BIOS call
  34.     xor    a            ; Set default drive = 'A'
  35.     ld    (defdrv),a        ; Save it
  36.     ld    a,ResDsk        ; <crw>
  37.     call    seldk            ; Select drive 0=A, 1=B, etc.
  38.     ld    a,(subflg)        ; Get submit flag
  39.     jr    cmd25a            ; Exit
  40. ;
  41. ; Search for file
  42. ;
  43. cmnd17:    call    seldrv            ; Select drive from FCB
  44.     ld    a,(ix+0)        ; Get drive number from FCB
  45.     sub    '?'            ; Test if '?'
  46.     jr    z,cmd17b        ; If so all entries match
  47.     ld    a,(ix+14)        ; Get system byte
  48.     cp    '?'            ; Test if '?'
  49.     jr    z,cmd17a        ; Yes, jump
  50.     ld    (ix+14),0        ; Load system byte with zero
  51. cmd17a:    ld    a,15            ; Test first 15 items in FCB
  52. cmd17b:    call    search            ; Do search
  53. cmd17c:    ld    hl,(dirbuf)        ; Copy directory buffer
  54.     ld    de,(DMA)        ; To DMA address
  55.     ld    bc,128            ; Directory=128 bytes
  56.     ldir
  57.     ret                ; Exit
  58. ;
  59. ; Search for next occurrence of file
  60. ;
  61. cmnd18:    ld    ix,(dcopy)        ; Get last FCB used by search
  62.     call    seldrv            ; Select drive from FCB
  63.     call    searcn            ; Search next file match
  64.     jr    cmd17c            ; And copy directory to DMA address
  65. ;
  66. ; Delete file
  67. ;
  68. cmnd19:    call    seldrv            ; Select drive from FCB
  69.     call    delete            ; Delete file
  70. cmd19a:    ld    a,(searex)        ; Get exit byte 00=file found,0ffh not
  71.     jr    cmd25a            ; And exit
  72. ;
  73. ; Rename file
  74. ;
  75. cmnd23:    call    seldrv            ; Select drive from FCB
  76.     call    renam            ; Rename file
  77.     jr    cmd19a            ; And exit
  78. ;
  79. ; Return login vector
  80. ;
  81. cmnd24:    ld    hl,(login)        ; Get login vector
  82. cmd24a:    ld    (pexit),hl        ; Save it
  83.     ret                ; And exit
  84. ;
  85. ; Return current drive
  86. ;
  87. cmnd25:    ld    a,(defdrv)        ; Get current drive
  88. cmd25a:    jp    exit            ; And exit
  89. ;
  90. ; Return allocation vector
  91. ;
  92. cmnd27:    ld    hl,(alv)        ; Get allocation vector
  93.     jr    cmd24a            ; And exit
  94. ;
  95. ; Return disk R/O vector
  96. ;
  97. cmnd29:    ld    hl,(dskro)        ; Get disk R/O vector
  98.     jr    cmd24a            ; And exit
  99. ;
  100. ; Set file attributes
  101. ;
  102. cmnd30:    call    seldrv            ; Select drive from FCB
  103.     call    cstat            ; Change status
  104.     jr    cmd19a            ; And exit
  105. ;
  106. ; Get Disk Parameter Block Address
  107. ;
  108. cmnd31:    ld    hl,(ixp)        ; get drive table
  109.     jr    cmd24a            ; And exit
  110. ;
  111. ; Set/get user code
  112. ;
  113. cmnd32:    ld    a,e            ; Get user code
  114.     inc    a            ; Test if 0ffh
  115.     ld    a,(user)        ; Get old user code
  116.     jr    z,cmd25a        ; If 0ffh then exit
  117.     ld    a,e            ; Get new user code
  118.     and    01fh            ; Mask it
  119.     ld    (user),a        ; Save it
  120.     ret                ; And exit
  121. ;
  122. ; Compute file size
  123. ;
  124. cmnd35:    call    seldrv            ; Select drive from FCB
  125.     call    filsz            ; Compute file size
  126.     jr    cmd19a            ; And exit
  127. ;
  128. ; Set random record count
  129. ;
  130. cmnd36:    ld    hl,32            ; Set pointer to next record
  131.     call    calrrc            ; Calculate random record count
  132. ldrrc:    ld    (ix+33),d        ; And save random record count
  133.     ld    (ix+34),c
  134.     ld    (ix+35),b
  135.     ret                ; And exit
  136. ;
  137. ; Reset individual disk drives
  138. ;
  139. cmnd37:    ld    a,e            ; Get mask LSB
  140.     cpl                ; Complement it
  141.     ld    e,a
  142.     ld    a,d            ; Get mask MSB
  143.     cpl                ; Complement it
  144.     ld    d,a
  145.     ld    hl,(login)        ; Get login vector
  146.     ld    a,e            ; Mask login vector
  147.     and    l            ; LSB
  148.     ld    l,a
  149.     ld    a,d            ; Mask login vector
  150.     and    h            ; MSB
  151.     ld    h,a
  152.     ld    (login),hl        ; Save login vector
  153.     ex    de,hl            ; Use login vector as mask
  154.     ld    hl,(dskro)        ; Get drive R/O vector
  155.     ld    a,e            ; Mask drive R/O vector
  156.     and    l            ; LSB
  157.     ld    l,a
  158.     ld    a,d            ; Mask drive R/O vector
  159.     and    h            ; LSB
  160.     ld    h,a
  161.     ld    (dskro),hl        ; Save drive R/O vector
  162.     ret                ; And exit
  163. ;
  164. ; Select disk from FCB
  165. ;
  166. seldrv:    ld    a,0ffh            ; Set disk select done flag
  167.     ld    (fldrv),a
  168.     ld    a,(defdrv)        ; Get current drive
  169.     ld    (drive),a        ; Save it in memory
  170.     ld    e,a            ; Save it in register e
  171.     ld    a,(ix+0)        ; Get drive from FCB
  172.     ld    (fcb0),a        ; Save it
  173.     cp    '?'            ; Test if '?'
  174.     jr    z,cmnd14        ; Yes, then select drive from register e
  175.     and    01fh            ; Mask drive
  176.     ld    a,e            ; Test if zero
  177.     jr    z,seldr0        ; Select drive from register e
  178.     ld    a,(ix+0)        ; Get drive from FCB
  179.     dec    a            ; Decrement drive
  180. seldr0:    call    seldk            ; Select drive
  181.     ld    a,(ix+0)        ; Get drive from FCB
  182.     and    0e0h            ; Remove drive bits
  183.     ld    b,a            ; Save register
  184.     ld    a,(user)        ; Get user number
  185.     or    b            ; Insert user number in FCB
  186.     ld    (ix+0),a
  187.     ret                ; And exit
  188. ;
  189. ; Select disk
  190. ;
  191. cmnd14:    ld    a,e            ; Copy drive number
  192. ;
  193. seldk:    and    0fh            ; Mask drive number to 0-15
  194.     ld    b,a            ; Save counter
  195.     ld    de,(login)        ; Get login vector
  196.     or    a            ; Test drive 'a'
  197.     jr    z,seldk1        ; Yes then jump
  198. seldk0:    rr    d            ; Shift login vector
  199.     rr    e            ; Until bit 0 register e
  200.     djnz    seldk0            ; Is current drive
  201. seldk1:    ld    hl,defdrv        ; Get pointer last drive
  202.     bit    0,e            ; Test if drive logged in
  203.     jr    z,seldk2        ; No, login drive
  204.     cp    (hl)            ; Test same drive
  205.     ret    z            ; Yes then exit
  206. seldk2:    ld    (hl),a            ; Save new current drive
  207.     push    de            ; Save drive logged in flag
  208.     ld    c,a            ; Copy drive number
  209.     call    SelDsk            ; Do BIOS select
  210.     ld    a,h            ; Test if error
  211.     or    l
  212.     jr    z,seldk3        ; Yes, illegal drive number
  213.     ld    e,(hl)            ; Get LSB translation vector
  214.     inc    hl            ; Increment pointer
  215.     ld    d,(hl)            ; Get MSB translation vector
  216.     inc    hl            ; Increment pointer
  217.     ld    (trans),de        ; Save translation vector
  218.     ld    (temp0),hl        ; Save address temp0
  219.  
  220.     ld    de,6
  221.     add    hl,de            ; Point to dirbuf pointer <crw>
  222.  
  223.     ld    de,dirbuf        ; Load dirbuf pointer
  224.     ld    bc,8            ; Copy 8 bytes pointers to
  225.                     ; ..dirbuf, csv (wacd), allocation
  226.     ldir                ; ..vector pointer for this disk
  227.     ld    hl,(ixp)        ; Get drive parameter address
  228.     ld    c,15            ; Copy 15 bytes
  229.     ldir
  230.     pop    de            ; Get drive logged in flag
  231.     bit    0,e            ; Test it
  232.     ret    nz            ; Drive logged in so return
  233.     ld    hl,(login)        ; Get login vector
  234.     call    sdrvb            ; Set drive bit in login vector
  235.     ld    (login),hl        ; Save login vector
  236.     jr    initdr            ; And setup drive tables
  237. seldk3:
  238.     ld    hl,(StSel)        ; Load error message address
  239.     jp    (hl)            ; And display error
  240.  
  241. ;
  242. ; Init drive
  243. ;  Clear allocation vector bit buffer after drive reset
  244. ;
  245. initdr:    ld    de,(maxlen)        ; Get length alv buffer-1 (bits)
  246.     ld    a,3            ; Divide by 8
  247. initd0:    srl    d            ; To get bytes
  248.     rr    e
  249.     dec    a
  250.     jr    nz,initd0
  251.     inc    de            ; Increment, so all bits are cleared
  252.     ld    hl,(alv)        ; Get pointer alv buffer
  253.     push    hl
  254. initd1:    ld    (hl),0            ; Clear 8 bits
  255.     inc    hl            ; Increment pointer
  256.     dec    de            ; Decrement counter
  257.     ld    a,d            ; Test if counter zero
  258.     or    e
  259.     jr    nz,initd1        ; Not then jump
  260.     pop    hl            ; Get alv pointer
  261.     ld    de,(ndir0)        ; Get first two bytes alv buffer
  262.     ld    (hl),e            ; Save LSB
  263.     inc    hl            ; Increment pointer
  264.     ld    (hl),d            ; Save MSB
  265.     ld    hl,(temp0)        ; Clear number of files
  266.     xor    a            ; On this drive
  267.     ld    (hl),a            ; Clear LSB
  268.     inc    hl            ; Increment pointer
  269.     ld    (hl),a            ; Clear MSB
  270.     ld    (subflg),a        ; Clear submit flag (reset disk command)
  271.     call    setfct            ; Set file count
  272. initd2:    ld    a,0ffh            ; Update directory checksum
  273.     call    rddir            ; Read FCB's from directory
  274.     call    tstfct            ; Test last FCB
  275.     ret    z            ; Yes then exit
  276.     call    caldir            ; Calculate entry point FCB
  277.     ld    a,(hl)            ; Get first byte FCB
  278.     cp    0e5h            ; Test empty directory entry
  279.     jr    z,initd2        ; Yes then get next FCB
  280.     cp    021h            ; Test time stamp
  281.     jr    z,initd2        ; Yes then get next FCB
  282.     ld    a,(user)        ; Get user number
  283.     cp    (hl)            ; Test if user is same
  284.     jr    nz,initd3        ; No then jump
  285.     inc    hl            ; Point to file name
  286.     ld    a,(hl)            ; Get first char filename
  287.     sub    '$'            ; Test if '$'
  288.     jr    nz,initd3        ; Not then jump
  289.     dec    a            ; Load a with 0ffh
  290.     ld    (subflg),a        ; Save it in subflg
  291. initd3:    ld    c,1            ; Set bit in alv buffer
  292.     call    fillbb            ; Set bits from FCB in alv buffer
  293.     call    setlf            ; Update last file count
  294.     jr    initd2            ;
  295. ;
  296. ; Set drive bit in HL
  297. ;
  298. sdrvb:    ex    de,hl            ; Copy hl=>de
  299.     ld    hl,1            ; Get mask drive "a"
  300.     ld    a,(defdrv)        ; Get current drive
  301.     or    a            ; Test if drive "a"
  302.     jr    z,sdrvb1        ; Yes then done
  303. sdrvb0:    add    hl,hl            ; Get next mask
  304.     dec    a            ; Decrement drive counter
  305.     jr    nz,sdrvb0        ; And test if done
  306. sdrvb1:    ld    a,d            ; Hl=hl or de
  307.     or    h
  308.     ld    h,a
  309.     ld    a,e
  310.     or    l
  311.     ld    l,a
  312.     ret                ; Exit
  313. ;
  314. ; Calculate sector/track directory
  315. ;
  316. stdir:    ld    hl,(filcnt)        ; Get FCB counter directory
  317.     srl    h            ; Divide by 4
  318.     rr    l            ; (4 FCB's / sector)
  319.     srl    h
  320.     rr    l
  321.     ld    (recdir),hl        ; Save value (used by checksum)
  322.     ex    de,hl            ; Copy it to de
  323.     ld    hl,0            ; Clear hl
  324. ;
  325. ; Calculate sector/track
  326. ;    Entry:    hl,de = sector number (128 byte sector)
  327. ;    Exit:    set track  = hl,de  /  maxsec
  328. ;        set sector = hl,de mod maxsec
  329. ;
  330. calst:    ld    bc,(maxsec)        ; Get sectors/track
  331.     ld    a,17            ; Set up loop counter
  332. calst0:    or    a            ; Test hl>=bc
  333.     sbc    hl,bc
  334.     ccf
  335.     jr    c,calst1        ; Yes then jump
  336.     add    hl,bc            ; No then restore hl
  337.     or    a            ; And clear carry
  338. calst1:    rl    e            ; Shift result in de
  339.     rl    d
  340.     dec    a            ; Test last bit done
  341.     jr    z,calst2        ; Yes then exit
  342.     rl    l            ; Shift next bit in hl
  343.     rl    h
  344.     jr    calst0            ; Continue
  345. calst2:    push    hl            ; Save sector number
  346.     ld    hl,(nftrk)        ; Get first track
  347.     add    hl,de            ; Add track number
  348.     ld    b,h            ; Copy it to bc
  349.     ld    c,l
  350.     call    SetTrk            ; BIOS call set track
  351.     pop    bc            ; Restore sector number
  352.     ld    de,(trans)        ; Get translation table address
  353.     call    SecTrn            ; BIOS call sector translation
  354.     ld    b,h            ; Copy result to bc
  355.     ld    c,l
  356.     jp    SetSec            ; BIOS call set sector
  357. ;
  358. ; Get disk map block number from FCB
  359. ;
  360. ; Exit: HL = address FCB
  361. ;    DE = disk map
  362. ;    BC = offset in disk map
  363. ;
  364. getdm:    ld    c,(ix+32)        ; Get next record
  365.     ld    a,(nblock)        ; Get number of blocks
  366.     ld    b,a            ; Save it
  367. getdm0:    srl    c            ; Shift next record
  368.     djnz    getdm0            ; Number of blocks times
  369. getdm1:    cpl                ; Complement number of blocks
  370.     add    a,9            ; Add 9
  371.     ld    b,a            ; B=8-number of blocks
  372.     ld    a,(nextnd)        ; Get extend mask
  373.     and    (ix+12)            ; Mask with extend
  374.     rrca                ; Rotate one right
  375. getdm2:    rlca                ; Rotate one left
  376.     djnz    getdm2            ; 8-number of blocks times
  377. getdm3:    add    a,c            ; Add the two values to get entry FCB
  378. getdm4:    push    ix            ; Get FCB address
  379.     pop    hl
  380.     ld    c,16            ; Add offset 16 to point to dm
  381.     add    hl,bc
  382.     ld    c,a            ; Add entry FCB
  383.     add    hl,bc
  384.     ld    a,(maxlen+1)        ; Test 8 bits/16 bits FCB entry
  385.     or    a
  386.     jr    nz,getdm5        ; 16 bits => jump
  387.     ld    e,(hl)            ; Get 8 bit value
  388.     ld    d,0            ; Make MSB zero
  389.     ret                ; And exit
  390. getdm5:    add    hl,bc            ; Add twice (16 bit values)
  391.     ld    e,(hl)            ; Get LSB
  392.     inc    hl            ; Increment pointer
  393.     ld    d,(hl)            ; Get MSB
  394.     dec    hl            ; Decrement pointer
  395.     ret                ; And exit
  396. ;
  397. ; Calculate sector number
  398. ;  entry: de=block number from FCB
  399. ;
  400. calsec:    ld    hl,0            ; Clear MSB sector number
  401.     ld    a,(nblock)        ; Get loop counter
  402.     ld    b,a            ; Save it in b
  403. calsc0:    sla    e            ; Shift l,d,e
  404.     rl    d
  405.     rl    l
  406.     djnz    calsc0            ; B times
  407. calsc1:    ld    a,(nmask)        ; Get sector mask
  408.     and    (ix+32)            ; And with next record
  409.     or    e            ; Set up LSB sector number
  410.     ld    e,a
  411.     ret                ; And exit
  412. ;
  413. ; Calculate dirbuf entry point
  414. ;
  415. caldir:    ld    hl,(dirbuf)        ; Get start address dirbuf
  416.     ld    a,(secpnt)        ; Get sector pointer
  417.     add    a,l            ; Add l=l+a
  418.     ld    l,a
  419.     ret    nc            ; No carry exit
  420.     inc    h            ; Increment h
  421.     ret                ; And exit
  422. ;
  423. ; Init file count
  424. ;
  425. setfct:    ld    hl,-1            ; Set up file count
  426.     ld    (filcnt),hl        ; Save it
  427.     ret                ; And exit
  428. ;
  429. ; Test file count
  430. ;
  431. tstfct:    ld    hl,(filcnt)        ; Test file count=0ffffh
  432.     ld    a,h            ; Get MSB
  433.     and    l            ; And LSB
  434.     inc    a            ; Test if result=0ffh
  435.     ret                ; And exit
  436. ;
  437. ; Set last file
  438. ;
  439. setlf:    call    tstlf            ; Test last file
  440.     ret    c            ; No then exit
  441.     inc    de            ; Increment last file
  442.     ld    (hl),d            ; Save it in temp0
  443.     dec    hl
  444.     ld    (hl),e
  445.     ret                ; And exit
  446. ;
  447. ; Test last file
  448. ;
  449. tstlf:    ld    hl,(temp0)        ; Get pointer to last file
  450.     ld    de,(filcnt)        ; Get file counter
  451.     ld    a,e            ; Subtract de-(hl)
  452.     sub    (hl)
  453.     inc    hl
  454.     ld    a,d
  455.     sbc    a,(hl)
  456.     ret                ; Exit
  457. ;
  458. ; Get next FCB from drive
  459. ;    Entry:    A = 0 check checksum
  460. ;        A = 0ffh update checksum
  461. ;
  462. rddir:    ld    c,a            ; Save checksum flag
  463.     ld    hl,(filcnt)        ; Get file counter
  464.     inc    hl            ; Increment it
  465.     ld    (filcnt),hl        ; And save it
  466.     ld    de,(nfiles)        ; Get maximum number of files
  467.     or    a            ; Clear carry
  468.     sbc    hl,de            ; Test if last file
  469.     add    hl,de
  470.     jr    z,rddir0        ; No jump
  471.     jr    nc,setfct        ; Yes set file count to 0ffffh
  472. rddir0:    ld    a,l            ; Get file count LSB
  473.     add    a,a            ; *32
  474.     add    a,a
  475.     add    a,a
  476.     add    a,a
  477.     add    a,a
  478.     and    060h            ; Mask it
  479.     ld    (secpnt),a        ; Save it for later use
  480.     ret    nz            ; Return if not first FCB sector
  481.     push    bc            ; Save checksum flag
  482.     call    stdir            ; Calculate sector/track directory
  483.     call    readdr            ; Read sector directory
  484.     pop    bc            ; Restore checksum flag
  485. ;
  486. ; Update/check checksum directory
  487. ; entry c=0 check checksum, c=0ffh update checksum
  488. ;
  489. chkdir:    ld    hl,(ncheck)        ; Get number of checked records
  490.     ld    de,(recdir)        ; Get current record
  491.     or    a            ; Clear carry
  492.     sbc    hl,de            ; Test current record
  493.     ret    z            ; Exit if zero
  494.     ret    c            ; Exit if greater then ncheck
  495.     ld    hl,(dirbuf)        ; Get dirbuf
  496.     ld    b,128            ; Set up counter
  497.     xor    a            ; Clear checksum
  498. chkdr0:    add    a,(hl)            ; Add checksum
  499.     inc    hl            ; Increment pointer
  500.     djnz    chkdr0            ; 128 times
  501.     ld    hl,(csv)        ; Get pointer checksum directory
  502.     add    hl,de            ; Add current record
  503.     inc    c            ; Test checksum flag
  504.     jr    z,chkdr1        ; 0ffh=> update checksum
  505.     cp    (hl)            ; Test checksum
  506.     ret    z            ; Exit if ok
  507.     ld    a,true
  508.     ld    (diff),a        ; Set disk changed flag
  509.     jp    setfn
  510. chkdr1:    ld    (hl),a            ; Update checksum
  511.     ret                ; And exit
  512. ;
  513. ; Read sector from drive
  514. ;
  515. ; readr and writer modified to give separate error message--b.h.
  516. ;
  517. readr:    call    read            ; BIOS call read sector
  518.     ld    hl,(rderr)
  519.     jr    write0            ; Test exit code
  520. ;
  521. ; Write sector on drive
  522. ;
  523. writer:    call    write            ; BIOS call write sector
  524.     ld    hl,(wrterr)
  525. write0:    or    a            ; Test exit code
  526.     ret    z            ; Exit if ok
  527.     ld    (retflg),a        ; Allow retry for read/write errors
  528.     jp    (hl)            ; DOS error on d: write error
  529. ;
  530. ; Read directory from drive
  531. ;
  532. readdr:    call    DMAdir            ; Set up DMA directory
  533.     call    readr            ; Read record
  534.     jr    stDMA            ; Set up DMA user
  535. ;
  536. ; Write directory on drive
  537. ;
  538. writdr:    ld    c,0ffh            ; Update checksum directory
  539.     call    chkdir
  540.     call    DMAdir            ; Set up DMA directory
  541.     ld    c,1            ; Write directory flag
  542.     call    writer            ; Write record
  543.     jr    stDMA            ; Set up DMA user
  544. ;
  545. ; Set DMA address command
  546. ;
  547. cmnd26:    ld    (DMA),de        ; Save DMA address
  548. ;
  549. stDMA:    ld    bc,(DMA)        ; Get DMA address
  550.     jr    DMAdr0            ; And do BIOS call
  551. ;
  552. ; Set DMA address directory
  553. ;
  554. DMAdir:    ld    bc,(dirbuf)        ; Get DMA address directory
  555. DMAdr0:    jp    setDMA            ; BIOS call set DMA
  556.  
  557. ;
  558. ; Get bit from allocation vector buffer
  559. ;
  560. ;    Entry:    DE = block number
  561. ;    Exit:    A  = bit in LSB
  562. ;        B  = bitnumber in a
  563. ;        HL = pointer in alv buffer
  564. ;
  565. getbit:    ld    a,e            ; Get bit number
  566.     and    7            ; Mask it
  567.     inc    a            ; Add 1
  568.     ld    b,a            ; Save it
  569.     ld    c,a            ; Twice
  570.     srl    d            ; Get byte number
  571.     rr    e            ; De=de/8
  572.     srl    d
  573.     rr    e
  574.     srl    d
  575.     rr    e
  576.     ld    hl,(alv)        ; Get start address alv buffer
  577.     add    hl,de            ; Add byte number
  578.     ld    a,(hl)            ; Get 8 bits
  579. getbt0:    rlca                ; Get correct bit
  580.     djnz    getbt0
  581.     ld    b,c            ; Restore bit number
  582.     ret                ; And return to caller
  583. ;
  584. ; Set/reset bit in allocation vector buffer
  585. ;    Entry    DE = block number
  586. ;         C = 0 reset bit, c=1 set bit
  587. ;
  588. setbit:    push    bc            ; Save set/reset bit
  589.     call    getbit            ; Get bit
  590.     and    0feh            ; Mask it
  591.     pop    de            ; Get set/reset bit
  592.     or    e            ; Set/reset bit
  593. setbt0:    rrca                ; Rotate bit in correct position
  594.     djnz    setbt0
  595.     ld    (hl),a            ; Save 8 bits
  596.     ret                ; And return to caller
  597. ;
  598. ; Fill bit buffer from FCB in dirbuf
  599. ;    Entry:    C = 0 reset bit
  600. ;        C = 1 set bit
  601. ;
  602. fillbb:    call    caldir            ; Get directory entry
  603.     ld    de,16            ; Get offset dm block
  604.     add    hl,de            ; Add offset
  605.     ld    b,e            ; Get block counter
  606. fillb0:    ld    e,(hl)            ; Get LSB block number
  607.     inc    hl            ; Increment pointer
  608.     ld    d,0            ; Reset MSB block number
  609.     ld    a,(maxlen+1)        ; Test >256 blocks present
  610.     or    a
  611.     jr    z,fillb1        ; No then jump
  612.     dec    b            ; Decrement block counter
  613.     ld    d,(hl)            ; Get correct MSB
  614.     inc    hl            ; Increment pointer
  615. fillb1:    ld    a,d            ; Test block number
  616.     or    e
  617.     jr    z,fillb2        ; Zero then get next block
  618.     push    hl            ; Save pointer
  619.     push    bc            ; Save counter and set/reset bit
  620.     ld    hl,(maxlen)        ; Get maximum lenght alv buffer
  621.     or    a            ; Reset carry
  622.     sbc    hl,de            ; Test de<=maxlen alv buffer
  623.     call    nc,setbit        ; Yes then insert bit
  624.     pop    bc            ; Get counter and set/reset bit
  625.     pop    hl            ; Get pointer
  626. fillb2:    djnz    fillb0            ; Repeat for all dm entries
  627.     ret                ; And return to caller
  628. ;
  629. ; Set write protect disk
  630. ;
  631. cmnd28:
  632. setwpd:    ld    hl,(dskro)        ; Get disk R/O vector
  633.     call    sdrvb            ; Include drive bit
  634.     ld    (dskro),hl        ; Save disk R/O bit
  635. setfn:    ld    de,(nfiles)        ; Get maximum number of files-1
  636.     inc    de            ; Increment it
  637.     ld    hl,(temp0)        ; Get pointer to disk parameter block
  638.     ld    (hl),e            ; And save number of files
  639.     inc    hl
  640.     ld    (hl),d
  641.     ret                ; And return to caller
  642. ;
  643. ; Check file R/O bit
  644. ;
  645. chkfro:    call    caldir            ; Get directory entry
  646.     ld    a,(searpu)        ; Test if public file
  647.     ld    b,a            ; Save it
  648.     ld    a,(searqu)        ; Test if question mark used in file name
  649.     or    b            ; A=public file or question mark used
  650. chkfr0:    ld    de,2            ; Offset to public file bit
  651.     add    hl,de            ; Add offset
  652.     or    a            ; Test question mark used
  653.     jr    z,chkfr1        ; No then don't test public file bit
  654.     bit    7,(hl)            ; Test public file
  655.     jr    nz,chkfr2        ; Yes then error
  656. chkfr1:    ld    e,7            ; Offset to file R/O bit
  657.     add    hl,de            ; Add offset
  658.     bit    7,(hl)            ; Test file R/O
  659.     jr    nz,chkfr2        ; Yes then error
  660.     or    a            ; Test question mark used
  661.     ret    z            ; No then don't test system file bit
  662.     inc    hl            ; Increment to system file
  663.     bit    7,(hl)            ; Test system file
  664.     ret    z            ; No system file then ok
  665. chkfr2:
  666.     ld    hl,(sfilro)        ; Get pointer to file R/O message
  667.     jp    (hl)            ; Display message
  668.  
  669. ;
  670. ; Check drive read only
  671. ;
  672. chkro:    ld    hl,(dskro)        ; Get drive R/O vector
  673.     call    sdrvb            ; Set drive bit
  674.     sbc    hl,de            ; Test extra bit added
  675.     ret    nz            ; Yes then drive not R/O
  676.     ld    hl,(stro)        ; Get pointer to drive R/O message
  677.     jp    (hl)            ; Display message
  678.  
  679. ;
  680. ; Get free block from allocation vector buffer
  681. ;    Entry:    DE = old block number
  682. ;    Exit:    DE = new block number (0 if no free block)
  683. ; HL counts up
  684. ; DE counts down
  685. ;
  686. getfre:    ld    h,d            ; Copy old block to hl
  687.     ld    l,e
  688. getfr0:    ld    a,d            ; Test down counter is zero
  689.     or    e
  690.     jr    z,getfr1        ; Yes then jump
  691.     dec    de            ; Decrememt down counter
  692.     push    hl            ; Save up/down counter
  693.     push    de
  694.     call    getbit            ; Get bit from alv buffer
  695.     rra                ; Test if zero
  696.     jr    nc,getfr3        ; Yes then found empty block
  697.     pop    de            ; Get up/down counter
  698.     pop    hl
  699. getfr1:    ld    bc,(maxlen)        ; Get maximum alv lenght-1 in bc
  700.     or    a            ; Clear carry
  701.     sbc    hl,bc            ; Test hl>=lenght alv-1
  702.     add    hl,bc            ; Restore hl (flags are not affected)
  703.     jr    nc,getfr2        ; End buffer then jump
  704.     inc    hl            ; Increment up counter
  705.     push    de            ; Save down/up counter
  706.     push    hl
  707.     ex    de,hl            ; Save up counter in de
  708.     call    getbit            ; Get bit from alv buffer
  709.     rra                ; Test if zero
  710.     jr    nc,getfr3        ; Yes then found empty block
  711.     pop    hl            ; Get down/up counter
  712.     pop    de
  713.     jr    getfr0            ; And test next block
  714. getfr2:    ld    a,d            ; Test if last block tested
  715.     or    e
  716.     jr    nz,getfr0        ; No then test next block
  717.     ret                ; Exit (de=0)
  718. getfr3:    scf                ; Set block number used
  719.     rla                ; Save bit
  720.     call    setbt0            ; Put bit in alv buffer
  721.     pop    de            ; Get correct counter
  722.     pop    hl            ; Restore stack pointer
  723.     ret                ; Exit (de=block number)
  724. ;
  725. ; Search for file name
  726. ;    Entry:    A = number of bytes to search for
  727. ;
  728. search:    ld    (searnb),a        ; Save number of bytes
  729.     ld    a,0ffh            ; Set exit code to 0ffh (not found)
  730.     ld    (searex),a
  731.     ld    (dcopy),ix        ; Copy FCB pointer to ram (search next)
  732.     call    setfct            ; Initiate file counter
  733. ;
  734. ; Mod. 0.1 had a bug in which the directory of a changed disk would not be
  735. ; read. Adding call home forces a directory read--b.h.
  736. ;
  737.     call    home            ; Call BIOS procedure
  738. ;
  739. ; Search next file name
  740. ;
  741. SearcN:    xor    a            ; Clear accu, check checksum dir.
  742.  
  743. ; Next 3 lines moved here from SEARC1: to clear flags
  744. ; when last file in dir. is a public file. - C.W. 2/87
  745.  
  746.     ld    (searqu),a        ; Clear question mark detected flag
  747.     ld    (searpu),a        ; Clear public file flag
  748.     res    7,(ix+8)        ; Reset public/system file flag
  749. ;
  750.     call    rddir            ; Get FCB from directory
  751.     call    tstfct            ; Test if past last entry
  752.     jp    z,searc8        ; Yes then jump
  753.     ld    de,(dcopy)        ; Get FCB pointer
  754.     ld    a,(de)            ; Get first byte
  755.     cp    0e5h            ; Test if searching empty directory
  756.     jr    z,searc1        ; Yes then jump
  757.     push    de            ; Save FCB pointer
  758.     call    tstlf            ; Test last file on this drive
  759.     pop    de            ; Restore FCB pointer
  760.     jr    nc,searc8        ; Yes then jump
  761. searc1:    call    caldir            ; Get entry in directory
  762.     ld    a,(hl)            ; Get first byte directory entry
  763.     cp    021h            ; Test time stamp
  764.     jr    z,searcn        ; Yes then get next directory entry
  765.     ld    a,(searnb)        ; Get number of bytes to search for
  766.     ld    b,a            ; Save it in counter
  767.     xor    a            ; Clear accu
  768.     ld    c,a            ; Clear counter
  769. searc2:    ld    a,b            ; Test if counter is zero
  770.     or    a
  771.     jr    z,searc9        ; Yes then jump
  772.     ld    a,(de)            ; Get byte from FCB
  773.     xor    '?'            ; Test if question mark
  774.     and    07fh            ; Mask it (remove high bit)
  775.     jr    z,searc6        ; Yes then jump
  776.     ld    a,c            ; Get FCB counter
  777.     or    a            ; Test whether first byte
  778.     jr    nz,searc3        ; No
  779.     ld    a,(flags)        ; Yes. get flag byte
  780.     bit    0,a            ; Test public file enable
  781.     jr    z,searc3        ; No
  782.     inc    hl            ; Yes. get pointer to public bit
  783.     inc    hl
  784.     bit    7,(hl)            ; Test public bit directory
  785.     dec    hl            ; Restore pointer
  786.     dec    hl
  787.     jr    z,searc3        ; No public file then jump
  788.     ld    a,(de)            ; Get first byte FCB
  789.     cp    0e5h            ; Test if searching empty directory
  790.     jr    z,searc3        ; Yes then jump
  791.     xor    (hl)            ; Test FCB=directory entry
  792.     and    07fh            ; Mask it
  793.     jr    z,searc5        ; Yes then jump
  794.     and    0e0h            ; Mask user number
  795.     jr    nz,searc3        ; Not the same then jump
  796.     dec    a            ; A=0ffh
  797.     ld    (searpu),a        ; Set public file found
  798.     set    7,(ix+8)        ; Set public/system file flag
  799.     jr    searc5            ; Jump found
  800. searc3:    ld    a,c            ; Get FCB counter
  801.     cp    13            ; Test if at user code
  802.     jr    z,searc5        ; Yes then no test
  803.     cp    12            ; Test if at extend number
  804.     ld    a,(de)            ; Get byte from FCB
  805.     jr    z,searc7        ; Jump if extent number
  806.     xor    (hl)            ; Test byte FCB=byte directory entry
  807.     and    07fh            ; Mask it
  808. searc4:    jr    nz,searcn        ; Not the same then get next entry
  809. searc5:    inc    de            ; Increment pointer FCB
  810.     inc    hl            ; Increment pointer directory entry
  811.     inc    c            ; Increment counter
  812.     dec    b            ; Decrement counter
  813.     jr    searc2            ; Test next byte
  814. searc6:    dec    a            ; Set question mark found flag
  815.     ld    (searqu),a
  816.     jr    searc5            ; Jump found
  817. searc7:    push    bc            ; Save counters
  818.     xor    (hl)            ; Test extends
  819.     ld    b,a            ; Save it
  820.     ld    a,(nextnd)        ; Get extent mask
  821.     cpl                ; Complement it
  822.     and    01fh            ; Mask it
  823.     and    b            ; Mask extents
  824.     pop    bc            ; Restore counters
  825.     jr    searc4            ; And test result
  826. searc8:    call    setfct            ; Error set file counter
  827.     ld    a,0ffh            ; And set exit code
  828.     ld    (pexit),a
  829.     ret                ; Return to caller
  830. searc9:    ld    a,(searqu)        ; Get question mark found flag
  831.     ld    b,a            ; Save it
  832.     ld    a,(searpu)        ; Get public file flag
  833.     and    b            ; Test if public file and question mark
  834.     jr    nz,searc4        ; Yes then search for next entry
  835.     call    setlf            ; Update last file count (empty FCB)
  836.     ld    a,(filcnt)        ; Get file counter
  837.     and    3            ; Mask it
  838.     ld    (pexit),a        ; And set exit code
  839.     xor    a            ; Clear exit code search
  840.     ld    (searex),a
  841.     ret                ; And return to caller
  842. ;
  843. ; Delete file
  844. ;
  845. delete:    call    chkro            ; Check disk R/O
  846.     ld    a,12            ; Number of bytes to search for
  847.     call    search            ; Search file
  848. del0:    call    tstfct            ; Test if file found
  849.     ret    z            ; Not then exit
  850.     call    chkfro            ; Check file R/O
  851.     call    caldir            ; Get entry point directory
  852.     ld    (hl),0e5h        ; Remove file
  853.     ld    c,0            ; Remove bits alv buffer
  854.     call    fillbb
  855.     call    wrFCB            ; Write directory buffer on disk
  856.     call    searcn            ; Search next entry
  857.     jr    del0            ; And test it
  858. ;
  859. ; Rename file
  860. ;
  861. renam:    call    chkro            ; Check disk R/O
  862.     ld    a,12            ; Number of bytes to search for
  863.     call    search            ; Search file
  864. renam0:    call    tstfct            ; Test if file found
  865.     ret    z            ; Not then exit
  866.     call    chkfro            ; Check file R/O
  867.     push    ix            ; Save FCB entry
  868.     pop    hl            ; Get it in hl
  869.     ld    de,16            ; Offset to new name
  870.     add    hl,de            ; Add offset
  871.     ex    de,hl            ; Copy hl=>de
  872.     call    caldir            ; Get directory entry
  873.     ld    b,11            ; Set up loop counter
  874. renam1:    inc    hl            ; Increment directory pointer
  875.     inc    de            ; Increment FCB pointer
  876.     ld    a,(de)            ; Get character from FCB
  877.     and    07fh            ; Mask it
  878.     cp    '?'            ; Test if question mark
  879.     jr    z,renam2        ; Yes then do not change char. on disk
  880.     ld    c,a            ; Save it in c
  881.     ld    a,(hl)            ; Get character from directory
  882.     and    080h            ; Mask status bit
  883.     or    c            ; Or with new character
  884.     ld    (hl),a            ; Save in directory
  885. renam2:    djnz    renam1            ; Loop until done
  886.     call    wrFCB            ; And write directory on disk
  887.     call    searcn            ; Search next file
  888.     jr    renam0            ; And test it
  889. ;
  890. ; Change status file
  891. ;
  892. cstat:    call    chkro            ; Check disk R/O
  893.     ld    a,12            ; Number of bytes to search for
  894.     call    search            ; Search file
  895. cstat0:    call    tstfct            ; Test if file found
  896.     ret    z            ; Not then exit
  897.     push    ix            ; Save FCB entry
  898.     pop    de            ; Get it in hl
  899.     call    caldir            ; Get directory entry
  900.     ld    b,11            ; Set up loop counter
  901. cstat1:    inc    hl            ; Increment directory pointer
  902.     inc    de            ; Increment FCB pointer
  903.     ld    a,(de)            ; Get status bit from FCB
  904.     and    080h            ; Mask it
  905.     ld    c,a            ; Save it in c
  906.     ld    a,(hl)            ; Get character from directory
  907.     and    07fh            ; Mask it
  908.     or    c            ; Or with new status bit
  909.     ld    (hl),a            ; Save in directory
  910.     djnz    cstat1            ; Loop until done
  911.     call    wrFCB            ; And write directory to disk
  912.     call    searcn            ; Search next file
  913.     jr    cstat0            ; And test it
  914. ;
  915. ; Compute file size
  916. ;
  917. filsz:    ld    bc,0            ; Reset file size lenght
  918.     ld    d,c
  919.     call    ldrrc            ; Save it in FCB+33,34,35
  920.     ld    a,12            ; Number of bytes to search for
  921.     call    search            ; Search file
  922. filsz0:    call    tstfct            ; Test if file found
  923.     ret    z            ; Not then exit
  924.     call    caldir            ; Get directory entry
  925.     ex    de,hl            ; Copy to de
  926.     ld    hl,15            ; Offset to next record
  927.     call    calrrc            ; Calculate random record count
  928.     ld    a,d            ; Test LSB < (ix+33)
  929.     sub    (ix+33)
  930.     ld    a,c            ; Test isb < (ix+34)
  931.     sbc    a,(ix+34)
  932.     ld    a,b            ; Test MSB < (ix+35)
  933.     sbc    a,(ix+35)
  934.     call    nc,ldrrc        ; Write new maximum
  935.     call    searcn            ; Search next file
  936.     jr    filsz0            ; And test it
  937. ;
  938. ; Write FCB on disk
  939. ;
  940. wrFCB:    call    stdir            ; Calculate sector/track directory
  941.     jp    writdr            ; Write directory on disk
  942. ;
  943. ; Find file
  944. ;
  945. findf:    ld    a,15            ; Number of bytes to search for
  946.     JP    search            ; Search file
  947. ;
  948. ; Open file command
  949. ;
  950. cmnd15:    call    seldrv            ; Select drive from FCB
  951.     ld    (ix+14),0        ; Clear FCB+14
  952. ;
  953. ; Open file
  954. ;
  955. openf:    call    findf            ; Find file
  956.     call    tstfct            ; Test file found
  957.     ret    z            ; No then exit
  958. openf0:    ld    a,(ix+8)        ; Get public/system file bit
  959.     push    af            ; Save it
  960.     ld    a,(ix+12)        ; Get extent number from FCB
  961.     push    af            ; Save it
  962.     call    caldir            ; Get directory entry
  963.     push    hl            ; Save it <crw>
  964.     ld    e,8            ; Set access date/time <crw>
  965.     call    stime            ; Zero flag set if stamps present <crw>
  966.     pop    hl            ; Get directory entry <crw>
  967.     push    ix            ; Save FCB entry
  968.     pop    de            ; Get in in de
  969.     ld    bc,32            ; Number of bytes to move
  970.     ldir                ; Move directory to FCB
  971.     call    z,wrFCB            ; Write directory to disk if stamps
  972.                     ; ..Present <crw>
  973. nowrit:    set    7,(ix+14)        ; Set FCB/file not modified
  974.     ld    b,(ix+12)        ; Get extent number
  975.     ld    c,(ix+15)        ; Get next record number
  976.     pop    af            ; Get old extent number
  977.     ld    (ix+12),a        ; Save it
  978.     cp    b            ; Compare old and new extent number
  979.     jr    z,openf1        ; Same then jump
  980.     ld    c,0            ; Set next record count to 0
  981.     jr    nc,openf1        ; Old extent >= new extent then jump
  982.     ld    c,80h            ; Set next record count to maximum
  983. openf1:    ld    (ix+15),c        ; Save next record count
  984.     pop    af            ; Get public/system file bit
  985.     rl    (ix+8)            ; Remove MSB from ix+8
  986.     rla                ; Set new MSB in carry
  987.     rr    (ix+8)            ; Save carry in ix+8
  988.     ret                ; And return to caller
  989. ;
  990. ; Close file command
  991. ;
  992. cmnd16:    call    seldrv            ; select drive from FCB
  993. ;
  994. ; Close file
  995. ;
  996. close:    bit    7,(ix+14)        ; test FCB/file modified
  997.     ret    nz            ; not then no close required
  998.     call    chkro            ; test disk R/O
  999.     ld    a,15            ; number of bytes to search for
  1000.     call    search            ; search file
  1001.     call    tstfct            ; test file present
  1002.     ret    z            ; no then exit
  1003.     call    chkfro            ; check file R/O
  1004.     call    caldir            ; get directory entry
  1005.     ld    bc,16            ; offset to dm block
  1006.     add    hl,bc            ; add offset
  1007.     ex    de,hl            ; save hl in de
  1008.     push    ix            ; save FCB pointer
  1009.     pop    hl            ; get it in hl
  1010.     add    hl,bc            ; add offset
  1011.     ld    a,(maxlen+1)        ; test number of block >= 256
  1012.     or    a
  1013.     jr    z,close0        ; no then jump
  1014.     dec    b            ; set flag
  1015. close0:    call    copydm            ; copy and test blocks
  1016.     ex    de,hl            ; exchange copy direction
  1017.     call    copydm            ; copy and test blocks
  1018.     ex    de,hl            ; exchange copy direction
  1019.     jr    nz,close4        ; block not the same then error
  1020.     inc    hl            ; increment pointer FCB
  1021.     inc    de            ; increment pointer directory
  1022.     bit    0,b            ; test number of block >= 256
  1023.     jr    z,close1        ; no then jump
  1024.     inc    hl            ; increment pointer FCB
  1025.     inc    de            ; increment pointer directory
  1026.     dec    c            ; decrement counter
  1027. close1:    dec    c            ; decrement counter
  1028.     jr    nz,close0        ; not ready then jump
  1029.     ld    hl,-20            ; add -20 to get extent number
  1030.     add    hl,de            ; hL contains pointer to extent number
  1031.     ld    a,(ix+12)        ; get extent number FCB
  1032.     cp    (hl)            ; compare with extent number directory
  1033.     jr    c,close3        ; fCB < directory then jump
  1034.     ld    (hl),a            ; save extent number in directory
  1035.     inc    hl            ; get pointer to next record
  1036.     inc    hl
  1037.     inc    hl
  1038.     ld    a,(ix+15)        ; get next record FCB
  1039. close2:    ld    (hl),a            ; save next record in directory
  1040. close3:    ld    e,4            ; Set last update date/time
  1041.     call    stime            ; Update time
  1042.     call    caldir            ; Get directory entry
  1043.     ld    bc,11            ; Point to archive byte
  1044.     add    hl,bc
  1045.     res    7,(hl)            ; reset archive bit
  1046.     res    7,(ix+11)        ; reset bit in FCB
  1047.     jp    wrFCB            ; write FCB on disk
  1048. ;
  1049. close4:    ld    a,0ffh            ; flag error
  1050.     ld    (pexit),a
  1051.     ret                ; and return to caller
  1052. ;
  1053. ; Copy and test disk map
  1054. ;
  1055. ;    Entry:    HL = pointer to first FCB
  1056. ;        DE = pointer to second FCB
  1057. ;         B = 000h if less then 256 blocks
  1058. ;             0ffh if more or equal to 256 blocks
  1059. ;    Exit:    Z  blocks are the same
  1060. ;        NZ blocks are not the same
  1061. ;
  1062. copydm:    ld    a,(hl)            ; get byte first FCB
  1063.     bit    0,b            ; test number of blocks >=256
  1064.     jr    z,copyd0        ; No then jump
  1065.     inc    hl            ; Increment pointer
  1066.     or    (hl)            ; Test byte =0
  1067.     dec    hl            ; Decrement pointer
  1068. copyd0:    or    a            ; Test block number is zero
  1069.     jr    nz,copyd1        ; No then compare blocks
  1070.     ld    a,(de)            ; Copy block from other FCB in empty location
  1071.     ld    (hl),a
  1072.     bit    0,b            ; Test number of blocks >=256
  1073.     ret    z            ; No then exit
  1074.     inc    hl            ; Increment to MSB block numbers
  1075.     inc    de
  1076.     ld    a,(de)            ; Copy block from other FCB in empty location
  1077.     ld    (hl),a
  1078.     jr    copyd2            ; Jump trick to save space
  1079. copyd1:    ld    a,(de)            ; Get block number first FCB
  1080.     sub    (hl)            ; Test if the same
  1081.     ret    nz            ; Not then return
  1082.     or    b            ; Test if >=256 blocks
  1083.     ret    z            ; No then return
  1084.     inc    hl            ; Increment to MSB block numbers
  1085.     inc    de
  1086. copyd2:    ld    a,(de)            ; Get block number first FCB
  1087.     sub    (hl)            ; Test if the same
  1088.     dec    hl            ; Decrement block FCB pointers
  1089.     dec    de
  1090.     ret                ; And exit to caller
  1091. ;
  1092. ; Make file command
  1093. ;
  1094. cmnd22:
  1095.     call    seldrv            ; Select drive from FCB
  1096.     ld    (ix+14),0        ; Clear FCB+14
  1097. ;
  1098. ; Make file
  1099. ;
  1100. make:    call    chkro            ; Check drive R/O
  1101.     ld    a,(ix+0)        ; Get first byte FCB
  1102.     push    af            ; Save it
  1103.     ld    (ix+0),0e5h        ; Set first byte to empty file
  1104.     ld    a,1            ; Search for 1 byte
  1105.     call    search            ; Search empty file
  1106.     pop    af            ; Get first byte FCB
  1107.     ld    (ix+0),a        ; Restore it
  1108.     call    tstfct            ; Test empty file found
  1109.     ret    z            ; No then return error
  1110.     xor    a            ; Clear FCB+13
  1111.     ld    (ix+13),a
  1112.     push    ix            ; Save FCB pointer
  1113.     pop    hl            ; Get it back in hl
  1114.     ld    de,15            ; Prepare offset
  1115.     add    hl,de            ; Add it
  1116.     ld    b,17            ; Set loop counter
  1117. make0:    ld    (hl),a            ; Clear FCB+15 up to FCB+31
  1118.     inc    hl            ; Increment pointer
  1119.     djnz    make0            ; And clear all bytes
  1120.     ld    e,2            ; Set creation date
  1121.     call    stime            ; Update time in directory
  1122.     ld    e,4            ; Set last update date/time
  1123.     call    stime            ; Update time in directory
  1124.     ld    e,8            ; Set access date/time <crw>
  1125.     call    stime
  1126.     res    7,(ix+8)        ; Reset public/system file bit
  1127.     res    7,(ix+11)        ; Reset archive bit if present
  1128.     call    caldir            ; Get directory entry
  1129.     push    ix            ; Save FCB entry
  1130.     pop    de            ; Get it in de
  1131.     ex    de,hl            ; Exchange FCB and directory entry
  1132.     ld    bc,32            ; Number of bytes to move
  1133.     ldir                ; Move bytes
  1134.     call    wrFCB            ; Write FCB on disk
  1135.     set    7,(ix+14)        ; Set FCB/file not modified
  1136.     ret                ; And return to caller
  1137. ;
  1138. ; Open next extent
  1139. ;
  1140. openex:    bit    7,(ix+14)        ; Test if FCB/file modified (write)
  1141.     jr    nz,openx2        ; Not then jump
  1142.     call    close            ; Close current FCB
  1143.     ld    a,(pexit)        ; Get exit code
  1144.     inc    a            ; Test if error
  1145.     ret    z            ; Yes then exit
  1146.     call    calnex            ; Calculate next extent
  1147.     jr    c,openx3        ; Error then jump
  1148.     jr    nz,openx5        ; fCB present from close then jump
  1149. openx0:    ld    a,15            ; Search first 15 bytes
  1150.     call    search            ; Search for file
  1151. openx1:    call    tstfct            ; Test if file found
  1152.     jr    nz,openx5        ; Yes then jump
  1153.     ld    a,(rdwr)        ; Test read/write flag
  1154.     or    a            ; Test if read
  1155.     jr    z,openx3        ; Yes then error
  1156.     call    make            ; Make new extent if write
  1157.     call    tstfct            ; Test if succesfull
  1158.     jr    nz,openx6        ; Yes then exit
  1159.     jr    openx3            ; No then error
  1160. openx2:    call    calnex            ; Calculate next extent
  1161.     jr    c,openx3        ; Error then jump
  1162.     bit    7,(ix+10)        ; Test system file bit
  1163.     jr    z,openx0        ; No system file then jump
  1164.     call    findf            ; Search for file
  1165.     jr    openx1            ; Use same routine
  1166. openx3:    set    7,(ix+14)        ; Set FCB/file not modified
  1167.     ld    a,0ffh            ; Set exit code
  1168. openx4:    ld    (pexit),a
  1169.     ret                ; And return to caller
  1170. openx5:    call    openf0            ; Open file
  1171. openx6:    xor    a            ; And clear exit code
  1172.     jr    openx4            ; Use same routine
  1173. ;
  1174. ; Calculate next extent
  1175. ;
  1176. ;    Exit:    C  overflow detected
  1177. ;        Z  search next extent
  1178. ;        NZ next extent present (close)
  1179. ;
  1180. calnex:    ld    b,(ix+12)        ; Get extent number
  1181.     ld    c,(ix+14)        ; Get FCB+14
  1182.     bit    6,c            ; Test error bit random record
  1183.     scf                ; Set error flag
  1184.     ret    nz            ; Non zero then error exit
  1185.     inc    b            ; Increment extent number
  1186.     ld    a,b            ; Get extent number
  1187.     and    01fh            ; Mask it
  1188.     ld    b,a            ; Save it in b
  1189.     jr    nz,calnx0        ; Non zero then jump
  1190.     inc    c            ; Increment FCB+14
  1191.     ld    a,c            ; Get it in a
  1192.     and    03fh            ; Mask it
  1193.     ld    c,a            ; Save it in c
  1194.     scf                ; Set error flag
  1195.     ret    z            ; And return if file overflow
  1196.     xor    a            ; Clear zero flag (not same extent)
  1197.     jr    calnx1            ; And save extent number and FCB+14
  1198. calnx0:    ld    a,(nextnd)        ; Get next extent mask
  1199.     and    b            ; Test if same extent (close)
  1200. calnx1:    ld    (ix+12),b        ; Save extent number
  1201.     ld    (ix+14),c        ; Save FCB+14
  1202.     ret                ; And return to caller
  1203. ;
  1204. ; Read random record command
  1205. ;
  1206. cmnd33:    call    seldrv            ; Select drive from FCB
  1207. ;
  1208. ; Read random sector
  1209. ;
  1210. rdran:    xor    a            ; Set read/write flag
  1211.     call    ldFCB            ; Load random record in FCB
  1212.     jr    z,reads            ; No error then read sector
  1213.     ret                ; Return error
  1214. ;
  1215. ; Read sequential
  1216. ;
  1217. cmnd20:    call    seldrv            ; Select drive from FCB
  1218. ;
  1219. ; Read sector
  1220. ;
  1221. reads:    xor    a            ; Set read/write flag
  1222.     ld    (rdwr),a        ; Save it
  1223.     ld    a,(ix+32)        ; Get record counter
  1224.     cp    080h            ; Test if last record this extent
  1225.     jr    nc,reads1        ; Yes then open next extent
  1226.     cp    (ix+15)            ; Test if greater then current record
  1227.     jr    c,reads2        ; No then get record
  1228. reads0:    ld    a,1            ; Set end of file flag
  1229.     ld    (pexit),a        ; Save it
  1230.     ret                ; And return to caller
  1231. reads1:
  1232.     call    openex            ; ..To open next extent
  1233.     ld    a,(pexit)        ; Get exit code
  1234.     or    a
  1235.     jr    nz,reads0        ; Yes then end of file
  1236.     ld    (ix+32),0        ; Clear record counter
  1237. reads2:    call    getdm            ; Get block number from dm in FCB
  1238.     ld    a,d            ; Test block number = 0
  1239.     or    e
  1240.     jr    z,reads0        ; Yes then end file
  1241.     call    calsec            ; Calculate sector number (128 bytes)
  1242.     call    calst            ; Calculate sector/track number
  1243.     call    readr            ; Read data
  1244.     ld    a,(funct)        ; Get function number
  1245.     cp    20            ; Test if read sequential
  1246.     ret    nz            ; No then return
  1247.     inc    (ix+32)            ; Increment next record counter
  1248.     ret                ; And return to caller
  1249. ;
  1250. ; ClrDsk - Reset Login Vector if disk change detected, and select drive
  1251. ;        from FCB. <crw>
  1252. ;
  1253. ;    Instead of setting disks to read-only, "diff" flag is set by
  1254. ;    calls to wrFCB from Delete, Rename, Change Status, Open, Close,
  1255. ;    Select, and Make if the disk in use has changed.  Next call to
  1256. ;    write sequential or random then resets all disks.    Two
  1257. ;    consecutive calls to write between which a disk was changed may
  1258. ;    overwrite data, as is also the case with CP/M.
  1259. ;
  1260. clrdsk:
  1261.     ld    a,(diff)        ; Disk changed flag
  1262.     or    a
  1263.     jr    z,clrd0
  1264.     xor    a
  1265.     ld    (diff),a        ; Clear flag
  1266.     ld    h,a
  1267.     ld    l,a
  1268.     ld    (login),hl        ; Clear all drives
  1269.                     ; ..(crude but effective)
  1270. clrd0:
  1271.     call    seldrv            ; Select disk from FCB
  1272.     ret
  1273. ;
  1274. ; Write random record commands
  1275. ;
  1276. cmnd34:
  1277. cmnd40:
  1278.     call    clrdsk            ; Reset disks if changed
  1279.                     ; ..and select drive from FCB
  1280. ;
  1281. ; Write random sector
  1282. ;
  1283. wrran:    ld    a,0ffh            ; Set read/write flag
  1284.     call    ldFCB            ; Load FCB from random record
  1285.     jr    z,writes        ; No error then write record
  1286.     ret                ; Return error
  1287. ;
  1288. ; Write sequential
  1289. ;
  1290. cmnd21:
  1291.     call    clrdsk            ; Reset disks if changed
  1292.                     ; ..and select drive from FCB
  1293. ;
  1294. ; Write sector
  1295. ;
  1296. writes:
  1297.     ld    a,0ffh            ; Set read/write flag
  1298.     ld    (rdwr),a        ; And save it
  1299.     call    chkro            ; Check disk R/O
  1300.     bit    7,(ix+9)        ; Test if file R/O
  1301.     jp    nz,chkfr2        ; Yes then file R/O message
  1302.     bit    7,(ix+8)        ; Test if public or system file
  1303.     jp    nz,chkfr2        ; Yes then file R/O message
  1304.     ld    a,(ix+32)        ; Get record count
  1305.     cp    080h            ; Test if end this extent
  1306.     jr    c,writs0        ; Yes then open next extent
  1307.     call    openex            ; Open next extent
  1308.     ld    a,(pexit)        ; Get error code
  1309.     or    a
  1310.     jp    nz,writs9        ; Error then directory full error
  1311.     ld    (ix+32),0        ; Clear record counter
  1312. writs0:    call    getdm            ; Get block number from FCB
  1313.     ld    a,d            ; Test if block number = 0
  1314.     or    e
  1315.     jr    nz,writs5        ; No then write sector
  1316.     push    hl            ; Save pointer to block number
  1317.     ld    a,c            ; Test first block number in extent
  1318.     or    a
  1319.     jr    z,writs1        ; Yes then jump
  1320.     dec    a            ; Decrement pointer to block number
  1321.     call    getdm4            ; Get previous blocknumber
  1322. writs1:    call    getfre            ; Get nearest free block
  1323.     pop    hl            ; Get pointer to block number
  1324.     ld    a,d            ; Test if blocknumber = 0
  1325.     or    e
  1326.     jr    z,writs8        ; Yes then disk full error
  1327.     res    7,(ix+14)        ; Reset FCB/file modified
  1328.     ld    (hl),e            ; Save blocknumber
  1329.     ld    a,(maxlen+1)        ; Get number of blocks
  1330.     or    a            ; Test if <256
  1331.     jr    z,writs2        ; Yes then jump
  1332.     inc    hl            ; Increment to MSB block number
  1333.     ld    (hl),d            ; Save MSB block number
  1334. writs2:    ld    c,2            ; Set write new block flag
  1335.     ld    a,(nmask)        ; Get sector mask
  1336.     and    (ix+32)            ; Mask with record counter
  1337.     jr    z,writsx        ; Zero then ok (at start new record)
  1338.     ld    c,0            ; Else clear new block flag
  1339. writsx:    ld    a,(funct)        ; Get function number
  1340.     sub    40            ; Test if write rr with zero fill
  1341.     jr    nz,writs6        ; No then jump
  1342.     push    de            ; Save blocknumber
  1343.     ld    hl,(dirbuf)        ; Use directory buffer for zero fill
  1344.     ld    b,128            ; 128 bytes to clear
  1345. writs3:    ld    (hl),a            ; Clear directory buffer
  1346.     inc    hl            ; Increment pointer
  1347.     djnz    writs3            ; Clear all bytes
  1348.     call    calsec            ; Calculate sector number (128 bytes)
  1349.     ld    a,(nmask)        ; Get sector mask
  1350.     ld    b,a            ; Copy it
  1351.     inc    b            ; Increment it to get number of writes
  1352.     cpl                ; Complement sector mask
  1353.     and    e            ; Mask sector number
  1354.     ld    e,a            ; And save it
  1355.     ld    c,2            ; Set write new block flag
  1356. writs4:    push    hl            ; Save registers
  1357.     push    de
  1358.     push    bc
  1359.     call    calst            ; Calculate sector/track
  1360.     call    DMAdir            ; Set DMA directory buffer
  1361.     pop    bc            ; Get write new block flag
  1362.     push    bc            ; Save it again
  1363.     call    writer            ; Write record on disk
  1364.     pop    bc            ; Restore registers
  1365.     pop    de
  1366.     pop    hl
  1367.     ld    c,0            ; Clear write new block flag
  1368.     inc    e            ; Increment sector number
  1369.     djnz    writs4            ; Write all blocks
  1370.     call    stDMA            ; Set user DMA address
  1371.     pop    de            ; Get block number
  1372. writs5:    ld    c,0            ; Clear write new block flag
  1373. writs6:    res    7,(ix+14)        ; Reset FCB/file modified flag
  1374.     push    bc            ; Save it
  1375.     call    calsec            ; Calculate sector number (128 bytes)
  1376.     call    calst            ; Calculate sector/track
  1377.     pop    bc            ; Get write new block flag
  1378.     call    writer            ; Write record on disk
  1379.     ld    a,(ix+32)        ; Get record counter
  1380.     cp    (ix+15)            ; Compare with next record
  1381.     jr    c,writs7        ; If less then jump
  1382.     inc    a            ; Increment record count
  1383.     ld    (ix+15),a        ; Save it on next record position
  1384.     res    7,(ix+14)        ; Reset FCB/file modified flag
  1385. writs7:    ld    a,(funct)        ; Get function number
  1386.     cp    21            ; Test write sequential
  1387.     ret    nz            ; Not then return
  1388.     inc    (ix+32)            ; Increment record count
  1389.     ret                ; And return to caller
  1390. writs8:    ld    a,2            ; Set disk full error
  1391.     ld    (pexit),a
  1392.     ret                ; And return to caller
  1393. writs9:    ld    a,1            ; Set directory full flag
  1394.     ld    (pexit),a
  1395.     ret                ; And return to caller
  1396. ;
  1397. ; Load FCB for random read/write
  1398. ;
  1399. ;    Exit:    Z  no error
  1400. ;        NZ error occured
  1401. ;
  1402. ldFCB:    ld    (rdwr),a        ; Save read/write flag
  1403.     ld    a,(ix+33)        ; Get first byte random record
  1404.     ld    d,a            ; Save it in d
  1405.     res    7,d            ; Reset MSB to get next record
  1406.     rla                ; Shift MSB in carry
  1407.     ld    a,(ix+34)        ; Load next byte random record
  1408.     rla                ; Shift carry
  1409.     push    af            ; Save it
  1410.     and    01fh            ; Mask next extent
  1411.     ld    c,a            ; Save it in c
  1412.     pop    af            ; Get byte
  1413.     rla                ; Shift 4 times
  1414.     rla
  1415.     rla
  1416.     rla
  1417.     and    0fh            ; Mask it
  1418.     ld    b,a            ; Save FCB+14
  1419.     ld    a,(ix+35)        ; Get next byte random record
  1420.     ld    e,6            ; Set random record to large flag
  1421.     cp    4            ; Test random record to large
  1422.     jr    nc,ldFCB8        ; Yes then error
  1423.     rlca                ; Shift 4 times
  1424.     rlca
  1425.     rlca
  1426.     rlca
  1427.     add    a,b            ; Add byte
  1428.     ld    b,a            ; Save FCB+14 in b
  1429.     ld    (ix+32),d        ; Set next record count
  1430.     ld    d,(ix+14)        ; Get FCB+14
  1431.     bit    6,d            ; Test error random record
  1432.     jr    nz,ldFCB0        ; Yes then jump
  1433.     ld    a,c            ; Get new extent number
  1434.     cp    (ix+12)            ; Compare with FCB
  1435.     jr    nz,ldFCB0        ; Not equal then open next extent
  1436.     ld    a,b            ; Get new FCB+14
  1437.     xor    (ix+14)            ; Compare with FCB+14
  1438.     and    03fh            ; Mask it
  1439.     jr    z,ldFCB6        ; Equal then return
  1440. ldFCB0:    bit    7,d            ; Test FCB modified (write)
  1441.     jr    nz,ldFCB1        ; No then jump
  1442.     push    de            ; Save registers
  1443.     push    bc
  1444.     call    close            ; Close extent
  1445.     pop    bc            ; Restore registers
  1446.     pop    de
  1447.     ld    e,3            ; Set close error
  1448.     ld    a,(pexit)        ; Get exit code
  1449.     inc    a
  1450.     jr    z,ldFCB7        ; Error then exit
  1451. ldFCB1:    ld    (ix+12),c        ; Save new extent number
  1452.     ld    (ix+14),b        ; Save new FCB+14
  1453.     bit    7,d            ; Test FCB modified (previous FCB)
  1454.     jr    nz,ldFCB3        ; No then jump
  1455. ldFCB2:    ld    a,15            ; Set number of bytes to search for
  1456.     call    search            ; Search next FCB
  1457.     jr    ldFCB4            ; Jump
  1458. ldFCB3:    bit    7,(ix+10)        ; Test if system file
  1459.     jr    z,ldFCB2        ; No use search
  1460.     call    findf            ; Open file
  1461. ldFCB4:    ld    a,(pexit)        ; Get error code
  1462.     inc    a
  1463.     jr    nz,ldFCB5        ; No error then exit
  1464.     ld    a,(rdwr)        ; Get read/write flag
  1465.     ld    e,4            ; Set read empty record
  1466.     inc    a
  1467.     jr    nz,ldFCB7        ; Read then error
  1468.     call    make            ; Make new FCB
  1469.     ld    e,5            ; Set make error
  1470.     ld    a,(pexit)        ; Get error code
  1471.     inc    a
  1472.     jr    z,ldFCB7        ; Error then exit
  1473.     jr    ldFCB6            ; No error exit (zero set)
  1474. ldFCB5:    call    openf0            ; Open file
  1475. ldFCB6:    xor    a            ; Set zero flag and clear error code
  1476.     ld    (pexit),a
  1477.     ret                ; And return to caller
  1478. ldFCB7:    ld    (ix+14),0c0h        ; Set random record error
  1479. ldFCB8:    ld    a,e            ; Get error code
  1480.     ld    (pexit),a        ; And save it
  1481.     set    7,(ix+14)        ; Set FCB/file not modified
  1482.     or    a            ; Clear zero flag
  1483.     ret                ; And return to caller
  1484. ;
  1485. ; Calculate random record
  1486. ;    Entry:    HL = offset in FCB
  1487. ;        DE = FCB pointer
  1488. ;    Exit:    D  = LSB random record
  1489. ;        C  = ISB random record
  1490. ;        B  = MSB random record
  1491. ;
  1492. calrrc:    add    hl,de            ; Pointer to FCB+15 or FCB+32
  1493.     ld    a,(hl)            ; Get byte
  1494.     ld    hl,12            ; Offset to extent number
  1495.     add    hl,de            ; Get pointer to extent byte
  1496.     ld    d,a            ; Save first byte
  1497.     ld    a,(hl)            ; Get extent byte
  1498.     and    01fh            ; Mask it
  1499.     rl    d            ; Shift MSB in carry
  1500.     adc    a,0            ; Add carry
  1501.     rra                ; Shift 1 time (16 bits)
  1502.     rr    d
  1503.     ld    c,a            ; Save isb
  1504.     inc    hl            ; Increment to FCB+14
  1505.     inc    hl
  1506.     ld    a,(hl)            ; Get FCB+14
  1507.     rrca                ; Shift 4 times
  1508.     rrca
  1509.     rrca
  1510.     rrca
  1511.     push    af            ; Save it
  1512.     and    03h            ; Mask MSB
  1513.     ld    b,a            ; Save it
  1514.     pop    af            ; Get LSB
  1515.     and    0f0h            ; Mask it
  1516.     add    a,c            ; Add with isb
  1517.     ld    c,a            ; Save isb
  1518.     ret    nc            ; No carry then return
  1519.     inc    b            ; Increment MSB
  1520.     ret                ; And return to caller
  1521.  
  1522. ; END Z80DDISK.Z80
  1523.  
  1524.