home *** CD-ROM | disk | FTP | other *** search
/ CBM Funet Archive / cbm-funet-archive-2003.iso / cbm / c128 / utilities / lrr270.sfx / lrr270.bin.s < prev    next >
Text File  |  1998-02-16  |  26KB  |  1,492 lines

  1. ; Little Red Reader/Writer utility package by Craig Bruce, 31-Jan-1992
  2. ; Written for C= Hacking Net-Magazine; for C-128, 1571, 1581
  3. ; Upgraded for FD-2000/4000 High Density MS-DOS disks, 08-Mar-1994
  4. ; Upgraded to clean up errors and add aborting, 16-May-1996
  5.  
  6. .org $5400
  7. .obj "@0:lrr270.bin"
  8.  
  9. ;====jump table and parameters interface ====
  10.  
  11. jmp initPackage ;()
  12. jmp msDir       ;( msDevice, msType ) : .AY=dirAddr, .X=direntCount
  13. jmp msRead      ;( msDevice, msType, startCluster, lenML,.A=trans,.X=cbmLfn )
  14. jmp msWrite     ;( msDevice, msType, writeDirent, .A=trans, .X=cbmLfn )
  15. jmp msFlush     ;( msDevice, msType )
  16. jmp msDelete    ;( writeDirent )
  17. jmp msFormat    ;( msDevice, msType, .A=low/highDensity )
  18. jmp msBytesFree ;( ) : .AYX=bytesFree
  19. jmp cbmCopy     ;( .A=inLfn, .X=outLfn, .Y=tr )
  20. jmp cbmDirent   ;( .A=lfn )
  21.  
  22. .byte $cb,134   ;identification (location pk+30)
  23. errno           .buf 1    ;0=ok,1-15=msdos,16-19=internal,20-30=cbm
  24. msDevice        .buf 1
  25. msType          .buf 1    ;$00=1571, $ff=1581 or FD-2000/4000
  26. startCluster    .buf 2
  27. lenML           .buf 2    ;length medium and low bytes
  28. writeDirent     .buf 2    ;pointer to dirent
  29. cdirBlocks      .buf 2    ;cbm dirent blocks
  30. cdirType        .buf 1    ;cbm dirent filetype
  31. cdirFlen        .buf 1    ;cbm dirent filename length
  32. cdirName        .buf 16   ;cbm dirent filename
  33.  
  34. ;====global declaraions====
  35.  
  36. kernelListen = $ffb1
  37. kernelSecond = $ff93
  38. kernelUnlsn  = $ffae
  39. kernelAcptr  = $ffa2
  40. kernelCiout  = $ffa8
  41. kernelSpinp  = $ff47
  42. kernelChkin  = $ffc6
  43. kernelChkout = $ffc9
  44. kernelClrchn = $ffcc
  45. kernelChrin  = $ffcf
  46. kernelChrout = $ffd2
  47. kernelGetin  = $ffe4
  48.  
  49. st = $90
  50. ciaClock = $dd00
  51. ciaFlags = $dc0d
  52. ciaData  = $dc0c
  53.  
  54. clusterBlockCount .buf 1        ;1 or 2
  55. fatBlocks         .buf 1        ;up to 9
  56. rootDirBlocks     .buf 1        ;up to 14
  57. rootDirEntries    .buf 1        ;up to 224
  58. totalSectors      .buf 2        ;up to 2880
  59. firstFileBlock    .buf 1
  60. firstRootDirBlock .buf 1
  61. fileClusterCount  .buf 2
  62. lastFatEntry      .buf 2
  63.  
  64. bufCylinder     .buf 1
  65. bufSide         .buf 1
  66. fatDirty        .buf 1
  67. dirDirty        .buf 14  ;flag for each directory block
  68. formatParms     .buf 1
  69. sectorsPerTrack .byte 9  ;default, up to 18
  70.                 .buf 4
  71. sectorsPerCyl   .byte 18 ;default, up to 36
  72.  
  73. ;====test routines====
  74.  
  75. msFormat = *
  76.    lda #$0e
  77.    sta $ff00
  78.    jsr mountDisk
  79.    lda #0  ;cylinder
  80.    ldx #0  ;side
  81.    jsr readTrack
  82.    lda #<trackbuf
  83.    ldy #>trackbuf
  84.    sta 1024
  85.    sty 1025
  86.    rts
  87.  
  88. ;====hardware level====
  89.  
  90. sendU0 = *  ;( .A=burstCommandCode ) : .CS=err
  91.    pha
  92.    lda #0
  93.    sta st
  94.    lda msDevice
  95.    jsr kernelListen
  96.    lda #$6f
  97.    jsr kernelSecond
  98.    lda #"u"
  99.    jsr kernelCiout
  100.    bit st
  101.    bmi sendU0Error
  102.    lda #"0"
  103.    jsr kernelCiout
  104.    pla
  105.    jsr kernelCiout
  106.    bit st
  107.    bmi sendU0Error
  108.    clc
  109.    rts
  110.  
  111.    sendU0Error = *
  112.    lda #25  ;device not present error
  113.    sta errno
  114.    sec
  115.    rts
  116.  
  117. toggleClock = *
  118.    lda ciaClock
  119.    eor #$10
  120.    sta ciaClock
  121.    rts
  122.  
  123. serialWait = *
  124.    lda #$08
  125. -  bit ciaFlags
  126.    beq -
  127.    rts
  128.  
  129. getBurstByte = *
  130.    jsr serialWait
  131.    ldx ciaData
  132.    jsr toggleClock
  133.    txa
  134.    rts
  135.  
  136. mountDisk = *  ;() : .CS=err
  137.    lda #%00011010
  138.    jsr sendU0
  139.    bcc +
  140.    rts
  141. +  jsr kernelUnlsn
  142.    bit st
  143.    bmi sendU0Error
  144.    clc
  145.    jsr kernelSpinp
  146.    bit ciaFlags
  147.    jsr toggleClock
  148.    jsr getBurstByte
  149.    and #$0f
  150.    sta errno
  151.    cmp #2
  152.    bcs mountExit
  153.    ldy #0
  154. -  jsr getBurstByte
  155.    sta formatParms,y
  156.    iny
  157.    cpy #6
  158.    bcc -
  159.    lda sectorsPerTrack
  160.    asl
  161.    sta sectorsPerCyl
  162.    ;** set interleave to 4 if 1571, don't bother for other drives
  163.    bit msType
  164.    bmi mountExit
  165.    lda #%00001000
  166.    jsr sendU0
  167.    bcc +
  168.    rts
  169. +  lda #4
  170.    jsr kernelCiout
  171.    jsr kernelUnlsn
  172.    clc
  173.    mountExit = *
  174.    rts
  175.  
  176. bufptr = 2
  177. secnum = 4
  178.  
  179. readTrack = *  ;( .A=cylinder, .X=side ) : trackbuf, .CS=err
  180.    pha
  181.    txa
  182.    and #$01
  183.    asl
  184.    asl
  185.    asl
  186.    asl
  187.    bit msType
  188.    bpl +
  189.    eor #$10
  190. +  jsr sendU0
  191.    pla
  192.    bcc +
  193.    rts
  194. +  jsr kernelCiout      ;cylinder number
  195.    lda #1               ;start sector number
  196.    jsr kernelCiout
  197.    lda sectorsPerTrack  ;sector count
  198.    jsr kernelCiout
  199.    jsr kernelUnlsn
  200.    sei
  201.    clc
  202.    jsr kernelSpinp
  203.    bit ciaFlags
  204.    jsr toggleClock
  205.    lda #<trackbuf
  206.    ldy #>trackbuf
  207.    sta bufptr+0
  208.    sty bufptr+1
  209.    lda #0
  210.    sta secnum
  211. -  bit msType
  212.    bmi +
  213.    jsr get1571BufPtr
  214. +  jsr readSector
  215.    bcs trackExit
  216.    inc secnum
  217.    lda secnum
  218.    cmp sectorsPerTrack
  219.    bcc -
  220.    jsr toggleClock
  221.    clc
  222.    trackExit = *
  223.    cli
  224.    rts
  225.  
  226. get1571BufPtr = *
  227.    lda #<trackbuf
  228.    sta bufptr
  229.    ldx secnum
  230.    clc
  231.    lda #>trackbuf
  232.    adc bufptr1571,x
  233.    sta bufptr+1
  234.    rts
  235.  
  236. bufptr1571 = *
  237.    .byte 0,8,16,6,14,4,12,2,10
  238.  
  239. readSector = *  ;( bufptr ) : .CS=err
  240.    jsr getBurstByte
  241.    and #$0f
  242.    sta errno
  243.    cmp #2
  244.    bcc +
  245.    rts
  246. +  ldx #2
  247.    ldy #0
  248.  
  249.    readByte = *
  250.    lda #$08
  251. -  bit ciaFlags
  252.    beq -
  253.    lda ciaClock
  254.    eor #$10
  255.    sta ciaClock
  256.    lda ciaData
  257.    sta (bufptr),y
  258.    iny
  259.    bne readByte
  260.    inc bufptr+1
  261.    dex
  262.    bne readByte
  263.    clc
  264.    rts
  265.  
  266. oldClock = 5
  267.  
  268. writeSector = *  ;( bufptr, .A=cylinder, .X=side, .Y=sector ) : .CS=err
  269.    pha
  270.    sty secnum
  271.    txa
  272.    and #$01
  273.    asl
  274.    asl
  275.    asl
  276.    asl
  277.    ora #$02
  278.    bit msType
  279.    bpl +
  280.    eor #$10
  281. +  jsr sendU0
  282.    pla
  283.    bcc +
  284.    rts
  285. +  jsr kernelCiout      ;track number
  286.    lda secnum           ;sector number
  287.    jsr kernelCiout
  288.    lda #1               ;sector count
  289.    jsr kernelCiout
  290.    jsr kernelUnlsn
  291.    sei
  292.    lda #$40
  293.    sta oldClock
  294.    sec
  295.    jsr kernelSpinp      ;set for burst output
  296.    sei
  297.    bit ciaFlags
  298.    ldx #2
  299.    ldy #0
  300.  
  301.    writeByte = *
  302.    lda ciaClock
  303.    cmp ciaClock
  304.    bne writeByte
  305.    eor oldClock
  306.    and #$40
  307.    beq writeByte
  308.    lda (bufptr),y
  309.    sta ciaData
  310.    lda oldClock
  311.    eor #$40
  312.    sta oldClock
  313.    lda #8
  314. -  bit ciaFlags
  315.    beq -
  316.    iny
  317.    bne writeByte
  318.    inc bufptr+1
  319.    dex
  320.    bne writeByte
  321.  
  322.    clc
  323.    jsr kernelSpinp
  324.    bit ciaFlags
  325.    jsr toggleClock
  326.    jsr serialWait
  327.    ldx ciaData
  328.    jsr toggleClock
  329.    txa
  330.    and #$0f
  331.    sta errno
  332.    cmp #2
  333.    cli
  334.    rts
  335.  
  336. ;====logical-sector level====
  337.  
  338. initPackage = *
  339.    lda #$0e
  340.    sta $ff00
  341.    lda #$ff
  342.    sta bufCylinder
  343.    sta bufSide
  344.    ldx #13
  345. -  sta dirDirty,x
  346.    dex
  347.    bpl -
  348.    sta fatDirty
  349.    clc
  350.    rts
  351.  
  352. sectorSave = 5
  353.  
  354. readBlock = *  ;( .A=cylinder,.X=side,.Y=sector ) : .AY=blkPtr,.CS=err
  355.    cmp bufCylinder
  356.    bne readBlockPhysical
  357.    cpx bufSide
  358.    bne readBlockPhysical
  359.    dey
  360.    tya
  361.    asl
  362.    clc
  363.    adc #>trackbuf
  364.    tay
  365.    lda #<trackbuf
  366.    clc
  367.    rts
  368.  
  369.    readBlockPhysical = *
  370.    sta bufCylinder
  371.    stx bufSide
  372.    sty sectorSave
  373.    jsr readTrack
  374.    bcc readBlockPhysicalOk
  375.    lda errno
  376.    and #$0f
  377.    cmp #11    ;disk change
  378.    beq +
  379. -  lda #$ff
  380.    sta bufCylinder
  381.    stx bufSide
  382.    sec
  383.    rts
  384. +  jsr mountDisk
  385.    lda bufCylinder
  386.    ldx bufSide
  387.    ldy sectorSave
  388.    bcc readBlockPhysical
  389.    jmp -
  390.  
  391.    readBlockPhysicalOk = *
  392.    lda bufCylinder
  393.    ldx bufSide
  394.    ldy sectorSave
  395.    jmp readBlock
  396.  
  397. divideByCylSecs = *  ;( .AY=number ) : .A=quotient, .Y=remainder
  398.    ldx #$ff
  399. -  inx
  400.    sec
  401.    sbc sectorsPerCyl
  402.    bcs -
  403.    dey
  404.    bpl -
  405.    clc
  406.    adc sectorsPerCyl
  407.    iny
  408.    tay
  409.    txa
  410.    rts
  411.  
  412. convertLogicalBlockNum = *  ;( .AY=blockNum ) : .A=cyl, .X=side, .Y=sec
  413.    jsr divideByCylSecs
  414.    ldx #0
  415.    cpy sectorsPerTrack
  416.    bcc +
  417.    pha
  418.    tya
  419.    sbc sectorsPerTrack
  420.    tay
  421.    pla
  422.    ldx #1
  423. +  iny
  424.    rts
  425.  
  426. destPtr = 6
  427. curCylinder = 8
  428. curSide = 9
  429. curSector = 10
  430. blockCountdown = 11
  431. sourcePtr = 12
  432.  
  433. copyBlocks = *  ;( .AY=startBlock, .X=blockCount, ($6)=dest ) : .CS=err
  434.    stx blockCountdown
  435.    jsr convertLogicalBlockNum
  436.    sta curCylinder
  437.    stx curSide
  438.    sty curSector
  439.  
  440.    copyBlockLoop = *
  441.    lda curCylinder
  442.    ldx curSide
  443.    ldy curSector
  444.    jsr readBlock
  445.    bcc +
  446.    rts
  447. +  sta sourcePtr+0
  448.    sty sourcePtr+1
  449.    ldx #2
  450.    ldy #0
  451. -  lda (sourcePtr),y
  452.    sta (destPtr),y
  453.    iny
  454.    lda (sourcePtr),y
  455.    sta (destPtr),y
  456.    iny
  457.    bne -
  458.    inc sourcePtr+1
  459.    inc destPtr+1
  460.    dex
  461.    bne -
  462.    inc curSector
  463.    lda curSector
  464.    cmp sectorsPerTrack
  465.    beq +
  466.    bcc +
  467.    lda #1
  468.    sta curSector
  469.    inc curSide
  470.    lda curSide
  471.    cmp #2
  472.    bcc +
  473.    lda #0
  474.    sta curSide
  475.    inc curCylinder
  476. +  dec blockCountdown
  477.    bne copyBlockLoop
  478.    clc
  479.    rts
  480.  
  481. convertClusterNum = *  ;( .AY=clusterNum ) : .AY=logicalBlockNum
  482.    sec
  483.    sbc #2
  484.    bcs +
  485.    dey
  486. +  ldx clusterBlockCount
  487.    cpx #1
  488.    beq +
  489.    asl
  490.    sty 7
  491.    rol 7
  492.    ldy 7
  493. +  clc
  494.    adc firstFileBlock
  495.    bcc +
  496.    iny
  497. +  rts
  498.  
  499. readCluster = *  ;( .AY=clusterNumber ) : clusterBuf, .CS=err
  500.    jsr convertClusterNum
  501.  
  502.    ;** read logical blocks comprising cluster
  503.    ldx #<clusterBuf
  504.    stx 6
  505.    ldx #>clusterBuf
  506.    stx 7
  507.    ldx clusterBlockCount
  508.    jmp copyBlocks
  509.  
  510. writeLogicalBlock = *  ;( .AY=logicalBlockNumber, bufptr ) : .CS=err
  511.    jsr convertLogicalBlockNum
  512.    cmp bufCylinder
  513.    bne +
  514.    cpx bufSide
  515.    bne +
  516.    pha
  517.    lda #$ff
  518.    sta bufCylinder
  519.    sta bufSide
  520.    pla
  521. +  jsr writeSector
  522.    rts
  523.  
  524. writeClusterSave .buf 2
  525.  
  526. writeCluster = *  ;( .AY=clusterNumber, clusterBuf ) : .CS=err
  527.    jsr convertClusterNum
  528.    ldx #<clusterBuf
  529.    stx bufptr+0
  530.    ldx #>clusterBuf
  531.    stx bufptr+1
  532.    sta writeClusterSave+0
  533.    sty writeClusterSave+1
  534.    jsr writeLogicalBlock
  535.    bcc +
  536.    rts
  537. +  lda clusterBlockCount
  538.    cmp #2
  539.    bcs +
  540.    rts
  541. +  lda writeClusterSave+0
  542.    ldy writeClusterSave+1
  543.    clc
  544.    adc #1
  545.    bcc +
  546.    iny
  547. +  jsr writeLogicalBlock
  548.    rts
  549.  
  550. ;====MS-DOS format level====
  551.  
  552. bootBlock = 2
  553.  
  554. msDir = *  ;( .A=forceMount ) : .AY=dirbuf, .X=dirEntries, .CS=err
  555.    ldx #$0e
  556.    stx $ff00
  557.  
  558.    cmp #$d0
  559.    bne +
  560.    jsr mountDisk
  561.    bcc +
  562.    rts
  563.  
  564.    ;** get parameters from boot sector
  565. +  lda #0
  566.    ldy #0
  567.    jsr convertLogicalBlockNum
  568.    jsr readBlock
  569.    bcc +
  570.    rts
  571. +  sta bootBlock+0
  572.    sty bootBlock+1
  573.    ldy #13              ;get cluster size
  574.    lda (bootBlock),y
  575.    sta clusterBlockCount
  576.    cmp #3
  577.    bcc +
  578.  
  579.    invalidParms = *
  580.    lda #17  ;invalid disk parms error
  581.    sta errno
  582.    sec
  583.    rts
  584.  
  585. +  ldy #16              ;check FAT replication count, must be 2
  586.    lda (bootBlock),y
  587.    cmp #2
  588.    bne invalidParms
  589.    ldy #22              ;get FAT size in sectors, max of 9
  590.    lda (bootBlock),y
  591.    sta fatBlocks
  592.    cmp #10
  593.    bcs invalidParms
  594.    ldy #17              ;get directory size
  595.    lda (bootBlock),y
  596.    sta rootDirEntries
  597.    cmp #225
  598.    bcs invalidParms
  599.    lsr
  600.    lsr
  601.    lsr
  602.    lsr
  603.    sta rootDirBlocks
  604.    ldy #19              ;get total sector count
  605.    lda (bootBlock),y
  606.    sta totalSectors+0
  607.    iny
  608.    lda (bootBlock),y
  609.    sta totalSectors+1
  610.    ldy #24              ;check sectors per track, must be 18 or fewer
  611.    lda (bootBlock),y
  612.    cmp #19
  613.    bcs invalidParms
  614.    ldy #26
  615.    lda (bootBlock),y
  616.    cmp #2               ;check number of sides, must be 2
  617.    bne invalidParms
  618.    ldy #14              ;check number of boot sectors, must be 1
  619.    lda (bootBlock),y
  620.    cmp #1
  621.    bne invalidParms
  622.  
  623.    ;** get derived parameters
  624.    lda fatBlocks        ;first root directory sector
  625.    asl
  626.    clc
  627.    adc #1
  628.    sta firstRootDirBlock
  629.    clc                  ;first file sector
  630.    adc rootDirBlocks
  631.    sta firstFileBlock
  632.    lda totalSectors+0   ;number of file clusters
  633.    ldy totalSectors+1
  634.    sec
  635.    sbc firstFileBlock
  636.    bcs +
  637.    dey
  638. +  sta fileClusterCount+0
  639.    sty fileClusterCount+1
  640.    lda clusterBlockCount
  641.    cmp #2
  642.    bne +
  643.    lsr fileClusterCount+1
  644.    ror fileClusterCount+0
  645. +  clc
  646.    lda fileClusterCount+0
  647.    adc #2
  648.    sta lastFatEntry+0
  649.    lda fileClusterCount+1
  650.    adc #0
  651.    sta lastFatEntry+1
  652.  
  653.    ;** load FAT
  654.    lda #<fatbuf
  655.    ldy #>fatbuf
  656.    sta 6
  657.    sty 7
  658.    lda #1
  659.    ldy #0
  660.    ldx fatBlocks
  661.    jsr copyBlocks
  662.    bcc +
  663.    rts
  664.  
  665.    ;** load actual directory
  666. +  lda #<dirbuf
  667.    ldy #>dirbuf
  668.    sta 6
  669.    sty 7
  670.    lda firstRootDirBlock
  671.    ldy #0
  672.    ldx rootDirBlocks
  673.    jsr copyBlocks
  674.    bcc +
  675.    rts
  676. +  lda #<dirbuf
  677.    ldy #>dirbuf
  678.    ldx rootDirEntries
  679.    clc
  680.    rts
  681.  
  682. entryAddr = 2
  683. entryWork = 4
  684. entryBits = 5
  685. entryData0 = 6
  686. entryData1 = 7
  687. entryData2 = 8
  688.  
  689. locateFatEntry = *  ;( .AY=fatEntryNumber ) : entryAddr, entryBits1
  690.    sta entryBits
  691.    ;** divide by two
  692.    sty entryAddr+1
  693.    lsr entryAddr+1
  694.    ror
  695.  
  696.    ;** times three
  697.    sta entryWork
  698.    ldx entryAddr+1
  699.    asl
  700.    rol entryAddr+1
  701.    clc
  702.    adc entryWork
  703.    sta entryAddr
  704.    txa
  705.    adc entryAddr+1
  706.    sta entryAddr+1
  707.  
  708.    ;** add base, get data
  709.    clc
  710.    lda entryAddr
  711.    adc #<fatbuf
  712.    sta entryAddr
  713.    lda entryAddr+1
  714.    adc #>fatbuf
  715.    sta entryAddr+1
  716.    ldy #2
  717. -  lda (entryAddr),y
  718.    sta entryData0,y
  719.    dey
  720.    bpl -
  721.    rts
  722.  
  723. getFatEntry = *  ;( .AY=fatEntryNumber ) : .AY=fatEntryValue
  724.    jsr locateFatEntry
  725.    lda entryBits
  726.    and #1
  727.    bne +
  728.  
  729.    ;** case 1: first 12-bit cluster
  730.    lda entryData1
  731.    and #$0f
  732.    tay
  733.    lda entryData0
  734.    rts
  735.  
  736.    ;** case 2: second 12-bit cluster
  737. +  lda entryData1
  738.    ldx #4
  739. -  lsr entryData2
  740.    ror
  741.    dex
  742.    bne -
  743.    ldy entryData2
  744.    rts
  745.  
  746. fatValue = 9
  747.  
  748. setFatEntry = *  ;( .AY=fatEntryNumber, (fatValue) )
  749.    jsr locateFatEntry
  750.    lda fatValue+1
  751.    and #$0f
  752.    sta fatValue+1
  753.    lda entryBits
  754.    and #1
  755.    bne +
  756.  
  757.    ;** case 1: first 12-bit cluster
  758.    lda fatValue
  759.    sta entryData0
  760.    lda entryData1
  761.    and #$f0
  762.    ora fatValue+1
  763.    sta entryData1
  764.    jmp setFatExit
  765.  
  766.    ;** case 2: second 12-bit cluster
  767. +  ldx #4
  768. -  asl fatValue
  769.    rol fatValue+1
  770.    dex
  771.    bne -
  772.    lda fatValue+1
  773.    sta entryData2
  774.    lda entryData1
  775.    and #$0f
  776.    ora fatValue
  777.    sta entryData1
  778.  
  779.    setFatExit = *
  780.    ldy #2
  781. -  lda entryData0,y
  782.    sta (entryAddr),y
  783.    dey
  784.    bpl -
  785.    sty fatDirty
  786.    rts
  787.  
  788. dirtyDirent = *  ;( writeDirent )
  789.    sec
  790.    lda writeDirent+0
  791.    sbc #<dirbuf
  792.    lda writeDirent+1
  793.    sbc #>dirbuf
  794.    lsr
  795.    and #$0f
  796.    tax
  797.    lda #$ff
  798.    sta dirDirty,x
  799.    rts
  800.  
  801. delCluster = 14
  802.  
  803. msDelete = *  ;( writeDirent )
  804.    ldy #$0e
  805.    sty $ff00
  806.    lda writeDirent+0
  807.    ldy writeDirent+1
  808.    sta 2
  809.    sty 3
  810.    lda #$e5
  811.    ldy #0
  812.    sta (2),y
  813.    ldy #26
  814.    lda (2),y
  815.    sta delCluster+0
  816.    iny
  817.    lda (2),y
  818.    sta delCluster+1
  819. -  lda delCluster+1
  820.    cmp #12  ;cluster number high byte
  821.    bcc +
  822.    jmp dirtyDirent
  823. +  tay
  824.    lda delCluster
  825.    jsr getFatEntry
  826.    pha
  827.    tya
  828.    pha
  829.    lda #0
  830.    sta fatValue+0
  831.    sta fatValue+1
  832.    lda delCluster+0
  833.    ldy delCluster+1
  834.    jsr setFatEntry
  835.    pla
  836.    sta delCluster+1
  837.    pla
  838.    sta delCluster
  839.    jmp -
  840.  
  841. flushBlock = 14
  842. flushCountdown = $60
  843. flushRepeats = $61
  844. flushDirIndex = $61
  845.  
  846. msFlush = *  ;( msDevice, msType ) : .CS=error
  847.    lda #$0e
  848.    sta $ff00
  849.    lda fatDirty
  850.    beq flushDirectory
  851.    lda #0
  852.    sta fatDirty
  853.  
  854.    ;** flush fat
  855.    lda #2
  856.    sta flushRepeats
  857.    lda #1
  858.    sta flushBlock
  859.  
  860.    masterFlush = *
  861.    lda fatBlocks
  862.    sta flushCountdown
  863.    lda #<fatbuf
  864.    ldy #>fatbuf
  865.    sta bufptr
  866.    sty bufptr+1
  867. -  lda flushBlock
  868.    ldy #0
  869.    jsr writeLogicalBlock
  870.    bcc +
  871.    rts
  872. +  inc flushBlock
  873.    dec flushCountdown
  874.    bne -
  875.    dec flushRepeats
  876.    bne masterFlush
  877.  
  878.    ;** flush directory
  879.    flushDirectory = *
  880.    lda firstRootDirBlock
  881.    sta flushBlock
  882.    lda rootDirBlocks
  883.    sta flushCountdown
  884.    lda #0
  885.    sta flushDirIndex
  886.    lda #<dirbuf
  887.    ldy #>dirbuf
  888.    sta bufptr+0
  889.    sty bufptr+1
  890. -  ldx flushDirIndex
  891.    lda dirDirty,x
  892.    beq +
  893.    lda #0
  894.    sta dirDirty,x
  895.    lda flushBlock
  896.    ldy #0
  897.    jsr writeLogicalBlock
  898.    dec bufptr+1
  899.    dec bufptr+1
  900. +  inc flushBlock
  901.    inc flushDirIndex
  902.    inc bufptr+1
  903.    inc bufptr+1
  904.    dec flushCountdown
  905.    bne -
  906.    clc
  907.    rts
  908.  
  909. bfFatEntry = 14
  910. bfBlocks = $60
  911.  
  912. msBytesFree = *  ;( ) : .AYX=fileBytesFree
  913.    ldy #$0e
  914.    sty $ff00
  915.    lda #2
  916.    ldy #0
  917.    sta bfFatEntry+0
  918.    sty bfFatEntry+1
  919.    sty bfBlocks+0
  920.    sty bfBlocks+1
  921. -  lda bfFatEntry+0
  922.    ldy bfFatEntry+1
  923.    jsr getFatEntry
  924.    sty 2
  925.    ora 2
  926.    bne +
  927.    inc bfBlocks+0
  928.    bne +
  929.    inc bfBlocks+1
  930. +  inc bfFatEntry
  931.    bne +
  932.    inc bfFatEntry+1
  933. +  lda bfFatEntry+0
  934.    cmp lastFatEntry+0
  935.    lda bfFatEntry+1
  936.    sbc lastFatEntry+1
  937.    bcc -
  938.    ldx clusterBlockCount
  939. -  asl bfBlocks
  940.    rol bfBlocks+1
  941.    dex
  942.    bne -
  943.    lda #0
  944.    ldy bfBlocks+0
  945.    ldx bfBlocks+1
  946.    rts
  947.  
  948. ;====file-copy level====
  949.  
  950. transMode = 14
  951. lfn = 15
  952. cbmDataPtr = $60
  953. cbmDataLen = $62
  954. cluster = $64
  955.  
  956. copyFileCluster = *  ;( cluster, lfn, transMode ) : .CS=err
  957.    lda cluster+0
  958.    ldy cluster+1
  959.    jsr readCluster
  960.    bcc +
  961.    rts
  962. +  lda #<clusterBuf
  963.    ldy #>clusterBuf
  964.    sta cbmDataPtr+0
  965.    sty cbmDataPtr+1
  966.    lda #0
  967.    sta cbmDataLen+0
  968.    lda clusterBlockCount
  969.    asl
  970.    sta cbmDataLen+1
  971.  
  972.    ;**get next cluster
  973.    lda cluster+0
  974.    ldy cluster+1
  975.    jsr getFatEntry
  976.    sta cluster+0
  977.    sty cluster+1
  978.    cpy #12  ;cluster number high byte
  979.    bcc copyFileClusterData
  980.    lda lenML
  981.    sta cbmDataLen
  982.    lda #$01
  983.    ldx clusterBlockCount
  984.    cpx #1
  985.    beq +
  986.    lda #$03
  987. +  and lenML+1
  988.    bne +
  989.    ldx lenML
  990.    beq copyFileClusterData
  991. +  sta cbmDataLen+1
  992.  
  993.    copyFileClusterData = *
  994.    jsr commieOut
  995.    rts
  996.  
  997. cbmDataLimit = $66
  998.  
  999. commieOut = *  ;( cbmDataPtr, cbmDataLen ) : .CS=err
  1000.    ldx lfn
  1001.    bne +
  1002.    clc
  1003.    rts
  1004. +  jsr kernelChkout
  1005.    bcc commieOutMore
  1006.    commieError = *
  1007.    clc
  1008.    adc #20
  1009.    sec
  1010.    sta errno
  1011.    rts
  1012.  
  1013.    commieOutMore = *
  1014.    lda #255
  1015.    ldx cbmDataLen+1
  1016.    bne +
  1017.    lda cbmDataLen
  1018. +  sta cbmDataLimit
  1019.    ldy #0
  1020. -  lda (cbmDataPtr),y
  1021.    bit transMode
  1022.    bpl +
  1023.    tax
  1024.    lda transBuf,x
  1025.    beq commieNext
  1026. +  jsr kernelChrout
  1027.    commieNext = *
  1028.    iny
  1029.    cpy cbmDataLimit
  1030.    bne -
  1031.  
  1032.    clc
  1033.    lda cbmDataPtr
  1034.    adc cbmDataLimit
  1035.    sta cbmDataPtr
  1036.    bcc +
  1037.    inc cbmDataPtr+1
  1038. +  sec
  1039.    lda cbmDataLen
  1040.    sbc cbmDataLimit
  1041.    sta cbmDataLen
  1042.    bcs +
  1043.    dec cbmDataLen+1
  1044. +  lda cbmDataLen
  1045.    ora cbmDataLen+1
  1046.    bne commieOutMore
  1047.    jsr kernelClrchn
  1048.    clc
  1049.    rts
  1050.  
  1051. testAbort = *
  1052.    jsr kernelGetin
  1053.    bne +
  1054.    clc
  1055.    rts
  1056. +  cmp #"a"
  1057.    bne testAbort
  1058.    lda #16  ;abort error
  1059.    sta errno
  1060.    sec
  1061.    rts
  1062.  
  1063. msRead = *  ;( cluster, lenML, .A=transMode, .X=lfn ) : .CS=err
  1064.    ldy #$0e
  1065.    sty $ff00
  1066.    sta transMode
  1067.    stx lfn
  1068.    lda startCluster+0
  1069.    ldy startCluster+1
  1070.    sta cluster+0
  1071.    sty cluster+1
  1072.    jmp +
  1073. -  jsr testAbort
  1074.    bcs ++
  1075.    jsr copyFileCluster
  1076.    bcc +
  1077.    rts
  1078. +  lda cluster+1
  1079.    cmp #12  ;cluster number high byte
  1080.    bcc -
  1081.    clc
  1082. +  rts
  1083.  
  1084. inLfn = $50
  1085. generateLf = $51
  1086. cbmDataMax = $52
  1087. reachedEof = $54
  1088. prevSt = $55
  1089.  
  1090. commieInInit = *  ;( .A=transMode, .X=inLfn )
  1091.    sta transMode
  1092.    stx inLfn
  1093.    lda #0
  1094.    sta generateLf
  1095.    sta reachedEof
  1096.    sta prevSt
  1097.    rts
  1098.  
  1099. commieIn = *  ;( cbmDataPtr++, cbmDataMax ) : cbmDataLen, .CS=err, .Z=eof
  1100.    lda #0
  1101.    sta cbmDataLen
  1102.    sta cbmDataLen+1
  1103.    ldx reachedEof
  1104.    beq +
  1105.    lda #0
  1106.    clc
  1107.    rts
  1108. +  ldx inLfn
  1109.    jsr kernelChkin
  1110.    bcc commieInMore
  1111.    jmp commieError
  1112.  
  1113.    commieInMore = *
  1114.    lda #255
  1115.    ldx cbmDataMax+1
  1116.    bne +
  1117.    lda cbmDataMax
  1118. +  sta cbmDataLimit
  1119.    ldy #0
  1120. -  jsr commieInByte
  1121.    bcc +
  1122.    rts
  1123. +  beq +
  1124.    sta (cbmDataPtr),y
  1125.    iny
  1126.    cpy cbmDataLimit
  1127.    bne -
  1128.  
  1129. +  sty cbmDataLimit
  1130.    clc
  1131.    lda cbmDataPtr
  1132.    adc cbmDataLimit
  1133.    sta cbmDataPtr
  1134.    bcc +
  1135.    inc cbmDataPtr+1
  1136. +  clc
  1137.    lda cbmDataLen
  1138.    adc cbmDataLimit
  1139.    sta cbmDataLen
  1140.    bcc +
  1141.    inc cbmDataLen+1
  1142. +  sec
  1143.    lda cbmDataMax
  1144.    sbc cbmDataLimit
  1145.    sta cbmDataMax
  1146.    bcs +
  1147.    dec cbmDataMax+1
  1148. +  lda reachedEof
  1149.    bne +
  1150.    lda cbmDataMax
  1151.    ora cbmDataMax+1
  1152.    bne commieInMore
  1153. +  jsr kernelClrchn
  1154.    lda cbmDataLen
  1155.    ora cbmDataLen+1
  1156.    clc
  1157.    rts
  1158.  
  1159. commieInByte = *  ;( ) : .A=char, .CS=err, .Z=eof, reachedEof
  1160.    ;** check for already past eof
  1161.    lda reachedEof
  1162.    beq +
  1163.    brk
  1164.    ;** check for generated linefeed
  1165. +  lda generateLf
  1166.    beq +
  1167.    lda #0
  1168.    sta generateLf
  1169.    lda #$0a
  1170.    clc
  1171.    rts
  1172.    ;** check for eof
  1173. +  lda prevSt
  1174.    and #$40
  1175.    beq +
  1176.    lda #$ff
  1177.    sta reachedEof
  1178.    lda #0
  1179.    clc
  1180.    rts
  1181.    ;** read actual character
  1182. +  jsr kernelChrin
  1183.    ldx st
  1184.    stx prevSt
  1185.    bcc +
  1186.    pha
  1187.    jsr kernelClrchn
  1188.    pla
  1189.    jmp commieError
  1190.    ;** translate if necessary
  1191. +  bit transMode
  1192.    bpl +
  1193.    tax
  1194.    lda transBufToAscii,x
  1195.    beq commieInByte
  1196.    cmp #$0d
  1197.    bne +
  1198.    sta generateLf
  1199.    ;** exit
  1200. +  ldx #$ff
  1201.    clc
  1202.    rts
  1203.  
  1204. firstFreeFatEntry = $5a
  1205.  
  1206. allocateFatEntry = *  ;( ) : .AY=fatEntry, .CS=err
  1207. -  lda firstFreeFatEntry
  1208.    cmp lastFatEntry
  1209.    lda firstFreeFatEntry+1
  1210.    sbc lastFatEntry+1
  1211.    bcc +
  1212.    lda #19 ;disk full err
  1213.    sta errno
  1214.    rts
  1215. +  lda firstFreeFatEntry
  1216.    ldy firstFreeFatEntry+1
  1217.    jsr getFatEntry
  1218.    sty 2
  1219.    ora 2
  1220.    bne +
  1221.    lda firstFreeFatEntry
  1222.    ldy firstFreeFatEntry+1
  1223.    clc
  1224.    rts
  1225. +  inc firstFreeFatEntry
  1226.    bne -
  1227.    inc firstFreeFatEntry+1
  1228.    jmp -
  1229.  
  1230. msFileLength = $5c  ;(3 bytes)
  1231.  
  1232. msWriteCluster = *  ; (*) : .CS=err
  1233.    ;** get a new cluster
  1234.    jsr allocateFatEntry
  1235.    bcc +
  1236.    rts
  1237.    ;** make previous fat entry point to new cluster
  1238. +  sta fatValue
  1239.    sty fatValue+1
  1240.    lda cluster
  1241.    ora cluster+1
  1242.    beq +
  1243.    lda cluster
  1244.    ldy cluster+1
  1245.    ldx fatValue
  1246.    stx cluster
  1247.    ldx fatValue+1
  1248.    stx cluster+1
  1249.    jsr setFatEntry
  1250.    jmp msClusterNew
  1251. +  lda writeDirent
  1252.    ldy writeDirent+1
  1253.    sta 2
  1254.    sty 3
  1255.    ldy #26
  1256.    lda fatValue
  1257.    sta (2),y
  1258.    sta cluster
  1259.    iny
  1260.    lda fatValue+1
  1261.    sta (2),y
  1262.    sta cluster+1
  1263.  
  1264.    ;** make new fat entry point to null
  1265.    msClusterNew = *
  1266.    lda #$ff
  1267.    ldy #$0f
  1268.    sta fatValue
  1269.    sty fatValue+1
  1270.    lda cluster
  1271.    ldy cluster+1
  1272.    jsr setFatEntry
  1273.    ;** write new cluster data
  1274. +  lda cluster
  1275.    ldy cluster+1
  1276.    jsr writeCluster
  1277.    bcc +
  1278.    rts
  1279.    ;** add cluster length to file length
  1280. +  clc
  1281.    lda msFileLength
  1282.    adc cbmDataLen
  1283.    sta msFileLength
  1284.    lda msFileLength+1
  1285.    adc cbmDataLen+1
  1286.    sta msFileLength+1
  1287.    bcc +
  1288.    inc msFileLength+2
  1289. +  clc
  1290.    rts
  1291.  
  1292. msWrite = *  ;( msDevice, msType, writeDirent, .A=trans, .X=cbmLfn ) :.CS=err
  1293.    ldy #$0e
  1294.    sty $ff00
  1295.    ;** initialize
  1296.    jsr commieInInit
  1297.    lda #0
  1298.    sta cluster
  1299.    sta cluster+1
  1300.    sta firstFreeFatEntry+1
  1301.    sta msFileLength
  1302.    sta msFileLength+1
  1303.    sta msFileLength+2
  1304.    lda #2
  1305.    sta firstFreeFatEntry
  1306.  
  1307.    ;** copy cluster from cbm file
  1308. -  jsr testAbort
  1309.    bcc +
  1310.    rts
  1311. +  lda #<clusterBuf
  1312.    ldy #>clusterBuf
  1313.    sta cbmDataPtr
  1314.    sty cbmDataPtr+1
  1315.    lda clusterBlockCount
  1316.    asl
  1317.    tay
  1318.    lda #0
  1319.    sta cbmDataMax
  1320.    sty cbmDataMax+1
  1321.    jsr commieIn
  1322.    bcc +
  1323.    rts
  1324. +  beq +
  1325.    jsr msWriteCluster
  1326.    bcc -
  1327.    rts
  1328.  
  1329.    ;** wrap up after writing - set file length, dirty flag, exit.
  1330. +  lda writeDirent
  1331.    ldy writeDirent+1
  1332.    sta 2
  1333.    sty 3
  1334.    ldx #0
  1335.    ldy #28
  1336. -  lda msFileLength,x
  1337.    sta (2),y
  1338.    iny
  1339.    inx
  1340.    cpx #3
  1341.    bcc -
  1342.    jsr dirtyDirent
  1343.    clc
  1344.    rts
  1345.  
  1346. ;===== commodore file level =====
  1347.  
  1348. cbmCopyTrans .buf 1
  1349.  
  1350. cbmCopy = *  ;( .A=inLfn, .X=outLfn, .Y=outAscToCbmTranslationFlag )
  1351.    sty cbmCopyTrans
  1352.    ldy #$0e
  1353.    sty $ff00
  1354.    stx lfn
  1355.    tax
  1356.    lda #0
  1357.    jsr commieInInit
  1358. -  jsr testAbort
  1359.    bcs +
  1360.    lda #<clusterBuf
  1361.    ldy #>clusterBuf
  1362.    sta cbmDataPtr+0
  1363.    sty cbmDataPtr+1
  1364.    lda #<1024
  1365.    ldy #>1024
  1366.    sta cbmDataMax+0
  1367.    sty cbmDataMax+1
  1368.    jsr commieIn
  1369.    bcs +
  1370.    beq +
  1371.    lda #<clusterBuf
  1372.    ldy #>clusterBuf
  1373.    sta cbmDataPtr+0
  1374.    sty cbmDataPtr+1
  1375.    lda cbmCopyTrans
  1376.    sta transMode
  1377.    jsr commieOut
  1378.    lda #0
  1379.    sta transMode
  1380.    bcs +
  1381.    jmp -
  1382. +  rts
  1383.  
  1384. cbmDirent = *  ;( .A=lfn )
  1385.    ldy #$0e
  1386.    sty $ff00
  1387.    tax
  1388.    jsr kernelChkin
  1389.    bcc ++
  1390.    cdirErr = *
  1391. +  lda #0
  1392.    sta cdirFlen
  1393.    sta cdirBlocks
  1394.    sta cdirBlocks+1
  1395.    rts
  1396.    ;** get block count
  1397. +  jsr cdirGetch
  1398.    jsr cdirGetch
  1399.    jsr cdirGetch
  1400.    sta cdirBlocks
  1401.    jsr cdirGetch
  1402.    sta cdirBlocks+1
  1403.    ;** look for filename
  1404.    lda #0
  1405.    sta cdirFlen
  1406. -  jsr cdirGetch
  1407.    cmp #34
  1408.    beq +
  1409.    cmp #"b"
  1410.    bne -
  1411.    jsr kernelClrchn
  1412.    rts
  1413.    ;** get filename
  1414. +  ldy #0
  1415. -  jsr cdirGetch
  1416.    cmp #34
  1417.    beq +
  1418.    sta cdirName,y
  1419.    iny
  1420.    bne -
  1421. +  sty cdirFlen
  1422. -  jsr cdirGetch
  1423.    cmp #" "
  1424.    beq -
  1425.    sta cdirType
  1426. -  jsr cdirGetch
  1427.    cmp #0
  1428.    bne -
  1429.    jsr kernelClrchn
  1430.    rts
  1431.  
  1432. cdirGetch = *
  1433.    jsr kernelChrin
  1434.    bcs +
  1435.    bit st
  1436.    bvs +
  1437.    rts
  1438. +  pla
  1439.    pla
  1440.    jsr kernelClrchn
  1441.    jmp cdirErr
  1442.  
  1443. ;===== data =====
  1444.  
  1445. transBuf = *
  1446.        ;0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
  1447. .byte $00,$00,$00,$00,$00,$00,$00,$00,$14,$09,$0d,$00,$93,$00,$00,$00 ;0
  1448. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;1
  1449. .byte $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f ;2
  1450. .byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f ;3
  1451. .byte $40,$c1,$c2,$c3,$c4,$c5,$c6,$c7,$c8,$c9,$ca,$cb,$cc,$cd,$ce,$cf ;4
  1452. .byte $d0,$d1,$d2,$d3,$d4,$d5,$d6,$d7,$d8,$d9,$da,$5b,$5c,$5d,$5e,$5f ;5
  1453. .byte $c0,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f ;6
  1454. .byte $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$db,$dc,$dd,$de,$df ;7
  1455. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;8
  1456. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;9
  1457. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;a
  1458. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;b
  1459. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;c
  1460. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;d
  1461. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;e
  1462. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;f
  1463.  
  1464. transBufToAscii = *
  1465.        ;0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
  1466. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$09,$00,$00,$00,$0d,$00,$00 ;0
  1467. .byte $00,$00,$00,$00,$08,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;1
  1468. .byte $20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$2a,$2b,$2c,$2d,$2e,$2f ;2
  1469. .byte $30,$31,$32,$33,$34,$35,$36,$37,$38,$39,$3a,$3b,$3c,$3d,$3e,$3f ;3
  1470. .byte $40,$61,$62,$63,$64,$65,$66,$67,$68,$69,$6a,$6b,$6c,$6d,$6e,$6f ;4
  1471. .byte $70,$71,$72,$73,$74,$75,$76,$77,$78,$79,$7a,$5b,$5c,$5d,$5e,$5f ;5
  1472. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;6
  1473. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;7
  1474. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;8
  1475. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;9
  1476. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;a
  1477. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;b
  1478. .byte $60,$41,$42,$43,$44,$45,$46,$47,$48,$49,$4a,$4b,$4c,$4d,$4e,$4f ;c
  1479. .byte $50,$51,$52,$53,$54,$55,$56,$57,$58,$59,$5a,$7b,$7c,$7d,$7e,$7f ;d
  1480. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00 ;e
  1481. .byte $00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$00,$7e ;f
  1482.  
  1483. ;====bss storage (size=22,016 bytes)====
  1484.  
  1485. bss = *
  1486. trackbuf   = bss+0     ;(9216)  ;room for 18 x 512-byte sectors
  1487. clusterBuf = bss+9216  ;(1024)  ;2 sectors
  1488. fatbuf     = bss+10240 ;(4608)  ;9 sectors
  1489. dirbuf     = bss+14848 ;(7168)  ;14 sectors = 224 dirents
  1490. bssEnd     = bss+22016
  1491.  
  1492.