NEW AUTO 3,1 *-------------------------------------- XDOS.DeallocAX stx bmcnt high address of block. pha save low address. ldx vcbptr check that bitmap block address is lda VCBs+VCB.TBLK+1,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 VCBs+VCB.BMAPIDX,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 bmbufhi branch if on page 1 of bitmap ora bmbuf+$100,y sta bmbuf+$100,y bcs L3C7D always. bmbufhi ora bmbuf,y this address + 2 is used as an 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 #MLI.E.BADFS bitmap block # impossible. sec bitmap disk address wrong rts (maybe data masquerading as indx block) *-------------------------------------- alc1blk 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 ldx vcbptr subtract 1 from total free vcb blocks lda VCBs+VCB.FBLK,x to account for newly allocated block. bne .7 dec VCBs+VCB.FBLK+1,x .7 dec VCBs+VCB.FBLK,x lda scrtch return address in y,a of newly ldy scrtch+1 allocated block. clc no errors. rts *-------------------------------------- nxtbmap ldx vcbptr inc to next bitmap, but 1st make sure there is another one. lda VCBs+VCB.TBLK+1,x lsr lsr lsr lsr cmp VCBs+VCB.BMAPIDX,x are there more maps ? beq L3D60 if no more to look at. inc VCBs+VCB.BMAPIDX,x add 1 to current map jsr upbmap fndbmap ldy vcbptr lda VCBs+VCB.DEV,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 VCBs+VCB.DEV,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 VCBs+VCB.BMAPIDX,y asl 2 pages per block sta basval clc no errors. L3D5F rts L3D60 lda #MLI.E.VOLFULL request can't be filled sec error rts *-------------------------------------- upbmap clc lda bmastat is current map modified ? bpl .9 no. jsr wrtbmap update device. bcs .9 if error on writing. stz bmastat mark bitmap buffer as free lda #0 MUST EXIT WITH A=0 .9 rts *-------------------------------------- gtbmap sta bmadev read bitmap specified by dev and vcb. ldy vcbptr get lowest map # with free blocks in it lda VCBs+VCB.BMAPIDX,y sta bmacmap associate offset with bitmap ctrl block. clc add this # to the base address of adc VCBs+VCB.BMAP,y 1st bitmap and save in bmadadr which sta bmadadr is address of bitmap to be used. lda VCBs+VCB.BMAP+1,y adc #$00 sta bmadadr+1 lda #$01 read device command .HS 2C BIT ABS wrtbmap lda #$02 write command. 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 /bmbuf * lda bmbufhi+2 address of the buffer (low = 0) jsr XDOS.RWBlock plx keep A=error code if CS stx DEVNUM L3DB6 rts *-------------------------------------- .DO LOWERCASE=1 XDOS.WriteGBufDir jsr XDOS.PackGBuf bra XDOS.WriteGBuf .FIN *-------------------------------------- XDOS.ReadGBuf_d_frst lda d_frst read 1st block of directory into gbuf ldx d_frst+1 .DO LOWERCASE=1 XDOS.ReadGBufAXDir jsr XDOS.ReadGBufAX bcc XDOS.UnpackGBuf rts .FIN XDOS.ReadGBufAX sta bloknml stx bloknml+1 XDOS.ReadGBuf lda #$01 read command. .HS 2C BIT ABS XDOS.WriteGBuf lda #$02 write command sta A4L pass to device handler. lda /gbuf general buffer. XDOS.RWBlock 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 #. jmp XDOS.DevCall call the driver. *-------------------------------------- .DO LOWERCASE=1 XDOS.CheckAndUnpackGBuf lda gbuf+$23 sta h_entln ldy gbuf+$24 sty h_maxent cmp #$27 bne .9 cpy #$0D beq XDOS.UnpackGBuf .9 lda #MLI.E.NOTPRODOS sec rts XDOS.UnpackGBuf jsr XDOS.ZPT.InitGBuf ldx h_maxent XDOS.UnpackZPT .EQ * .1 lda (zpt) and #$0F beq .6 ldy #$1D MIN_VERSION lda (zpt),y bpl .6 no lowercase information lda (zpt) and #$0F tay .2 cpy #8 CS if MIN_VERSION to use phy bcs .3 ldy #$1D MIN_VERSION lda (zpt),y ply and whichbit,y beq .5 bra .4 .3 ldy #$1C VERSION lda (zpt),y ply and whichbit-8,y beq .5 .4 lda (zpt),y eor #$20 to lowercase sta (zpt),y .5 dey bne .2 .6 dex beq .8 jsr XDOS.ZPT.Next bra .1 .8 clc make sure CC rts *-------------------------------------- *XDOS.PackGBuf.Bitmap .BS 2 XDOS.PackGBuf.Bitmap .EQ sos *-------------------------------------- XDOS.PackGBuf jsr XDOS.ZPT.InitGBuf ldx h_maxent .1 lda (zpt) and #$0F beq .6 stz XDOS.PackGBuf.Bitmap stz XDOS.PackGBuf.Bitmap+1 tay .2 lda (zpt),y cmp #'a' bcc .5 cmp #'z'+1 bcs .5 eor #$20 to uppercase sta (zpt),y cpy #8 CS if MIN_VERSION to use bcs .3 lda whichbit,y tsb XDOS.PackGBuf.Bitmap+1 bra .4 .3 lda whichbit-8,y tsb XDOS.PackGBuf.Bitmap .4 lda #$80 tsb XDOS.PackGBuf.Bitmap+1 .5 dey bne .2 ldy #$1C VERSION lda XDOS.PackGBuf.Bitmap sta (zpt),y iny MIN_VERSION lda XDOS.PackGBuf.Bitmap+1 sta (zpt),y .6 jsr XDOS.ZPT.Next dex bne .1 rts *-------------------------------------- XDOS.ZPT.InitGBuf lda /gbuf XDOS.ZPT.InitA sta zpt+1 lda #4 sta zpt rts *-------------------------------------- XDOS.ZPT.Next lda h_entln XDOS.ZPT.NextA clc adc zpt sta zpt bcc .8 inc zpt+1 clc .8 rts .FIN *-------------------------------------- XDOS.GetMark ldx fcbptr index to open fcb. ldy #$02 index to user's mark parameter. .1 lda FCBs+FCB.MARK,x transfer current position sta (A3L),y to user's parameter list inx iny cpy #$05 transfer 3 bytes bne .1 clc rts L3DFD lda #MLI.E.BEYEOF invalid position sec rts *-------------------------------------- XDOS.SetMark ldy #$04 index to user's desired position. ldx fcbptr file's control block index. inx inc by 2 for index to hi eof inx sec indicate comparisons are necessary. .1 lda (A3L),y move it to 'tpos' sta tposll-2,y bcc .2 branch if mark < eof cmp FCBs+FCB.EOF,x bcc .2 branch if mark qualifies. bne L3DFD branch if mark > eof (invalid position) dex .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 ldy fcbptr test to see if new position is lda FCBs+FCB.MARK+1,y within the same (current) data block. and #$FE sta scrtch 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. cmp FCBs+FCB.MARK+2,y bne L3E44 branch if not. jmp svmark if so, adj fcb, position ptr and return. L3E44 lda FCBs+FCB.STYPE,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 sta FCBs,y lda #MLI.E.BADREF and report error sec rts L3E59 lda FCBs+FCB.STYPE,y use storage type as # of index levels sta levels since 1=seed, 2=sapling, 3=tree. lda FCBs+FCB.F,y and #FCB.F.DBLKMOD if previous data was modified then beq L3E6B disk must be updated. jsr wfcbdat bcs L3ED4 if error. L3E6B ldy fcbptr test to see if current index block lda FCBs+FCB.MARK+2,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 ? dex bne datlevel1 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 FCBs+FCB.1stBLK,y unallocated. 1st block is only block sta bloknml and it's data. lda FCBs+FCB.1stBLK+1,y high block address. jmp rnewpos go read in block and set statuses. L3E9D lda FCBs+FCB.F,y check to see if previous index block and #FCB.F.IBLKMOD 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. lda tposhi is new position within range of a lsr sapling file (less than 128k) ? php save results lda #$07 (no level is allocated for new pos'n) plp restore z-flag. bne L3F18 go mark all as dummy. jsr XDOS.ClrFCBStatus clr status bits 0,1,2 (index/data/alloc) dex check for seed beq L3E89 if seed, check for position < 512. jsr rfcbfst go get only index block. bcs L3ED4 if error. jsr XDOS.UpdateFCBIBlk save newly loaded index block's address. datlevel1 bra datlevel branch always L3ED4 rts posindex jsr XDOS.ClrFCBStatus 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 tay lda (zpt),y inc zpt+1 cmp (zpt),y (both high and low = 0 if no index exists) bne saplevel tax are both bytes 0 ? bne saplevel dec zpt+1 L3EEF lda #$03 show neither index or data block alloc'd bra L3F18 saplevel sta bloknml read in next lower index block. lda (zpt),y (high address) sta bloknml+1 dec zpt+1 * jsr rfcbidx read in sapling level lda #$01 prepare to read index block : read command sta A4L ldx #zpt address of current index buffer. jsr fileio1 go read index block. bcs L3ED4 error jsr XDOS.UpdateFCBIBlk save block address of this index in fcb datlevel jsr XDOS.Tpos2Y get block address of data block lda (zpt),y data block address low inc zpt+1 cmp (zpt),y bne L3F51 tax bne L3F51 lda #$01 show data block as never been allocated dec zpt+1 L3F18 jsr XDOS.SetFCBStatus set status to show what's missing lsr discard bit that says data block lsr unallocated because carry indicates if jsr zipdata index block is invalid and needs to be zeroed. bcc svmark branch if it doesn't need zeroed jsr zeroindex zero index block in user's i/o buffer bra svmark *-------------------------------------- zipdata lda #$00 tay L3F42 sta (datptr),y zero out data area iny bne L3F42 inc datptr+1 L3F49 sta (datptr),y iny bne L3F49 dec datptr+1 rts *-------------------------------------- L3F51 sta bloknml get data block of new position lda (zpt),y (high address) dec zpt+1 rnewpos sta bloknml+1 jsr XDOS.ReadFCB.DBLK bcs L3F86 if error. jsr XDOS.ClrFCBStatus show whole chain is allocated. *-------------------------------------- svmark ldy fcbptr update position in fcb iny iny ldx #$02 L3F68 lda FCBs+FCB.MARK,y save old mark in case calling routine sta oldmark,x fails later. lda tposll,x sta FCBs+FCB.MARK,y dey dex move 3 byte position marker bpl L3F68 clc set up indirect address to buffer lda datptr page pointed to by the current sta sos position marker. lda tposlh and #$01 adc datptr+1 sta sos+1 L3F86 rts carry set if error *-------------------------------------- dirmark cmp #$0D is it a directory ? beq L3F9C yes... lda #MLI.E.INCFF no, so compatability problem. jsr GP.P8errv should not have been opened !!! L3F9C lda scrtch recover results of previous subtraction. lsr use difference as counter for how many sta cntent blocks must be read to get to new pos'n. lda FCBs+FCB.MARK+1,y test for positive direction cmp tposlh indicated by carry. lda FCBs+FCB.MARK+2,y sbc tposhi bcc L3FB9 if set, position forward. otherwise, L3FAB ldy #$00 read directory file in reverse order. jsr dirpos1 read previous block. bcs L3FD6 if error. inc cntent count up to 128. bpl L3FAB loop if more blocks to pass over. bmi svmark always. L3FB9 ldy #$02 position is forward from current. jsr dirpos1 read next directory block bcs L3FD6 if error. dec cntent bne L3FB9 loop if position not found in this block beq svmark branch always. *-------------------------------------- dirpos1 lda (datptr),y get link address of previous or next sta bloknml directory block. cmp #$01 test for null byte into carry iny but first be sure there is a link. lda (datptr),y get the rest of the link. bne L3FD8 branch if certain link exists. bcs L3FD8 was the low part null as well ? lda #MLI.E.EOF something is wrong with directory file! L3FD6 sec error. rts L3FD8 sta bloknml+1 *-------------------------------------- XDOS.ReadFCB.DBLK lda #$01 read command sta A4L ldx #datptr points at address of data buffer. jsr fileio1 go do file input. bcs L3FF2 error. ldy fcbptr lda bloknml sta FCBs+FCB.DBLK,y save block # just read in fcb. lda bloknml+1 sta FCBs+FCB.DBLK+1,y * clc L3FF2 rts *-------------------------------------- *rfcbidx lda #$01 prepare to read index block : read command * sta A4L * ldx #zpt address of current index buffer. * jsr fileio1 go read index block. * bcs L400C error * ldy fcbptr * lda bloknml * sta FCBs+FCB.IBLK,y save block address of this index in fcb * lda bloknml+1 * sta FCBs+FCB.IBLK+1,y ** clc *L400C rts *-------------------------------------- wfcbfst jsr upbmap update the bitmap and write file's 1st block. lda #$02 write command .HS 2C skip next instruction rfcbfst lda #$01 read command. pha save the command lda #FCB.1stBLK ora fcbptr add offset to fcbptr tay pla ldx #zpt rd block into index portion of file buf *-------------------------------------- dofileio sta A4L command lda FCBs,y get disk block address from fcb. sta bloknml block 0 not legal bne .1 lda FCBs+1,y high address of disk block bne .2 lda #$0C Block = $0000, allocation error. jsr GP.SysDeath doesn't return... .1 lda FCBs+1,y .2 sta bloknml+1 *-------------------------------------- fileio1 lda $00,x get memory address of buffer from sta buf page zero pointed to by x register lda $01,x sta buf+1 and pass address to device handler jsr XDOS.FCBDevIDSelect lda #$FF also, set to indicate reg call made to sta ioaccess device handler. lda DEVNUM transfer device # for dispatcher sta unitnum to convert to unit #. stz p8error clear global error code. jmp XDOS.DevCall call the driver. *-------------------------------------- wfcbdat ldx #datptr point at memory address with x and lda #FCB.DBLK disk address with y. ora fcbptr add offset to fcbptr tay and put in y. lda #$02 write data block. jsr dofileio bcs L4096 if errors. lda #$BF mark data status as current. bra XDOS.ResetFCBStatus wfcbidx jsr upbmap update bitmap. ldx #zpt point to address of index buffer lda #FCB.IBLK and block address of that index block. ora fcbptr tay lda #$02 jsr dofileio go write out index block. bcs L4096 if errors. lda #$7F mark index status as current. *-------------------------------------- XDOS.ResetFCBStatus ldx fcbptr and FCBs+FCB.F,x sta FCBs+FCB.F,x L4096 rts *-------------------------------------- XDOS.Open jsr XDOS.FindFileOrVol look up the file. bcs L4096 if not, then error. L40A0 jsr tstopen are any other files writing to this bcc L40AD same file ? branch if not. L40A5 lda #MLI.E.OPEN file is busy, shared access not allowed. .HS 2C L40A9 lda #MLI.E.UNSUPST file is wrong storage type. .HS 2C L40AB lda #MLI.E.FCBFULL fcb full error. sec rts L40AD lda fcbflg if this byte <> 0 then free fcb found beq L40AB and available for use. ldx fcbptr get address of 1st free fcb found. L40B9 ldy #FCB L40BD stz FCBs,x but clean it first. inx dey bne L40BD ldy #0 ldx fcbptr L40CB lda d_dev,y move ownership info. sta FCBs+FCB.DEVID,x note: this code depends upon the defined inx order of both the fcb and directory entry buffer. iny cpy #6 bne L40CB lda d_stor get storage type and jsr XDOS.SetFCBSType tax save in x for later comparison lda d_attr get file's attributes and use it and #$03 as a default access request. cpx #$0D if directory, don't allow write enable. bne L40EB and #$01 read enabled bit L40EB sta FCBs+FCB.ACCESS,y and #$02 check for write enabled request. beq L40F7 branch for open as read-only lda totent otherwise, be sure no one else is bne L40A5 reading the same file. branch if busy. L40F7 cpx #$04 is it a tree file type ? bcc L40FF yes. cpx #$0D is it a directory type ? bne L40A9 if not, wrong storage type. L40FF ldx #$06 move address of 1st block of file, end L4101 sta bloknml+1 of file and current usage count. lda fcbptr ora ofcbtbl,x this is done via a translation table tay between directory info and fcb. lda d_frst,x sta FCBs,y dex bpl L4101 last loop stores hi address of 1st block sta bloknml and this is the low one. ldx fcbptr lda cntent this was set up by 'tstopen'. sta FCBs,x claim fcb for this file. jsr alcbuffr go allocate buffer in memory tables. bcs L4147 if errors. ldx fcbptr jsr XDOS.GetFCBBufX rtn addr of bufs in data & index ptrs. lda flevel mark level at which sta FCBs+FCB.FLEVEL,x file was opened. lda FCBs+FCB.STYPE,x file must be positioned at beginning. cmp #$04 is it a tree file ? bcs L415E no, assume a directory. lda #$FF fool the position routine into giving sta FCBs+FCB.MARK+2,x a valid position with preloaded data, ldy #$02 etc. set desired position to 0. lda #$00 L413C sta tposll,y dey bpl L413C jsr rdposn let tree position routine do the rest. bcc L4163 if successful. L4147 pha save error code. ldx fcbptr free buffer space. stz FCBs,x necessary to release fcb also. lda FCBs+FCB.BUFID,x beq L4156 if no bufnum, ok because never alloc'd. jsr relbuffr go release buffer. L4156 pla error code. sec rts L415E jsr XDOS.ReadFCB.DBLK read in 1st block of directory file. bcs L4147 return error after freeing buffer & fcb. L4163 ldx vcbptr index to vcb. inc VCBs+VCB.OFCNT,x add 1 to # of files currently open ldx fcbptr index to fcb. lda FCBs+FCB.ID,x return ref # to user. ldy #$05 sta (A3L),y * clc open is successful rts *-------------------------------------- tstopen stz cntent returns the ref # of a free fcb. stz totent flag to indicate file already open. stz fcbflg flag indicates a free fcb is available. lda #$00 L4188 tay index to next fcb. ldx fcbflg test for free fcb found. bne L4191 if already found. inc cntent L4191 lda FCBs,y is this fcb in use ? bne L41A3 yes. txa if not, should we claim it ? bne L41C1 branch if free fcb already found. sty fcbptr save index to new free fcb. lda #$FF set fcb flag to indicate sta fcbflg free fcb found. bne L41C1 branch always to test next fcb. L41A3 tya add offset to index to ownership info ora #$06 tay and put it back in y. ldx #$06 index to directory entry owner info. L41A9 lda FCBs,y all bytes must match to say that it's cmp d_dev-1,x the same file again. bne L41C1 if not, then next fcb. dey index to next lower bytes. dex bne L41A9 loop to check all owner info. inc totent file is already open, now see lda FCBs+FCB.ACCESS,y if it's already opened for write. and #$02 if so report file busy (with carry set). and #$02 if so report file busy (with carry set). beq L41C1 branch if this file is read access only. sec rts L41C1 tya calc position of next fcb. and #$E0 first strip any possible index offsets. clc adc #FCB inc to next fcb. bcc L4188 branch if more to compare. clc report no conflicts. rts *-------------------------------------- XDOS.UpdateFCBIBlk ldy fcbptr lda bloknml sta FCBs+FCB.IBLK,y save block address of this index in fcb lda bloknml+1 sta FCBs+FCB.IBLK+1,y rts *-------------------------------------- MAN SAVE usr/src/prodos.fx/prodos.s.xdos.c LOAD usr/src/prodos.fx/prodos.s ASM