URL
https://opencores.org/ocsvn/rtf65002/rtf65002/trunk
Subversion Repositories rtf65002
[/] [rtf65002/] [trunk/] [software/] [asm/] [DOS.asm] - Rev 40
Compare with Previous | Blame | View Log
;==============================================================================; __; \\__/ o\ (C) 2014 Robert Finch, Stratford; \ __ / All rights reserved.; \/_// robfinch<remove>@opencores.org; ||;;; This source file is free software: you can redistribute it and/or modify; it under the terms of the GNU Lesser General Public License as published; by the Free Software Foundation, either version 3 of the License, or; (at your option) any later version.;; This source file is distributed in the hope that it will be useful,; but WITHOUT ANY WARRANTY; without even the implied warranty of; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the; GNU General Public License for more details.;; You should have received a copy of the GNU General Public License; along with this program. If not, see <http://www.gnu.org/licenses/>.;; DOS.asm; Disk operating system code;==============================================================================;cpu rtf65002; 64GB card; 36 address bits; 9 bits for 512 byte block size; 27 bits for block number; 4kB cluster size = 3 bits; 24 bit cluster number; 2MB bitmap of allocated clusters ( contained in 512 clusters); 512 super bitmap bits;NO_DEV EQU -1READING EQU 'R'WRITING EQU 'W'DIRTY EQU 'D'CLEAN EQU 'C'NORMAL EQU 0ONE_SHOT EQU 1WRITE_IMMED EQU 2ZUPER_BLOCK EQU 2 ; write superblock immediatelySUPER_BLOCK_NUM EQU 1 ; should calculate this;; Note that structure offsets are word offsets; The super block always occupies a whole block for simplicity even though; it's mostly unused.;; STRUCT SUPER_BLOCK;s_inodes_count EQU 0s_blocks_count EQU 1s_r_blocks_count EQU 2s_free_blocks_count EQU 3s_free_inodes_count EQU 4s_first_data_block EQU 5s_log_block_size EQU 6s_log_frag_size EQU 7s_blocks_per_group EQU 8s_frags_per_group EQU 9s_inodes_per_group EQU 10s_pad EQU 11s_mtime EQU 12s_wtime EQU 14s_mnt_cnt EQU 16s_max_mnt_cnt EQU 17s_magic EQU 18s_state EQU 19s_errors EQU 20s_minor_rev_level EQU 21s_lastcheck EQU 22s_checkinterval EQU 24s_creator_os EQU 26s_rev_level EQU 27s_def_res_uid EQU 28s_def_res_gid EQU 29s_inode_size EQU 31s_volume_name EQU 40; In memory management fieldss_inodes_per_block EQU 124s_dev EQU 125s_dirty EQU 126SUPERBUF_SIZE EQU 128; STRUCT INODE;i_mode EQU 0i_uid EQU 1i_size EQU 2i_gid EQU 3i_atime EQU 4i_ctime EQU 6i_mtime EQU 8i_dtime EQU 10i_links_count EQU 12i_blocks EQU 13i_flags EQU 14i_osd1 EQU 15INODE_P0 EQU 16INODE_P1 EQU INODE_P0+1INODE_P2 EQU INODE_P1+1INODE_P3 EQU INODE_P2+1INODE_P4 EQU INODE_P3+1INODE_P5 EQU INODE_P4+1INODE_P6 EQU INODE_P5+1INODE_P7 EQU INODE_P6+1INODE_P8 EQU INODE_P7+1INODE_P9 EQU INODE_P8+1INODE_P10 EQU INODE_P9+1INODE_P11 EQU INODE_P10+1INODE_IP EQU INODE_P11+1 ; indirect pointerINODE_IIP EQU INODE_IP+1 ; double indirect pointerINODE_IIIP EQU INODE_IIP+1 ; triple indirect pointeri_generation EQU 31i_file_acl EQU 32i_dir_acl EQU 33i_faddr EQU 34i_osd2 EQU 35INODE_DEV EQU 37INODE_INUM EQU 38INODE_ICOUNT EQU 39INODE_DIRTY EQU 40INODE_SIZE EQU 41 ; 41 words; STRUCT BGDESC;bg_block_bitmap EQU 0bg_inode_bitmap EQU 1bg_inode_table EQU 2bg_free_blocks_count EQU 3bg_free_inodes_count EQU 4bg_used_dirs_count EQU 5bg_reserved EQU 6BGDESC_SIZE EQU 8bg_dev EQU 9bg_group_num EQU 10bg_dirty EQU 11BGD_BUFSIZE EQU 12; STRUCT DIRENTRY; Directory entries are 64 bytes; 28 character file name; 4 byte i-node number;DE_NAME EQU 0DE_TYPE EQU 14DE_INODE EQU 15DE_SIZE EQU 16 ; size in words; Structure of a disk buffer; The disk buffer contains a number of fields for file system management; followed by a payload area containing disk block contents.;; STRUCT BUF;b_dev EQU 0 ; deviceb_blocknum EQU 1 ; disk block numberb_count EQU 2 ; reference countb_dirty EQU 3 ; buffer has been alteredb_next EQU 4 ; next buffer on LRU listb_prev EQU 5b_hash EQU 6 ; pointer to hashed bufferb_data EQU 8 ; beginning of data areaBUF_INODE EQU 8BUF_SIZE EQU b_data+256NR_BUFS EQU 8192 ; number of disk buffers in the system (must be a power of 2)NR_BUF_HASH EQU 1024 ; number of hash chains (must be a power of two)NR_BGD_BUFS EQU 1024BT_DATA_BLOCK EQU 0BT_SUPERBLOCK EQU 1IAM_BUF_SIZE EQU 1032 ; 1024 + 8CAM_SUPERMAP_SIZE EQU 128; $00000000 super block; $00000001 iam super map (512 bits); $00000002 inode allocation map (128kB); $00000102 inode array (1M x 128 byte entries); $00040102 cam super bitmap bits (512 bits); $00040103 cluster allocation map (2MB); $00041103 start of data clusters; Approximately 12MB (10% of memory) is allowed for the file system variables.; Most of the space 8MB+ is alloted to disk buffers.DOS_DATA EQU 0x00300000 ; start address of DOS data areasuper_bufs EQU DOS_DATAsuper_bufs_end EQU super_bufs + SUPERBUF_SIZE * 32BGD_bufs EQU super_bufs_endBGD_bufs_end EQU BGD_bufs + NR_BGD_BUFS * BGD_BUFSIZE ; 32 kB = 1024 descriptorsiam_bufs EQU BGD_bufs_endinode_array EQU iam_bufs + IAM_BUF_SIZE * 32 ; 129 kB worthinode_array_end EQU inode_array + INODE_SIZE * 256 ; 41kB worth (256 open files)data_bufs EQU 0x00320000 ; room for 8192 buffersdata_bufs_end EQU data_bufs + BUF_SIZE * NR_BUFSbuf_hash EQU data_bufs_endbuf_hash_end EQU buf_hash + NR_BUF_HASHsuperbuf_dump EQU buf_hash_end + 1bufs_in_use EQU superbuf_dump + 1blockbuf_dump EQU bufs_in_use + 1disk_size EQU blockbuf_dump + 1block_size EQU disk_size + 1fs_start_block EQU block_size + 1bgdt_valid EQU fs_start_block + 1front EQU bgdt_valid + 1rear EQU front + 1panicking EQU rear + 1fs_active EQU panicking + 1DOS_DATA_ENDS EQU 0x0540000; number of buffers for the inode allocation map; number of buffers for inode array; Total caching to be 12MB; 9MB reserved for data block caching; 3MB reserved for file management cachinginode_bufs EQU DOS_DATA ; 128B x 256 bufsiam_buf EQU 0x01FBE800sector_buf EQU 0x01FBEC00org $FFFFD800;------------------------------------------------------------------------------; Initialize the file system.;------------------------------------------------------------------------------;init_fs:stz bgdt_validjsr init_superbufsjsr init_databufslda #'A'sta fs_activelda #4ldx #0 ; no flags (em =0 native mode)ldy #fs_cleanjsr StartTaskrts;------------------------------------------------------------------------------; The file system offset is the offset in disk sectors to the start; of the file system. It may be desireable to reserve a number of; disk sectors prior to the actual file system start.;------------------------------------------------------------------------------;get_filesystem_offset:lda #2rts;------------------------------------------------------------------------------; Initialize super block buffer array.;------------------------------------------------------------------------------;init_superbufs:phaphxldx #super_bufsisb1:lda #NO_DEVsta s_dev,xlda #CLEANsta s_dirty,xadd r2,r2,#SUPERBUF_SIZEcpx #super_bufs_endbltu isb1plxplartsinit_databufs:phaphxphystz bufs_in_useldx #data_bufsstx frontlda #data_bufs_endsub #BUF_SIZEsta rearidb1:lda #NO_DEVsta b_dev,xlda #CLEANsta b_dirty,xsub r3,r2,#BUF_SIZEsty b_prev,xadd r3,r2,#BUF_SIZEsty b_next,xsty b_hash,xtyxcpx #data_bufs_endbltu idb1ldx frontstz b_prev,xstx buf_hash ; buf_hash[0] = frontldx rearstz b_next,xplyplxplarts;------------------------------------------------------------------------------; Parameters:; r1 = device; Returns:; r1 = block size in bytes;------------------------------------------------------------------------------get_block_size:phxphyjsr get_supertaxldy s_log_block_size,xlda #1024asl r1,r1,r3plyplxrtsget_log_block_size:phxjsr get_supertaxlda s_log_block_size,xplxrtsget_inode_size:phxjsr get_supertaxlda s_inode_size,xplxrtsget_inodes_per_group:phxjsr get_supertaxlda s_inodes_per_group,xplxrts; inodes per block does not need to be a power of 2;get_inodes_per_block:phxphajsr get_block_sizetaxplajsr get_inode_sizediv r1,r2,r1plxrtsget_bgd_per_block:jsr get_block_sizelsr ; BGD size is 32 byteslsrlsrlsrlsrrtsget_bits_per_block:jsr get_block_sizeaslaslaslrtsget_num_bgd:phxjsr get_superlda s_blocks_count,r1taxjsr get_bits_per_blockdiv r1,r2,r1plxrts;==============================================================================; INODE code;==============================================================================;------------------------------------------------------------------------------; Free an inode.;; Parameters:; r1 = device number; r2 = inode number;------------------------------------------------------------------------------;free_inode:phaphxphypush r4push r5push r7push r8push r9ld r7,r1 ; r7 = device numberjsr get_inodes_per_groupdiv r4,r2,r1 ; r4 = group number of inodemod r5,r2,r1 ; r5 = group indexld r1,r7ld r2,r4jsr get_bgdt_entryld r9,r1 ; r9 = pointer to BGDescld r1,r7ld r2,bg_inode_bitmap,r9jsr get_block ; get the bitmap blockld r8,r1 ; r8 = bitmap blockld r1,r5bmt b_data,r8 ; is the inode already free ?beq fi1bmc b_data,r8inc bg_free_inodes_count,r9lda #DIRTYsta bg_dirty,r9jsr get_supertaxinc s_free_inodes_count,xlda #DIRTYsta s_dirty,xsta b_dirty,r8txyjsr get_datetimestx s_mtime,ysta s_mtime+1,yfi1:pop r9pop r8pop r7pop r5pop r4plyplxplarts;------------------------------------------------------------------------------; Allocate an inode; This is called when a file or directory is created. The routine allocates; an inode on disk, then gets an inode buffer.;; Parameters:; r1 = device number; r2 = mode bits; Returns:; r1 = pointer to inode buffer;------------------------------------------------------------------------------;alloc_inode:phxphypush r4push r7push r8push r9push r10push r11; search the super match for a block with available inodelda #0 ; start at bit zerold r7,r1ld r8,r2jsr get_num_bgdtayjsr get_inodes_per_blockld r9,r1ld r2,#0 ; start with group #0alin2:ld r1,r7jsr get_bgdt_entryld r4,r1lda bg_free_inodes_count,r4bne alin3inxdeybne alin2ld r1,r7jsr dos_msgdb "Out of inodes on device ",0alin7:pop r11pop r10pop r9pop r8pop r7pop r4plyplxlda #0rtsalin3:ld r1,r7ld r10,r2 ; r10 = bgd entry numberldx bg_inode_bitmap,r4ldy #NORMALjsr get_blocktaxld r3,r9 ; r3 = indoes per blocklda #0alin5:bmt b_data,xbeq alin4inadeybne alin5alin4:bms b_data,x ; mark inode allocatedld r5,r1 ; r5 = inode number within blockdec bg_free_inodes_count,r4mul r11,r10,r9add r5,r5,r11 ; r5 = inode numberlda #DIRTYsta bg_dirty,r4jsr get_super ; decrement free inode count in superblockdec s_free_inodes_count,r1 ; and mark the superblock dirtytaylda #DIRTYsta s_dirty,yjsr get_datetimestx i_mtime,ysta i_mtime+1,y;ld r1,r7 ; r1 = device numberld r2,r5 ; r2 = inode numberjsr get_inodecmp #0bne alin6ld r1,r7ld r2,r5jsr free_inodebra alin7alin6:st r8,i_mode,r1stz i_link_count,r1; set uid,gidst r7,i_dev,r1jsr wipe_inodepop r11pop r10pop r9pop r8pop r7pop r4plyplxrts;------------------------------------------------------------------------------;------------------------------------------------------------------------------;wipe_inode:phaphxphytaystz i_size,yjsr get_datetimestx i_mtime,ysta i_mtime+1,ylda #DIRTYsta i_dirty,yldx #15win1:stz INODE_P0,yinydexbne win1plyplxplarts;------------------------------------------------------------------------------; Get an inode;; There are 256 inode buffers in the system which allows for 256 files; to be open at once.;; Parameters:; r1 = device; r2 = inode number; Returns:; r1 = pointer to inode buffer;------------------------------------------------------------------------------;get_inode:; push working registerspush r4 ; r4 = buffer numberpush r5 ; r5 points to inode bufferpush r6push r7ld r7,#0 ; tracks the last free buffer; Search the in use inode buffers for the one corresponding; to the given device and node number. If found then increment; the reference count and return a pointer to the buffer.ld r4,#0ld r5,#inode_bufsgib4:ld r6,INODE_ICOUNT,r5 ; check the count field to see if in usebeq gib3 ; branch if not in usecmp INODE_DEV,r5 ; now check for a matching devicebne gib5 ; branch if no matchcpx INODE_INUM,r5 ; now check for matching node numberbne gib5inc INODE_ICOUNT,r5 ; increment countld r1,r5pop r7pop r6 ; pop working registerspop r5pop r4cmp #0rtsgib3:ld r7,r5 ; remember the free inodegib5:add r4,#1 ; increment buffer numberadd r5,r5,#INODE_SIZE ; size of an inode in wordscmp r4,#256 ; have we searched all buffers ?bltu gib4cmp r7,#0 ; test if free buffer foundbne gib6pop r7pop r6pop r5pop r4ld r1,#0 ; no more inode buffers availablertsgib6:sta INODE_DEV,r7stx INODE_INUM,r7inc INODE_ICOUNT,r7 ; count field =1, was 0cmp #NO_DEV ; if there was a device number suppliedbeq gib7 ; read the inode from the deviceld r1,r7ldx #READINGjsr rw_inodegib7:ld r1,r7pop r7 ; restore work registerspop r6pop r5pop r4cmp #0rts;------------------------------------------------------------------------------; Put inode;; Parameters:; r1 = pointer to inode buffer;------------------------------------------------------------------------------;put_inode:cmp #0 ; check for NULL pointerbne pi1rtspi1:phxtaxdec INODE_ICOUNT,xbne pi2; If the number of links to the inode is zero; then deallocate the storage for the inodepi2:lda INODE_DIRTY,xcmp #DIRTYbne pi3txa ; acc = inode buffer pointerldx #WRITINGjsr rw_inodepi3:plxrts;------------------------------------------------------------------------------; Parameters:; r1 = inode; r2 = R/W indicator;------------------------------------------------------------------------------rw_inode:phaphxphypush r4push r5push r6push r7; get the super block for the devicephxphalda INODE_DEV,r1jsr get_inodes_per_groupld r5,r1 ; r4 = inodes per groupplaldx INODE_INUM,r1div r6,r2,r5 ; r6 = group numbermod r7,r2,r5 ; r7 = index into grouplda INODE_DEV,r1phald r2,r6jsr get_bgdt_entrylda bg_inode_table,r1 ; get block address of inode tablephajsr get_inodes_per_blockdiv r6,r7,r1mod r8,r7,r1plaadd r2,r1,r6plaldy #NORMALjsr get_blockld r7,r1 ; r7 = pointer to block bufferpop r4 ; r4 = inodeadd r5,r1,#BUF_INODE ; r5 = address of inode datamul r6,r8,#INODE_SIZEadd r5,r5,r6pop r6 ; r6 = R/W indicatorcmp r6,#READINGbne rwi1jsr get_inode_sizedeald r2,r5ld r3,r4mvnbra rwi2rwi1:jsr get_inode_sizedeald r2,r4ld r3,r5mvnjsr get_datetimestx INODE_WTIME,r4sta INODE_WTIME+1,r4lda #DIRTYsta b_dirty,r7rwi2:jsr get_datetimestx INODE_ATIME,r4sta INODE_ATIME+1,r4ld r1,r7 ; r1 = pointer to block bufferld r2,#INODE_BLOCKjsr put_blocklda #CLEANsta INODE_DIRTY,r4pop r7pop r6pop r5pop r4plyplxplarts;------------------------------------------------------------------------------;------------------------------------------------------------------------------dup_inode:inc INODE_ICOUNT,r1rts;------------------------------------------------------------------------------; get_bgdt_entry:; Get block group descriptor from the descriptor table.;; Parameters:; r1 = device number; r2 = group number; Returns:; r1 = pointer to BGD buffer;------------------------------------------------------------------------------;get_bgdt_entry:push r5and r5,r2,#NR_BGD_BUFS-1 ; r5 = hashed group numbermul r5,r5,#BGD_BUFSIZEadd r5,r5,#BGD_bufs ; r5 = pointer to BGD buffercmp bg_dev,r5bne gbe1cpx bg_group_num,r5beq gbe2gbe1:push r4push r6push r7push r8ld r6,r1 ; r6 = device numberld r7,r2 ; r7 = group number; does the buffer need to be written to disk ?ld r4,bg_dirty,r5cmp r4,#CLEANbeq gbe3; Compute the block number containing the groupjsr get_bgd_per_blockld r2,bg_group_num,r5div r8,r2,r1mod r4,r2,r1lda fs_start_blockina ; the next block after the file system startadd r2,r1,r8 ; r2 = block numberld r1,r6 ; r1 = device numberjsr get_blockphaadd r1,r1,#b_data ; move to data areamul r4,r4,#BGDESC_SIZEadd r1,r1,r4 ; r1 = pointer to desired BGD; copy BGD to the blocktayld r2,r5lda #BGDESC_SIZE-1mvnplald r2,#DIRTYstx b_dirty,r1gbe3:; Compute the block number containing the groupld r1,r6ld r2,r7jsr get_bgd_per_blockdiv r8,r2,r1mod r4,r2,r1lda fs_start_blockina ; the next block after the file system startadd r2,r1,r8 ; r2 = block numberld r1,r6 ; r1 = device numberjsr get_blockadd r1,r1,#b_data ; move to data areamul r4,r4,#BGDESC_SIZEadd r1,r1,r4 ; r1 = pointer to desired BGD; copy BGD from the block to the buffertaxld r3,r5lda #BGDESC_SIZE-1mvnst r6,bg_dev,r5st r7,bg_group_num,r5lda #CLEANsta bg_dirty,r5pop r8pop r7pop r6pop r4gbe2:ld r1,r5pop r5rts;==============================================================================; Block Caching;==============================================================================;------------------------------------------------------------------------------; get_block;; Gets a block from the device. First the block cache is checked for the; block; if found the cached buffer is returned.; The block number is hashed to determine where to start the search for a; cached buffer.;; Parameters:; r1 = device; r2 = block number; r3 = only searching; Returns:; r1 = pointer to buffer containing block;------------------------------------------------------------------------------;get_block:phxphypush r4push r5push r6push r7push r8ld r4,r1 ; r4 = device numberld r5,r2 ; r5 = block numberand r6,r5,#NR_BUF_HASH-1ldx buf_hash,r6cmp r4,#NO_DEVbeq gb11gb15:cmp r2,r0 ; while (bp <> NULL) {beq gb12cmp r4,b_dev,x ; if (bp->b_dev == dev) {bne gb13cmp r5,b_blocknum,x ; if (bp->b_blocknum==block) {bne gb13cmp r0,b_count,x ; if (bp->b_count==0)bne gb14inc bufs_in_use ; bufs_in_use++gb14:inc b_count,x ; bp->b_count++txa ; return (bp)gb_ret:pop r8pop r7pop r6pop r5pop r4plyplxrtsgb13:ldx b_hash,x ; bp = bp->b_hashbra gb15gb11:gb12:lda bufs_in_usecmp #NR_BUFSbltu gb16jsr panicdb "All buffers in use.",0gb16:inc bufs_in_useldx frontgb18:cmp r0,b_count,xbls gb17cmp r0,b_next,xbeq gb17ldx b_next,xbra gb18gb17:cmp r2,r0beq gb19cmp r0,b_count,xbls gb20gb19:jsr panicdb "No free buffer.", 0gb20:ld r6,b_blocknum,xand r6,r6,#NR_BUF_HASH-1ld r7,buf_hash,r6cmp r7,r2bne gb21ld r8,b_hash,xst r8,buf_hash,r6bra gb22gb21:cmp r0,b_hash,r7beq gb22cmp r2,b_hash,r7bne gb23ld r8,b_hash,xst r8,b_hash,r7bra gb22gb23:ld r7,b_hash,r7bra gb21gb22:ld r8,b_dirty,xcmp r8,#DIRTYbne gb24ld r8,b_dev,xcmp r8,#NO_DEVbeq gb24phxtxaldx #WRITINGjsr rw_blockplxgb24:st r4,b_dev,x ; bp->b_dev = devst r5,b_blocknum,x ; bp->b_blocknum = blockinc b_count,x ; bp->b_count++ld r7,buf_hash,r6st r7,b_hash,x ; bp->b_hash = buf_hash[bp->b_blocknr & (NR_b_hash - 1)]st r2,buf_hash,r6 ; buf_hash[bp->b_blocknr & (NR_b_hash - 1)] = bpcmp r4,#NO_DEVbeq gb25cmp r3,#NORMALbne gb25phxtxaldx #READINGjsr rw_blockplabra gb_retgb25:txabra gb_ret;------------------------------------------------------------------------------; put_block; Put a block back to device;; Parameters:; r1 = pointer to buffer to put; r2 = block type;;------------------------------------------------------------------------------;put_block:cmp #0 ; NULL pointer checkbne pb1pb2:rtspb1:phaphxpush r4push r5push r7push r8ld r4,r1ld r5,r2dec b_count,r1 ; if buf count > 0 then buffer is still in usebne pb2dec bufs_in_usetaxld r7,b_next,xld r8,b_prev,xbeq pb3st r7,b_next,r8 ; prev_ptr->b_next = next_ptrbra pb4pb3:st r7,front ; front = next_ptrpb4:cmp r7,r0beq pb5st r8,b_next,r7bra pb6pb5:st r8,rearpb6:bit r5,#ONE_SHOTbeq pb7stz b_prev,xlda frontsta b_next,xbne bp8stx rearbra bp9bp8:stx b_prev,r1 ; front->b_prev = bpbp9:stx front ; front = bpbra bp10pb7:stz b_next,x ; bp->b_next = NULLlda rearsta b_prev,x ; bp->b_prev = rearbne bp11stx front ; front = bpbra bp12bp11:stx b_next,r1 ; rear->b_next = bpbp12:stx rear ; read = bpbp10:cmp r0,b_dev,xbeq bp13lda #DIRTYcmp b_dirty,xbne bp13bit r5,#WRITE_IMMEDbeq bp13phxtxaldx #WRITINGjsr rw_blockplxbp13:cmp r5,#ZUPER_BLOCKbne bp14lda #NO_DEVsta b_dev,xbp14:pop r8pop r7pop r5pop r4plxplarts;------------------------------------------------------------------------------; block_to_sector:; Convert a block number to a sector number.;; Parameters:; r1 = block number; Returns:; r1 = sector number;------------------------------------------------------------------------------block_to_sector:phxphajsr get_log_block_sizetaxplainxasl r1,r1,r2plxrts;------------------------------------------------------------------------------; rw_block:; ToDo: add error handling;; Parameters:; r1 = pointer to buffer to operate on; r2 = R/W flag;------------------------------------------------------------------------------;rw_block:phxphypush r4push r5phald r5,r1 ; r5 = pointer to data bufferadd r5,r5,#b_dataldy b_dev,r1cpy #NO_DEVbeq rwb1ldy b_blocknum,r1 ; y = block numberld r4,#1 ; r4 = # of blockslda b_dev,r1 ; device numbercpx #READINGbne rwb2ldx #11 ; read blocks opcodebra rwb1rwb2:ldx #12 ; write blocks opcoderwb1:jsr DeviceOpplaldy #CLEANsty b_dirty,r1pop r5pop r4plyplxrts;------------------------------------------------------------------------------; invalidate_dev; Cycle through all the block buffers and mark the buffers for the; matching device as free.;; Parameters:; r1 = device number;------------------------------------------------------------------------------;invalidate_dev:phxphypush r4ldy #NR_BUFSldx #data_bufsid2:ld r4,b_dev,xcmp r4,r1bne id1ld r4,#NO_DEVst r4,b_dev,xid1:add r2,r2,#BUF_SIZEdeybne id2; invalidate the superblock; ldy #32; ldx #super_bufsid3:; ld r4,s_dev,x; cmp r4,r1; bne id4; ld r4,#NO_DEV; st r4,s_dev,xid4:; add r2,r2,#SUPERBUF_SIZE; dey; bne id3pop r4plyplxrts;==============================================================================; SUPERBLOCK code;==============================================================================;------------------------------------------------------------------------------; get_super:; Get the super block.; There is a super block for each device. Superblocks have their own buffer; cache.;; Parameters:; r1 = device number; Returns:; r1 = pointer to superblock buffer;------------------------------------------------------------------------------;get_super:phxphypush r4; first search the superbuf array to see if the block is already; memory residentldy #0ldx #super_bufsgs2:ld r4,s_dev,xcmp r1,r4 ; device number match ?beq gs1 ; yes, found superblock buffer for devicecmp r4,#NO_DEVbne gs4txy ; record empty buffergs4:add r2,r2,#SUPERBUF_SIZEcpx #super_bufs_endblo gs2cpy #0beq gs5tyxsta s_dev,xbra gs3gs5:; Here we couldn't find the device superblock cached and there wasn't a slot free.; So dump one from memory and load cacheinc superbuf_dump ; "randomizer" for dump selectldx superbuf_dumpand r2,r2,#31 ; 32 buffersmul r2,r2,#SUPERBUF_SIZEadd r2,r2,#super_bufs; if the superblock is dirty, then write it outldy s_dirty,xcpy #DIRTYbne gs3jsr write_supergs3:sta s_dev,xjsr read_supergs1:txapop r4plyplxrts;------------------------------------------------------------------------------; read_super:; Read the superblock from disk. Only a single sector is read.;; Parameters:; r1 = pointer to superblock buffer;------------------------------------------------------------------------------;read_super:phaphxphyldy s_dev,r1 ; save device number in .Yphajsr get_filesystem_offsettaxplaphaasl ; convert pointer to byte pointerasljsr SDReadSectorplxlda #CLEAN ; mark superblock cleansta s_dirty,xsty s_dev,x ; restore device numberplyplxplarts;------------------------------------------------------------------------------; Parameters:; r1 = pointer to superblock buffer;------------------------------------------------------------------------------write_super:phaphxphypush r4ld r4,r1ldy s_dev,r1 ; save device number in .Yjsr get_datetimestx s_wtime,r4sta s_wtime+1,r4pop r4phajsr get_filesystem_offsettaxplaphaasl ; convert pointer to byte pointerasljsr SDWriteSectorplxlda #CLEANsta s_dirty,xsty s_dev,x ; restore device numberplyplxplarts;==============================================================================; Utility functions;==============================================================================;------------------------------------------------------------------------------; get_datetime:; Get the date and time.; Returns:; r1 = date; r2 = time;------------------------------------------------------------------------------get_datetime:phpseistz DATETIME_SNAPSHOT ; take a snapshot of the running date/timelda DATETIME_DATEldx DATETIME_TIMEplprts;------------------------------------------------------------------------------; panic; Display a filesystem panic message and abort.;; Parameters:; r1 = numeric constant; inline string;------------------------------------------------------------------------------;panic:phalda panickingbeq pan1plartspan1:inasta panicking ; panicking = TRUE;jsr dos_msgdb "File system panic: ", 0plyplx ; pull return address from stackpan2:lb r1,0,xbeq pan3jsr DisplayCharinxbra pan2pan3:inxphxtyacmp #NO_NUMbeq pan4ldx #5jsr PRTNUMpan4:jsr CRLFjsr do_syncjsr sys_abort;pan5: ; we should not get back to here after the sys_abort()bra pan5;------------------------------------------------------------------------------; Display a message on the screen; Parameters:; inline string;------------------------------------------------------------------------------;dos_msg:plx ; get return addressdm2:lb r1,0,xbeq dm1jsr DisplayCharinxbra dm2dm1:inxphxrts;==============================================================================;==============================================================================;------------------------------------------------------------------------------; File system CLEAN task;------------------------------------------------------------------------------fs_clean:fsc4:lda #100 ; sleep for 1sjsr Sleepfsc3:lda fs_active ; is the file system active ?cmp #'A'bne fsc4ldx #data_bufsfsc2:lda b_dev,x ; is the buffer in use ?cmp #NO_DEVbeq fsc1 ; if not, goto next bufferseilda b_dirty,x ; is the buffer dirty ?cmp #CLEANbeq fsc1 ; if not, goto next buffer; Found a dirty bufferphxtxaldx #WRITING ; write the dirty buffer out to diskjsr rw_blockplxlda #CLEAN ; mark the buffer as cleansta b_dirty,xfsc1: ; iterate to the next buffercliadd r2,r2,#BUF_SIZEcpx #data_bufs_endbltu fsc2bra fsc3;==============================================================================; DOS commands;==============================================================================;------------------------------------------------------------------------------; MKFS - make file system;------------------------------------------------------------------------------;;numb_block_group_sectors:; nbg = ((disk size in bytes /; (blocks per block group * block size)) * block group descriptor size ) / block size + 1jsr SDInitlda #1024sta block_sizejsr SDReadPartjsr get_supertax; blocks_count = disk size * 512 / block sizejsr get_log_block_sizetaxinxlda disk_size ; disk size in sectorslsr r1,r1,r2 ; r1 = disk size in blockssta s_block_count,xsta s_free_blocks_count,x; # files = block count * block size / 2048 (average file size)lda disk_sizelsrlsrsta s_inodes_count,xsta s_free_inodes_count,xstz s_log_block_size,x ; 0=1kBlda #8192sta s_blocks_per_group,xsta s_inodes_per_group,xlda #$EF54EF54sta s_magic,xstz s_errors,xjsr get_filesystem_offsetjsr SDWriteSector ; put_blocklda disk_sizediv r1,r1,#16384 ; 8388608/512div r1,r1,#32 ; divide by size of block group descriptotadd r1,#1 ; round upadd r4,r1,#2 ; boot block + superblock; acc = number of blocks for descriptor tabletayst r4,bg_block_bitmap,rts
