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/>.
25 ; ---------------- Defines for the Filesystem Interface -------
27 ;*****************************************************
28 ;* Disk-Manager constants *
29 ;*****************************************************
33 ; .equ dskType_RAM = 3
35 ;*****************************************************
36 ;* CP/M to host disk constants *
37 ;*****************************************************
38 .equ MAXDISKS = 8 ;Max number of Disks (partitions)
39 .equ PARTENTRY_SIZE = 9 ;Size of a Partitiontableentry
40 .equ blksize = 1024 ;CP/M allocation size
41 .equ hostsize = 512 ;host disk sector size
42 ; .equ hostspt = 20 ;host disk sectors/trk
43 .equ hostblk = hostsize/128 ;CP/M sects/host buff
44 ; .equ CPMSPT = hostblk*hostspt ;CP/M sectors/track
46 .equ SECMSK = hostblk-1 ;sector mask
47 .equ SECSHF = log2(hostblk) ;sector shift
49 ;*****************************************************
50 ;* BDOS constants on entry to write *
51 ;*****************************************************
52 .equ WRALL = 0 ;write to allocated
53 .equ WRDIR = 1 ;write to directory
54 .equ WRUAL = 2 ;write to unallocated
55 .equ WRTMSK= 3 ;write type mask
62 ;----------------------------------------------- Start of Data Segment
66 ; The following 3 variables are copied from DRAM.
73 ndisks: .byte 1 ;Number of CP/M disks
75 ; The following 5 variables are accessed from 8080/z80 via the
76 ; virtual port interface. Don't change order.
79 bcbadr: .byte 2 ;adr of BiosControlBlock
80 seekdsk: .byte 1 ;seek disk number
81 seektrk: .byte 2 ;seek track number
82 seeksec: .byte 2 ;seek sector number
83 dmaadr: .byte 2 ;last dma address
85 unacnt: .byte 1 ;unalloc rec cnt
86 unadsk: .byte 1 ;last unalloc disk
87 unatrk: .byte 2 ;last unalloc track
88 unasec: .byte 1 ;last unalloc sector
90 erflag: .byte 1 ;error reporting
91 wrtype: .byte 1 ;write operation type
93 hostbuf: .byte hostsize ;host buffer (from/to SD-card)
94 hostparttbl: .byte PARTENTRY_SIZE*MAXDISKS ;host partition table (type, start sector, sector count)
96 hostdsk: .byte 1 ;host disk number
97 hosttype: .byte 1 ;host disk type (same entry as 1 parition entry)
98 hostlba: .byte 3 ;host sector number (relative to partition start)
101 ; ------------------------------- Start of Code Segment
104 ;---------------------------------------------------------------------
115 printstring "drvtbl ("
142 lds temp2,biosdrvtbl+1
146 lds temp2,biosdirbuf+1
150 lds temp2,biosenddat+1
156 ; ====================================================================
157 ; Function: Get a Pointer to a Partitiontable entry
158 ; ====================================================================
160 ; --------------------------------------------------------------------
161 ; Registers : [w] z Pointer to the Partitionentry
162 ; [r] xl Number of Diskentry to Read
165 ; --------------------------------------------------------------------
167 ; ====================================================================
170 ldi zl,PARTENTRY_SIZE
177 ; ====================================================================
178 ; Function: Virtual Port Interface
179 ; ====================================================================
181 ; --------------------------------------------------------------------
185 ; --------------------------------------------------------------------
187 ; ====================================================================
196 rcall dsk_param_getadr
198 cpi temp3,bcbadr+1-seektrk
202 cpi temp3,bcbadr+1-biospar_base
207 cpi temp3,seekdsk-biospar_base
209 rcall dsk_param_getadr
224 ; rcall dbg_print_biosd
230 ; ====================================================================
231 ; Function: Check if disk exists
232 ; ====================================================================
234 ; --------------------------------------------------------------------
237 ; return 0, if selected disk not exist.
238 ; return !0, if disk exist
239 ; --------------------------------------------------------------------
241 ; ====================================================================
247 printstring "DiskCheck: "
251 brsh dsk_dchrd ;maybe ramdisk
253 ; Check if selected disk # is less then # of disks.
259 ; No disks yet, need to init
261 rcall mgr_init_partitions ;disk chanched?
278 printstring "Select: "
286 rcall dram_readw_pp ;get drive table entry
288 or temp,temp2 ;if !0, drive is allready initialized
310 ldi temp,0 ;error return
317 cpi temp,RAMDISKNR+RAMDISKCNT
320 ldi temp,0xff ;return ok
324 ldi temp,0 ;error return
328 ; ====================================================================
329 ; Function: Return status of last disk i/o function
330 ; ====================================================================
332 ; --------------------------------------------------------------------
335 ; --------------------------------------------------------------------
337 ; ====================================================================
343 ; -------------------------------------------------------------------
351 ; Test DPBs (avrcpm format)
356 .db 0x03,0x07 ;block shift, bock mask
357 .db 0x00,0xF2 ;extent mask, low(disk size -1),
358 .db 0x00,0x3F ;high(disk size -1), low(dir max)
359 .db 0x00,0xC0 ;high(dir max), alloc0
360 .db 0x00,0x10 ;alloc1, low(chk size)
361 .db 0x00,0x02 ;high(chk size), low(offset)
362 .db 0x00,0x00 ;high(offset), fill
365 .db 0x03,0x07 ;block shift, bock mask
366 .db 0x00,0xF2 ;extent mask, low(disk size -1),
367 .db 0x00,0x3F ;high(disk size -1), low(dir max)
368 .db 0x00,0xC0 ;high(dir max), alloc0
369 .db 0x00,0x10 ;alloc1, low(chk size)
370 .db 0x00,0x02 ;high(chk size), low(offset)
371 .db 0x00,0x00 ;high(offset), fill
374 .db 0x03,0x07 ;block shift, bock mask
375 .db 0x00,0xF2 ;extent mask, low(disk size -1),
376 .db 0x00,0x3F ;high(disk size -1), low(dir max)
377 .db 0x00,0xC0 ;high(dir max), alloc0
378 .db 0x00,0x10 ;alloc1, low(chk size)
379 .db 0x00,0x02 ;high(chk size), low(offset)
380 .db 0x00,0x00 ;high(offset), fill
383 .db 0x03,0x07 ;block shift, bock mask
384 .db 0x00,0xF2 ;extent mask, low(disk size -1),
385 .db 0x00,0x3F ;high(disk size -1), low(dir max)
386 .db 0x00,0xC0 ;high(dir max), alloc0
387 .db 0x00,0x10 ;alloc1, low(chk size)
388 .db 0x00,0x02 ;high(chk size), low(offset)
389 .db 0x00,0x00 ;high(offset), fill
392 .db 0x03,0x07 ;block shift, bock mask
393 .db 0x00,0xF2 ;extent mask, low(disk size -1),
394 .db 0x00,0x3F ;high(disk size -1), low(dir max)
395 .db 0x00,0xC0 ;high(dir max), alloc0
396 .db 0x00,0x10 ;alloc1, low(chk size)
397 .db 0x00,0x02 ;high(chk size), low(offset)
398 .db 0x00,0x00 ;high(offset), fill
401 .db 0x03,0x07 ;block shift, bock mask
402 .db 0x00,0xF2 ;extent mask, low(disk size -1),
403 .db 0x00,0x3F ;high(disk size -1), low(dir max)
404 .db 0x00,0xC0 ;high(dir max), alloc0
405 .db 0x00,0x10 ;alloc1, low(chk size)
406 .db 0x00,0x02 ;high(chk size), low(offset)
407 .db 0x00,0x00 ;high(offset), fill
410 .db 0x03,0x07 ;block shift, bock mask
411 .db 0x00,0xF2 ;extent mask, low(disk size -1),
412 .db 0x00,0x3F ;high(disk size -1), low(dir max)
413 .db 0x00,0xC0 ;high(dir max), alloc0
414 .db 0x00,0x10 ;alloc1, low(chk size)
415 .db 0x00,0x02 ;high(chk size), low(offset)
416 .db 0x00,0x00 ;high(offset), fill
419 .db 0x03,0x07 ;block shift, bock mask
420 .db 0x00,0xF2 ;extent mask, low(disk size -1),
421 .db 0x00,0x3F ;high(disk size -1), low(dir max)
422 .db 0x00,0xC0 ;high(dir max), alloc0
423 .db 0x00,0x10 ;alloc1, low(chk size)
424 .db 0x00,0x02 ;high(chk size), low(offset)
425 .db 0x00,0x00 ;high(offset), fill
429 .db 0x04,0x0F ;block shift, bock mask
430 .db 0x00,0xFB ;extent mask, low(disk size -1),
431 .db 0x01,0xBF ;high(disk size -1), low(dir max)
432 .db 0x00,0xE0 ;high(dir max), alloc0
433 .db 0x00,0x30 ;alloc1, low(chk size)
434 .db 0x00,0x02 ;high(chk size), low(offset)
435 .db 0x00,0x00 ;high(offset), fill
438 .db 0x05,0x1F ;block shift, bock mask
439 .db 0x01,0xFD ;extent mask, low(disk size -1),
440 .db 0x07,0xFF ;high(disk size -1), low(dir max)
441 .db 0x01,0xF0 ;high(dir max), alloc0
442 .db 0x00,0x80 ;alloc1, low(chk size)
443 .db 0x00,0x02 ;high(chk size), low(offset)
444 .db 0x00,0x00 ;high(offset), fill
462 cpi yl,low(tmpdpb + 15)
470 ; ====================================================================
471 ; Function: Clear drive table
472 ; ====================================================================
474 ; --------------------------------------------------------------------
478 ; --------------------------------------------------------------------
480 ; ====================================================================
482 ; For now, only entries 1 - 7 are cleared.
496 lds temp2,biosenddat+1
502 ; ----------------------------------------------------------------------
503 ; Init CP/M data structures
511 mov temp3,temp ;save disk #
521 ; -----------------------------------------------------------------
522 ; DPH: | XLT | | | |DIRBUF | DPB | CSV | ALV |
523 ; -----------------------------------------------------------------
524 ;(offset) 0 2 4 6 8 10 12 14
536 rcall dram_writew_pp ;XLT
539 lds temp2,biosdirbuf+1
540 rcall dram_writew_pp ;DIRBUF
543 ; -------------------------------------------------------------
544 ; DPB: | SPT |BSH|BLM|EXM| DSM | DRM |AL0|AL1| CKS | OFF |
545 ; -------------------------------------------------------------
558 cpi zl,low(tmpdpb + 15)
564 rcall dram_writew_pp ;DPB
566 ; get mem for dir check vector
568 lds temp,tmpdpb+11 ;cks
569 lds temp2,tmpdpb+11+1
576 rcall dram_writew_pp ;CSV
578 ; get mem for alloc vector
580 lds temp,tmpdpb+5 ;dsm
589 ror temp ;(dsm+1+7)/8
592 rcall dram_writew_pp ;ALV
594 ; success, insert DPH into drvtbl
603 ori temp,0xff ;return ok
612 eor temp,temp ;return 0 (+ Z-flag)
616 ; ====================================================================
617 ; Function: Does a Disk interaction
618 ; ====================================================================
620 ; --------------------------------------------------------------------
622 ; Variables : [r] seeksec Sector to read
623 ; [r] seektrk Track to read
624 ; --------------------------------------------------------------------
626 ; ====================================================================
638 printstring "Disk read: "
642 printstring "Disk write: "
647 printstring ": track "
651 printstring ", sector "
654 printstring ", dma-addr "
662 printstring " wrtype "
668 ;See what has to be done.
678 printstring "DISK I/O: Invalid Function code: "
683 sts ndisks,_0 ;no active partitions
685 cbi flags,hostact ;host buffer inactive
686 sts unacnt,_0 ;clear unalloc count
690 sbis flags,hostwrt ;check for pending write
691 cbi flags,hostact ;clear host active flag
696 ; ====================================================================
697 ; Function: Does a Disk read operation
698 ; ====================================================================
700 ; --------------------------------------------------------------------
701 ; Registers : in: temp
702 ; Variables : [r] seekdsk Number of Disk to Read
703 ; [r] seeksec Sector to read
704 ; [r] seektrk Track to read
705 ; --------------------------------------------------------------------
707 ; ====================================================================
710 sbi flags,readop ; Set read operation flag
719 rcall dsk_getpartentry ; Get Paritiontableentry
720 ld temp,z ; Get Partitiontype
723 cpi temp,dskType_None
726 ; It must be a FAT16-Imagefile or CP/M Partition.
728 sbi flags,rsflag ;must read data
729 ldi temp,WRUAL ;write type
730 sts wrtype,temp ;treat as unalloc
731 rjmp dsk_rwoper ;to perform the read
736 ; ====================================================================
737 ; Function: Does a Disk write operation
738 ; ====================================================================
740 ; --------------------------------------------------------------------
741 ; Registers : in: temp Write type
742 ; Variables : [r] seekdsk Number of Disk to Read
743 ; [r] seeksec Sector to read
744 ; [r] seektrk Track to read
745 ; --------------------------------------------------------------------
747 ; ====================================================================
749 ;write the selected sector
751 cbi flags,readop ; not a read operation
759 rcall dsk_getpartentry ; Get Paritiontableentry
760 ld temp2,z ; Get Partitiontype
763 cpi temp2,dskType_None
768 ; It must be a FAT16-Imagefile or CP/M Partition.
770 cbi flags,readop ;not a read operation
773 sts wrtype,temp ;save write type
775 cpi temp,WRUAL ;write unallocated?
776 brne dsk_chkuna ;check for unalloc
778 ; write to unallocated, set parameters
779 ldi temp,blksize/128 ;next unalloc recs
781 lds temp,seekdsk ;disk to seek
782 sts unadsk,temp ;unadsk = sekdsk
784 sts unatrk,temp ;unatrk = sectrk
786 sts unatrk+1,temp ;unatrk = sectrk
788 sts unasec,temp ;unasec = seksec
791 ;check for write to unallocated sector
792 lds temp,unacnt ;any unalloc remain?
794 breq dsk_alloc ;skip if not
796 ; more unallocated records remain
797 dec temp ;unacnt = unacnt-1
799 lds temp,seekdsk ;same disk?
801 cp temp,temp2 ;seekdsk = unadsk?
802 brne dsk_alloc ;skip if not
809 cp temp,temp3 ;seektrk = unatrk?
811 brne dsk_alloc ;skip if not
813 ; tracks are the same
814 lds temp,seeksec ;same sector?
816 cp temp,temp2 ;seeksec = unasec?
817 brne dsk_alloc ;skip if not
819 ; match, move to next sector for future ref
820 inc temp2 ;unasec = unasec+1
822 cpi temp2,CPMSPT ;end of track? (count CP/M sectors)
823 brlo dsk_noovf ;skip if no overflow
825 ; overflow to next track
826 sts unasec,_0 ;unasec = 0
829 subi temp, low(-1) ;unatrk = unatrk+1
835 cbi flags,rsflag ;rsflag = 0
836 rjmp dsk_rwoper ;to perform the write
839 ;not an unallocated record, requires pre-read
840 sts unacnt,_0 ;unacnt = 0
841 sbi flags,rsflag ;rsflag = 1
847 ; ====================================================================
848 ; Function: Does a Disk read/write operation
849 ; ====================================================================
851 ; --------------------------------------------------------------------
853 ; Variables : [r] seekdsk Number of Disk to Read
854 ; [r] seeksec Sector to read
855 ; [r] seektrk Track to read
856 ; --------------------------------------------------------------------
858 ; ====================================================================
860 ;enter here to perform the read/write
862 printstring ", flags: "
866 sts erflag,_0 ;no errors (yet)
868 ;Convert track/sector to an LBA address (in 128byte blocks)
874 lds temp4,seektrk+1 ;
880 add xh,r0 ;yl:xh:xl := sec + trk * SectorsPerTrack
884 andi temp,SECMSK ;mask buffer number
885 push temp ;save for later
887 ;Convert from CP/M LBA blocks to host LBA blocks
895 ;yl:xh:xl = host block to seek
896 ; active host sector?
897 in _tmp0,flags ;host active flag
898 sbi flags,hostact ;always becomes 1
899 sbrs _tmp0,hostact ;was it already?
900 rjmp dsk_filhst ;fill host if not
902 ; host buffer active, same as seek buffer?
904 lds temp2,hostdsk ;same disk?
905 cp temp,temp2 ;seekdsk = hostdsk?
908 ; same disk, same block?
918 ;proper disk, but not correct sector
919 sbis flags,hostwrt ;host written?
924 rcall dsk_writehost ;clear host buff
930 ;may have to fill the host buffer
937 sbic flags,rsflag ;need to read?
938 rcall dsk_readhost ;yes, if 1
939 cbi flags,hostwrt ;no pending write
943 ;copy data to or from buffer
946 pop temp2 ;get buffer number (which part of hostbuf)
948 add zl,r0 ;offset in hostbuf
954 printstring "; host buf adr: "
962 ldi temp3,128 ;length of move
963 sbic flags,readop ;which way?
964 rjmp dsk_rmove ;skip if read
966 ; mark write operation
967 sbi flags,hostwrt ;hostwrt = 1
983 ; data has been moved to/from host buffer
984 lds temp,wrtype ;write type
985 cpi temp,WRDIR ;to directory?
987 ret ;no further processing
989 ; clear host buffer for directory write
995 rcall dsk_writehost ;clear host buff
996 cbi flags,hostwrt ;buffer written
999 ; ====================================================================
1000 ; Function: Does a Disk write operation
1001 ; ====================================================================
1003 ; --------------------------------------------------------------------
1005 ; Variables : [r] seekdsk Number of Disk to Read
1006 ; [r] seeksec Sector to read
1007 ; [r] seektrk Track to read
1008 ; --------------------------------------------------------------------
1010 ; ====================================================================
1013 rcall dsk_getpartentry
1017 ; Is it a FAT16 Diskimage ?
1018 cpi temp,dskType_FAT
1023 ; Is it a CP/M Partition ?
1024 cpi temp,dskType_CPM
1027 ; Disktype not supported -> Return
1030 ; ====================================================================
1031 ; Function: Does a Disk read operation
1032 ; ====================================================================
1034 ; --------------------------------------------------------------------
1036 ; Variables : [r] seekdsk Number of Disk to Read
1037 ; [r] seeksec Sector to read
1038 ; [r] seektrk Track to read
1039 ; --------------------------------------------------------------------
1041 ; ====================================================================
1044 rcall dsk_getpartentry
1048 ; Is it a FAT16 Diskimage ?
1049 cpi temp,dskType_FAT
1054 ; Is it a CP/M Partition ?
1055 cpi temp,dskType_CPM
1058 ; Disktype not supported -> Return