OpenCores
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             -1
READING         EQU             'R'
WRITING         EQU             'W'
DIRTY           EQU             'D'
CLEAN           EQU             'C'
NORMAL          EQU             0

ONE_SHOT        EQU             1
WRITE_IMMED     EQU             2
ZUPER_BLOCK     EQU             2       ; write superblock immediately
SUPER_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             0
s_blocks_count                  EQU             1
s_r_blocks_count                EQU             2
s_free_blocks_count             EQU             3
s_free_inodes_count             EQU             4
s_first_data_block              EQU             5
s_log_block_size                EQU             6
s_log_frag_size                 EQU             7
s_blocks_per_group              EQU             8
s_frags_per_group               EQU             9
s_inodes_per_group              EQU             10
s_pad                                   EQU             11
s_mtime                                 EQU             12
s_wtime                                 EQU             14
s_mnt_cnt                               EQU             16
s_max_mnt_cnt                   EQU             17
s_magic                                 EQU             18
s_state                                 EQU             19
s_errors                                EQU             20
s_minor_rev_level               EQU             21
s_lastcheck                             EQU             22
s_checkinterval                 EQU             24
s_creator_os                    EQU             26
s_rev_level                             EQU             27
s_def_res_uid                   EQU             28
s_def_res_gid                   EQU             29
s_inode_size                    EQU             31
s_volume_name                   EQU             40
; In memory management fields
s_inodes_per_block              EQU             124
s_dev                                   EQU             125
s_dirty                                 EQU             126
SUPERBUF_SIZE                   EQU             128

; STRUCT INODE
;
i_mode          EQU             0
i_uid           EQU             1
i_size          EQU             2
i_gid           EQU             3
i_atime         EQU             4
i_ctime         EQU             6
i_mtime         EQU             8
i_dtime         EQU             10
i_links_count   EQU     12
i_blocks        EQU             13
i_flags         EQU             14
i_osd1          EQU             15
INODE_P0        EQU             16
INODE_P1        EQU             INODE_P0+1
INODE_P2        EQU             INODE_P1+1
INODE_P3        EQU             INODE_P2+1
INODE_P4        EQU             INODE_P3+1
INODE_P5        EQU             INODE_P4+1
INODE_P6        EQU             INODE_P5+1
INODE_P7        EQU             INODE_P6+1
INODE_P8        EQU             INODE_P7+1
INODE_P9        EQU             INODE_P8+1
INODE_P10       EQU             INODE_P9+1
INODE_P11       EQU             INODE_P10+1
INODE_IP        EQU             INODE_P11+1             ; indirect pointer
INODE_IIP       EQU             INODE_IP+1              ; double indirect pointer
INODE_IIIP      EQU             INODE_IIP+1             ; triple indirect pointer
i_generation    EQU             31
i_file_acl              EQU             32
i_dir_acl               EQU             33
i_faddr                 EQU             34
i_osd2                  EQU             35
INODE_DEV       EQU             37
INODE_INUM      EQU             38
INODE_ICOUNT    EQU     39
INODE_DIRTY     EQU             40
INODE_SIZE      EQU             41                              ; 41 words

; STRUCT BGDESC
;
bg_block_bitmap                 EQU             0
bg_inode_bitmap                 EQU             1
bg_inode_table                  EQU             2
bg_free_blocks_count    EQU             3
bg_free_inodes_count    EQU             4
bg_used_dirs_count              EQU             5
bg_reserved                             EQU             6
BGDESC_SIZE                             EQU             8
bg_dev                                  EQU             9
bg_group_num                    EQU             10
bg_dirty                                EQU             11
BGD_BUFSIZE                             EQU             12

; STRUCT DIRENTRY
; Directory entries are 64 bytes
; 28 character file name
;  4 byte i-node number
;
DE_NAME                 EQU             0
DE_TYPE                 EQU             14
DE_INODE                EQU             15
DE_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                ; device 
b_blocknum      EQU             1               ; disk block number
b_count         EQU             2               ; reference count
b_dirty         EQU             3               ; buffer has been altered
b_next          EQU             4               ; next buffer on LRU list
b_prev          EQU             5
b_hash          EQU             6               ; pointer to hashed buffer
b_data          EQU             8               ; beginning of data area
BUF_INODE               EQU             8
BUF_SIZE                EQU             b_data+256

NR_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             1024
BT_DATA_BLOCK   EQU             0
BT_SUPERBLOCK   EQU             1

