; Filesystem functions for the Interaction with BIOS and Disks ; ; Copyright (C) 2010 Frank Zoll ; ; This file is part of avrcpm. ; ; avrcpm is free software: you can redistribute it and/or modify it ; under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; avrcpm 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 avrcpm. If not, see . ; ; $Id$ ; ; ---------------- Defines for the Filesystem Interface ------- ;***************************************************** ;* Disk-Manager constants * ;***************************************************** .equ dskType_None = 0 .equ dskType_CPM = 1 .equ dskType_FAT = 2 .equ dskType_RAM = 3 ;***************************************************** ;* CP/M to host disk constants * ;***************************************************** .equ MAXDISKS = 4 ;Max number of Disks (partitions) .equ PARTENTRY_SIZE = 9 ;Size of a Partitiontableentry .equ blksize = 1024 ;CP/M allocation size .equ hostsize = 512 ;host disk sector size ; .equ hostspt = 20 ;host disk sectors/trk .equ hostblk = hostsize/128 ;CP/M sects/host buff ; .equ CPMSPT = hostblk*hostspt;CP/M sectors/track .equ CPMSPT = 26 ; .equ SECMSK = hostblk-1 ;sector mask .equ SECSHF = log2(hostblk) ;sector shift ;***************************************************** ;* BDOS constants on entry to write * ;***************************************************** .equ WRALL = 0 ;write to allocated .equ WRDIR = 1 ;write to directory .equ WRUAL = 2 ;write to unallocated .equ WRTMSK= 3 ;write type mask ;----------------------------------------------- Start of Data Segment .dseg ndisks: .byte 1 ;Number of CP/M disks seekdsk: .byte 1 ;seek disk number seektrk: .byte 2 ;seek track number seeksec: .byte 1 ;seek sector number unacnt: .byte 1 ;unalloc rec cnt unadsk: .byte 1 ;last unalloc disk unatrk: .byte 2 ;last unalloc track unasec: .byte 1 ;last unalloc sector erflag: .byte 1 ;error reporting wrtype: .byte 1 ;write operation type dmaadr: .byte 2 ;last dma address hostbuf: .byte hostsize ;host buffer (from/to SD-card) hostparttbl: .byte PARTENTRY_SIZE*MAXDISKS ;host partition table (type, start sector, sector count) hostparttbltop: hostdsk: .byte 1 ;host disk number hosttype: .byte 1 ;host disk type (same entry as 1 parition entry) hostlba: .byte 3 ;host sector number (relative to partition start) ; ------------------------------- Start of Code Segment .cseg ; ==================================================================== ; Function: Get a Pointer to a Partitiontable entry ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : [w] z Pointer to the Partitionentry ; [r] xl Number of Diskentry to Read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_getpartentry: ldiw z,hostparttbl mov temp,xl dsk_getpartentryloop: cp temp,_0 breq dsk_getpartentryloopend adiw z,PARTENTRY_SIZE dec temp jmp dsk_getpartentryloop dsk_getpartentryloopend: ret ; ==================================================================== ; Function: ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dskDiskCheck: lds temp2,seekdsk cpi temp2,RAMDISKNR brsh dsk_dchrd ;maybe ramdisk ; Check if selected disk # is less then # of disks. lds temp,ndisks tst temp brne dsk_dchpart1 ; Need to init rcall mgr_init_partitions cbr temp,0x80 lds temp2,seekdsk dsk_dchpart1: cp temp2,temp brsh dsk_dcher dsk_dchend: ldi temp,0 ret dsk_dchrd: #if RAMDISKCNT cpi temp,RAMDISKNR+RAMDISKCNT brlo dsk_dchend #endif dsk_dcher: ldi temp,0xff ;error return ret dskErrorRet: lds temp,erflag ret dskDiskSel: sts seekdsk,temp ret dskTrackSel_l: sts seektrk,temp sts seektrk+1,_0 ret dskTrackSel_h: sts seektrk+1,temp ret dskSecSel: sts seeksec,temp ret dskDmal: sts dmaadr,temp ret dskDmah: sts dmaadr+1,temp ret ; ==================================================================== ; Function: Does a Disk interaction ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dskDoIt: .if DISK_DEBUG push temp sbrc temp,READ_FUNC rjmp dskdbgr sbrc temp,WRITE_FUNC rjmp dskdbgw rjmp dskdbge dskdbgr: printnewline printstring "Disk read: " rjmp dskdbg1 dskdbgw: printnewline printstring "Disk write: " dskdbg1: lds temp,seekdsk subi temp,-('A') rcall uartputc printstring ": track " lds temp2,seektrk+1 lds temp,seektrk rcall printhexw printstring ", sector " lds temp,seeksec rcall printhex printstring ", dma-addr " lds temp2,dmaadr+1 lds temp,dmaadr rcall printhexw pop temp push temp sbrs temp,WRITE_FUNC rjmp dskdbge printstring " wrtype " andi temp,3 rcall printhex dskdbge: pop temp .endif ;See what has to be done. sbrc temp,READ_FUNC rjmp dsk_read sbrc temp,WRITE_FUNC rjmp dsk_write sbrc temp,HOME_FUNC rjmp dsk_home sbrc temp,BOOT_FUNC rjmp dsk_boot printstring "DISK I/O: Invalid Function code: " rcall printhex rjmp haltinv dsk_boot: sts ndisks,_0 ;no active partitions dsk_cboot: cbi flags,hostact ;host buffer inactive sts unacnt,_0 ;clear unalloc count ret dsk_home: sbis flags,hostwrt ;check for pending write cbi flags,hostact ;clear host active flag ret ; ==================================================================== ; Function: Does a Disk read operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_read: sts erflag,_0 sbi flags,readop ; Set read operation flag lds xl,seekdsk rcall dsk_getpartentry ; Get Paritiontableentry ld temp,z ; Get Partitiontype ; Isn't it a Disk ? cpi temp,dskType_None brne PC+2 rjmp dsk_read_err ; Is it a RamDisk ? cpi temp,dskType_RAM brne PC+2 rjmp rdsk_read ; It must be a FAT16-Imagefile or CP/M Partition. sts unacnt,_0 sbi flags,rsflag ;must read data ldi temp,WRUAL ;write type sts wrtype,temp ;treat as unalloc rjmp dsk_rwoper ;to perform the read dsk_read_err: ret ; ==================================================================== ; Function: Does a Disk write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_write: ;write the selected sector sts erflag,_0 cbi flags,readop ; not a read operation lds xl,seekdsk rcall dsk_getpartentry ; Get Paritiontableentry ld temp,z ; Get Partitiontype ; Isn't it a Disk ? cpi temp,dskType_None brne PC+2 rjmp dsk_write_err ; Is it a RamDisk ? cpi temp,dskType_RAM brne PC+2 rjmp rdsk_write ; It must be a FAT16-Imagefile or CP/M Partition. cbi flags,readop ;not a read operation andi temp,WRTMSK sts wrtype,temp ;save write type cpi temp,WRUAL ;write unallocated? brne dsk_chkuna ;check for unalloc ; write to unallocated, set parameters ldi temp,blksize/128 ;next unalloc recs sts unacnt,temp lds temp,seekdsk ;disk to seek sts unadsk,temp ;unadsk = sekdsk lds temp,seektrk sts unatrk,temp ;unatrk = sectrk lds temp,seektrk+1 sts unatrk+1,temp ;unatrk = sectrk lds temp,seeksec sts unasec,temp ;unasec = seksec ; dsk_chkuna: ;check for write to unallocated sector lds temp,unacnt ;any unalloc remain? tst temp breq dsk_alloc ;skip if not ; more unallocated records remain dec temp ;unacnt = unacnt-1 sts unacnt,temp lds temp,seekdsk ;same disk? lds temp2,unadsk cp temp,temp2 ;seekdsk = unadsk? brne dsk_alloc ;skip if not ; disks are the same lds temp,unatrk lds temp2,unatrk+1 lds temp3,seektrk lds temp4,seektrk+1 cp temp,temp3 ;seektrk = unatrk? cpc temp2,temp4 brne dsk_alloc ;skip if not ; tracks are the same lds temp,seeksec ;same sector? lds temp2,unasec cp temp,temp2 ;seeksec = unasec? brne dsk_alloc ;skip if not ; match, move to next sector for future ref inc temp2 ;unasec = unasec+1 sts unasec,temp2 cpi temp2,CPMSPT ;end of track? (count CP/M sectors) brlo dsk_noovf ;skip if no overflow ; overflow to next track sts unasec,_0 ;unasec = 0 lds temp,unatrk lds temp2,unatrk+1 subi temp, low(-1) ;unatrk = unatrk+1 sbci temp2,high(-1) sts unatrk,temp sts unatrk+1,temp2 ; dsk_noovf: cbi flags,rsflag ;rsflag = 0 rjmp dsk_rwoper ;to perform the write ; dsk_alloc: ;not an unallocated record, requires pre-read sts unacnt,_0 ;unacnt = 0 sbi flags,rsflag ;rsflag = 1 rjmp dsk_rwoper dsk_write_err: ret ; ==================================================================== ; Function: Does a Disk read/write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_rwoper: ;enter here to perform the read/write .if DISK_DEBUG printstring ", flags: " in temp,flags rcall printhex .endif sts erflag,_0 ;no errors (yet) ;Convert track/sector to an LBA address (in 128byte blocks) lds xl,seeksec ; ldi xh,0 ; ldi yl,0 ; lds temp3,seektrk ; lds temp4,seektrk+1 ; ldi temp,CPMSPT ; mul temp3,temp ; add xl,r0 ; adc xh,r1 ; mul temp4,temp ; add xh,r0 ;yl:xh:xl := sec + trk * SectorsPerTrack adc yl,r1 ; mov temp,xl andi temp,SECMSK ;mask buffer number push temp ;save for later ;Convert from CP/M LBA blocks to host LBA blocks ldi temp,SECSHF dsk_sh1: lsr yl ror xh ror xl dec temp brne dsk_sh1 ;yl:xh:xl = host block to seek ; active host sector? in _tmp0,flags ;host active flag sbi flags,hostact ;always becomes 1 sbrs _tmp0,hostact ;was it already? rjmp dsk_filhst ;fill host if not ; host buffer active, same as seek buffer? lds temp,seekdsk lds temp2,hostdsk ;same disk? cp temp,temp2 ;seekdsk = hostdsk? brne dsk_nomatch ; same disk, same block? lds temp,hostlba lds temp2,hostlba+1 lds temp3,hostlba+2 cp xl,temp cpc xh,temp2 cpc yl,temp3 breq dsk_match ; dsk_nomatch: ;proper disk, but not correct sector sbis flags,hostwrt ;host written? rjmp dsk_filhst push xl push xh push yl rcall dsk_writehost ;clear host buff pop yl pop xh pop xl dsk_filhst: ;may have to fill the host buffer lds temp,seekdsk sts hostdsk,temp sts hostlba,xl sts hostlba+1,xh sts hostlba+2,yl sbic flags,rsflag ;need to read? rcall dsk_readhost ;yes, if 1 cbi flags,hostwrt ;no pending write dsk_match: ;copy data to or from buffer ldiw z,hostbuf ldi temp,128 pop temp2 ;get buffer number (which part of hostbuf) mul temp2,temp add zl,r0 ;offset in hostbuf adc zh,r1 .if DISK_DEBUG > 2 push r0 push r1 printstring "; host buf adr: " pop temp2 pop temp rcall printhexw .endif lds xl,dmaadr lds xh,dmaadr+1 ldi temp3,128 ;length of move sbic flags,readop ;which way? rjmp dsk_rmove ;skip if read ; mark write operation sbi flags,hostwrt ;hostwrt = 1 dsk_wmove: mem_read st z+,temp adiw xl,1 dec temp3 brne dsk_wmove rjmp dsk_rwmfin dsk_rmove: ld temp,z+ mem_write adiw xl,1 dec temp3 brne dsk_rmove dsk_rwmfin: ; data has been moved to/from host buffer lds temp,wrtype ;write type cpi temp,WRDIR ;to directory? breq dsk_wdir ret ;no further processing dsk_wdir: ; clear host buffer for directory write lds temp,erflag tst temp ;errors? breq dsk_wdir1 ret ;skip if so dsk_wdir1: rcall dsk_writehost ;clear host buff cbi flags,hostwrt ;buffer written ret ; ==================================================================== ; Function: Does a Disk write operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_writehost: lds xl,hostdsk rcall dsk_getpartentry ld temp,z ; Is it a FAT16 Diskimage ? cpi temp,dskType_FAT brne PC+2 rjmp fat_writehost ; Is it a CP/M Partition ? cpi temp,dskType_CPM brne PC+2 rjmp cpm_writehost ; Disktype not supported -> Return ret ; ==================================================================== ; Function: Does a Disk read operation ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : none ; Variables : [r] seekdsk Number of Disk to Read ; [r] seeksec Sector to read ; [r] seektrk Track to read ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_readhost: lds xl,hostdsk rcall dsk_getpartentry ld temp,z ; Is it a FAT16 Diskimage ? cpi temp,dskType_FAT brne PC+2 rjmp fat_readhost ; Is it a CP/M Partition ? cpi temp,dskType_CPM brne PC+2 rjmp cpm_readhost ; Disktype not supported -> Return ret