From a35dde3f8d183ee775c7206feeadf73406df051c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20GIBERT?= Date: Wed, 11 Sep 2019 17:53:33 +0200 Subject: [PATCH] Kernel 0.93+ --- .Floppies/A2OSX.BUILD.po | Bin 33553920 -> 33553920 bytes ProDOS.203/ProDOS.S.CCLK.txt | 14 +- ProDOS.203/ProDOS.S.DiskII.txt | 28 +- ProDOS.203/ProDOS.S.GP.txt | 2 +- ProDOS.203/ProDOS.S.LDR.A.txt | 769 +++++++++++++ ProDOS.203/ProDOS.S.LDR.B.txt | 908 +++++++++++++++ ProDOS.203/ProDOS.S.LDR.txt | 1672 ---------------------------- ProDOS.203/ProDOS.S.RAM.txt | 2 +- ProDOS.203/ProDOS.S.RAMI.txt | 2 +- ProDOS.203/ProDOS.S.RAMX.txt | 30 +- ProDOS.203/ProDOS.S.SEL0.txt | 90 +- ProDOS.203/ProDOS.S.SEL1.txt | 82 +- ProDOS.203/ProDOS.S.SEL2.txt | 61 +- ProDOS.203/ProDOS.S.TCLK.txt | 2 +- ProDOS.203/ProDOS.S.XDOS.A.txt | 663 +++++++++++ ProDOS.203/ProDOS.S.XDOS.B.txt | 869 +++++++++++++++ ProDOS.203/ProDOS.S.XDOS.C.txt | 1897 +++++--------------------------- ProDOS.203/ProDOS.S.XDOS.D.txt | 590 ++++++++++ ProDOS.203/ProDOS.S.XDOS.E.txt | 615 +++++++++++ ProDOS.203/ProDOS.S.XDOS.F.txt | 355 ++++++ ProDOS.203/ProDOS.S.XDOS.M.txt | 152 +-- ProDOS.203/ProDOS.S.XDOS.txt | 1756 ----------------------------- ProDOS.203/ProDOS.S.txt | 64 +- 23 files changed, 5336 insertions(+), 5287 deletions(-) create mode 100644 ProDOS.203/ProDOS.S.LDR.A.txt create mode 100644 ProDOS.203/ProDOS.S.LDR.B.txt delete mode 100644 ProDOS.203/ProDOS.S.LDR.txt create mode 100644 ProDOS.203/ProDOS.S.XDOS.A.txt create mode 100644 ProDOS.203/ProDOS.S.XDOS.B.txt create mode 100644 ProDOS.203/ProDOS.S.XDOS.D.txt create mode 100644 ProDOS.203/ProDOS.S.XDOS.E.txt create mode 100644 ProDOS.203/ProDOS.S.XDOS.F.txt delete mode 100644 ProDOS.203/ProDOS.S.XDOS.txt diff --git a/.Floppies/A2OSX.BUILD.po b/.Floppies/A2OSX.BUILD.po index fff7ec69dddd626eb3d8827e5712148f26774f5b..e7b4d92ded2ccb2f746049ad6d67d5a203a0d036 100644 GIT binary patch delta 349727 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 delta 355028 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 zkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M z2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4E zl8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaq zBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw* zLXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4 zBqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7t zNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wed zkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M z2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4E zl8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaq zBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw* zLXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4 zBqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7t zNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wed zkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M z2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4E zl8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaq zBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw* zLXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4 zBqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7t zNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wed zkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M z2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4E zl8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaq zBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw* zLXwaqBne4El8_`M2}wedkR&7tNkWp4BqRw*LXwaqBne4El8_`M2}wedkR&7tNkWp4 cBqRw*LXwaqBne4El8_`M3I9Jy_@#{h2RkPiBme*a diff --git a/ProDOS.203/ProDOS.S.CCLK.txt b/ProDOS.203/ProDOS.S.CCLK.txt index f70d6441..6f36bc34 100644 --- a/ProDOS.203/ProDOS.S.CCLK.txt +++ b/ProDOS.203/ProDOS.S.CCLK.txt @@ -5,23 +5,24 @@ NEW * $2F80-$2FFC moved to $D742 .OP 65816 -ofsC .EQ cclock_0-tclk_in offset to Cortland clock org +ofsC .EQ *-tclk_in offset to Cortland clock org -cclock_0 SHORT I,M 8 bit mode. +cclock_0 +* SHORT I,M 8 bit mode. lda statereg state register. sta savestate save for restore after tool call. and #$CF clear the read/write aux memory bits. sta statereg make it real clc set e = 0 to set native mode xce - LONG I,M 16 bit mode. +* LONG I,M 16 bit mode. lda #$0000 zero out result space. pha push 4 words for hex time result pha pha pha - _ReadTimeHex - SHORT M back to 8 bit to get results from stack + >IIGS ReadTimeHex +* SHORT M back to 8 bit to get results from stack lda savestate restore state register sta statereg pla pull off seconds and ignore @@ -61,7 +62,8 @@ savestate .EQ *-ofsC .HS 000000000000 cclk_end .EQ * end of obj cclock_0. .HS 000000 pad to page boundary - LONGI OFF +* LONG I OFF + .OP 65C02 *-------------------------------------- MAN SAVE USR/SRC/PRODOS.203/PRODOS.S.CCLK diff --git a/ProDOS.203/ProDOS.S.DiskII.txt b/ProDOS.203/ProDOS.S.DiskII.txt index 561a2e61..ce4687c0 100644 --- a/ProDOS.203/ProDOS.S.DiskII.txt +++ b/ProDOS.203/ProDOS.S.DiskII.txt @@ -1,16 +1,9 @@ NEW AUTO 3,1 * disk ii driver. object code = xrw_0 - -* critical timing requires page bound considerations for code and data. -* virtually the entire 'write' routine must not cross page boundaries. -* critical branches in the 'write', 'read', and 'read adr' subroutines -* which must not cross page boundaries are noted in comments. -* the cld at blockio must be present to determine bank of $D000 * $5300-5A00 moved to language card bank 1 at $D000 - .OP 6502 - .OR $D000 +ofsD .EQ *-rwts offset to disk ii driver or blockio cld $D8 to flag language card bank 1 (main) jsr rsetphse @@ -110,7 +103,7 @@ L537F lda #$01 wait 100us for each count in montime L538E lda A4L get command # beq L53FD if 0 then status command - lsr a set carry = 1 for read, 0 for write. + lsr set carry = 1 for read, 0 for write. bcs L5398 must prenibblize for write jsr prenib16 L5398 ldy #$40 64 retries @@ -630,13 +623,13 @@ L57F0 rts drvindx .EQ *-ofsD pha preserve acc across call lda A4L+1 - lsr a - lsr a - lsr a - lsr a + lsr + lsr + lsr + lsr cmp #$08 and #$07 - rol a + rol tax index to table. pla restore acc rts @@ -719,7 +712,7 @@ wrefa2 .EQ *-ofsD beq L58C0 (2+) branch if code written was page aligned. lda A2H (3) get byte address of last byte to be written. beq L58B3 (2+) branch if only 1 byte left to write. - lsr a (2) test for odd or even last byte (carry set/clear) + lsr (2) test for odd or even last byte (carry set/clear) lda pch (3) restore nibl to acc. sta q6h,x (5) lda q6l,x (4) @@ -755,7 +748,7 @@ wrefa6 .EQ *-ofsD bcc L5881 (3-) branch if not the last. bcs L58B1 (3) waste 3 cycles, branch always. L58B1 bcs L58C0 (3) branch always. -L58B3 lda |pch (4) absolute reference to zero page +L58B3 lda pch (4) absolute reference to zero page sta q6h,x (5) lda q6l,x (4) pha (3) waste 14 micro-seconds total @@ -872,7 +865,7 @@ prn3 .EQ *-ofsD get byte from highest group. L595F sta pch beq L596F branch if data to be written is page lda A2H aligned. check if last byte is even - lsr a or odd address. shift even/odd -> carry. + lsr or odd address. shift even/odd -> carry. lda (buf),y if even, then leave intact. bcc L596D branch if odd. iny if even, then pre-xor with byte 1. @@ -953,7 +946,6 @@ spunit .EQ *-ofsD ref pathbuf-$10 .HS 0000000000000000 * pathname buffer starts at this page boundary (pathbuf = $D700) -*-------------------------------------- MAN SAVE USR/SRC/PRODOS.203/PRODOS.S.DISKII LOAD USR/SRC/PRODOS.203/PRODOS.S diff --git a/ProDOS.203/ProDOS.S.GP.txt b/ProDOS.203/ProDOS.S.GP.txt index 1a891271..e8741186 100644 --- a/ProDOS.203/ProDOS.S.GP.txt +++ b/ProDOS.203/ProDOS.S.GP.txt @@ -55,7 +55,7 @@ aftirq .EQ *-ofsG irq returns here. oldacc .EQ *-ofsG .DA #0 afbank .EQ *-ofsG - .HS 0 + .HS 00 * memory map of lower 48k. each bit represents 1 page. * protected pages = 1, unprotected = 0 diff --git a/ProDOS.203/ProDOS.S.LDR.A.txt b/ProDOS.203/ProDOS.S.LDR.A.txt new file mode 100644 index 00000000..72ebe27c --- /dev/null +++ b/ProDOS.203/ProDOS.S.LDR.A.txt @@ -0,0 +1,769 @@ +NEW + AUTO 3,1 + .OP 65C02 + +H2000 jmp prostart + jmp atalkset appletalk setup for network boot + jmp p16start GQuit setup for gs/os + +LDR.MSG.AppleII .AS "Apple II" +LDR.MSG.ProDOS .AS "ProDOS 8 V2.0.3 " + .AS "06-May-93" +H202F .AS " " +H203B .AS "Copyright Apple Computer, Inc., 1983-93" +H2062 .AS "All Rights Reserved." + +p16start inc setuprts set = 2 for GQuit rts +atalkset inc setuprts set = 1 for appletalk rts +prostart lda unitnum + sta LDR.MLIONLINE.P+1 + jsr LDR.Splash + +* test for at least a 65c02 + + sed + lda #$99 a negative # + clc + adc #$01 +1 in decimal = 0 (positive) + cld + bmi m48k if 6502 because will not clear N flag + +* machine at least an m65c02 + + lda #$01 patch for the gs rom + trb statereg to force off intcxrom + ldx #H232B yx=232B location table + ldy /H232B + jsr reloc move interpreter loader to $800 + bcs m48k error + +* test for at least 64k + + ldy #$00 + lda #$FF + sta kversion at least 48k ? + eor kversion + sec + bne m48k if not. + + sta kversion try again to be sure + lda kversion + bne m48k still not. + + lda romin read ROM + jsr whchrom get preliminary system config + bcs m48k machine too small + lda idapple + and #$20 + bne m64k if at least 64k //+. +m48k jmp H22EB need enhanced IIe + +* we have 64k, now determine model: //e , iic, or Cortland (//gs) + +m64k ldx #H2367 yx=2367 relocation table + ldy /H2367 + jsr reloc + lda kversion + sta xdosver save current version for dir use + +H20CE bcc H20D3 + jmp relocerr + +H20D3 lda romin read ROM + ldx version ROM id byte + cpx #$06 + bne H211D then it's a //e + lda #$E0 + bit zidbyte another ROM id byte + php + lda idapple + and #$37 + plp + bvc set3 if //c or //x + bmi set7 if //e + +set3 php + ora #$08 + plp + bpl mach2 if //c + ora #$40 + bpl H20FD always taken. + +mach2 inc cflag //c or later + bvs H20FD +set7 ora #$80 + +H20FD sta idapple + lda romin read ROM + sec + jsr idroutine returns system info + bcs H211D branch if // family + inc cortland it's a Cortland, set loader flag + stz vmode force setvid to reset cursor + jsr setvid reset output to screen + lda setuprts + bne H211D branch if prodos 8 alone + +* running from gs/os shell so zero out os_boot for appletalk + + sta >OS_BOOT indicates O/S initially booted. + jsr patch101 patch for gs/os - rev note #101 + +* put dispatcher in bank 2 of language card + +H211D lda LDR.MLIONLINE.P+1 place boot devnum in globals + sta LDR.MLIREADBLOCK.P+1 + sta devnum last device used + jsr devsrch finish setting up globals + lda LDR.MLIREADBLOCK.P+1 + sta devnum + jsr lc1in switch in language card bank 1. + ldx #rlclk64 set up clock + ldy /rlclk64 + jsr reloc + +H2139 bcs H20CE + lda #calldisp + sta jspare+1 P8 system death vector + lda /calldisp + sta jspare+2 + lda altram read/write RAM bank 2 + lda altram + ldx #altdsptbl GQuit dispatcher + ldy /altdsptbl + lda setuprts + cmp #$02 is this a GQuit setup? + beq H216E taken to use GQuit dispatcher. + ldx #newquitbl else, use Bird's Better Bye + ldy /newquitbl if correct machine. + lda machid machine ID byte + bit #$00 //c ? + bne H216E if yes, can use. + and #$C2 + cmp #$82 //e with 80 col card ? + beq H216E if yes, can use. + ldx #dsp64 else, use original quit code + ldy /dsp64 + inc newquitflag using old quit code so set flag + +H216E jsr reloc + lda #$EE byte to distinguish LC bank 2 + sta $D000 + jsr lc1in switch in LC bank 1 + bcs H2139 + +* test for 128k needed to install ram disk + + lda machid machine ID byte + and #$30 + eor #$30 + bne noramdsk if < 128k + ldx #$FF + php save interrupt status + pla in acc. + sei no interrupts. + sta setaltzp use alt zero page/stack + stx auxsp init aux sp to $FF + sta setstdzp use main zero page/stack + pha restore interrupt status + plp + sta int3rom enable internal slot 3 ROM + jsr H2C80 install ram disk + +* check interrupt vector to determine ROM version + +noramdsk lda romin1 read ROM/write RAM bank 2 + ldy irqv interrupt vector + ldx irqv+1 x = high byte + jsr lc1in set language card bank 1 to r/w + cpx #$D0 is it > $D000 (old roms) + lda #$00 + bcs H21C5 branch if old roms + sta setaltzp use alt zero page/stack + lda #$FF set aux sp = $FF + sta auxsp + stx irqv+1 interrupt vector + sty irqv save irq vector in aux lc + sta setstdzp use main zero page/stack + stx irqv+1 save irq vector in main lc + sty irqv + lda #$01 + +H21C5 sta irqflag 1 = new roms + stz cortflag assume not Cortland system + lda cortland running on a Cortland ? + beq H21D5 branch if not. + inc cortflag yes it's Cortland + bra docard + +* check for a rom in slot 3. if no rom, use internal $C300 firmware + +H21D5 sta int3rom enable internal slot 3 ROM + lda rommap slot ROM bit map + and #$08 mask all but slot 3 + bne isromin3 taken if rom in slot 3 + bra H2247 else continue booting + +* found a rom in slot 3. is it an external, identifiable 80 col card +* with interrupt routines? if so, enable it else use internal $C300 firmware. + +isromin3 sta slot3rom enable slot 3 rom + lda slot3id1 check card id bytes + cmp #$38 + bne hitswtch not terminal card + lda slot3id2 + cmp #$18 + bne hitswtch + lda slot3id3 + cmp #$01 + bne hitswtch + lda ext80col is it an apple 80 col compatible card? + and #$F0 + cmp #$80 + bne hitswtch if not. + lda machid machine ID byte + and #$C8 + cmp #$C0 is it a //+ ? + beq docard yes + lda slot3irq + cmp #$2C does card have an interrupt handler? + beq docard yes + +hitswtch sta int3rom enable internal $C300 firmware + +* verify that the card in aux slot is actually present + + sta store80on enable 80-col store + sta txtpage2 switch in text page 2 + lda #$EE + sta txtp2 + asl + asl txtp2 + cmp txtp2 + bne H2230 + lsr + lsr txtp2 + cmp txtp2 + +H2230 sta txtpage1 main memory + sta store80off disable 80-col store + beq docard branch if card is there + lda machid machine ID byte + and #$FD clear 80-col bit 2 (no card) + bne H2244 always + +docard lda machid + ora #$02 turn bit 2 on (80-col card is present) + +H2244 sta machid +H2247 lda cortland are we running on a //gs ? + beq H225D if not. + lda #$4C enable clock routine by putting a jmp + sta clockv in front of clock vector + ldx #cortclock yx = relocation table + ldy /cortclock for cortland clock driver + jsr reloc + lda #$01 set bit 0 = clock present + tsb machid + +H225D lda setuprts get setup entry point flag + beq H2267 taken if normal boot. + lda romin read ROM + rts return to caller at setup entry point. + +setuprts .DA #$00 0 = normal boot, <>0 = return + +* set prefix to boot device + +H2267 jsr MLI online + .DA #MLIONLINE + .DA LDR.MLIONLINE.P + bcs relocerr + + lda PrefixBuf+1 get volume name length. + and #$0F strip devnum + beq relocerr + + inc add 1 for leading '/' + sta PrefixBuf save prefix length. + lda #'/' place leading '/' in prefix buffer + sta PrefixBuf+1 + + jsr MLI set prefix + .DA #MLISETPREFIX + .DA LDR.MLISETPREFIX.P + bcs relocerr + + tax =0 + stx ZP.DstPtr + ldy #$02 read directory into buffer + lda /DirBlkBuf + +H228E sta ZP.DstPtr+1 + sta LDR.MLIREADBLOCK.P+4 + sty LDR.MLIREADBLOCK.P+5 + stx LDR.MLIREADBLOCK.P+6 + + jsr MLI read block + .DA #MLIREADBLOCK + .DA LDR.MLIREADBLOCK.P + bcs relocerr + + ldy #$03 get next block# from link + lda (ZP.DstPtr),y + tax + dey + ora (ZP.DstPtr),y if both bytes are the same + beq H22B7 then no more blocks of directory. + lda (ZP.DstPtr),y + tay + lda ZP.DstPtr+1 + clc + adc #$02 add $200 to buffer pointer + cmp /dbuf+$800 until it points past end of buffer. + bcc H228E if ok, read next block. + +H22B7 jmp lodintrp jmp to 'licode' (load interpreter) + +* relocation/configuration error + +relocerr sta romin read ROM + jsr home + + ldy #$1D + +.1 lda LDR.MSG.LdrErr,y + sta vline12+4,y + dey + bpl .1 + + bmi * + +LDR.MSG.LdrErr .AS "Relocation/Configuration Error" + + ldy #$23 + +.1 lda LDR.MSG.EnhErr,y + sta vline14+2,y + dey + bpl .1 + + bmi * + +LDR.MSG.EnhErr .AS "REQUIRES ENHANCED APPLE IIE OR LATER" + +LDR.MLIONLINE.P .DA #2 + .DA #$60 + .DA PrefixBuf+1 + +LDR.MLISETPREFIX.P + .DA #1 + .DA PrefixBuf + +LDR.MLIREADBLOCK.P + .DA #3 + .DA #0 unit number + .DA 0 2 byte data buffer + .DA 0 2 byte block number + +cortland .BS 1 cortland loader flag (1 = Cortland) +newquitflag .BS 1 1 = old quit code + +H232B .DA #1 move interpreter loader code + .DA lodintrp destination address + .DA H257B-licode length to move + .DA licode source address + .DA #$01 move $3F0 vectors + .DA p3vect destination + .DA $0010 16 bytes to move + .DA H257B source + .DA #$01 + .DA lookptr + .DA $0002 + .DA ZP.DstPtr + .DA #$01 move 128k test to zero page + .DA tst128 destination + .DA H2622-H25DC length + .DA H25DC source + .DA #FF done + +dsp64 .DA #$01 move p8 dispatcher code + .DA displc2 destination + .DA birdbye-disp1obj length (must be <= 3 pages) + .DA disp1obj source + .DA #FF done + +newquitbl .DA #$01 move Bird's Bye code + .DA displc2 dest + .DA GQdisp-birdbye length (must be <= 3 pages) + .DA birdbye source + .DA #FF done + +altdsptbl .DA #$01 move GQuit launcher + .DA displc2 destination + .DA $0300 length (must be <= 3 pages) + .DA GQdisp source + .DA #$01 move a copy of GQuit launcher + .DA dispadr to dispadr for gsos + .DA $0300 length (must be <= 3 pages) + .DA GQdisp source + .DA #FF done + +* tables for moving 64k version of mli for execution + +H2367 .DA #$01 relocation table. 1=move src to ZP.DstPtr + .DA lanirq destination + .DA H2E00-H2D9B length to move + .DA H2D9B source + .DA #$01 + .DA MLI globals + .DA $0100 in one page + .DA H2E00 + .HS 00 0=clear buffers $D700-$DDFF + .DA pathbuf + .DA xdosorg-pathbuf + .DA #$01 + .DA xdosorg + .DA ramsrc-xdosobj length of mli + .DA xdosobj + .DA #$01 + .DA rwts + .DA disp1obj-blockio length of disk ii driver + .DA blockio + .DA #FF done + +* move thunderclock + +rlclk64 .DA #$01 relocation table. 1=move src to ZP.DstPtr + .DA tclk_in destination + .DA tclk_end-tclock_0 length of thunderclock driver + .DA tclock_0 source + .DA #$04 4=relocate and move program + .DA tclk_in + .DA H2F69-tclock_0 + .DA tclk_in + .HS 00 + .HS C1C1 +clock64 .DA #$00 + .DA #FF done + +* move cortland clock + +cortclock .DA #$01 relocation table. 1=move src to ZP.DstPtr + .DA tclk_in destination + .DA cclk_end-cclock_0 length of cortland clock driver + .DA cclock_0 source + .DA #FF done + +* load and run appletalk configuration file (atinit) if present +* or continue loading and running .system file + +* loader origin $800 + +ofsL .EQ *-lodintrp offset from loader org + +licode jsr MLI check for file 'atinit' + .DA #MLIGETFILEINFO + .DA gfi_list + bcc gfi_ok branch if 'atinit' file found + cmp #$46 file not found? + beq H23DF if so, continue loading interpreter + bne H23E2 +gfi_ok lda gfi_type + cmp #$E2 is 'atinit' correct file type? + bne H23E2 error - wrong file type + jsr MLI open 'atinit' file + .DA #$C8 + .DA atopen parms + bne H23E2 error + lda #$9F max size = 39.75k ($2000-$BF00) + sta rdlen+1 + stz rdlen + jsr MLI read 'atinit' file to 'sysentry' + .DA #$CA + .DA rdparm + bne H23E2 error - too big + jsr MLI close 'atinit' file + .DA #$CC + .DA clparm + bne H23E2 error + lda romin enable ROM + jsr sysentry execute ATinit +H23DF jmp goloadint execute .system file + +* fatal error + +H23E2 ldx H23F0 +H23E5 lda H23F0,x + sta vline16,x + dex + bne H23E5 + beq * + +H23F0 .DA #$1A length of message + .AS "Unable to load ATInit file" + +gfi_list .EQ *-ofsL + .DA #$0A + .DA atinitname + .HS 00 +gfi_type .EQ *-ofsL + .HS 00000000 + .HS 0000000000000000 + .HS 0000 +atopen .EQ *-ofsL parms to open 'atinit' + .HS 03 + .DA atinitname + .DA iobuf i/o buffer + .HS 01 ref# hard coded since no other files +atinitname .EQ *-ofsL + .DA #06 length of name + .AS "atinit" name of appletalk config file +goloadint .EQ *-ofsL + lda /dbuf search directory buffer + sta idxl+1 + lda #$04 start 1 entry past header + bne H2434 always. +H2432 lda idxl calc next entry position +H2434 clc + adc dbuf+35 inc to next entry address + sta idxl + bcs H2451 branch if page cross. + adc dbuf+35 test for end of block. + bcc H2453 branch if not page cross + lda idxl+1 + lsr end of block? + bcc H2453 no. + cmp #$09 end of directory? + bne H244D no. + jmp nointrp no interpreter, go quit. +H244D lda #$04 reset index to 1st entry in next block. + sta idxl +H2451 inc idxl+1 inc to next page. +H2453 ldy #$10 check file type. + lda #$FF must be a prodos sys file + eor (idxl),y + bne H2432 if not sys. + tay see if active + lda (idxl),y + beq H2432 if deleted file. + and #$0F strip file 'kind'. + sta PrefixBuf save length of name. + cmp #$08 must be at least 'x.system' + bcc H2432 else, ignore it. + tay compare last 7 chars for '.system' + ldx #$06 +H246C lda (idxl),y + eor iterp,x + asl + bne H2432 branch if something else + dey + dex + bpl H246C + ldy #$00 +H247A iny + lda (idxl),y + sta PrefixBuf,y + ora #$80 msb on so can be displayed if error + sta iomess+$11,y + cpy PrefixBuf + bne H247A + lda #$A0 space after name + sta iomess+$12,y + tya error message length + adc #$13 (carry set) + sta ierlen + jsr MLI open interpreter file + .DA #$C8 + .DA opparm + bne badlod + jsr MLI get eof (length of file) + .DA #$D1 + .DA efparm + bne badlod + lda eof+2 + bne toolong + lda eof+1 + cmp #$9F max size = 39.75k ($2000-$BF00) + bcs toolong + sta rdlen+1 + lda eof + sta rdlen (read entire file) + jsr MLI read interpreter file + .DA #$CA + .DA rdparm + beq H24C8 go close if successfully read. + cmp #$56 memory conflict? + beq toolong then too large + bne badlod else, unable to load. +H24C8 jsr MLI close interpreter file + .DA #$CC + .DA clparm + bne badlod hopefully never taken + +* if booting on a //c then see if esc is in keyboard buffer +* and clear it. it may have been pressed to shift speed +* of accelerator chip + + lda cflag + beq H24DF taken if not booting on a //c + lda kbd else, check for keypress + cmp #$9B escape? + bne H24DF if not. + sta kbdstrobe clear keyboard +H24DF lda romin enable ROM + jmp sysentry go run interpreter +cflag .EQ *-ofsL + .HS 00 set if a //c. +nointrp .EQ *-ofsL no interpreter found, + jsr MLI so quit. + .DA #$65 + .DA quitparm +badlod ldy ierlen center the error message + lda #$27 + sec + sbc ierlen + lsr + adc ierlen + tax +H24FA lda iomess,y + sta vline16,x + dex + dey + bpl H24FA + bmi H2511 +toolong ldy #$1E +H2508 lda lgmess,y + sta vline16+5,y + dey + bpl H2508 +H2511 bmi H2511 +lgmess .EQ *-ofsL + .AS "** System program too large **" +iomess .EQ *-ofsL + .AS "** Unable to load" + .AS " X.System *********" +ierlen .EQ *-ofsL + .HS 00 +opparm .EQ *-ofsL parms for open call + .HS 03 + .DA PrefixBuf + .DA iobuf + .HS 01 +efparm .EQ *-ofsL parms for get eof call + .HS 02 + .DA #01 +eof .EQ *-ofsL + .HS 000000 length of file. +rdparm .EQ *-ofsL parms for read call + .HS 04 + .HS 01 + .DA sysentry +rdlen .EQ *-ofsL + .HS 0000 + .HS 0000 +clparm .EQ *-ofsL parms for close call + .HS 01 + .HS 00 +quitparm .EQ *-ofsL parms for quit call + .HS 04 + .HS 00 + .HS 0000 + .HS 00 + .HS 0000 +iterp .EQ *-ofsL interpreter suffix that is required + .AS ".SYSTEM" + +* 16 bytes moved to $03F0 vectors + +H257B .DA breakv + .DA oldrst + .DA #$5A powerup byte + jmp oldrst '&' vector + jmp oldrst ctrl-y vector + .HS 004000 + .DA irqent global page interrupt vector +lc1in lda ramin read/write language card RAM bank 1 + lda ramin + rts + +* determine which system model and save in machine id (idapple) + +whchrom stz idapple assume standard apple // + ldx version check hardware id + cpx #$38 is it apple // (autostart rom)? + beq H25BE if yes + lda #$80 + cpx #$06 apple //e? + beq H25BC if yes + lda #$40 + cpx #$EA apple //+? + bne H25B6 it not, then machine is unknown. + ldx HFB1E apple /// in emulation? + cpx #$AD + beq H25BC taken if apple //+. + lda #$D0 test again for apple /// emulation + cpx #$8A because will only have 48k memory. + bne H25B6 if taken, then machine is unknown. +H25B4 sec apple /// emulation is not allowed + rts because insufficient memory. +H25B6 lda #$02 machine unknown + sta (ZP.DstPtr),y + bne H25D9 always. +H25BC sta idapple save machine id + +* check for language card ram + +H25BE jsr lc1in switch in language card bank 1 + lda #$AA + sta $D000 + eor $D000 if LC present, result = 0. + bne H25B4 othewise, insufficient memory. + lsr $D000 check lc again + lda #$55 + eor $D000 + bne H25B4 not sufficent memory. + lda #$20 LC ram is available + ora idapple +H25D9 jmp tst128 jumps to page 0 routine below + +* test for 128k. use page 0 for this routine + +H25DC sta idapple H25DC-2621 was moved to location tst128 + bpl not128 if already determined < 128k + lda #$EE + sta wrcardram write to aux mem while on main zp + sta rdcardram and read aux mem. + sta dbuf write these locs just to test aux mem + sta lodintrp 1k apart from each other. + lda dbuf + cmp #$EE + bne noaux + asl dbuf may be sparse mem mapping so + asl change value and see what happens. + cmp dbuf + bne noaux branch if not sparse mapping. + cmp lodintrp + bne H2606 if not sparse. +noaux sec no aux memory available. + bcs H2607 +H2606 clc +H2607 sta wrmainram switch back to main memory + sta rdmainram + bcs not128 if < 128k + lda idapple + ora #$30 set id = 128k present + sta idapple +not128 lda lookptr+1 + sec + sbc #$05 + sta lookptr+1 + bcs H2620 + dec lookptr +H2620 clc + rts + +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.LDR.A +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.LDR.B.txt b/ProDOS.203/ProDOS.S.LDR.B.txt new file mode 100644 index 00000000..f189369a --- /dev/null +++ b/ProDOS.203/ProDOS.S.LDR.B.txt @@ -0,0 +1,908 @@ +NEW + AUTO 3,1 + +* prodos greeting splash screen + +LDR.Splash lda spkr click speaker + sta clr80vid disable 80 col hardware + sta store80off disable 80 col store + jsr setnorm set normal text mode + jsr init init text screen + jsr setvid reset output to screen + jsr setkbd reset input to keyboard + cld + jsr home + + ldx #$07 + +.1 lda H2009,x print title + sta vline10+16,x + dex + bpl .1 + + ldx #$1D + +.2 lda H2011,x + sta vline12+5,x + dex + bpl .2 + + ldx #$0B + +.3 lda H202F,x + sta vline14+14,x + dex + bpl .3 + + ldx #$26 + +.4 lda H203B,x + sta vline23,x + dex + bpl .4 + + ldx #$13 + +.5 lda H2062,x + sta vline24+10,x + dex + bpl .5 + + sec + jsr idroutine returns system info + bcs .8 taken if not a //gs + + lda #$80 + trb newvideo video mode select + +.8 lda spkr click speaker + rts + +* find all disk devices in system slots and set up address +* and device table in prodos global page. if there is a disk +* card in slot 2 then limit the # of devices in slot 5 +* smartport to only 2 + +numdev2 .HS 0000000000000000 8 bytes for smartport call +driveradr .DA 0 +d2idx .DA #0 +diskins2 .DA #0 msb clear if drive in slot 2 + +devsrch stz ZP.DstPtr + stz ZP.DstPtr+1 + stz idxl + ldx #$FF init to no active devices. + stx numdevs count (-1) active devices. + lda #$0E start disk // area at end of devlist. + sta d2idx + +* check slot 2. if there is a disk card then clear the msb of diskins2. this +* will limit the # of devices in any slot 5 spartport card to 2. + + lda #$C2 + sta idxl+1 check slot 2 + jsr cmpid is there a disk in slot 2 ? + ror diskins2 if so, clear msb else set it. + lda #$C7 search slots from high to low + sta idxl+1 + +H26AB jsr cmpid + bcs H270C if no ProDOS device in this slot. + lda (idxl),y check last byte of $Cn rom (y = $ff) + beq diskii branch if 16 sector disk II. + cmp #$FF if = $FF then 13 sector disk II. + bcs H270C ignore if 13 sector boot ROM + sta driveradr else assume it's an intelligent disk. + ldy #$07 check for a smartport device. + lda (idxl),y + bne H26C4 no smartport + jmp smartprt +H26C4 ldy #$FE + lda (idxl),y get attributes. + and #$03 verify it provides read and status calls. + cmp #$03 + sec assume it's an off-brand disk + bne H270C + jsr setdevid set up the devid byte from attributes + clc + php remember that it's not a disk //. + lsr move # of units (0=1, 1=2) to carry. + lda idxl+1 store hi entry addr (low already done) + bne H26E6 branch always. +diskii sta devid =0 since disk ii's have null attributes + sec + php remember it's a disk // + lda H2802 + sta driveradr + lda H2802+1 +H26E6 sta driveradr+1 + jsr installdev install 1 or 2 devices from this slot. + plp get back if it's a disk // (carry). + bcc nxtdsk2 if not disk //. + dex move the list pointer back by 2 devices + dex + stx numdevs count (-1) active devices + dec d2idx increase the disk two index + dec d2idx + ldy d2idx + inx adj since device count starts with $FF. + lda devlist+1,x get entries for disk // + sta devlist,y move then toward the end of the list + lda devlist,x + sta devlist+1,y + dex back to numdevs again +nxtdsk2 clc +H270C jsr sltrom test for ROM in given slot and set flags + dec idxl+1 next lower slot. + lda idxl+1 + and #$07 have all slots been checked ? + bne H26AB no. + +* perform the new device search, mapping unmounted smartport devices +* to empty slots in the device table. + + jsr newmount + +* now copy the disk // list to the end of the regular list. +* start by making the device count include disk //'s + + ldx numdevs current device count - 1 + lda #$0E + sec + sbc d2idx + beq H2747 if there were no disk //'s then done. + clc + adc numdevs sum of disk //'s and others. + sta numdevs + inx move to open space in regular list. + ldy #$0D first disk // entry. +H272F lda devlist,y + pha + lda devlist,x + sta devlist,y + pla + sta devlist,x + inx + dey + sty d2idx use as a temp + cpx d2idx + bcc H272F continue until indexes cross +H2747 ldy #$00 + ldx numdevs now change the device order so that +H274C lda devlist,x the boot device will have highest + pha priority. + and #$7F strip off high bit + eor devnum for comparison. + asl + bne H275A + pla + iny +H275A dex + bpl H274C + ldx numdevs now reverse order of search, hi to lo. + tya was boot device found ? + beq H2777 + lda devnum make boot device 1st in search order. + sta devlist,x + dex + bmi H277E branch if only one device. + dey is this a 2 drive device ? + beq H2777 branch if not. + eor #$80 make boot device, drive 2 next. + sta devlist,x + dex + bmi H277E branch if only 1 device, 2 drives. +H2777 pla + sta devlist,x + dex + bpl H2777 +H277E jsr fndtrd save accumulated machine id. + beq H2787 + sta machid machine ID byte + rts +H2787 jmp H25B6 +stadrv ora devid combine with attributes. + ldx numdevs + inx put device # into device list. + sta devlist,x + asl now form drive 2 device number, if any. + rts +sltrom bcc H27F3 branch if disk drive + +* test for clock card + + ldy #$06 +H2799 lda (idxl),y + cmp dskid,y + bne H27BA no clock + dey + dey + bpl H2799 + lda idxl+1 transfer hi slot address + sbc #$C1 minus $C1 (default) to relocate + sta clock64 references to clock rom. + lda #$4C enable jump vector in globals. + sta clockv P8 clock vector. + lda idapple mark clock as present. + beq H277E + ora #$01 + sta idapple xxxxxxx1 = clock present. + bne H27F3 always taken. + +* test for 80 col card + +H27BA ldy #$05 + lda (idxl),y + cmp #$38 + bne H27E4 + ldy #$07 + lda (idxl),y + cmp #$18 + bne H27E4 + ldy #$0B + lda (idxl),y + dec a must = 1 + bne H27E4 + iny + lda (idxl),y + and #$F0 mask off low nibble. + cmp #$80 generic for 80-col card. + bne H27E4 + lda idapple + beq H277E + ora #$02 + sta idapple xxxxxx1x = 80 col card. + bne H27F3 always taken. + +* test for any other rom + +H27E4 ldx #$00 + lda (idxl) + cmp #$FF apple /// non-slot? + beq H2801 invalid rom +H27EC cmp (idxl) look for floating bus + bne H2801 no rom + inx + bne H27EC +H27F3 lda idxl+1 mark a bit in slot byte + and #$07 to indicate rom present. + tax + lda sltbit,x + ora rommap mark bit to flag rom present + sta rommap slot ROM bit map +H2801 rts + +H2802 .DA rwts disk ii driver + +* id bytes: evens for clock, odds for disk + +dskid .HS 082028005803703C + +* slot bits + +sltbit .HS 0002040810204080 + +fndtrd clc + ldy sltbit +H2818 lda (lookptr),y + and #$DF + adc sltbit + sta sltbit + rol sltbit + iny + cpy sltbit+3 + bne H2818 + tya + asl + asl + asl + asl + tay + eor sltbit + adc #$0B + bne H283B + lda idapple + rts + +H283B lda #$00 + rts + +installdev php how many drives (carry). + lda idxl+1 get index to global device table + and #$07 for this slot... + asl + tay into y reg. + asl + asl now form device # = slot # + asl in high nibble. + jsr stadrv OR in low nibble, store in dev list. + plp restore # of devices in carry. + ror if 2 drives, then bit 7=1. + bpl H2853 branch if a 1 drive device (e.g. hard drive) + inx else presume that 2nd drive is present. + sta devlist,x active device list. + +H2853 stx numdevs save updated device count. + asl shift # of drives back into carry. + lda driveradr get high address of device driver. + sta drivertbl1,y device driver table 1. + bcc H2862 branch if single drive. + sta drivertbl2,y device driver table 2. + +H2862 lda driveradr+1 + sta drivertbl1+1,y + bcc H286D + sta drivertbl2+1,y + +H286D rts + +* query smartport status to determine # of devices +* and install up to 4 units in table if card is in slot 5 +* otherwise only 2 units. this includes a patch #74 + +smartprt jsr setdevid setup the devid byte from attributes + lda idxl+1 + sta driveradr+1 + lda driveradr + sta pscall+1 modify operand + clc + adc #$03 + sta spvect+1 + lda driveradr+1 + sta spvect+2 + sta pscall+2 modify operand + asl convert $Cn to $n0 + asl + asl + asl + sta unitnum unit number + stz A4L force a prodos status call + stz buf dummy pointer + stz bloknml # of bytes to transfer + stz bloknml+1 + lda #$10 + sta buf+1 dummy pointer should be <> 0 + +* do a prodos status call patched in from above + +pscall jsr $0000 self modifying code + ldy #$FB + lda (idxl),y check device id + and #$02 SCSI? + beq H28B1 no, no need to init Cocoon + sta statunit device = 2 for SCSI + +* initialize SCSI Cocoon to build internal device tables +* and report true # of devices attached + + jsr spvect status of Cocoon + .HS 00 + .DA spcparms ignore any errors. +H28B1 stz statunit set unit# = 0 + jsr spvect call to get the device count. + .HS 00 this is a status call + .DA spcparms + lda numdev2 + beq donesp no devices, so done. + cmp #$02 carry set if 2,3,4 + jsr installdev do the 1st and 2nd device if exists. + lda idxl+1 + cmp #$C5 + bne donesp if not slot 5 + +* for slot 5, if there is a disk card in slot 2 +* then only install 2 devices otherwise map +* extra devices as slot 2 + + bit diskins2 disk in slot 2 ? + bpl donesp yes - so done + lda numdev2 + cmp #$03 carry set if 3,4,... + bcc donesp + cmp #$04 carry set if 4,5,6,... + lda #$C2 map extra devices as slot 2 + sta idxl+1 + jsr installdev + lda #$C5 + sta idxl+1 +donesp jmp nxtdsk2 it's a disk device. +setdevid ldy #$FE check attributes byte. +H28E8 lda (idxl),y + lsr move hi nibble to lo nibble for + lsr device table entries. + lsr + lsr + sta devid + rts + +* check unknown card to see if disk id = $Cn00:nn 20 nn 00 nn 03 + +cmpid lda clrrom switch out $C8 ROMs + ldy #$05 +H28F6 lda (idxl),y compare id bytes + cmp dskid,y + sec set if no disk card + bne H2903 + dey + dey + bpl H28F6 loop until all 4 id bytes match. + clc clear if disk card +H2903 rts + +* smartport call parameters + +spcparms .DA #$03 # of parms +statunit .DA #$00 unit number (code for smartport stat) + .DA numdev2 + .DA #00 status code (0 = general status) + +* indexes into driver table + +driveridx .DA #$06 s3, d1 + .DA #$1E s7, d2 + .DA #$0E s7, d1 + .DA #$1C s6, d2 + .DA #$0C s6, d1 + .DA #$1A s5, d2 + .DA #$0A s5, d1 + .DA #$14 s2, d2 + .DA #$04 s2, d1 + .DA #$12 s1, d2 + .DA #$02 s1, d1 + .DA #$18 s4, d2 + .DA #$08 s4, d1 + +* self modifying jmp = smartport entry address + +spvect jmp $0000 self modifying +newmount stz idxl + lda #$C7 start with slot 7 ($C700) + sta idxl+1 +H291F jsr H29EB is there a smartport device here? + bcs H2974 no, next device. + ldy #$FF get smartport address. + lda (idxl),y + clc + adc #$03 add 3 for smartport call + sta spvect+1 + lda idxl+1 + sta spvect+2 + dey + jsr H28E8 set up device attributes + stz statunit + jsr spvect do a status call on smartport itself + .HS 00 + .DA spcparms + lda numdev2 # of devices on smartport + cmp #$03 + bcc H2974 only 2 devices,skip to next one. + inc add 1 for comparisons. + sta driveradr # of devices + 1. + lda #$03 start at unit #3 (non-slot 5) + ldx spvect+2 + cpx #$C5 is this slot 5? + bne H295B no, start at 3. + bit diskins2 disk controller in slot 2? + bpl H295B yes, so allow remapping of s5 devices + lda #$05 else start looking at unit #5 + +* find block devices on this smartport + +H295B cmp driveradr have we done all units in this slot? + bcs H2974 yes, skip to next slot. + sta statunit store the unit#. + jsr spvect do status call + .HS 00 + .DA spcparms + lda numdev2 is this a block device? + bmi mount yes, so mount it. +H296E lda statunit go check the next unit# + inc + bra H295B +H2974 dec idxl+1 + lda idxl+1 + cmp #$C0 searched down to slot 0? + bne H291F if not. + rts +mount ldx #$0C +H297F ldy driveridx,x + lda drivertbl1,y device driver table 1 + cmp #nodevice + bne H2990 + lda drivertbl1+1,y + cmp /nodevice + beq H2994 +H2990 dex + bpl H297F + rts ran out of space for devices, exit. + +* empty slot found + +H2994 lda idxl+1 + pha + phx + phy + tya which slot is empty? + lsr shift into slot# + and #$07 now 1-7 + ora #$C0 now $C1-$C7 + sta idxl+1 + jsr H29EB smartport interface in this slot? + ply + plx + pla + sta idxl+1 + bcc H2990 yes, can't use to mirror the device. + jsr lc1in write enable LC ram bank 1. + tya divide index by 2 + lsr + tax + lda statunit + sta spunit-1,x store the smartport unit # + lda spvect+1 and entry address. + sta spvectlo-1,x + lda spvect+2 + sta spvecthi-1,x + lda romin write protect lc ram. + inc numdevs + ldx numdevs + tya + lsr + cmp #$08 + bcc nodev2 drive 2 mount + sbc #$08 + ora #$08 +nodev2 asl + asl + asl + asl + ora devid include device attributes + sta devlist,x in the active device list. + lda #remap_sp + sta drivertbl1,y device driver table 1 + lda /remap_sp + sta drivertbl1+1,y + bra H296E +H29EB jsr cmpid is it a disk controller? + bcs H29F8 no, so return. + sec assume no smartport + ldy #$07 + lda (idxl),y is it a smartport? + bne H29F8 if not. + clc smartport found +H29F8 rts + +* relocation subroutine. on entry, regs yx = address of parameter table +* with the following parameters: +* +* (1) command: 0 = zero destination range +* 1 = move data from src to ZP.DstPtr +* 2 = hi addr ref tbl, relocate and move +* 3 = lo/hi addr ref tbl, relocate and move +* 4 = program, relocate and move +* >4 = end of sequence of commands +* (2) destination +* (2) length +* (2) source +* (1) # of address ranges (n) to be relocated +* (n+1) list of low page addresses to be relocated +* (n+1) list of high page addresses to be relocated +* (n+1) list of offset amounts to be added to be added +* if low and high limits have not been met +* +* on exit, carry set if error and yx = addr of error +* with acc = $00 for table error or $FF if illegal opcode + +reloc stx idxl save address of control table + sty idxl+1 +rloop lda (idxl) get relocation command. + cmp #$05 + bcs rlend taken if >= 5 then done. + tax move destination to page 0 + ldy #$01 for indirect access. + lda (idxl),y + sta ZP.DstPtr + iny + lda (idxl),y + sta ZP.DstPtr+1 + iny + lda (idxl),y also the length (byte count) + sta cnt of the destination area. + iny + lda (idxl),y + sta cnt+1 + bmi rlerr branch if >= 32k. + txa is it a request to zero destination? + beq zero if yes. + iny + lda (idxl),y get source address. + sta src used for move. + sta cde used for relocation + iny + clc + adc cnt add length to get final address + sta ecde + lda (idxl),y + sta src+1 + sta cde+1 + adc cnt+1 + sta ecde+1 + dex test for 'move' command + beq H2AA3 branch if move only (no relocation) + stx wsize save element size (1,2,3) + iny + lda (idxl),y get # of ranges that are valid + sta sgcnt relocation target addresses. + tax separate serial range groups into tbls +H2A42 iny + lda (idxl),y transfer low limits to 'limlo' table + sta limlo,x + dex + bpl H2A42 + ldx sgcnt # of ranges +H2A4E iny + lda (idxl),y transfer high limits to 'limhi' table + sta limhi,x + dex + bpl H2A4E + ldx sgcnt # of ranges +H2A5A iny + lda (idxl),y transfer offsets to 'ofset' table + sta ofset,x + dex + bpl H2A5A + jsr adjtbl adj index pointer to next entry. + ldx wsize test for machine code relocation + cpx #$03 + beq rlcode branch if program relocation + jsr reladr otherwise, relocate addresses in +H2A70 jsr move tables then move to destination. + bra rloop do next table +rlend clc + rts +rlerr jmp tblerr +rlcode jsr rlprog relocate machine code refs + bra H2A70 + +* fill destination range with 0's + +zero jsr adjtbl adj table pointer to next entry. + lda #$00 + ldy cnt+1 is it at least 1 page? + beq H2A94 branch if not. + tay +H2A89 sta (ZP.DstPtr),y + iny + bne H2A89 + inc ZP.DstPtr+1 next page + dec cnt+1 + bne H2A89 if more pages to clear. +H2A94 ldy cnt any bytes left to 0? + beq H2AA0 if not. + tay +H2A99 sta (ZP.DstPtr),y zero out remainder + iny + cpy cnt + bcc H2A99 +H2AA0 jmp rloop +H2AA3 jsr adjtbl + bra H2A70 +adjtbl tya add previous table length to + sec get next entry position in table + adc idxl + sta idxl + bcc H2AB2 + inc idxl+1 +H2AB2 rts +move lda src+1 is move up, down or not at all? + cmp ZP.DstPtr+1 + bcc movup + bne movdn + lda src + cmp ZP.DstPtr + bcc movup + bne movdn + rts no move. +movup ldy cnt+1 calc highest page to move up + tya and adj src and ZP.DstPtr. + clc + adc src+1 + sta src+1 + tya + clc + adc ZP.DstPtr+1 + sta ZP.DstPtr+1 + ldy cnt move partial page 1st. + beq H2ADE taken if no partial pages +H2AD6 dey + lda (src),y + sta (ZP.DstPtr),y + tya end of page transfer? + bne H2AD6 no +H2ADE dec ZP.DstPtr+1 + dec src+1 + dec cnt+1 done with all pages? + bpl H2AD6 no + rts +movdn ldy #$00 + lda cnt+1 partial page move only? + beq H2AFC taken if < 1 page to move +H2AED lda (src),y + sta (ZP.DstPtr),y + iny + bne H2AED + inc ZP.DstPtr+1 next page + inc src+1 + dec cnt+1 more pages? + bne H2AED if more. +H2AFC lda cnt move partial page. + beq H2B09 if no more to move +H2B00 lda (src),y + sta (ZP.DstPtr),y + iny + cpy cnt + bne H2B00 +H2B09 rts + +* relocate addresses + +reladr ldy wsize 1 or 2 byte reference + dey + lda (cde),y + jsr adjadr relocate reference. + lda wsize update and test code pointer. + jsr adjcde + bcc reladr if more to do + rts +rlprog ldy #$00 get next opcode + lda (cde),y + jsr oplen determine if a 3 byte instruction. + beq rperr branch if not an opcode + cmp #$03 + bne H2B30 + ldy #$02 + jsr adjadr relocate address + lda #$03 +H2B30 jsr adjcde update and test if done. + bcc rlprog if more to do + rts +rperr pla + pla + ldx cde bad code address in y,x + ldy cde+1 + lda #$FF indicates bad opcode + sec + rts +tblerr ldx idxl bad table address in y,x + ldy idxl+1 + lda #$00 indicates input table error + sec + rts +adjadr lda (cde),y get page address and + ldx sgcnt test against limits. +H2B4D cmp limlo,x is it >= low? + bcc H2B59 if not. + cmp limhi,x is it <= high? + bcc H2B5D branch if it is + beq H2B5D +H2B59 dex try next limit set + bpl H2B4D + rts return w/o adjustment. +H2B5D clc add offset to form relocated + adc ofset,x page address and replace + sta (cde),y old address with result. + rts +adjcde clc update code pointer + adc cde + ldy cde+1 + bcc H2B6C branch if not page cross + iny otherwise, update page#. +H2B6C cpy ecde+1 has all code/data been processed? + bcc H2B72 if not. + cmp ecde +H2B72 sta cde save updated values. + sty cde+1 + rts return result (carry set = done). +oplen pha form index to tbl & which 2-bit group. + and #$03 low 2 bits specify group + tay + pla + lsr upper 6 bits specify byte in table + lsr + tax + lda opcodln,x +nxgroup dey is opcode len in lowest 2 bits of acc? + bmi H2B89 branch if it is + lsr shift to next group. + lsr (if length = 0 then error) + bne nxgroup +H2B89 and #$03 + rts if z-set then error + +* relocation table contains length of each opcode in 2-bit groups + +opcodln .HS 0928193C0A280D3C + .HS 0B2A193F0A280D3C + .HS 0928193F0A280D3C + .HS 0928193F0A280D3C + .HS 082A113F0A2A1D0C + .HS 2A2A193F0A2A1D3F + .HS 0A2A193F0A280D3C + .HS 0A2A193F0A280D3C + +wsize .HS 00 +sgcnt .HS 00 +limlo .HS 0000000000000000 +limhi .HS 0000000000000000 +ofset .HS 0000000000000000 + +* patch to gsos vectors so error is returned for os calls - rev note #101 + +patch101 .OP 65816 + php + sei disable interrupts + clc + xce full native mode + + phb save DBR + pha + pha + pea $0000 length of patch + pea $0010 0000/0010 = 16 bytes + pea $3101 user id for prodos 8 + pea $8018 attributes (locked/nospec/nocross) + pha + pha + >IIGS NewHandle + lda $01,s retrieve handle + tax + lda $03,s + tay + pea $0000 copy the code into the handle + pea L2C4D + phy + phx + pea $0000 length of patch = 0000/0010 + pea $0010 + _PtrToHand + plx low word of handle + plb set DBR to handle's bank + lda >1,x get upper 16 bits of 24 bit address + tay save in y + lda 0,x get low 8 bits of address + and #$00FF clear high byte + xba put address in high byte + ora #$005C include JML opcode + sta >GSOS2 store in gsos vectors + clc + adc #$000B + sta >GSOS + tya store upper 16 bits too + sta >GSOS2+2 + adc #$0000 adj for possible page crossing + sta >GSOS+2 + plb remove garbage byte from stack + plb restore DBR. + sec + xce back to emulation mode + plp + rts + +* copy of the code that goes in the handle + +L2C4D lda $01,s + sta $07,s + lda $02,s + sta $08,s + pla + pla + pla + lda #$00FF #NoOS + sec + rtl + + .BS $2C80-* +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.LDR.B +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.LDR.txt b/ProDOS.203/ProDOS.S.LDR.txt deleted file mode 100644 index 824e5fd6..00000000 --- a/ProDOS.203/ProDOS.S.LDR.txt +++ /dev/null @@ -1,1672 +0,0 @@ -NEW - AUTO 3,1 - .OP 65C02 - -H2000 jmp prostart - jmp atalkset appletalk setup for network boot - jmp p16start GQuit setup for gs/os - -LDR.MSG.AppleII .AS "Apple II" -LDR.MSG.ProDOS .AS "ProDOS 8 V2.0.3 " - .AS "06-May-93" -H202F .AS " " -H203B .AS "Copyright Apple Computer, Inc., 1983-93" -H2062 .AS "All Rights Reserved." - -p16start inc setuprts set = 2 for GQuit rts -atalkset inc setuprts set = 1 for appletalk rts -prostart lda unitnum - sta LDR.MLIONLINE.P+1 - jsr LDR.Splash - -* test for at least a 65c02 - - sed - lda #$99 a negative # - clc - adc #$01 +1 in decimal = 0 (positive) - cld - bmi m48k if 6502 because will not clear N flag - -* machine at least an m65c02 - - lda #$01 patch for the gs rom - trb statereg to force off intcxrom - ldx #H232B yx=232B location table - ldy /H232B - jsr reloc move interpreter loader to $800 - bcs m48k error - -* test for at least 64k - - ldy #$00 - lda #$FF - sta kversion at least 48k ? - eor kversion - sec - bne m48k if not. - - sta kversion try again to be sure - lda kversion - bne m48k still not. - - lda romin read ROM - jsr whchrom get preliminary system config - bcs m48k machine too small - lda idapple - and #$20 - bne m64k if at least 64k //+. -m48k jmp H22EB need enhanced IIe - -* we have 64k, now determine model: //e , iic, or Cortland (//gs) - -m64k ldx #H2367 yx=2367 relocation table - ldy /H2367 - jsr reloc - lda kversion - sta xdosver save current version for dir use - -H20CE bcc H20D3 - jmp relocerr - -H20D3 lda romin read ROM - ldx version ROM id byte - cpx #$06 - bne H211D then it's a //e - lda #$E0 - bit zidbyte another ROM id byte - php - lda idapple - and #$37 - plp - bvc set3 if //c or //x - bmi set7 if //e - -set3 php - ora #$08 - plp - bpl mach2 if //c - ora #$40 - bpl H20FD always taken. - -mach2 inc cflag //c or later - bvs H20FD -set7 ora #$80 - -H20FD sta idapple - lda romin read ROM - sec - jsr idroutine returns system info - bcs H211D branch if // family - inc cortland it's a Cortland, set loader flag - stz vmode force setvid to reset cursor - jsr setvid reset output to screen - lda setuprts - bne H211D branch if prodos 8 alone - -* running from gs/os shell so zero out os_boot for appletalk - - sta >OS_BOOT indicates O/S initially booted. - jsr patch101 patch for gs/os - rev note #101 - -* put dispatcher in bank 2 of language card - -H211D lda LDR.MLIONLINE.P+1 place boot devnum in globals - sta LDR.MLIREADBLOCK.P+1 - sta devnum last device used - jsr devsrch finish setting up globals - lda LDR.MLIREADBLOCK.P+1 - sta devnum - jsr lc1in switch in language card bank 1. - ldx #rlclk64 set up clock - ldy /rlclk64 - jsr reloc - -H2139 bcs H20CE - lda #calldisp - sta jspare+1 P8 system death vector - lda /calldisp - sta jspare+2 - lda altram read/write RAM bank 2 - lda altram - ldx #altdsptbl GQuit dispatcher - ldy /altdsptbl - lda setuprts - cmp #$02 is this a GQuit setup? - beq H216E taken to use GQuit dispatcher. - ldx #newquitbl else, use Bird's Better Bye - ldy /newquitbl if correct machine. - lda machid machine ID byte - bit #$00 //c ? - bne H216E if yes, can use. - and #$C2 - cmp #$82 //e with 80 col card ? - beq H216E if yes, can use. - ldx #dsp64 else, use original quit code - ldy /dsp64 - inc newquitflag using old quit code so set flag - -H216E jsr reloc - lda #$EE byte to distinguish LC bank 2 - sta $D000 - jsr lc1in switch in LC bank 1 - bcs H2139 - -* test for 128k needed to install ram disk - - lda machid machine ID byte - and #$30 - eor #$30 - bne noramdsk if < 128k - ldx #$FF - php save interrupt status - pla in acc. - sei no interrupts. - sta setaltzp use alt zero page/stack - stx auxsp init aux sp to $FF - sta setstdzp use main zero page/stack - pha restore interrupt status - plp - sta int3rom enable internal slot 3 ROM - jsr H2C80 install ram disk - -* check interrupt vector to determine ROM version - -noramdsk lda romin1 read ROM/write RAM bank 2 - ldy irqv interrupt vector - ldx irqv+1 x = high byte - jsr lc1in set language card bank 1 to r/w - cpx #$D0 is it > $D000 (old roms) - lda #$00 - bcs H21C5 branch if old roms - sta setaltzp use alt zero page/stack - lda #$FF set aux sp = $FF - sta auxsp - stx irqv+1 interrupt vector - sty irqv save irq vector in aux lc - sta setstdzp use main zero page/stack - stx irqv+1 save irq vector in main lc - sty irqv - lda #$01 - -H21C5 sta irqflag 1 = new roms - stz cortflag assume not Cortland system - lda cortland running on a Cortland ? - beq H21D5 branch if not. - inc cortflag yes it's Cortland - bra docard - -* check for a rom in slot 3. if no rom, use internal $C300 firmware - -H21D5 sta int3rom enable internal slot 3 ROM - lda rommap slot ROM bit map - and #$08 mask all but slot 3 - bne isromin3 taken if rom in slot 3 - bra H2247 else continue booting - -* found a rom in slot 3. is it an external, identifiable 80 col card -* with interrupt routines? if so, enable it else use internal $C300 firmware. - -isromin3 sta slot3rom enable slot 3 rom - lda slot3id1 check card id bytes - cmp #$38 - bne hitswtch not terminal card - lda slot3id2 - cmp #$18 - bne hitswtch - lda slot3id3 - cmp #$01 - bne hitswtch - lda ext80col is it an apple 80 col compatible card? - and #$F0 - cmp #$80 - bne hitswtch if not. - lda machid machine ID byte - and #$C8 - cmp #$C0 is it a //+ ? - beq docard yes - lda slot3irq - cmp #$2C does card have an interrupt handler? - beq docard yes - -hitswtch sta int3rom enable internal $C300 firmware - -* verify that the card in aux slot is actually present - - sta store80on enable 80-col store - sta txtpage2 switch in text page 2 - lda #$EE - sta txtp2 - asl - asl txtp2 - cmp txtp2 - bne H2230 - lsr a - lsr txtp2 - cmp txtp2 - -H2230 sta txtpage1 main memory - sta store80off disable 80-col store - beq docard branch if card is there - lda machid machine ID byte - and #$FD clear 80-col bit 2 (no card) - bne H2244 always - -docard lda machid - ora #$02 turn bit 2 on (80-col card is present) - -H2244 sta machid -H2247 lda cortland are we running on a //gs ? - beq H225D if not. - lda #$4C enable clock routine by putting a jmp - sta clockv in front of clock vector - ldx #cortclock yx = relocation table - ldy /cortclock for cortland clock driver - jsr reloc - lda #$01 set bit 0 = clock present - tsb machid - -H225D lda setuprts get setup entry point flag - beq H2267 taken if normal boot. - lda romin read ROM - rts return to caller at setup entry point. - -setuprts .DA #$00 0 = normal boot, <>0 = return - -* set prefix to boot device - -H2267 jsr MLI online - .DA #MLIONLINE - .DA LDR.MLIONLINE.P - bcs relocerr - - lda PrefixBuf+1 get volume name length. - and #$0F strip devnum - beq relocerr - - inc add 1 for leading '/' - sta PrefixBuf save prefix length. - lda #'/' place leading '/' in prefix buffer - sta PrefixBuf+1 - - jsr MLI set prefix - .DA #MLISETPREFIX - .DA LDR.MLISETPREFIX.P - bcs relocerr - - tax =0 - stx ZP.DstPtr - ldy #$02 read directory into buffer - lda /DirBlkBuf - -H228E sta ZP.DstPtr+1 - sta LDR.MLIREADBLOCK.P+4 - sty LDR.MLIREADBLOCK.P+5 - stx LDR.MLIREADBLOCK.P+6 - - jsr MLI read block - .DA MLIREADBLOCK - .DA LDR.MLIREADBLOCK.P - bcs relocerr - - ldy #$03 get next block# from link - lda (ZP.DstPtr),y - tax - dey - ora (ZP.DstPtr),y if both bytes are the same - beq H22B7 then no more blocks of directory. - lda (ZP.DstPtr),y - tay - lda ZP.DstPtr+1 - clc - adc #$02 add $200 to buffer pointer - cmp #>dbuf+$800 until it points past end of buffer. - bcc H228E if ok, read next block. - -H22B7 jmp lodintrp jmp to 'licode' (load interpreter) - -* relocation/configuration error - -relocerr sta romin read ROM - jsr home - - ldy #$1D - -.1 lda LDR.MSG.LdrErr,y - sta vline12+4,y - dey - bpl .1 - - bmi * - -LDR.MSG.LdrErr .AS "Relocation/Configuration Error" - - ldy #$23 - -.1 lda LDR.MSG.EnhErr,y - sta vline14+2,y - dey - bpl .1 - - bmi * - -LDR.MSG.EnhErr .AS "REQUIRES ENHANCED APPLE IIE OR LATER" - -LDR.MLIONLINE.P .DA #2 - .DA #$60 - .DA PrefixBuf+1 - -LDR.MLISETPREFIX.P - .DA #1 - .DA PrefixBuf - -LDR.MLIREADBLOCK.P - .DA #3 - .DA #0 unit number - .DA 0 2 byte data buffer - .DA 0 2 byte block number - -cortland .BS 1 cortland loader flag (1 = Cortland) -newquitflag .BS 1 1 = old quit code - -H232B .DA #1 move interpreter loader code - .DA lodintrp destination address - .DA H257B-licode' length to move - .DA licode' source address - .DA #$01' move $3F0 vectors - .DA p3vect' destination - .DA $0010' 16 bytes to move - .DA H257B' source - .DA #$01' - .DA lookptr' - .DA $0002' - .DA ZP.DstPtr' - .DA #$01' move 128k test to zero page - .DA tst128' destination - .DA H2622-H25DC' length - .DA H25DC' source - .DA #FF' done - -dsp64 .DA #$01' move p8 dispatcher code - .DA displc2' destination - .DA birdbye-disp1obj' length (must be <= 3 pages) - .DA disp1obj' source - .DA #FF' done - -newquitbl dc i1'$01' move Bird's Bye code - .DA displc2' dest - .DA GQdisp-birdbye' length (must be <= 3 pages) - .DA birdbye' source - .DA #FF' done - -altdsptbl .DA #$01' move GQuit launcher - .DA displc2 destination - .DA $0300' length (must be <= 3 pages) - .DA GQdisp' source - .DA #$01' move a copy of GQuit launcher - .DA dispadr' to dispadr for gsos - .DA $0300' length (must be <= 3 pages) - .DA GQdisp' source - .DA #FF' done - -* tables for moving 64k version of mli for execution - -H2367 .DA #$01' relocation table. 1=move src to ZP.DstPtr - .DA lanirq' destination - .DA H2E00-H2D9B' length to move - .DA H2D9B' source - .DA #$01' - .DA MLI' globals - .DA $0100' in one page - .DA H2E00' - .HS 00 0=clear buffers $D700-$DDFF - .DA pathbuf - .DA xdosorg-pathbuf' - .DA #$01' - .DA xdosorg' - .DA ramsrc-xdosobj' length of mli - .DA xdosobj' - .DA #$01' - .DA rwts' - .DA disp1obj-blockio' length of disk ii driver - .DA blockio' - .DA #FF' done - -* move thunderclock - -rlclk64 .DA #$01' relocation table. 1=move src to ZP.DstPtr - .DA tclk_in' destination - .DA tclk_end-tclock_0' length of thunderclock driver - .DA tclock_0' source - .DA #$04' 4=relocate and move program - .DA tclk_in' - .DA H2F69-tclock_0' - .DA tclk_in' - .HS 00 - dc h'C1C1' -clock64 .DA #$00' - .DA #FF' done - -* move cortland clock - -cortclock dc i1'$01' relocation table. 1=move src to ZP.DstPtr - .DA tclk_in' destination - .DA cclk_end-cclock_0' length of cortland clock driver - .DA cclock_0' source - .DA #FF' done - -* load and run appletalk configuration file (atinit) if present -* or continue loading and running .system file - -* loader origin $800 - -ofsL .EQ licode-lodintrp offset from loader org - -licode jsr MLI check for file 'atinit' - .DA #MLIGETFILEINFO - .DA #gfi_list' - bcc gfi_ok branch if 'atinit' file found - cmp #$46 file not found? - beq H23DF if so, continue loading interpreter - bne H23E2 -gfi_ok lda gfi_type - cmp #$E2 is 'atinit' correct file type? - bne H23E2 error - wrong file type - jsr MLI open 'atinit' file - .DA #$C8' - .DA atopen' parms - bne H23E2 error - lda #$9F max size = 39.75k ($2000-$BF00) - sta rdlen+1 - stz rdlen - jsr MLI read 'atinit' file to 'sysentry' - .DA #$CA' - .DA rdparm' - bne H23E2 error - too big - jsr MLI close 'atinit' file - .DA #$CC' - .DA clparm' - bne H23E2 error - lda romin enable ROM - jsr sysentry execute ATinit -H23DF jmp goloadint execute .system file - -* fatal error - -H23E2 ldx H23F0 -H23E5 lda H23F0,x - sta vline16,x - dex - bne H23E5 - beq * - -H23F0 .DA #$1A length of message - .AS "Unable to load ATInit file" - -gfi_list .EQ *-ofsL - .DA #0A' - .DA atinitname' - .HS 00 -gfi_type .EQ *-ofsL - dc h'00000000' - .DA #0000000000000000' - .HS 0000 -atopen .EQ *-ofsL parms to open 'atinit' - dc h'03' - .DA atinitname' - .DA iobuf' i/o buffer - dc h'01' ref# hard coded since no other files -atinitname .EQ *-ofsL - .DA #06' length of name - dc c'atinit' name of appletalk config file -goloadint .EQ *-ofsL - lda #>dbuf search directory buffer - sta idxl+1 - lda #$04 start 1 entry past header - bne H2434 always. -H2432 lda idxl calc next entry position -H2434 clc - adc dbuf+35 inc to next entry address - sta idxl - bcs H2451 branch if page cross. - adc dbuf+35 test for end of block. - bcc H2453 branch if not page cross - lda idxl+1 - lsr a end of block? - bcc H2453 no. - cmp #$09 end of directory? - bne H244D no. - jmp nointrp no interpreter, go quit. -H244D lda #$04 reset index to 1st entry in next block. - sta idxl -H2451 inc idxl+1 inc to next page. -H2453 ldy #$10 check file type. - lda #$FF must be a prodos sys file - eor (idxl),y - bne H2432 if not sys. - tay see if active - lda (idxl),y - beq H2432 if deleted file. - and #$0F strip file 'kind'. - sta PrefixBuf save length of name. - cmp #$08 must be at least 'x.system' - bcc H2432 else, ignore it. - tay compare last 7 chars for '.system' - ldx #$06 -H246C lda (idxl),y - eor iterp,x - asl - bne H2432 branch if something else - dey - dex - bpl H246C - ldy #$00 -H247A iny - lda (idxl),y - sta PrefixBuf,y - ora #$80 msb on so can be displayed if error - sta iomess+$11,y - cpy PrefixBuf - bne H247A - lda #$A0 space after name - sta iomess+$12,y - tya error message length - adc #$13 (carry set) - sta ierlen - jsr MLI open interpreter file - .DA #$C8' - .DA opparm' - bne badlod - jsr MLI get eof (length of file) - .DA #$D1' - .DA efparm' - bne badlod - lda eof+2 - bne toolong - lda eof+1 - cmp #$9F max size = 39.75k ($2000-$BF00) - bcs toolong - sta rdlen+1 - lda eof - sta rdlen (read entire file) - jsr MLI read interpreter file - .DA #$CA' - .DA rdparm' - beq H24C8 go close if successfully read. - cmp #$56 memory conflict? - beq toolong then too large - bne badlod else, unable to load. -H24C8 jsr MLI close interpreter file - .DA #$CC' - .DA clparm' - bne badlod hopefully never taken - -* if booting on a //c then see if esc is in keyboard buffer -* and clear it. it may have been pressed to shift speed -* of accelerator chip - - lda cflag - beq H24DF taken if not booting on a //c - lda kbd else, check for keypress - cmp #$9B escape? - bne H24DF if not. - sta kbdstrobe clear keyboard -H24DF lda romin enable ROM - jmp sysentry go run interpreter -cflag .EQ *-ofsL - .HS 00 set if a //c. -nointrp .EQ *-ofsL no interpreter found, - jsr MLI so quit. - .DA #$65' - .DA quitparm' -badlod ldy ierlen center the error message - lda #$27 - sec - sbc ierlen - lsr a - adc ierlen - tax -H24FA lda iomess,y - sta vline16,x - dex - dey - bpl H24FA - bmi H2511 -toolong ldy #$1E -H2508 lda lgmess,y - sta vline16+5,y - dey - bpl H2508 -H2511 bmi H2511 -lgmess .EQ *-ofsL - dc c'** System program too large **' -iomess .EQ *-ofsL - dc c'** Unable to load' - dc c' X.System *********' -ierlen .EQ *-ofsL - .HS 00 -opparm .EQ *-ofsL parms for open call - dc h'03' - .DA PrefixBuf' - .DA iobuf' - dc h'01' -efparm .EQ *-ofsL parms for get eof call - dc h'02' - .DA #01' -eof .EQ *-ofsL - dc h'000000' length of file. -rdparm .EQ *-ofsL parms for read call - dc h'04' - dc h'01' - .DA sysentry' -rdlen .EQ *-ofsL - .HS 0000 - .HS 0000 -clparm .EQ *-ofsL parms for close call - dc h'01' - .HS 00 -quitparm .EQ *-ofsL parms for quit call - dc h'04' - .HS 00 - .HS 0000 - .HS 00 - .HS 0000 -iterp .EQ *-ofsL interpreter suffix that is required - dc c'.SYSTEM' - -* 16 bytes moved to $03F0 vectors - -H257B dc i2'breakv' - .DA oldrst' - .DA #5A' powerup byte - jmp oldrst '&' vector - jmp oldrst ctrl-y vector - .DA #004000' - .DA irqent' global page interrupt vector -lc1in lda ramin read/write language card RAM bank 1 - lda ramin - rts - -* determine which system model and save in machine id (idapple) - -whchrom stz idapple assume standard apple // - ldx version check hardware id - cpx #$38 is it apple // (autostart rom)? - beq H25BE if yes - lda #$80 - cpx #$06 apple //e? - beq H25BC if yes - lda #$40 - cpx #$EA apple //+? - bne H25B6 it not, then machine is unknown. - ldx HFB1E apple /// in emulation? - cpx #$AD - beq H25BC taken if apple //+. - lda #$D0 test again for apple /// emulation - cpx #$8A because will only have 48k memory. - bne H25B6 if taken, then machine is unknown. -H25B4 sec apple /// emulation is not allowed - rts because insufficient memory. -H25B6 lda #$02 machine unknown - sta (ZP.DstPtr),y - bne H25D9 always. -H25BC sta idapple save machine id - -* check for language card ram - -H25BE jsr lc1in switch in language card bank 1 - lda #$AA - sta $D000 - eor $D000 if LC present, result = 0. - bne H25B4 othewise, insufficient memory. - lsr $D000 check lc again - lda #$55 - eor $D000 - bne H25B4 not sufficent memory. - lda #$20 LC ram is available - ora idapple -H25D9 jmp tst128 jumps to page 0 routine below - -* test for 128k. use page 0 for this routine - -H25DC sta idapple H25DC-2621 was moved to location tst128 - bpl not128 if already determined < 128k - lda #$EE - sta wrcardram write to aux mem while on main zp - sta rdcardram and read aux mem. - sta dbuf write these locs just to test aux mem - sta lodintrp 1k apart from each other. - lda dbuf - cmp #$EE - bne noaux - asl dbuf may be sparse mem mapping so - asl change value and see what happens. - cmp dbuf - bne noaux branch if not sparse mapping. - cmp lodintrp - bne H2606 if not sparse. -noaux sec no aux memory available. - bcs H2607 -H2606 clc -H2607 sta wrmainram switch back to main memory - sta rdmainram - bcs not128 if < 128k - lda idapple - ora #$30 set id = 128k present - sta idapple -not128 lda lookptr+1 - sec - sbc #$05 - sta lookptr+1 - bcs H2620 - dec lookptr -H2620 clc - rts - -* prodos greeting splash screen - -LDR.Splash lda spkr click speaker - sta clr80vid disable 80 col hardware - sta store80off disable 80 col store - jsr setnorm set normal text mode - jsr init init text screen - jsr setvid reset output to screen - jsr setkbd reset input to keyboard - cld - jsr home - - ldx #$07 - -.1 lda H2009,x print title - sta vline10+16,x - dex - bpl .1 - - ldx #$1D - -.2 lda H2011,x - sta vline12+5,x - dex - bpl .2 - - ldx #$0B - -.3 lda H202F,x - sta vline14+14,x - dex - bpl .3 - - ldx #$26 - -.4 lda H203B,x - sta vline23,x - dex - bpl .4 - - ldx #$13 - -.5 lda H2062,x - sta vline24+10,x - dex - bpl .5 - - sec - jsr idroutine returns system info - bcs .8 taken if not a //gs - - lda #$80 - trb newvideo video mode select - -.8 lda spkr click speaker - rts - -* find all disk devices in system slots and set up address -* and device table in prodos global page. if there is a disk -* card in slot 2 then limit the # of devices in slot 5 -* smartport to only 2 - -numdev2 .HS 0000000000000000 8 bytes for smartport call -driveradr .DA 0 -d2idx .DA #0 -diskins2 .DA #0 msb clear if drive in slot 2 - -devsrch stz ZP.DstPtr - stz ZP.DstPtr+1 - stz idxl - ldx #$FF init to no active devices. - stx numdevs count (-1) active devices. - lda #$0E start disk // area at end of devlist. - sta d2idx - -* check slot 2. if there is a disk card then clear the msb of diskins2. this -* will limit the # of devices in any slot 5 spartport card to 2. - - lda #$C2 - sta idxl+1 check slot 2 - jsr cmpid is there a disk in slot 2 ? - ror diskins2 if so, clear msb else set it. - lda #$C7 search slots from high to low - sta idxl+1 - -H26AB jsr cmpid - bcs H270C if no ProDOS device in this slot. - lda (idxl),y check last byte of $Cn rom (y = $ff) - beq diskii branch if 16 sector disk II. - cmp #$FF if = $FF then 13 sector disk II. - bcs H270C ignore if 13 sector boot ROM - sta driveradr else assume it's an intelligent disk. - ldy #$07 check for a smartport device. - lda (idxl),y - bne H26C4 no smartport - jmp smartprt -H26C4 ldy #$FE - lda (idxl),y get attributes. - and #$03 verify it provides read and status calls. - cmp #$03 - sec assume it's an off-brand disk - bne H270C - jsr setdevid set up the devid byte from attributes - clc - php remember that it's not a disk //. - lsr a move # of units (0=1, 1=2) to carry. - lda idxl+1 store hi entry addr (low already done) - bne H26E6 branch always. -diskii sta devid =0 since disk ii's have null attributes - sec - php remember it's a disk // - lda H2802 - sta driveradr - lda H2802+1 -H26E6 sta driveradr+1 - jsr installdev install 1 or 2 devices from this slot. - plp get back if it's a disk // (carry). - bcc nxtdsk2 if not disk //. - dex move the list pointer back by 2 devices - dex - stx numdevs count (-1) active devices - dec d2idx increase the disk two index - dec d2idx - ldy d2idx - inx adj since device count starts with $FF. - lda devlist+1,x get entries for disk // - sta devlist,y move then toward the end of the list - lda devlist,x - sta devlist+1,y - dex back to numdevs again -nxtdsk2 clc -H270C jsr sltrom test for ROM in given slot and set flags - dec idxl+1 next lower slot. - lda idxl+1 - and #$07 have all slots been checked ? - bne H26AB no. - -* perform the new device search, mapping unmounted smartport devices -* to empty slots in the device table. - - jsr newmount - -* now copy the disk // list to the end of the regular list. -* start by making the device count include disk //'s - - ldx numdevs current device count - 1 - lda #$0E - sec - sbc d2idx - beq H2747 if there were no disk //'s then done. - clc - adc numdevs sum of disk //'s and others. - sta numdevs - inx move to open space in regular list. - ldy #$0D first disk // entry. -H272F lda devlist,y - pha - lda devlist,x - sta devlist,y - pla - sta devlist,x - inx - dey - sty d2idx use as a temp - cpx d2idx - bcc H272F continue until indexes cross -H2747 ldy #$00 - ldx numdevs now change the device order so that -H274C lda devlist,x the boot device will have highest - pha priority. - and #$7F strip off high bit - eor devnum for comparison. - asl - bne H275A - pla - iny -H275A dex - bpl H274C - ldx numdevs now reverse order of search, hi to lo. - tya was boot device found ? - beq H2777 - lda devnum make boot device 1st in search order. - sta devlist,x - dex - bmi H277E branch if only one device. - dey is this a 2 drive device ? - beq H2777 branch if not. - eor #$80 make boot device, drive 2 next. - sta devlist,x - dex - bmi H277E branch if only 1 device, 2 drives. -H2777 pla - sta devlist,x - dex - bpl H2777 -H277E jsr fndtrd save accumulated machine id. - beq H2787 - sta machid machine ID byte - rts -H2787 jmp H25B6 -stadrv ora devid combine with attributes. - ldx numdevs - inx put device # into device list. - sta devlist,x - asl now form drive 2 device number, if any. - rts -sltrom bcc H27F3 branch if disk drive - -* test for clock card - - ldy #$06 -H2799 lda (idxl),y - cmp dskid,y - bne H27BA no clock - dey - dey - bpl H2799 - lda idxl+1 transfer hi slot address - sbc #$C1 minus $C1 (default) to relocate - sta clock64 references to clock rom. - lda #$4C enable jump vector in globals. - sta clockv P8 clock vector. - lda idapple mark clock as present. - beq H277E - ora #$01 - sta idapple xxxxxxx1 = clock present. - bne H27F3 always taken. - -* test for 80 col card - -H27BA ldy #$05 - lda (idxl),y - cmp #$38 - bne H27E4 - ldy #$07 - lda (idxl),y - cmp #$18 - bne H27E4 - ldy #$0B - lda (idxl),y - dec a must = 1 - bne H27E4 - iny - lda (idxl),y - and #$F0 mask off low nibble. - cmp #$80 generic for 80-col card. - bne H27E4 - lda idapple - beq H277E - ora #$02 - sta idapple xxxxxx1x = 80 col card. - bne H27F3 always taken. - -* test for any other rom - -H27E4 ldx #$00 - lda (idxl) - cmp #$FF apple /// non-slot? - beq H2801 invalid rom -H27EC cmp (idxl) look for floating bus - bne H2801 no rom - inx - bne H27EC -H27F3 lda idxl+1 mark a bit in slot byte - and #$07 to indicate rom present. - tax - lda sltbit,x - ora rommap mark bit to flag rom present - sta rommap slot ROM bit map -H2801 rts - -H2802 .DA rwts disk ii driver - -* id bytes: evens for clock, odds for disk - -dskid .HS 082028005803703C - -* slot bits - -sltbit .HS 0002040810204080 - -fndtrd clc - ldy sltbit -H2818 lda (lookptr),y - and #$DF - adc sltbit - sta sltbit - rol sltbit - iny - cpy sltbit+3 - bne H2818 - tya - asl - asl - asl - asl - tay - eor sltbit - adc #$0B - bne H283B - lda idapple - rts - -H283B lda #$00 - rts - -installdev php how many drives (carry). - lda idxl+1 get index to global device table - and #$07 for this slot... - asl - tay into y reg. - asl - asl now form device # = slot # - asl in high nibble. - jsr stadrv OR in low nibble, store in dev list. - plp restore # of devices in carry. - ror a if 2 drives, then bit 7=1. - bpl H2853 branch if a 1 drive device (e.g. hard drive) - inx else presume that 2nd drive is present. - sta devlist,x active device list. - -H2853 stx numdevs save updated device count. - asl shift # of drives back into carry. - lda driveradr get high address of device driver. - sta drivertbl1,y device driver table 1. - bcc H2862 branch if single drive. - sta drivertbl2,y device driver table 2. - -H2862 lda driveradr+1 - sta drivertbl1+1,y - bcc H286D - sta drivertbl2+1,y - -H286D rts - -* query smartport status to determine # of devices -* and install up to 4 units in table if card is in slot 5 -* otherwise only 2 units. this includes a patch #74 - -smartprt jsr setdevid setup the devid byte from attributes - lda idxl+1 - sta driveradr+1 - lda driveradr - sta pscall+1 modify operand - clc - adc #$03 - sta spvect+1 - lda driveradr+1 - sta spvect+2 - sta pscall+2 modify operand - asl convert $Cn to $n0 - asl - asl - asl - sta unitnum unit number - stz A4L force a prodos status call - stz buf dummy pointer - stz bloknml # of bytes to transfer - stz bloknml+1 - lda #$10 - sta buf+1 dummy pointer should be <> 0 - -* do a prodos status call patched in from above - -pscall jsr $0000 self modifying code - ldy #$FB - lda (idxl),y check device id - and #$02 SCSI? - beq H28B1 no, no need to init Cocoon - sta statunit device = 2 for SCSI - -* initialize SCSI Cocoon to build internal device tables -* and report true # of devices attached - - jsr spvect status of Cocoon - .HS 00 - .DA spcparms' ignore any errors. -H28B1 stz statunit set unit# = 0 - jsr spvect call to get the device count. - .HS 00 this is a status call - .DA spcparms' - lda numdev2 - beq donesp no devices, so done. - cmp #$02 carry set if 2,3,4 - jsr installdev do the 1st and 2nd device if exists. - lda idxl+1 - cmp #$C5 - bne donesp if not slot 5 - -* for slot 5, if there is a disk card in slot 2 -* then only install 2 devices otherwise map -* extra devices as slot 2 - - bit diskins2 disk in slot 2 ? - bpl donesp yes - so done - lda numdev2 - cmp #$03 carry set if 3,4,... - bcc donesp - cmp #$04 carry set if 4,5,6,... - lda #$C2 map extra devices as slot 2 - sta idxl+1 - jsr installdev - lda #$C5 - sta idxl+1 -donesp jmp nxtdsk2 it's a disk device. -setdevid ldy #$FE check attributes byte. -H28E8 lda (idxl),y - lsr a move hi nibble to lo nibble for - lsr a device table entries. - lsr a - lsr a - sta devid - rts - -* check unknown card to see if disk id = $Cn00:nn 20 nn 00 nn 03 - -cmpid lda clrrom switch out $C8 ROMs - ldy #$05 -H28F6 lda (idxl),y compare id bytes - cmp dskid,y - sec set if no disk card - bne H2903 - dey - dey - bpl H28F6 loop until all 4 id bytes match. - clc clear if disk card -H2903 rts - -* smartport call parameters - -spcparms .DA #$03 # of parms -statunit .DA #$00 unit number (code for smartport stat) - .DA numdev2 - .DA #00 status code (0 = general status) - -* indexes into driver table - -driveridx .DA #$06 s3, d1 - .DA #$1E s7, d2 - .DA #$0E s7, d1 - .DA #$1C s6, d2 - .DA #$0C s6, d1 - .DA #$1A s5, d2 - .DA #$0A s5, d1 - .DA #$14 s2, d2 - .DA #$04 s2, d1 - .DA #$12 s1, d2 - .DA #$02 s1, d1 - .DA #$18 s4, d2 - .DA #$08 s4, d1 - -* self modifying jmp = smartport entry address - -spvect jmp $0000 self modifying -newmount stz idxl - lda #$C7 start with slot 7 ($C700) - sta idxl+1 -H291F jsr H29EB is there a smartport device here? - bcs H2974 no, next device. - ldy #$FF get smartport address. - lda (idxl),y - clc - adc #$03 add 3 for smartport call - sta spvect+1 - lda idxl+1 - sta spvect+2 - dey - jsr H28E8 set up device attributes - stz statunit - jsr spvect do a status call on smartport itself - .HS 00 - .DA spcparms' - lda numdev2 # of devices on smartport - cmp #$03 - bcc H2974 only 2 devices,skip to next one. - inc add 1 for comparisons. - sta driveradr # of devices + 1. - lda #$03 start at unit #3 (non-slot 5) - ldx spvect+2 - cpx #$C5 is this slot 5? - bne H295B no, start at 3. - bit diskins2 disk controller in slot 2? - bpl H295B yes, so allow remapping of s5 devices - lda #$05 else start looking at unit #5 - -* find block devices on this smartport - -H295B cmp driveradr have we done all units in this slot? - bcs H2974 yes, skip to next slot. - sta statunit store the unit#. - jsr spvect do status call - .HS 00 - .DA spcparms' - lda numdev2 is this a block device? - bmi mount yes, so mount it. -H296E lda statunit go check the next unit# - inc - bra H295B -H2974 dec idxl+1 - lda idxl+1 - cmp #$C0 searched down to slot 0? - bne H291F if not. - rts -mount ldx #$0C -H297F ldy driveridx,x - lda drivertbl1,y device driver table 1 - cmp #nodevice - bne H2990 - lda drivertbl1+1,y - cmp /nodevice - beq H2994 -H2990 dex - bpl H297F - rts ran out of space for devices, exit. - -* empty slot found - -H2994 lda idxl+1 - pha - phx - phy - tya which slot is empty? - lsr a shift into slot# - and #$07 now 1-7 - ora #$C0 now $C1-$C7 - sta idxl+1 - jsr H29EB smartport interface in this slot? - ply - plx - pla - sta idxl+1 - bcc H2990 yes, can't use to mirror the device. - jsr lc1in write enable LC ram bank 1. - tya divide index by 2 - lsr a - tax - lda statunit - sta spunit-1,x store the smartport unit # - lda spvect+1 and entry address. - sta spvectlo-1,x - lda spvect+2 - sta spvecthi-1,x - lda romin write protect lc ram. - inc numdevs - ldx numdevs - tya - lsr a - cmp #$08 - bcc nodev2 drive 2 mount - sbc #$08 - ora #$08 -nodev2 asl - asl - asl - asl - ora devid include device attributes - sta devlist,x in the active device list. - lda #remap_sp - sta drivertbl1+1,y - bra H296E -H29EB jsr cmpid is it a disk controller? - bcs H29F8 no, so return. - sec assume no smartport - ldy #$07 - lda (idxl),y is it a smartport? - bne H29F8 if not. - clc smartport found -H29F8 rts - -* relocation subroutine. on entry, regs yx = address of parameter table -* with the following parameters: -* -* (1) command: 0 = zero destination range -* 1 = move data from src to ZP.DstPtr -* 2 = hi addr ref tbl, relocate and move -* 3 = lo/hi addr ref tbl, relocate and move -* 4 = program, relocate and move -* >4 = end of sequence of commands -* (2) destination -* (2) length -* (2) source -* (1) # of address ranges (n) to be relocated -* (n+1) list of low page addresses to be relocated -* (n+1) list of high page addresses to be relocated -* (n+1) list of offset amounts to be added to be added -* if low and high limits have not been met -* -* on exit, carry set if error and yx = addr of error -* with acc = $00 for table error or $FF if illegal opcode - -reloc stx idxl save address of control table - sty idxl+1 -rloop lda (idxl) get relocation command. - cmp #$05 - bcs rlend taken if >= 5 then done. - tax move destination to page 0 - ldy #$01 for indirect access. - lda (idxl),y - sta ZP.DstPtr - iny - lda (idxl),y - sta ZP.DstPtr+1 - iny - lda (idxl),y also the length (byte count) - sta cnt of the destination area. - iny - lda (idxl),y - sta cnt+1 - bmi rlerr branch if >= 32k. - txa is it a request to zero destination? - beq zero if yes. - iny - lda (idxl),y get source address. - sta src used for move. - sta cde used for relocation - iny - clc - adc cnt add length to get final address - sta ecde - lda (idxl),y - sta src+1 - sta cde+1 - adc cnt+1 - sta ecde+1 - dex test for 'move' command - beq H2AA3 branch if move only (no relocation) - stx wsize save element size (1,2,3) - iny - lda (idxl),y get # of ranges that are valid - sta sgcnt relocation target addresses. - tax separate serial range groups into tbls -H2A42 iny - lda (idxl),y transfer low limits to 'limlo' table - sta limlo,x - dex - bpl H2A42 - ldx sgcnt # of ranges -H2A4E iny - lda (idxl),y transfer high limits to 'limhi' table - sta limhi,x - dex - bpl H2A4E - ldx sgcnt # of ranges -H2A5A iny - lda (idxl),y transfer offsets to 'ofset' table - sta ofset,x - dex - bpl H2A5A - jsr adjtbl adj index pointer to next entry. - ldx wsize test for machine code relocation - cpx #$03 - beq rlcode branch if program relocation - jsr reladr otherwise, relocate addresses in -H2A70 jsr move tables then move to destination. - bra rloop do next table -rlend clc - rts -rlerr jmp tblerr -rlcode jsr rlprog relocate machine code refs - bra H2A70 - -* fill destination range with 0's - -zero jsr adjtbl adj table pointer to next entry. - lda #$00 - ldy cnt+1 is it at least 1 page? - beq H2A94 branch if not. - tay -H2A89 sta (ZP.DstPtr),y - iny - bne H2A89 - inc ZP.DstPtr+1 next page - dec cnt+1 - bne H2A89 if more pages to clear. -H2A94 ldy cnt any bytes left to 0? - beq H2AA0 if not. - tay -H2A99 sta (ZP.DstPtr),y zero out remainder - iny - cpy cnt - bcc H2A99 -H2AA0 jmp rloop -H2AA3 jsr adjtbl - bra H2A70 -adjtbl tya add previous table length to - sec get next entry position in table - adc idxl - sta idxl - bcc H2AB2 - inc idxl+1 -H2AB2 rts -move lda src+1 is move up, down or not at all? - cmp ZP.DstPtr+1 - bcc movup - bne movdn - lda src - cmp ZP.DstPtr - bcc movup - bne movdn - rts no move. -movup ldy cnt+1 calc highest page to move up - tya and adj src and ZP.DstPtr. - clc - adc src+1 - sta src+1 - tya - clc - adc ZP.DstPtr+1 - sta ZP.DstPtr+1 - ldy cnt move partial page 1st. - beq H2ADE taken if no partial pages -H2AD6 dey - lda (src),y - sta (ZP.DstPtr),y - tya end of page transfer? - bne H2AD6 no -H2ADE dec ZP.DstPtr+1 - dec src+1 - dec cnt+1 done with all pages? - bpl H2AD6 no - rts -movdn ldy #$00 - lda cnt+1 partial page move only? - beq H2AFC taken if < 1 page to move -H2AED lda (src),y - sta (ZP.DstPtr),y - iny - bne H2AED - inc ZP.DstPtr+1 next page - inc src+1 - dec cnt+1 more pages? - bne H2AED if more. -H2AFC lda cnt move partial page. - beq H2B09 if no more to move -H2B00 lda (src),y - sta (ZP.DstPtr),y - iny - cpy cnt - bne H2B00 -H2B09 rts - -* relocate addresses - -reladr ldy wsize 1 or 2 byte reference - dey - lda (cde),y - jsr adjadr relocate reference. - lda wsize update and test code pointer. - jsr adjcde - bcc reladr if more to do - rts -rlprog ldy #$00 get next opcode - lda (cde),y - jsr oplen determine if a 3 byte instruction. - beq rperr branch if not an opcode - cmp #$03 - bne H2B30 - ldy #$02 - jsr adjadr relocate address - lda #$03 -H2B30 jsr adjcde update and test if done. - bcc rlprog if more to do - rts -rperr pla - pla - ldx cde bad code address in y,x - ldy cde+1 - lda #$FF indicates bad opcode - sec - rts -tblerr ldx idxl bad table address in y,x - ldy idxl+1 - lda #$00 indicates input table error - sec - rts -adjadr lda (cde),y get page address and - ldx sgcnt test against limits. -H2B4D cmp limlo,x is it >= low? - bcc H2B59 if not. - cmp limhi,x is it <= high? - bcc H2B5D branch if it is - beq H2B5D -H2B59 dex try next limit set - bpl H2B4D - rts return w/o adjustment. -H2B5D clc add offset to form relocated - adc ofset,x page address and replace - sta (cde),y old address with result. - rts -adjcde clc update code pointer - adc cde - ldy cde+1 - bcc H2B6C branch if not page cross - iny otherwise, update page#. -H2B6C cpy ecde+1 has all code/data been processed? - bcc H2B72 if not. - cmp ecde -H2B72 sta cde save updated values. - sty cde+1 - rts return result (carry set = done). -oplen pha form index to tbl & which 2-bit group. - and #$03 low 2 bits specify group - tay - pla - lsr a upper 6 bits specify byte in table - lsr a - tax - lda opcodln,x -nxgroup dey is opcode len in lowest 2 bits of acc? - bmi H2B89 branch if it is - lsr a shift to next group. - lsr a (if length = 0 then error) - bne nxgroup -H2B89 and #$03 - rts if z-set then error - -* relocation table contains length of each opcode in 2-bit groups - -opcodln .HS 0928193C0A280D3C - .HS 0B2A193F0A280D3C - .HS 0928193F0A280D3C - .HS 0928193F0A280D3C - .HS 082A113F0A2A1D0C - .HS 2A2A193F0A2A1D3F - .HS 0A2A193F0A280D3C - .HS 0A2A193F0A280D3C - -wsize .HS 00 -sgcnt .HS 00 -limlo .HS 0000000000000000 -limhi .HS 0000000000000000 -ofset .HS 0000000000000000 - -* patch to gsos vectors so error is returned for os calls - rev note #101 - -patch101 .OP 65816 - php - sei disable interrupts - clc - xce full native mode - - phb save DBR - pha - pha - pea $0000 length of patch - pea $0010 0000/0010 = 16 bytes - pea $3101 user id for prodos 8 - pea $8018 attributes (locked/nospec/nocross) - pha - pha - _NewHandle - lda $01,s retrieve handle - tax - lda $03,s - tay - pea $0000 copy the code into the handle - pea L2C4D - phy - phx - pea $0000 length of patch = 0000/0010 - pea $0010 - _PtrToHand - plx low word of handle - plb set DBR to handle's bank - lda |1,x get upper 16 bits of 24 bit address - tay save in y - lda |0,x get low 8 bits of address - and #$00FF clear high byte - xba put address in high byte - ora #$005C include JML opcode - sta >GSOS2 store in gsos vectors - clc - adc #$000B - sta >GSOS - tya store upper 16 bits too - sta >GSOS2+2 - adc #$0000 adj for possible page crossing - sta >GSOS+2 - plb remove garbage byte from stack - plb restore DBR. - sec - xce back to emulation mode - plp - rts - -* copy of the code that goes in the handle - -L2C4D lda $01,s - sta $07,s - lda $02,s - sta $08,s - pla - pla - pla - lda #$00FF #NoOS - sec - rtl - - .BS $2C80-* -MAN -SAVE USR/SRC/PRODOS.203/PRODOS.S.LDR - - -LOAD USR/SRC/PRODOS.203/PRODOS.S -ASM diff --git a/ProDOS.203/ProDOS.S.RAM.txt b/ProDOS.203/ProDOS.S.RAM.txt index 7d439aeb..df54fd97 100644 --- a/ProDOS.203/ProDOS.S.RAM.txt +++ b/ProDOS.203/ProDOS.S.RAM.txt @@ -4,7 +4,7 @@ NEW * /RAM driver (main bank portion) * origin = $FF00 -ofsR2 .EQ lcsrc-lcdest offset from ram driver org +ofsR2 .EQ *-lcdest offset from ram driver org lcsrc cld no decimal. ldx #$0B save 13 bytes of parms diff --git a/ProDOS.203/ProDOS.S.RAMI.txt b/ProDOS.203/ProDOS.S.RAMI.txt index d19f0e45..2b75b2fd 100644 --- a/ProDOS.203/ProDOS.S.RAMI.txt +++ b/ProDOS.203/ProDOS.S.RAMI.txt @@ -42,7 +42,7 @@ RAM_1 .BS $2C80-* rts end of obj ram_1 RAM_1_END .EQ * end of /RAM installer - .BS #256-* pad 0's to page boundary + .BS 256-* pad 0's to page boundary *-------------------------------------- MAN SAVE USR/SRC/PRODOS.203/PRODOS.S.RAMI diff --git a/ProDOS.203/ProDOS.S.RAMX.txt b/ProDOS.203/ProDOS.S.RAMX.txt index ffcc2378..fc669a47 100644 --- a/ProDOS.203/ProDOS.S.RAMX.txt +++ b/ProDOS.203/ProDOS.S.RAMX.txt @@ -1,6 +1,6 @@ NEW AUTO 3,1 -object code = ram_0 +* object code = ram_0 * /RAM driver (aux bank portion) * this code is packed into $200 length with no room for expansion !! * (see note at end of this obj) @@ -16,7 +16,7 @@ object code = ram_0 * $60-$67: returns blocks $68-$7F in bank 1 of language card * $68-$7F: returns blocks $68-$7F in bank 2 of language card -ofsR0 .EQ ramsrc-ramdest offset to /RAM driver org +ofsR0 .EQ *-ramdest offset to /RAM driver org ramsrc lda rd80col read 80 store pha save for later @@ -29,7 +29,7 @@ L5109 lda A4L,x cmd, unit, bufptr and block (lo) and formatflg format the volume first time bne L514F thru, or when requested. ldx bloknml save R01 during format. - lda #>vblock1 block to be cleared. + lda /vblock1 block to be cleared. jsr clrbuf1 clears all buffers. ldy #$03 format volume in 2 chunks. L511F lda VDIR,y @@ -87,9 +87,9 @@ L5179 sta R01 restore R1. pha ldx R2L sta setaltzp use alternate zero page/stack - lda #>dbuf set R2 to dbuf + lda /dbuf set R2 to dbuf sta R2H - lda # 0 from setptr @@ -119,7 +119,7 @@ L51B8 jsr blockdo0 transfer main to dbuf. * write is done (R2->R1); if cmd is 1, a read is done (R1->R2). blockdo0 .EQ *-ofsR0 set up R1 = dbuf - lda #>dbuf + lda /dbuf blockdo1 .EQ *-ofsR0 sta R01 blockdo .EQ *-ofsR0 @@ -136,16 +136,16 @@ L51CC lda (A1L),y transfer A1,A2 to A4,A3 sta wrcardram back the way it was. donewrt .EQ *-ofsR0 mainwrt returns here rts -L51DB lda #mainwrt + lda /mainwrt jmp ex1 set passit+1 and transfer * setptr is used by other routines to set up pointers and dtect read or write setptr .EQ *-ofsR0 lda tcmd is it read or write ? - lsr a + lsr bcs L5208 taken if write. lda R2H destination page sta A4L+1 @@ -160,7 +160,7 @@ setptr .EQ *-ofsR0 sta A1L sta A2L beq L5223 -L5208 lda R2H source page +L5208 lda R2H source page sta A1L+1 sta A2L+1 lda R2L @@ -172,8 +172,8 @@ L5208 lda R2H source page lda #$00 destination page aligned sta A4L sta A3L -L5223 inc2L+1 - inc3L+1 +L5223 inc A2L+1 + inc A3L+1 rts * tzip is called if blocks 0,1,4,5 are requested. @@ -187,7 +187,7 @@ tzip jsr clrbuf0 fill dbuf with 0's * should only be called on a read or format. clrbuf0 .EQ *-ofsR0 - lda #>dbuf dbuf is temp buffer. + lda /dbuf dbuf is temp buffer. clrbuf1 .EQ *-ofsR0 sta R01 assign to block. clrbuf2 .EQ *-ofsR0 @@ -266,7 +266,7 @@ L5285 asl acc = 2 * acc * at $800 is used to build/read a full size bitmap block. tbmap .EQ *-ofsR0 - lda #>dbuf use temp buffer as block + lda /dbuf use temp buffer as block sta R01 jsr setptr set pointers, test read/write. bcs L52A9 branch if it's write. @@ -307,7 +307,7 @@ VDIR .EQ *-ofsR0 start of vdir. .HS F3 storage type = F, name length = 3 .AS "RAM" access .EQ *-ofsR0 - .DA #C3 destroy, rename, read enabled + .DA #$C3 destroy, rename, read enabled .HS 27 entry length .HS 0D .HS 0000 diff --git a/ProDOS.203/ProDOS.S.SEL0.txt b/ProDOS.203/ProDOS.S.SEL0.txt index 55659758..d0c43d24 100644 --- a/ProDOS.203/ProDOS.S.SEL0.txt +++ b/ProDOS.203/ProDOS.S.SEL0.txt @@ -9,7 +9,7 @@ NEW * must remain somewhere between $E000-$F7FF. this routine must be less * than 3 pages in length. -ofsS .EQ disp1obj-dispadr offset to dispatcher org +ofsS .EQ *-dispadr offset to dispatcher org disp1obj lda romin read ROM sta clr80vid disable 80 col hardware @@ -31,14 +31,14 @@ L5A22 sta memmap,x sta memmap $400-$7FF (text screen display) L5A2D jsr home clear screen jsr crout position top/left - ldx #dispadr set reset vector to 'dispadr' + lda /dispadr set reset vector to 'dispadr' sta softev+1 jsr setpwrc create power-up byte lda #$A0 @@ -46,8 +46,8 @@ L5D3F dex decrement list pointer and restore. volname sta ol_unit store unit number for online. jsr MLI - .DA #$C5' online call - .DA ol_parms' + .DA #$C5 online call + .DA ol_parms bcs L5D32 error check. stz dlevel haven't read root directory yet. lda PrefixBuf+1 load description byte. @@ -65,8 +65,8 @@ vnam1 .EQ *-ofsB * open and read directory jsr MLI - .DA #$C8' open - .DA op_parms' + .DA #$C8 open + .DA op_parms bcc L5D7F good open. lda dlevel trying to open root directory ? beq L5D32 yes, just move to next volume. @@ -124,8 +124,8 @@ L5DCE dey decrement file block counter L5DD8 adc #$04 add 4 and put in sta fpos_lo low byte of setmark. jsr MLI call mli - .DA #$CE' set mark - .DA #smparms' parameters address = $0060 + .DA #$CE set mark + .DA #smparms parameters address = $0060 .HS 00 bcs L5DB3 error jsr doread @@ -161,8 +161,8 @@ L5E15 lda sysentry,y get byte of filename bne L5DB5 get next file (branch always) L5E26 jmp ds2 error. try next unit. L5E29 jsr MLI close directory file - .DA #$CC' - .DA cl_parms' + .DA #$CC + .DA cl_parms bcs L5E26 error. jsr settxt use full screen for windows jsr home @@ -262,8 +262,8 @@ L5EF1 jmp vnam1 get new directory info. * run selected file L5EF4 jsr MLI set prefix - .DA #$C6' - .DA pf_parms' + .DA #$C6 + .DA pf_parms bcs L5EED error. ldx valcnt get name number. jsr namecalc set up name storage area (on return y=0) @@ -276,15 +276,15 @@ L5F04 iny start at y = 1. bcc L5F04 loop until all transferred. stx PrefixBuf put prefix length into buffer. ldy valcnt get file number. - lda |filetyps,y get file type. + lda filetyps,y get file type. bpl L5EF0 branch if directory. jsr settxt reset to full window. jsr home makes for no flash. lda #$95 ctrl-u jsr cout turn off 80 columns. jsr MLI open file - .DA #$C8' - .DA op_parms' + .DA #$C8 + .DA op_parms bcs L5EED if error. lda op_refn move reference number sta rd_refn for read. @@ -294,8 +294,8 @@ L5F04 iny start at y = 1. jsr doread read selected file. php save possible error. jsr MLI close file. ignore any error from close - .DA #$CC' - .DA cl_parms' + .DA #$CC + .DA cl_parms plp restore status from read. bcs L5EED if any errors. jmp sysentry execute selected system file. @@ -327,7 +327,7 @@ namecalc .EQ *-ofsB asl rol fnstore+1 sta fnstore low pointer - lda #>iobuf + lda /iobuf clc adc fnstore+1 sta fnstore+1 @@ -353,7 +353,7 @@ nameprnt .EQ *-ofsB stz ch80col adjust cursor position. lda invflg save current inverse setting pha - ldy #>16 pea errval push address of string buffer. pea $0004 make string 4 digits long. - _Int2Hex convert value to hex string. + >IIGS Int2Hex convert value to hex string. pha make space for return value. pea $0000 quitstr1>>16 pea quitstr1 push first error message address @@ -154,11 +154,11 @@ L60AB clc native mode pea button1 push first button text address pea $0000 quitbtn2>>16 pea quitbtn2 push 2nd button text address (null) - _TLTextMountVolume make the dialog box + >IIGS TLTextMountVolume make the dialog box pla retrieve button press (not used) sec emulation mode xce - jsr MLI quit back to GQuit + jsr MLI quit back to GQuit .DA #$65 .DA quitparms @@ -203,7 +203,7 @@ L6101 pha save error code in case esc pressed. pea button1 'Return' pea $0000 button2>>16 pea button2 'Escape' - _TLTextMountVolume + >IIGS TLTextMountVolume lda [$01] restore first 2 bytes of vilume name xba back to their original positions inc and values. @@ -227,12 +227,12 @@ L613C sec indicate Escape was pressed. * output: volume name is stored in volbuf. copyvol .EQ *-ofsQ - lda |1,x get the first slash - sta volbuf+1 - ldy #$0002 initialize the length count. - LONGI OFF - LONGA OFF -L6148 lda |2,x now copy the volume name up to + lda 1,x get the first slash + sta volbuf+1 + ldy #$0002 initialize the length count. +* LONGI OFF +* LONGA OFF +L6148 lda 2,x now copy the volume name up to cmp #$2F the separating slash. beq L6156 sta volbuf,y @@ -264,9 +264,9 @@ L6170 lda #$FF put flag conditioning value on pha the stack (assume error). clc native 16-bit mode. xce - LONG I,M +* LONG I,M pha make room on stack for user id. - _MMStartUp start up the memory manager. + >IIGS MMStartUp start up the memory manager. pla get the user id and pha leave it on the stack. pha @@ -277,7 +277,7 @@ L6170 lda #$FF put flag conditioning value on pea $0000 totally unrestricted block. pha LocationPtr (not used) pha - _NewHandle go get the block of memory. + >IIGS NewHandle go get the block of memory. pla get the handle from the stack. plx bcs L620A branch if error, no memory available. @@ -287,7 +287,7 @@ L6170 lda #$FF put flag conditioning value on pea $0001 get a type 1 (filename) message. phx put the message handle on the stack pha (still in acc and x regs) - _MessageCenter + >IIGS MessageCenter bcs L6203 branch if no message. pha leave 4 bytes free on stack pha (will be used as a direct page pointer) @@ -311,7 +311,7 @@ L6170 lda #$FF put flag conditioning value on inc $02 L61D1 lda [$00] get the length of the string. and #$00FF mask off high (leaving just the length) - SHORT M 8 bit accumulator +* SHORT M 8 bit accumulator cmp sysentry+5 check against length of app buffer. beq L61DF if equal then continue with move. bcs bad_msg if too long then bad message. @@ -323,7 +323,8 @@ L61E0 lda [$00],y get a character. bpl L61E0 lda #$00 change flag conditioning value on stack sta $0D,s to indicate a filename is passed. -bad_msg LONG M 16-bit acc. +bad_msg +* LONG M 16-bit acc. pld restore direct register. pla fix stack because handle and userid pla still on stack. @@ -331,12 +332,12 @@ bad_msg LONG M 16-bit acc. pea $0001 message type 1. pha garbage handle (not used). pha - _MessageCenter go delete the message. -L6203 _DisposeHandle throw away message (handle is on stack) -L620A _MMShutDown shutdown the memory manager (userid is + >IIGS MessageCenter go delete the message. +L6203 >IIGS DisposeHandle throw away message (handle is on stack) +L620A >IIGS MMShutDown shutdown the memory manager (userid is sec on stack). xce back to emulation mode. - LONGA OFF +* LONGA OFF pla condition z-flag with value on stack. bne L6231 then done. ldx inbuf get length of pathname. @@ -359,11 +360,11 @@ L6231 rts and go launch the app. * on exit: * carry clear = disk was found * carry set = disk not found - + .OP 65816 ckfordrv .EQ *-ofsQ clc native mode xce - LONG I 16-bit regs, 8-bit acc. +* LONG I 16-bit regs, 8-bit acc. ldx #sysentry+6 point to pathname buffer. jsr copyvol copy volume name to pathname buffer. .1 sec emulation mode. @@ -374,14 +375,14 @@ ckfordrv .EQ *-ofsQ bcc .2 branch if volume found, clc (native mode) xce - LONG I,M +* LONG I,M jsr mountvol else ask user to mount the volume. bcc .1 if pressed, then try again. sec emulation mode. xce sec disk not found. .2 rts - + .OP 65C02 * Prodos 8 parameter lists pfxparms .EQ *-ofsQ set prefix parms. diff --git a/ProDOS.203/ProDOS.S.TCLK.txt b/ProDOS.203/ProDOS.S.TCLK.txt index 939193cd..3e3fe828 100644 --- a/ProDOS.203/ProDOS.S.TCLK.txt +++ b/ProDOS.203/ProDOS.S.TCLK.txt @@ -6,7 +6,7 @@ NEW * $2F00-2F7C moved to $D742 -ofsT .EQ tclock_0-tclk_in offset to Thunderclock org +ofsT .EQ *-tclk_in offset to Thunderclock org tclock_0 ldx clkslt clock slot = $C1. lda clkmode,x save current mode diff --git a/ProDOS.203/ProDOS.S.XDOS.A.txt b/ProDOS.203/ProDOS.S.XDOS.A.txt new file mode 100644 index 00000000..ad535fd1 --- /dev/null +++ b/ProDOS.203/ProDOS.S.XDOS.A.txt @@ -0,0 +1,663 @@ +NEW + AUTO 3,1 +* object code = mli_2 +* xdos mli system call processor + .OP 65C02 +ofsX .EQ *-xdosorg offset to xdos org + +xdosmli .EQ *-ofsX xdos MLI in aux ram +* cld no decimal. + pla get processor status + sta spare1 save it temporarily + sty mliy save x and y + stx mlix + pla find out the address of the caller + sta A3L + clc preserve the address of the call spec. + adc #$04 + sta mliretn last MLI call return address + pla + sta A3L+1 + adc #$00 + sta mliretn+1 + lda spare1 + pha pull processor status + plp to re-enable interrupts. + cld still no decimal + ldy #$00 + sty p8error clear any previous errors. + iny find out if command is valid. + lda (A3L),y get command # + lsr and hash it to a range of 0-$1F + lsr + lsr + lsr + clc + adc (A3L),y + and #$1F + tax + lda (A3L),y check result to see if valid command # + cmp scnums,x + bne scnerr + iny index to call spec parm list. + lda (A3L),y make A3L point to parameter count byte + pha in parameter block. + iny + lda (A3L),y + sta A3L+1 + pla + sta A3L + ldy #$00 make sure parameter list has the + lda pcntbl,x correct # of parameters. + beq goclock clock has 0 parameters. + cmp (A3L),y + bne scperr error if wrong count. + lda scnums,x get call # again + cmp #$65 is it quit? + beq special if so, then call quit dispatcher + asl carry set if bfm or dev mgr + bpl godevmgr + bcs gobfmgr + lsr shift back down for interrupt manager + and #$03 valid calls are 0 and 1 + jsr intmgr + bra exitmli +special jmp jspare P8 system death vector +goclock jsr clockv go read clock. + bra exitmli no errors possible +godevmgr lsr shift back down for device manager. + adc #$01 valid commands are 1 and 2. + sta A4L save command #. + jsr devmgr execute read or write request. + bra exitmli +gobfmgr lsr shift back down for block file manager. + and #$1F valid commands are 0-$13 + tax + jsr bfmgr +exitmli stz bubit clear backup bit + ldy p8error P8 error code + cpy #$01 if > 0 then set carry + tya and set z flag. + php disable interrupts until exit complete. + sei + lsr mliact indicate MLI done. + plx save status register until return. + lda mliretn+1 place last MLI call return address + pha on stack. return is done via 'rti' + lda mliretn so the status register is restored + pha at the same time, so + phx place status back on stack + tya return error, if any. + ldx mlix MLI X register savearea + ldy mliy MLI Y register savearea + pha + lda bnkbyt1 restore language card status + jmp HBFA0 and return. +nodevice .EQ *-ofsX + lda #$28 no device connected. + jsr p8errv P8 error vector. +scnerr lda #$01 no such command. + bne H30B0 +scperr lda #$04 parameter count is invalid +H30B0 jsr gosyserr + bcs exitmli always taken + +* ProDOS Device Manager + +devmgr .EQ *-ofsX + ldy #$05 + php do not allow interrupts. + sei the call spec for devices must +H30B9 lda (A3L),y be passed to drivers in page zero: + sta (A4L),y sta $0042,y + dey + bne H30B9 + ldx buf+1 buffer page + stx usrbuf+1 to user buffer + inx + inx + lda buf is buffer page aligned (nn00) ? + beq H30CC branch if it is + inx else account for 3-page straddle +H30CC jsr vldbuf1 make sure user buffer is not + bcs dvmgrerr conflicting with protected ram. + jsr dmgr call internal entry for device dispatch + bcs dvmgrerr branch if error + plp + clc no error + rts +dvmgrerr plp restore interrupt status +gosyserr .EQ *-ofsX + jsr p8errv P8 error vector +dmgr .EQ *-ofsX interrupts must always be off. + lda unitnum get device # and + and #$F0 strip misc lower nibble + sta unitnum then save it. + lsr use as index to device table + lsr + lsr + tax + lda drivertbl1,x fetch driver address + sta goadr + lda drivertbl1+1,x + sta goadr+1 +gocmd .EQ *-ofsX + jmp (goadr) goto driver (or error if no driver) + +* ProDOS interrupt manager + +intmgr .EQ *-ofsX + sta A4L interrupt command + lsr allocate interrupt or deallocate? + bcs dealcint branch if deallocate. + ldx #$03 test for a free interrupt space in tbl. +alcint lda inttbl-2,x test high address for 0. + bne H3118 branch if spot occupied. + ldy #$03 get address of routine. + lda (A3L),y must not be zero page. + beq badint error if it is. + sta inttbl-2,x save high address + dey + lda (A3L),y + sta inttbl-3,x and low address. + txa return interrupt # in range 1-4 + lsr + dey + sta (A3L),y pass back to user. + clc no errors. + rts +H3118 inx + inx next lower priority spot + cpx #$0B are all 4 already allocated? + bne alcint branch if not. + lda #$25 interrupt table full + bne H3124 +badint lda #$53 invalid parameter. +H3124 jsr p8errv P8 error vector. +dealcint ldy #$01 zero out interrupt vector + lda (A3L),y but make sure it is a valid #. + beq badint error if < 1 + cmp #$05 or > 4 + bcs badint + asl + tax + lda #$00 now clear it + sta inttbl-2,x + sta inttbl-1,x + clc + rts +irqrecev .EQ *-ofsX + lda accsav get acc from where old ROM put it. + sta p8areg + stx p8xreg entry point on ram card interrupt + sty p8yreg + tsx + stx p8sreg + lda irqflag irq flag = 0 if old roms + bne H315D and 1 if new roms. + pla restore return address and p-reg. + sta p8preg + pla + sta intadr interrupt return address + pla + sta intadr+1 +H315D txs + lda mslot set up to re-enable $Cn00 rom + sta irqdev+2 + tsx make sure stack has room for 16 bytes. + bmi H3170 branch if stack ok + ldy #$0F otherwise, make room and save it. +H3169 pla + sta svstack,y + dey + bpl H3169 +H3170 ldx #$FA save 6 bytes of page 0 +H3172 lda $00,x + sta svzerop-$FA,x + inx + bne H3172 + +* poll interrupt routines for a claimer + + lda inttbl+1 test for a valid routine. + beq intr2 branch if no routine. + jsr goint1 execute + bcc irqdone +intr2 lda inttbl+3 repeat 3 more times + beq intr3 + jsr goint2 + bcc irqdone +intr3 lda inttbl+5 + beq intr4 + jsr goint3 + bcc irqdone +intr4 lda inttbl+7 + beq H31A2 + jsr goint4 + bcc irqdone +H31A2 inc irqcount allow 255 unclaimed interrupts + bne irqdone before system death. + lda #$01 bad irq so + jsr sysdeath kill the system. +irqdone ldx #$FA +H31AE lda svzerop-$FA,x restore the zero page + sta $00,x + inx + bne H31AE + ldx p8sreg test if stack needs restoring. + bmi H31C6 branch if not. + ldy #$00 +H31BD lda svstack,y restore stack + pha + iny + cpy #$10 + bne H31BD +H31C6 lda irqflag check for old roms. + bne H31DD branch if new roms. + ldy p8yreg restore registers. + ldx p8xreg + lda clrrom re-enable i/o card. +irqdev .EQ *-ofsX + lda $C100 Cn is self modifying. + lda irqdev+2 restore device id. + sta mslot slot being accessed. +H31DD jmp irqexit do necessary bank switches and return. +irqflag .EQ *-ofsX + .HS 00 0 = old roms. 1 = new roms. +irqcount .EQ *-ofsX + .HS 00 # of unclaimed interrupts. +svstack .EQ *-ofsX temporary save area from stack + .HS 0000000000000000 + .HS 0000000000000000 +svzerop .EQ *-ofsX temporary save area for zero page + .HS 000000000000 +goint1 .EQ *-ofsX + jmp (inttbl) interrupt routine 1 +goint2 .EQ *-ofsX + jmp (inttbl+2) interrupt routine 2 +goint3 .EQ *-ofsX + jmp (inttbl+4) interrupt routine 3 +goint4 .EQ *-ofsX + jmp (inttbl+6) interrupt routine 4 +syserr1 .EQ *-ofsX + sta p8error P8 error code + plx + plx pop 1 level of return + sec + rts +sysdeath1 .EQ *-ofsX + tax death error code. + sta clr80vid disable 80 col hardware. + lda txtset switch in text. + lda cortflag is this a Cortland? + beq H321A if not, don't use super hires switch. + stz newvideo force off super hires. +H321A lda txtpage1 switch in text page 1. + ldy #$13 +H321F lda #$20 inverse space border + sta vline11+10,y + sta vline13+10,y + lda deathmsg,y + sta vline12+10,y 'RESTART SYSTEM-$0x' + dey + bpl H321F + txa x = death error code + and #$0F convert to ascii + ora #$B0 + cmp #$BA + bcc H323B branch if not > 9. + adc #$06 inc to alpha a-f +H323B sta vline12+28 death error code 1 to F +H323E bra H323E end of xdos mli + +* ProDOS Block File Manager + +bfmgr .EQ *-ofsX + lda disptch,x translate into command address. + asl bit 7 indicates pathname to process + sta cmdtemp + and #$3F bit 6 is refnum, 5 is time to process + tax + lda cmdtable,x move address to indirect jump + sta goadr + lda cmdtable+1,x high byte + sta goadr+1 + lda #$20 init backup bit flag + sta bkbitflg to say 'file modified' + bcc nopath + jsr setpath process pathname before calling command + bcs errorsys branch if bad name. +nopath asl cmdtemp test for refnum processing + bcc nopreref + jsr findfcb set pointers to fcb and vcb of file + bcs errorsys +nopreref asl cmdtemp check for necessity of time stamp + bcc H3274 + jsr clockv date/time +H3274 jsr gocmd execute command + bcc goodop +errorsys jsr p8errv P8 error vector +goodop rts +setpath .EQ *-ofsX + ldy #$01 index to pathname pointer + lda (A3L),y low pointer address + sta zpt + iny + lda (A3L),y hi pointer address + sta zpt+1 +synpath .EQ *-ofsX entry used by rename for 2nd pathname. + ldx #$00 x = index to pathbuf + ldy #$00 y = index to input pathname. + stx prfxflg assume prefix is in use. + stx pathbuf mark pathbuf = nothing processed. + lda (zpt),y validate pathname length > 0 and < 65 + beq errsyn + cmp #$41 + bcs errsyn + sta pathcnt this is used to compare for + inc pathcnt end of pathname processing. + iny now check for full pathname... + lda (zpt),y (full name if starts with '/') + ora #$80 + cmp #$AF + bne H32AD branch if prefix appended. + sta prfxflg set prefix flag = prefix not used. + iny index to 1st character of pathname. +H32AD lda #$FF set current position of pathbuf + sta pathbuf,x to indicate end of pathname. + sta namcnt $FF = no chars processed in local name. + stx namptr pointer to local name length byte. +H32B8 cpy pathcnt done with pathname processing? + bcs endpath + lda (zpt),y get character + and #$7F + inx prepare for next char + iny + cmp #$2F is it delimiter '/' ? + beq endname yes + cmp #$61 lowercase? + bcc H32CD no + and #$5F shift to uppercase +H32CD sta pathbuf,x store char + inc namcnt is it the 1st char of a local name? + bne H32DA no + inc namcnt increment to 1 + bne H32E6 1st char must be alpha (always taken) +H32DA cmp #$2E is it '.' ? + beq H32B8 ok, then do next char + cmp #$30 at least a '0' ? + bcc errsyn error if not + cmp #$3A is it numeric? + bcc H32B8 yes, get next char +H32E6 cmp #$41 at least an 'a' ? + bcc errsyn error if not + cmp #$5B is it > 'z' ? + bcc H32B8 branch if valid alpha to get next char +errsyn sec bad pathname + lda #$40 + rts +endpath lda #$00 end pathname with a 0 + bit namcnt also make sure count is positive + bpl H32FD + sta namcnt + dex +H32FD inx + sta pathbuf,x + beq errsyn error if '/' only. + stx pathcnt save length of pathname + tax +endname lda namcnt validate local name < 16 + cmp #$10 + bcs errsyn + phx save pointer + ldx namptr get index to beginning of local name + sta pathbuf,x save local name's length + plx restore pointer + bne H32AD branch if more names to process + clc probably no error, but + lda prfxflg make sure all pathnames are prefixed + bne H3323 or begin with a '/'. + lda newpfxptr must be non-zero + beq errsyn +H3323 rts + +* set prefix command + +setprefx .EQ *-ofsX + jsr setpath call is made to detect if a null path. + bcc H3333 path ok. + ldy pathbuf is it a null pathname? + bne pfxerr error if not + jsr stypfx indicate null prefix + clc no error + rts +H3333 jsr findfile go find specified prefix directory. + bcc H333C if no error. + cmp #$40 bad pathname. + bne pfxerr branch if error is not root directory. +H333C lda d_stor make sure last local name is dir type + and #$D0 (either root or sub). + eor #$D0 directory? + bne ptyperr wrong type + ldy prfxflg new or appended prefix? + bne H334D + lda newpfxptr append new prefix to old +H334D tay + sec find new beginning of prefix + sbc pathcnt + cmp #$C0 too long? + bcc errsyn then error + tax + jsr stapfx + lda d_dev save device # + sta p_dev + lda d_frst and address of 1st block + sta p_blok + lda d_frst+1 + sta p_blok+1 +movprfx lda pathbuf,y + sta pathbuf,x + iny + inx + bne movprfx + clc good prefix + rts +ptyperr lda #$4B filetype error (not a directory) +pfxerr sec + rts + +* get prefix command + +getprefx .EQ *-ofsX calc how big a buffer is needed. + clc get index to users pathname buffer + ldy #$01 + lda (A3L),y + sta usrbuf user buffer ptr + iny + lda (A3L),y + sta usrbuf+1 + stz cbytes+1 set buffer length at 64 char max + lda #$40 + sta cbytes + jsr valdbuf go validate prefix buffer address + bcs pfxerr + ldy #$00 y = indirect index to user buffer. + lda newpfxptr get address of beginning of prefix + tax + beq nulprfx if null prefix. + eor #$FF get total length of prefix + adc #$02 add 2 for leading and trailing slashes. +nulprfx sta (usrbuf),y store length in user's buffer. + beq gotprfx branch if null prefix. +sendprfx iny inc to next user buffer location. + lda pathbuf,x get next char of prefix. +sndlimit sta (usrbuf),y give char to user. + and #$F0 check for length descriptor. + bne H33B3 branch if regular character + lda #$2F otherwise, substitute a slash. + bne sndlimit branch always +H33B3 inx + bne sendprfx branch if more to send. + iny + lda #$2F end with '/' + sta (usrbuf),y +gotprfx clc no error + rts +findfcb .EQ *-ofsX + ldy #$01 index to ref# + lda (A3L),y is it a valid file# ? + beq badref must not be 0. + cmp #$09 must be 1 to 8 only. + bcs badref + pha + dec a + lsr + ror + ror + ror multiply by 32. + sta fcbptr used as an index to fcb + tay + pla restore ref# in acc + cmp fcbbuf,y + bne errnoref +fndfcbuf .EQ *-ofsX get page address of file buffer. + lda fcbbuf+11,y + jsr getbufadr get file's address into bufaddrl,h + ldx bufaddrh (y=fcbptr preserved) + beq fcbdead fcb corrupted + stx datptr+1 save ptr to data area of buffer + inx + inx index block always 2 pages after data + stx zpt+1 + lda fcbbuf+1,y also set up device # + sta devnum + lda bufaddrl + sta datptr index and data buffers always on + sta zpt page boundaries. +fndfvol tax search for associated vcb + lda vcbbuf+16,x + cmp fcbbuf+1,y is this vcb the same device? + beq tstvopen if it is, make sure volume is active. +nxtfvol txa adjust index to next vcb. + clc + adc #$20 + bcc fndfvol loop until volume found. + lda #$0A open file has no volume so + jsr sysdeath kill the system. +fcbdead lda #$0B fcb error so + jsr sysdeath kill the system. +tstvopen lda vcbbuf,x make sure this vcb is open. + beq nxtfvol branch if it is not active. + stx vcbptr save ptr to good vcb. + clc no error + rts +errnoref lda #$00 put a zero into this fcb to + sta fcbbuf,y show free fcb. +badref lda #$43 requested refnum is + sec illegal (out of range) + rts + +* online command + +online .EQ *-ofsX move user spec'd buffer ptr to usrbuf. + jsr mvdbufr figure out how big buffer has to be. + stz cbytes set this for valdbuf routine. + stz cbytes+1 + ldy #$01 + lda (A3L),y if 0 then cbytes=$100 else $010 for one + and #$F0 device. mask out unused nibble. + sta devnum last device used. + beq H343C branch if all devices. + lda #$10 cbytes = $010 + sta cbytes + bne H343F always taken +H343C inc cbytes+1 cbytes = $100 +H343F jsr valdbuf go validate buffer range against + bcs onlinerr allocated memory. + lda #$00 zero out user buffer space + ldy cbytes +H3449 dey + sta (usrbuf),y + bne H3449 + sta namptr used as pointer to user buffer. + lda devnum get device # again. + bne H3474 branch if only 1 device to process. + jsr mvdevnums get list of currently recognized dev's. +H3459 phx save index to last item on list + lda loklst,x + sta devnum save desired device to look at. + jsr online1 log this volume and return it's name. + lda namptr inc pointer for next device + clc + adc #$10 + sta namptr + plx get index to device list. + dex next device. + bpl H3459 branch if there is another device. + lda #$00 no errors for multiple on-line + clc +onlinerr rts +online1 .EQ *-ofsX +H3474 jsr fnddvcb see if it has already been logged in. + bcs olinerr1 branch if vcb is full. + ldx #$00 read in root (volume) directory + lda #$02 + jsr rdblk read it into general purpose buffer. + ldx vcbptr index to the vcb entry. + bcc volfound branch if read was ok. + tay error value. + lda vcbbuf+17,x don't take the vcb offline if + bne rtrnerr there are active files present. + sta vcbbuf,x now take the volume offline + sta vcbbuf+16,x +rtrnerr tya error value. + bcs olinerr1 branch if unable to read. +volfound lda vcbbuf,x has it been logged in before? + beq H349E if not. + lda vcbbuf+17,x it has, are there active files? + bmi H34AA branch if volume is currently busy. +H349E jsr logvcb1 go log it in. + bcs olinerr1 branch if there is a problem. + lda #$57 anticipate a duplicate active volume + bit duplflag exits. + bmi olinerr1 branch if so. +H34AA ldx vcbptr + jsr cmpvcb does vol read compare with logged vol? + lda #$2E anticipate wrong volume mounted. + bcc H34D0 branch if ok. +olinerr1 pha save error code. + jsr svdevn report what device has problem. + pla error code. + iny tell what error was encountered. + sta (usrbuf),y + cmp #$57 duplicate volume error? + bne H34CE no. + iny report which other device has same name + ldx vcbentry + lda vcbbuf+16,x + sta (usrbuf),y + stz duplflag clear duplicate flag. + lda #$57 duplicate volume error code. +H34CE sec flag error + rts +H34D0 lda vcbbuf,x get volume name count + sta namcnt + ldy namptr index to user's buffer. +H34D9 lda vcbbuf,x move name to user's buffer + sta (usrbuf),y + inx + iny + dec namcnt + bpl H34D9 +svdevn .EQ *-ofsX + ldy namptr index to 1st byte of this entry. + lda devnum upper nibble = device# and + ora (usrbuf),y lower nibble = name length. + sta (usrbuf),y + clc no errors + rts end of block file manager + +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.A +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.XDOS.B.txt b/ProDOS.203/ProDOS.S.XDOS.B.txt new file mode 100644 index 00000000..6f862728 --- /dev/null +++ b/ProDOS.203/ProDOS.S.XDOS.B.txt @@ -0,0 +1,869 @@ +NEW + AUTO 3,1 + +* create file + +create .EQ *-ofsX + jsr lookfile check for duplicate, get free entry + bcs tstfnf error code may be 'file not found' + lda #$47 name already exists +crerr1 sec + rts +tstfnf cmp #$46 'file not found' is ok + bne crerr1 otherwise exit with error. + ldy #$07 test for tree or directory file, + lda (A3L),y no other kinds are legal. + cmp #$04 is it seed, sapling or tree? + bcc tstdspc branch if it is + cmp #$0D + bne ctyperr report type error if not directory. +tstdspc lda devnum make sure destination device + jsr twrprot1 is not write protected. + bcs H351D + lda nofree is there space in directory to + beq xtndir add this file? branch if not + jmp creat1 otherwise, go create file. +ctyperr lda #$4B filetype error + sec +H351D rts +xtndir lda own_blk before extending directory, + ora own_blk+1 make sure it's a subdirectory. + bne H352A + lda #$49 otherwise, directory full error + sec + rts +H352A lda bloknml preserve disk address of current (last) + pha directory link, before allocating an + lda bloknml+1 extended block. + pha + jsr alc1blk allocate a block for extending directory + plx + stx bloknml+1 restore block addr of dir info in gbuf + plx + stx bloknml + bcs H351D unable to allocate. + sta gbuf+2 save block address in y,a to + sty gbuf+3 current directory. + jsr wrtgbuf update directory block with new link. + bcs H351D if error + ldx #$01 +swpbloks lda bloknml,x prepare new directory block + sta gbuf,x using current block as back link + lda gbuf+2,x + sta bloknml,x and save new block as next to be written + dex + bpl swpbloks + inx + txa x and a = 0 +clrdir sta gbuf+2,x + sta gbuf+$100,x + inx + bne clrdir + jsr wrtgbuf write prepared directory extension. + bcs H351D if error + lda own_blk + ldx own_blk+1 + jsr rdblk read in parent directory block + ldx own_ent and calc entry address. + lda /gbuf + sta zpt+1 + lda #$04 +ocalc clc + dex has entry address been calulated? + beq H3584 if yes. + adc own_len next entry address + bcc ocalc + inc zpt+1 entry must be in 2nd 256 bytes of block + bcs ocalc always taken. +H3584 sta zpt + ldy #$13 index to block count +H3588 lda (zpt),y + adc dinctbl-$13,y add 1 to block count and + sta (zpt),y + iny + tya $200 to the directory's eof. + eor #$18 done with usage/eof update? + bne H3588 branch if not. + jsr wrtgbuf go update parent. + bcs crerr2 + jmp create +crerr2 rts return and report errors +creat1 .EQ *-ofsX + ldx #$00 zero out gbuf +H35A0 stz gbuf,x + stz gbuf+$100,x and data block of file. + inx + bne H35A0 + ldy #$0B move user specified date/time +cmvtime lda (A3L),y to directory. + sta d_filid,y + txa if all 4 bytes of date/time = 0 + ora (A3L),y then use built-in date/time. + tax + dey + cpy #$07 + bne cmvtime + txa does user want default time? + bne cmvname if not. + ldx #$03 +mvdftime lda p8date,x move current default date/time + sta d_credt,x + dex + bpl mvdftime +cmvname lda (A3L),y y = index to file kind. + cmp #$04 + lda #$10 assume tree type + bcc csvfkind + lda #$D0 it's directory. +csvfkind ldx namptr index to local name of pathname. + ora pathbuf,x combine file kind with name length. + sta d_stor sos calls this 'storage type'. + and #$0F strip back to name length + tay and use as counter for move. + clc + adc namptr calc end of name + tax +crname lda pathbuf,x move local name as filename + sta d_stor,y + dex + dey + bne crname + ldy #$03 index to 'access' parameter + lda (A3L),y + sta d_attr + iny also move 'file identification' + lda (A3L),y + sta d_filid +cmvauxid iny move auxillary identification bytes + lda (A3L),y + sta d_auxid-5,y + cpy #$06 + bne cmvauxid + lda xdosver save current xdos version # + sta d_sosver + lda compat and backward compatibility # + sta d_comp + lda #$01 usage is always 1 block + sta d_usage + lda d_head place back pointer to header block + sta d_dhdr + lda d_head+1 + sta d_dhdr+1 + lda d_stor storage type. + and #$E0 is it a directory? + beq cralcblk branch if seed file. + ldx #$1E move header to data block +cmvheadr lda d_stor,x + sta gbuf+4,x + dex + bpl cmvheadr + eor #$30 + sta gbuf+4 make it a directory header mark. + ldx #$07 overwrite password area and other +cmvpass lda pass,x header info. + sta gbuf+20,x + lda xdosver,x + sta gbuf+32,x + dex + bpl cmvpass + ldx #$02 and include info about parent directory + stx d_eof+1 +cmvparnt lda d_entblk,x + sta gbuf+39,x + dex + bpl cmvparnt + lda h_entln lastly, the length of parent's + sta gbuf+42 directory entries. +cralcblk jsr alc1blk get address of file's data block + bcs crerr3 + sta d_frst + sty d_frst+1 + sta bloknml + sty bloknml+1 + jsr wrtgbuf go write data block of file + bcs crerr3 + inc h_fcnt add 1 to total # of files in this dir + bne credone + inc h_fcnt+1 +credone jsr drevise go revise directories with new file + bcs crerr3 + jmp upbmap lastly, update volume bitmap +entcalc .EQ *-ofsX + lda /gbuf set high address of dir entry + sta zpt+1 index pointer. + lda #$04 calc address of entry based + ldx d_entnum on the entry #. +H3689 clc +H368A dex addr = gbuf + ((d_entnum-1) * h_entln) + beq H3696 branch with carry clear = no errors. + adc h_entln + bcc H368A + inc zpt+1 inc hi address. + bcs H3689 always. +H3696 sta zpt newly calculated low address. +crerr3 rts carry set if error. +drevise .EQ *-ofsX + lda p8date + beq H36A9 if no clock, then don't mod date/time. + ldx #$03 +modtime lda p8date,x move last modification date/time + sta d_moddt,x to entry being updated. + dex + bpl modtime +drevise1 .EQ *-ofsX +H36A9 lda d_attr mark entry as backupable + ora bkbitflg (bit 5 = backup needed) + sta d_attr + lda d_dev get device # of directory + sta devnum to be revised + lda d_entblk and address of direcotry block. + ldx d_entblk+1 + jsr rdblk read block into general purpose buffer + bcs crerr3 + jsr entcalc fix up ptr to entry location within gbuf. + ldy h_entln now move 'd.' info to directory. + dey +H36CA lda d_stor,y + sta (zpt),y + dey + bpl H36CA + lda d_head is the entry block same as + cmp bloknml the entry's header block? + bne H36E0 if no, go save entry block + lda d_head+1 then maybe, so test high addresses. + cmp bloknml+1 + beq uphead branch if they are the same block. +H36E0 jsr wrtgbuf go write updated directory block. + bcs crerr3 + lda d_head get address of header block and + ldx d_head+1 + jsr rdblk go read in header block to modify. + bcs crerr3 +uphead ldy #$01 update current # of files in this dir. +H36F2 lda h_fcnt,y + sta gbuf+37,y (current entry count) + dey + bpl H36F2 + lda h_attr also update header's attributes. + sta gbuf+34 + jsr wrtgbuf go write updated header + bcs H375A +ripple lda gbuf+4 test for 'root' directory because + and #$F0 if it is, then directory revision + eor #$F0 is complete (leaves carry clear). + beq H3770 branch if done. + lda gbuf+41 get entry # + sta d_entnum + lda gbuf+42 and the length of ertries in that dir + sta h_entln + lda gbuf+39 get addr of parent entry's dir block + ldx gbuf+40 + jsr rdblk read it + bcs H375A + jsr entcalc get indirect ptr to parent entry in gbuf + lda p8date don't touch mod + beq H373B if no clock... + ldx #$03 update the modification date & time + ldy #$24 for this entry too +H3732 lda p8date,x + sta (zpt),y + dey + dex + bpl H3732 +H373B jsr wrtgbuf write updated entry back to disk. + bcs H375A if error. + ldy #$25 compare current block # to this + lda (zpt),y entry's header block. + iny + cmp bloknml are low addresses the same? + sta bloknml + bne H3751 branch if entry doesn't reside in same + lda (zpt),y block as header. + cmp bloknml+1 are high address the same? + beq ripple they are the same, continue to root dir. +H3751 lda (zpt),y not same so read in this dir's header. + sta bloknml+1 + jsr rdgbuf + bcc ripple continue if read was good +H375A rts +tsterr lda #$52 not tree or dir, unrecognized type + sec + rts +tstsos .EQ *-ofsX test if xdos disk. + lda gbuf pointer to previous dir block + ora gbuf+1 must be null + bne tsterr + lda gbuf+4 test for header + and #$E0 + cmp #$E0 + bne tsterr +H3770 clc no error + rts +findfile .EQ *-ofsX + jsr lookfile see if file exists + bcs nofind +moventry .EQ *-ofsX + ldy h_entln +H377A lda (zpt),y move entry into storage + sta d_stor,y + dey + bpl H377A + lda #$00 no errors +nofind rts +lookfile .EQ *-ofsX + jsr preproot go find volume + bcs fnderr + bne L37C5 branch if more than root + lda /gbuf otherwise, report a bad path error + sta zpt+1 (but 1st create a phantom entry + lda #$04 for open) + sta zpt + ldy #$1F move in id and date info +phantm1 lda (zpt),y + sta d_stor,y + dey + cpy #$17 + bne phantm1 +phantm2 lda rootstuf-$10,y + sta d_stor,y + dey + cpy #$0F + bne phantm2 + lda #$D0 fake directory file + sta d_stor + lda gbuf+2 check forward link. + ora gbuf+3 if non-zero, assume full sized directory + bne H37C2 else assume it's the slot 3 /RAM volume + lda #$02 so reset eof and blocks_used fields + sta d_eof+1 + lda #$01 + sta d_usage +H37C2 lda #$40 bad path (carry set) + rts +lookfil0 .EQ *-ofsX +L37C5 stz nofree reset free entry indicator. + sec dir to be searched has header in this block. +L37C9 stz totent reset entry counter. + jsr looknam look for name pointed to by pnptr. + bcc namfound if name was found. + lda entcntl have we looked at all of the + sbc totent entries in this directory? + bcc L37E2 maybe, check hi count. + bne L37EB no, read next directory block. + cmp entcnth has the last entry been looked at? + beq errfnf yes, give 'file not found' error + bne L37EB or branch always. +L37E2 dec entcnth should be at least one + bpl L37EB so this should be branch always... +errdir lda #$51 directory error +fnderr sec + rts +L37EB sta entcntl keep a running count. + lda /gbuf reset indirect pointer + sta zpt+1 + lda gbuf+2 get link to next dir block + bne L37FC (if there is one). + cmp gbuf+3 are both zero, i.e. no link? if so, + beq errdir then not all entries were acct'd for. +L37FC ldx gbuf+3 acc has value for block# (low). + jsr rdblk go read the next linked directory. + bcc L37C9 if no error. + rts return error in acc. +errfnf lda nofree was any free entry found? + bne fnf0 + lda gbuf+2 test link + bne L3814 + cmp gbuf+3 if both are 0 then give up. + beq fnf0 report 'not found'. +L3814 sta d_entblk + lda gbuf+3 + sta d_entblk+1 assume 1st entry of next block + lda #$01 is free for use. + sta d_entnum mark as valid (for create) + sta nofree +fnf0 jsr nxtpnam1 'file not found' or 'path not found'? +errpath1 sec if non-zero then 'path not found' + beq fnf1 + lda #$44 path not found + rts +fnf1 lda #$46 file not found + rts +namfound jsr nxtpname adj index to next name in path. + beq filfound branch if that was the last name. + ldy #$00 be sure this is a directory entry. + lda (zpt),y high nibble will tell. + and #$F0 + cmp #$D0 is it a subdirectory? + bne errpath1 error if not. + ldy #$11 get address of 1st subdirectory block + lda (zpt),y + sta bloknml (no checking done for a valid block#) + iny + sta d_head save as file's header block too + lda (zpt),y + sta bloknml+1 + sta d_head+1 + jsr rdgbuf read subdirectory into gbuf. + bcs fnderr1 if error. + lda gbuf+37 get the # of files contained in this + sta entcntl directory. + lda gbuf+38 + sta entcnth + lda gbuf+20 make sure password is disabled + ldx #$00 + sec + rol +L3869 bcc L386C + inx +L386C asl + bne L3869 + cpx #$05 is password disabled? + beq movhead + lda #$4A directory is not compatible +fnderr1 sec + rts +movhead jsr movhed0 move directory info. + jmp lookfil0 do next local pathname. +movhed0 .EQ *-ofsX + ldx #$0A move this directory info +L387F lda gbuf+28,x + sta h_credt,x + dex + bpl L387F + lda gbuf+4 if this is root, then nothing to do + and #$F0 + eor #$F0 test header type. + beq L389C branch if root + ldx #$03 otherwise, save owner info about +L3893 lda gbuf+39,x this header. + sta own_blk,x + dex + bpl L3893 +L389C rts +entadr .EQ *-ofsX +filfound lda h_maxent figure out which entry # this is + sec + sbc cntent max entries - count entries + 1 + adc #$00 = entry # (carry was set) + sta d_entnum + lda bloknml and indicate block # of this directory + sta d_entblk + lda bloknml+1 + sta d_entblk+1 + clc + rts +looknam .EQ *-ofsX reset count of files per block + lda h_maxent + sta cntent + lda /gbuf + sta zpt+1 + lda #$04 +L38C1 sta zpt reset indirect pointer to gbuf + bcs L38F8 branch if this block contains a header + ldy #$00 + lda (zpt),y get length of name in directory. + bne isname branch if there is a name. + lda nofree test if a free entry has been declared. + bne L38F8 yes, inc to next entry. + jsr entadr set address for current entry. + inc nofree indicate a free spot has been found. + bne L38F8 always. +isname and #$0F strip byte (is checked by 'filfound') + inc totent inc count of valid files found. + sta namcnt save name length as counter. + ldx namptr get index to current path. + cmp pathbuf,x are both names the same length? + bne L38F8 no, inc to next entry. +cmpname inx (first) next letter index + iny + lda (zpt),y compare names letter by letter + cmp pathbuf,x + bne L38F8 + dec namcnt all letters compared? + bne cmpname no, continue. + clc a match is found. +noname rts +L38F8 dec cntent checked all entries in this block? + sec + beq noname yes, no name match. + lda h_entln add entry length to current pointer + clc + adc zpt + bcc L38C1 branch if still in 1st page. + inc zpt+1 look on 2nd page. + clc carry should always be clear before + bcc L38C1 looking at next. +preproot .EQ *-ofsX + jsr findvol search vcb's and dev's for spec'd volume + bcs novolume + lda #$00 zero out directory temps + ldy #$42 +L3914 sta own_blk,y and owner info + dey + bpl L3914 + lda devnum setup device # for this directory + sta d_dev + jsr movhed0 setup other header info from directory + ldy #$01 in gbuf and clean up misc info. + ldx vcbptr + inx +L3929 lda vcbbuf+18,x misc info includes + sta h_tblk,y total # of blocks, + lda vcbbuf+26,x the address of the 1st bitmap, + sta h_bmap,y + lda bloknml,y directory's disk address, + sta d_head,y + lda h_fcnt,y and setting up a counter for the # of + sta entcntl,y files in this directory. + dex + dey + bpl L3929 +nxtpname .EQ *-ofsX + jsr nxtpnam1 get new namptr in y and namlen in acc. + sty namptr save new pathname pointer. + rts (status reg according to accumulator) +nxtpnam1 .EQ *-ofsX + ldy namptr inc pathname pointer to next name + lda pathbuf,y in the path. + sec + adc namptr if this addition results in zero, + tay then prefixed directory has been moved + bne L395F to another device. branch if not. + lda devnum revise devnum for prefixed directory + sta p_dev +L395F lda pathbuf,y test for end of name. + clc no errors +novolume rts +findvol .EQ *-ofsX + lda #$00 + ldy preflag use prefix volume name to look up vcb. + bit prfxflg is this a prefixed path? + bpl L396F branch if it is + tay set ptr to volume name +L396F sty vnptr and save. + sta devnum zero out dev# until vcb located. +L3975 pha acc now used as vcb lookup index. + tax index pointer to x. + lda vcbbuf,x get vcb volume name length. + bne L3987 branch if claimed vcb to be tested. +L397C ldy vnptr restore pointer to requested vol name. + pla now adj vcb index to next vcb entry. + clc + adc #$20 + bcc L3975 branch if more vcb's to check + bcs L39D4 otherwise go look for unlogged volumes. +L3987 sta namcnt save length of vol name to be compared. +L398A cmp pathbuf,y is it the same as requested vol name? + bne L397C branch if not + inx + iny next character + lda vcbbuf,x + dec namcnt last character? + bpl L398A if not. + plx restore pointer to matching vcb. + stx vcbptr save it for future reference. + lda vcbbuf+16,x get it's device # + sta devnum and save it. + stz bloknml+1 assume prefix is not used and + lda #$02 that root directory is to be used. + sta bloknml + lda vnptr = 0 if no prefix. +L39AC tay if prefix then find ptr to prefixed + sta namptr dir name. save path ptr. + beq L39C2 branch if no prefix. + sec + adc pathbuf,y inc to next dir in prefix path. + bcc L39AC branch if another dir in prefix. + lda p_blok volume verification will occur at + sta bloknml subdirectory level. + lda p_blok+1 + sta bloknml+1 + +* verify volume name + +L39C2 jsr rdgbuf read in directory (or prefix dir) + bcs L39CC if error then look on other devices. + jsr cmppnam compare dir name with path name. + bcc L39F0 if they match, stop looking. +L39CC ldx vcbptr check if current (matched) vcb is active + lda vcbbuf+17,x i.e. does it have open files? + bmi L39ED report not found if active. +L39D4 lda vnptr make path ptr same as volume ptr + sta namptr + jsr mvdevnums copy all device #'s to be examined. + lda devnum log current device 1st before searching + bne L39F1 others. +L39E2 ldx numdevs scan look list for devices we need +L39E5 lda loklst,x to search for the requested volume. + bne L39F4 branch if we've a device to look at. + dex + bpl L39E5 look at next one. +L39ED lda #$45 no mounted volume + sec error +L39F0 rts +L39F1 ldx numdevs now remove the device from the list +L39F4 cmp loklst,x of prospective devices. + beq L39FE branch if match. + dex look until found. + bpl L39F4 always taken (usually) unless + bmi L39ED if dev was removed from devlst (/RAM). +L39FE sta devnum preserve device to be checked next. + stz loklst,x mark this one as tested. + jsr fnddvcb find vcb that claims this dev (if any). + bcs L3A29 branch if vcb full. + ldx vcbptr did fndvcb find it or return free vcb? + lda vcbbuf,x + beq L3A16 if free vcb. + lda vcbbuf+17,x is this volume active? + bmi L39E2 if so, no need to re-log. +L3A16 lda #$02 go read root dir into gbuf + ldx #$00 + jsr rdblk + bcs L39E2 ignore if unable to read. + jsr logvcb go log in volume name. + bcs L39E2 look at next if non-xdos disk mounted. + jsr cmppnam is this the volume ? + bcs L39E2 if not +L3A29 rts +mvdevnums .EQ *-ofsX + ldx numdevs copy all dev #'s to be checked. +L3A2D lda devlist,x active device list. + and #$F0 strip device type info. + sta loklst,x copy them to a temp workspace + dex + bpl L3A2D + ldx numdevs + rts +fnddvcb .EQ *-ofsX look for vcb with this device# + lda #$00 + ldy #$FF +L3A40 tax new index to next vcb + lda vcbbuf+16,x check all devnums + cmp devnum is this the vcb? + bne L3A4E if not + stx vcbptr + clc indicates found + rts +L3A4E lda vcbbuf,x is this a free vcb? + bne L3A57 if not + iny + stx vcbptr +L3A57 txa + clc inc index to next vcb + adc #$20 + bne L3A40 + tya any free vcb's available? + bpl L3A79 yes + lda #$00 look for an entry to kick out +L3A62 tax + lda vcbbuf+17,x any open files? + bpl L3A70 no, kick this one out. + txa next vcb + clc + adc #$20 (vcb entry size) + bne L3A62 + beq L3A7A all vcb entries have open files +L3A70 stx vcbptr save entry index. + stz vcbbuf,x free this entry + stz vcbbuf+16,x +L3A79 clc no error. +L3A7A lda #$55 # vcb full error + rts +cmppnam .EQ *-ofsX + ldx #$00 index to directory name. + ldy namptr index to pathname. + lda gbuf+4 get dir name length and type. + cmp #$E0 is it a directory? + bcc L3A90 if not. + and #$0F isolate name length and + sta namcnt save as a counter. + bne L3A95 branch if valid length. +L3A90 sec indicate not found + rts +L3A92 lda gbuf+4,x next char +L3A95 cmp pathbuf,y + bne L3A90 if not the same. + inx check next char + iny + dec namcnt + bpl L3A92 if more to compare. + clc match found + rts +logvcb .EQ *-ofsX + ldx vcbptr previously logged in volume? + lda vcbbuf,x (acc = 0?) + beq L3AB0 no, go prepare vcb. + jsr cmpvcb does vcb match vol read? + bcc L3B05 yes, do not disturb. +logvcb1 .EQ *-ofsX +L3AB0 ldy #$1F zero out vcb entry +L3AB2 stz vcbbuf,x + inx + dey + bpl L3AB2 + jsr tstsos make sure it's an xdos disk + bcs L3B05 if not, return carry set. + jsr tstdupvol does a duplicate with open files + bcs L3B04 already exist? branch if yes. + lda gbuf+4 move volume name to vcb. + and #$0F strip root marker + tay + pha + ora vcbptr + tax +L3ACE lda gbuf+4,y + sta vcbbuf,x + dex + dey + bne L3ACE + pla get length again + sta vcbbuf,x and save. + lda devnum last device used. + sta vcbbuf+16,x save device # and + lda gbuf+41 total # of blocks on this unit. + sta vcbbuf+18,x + lda gbuf+42 + sta vcbbuf+19,x + lda bloknml save address of root directory. + sta vcbbuf+22,x + lda bloknml+1 + sta vcbbuf+23,x + lda gbuf+39 save address of the 1st bitmap. + sta vcbbuf+26,x + lda gbuf+40 + sta vcbbuf+27,x +L3B04 clc indicate logged if possible +L3B05 rts +cmpvcb .EQ *-ofsX compare volume name in vcb + lda gbuf+4 with name in directory. + and #$0F + cmp vcbbuf,x are they the same length? + stx xvcbptr (see rev note #23) + bne L3B1E if not the same. + tay + ora xvcbptr + tax +L3B18 lda gbuf+4,y + cmp vcbbuf,x +L3B1E sec anticipate different names. + bne L3B26 if not the same. + dex + dey + bne L3B18 + clc indicate match. +L3B26 ldx xvcbptr offset to start of vcb (rev note #23) + rts +tstdupvol .EQ *-ofsX check for other logged in volumes + lda #$00 with the same name. +L3B2C tax + jsr cmpvcb + bcs L3B41 if no match. + lda vcbbuf+17,x test for any open files. + bmi L3B4B cannot look at this volume. + lda #$00 take duplicate offline if no open files + sta vcbbuf,x + sta vcbbuf+16,x + beq L3B49 ok to log in new volume. +L3B41 txa index to next vcb + clc + and #$E0 strip odd stuff. + adc #$20 inc to next entry. + bcc L3B2C branch if more to check +L3B49 clc + rts +L3B4B sta duplflag duplicate has been found. + stx vcbentry save pointer to conflicting vcb. + sec error. + rts +tstfrblk .EQ *-ofsX test if enough free blocks available + ldx vcbptr for request. + lda vcbbuf+21,x check if proper count for this volume. + ora vcbbuf+20,x + bne L3BAD branch if count is non-zero. +tkfrecnt .EQ *-ofsX + jsr cntbms get # of bitmaps + sta bmcnt and save. + stz scrtch start count at 0 + stz scrtch+1 + lda #$FF mark 'first free' temp as unknown + sta nofree + jsr upbmap update volume bitmap. + bcs L3BC1 if error. + ldx vcbptr get address of 1st bitmap + lda vcbbuf+26,x + sta bloknml + lda vcbbuf+27,x + sta bloknml+1 +L3B81 jsr rdgbuf use general buffer for temp space to + bcs L3BC1 count free blocks (bits). + jsr count + dec bmcnt was that the last bitmap? + bmi L3B96 if so, go change fcb so not done again. + inc bloknml + bne L3B81 + inc bloknml+1 + bra L3B81 +L3B96 ldx vcbptr mark which block had 1st free space + lda nofree + bmi L3BBE if no free space was found. + sta vcbbuf+28,x update the free count. + lda scrtch+1 + sta vcbbuf+21,x update volume control byte. + lda scrtch + sta vcbbuf+20,x +L3BAD lda vcbbuf+20,x compare total available free blocks + sec on this volume. + sbc reql + lda vcbbuf+21,x + sbc reqh + bcc L3BBE + clc + rts +L3BBE lda #$48 disk full + sec +L3BC1 rts +count .EQ *-ofsX + ldy #$00 +L3BC4 lda gbuf,y bit pattern. + beq L3BCC don't count + jsr cntfree +L3BCC lda gbuf+$100,y do both pages with same loop + beq L3BD4 + jsr cntfree +L3BD4 iny + bne L3BC4 loop until all 512 bytes counted. + bit nofree has 1st block w/free space been found? + bpl L3BEE if yes. + lda scrtch test to see if any blocks were counted + ora scrtch+1 + beq L3BEE branch if none counted. + jsr cntbms get total # of maps. + sec subtract countdown from total bitmaps + sbc bmcnt + sta nofree +L3BEE rts +cntfree .EQ *-ofsX +L3BEF asl count the # of bits in this byte + bcc L3BFA + inc scrtch + bne L3BFA + inc scrtch+1 +L3BFA ora #$00 + bne L3BEF loop until all bits counted + rts +cntbms .EQ *-ofsX + ldx vcbptr + ldy vcbbuf+19,x return the # of bitmaps + lda vcbbuf+18,x possible with the total count + bne L3C0B found in the vcb. + dey adj for bitmap block boundary +L3C0B tya + lsr divide by 16. the result is + lsr the # of bitmaps. + lsr + lsr + rts +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.B +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.XDOS.C.txt b/ProDOS.203/ProDOS.S.XDOS.C.txt index 54913451..191a8917 100644 --- a/ProDOS.203/ProDOS.S.XDOS.C.txt +++ b/ProDOS.203/ProDOS.S.XDOS.C.txt @@ -1,64 +1,290 @@ NEW AUTO 3,1 - + +* deallocate a block's entry in bitmap +* on entry, x,a = address of block + +dealloc .EQ *-ofsX + stx bmcnt high address of block. + pha save low address. + ldx vcbptr check that bitmap block address is + lda vcbbuf+19,x valid given the total # of blocks + cmp bmcnt on the volume. + pla + bcc L3C8C branch if invalid + tax + and #$07 bit to be or'd in + tay + lda whichbit,y (shifting takes 7 bytes, but is slower) + sta nofree save bit pattern. + txa low block address. + lsr bmcnt + ror get pointer to byte in block that + lsr bmcnt represents the block address. + ror + lsr bmcnt + ror + sta bmptr save pointer. + lsr bmcnt transfer bit which is page of bitmap + rol half + jsr fndbmap make sure device is correct one. + bcs L3C8B error. + lda bmacmap current map. + cmp bmcnt is in-core bitmap the correct one ? + beq L3C64 branch if yes. + jsr upbmap put current map away. + bcs L3C8B error. + lda bmcnt get map # + ldx vcbptr + sta vcbbuf+28,x and make it current. + lda bmadev + jsr gtbmap read it into buffer + bcs L3C8B +L3C64 ldy bmptr index to byte + lsr half + lda nofree (get indiviual bit) + bcc L3C77 branch if on page 1 of bitmap + ora bmbuf+$100,y + sta bmbuf+$100,y + bcs L3C7D always. +bmbufhi .EQ *-ofsX this address + 2 is used as an +L3C77 ora bmbuf,y absolute reference to bmbuf high byte. + sta bmbuf,y +L3C7D lda #$80 mark bitmap as modified + tsb bmastat + inc deblock inc count of blocks deallocated + bne L3C8A + inc deblock+1 +L3C8A clc +L3C8B rts +L3C8C lda #$5A bitmap block # impossible. + sec bitmap disk address wrong + rts (maybe data masquerading as indx block) +alc1blk .EQ *-ofsX + jsr fndbmap get address of bitmap. + bcs L3CB8 error. +L3C95 ldy #$00 begin search at start of bitmap block. + sty half which half (page) to search +L3C9A lda bmbuf,y + bne L3CB9 free blocks indicated by 'on' bits + iny + bne L3C9A check all in 1st page. + inc half now search page 2. + inc basval base value = base address / 2048. +L3CA8 lda bmbuf+$100,y search 2nd half for free block + bne L3CB9 + iny + bne L3CA8 + inc basval add 2048 offset for next page. + jsr nxtbmap get next bitmap (if exists) and + bcc L3C95 update vcb. branch if no error. +L3CB8 rts return error. +L3CB9 sty bmptr save index pointer to valid bit group. + lda basval prep for block address calculation + sta scrtch+1 + tya address of bit pattern. + asl multiply this and basval by 8 + rol scrtch+1 + asl + rol scrtch+1 + asl + rol scrtch+1 + tax low address within 7 of actual address + sec + lda half + beq L3CDB branch if allocating from 1st half. + lda bmbuf+$100,y get pattern from 2nd page. + bcs L3CDE always. +L3CDB lda bmbuf,y get bit pattern from 1st page. +L3CDE rol find left most 'on' bit + bcs L3CE4 if found. + inx adjust low address. + bne L3CDE always. +L3CE4 lsr restore pos'n of all but left most bit. + bcc L3CE4 loop until mark moves into carry. + stx scrtch save low address. + ldx half which half of bitmap ? + bne L3CF4 if page 2. + sta bmbuf,y + beq L3CF7 always. +L3CF4 sta bmbuf+$100,y update to show allocated block in use. +L3CF7 lda #$80 indicate map is modified. + tsb bmastat + ldy vcbptr subtract 1 from total free vcb blocks + lda vcbbuf+20,y to account for newly allocated block. + sbc #$01 (carry is set) + sta vcbbuf+20,y + bcs L3D10 if high free count doesn't need adj. + lda vcbbuf+21,y adjust high count + dec a + sta vcbbuf+21,y +L3D10 clc no errors. + lda scrtch return address in y,a of newly + ldy scrtch+1 allocated block. + rts +nxtbmap .EQ *-ofsX inc to next bitmap + ldy vcbptr but 1st make sure there is another one. + lda vcbbuf+19,y + lsr + lsr + lsr + lsr + cmp vcbbuf+28,y are there more maps ? + beq L3D60 if no more to look at. + lda vcbbuf+28,y add 1 to current map + inc + sta vcbbuf+28,y + jsr upbmap +fndbmap .EQ *-ofsX + ldy vcbptr + lda vcbbuf+16,y get device #. + cmp bmadev does this map match this device ? + beq L3D4A yes. + jsr upbmap otherwise, save other volume's bitmap + bcs L3D5F + ldy vcbptr + lda vcbbuf+16,y + sta bmadev and read in fresh bitmap for this dev. +L3D4A ldy bmastat is it already modified ? + bmi L3D54 yes, return pointer + jsr gtbmap otherwise read in fresh bitmap. + bcs L3D5F if error. +L3D54 ldy vcbptr get relative block # of bitmap. + lda vcbbuf+28,y + asl 2 pages per block + sta basval + clc no errors. +L3D5F rts +L3D60 lda #$48 request can't be filled + sec error + rts +upbmap .EQ *-ofsX + clc + lda bmastat is current map modified ? + bpl L3D5F no. + jsr wrtbmap update device. + bcs L3D5F if error on writing. + lda #$00 + sta bmastat mark bitmap buffer as free + rts +gtbmap .EQ *-ofsX read bitmap specified by dev and vcb. + sta bmadev + ldy vcbptr get lowest map # with free blocks in it + lda vcbbuf+28,y + sta bmacmap associate offset with bitmap ctrl block. + clc add this # to the base address of + adc vcbbuf+26,y 1st bitmap and save in bmadadr which + sta bmadadr is address of bitmap to be used. + lda vcbbuf+27,y + adc #$00 + sta bmadadr+1 + lda #$01 read device command +L3D92 sta A4L + lda devnum save current dev # + pha + lda bmadev get bitmap's dev # + sta devnum + lda bmadadr and disk address + sta bloknml + lda bmadadr+1 + sta bloknml+1 + lda bmbufhi+2 address of the buffer (low = 0) + jsr dobitmap + tax error code (if any). + pla restore current dev # + sta devnum + bcc L3DB6 and return it if no error. + txa error code +L3DB6 rts +rdblk .EQ *-ofsX + sta bloknml + stx bloknml+1 + jsr rdgbuf + rts +wrtbmap .EQ *-ofsX write bitmap. + lda #$02 write command. + bne L3D92 always. +wrtgbuf .EQ *-ofsX + lda #$02 write command + bne L3DC9 always. +rdgbuf .EQ *-ofsX + lda #$01 read command. +L3DC9 sta A4L pass to device handler. + lda /gbuf general buffer. +dobitmap .EQ *-ofsX + php no interrupts + sei + sta buf+1 buffer high. + stz buf buffer low (always on page boundary) + stz p8error clear global error code. + lda #$FF indicates reg call made to dev handler + sta ioaccess + lda devnum transfer dev # for dispatcher to + sta unitnum convert to unit #. + jsr dmgr call the driver. + bcs L3DE8 if error. + plp restore interrupts. + clc + rts +L3DE8 plp file i/o error. restore interrupts. + sec + rts + * get mark command - -getmark .EQ *-ofsX +getmark .EQ *-ofsX ldx fcbptr index to open fcb. - ldy #$02 index to user's mark parmeter. -L3DF0 lda fcbbuf+18,x transfer current position + ldy #$02 index to user's mark parmeter. +.1 lda fcbbuf+18,x transfer current position sta (A3L),y to user's parameter list inx iny - cpy #$05 transfer 3 bytes - bne L3DF0 + cpy #$05 transfer 3 bytes + bne .1 clc rts -L3DFD lda #$4D invalid position +L3DFD lda #$4D invalid position sec rts - * set mark command - -setmark .EQ *-ofsX +setmark .EQ *-ofsX ldy #$04 index to user's desired position. - ldx fcbptr file's control block index. - inx inc by 2 for index to hi eof + ldx fcbptr file's control block index. + inx inc by 2 for index to hi eof inx - sec indicate comparisons are necessary. -L3E09 lda (A3L),y move it to 'tpos' + sec indicate comparisons are necessary. +.1 lda (A3L),y move it to 'tpos' sta tposll-2,y - bcc L3E18 branch if mark < eof + bcc .2 branch if mark < eof cmp fcbbuf+21,x - bcc L3E18 branch if mark qualifies. - bne L3DFD branch if mark > eof (invalid position) + bcc .2 branch if mark qualifies. + bne L3DFD branch if mark > eof (invalid position) dex -L3E18 dey move/compare next lower byte of mark. - tya test for all bytes moved/tested. - eor #$01 preserves carry status. - bne L3E09 branch if more. -rdposn .EQ *-ofsX +.2 dey move/compare next lower byte of mark. + tya test for all bytes moved/tested. + eor #$01 preserves carry status. + bne .1 branch if more. +rdposn .EQ *-ofsX ldy fcbptr test to see if new position is - lda fcbbuf+19,y within the same (current) data block. + lda fcbbuf+19,y within the same (current) data block. and #$FE sta scrtch - lda tposlh middle byte of new position + lda tposlh middle byte of new position sec sbc scrtch sta scrtch - bcc L3E44 branch if < current position. - cmp #$02 must be within 512 bytes of beginning - bcs L3E44 of current position. - lda tposhi make sure within the same 64k. + bcc L3E44 branch if < current position. + cmp #$02 must be within 512 bytes of beginning + bcs L3E44 of current position. + lda tposhi make sure within the same 64k. cmp fcbbuf+20,y - bne L3E44 branch if not. - jmp svmark if so, adj fcb, position ptr and return. -L3E44 lda fcbbuf+7,y determine file type for positioning. - beq L3E50 0 = invalid file type. - cmp #$04 tree class file? - bcc L3E59 yes, go position. + bne L3E44 branch if not. + jmp svmark if so, adj fcb, position ptr and return. +L3E44 lda fcbbuf+7,y determine file type for positioning. + beq L3E50 0 = invalid file type. + cmp #$04 tree class file? + bcc L3E59 yes, go position. jmp dirmark no, test for dir type. -L3E50 ldy #$A4 clear illegal filetype entry in fcb +L3E50 ldy #$A4 clear illegal filetype entry in fcb sta fcbbuf,y lda #$43 and report error sec @@ -71,36 +297,36 @@ L3E59 lda fcbbuf+7,y use storage type as # of index levels jsr wfcbdat bcs L3ED4 if error. L3E6B ldy fcbptr test to see if current index block - lda fcbbuf+20,y is usable by checking if new + lda fcbbuf+20,y is usable by checking if new and #$FE position is within 128k of the sta scrtch beginning of current sapling level lda tposhi chunk. sec sbc scrtch - bcc L3E9D branch if a new index block is needed. - cmp #$02 is new position within 128k of old ? - bcs L3E9D branch if not. - ldx levels is it a seed file ? + bcc L3E9D branch if a new index block is needed. + cmp #$02 is new position within 128k of old ? + bcs L3E9D branch if not. + ldx levels is it a seed file ? dex - bne datlevel no, use current indexes. -L3E89 lda tposlh is new position < 512 ? - lsr a + bne datlevel no, use current indexes. +L3E89 lda tposlh is new position < 512 ? + lsr ora tposhi - bne L3EEF no, mark both data and index block as - lda fcbbuf+12,y unallocated. 1st block is only block - sta bloknml and it's data. - lda fcbbuf+13,y high block address. - jmp rnewpos go read in block and set statuses. -L3E9D lda fcbbuf+8,y check to see if previous index block - and #$80 was modified. - beq L3EA9 read in over it if current up to date. - jsr wfcbidx go update index on disk (fcb block addr) + bne L3EEF no, mark both data and index block as + lda fcbbuf+12,y unallocated. 1st block is only block + sta bloknml and it's data. + lda fcbbuf+13,y high block address. + jmp rnewpos go read in block and set statuses. +L3E9D lda fcbbuf+8,y check to see if previous index block + and #$80 was modified. + beq L3EA9 read in over it if current up to date. + jsr wfcbidx go update index on disk (fcb block addr) bcs L3ED4 L3EA9 ldx levels be sure there is a top index cpx #$03 before reading it... - beq posindex branch if file is a tree. + beq posindex branch if file is a tree. lda tposhi is new position within range of a - lsr a sapling file (less than 128k) ? + lsr sapling file (less than 128k) ? php save results lda #$07 (no level is allocated for new pos'n) plp restore z-flag. @@ -121,7 +347,7 @@ posindex jsr clrstats clr all alloc requirements for previous jsr rfcbfst position. get highest level index block bcs L3ED4 lda tposhi then test for a sap level index block - lsr a + lsr tay lda (zpt),y inc zpt+1 @@ -139,9 +365,9 @@ saplevel sta bloknml read in next lower index block. jsr rfcbidx read in sapling level bcs L3ED4 datlevel lda tposhi get block address of data block - lsr a + lsr lda tposlh ( if there is one ) - ror a + ror tay lda (zpt),y data block address low inc zpt+1 @@ -154,8 +380,8 @@ datlevel lda tposhi get block address of data block L3F18 ldy fcbptr set status to show what's missing ora fcbbuf+8,y sta fcbbuf+8,y - lsr a discard bit that says data block - lsr a unallocated because carry indicates if + lsr discard bit that says data block + lsr unallocated because carry indicates if jsr zipdata index block is invalid and needs to be bcc L3F61 zeroed. branch if it doesn't need zeroed jsr zeroindex zero index block in user's i/o buffer @@ -224,7 +450,7 @@ dirmark .EQ *-ofsX lda #$4A no, so compatability problem. jsr p8errv should not have been opened !!! L3F9C lda scrtch recover results of previous subtraction. - lsr a use difference as counter for how many + lsr use difference as counter for how many sta cntent blocks must be read to get to new pos'n. lda fcbbuf+19,y test for positive direction cmp tposlh indicated by carry. @@ -282,7 +508,7 @@ rfcbidx .EQ *-ofsX prepare to read index block. clc L400C rts L400D lda #$02 write command - dc h'2C' skip next instruction + .HS 2C skip next instruction rfcbfst .EQ *-ofsX lda #$01 read command. pha save the command @@ -389,10 +615,10 @@ L40CB lda d_dev-1,x move ownership info. dex entry buffer. bne L40CB lda d_stor get storage type and - lsr a strip off file name length - lsr a by dividing by 16. - lsr a - lsr a + lsr strip off file name length + lsr by dividing by 16. + lsr + lsr tax save in x for later comparison sta fcbbuf+7,y and in fcb for future access. lda d_attr get file's attributes and use it @@ -508,1546 +734,7 @@ L41C1 tya calc position of next fcb. clc report no conflicts. rts -* read command -readf .EQ *-ofsX - jsr mvdbufr xfer buffer address and request count - jsr mvcbytes to a more accessable location, also - pha get fcb attributes and save on stack. - jsr calcmrk calc mark after read, test if mark > eof - pla carry set means end mark > eof. - and #$01 test for read enabled. - bne L41DE branch if ok to read. - lda #$4E illegal access. - bne L4202 always. -L41DE bcc L4205 branch if result mark < eof. adjust - ldy fcbptr request to read until just before eof. - lda fcbbuf+21,y result = (eof-1) - position - sbc tposll - sta cbytes - sta rwreql - lda fcbbuf+22,y - sbc tposlh - sta cbytes+1 - sta rwreqh - ora cbytes if both bytes = 0 then eof error - bne L4210 - lda #$4C eof error -L4202 jmp errfix1 -L4205 lda cbytes - ora cbytes+1 - bne L4210 if read request definitely non-zero. -L420D jmp rwdone do nothing. -L4210 jsr valdbuf validate user's data buffer range. - bcs L4202 branch if memory conflict. - jsr gfcbstyp get storage type - cmp #$04 and find out if it's a tree or other. - bcc L421F branch if a tree file - jmp dread otherwise assume it's a directory. -L421F jsr rdposn set up data pointer. - bcs L4202 errors. - jsr preprw test for newline, setup for partial - jsr readpart read. move current data buffer contents - bvs L420D to user area. branch if satisfied. - bcs L421F indicates newline is set. - lda rwreqh how many blocks are to be read ? - lsr a if < 2 then use the slow way. - beq L421F - sta cmdtemp save bulk block count. - jsr gfcbstat make sure current data area doesn't - and #$40 need writing before resetting ptr to - bne L421F read into user's area. branch if data - sta ioaccess needs to be written to force 1st call - lda usrbuf thru all dev handler checking. make - sta datptr the data buffer the user's space. - lda usrbuf+1 - sta datptr+1 -L4249 jsr rdposn get next block directly into user space. - bcs L42B7 if error. -L424E inc datptr+1 incll ptrs by one block (512 bytes) - inc datptr+1 - dec rwreqh - dec rwreqh - inc tposlh - inc tposlh - bne L4269 if pos'n doesn't get to a 64k boundary - inc tposhi otherwise, must check for a 128k one. - lda tposhi carry set if 128k boundary reached. - eor #$01 - lsr a -L4269 dec cmdtemp has all been read fast ? - bne L427B branch if more to read. - jsr fxdatptr go fix up data pointer to xdos buffer. - lda rwreql test for end of read. - ora rwreqh are both 0 ? - beq L42C3 yes, done. - bne L421F no, read last partial block -L427B bcs L4249 - lda tposhi get index to next block address - lsr a - lda tposlh - ror a - tay index to address = int(pos/512) - lda (zpt),y get low address - sta bloknml - inc zpt+1 - cmp (zpt),y are hi and low address the same? - bne L4299 no, it's a real block address. - cmp #$00 are both bytes 0 ? - bne L4299 no, must be real data. - sta ioaccess don't do repeat io just after sparse. - beq L429C branch always (carry set). -L4299 lda (zpt),y get high address - clc -L429C dec zpt+1 - bcs L4249 if no block to read. - sta bloknml+1 - lda ioaccess has 1st call gone to device yet ? - beq L4249 no, go thru normal route - clc - php interrupts can't occur during dmgr call - sei - lda datptr+1 reset hi buffer address for dev handler - sta buf+1 - jsr dmgr - bcs L42B6 if error - plp - bcc L424E no errors, branch always. -L42B6 plp restore interrupts. -L42B7 pha save error code. - jsr fxdatptr go restore data pointers, etc. - pla -errfix1 .EQ *-ofsX - pha save error code - jsr rwdone pass back # of bytes actually read - pla - sec error - rts -rwdone .EQ *-ofsX -L42C3 ldy #$06 return total # of bytes actually read - sec derived from cbytes-rwreq. - lda cbytes - sbc rwreql - sta (A3L),y - iny - lda cbytes+1 - sbc rwreqh - sta (A3L),y - jmp rdposn leave with valid position in fcb. -preprw .EQ *-ofsX - ldy fcbptr adj pointer to user's buffer to make - sec the transfer - lda usrbuf - sbc tposll - sta usrbuf - bcs L42E9 if no adjustment to hi address needed - dec usrbuf+1 -L42E9 lda fcbbuf+31,y test for new line enabled. - clc - beq L42F9 if new line not enabled. - sec carry indicates new line enabled - sta nlmask - lda fcbbuf+10,y move newline character to more - sta nlchar accesible spot. -L42F9 ldy tposll index to 1st data. - lda datptr reset low order of position pointer to - sta sos beginning of page. - ldx rwreql get low order count of requested bytes. - rts return statuses. -readpart .EQ *-ofsX - txa x = low count of bytes to move. - bne L430F branch if request is not an even page. - lda rwreqh a call of 0 bytes should never get here! - beq L435D branch if nothing to do. - dec rwreqh -L430F dex -L4310 lda (sos),y move data to user's buffer - sta (usrbuf),y - bcs tstnewl test for newline 1st ! -L4316 txa note: x must be unchanged from tstnewl ! - beq L4332 go see if read request is satified... -L4319 dex dec # of bytes left to move. - iny page crossed ? - bne L4310 no, move next byte. - lda sos+1 test for end of buffer, but first - inc usrbuf+1 adjust user buffer pointer - inc tposlh and position - bne L4329 - inc tposhi -L4329 inc sos+1 and sos buffer high address. - eor datptr+1 (carry is undisturbed) - beq L4310 branch if more to read in buffer. - clv indicate not finished. - bvc L4360 always. -L4332 lda rwreqh - beq L4350 branch if request is satisfied. - iny done with this block of data ? - bne L4340 no, adjust high byte of request. - lda sos+1 maybe, check for end of block buffer. - eor datptr+1 (don't disturb carry). - bne L4343 if hi count can be dealt with next time -L4340 dec rwreqh -L4343 dey restore proper value - bra L4319 -tstnewl lda (sos),y get last byte transferred again. - and nlmask only bits on in mask are significant. - eor nlchar does it match newline character? - bne L4316 no, read next. -L4350 iny adjust position. - bne L435D - inc usrbuf+1 inc pointers - inc tposlh - bne L435D - inc tposhi -L435D bit setvflg (sets v flag) -L4360 sty tposll save low position - bvs L4366 - inx leave request as +1 for next call -L4366 stx rwreql and remainder of request count. - php save statuses - clc adjust user's low buffer address - tya - adc usrbuf - sta usrbuf - bcc L4374 - inc usrbuf+1 adjust hi address as needed. -L4374 plp restore return statuses. -setvflg .EQ *-ofsX this byte ($60) is used to set v flag. - rts -fxdatptr .EQ *-ofsX put current user buffer - lda datptr address back to normal - sta usrbuf - lda datptr+1 - sta usrbuf+1 bank pair byte should be moved also. - ldy fcbptr restore buffer address - jmp fndfcbuf - -* read directory file - -dread .EQ *-ofsX -L4384 jsr rdposn - bcs L43B8 pass back any errors. - jsr preprw prepare for transfer. - jsr readpart move data to user's buffer. - bvc L4384 repeat until request is satisfied. - jsr rwdone update fcb as to new position. - bcc L43B6 branch if done with no errors. - cmp #$4C was last read to end of file ? - sec anticipate some other error. - bne L43B7 branch if not eof error. - jsr svmark - jsr zipdata clear out data block. - ldy #$00 provide dummy back pointer for future - ldx fcbptr re-position. x = hi byte of last block -L43A6 lda fcbbuf+16,x - sta (datptr),y - lda #$00 mark current block as impossible - sta fcbbuf+16,x - inx - iny inc indexes to do both hi and low bytes - cpy #$02 - bne L43A6 -L43B6 clc no error -L43B7 rts -L43B8 jmp errfix1 report how much xfer'd before error. -mvcbytes .EQ *-ofsX move request count to a more - ldy #$04 accessable location - lda (A3L),y - sta cbytes - sta rwreql - iny - lda (A3L),y - sta cbytes+1 - sta rwreqh - ldy fcbptr return y = val(fcbptr), - lda fcbbuf+9,y a = attributes - clc and carry clear... - rts -mvdbufr .EQ *-ofsX move the pointer to user's buffer - ldy #$02 to the block file manager - lda (A3L),y - sta usrbuf z-page area - iny - lda (A3L),y - sta usrbuf+1 -gfcbstyp .EQ *-ofsX - ldy fcbptr return storage type - lda fcbbuf+7,y - rts - -* this subroutine adds the requested byte count to mark and returns sum -* in scrtch and also returns mark in tpos and oldmark. -* -* on exit: -* y,x,a is unknown -* carry set indicates scrtch > eof - -calcmrk .EQ *-ofsX - ldx #$00 - ldy fcbptr - clc -L43EE lda fcbbuf+18,y - sta tposll,x - sta oldmark,x - adc cbytes,x - sta scrtch,x - txa - eor #$02 cbytes+2 always=0 - beq L4406 - iny - inx - bne L43EE always. -eoftest .EQ *-ofsX -L4406 lda scrtch,x new mark in scrtch. - cmp fcbbuf+21,y is new position > eof ? - bcc L4414 no, proceed. - bne L4414 yes, adjust 'cbytes' request - dey - dex all tree bytes compared ? - bpl L4406 no, test next lowest -L4414 rts -werreof .EQ *-ofsX - jsr plus2fcb reset eof to pre-error position. -L4418 lda oldeof,x place oldeof back into fcb - sta fcbbuf+21,y - lda oldmark,x also reset mark to last best - sta fcbbuf+18,y write position - sta scrtch,x and copy mark to scrtch for test of - dey eof less than mark. - dex - bpl L4418 - jsr plus2fcb get pointers to test eof < mark. - jsr eoftest carry set means mark > eof !! - -* drop into wadjeof to adjust eof to mark if necessary - -wadjeof .EQ *-ofsX - jsr plus2fcb get y=fcbptr+2, x=2, a=y. -L4434 lda fcbbuf+21,y copy eof to old eof - sta oldeof,x - bcc L4442 and if carry set... - lda scrtch,x then copy scrtch to fcb's eof. - sta fcbbuf+21,y -L4442 dey - dex copy all 3 bytes - bpl L4434 - rts -plus2fcb .EQ *-ofsX - lda #$02 on exit both a and y = fcbptr+2. - tax x = 2 - ora fcbptr - tay - rts - -* write command - -writef .EQ *-ofsX first determine if requested - jsr mvcbytes write is legal. - pha - jsr calcmrk save a copy of eof to old eof, set/clr - jsr wadjeof carry to determine if new mark > eof. - pla get attributes again. - and #$02 is write enabled ? - bne L4462 yes, continue... -L445E lda #$4E illegal access error. - bne L44A2 -L4462 jsr tstwprot otherwise, make sure device is not - bcs L44A2 write protected. if so, branch to abort. - lda cbytes - ora cbytes+1 anything to write ? - bne L4472 branch if so, - jmp rwdone else do nothing. -L4472 jsr mvdbufr move the user's buffer ptr to bfm zero - cmp #$04 page area, also get storage type. - bcs L445E if not tree, return an access error. -L4479 jsr rdposn - bcs L44A2 - jsr gfcbstat - and #$07 - beq L44E9 - ldy #$00 is enough disk space available for -L4487 iny indexes and data block ? - lsr a - bne L4487 - sty reql - sta reqh - jsr tstfrblk - bcs L44A2 pass back any errors. - jsr gfcbstat now get more specific. - and #$04 are we lacking a tree top ? - beq L44AC no, test for lack of sapling level index - jsr topdown go allocate tree top and adj file type. - bcc L44B8 continue with allocation of data block. -L44A2 pha save error. - jsr errfix1 error return. - jsr werreof adjust eof and mark to pre-error state. - pla restore error code. - sec - rts -L44AC jsr gfcbstat get status byte again. - and #$02 do we need a sapling level index block ? - beq L44B8 no, assume it's just a data block needed - jsr sapdown go alloc an indx blk and update tree top - bcs L44A2 if error. -L44B8 jsr alcwblk go allocate for data block. - bcs L44A2 - jsr gfcbstat clear allocation required bits in status - ora #$80 but first indicate index block is dirty. - and #$F8 - sta fcbbuf+8,y - lda tposhi calculate position within index block. - lsr a - lda tposlh - ror a - tay now put block address into index block. - inc zpt+1 high byte first. - lda scrtch+1 - tax - sta (zpt),y - dec zpt+1 restore pointer to lower page of index - lda scrtch block. get low block address. - sta (zpt),y store low address. - ldy fcbptr update fcb to indicate that this block - sta fcbbuf+16,y is allocated. - txa get high address again. - sta fcbbuf+17,y -L44E9 jsr preprw - jsr wrtpart - bvc L4479 - jmp rwdone update fcb with new position -wrtpart .EQ *-ofsX - txa - bne L44FF branch if request is not even pages - lda rwreqh a call of 0 bytes should never get here! - beq L4546 do nothing - dec rwreqh -L44FF dex - lda (usrbuf),y move data from user's buffer - sta (sos),y - txa - beq L4525 -L4507 iny page crossed ? - bne L44FF no, keep moving. - lda sos+1 test for end of buffer - inc usrbuf+1 but first adjust user buffer pointer - inc tposlh and position - bne L451C - inc tposhi - bne L451C - lda #$4D out of range if > 32MB - bne L44A2 -L451C inc sos+1 adjust sos buffer high address - eor datptr+1 (carry is undisturbed) - beq L44FF branch if more to write to buffer. - clv indicates not finished. - bvc L4549 always. -L4525 lda rwreqh - beq L4539 branch if request satisfied. - iny done with this block of data ? - bne L4533 if not. - lda sos+1 this is necessary for proper - eor datptr+1 adjustment of request count - bne L4536 -L4533 dec rwreqh -L4536 dey reset modified y - bra L4507 -L4539 iny and position - bne L4546 - inc usrbuf+1 inc pointers - inc tposlh - bne L4546 - inc tposhi -L4546 bit setvflg set v flag -L4549 sty tposll save low position - stx rwreql and remainder of request count. - php save statuses - jsr gfcbstat - ora #$50 - sta fcbbuf+8,y - clc adjust user's low buffer address - lda tposll - adc usrbuf - sta usrbuf - bcc L4564 - inc usrbuf+1 adjust high address as needed. -L4564 jsr fcbused set directory flush bit. - plp restore return statuses - rts -topdown .EQ *-ofsX - jsr swapdown make current 1st block an entry in new - bcs L45B1 top. branch if errors. - jsr gfcbstyp get storage type - -* has storage type been changed to 'tree' ? if not, assume it was originally -* a seed and both levels need to be built. otherwise, only an index needs -* to be allocated. - - cmp #$03 tree type - beq L457A - jsr swapdown make previous swap a sap level index - bcs L45B1 block. branch if errors. -L457A jsr alcwblk get another block address for the sap - bcs L45B1 level index. branch if errors. - lda tposhi calculate position of new index block - lsr a in the top of the tree. - tay - lda scrtch get address of newly allocated index - tax block again. - sta (zpt),y - inc zpt+1 - lda scrtch+1 - sta (zpt),y save hi address - dec zpt+1 - ldy fcbptr make newly allocated block the current - sta fcbbuf+15,y index block. - txa - sta fcbbuf+14,y - jsr wfcbfst save new top of tree - bcs L45B1 - jmp zeroindex zero index block in user's i/o buffer. -sapdown .EQ *-ofsX - jsr gfcbstyp find out if dealing with a tree. - cmp #$01 if seed then adj to file type is needed. - beq L45B2 branch if seed - jsr rfcbfst otherwise read in top of tree. - bcc L457A if no error. -L45B1 rts return errors. -swapdown .EQ *-ofsX make current seed into a sapling. -L45B2 jsr alcwblk allocate a block before swap. - bcs L45F6 return errors. - ldy fcbptr get previous first block - lda fcbbuf+12,y address into index block. - pha save temporarily while swapping in new - lda scrtch top index. get new block address (low) - tax - sta fcbbuf+12,y - lda fcbbuf+13,y - pha - lda scrtch+1 and high address too - sta fcbbuf+13,y - sta fcbbuf+15,y make new top also the current index in - txa memory. get low address again. - sta fcbbuf+14,y - inc zpt+1 make previous the 1st entry in sub index - pla - sta (zpt) - dec zpt+1 - pla - sta (zpt) - jsr wfcbfst save new file top. - bcs L45F6 if error. - jsr gfcbstyp now adjust storage type by adding 1 - adc #$01 (seed becomes sapling becomes tree) - sta fcbbuf+7,y - lda fcbbuf+8,y mark storage type modified - ora #$08 - sta fcbbuf+8,y - clc no error -L45F6 rts -alcwblk .EQ *-ofsX - jsr alc1blk - bcs L4616 - jsr gfcbstat mark usage as modified - ora #$10 - sta fcbbuf+8,y - lda fcbbuf+24,y inc current usage count by 1 - clc - adc #$01 - sta fcbbuf+24,y - lda fcbbuf+25,y - adc #$00 - sta fcbbuf+25,y -L4615 clc no error -L4616 rts -tstwprot .EQ *-ofsX check for 'never been modified' - jsr gfcbstat condition - and #$F0 - bne L4615 ordinary rts if known write ok. - lda fcbbuf+1,y get file's dev #. - sta devnum get current status of block device. -twrprot1 .EQ *-ofsX make the device status call - sta unitnum - lda bloknml+1 - pha - lda bloknml save the current block values - pha - stz A4L - stz bloknml zero the block # - stz bloknml+1 - php - sei - jsr dmgr - bcs L463B branch if write protect error - lda #$00 otherwise, assume no errors. -L463B plp restore interrupt status - clc - tax save error. - beq L4641 branch if no error - sec else, set carry to show error. -L4641 pla - sta bloknml restore the block # - pla - sta bloknml+1 - txa - rts carry is indeterminate. - -* close command - -closef .EQ *-ofsX close all ? - ldy #$01 - lda (A3L),y - bne L4683 no, just one of them. - sta cferr clear global close error. - lda #$00 start at the beginning. -L4654 sta fcbptr save current low byte of pointer. - tay get the level at which the file - lda fcbbuf+27,y was opened. - cmp flevel if file's level is < global level - bcc L4675 then don't close. - lda fcbbuf,y is this reference file open ? - beq L4675 no, try next. - jsr flush2 clean it out... - bcs L46B6 return flush errors. - jsr close2 update fcb & vcb - ldy #$01 - lda (A3L),y - beq L4675 no error if close all. - bcs L46B6 close error. -L4675 lda fcbptr inc pointer to next fcb - clc - adc #$20 - bcc L4654 branch if within same page. - lda cferr on final close report logged errors. - beq L46B4 branch if errors. - rts (carry already set). -L4683 jsr flush1 flush file 1st (including updating - bcs L46B6 bitmap). branch if errors. -close2 .EQ *-ofsX - ldy fcbptr - lda fcbbuf+11,y release file buffer - jsr relbuffr - bcs L46B6 - lda #$00 - ldy fcbptr - sta fcbbuf,y free fcb too - lda fcbbuf+1,y - sta devnum go look for associated vcb - jsr fnddvcb - ldx vcbptr get vcb pointer. - dec vcbbuf+30,x indicate one less file open. - bne L46B4 branch if that wasn't the last... - lda vcbbuf+17,x - and #$7F strip 'files open' bit - sta vcbbuf+17,x -L46B4 clc - rts -L46B6 bcs L46E6 don't report close all error now. - -* flush command - -flushf .EQ *-ofsX - ldy #$01 flush all ? - lda (A3L),y - bne L46E9 no, just one of them. - sta cferr clear global flush error. - lda #$00 start at the beginning. -L46C3 sta fcbptr save current low byte of pointer. - tay index to ref #. - lda fcbbuf,y is this reference file open ? - beq L46D1 no, try next. - jsr flush2 clean it out... - bcs L46E6 return anty errors. -L46D1 lda fcbptr inc pointer to next fcb. - clc - adc #$20 - bcc L46C3 branch if within same page -L46D9 clc - lda cferr on last flush, - beq L46E0 branch if no logged errors. - sec report error now -L46E0 rts -flush2 .EQ *-ofsX - jsr fndfcbuf must set up vcb & buffer locations 1st. - bcc L46F1 branch if no error. -L46E6 jmp glberr error so check for close or flush all. -flush1 .EQ *-ofsX for normal refnum flush, -L46E9 stz cferr clear global error. - jsr findfcb setup pointer to fcb user references. - bcs L46E6 return any errors. -L46F1 lda fcbbuf+9,y test to see if file is modified. - and #$02 is it write enabled ? - beq L46D9 branch if 'read only' - lda fcbbuf+28,y has eof been modified ? - bmi L4704 if yes. - jsr gfcbstat has data been modified ? - and #$70 (was written to while it's been open?) - beq L46D9 if not. -L4704 jsr gfcbstat - and #$40 does current data buffer need to be - beq L4710 written ? branch if not. - jsr wfcbdat if so, go write it. - bcs L46E6 if error. -L4710 jsr gfcbstat check to see if the index block (tree - and #$80 files only) needs to be written. - beq L471C branch if not. - jsr wfcbidx - bcs L46E6 return any errors. -L471C lda #$06 prepare to update directory - tax - ora fcbptr - tay -L4723 lda fcbbuf,y note: this code depends on the defined - sta d_dev-1,x order of the file control block and the - dey temporary directory area in 'work space' - dex - bne L4723 - sta devnum - lda d_head read the directory header for this file - ldx d_head+1 - jsr rdblk into the general purpose buffer. - bcs L46E6 if error. - jsr movhed0 move header info. - lda d_entblk get address of directory block that - ldy d_entblk+1 contains the file entry. - cmp d_head test to see if it's the same block the - bne L474E header is in. branch if not. - cpy d_head+1 - beq L4755 branch if header block = entry block -L474E sta bloknml - sty bloknml+1 - jsr rdgbuf get block with file entry in general -L4755 jsr entcalc buffer. set up pointer to entry. - jsr moventry move entry to temp entry buffer in - ldy fcbptr 'work space'. update 'blocks used' count - lda fcbbuf+24,y - sta d_usage - lda fcbbuf+25,y - sta d_usage+1 - ldx #$00 and move in end of file mark whether -L476C lda fcbbuf+21,y needed or not. - sta d_eof,x - inx - cpx #$03 move all 3 bytes - beq L4780 - lda fcbbuf+12,y also move in the address of the file's - sta d_filid,x first block since it might have changed - iny since the file first opened. - bne L476C branch always. -L4780 lda fcbbuf+5,y the last thing to update is storage - asl type (y=fcbptr+2). shift into high - asl nibble. - asl - asl - sta scrtch - lda d_stor get old type byte (might be the same). - and #$0F strip off old type, - ora scrtch add in the new type - sta d_stor and put it away. - jsr drevise go update directory. - bcs L47B4 error. - ldy fcbptr mark - lda fcbbuf+28,y fcb/directory - and #$7F as - sta fcbbuf+28,y undirty. - lda d_dev see if bitmap should be written. - cmp bmadev is it in same as current file ? - bne L47B2 yes, put it on the disk if necessary. - jsr upbmap go put it away. - bcs L47B4 flush error -L47B2 clc - rts - -* report error only if not a close all or flush all - -glberr .EQ *-ofsX -L47B4 ldy #$01 - pha - lda (A3L),y - bne L47C1 not an 'all' so report now - clc - pla - sta cferr save for later - rts -L47C1 pla - rts -gfcbstat .EQ *-ofsX - ldy fcbptr index to fcb. - lda fcbbuf+8,y return status byte. - rts -L47CA lda #$4E access error - sec -L47CD rts - -seteof .EQ *-ofsX can only move end of tree, sapling - jsr gfcbstyp or seed. - cmp #$04 tree type ? - bcs L47CA if not then access error - asl - asl - asl - asl - sta stortyp may be used later. - lda fcbbuf+9,y - and #$02 is write enabled to set new eof ? - beq L47CA no, access error. - jsr tstwprot hardware write protected ? - bcs L47CA yes, access error. - ldy fcbptr save old eof so it can be seen - iny whether blocks need to be released - iny upon contraction. - ldx #$02 all 3 bytes of the eof -L47EF lda fcbbuf+21,y - sta oldeof,x - dey - dex - bpl L47EF - ldy #$04 - ldx #$02 -L47FD lda (A3L),y position mark to new eof - sta tposll,x - dey - dex - bpl L47FD - ldx #$02 point to 3rd byte. -L4808 lda oldeof,x see if eof moved backwards so blocks - cmp tposll,x can be released. - bcc L4815 (branch if not) - bne purge branch if blocks to be released - dex - bpl L4808 all 3 bytes -eofset .EQ *-ofsX -L4815 ldy #$04 - ldx fcbptr place new end of file into fcb - inx - inx -L481C lda (A3L),y - sta fcbbuf+21,x - dex - dey - cpy #$02 all 3 bytes moved ? - bcs L481C no. - jmp fcbused mark fcb as dirty. -purge jsr flush1 make sure file is current - bcs L47CD - ldx datptr+1 pointer to index block - inx - inx - stx zpt+1 (zero page conflict with dir buf ptr) - ldx datptr - stx zpt - ldy fcbptr check if eof < mark - iny - iny - ldx #$02 -L4840 lda fcbbuf+18,y - cmp tposll,x compare until not equal or carry clear. - bcc L485F branch if eof > mark. - bne L484E branch if eof < mark. - dey - dex - bpl L4840 compare all 3 bytes -L484E ldy fcbptr - ldx #$00 -L4853 lda tposll,x fake position, correct position will - sta fcbbuf+18,y be made below... - iny - inx - cpx #$03 move all 3 bytes - bne L4853 -L485F jsr tkfrecnt force free block count before releasing - lda tposll blocks. prepare for purge of excess... - sta dseed all blocks and bytes beyond new eof - lda tposlh must be zero'd - sta dsap - and #$01 - sta dseed+1 - lda tposhi - lsr a - sta dtree - ror dsap pass position in terms of block & bytes. - lda dseed now adjust for boundaries of $200 - ora dseed+1 - bne L48A2 branch if no adjustment necessary. - lda dsap get correct block ositions for sap - sec and tree levels. - sbc #$01 - sta dsap deallocate for last (phantom) block - lda #$02 and don't modify last data block. - bcs L489F branch if tree level unaffected. - dec dtree - bpl L489F branch if new eof not zero - lda #$00 - sta dtree otherwise, make a null seed out of it. - sta dsap -L489F sta dseed+1 -L48A2 ldy fcbptr also must pass file's 1st block address. - lda fcbbuf+12,y - sta firstbl - lda fcbbuf+13,y - sta firstbh - stz deblock lastly, initialize # of blocks to - stz deblock+1 be free'd. - jsr detree deallocate blocks from tree. - php save any error status until fcb - pha is cleaned up. - sec - ldy fcbptr - ldx #$00 -L48C2 lda firstbl,x - sta fcbbuf+12,y move in possible new first file block - lda fcbbuf+24,y address. adjust usage count also - sbc deblock,x - sta fcbbuf+24,y - iny - inx - txa - and #$01 test for both bytes adjusted - bne L48C2 without disturbing carry. - lda stortyp get possibly modified storage type - lsr a - lsr a - lsr a - lsr a - ldy fcbptr and save it in fcb. - sta fcbbuf+7,y - jsr clrstats make it look as though position has - jsr dvcbrev nothing allocated, update total blocks - ldy fcbptr in fcb and correct position. - iny - iny - ldx #$02 -L48F2 lda fcbbuf+18,y tell 'rdposn' to go to correct - sta tposll,x - eor #$80 position from incorrect place. - sta fcbbuf+18,y - dey - dex - bpl L48F2 - jsr rdposn go to correct position. - bcc L490D if no error. - tax otherwise, report latest error. - pla - plp - txa restore latest error code to stack - sec - php - pha save new error. - -* mark file as in need of a flush and update fcb with new end of file, -* then flush it. - -L490D jsr eofset go mark and update - jsr flush1 then go do the flush. - bcc L491C branch if no error. - tax save latest error. - pla clean previous error off stack - plp - txa and restore latest error to stack. - sec show error condition. - php restore error status to stack - pha and the error code. -L491C pla report any errors that may have - plp appeared. - rts - -geteof .EQ *-ofsX - ldx fcbptr index to end of file mark - ldy #$02 and index to user's call parameters -L4924 lda fcbbuf+21,x - sta (A3L),y - inx - iny - cpy #$05 - bne L4924 loop until all 3 bytes moved - clc no errors - rts - -newline .EQ *-ofsX - ldy #$02 adjust newline status for open file. - lda (A3L),y on or off ? - ldx fcbptr it will be 0 if off. - sta fcbbuf+31,x set new line mask - iny - lda (A3L),y and move in 'new-line' byte - sta fcbbuf+10,x - clc no error possible - rts - -getinfo .EQ *-ofsX - jsr findfile look for file. - bcc L4988 no error. - cmp #$40 was it a root directory file ? - sec (in case of no match) - bne L49A4 if not, then error. - lda #$F0 - sta d_stor for get info, report proper storage - stz reql type. forca a count of free blocks. - stz reqh - ldx vcbptr - jsr tkfrecnt get a fresh count of free blocks on - ldx vcbptr this volume. - lda vcbbuf+21,x return total blocks and total in use. - sta reqh 1st transfer 'free' blocks to zpage - lda vcbbuf+20,x for later subtraction to determine - sta reql the 'used' count. - lda vcbbuf+19,x transfer to 'd.' table as aux id - sta d_auxid+1 (total block count is considered aux id - pha for the volume) - lda vcbbuf+18,x - sta d_auxid - sec subtract and report the number of - sbc reql blocks 'in use' - sta d_usage - pla - sbc reqh - sta d_usage+1 -L4988 lda d_stor transfer bytes from internal order to - lsr a call spec via 'inftabl' translation - lsr a table but first change storage type to - lsr a external (low nibble) format. - lsr a - sta d_stor - ldy #$11 index to last of user's spec table. -L4994 lda inftabl-3,y - and #$7F strip bit used by setinfo - tax - lda d_stor,x move directory info to call spec. table - sta (A3L),y - dey - cpy #$03 - bcs L4994 if all info bytes moved, retn carry clr -L49A4 rts - -setinfo .EQ *-ofsX - jsr findfile get the file to work on. - bcs L49CF if error. - lda bubit see if backup bit can be cleared - eor #$20 - and d_attr - and #$20 - sta bkbitflg or preserve current... - ldy #$0D init pointer to user supplied list. -L49B9 ldx inftabl-3,y get index to corresponding 'd.' table. - bmi L49C3 branch if parameter can't be set. - lda (A3L),y - sta d_stor,x -L49C3 dey has user's request been satisfied ? - cpy #$03 - bcs L49B9 no, move next byte. - and #$18 make sure no illegal access bits were - beq L49D0 set !! branch if legal access. - lda #$4E otherwise, access error. - sec -L49CF rts -L49D0 ldy #$0B - lda (A3L),y was clock null input ? - beq L49D9 if yes. - jmp drevise1 end by updating directory. -L49D9 jmp drevise update with clock also... - -rename .EQ *-ofsX - jsr lookfile look for source (original) file. - bcc L4A1E if found. - cmp #$40 trying to rename a volume ? - bne L49FD no, return error. - jsr renpath syntax new name. - bcs L49FD rename error. - ldy pathbuf find out if only rootname for new name - iny - lda pathbuf,y must be $FF if volume name only. - bne L4A72 if not single name - ldx vcbptr check for open files before changing. - lda vcbbuf+17,x - bpl L49FF if volume not busy. - lda #$50 file busy error. -L49FD sec - rts -L49FF ldy #$00 get newname's length - lda pathbuf,y - ora #$F0 (root file storage type) - jsr mvrotnam update root directory. - bcs L4A74 rename error. - ldy #$00 - ldx vcbptr update vcb also. -L4A10 lda pathbuf,y move new name to vcb. - beq L4A1C - sta vcbbuf,x - iny next character - inx - bne L4A10 always. -L4A1C clc no errors - rts -L4A1E jsr getnamptr set y = 1st char of path, x = 0. -L4A21 lda pathbuf,y move original name to gbuf - sta gbuf,x for later comparison to new name. - bmi L4A2D if last character has been moved - iny otherwise, get the next one. - inx - bne L4A21 always. -L4A2D jsr renpath get new name syntaxed. - bcs L4A74 rename error. - jsr getnamptr set y = path, x = 0. - lda pathbuf,y now compare new name with old name -L4A38 cmp gbuf,x to make sure they are in the same dir. - php save result of comparison. - and #$F0 was last char really a count ? - bne L4A46 if not. - sty rnptr save pointer to next name, it might - stx namptr be the last. -L4A46 plp result of last comparison ? - bne L4A52 branch if different character or count. - inx bump pointers. - iny - lda pathbuf,y was it the last character ? - bne L4A38 if not. - clc no operation, names were the same. - rts -L4A52 ldy rnptr index to last name in the chain. - lda pathbuf,y get last name length. - sec - adc rnptr - tay - lda pathbuf,y this byte should be $00 ! - bne L4A72 if not, bad path error. - ldx namptr index to last of original name - lda gbuf,x - sec - adc namptr - tax - lda gbuf,x this byte should also be $00. - beq L4A76 if so, continue processing. -L4A72 lda #$40 bad pathname error. -L4A74 sec - rts -L4A76 jsr lookfile test for duplicate file name. - bcs L4A7F branch if file not found, which is ok !! - lda #$47 duplicate name error. - sec - rts -L4A7F cmp #$46 was it a valid file not found ? - bne L4A74 no, rename error. - jsr setpath syntax pathname of file to be changed. - jsr findfile get all the info on this file. - bcs L4A74 rename error. - jsr tstopen is file in use ? - lda #$50 anticipate file busy error. - bcs L4A74 error if in use. - lda d_attr test bit which allows rename. - and #$40 - bne L4A9D branch if ok to rename - lda #$4E otherwise, illegal access. -L4A9B sec - rts -L4A9D lda d_stor find out which storage type. - and #$F0 strip off name length. - cmp #$D0 is it a directory ? - beq L4AAE then ok. - cmp #$40 is it a seed, sapling or tree ? - bcc L4AAE then ok. - lda #$4A file incompatible error. - bne L4A9B always. -L4AAE jsr renpath since both names go into the directory, - bcs L4A74 syntax the new name to get the local - ldy rnptr name address. y = index to local name - ldx pathbuf,y length. adj y to last char of new name. - tya - adc pathbuf,y - tay -L4ABE lda pathbuf,y move local name to dir entry workspace. - sta d_stor,x - dey - dex - bne L4ABE - lda d_stor preserve file storage type. - and #$F0 strip off old name length. - tax - ora pathbuf,y add in new name's length. - sta d_stor - cpx #$D0 that file must be changed also. - bne L4AF0 branch if not directory type. - lda d_frst read in 1st header block of subdir - ldx d_frst+1 - jsr rdblk - bcs L4A74 errors. - ldy rnptr change the header's name to match the - lda pathbuf,y owner's new name. get local name length. - ora #$E0 assume it's a header. - jsr mvrotnam - bcs L4A74 -L4AF0 jmp drevise1 end by updating all path directories. -mvrotnam .EQ *-ofsX - ldx #$00 -L4AF5 sta gbuf+4,x - inx - iny - lda pathbuf,y - bne L4AF5 - jmp wrtgbuf write changed header block. -renpath .EQ *-ofsX - ldy #$03 get address to new pathname - lda (A3L),y - iny - sta zpt - lda (A3L),y set up for syntaxing routine (synpath) - sta zpt+1 - jmp synpath do syntax (returns y = local namelength) -getnamptr .EQ *-ofsX - ldy #$00 return pointer to 1st name of path. - bit prfxflg is this a prefixed name ? - bmi L4B1A branch if not. - ldy newpfxptr -L4B1A ldx #$00 - rts - -destroy .EQ *-ofsX - jsr findfile look for file to be destroyed. - bcs L4B66 if error. - jsr tstopen is it open ? - lda totent - bne L4B64 error if open. - stz reql force proper free count in volume. - stz reqh (no disk access occurs if already - jsr tstfrblk proper) - bcc L4B39 no errors. - cmp #$48 was error a full disk ? - bne L4B66 no, report error. -L4B39 lda d_attr make sure ok to destroy file. - and #$80 - bne L4B45 branch if ok to destroy. - lda #$4E access error - jsr p8errv (returns to caller) -L4B45 lda devnum last device used. - jsr twrprot1 test for write protected hardware - bcs L4B66 before going thru deallocation. - lda d_frst 'detree' needs first block address - sta firstbl - lda d_frst+1 - sta firstbh - lda d_stor find out which storage type. - and #$F0 strip off name length. - cmp #$40 is it a seed, sapling or tree ? - bcc L4B68 branch if it is. - bra L4BCF otherwise, test for directory destroy. -L4B64 lda #$50 file busy error. -L4B66 sec can't be destroyed - rts -L4B68 sta stortyp destroy a tree file. save storage type. - ldx #$05 - lda #$00 set 'detree' input variables, must be -L4B6F sta stortyp,x in order: deblock, dtree, dsap, dseed. - dex - bne L4B6F loop until all zero'd. - lda #$02 this avoids an extra file i/o and pre- - sta dseed+1 vents destruction of any deleted data. - inc delflag don't allow detree to zero index blocks. - jsr detree make trees and saplings into seeds. - dec delflag reset flag. - bcs L4B93 (de-evolution) -L4B85 ldx firstbh - lda firstbl now deallocate seed. - jsr dealloc - bcs L4B93 - jsr upbmap -L4B93 pha save possible error code. - lda #$00 update directory to free entry space. - sta d_stor - cmp h_fcnt file entry wrap ? - bne L4BA1 branch if no carry adjustment. - dec h_fcnt+1 take carry from hi byte of file entries. -L4BA1 dec h_fcnt mark header with one less file. - jsr dvcbrev go update block count in vcb (ignore - jsr drevise error, if any) and update dir last. - tax save possible new error code, - pla restore possible old error code. - bcc L4BAF branch if last call succeeded. - txa last call failed, use it's error code. -L4BAF cmp #$01 adjust carry accordingly - rts -dvcbrev .EQ *-ofsX update block free count in vcb. - ldy vcbptr point to vcb of correct device. - lda deblock get # of blocks recently freed. - adc vcbbuf+20,y - sta vcbbuf+20,y update current free block count. - lda deblock+1 - adc vcbbuf+21,y - sta vcbbuf+21,y - lda #$00 force re-scan from 1st bitmap - sta vcbbuf+28,y - rts -L4BCD bcc L4B85 branch widened (always taken) -L4BCF cmp #$D0 is this a directory file ? - bne L4C1B no, file incompatible. - jsr fndbmap make sure a buffer available for bitmap - bcs L4C1A if error. - lda d_frst read 1st block of directory into gbuf - sta bloknml - lda d_frst+1 - sta bloknml+1 - jsr rdgbuf - bcs L4C1A - lda gbuf+37 do any files exist in this directory ? - bne L4BF1 if so, access error. - lda gbuf+38 - beq L4BF6 -L4BF1 lda #$4E access error. - jsr p8errv P8 error vector -L4BF6 sta gbuf+4 make it an invalid subdirectory - jsr wrtgbuf - bcs L4C1A -L4BFE lda gbuf+2 get forward link. - cmp #$01 test for null block into carry. - ldx gbuf+3 get the rest of the block address. - bne L4C0A branch if not null. - bcc L4BCD was the low part null as well ? -L4C0A jsr dealloc free this block. - bcs L4C1A - lda gbuf+2 - ldx gbuf+3 - jsr rdblk - bcc L4BFE loop until all freed -L4C1A rts -L4C1B lda #$4A file incompatible - jsr p8errv (returns to caller) -fcbused .EQ *-ofsX mark fcb as dirty so the directory - pha will be flushed on 'flush'. - tya save regs. - pha - ldy fcbptr - lda fcbbuf+28,y fetch current fcb dirty byte. - ora #$80 mark fcb as dirty. - sta fcbbuf+28,y save it back - pla and restore regs. - tay - pla - rts - -* 'detree' deallocates blocks from tree files. it is assumed that the device has -* been pre-selected and the 'gbuf' may be used. -* -* on entry: -* stortype = storage type in upper nibble, lower nibble is undisturbed. -* firstbl & firstbh = first block of file (index or data). -* deblock = 0 -* dtree = ptr to 1st block with data to be deallocated at tree level. -* dsap = ptr to 1st block at sapling level. -* dseed = byte (0-511) position to be zeroed from (inclusive). -* -* on exit: -* stortype = modified result of storage type (if applicable). -* firstbl & h = modified if storage type changed. -* deblock = total number of blocks freed at all levels. -* dtree, dsap, deseed unchanged. -* -* to trim a tree to a seed file, both dtree and dsap must be zero. -* to go from tree to sapling, dtree alone must be zero. - -detree .EQ *-ofsX - lda stortyp which kind of tree ? - cmp #$20 is it a 'seed' ? - bcc L4C46 if yes. - cmp #$30 a sapling ? - bcc L4C51 if yes. - cmp #$40 is it at least a 'tree' ? - bcc L4C59 branch if it is. - lda #$0C block allocation error. - jsr sysdeath P8 system death vector - -* seedling file type - make sure first desireable block is the only -* block available in a seedling file. - -L4C46 lda dsap - ora dtree - bne L4CC2 - jmp seedel0 - -* sapling file type - make sure first desireable block is within the range of -* blocks available in a sapling file - -L4C51 lda dtree can't have any blocks in this range - bne L4CC2 if so then done - jmp sapdel0 else go deallocate -L4C59 lda #$80 - sta topdest for tree top start at end, work backwards. -L4C5E jsr drdfrst read specified first block into gbuf. - bcs L4CC2 return errors. - ldy topdest get current pointer to top indexes. - cpy dtree have enough sapling indexes been - beq L4CC3 deallocated? yes, now deallocate blocks - ldx #$07 buffer up to 8 sapling index block -L4C6D lda gbuf,y addresses. fetch low block address - sta dealbufl,x and save it. - ora gbuf+$100,y is it a real block that is allocated? - beq L4C81 branch if phantom block. - lda gbuf+$100,y fetch high block address - sta dealbufh,x and save it. - dex decrement and test for dealc buf filled. - bmi L4C93 branch if 8 addresses fetched. -L4C81 dey look for end of deallocation limit. - cpy dtree is this the last position on tree level? - bne L4C6D if not. - iny - lda #$00 fill rest of dealc buffer with null addresses. -L4C8A sta dealbufl,x - sta dealbufh,x - dex - bpl L4C8A -L4C93 dey decrement to prepare for next time. - sty topdest save index. - ldx #$07 -L4C99 stx dtmpx save index to dealc buf. - lda dealbufl,x - sta bloknml - ora dealbufh,x finished ? - beq L4C5E branch if done with this level. - lda dealbufh,x complete address with high byte, - sta bloknml+1 - jsr rdgbuf read sapling level into gbuf. - bcs L4CC2 return errors. - jsr dealblk go free all data indexes in this block - bcs L4CC2 - jsr wrtgbuf write the flipped index block - bcs L4CC2 - ldx dtmpx restore index to dealc buff. - dex are there more to free? - bpl L4C99 branch if so. - bmi L4C5E branch always to get up to 8 more -L4CC2 rts sapling block numbers. -L4CC3 ldy dtree deallocate all sapling blocks greater - iny than specified block. - jsr dalblk1 (master index in gbuf) - bcs L4CC2 if errors. - jsr wrtgbuf write updated master index back to disk. - bcs L4CC2 - ldy dtree figure out if tree can become sapling. - beq L4CEB branch if it can. - lda gbuf,y otherwise, continue with partial. - sta bloknml deallocation of last sapling index. - ora gbuf+$100,y is there such a sapling index block ? - beq L4CC2 all done if not. - lda gbuf+$100,y read in sapling level to be modified. - sta bloknml+1 - jsr rdgbuf read highest sapling index into gbuf. - bcc L4CF5 - rts -L4CEB jsr shrink shrink tree to sapling - bcs L4CC2 -sapdel0 .EQ *-ofsX - jsr drdfrst read specified sapling level index - bcs L4CC2 into gbuf. branch if error. -L4CF5 ldy dsap pointer to last of desirable indexes. - iny inc to 1st undesirable. - beq L4D05 branch if all are desirable. - jsr dalblk1 deallocate all indexes above specified. - bcs L4CC2 - jsr wrtgbuf write out the index block - bcs L4CC2 -L4D05 ldy dsap prepare to clean up last data block. - beq L4D1F branch if possibility of making a seed. -L4D0A lda gbuf,y fetch low order data block address. - sta bloknml - ora gbuf+$100,y is it a real block ? - beq L4CC2 if not, then done. - lda gbuf+$100,y - sta bloknml+1 - jsr rdgbuf go read data block into gbuf. - bcc L4D2E branch if good read - rts or return error. -L4D1F lda dtree are both tree and sap levels zero ? - bne L4D0A if not. - jsr shrink reduce this sap to a seed. - bcs L4D52 if error. -seedel0 .EQ *-ofsX - jsr drdfrst go read data block. - bcs L4D52 if error. -L4D2E ldy dseed+1 check high byte for no deletion. - beq L4D39 branch if all of 2nd page to be deleted. - dey if dseed > $200 then all were done. - bne L4D52 branch if that is the case. - ldy dseed clear only bytes >= dseed. -L4D39 lda #$00 -L4D3B sta gbuf+$100,y zero out unwanted data - iny - bne L4D3B - ldy dseed+1 is that all ? - bne L4D4F yes. - ldy dseed -L4D49 sta gbuf,y - iny - bne L4D49 -L4D4F jmp wrtgbuf update data block to disk. -L4D52 rts return error status. -drdfrst .EQ *-ofsX read specified 1st block into gbuf - lda firstbl - ldx firstbh - jmp rdblk go read it - -* beware that dealloc may bring in a new bitmap block and may destroy -* locations 46 and 47 which are used to point to the current index block. - -shrink .EQ *-ofsX - ldx firstbh first deallocate top index block - txa - pha - lda firstbl - pha save block address of this index block. - jsr dealloc free it from the bitmap - pla - sta bloknml set master of sapling - pla index block address. - sta bloknml+1 - bcs L4D8D report errors. - lda gbuf get # of new 1st block from old index. - sta firstbl - lda gbuf+$100 - sta firstbh - ldy #$00 - jsr swapme flip that one entry in old top index. - sec now change file type, - lda stortyp from tree to sapling, - sbc #$10 or from sapling to seed. - sta stortyp - jsr wrtgbuf write the (deallocated) old top index. -L4D8D rts return error status. -dealblk .EQ *-ofsX - ldy #$00 start at beginning. -dalblk1 .EQ *-ofsX - lda bloknml save disk address of gbuf's data. - pha - lda bloknml+1 - pha -L4D96 sty saptr save current index. - lda gbuf,y get low address of block to deallocate. - cmp #$01 test for null block into carry. - ldx gbuf+$100,y get remainder of block address. - bne L4DA5 branch if not null. - bcc L4DB0 was the low part null too ? -L4DA5 jsr dealloc free it up on volume bitmap. - bcs L4DB4 return any error. - ldy saptr get index to sapling level index block. - jsr swapme -L4DB0 iny next block address. - bne L4D96 if more to deallocate or test. - clc no error. -L4DB4 tax save error code, if any. - pla restore blocknm (16 bit) - sta bloknml+1 - pla - sta bloknml - txa restore return code - rts -swapme .EQ *-ofsX - lda delflag swapping or zeroing ? - bne L4DC5 skip if swapping. - tax make x = 0. - beq L4DCB zero the index (always taken). -L4DC5 ldx gbuf+$100,y index high - lda gbuf,y index low -L4DCB sta gbuf+$100,y save index high - txa - sta gbuf,y save index low - rts done. - -*-------------------------------------- MAN SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.C LOAD USR/SRC/PRODOS.203/PRODOS.S diff --git a/ProDOS.203/ProDOS.S.XDOS.D.txt b/ProDOS.203/ProDOS.S.XDOS.D.txt new file mode 100644 index 00000000..acf5bb88 --- /dev/null +++ b/ProDOS.203/ProDOS.S.XDOS.D.txt @@ -0,0 +1,590 @@ +NEW + AUTO 3,1 + +* read command + +readf .EQ *-ofsX + jsr mvdbufr xfer buffer address and request count + jsr mvcbytes to a more accessable location, also + pha get fcb attributes and save on stack. + jsr calcmrk calc mark after read, test if mark > eof + pla carry set means end mark > eof. + and #$01 test for read enabled. + bne L41DE branch if ok to read. + lda #$4E illegal access. + bne L4202 always. +L41DE bcc L4205 branch if result mark < eof. adjust + ldy fcbptr request to read until just before eof. + lda fcbbuf+21,y result = (eof-1) - position + sbc tposll + sta cbytes + sta rwreql + lda fcbbuf+22,y + sbc tposlh + sta cbytes+1 + sta rwreqh + ora cbytes if both bytes = 0 then eof error + bne L4210 + lda #$4C eof error +L4202 jmp errfix1 +L4205 lda cbytes + ora cbytes+1 + bne L4210 if read request definitely non-zero. +L420D jmp rwdone do nothing. +L4210 jsr valdbuf validate user's data buffer range. + bcs L4202 branch if memory conflict. + jsr gfcbstyp get storage type + cmp #$04 and find out if it's a tree or other. + bcc L421F branch if a tree file + jmp dread otherwise assume it's a directory. +L421F jsr rdposn set up data pointer. + bcs L4202 errors. + jsr preprw test for newline, setup for partial + jsr readpart read. move current data buffer contents + bvs L420D to user area. branch if satisfied. + bcs L421F indicates newline is set. + lda rwreqh how many blocks are to be read ? + lsr if < 2 then use the slow way. + beq L421F + sta cmdtemp save bulk block count. + jsr gfcbstat make sure current data area doesn't + and #$40 need writing before resetting ptr to + bne L421F read into user's area. branch if data + sta ioaccess needs to be written to force 1st call + lda usrbuf thru all dev handler checking. make + sta datptr the data buffer the user's space. + lda usrbuf+1 + sta datptr+1 +L4249 jsr rdposn get next block directly into user space. + bcs L42B7 if error. +L424E inc datptr+1 incll ptrs by one block (512 bytes) + inc datptr+1 + dec rwreqh + dec rwreqh + inc tposlh + inc tposlh + bne L4269 if pos'n doesn't get to a 64k boundary + inc tposhi otherwise, must check for a 128k one. + lda tposhi carry set if 128k boundary reached. + eor #$01 + lsr +L4269 dec cmdtemp has all been read fast ? + bne L427B branch if more to read. + jsr fxdatptr go fix up data pointer to xdos buffer. + lda rwreql test for end of read. + ora rwreqh are both 0 ? + beq L42C3 yes, done. + bne L421F no, read last partial block +L427B bcs L4249 + lda tposhi get index to next block address + lsr + lda tposlh + ror + tay index to address = int(pos/512) + lda (zpt),y get low address + sta bloknml + inc zpt+1 + cmp (zpt),y are hi and low address the same? + bne L4299 no, it's a real block address. + cmp #$00 are both bytes 0 ? + bne L4299 no, must be real data. + sta ioaccess don't do repeat io just after sparse. + beq L429C branch always (carry set). +L4299 lda (zpt),y get high address + clc +L429C dec zpt+1 + bcs L4249 if no block to read. + sta bloknml+1 + lda ioaccess has 1st call gone to device yet ? + beq L4249 no, go thru normal route + clc + php interrupts can't occur during dmgr call + sei + lda datptr+1 reset hi buffer address for dev handler + sta buf+1 + jsr dmgr + bcs L42B6 if error + plp + bcc L424E no errors, branch always. +L42B6 plp restore interrupts. +L42B7 pha save error code. + jsr fxdatptr go restore data pointers, etc. + pla +errfix1 .EQ *-ofsX + pha save error code + jsr rwdone pass back # of bytes actually read + pla + sec error + rts +rwdone .EQ *-ofsX +L42C3 ldy #$06 return total # of bytes actually read + sec derived from cbytes-rwreq. + lda cbytes + sbc rwreql + sta (A3L),y + iny + lda cbytes+1 + sbc rwreqh + sta (A3L),y + jmp rdposn leave with valid position in fcb. +preprw .EQ *-ofsX + ldy fcbptr adj pointer to user's buffer to make + sec the transfer + lda usrbuf + sbc tposll + sta usrbuf + bcs L42E9 if no adjustment to hi address needed + dec usrbuf+1 +L42E9 lda fcbbuf+31,y test for new line enabled. + clc + beq L42F9 if new line not enabled. + sec carry indicates new line enabled + sta nlmask + lda fcbbuf+10,y move newline character to more + sta nlchar accesible spot. +L42F9 ldy tposll index to 1st data. + lda datptr reset low order of position pointer to + sta sos beginning of page. + ldx rwreql get low order count of requested bytes. + rts return statuses. +readpart .EQ *-ofsX + txa x = low count of bytes to move. + bne L430F branch if request is not an even page. + lda rwreqh a call of 0 bytes should never get here! + beq L435D branch if nothing to do. + dec rwreqh +L430F dex +L4310 lda (sos),y move data to user's buffer + sta (usrbuf),y + bcs tstnewl test for newline 1st ! +L4316 txa note: x must be unchanged from tstnewl ! + beq L4332 go see if read request is satified... +L4319 dex dec # of bytes left to move. + iny page crossed ? + bne L4310 no, move next byte. + lda sos+1 test for end of buffer, but first + inc usrbuf+1 adjust user buffer pointer + inc tposlh and position + bne L4329 + inc tposhi +L4329 inc sos+1 and sos buffer high address. + eor datptr+1 (carry is undisturbed) + beq L4310 branch if more to read in buffer. + clv indicate not finished. + bvc L4360 always. +L4332 lda rwreqh + beq L4350 branch if request is satisfied. + iny done with this block of data ? + bne L4340 no, adjust high byte of request. + lda sos+1 maybe, check for end of block buffer. + eor datptr+1 (don't disturb carry). + bne L4343 if hi count can be dealt with next time +L4340 dec rwreqh +L4343 dey restore proper value + bra L4319 +tstnewl lda (sos),y get last byte transferred again. + and nlmask only bits on in mask are significant. + eor nlchar does it match newline character? + bne L4316 no, read next. +L4350 iny adjust position. + bne L435D + inc usrbuf+1 inc pointers + inc tposlh + bne L435D + inc tposhi +L435D bit setvflg (sets v flag) +L4360 sty tposll save low position + bvs L4366 + inx leave request as +1 for next call +L4366 stx rwreql and remainder of request count. + php save statuses + clc adjust user's low buffer address + tya + adc usrbuf + sta usrbuf + bcc L4374 + inc usrbuf+1 adjust hi address as needed. +L4374 plp restore return statuses. +setvflg .EQ *-ofsX this byte ($60) is used to set v flag. + rts +fxdatptr .EQ *-ofsX put current user buffer + lda datptr address back to normal + sta usrbuf + lda datptr+1 + sta usrbuf+1 bank pair byte should be moved also. + ldy fcbptr restore buffer address + jmp fndfcbuf + +* read directory file + +dread .EQ *-ofsX +L4384 jsr rdposn + bcs L43B8 pass back any errors. + jsr preprw prepare for transfer. + jsr readpart move data to user's buffer. + bvc L4384 repeat until request is satisfied. + jsr rwdone update fcb as to new position. + bcc L43B6 branch if done with no errors. + cmp #$4C was last read to end of file ? + sec anticipate some other error. + bne L43B7 branch if not eof error. + jsr svmark + jsr zipdata clear out data block. + ldy #$00 provide dummy back pointer for future + ldx fcbptr re-position. x = hi byte of last block +L43A6 lda fcbbuf+16,x + sta (datptr),y + lda #$00 mark current block as impossible + sta fcbbuf+16,x + inx + iny inc indexes to do both hi and low bytes + cpy #$02 + bne L43A6 +L43B6 clc no error +L43B7 rts +L43B8 jmp errfix1 report how much xfer'd before error. +mvcbytes .EQ *-ofsX move request count to a more + ldy #$04 accessable location + lda (A3L),y + sta cbytes + sta rwreql + iny + lda (A3L),y + sta cbytes+1 + sta rwreqh + ldy fcbptr return y = val(fcbptr), + lda fcbbuf+9,y a = attributes + clc and carry clear... + rts +mvdbufr .EQ *-ofsX move the pointer to user's buffer + ldy #$02 to the block file manager + lda (A3L),y + sta usrbuf z-page area + iny + lda (A3L),y + sta usrbuf+1 +gfcbstyp .EQ *-ofsX + ldy fcbptr return storage type + lda fcbbuf+7,y + rts + +* this subroutine adds the requested byte count to mark and returns sum +* in scrtch and also returns mark in tpos and oldmark. +* +* on exit: +* y,x,a is unknown +* carry set indicates scrtch > eof + +calcmrk .EQ *-ofsX + ldx #$00 + ldy fcbptr + clc +L43EE lda fcbbuf+18,y + sta tposll,x + sta oldmark,x + adc cbytes,x + sta scrtch,x + txa + eor #$02 cbytes+2 always=0 + beq L4406 + iny + inx + bne L43EE always. +eoftest .EQ *-ofsX +L4406 lda scrtch,x new mark in scrtch. + cmp fcbbuf+21,y is new position > eof ? + bcc L4414 no, proceed. + bne L4414 yes, adjust 'cbytes' request + dey + dex all tree bytes compared ? + bpl L4406 no, test next lowest +L4414 rts +werreof .EQ *-ofsX + jsr plus2fcb reset eof to pre-error position. +L4418 lda oldeof,x place oldeof back into fcb + sta fcbbuf+21,y + lda oldmark,x also reset mark to last best + sta fcbbuf+18,y write position + sta scrtch,x and copy mark to scrtch for test of + dey eof less than mark. + dex + bpl L4418 + jsr plus2fcb get pointers to test eof < mark. + jsr eoftest carry set means mark > eof !! + +* drop into wadjeof to adjust eof to mark if necessary + +wadjeof .EQ *-ofsX + jsr plus2fcb get y=fcbptr+2, x=2, a=y. +L4434 lda fcbbuf+21,y copy eof to old eof + sta oldeof,x + bcc L4442 and if carry set... + lda scrtch,x then copy scrtch to fcb's eof. + sta fcbbuf+21,y +L4442 dey + dex copy all 3 bytes + bpl L4434 + rts +plus2fcb .EQ *-ofsX + lda #$02 on exit both a and y = fcbptr+2. + tax x = 2 + ora fcbptr + tay + rts + +* write command + +writef .EQ *-ofsX first determine if requested + jsr mvcbytes write is legal. + pha + jsr calcmrk save a copy of eof to old eof, set/clr + jsr wadjeof carry to determine if new mark > eof. + pla get attributes again. + and #$02 is write enabled ? + bne L4462 yes, continue... +L445E lda #$4E illegal access error. + bne L44A2 +L4462 jsr tstwprot otherwise, make sure device is not + bcs L44A2 write protected. if so, branch to abort. + lda cbytes + ora cbytes+1 anything to write ? + bne L4472 branch if so, + jmp rwdone else do nothing. +L4472 jsr mvdbufr move the user's buffer ptr to bfm zero + cmp #$04 page area, also get storage type. + bcs L445E if not tree, return an access error. +L4479 jsr rdposn + bcs L44A2 + jsr gfcbstat + and #$07 + beq L44E9 + ldy #$00 is enough disk space available for +L4487 iny indexes and data block ? + lsr + bne L4487 + sty reql + sta reqh + jsr tstfrblk + bcs L44A2 pass back any errors. + jsr gfcbstat now get more specific. + and #$04 are we lacking a tree top ? + beq L44AC no, test for lack of sapling level index + jsr topdown go allocate tree top and adj file type. + bcc L44B8 continue with allocation of data block. +L44A2 pha save error. + jsr errfix1 error return. + jsr werreof adjust eof and mark to pre-error state. + pla restore error code. + sec + rts +L44AC jsr gfcbstat get status byte again. + and #$02 do we need a sapling level index block ? + beq L44B8 no, assume it's just a data block needed + jsr sapdown go alloc an indx blk and update tree top + bcs L44A2 if error. +L44B8 jsr alcwblk go allocate for data block. + bcs L44A2 + jsr gfcbstat clear allocation required bits in status + ora #$80 but first indicate index block is dirty. + and #$F8 + sta fcbbuf+8,y + lda tposhi calculate position within index block. + lsr + lda tposlh + ror + tay now put block address into index block. + inc zpt+1 high byte first. + lda scrtch+1 + tax + sta (zpt),y + dec zpt+1 restore pointer to lower page of index + lda scrtch block. get low block address. + sta (zpt),y store low address. + ldy fcbptr update fcb to indicate that this block + sta fcbbuf+16,y is allocated. + txa get high address again. + sta fcbbuf+17,y +L44E9 jsr preprw + jsr wrtpart + bvc L4479 + jmp rwdone update fcb with new position +wrtpart .EQ *-ofsX + txa + bne L44FF branch if request is not even pages + lda rwreqh a call of 0 bytes should never get here! + beq L4546 do nothing + dec rwreqh +L44FF dex + lda (usrbuf),y move data from user's buffer + sta (sos),y + txa + beq L4525 +L4507 iny page crossed ? + bne L44FF no, keep moving. + lda sos+1 test for end of buffer + inc usrbuf+1 but first adjust user buffer pointer + inc tposlh and position + bne L451C + inc tposhi + bne L451C + lda #$4D out of range if > 32MB + bne L44A2 +L451C inc sos+1 adjust sos buffer high address + eor datptr+1 (carry is undisturbed) + beq L44FF branch if more to write to buffer. + clv indicates not finished. + bvc L4549 always. +L4525 lda rwreqh + beq L4539 branch if request satisfied. + iny done with this block of data ? + bne L4533 if not. + lda sos+1 this is necessary for proper + eor datptr+1 adjustment of request count + bne L4536 +L4533 dec rwreqh +L4536 dey reset modified y + bra L4507 +L4539 iny and position + bne L4546 + inc usrbuf+1 inc pointers + inc tposlh + bne L4546 + inc tposhi +L4546 bit setvflg set v flag +L4549 sty tposll save low position + stx rwreql and remainder of request count. + php save statuses + jsr gfcbstat + ora #$50 + sta fcbbuf+8,y + clc adjust user's low buffer address + lda tposll + adc usrbuf + sta usrbuf + bcc L4564 + inc usrbuf+1 adjust high address as needed. +L4564 jsr fcbused set directory flush bit. + plp restore return statuses + rts +topdown .EQ *-ofsX + jsr swapdown make current 1st block an entry in new + bcs L45B1 top. branch if errors. + jsr gfcbstyp get storage type + +* has storage type been changed to 'tree' ? if not, assume it was originally +* a seed and both levels need to be built. otherwise, only an index needs +* to be allocated. + + cmp #$03 tree type + beq L457A + jsr swapdown make previous swap a sap level index + bcs L45B1 block. branch if errors. +L457A jsr alcwblk get another block address for the sap + bcs L45B1 level index. branch if errors. + lda tposhi calculate position of new index block + lsr in the top of the tree. + tay + lda scrtch get address of newly allocated index + tax block again. + sta (zpt),y + inc zpt+1 + lda scrtch+1 + sta (zpt),y save hi address + dec zpt+1 + ldy fcbptr make newly allocated block the current + sta fcbbuf+15,y index block. + txa + sta fcbbuf+14,y + jsr wfcbfst save new top of tree + bcs L45B1 + jmp zeroindex zero index block in user's i/o buffer. +sapdown .EQ *-ofsX + jsr gfcbstyp find out if dealing with a tree. + cmp #$01 if seed then adj to file type is needed. + beq L45B2 branch if seed + jsr rfcbfst otherwise read in top of tree. + bcc L457A if no error. +L45B1 rts return errors. +swapdown .EQ *-ofsX make current seed into a sapling. +L45B2 jsr alcwblk allocate a block before swap. + bcs L45F6 return errors. + ldy fcbptr get previous first block + lda fcbbuf+12,y address into index block. + pha save temporarily while swapping in new + lda scrtch top index. get new block address (low) + tax + sta fcbbuf+12,y + lda fcbbuf+13,y + pha + lda scrtch+1 and high address too + sta fcbbuf+13,y + sta fcbbuf+15,y make new top also the current index in + txa memory. get low address again. + sta fcbbuf+14,y + inc zpt+1 make previous the 1st entry in sub index + pla + sta (zpt) + dec zpt+1 + pla + sta (zpt) + jsr wfcbfst save new file top. + bcs L45F6 if error. + jsr gfcbstyp now adjust storage type by adding 1 + adc #$01 (seed becomes sapling becomes tree) + sta fcbbuf+7,y + lda fcbbuf+8,y mark storage type modified + ora #$08 + sta fcbbuf+8,y + clc no error +L45F6 rts +alcwblk .EQ *-ofsX + jsr alc1blk + bcs L4616 + jsr gfcbstat mark usage as modified + ora #$10 + sta fcbbuf+8,y + lda fcbbuf+24,y inc current usage count by 1 + clc + adc #$01 + sta fcbbuf+24,y + lda fcbbuf+25,y + adc #$00 + sta fcbbuf+25,y +L4615 clc no error +L4616 rts +tstwprot .EQ *-ofsX check for 'never been modified' + jsr gfcbstat condition + and #$F0 + bne L4615 ordinary rts if known write ok. + lda fcbbuf+1,y get file's dev #. + sta devnum get current status of block device. +twrprot1 .EQ *-ofsX make the device status call + sta unitnum + lda bloknml+1 + pha + lda bloknml save the current block values + pha + stz A4L + stz bloknml zero the block # + stz bloknml+1 + php + sei + jsr dmgr + bcs .1 branch if write protect error + lda #$00 otherwise, assume no errors. +.1 plp restore interrupt status + clc + tax save error. + beq .2 branch if no error + sec else, set carry to show error. +.2 pla + sta bloknml restore the block # + pla + sta bloknml+1 + txa + rts carry is indeterminate. + +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.D +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.XDOS.E.txt b/ProDOS.203/ProDOS.S.XDOS.E.txt new file mode 100644 index 00000000..9e2db218 --- /dev/null +++ b/ProDOS.203/ProDOS.S.XDOS.E.txt @@ -0,0 +1,615 @@ +NEW + AUTO 3,1 + +* close command + +closef .EQ *-ofsX close all ? + ldy #$01 + lda (A3L),y + bne L4683 no, just one of them. + sta cferr clear global close error. + lda #$00 start at the beginning. +L4654 sta fcbptr save current low byte of pointer. + tay get the level at which the file + lda fcbbuf+27,y was opened. + cmp flevel if file's level is < global level + bcc L4675 then don't close. + lda fcbbuf,y is this reference file open ? + beq L4675 no, try next. + jsr flush2 clean it out... + bcs L46B6 return flush errors. + jsr close2 update fcb & vcb + ldy #$01 + lda (A3L),y + beq L4675 no error if close all. + bcs L46B6 close error. +L4675 lda fcbptr inc pointer to next fcb + clc + adc #$20 + bcc L4654 branch if within same page. + lda cferr on final close report logged errors. + beq L46B4 branch if errors. + rts (carry already set). +L4683 jsr flush1 flush file 1st (including updating + bcs L46B6 bitmap). branch if errors. +close2 .EQ *-ofsX + ldy fcbptr + lda fcbbuf+11,y release file buffer + jsr relbuffr + bcs L46B6 + lda #$00 + ldy fcbptr + sta fcbbuf,y free fcb too + lda fcbbuf+1,y + sta devnum go look for associated vcb + jsr fnddvcb + ldx vcbptr get vcb pointer. + dec vcbbuf+30,x indicate one less file open. + bne L46B4 branch if that wasn't the last... + lda vcbbuf+17,x + and #$7F strip 'files open' bit + sta vcbbuf+17,x +L46B4 clc + rts +L46B6 bcs L46E6 don't report close all error now. + +* flush command + +flushf .EQ *-ofsX + ldy #$01 flush all ? + lda (A3L),y + bne L46E9 no, just one of them. + sta cferr clear global flush error. + lda #$00 start at the beginning. +L46C3 sta fcbptr save current low byte of pointer. + tay index to ref #. + lda fcbbuf,y is this reference file open ? + beq L46D1 no, try next. + jsr flush2 clean it out... + bcs L46E6 return anty errors. +L46D1 lda fcbptr inc pointer to next fcb. + clc + adc #$20 + bcc L46C3 branch if within same page +L46D9 clc + lda cferr on last flush, + beq L46E0 branch if no logged errors. + sec report error now +L46E0 rts +flush2 .EQ *-ofsX + jsr fndfcbuf must set up vcb & buffer locations 1st. + bcc L46F1 branch if no error. +L46E6 jmp glberr error so check for close or flush all. +flush1 .EQ *-ofsX for normal refnum flush, +L46E9 stz cferr clear global error. + jsr findfcb setup pointer to fcb user references. + bcs L46E6 return any errors. +L46F1 lda fcbbuf+9,y test to see if file is modified. + and #$02 is it write enabled ? + beq L46D9 branch if 'read only' + lda fcbbuf+28,y has eof been modified ? + bmi L4704 if yes. + jsr gfcbstat has data been modified ? + and #$70 (was written to while it's been open?) + beq L46D9 if not. +L4704 jsr gfcbstat + and #$40 does current data buffer need to be + beq L4710 written ? branch if not. + jsr wfcbdat if so, go write it. + bcs L46E6 if error. +L4710 jsr gfcbstat check to see if the index block (tree + and #$80 files only) needs to be written. + beq L471C branch if not. + jsr wfcbidx + bcs L46E6 return any errors. +L471C lda #$06 prepare to update directory + tax + ora fcbptr + tay +L4723 lda fcbbuf,y note: this code depends on the defined + sta d_dev-1,x order of the file control block and the + dey temporary directory area in 'work space' + dex + bne L4723 + sta devnum + lda d_head read the directory header for this file + ldx d_head+1 + jsr rdblk into the general purpose buffer. + bcs L46E6 if error. + jsr movhed0 move header info. + lda d_entblk get address of directory block that + ldy d_entblk+1 contains the file entry. + cmp d_head test to see if it's the same block the + bne L474E header is in. branch if not. + cpy d_head+1 + beq L4755 branch if header block = entry block +L474E sta bloknml + sty bloknml+1 + jsr rdgbuf get block with file entry in general +L4755 jsr entcalc buffer. set up pointer to entry. + jsr moventry move entry to temp entry buffer in + ldy fcbptr 'work space'. update 'blocks used' count + lda fcbbuf+24,y + sta d_usage + lda fcbbuf+25,y + sta d_usage+1 + ldx #$00 and move in end of file mark whether +L476C lda fcbbuf+21,y needed or not. + sta d_eof,x + inx + cpx #$03 move all 3 bytes + beq L4780 + lda fcbbuf+12,y also move in the address of the file's + sta d_filid,x first block since it might have changed + iny since the file first opened. + bne L476C branch always. +L4780 lda fcbbuf+5,y the last thing to update is storage + asl type (y=fcbptr+2). shift into high + asl nibble. + asl + asl + sta scrtch + lda d_stor get old type byte (might be the same). + and #$0F strip off old type, + ora scrtch add in the new type + sta d_stor and put it away. + jsr drevise go update directory. + bcs L47B4 error. + ldy fcbptr mark + lda fcbbuf+28,y fcb/directory + and #$7F as + sta fcbbuf+28,y undirty. + lda d_dev see if bitmap should be written. + cmp bmadev is it in same as current file ? + bne L47B2 yes, put it on the disk if necessary. + jsr upbmap go put it away. + bcs L47B4 flush error +L47B2 clc + rts + +* report error only if not a close all or flush all + +glberr .EQ *-ofsX +L47B4 ldy #$01 + pha + lda (A3L),y + bne L47C1 not an 'all' so report now + clc + pla + sta cferr save for later + rts +L47C1 pla + rts +gfcbstat .EQ *-ofsX + ldy fcbptr index to fcb. + lda fcbbuf+8,y return status byte. + rts +L47CA lda #$4E access error + sec +L47CD rts + +seteof .EQ *-ofsX can only move end of tree, sapling + jsr gfcbstyp or seed. + cmp #$04 tree type ? + bcs L47CA if not then access error + asl + asl + asl + asl + sta stortyp may be used later. + lda fcbbuf+9,y + and #$02 is write enabled to set new eof ? + beq L47CA no, access error. + jsr tstwprot hardware write protected ? + bcs L47CA yes, access error. + ldy fcbptr save old eof so it can be seen + iny whether blocks need to be released + iny upon contraction. + ldx #$02 all 3 bytes of the eof +L47EF lda fcbbuf+21,y + sta oldeof,x + dey + dex + bpl L47EF + ldy #$04 + ldx #$02 +L47FD lda (A3L),y position mark to new eof + sta tposll,x + dey + dex + bpl L47FD + ldx #$02 point to 3rd byte. +L4808 lda oldeof,x see if eof moved backwards so blocks + cmp tposll,x can be released. + bcc L4815 (branch if not) + bne purge branch if blocks to be released + dex + bpl L4808 all 3 bytes +eofset .EQ *-ofsX +L4815 ldy #$04 + ldx fcbptr place new end of file into fcb + inx + inx +L481C lda (A3L),y + sta fcbbuf+21,x + dex + dey + cpy #$02 all 3 bytes moved ? + bcs L481C no. + jmp fcbused mark fcb as dirty. +purge jsr flush1 make sure file is current + bcs L47CD + ldx datptr+1 pointer to index block + inx + inx + stx zpt+1 (zero page conflict with dir buf ptr) + ldx datptr + stx zpt + ldy fcbptr check if eof < mark + iny + iny + ldx #$02 +L4840 lda fcbbuf+18,y + cmp tposll,x compare until not equal or carry clear. + bcc L485F branch if eof > mark. + bne L484E branch if eof < mark. + dey + dex + bpl L4840 compare all 3 bytes +L484E ldy fcbptr + ldx #$00 +L4853 lda tposll,x fake position, correct position will + sta fcbbuf+18,y be made below... + iny + inx + cpx #$03 move all 3 bytes + bne L4853 +L485F jsr tkfrecnt force free block count before releasing + lda tposll blocks. prepare for purge of excess... + sta dseed all blocks and bytes beyond new eof + lda tposlh must be zero'd + sta dsap + and #$01 + sta dseed+1 + lda tposhi + lsr a + sta dtree + ror dsap pass position in terms of block & bytes. + lda dseed now adjust for boundaries of $200 + ora dseed+1 + bne L48A2 branch if no adjustment necessary. + lda dsap get correct block ositions for sap + sec and tree levels. + sbc #$01 + sta dsap deallocate for last (phantom) block + lda #$02 and don't modify last data block. + bcs L489F branch if tree level unaffected. + dec dtree + bpl L489F branch if new eof not zero + lda #$00 + sta dtree otherwise, make a null seed out of it. + sta dsap +L489F sta dseed+1 +L48A2 ldy fcbptr also must pass file's 1st block address. + lda fcbbuf+12,y + sta firstbl + lda fcbbuf+13,y + sta firstbh + stz deblock lastly, initialize # of blocks to + stz deblock+1 be free'd. + jsr detree deallocate blocks from tree. + php save any error status until fcb + pha is cleaned up. + sec + ldy fcbptr + ldx #$00 +L48C2 lda firstbl,x + sta fcbbuf+12,y move in possible new first file block + lda fcbbuf+24,y address. adjust usage count also + sbc deblock,x + sta fcbbuf+24,y + iny + inx + txa + and #$01 test for both bytes adjusted + bne L48C2 without disturbing carry. + lda stortyp get possibly modified storage type + lsr a + lsr a + lsr a + lsr a + ldy fcbptr and save it in fcb. + sta fcbbuf+7,y + jsr clrstats make it look as though position has + jsr dvcbrev nothing allocated, update total blocks + ldy fcbptr in fcb and correct position. + iny + iny + ldx #$02 +L48F2 lda fcbbuf+18,y tell 'rdposn' to go to correct + sta tposll,x + eor #$80 position from incorrect place. + sta fcbbuf+18,y + dey + dex + bpl L48F2 + jsr rdposn go to correct position. + bcc L490D if no error. + tax otherwise, report latest error. + pla + plp + txa restore latest error code to stack + sec + php + pha save new error. + +* mark file as in need of a flush and update fcb with new end of file, +* then flush it. + +L490D jsr eofset go mark and update + jsr flush1 then go do the flush. + bcc L491C branch if no error. + tax save latest error. + pla clean previous error off stack + plp + txa and restore latest error to stack. + sec show error condition. + php restore error status to stack + pha and the error code. +L491C pla report any errors that may have + plp appeared. + rts + +geteof .EQ *-ofsX + ldx fcbptr index to end of file mark + ldy #$02 and index to user's call parameters +L4924 lda fcbbuf+21,x + sta (A3L),y + inx + iny + cpy #$05 + bne L4924 loop until all 3 bytes moved + clc no errors + rts + +newline .EQ *-ofsX + ldy #$02 adjust newline status for open file. + lda (A3L),y on or off ? + ldx fcbptr it will be 0 if off. + sta fcbbuf+31,x set new line mask + iny + lda (A3L),y and move in 'new-line' byte + sta fcbbuf+10,x + clc no error possible + rts + +getinfo .EQ *-ofsX + jsr findfile look for file. + bcc L4988 no error. + cmp #$40 was it a root directory file ? + sec (in case of no match) + bne L49A4 if not, then error. + lda #$F0 + sta d_stor for get info, report proper storage + stz reql type. forca a count of free blocks. + stz reqh + ldx vcbptr + jsr tkfrecnt get a fresh count of free blocks on + ldx vcbptr this volume. + lda vcbbuf+21,x return total blocks and total in use. + sta reqh 1st transfer 'free' blocks to zpage + lda vcbbuf+20,x for later subtraction to determine + sta reql the 'used' count. + lda vcbbuf+19,x transfer to 'd.' table as aux id + sta d_auxid+1 (total block count is considered aux id + pha for the volume) + lda vcbbuf+18,x + sta d_auxid + sec subtract and report the number of + sbc reql blocks 'in use' + sta d_usage + pla + sbc reqh + sta d_usage+1 +L4988 lda d_stor transfer bytes from internal order to + lsr a call spec via 'inftabl' translation + lsr a table but first change storage type to + lsr a external (low nibble) format. + lsr a + sta d_stor + ldy #$11 index to last of user's spec table. +L4994 lda inftabl-3,y + and #$7F strip bit used by setinfo + tax + lda d_stor,x move directory info to call spec. table + sta (A3L),y + dey + cpy #$03 + bcs L4994 if all info bytes moved, retn carry clr +L49A4 rts + +setinfo .EQ *-ofsX + jsr findfile get the file to work on. + bcs L49CF if error. + lda bubit see if backup bit can be cleared + eor #$20 + and d_attr + and #$20 + sta bkbitflg or preserve current... + ldy #$0D init pointer to user supplied list. +L49B9 ldx inftabl-3,y get index to corresponding 'd.' table. + bmi L49C3 branch if parameter can't be set. + lda (A3L),y + sta d_stor,x +L49C3 dey has user's request been satisfied ? + cpy #$03 + bcs L49B9 no, move next byte. + and #$18 make sure no illegal access bits were + beq L49D0 set !! branch if legal access. + lda #$4E otherwise, access error. + sec +L49CF rts +L49D0 ldy #$0B + lda (A3L),y was clock null input ? + beq L49D9 if yes. + jmp drevise1 end by updating directory. +L49D9 jmp drevise update with clock also... + +rename .EQ *-ofsX + jsr lookfile look for source (original) file. + bcc L4A1E if found. + cmp #$40 trying to rename a volume ? + bne L49FD no, return error. + jsr renpath syntax new name. + bcs L49FD rename error. + ldy pathbuf find out if only rootname for new name + iny + lda pathbuf,y must be $FF if volume name only. + bne L4A72 if not single name + ldx vcbptr check for open files before changing. + lda vcbbuf+17,x + bpl L49FF if volume not busy. + lda #$50 file busy error. +L49FD sec + rts +L49FF ldy #$00 get newname's length + lda pathbuf,y + ora #$F0 (root file storage type) + jsr mvrotnam update root directory. + bcs L4A74 rename error. + ldy #$00 + ldx vcbptr update vcb also. +L4A10 lda pathbuf,y move new name to vcb. + beq L4A1C + sta vcbbuf,x + iny next character + inx + bne L4A10 always. +L4A1C clc no errors + rts +L4A1E jsr getnamptr set y = 1st char of path, x = 0. +L4A21 lda pathbuf,y move original name to gbuf + sta gbuf,x for later comparison to new name. + bmi L4A2D if last character has been moved + iny otherwise, get the next one. + inx + bne L4A21 always. +L4A2D jsr renpath get new name syntaxed. + bcs L4A74 rename error. + jsr getnamptr set y = path, x = 0. + lda pathbuf,y now compare new name with old name +L4A38 cmp gbuf,x to make sure they are in the same dir. + php save result of comparison. + and #$F0 was last char really a count ? + bne L4A46 if not. + sty rnptr save pointer to next name, it might + stx namptr be the last. +L4A46 plp result of last comparison ? + bne L4A52 branch if different character or count. + inx bump pointers. + iny + lda pathbuf,y was it the last character ? + bne L4A38 if not. + clc no operation, names were the same. + rts +L4A52 ldy rnptr index to last name in the chain. + lda pathbuf,y get last name length. + sec + adc rnptr + tay + lda pathbuf,y this byte should be $00 ! + bne L4A72 if not, bad path error. + ldx namptr index to last of original name + lda gbuf,x + sec + adc namptr + tax + lda gbuf,x this byte should also be $00. + beq L4A76 if so, continue processing. +L4A72 lda #$40 bad pathname error. +L4A74 sec + rts +L4A76 jsr lookfile test for duplicate file name. + bcs L4A7F branch if file not found, which is ok !! + lda #$47 duplicate name error. + sec + rts +L4A7F cmp #$46 was it a valid file not found ? + bne L4A74 no, rename error. + jsr setpath syntax pathname of file to be changed. + jsr findfile get all the info on this file. + bcs L4A74 rename error. + jsr tstopen is file in use ? + lda #$50 anticipate file busy error. + bcs L4A74 error if in use. + lda d_attr test bit which allows rename. + and #$40 + bne L4A9D branch if ok to rename + lda #$4E otherwise, illegal access. +L4A9B sec + rts +L4A9D lda d_stor find out which storage type. + and #$F0 strip off name length. + cmp #$D0 is it a directory ? + beq L4AAE then ok. + cmp #$40 is it a seed, sapling or tree ? + bcc L4AAE then ok. + lda #$4A file incompatible error. + bne L4A9B always. +L4AAE jsr renpath since both names go into the directory, + bcs L4A74 syntax the new name to get the local + ldy rnptr name address. y = index to local name + ldx pathbuf,y length. adj y to last char of new name. + tya + adc pathbuf,y + tay +L4ABE lda pathbuf,y move local name to dir entry workspace. + sta d_stor,x + dey + dex + bne L4ABE + lda d_stor preserve file storage type. + and #$F0 strip off old name length. + tax + ora pathbuf,y add in new name's length. + sta d_stor + cpx #$D0 that file must be changed also. + bne L4AF0 branch if not directory type. + lda d_frst read in 1st header block of subdir + ldx d_frst+1 + jsr rdblk + bcs L4A74 errors. + ldy rnptr change the header's name to match the + lda pathbuf,y owner's new name. get local name length. + ora #$E0 assume it's a header. + jsr mvrotnam + bcs L4A74 +L4AF0 jmp drevise1 end by updating all path directories. +mvrotnam .EQ *-ofsX + ldx #$00 +L4AF5 sta gbuf+4,x + inx + iny + lda pathbuf,y + bne L4AF5 + jmp wrtgbuf write changed header block. +renpath .EQ *-ofsX + ldy #$03 get address to new pathname + lda (A3L),y + iny + sta zpt + lda (A3L),y set up for syntaxing routine (synpath) + sta zpt+1 + jmp synpath do syntax (returns y = local namelength) +getnamptr .EQ *-ofsX + ldy #$00 return pointer to 1st name of path. + bit prfxflg is this a prefixed name ? + bmi L4B1A branch if not. + ldy newpfxptr +L4B1A ldx #$00 + rts + +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.E +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.XDOS.F.txt b/ProDOS.203/ProDOS.S.XDOS.F.txt new file mode 100644 index 00000000..a9b22b6f --- /dev/null +++ b/ProDOS.203/ProDOS.S.XDOS.F.txt @@ -0,0 +1,355 @@ +NEW + AUTO 3,1 + +destroy .EQ *-ofsX + jsr findfile look for file to be destroyed. + bcs L4B66 if error. + jsr tstopen is it open ? + lda totent + bne L4B64 error if open. + stz reql force proper free count in volume. + stz reqh (no disk access occurs if already + jsr tstfrblk proper) + bcc L4B39 no errors. + cmp #$48 was error a full disk ? + bne L4B66 no, report error. +L4B39 lda d_attr make sure ok to destroy file. + and #$80 + bne L4B45 branch if ok to destroy. + lda #$4E access error + jsr p8errv (returns to caller) +L4B45 lda devnum last device used. + jsr twrprot1 test for write protected hardware + bcs L4B66 before going thru deallocation. + lda d_frst 'detree' needs first block address + sta firstbl + lda d_frst+1 + sta firstbh + lda d_stor find out which storage type. + and #$F0 strip off name length. + cmp #$40 is it a seed, sapling or tree ? + bcc L4B68 branch if it is. + bra L4BCF otherwise, test for directory destroy. +L4B64 lda #$50 file busy error. +L4B66 sec can't be destroyed + rts +L4B68 sta stortyp destroy a tree file. save storage type. + ldx #$05 + lda #$00 set 'detree' input variables, must be +L4B6F sta stortyp,x in order: deblock, dtree, dsap, dseed. + dex + bne L4B6F loop until all zero'd. + lda #$02 this avoids an extra file i/o and pre- + sta dseed+1 vents destruction of any deleted data. + inc delflag don't allow detree to zero index blocks. + jsr detree make trees and saplings into seeds. + dec delflag reset flag. + bcs L4B93 (de-evolution) +L4B85 ldx firstbh + lda firstbl now deallocate seed. + jsr dealloc + bcs L4B93 + jsr upbmap +L4B93 pha save possible error code. + lda #$00 update directory to free entry space. + sta d_stor + cmp h_fcnt file entry wrap ? + bne L4BA1 branch if no carry adjustment. + dec h_fcnt+1 take carry from hi byte of file entries. +L4BA1 dec h_fcnt mark header with one less file. + jsr dvcbrev go update block count in vcb (ignore + jsr drevise error, if any) and update dir last. + tax save possible new error code, + pla restore possible old error code. + bcc L4BAF branch if last call succeeded. + txa last call failed, use it's error code. +L4BAF cmp #$01 adjust carry accordingly + rts +dvcbrev .EQ *-ofsX update block free count in vcb. + ldy vcbptr point to vcb of correct device. + lda deblock get # of blocks recently freed. + adc vcbbuf+20,y + sta vcbbuf+20,y update current free block count. + lda deblock+1 + adc vcbbuf+21,y + sta vcbbuf+21,y + lda #$00 force re-scan from 1st bitmap + sta vcbbuf+28,y + rts +L4BCD bcc L4B85 branch widened (always taken) +L4BCF cmp #$D0 is this a directory file ? + bne L4C1B no, file incompatible. + jsr fndbmap make sure a buffer available for bitmap + bcs L4C1A if error. + lda d_frst read 1st block of directory into gbuf + sta bloknml + lda d_frst+1 + sta bloknml+1 + jsr rdgbuf + bcs L4C1A + lda gbuf+37 do any files exist in this directory ? + bne L4BF1 if so, access error. + lda gbuf+38 + beq L4BF6 +L4BF1 lda #$4E access error. + jsr p8errv P8 error vector +L4BF6 sta gbuf+4 make it an invalid subdirectory + jsr wrtgbuf + bcs L4C1A +L4BFE lda gbuf+2 get forward link. + cmp #$01 test for null block into carry. + ldx gbuf+3 get the rest of the block address. + bne L4C0A branch if not null. + bcc L4BCD was the low part null as well ? +L4C0A jsr dealloc free this block. + bcs L4C1A + lda gbuf+2 + ldx gbuf+3 + jsr rdblk + bcc L4BFE loop until all freed +L4C1A rts +L4C1B lda #$4A file incompatible + jsr p8errv (returns to caller) +fcbused .EQ *-ofsX mark fcb as dirty so the directory + pha will be flushed on 'flush'. + tya save regs. + pha + ldy fcbptr + lda fcbbuf+28,y fetch current fcb dirty byte. + ora #$80 mark fcb as dirty. + sta fcbbuf+28,y save it back + pla and restore regs. + tay + pla + rts + +* 'detree' deallocates blocks from tree files. it is assumed that the device has +* been pre-selected and the 'gbuf' may be used. +* +* on entry: +* stortype = storage type in upper nibble, lower nibble is undisturbed. +* firstbl & firstbh = first block of file (index or data). +* deblock = 0 +* dtree = ptr to 1st block with data to be deallocated at tree level. +* dsap = ptr to 1st block at sapling level. +* dseed = byte (0-511) position to be zeroed from (inclusive). +* +* on exit: +* stortype = modified result of storage type (if applicable). +* firstbl & h = modified if storage type changed. +* deblock = total number of blocks freed at all levels. +* dtree, dsap, deseed unchanged. +* +* to trim a tree to a seed file, both dtree and dsap must be zero. +* to go from tree to sapling, dtree alone must be zero. + +detree .EQ *-ofsX + lda stortyp which kind of tree ? + cmp #$20 is it a 'seed' ? + bcc L4C46 if yes. + cmp #$30 a sapling ? + bcc L4C51 if yes. + cmp #$40 is it at least a 'tree' ? + bcc L4C59 branch if it is. + lda #$0C block allocation error. + jsr sysdeath P8 system death vector + +* seedling file type - make sure first desireable block is the only +* block available in a seedling file. + +L4C46 lda dsap + ora dtree + bne L4CC2 + jmp seedel0 + +* sapling file type - make sure first desireable block is within the range of +* blocks available in a sapling file + +L4C51 lda dtree can't have any blocks in this range + bne L4CC2 if so then done + jmp sapdel0 else go deallocate +L4C59 lda #$80 + sta topdest for tree top start at end, work backwards. +L4C5E jsr drdfrst read specified first block into gbuf. + bcs L4CC2 return errors. + ldy topdest get current pointer to top indexes. + cpy dtree have enough sapling indexes been + beq L4CC3 deallocated? yes, now deallocate blocks + ldx #$07 buffer up to 8 sapling index block +L4C6D lda gbuf,y addresses. fetch low block address + sta dealbufl,x and save it. + ora gbuf+$100,y is it a real block that is allocated? + beq L4C81 branch if phantom block. + lda gbuf+$100,y fetch high block address + sta dealbufh,x and save it. + dex decrement and test for dealc buf filled. + bmi L4C93 branch if 8 addresses fetched. +L4C81 dey look for end of deallocation limit. + cpy dtree is this the last position on tree level? + bne L4C6D if not. + iny + lda #$00 fill rest of dealc buffer with null addresses. +L4C8A sta dealbufl,x + sta dealbufh,x + dex + bpl L4C8A +L4C93 dey decrement to prepare for next time. + sty topdest save index. + ldx #$07 +L4C99 stx dtmpx save index to dealc buf. + lda dealbufl,x + sta bloknml + ora dealbufh,x finished ? + beq L4C5E branch if done with this level. + lda dealbufh,x complete address with high byte, + sta bloknml+1 + jsr rdgbuf read sapling level into gbuf. + bcs L4CC2 return errors. + jsr dealblk go free all data indexes in this block + bcs L4CC2 + jsr wrtgbuf write the flipped index block + bcs L4CC2 + ldx dtmpx restore index to dealc buff. + dex are there more to free? + bpl L4C99 branch if so. + bmi L4C5E branch always to get up to 8 more +L4CC2 rts sapling block numbers. +L4CC3 ldy dtree deallocate all sapling blocks greater + iny than specified block. + jsr dalblk1 (master index in gbuf) + bcs L4CC2 if errors. + jsr wrtgbuf write updated master index back to disk. + bcs L4CC2 + ldy dtree figure out if tree can become sapling. + beq L4CEB branch if it can. + lda gbuf,y otherwise, continue with partial. + sta bloknml deallocation of last sapling index. + ora gbuf+$100,y is there such a sapling index block ? + beq L4CC2 all done if not. + lda gbuf+$100,y read in sapling level to be modified. + sta bloknml+1 + jsr rdgbuf read highest sapling index into gbuf. + bcc L4CF5 + rts +L4CEB jsr shrink shrink tree to sapling + bcs L4CC2 +sapdel0 .EQ *-ofsX + jsr drdfrst read specified sapling level index + bcs L4CC2 into gbuf. branch if error. +L4CF5 ldy dsap pointer to last of desirable indexes. + iny inc to 1st undesirable. + beq L4D05 branch if all are desirable. + jsr dalblk1 deallocate all indexes above specified. + bcs L4CC2 + jsr wrtgbuf write out the index block + bcs L4CC2 +L4D05 ldy dsap prepare to clean up last data block. + beq L4D1F branch if possibility of making a seed. +L4D0A lda gbuf,y fetch low order data block address. + sta bloknml + ora gbuf+$100,y is it a real block ? + beq L4CC2 if not, then done. + lda gbuf+$100,y + sta bloknml+1 + jsr rdgbuf go read data block into gbuf. + bcc L4D2E branch if good read + rts or return error. +L4D1F lda dtree are both tree and sap levels zero ? + bne L4D0A if not. + jsr shrink reduce this sap to a seed. + bcs L4D52 if error. +seedel0 .EQ *-ofsX + jsr drdfrst go read data block. + bcs L4D52 if error. +L4D2E ldy dseed+1 check high byte for no deletion. + beq L4D39 branch if all of 2nd page to be deleted. + dey if dseed > $200 then all were done. + bne L4D52 branch if that is the case. + ldy dseed clear only bytes >= dseed. +L4D39 lda #$00 +L4D3B sta gbuf+$100,y zero out unwanted data + iny + bne L4D3B + ldy dseed+1 is that all ? + bne L4D4F yes. + ldy dseed +L4D49 sta gbuf,y + iny + bne L4D49 +L4D4F jmp wrtgbuf update data block to disk. +L4D52 rts return error status. +drdfrst .EQ *-ofsX read specified 1st block into gbuf + lda firstbl + ldx firstbh + jmp rdblk go read it + +* beware that dealloc may bring in a new bitmap block and may destroy +* locations 46 and 47 which are used to point to the current index block. + +shrink .EQ *-ofsX + ldx firstbh first deallocate top index block + txa + pha + lda firstbl + pha save block address of this index block. + jsr dealloc free it from the bitmap + pla + sta bloknml set master of sapling + pla index block address. + sta bloknml+1 + bcs L4D8D report errors. + lda gbuf get # of new 1st block from old index. + sta firstbl + lda gbuf+$100 + sta firstbh + ldy #$00 + jsr swapme flip that one entry in old top index. + sec now change file type, + lda stortyp from tree to sapling, + sbc #$10 or from sapling to seed. + sta stortyp + jsr wrtgbuf write the (deallocated) old top index. +L4D8D rts return error status. +dealblk .EQ *-ofsX + ldy #$00 start at beginning. +dalblk1 .EQ *-ofsX + lda bloknml save disk address of gbuf's data. + pha + lda bloknml+1 + pha +L4D96 sty saptr save current index. + lda gbuf,y get low address of block to deallocate. + cmp #$01 test for null block into carry. + ldx gbuf+$100,y get remainder of block address. + bne L4DA5 branch if not null. + bcc L4DB0 was the low part null too ? +L4DA5 jsr dealloc free it up on volume bitmap. + bcs L4DB4 return any error. + ldy saptr get index to sapling level index block. + jsr swapme +L4DB0 iny next block address. + bne L4D96 if more to deallocate or test. + clc no error. +L4DB4 tax save error code, if any. + pla restore blocknm (16 bit) + sta bloknml+1 + pla + sta bloknml + txa restore return code + rts +swapme .EQ *-ofsX + lda delflag swapping or zeroing ? + bne L4DC5 skip if swapping. + tax make x = 0. + beq L4DCB zero the index (always taken). +L4DC5 ldx gbuf+$100,y index high + lda gbuf,y index low +L4DCB sta gbuf+$100,y save index high + txa + sta gbuf,y save index low + rts done. + +MAN +SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS.F +LOAD USR/SRC/PRODOS.203/PRODOS.S +ASM diff --git a/ProDOS.203/ProDOS.S.XDOS.M.txt b/ProDOS.203/ProDOS.S.XDOS.M.txt index 991d9a68..ab445671 100644 --- a/ProDOS.203/ProDOS.S.XDOS.M.txt +++ b/ProDOS.203/ProDOS.S.XDOS.M.txt @@ -90,9 +90,9 @@ cmembit .EQ *-ofsX lda whichbit,y bit position representation. pha save bit position mask for now. txa page address. - lsr a - lsr a determine 2k set - lsr a + lsr + lsr determine 2k set + lsr tay return it in y. pla restore bit mask. return bit position rts in a & y, pointer to memtabl in x. @@ -162,11 +162,11 @@ L4EC7 rts calldisp .EQ *-ofsX lda altram read/write RAM bank 2 lda altram - lda #>dispadr + lda /dispadr sta A2L+1 - lda #displc2 + lda /displc2 sta A1L+1 stz A1L ldy #$00 @@ -176,15 +176,15 @@ L4EE0 dey move a page of code. sta (A2L),y tya bne L4EE0 - inc1L+1 pointers to next page - inc2L+1 + inc A1L+1 pointers to next page + inc A2L+1 dex move all pages needed bne L4EE0 lda ramin read/write RAM bank 1 lda ramin swap mli space back in stz mliact MLI active flag stz softev - lda #>dispadr point RESET to dispatch entry + lda /dispadr point RESET to dispatch entry sta softev+1 eor #$A5 sta pwredup power up byte @@ -198,9 +198,9 @@ remap_sp .EQ *-ofsX lda A4L command number sta cmdnum bne L4F1B taken if not status call - ldy #spstatlist + ldy /spstatlist sty buf+1 stz bloknml set statcode = 0 for simple status call L4F1B cmp #$03 format command ? @@ -208,10 +208,10 @@ L4F1B cmp #$03 format command ? ldx #$01 format has only 1 parameter. L4F21 stx statparms set # of parms. lda unitnum - lsr a turn unit number into an index - lsr a - lsr a - lsr a + lsr turn unit number into an index + lsr + lsr + lsr tax lda spunit-1,x get the smartport unit number and sta sp_unitnum store into smartport parm list. @@ -228,7 +228,7 @@ sp_vector .EQ *-ofsX smartport call jsr $0000 (entry address gets modified) cmdnum .EQ *-ofsX .HS 00 command # - .DA statparms' + .DA statparms bcs L4F6E ldx cmdnum status call ? bne L4F6E no... @@ -246,90 +246,90 @@ L4F65 and #$44 mask all but write allowed and write L4F6D sec L4F6E rts spvectlo .EQ *-ofsX storage for low byte of smartport - .DA #0000000000000000' entry. - .DA #00000000000000' + .HS 0000000000000000 entry. + .HS 00000000000000 spvecthi .EQ *-ofsX storage for high byte of smartport - .DA #0000000000000000' entry. - .DA #00000000000000' + .HS 0000000000000000 entry. + .HS 00000000000000 statparms .EQ *-ofsX # of parms (always 3 except format) - dc h'03' + .HS 03 sp_unitnum .EQ *-ofsX .HS 00 unit number sp_bufptr .EQ *-ofsX .HS 0000 data buffer - dc h'000000' block number (3 bytes) + .HS 000000 block number (3 bytes) * data tables scnums .EQ *-ofsX table of valid mli command numbers. - dc h'D3000000' - .DA #40410000808182' - .DA #65C0C1C2C3C4C5C6' - .DA #C7C8C9CACBCCCDCE' - .DA #CF00D0D1D2' + .HS D3000000 + .HS 40410000808182 + .HS 65C0C1C2C3C4C5C6 + .HS C7C8C9CACBCCCDCE + .HS CF00D0D1D2 pcntbl .EQ *-ofsX parameter counts for the calls - dc h'02FFFF' - .DA #FF0201FFFF030300' - .DA #04070102070A0201' - .DA #0103030404010102' - .DA #02FF020202' + .HS 02FFFF + .HS FF0201FFFF030300 + .HS 04070102070A0201 + .HS 0103030404010102 + .HS 02FF020202 * command table cmdtable .EQ *-ofsX - .DA create' create - .DA destroy' destroy - .DA rename' rename - .DA setinfo' setinfo - .DA getinfo' getinfo - .DA online' online - .DA setprefx' set prefix - .DA getprefx' get prefix - .DA openf' open - .DA newline' newline - .DA readf' read - .DA writef' write - .DA closef' close - .DA flushf' flush - .DA setmark' set mark - .DA getmark' get mark - .DA seteof' seteof - .DA geteof' geteof - .DA setbuf' setbuf - .DA getbuf' getbuf + .DA create create + .DA destroy destroy + .DA rename rename + .DA setinfo setinfo + .DA getinfo getinfo + .DA online online + .DA setprefx set prefix + .DA getprefx get prefix + .DA openf open + .DA newline newline + .DA readf read + .DA writef write + .DA closef close + .DA flushf flush + .DA setmark set mark + .DA getmark get mark + .DA seteof seteof + .DA geteof geteof + .DA setbuf setbuf + .DA getbuf getbuf * corresponding command function bytes disptch .EQ *-ofsX - dc h'A0A1A2A3' - .DA #84050607' - dc h'88494A4B' - .DA #2C2D4E4F' - .DA #50515253' + .HS A0A1A2A3 + .HS 84050607 + .HS 88494A4B + .HS 2C2D4E4F + .HS 50515253 dinctbl .EQ *-ofsX table to increment - dc h'0100000200' directory usage/eof counts + .HS 0100000200 directory usage/eof counts pass .EQ *-ofsX - dc h'75' + .HS 75 xdosver .EQ *-ofsX - dc h'00' + .HS 00 compat .EQ *-ofsX .HS 00 - dc h'C3270D000000' + .HS C3270D000000 rootstuf .EQ *-ofsX - .DA #0F02000400000800' + .HS 0F02000400000800 whichbit .EQ *-ofsX - .DA #8040201008040201' + .HS 8040201008040201 ofcbtbl .EQ *-ofsX - .DA #0C0D1819151617' + .HS 0C0D1819151617 inftabl .EQ *-ofsX - .DA #1E101F2080939421' - .DA #22232418191A1B' + .HS 1E101F2080939421 + .HS 22232418191A1B deathmsg .EQ *-ofsX - dc h'20' - msb on - dc c'RESTART SYSTEM-$01' - dc h'20' + .HS 20 + + .AS 'RESTART SYSTEM-$01' + .HS 20 *** work space *** @@ -368,8 +368,8 @@ d_entblk .EQ *-ofsX address of block which contains entry d_entnum .EQ *-ofsX entry number within block .HS 00 d_stor .EQ *-ofsX - dc h'0000000000000000' file name - dc h'0000000000000000' + .HS 0000000000000000 file name + .HS 0000000000000000 d_filid .EQ *-ofsX user's identification byte .HS 00 d_frst .EQ *-ofsX first block of file @@ -377,7 +377,7 @@ d_frst .EQ *-ofsX first block of file d_usage .EQ *-ofsX # of blocks allocated to this file .HS 0000 d_eof .EQ *-ofsX current end of file marker - dc h'000000' + .HS 000000 d_credt .EQ *-ofsX .HS 0000 file creation date .HS 0000 file creation time @@ -395,11 +395,11 @@ d_moddt .EQ *-ofsX d_dhdr .EQ *-ofsX file directory header block address .HS 0000 scrtch .EQ *-ofsX scratch area for - .DA #00000000' allocation address conversion. + .DA #00000000 allocation address conversion. oldeof .EQ *-ofsX temp used in r/w - dc h'000000' + .HS 000000 oldmark .EQ *-ofsX - .DA #000000' + .DA #000000 xvcbptr .EQ *-ofsX used in 'cmpvcb' as a temp .HS 00 vcbptr .EQ *-ofsX diff --git a/ProDOS.203/ProDOS.S.XDOS.txt b/ProDOS.203/ProDOS.S.XDOS.txt deleted file mode 100644 index b1dfaa22..00000000 --- a/ProDOS.203/ProDOS.S.XDOS.txt +++ /dev/null @@ -1,1756 +0,0 @@ -NEW - AUTO 3,1 -* object code = mli_2 -* xdos mli system call processor - .OP 65C02 -ofsX .EQ xdosobj-xdosorg offset to xdos org - -xdosmli .EQ *-ofsX xdos MLI in aux ram -xdosobj cld no decimal. - pla get processor status - sta spare1 save it temporarily - sty mliy save x and y - stx mlix - pla find out the address of the caller - sta A3L - clc preserve the address of the call spec. - adc #$04 - sta mliretn last MLI call return address - pla - sta A3L+1 - adc #$00 - sta mliretn+1 - lda spare1 - pha pull processor status - plp to re-enable interrupts. - cld still no decimal - ldy #$00 - sty p8error clear any previous errors. - iny find out if command is valid. - lda (A3L),y get command # - lsr a and hash it to a range of 0-$1F - lsr a - lsr a - lsr a - clc - adc (A3L),y - and #$1F - tax - lda (A3L),y check result to see if valid command # - cmp scnums,x - bne scnerr - iny index to call spec parm list. - lda (A3L),y make A3L point to parameter count byte - pha in parameter block. - iny - lda (A3L),y - sta A3L+1 - pla - sta A3L - ldy #$00 make sure parameter list has the - lda pcntbl,x correct # of parameters. - beq goclock clock has 0 parameters. - cmp (A3L),y - bne scperr error if wrong count. - lda scnums,x get call # again - cmp #$65 is it quit? - beq special if so, then call quit dispatcher - asl carry set if bfm or dev mgr - bpl godevmgr - bcs gobfmgr - lsr a shift back down for interrupt manager - and #$03 valid calls are 0 and 1 - jsr intmgr - bra exitmli -special jmp jspare P8 system death vector -goclock jsr clockv go read clock. - bra exitmli no errors possible -godevmgr lsr a shift back down for device manager. - adc #$01 valid commands are 1 and 2. - sta A4L save command #. - jsr devmgr execute read or write request. - bra exitmli -gobfmgr lsr a shift back down for block file manager. - and #$1F valid commands are 0-$13 - tax - jsr bfmgr -exitmli stz bubit clear backup bit - ldy p8error P8 error code - cpy #$01 if > 0 then set carry - tya and set z flag. - php disable interrupts until exit complete. - sei - lsr mliact indicate MLI done. - plx save status register until return. - lda mliretn+1 place last MLI call return address - pha on stack. return is done via 'rti' - lda mliretn so the status register is restored - pha at the same time, so - phx place status back on stack - tya return error, if any. - ldx mlix MLI X register savearea - ldy mliy MLI Y register savearea - pha - lda bnkbyt1 restore language card status - jmp HBFA0 and return. -nodevice .EQ *-ofsX - lda #$28 no device connected. - jsr p8errv P8 error vector. -scnerr lda #$01 no such command. - bne H30B0 -scperr lda #$04 parameter count is invalid -H30B0 jsr gosyserr - bcs exitmli always taken - -* ProDOS Device Manager - -devmgr .EQ *-ofsX - ldy #$05 - php do not allow interrupts. - sei the call spec for devices must -H30B9 lda (A3L),y be passed to drivers in page zero: - sta |A4L),y sta $0042,y - dey - bne H30B9 - ldx buf+1 buffer page - stx usrbuf+1 to user buffer - inx - inx - lda buf is buffer page aligned (nn00) ? - beq H30CC branch if it is - inx else account for 3-page straddle -H30CC jsr vldbuf1 make sure user buffer is not - bcs dvmgrerr conflicting with protected ram. - jsr dmgr call internal entry for device dispatch - bcs dvmgrerr branch if error - plp - clc no error - rts -dvmgrerr plp restore interrupt status -gosyserr .EQ *-ofsX - jsr p8errv P8 error vector -dmgr .EQ *-ofsX interrupts must always be off. - lda unitnum get device # and - and #$F0 strip misc lower nibble - sta unitnum then save it. - lsr a use as index to device table - lsr a - lsr a - tax - lda drivertbl1,x fetch driver address - sta goadr - lda drivertbl1+1,x - sta goadr+1 -gocmd .EQ *-ofsX - jmp (goadr) goto driver (or error if no driver) - -* ProDOS interrupt manager - -intmgr .EQ *-ofsX - sta A4L interrupt command - lsr a allocate interrupt or deallocate? - bcs dealcint branch if deallocate. - ldx #$03 test for a free interrupt space in tbl. -alcint lda inttbl-2,x test high address for 0. - bne H3118 branch if spot occupied. - ldy #$03 get address of routine. - lda (A3L),y must not be zero page. - beq badint error if it is. - sta inttbl-2,x save high address - dey - lda (A3L),y - sta inttbl-3,x and low address. - txa return interrupt # in range 1-4 - lsr a - dey - sta (A3L),y pass back to user. - clc no errors. - rts -H3118 inx - inx next lower priority spot - cpx #$0B are all 4 already allocated? - bne alcint branch if not. - lda #$25 interrupt table full - bne H3124 -badint lda #$53 invalid parameter. -H3124 jsr p8errv P8 error vector. -dealcint ldy #$01 zero out interrupt vector - lda (A3L),y but make sure it is a valid #. - beq badint error if < 1 - cmp #$05 or > 4 - bcs badint - asl - tax - lda #$00 now clear it - sta inttbl-2,x - sta inttbl-1,x - clc - rts -irqrecev .EQ *-ofsX - lda accsav get acc from where old ROM put it. - sta p8areg - stx p8xreg entry point on ram card interrupt - sty p8yreg - tsx - stx p8sreg - lda irqflag irq flag = 0 if old roms - bne H315D and 1 if new roms. - pla restore return address and p-reg. - sta p8preg - pla - sta intadr interrupt return address - pla - sta intadr+1 -H315D txs - lda mslot set up to re-enable $Cn00 rom - sta irqdev+2 - tsx make sure stack has room for 16 bytes. - bmi H3170 branch if stack ok - ldy #$0F otherwise, make room and save it. -H3169 pla - sta svstack,y - dey - bpl H3169 -H3170 ldx #$FA save 6 bytes of page 0 -H3172 lda $00,x - sta svzerop-$FA,x - inx - bne H3172 - -* poll interrupt routines for a claimer - - lda inttbl+1 test for a valid routine. - beq intr2 branch if no routine. - jsr goint1 execute - bcc irqdone -intr2 lda inttbl+3 repeat 3 more times - beq intr3 - jsr goint2 - bcc irqdone -intr3 lda inttbl+5 - beq intr4 - jsr goint3 - bcc irqdone -intr4 lda inttbl+7 - beq H31A2 - jsr goint4 - bcc irqdone -H31A2 inc irqcount allow 255 unclaimed interrupts - bne irqdone before system death. - lda #$01 bad irq so - jsr sysdeath kill the system. -irqdone ldx #$FA -H31AE lda svzerop-$FA,x restore the zero page - sta $00,x - inx - bne H31AE - ldx p8sreg test if stack needs restoring. - bmi H31C6 branch if not. - ldy #$00 -H31BD lda svstack,y restore stack - pha - iny - cpy #$10 - bne H31BD -H31C6 lda irqflag check for old roms. - bne H31DD branch if new roms. - ldy p8yreg restore registers. - ldx p8xreg - lda clrrom re-enable i/o card. -irqdev .EQ *-ofsX - lda $C100 Cn is self modifying. - lda irqdev+2 restore device id. - sta mslot slot being accessed. -H31DD jmp irqexit do necessary bank switches and return. -irqflag .EQ *-ofsX - .HS 00 0 = old roms. 1 = new roms. -irqcount .EQ *-ofsX - .HS 00 # of unclaimed interrupts. -svstack .EQ *-ofsX temporary save area from stack - .HS 0000000000000000 - .HS 0000000000000000 -svzerop .EQ *-ofsX temporary save area for zero page - .HS 000000000000 -goint1 .EQ *-ofsX - jmp (inttbl) interrupt routine 1 -goint2 .EQ *-ofsX - jmp (inttbl+2) interrupt routine 2 -goint3 .EQ *-ofsX - jmp (inttbl+4) interrupt routine 3 -goint4 .EQ *-ofsX - jmp (inttbl+6) interrupt routine 4 -syserr1 .EQ *-ofsX - sta p8error P8 error code - plx - plx pop 1 level of return - sec - rts -sysdeath1 .EQ *-ofsX - tax death error code. - sta clr80vid disable 80 col hardware. - lda txtset switch in text. - lda cortflag is this a Cortland? - beq H321A if not, don't use super hires switch. - stz newvideo force off super hires. -H321A lda txtpage1 switch in text page 1. - ldy #$13 -H321F lda #$20 inverse space border - sta vline11+10,y - sta vline13+10,y - lda deathmsg,y - sta vline12+10,y 'RESTART SYSTEM-$0x' - dey - bpl H321F - txa x = death error code - and #$0F convert to ascii - ora #$B0 - cmp #$BA - bcc H323B branch if not > 9. - adc #$06 inc to alpha a-f -H323B sta vline12+28 death error code 1 to F -H323E bra H323E end of xdos mli - -* ProDOS Block File Manager - -bfmgr .EQ *-ofsX - lda disptch,x translate into command address. - asl bit 7 indicates pathname to process - sta cmdtemp - and #$3F bit 6 is refnum, 5 is time to process - tax - lda cmdtable,x move address to indirect jump - sta goadr - lda cmdtable+1,x high byte - sta goadr+1 - lda #$20 init backup bit flag - sta bkbitflg to say 'file modified' - bcc nopath - jsr setpath process pathname before calling command - bcs errorsys branch if bad name. -nopath asl cmdtemp test for refnum processing - bcc nopreref - jsr findfcb set pointers to fcb and vcb of file - bcs errorsys -nopreref asl cmdtemp check for necessity of time stamp - bcc H3274 - jsr clockv date/time -H3274 jsr gocmd execute command - bcc goodop -errorsys jsr p8errv P8 error vector -goodop rts -setpath .EQ *-ofsX - ldy #$01 index to pathname pointer - lda (A3L),y low pointer address - sta zpt - iny - lda (A3L),y hi pointer address - sta zpt+1 -synpath .EQ *-ofsX entry used by rename for 2nd pathname. - ldx #$00 x = index to pathbuf - ldy #$00 y = index to input pathname. - stx prfxflg assume prefix is in use. - stx pathbuf mark pathbuf = nothing processed. - lda (zpt),y validate pathname length > 0 and < 65 - beq errsyn - cmp #$41 - bcs errsyn - sta pathcnt this is used to compare for - inc pathcnt end of pathname processing. - iny now check for full pathname... - lda (zpt),y (full name if starts with '/') - ora #$80 - cmp #$AF - bne H32AD branch if prefix appended. - sta prfxflg set prefix flag = prefix not used. - iny index to 1st character of pathname. -H32AD lda #$FF set current position of pathbuf - sta pathbuf,x to indicate end of pathname. - sta namcnt $FF = no chars processed in local name. - stx namptr pointer to local name length byte. -H32B8 cpy pathcnt done with pathname processing? - bcs endpath - lda (zpt),y get character - and #$7F - inx prepare for next char - iny - cmp #$2F is it delimiter '/' ? - beq endname yes - cmp #$61 lowercase? - bcc H32CD no - and #$5F shift to uppercase -H32CD sta pathbuf,x store char - inc namcnt is it the 1st char of a local name? - bne H32DA no - inc namcnt increment to 1 - bne H32E6 1st char must be alpha (always taken) -H32DA cmp #$2E is it '.' ? - beq H32B8 ok, then do next char - cmp #$30 at least a '0' ? - bcc errsyn error if not - cmp #$3A is it numeric? - bcc H32B8 yes, get next char -H32E6 cmp #$41 at least an 'a' ? - bcc errsyn error if not - cmp #$5B is it > 'z' ? - bcc H32B8 branch if valid alpha to get next char -errsyn sec bad pathname - lda #$40 - rts -endpath lda #$00 end pathname with a 0 - bit namcnt also make sure count is positive - bpl H32FD - sta namcnt - dex -H32FD inx - sta pathbuf,x - beq errsyn error if '/' only. - stx pathcnt save length of pathname - tax -endname lda namcnt validate local name < 16 - cmp #$10 - bcs errsyn - phx save pointer - ldx namptr get index to beginning of local name - sta pathbuf,x save local name's length - plx restore pointer - bne H32AD branch if more names to process - clc probably no error, but - lda prfxflg make sure all pathnames are prefixed - bne H3323 or begin with a '/'. - lda newpfxptr must be non-zero - beq errsyn -H3323 rts - -* set prefix command - -setprefx .EQ *-ofsX - jsr setpath call is made to detect if a null path. - bcc H3333 path ok. - ldy pathbuf is it a null pathname? - bne pfxerr error if not - jsr stypfx indicate null prefix - clc no error - rts -H3333 jsr findfile go find specified prefix directory. - bcc H333C if no error. - cmp #$40 bad pathname. - bne pfxerr branch if error is not root directory. -H333C lda d_stor make sure last local name is dir type - and #$D0 (either root or sub). - eor #$D0 directory? - bne ptyperr wrong type - ldy prfxflg new or appended prefix? - bne H334D - lda newpfxptr append new prefix to old -H334D tay - sec find new beginning of prefix - sbc pathcnt - cmp #$C0 too long? - bcc errsyn then error - tax - jsr stapfx - lda d_dev save device # - sta p_dev - lda d_frst and address of 1st block - sta p_blok - lda d_frst+1 - sta p_blok+1 -movprfx lda pathbuf,y - sta pathbuf,x - iny - inx - bne movprfx - clc good prefix - rts -ptyperr lda #$4B filetype error (not a directory) -pfxerr sec - rts - -* get prefix command - -getprefx .EQ *-ofsX calc how big a buffer is needed. - clc get index to users pathname buffer - ldy #$01 - lda (A3L),y - sta usrbuf user buffer ptr - iny - lda (A3L),y - sta usrbuf+1 - stz cbytes+1 set buffer length at 64 char max - lda #$40 - sta cbytes - jsr valdbuf go validate prefix buffer address - bcs pfxerr - ldy #$00 y = indirect index to user buffer. - lda newpfxptr get address of beginning of prefix - tax - beq nulprfx if null prefix. - eor #$FF get total length of prefix - adc #$02 add 2 for leading and trailing slashes. -nulprfx sta (usrbuf),y store length in user's buffer. - beq gotprfx branch if null prefix. -sendprfx iny inc to next user buffer location. - lda pathbuf,x get next char of prefix. -sndlimit sta (usrbuf),y give char to user. - and #$F0 check for length descriptor. - bne H33B3 branch if regular character - lda #$2F otherwise, substitute a slash. - bne sndlimit branch always -H33B3 inx - bne sendprfx branch if more to send. - iny - lda #$2F end with '/' - sta (usrbuf),y -gotprfx clc no error - rts -findfcb .EQ *-ofsX - ldy #$01 index to ref# - lda (A3L),y is it a valid file# ? - beq badref must not be 0. - cmp #$09 must be 1 to 8 only. - bcs badref - pha - dec a - lsr a - ror a - ror a - ror a multiply by 32. - sta fcbptr used as an index to fcb - tay - pla restore ref# in acc - cmp fcbbuf,y - bne errnoref -fndfcbuf .EQ *-ofsX get page address of file buffer. - lda fcbbuf+11,y - jsr getbufadr get file's address into bufaddrl,h - ldx bufaddrh (y=fcbptr preserved) - beq fcbdead fcb corrupted - stx datptr+1 save ptr to data area of buffer - inx - inx index block always 2 pages after data - stx zpt+1 - lda fcbbuf+1,y also set up device # - sta devnum - lda bufaddrl - sta datptr index and data buffers always on - sta zpt page boundaries. -fndfvol tax search for associated vcb - lda vcbbuf+16,x - cmp fcbbuf+1,y is this vcb the same device? - beq tstvopen if it is, make sure volume is active. -nxtfvol txa adjust index to next vcb. - clc - adc #$20 - bcc fndfvol loop until volume found. - lda #$0A open file has no volume so - jsr sysdeath kill the system. -fcbdead lda #$0B fcb error so - jsr sysdeath kill the system. -tstvopen lda vcbbuf,x make sure this vcb is open. - beq nxtfvol branch if it is not active. - stx vcbptr save ptr to good vcb. - clc no error - rts -errnoref lda #$00 put a zero into this fcb to - sta fcbbuf,y show free fcb. -badref lda #$43 requested refnum is - sec illegal (out of range) - rts - -* online command - -online .EQ *-ofsX move user spec'd buffer ptr to usrbuf. - jsr mvdbufr figure out how big buffer has to be. - stz cbytes set this for valdbuf routine. - stz cbytes+1 - ldy #$01 - lda (A3L),y if 0 then cbytes=$100 else $010 for one - and #$F0 device. mask out unused nibble. - sta devnum last device used. - beq H343C branch if all devices. - lda #$10 cbytes = $010 - sta cbytes - bne H343F always taken -H343C inc cbytes+1 cbytes = $100 -H343F jsr valdbuf go validate buffer range against - bcs onlinerr allocated memory. - lda #$00 zero out user buffer space - ldy cbytes -H3449 dey - sta (usrbuf),y - bne H3449 - sta namptr used as pointer to user buffer. - lda devnum get device # again. - bne H3474 branch if only 1 device to process. - jsr mvdevnums get list of currently recognized dev's. -H3459 phx save index to last item on list - lda loklst,x - sta devnum save desired device to look at. - jsr online1 log this volume and return it's name. - lda namptr inc pointer for next device - clc - adc #$10 - sta namptr - plx get index to device list. - dex next device. - bpl H3459 branch if there is another device. - lda #$00 no errors for multiple on-line - clc -onlinerr rts -online1 .EQ *-ofsX -H3474 jsr fnddvcb see if it has already been logged in. - bcs olinerr1 branch if vcb is full. - ldx #$00 read in root (volume) directory - lda #$02 - jsr rdblk read it into general purpose buffer. - ldx vcbptr index to the vcb entry. - bcc volfound branch if read was ok. - tay error value. - lda vcbbuf+17,x don't take the vcb offline if - bne rtrnerr there are active files present. - sta vcbbuf,x now take the volume offline - sta vcbbuf+16,x -rtrnerr tya error value. - bcs olinerr1 branch if unable to read. -volfound lda vcbbuf,x has it been logged in before? - beq H349E if not. - lda vcbbuf+17,x it has, are there active files? - bmi H34AA branch if volume is currently busy. -H349E jsr logvcb1 go log it in. - bcs olinerr1 branch if there is a problem. - lda #$57 anticipate a duplicate active volume - bit duplflag exits. - bmi olinerr1 branch if so. -H34AA ldx vcbptr - jsr cmpvcb does vol read compare with logged vol? - lda #$2E anticipate wrong volume mounted. - bcc H34D0 branch if ok. -olinerr1 pha save error code. - jsr svdevn report what device has problem. - pla error code. - iny tell what error was encountered. - sta (usrbuf),y - cmp #$57 duplicate volume error? - bne H34CE no. - iny report which other device has same name - ldx vcbentry - lda vcbbuf+16,x - sta (usrbuf),y - stz duplflag clear duplicate flag. - lda #$57 duplicate volume error code. -H34CE sec flag error - rts -H34D0 lda vcbbuf,x get volume name count - sta namcnt - ldy namptr index to user's buffer. -H34D9 lda vcbbuf,x move name to user's buffer - sta (usrbuf),y - inx - iny - dec namcnt - bpl H34D9 -svdevn .EQ *-ofsX - ldy namptr index to 1st byte of this entry. - lda devnum upper nibble = device# and - ora (usrbuf),y lower nibble = name length. - sta (usrbuf),y - clc no errors - rts end of block file manager - -* create file - -create .EQ *-ofsX - jsr lookfile check for duplicate, get free entry - bcs tstfnf error code may be 'file not found' - lda #$47 name already exists -crerr1 sec - rts -tstfnf cmp #$46 'file not found' is ok - bne crerr1 otherwise exit with error. - ldy #$07 test for tree or directory file, - lda (A3L),y no other kinds are legal. - cmp #$04 is it seed, sapling or tree? - bcc tstdspc branch if it is - cmp #$0D - bne ctyperr report type error if not directory. -tstdspc lda devnum make sure destination device - jsr twrprot1 is not write protected. - bcs H351D - lda nofree is there space in directory to - beq xtndir add this file? branch if not - jmp creat1 otherwise, go create file. -ctyperr lda #$4B filetype error - sec -H351D rts -xtndir lda own_blk before extending directory, - ora own_blk+1 make sure it's a subdirectory. - bne H352A - lda #$49 otherwise, directory full error - sec - rts -H352A lda bloknml preserve disk address of current (last) - pha directory link, before allocating an - lda bloknml+1 extended block. - pha - jsr alc1blk allocate a block for extending directory - plx - stx bloknml+1 restore block addr of dir info in gbuf - plx - stx bloknml - bcs H351D unable to allocate. - sta gbuf+2 save block address in y,a to - sty gbuf+3 current directory. - jsr wrtgbuf update directory block with new link. - bcs H351D if error - ldx #$01 -swpbloks lda bloknml,x prepare new directory block - sta gbuf,x using current block as back link - lda gbuf+2,x - sta bloknml,x and save new block as next to be written - dex - bpl swpbloks - inx - txa x and a = 0 -clrdir sta gbuf+2,x - sta gbuf+$100,x - inx - bne clrdir - jsr wrtgbuf write prepared directory extension. - bcs H351D if error - lda own_blk - ldx own_blk+1 - jsr rdblk read in parent directory block - ldx own_ent and calc entry address. - lda #>gbuf - sta zpt+1 - lda #$04 -ocalc clc - dex has entry address been calulated? - beq H3584 if yes. - adc own_len next entry address - bcc ocalc - inc zpt+1 entry must be in 2nd 256 bytes of block - bcs ocalc always taken. -H3584 sta zpt - ldy #$13 index to block count -H3588 lda (zpt),y - adc dinctbl-$13,y add 1 to block count and - sta (zpt),y - iny - tya $200 to the directory's eof. - eor #$18 done with usage/eof update? - bne H3588 branch if not. - jsr wrtgbuf go update parent. - bcs crerr2 - jmp create -crerr2 rts return and report errors -creat1 .EQ *-ofsX - ldx #$00 zero out gbuf -H35A0 stz gbuf,x - stz gbuf+$100,x and data block of file. - inx - bne H35A0 - ldy #$0B move user specified date/time -cmvtime lda (A3L),y to directory. - sta d_filid,y - txa if all 4 bytes of date/time = 0 - ora (A3L),y then use built-in date/time. - tax - dey - cpy #$07 - bne cmvtime - txa does user want default time? - bne cmvname if not. - ldx #$03 -mvdftime lda p8date,x move current default date/time - sta d_credt,x - dex - bpl mvdftime -cmvname lda (A3L),y y = index to file kind. - cmp #$04 - lda #$10 assume tree type - bcc csvfkind - lda #$D0 it's directory. -csvfkind ldx namptr index to local name of pathname. - ora pathbuf,x combine file kind with name length. - sta d_stor sos calls this 'storage type'. - and #$0F strip back to name length - tay and use as counter for move. - clc - adc namptr calc end of name - tax -crname lda pathbuf,x move local name as filename - sta d_stor,y - dex - dey - bne crname - ldy #$03 index to 'access' parameter - lda (A3L),y - sta d_attr - iny also move 'file identification' - lda (A3L),y - sta d_filid -cmvauxid iny move auxillary identification bytes - lda (A3L),y - sta d_auxid-5,y - cpy #$06 - bne cmvauxid - lda xdosver save current xdos version # - sta d_sosver - lda compat and backward compatibility # - sta d_comp - lda #$01 usage is always 1 block - sta d_usage - lda d_head place back pointer to header block - sta d_dhdr - lda d_head+1 - sta d_dhdr+1 - lda d_stor storage type. - and #$E0 is it a directory? - beq cralcblk branch if seed file. - ldx #$1E move header to data block -cmvheadr lda d_stor,x - sta gbuf+4,x - dex - bpl cmvheadr - eor #$30 - sta gbuf+4 make it a directory header mark. - ldx #$07 overwrite password area and other -cmvpass lda pass,x header info. - sta gbuf+20,x - lda xdosver,x - sta gbuf+32,x - dex - bpl cmvpass - ldx #$02 and include info about parent directory - stx d_eof+1 -cmvparnt lda d_entblk,x - sta gbuf+39,x - dex - bpl cmvparnt - lda h_entln lastly, the length of parent's - sta gbuf+42 directory entries. -cralcblk jsr alc1blk get address of file's data block - bcs crerr3 - sta d_frst - sty d_frst+1 - sta bloknml - sty bloknml+1 - jsr wrtgbuf go write data block of file - bcs crerr3 - inc h_fcnt add 1 to total # of files in this dir - bne credone - inc h_fcnt+1 -credone jsr drevise go revise directories with new file - bcs crerr3 - jmp upbmap lastly, update volume bitmap -entcalc .EQ *-ofsX - lda #>gbuf set high address of dir entry - sta zpt+1 index pointer. - lda #$04 calc address of entry based - ldx d_entnum on the entry #. -H3689 clc -H368A dex addr = gbuf + ((d_entnum-1) * h_entln) - beq H3696 branch with carry clear = no errors. - adc h_entln - bcc H368A - inc zpt+1 inc hi address. - bcs H3689 always. -H3696 sta zpt newly calculated low address. -crerr3 rts carry set if error. -drevise .EQ *-ofsX - lda p8date - beq H36A9 if no clock, then don't mod date/time. - ldx #$03 -modtime lda p8date,x move last modification date/time - sta d_moddt,x to entry being updated. - dex - bpl modtime -drevise1 .EQ *-ofsX -H36A9 lda d_attr mark entry as backupable - ora bkbitflg (bit 5 = backup needed) - sta d_attr - lda d_dev get device # of directory - sta devnum to be revised - lda d_entblk and address of direcotry block. - ldx d_entblk+1 - jsr rdblk read block into general purpose buffer - bcs crerr3 - jsr entcalc fix up ptr to entry location within gbuf. - ldy h_entln now move 'd.' info to directory. - dey -H36CA lda d_stor,y - sta (zpt),y - dey - bpl H36CA - lda d_head is the entry block same as - cmp bloknml the entry's header block? - bne H36E0 if no, go save entry block - lda d_head+1 then maybe, so test high addresses. - cmp bloknml+1 - beq uphead branch if they are the same block. -H36E0 jsr wrtgbuf go write updated directory block. - bcs crerr3 - lda d_head get address of header block and - ldx d_head+1 - jsr rdblk go read in header block to modify. - bcs crerr3 -uphead ldy #$01 update current # of files in this dir. -H36F2 lda h_fcnt,y - sta gbuf+37,y (current entry count) - dey - bpl H36F2 - lda h_attr also update header's attributes. - sta gbuf+34 - jsr wrtgbuf go write updated header - bcs H375A -ripple lda gbuf+4 test for 'root' directory because - and #$F0 if it is, then directory revision - eor #$F0 is complete (leaves carry clear). - beq H3770 branch if done. - lda gbuf+41 get entry # - sta d_entnum - lda gbuf+42 and the length of ertries in that dir - sta h_entln - lda gbuf+39 get addr of parent entry's dir block - ldx gbuf+40 - jsr rdblk read it - bcs H375A - jsr entcalc get indirect ptr to parent entry in gbuf - lda p8date don't touch mod - beq H373B if no clock... - ldx #$03 update the modification date & time - ldy #$24 for this entry too -H3732 lda p8date,x - sta (zpt),y - dey - dex - bpl H3732 -H373B jsr wrtgbuf write updated entry back to disk. - bcs H375A if error. - ldy #$25 compare current block # to this - lda (zpt),y entry's header block. - iny - cmp bloknml are low addresses the same? - sta bloknml - bne H3751 branch if entry doesn't reside in same - lda (zpt),y block as header. - cmp bloknml+1 are high address the same? - beq ripple they are the same, continue to root dir. -H3751 lda (zpt),y not same so read in this dir's header. - sta bloknml+1 - jsr rdgbuf - bcc ripple continue if read was good -H375A rts -tsterr lda #$52 not tree or dir, unrecognized type - sec - rts -tstsos .EQ *-ofsX test if xdos disk. - lda gbuf pointer to previous dir block - ora gbuf+1 must be null - bne tsterr - lda gbuf+4 test for header - and #$E0 - cmp #$E0 - bne tsterr -H3770 clc no error - rts -findfile .EQ *-ofsX - jsr lookfile see if file exists - bcs nofind -moventry .EQ *-ofsX - ldy h_entln -H377A lda (zpt),y move entry into storage - sta d_stor,y - dey - bpl H377A - lda #$00 no errors -nofind rts -lookfile .EQ *-ofsX - jsr preproot go find volume - bcs fnderr - bne L37C5 branch if more than root - lda #>gbuf otherwise, report a bad path error - sta zpt+1 (but 1st create a phantom entry - lda #$04 for open) - sta zpt - ldy #$1F move in id and date info -phantm1 lda (zpt),y - sta d_stor,y - dey - cpy #$17 - bne phantm1 -phantm2 lda rootstuf-$10,y - sta d_stor,y - dey - cpy #$0F - bne phantm2 - lda #$D0 fake directory file - sta d_stor - lda gbuf+2 check forward link. - ora gbuf+3 if non-zero, assume full sized directory - bne H37C2 else assume it's the slot 3 /RAM volume - lda #$02 so reset eof and blocks_used fields - sta d_eof+1 - lda #$01 - sta d_usage -H37C2 lda #$40 bad path (carry set) - rts -lookfil0 .EQ *-ofsX -L37C5 stz nofree reset free entry indicator. - sec dir to be searched has header in this block. -L37C9 stz totent reset entry counter. - jsr looknam look for name pointed to by pnptr. - bcc namfound if name was found. - lda entcntl have we looked at all of the - sbc totent entries in this directory? - bcc L37E2 maybe, check hi count. - bne L37EB no, read next directory block. - cmp entcnth has the last entry been looked at? - beq errfnf yes, give 'file not found' error - bne L37EB or branch always. -L37E2 dec entcnth should be at least one - bpl L37EB so this should be branch always... -errdir lda #$51 directory error -fnderr sec - rts -L37EB sta entcntl keep a running count. - lda #>gbuf reset indirect pointer - sta zpt+1 - lda gbuf+2 get link to next dir block - bne L37FC (if there is one). - cmp gbuf+3 are both zero, i.e. no link? if so, - beq errdir then not all entries were acct'd for. -L37FC ldx gbuf+3 acc has value for block# (low). - jsr rdblk go read the next linked directory. - bcc L37C9 if no error. - rts return error in acc. -errfnf lda nofree was any free entry found? - bne fnf0 - lda gbuf+2 test link - bne L3814 - cmp gbuf+3 if both are 0 then give up. - beq fnf0 report 'not found'. -L3814 sta d_entblk - lda gbuf+3 - sta d_entblk+1 assume 1st entry of next block - lda #$01 is free for use. - sta d_entnum mark as valid (for create) - sta nofree -fnf0 jsr nxtpnam1 'file not found' or 'path not found'? -errpath1 sec if non-zero then 'path not found' - beq fnf1 - lda #$44 path not found - rts -fnf1 lda #$46 file not found - rts -namfound jsr nxtpname adj index to next name in path. - beq filfound branch if that was the last name. - ldy #$00 be sure this is a directory entry. - lda (zpt),y high nibble will tell. - and #$F0 - cmp #$D0 is it a subdirectory? - bne errpath1 error if not. - ldy #$11 get address of 1st subdirectory block - lda (zpt),y - sta bloknml (no checking done for a valid block#) - iny - sta d_head save as file's header block too - lda (zpt),y - sta bloknml+1 - sta d_head+1 - jsr rdgbuf read subdirectory into gbuf. - bcs fnderr1 if error. - lda gbuf+37 get the # of files contained in this - sta entcntl directory. - lda gbuf+38 - sta entcnth - lda gbuf+20 make sure password is disabled - ldx #$00 - sec - rol a -L3869 bcc L386C - inx -L386C asl - bne L3869 - cpx #$05 is password disabled? - beq movhead - lda #$4A directory is not compatible -fnderr1 sec - rts -movhead jsr movhed0 move directory info. - jmp lookfil0 do next local pathname. -movhed0 .EQ *-ofsX - ldx #$0A move this directory info -L387F lda gbuf+28,x - sta h_credt,x - dex - bpl L387F - lda gbuf+4 if this is root, then nothing to do - and #$F0 - eor #$F0 test header type. - beq L389C branch if root - ldx #$03 otherwise, save owner info about -L3893 lda gbuf+39,x this header. - sta own_blk,x - dex - bpl L3893 -L389C rts -entadr .EQ *-ofsX -filfound lda h_maxent figure out which entry # this is - sec - sbc cntent max entries - count entries + 1 - adc #$00 = entry # (carry was set) - sta d_entnum - lda bloknml and indicate block # of this directory - sta d_entblk - lda bloknml+1 - sta d_entblk+1 - clc - rts -looknam .EQ *-ofsX reset count of files per block - lda h_maxent - sta cntent - lda #>gbuf - sta zpt+1 - lda #$04 -L38C1 sta zpt reset indirect pointer to gbuf - bcs L38F8 branch if this block contains a header - ldy #$00 - lda (zpt),y get length of name in directory. - bne isname branch if there is a name. - lda nofree test if a free entry has been declared. - bne L38F8 yes, inc to next entry. - jsr entadr set address for current entry. - inc nofree indicate a free spot has been found. - bne L38F8 always. -isname and #$0F strip byte (is checked by 'filfound') - inc totent inc count of valid files found. - sta namcnt save name length as counter. - ldx namptr get index to current path. - cmp pathbuf,x are both names the same length? - bne L38F8 no, inc to next entry. -cmpname inx (first) next letter index - iny - lda (zpt),y compare names letter by letter - cmp pathbuf,x - bne L38F8 - dec namcnt all letters compared? - bne cmpname no, continue. - clc a match is found. -noname rts -L38F8 dec cntent checked all entries in this block? - sec - beq noname yes, no name match. - lda h_entln add entry length to current pointer - clc - adc zpt - bcc L38C1 branch if still in 1st page. - inc zpt+1 look on 2nd page. - clc carry should always be clear before - bcc L38C1 looking at next. -preproot .EQ *-ofsX - jsr findvol search vcb's and dev's for spec'd volume - bcs novolume - lda #$00 zero out directory temps - ldy #$42 -L3914 sta own_blk,y and owner info - dey - bpl L3914 - lda devnum setup device # for this directory - sta d_dev - jsr movhed0 setup other header info from directory - ldy #$01 in gbuf and clean up misc info. - ldx vcbptr - inx -L3929 lda vcbbuf+18,x misc info includes - sta h_tblk,y total # of blocks, - lda vcbbuf+26,x the address of the 1st bitmap, - sta h_bmap,y - lda |bloknml,y directory's disk address, - sta d_head,y - lda h_fcnt,y and setting up a counter for the # of - sta entcntl,y files in this directory. - dex - dey - bpl L3929 -nxtpname .EQ *-ofsX - jsr nxtpnam1 get new namptr in y and namlen in acc. - sty namptr save new pathname pointer. - rts (status reg according to accumulator) -nxtpnam1 .EQ *-ofsX - ldy namptr inc pathname pointer to next name - lda pathbuf,y in the path. - sec - adc namptr if this addition results in zero, - tay then prefixed directory has been moved - bne L395F to another device. branch if not. - lda devnum revise devnum for prefixed directory - sta p_dev -L395F lda pathbuf,y test for end of name. - clc no errors -novolume rts -findvol .EQ *-ofsX - lda #$00 - ldy preflag use prefix volume name to look up vcb. - bit prfxflg is this a prefixed path? - bpl L396F branch if it is - tay set ptr to volume name -L396F sty vnptr and save. - sta devnum zero out dev# until vcb located. -L3975 pha acc now used as vcb lookup index. - tax index pointer to x. - lda vcbbuf,x get vcb volume name length. - bne L3987 branch if claimed vcb to be tested. -L397C ldy vnptr restore pointer to requested vol name. - pla now adj vcb index to next vcb entry. - clc - adc #$20 - bcc L3975 branch if more vcb's to check - bcs L39D4 otherwise go look for unlogged volumes. -L3987 sta namcnt save length of vol name to be compared. -L398A cmp pathbuf,y is it the same as requested vol name? - bne L397C branch if not - inx - iny next character - lda vcbbuf,x - dec namcnt last character? - bpl L398A if not. - plx restore pointer to matching vcb. - stx vcbptr save it for future reference. - lda vcbbuf+16,x get it's device # - sta devnum and save it. - stz bloknml+1 assume prefix is not used and - lda #$02 that root directory is to be used. - sta bloknml - lda vnptr = 0 if no prefix. -L39AC tay if prefix then find ptr to prefixed - sta namptr dir name. save path ptr. - beq L39C2 branch if no prefix. - sec - adc pathbuf,y inc to next dir in prefix path. - bcc L39AC branch if another dir in prefix. - lda p_blok volume verification will occur at - sta bloknml subdirectory level. - lda p_blok+1 - sta bloknml+1 - -* verify volume name - -L39C2 jsr rdgbuf read in directory (or prefix dir) - bcs L39CC if error then look on other devices. - jsr cmppnam compare dir name with path name. - bcc L39F0 if they match, stop looking. -L39CC ldx vcbptr check if current (matched) vcb is active - lda vcbbuf+17,x i.e. does it have open files? - bmi L39ED report not found if active. -L39D4 lda vnptr make path ptr same as volume ptr - sta namptr - jsr mvdevnums copy all device #'s to be examined. - lda devnum log current device 1st before searching - bne L39F1 others. -L39E2 ldx numdevs scan look list for devices we need -L39E5 lda loklst,x to search for the requested volume. - bne L39F4 branch if we've a device to look at. - dex - bpl L39E5 look at next one. -L39ED lda #$45 no mounted volume - sec error -L39F0 rts -L39F1 ldx numdevs now remove the device from the list -L39F4 cmp loklst,x of prospective devices. - beq L39FE branch if match. - dex look until found. - bpl L39F4 always taken (usually) unless - bmi L39ED if dev was removed from devlst (/RAM). -L39FE sta devnum preserve device to be checked next. - stz loklst,x mark this one as tested. - jsr fnddvcb find vcb that claims this dev (if any). - bcs L3A29 branch if vcb full. - ldx vcbptr did fndvcb find it or return free vcb? - lda vcbbuf,x - beq L3A16 if free vcb. - lda vcbbuf+17,x is this volume active? - bmi L39E2 if so, no need to re-log. -L3A16 lda #$02 go read root dir into gbuf - ldx #$00 - jsr rdblk - bcs L39E2 ignore if unable to read. - jsr logvcb go log in volume name. - bcs L39E2 look at next if non-xdos disk mounted. - jsr cmppnam is this the volume ? - bcs L39E2 if not -L3A29 rts -mvdevnums .EQ *-ofsX - ldx numdevs copy all dev #'s to be checked. -L3A2D lda devlist,x active device list. - and #$F0 strip device type info. - sta loklst,x copy them to a temp workspace - dex - bpl L3A2D - ldx numdevs - rts -fnddvcb .EQ *-ofsX look for vcb with this device# - lda #$00 - ldy #$FF -L3A40 tax new index to next vcb - lda vcbbuf+16,x check all devnums - cmp devnum is this the vcb? - bne L3A4E if not - stx vcbptr - clc indicates found - rts -L3A4E lda vcbbuf,x is this a free vcb? - bne L3A57 if not - iny - stx vcbptr -L3A57 txa - clc inc index to next vcb - adc #$20 - bne L3A40 - tya any free vcb's available? - bpl L3A79 yes - lda #$00 look for an entry to kick out -L3A62 tax - lda vcbbuf+17,x any open files? - bpl L3A70 no, kick this one out. - txa next vcb - clc - adc #$20 (vcb entry size) - bne L3A62 - beq L3A7A all vcb entries have open files -L3A70 stx vcbptr save entry index. - stz vcbbuf,x free this entry - stz vcbbuf+16,x -L3A79 clc no error. -L3A7A lda #$55 # vcb full error - rts -cmppnam .EQ *-ofsX - ldx #$00 index to directory name. - ldy namptr index to pathname. - lda gbuf+4 get dir name length and type. - cmp #$E0 is it a directory? - bcc L3A90 if not. - and #$0F isolate name length and - sta namcnt save as a counter. - bne L3A95 branch if valid length. -L3A90 sec indicate not found - rts -L3A92 lda gbuf+4,x next char -L3A95 cmp pathbuf,y - bne L3A90 if not the same. - inx check next char - iny - dec namcnt - bpl L3A92 if more to compare. - clc match found - rts -logvcb .EQ *-ofsX - ldx vcbptr previously logged in volume? - lda vcbbuf,x (acc = 0?) - beq L3AB0 no, go prepare vcb. - jsr cmpvcb does vcb match vol read? - bcc L3B05 yes, do not disturb. -logvcb1 .EQ *-ofsX -L3AB0 ldy #$1F zero out vcb entry -L3AB2 stz vcbbuf,x - inx - dey - bpl L3AB2 - jsr tstsos make sure it's an xdos disk - bcs L3B05 if not, return carry set. - jsr tstdupvol does a duplicate with open files - bcs L3B04 already exist? branch if yes. - lda gbuf+4 move volume name to vcb. - and #$0F strip root marker - tay - pha - ora vcbptr - tax -L3ACE lda gbuf+4,y - sta vcbbuf,x - dex - dey - bne L3ACE - pla get length again - sta vcbbuf,x and save. - lda devnum last device used. - sta vcbbuf+16,x save device # and - lda gbuf+41 total # of blocks on this unit. - sta vcbbuf+18,x - lda gbuf+42 - sta vcbbuf+19,x - lda bloknml save address of root directory. - sta vcbbuf+22,x - lda bloknml+1 - sta vcbbuf+23,x - lda gbuf+39 save address of the 1st bitmap. - sta vcbbuf+26,x - lda gbuf+40 - sta vcbbuf+27,x -L3B04 clc indicate logged if possible -L3B05 rts -cmpvcb .EQ *-ofsX compare volume name in vcb - lda gbuf+4 with name in directory. - and #$0F - cmp vcbbuf,x are they the same length? - stx xvcbptr (see rev note #23) - bne L3B1E if not the same. - tay - ora xvcbptr - tax -L3B18 lda gbuf+4,y - cmp vcbbuf,x -L3B1E sec anticipate different names. - bne L3B26 if not the same. - dex - dey - bne L3B18 - clc indicate match. -L3B26 ldx xvcbptr offset to start of vcb (rev note #23) - rts -tstdupvol .EQ *-ofsX check for other logged in volumes - lda #$00 with the same name. -L3B2C tax - jsr cmpvcb - bcs L3B41 if no match. - lda vcbbuf+17,x test for any open files. - bmi L3B4B cannot look at this volume. - lda #$00 take duplicate offline if no open files - sta vcbbuf,x - sta vcbbuf+16,x - beq L3B49 ok to log in new volume. -L3B41 txa index to next vcb - clc - and #$E0 strip odd stuff. - adc #$20 inc to next entry. - bcc L3B2C branch if more to check -L3B49 clc - rts -L3B4B sta duplflag duplicate has been found. - stx vcbentry save pointer to conflicting vcb. - sec error. - rts -tstfrblk .EQ *-ofsX test if enough free blocks available - ldx vcbptr for request. - lda vcbbuf+21,x check if proper count for this volume. - ora vcbbuf+20,x - bne L3BAD branch if count is non-zero. -tkfrecnt .EQ *-ofsX - jsr cntbms get # of bitmaps - sta bmcnt and save. - stz scrtch start count at 0 - stz scrtch+1 - lda #$FF mark 'first free' temp as unknown - sta nofree - jsr upbmap update volume bitmap. - bcs L3BC1 if error. - ldx vcbptr get address of 1st bitmap - lda vcbbuf+26,x - sta bloknml - lda vcbbuf+27,x - sta bloknml+1 -L3B81 jsr rdgbuf use general buffer for temp space to - bcs L3BC1 count free blocks (bits). - jsr count - dec bmcnt was that the last bitmap? - bmi L3B96 if so, go change fcb so not done again. - inc bloknml - bne L3B81 - inc bloknml+1 - bra L3B81 -L3B96 ldx vcbptr mark which block had 1st free space - lda nofree - bmi L3BBE if no free space was found. - sta vcbbuf+28,x update the free count. - lda scrtch+1 - sta vcbbuf+21,x update volume control byte. - lda scrtch - sta vcbbuf+20,x -L3BAD lda vcbbuf+20,x compare total available free blocks - sec on this volume. - sbc reql - lda vcbbuf+21,x - sbc reqh - bcc L3BBE - clc - rts -L3BBE lda #$48 disk full - sec -L3BC1 rts -count .EQ *-ofsX - ldy #$00 -L3BC4 lda gbuf,y bit pattern. - beq L3BCC don't count - jsr cntfree -L3BCC lda gbuf+$100,y do both pages with same loop - beq L3BD4 - jsr cntfree -L3BD4 iny - bne L3BC4 loop until all 512 bytes counted. - bit nofree has 1st block w/free space been found? - bpl L3BEE if yes. - lda scrtch test to see if any blocks were counted - ora scrtch+1 - beq L3BEE branch if none counted. - jsr cntbms get total # of maps. - sec subtract countdown from total bitmaps - sbc bmcnt - sta nofree -L3BEE rts -cntfree .EQ *-ofsX -L3BEF asl count the # of bits in this byte - bcc L3BFA - inc scrtch - bne L3BFA - inc scrtch+1 -L3BFA ora #$00 - bne L3BEF loop until all bits counted - rts -cntbms .EQ *-ofsX - ldx vcbptr - ldy vcbbuf+19,x return the # of bitmaps - lda vcbbuf+18,x possible with the total count - bne L3C0B found in the vcb. - dey adj for bitmap block boundary -L3C0B tya - lsr a divide by 16. the result is - lsr a the # of bitmaps. - lsr a - lsr a - rts - -* deallocate a block's entry in bitmap -* on entry, x,a = address of block - -dealloc .EQ *-ofsX - stx bmcnt high address of block. - pha save low address. - ldx vcbptr check that bitmap block address is - lda vcbbuf+19,x valid given the total # of blocks - cmp bmcnt on the volume. - pla - bcc L3C8C branch if invalid - tax - and #$07 bit to be or'd in - tay - lda whichbit,y (shifting takes 7 bytes, but is slower) - sta nofree save bit pattern. - txa low block address. - lsr bmcnt - ror a get pointer to byte in block that - lsr bmcnt represents the block address. - ror a - lsr bmcnt - ror a - sta bmptr save pointer. - lsr bmcnt transfer bit which is page of bitmap - rol half - jsr fndbmap make sure device is correct one. - bcs L3C8B error. - lda bmacmap current map. - cmp bmcnt is in-core bitmap the correct one ? - beq L3C64 branch if yes. - jsr upbmap put current map away. - bcs L3C8B error. - lda bmcnt get map # - ldx vcbptr - sta vcbbuf+28,x and make it current. - lda bmadev - jsr gtbmap read it into buffer - bcs L3C8B -L3C64 ldy bmptr index to byte - lsr half - lda nofree (get indiviual bit) - bcc L3C77 branch if on page 1 of bitmap - ora bmbuf+$100,y - sta bmbuf+$100,y - bcs L3C7D always. -bmbufhi .EQ *-ofsX this address + 2 is used as an -L3C77 ora bmbuf,y absolute reference to bmbuf high byte. - sta bmbuf,y -L3C7D lda #$80 mark bitmap as modified - tsb bmastat - inc deblock inc count of blocks deallocated - bne L3C8A - inc deblock+1 -L3C8A clc -L3C8B rts -L3C8C lda #$5A bitmap block # impossible. - sec bitmap disk address wrong - rts (maybe data masquerading as indx block) -alc1blk .EQ *-ofsX - jsr fndbmap get address of bitmap. - bcs L3CB8 error. -L3C95 ldy #$00 begin search at start of bitmap block. - sty half which half (page) to search -L3C9A lda bmbuf,y - bne L3CB9 free blocks indicated by 'on' bits - iny - bne L3C9A check all in 1st page. - inc half now search page 2. - inc basval base value = base address / 2048. -L3CA8 lda bmbuf+$100,y search 2nd half for free block - bne L3CB9 - iny - bne L3CA8 - inc basval add 2048 offset for next page. - jsr nxtbmap get next bitmap (if exists) and - bcc L3C95 update vcb. branch if no error. -L3CB8 rts return error. -L3CB9 sty bmptr save index pointer to valid bit group. - lda basval prep for block address calculation - sta scrtch+1 - tya address of bit pattern. - asl multiply this and basval by 8 - rol scrtch+1 - asl - rol scrtch+1 - asl - rol scrtch+1 - tax low address within 7 of actual address - sec - lda half - beq L3CDB branch if allocating from 1st half. - lda bmbuf+$100,y get pattern from 2nd page. - bcs L3CDE always. -L3CDB lda bmbuf,y get bit pattern from 1st page. -L3CDE rol a find left most 'on' bit - bcs L3CE4 if found. - inx adjust low address. - bne L3CDE always. -L3CE4 lsr a restore pos'n of all but left most bit. - bcc L3CE4 loop until mark moves into carry. - stx scrtch save low address. - ldx half which half of bitmap ? - bne L3CF4 if page 2. - sta bmbuf,y - beq L3CF7 always. -L3CF4 sta bmbuf+$100,y update to show allocated block in use. -L3CF7 lda #$80 indicate map is modified. - tsb bmastat - ldy vcbptr subtract 1 from total free vcb blocks - lda vcbbuf+20,y to account for newly allocated block. - sbc #$01 (carry is set) - sta vcbbuf+20,y - bcs L3D10 if high free count doesn't need adj. - lda vcbbuf+21,y adjust high count - dec a - sta vcbbuf+21,y -L3D10 clc no errors. - lda scrtch return address in y,a of newly - ldy scrtch+1 allocated block. - rts -nxtbmap .EQ *-ofsX inc to next bitmap - ldy vcbptr but 1st make sure there is another one. - lda vcbbuf+19,y - lsr a - lsr a - lsr a - lsr a - cmp vcbbuf+28,y are there more maps ? - beq L3D60 if no more to look at. - lda vcbbuf+28,y add 1 to current map - inc - sta vcbbuf+28,y - jsr upbmap -fndbmap .EQ *-ofsX - ldy vcbptr - lda vcbbuf+16,y get device #. - cmp bmadev does this map match this device ? - beq L3D4A yes. - jsr upbmap otherwise, save other volume's bitmap - bcs L3D5F - ldy vcbptr - lda vcbbuf+16,y - sta bmadev and read in fresh bitmap for this dev. -L3D4A ldy bmastat is it already modified ? - bmi L3D54 yes, return pointer - jsr gtbmap otherwise read in fresh bitmap. - bcs L3D5F if error. -L3D54 ldy vcbptr get relative block # of bitmap. - lda vcbbuf+28,y - asl 2 pages per block - sta basval - clc no errors. -L3D5F rts -L3D60 lda #$48 request can't be filled - sec error - rts -upbmap .EQ *-ofsX - clc - lda bmastat is current map modified ? - bpl L3D5F no. - jsr wrtbmap update device. - bcs L3D5F if error on writing. - lda #$00 - sta bmastat mark bitmap buffer as free - rts -gtbmap .EQ *-ofsX read bitmap specified by dev and vcb. - sta bmadev - ldy vcbptr get lowest map # with free blocks in it - lda vcbbuf+28,y - sta bmacmap associate offset with bitmap ctrl block. - clc add this # to the base address of - adc vcbbuf+26,y 1st bitmap and save in bmadadr which - sta bmadadr is address of bitmap to be used. - lda vcbbuf+27,y - adc #$00 - sta bmadadr+1 - lda #$01 read device command -L3D92 sta A4L - lda devnum save current dev # - pha - lda bmadev get bitmap's dev # - sta devnum - lda bmadadr and disk address - sta bloknml - lda bmadadr+1 - sta bloknml+1 - lda bmbufhi+2 address of the buffer (low = 0) - jsr dobitmap - tax error code (if any). - pla restore current dev # - sta devnum - bcc L3DB6 and return it if no error. - txa error code -L3DB6 rts -rdblk .EQ *-ofsX - sta bloknml - stx bloknml+1 - jsr rdgbuf - rts -wrtbmap .EQ *-ofsX write bitmap. - lda #$02 write command. - bne L3D92 always. -wrtgbuf .EQ *-ofsX - lda #$02 write command - bne L3DC9 always. -rdgbuf .EQ *-ofsX - lda #$01 read command. -L3DC9 sta A4L pass to device handler. - lda #>gbuf general buffer. -dobitmap .EQ *-ofsX - php no interrupts - sei - sta buf+1 buffer high. - stz buf buffer low (always on page boundary) - stz p8error clear global error code. - lda #$FF indicates reg call made to dev handler - sta ioaccess - lda devnum transfer dev # for dispatcher to - sta unitnum convert to unit #. - jsr dmgr call the driver. - bcs L3DE8 if error. - plp restore interrupts. - clc - rts -L3DE8 plp file i/o error. restore interrupts. - sec - rts - -*-------------------------------------- -MAN -SAVE USR/SRC/PRODOS.203/PRODOS.S.XDOS -LOAD USR/SRC/PRODOS.203/PRODOS.S -ASM diff --git a/ProDOS.203/ProDOS.S.txt b/ProDOS.203/ProDOS.S.txt index 861c0fd8..9f7d26c4 100644 --- a/ProDOS.203/ProDOS.S.txt +++ b/ProDOS.203/ProDOS.S.txt @@ -5,17 +5,38 @@ NEW .OR $0000 .TF PRODOS203,TSYS *-------------------------------------- + .INB INC/ZP.I .INB INC/IO.I - .INB INC/MONITOR.I +* .INB INC/MONITOR.I .INB INC/MLI.I .INB INC/MLI.E.I - .INB INC/ZP.I *-------------------------------------- +MMStartUp .EQ 0000 +NewHandle .EQ 0000 +MessageCenter .EQ 0000 +DisposeHandle .EQ 0000 +MMShutDown .EQ 0000 +ReadTimeHex .EQ 0000 +Int2Hex .EQ 0000 +TLTextMountVolume .EQ 0000 + .MA IIGS + ldx ##]1 + jsl $E10000 + .EM +*-------------------------------------- +idxl .EQ $10 general use 16 bit index pointer ZP.SrcPtr .EQ $12 ZP.DstPtr .EQ $14 +cnt .EQ $16 *-------------------------------------- +ramdest .EQ $200 load address for aux bank /RAM driver PrefixBuf .EQ $280 +lodintrp .EQ $800 DirBlkBuf .EQ $C00 +dispadr .EQ $1000 +tclk_in .EQ $D742 clock driver in bank 2 +xdosorg .EQ $DE00 xdos MLI in aux memory +lcdest .EQ $FF00 *-------------------------------------- * $2000 mli_0 mli loader/relocator * $2C80 ram_1 installer for /RAM @@ -31,25 +52,30 @@ DirBlkBuf .EQ $C00 * $5D00 sel_1 enhanced quit code (Bird's Better Bye) * $6000 sel_2 GQuit dispatcher support - .PH $2000 +* .PH $2000 - .INB USR/SRC/PRODOS.203/PRODOS.S.LDR - .INB USR/SRC/PRODOS.203/PRODOS.S.RAMI - .INB USR/SRC/PRODOS.203/PRODOS.S.RAM - .INB USR/SRC/PRODOS.203/PRODOS.S.IRQ - .INB USR/SRC/PRODOS.203/PRODOS.S.GP - .INB USR/SRC/PRODOS.203/PRODOS.S.TCLK - .INB USR/SRC/PRODOS.203/PRODOS.S.CCLK - .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS - .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.C - .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.M - .INB USR/SRC/PRODOS.203/PRODOS.S.RAMX - .INB USR/SRC/PRODOS.203/PRODOS.S.DISKII - .INB USR/SRC/PRODOS.203/PRODOS.S.SEL0 - .INB USR/SRC/PRODOS.203/PRODOS.S.SEL1 - .INB USR/SRC/PRODOS.203/PRODOS.S.SEL2 + .INB USR/SRC/PRODOS.203/PRODOS.S.LDR.A + .INB USR/SRC/PRODOS.203/PRODOS.S.LDR.B + .INB USR/SRC/PRODOS.203/PRODOS.S.RAMI + .INB USR/SRC/PRODOS.203/PRODOS.S.RAM + .INB USR/SRC/PRODOS.203/PRODOS.S.IRQ + .INB USR/SRC/PRODOS.203/PRODOS.S.GP + .INB USR/SRC/PRODOS.203/PRODOS.S.TCLK + .INB USR/SRC/PRODOS.203/PRODOS.S.CCLK + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.A + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.B + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.C + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.D + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.E + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.F + .INB USR/SRC/PRODOS.203/PRODOS.S.XDOS.M + .INB USR/SRC/PRODOS.203/PRODOS.S.RAMX + .INB USR/SRC/PRODOS.203/PRODOS.S.DISKII + .INB USR/SRC/PRODOS.203/PRODOS.S.SEL0 + .INB USR/SRC/PRODOS.203/PRODOS.S.SEL1 + .INB USR/SRC/PRODOS.203/PRODOS.S.SEL2 - .EP +* .EP *-------------------------------------- MAN SAVE USR/SRC/PRODOS.203/PRODOS.S