IAM_BUF_SIZE    EQU             1032    ; 1024 + 8
CAM_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 area
super_bufs              EQU             DOS_DATA
super_bufs_end  EQU             super_bufs + SUPERBUF_SIZE * 32
BGD_bufs                EQU             super_bufs_end
BGD_bufs_end    EQU             BGD_bufs + NR_BGD_BUFS * BGD_BUFSIZE    ; 32 kB = 1024 descriptors
iam_bufs                EQU             BGD_bufs_end
inode_array             EQU             iam_bufs + IAM_BUF_SIZE * 32    ; 129 kB worth 
inode_array_end EQU             inode_array + INODE_SIZE * 256  ; 41kB worth (256 open files)
data_bufs               EQU             0x00320000                      ; room for 8192 buffers
data_bufs_end   EQU             data_bufs + BUF_SIZE * NR_BUFS
buf_hash                EQU             data_bufs_end
buf_hash_end    EQU             buf_hash + NR_BUF_HASH
superbuf_dump   EQU             buf_hash_end + 1
bufs_in_use             EQU             superbuf_dump + 1
blockbuf_dump   EQU             bufs_in_use + 1
disk_size               EQU             blockbuf_dump + 1
block_size              EQU             disk_size + 1
fs_start_block  EQU             block_size + 1
bgdt_valid              EQU             fs_start_block + 1
front                   EQU             bgdt_valid + 1
rear                    EQU             front + 1
panicking               EQU             rear + 1
fs_active               EQU             panicking + 1
DOS_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 caching

inode_bufs      EQU             DOS_DATA        ; 128B x 256 bufs
iam_buf         EQU             0x01FBE800
sector_buf      EQU             0x01FBEC00

        org             $FFFFD800

;------------------------------------------------------------------------------
; Initialize the file system.
;------------------------------------------------------------------------------
;
init_fs:
        stz             bgdt_valid
        jsr             init_superbufs
        jsr             init_databufs
        lda             #'A'
        sta             fs_active
        lda             #4
        ldx             #0                              ; no flags (em =0 native mode)
        ldy             #fs_clean
        jsr             StartTask
        rts

;------------------------------------------------------------------------------
; 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             #2
        rts

;------------------------------------------------------------------------------
; Initialize super block buffer array.
;------------------------------------------------------------------------------
;
init_superbufs:
        pha
        phx
        ldx             #super_bufs
isb1:
        lda             #NO_DEV
        sta             s_dev,x
        lda             #CLEAN
        sta             s_dirty,x
        add             r2,r2,#SUPERBUF_SIZE
        cpx             #super_bufs_end
        bltu    isb1
        plx
        pla
        rts

init_databufs:
        pha
        phx
        phy
        stz             bufs_in_use
        ldx             #data_bufs
        stx             front
        lda             #data_bufs_end
        sub             #BUF_SIZE
        sta             rear
idb1:
        lda             #NO_DEV
        sta             b_dev,x
        lda             #CLEAN
        sta             b_dirty,x
        sub             r3,r2,#BUF_SIZE
        sty             b_prev,x
        add             r3,r2,#BUF_SIZE
        sty             b_next,x
        sty             b_hash,x
        tyx
        cpx             #data_bufs_end
        bltu    idb1
        ldx             front
        stz             b_prev,x
        stx             buf_hash                        ; buf_hash[0] = front
        ldx             rear
        stz             b_next,x        
        ply
        plx
        pla
        rts

;------------------------------------------------------------------------------
; Parameters:
;       r1 = device
; Returns:
;       r1 = block size in bytes
;------------------------------------------------------------------------------
get_block_size:
        phx
        phy
        jsr             get_super
        tax
        ldy             s_log_block_size,x
        lda             #1024
        asl             r1,r1,r3
        ply
        plx
        rts

get_log_block_size:
        phx
        jsr             get_super
        tax
        lda             s_log_block_size,x
        plx
        rts

get_inode_size:
        phx
        jsr             get_super
        tax
        lda             s_inode_size,x
        plx
        rts

get_inodes_per_group:
        phx
        jsr             get_super
        tax
        lda             s_inodes_per_group,x
        plx
        rts

; inodes per block does not need to be a power of 2
;
get_inodes_per_block:
        phx
        pha
        jsr             get_block_size
        tax
        pla
        jsr             get_inode_size
        div             r1,r2,r1
        plx
        rts

