From f99e55222427de080be8756ca6f47216c43b7292 Mon Sep 17 00:00:00 2001 From: sorgelig Date: Tue, 29 May 2018 14:12:40 +0800 Subject: [PATCH] minimig_hdd: cleanup and refactoring. --- minimig_hdd.cpp | 872 ++++++++++++++++++----------------------- minimig_hdd.h | 4 +- minimig_hdd_internal.h | 2 + 3 files changed, 380 insertions(+), 498 deletions(-) diff --git a/minimig_hdd.cpp b/minimig_hdd.cpp index 7f3e8d0..d6ca154 100644 --- a/minimig_hdd.cpp +++ b/minimig_hdd.cpp @@ -33,20 +33,20 @@ along with this program. If not, see . #include "debug.h" #include "fpga_io.h" -#define CMD_IDECMD 0x04 -#define CMD_IDEDAT 0x08 +#define CMD_IDECMD 0x04 +#define CMD_IDEDAT 0x08 -#define CMD_IDE_REGS_RD 0x80 -#define CMD_IDE_REGS_WR 0x90 -#define CMD_IDE_DATA_WR 0xA0 -#define CMD_IDE_DATA_RD 0xB0 -#define CMD_IDE_STATUS_WR 0xF0 +#define CMD_IDE_REGS_RD 0x80 +#define CMD_IDE_REGS_WR 0x90 +#define CMD_IDE_DATA_WR 0xA0 +#define CMD_IDE_DATA_RD 0xB0 +#define CMD_IDE_STATUS_WR 0xF0 -#define IDE_STATUS_END 0x80 -#define IDE_STATUS_IRQ 0x10 -#define IDE_STATUS_RDY 0x08 -#define IDE_STATUS_REQ 0x04 -#define IDE_STATUS_ERR 0x01 +#define IDE_STATUS_END 0x80 +#define IDE_STATUS_IRQ 0x10 +#define IDE_STATUS_RDY 0x08 +#define IDE_STATUS_REQ 0x04 +#define IDE_STATUS_ERR 0x01 #define ACMD_RECALIBRATE 0x10 #define ACMD_DIAGNOSTIC 0x90 @@ -64,23 +64,120 @@ along with this program. If not, see . // hardfile structure typedef struct { - int enabled; - fileTYPE file; - unsigned long cylinders; - unsigned short heads; - unsigned short sectors; - unsigned short sectors_per_block; - unsigned short partition; // partition no. - long offset; // if a partition, the lba offset of the partition. Can be negative if we've synthesized an RDB. + int unit; + int enabled; + fileTYPE file; + uint32_t cylinders; + uint16_t heads; + uint16_t sectors; + uint16_t sectors_per_block; + int32_t offset; // if a partition, the lba offset of the partition. Can be negative if we've synthesized an RDB. + + uint8_t lu; + int32_t lba, nextlba; + uint16_t sector; + uint16_t cylinder; + uint16_t head; + uint16_t sector_count; } hdfTYPE; -static hdfTYPE hdf[4] = { 0 }; - +static hdfTYPE HDF[4] = { 0 }; static uint8_t sector_buffer[512]; -static unsigned char GetDiskStatus(void) +static void CalcGeometry(hdfTYPE *hdf) { - unsigned char status; + uint32_t head, cyl, spt; + uint32_t sptt[] = { 63, 127, 255, 0 }; + uint32_t total = hdf->file.size / 512; + for (int i = 0; sptt[i] != 0; i++) + { + spt = sptt[i]; + for (head = 4; head <= 16; head++) + { + cyl = total / (head * spt); + if (total <= 1024 * 1024) + { + if (cyl <= 1023) break; + } + else + { + if (cyl < 16383) break; + if (cyl < 32767 && head >= 5) break; + if (cyl <= 65536) break; + } + } + if (head <= 16) break; + } + + hdf->cylinders = cyl; + hdf->heads = (uint16_t)head; + hdf->sectors = (uint16_t)spt; +} + +static void GetRDBGeometry(hdfTYPE *hdf) +{ + struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; + hdf->heads = SWAP(rdb->rdb_Heads); + hdf->sectors = SWAP(rdb->rdb_Sectors); + hdf->cylinders = SWAP(rdb->rdb_Cylinders); + if (hdf->sectors > 255 || hdf->heads > 16) + { + printf("ATTN: Illegal CHS value(s)."); + if (!(hdf->sectors & 1) && (hdf->sectors < 512) && (hdf->heads <= 8)) + { + printf(" Translate: sectors %d->%d, heads %d->%d.\n", hdf->sectors, hdf->sectors / 2, hdf->heads, hdf->heads * 2); + hdf->sectors /= 2; + hdf->heads *= 2; + return; + } + + printf(" DANGEROUS: Cannot translate to legal CHS values. Re-calculate the CHS.\n"); + CalcGeometry(hdf); + } +} + +static void SetHardfileGeometry(hdfTYPE *hdf, int isHDF) +{ + struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; + uint8_t flg = 0; + + hdf->offset = 0; + + for (int i = 0; i<16; ++i) + { + if (!FileReadSec(&hdf->file, sector_buffer)) break; + for (int i = 0; i < 512; i++) flg |= sector_buffer[i]; + + if (rdb->rdb_ID == RDB_MAGIC) + { + printf("Found RDB header -> native Amiga image.\n"); + GetRDBGeometry(hdf); + return; + } + } + + if (isHDF && flg) + { + //use UAE settings. + hdf->heads = 1; + hdf->sectors = 32; + + int spc = hdf->heads * hdf->sectors; + hdf->cylinders = hdf->file.size / (512 * spc) + 1; + hdf->offset = -spc; + + printf("No RDB header found in HDF image. Assume it's image of single partition. Use Virtual RDB header.\n"); + } + else + { + CalcGeometry(hdf); + printf("No RDB header found. Possible non-Amiga or empty image.\n"); + } +} + +static uint8_t GetDiskStatus(void) +{ + uint8_t status; EnableFpga(); status = (uint8_t)(spi_w(0) >> 8); @@ -106,14 +203,14 @@ static uint32_t RDBChecksum(uint32_t *p, int set) } // if the HDF file doesn't have a RigidDiskBlock, we synthesize one -static void FakeRDB(int unit, int block) +static void FakeRDB(hdfTYPE *hdf) { int i; // start by clearing the sector buffer memset(sector_buffer, 0, 512); // if we're asked for LBA 0 we create an RDSK block, and if LBA 1, a PART block - switch (block) + switch (hdf->lba) { case 0: { // RDB @@ -133,9 +230,9 @@ static void FakeRDB(int unit, int block) rdb->rdb_Reserved1[3] = 0xffffffff; rdb->rdb_Reserved1[4] = 0xffffffff; rdb->rdb_Reserved1[5] = 0xffffffff; - rdb->rdb_Cylinders = hdf[unit].cylinders; - rdb->rdb_Sectors = hdf[unit].sectors; - rdb->rdb_Heads = hdf[unit].heads; + rdb->rdb_Cylinders = hdf->cylinders; + rdb->rdb_Sectors = hdf->sectors; + rdb->rdb_Heads = hdf->heads; rdb->rdb_Interleave = 1; rdb->rdb_Park = rdb->rdb_Cylinders; rdb->rdb_WritePreComp = rdb->rdb_Cylinders; @@ -164,15 +261,15 @@ static void FakeRDB(int unit, int block) pb->pb_Flags = 0x1; // bootable pb->pb_DevFlags = 0; strcpy(pb->pb_DriveName, "0HD\003"); // "DHx" BCPL string - pb->pb_DriveName[0] = unit + '0'; + pb->pb_DriveName[0] = hdf->unit + '0'; pb->pb_Environment.de_TableSize = 0x10; pb->pb_Environment.de_SizeBlock = 0x80; - pb->pb_Environment.de_Surfaces = hdf[unit].heads; + pb->pb_Environment.de_Surfaces = hdf->heads; pb->pb_Environment.de_SectorPerBlock = 1; - pb->pb_Environment.de_BlocksPerTrack = hdf[unit].sectors; + pb->pb_Environment.de_BlocksPerTrack = hdf->sectors; pb->pb_Environment.de_Reserved = 2; pb->pb_Environment.de_LowCyl = 1; - pb->pb_Environment.de_HighCyl = hdf[unit].cylinders - 1; + pb->pb_Environment.de_HighCyl = hdf->cylinders - 1; pb->pb_Environment.de_NumBuffers = 30; pb->pb_Environment.de_MaxTransfer = 0xffffff; pb->pb_Environment.de_Mask = 0x7ffffffe; @@ -186,23 +283,23 @@ static void FakeRDB(int unit, int block) } // builds Identify Device struct -static void IdentifyDevice(unsigned short *pBuffer, unsigned char unit) +static void IdentifyDevice(uint16_t *pBuffer, hdfTYPE *hdf) { char *p, i, x; - unsigned long total_sectors = hdf[unit].cylinders * hdf[unit].heads * hdf[unit].sectors; + uint32_t total_sectors = hdf->cylinders * hdf->heads * hdf->sectors; memset(pBuffer, 0, 512); - if(hdf[unit].enabled) + if(hdf->enabled) { pBuffer[0] = 1 << 6; // hard disk - pBuffer[1] = hdf[unit].cylinders; // cyl count - pBuffer[3] = hdf[unit].heads; // head count - pBuffer[6] = hdf[unit].sectors; // sectors per track + pBuffer[1] = hdf->cylinders; // cyl count + pBuffer[3] = hdf->heads; // head count + pBuffer[6] = hdf->sectors; // sectors per track // FIXME - can get serial no from card itself. memcpy((char*)&pBuffer[10], "MiniMigHardfile0000 ", 20); // serial number - byte swapped p = (char*)&pBuffer[27]; - if (hdf[unit].offset < 0) + if (hdf->offset < 0) { memcpy((char*)&pBuffer[23], ".000 ", 8); // firmware version - byte swapped memcpy(p, "DON'T REPARTITION! ", 40); @@ -212,9 +309,9 @@ static void IdentifyDevice(unsigned short *pBuffer, unsigned char unit) memcpy((char*)&pBuffer[23], ".100 ", 8); // firmware version - byte swapped memcpy(p, "MiSTer ", 40); // model name - byte swapped p += 8; - char *s = strrchr(config.hardfile[unit].filename, '/'); + char *s = strrchr(config.hardfile[hdf->unit].filename, '/'); if (s) s++; - else s = config.hardfile[unit].filename; + else s = config.hardfile[hdf->unit].filename; i = strlen(s); if (i > 32) s += i - 32; @@ -233,40 +330,14 @@ static void IdentifyDevice(unsigned short *pBuffer, unsigned char unit) pBuffer[47] = 0x8010; // maximum sectors per block in Read/Write Multiple command pBuffer[49] = 1<<9; // LBA support pBuffer[53] = 1; - pBuffer[54] = hdf[unit].cylinders; - pBuffer[55] = hdf[unit].heads; - pBuffer[56] = hdf[unit].sectors; - pBuffer[57] = (unsigned short)total_sectors; - pBuffer[58] = (unsigned short)(total_sectors >> 16); + pBuffer[54] = hdf->cylinders; + pBuffer[55] = hdf->heads; + pBuffer[56] = hdf->sectors; + pBuffer[57] = (uint16_t)total_sectors; + pBuffer[58] = (uint16_t)(total_sectors >> 16); } -static uint32_t chs2lba(unsigned short cylinder, unsigned char head, unsigned short sector, unsigned char unit) -{ - unsigned char uselba = head & 0x40; - head &= 0xF; - - uint32_t lba; - - if (uselba) - { - lba = (head << 24) | (cylinder << 8) | sector; - } - else - { - lba = cylinder; - lba *= hdf[unit].heads; - lba += head; - lba *= hdf[unit].sectors; - lba = lba + sector - 1; - - } - - //printf("IDE%d chs2lba(%s: %d,%d,%d) -> %d\n", unit, uselba ? "LBA" : "CHS", cylinder, head, sector, lba); - - return lba; -} - -static void WriteTaskFile(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned char cylinder_low, unsigned char cylinder_high, unsigned char drive_head) +static void WriteTaskFile(uint8_t error, uint8_t sector_count, uint8_t sector_number, uint8_t cylinder_low, uint8_t cylinder_high, uint8_t drive_head) { EnableFpga(); @@ -285,19 +356,7 @@ static void WriteTaskFile(unsigned char error, unsigned char sector_count, unsig DisableFpga(); } -static void WriteTaskFileEx(unsigned char error, unsigned char sector_count, unsigned char sector_number, unsigned short cylinder, unsigned char drive_head, uint32_t lba) -{ - if (drive_head & 0x40) - { - WriteTaskFile(error, sector_count, (unsigned char)lba, (unsigned char)(lba>>8), (unsigned char)(lba >> 16), (drive_head&0xF0)|((unsigned char)(lba >> 24)&0xF)); - } - else - { - WriteTaskFile(error, sector_count, sector_number, (unsigned char)cylinder, (unsigned char)(cylinder >> 8), drive_head); - } -} - -static void WriteStatus(unsigned char status) +static void WriteStatus(uint8_t status) { EnableFpga(); spi_w((CMD_IDE_STATUS_WR<<8) | status); @@ -306,15 +365,15 @@ static void WriteStatus(unsigned char status) DisableFpga(); } -static void ATA_Recalibrate(unsigned char* tfr, unsigned char unit) +static void ATA_Recalibrate(uint8_t* tfr, hdfTYPE *hdf) { // Recalibrate 0x10-0x1F (class 3 command: no data) - hdd_debugf("IDE%d: Recalibrate", unit); - WriteTaskFileEx(0, 0, 1, 0, tfr[6] & 0xF0, 0); + hdd_debugf("IDE%d: Recalibrate", hdf->unit); + WriteTaskFile(0, 0, tfr[6] & 0x40 ? 0 : 1, 0, 0, tfr[6] & 0xF0); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } -static void ATA_Diagnostic(unsigned char* tfr) +static void ATA_Diagnostic(uint8_t* tfr, hdfTYPE *hdf) { // Execute Drive Diagnostic (0x90) hdd_debugf("IDE: Drive Diagnostic"); @@ -322,12 +381,12 @@ static void ATA_Diagnostic(unsigned char* tfr) WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } -static void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit) +static void ATA_IdentifyDevice(uint8_t* tfr, hdfTYPE *hdf) { int i; // Identify Device (0xec) - hdd_debugf("IDE%d: Identify Device", unit); - IdentifyDevice((uint16_t*)sector_buffer, unit); + hdd_debugf("IDE%d: Identify Device", hdf->unit); + IdentifyDevice((uint16_t*)sector_buffer, hdf); WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type EnableFpga(); @@ -339,27 +398,104 @@ static void ATA_IdentifyDevice(unsigned char* tfr, unsigned char unit) WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } -static void ATA_Initialize(unsigned char* tfr, unsigned char unit) +static void ATA_Initialize(uint8_t* tfr, hdfTYPE *hdf) { // Initialize Device Parameters (0x91) hdd_debugf("Initialize Device Parameters"); - hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); + hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", hdf->unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); WriteTaskFile(0, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } -static void ATA_SetMultipleMode(unsigned char* tfr, unsigned char unit) +static void ATA_SetMultipleMode(uint8_t* tfr, hdfTYPE *hdf) { // Set Multiple Mode (0xc6) hdd_debugf("Set Multiple Mode"); - hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); - hdf[unit].sectors_per_block = tfr[2]; + hdd_debugf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X", hdf->unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); + hdf->sectors_per_block = tfr[2]; WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); } -static int HardFileSeek(hdfTYPE *pHDF, unsigned long lba) +static int Preface(uint8_t* tfr, hdfTYPE *hdf) { - return FileSeekLBA(&pHDF->file, lba); + hdf->sector = tfr[3]; + hdf->cylinder = tfr[4] | (tfr[5] << 8); + hdf->head = tfr[6] & 0x0F; + hdf->lu = tfr[6] & 0xF0; + hdf->sector_count = tfr[2]; + if (hdf->sector_count == 0) hdf->sector_count = 256; + + uint8_t uselba = hdf->lu & 0x40; + + if (uselba) + { + hdf->lba = (hdf->head << 24) | (hdf->cylinder << 8) | hdf->sector; + } + else + { + hdf->lba = hdf->cylinder; + hdf->lba *= hdf->heads; + hdf->lba += hdf->head; + hdf->lba *= hdf->sectors; + hdf->lba += hdf->sector - 1; + } + + //printf("setCHS: %s: %d,%d,%d -> %d\n", uselba ? "LBA" : "CHS", hdf->cylinder, hdf->head, hdf->sector, hdf->lba); + hdf->nextlba = hdf->lba; + + if (hdf->enabled && hdf->lba >= 0 && hdf->file.size) + { + FileSeekLBA(&hdf->file, (hdf->lba + hdf->offset) < 0 ? 0 : hdf->lba + hdf->offset); + return 1; + } + + return 0; +} + +static void nextCHS(hdfTYPE *hdf) +{ + // do not increment after last sector + if (hdf->sector_count) + { + hdf->nextlba++; + if (hdf->lu & 0x40) + { + hdf->sector = (uint8_t)hdf->nextlba; + hdf->cylinder = (uint16_t)(hdf->nextlba >> 8); + hdf->head = 0xF & (uint8_t)(hdf->nextlba >> 24); + } + else + { + if (hdf->sector == hdf->sectors) + { + hdf->sector = 1; + hdf->head++; + if (hdf->head == hdf->heads) + { + hdf->head = 0; + hdf->cylinder++; + } + } + else + { + hdf->sector++; + } + } + } +} + +static void updateTaskFile(hdfTYPE *hdf) +{ + WriteTaskFile(0, hdf->sector_count, hdf->sector, (uint8_t)hdf->cylinder, (uint8_t)(hdf->cylinder >> 8), (uint8_t)(hdf->lu | hdf->head)); +} + +static void ReadSector(hdfTYPE *hdf) +{ + // sector outside limit (fake rdb header) + if ((hdf->lba + hdf->offset) < 0) + FakeRDB(hdf); + else + FileReadSec(&hdf->file, sector_buffer); } static void SendSector() @@ -382,200 +518,15 @@ static void RecvSector() DisableFpga(); } -static void ATA_ReadSectors(unsigned char* tfr, unsigned char unit) +static void WriteSector(hdfTYPE *hdf) { - // Read Sectors (0x20) - long lba, nextlba; - unsigned short sector = tfr[3]; - unsigned short cylinder = tfr[4] | (tfr[5] << 8); - unsigned short head = tfr[6] & 0x0F; - unsigned short sector_count = tfr[2]; - if (sector_count == 0) sector_count = 0x100; - hdd_debugf("IDE%d: read %d.%d.%d, %d", unit, cylinder, head, sector, sector_count); + //Do not write to fake RDB header + if ((hdf->lba + hdf->offset) < 0) return; - if(hdf[unit].enabled && ((lba = chs2lba(cylinder, tfr[6], sector, unit))>=0)) + //Write RDB header, grab the CHS! + if (!hdf->offset && hdf->lba < 16 && (*(uint32_t*)sector_buffer) == RDB_MAGIC) { - nextlba = lba; - - if (hdf[unit].file.size) HardFileSeek(&hdf[unit], (lba + hdf[unit].offset) < 0 ? 0 : lba + hdf[unit].offset); - while (sector_count) - { - if (sector_count != 1) { - if (sector == hdf[unit].sectors) { - sector = 1; - head++; - if (head == hdf[unit].heads) { - head = 0; - cylinder++; - } - } - else { - sector++; - } - nextlba++; - } - - WriteTaskFileEx(0, tfr[2], sector, cylinder, (tfr[6] & 0xF0) | head, nextlba); - WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type - - // sector outside limit (fake rdb header) or to be modified sector of first partition - if (((lba + hdf[unit].offset)<0) || (!unit && !lba)) - { - if ((lba + hdf[unit].offset)<0) - { - FakeRDB(unit, lba); - } - else - { - // read sector into buffer - FileReadSec(&hdf[unit].file, sector_buffer); - // adjust checksum by the difference between old and new flag value - struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; - rdb->rdb_ChkSum = SWAP(SWAP(rdb->rdb_ChkSum) + SWAP(rdb->rdb_Flags) - 0x12); - - // adjust flags - rdb->rdb_Flags = SWAP(0x12); - } - - EnableFpga(); - SendSector(); - WriteStatus(sector_count == 1 ? IDE_STATUS_IRQ | IDE_STATUS_END : IDE_STATUS_IRQ); - } - else - { - while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer - WriteStatus(IDE_STATUS_IRQ); - if (hdf[unit].file.size) - { - FileReadSec(&hdf[unit].file, sector_buffer); - SendSector(); - } - } - lba++; - sector_count--; // decrease sector count - } - } -} - -// multiple sector transfer per IRQ -static void ATA_ReadMultiple(unsigned char* tfr, unsigned char unit) -{ - WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type - - long lba, nextlba; - unsigned short sector = tfr[3]; - unsigned short cylinder = tfr[4] | (tfr[5] << 8); - unsigned short head = tfr[6] & 0x0F; - unsigned short sector_count = tfr[2]; - if (sector_count == 0) sector_count = 0x100; - hdd_debugf("IDE%d: read_multi %d.%d.%d, %d", unit, cylinder, head, sector, sector_count); - - if (hdf[unit].enabled && ((lba = chs2lba(cylinder, tfr[6], sector, unit)) >= 0)) - { - nextlba = lba; - - if (hdf[unit].file.size) HardFileSeek(&hdf[unit], (lba + hdf[unit].offset) < 0 ? 0 : lba + hdf[unit].offset); - while (sector_count) - { - while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer - unsigned short block_count = sector_count; - if (block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block; - WriteStatus(IDE_STATUS_IRQ); - while (block_count--) - { - if (hdf[unit].file.size) - { - if ((lba + hdf[unit].offset)<0) - { - FakeRDB(unit, lba); - } - else - { - FileReadSec(&hdf[unit].file, sector_buffer); - } - SendSector(); - } - if (sector_count != 1) - { - if (sector == hdf[unit].sectors) - { - sector = 1; - head++; - if (head == hdf[unit].heads) - { - head = 0; - cylinder++; - } - } - else - { - sector++; - } - nextlba++; - } - lba++; - sector_count--; - } - WriteTaskFileEx(0, tfr[2], sector, cylinder, (tfr[6] & 0xF0) | head, nextlba); - } - } - WriteStatus(IDE_STATUS_END); -} - -static void GetRDBGeometry(hdfTYPE *pHDF) -{ - struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; - pHDF->heads = SWAP(rdb->rdb_Heads); - pHDF->sectors = SWAP(rdb->rdb_Sectors); - pHDF->cylinders = SWAP(rdb->rdb_Cylinders); - if (pHDF->sectors > 255 || pHDF->heads > 16) - { - printf("ATTN: Illegal CHS value(s)."); - if (!(pHDF->sectors & 1) && (pHDF->sectors < 512) && (pHDF->heads <= 8)) - { - printf(" Translate: sectors %d->%d, heads %d->%d.\n", pHDF->sectors, pHDF->sectors / 2, pHDF->heads, pHDF->heads * 2); - pHDF->sectors /= 2; - pHDF->heads *= 2; - return; - } - - printf(" DANGEROUS: Cannot translate to legal CHS values. Re-calculate the CHS.\n"); - - uint32_t head, cyl, spt; - uint32_t sptt[] = { 63, 127, 255, 0 }; - uint32_t total = pHDF->file.size / 512; - for (int i = 0; sptt[i] != 0; i++) - { - spt = sptt[i]; - for (head = 4; head <= 16; head++) - { - cyl = total / (head * spt); - if (total <= 1024 * 1024) - { - if (cyl <= 1023) break; - } - else - { - if (cyl < 16383) break; - if (cyl < 32767 && head >= 5) break; - if (cyl <= 65536) break; - } - } - if (head <= 16) break; - } - - pHDF->cylinders = cyl; - pHDF->heads = (unsigned short)head; - pHDF->sectors = (unsigned short)spt; - } -} - -static void write_sector(int unit, uint32_t lba) -{ - // Write RDB header, grab the CHS! - if (lba < 16 && (*(uint32_t*)sector_buffer) == 0x4B534452) - { - printf("Writing RDB header, LBA=%d: ", lba); + printf("Writing RDB header, LBA=%d: ", hdf->lba); uint32_t sum = RDBChecksum((uint32_t*)sector_buffer, 0); if (sum) { @@ -583,151 +534,136 @@ static void write_sector(int unit, uint32_t lba) } else { - GetRDBGeometry(&hdf[unit]); - printf("Using new CHS: %u/%u/%u (%lu MB)\n", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors, ((((unsigned long)hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11)); + GetRDBGeometry(hdf); + printf("Using new CHS: %u/%u/%u (%lu MB)\n", hdf->cylinders, hdf->heads, hdf->sectors, ((((uint32_t)hdf->cylinders) * hdf->heads * hdf->sectors) >> 11)); } } - FileWriteSec(&hdf[unit].file, sector_buffer); + FileWriteSec(&hdf->file, sector_buffer); } -static void ATA_WriteSectors(unsigned char* tfr, unsigned char unit) +// Read Sectors (0x20) +static void ATA_ReadSectors(uint8_t* tfr, hdfTYPE *hdf) +{ + WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type + + if(Preface(tfr, hdf)) + { + while (hdf->sector_count) + { + while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer + WriteStatus(IDE_STATUS_IRQ); + + ReadSector(hdf); + + // to be modified sector of first partition + if (!hdf->unit && !hdf->lba) + { + struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; + if (rdb->rdb_ID == RDB_MAGIC) + { + // adjust checksum by the difference between old and new flag value + rdb->rdb_ChkSum = SWAP(SWAP(rdb->rdb_ChkSum) + SWAP(rdb->rdb_Flags) - 0x12); + rdb->rdb_Flags = SWAP(0x12); + } + } + SendSector(); + + hdf->lba++; + hdf->sector_count--; + nextCHS(hdf); + updateTaskFile(hdf); + } + } + WriteStatus(IDE_STATUS_END); +} + +// multiple sector transfer per IRQ +static void ATA_ReadMultiple(uint8_t* tfr, hdfTYPE *hdf) +{ + WriteStatus(IDE_STATUS_RDY); // pio in (class 1) command type + + if (Preface(tfr, hdf)) + { + while (hdf->sector_count) + { + while (!(GetDiskStatus() & CMD_IDECMD)); // wait for empty sector buffer + uint16_t block_count = hdf->sector_count; + if (block_count > hdf->sectors_per_block) block_count = hdf->sectors_per_block; + WriteStatus(IDE_STATUS_IRQ); + while (block_count--) + { + ReadSector(hdf); + SendSector(); + + hdf->lba++; + hdf->sector_count--; + nextCHS(hdf); + } + updateTaskFile(hdf); + } + } + WriteStatus(IDE_STATUS_END); +} + +static void ATA_WriteSectors(uint8_t* tfr, hdfTYPE *hdf) { WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type - long lba, nextlba; - unsigned short sector = tfr[3]; - unsigned short cylinder = tfr[4] | (tfr[5] << 8); - unsigned short head = tfr[6] & 0x0F; - unsigned short sector_count = tfr[2]; - if (sector_count == 0) sector_count = 0x100; - - if (hdf[unit].enabled && ((lba = chs2lba(cylinder, tfr[6], sector, unit)) >= 0)) + if (Preface(tfr, hdf)) { - nextlba = lba; - - lba += hdf[unit].offset; - if (hdf[unit].file.size) - { - // File size will be 0 in direct card modes - HardFileSeek(&hdf[unit], (lba > -1) ? lba : 0); - } - - while (sector_count) + hdf->lba += hdf->offset; + while (hdf->sector_count) { while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer - // decrease sector count - if (sector_count != 1) - { - if (sector == hdf[unit].sectors) - { - sector = 1; - head++; - if (head == hdf[unit].heads) - { - head = 0; - cylinder++; - } - } - else - { - sector++; - } - nextlba++; - } - WriteTaskFileEx(0, tfr[2], sector, cylinder, (tfr[6] & 0xF0) | head, nextlba); - RecvSector(); - sector_count--; // decrease sector count - if (sector_count) - { - WriteStatus(IDE_STATUS_IRQ); - } - else - { - WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); - } - // Don't attempt to write to fake RDB - if (hdf[unit].file.size && (lba > -1)) write_sector(unit, lba); - lba++; + RecvSector(); + hdf->sector_count--; + + nextCHS(hdf); + updateTaskFile(hdf); + WriteStatus(hdf->sector_count ? IDE_STATUS_IRQ : IDE_STATUS_END | IDE_STATUS_IRQ); + + WriteSector(hdf); + hdf->lba++; } } } -static void ATA_WriteMultiple(unsigned char* tfr, unsigned char unit) +static void ATA_WriteMultiple(uint8_t* tfr, hdfTYPE *hdf) { - // write sectors WriteStatus(IDE_STATUS_REQ); // pio out (class 2) command type - long lba, nextlba; - unsigned short sector = tfr[3]; - unsigned short cylinder = tfr[4] | (tfr[5] << 8); - unsigned short head = tfr[6] & 0x0F; - unsigned short sector_count = tfr[2]; - if (sector_count == 0) sector_count = 0x100; - - if (hdf[unit].enabled && ((lba = chs2lba(cylinder, tfr[6], sector, unit)) >= 0)) + if (Preface(tfr, hdf)) { - nextlba = lba; - - lba += hdf[unit].offset; - if (hdf[unit].file.size) + hdf->lba += hdf->offset; + while (hdf->sector_count) { - // File size will be 0 in direct card modes - HardFileSeek(&hdf[unit], (lba > -1) ? lba : 0); - } - - while (sector_count) - { - unsigned short block_count = sector_count; - if (block_count > hdf[unit].sectors_per_block) block_count = hdf[unit].sectors_per_block; + uint16_t block_count = hdf->sector_count; + if (block_count > hdf->sectors_per_block) block_count = hdf->sectors_per_block; while (block_count) { while (!(GetDiskStatus() & CMD_IDEDAT)); // wait for full write buffer - // decrease sector count - if (sector_count != 1) - { - if (sector == hdf[unit].sectors) - { - sector = 1; - head++; - if (head == hdf[unit].heads) - { - head = 0; - cylinder++; - } - } - else - { - sector++; - } - nextlba++; - } - RecvSector(); - if (hdf[unit].file.size && (lba > -1)) write_sector(unit, lba); - lba++; - block_count--; // decrease block count - sector_count--; // decrease sector count - } - WriteTaskFileEx(0, tfr[2], sector, cylinder, (tfr[6] & 0xF0) | head, nextlba); - if (sector_count) - { - WriteStatus(IDE_STATUS_IRQ); - } - else - { - WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ); + RecvSector(); + WriteSector(hdf); + hdf->lba++; + + block_count--; + hdf->sector_count--; + nextCHS(hdf); } + updateTaskFile(hdf); + WriteStatus(hdf->sector_count ? IDE_STATUS_IRQ : IDE_STATUS_END | IDE_STATUS_IRQ); } } } -void HandleHDD(unsigned char c1, unsigned char c2) +void HandleHDD(uint8_t c1, uint8_t c2) { if (c1 & CMD_IDECMD) { - unsigned char unit = 0; - unsigned char tfr[8]; + uint8_t unit = 0; + uint8_t tfr[8]; DISKLED_ON; EnableFpga(); @@ -735,31 +671,38 @@ void HandleHDD(unsigned char c1, unsigned char c2) spi_w(0); spi_w(0); - //printf("SPI:"); for (int i = 0; i < 8; i++) { uint16_t tmp = spi_w(0); tfr[i] = (uint8_t)tmp; if (i == 6) unit = ((tmp >> 7) & 2) | ((tmp >> 4) & 1); - //printf(" %03X", tmp); } - //printf(" -> unit: %d\n", unit); DisableFpga(); //printf("IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); + hdfTYPE *hdf = &HDF[unit]; - if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) ATA_Recalibrate(tfr, unit); - else if (tfr[7] == ACMD_DIAGNOSTIC) ATA_Diagnostic(tfr); - else if (tfr[7] == ACMD_IDENTIFY_DEVICE) ATA_IdentifyDevice(tfr, unit); - else if (tfr[7] == ACMD_INITIALIZE_PARAMETERS) ATA_Initialize(tfr, unit); - else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) ATA_SetMultipleMode(tfr, unit); - else if (tfr[7] == ACMD_READ_SECTORS) ATA_ReadSectors(tfr, unit); - else if (tfr[7] == ACMD_READ_MULTIPLE) ATA_ReadMultiple(tfr, unit); - else if (tfr[7] == ACMD_WRITE_SECTORS) ATA_WriteSectors(tfr, unit); - else if (tfr[7] == ACMD_WRITE_MULTIPLE) ATA_WriteMultiple(tfr, unit); + if (hdf->enabled) + { + if ((tfr[7] & 0xF0) == ACMD_RECALIBRATE) ATA_Recalibrate (tfr, hdf); + else if (tfr[7] == ACMD_DIAGNOSTIC) ATA_Diagnostic (tfr, hdf); + else if (tfr[7] == ACMD_IDENTIFY_DEVICE) ATA_IdentifyDevice (tfr, hdf); + else if (tfr[7] == ACMD_INITIALIZE_PARAMETERS) ATA_Initialize (tfr, hdf); + else if (tfr[7] == ACMD_SET_MULTIPLE_MODE) ATA_SetMultipleMode (tfr, hdf); + else if (tfr[7] == ACMD_READ_SECTORS) ATA_ReadSectors (tfr, hdf); + else if (tfr[7] == ACMD_READ_MULTIPLE) ATA_ReadMultiple (tfr, hdf); + else if (tfr[7] == ACMD_WRITE_SECTORS) ATA_WriteSectors (tfr, hdf); + else if (tfr[7] == ACMD_WRITE_MULTIPLE) ATA_WriteMultiple (tfr, hdf); + else + { + printf("Unknown ATA command: IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); + WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); + WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR); + } + } else { - printf("Unknown ATA command: IDE%d: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); + printf("IDE%d not enabled: %02X.%02X.%02X.%02X.%02X.%02X.%02X.%02X\n", unit, tfr[0], tfr[1], tfr[2], tfr[3], tfr[4], tfr[5], tfr[6], tfr[7]); WriteTaskFile(0x04, tfr[2], tfr[3], tfr[4], tfr[5], tfr[6]); WriteStatus(IDE_STATUS_END | IDE_STATUS_IRQ | IDE_STATUS_ERR); } @@ -767,96 +710,33 @@ void HandleHDD(unsigned char c1, unsigned char c2) } } -static void SetHardfileGeometry(hdfTYPE *pHDF, int isHDF) +uint8_t OpenHardfile(uint8_t unit) { - struct RigidDiskBlock *rdb = (struct RigidDiskBlock *)sector_buffer; - uint8_t flg = 0; - - pHDF->offset = 0; - - for (int i = 0; i<16; ++i) - { - if (!FileReadSec(&pHDF->file, sector_buffer)) break; - for (int i = 0; i < 512; i++) flg |= sector_buffer[i]; - - if (rdb->rdb_ID == 0x4B534452) - { - printf("Found RDB header -> native Amiga image.\n"); - GetRDBGeometry(pHDF); - return; - } - } - - unsigned long head, cyl, spt; - unsigned long sptt[] = { 63, 127, 255, 0 }; - uint32_t total = pHDF->file.size / 512; - - for (int i = 0; sptt[i] != 0; i++) - { - spt = sptt[i]; - for (head = 4; head <= 16; head++) - { - cyl = total / (head * spt); - if (total <= 1024 * 1024) - { - if (cyl <= 1023) break; - } - else - { - if (cyl < 16383) break; - if (cyl < 32767 && head >= 5) break; - if (cyl <= 65536) break; // Should there some head constraint here? - } - } - if (head <= 16) break; - } - pHDF->cylinders = cyl; - pHDF->heads = (unsigned short)head; - pHDF->sectors = (unsigned short)spt; - - if (isHDF && flg) - { - //use UAE settings. - pHDF->heads = 1; - pHDF->sectors = 32; - - int spc = pHDF->heads * pHDF->sectors; - pHDF->cylinders = pHDF->file.size / (512 * spc) + 1; - pHDF->offset = -spc; - - printf("No RDB header found in HDF image. Assume it's image of single partition. Use Virtual RDB header.\n"); - } - else - { - printf("No RDB header found. Possible non-Amiga or empty image.\n"); - } -} - -unsigned char OpenHardfile(unsigned char unit) -{ - hdf[unit].enabled = 0; + hdfTYPE *hdf = &HDF[unit]; + hdf->unit = unit; + hdf->enabled = 0; if (config.enable_ide && config.hardfile[unit].enabled) { printf("\nChecking HDD %d\n", unit); if (config.hardfile[unit].filename[0]) { - if (FileOpenEx(&hdf[unit].file, config.hardfile[unit].filename, FileCanWrite(config.hardfile[unit].filename) ? O_RDWR : O_RDONLY)) + if (FileOpenEx(&hdf->file, config.hardfile[unit].filename, FileCanWrite(config.hardfile[unit].filename) ? O_RDWR : O_RDONLY)) { - hdf[unit].enabled = 1; - printf("file: \"%s\": ", hdf[unit].file.name); - SetHardfileGeometry(&hdf[unit], !strcasecmp(".hdf", config.hardfile[unit].filename + strlen(config.hardfile[unit].filename) - 4)); - printf("size: %llu (%llu MB)\n", hdf[unit].file.size, hdf[unit].file.size >> 20); - printf("CHS: %u/%u/%u", hdf[unit].cylinders, hdf[unit].heads, hdf[unit].sectors); - printf(" (%lu MB), ", ((((unsigned long)hdf[unit].cylinders) * hdf[unit].heads * hdf[unit].sectors) >> 11)); - printf("Offset: %d\n", hdf[unit].offset); + hdf->enabled = 1; + printf("file: \"%s\": ", hdf->file.name); + SetHardfileGeometry(hdf, !strcasecmp(".hdf", config.hardfile[unit].filename + strlen(config.hardfile[unit].filename) - 4)); + printf("size: %llu (%llu MB)\n", hdf->file.size, hdf->file.size >> 20); + printf("CHS: %u/%u/%u", hdf->cylinders, hdf->heads, hdf->sectors); + printf(" (%lu MB), ", ((((uint32_t)hdf->cylinders) * hdf->heads * hdf->sectors) >> 11)); + printf("Offset: %d\n", hdf->offset); return 1; } } printf("HDD %d: not present\n", unit); } - // close opened before. - FileClose(&hdf[unit].file); + // close if opened earlier. + FileClose(&hdf->file); return 0; } @@ -871,7 +751,7 @@ int checkHDF(const char* name, struct RigidDiskBlock **rdb) for (int i = 0; i<16; ++i) { if (!FileReadSec(&file, sector_buffer)) break; - if ((*rdb)->rdb_ID == 0x4B534452) + if ((*rdb)->rdb_ID == RDB_MAGIC) { FileClose(&file); (*rdb)->rdb_Heads = SWAP((*rdb)->rdb_Heads); diff --git a/minimig_hdd.h b/minimig_hdd.h index 3df900f..e4259a9 100644 --- a/minimig_hdd.h +++ b/minimig_hdd.h @@ -6,8 +6,8 @@ #include "minimig_hdd_internal.h" // functions -void HandleHDD(unsigned char c1, unsigned char c2); -unsigned char OpenHardfile(unsigned char unit); +void HandleHDD(uint8_t c1, uint8_t c2); +uint8_t OpenHardfile(uint8_t unit); int checkHDF(const char* name, struct RigidDiskBlock **rdb); #endif // __HDD_H__ diff --git a/minimig_hdd_internal.h b/minimig_hdd_internal.h index 4d740c0..f8b67ec 100644 --- a/minimig_hdd_internal.h +++ b/minimig_hdd_internal.h @@ -5,6 +5,8 @@ // For hardfiles that have no RDB information, we'll just create a single-partition RDB and Part block // on blocks 0 and 1. All other blocks within the first cylinder will be translated into the hardfile +#define RDB_MAGIC 0x4B534452 // "RDSK" + struct RigidDiskBlock { unsigned long rdb_ID; // "RDSK" unsigned long rdb_Summedlongs; // 0x40