; Filesystem functions for the Interaction with BIOS and Disks ; ; Copyright (C) 2010 Frank Zoll ; Copyright (C) 2010,2011,2013 Leo C. ; ; 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 * ;***************************************************** ; Fields in the parttabl .equ MAXDISKS = 8 ;Max number of Disks (partitions) .equ PARTENTRY_SIZE = 9 ;Size of a Partitiontableentry .equ PTAB_TYPE = 0 .equ PTAB_START = 1 .equ PTAB_SIZE = 5 .equ PTAB_SPT = 7 .equ PTAB_BSH = 8 .equ dskType_None = 0 << 4 .equ dskType_CPM = 1 << 4 .equ dskType_FAT = 2 << 4 ; .equ dskType_RAM = 3 << 4 .equ dskType_MASK = 0xf << 4 ;***************************************************** ;* CP/M to host disk constants * ;***************************************************** ; .equ blksize = 1024 ;CP/M allocation size ; .equ CPMSPT = 26 ; .equ HOSTSIZE = 512 ;host disk sector size .equ HOSTBLK = HOSTSIZE/128 ;CP/M sects/host buff .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 fsys_vars: ; The following 3 variables are copied from DRAM. ; Don't change order. biosdrvtbl: .byte 2 ; biosdirbuf: .byte 2 ; biosenddat: .byte 2 ; ndisks: .byte 1 ;Number of CP/M disks .equ o_ndisks = ndisks-fsys_vars ; The following 5 variables are accessed from 8080/z80 via the ; virtual port interface. Don't change order. biospar_base: bcbadr: .byte 2 ;adr of BiosControlBlock seekdsk: .byte 1 ;seek disk number seektrk: .byte 2 ;seek track number seeksec: .byte 2 ;seek sector number dmaadr: .byte 2 ;last dma address .equ o_bcbadr = bcbadr-fsys_vars .equ o_seekdsk = seekdsk-fsys_vars .equ o_seektrk = seektrk-fsys_vars .equ o_seeksec = seeksec-fsys_vars .equ o_dmaadr = dmaadr-fsys_vars hdrsize: .byte 1 ;Image header size (offset) cpmspt: .byte 1 ;CP/M sectors per track secpblk: .byte 1 ;sectors per block (alloc size) unacnt: .byte 1 ;unalloc rec cnt unadsk: .byte 1 ;last unalloc disk unalba: .byte 2 ;last unalloc disk block .equ o_hdrsize = hdrsize-fsys_vars .equ o_cpmspt = cpmspt-fsys_vars .equ o_secpblk = secpblk-fsys_vars .equ o_unacnt = unacnt-fsys_vars .equ o_unadsk = unadsk-fsys_vars .equ o_unalba = unalba-fsys_vars erflag: .byte 1 ;error reporting wrtype: .byte 1 ;write operation type .equ o_erflag = erflag-fsys_vars .equ o_wrtype = wrtype-fsys_vars hostdsk: .byte 1 ;host disk number hostlba: .byte 2 ;host sector number (relative to partition start) .equ o_hostdsk = hostdsk-fsys_vars .equ o_hostlba = hostlba-fsys_vars hostparttbl: .byte PARTENTRY_SIZE*MAXDISKS ;host partition table (type, start sector, sector count) hostparttbltop: hostbuf: .byte HOSTSIZE ;host buffer (from/to SD-card) ; ------------------------------- Start of Code Segment .cseg ;--------------------------------------------------------------------- .if DSKSEL_DEBUG dbg_prdrvtbl: push xh push xl push temp3 push temp2 push temp printnewline printstring "drvtbl (" ldsw x,biosdrvtbl movw temp,x lcall printhexw printstring "): " ldi temp3,16 dbg_pcpel: lcall dram_readw_pp lcall printhexw printstring " " dec temp3 brne dbg_pcpel pop temp pop temp2 pop temp3 pop xl pop xh ret dbg_print_biosd: printnewline lds temp,bcbadr lds temp2,bcbadr+1 lcall printhexw printstring " " lds temp,biosdrvtbl lds temp2,biosdrvtbl+1 lcall printhexw printstring " " lds temp,biosdirbuf lds temp2,biosdirbuf+1 lcall printhexw printstring " " lds temp,biosenddat lds temp2,biosenddat+1 lcall printhexw printstring " " ret .endif ; ==================================================================== ; ==================================================================== ; Function: Get a Pointer to a Partitiontable entry ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : [w] z Pointer to the Partitionentry ; [r] zl Number of Diskentry to Read ; [w] r0 scratch ; [w] r1 " ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_getpartentry: ldi zh,PARTENTRY_SIZE mul zh,zl ldiw z,hostparttbl add zl,r0 adc zh,r1 ret ; ==================================================================== ; ==================================================================== ; Function: Virtual Port Interface ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_param_getadr: ldiw z,biospar_base add zl,temp3 adc zh,_0 ret dsk_param_set: rcall dsk_param_getadr st z,temp cpi temp3,bcbadr+1-biospar_base breq SetBCB ret dsk_param_get: cpi temp3,seekdsk-biospar_base breq dskDiskCheck rcall dsk_param_getadr ld temp,z ret SetBCB: lds xl,bcbadr mov xh,temp ldiw z,biosdrvtbl ldi temp3,6 sbcb_l: rcall dram_read_pp st z+,temp dec temp3 brne sbcb_l ; rcall dbg_print_biosd rcall dpb_drvtblclear ; rcall dbg_prdrvtbl ret ; ==================================================================== ; Function: Check if disk exists ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; return 0, if selected disk not exist. ; return !0, if disk exist ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dskDiskCheck: lds temp2,ndisks lds temp,seekdsk .if DSKSEL_DEBUG printnewline printstring "DiskCheck: " lcall printhexw .endif cpi temp,RAMDISKNR brsh dsk_dchrd ;maybe ramdisk tst temp2 ;0 disks? brne dsk_dchpart1 ; No disks yet, need to init rcall dpb_drvtblclear .if 0 ldi temp2,0x40 ldi temp,1 lcall clockput .endif rcall mgr_init_partitions ;disk changed? push temp .if 0 ldi temp2,0x40 ldi temp,2 lcall clockput ; sbrs temp,7 ; rjmp dsk_dchpart0 lcall mgr_prnt_parttbl printnewline .endif ; rcall dbg_prdrvtbl pop temp2 dsk_dchpart0: cbr temp2,0x80 lds temp,seekdsk ; Check if selected disk # is less then # of disks. dsk_dchpart1: cp temp,temp2 brsh dsk_dch_err .if DSKSEL_DEBUG printnewline printstring "Select: " lcall printhex .endif rcall dpb_drvtbl_entry_get or temp,temp2 ;if !0, drive is allready initialized brne dsk_dchend lds temp3,seekdsk mov temp,temp3 rcall dpb_biosdph_get dsk_dchend: .if DSKSEL_DEBUG push temp lds temp,seekdsk rcall dpb_drvtbl_entry_get printstring ", " lcall printhexw pop temp .endif ret dsk_dch_err: ldi temp,0 ;error return ret ; Check RAMDISK dsk_dchrd: #if RAMDISKCNT cpi temp,RAMDISKNR+RAMDISKCNT brsh dsk_dchrd_err ldi temp,0xff ;return ok ret #endif dsk_dchrd_err: ldi temp,0 ;error return ret ; ==================================================================== ; Function: Return status of last disk i/o function ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dskErrorRet: lds temp,erflag ret ; ==================================================================== ; ==================================================================== str_CPM_Disk: .db 10,"",0 ; DPBs for varios fixed formats ; dpb data starts at 2. byte dpbdat_avrcpm: ;(dpb243) .db 0x00,0x1A ;sector offset, low(spt) .db 0x00,0x03 ;high (spt), block shift .db 0x07,0x00 ;bock mask, extent mask .db 0xF2,0x00 ;disk size - 1, .db 0x3F,0x00 ;dir max .db 0xC0,0x00 ;alloc0, alloc1 .db 0x10,0x00 ;chk size .db 0x02,0x00 ;offset dpbdat_myz80: ; .db 0x02,0x80 ;sector offset, low(spt) .db 0x00,0x05 ;high (spt), block shift .db 0x1F,0x01 ;bock mask, extent mask .db 0xFF,0x07 ;disk size - 1, .db 0xFF,0x03 ;dir max .db 0xFF,0x00 ;alloc0, alloc1 .db 0x00,0x01 ;chk size .db 0x00,0x00 ;offset dpbdat_simhd: ; .db 0x00,0x20 ;sector offset, low(spt) .db 0x00,0x05 ;high (spt), block shift .db 0x1F,0x01 ;bock mask, extent mask .db 0xF9,0x07 ;disk size - 1, .db 0xFF,0x03 ;dir max .db 0xFF,0x00 ;alloc0, alloc1 .db 0x00,0x01 ;chk size .db 0x06,0x00 ;offset #if 0 ;rd1016 .db 0x20,0x00 ;spt .db 0x04,0x0F ;block shift, bock mask .db 0x00,0xFB ;extent mask, low(disk size -1), .db 0x01,0xBF ;high(disk size -1), low(dir max) .db 0x00,0xE0 ;high(dir max), alloc0 .db 0x00,0x30 ;alloc1, low(chk size) .db 0x00,0x02 ;high(chk size), low(offset) .db 0x00,0x00 ;high(offset), fill ;rd9192s .db 0x20,0x00 ;spt .db 0x05,0x1F ;block shift, bock mask .db 0x01,0xFD ;extent mask, low(disk size -1), .db 0x07,0xFF ;high(disk size -1), low(dir max) .db 0x01,0xF0 ;high(dir max), alloc0 .db 0x00,0x80 ;alloc1, low(chk size) .db 0x00,0x02 ;high(chk size), low(offset) .db 0x00,0x00 ;high(offset), fill #endif ; ==================================================================== ; Function: get drive table entry pointer for drive # in temp ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dpb_drvtbl_entry_p: ldsw x,biosdrvtbl lsl temp ;drive # add xl,temp adc xh,_0 ret ; ==================================================================== ; Function: get drive table entry for drive # in temp ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dpb_drvtbl_entry_get: rcall dpb_drvtbl_entry_p ljmp dram_readw_pp ; ==================================================================== ; Function: Clear drive table (entries 0 to 7) ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== ; dpb_drvtblclear: ldsw x,biosdrvtbl sbiw x,0 breq dpb_drvi_ex dpb_drvi_1: ldi temp3,8 dpb_drvi_lp: ldi temp,0 ldi temp2,0 rcall dram_writew_pp dec temp3 brne dpb_drvi_lp lds temp,biosenddat lds temp2,biosenddat+1 cp temp,_0 cpc temp2,_0 breq dpb_drvi_ex rcall heap_init dpb_drvi_ex: clr temp ret ; ==================================================================== ; Function: Test disk format: avrcpmhd ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp drive # ; ; -------------------------------------------------------------------- ; Description: Not implemented yet. ; ==================================================================== dsk_tst_avrcpmhd: clr temp ; Test, return 'not found' for now. ret ; ==================================================================== ; Function: Test disk format: YAZE ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp drive # ; ; -------------------------------------------------------------------- ; Description: From the YAZE Doc: ; ; The new disk header occupies the first 128 BYTES of the file and has the ; new format: ; ; 0 - 9 ; 10 - 15 a null-terminated ascii comment (may be empty) ; new 16 version (0 = yaze-1.06/1.10, 1 = yaze-ag-2.xx) ; 17 - 31 a null-terminated ascii comment (may be empty) ; 32 - 33 sectors per track ; 34 block shift factor ; 35 block mask ; 36 extent mask ; 37 - 38 disk size max ; 39 - 40 directory max ; 41 al0 ; 42 al1 ; 43 - 44 check size (always zero) ; 45 - 46 track offset ; new 47 psh (used if version=1 and CP/M 3.1 is running) ; new 48 phm ( " " " " " " " " " ) ; 49 - 127 unused (zeros) ; ==================================================================== dsk_tst_yaze: ldiw y,hostbuf ldiw z,str_CPM_Disk*2 lpm temp2,z+ ; get length lcall strncmp_p brne dsk_tyze_not ldiw z,hostbuf+31 clt ;dpb in RAM ldi temp,1 ;1 sector header size st z,temp ori temp,0xff ret dsk_tyze_not: clr temp ;Not a YAZE disk image. ret ; ==================================================================== ; Function: Test disk format: MyZ80 ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp drive # ; ; -------------------------------------------------------------------- ; Description: Test, if first 2 Sectors are filled with 0xE5, ; and Size = 8192KB + 256Bytes. ; ==================================================================== dsk_tst_myz80: mov zl,temp3 rcall dsk_getpartentry ;get partition entry ldd temp,z+PTAB_SIZE ldd temp2,z+PTAB_SIZE+1 ;check, if size is 16385 phys. sectors cpi temp,low(16385) ldi temp,high(16385) cpc temp2,temp brne dsk_tmyz80_not ;wrong size ldiw z,hostbuf ldi temp2,0 dsk_tmyz80_loop: ld temp,z+ cpi temp,0xE5 brne dsk_tmyz80_not dec temp2 brne dsk_tmyz80_loop ldiw z,dpbdat_myz80*2 set ori temp,0xff ret dsk_tmyz80_not: clr temp ;Not a MyZ80 hard disk image. ret ; ==================================================================== ; Function: Test disk format: simhd, simh altair 8800 hard disk format ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp drive # ; ; -------------------------------------------------------------------- ; Description: Test, if Size = 8192 KB and ; first 6 tracks are filled with 0xE5. ; Actually, only the first phys. sector is tested, since ; the other 47 sectors are not in memory at this time. ; ==================================================================== dsk_tst_simhd: mov zl,temp3 rcall dsk_getpartentry ;get partition entry ldd temp,z+PTAB_SIZE ldd temp2,z+PTAB_SIZE+1 ;check, if size is 16384 phys. sectors cpi temp,low(16384) ldi temp,high(16384) cpc temp2,temp brne dsk_tsimhd_not ;wrong size ldiw y,hostbuf+128-10 ldiw z,str_CPM_Disk*2 lpm temp2,z+ ; get length lcall strncmp_p breq dsk_tsimhd_found ldiw z,hostbuf ldi temp2,high(512) clr _tmp0 ;low(512) dsk_tsimhd_loop: ld temp,z+ cpi temp,0xE5 brne dsk_tsimhd_not add _tmp0,_255 adc temp2,_255 brne dsk_tsimhd_loop dsk_tsimhd_found: ldiw z,dpbdat_simhd*2 set ori temp,0xff ret dsk_tsimhd_not: clr temp ;Not a simhd hard disk image. ret ; ==================================================================== ; Function: ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp3 drive # ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_format_get: ; Get first sector (512 byte) of current drive into hostbuf. ldi temp,0 ldi temp2,0 ; rcall dsk_readhost_lba ; Test for variable format avrcpmhd. rcall dsk_tst_avrcpmhd brne dsk_imgt_done ; Test for YAZE formats. rcall dsk_tst_yaze brne dsk_imgt_done ; Test for simhd format. rcall dsk_tst_simhd brne dsk_imgt_done ; Test for MyZ80 format. rcall dsk_tst_myz80 brne dsk_imgt_done ; No special image found. Use avrcpm. ldiw z,dpbdat_avrcpm*2 set ori temp,0xff dsk_imgt_done: ret ; ==================================================================== ; Function: Add CP/M image format data to partition table data ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp3 drive # ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dpb_imgdata_get: ; Test for known CP/M formats rcall dsk_format_get breq dpb_imgd_err ;no known format detected dpb_imgd_0: brtc dpb_imgd_variable dpb_imgd_fixed: lpm temp, z+ ;image header lpm yl,z+ ;low(SPT) lpm yh,z+ ;high(SPT) lpm temp2,z+ ;BSH rjmp dpb_imgd_common dpb_imgd_variable: ld temp, z+ ;image header ld yl,z+ ;low(SPT) ld yh,z+ ;high(SPT) ld temp2,z+ ;BSH dpb_imgd_common: mov zl,temp3 rcall dsk_getpartentry ;get partition entry std z+PTAB_SPT,yl tst yh ;more then 256 sectors per track? breq dpb_imgd_1 ;todo: support 16 bit sector numbers dsk_imgprp_err: printnewline ldi temp,'A' add temp,temp3 lcall uartputc printstring ": Format not supported: Too much sectors per track! " printnewline dpb_imgd_err: clr temp ret dpb_imgd_1: andi temp2,0x0f swap temp2 std z+PTAB_BSH,temp2 andi temp,~dskType_MASK ldd temp2,z+PTAB_TYPE andi temp2,dskType_MASK or temp,temp2 std z+PTAB_TYPE,temp ori temp,255 ret ; ==================================================================== ; Function: ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp drive # ; ; return !0 if ok ; 0 on error ; -------------------------------------------------------------------- ; Description: Init CP/M data structures ; ; ----------------------------------------------------------------- ; DPH: | XLT | | | |DIRBUF | DPB | CSV | ALV | ; ----------------------------------------------------------------- ;offset: 0 2 4 6 8 10 12 14 ; ; ------------------------------------------------------------- ; DPB: | SPT |BSH|BLM|EXM| DSM | DRM |AL0|AL1| CKS | OFF | ; ------------------------------------------------------------- ;offset: 0 2 3 4 5 7 9 10 11 13 ; ==================================================================== dpb_biosdph_get: mov temp3,temp ;save disk # rcall dsk_format_get brne dpb_di_0 rjmp dpb_di_err dpb_di_0: ; get mem for DPH ldi temp, low (16) ldi temp2,high(16) rcall heap_get ;returns ptr to dph mem brne dpb_di_1 rjmp dpb_di_err ; dpb_di_1: movw x,temp movw y,temp ;save dph pointer ldi temp,0 ldi temp2,0 rcall dram_writew_pp ;XLT adiw x,6 lds temp,biosdirbuf lds temp2,biosdirbuf+1 rcall dram_writew_pp ;DIRBUF ; get mem for DPB ldi temp, low (15) ldi temp2,high(15) rcall heap_get breq dpb_di_err_p1 movw x,temp adiw z,1 ;skip sector offset byte push temp3 ldi temp3,15 dpb_dicpl: brtc PC+2 ; lpm temp,z+ brts PC+2 ; ld temp,z+ rcall dram_write_pp dec temp3 brne dpb_dicpl pop temp3 sbiw x,15 sbiw z,15 movw temp,x movw x,y adiw x,10 rcall dram_writew_pp ;DPB brtc dpb_dicks_variable dpb_dicks_fixed: adiw z,5 lpm _tmp0,z+ ;dsm lpm _tmp1,z+ adiw z,11-5-2 lpm temp,z+ ;cks lpm temp2,z+ rjmp dpb_dicks_common dpb_dicks_variable: ldd _tmp0,z+5 ;dsm ldd _tmp1,z+5+1 ldd temp,z+11 ;cks ldd temp2,z+11+1 ; get mem for dir check vector dpb_dicks_common: cp temp,_0 cpc temp2,_0 breq dpb_dicks0 rcall heap_get breq dpb_di_err_p1 dpb_dicks0: rcall dram_writew_pp ;CSV ; get mem for alloc vector movw temp,_tmp0 subi temp, low (-8) sbci temp2,high(-8) lsr temp2 ror temp lsr temp2 ror temp lsr temp2 ror temp ;(dsm+1+7)/8 rcall heap_get breq dpb_di_err_p1 rcall dram_writew_pp ;ALV ; success, insert DPH into drvtbl mov temp,temp3 rcall dpb_drvtbl_entry_p movw temp,y rcall dram_writew_pp ori temp,0xff ;return ok ret ; error, free mem dpb_di_err_p1: movw temp,y rcall heap_release dpb_di_err: eor temp,temp ;return 0 (+ Z-flag) ret ; ==================================================================== ; Function: ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_setdrvparam: ldd temp2,z+PTAB_TYPE andi temp2,~dskType_MASK ;Lower nibble is image header size std y+o_hdrsize,temp2 ldd temp2,z+PTAB_SPT std y+o_cpmspt,temp2 ;CP/M sectors per track ldd temp2,z+PTAB_BSH swap temp2 andi temp2,0x0f clr _tmp0 inc _tmp0 dsk_sdrvpl: lsl _tmp0 dec temp2 brne dsk_sdrvpl std y+o_secpblk,_tmp0 ;Sectors per block ret ; ==================================================================== ; Function: Does a Disk interaction ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : ; Variables : ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dskDoIt: ldiw y,fsys_vars std y+o_erflag,_0 .if DISK_DEBUG push temp sbrc temp,HOME_FUNC rjmp dskdbghome sbrc temp,BOOT_FUNC rjmp dskdbgboot .if DISK_DEBUG > 1 sbrc temp,READ_FUNC rjmp dskdbgread sbrc temp,WRITE_FUNC rjmp dskdbgwrite .endif rjmp dskdbge dskdbgread: printnewline printstring "dsk RD: " rjmp dskdbg1 dskdbgwrite: printnewline printstring "dsk WR: " rjmp dskdbg1 dskdbghome: printnewline printstring " HOME: " rjmp dskdbg1 dskdbgboot: printnewline printstring " BOOT: " dskdbg1: ldd temp,y+o_seekdsk subi temp,-('A') lcall uartputc printstring ": trk " ldd temp2,y+o_seektrk+1 ldd temp,y+o_seektrk lcall printhexw printstring ", sec " ldd temp,y+o_seeksec lcall printhex printstring ", dma " ldd temp2,y+o_dmaadr+1 ldd temp,y+o_dmaadr lcall printhexw dskdbge: pop temp .endif ;See what has to be done. sbrc temp,READ_FUNC rjmp dsk_readwrite sbrc temp,WRITE_FUNC rjmp dsk_readwrite sbrc temp,HOME_FUNC rjmp dsk_home sbrc temp,BOOT_FUNC rjmp dsk_boot printstring "DISK I/O: Invalid Function code: " lcall printhex ljmp haltinv dsk_boot: std y+o_ndisks,_0 ;no active partitions dsk_inval_hostbuf: cbi flags,hostact ;host buffer inactive std y+o_unacnt,_0 ;clear unalloc count ret dsk_home: sbis flags,hostwrt ;check for pending write cbi flags,hostact ;clear host active flag ret dsk_readwrite: ; RAM disk? ldd zl,y+o_seekdsk #if RAMDISKCNT cpi zl,RAMDISKNR brlt dsk_rw_noramdisk sbrc temp,WRITE_FUNC rjmp rdsk_write rjmp rdsk_read dsk_rw_noramdisk: #endif rcall dsk_getpartentry ;Get Paritiontableentry ld temp2,z ;Get Partitiontype andi temp2,dskType_MASK ; Isn't it a Disk ? cpi temp2,dskType_None brne PC+2 ret ;return error ; It must be a FAT16-Imagefile or CP/M Partition. sbrc temp,WRITE_FUNC rjmp dsk_write sbi flags,readop ;Set read operation flag sbi flags,rsflag ;must read data std y+o_unacnt,_0 ldi temp,WRUAL ;write type std y+o_wrtype,temp ;treat as unalloc rjmp dsk_rw dsk_write: cbi flags,readop ;Not a read operation andi temp,WRTMSK std y+o_wrtype,temp ;save write type dsk_rw: rcall dsk_setdrvparam ;todo: do this only if needed (disk change) ; Convert track/sector to an LBA address (in 128byte blocks) ldd xl,y+o_seeksec ; ldi xh,0 ; ldi temp2,0 ; ldd temp,y+o_hdrsize ;add image header size add xl,temp ; adc xh,_0 ; ldd temp,y+o_cpmspt ; ldd _tmp0,y+o_seektrk ; mul temp,_tmp0 ; add xl,r0 ; adc xh,r1 ; ldd _tmp0,y+o_seektrk+1 ; mul temp,_tmp0 ; add xh,r0 ;temp2:xh:xl := sec + trk * SectorsPerTrack adc temp2,r1 ; mov temp3,xl andi temp3,SECMSK ;mask buffer number ; Convert from CP/M LBA blocks to host LBA blocks ldi temp,SECSHF dsk_sh1: lsr temp2 ror xh ror xl dec temp brne dsk_sh1 ;todo: temp2 should be 0 here. ;xh:xl = host block to seek ; sbic flags,readop rjmp dsk_rwoper ;to perform the read ; Write operation cbi flags,rsflag ;rsflag = 0 ldd temp,y+o_wrtype ; cpi temp,WRUAL ;write unallocated? brne dsk_chkuna ;check for unalloc ; write to unallocated, set parameters ldd temp,y+o_secpblk ;next unalloc recs (blocksize/128) cpi temp3,0 ;cpm sector on phys. sector boundary? breq dsk_una1 sbi flags,rsflag ; no, rsflag = 1 subi temp,HOSTBLK ;don't write ldd _tmp0,y+o_hdrsize ; in next bock add temp,_tmp0 ; if there is a header dsk_una1: std y+o_unacnt,temp ldd temp,y+o_seekdsk ;disk to seek std y+o_unadsk,temp ;unadsk = sekdsk std y+o_unalba, xl ;unalba = seeklba (== hostlba) std y+o_unalba+1,xh ; check for write to unallocated sector dsk_chkuna: ldd temp,y+o_unacnt ;any unalloc remain? tst temp breq dsk_alloc ;skip if not ; more unallocated records remain dec temp ;unacnt = unacnt-1 std y+o_unacnt,temp ldd temp,y+o_seekdsk ;same disk? ldd temp2,y+o_unadsk cp temp,temp2 ;seekdsk = unadsk? brne dsk_alloc ;skip if not ; disks are the same ldd _tmp0,y+o_unalba ldd _tmp1,y+o_unalba+1 cp _tmp0,xl ;seeklba = unalba? cpc _tmp1,xh brne dsk_alloc ;skip if not ; block address is the same ; move to next sector for future ref mov temp,temp3 inc temp ;next part andi temp,SECMSK brne dsk_noovf ;skip if no overflow ; overflow to next block sub _tmp0,_255 ;unalba = unalba+1 sbc _tmp1,_255 std y+o_unalba, _tmp0 std y+o_unalba+1,_tmp1 dsk_noovf: rjmp dsk_rwoper ;to perform the write ; not an unallocated record, requires pre-read dsk_alloc: std y+o_unacnt,_0 ;unacnt = 0 sbi flags,rsflag ;rsflag = 1 ; Enter here to perform the read/write dsk_rwoper: .if DISK_DEBUG > 1 printstring ", flags|wtyp " in temp,flags cbr temp,WRTMSK ldd _tmp0,y+o_wrtype or temp,_tmp0 lcall printhex printstring ", buf " mov temp,temp3 lcall printhex .endif push temp3 movw temp,x ldd temp3,y+o_seekdsk rcall dsk_rw_hostbuf pop temp ;get back buffer number (which part of hostbuf) ldiw y,fsys_vars ; copy data to or from buffer ldiw z,hostbuf ldi temp3,128 mul temp,temp3 add zl,r0 ;offset in hostbuf adc zh,r1 ldd xl,y+o_dmaadr ldd xh,y+o_dmaadr+1 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 ldd temp,y+o_wrtype ;write type cpi temp,WRDIR ;to directory? breq dsk_wdir ret ;no further processing ; clear host buffer for directory write dsk_wdir: ldd temp,y+o_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: ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp2:temp block to read (lba) ; temp3 disk # ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_readhost_lba: .if HOSTRW_DEBUG printnewline printstring "Readhost LBA" .endif sbi flags,rsflag ;must read data rcall dsk_rw_hostbuf lds temp,erflag ;returns 0, if ok tst temp ret ; ==================================================================== ; Function: Get physical disk sector in hostbuf. ; ==================================================================== ; Parameters ; -------------------------------------------------------------------- ; Registers : temp2:temp host block to read/write (lba) ; temp3 disk # ; ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_rw_hostbuf: ldiw y,fsys_vars ;xh:xl = host block to seek std y+o_erflag,_0 ;no errors (yet) ; 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? ldd _tmp0,y+o_hostdsk ;same disk? cp temp3,_tmp0 ;seekdsk = hostdsk? brne dsk_nomatch ; same disk, same block? ldd _tmp0,y+o_hostlba cp temp, _tmp0 ldd _tmp0,y+o_hostlba+1 cpc temp2,_tmp0 breq dsk_match dsk_nomatch: ;proper disk, but not correct sector sbis flags,hostwrt ;host written? rjmp dsk_filhst push temp3 push temp2 push temp rcall dsk_writehost ;clear host buff pop temp pop temp2 pop temp3 ; may have to fill the host buffer dsk_filhst: ldiw y,fsys_vars std y+o_hostlba,temp std y+o_hostlba+1,temp2 std y+o_hostdsk,temp3 sbic flags,rsflag ;need to read? rcall dsk_readhost ;yes, if 1 cbi flags,hostwrt ;no pending write dsk_match: 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: .if HOSTRW_DEBUG .if DISK_DEBUG == 0 printnewline printstring "Host write: " .else printstring ", hst WR " .endif .endif rcall dsk_hostparam breq dsk_hstwr_err ldiw z,hostbuf lcall mmcWriteSect tst temp brne dsk_hstwr_err dsk_hstwr_ok: sts erflag,_0 ret dsk_hstwr_err: sts erflag,_255 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: .if HOSTRW_DEBUG .if DISK_DEBUG == 0 printnewline printstring "Host read: " .else printstring ", hst RD " .endif .endif rcall dsk_hostparam breq dsk_hstrd_err ldiw z,hostbuf lcall mmcReadSect tst temp brne dsk_hstrd_err dsk_hstrd_ok: sts erflag,_0 ret dsk_hstrd_err: sts erflag,_255 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 ; hostdsk = host disk #, (partition #) ; hostlba = host block #, relative to partition start ; Read/Write "hostsize" bytes to/from hostbuf ; -------------------------------------------------------------------- ; Description: ; ==================================================================== dsk_hostparam: lds zl,hostdsk .if HOSTRW_DEBUG mov temp,zl subi temp,-('A') lcall uartputc .endif rcall dsk_getpartentry lds xl,hostlba ; get sector to access lds xh,hostlba+1 .if HOSTRW_DEBUG printstring ": lba " push r15 push r14 clr r14 clr r15 movw temp,x lcall print_ultoa pop r14 pop r15 .endif ldd _tmp0,z+PTAB_SIZE ; get disksize ldd _tmp1,z+PTAB_SIZE+1 cp xl,_tmp0 ; check given sector against disksize cpc xh,_tmp1 brcc dsk_hst_param_err ldd temp,z+PTAB_TYPE andi temp,dskType_MASK #if FAT16_SUPPORT ; Is it a FAT16 Diskimage ? cpi temp,dskType_FAT brne dsk_hstpar_nofat rcall fat_lba_to_phys rjmp dsk_hstpar_gotit dsk_hstpar_nofat: #endif #if CPMDSK_SUPPORT ; Is it a CP/M Partition ? cpi temp,dskType_CPM brne dsk_hstpar_nocpm lcall cpm_lba_to_phys rjmp dsk_hstpar_gotit dsk_hstpar_nocpm: #endif ; Disktype not supported rjmp dsk_hst_param_err dsk_hstpar_gotit: .if HOSTRW_DEBUG printstring ", abs " push r15 push r14 push temp2 push temp movw temp,x movw r14,y lcall print_ultoa pop temp pop temp2 pop r14 pop r15 .endif ori temp,255 ret dsk_hst_param_err: .if HOSTRW_DEBUG printstring ", max: " push r15 push r14 push temp2 push temp movw temp,_tmp0 clr r14 clr r15 lcall print_ultoa pop temp pop temp2 pop r14 pop r15 printstring " " .endif clr temp ret ; -------------------------------------------------------------------- ; vim:set ts=8 noet nowrap