get_bgd_per_block:
        jsr             get_block_size
        lsr             ; BGD size is 32 bytes
        lsr
        lsr
        lsr
        lsr
        rts
        
get_bits_per_block:
        jsr             get_block_size
        asl
        asl
        asl
        rts

get_num_bgd:
        phx
        jsr             get_super
        lda             s_blocks_count,r1
        tax
        jsr             get_bits_per_block
        div             r1,r2,r1
        plx
        rts
        
;==============================================================================
; INODE code
;==============================================================================
;------------------------------------------------------------------------------
; Free an inode.
;
; Parameters:
;       r1 = device number
;       r2 = inode number
;------------------------------------------------------------------------------
;       
free_inode:
        pha
        phx
        phy
        push    r4
        push    r5
        push    r7
        push    r8
        push    r9
        ld              r7,r1           ; r7 = device number
        jsr             get_inodes_per_group
        div             r4,r2,r1        ; r4 = group number of inode
        mod             r5,r2,r1        ; r5 = group index
        ld              r1,r7
        ld              r2,r4
        jsr             get_bgdt_entry
        ld              r9,r1           ; r9 = pointer to BGDesc
        ld              r1,r7
        ld              r2,bg_inode_bitmap,r9
        jsr             get_block       ; get the bitmap block
        ld              r8,r1           ; r8 = bitmap block
        ld              r1,r5
        bmt             b_data,r8       ; is the inode already free ?
        beq             fi1
        bmc             b_data,r8
        inc             bg_free_inodes_count,r9
        lda             #DIRTY
        sta             bg_dirty,r9
        jsr             get_super
        tax
        inc             s_free_inodes_count,x
        lda             #DIRTY
        sta             s_dirty,x
        sta             b_dirty,r8
        txy
        jsr             get_datetime
        stx             s_mtime,y
        sta             s_mtime+1,y
fi1:
        pop             r9
        pop             r8
        pop             r7
        pop             r5
        pop             r4
        ply
        plx
        pla
        rts

;------------------------------------------------------------------------------
; 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:
        phx
        phy
        push    r4
        push    r7
        push    r8
        push    r9
        push    r10
        push    r11
; search the super match for a block with available inode
        lda             #0                              ; start at bit zero
        ld              r7,r1
        ld              r8,r2
        jsr             get_num_bgd
        tay
        jsr             get_inodes_per_block
        ld              r9,r1
        ld              r2,#0                   ; start with group #0
alin2:
        ld              r1,r7
        jsr             get_bgdt_entry
        ld              r4,r1
        lda             bg_free_inodes_count,r4
        bne             alin3
        inx
        dey
        bne             alin2
        ld              r1,r7
        jsr             dos_msg
        db              "Out of inodes on device ",0
alin7:
        pop             r11
        pop             r10
        pop             r9
        pop             r8
        pop             r7
        pop             r4
        ply
        plx
        lda             #0
        rts
alin3:
        ld              r1,r7
        ld              r10,r2                                  ; r10 = bgd entry number
        ldx             bg_inode_bitmap,r4
        ldy             #NORMAL
        jsr             get_block
        tax
        ld              r3,r9                                   ; r3 = indoes per block
        lda             #0
alin5:
        bmt             b_data,x
        beq             alin4
        ina
        dey
        bne             alin5
alin4:
        bms             b_data,x                                ; mark inode allocated
        ld              r5,r1                                   ; r5 = inode number within block
        dec             bg_free_inodes_count,r4
        mul             r11,r10,r9
        add             r5,r5,r11                                       ; r5 = inode number
        lda             #DIRTY
        sta             bg_dirty,r4
        jsr             get_super                               ; decrement free inode count in superblock
        dec             s_free_inodes_count,r1  ; and mark the superblock dirty
        tay
        lda             #DIRTY
        sta             s_dirty,y
        jsr             get_datetime
        stx             i_mtime,y
        sta             i_mtime+1,y
        ;
        ld              r1,r7                                   ; r1 = device number
        ld              r2,r5                                   ; r2 = inode number
        jsr             get_inode
        cmp             #0
        bne             alin6
        ld              r1,r7
        ld              r2,r5
        jsr             free_inode
        bra             alin7
