.include "dram-4bit.asm"
#endif
.include "remainders.asm"
+
+; >>>-------------------------------------- Virtual Devices
+ .include "virt_ports.asm" ; Virtual Ports for BIOS
+; <<<-------------------------------------- Virtual Devices
+
+; >>>-------------------------------------- File System Management
+ .include "dsk_fsys.asm" ; Basic Filesystem definitions
+ .include "dsk_cpm.asm" ; CPM- Disk Interaktion
+ .include "dsk_ram.asm" ; RAM- Disk Interaktion
+ .include "dsk_fat16.asm" ; FAT16-DISK Interaktion
+ .include "dsk_mgr.asm" ; Disk- Manager
+; <<<-------------------------------------- File System Management
; .include "z80int.asm" ;Old 8080 interpreter.
; .include "8080int.asm" ;New 8080 interpreter.
; .include "8080int-t3.asm"
#define BAUD 38400 /* console baud rate */
#endif
-#define PARTID 0x52 /* Partition table id */
- /* http://www.win.tue.nl/~aeb/partitions/partition_types-1.html */
#define K 1024
#define M 1204*K
--- /dev/null
+; Various functions for the Interaction with the FAT16 Filesystem
+;
+; 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 <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;\r
+\r
+; ===========================================================================\r
+; Prelimitary !\r
+; °°°°°°°°°°°°°\r
+; Size of a Sector is fixed to 512 Bytes by Base - MMC Driver implementation\r
+; The Functions below therefore assume a fixed Size of 512 Bytes per Sector.\r
+; ===========================================================================\r
+\r
+#ifndef FAT16_SUPPORT\r
+ #define FAT16_SUPPORT 1\r
+ #define FAT16_DEBUG 2\r
+#endif\r
+\r
+#if FAT16_SUPPORT\r
+\r
+\r
+;-------------------------------- Defines for FAT16 Structures
+#define PARTID_FAT16 0x0E\r
+\r
+;#define FAT16_BSO_SECSIZE 0x0b ; BootSectorOffset to Sectorsize Word\r
+#define FAT16_BSO_CLUSTSZ 0x0d ; BootSectorOffset to Clustersize Byte\r
+#define FAT16_BSO_RESSECT 0x0e ; BootSectorOffset to Number of Reserved Sectors\r
+#define FAT16_BSO_VOLPTR 0x1c ; BootSectorOffset to First VolumeSector\r
+#define FAT16_BSO_SECPERFAT 0x16 ; BootSectorOffset to Number of Sectors per Fat\r
+#define FAT16_BSO_NUMFATCP 0x10 ; BootSectorOffset to Ammount of FAT Copys\r
+#define FAT16_BSO_NUMDIRENT 0x11 ; BootSectorOffset to Max. Root Dir. Entrys\r
+\r
+;-------------------------------- Start of Data Segment
+
+ .dseg\r
+\r
+fat_partfound: .byte 1 ; (0= no fat partition found 1=found partition)
+fat_parttbl: .byte 8 ; first fat16 partition entry (start sector, sector count)
+;fat_sectorsize: .byte 2 ; size of sector in bytes\r
+fat_clustersize: .byte 1 ; sectors per cluster\r
+fat_ressectors: .byte 2 ; number of reserved sectors\r
+fat_secperfat: .byte 2 ; number of sectors per fat\r
+fat_numfatcp: .byte 1 ; Number of FAT Copies\r
+fat_numdirentrys:.byte 2 ; Max. ammount of Directory Entrys within Rootdirektory\r
+fat_ptr2fat: .byte 4 ; pointer to the first fat sector\r
+fat_ptr2dir: .byte 4 ; pointer to the first root directory sector\r
+fat_ptr2dat: .byte 4 ; pointer to the first data sector\r
+\r
+; ------------------------------- Start of Code Segment
+ .cseg\r
+\r
+; ====================================================================\r
+; Function: Does a Disk read/write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+fat_init_partitiontable:\r
+\r
+ sts fat_partfound,_0\r
+\r
+ ldiw y,fat_parttbl\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ st y+,_0\r
+ ret\r
+\r
+; ====================================================================\r
+; Function: Add's a FAT16 Partition for later Scanning
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : \r
+; Variables : \r
+; --------------------------------------------------------------------\r
+; Description:\r
+; This funktion sets the internal Variables to set Start and Size\r
+; of a given FAT16 Paritition. This Information will be used for a\r
+; later scanning of the Partition. See Function "fat_scan_partition"\r
+; for more information. \r
+; ====================================================================\r
+fat_add_partition:\r
+ \r
+.if FAT16_DEBUG > 0
+ printstring "fat16 part found",0\r
+ printnewline\r
+.endif\r
+\r
+\r
+; save variables on stack\r
+ push yl\r
+ push yh\r
+\r
+; set fat16 partition found flag\r
+ ldi yl,1\r
+ sts fat_partfound,yl\r
+\r
+; save data from first fat16 partition\r
+ ldiw y,fat_parttbl
+
+ ldd temp,z+PART_START
+ st y+,temp
+ ldd temp,z+PART_START+1
+ st y+,temp
+ ldd temp,z+PART_START+2
+ st y+,temp
+ ldd temp,z+PART_START+3
+ st y+,temp
+
+ ldd temp,z+PART_SIZE
+ st y+,temp
+ ldd temp,z+PART_SIZE+1
+ st y+,temp
+ ldd temp,z+PART_SIZE+2
+ st y+,temp
+ ldd temp,z+PART_SIZE+3
+ st y+,temp\r
+\r
+\r
+; reload variables from stack\r
+ pop yh\r
+ pop yl\r
+
+ ret
+\r
+; --------------------------------------------------------------------------- \r
+; Read and Scann a FAT16 Partition for Imagedatefiles
+; --------------------------------------------------------------------------- \r
+; This Routine reads the Bootblock and scanns it for a Diskimage\r
+; Input Registers : none\r
+; Output Registers : none\r
+; Changes Variables: none\r
+; --------------------------------------------------------------------------- \r
+\r
+\r
+fat_scan_partition:\r
+\r
+.if FAT16_DEBUG > 0
+ printstring "fat16 scanning",0\r
+ printnewline\r
+.endif\r
+\r
+; Check if a FAT16 Partition was realy found\r
+ lds yl,fat_partfound\r
+ cpi yl,1 \r
+ brne fat_scan_error \r
+\r
+\r
+.if FAT16_DEBUG > 0
+ printstring "free entrys in ptable ?",0\r
+ printnewline\r
+.endif\r
+\r
+; Check for free Entrys in Partition table\r
+ lds yl,ndisks\r
+ cpi yl,MAXDISKS\r
+ breq fat_scan_error\r
+\r
+.if FAT16_DEBUG > 0
+ printstring "read fat bootblock.",0\r
+ printnewline\r
+.endif\r
+\r
+; Scan partition start\r
+ ldiw z,fat_parttbl
+ ldd xl,z+0
+ ldd xh,z+1
+ ldd yl,z+2
+ ldd yh,z+3\r
+\r
+; Load first sector from Partition
+ rcall mmcReadSect
+ tst temp
+ breq fat_bootblock_check\r
+\r
+; Read error: Block not found\r
+fat_scan_error:\r
+ clr temp\r
+ ret\r
+\r
+fat_bootblock_check:\r
+\r
+.if FAT16_DEBUG > 0
+ printstring "fat16 bootblock check",0\r
+ printnewline\r
+.endif\r
+\r
+; -> Size of Sectors fixed at 512 Bytes\r
+; Get ammount of Bytes per Sector\r
+; ldiw z,hostbuf+FAT16_BSO_SECSIZE\r
+; ldiw y,fat_sectorsize\r
+; ld temp,z\r
+; st y+, temp\r
+; ldd temp2,z+1\r
+; st y , temp2\r
+;\r
+;.if FAT16_DEBUG > 0\r
+; printstring "Bytes per Sector ",0\r
+; rcall printhexw\r
+; printnewline\r
+;.endif\r
+\r
+; Anzahl der Sectoren pro Cluster lesen\r
+ ldiw z,hostbuf+FAT16_BSO_CLUSTSZ\r
+ ld temp,z\r
+ sts fat_clustersize,temp\r
+\r
+.if FAT16_DEBUG > 0\r
+ printstring "Sectors per Cluster ",0\r
+ rcall printhex\r
+ printnewline\r
+.endif\r
+\r
+; Anzahl der reservierten Sectoren\r
+ ldiw z,hostbuf+FAT16_BSO_RESSECT\r
+ ld temp,z+\r
+ sts fat_ressectors,temp ; low byte\r
+ ld temp2,z\r
+ sts fat_ressectors+1,temp2 ; high byte\r
+\r
+.if FAT16_DEBUG > 0\r
+ printstring "Reserved Sectors__: ",0\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Anzahl der Sectoren pro FAT\r
+ ldiw z,hostbuf+FAT16_BSO_SECPERFAT\r
+ ld temp,z+\r
+ sts fat_secperfat,temp ; low byte\r
+ ld temp2,z\r
+ sts fat_secperfat+1,temp2 ; high byte\r
+\r
+.if FAT16_DEBUG > 0\r
+ printstring "Sectors per FAT__: ",0\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Anzahl der FAT kopien\r
+ ldiw z,hostbuf+FAT16_BSO_NUMFATCP\r
+ ld temp,z\r
+ sts fat_numfatcp,temp ; low byte\r
+\r
+.if FAT16_DEBUG > 0\r
+ printstring "Ammount of FAT copies: ",0\r
+ rcall printhex\r
+ printnewline\r
+.endif\r
+\r
+; Max. Anzahl der Dir. Enträge im Root Verz.\r
+ ldiw z,hostbuf+FAT16_BSO_NUMDIRENT\r
+ ld temp,z+\r
+ sts fat_numdirentrys,temp ; low byte\r
+ ld temp2,z\r
+ sts fat_numdirentrys+1,temp2 ; high byte\r
+\r
+.if FAT16_DEBUG > 0\r
+ printstring "Max. entrys in Rootdir.: ",0\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Print begin of Volume\r
+.if FAT16_DEBUG > 1\r
+\r
+ ldiw z,fat_parttbl
+ ldd xl,z+0
+ ldd xh,z+1
+ ldd yl,z+2
+ ldd yh,z+3\r
+\r
+ printstring "Begin of Volume at: ",0\r
+ mov temp ,yl\r
+ mov temp2,yh\r
+ rcall printhexw\r
+ mov temp ,xl\r
+ mov temp2,xh\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Calculate begin of FAT within the Volume\r
+ lds temp ,fat_ressectors\r
+ lds temp2,fat_ressectors+1\r
+\r
+ ldiw z,fat_parttbl
+ ldd xl,z+0
+ ldd xh,z+1
+ ldd yl,z+2
+ ldd yh,z+3\r
+\r
+ add xl,temp\r
+ adc xh,temp2\r
+ adc yl,_0\r
+ adc yh,_0\r
+\r
+ sts fat_ptr2fat ,xl\r
+ sts fat_ptr2fat+1,xh\r
+ sts fat_ptr2fat+2,yl\r
+ sts fat_ptr2fat+3,yh\r
+\r
+.if FAT16_DEBUG > 1\r
+ printstring "Begin of FAT at___: ",0\r
+ mov temp ,yl\r
+ mov temp2,yh\r
+ rcall printhexw\r
+ mov temp ,xl\r
+ mov temp2,xh\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Calculate begin of Root- Directory within the Volume\r
+ ldiw z,fat_ptr2fat\r
+ ldd xl,z+0\r
+ ldd xh,z+1\r
+ ldd yl,z+2\r
+ ldd yh,z+3\r
+\r
+ lds temp ,fat_secperfat\r
+ lds temp2,fat_secperfat+1\r
+ lds temp3,fat_numfatcp\r
+\r
+fat_calc_dp_loop:\r
+ cp temp3,_0\r
+ breq fat_calc_dp_lend\r
+\r
+ add xl,temp\r
+ adc xh,temp2\r
+ adc yl,_0\r
+ adc yh,_0\r
+\r
+ dec temp3\r
+\r
+ jmp fat_calc_dp_loop\r
+fat_calc_dp_lend:\r
+\r
+ sts fat_ptr2dir ,xl\r
+ sts fat_ptr2dir+1,xh\r
+ sts fat_ptr2dir+2,yl\r
+ sts fat_ptr2dir+3,yh\r
+\r
+\r
+.if FAT16_DEBUG > 1\r
+ printstring "Begin of DIR at___: ",0\r
+ mov temp ,yl\r
+ mov temp2,yh\r
+ rcall printhexw\r
+ mov temp ,xl\r
+ mov temp2,xh\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Calculate begin of DATA Clusters within the Volume\r
+; Num. Dir.Sektors = (Num. of Dir. Entrys * 32) / Bytes per Sektor\r
+\r
+; Sectorsize is fixed at 512 Bytes, makes 16 Entrys per Sektor\r
+\r
+ lds zl,fat_numdirentrys ; low byte\r
+ lds zh,fat_numdirentrys+1 ; high byte\r
+\r
+; Num. Direntrys / 16\r
+ lsr zh\r
+ ror zl\r
+ lsr zh\r
+ ror zl\r
+ lsr zh\r
+ ror zl\r
+ lsr zh\r
+ ror zl\r
+\r
+ lds xl,fat_ptr2dir\r
+ lds xh,fat_ptr2dir+1\r
+ lds yl,fat_ptr2dir+2\r
+ lds yh,fat_ptr2dir+3\r
+\r
+ add xl,zl\r
+ adc xh,zh\r
+ adc yl,_0\r
+ adc yh,_0\r
+\r
+ sts fat_ptr2dat ,xl\r
+ sts fat_ptr2dat+1,xh\r
+ sts fat_ptr2dat+2,yl\r
+ sts fat_ptr2dat+3,yh\r
+\r
+.if FAT16_DEBUG > 1\r
+ printstring "Begin of Data at__: ",0\r
+ mov temp ,yl\r
+ mov temp2,yh\r
+ rcall printhexw\r
+ mov temp ,xl\r
+ mov temp2,xh\r
+ rcall printhexw\r
+ printnewline\r
+.endif\r
+\r
+; Here Starts the Scann of the Directory for valid image Files.\r
+\r
+ lds xl,fat_ptr2dir\r
+ lds xh,fat_ptr2dir+1\r
+ lds yl,fat_ptr2dir+2\r
+ lds yh,fat_ptr2dir+3\r
+\r
+; Load first sector from Directory
+ call mmcReadSect
+ tst temp
+ breq fat_look_for_images\r
+\r
+; Read error: Block not found\r
+ clr temp\r
+ ret\r
+\r
+; Looks at a read directory block for image entrys\r
+fat_look_for_images:\r
+ \r
+ ldiw z,hostbuf\r
+ ldi temp2,0\r
+\r
+fat_look_for_loop: \r
+ ldd temp,z+0\r
+ cpi temp,'C'\r
+ brne fat_look_not_ok\r
+ \r
+ ldd temp,z+1\r
+ cpi temp,'P'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+2\r
+ cpi temp,'M'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+3\r
+ cpi temp,'D'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+4\r
+ cpi temp,'S'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+5\r
+ cpi temp,'K'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+6\r
+ cpi temp,'_'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+8\r
+ cpi temp,'I'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+9\r
+ cpi temp,'M'\r
+ brne fat_look_not_ok\r
+\r
+ ldd temp,z+10\r
+ cpi temp,'G'\r
+ brne fat_look_not_ok\r
+\r
+ jmp fat_store_new_entry\r
+\r
+fat_look_not_ok:\r
+ \r
+ //ldi temp,32\r
+ addiw z,32 \r
+\r
+ inc temp2\r
+ cpi temp2,16 ; max entrys/sector\r
+ breq fat_scan_next_sector\r
+ jmp fat_look_for_loop\r
+\r
+fat_scan_next_sector:\r
+\r
+ ret\r
+\r
+\r
+; Create new Partition Entry\r
+fat_store_new_entry:\r
+\r
+; Found a valid image\r
+.if FAT16_DEBUG > 1\r
+ printstring "Found a valid Image ! ",0\r
+ printnewline\r
+.endif\r
+\r
+ ldiw y,hostparttbl\r
+ lds temp,ndisks\r
+\r
+fat_look_store_loop:\r
+ cp temp,_0\r
+ breq fat_look_store\r
+\r
+ adiw y,PARTENTRY_SIZE\r
+ dec temp\r
+ jmp fat_look_store_loop\r
+\r
+fat_look_store:\r
+; Set Type of Partition to FAT16- Fileimage\r
+ ldi temp,dskType_FAT\r
+ st y+,temp\r
+\r
+; Offset to Startcluster + 2
+ ldd temp,z+0x1A
+ st y+,temp
+ ldd temp,z+0x1B
+ st y+,temp \r
+ ldi temp,0\r
+ st y+,temp
+ st y+,temp\r
+\r
+; Filesize in Bytes - 2,4,8,16,32,64,128,256,512 \r
+; ldd temp,z+0x1C\r
+; st y+,temp
+; ldd temp,z+0x1D\r
+; st y+,temp
+; ldd temp,z+0x1E\r
+; st y+,temp
+; ldd temp,z+0x1F\r
+; st y+,temp\r
+\r
+; Convert Filesize to ammount of sectors\r
+ ldd xl,z+0x1D\r
+ ldd xh,z+0x1E\r
+ ldd zl,z+0x1F\r
+ mov zh,_0\r
+\r
+ lsr zh\r
+ ror zl\r
+ ror xh\r
+ ror xl\r
+\r
+; store ammount of sectors in partitiontable \r
+ st y+,xl
+ st y+,xh
+ st y+,zl
+ st y+,zh
+\r
+; Check for another free entry in partition table\r
+ lds temp,ndisks\r
+ inc temp\r
+ sts ndisks,temp\r
+ \r
+\r
+.if FAT16_DEBUG > 1\r
+; Test finding of the first sector\r
+ ldd xl,z+0x1A\r
+ ldd xh,z+0x1B\r
+ ldi zl,0\r
+\r
+ rcall fat_gethostsec\r
+\r
+ printstring "Begin of Image at: ",0\r
+ mov temp ,yl\r
+ mov temp2,yh\r
+ rcall printhexw\r
+ mov temp ,xl\r
+ mov temp2,xh\r
+ rcall printhexw\r
+ printnewline\r
+\r
+.endif\r
+ \r
+; cp temp,MAXDISKS\r
+; brne fat_scan_for_more \r
+ \r
+ ret\r
+\r
+\r
+; ====================================================================\r
+; Function: Cluster+Offset to HostSector
+; ====================================================================\r
+; Parameters: [in] xh,xl Cluster Number\r
+; [in] zl Offset\r
+; [out] yh,yl,xh,xl Sector Number on Disk\r
+; --------------------------------------------------------------------\r
+; Registers : \r
+; Variables : [used] fat_clustersize Ammount of Sectors per Cluster\r
+; [changes] temp\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ! Only works with Clustersizes 1,2,4,8,16,32,64,128 !\r
+; ====================================================================\r
+fat_gethostsec:\r
+\r
+; Get Offset into Data area of Disk\r
+ rcall fat_clusttosec\r
+\r
+; add given offset\r
+ add xl,zl\r
+ adc xh,_0\r
+ adc yl,_0\r
+ adc yh,_0\r
+\r
+; add begin of data area to offset\r
+ lds temp,fat_ptr2dat+0\r
+ add xl,temp\r
+ lds temp,fat_ptr2dat+1\r
+ adc xh,temp\r
+ lds temp,fat_ptr2dat+2\r
+ adc yl,temp\r
+ lds temp,fat_ptr2dat+3\r
+ adc yh,temp\r
+ ret\r
+\r
+; ====================================================================\r
+; Function: Cluster to Sector
+; ====================================================================\r
+; Parameters: [in] xl,xh Cluster Number\r
+; [out] xl,xh,yl,yh Sector Number\r
+; --------------------------------------------------------------------\r
+; Registers : \r
+; Variables : [used] fat_clustersize Ammount of Sectors per Cluster\r
+; [changes] temp\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ! Only works with Clustersizes 1,2,4,8,16,32,64,128 !\r
+; ====================================================================\r
+fat_clusttosec:\r
+ clr yl\r
+ clr yh\r
+\r
+ ldi temp,2\r
+ sub xl,temp ; Substract the 2 reserved clusters\r
+ sbc xh,_0\r
+\r
+ lds temp,fat_clustersize\r
+\r
+fat_c2s_loop:\r
+ lsr temp\r
+ tst temp\r
+ breq fat_c2s_end\r
+\r
+ lsl xl\r
+ rol xh\r
+ rol yl\r
+ rol yh\r
+ rjmp fat_c2s_loop\r
+\r
+fat_c2s_end:\r
+ ret\r
+\r
+; ====================================================================\r
+; Function: CP/M Sector to Cluster & Offset
+; ====================================================================\r
+; Parameters: [in] xl,xh Cluster Number\r
+; [out] xl,xh,yl,yh Sector Number\r
+; --------------------------------------------------------------------\r
+; Registers : \r
+; Variables : [used] fat_clustersize Ammount of Sectors per Cluster\r
+; [changes] temp\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ! Only works with Clustersizes 1,2,4,8,16,32,64,128 !\r
+; ====================================================================\r
+fat_cpmtoclust:\r
+\r
+ ret\r
+\r
+; ====================================================================\r
+; Function: Does a Disk write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; hostdsk = host disk #, (partition #)
+; hostlba = host block #, relative to partition start
+; Read/Write "hostsize" bytes to/from hostbuf\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================
+
+fat_hostparam:
+ lds xl,hostdsk
+\r
+.if HOSTRW_DEBUG
+ mov temp,xl
+ subi temp,-('A')
+ rcall uartputc
+ printstring ": "
+.endif
+\r
+ rcall dsk_getpartentry ; get partition entry
+\r
+fat_hostlend:\r
+ lds temp ,hostlba
+ lds temp2,hostlba+1
+ lds temp3,hostlba+2
+
+.if HOSTRW_DEBUG
+ printstring "lba: "
+ clr temp4
+ rcall print_ultoa
+.endif
+
+ ldd xl,z+5 ; get size of disk in sectors
+ ldd xh,z+6
+ ldd yl,z+7
+
+ cp temp,xl ; check given sector against disksize
+ cpc temp2,xh
+ cpc temp3,yl
+ brcs fat_hp1
+
+.if HOSTRW_DEBUG
+ printstring ", max: "
+ push temp4
+ push temp3
+ push temp2
+ push temp
+ movw temp,x
+ mov temp3,yl
+ clr temp4
+ rcall print_ultoa
+ pop temp
+ pop temp2
+ pop temp3
+ pop temp4
+ printstring " "
+.endif
+
+ clr temp
+ ret
+
+fat_hp1:
+ ldd xl,z+1 ; startsector
+ ldd xh,z+2
+ ldd yl,z+3
+ ldd yh,z+4
+
+ add xl,temp ; startsector + offset
+ adc xh,temp2
+ adc yl,temp3
+ adc yh,_0\r
+
+.if HOSTRW_DEBUG
+ printstring ", abs:"
+ push temp4
+ push temp3
+ push temp2
+ push temp
+ movw temp,x
+ movw temp3,y
+ rcall print_ultoa
+ pop temp
+ pop temp2
+ pop temp3
+ pop temp4
+ printstring " "
+.endif\r
+
+ ori temp,255
+fat_hpex:
+ ret
+
+; ====================================================================\r
+; Function: Does a Disk write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================
+
+fat_writehost:
+.if HOSTRW_DEBUG
+ printnewline
+ printstring "host write "
+.endif
+ rcall fat_hostparam
+ breq fat_rdwr_err
+
+ ;call mmcWriteSect ; disabled till read is functioning
+ tst temp
+ breq fat_rdwr_ok
+
+ rcall mgr_init_partitions
+ cbr temp,0x80
+ breq fat_rdwr_err
+
+ rcall fat_hostparam
+ breq fat_rdwr_err
+ ;call mmcWriteSect ; disabled till read is functioning
+ tst temp
+ brne fat_rdwr_err
+ rjmp fat_rdwr_ok
+
+; ====================================================================\r
+; Function: Does a Disk read operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+
+fat_readhost:
+.if HOSTRW_DEBUG
+ printnewline
+ printstring "host read "
+.endif\r
+
+ rcall fat_hostparam
+ breq fat_rdwr_err
+
+ call mmcReadSect
+ tst temp
+ breq fat_rdwr_ok
+
+ rcall mgr_init_partitions
+ cbr temp,0x80
+ breq fat_rdwr_err
+
+ rcall fat_hostparam
+ breq fat_rdwr_err
+ call mmcReadSect
+ tst temp
+ brne fat_rdwr_err
+
+fat_rdwr_ok:
+ sts erflag,_0
+ ret
+
+fat_rdwr_err:
+ sts erflag,_255
+ ret\r
+#endif\r
--- /dev/null
+; 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 <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;\r
+\r
+\r
+; ---------------- Defines for the Filesystem Interface -------
+
+\r
+;*****************************************************
+;* Disk-Manager constants *
+;*****************************************************
+ .equ dskType_None = 0\r
+ .equ dskType_CPM = 1\r
+ .equ dskType_FAT = 2\r
+ .equ dskType_RAM = 3\r
+
+;*****************************************************
+;* CP/M to host disk constants *
+;*****************************************************
+ .equ MAXDISKS = 4 ;Max number of Disks (partitions)\r
+ .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\r
+;----------------------------------------------- Start of Data Segment
+
+ .dseg\r
+\r
+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\r
+
+hostbuf: .byte hostsize ;host buffer (from/to SD-card)\r
+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)\r
+hostlba: .byte 3 ;host sector number (relative to partition start)\r
+\r
+\r
+; ------------------------------- Start of Code Segment
+ .cseg\r
+\r
+; ====================================================================\r
+; Function: Get a Pointer to a Partitiontable entry
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : [w] z Pointer to the Partitionentry\r
+; [r] xl Number of Diskentry to Read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+dsk_getpartentry:\r
+ \r
+ ldiw z,hostparttbl\r
+ mov temp,xl\r
+\r
+dsk_getpartentryloop:\r
+ cp temp,_0\r
+ breq dsk_getpartentryloopend\r
+ adiw z,PARTENTRY_SIZE\r
+ dec temp\r
+ jmp dsk_getpartentryloop\r
+dsk_getpartentryloopend:\r
+ ret
+\r
+; ====================================================================\r
+; Function:
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+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\r
+
+; ====================================================================\r
+; Function: Does a Disk interaction
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================
+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
+\r
+\r
+
+; ====================================================================\r
+; Function: Does a Disk read operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================
+dsk_read:
+ sts erflag,_0
+ sbi flags,readop ; Set read operation flag\r
+ lds xl,seekdsk
+ rcall dsk_getpartentry ; Get Paritiontableentry\r
+ ld temp,z ; Get Partitiontype\r
+\r
+; Isn't it a Disk ?\r
+ cpi temp,dskType_None\r
+ brne PC+2\r
+ rjmp dsk_read_err\r
+; Is it a RamDisk ?
+ cpi temp,dskType_RAM\r
+ brne PC+2\r
+ rjmp rdsk_read\r
+; It must be a FAT16-Imagefile or CP/M Partition.\r
+ 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\r
+
+dsk_read_err:\r
+ ret\r
+
+; ====================================================================\r
+; Function: Does a Disk write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================
+dsk_write:
+ ;write the selected sector
+ sts erflag,_0
+ cbi flags,readop ; not a read operation\r
+ lds xl,seekdsk
+ rcall dsk_getpartentry ; Get Paritiontableentry\r
+ ld temp,z ; Get Partitiontype\r
+\r
+; Isn't it a Disk ?\r
+ cpi temp,dskType_None\r
+ brne PC+2\r
+ rjmp dsk_write_err\r
+\r
+; Is it a RamDisk ?
+ cpi temp,dskType_RAM\r
+ brne PC+2\r
+ rjmp rdsk_write\r
+\r
+; It must be a FAT16-Imagefile or CP/M Partition.\r
+
+ 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\r
+\r
+dsk_write_err:\r
+ ret\r
+\r
+; ====================================================================\r
+; Function: Does a Disk read/write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+dsk_rwoper:\r
+ ;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\r
+
+.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\r
+\r
+; ====================================================================\r
+; Function: Does a Disk write operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+dsk_writehost:\r
+ lds xl,hostdsk\r
+ rcall dsk_getpartentry\r
+ ld temp,z\r
+\r
+; Is it a FAT16 Diskimage ?
+ cpi temp,dskType_FAT\r
+ brne PC+2\r
+ rjmp fat_writehost\r
+\r
+; Is it a CP/M Partition ?
+ cpi temp,dskType_CPM\r
+ brne PC+2\r
+ rjmp cpm_writehost\r
+; Disktype not supported -> Return \r
+ ret\r
+\r
+; ====================================================================\r
+; Function: Does a Disk read operation
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seekdsk Number of Disk to Read\r
+; [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+dsk_readhost:\r
+ lds xl,hostdsk\r
+ rcall dsk_getpartentry\r
+ ld temp,z\r
+\r
+; Is it a FAT16 Diskimage ?
+ cpi temp,dskType_FAT\r
+ brne PC+2\r
+ rjmp fat_readhost\r
+\r
+; Is it a CP/M Partition ?
+ cpi temp,dskType_CPM\r
+ brne PC+2\r
+ rjmp cpm_readhost\r
+; Disktype not supported -> Return \r
+ ret\r
+\r
--- /dev/null
+; Various Management functions for the Interaction with the File-\r
+; systems
+;
+; 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 <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;\r
+\r
+\r
+; ------------------------- Defines for the disk management Structures
+\r
+;----------------------------------------------- Start of Data Segment
+
+ .dseg\r
+\r
+\r
+\r
+; ------------------------------- Start of Code Segment
+ .cseg\r
+\r
+; ====================================================================\r
+; Function: Scans a Disk for CP/M Partions
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [w] temp Status of Operation\r
+; (0x80 - Operation Failure )\r
+; (others - Operation Suceded)\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; This Function scans an SD-Cards Boot-Sector for valid Partitions.\r
+; First all original CP/M Partitions will be usesed as Drives for\r
+; the CPM-System. Wenn all CP/M Partitions are found, a second\r
+; scann will be made. In the second Scan, the first FAT16 Partition\r
+; on the Disk will be used for a detailed analyses. If there\r
+; are any Files like "cpm_x.img" are found, these Files will be\r
+; used as Disks by the CP/M- System. ( x must be in the Range A to D )\r
+; ====================================================================
+mgr_init_partitions:\r
+\r
+ sts ndisks,_0 ; Set Number of Disks to 0\r
+\r
+; Initialize temp partition table\r
+ ldiw y,tmp_tbl
+ ldi temp2,PARTENTRY_SIZE*MAXDISKS
+mgr_picl:
+ st y+,_0
+ dec temp2
+ brne mgr_picl\r
+\r
+; Start mmc Card interaction
+ call mmcInit
+ andi temp,MMCST_NOINIT & MMCST_NODISK
+ brne mgr_pierr
+
+;Load first sector from MMC (boot sector)
+ ldiw y,0 ; Sector 0
+ movw x,y
+ call mmcReadSect
+ tst temp
+ breq mgr_check_bootsektor
+
+mgr_pierr:
+ clr temp
+ ret\r
+\r
+mgr_check_bootsektor:\r
+;Pointer to first temp table entry\r
+ ldiw y,tmp_tbl
+;Test, if it has a valid MBR
+
+ ldiw z,hostbuf+510-1 ;Point to last byte of partition table
+
+ ldi temp3,0 ;temp3 holds number of found disks (paritions)
+ ldd temp,z+1 ;MBR signature (0xAA55) at and of sector?
+ ldd temp2,z+2
+ ldi temp4,0xAA
+ cpi temp,0x55
+ cpc temp2,temp4
+ breq mgr_search
+
+;No MBR, no partition table ...
+ inc temp3 ;pretend we have one.
+ ldi temp,high((1<<16) * 128/512)\r
+ ldi temp2,dskType_CPM\r
+ std y+0,temp2
+ std y+1,_0 ;start at beginning of card
+ std y+2,_0
+ std y+3,_0
+ std y+4,_0
+ std y+5,_0 ;max CP/M 2.2 disk size
+ std y+6,temp ;
+ std y+7,_0
+ std y+8,_0
+ rjmp mgr_pend\r
+\r
+; Search for valid Partitions and ImageFiles \r
+mgr_search:\r
+ sbiw z,63 ;Now at first byte of partition table
+ ldi temp4,high(hostbuf+510)
+\r
+mgr_ploop:
+\r
+; Get Partitiontype\r
+ ldd temp,z+PART_TYPE
+\r
+; Test for CP/M Partition\r
+ cpi temp,PARTID_CPM
+ brne mgr_nextp
+
+ rcall cpm_add_partition
+\r
+ inc temp3
+ cpi temp3,MAXDISKS
+ breq mgr_pend\r
+ rjmp mgr_nextp\r
+
+mgr_nextp:
+ adiw zl,16
+ cpi zl,low(hostbuf+510)
+ cpc zh,temp4
+ brlo mgr_ploop\r
+\r
+; Test for FAT16 Partition\r
+ ldiw z,hostbuf+510-1-63 ;Point to first byte of partition table
+ ldi temp4,high(hostbuf+510)
+\r
+mgr_ploop2:
+\r
+; Get Partitiontype\r
+ ldd temp,z+PART_TYPE
+\r
+; Test for FAT Partition\r
+ cpi temp,PARTID_FAT16
+ brne mgr_nextp2
+
+ rcall fat_add_partition
+
+ rjmp mgr_pend\r
+
+mgr_nextp2:
+ adiw zl,16
+ cpi zl,low(hostbuf+510)
+ cpc zh,temp4
+ brlo mgr_ploop2\r
+\r
+mgr_pend:\r
+\r
+; Initialize RAM-Disks\r
+ rcall rdsk_add_partition\r
+\r
+;Store new partitions and check if the SD card has been changed.
+
+ ldiw y,tmp_tbl
+ ldiw z,hostparttbl
+ ldi temp4,PARTENTRY_SIZE*MAXDISKS
+ clt\r
+
+mgr_pcpl:
+ ld temp,y+
+ ld temp2,z
+ st z+,temp
+ cpse temp,temp2
+ set
+ dec temp4
+ brne mgr_pcpl
+
+ mov temp,temp3
+ sts ndisks,temp
+ brtc mgr_pcpe
+
+ tst temp
+ breq mgr_pcpe
+
+; SD card not changed.
+ rcall fat_scan_partition\r
+\r
+ lds temp,ndisks\r
+ sbr temp,0x80
+
+mgr_pcpe:\r
+
+ ret\r
+\r
+\r
+; ====================================================================\r
+; Function: Print partition table info
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] hostparttbl Table with Partitioninformations\r
+; [r] hostparttbltop Pointer to the Top of the Table\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+
+mgr_prnt_parttbl:
+ ldiw z,hostparttbl
+pprl:
+ ldd temp ,z+1 ;Get partition start
+ ldd temp2,z+2
+ ldd temp3,z+3
+ ldd temp4,z+4
+ printnewline
+ cp temp,_0 ;If zero ...
+ cpc temp2,_0
+ cpc temp3,_0
+ cpc temp4,_0
+ breq mgr_prnop ;... no partition table at 0
+\r
+; Partitiontype examining\r
+ ldd xl,z+0\r
+; CP/M ?\r
+ cpi xl,dskType_CPM\r
+ brne mgr_prtb_nocpm\r
+ rcall mgr_prnt_table_cpm
+ rjmp mgr_prnt_size\r
+\r
+; FAT16 ?\r
+mgr_prtb_nocpm:
+ cpi xl,dskType_FAT\r
+ brne mgr_prtb_nofat\r
+ rcall mgr_prnt_table_fat
+ rjmp mgr_prnt_size
+; RAMDISK ?\r
+mgr_prtb_nofat:\r
+ cpi xl,dskType_RAM\r
+ brne mgr_prnt_err\r
+ rcall mgr_prnt_table_ram
+ rjmp mgr_prnt_size\r
+; Entry Error\r
+mgr_prnt_err: \r
+ rcall mgr_prnt_table_err
+ rjmp mgr_prnt_size\r
+\r
+mgr_prnop:
+ rcall mgr_prnt_image
+\r
+mgr_prnt_size:\r
+ rcall print_ultoa
+ printstring ", size: "
+\r
+ ldd temp ,z+5 ;Get partition size
+ ldd temp2,z+6 ;Get partition size
+ ldd temp3,z+7 ;Get partition size
+ ldd temp4,z+8 ;Get partition size
+
+ lsr temp4
+ ror temp3
+ ror temp2
+ ror temp
+ rcall print_ultoa
+ printstring "KB."\r
+
+mgr_goto_next_part:
+ adiw z,PARTENTRY_SIZE
+ ldi temp,high(hostparttbltop)
+ cpi zl, low (hostparttbltop)
+ cpc zh,temp
+ brlo pprl
+\r
+mgr_pppre:
+ ret
+ \r
+\r
+mgr_prnt_fatsize:
+ rcall print_ultoa
+ printstring ", size: "
+ \r
+ ldd temp ,z+5 ;Get partition size
+ ldd temp2,z+6 ;Get partition size
+ ldd temp3,z+7 ;Get partition size
+ ldd temp4,z+8 ;Get partition size
+
+ rcall print_ultoa
+ printstring "BYTE."
+
+ jmp mgr_goto_next_part\r
+
+mgr_prnt_table_cpm:
+ printstring "CP/M partition at: "
+ ret\r
+\r
+mgr_prnt_table_fat:
+ printstring "FAT16 File-Image at: "
+ ret\r
+\r
+mgr_prnt_table_ram:
+ printstring "Ramdisk at: "
+ ret\r
+\r
+mgr_prnt_table_err:
+ printstring "Unknown Entry at: "
+ ret\r
+
+mgr_prnt_image:
+ printstring "Assuming CP/M image at: "
+ ret\r
+
+\r
--- /dev/null
+; Various functions for the Interaction with the CPM Filesystem
+;
+; 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 <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;\r
+\r
+#ifndef RAMDSK_SUPPORT\r
+ #define RAMDSK_SUPPORT 0 \r
+#endif\r
+\r
+#if RAMDSK_SUPPORT\r
+\r
+;-------------------------------------- Defines for RAMDISK Structures
+\r
+;----------------------------------------------- Start of Data Segment
+
+ .dseg\r
+\r
+rdskbuf: .byte 128 ; Buffer for RAM-Disk interaktions\r
+\r
+; ---------------------------------------------- Start of Code Segment
+ .cseg\r
+
+; ====================================================================\r
+; Function: Calculate an sets the adress of Sector within the RAMDISK
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; [w] temp3 Number of Bytes per Sector (128) \r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+
+
+rdsk_adr:
+ ldi xl,0
+ lds xh,seeksec
+ lds temp2,seektrk
+
+ lsr xh
+ ror xl ;Col 0..7
+
+ mov temp,temp2
+ andi temp,0x0f
+ swap temp
+ or xh,temp ;Row 0..7
+
+ ldiw z,rdskbuf
+ ldi temp3,128
+ DRAM_SETADDR xh, ~0,(1<<ram_ras), ~0,(1<<ram_a8)|(1<<ram_oe)
+ cbi P_RAS,ram_ras
+
+.if DISK_DEBUG > 1
+ mov temp,xh
+ rcall printhex
+ printstring " "
+ mov temp,xl
+ rcall printhex
+ printstring " "
+.endif
+ ret
+
+; ====================================================================\r
+; Function: Does a read opperation on a RAMDISK
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; [r] flags RW operation Flags\r
+; [w] erflag Error Status of the operation\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+
+
+rdsk_read:
+\r
+.if DISK_DEBUG > 1
+ printnewline
+ printstring "rd-adr: "
+.endif
+ rcall rdsk_adr
+\r
+rdsk_rdl:
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
+ cbi P_CAS,ram_cas
+ cbi P_A8,ram_a8
+ inc xl
+ dram_wait DRAM_WAITSTATES ;
+ in temp,P_DQ-2 ; PIN
+ sbi P_CAS,ram_cas
+
+ cbi P_CAS,ram_cas
+ andi temp,0x0f
+ swap temp
+ dram_wait DRAM_WAITSTATES ;
+ in temp2,P_DQ-2 ; PIN
+ andi temp2,0x0f
+ or temp,temp2
+
+ sbi P_OE,ram_oe
+ sbi P_CAS,ram_cas
+ dec temp3
+ st z+,temp
+ brne rdsk_rdl
+
+ sbi P_RAS,ram_ras
+ ldiw z,rdskbuf
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldi temp3,128
+rdsk_rdstl:
+ ld temp,z+
+ mem_write
+ adiw x,1
+ dec temp3
+ brne rdsk_rdstl
+ ret
+
+; ====================================================================\r
+; Function: Does a write opperation on a RAMDISK
+; ====================================================================\r
+; Parameters\r
+; --------------------------------------------------------------------\r
+; Registers : none\r
+; Variables : [r] seeksec Sector to read\r
+; [r] seektrk Track to read\r
+; [r] flags RW operation Flags\r
+; [w] erflag Error Status of the operation\r
+; --------------------------------------------------------------------\r
+; Description:\r
+; ====================================================================\r
+
+rdsk_write:
+.if DISK_DEBUG > 1
+ printnewline
+ printstring "wr-adr: "
+.endif
+ lds xl,dmaadr
+ lds xh,dmaadr+1
+ ldiw z,rdskbuf
+ ldi temp3,128
+rdsk_wrldl:
+ mem_read
+ st z+,temp
+ adiw x,1
+ dec temp3
+ brne rdsk_wrldl
+
+ ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out DDRC,temp2
+ rcall rdsk_adr
+rdsk_wrl:
+ ld temp,z+
+ mov temp2,temp
+ andi temp,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp,(1<<ram_cas)
+ out PORTC,temp
+ DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
+ cbi PORTC,ram_cas
+ sbi PORTD,ram_a8
+ sbi PORTC,ram_cas
+ swap temp2
+ andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
+ ori temp2,(1<<ram_cas)
+ out PORTC,temp2
+ cbi PORTC,ram_cas
+ inc xl
+ sbi PORTC,ram_cas
+ dec temp3
+ brne rdsk_wrl
+
+ sbi P_RAS,ram_ras
+ ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
+ out DDRC,temp
+ out PORTC,temp
+ ret\r
+\r
+\r
+rdsk_add_partition:\r
+ ret\r
+\r
+
+#else\r
+\r
+rdsk_read:\r
+ ret\r
+rdsk_write:\r
+ ret\r
+rdsk_add_partition:\r
+ ret\r
+\r
+#endif\r
boot_again:
printnewline
printstring "Initing mmc...",0
- rcall dsk_partinit
+ printnewline
+ call mgr_init_partitions
cbr temp,0x80
brne boot_ipl2
printstring "No bootable CP/M disk found! Please change MMC/SD-Card."
+ printnewline
ldi temp2,18
boot_iplwl:
ldi temp,255
boot_ipl2:
- rcall prnt_parttbl
+ call mgr_prnt_parttbl
printnewline
printstring "Partinit done."
; Read first sector of first CP/M partition
- lds xl,hostparttbl
- lds xh,hostparttbl+1
- lds yl,hostparttbl+2
- lds yh,hostparttbl+3
+ lds xl,hostparttbl+1
+ lds xh,hostparttbl+2
+ lds yl,hostparttbl+3
+ lds yh,hostparttbl+4
rcall mmcReadSect
rcall dsk_cboot ;init (de)blocking buffer
brne iplwriteloop
cpi zh,high(hostbuf+128)
brne iplwriteloop
- rjmp z80_init
+ jmp z80_init
; printstring "String"
.macro printstring
- rcall printstr
+ call printstr
.if strlen(@0) % 2
.db @0,0
.else
.endif
ret
+\r
+;--------------------------------------------------------------
+; Read word \r
+; TODO: Read Word to ZL,ZH at given ZL/ZH Offset\r
+; Need for reading of single FAT16 Entrys without killing the\r
+; Entrys in hostbuffer...\r
+;
+; in zh,zl: Pointer to Word within the Sector to read
+; in yh..xl: Start sector number (LBA)
+; out xh,xl : word thats been read\r
+
+mmcReadWord:
+.if MMC_DEBUG > 1
+ printnewline
+ printstring "mmcRdWord "
+.endif
+ lds _tmp0,mmcStat
+ ldi temp,RES_NOTRDY
+ sbrc _tmp0,MMCST_NOINIT
+ ret
+
+ spi_clkfast
+ lds temp,mmcCardType
+ sbrs temp,log2(CT_BLOCK)
+ rcall mul_yx_512 ;Convert to byte address (*512)
+\r
+ ldi temp2,CMD17
+ rcall mmcCmd
+ ldi temp2,RES_ERROR
+ brne mmc_rdexw
+
+; Receive a data packet from MMC
+
+ ldiw y,512 ;Number of bytes to tranfer
+ ldi temp,200 ;Wait for data packet in timeout of 200ms.
+ sts delay_timer1,temp
+mmc_rcvw_wl:
+ rcall spi_rcvr
+ cp temp,_255
+ brne mmc_rcvw_start
+ lds temp2,delay_timer1
+ cpi temp2,0
+ brne mmc_rcvw_wl
+mmc_rcvw_start:
+ cpi temp,0xFE ;If not valid data token,
+ ldi temp2,RES_ERROR
+ brne mmc_rdexw
+
+ rcall spi_rcvr ;Shift in first byte.
+ out SPDR,_255 ;Start shift in next byte.
+mmc_rcvw_rl:
+ sbiw yl,1
+ breq mmc_rcvw_rle
+ //st z+,temp
+ spi_waitm
+ in temp,SPDR
+ out SPDR,_255
+ rjmp mmc_rcvw_rl
+
+mmc_rcvw_rle:
+ //st z+,temp ;Store last byte in buffer
+ rcall spi_wait ; while SPI module shifts in crc part1.
+ rcall spi_rcvr ;Read second crc.
+
+ ldi temp2,RES_OK ;Return success
+mmc_rdexw:
+ rcall mmcDeselect
+ spi_disable
+ mov temp,temp2
+.if MMC_DEBUG > 1
+ printstring "RdWordRes: "
+ rcall printhex
+ printstring " "
+.endif
+ ret\r
;--------------------------------------------------------------
; Write sector
pop zl
pop zh
ret
-
-; ---------------- Virtual peripherial interface ----------------
-
-;The hw is modelled to make writing a CPM BIOS easier.
-;Ports:
-;0 - Con status. Returns 0xFF if the UART has a byte, 0 otherwise.
-;1 - Console input, aka UDR.
-;2 - Console output
-;3 - "UART" status: bit 0=rx, bit 1 = tx
-;4 - "UART" data register, no wait
-;15 - Disk select
-;16,17 - Track select
-;18 - Sector select
-;20 - Write addr l
-;21 - Write addr h
-;22 - Trigger - write to read, to write a sector using the above info;
-; , write to allocated/dirctory/unallocated
-
- .equ READ_FUNC = 7
- .equ WRITE_FUNC = 6
- .equ BOOT_FUNC = 5
- .equ HOME_FUNC = 4
-
-
-
-;*****************************************************
-;* CP/M to host disk constants *
-;*****************************************************
- .equ MAXDISKS = 4 ;Max number of Disks (partitions)
- .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
-
-
- .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
-
-hostparttbl: .byte 8*MAXDISKS ;host partition table (start sector, sector count)
-hostparttbltop:
-hostdsk: .byte 1 ;host disk number
-hostlba: .byte 3 ;host sector number (relative to partition start)
-
-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)
+\r
+ .dseg\r
.cseg
-conStatus:
- lds temp,rxcount
- cpse temp,_0
- ldi temp,0xff
- ret
-
-conInp:
- rjmp uartgetc
-
-dbgOut:
- printnewline
- printstring "Debug: "
- rcall printhex
- ret
-
-conOut:
- rjmp uartputc
-
-uartstat:
- clr temp
- lds temp2,rxcount
- cpse temp2,_0
- sbr temp,0x01
- lds temp2,txcount
- cpi temp2,TXBUFSIZE
- breq uartst_1
- sbr temp,0x02
-uartst_1:
- ret
-
-uartout:
- lds temp2,txcount
- cpi temp2,TXBUFSIZE
- breq uartout_1
- rjmp uartputc
-uartout_1:
- ret
-
-uartin:
- clr temp
- lds temp2,rxcount
- cpse temp2,_0
- rjmp uartgetc
- ret
-
-;Called with port in temp2. Should return value in temp.
-portRead:
- cpi temp2,0
- breq conStatus
- cpi temp2,1
- breq conInp
- cpi temp2,3
- breq uartstat
- cpi temp2,4
- breq uartin
-
- cpi temp2,15
- breq dskDiskCheck
- cpi temp2,22
- breq dskErrorRet
-
- cpi temp2,TIMER_MSECS
- brlo pr_noclock
- cpi temp2,TIMER_MSECS+6
- brsh pr_noclock
- rjmp clockget
-
-pr_noclock:
- ldi temp,0xFF
- ret
-
-;Called with port in temp2 and value in temp.
-portWrite:
- cpi temp2,0
- breq dbgOut
- cpi temp2,2
- breq conOut
- cpi temp2,4
- breq uartout
-
- cpi temp2,15
- breq dskDiskSel
- cpi temp2,16
- breq dskTrackSel_l
- cpi temp2,17
- breq dskTrackSel_h
- cpi temp2,18
- breq dskSecSel
- cpi temp2,20
- breq dskDmaL
- cpi temp2,21
- breq dskDmaH
-
- cpi temp2,22
- breq dskDoIt
-
- cpi temp2,TIMERPORT
- brlo pw_noclock
- cpi temp2,TIMER_MSECS+6
- brsh pw_noclock
- rjmp clockput
-
-pw_noclock:
- ret
-
-
-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 dsk_partinit
- 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
-
-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
-
-
-dsk_read:
-
- sbi flags,readop ;read operation
- ;RAM disk?
- lds temp2,seekdsk
-#if RAMDISKCNT
- cpi temp2,RAMDISKNR
- brlt PC+2
- rjmp rdskDoIt
-#endif
- 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_write:
- ;write the selected CP/M sector
-
- cbi flags,readop ;not a read operation
-
- ;RAM disk?
- lds temp2,seekdsk
-#if RAMDISKCNT
- cpi temp2,RAMDISKNR
- brlt PC+2
- rjmp rdskDoIt
-#endif
- 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
-
-;*****************************************************
-;* Common code for READ and WRITE follows *
-;*****************************************************
-
-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
-;*****************************************************
-
-; hostdsk = host disk #, (partition #)
-; hostlba = host block #, relative to partition start
-; Read/Write "hostsize" bytes to/from hostbuf
-dsk_hostparam:
- ldiw z,hostparttbl
- lds temp,hostdsk
-.if HOSTRW_DEBUG
- push temp
- subi temp,-('A')
- rcall uartputc
- printstring ": "
- pop temp
-.endif
-
- lsl temp
- lsl temp
- lsl temp
- add zl,temp
- adc zh,_0
-
- lds temp,hostlba
- lds temp2,hostlba+1
- lds temp3,hostlba+2
-
-.if HOSTRW_DEBUG
- printstring "lba: "
- clr temp4
- rcall print_ultoa
-.endif
- ldd xl,z+4
- ldd xh,z+5
- ldd yl,z+6
-
- cp temp,xl
- cpc temp2,xh
- cpc temp3,yl
- brcs dsk_hp1
-
-.if HOSTRW_DEBUG
- printstring ", max: "
- push temp4
- push temp3
- push temp2
- push temp
- movw temp,x
- mov temp3,yl
- clr temp4
- rcall print_ultoa
- pop temp
- pop temp2
- pop temp3
- pop temp4
- printstring " "
-.endif
-
- clr temp
- ret
-
-dsk_hp1:
- ldd xl,z+0
- ldd xh,z+1
- ldd yl,z+2
- ldd yh,z+3
-
- add xl,temp
- adc xh,temp2
- adc yl,temp3
- adc yh,_0
-.if HOSTRW_DEBUG
- printstring ", abs:"
- push temp4
- push temp3
- push temp2
- push temp
- movw temp,x
- movw temp3,y
- rcall print_ultoa
- pop temp
- pop temp2
- pop temp3
- pop temp4
- printstring " "
-.endif
- ori temp,255
-dsk_hpex:
- ret
-
-;*****************************************************
-;* WRITEhost performs the physical write to *
-;* the host disk, READhost reads the physical *
-;* disk. *
-;*****************************************************
-
-dsk_writehost:
-.if HOSTRW_DEBUG
- printnewline
- printstring "host write "
-.endif
- rcall dsk_hostparam
- breq dsk_rdwr_err
-
- rcall mmcWriteSect
- tst temp
- breq dsk_rdwr_ok
-
- rcall dsk_partinit
- cbr temp,0x80
- breq dsk_rdwr_err
-
- rcall dsk_hostparam
- breq dsk_rdwr_err
- rcall mmcWriteSect
- tst temp
- brne dsk_rdwr_err
- rjmp dsk_rdwr_ok
-
-
-dsk_readhost:
-.if HOSTRW_DEBUG
- printnewline
- printstring "host read "
-.endif
- rcall dsk_hostparam
- breq dsk_rdwr_err
-
- rcall mmcReadSect
- tst temp
- breq dsk_rdwr_ok
-
- rcall dsk_partinit
- cbr temp,0x80
- breq dsk_rdwr_err
-
- rcall dsk_hostparam
- breq dsk_rdwr_err
- rcall mmcReadSect
- tst temp
- brne dsk_rdwr_err
-
-dsk_rdwr_ok:
- sts erflag,_0
- ret
-
-dsk_rdwr_err:
- sts erflag,_255
- ret
-
-;***************************************************************************
-
-#if RAMDISKCNT
-
-; ----------------- RAM disk -----------------
-
- .dseg
-rdskbuf:
- .byte 128
-
- .cseg
-;----------------------------------------------
-
-rdsk_adr:
- ldi xl,0
- lds xh,seeksec
- lds temp2,seektrk
-
- lsr xh
- ror xl ;Col 0..7
-
- mov temp,temp2
- andi temp,0x0f
- swap temp
- or xh,temp ;Row 0..7
-
- ldiw z,rdskbuf
- ldi temp3,128
- DRAM_SETADDR xh, ~0,(1<<ram_ras), ~0,(1<<ram_a8)|(1<<ram_oe)
- cbi P_RAS,ram_ras
-
-.if DISK_DEBUG > 1
- mov temp,xh
- rcall printhex
- printstring " "
- mov temp,xl
- rcall printhex
- printstring " "
-.endif
- ret
-
-;----------------------------------------------
-
-rdskDoIt:
- sts erflag,_0
- sbis flags,readop
- rjmp rdsk_wr
-
-.if DISK_DEBUG > 1
- printnewline
- printstring "rd-adr: "
-.endif
- rcall rdsk_adr
-rdsk_rdl:
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_oe)), (1<<ram_a8)
- cbi P_CAS,ram_cas
- cbi P_A8,ram_a8
- inc xl
- dram_wait DRAM_WAITSTATES ;
- in temp,P_DQ-2 ; PIN
- sbi P_CAS,ram_cas
-
- cbi P_CAS,ram_cas
- andi temp,0x0f
- swap temp
- dram_wait DRAM_WAITSTATES ;
- in temp2,P_DQ-2 ; PIN
- andi temp2,0x0f
- or temp,temp2
-
- sbi P_OE,ram_oe
- sbi P_CAS,ram_cas
- dec temp3
- st z+,temp
- brne rdsk_rdl
-
- sbi P_RAS,ram_ras
- ldiw z,rdskbuf
- lds xl,dmaadr
- lds xh,dmaadr+1
- ldi temp3,128
-rdsk_rdstl:
- ld temp,z+
- mem_write
- adiw x,1
- dec temp3
- brne rdsk_rdstl
- ret
-
-
-rdsk_wr:
-.if DISK_DEBUG > 1
- printnewline
- printstring "wr-adr: "
-.endif
- lds xl,dmaadr
- lds xh,dmaadr+1
- ldiw z,rdskbuf
- ldi temp3,128
-rdsk_wrldl:
- mem_read
- st z+,temp
- adiw x,1
- dec temp3
- brne rdsk_wrldl
-
- ldi temp2,RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp2
- rcall rdsk_adr
-rdsk_wrl:
- ld temp,z+
- mov temp2,temp
- andi temp,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp,(1<<ram_cas)
- out PORTC,temp
- DRAM_SETADDR xl, ~(1<<ram_ras),0, ~((1<<ram_a8)),(1<<ram_oe)
- cbi PORTC,ram_cas
- sbi PORTD,ram_a8
- sbi PORTC,ram_cas
- swap temp2
- andi temp2,RAM_DQ_MASK & ~(1<<ram_w)
- ori temp2,(1<<ram_cas)
- out PORTC,temp2
- cbi PORTC,ram_cas
- inc xl
- sbi PORTC,ram_cas
- dec temp3
- brne rdsk_wrl
-
- sbi P_RAS,ram_ras
- ldi temp,~RAM_DQ_MASK | (1<<ram_w) | (1<<ram_cas)
- out DDRC,temp
- out PORTC,temp
- ret
-
-
-#endif /* RAMDISKCNT */
-
-;---------------------------------------------------------------------
-
-; Partition table offsets:
-#define PART_TYPE 4
-#define PART_START 8
-#define PART_SIZE 12
-
- .dseg
-tmp_tbl:
- .byte 8*MAXDISKS
-
- .cseg
-dsk_partinit:
- sts ndisks,_0
- rcall mmcInit
- andi temp,MMCST_NOINIT & MMCST_NODISK
- brne dsk_pierr
-
-;Load first sector from MMC (boot sector)
- ldiw y,0 ; Sector 0
- movw x,y
- rcall mmcReadSect
- tst temp
- breq dsk_pi1
-
-dsk_pierr:
- clr temp
- ret
-
-dsk_pi1:
- ldiw y,tmp_tbl
- ldi temp2,8*MAXDISKS
-dsk_picl:
- st y+,_0
- dec temp2
- brne dsk_picl
- sbiw y,8*MAXDISKS
-
-;Test, if it has a valid MBR
-
- ldiw z,hostbuf+510-1 ;Point to last byte of partition table
-
- ldi temp3,0 ;temp3 holds number of found disks (paritions)
- ldd temp,z+1 ;MBR signature (0xAA55) at and of sector?
- ldd temp2,z+2
- ldi temp4,0xAA
- cpi temp,0x55
- cpc temp2,temp4
- breq dsk_part
-
-;No MBR, no partition table ...
- inc temp3 ;pretend we have one.
- ldi temp,high((1<<16) * 128/512)
- std y+0,_0 ;start at beginning of card
- std y+1,_0
- std y+2,_0
- std y+3,_0
- std y+4,_0 ;max CP/M 2.2 disk size
- std y+5,temp ;
- std y+6,_0
- std y+7,_0
- rjmp dsk_pend
-
-;Search Partition Table for CP/M partitions
-dsk_part:
- sbiw z,63 ;Now at first byte of partition table
- ldi temp4,high(hostbuf+510)
-dsk_ploop:
- ldd temp,z+PART_TYPE
- cpi temp,PARTID
- brne dsk_nextp
-
-; Found a CP/M partition
-
- ldd temp,z+PART_START
- st y+,temp
- ldd temp,z+PART_START+1
- st y+,temp
- ldd temp,z+PART_START+2
- st y+,temp
- ldd temp,z+PART_START+3
- st y+,temp
-
- ldd temp,z+PART_SIZE
- st y+,temp
- ldd temp,z+PART_SIZE+1
- st y+,temp
- ldd temp,z+PART_SIZE+2
- st y+,temp
- ldd temp,z+PART_SIZE+3
- st y+,temp
-
- inc temp3
- cpi temp3,MAXDISKS
- breq dsk_pend
-dsk_nextp:
- adiw zl,16
- cpi zl,low(hostbuf+510)
- cpc zh,temp4
- brlo dsk_ploop
-
-dsk_pend:
-
-;Store new partitions and check if the SD card has been changed.
-
- ldiw y,tmp_tbl
- ldiw z,hostparttbl
- ldi temp4,8*MAXDISKS
- clt
-dsk_pcpl:
- ld temp,y+
- ld temp2,z
- st z+,temp
- cpse temp,temp2
- set
- dec temp4
- brne dsk_pcpl
-
- mov temp,temp3
- sts ndisks,temp
- brtc dsk_pcpe
-
- tst temp
- breq dsk_pcpe
-
-; SD card changed.
- sbr temp,0x80
-
-dsk_pcpe:
- ret
-
-;---------------------------------------------------------------------
-; Print partition table info
-
-prnt_parttbl:
- ldiw z,hostparttbl
-pprl:
- ldd xl,z+4 ;Get partition size
- ldd xh,z+5
- ldd yl,z+6
- ldd yh,z+7
- cp xl,_0 ;If zero ...
- cpc xh,_0
- cpc yl,_0
- cpc yh,_0
- breq pppre ;... No more partitions.
-
- ldd temp,z+0 ;Get partition start
- ldd temp2,z+1
- ldd temp3,z+2
- ldd temp4,z+3
- printnewline
- cp temp,_0 ;If zero ...
- cpc temp2,_0
- cpc temp3,_0
- cpc temp4,_0
- breq prnop ;... no partition table at 0
-
- rcall prstr_table
- rjmp pprsz
-prnop:
- rcall prstr_image
-pprsz:
- rcall print_ultoa
- printstring ", size: "
- movw temp,x
- movw temp3,y
-
- lsr temp4
- ror temp3
- ror temp2
- ror temp
- rcall print_ultoa
- printstring "KB."
-
- adiw z,8
- ldi temp,high(hostparttbltop)
- cpi zl, low (hostparttbltop)
- cpc zh,temp
- brlo pprl
-pppre:
- ret
-
-prstr_table:
- printstring "CP/M partition at: "
- ret
-prstr_image:
- printstring "Assuming CP/M image at: "
- ret
; ****************************************************************************
--- /dev/null
+; Virtual Ports for the BIOS Interaction
+;
+; 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 <http://www.gnu.org/licenses/>.
+;
+; $Id$
+;\r
+\r
+\r
+; ---------------- Defines for the Virtual peripherial interface -------
+
+;The hw is modelled to make writing a CPM BIOS easier.
+;Ports:
+;0 - Con status. Returns 0xFF if the UART has a byte, 0 otherwise.
+;1 - Console input, aka UDR.
+;2 - Console output
+;3 - "UART" status: bit 0=rx, bit 1 = tx
+;4 - "UART" data register, no wait
+;15 - Disk select
+;16,17 - Track select
+;18 - Sector select
+;20 - Write addr l
+;21 - Write addr h
+;22 - Trigger - write to read, to write a sector using the above info;
+; , write to allocated/dirctory/unallocated
+
+ .equ READ_FUNC = 7
+ .equ WRITE_FUNC = 6
+ .equ BOOT_FUNC = 5
+ .equ HOME_FUNC = 4
+\r
+;----------------------------------------------- Start of Data Segment
+
+ .dseg\r
+\r
+\r
+; ---------------------------------------------- Start of Code Segment
+ .cseg\r
+\r
+uartstat:
+ clr temp
+ lds temp2,rxcount
+ cpse temp2,_0
+ sbr temp,0x01
+ lds temp2,txcount
+ cpi temp2,TXBUFSIZE
+ breq uartst_1
+ sbr temp,0x02
+uartst_1:
+ ret
+
+uartout:
+ lds temp2,txcount
+ cpi temp2,TXBUFSIZE
+ breq uartout_1
+ rjmp uartputc
+uartout_1:
+ ret
+
+uartin:
+ clr temp
+ lds temp2,rxcount
+ cpse temp2,_0
+ rjmp uartgetc
+ ret\r
+\r
+conStatus:
+ lds temp,rxcount
+ cpse temp,_0
+ ldi temp,0xff
+ ret
+
+conInp:
+ rjmp uartgetc
+
+dbgOut:
+ printnewline
+ printstring "Debug: "
+ rcall printhex
+ ret
+
+conOut:
+ rjmp uartputc\r
+\r
+;Called with port in temp2. Should return value in temp.
+portRead:
+ cpi temp2,0
+ breq conStatus
+ cpi temp2,1
+ breq conInp
+ cpi temp2,3
+ breq uartstat
+ cpi temp2,4
+ breq uartin
+
+ cpi temp2,15
+ breq dskDiskCheck
+ cpi temp2,22
+ breq dskErrorRet
+
+ cpi temp2,TIMER_MSECS
+ brlo pr_noclock
+ cpi temp2,TIMER_MSECS+6
+ brsh pr_noclock
+ rjmp clockget
+
+pr_noclock:
+ ldi temp,0xFF
+ ret
+
+;Called with port in temp2 and value in temp.
+portWrite:
+ cpi temp2,0
+ breq dbgOut
+ cpi temp2,2
+ breq conOut
+ cpi temp2,4
+ breq uartout
+
+ cpi temp2,15
+ breq dskDiskSel
+ cpi temp2,16
+ breq dskTrackSel_l
+ cpi temp2,17
+ breq dskTrackSel_h
+ cpi temp2,18
+ breq dskSecSel
+ cpi temp2,20
+ breq dskDmaL
+ cpi temp2,21
+ breq dskDmaH
+
+ cpi temp2,22
+ breq dskDoIt
+
+ cpi temp2,TIMERPORT
+ brlo pw_noclock
+ cpi temp2,TIMER_MSECS+6
+ brsh pw_noclock
+ rjmp clockput
+
+pw_noclock:
+ ret\r
+\r
+
+\r
+
+;---------------------------------------------------------------------