1 ; Filesystem functions for the Interaction with BIOS and Disks
3 ; Copyright (C) 2010 Frank Zoll
5 ; This file is part of avrcpm.
7 ; avrcpm is free software: you can redistribute it and/or modify it
8 ; under the terms of the GNU General Public License as published by
9 ; the Free Software Foundation, either version 3 of the License, or
10 ; (at your option) any later version.
12 ; avrcpm is distributed in the hope that it will be useful,
13 ; but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 ; GNU General Public License for more details.
17 ; You should have received a copy of the GNU General Public License
18 ; along with avrcpm. If not, see <http://www.gnu.org/licenses/>.
24 ; ---------------- Defines for the Filesystem Interface -------
26 ;*****************************************************
27 ;* Disk-Manager constants *
28 ;*****************************************************
34 ;*****************************************************
35 ;* CP/M to host disk constants *
36 ;*****************************************************
37 .equ MAXDISKS = 6 ;Max number of Disks (partitions)
38 .equ PARTENTRY_SIZE = 9 ;Size of a Partitiontableentry
39 .equ blksize = 1024 ;CP/M allocation size
40 .equ hostsize = 512 ;host disk sector size
41 ; .equ hostspt = 20 ;host disk sectors/trk
42 .equ hostblk = hostsize/128 ;CP/M sects/host buff
43 ; .equ CPMSPT = hostblk*hostspt ;CP/M sectors/track
45 .equ SECMSK = hostblk-1 ;sector mask
46 .equ SECSHF = log2(hostblk) ;sector shift
48 ;*****************************************************
49 ;* BDOS constants on entry to write *
50 ;*****************************************************
51 .equ WRALL = 0 ;write to allocated
52 .equ WRDIR = 1 ;write to directory
53 .equ WRUAL = 2 ;write to unallocated
54 .equ WRTMSK= 3 ;write type mask
61 ;----------------------------------------------- Start of Data Segment
65 ; The following 3 variables are copied from DRAM.
72 ndisks: .byte 1 ;Number of CP/M disks
74 ; The following 5 variables are accessed from 8080/z80 via the
75 ; virtual port interface. Don't change order.
78 bcbadr: .byte 2 ;adr of BiosControlBlock
79 seekdsk: .byte 1 ;seek disk number
80 seektrk: .byte 2 ;seek track number
81 seeksec: .byte 2 ;seek sector number
82 dmaadr: .byte 2 ;last dma address
84 unacnt: .byte 1 ;unalloc rec cnt
85 unadsk: .byte 1 ;last unalloc disk
86 unatrk: .byte 2 ;last unalloc track
87 unasec: .byte 1 ;last unalloc sector
89 erflag: .byte 1 ;error reporting
90 wrtype: .byte 1 ;write operation type
92 hostbuf: .byte hostsize ;host buffer (from/to SD-card)
93 hostparttbl: .byte PARTENTRY_SIZE*MAXDISKS ;host partition table (type, start sector, sector count)
95 hostdsk: .byte 1 ;host disk number
96 hosttype: .byte 1 ;host disk type (same entry as 1 parition entry)
97 hostlba: .byte 3 ;host sector number (relative to partition start)
100 ; ------------------------------- Start of Code Segment
103 ; ====================================================================
104 ; Function: Virtual Port Interface
105 ; ====================================================================
107 ; --------------------------------------------------------------------
111 ; --------------------------------------------------------------------
113 ; ====================================================================
122 rcall dsk_param_getadr
124 cpi temp3,bcbadr+1-seektrk
128 cpi temp3,bcbadr+1-biospar_base
133 cpi temp3,seekdsk-biospar_base
135 rcall dsk_param_getadr
142 brsh dsk_dchrd ;maybe ramdisk
144 ; Check if selected disk # is less then # of disks.
150 ; No disks yet, need to init
152 rcall mgr_init_partitions ;disk chanched?
168 printstring "Select: "
194 cpi temp,RAMDISKNR+RAMDISKCNT
198 ldi temp,0xff ;error return
216 rcall dbg_print_biosd
221 ;---------------------------------------------------------------------
230 printstring "drvtbl ("
250 ; -------------------------------------------------------------------
258 lds temp2,biosdrvtbl+1
262 lds temp2,biosdirbuf+1
266 lds temp2,biosenddat+1
273 ; -------------------------------------------------------------------
281 ; init bios disk tables.
282 ; leave drive 'A' out for now
291 lds temp2,biosenddat+1
310 ; Test DPBs (avrcpm format)
315 .db 0x03,0x07 ;block shift, bock mask
316 .db 0x00,0xF2 ;extent mask, low(disk size -1),
317 .db 0x00,0x3F ;high(disk size -1), low(dir max)
318 .db 0x00,0xC0 ;high(dir max), alloc0
319 .db 0x00,0x10 ;alloc1, low(chk size)
320 .db 0x00,0x02 ;high(chk size), low(offset)
321 .db 0x00,0x00 ;high(offset), fill
324 .db 0x03,0x07 ;block shift, bock mask
325 .db 0x00,0xF2 ;extent mask, low(disk size -1),
326 .db 0x00,0x3F ;high(disk size -1), low(dir max)
327 .db 0x00,0xC0 ;high(dir max), alloc0
328 .db 0x00,0x10 ;alloc1, low(chk size)
329 .db 0x00,0x02 ;high(chk size), low(offset)
330 .db 0x00,0x00 ;high(offset), fill
333 .db 0x03,0x07 ;block shift, bock mask
334 .db 0x00,0xF2 ;extent mask, low(disk size -1),
335 .db 0x00,0x3F ;high(disk size -1), low(dir max)
336 .db 0x00,0xC0 ;high(dir max), alloc0
337 .db 0x00,0x10 ;alloc1, low(chk size)
338 .db 0x00,0x02 ;high(chk size), low(offset)
339 .db 0x00,0x00 ;high(offset), fill
342 .db 0x03,0x07 ;block shift, bock mask
343 .db 0x00,0xF2 ;extent mask, low(disk size -1),
344 .db 0x00,0x3F ;high(disk size -1), low(dir max)
345 .db 0x00,0xC0 ;high(dir max), alloc0
346 .db 0x00,0x10 ;alloc1, low(chk size)
347 .db 0x00,0x02 ;high(chk size), low(offset)
348 .db 0x00,0x00 ;high(offset), fill
352 .db 0x04,0x0F ;block shift, bock mask
353 .db 0x00,0xFB ;extent mask, low(disk size -1),
354 .db 0x01,0xBF ;high(disk size -1), low(dir max)
355 .db 0x00,0xE0 ;high(dir max), alloc0
356 .db 0x00,0x30 ;alloc1, low(chk size)
357 .db 0x00,0x02 ;high(chk size), low(offset)
358 .db 0x00,0x00 ;high(offset), fill
361 .db 0x05,0x1F ;block shift, bock mask
362 .db 0x01,0xFD ;extent mask, low(disk size -1),
363 .db 0x07,0xFF ;high(disk size -1), low(dir max)
364 .db 0x01,0xF0 ;high(dir max), alloc0
365 .db 0x00,0x80 ;alloc1, low(chk size)
366 .db 0x00,0x02 ;high(chk size), low(offset)
367 .db 0x00,0x00 ;high(offset), fill
385 cpi yl,low(tmpdpb + 15)
394 ; for now, only entries 1 - 3 are cleared.
396 ; ====================================================================
397 ; Function: Clear drive table
398 ; ====================================================================
400 ; --------------------------------------------------------------------
404 ; --------------------------------------------------------------------
406 ; ====================================================================
408 ; For now, only entries 1 - 3 are cleared.
422 lds temp2,biosenddat+1
428 ; ----------------------------------------------------------------------
429 ; Init CP/M data structures
435 mov temp3,temp ;save disk #
445 ; -----------------------------------------------------------------
446 ; DPH: | XLT | | | |DIRBUF | DPB | CSV | ALV |
447 ; -----------------------------------------------------------------
448 ;(offset) 0 2 4 6 8 10 12 14
460 rcall dram_writew_pp ;XLT
463 lds temp2,biosdirbuf+1
464 rcall dram_writew_pp ;DIRBUF
467 ; -------------------------------------------------------------
468 ; DPB: | SPT |BSH|BLM|EXM| DSM | DRM |AL0|AL1| CKS | OFF |
469 ; -------------------------------------------------------------
482 cpi zl,low(tmpdpb + 15)
488 rcall dram_writew_pp ;DPB
490 ; get mem for dir check vector
492 lds temp,tmpdpb+11 ;cks
493 lds temp2,tmpdpb+11+1
500 rcall dram_writew_pp ;CSV
502 ; get mem for alloc vector
504 lds temp,tmpdpb+5 ;dsm
513 ror temp ;(dsm+1+7)/8
516 rcall dram_writew_pp ;ALV
518 ; success, insert DPH into drvtbl
540 ; ====================================================================
541 ; Function: Get a Pointer to a Partitiontable entry
542 ; ====================================================================
544 ; --------------------------------------------------------------------
545 ; Registers : [w] z Pointer to the Partitionentry
546 ; [r] xl Number of Diskentry to Read
549 ; --------------------------------------------------------------------
551 ; ====================================================================
554 ldi zl,PARTENTRY_SIZE
562 ; ====================================================================
563 ; Function: Does a Disk interaction
564 ; ====================================================================
566 ; --------------------------------------------------------------------
568 ; Variables : [r] seeksec Sector to read
569 ; [r] seektrk Track to read
570 ; --------------------------------------------------------------------
572 ; ====================================================================
584 printstring "Disk read: "
588 printstring "Disk write: "
593 printstring ": track "
597 printstring ", sector "
600 printstring ", dma-addr "
608 printstring " wrtype "
614 ;See what has to be done.
624 printstring "DISK I/O: Invalid Function code: "
629 sts ndisks,_0 ;no active partitions
631 cbi flags,hostact ;host buffer inactive
632 sts unacnt,_0 ;clear unalloc count
636 sbis flags,hostwrt ;check for pending write
637 cbi flags,hostact ;clear host active flag
642 ; ====================================================================
643 ; Function: Does a Disk read operation
644 ; ====================================================================
646 ; --------------------------------------------------------------------
647 ; Registers : in: temp
648 ; Variables : [r] seekdsk Number of Disk to Read
649 ; [r] seeksec Sector to read
650 ; [r] seektrk Track to read
651 ; --------------------------------------------------------------------
653 ; ====================================================================
656 sbi flags,readop ; Set read operation flag
665 rcall dsk_getpartentry ; Get Paritiontableentry
666 ld temp,z ; Get Partitiontype
669 cpi temp,dskType_None
673 ; It must be a FAT16-Imagefile or CP/M Partition.
675 sbi flags,rsflag ;must read data
676 ldi temp,WRUAL ;write type
677 sts wrtype,temp ;treat as unalloc
678 rjmp dsk_rwoper ;to perform the read
683 ; ====================================================================
684 ; Function: Does a Disk write operation
685 ; ====================================================================
687 ; --------------------------------------------------------------------
688 ; Registers : in: temp Write type
689 ; Variables : [r] seekdsk Number of Disk to Read
690 ; [r] seeksec Sector to read
691 ; [r] seektrk Track to read
692 ; --------------------------------------------------------------------
694 ; ====================================================================
696 ;write the selected sector
698 cbi flags,readop ; not a read operation
707 rcall dsk_getpartentry ; Get Paritiontableentry
708 ld temp2,z ; Get Partitiontype
711 cpi temp2,dskType_None
715 ; It must be a FAT16-Imagefile or CP/M Partition.
717 cbi flags,readop ;not a read operation
720 sts wrtype,temp ;save write type
722 cpi temp,WRUAL ;write unallocated?
723 brne dsk_chkuna ;check for unalloc
725 ; write to unallocated, set parameters
726 ldi temp,blksize/128 ;next unalloc recs
728 lds temp,seekdsk ;disk to seek
729 sts unadsk,temp ;unadsk = sekdsk
731 sts unatrk,temp ;unatrk = sectrk
733 sts unatrk+1,temp ;unatrk = sectrk
735 sts unasec,temp ;unasec = seksec
738 ;check for write to unallocated sector
739 lds temp,unacnt ;any unalloc remain?
741 breq dsk_alloc ;skip if not
743 ; more unallocated records remain
744 dec temp ;unacnt = unacnt-1
746 lds temp,seekdsk ;same disk?
748 cp temp,temp2 ;seekdsk = unadsk?
749 brne dsk_alloc ;skip if not
756 cp temp,temp3 ;seektrk = unatrk?
758 brne dsk_alloc ;skip if not
760 ; tracks are the same
761 lds temp,seeksec ;same sector?
763 cp temp,temp2 ;seeksec = unasec?
764 brne dsk_alloc ;skip if not
766 ; match, move to next sector for future ref
767 inc temp2 ;unasec = unasec+1
769 cpi temp2,CPMSPT ;end of track? (count CP/M sectors)
770 brlo dsk_noovf ;skip if no overflow
772 ; overflow to next track
773 sts unasec,_0 ;unasec = 0
776 subi temp, low(-1) ;unatrk = unatrk+1
782 cbi flags,rsflag ;rsflag = 0
783 rjmp dsk_rwoper ;to perform the write
786 ;not an unallocated record, requires pre-read
787 sts unacnt,_0 ;unacnt = 0
788 sbi flags,rsflag ;rsflag = 1
794 ; ====================================================================
795 ; Function: Does a Disk read/write operation
796 ; ====================================================================
798 ; --------------------------------------------------------------------
800 ; Variables : [r] seekdsk Number of Disk to Read
801 ; [r] seeksec Sector to read
802 ; [r] seektrk Track to read
803 ; --------------------------------------------------------------------
805 ; ====================================================================
807 ;enter here to perform the read/write
809 printstring ", flags: "
813 sts erflag,_0 ;no errors (yet)
815 ;Convert track/sector to an LBA address (in 128byte blocks)
821 lds temp4,seektrk+1 ;
827 add xh,r0 ;yl:xh:xl := sec + trk * SectorsPerTrack
831 andi temp,SECMSK ;mask buffer number
832 push temp ;save for later
834 ;Convert from CP/M LBA blocks to host LBA blocks
842 ;yl:xh:xl = host block to seek
843 ; active host sector?
844 in _tmp0,flags ;host active flag
845 sbi flags,hostact ;always becomes 1
846 sbrs _tmp0,hostact ;was it already?
847 rjmp dsk_filhst ;fill host if not
849 ; host buffer active, same as seek buffer?
851 lds temp2,hostdsk ;same disk?
852 cp temp,temp2 ;seekdsk = hostdsk?
855 ; same disk, same block?
865 ;proper disk, but not correct sector
866 sbis flags,hostwrt ;host written?
871 rcall dsk_writehost ;clear host buff
877 ;may have to fill the host buffer
884 sbic flags,rsflag ;need to read?
885 rcall dsk_readhost ;yes, if 1
886 cbi flags,hostwrt ;no pending write
890 ;copy data to or from buffer
893 pop temp2 ;get buffer number (which part of hostbuf)
895 add zl,r0 ;offset in hostbuf
901 printstring "; host buf adr: "
909 ldi temp3,128 ;length of move
910 sbic flags,readop ;which way?
911 rjmp dsk_rmove ;skip if read
913 ; mark write operation
914 sbi flags,hostwrt ;hostwrt = 1
930 ; data has been moved to/from host buffer
931 lds temp,wrtype ;write type
932 cpi temp,WRDIR ;to directory?
934 ret ;no further processing
936 ; clear host buffer for directory write
942 rcall dsk_writehost ;clear host buff
943 cbi flags,hostwrt ;buffer written
946 ; ====================================================================
947 ; Function: Does a Disk write operation
948 ; ====================================================================
950 ; --------------------------------------------------------------------
952 ; Variables : [r] seekdsk Number of Disk to Read
953 ; [r] seeksec Sector to read
954 ; [r] seektrk Track to read
955 ; --------------------------------------------------------------------
957 ; ====================================================================
960 rcall dsk_getpartentry
964 ; Is it a FAT16 Diskimage ?
970 ; Is it a CP/M Partition ?
974 ; Disktype not supported -> Return
977 ; ====================================================================
978 ; Function: Does a Disk read operation
979 ; ====================================================================
981 ; --------------------------------------------------------------------
983 ; Variables : [r] seekdsk Number of Disk to Read
984 ; [r] seeksec Sector to read
985 ; [r] seektrk Track to read
986 ; --------------------------------------------------------------------
988 ; ====================================================================
991 rcall dsk_getpartentry
995 ; Is it a FAT16 Diskimage ?
1001 ; Is it a CP/M Partition ?
1002 cpi temp,dskType_CPM
1005 ; Disktype not supported -> Return