alin6:
        st              r8,i_mode,r1
        stz             i_link_count,r1
        ; set uid,gid
        st              r7,i_dev,r1
        jsr             wipe_inode
        pop             r11
        pop             r10
        pop             r9
        pop             r8
        pop             r7
        pop             r4
        ply
        plx
        rts

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
;
wipe_inode:
        pha
        phx
        phy
        tay
        stz             i_size,y
        jsr             get_datetime
        stx             i_mtime,y
        sta             i_mtime+1,y
        lda             #DIRTY
        sta             i_dirty,y
        ldx             #15
win1:
        stz             INODE_P0,y
        iny
        dex
        bne             win1
        ply
        plx
        pla
        rts

;------------------------------------------------------------------------------
; 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 registers
        push    r4                                              ; r4 = buffer number            
        push    r5                                              ; r5 points to inode buffer
        push    r6
        push    r7
        ld              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,#0
        ld              r5,#inode_bufs
gib4:
        ld              r6,INODE_ICOUNT,r5              ; check the count field to see if in use
        beq             gib3                                    ; branch if not in use
        cmp             INODE_DEV,r5                    ; now check for a matching device
        bne             gib5                                    ; branch if no match                                    
        cpx             INODE_INUM,r5                   ; now check for matching node number
        bne             gib5
        inc             INODE_ICOUNT,r5                 ; increment count
        ld              r1,r5
        pop             r7
        pop             r6                                              ; pop working registers
        pop             r5
        pop             r4
        cmp             #0
        rts

gib3:
        ld              r7,r5                                   ; remember the free inode
gib5:
        add             r4,#1                                   ; increment buffer number
        add             r5,r5,#INODE_SIZE               ; size of an inode in words
        cmp             r4,#256                                 ; have we searched all buffers ?
        bltu    gib4
        cmp             r7,#0                                   ; test if free buffer found
        bne             gib6
        pop             r7
        pop             r6
        pop             r5
        pop             r4
        ld              r1,#0                                   ; no more inode buffers available
        rts
gib6:
        sta             INODE_DEV,r7
        stx             INODE_INUM,r7
        inc             INODE_ICOUNT,r7                 ; count field =1, was 0
        cmp             #NO_DEV                                 ; if there was a device number supplied
        beq             gib7                                    ; read the inode from the device
        ld              r1,r7
        ldx             #READING
        jsr             rw_inode
gib7:
        ld              r1,r7
        pop             r7                                              ; restore work registers
        pop             r6
        pop             r5
        pop             r4
        cmp             #0
        rts
                
;------------------------------------------------------------------------------
; Put inode
;
; Parameters:
;       r1 = pointer to inode buffer
;------------------------------------------------------------------------------
;
put_inode:
        cmp             #0                                      ; check for NULL pointer
        bne             pi1
        rts
pi1:
        phx
        tax
        dec             INODE_ICOUNT,x
        bne             pi2
        ; If the number of links to the inode is zero
        ; then deallocate the storage for the inode
pi2:
        lda             INODE_DIRTY,x
        cmp             #DIRTY
        bne             pi3
        txa                                                     ; acc = inode buffer pointer
        ldx             #WRITING
        jsr             rw_inode
pi3:
        plx
        rts

;------------------------------------------------------------------------------
; Parameters:
;       r1 = inode
;       r2 = R/W indicator
;------------------------------------------------------------------------------
rw_inode:
        pha
        phx
        phy
        push    r4
        push    r5
        push    r6
        push    r7
        ; get the super block for the device
        phx
        pha
        lda             INODE_DEV,r1
        jsr             get_inodes_per_group
        ld              r5,r1                   ; r4 = inodes per group
        pla
        ldx             INODE_INUM,r1
        div             r6,r2,r5                ; r6 = group number
        mod             r7,r2,r5                ; r7 = index into group
        lda             INODE_DEV,r1
        pha
        ld              r2,r6
        jsr             get_bgdt_entry
        lda             bg_inode_table,r1       ; get block address of inode table
        pha
        jsr             get_inodes_per_block
        div             r6,r7,r1
        mod             r8,r7,r1
        pla
        add             r2,r1,r6
        pla
        ldy             #NORMAL
        jsr             get_block

        ld              r7,r1                           ; r7 = pointer to block buffer
        pop             r4                                      ; r4 = inode
        add             r5,r1,#BUF_INODE        ; r5 = address of inode data

        mul             r6,r8,#INODE_SIZE
        add             r5,r5,r6
        pop             r6                                      ; r6 = R/W indicator
        cmp             r6,#READING
        bne             rwi1
        jsr             get_inode_size
        dea
        ld              r2,r5
        ld              r3,r4
        mvn
        bra             rwi2
rwi1:                   
        jsr             get_inode_size
        dea
        ld              r2,r4
        ld              r3,r5
        mvn
        jsr             get_datetime
        stx             INODE_WTIME,r4
        sta             INODE_WTIME+1,r4
        lda             #DIRTY
        sta             b_dirty,r7
rwi2:
        jsr             get_datetime
        stx             INODE_ATIME,r4
        sta             INODE_ATIME+1,r4
        ld              r1,r7                           ; r1 = pointer to block buffer
        ld              r2,#INODE_BLOCK
        jsr             put_block
        lda             #CLEAN
        sta             INODE_DIRTY,r4
        pop             r7
        pop             r6
        pop             r5
        pop             r4
        ply
        plx
        pla
        rts

;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
dup_inode:
        inc             INODE_ICOUNT,r1
        rts

;------------------------------------------------------------------------------
; 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    r5
        and             r5,r2,#NR_BGD_BUFS-1            ; r5 = hashed group number
        mul             r5,r5,#BGD_BUFSIZE
        add             r5,r5,#BGD_bufs         ; r5 = pointer to BGD buffer
        cmp             bg_dev,r5
        bne             gbe1
        cpx             bg_group_num,r5
        beq             gbe2
gbe1:
        push    r4
        push    r6
        push    r7
        push    r8
        ld              r6,r1                           ; r6 = device number
        ld              r7,r2                           ; r7 = group number
        ; does the buffer need to be written to disk ?
        ld              r4,bg_dirty,r5
        cmp             r4,#CLEAN
        beq             gbe3
        ; Compute the block number containing the group
        jsr             get_bgd_per_block
        ld              r2,bg_group_num,r5
        div             r8,r2,r1
        mod             r4,r2,r1
        lda             fs_start_block
        ina                                                     ; the next block after the file system start
        add             r2,r1,r8                        ; r2 = block number
        ld              r1,r6                           ; r1 = device number
        jsr             get_block
        pha
        add             r1,r1,#b_data           ; move to data area
        mul             r4,r4,#BGDESC_SIZE
        add             r1,r1,r4                        ; r1 = pointer to desired BGD
        ; copy BGD to the block
        tay
        ld              r2,r5
        lda             #BGDESC_SIZE-1
        mvn
        pla
        ld              r2,#DIRTY
        stx             b_dirty,r1
gbe3:
        ; Compute the block number containing the group
        ld              r1,r6
        ld              r2,r7
        jsr             get_bgd_per_block
        div             r8,r2,r1
        mod             r4,r2,r1
        lda             fs_start_block
        ina                                                     ; the next block after the file system start
        add             r2,r1,r8                        ; r2 = block number
        ld              r1,r6                           ; r1 = device number
        jsr             get_block
        add             r1,r1,#b_data           ; move to data area
        mul             r4,r4,#BGDESC_SIZE
        add             r1,r1,r4                        ; r1 = pointer to desired BGD
        ; copy BGD from the block to the buffer
        tax
        ld              r3,r5
        lda             #BGDESC_SIZE-1
        mvn
        st              r6,bg_dev,r5
        st              r7,bg_group_num,r5
        lda             #CLEAN
        sta             bg_dirty,r5
        pop             r8
        pop             r7
        pop             r6
        pop             r4
gbe2:
        ld              r1,r5
        pop             r5
        rts

;==============================================================================
; 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:
        phx
        phy
        push    r4
        push    r5
        push    r6
        push    r7
        push    r8
        ld              r4,r1                           ; r4 = device number
        ld              r5,r2                           ; r5 = block number
        and             r6,r5,#NR_BUF_HASH-1
        ldx             buf_hash,r6
        cmp             r4,#NO_DEV
        beq             gb11
gb15:
        cmp             r2,r0                           ; while (bp <> NULL) {
        beq             gb12
        cmp             r4,b_dev,x              ;       if (bp->b_dev == dev) {
        bne             gb13
        cmp             r5,b_blocknum,x ;               if (bp->b_blocknum==block) {
        bne             gb13
        cmp             r0,b_count,x            ;                       if (bp->b_count==0)
        bne             gb14
        inc             bufs_in_use                     ;                               bufs_in_use++
gb14:
        inc             b_count,x                       ;                       bp->b_count++
        txa                                                     ;                       return (bp)
gb_ret:
        pop             r8
        pop             r7
        pop             r6
        pop             r5
        pop             r4
        ply
        plx
        rts
gb13:
        ldx             b_hash,x                        ;       bp = bp->b_hash
        bra             gb15
gb11:
gb12:
        lda             bufs_in_use
        cmp             #NR_BUFS
        bltu    gb16
        jsr             panic
        db              "All buffers in use.",0
gb16:
        inc             bufs_in_use
        ldx             front
gb18:
        cmp             r0,b_count,x
        bls             gb17
        cmp             r0,b_next,x
        beq             gb17
        ldx             b_next,x
        bra             gb18
gb17:
        cmp             r2,r0
        beq             gb19
        cmp             r0,b_count,x
        bls             gb20
gb19:   
        jsr             panic
        db              "No free buffer.", 0
gb20:
        ld              r6,b_blocknum,x
        and             r6,r6,#NR_BUF_HASH-1
        ld              r7,buf_hash,r6
        cmp             r7,r2
        bne             gb21
        ld              r8,b_hash,x
        st              r8,buf_hash,r6
        bra             gb22
gb21:
        cmp             r0,b_hash,r7
        beq             gb22
        cmp             r2,b_hash,r7
        bne             gb23
        ld              r8,b_hash,x
        st              r8,b_hash,r7
        bra             gb22
gb23:
        ld              r7,b_hash,r7
        bra             gb21
gb22:
        ld              r8,b_dirty,x
        cmp             r8,#DIRTY
        bne             gb24
        ld              r8,b_dev,x
        cmp             r8,#NO_DEV
        beq             gb24
        phx
        txa
        ldx             #WRITING
        jsr             rw_block
        plx
gb24:
        st              r4,b_dev,x              ; bp->b_dev = dev
        st              r5,b_blocknum,x ; bp->b_blocknum = block
        inc             b_count,x                       ; bp->b_count++
        ld              r7,buf_hash,r6
        st              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)] = bp
        cmp             r4,#NO_DEV
        beq             gb25
        cmp             r3,#NORMAL
        bne             gb25
        phx
        txa
        ldx             #READING
        jsr             rw_block
        pla
        bra             gb_ret
gb25:
        txa
        bra             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 check
        bne             pb1
pb2:
        rts
pb1:
        pha
        phx
        push    r4
        push    r5
        push    r7
        push    r8
        ld              r4,r1
        ld              r5,r2
        dec             b_count,r1      ; if buf count > 0 then buffer is still in use
        bne             pb2
        dec             bufs_in_use
        tax
        ld              r7,b_next,x
        ld              r8,b_prev,x
        beq             pb3
        st              r7,b_next,r8    ; prev_ptr->b_next = next_ptr
        bra             pb4
pb3:
        st              r7,front                ; front = next_ptr
pb4:
        cmp             r7,r0
        beq             pb5
        st              r8,b_next,r7
        bra             pb6
pb5:
        st              r8,rear
pb6:
        bit             r5,#ONE_SHOT
        beq             pb7
        stz             b_prev,x
        lda             front
        sta             b_next,x
        bne             bp8
        stx             rear
        bra             bp9
bp8:
        stx             b_prev,r1               ; front->b_prev = bp
bp9:
        stx             front                   ; front = bp
        bra             bp10
pb7:
        stz             b_next,x                ; bp->b_next = NULL
        lda             rear
        sta             b_prev,x                ; bp->b_prev = rear
        bne             bp11
        stx             front                   ; front = bp
        bra             bp12
bp11:
        stx             b_next,r1               ; rear->b_next = bp
bp12:
        stx             rear                    ; read = bp
bp10:
        cmp             r0,b_dev,x
        beq             bp13
        lda             #DIRTY
        cmp             b_dirty,x
        bne             bp13
        bit             r5,#WRITE_IMMED 
        beq             bp13
        phx
        txa
        ldx             #WRITING
        jsr             rw_block
        plx
bp13:
        cmp             r5,#ZUPER_BLOCK
        bne             bp14
        lda             #NO_DEV
        sta             b_dev,x
bp14:
        pop             r8
        pop             r7
        pop             r5
        pop             r4
        plx
        pla
        rts
        
;------------------------------------------------------------------------------
; block_to_sector:
;       Convert a block number to a sector number.
;
; Parameters:
;       r1 = block number
; Returns:
;       r1 = sector number
;------------------------------------------------------------------------------
block_to_sector:
        phx
        pha
        jsr             get_log_block_size
        tax
        pla
        inx
        asl             r1,r1,r2
        plx
        rts

;------------------------------------------------------------------------------
; rw_block:
; ToDo: add error handling
;
; Parameters:
;       r1 = pointer to buffer to operate on
;       r2 = R/W flag
;------------------------------------------------------------------------------
;
rw_block:
        phx
        phy
        push    r4
        push    r5
        pha
        ld              r5,r1                           ; r5 = pointer to data buffer
        add             r5,r5,#b_data
        ldy             b_dev,r1
        cpy             #NO_DEV
        beq             rwb1
        ldy             b_blocknum,r1           ; y = block number
        ld              r4,#1                           ; r4 = # of blocks
        lda             b_dev,r1                        ; device number
        cpx             #READING
        bne             rwb2
        ldx             #11                                     ; read blocks opcode
        bra             rwb1
rwb2:
        ldx             #12                                     ; write blocks opcode
rwb1:
        jsr             DeviceOp
        pla
        ldy             #CLEAN
        sty             b_dirty,r1
        pop             r5
        pop             r4
        ply
        plx
        rts

;------------------------------------------------------------------------------
; invalidate_dev
;       Cycle through all the block buffers and mark the buffers for the 
; matching device as free.
;
; Parameters:
;       r1 = device number
;------------------------------------------------------------------------------
;
invalidate_dev:
        phx
        phy
        push    r4
        ldy             #NR_BUFS
        ldx             #data_bufs
id2:
        ld              r4,b_dev,x
        cmp             r4,r1
        bne             id1
        ld              r4,#NO_DEV
        st              r4,b_dev,x
id1:
        add             r2,r2,#BUF_SIZE
        dey
        bne             id2

; invalidate the superblock
;       ldy             #32
;       ldx             #super_bufs
id3:
;       ld              r4,s_dev,x
;       cmp             r4,r1
;       bne             id4
;       ld              r4,#NO_DEV
;       st              r4,s_dev,x
id4:
;       add             r2,r2,#SUPERBUF_SIZE
;       dey
;       bne             id3

        pop             r4
        ply
        plx
        rts
        
;==============================================================================
; 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:
        phx
        phy
        push    r4
        ; first search the superbuf array to see if the block is already
        ; memory resident
        ldy             #0
        ldx             #super_bufs
gs2:
        ld              r4,s_dev,x
        cmp             r1,r4                                   ; device number match ?
        beq             gs1                                             ; yes, found superblock buffer for device
        cmp             r4,#NO_DEV
        bne             gs4
        txy                                                             ; record empty buffer
gs4:
        add             r2,r2,#SUPERBUF_SIZE
        cpx             #super_bufs_end
        blo             gs2
        cpy             #0
        beq             gs5
        tyx
        sta             s_dev,x
        bra             gs3
gs5:
        ; Here we couldn't find the device superblock cached and there wasn't a slot free.
        ; So dump one from memory and load cache
        inc             superbuf_dump                   ; "randomizer" for dump select
        ldx             superbuf_dump
        and             r2,r2,#31                               ; 32 buffers
        mul             r2,r2,#SUPERBUF_SIZE
        add             r2,r2,#super_bufs
        ; if the superblock is dirty, then write it out
        ldy             s_dirty,x
        cpy             #DIRTY
        bne             gs3
        jsr             write_super
gs3:
        sta             s_dev,x
        jsr             read_super
gs1:
        txa
        pop             r4
        ply
        plx
        rts

;------------------------------------------------------------------------------
; read_super:
;       Read the superblock from disk. Only a single sector is read.
;
; Parameters:
;       r1 = pointer to superblock buffer
;------------------------------------------------------------------------------
;
read_super:
        pha
        phx
        phy
        ldy             s_dev,r1                        ; save device number in .Y
        pha
        jsr             get_filesystem_offset
        tax
        pla
        pha
        asl                                                     ; convert pointer to byte pointer
        asl
        jsr             SDReadSector
        plx
        lda             #CLEAN                          ; mark superblock clean
        sta             s_dirty,x
        sty             s_dev,x                         ; restore device number
        ply
        plx
        pla
        rts
        
;------------------------------------------------------------------------------
; Parameters:
;       r1 = pointer to superblock buffer
;------------------------------------------------------------------------------
write_super:
        pha
        phx
        phy
        push    r4
        ld              r4,r1
        ldy             s_dev,r1                        ; save device number in .Y
        jsr             get_datetime
        stx             s_wtime,r4
        sta             s_wtime+1,r4
        pop             r4
        pha
        jsr             get_filesystem_offset
        tax
        pla
        pha
        asl                                                     ; convert pointer to byte pointer
        asl
        jsr             SDWriteSector
        plx
        lda             #CLEAN
        sta             s_dirty,x
        sty             s_dev,x                         ; restore device number
        ply
        plx
        pla
        rts
        
;==============================================================================
; Utility functions
;==============================================================================

;------------------------------------------------------------------------------
; get_datetime:
;       Get the date and time.
; Returns:
;       r1 = date
;       r2 = time
;------------------------------------------------------------------------------
get_datetime:
        php
        sei
        stz             DATETIME_SNAPSHOT       ; take a snapshot of the running date/time
        lda             DATETIME_DATE
        ldx             DATETIME_TIME
        plp
        rts

;------------------------------------------------------------------------------
; panic
;       Display a filesystem panic message and abort.
;
; Parameters:
;       r1 = numeric constant
;       inline string
;------------------------------------------------------------------------------
;
panic:
        pha
        lda             panicking
        beq             pan1
        pla
        rts
pan1:
        ina
        sta             panicking       ; panicking = TRUE;
        jsr             dos_msg
        db              "File system panic: ", 0
        ply
        plx                                             ; pull return address from stack
pan2:
        lb              r1,0,x
        beq             pan3
        jsr             DisplayChar
        inx
        bra             pan2
pan3:
        inx
        phx
        tya
        cmp             #NO_NUM
        beq             pan4
        ldx             #5
        jsr             PRTNUM
pan4:
        jsr             CRLF
        jsr             do_sync
        jsr             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 address
dm2:
        lb              r1,0,x
        beq             dm1
        jsr             DisplayChar
        inx
        bra             dm2
dm1:
        inx
        phx
        rts

;==============================================================================
;==============================================================================
;------------------------------------------------------------------------------
; File system CLEAN task
;------------------------------------------------------------------------------
fs_clean:
fsc4:
        lda             #100                    ; sleep for 1s
        jsr             Sleep
fsc3:
        lda             fs_active               ; is the file system active ?
        cmp             #'A'
        bne             fsc4
        ldx             #data_bufs
fsc2:
        lda             b_dev,x                 ; is the buffer in use ?
        cmp             #NO_DEV
        beq             fsc1                    ; if not, goto next buffer
        sei
        lda             b_dirty,x               ; is the buffer dirty ?
        cmp             #CLEAN
        beq             fsc1                    ; if not, goto next buffer
        ; Found a dirty buffer
        phx
        txa
        ldx             #WRITING                ; write the dirty buffer out to disk
        jsr             rw_block
        plx
        lda             #CLEAN                  ; mark the buffer as clean
        sta             b_dirty,x
fsc1:                                           ; iterate to the next buffer
        cli
        add             r2,r2,#BUF_SIZE
        cpx             #data_bufs_end
        bltu    fsc2
        bra             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 + 1
        
        jsr             SDInit
        lda             #1024
        sta             block_size
        jsr             SDReadPart
        jsr             get_super
        tax
        ;       blocks_count = disk size * 512 / block size
        jsr             get_log_block_size
        tax
        inx
        lda             disk_size               ; disk size in sectors
        lsr             r1,r1,r2                ; r1 = disk size in blocks
        sta             s_block_count,x
        sta             s_free_blocks_count,x
        ; # files = block count * block size / 2048 (average file size)
        lda             disk_size
        lsr
        lsr
        sta             s_inodes_count,x
        sta             s_free_inodes_count,x
        stz             s_log_block_size,x      ; 0=1kB
        lda             #8192
        sta             s_blocks_per_group,x
        sta             s_inodes_per_group,x
        lda             #$EF54EF54
        sta             s_magic,x
        stz             s_errors,x
        jsr             get_filesystem_offset
        jsr             SDWriteSector           ; put_block

        lda             disk_size
        div             r1,r1,#16384                    ; 8388608/512
        div             r1,r1,#32                               ; divide by size of block group descriptot
        add             r1,#1                                   ; round up
        add             r4,r1,#2                                ; boot block + superblock
        ; acc = number of blocks for descriptor table
        tay
        st              r4,bg_block_bitmap,
        rts     


Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.