From 7b97435dc72d6863ec879ce4f6b1b27d5df12544 Mon Sep 17 00:00:00 2001 From: Uwe Seimet Date: Tue, 24 Aug 2021 14:54:00 +0200 Subject: [PATCH] Extraced DiskTrack and DiskCache --- src/raspberrypi/devices/disk.cpp | 655 ------------------ src/raspberrypi/devices/disk_track_cache.cpp | 677 +++++++++++++++++++ src/raspberrypi/devices/disk_track_cache.h | 110 +++ 3 files changed, 787 insertions(+), 655 deletions(-) create mode 100644 src/raspberrypi/devices/disk_track_cache.cpp create mode 100644 src/raspberrypi/devices/disk_track_cache.h diff --git a/src/raspberrypi/devices/disk.cpp b/src/raspberrypi/devices/disk.cpp index 53373c9c..06bbd14d 100644 --- a/src/raspberrypi/devices/disk.cpp +++ b/src/raspberrypi/devices/disk.cpp @@ -30,322 +30,6 @@ //=========================================================================== -//=========================================================================== -// -// Disk Track -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -DiskTrack::DiskTrack() -{ - // Initialization of internal information - dt.track = 0; - dt.size = 0; - dt.sectors = 0; - dt.raw = FALSE; - dt.init = FALSE; - dt.changed = FALSE; - dt.length = 0; - dt.buffer = NULL; - dt.maplen = 0; - dt.changemap = NULL; - dt.imgoffset = 0; -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -DiskTrack::~DiskTrack() -{ - // Release memory, but do not save automatically - if (dt.buffer) { - free(dt.buffer); - dt.buffer = NULL; - } - if (dt.changemap) { - free(dt.changemap); - dt.changemap = NULL; - } -} - -//--------------------------------------------------------------------------- -// -// Initialization -// -//--------------------------------------------------------------------------- -void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff) -{ - ASSERT(track >= 0); - ASSERT((size >= 8) && (size <= 11)); - ASSERT((sectors > 0) && (sectors <= 0x100)); - ASSERT(imgoff >= 0); - - // Set Parameters - dt.track = track; - dt.size = size; - dt.sectors = sectors; - dt.raw = raw; - - // Not initialized (needs to be loaded) - dt.init = FALSE; - - // Not Changed - dt.changed = FALSE; - - // Offset to actual data - dt.imgoffset = imgoff; -} - -//--------------------------------------------------------------------------- -// -// Load -// -//--------------------------------------------------------------------------- -BOOL DiskTrack::Load(const Filepath& path) -{ - Fileio fio; - int i; - - // Not needed if already loaded - if (dt.init) { - ASSERT(dt.buffer); - ASSERT(dt.changemap); - return TRUE; - } - - // Calculate offset (previous tracks are considered to - // hold 256 sectors) - off_t offset = ((off_t)dt.track << 8); - if (dt.raw) { - ASSERT(dt.size == 11); - offset *= 0x930; - offset += 0x10; - } else { - offset <<= dt.size; - } - - // Add offset to real image - offset += dt.imgoffset; - - // Calculate length (data size of this track) - int length = dt.sectors << dt.size; - - // Allocate buffer memory - ASSERT((dt.size >= 8) && (dt.size <= 11)); - ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); - - if (dt.buffer == NULL) { - if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { - LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); - } - dt.length = length; - } - - if (!dt.buffer) { - return FALSE; - } - - // Reallocate if the buffer length is different - if (dt.length != (DWORD)length) { - free(dt.buffer); - if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { - LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); - } - dt.length = length; - } - - // Reserve change map memory - if (dt.changemap == NULL) { - dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); - dt.maplen = dt.sectors; - } - - if (!dt.changemap) { - return FALSE; - } - - // Reallocate if the buffer length is different - if (dt.maplen != (DWORD)dt.sectors) { - free(dt.changemap); - dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); - dt.maplen = dt.sectors; - } - - // Clear changemap - memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); - - // Read from File - if (!fio.OpenDIO(path, Fileio::ReadOnly)) { - return FALSE; - } - if (dt.raw) { - // Split Reading - for (i = 0; i < dt.sectors; i++) { - // Seek - if (!fio.Seek(offset)) { - fio.Close(); - return FALSE; - } - - // Read - if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) { - fio.Close(); - return FALSE; - } - - // Next offset - offset += 0x930; - } - } else { - // Continuous reading - if (!fio.Seek(offset)) { - fio.Close(); - return FALSE; - } - if (!fio.Read(dt.buffer, length)) { - fio.Close(); - return FALSE; - } - } - fio.Close(); - - // Set a flag and end normally - dt.init = TRUE; - dt.changed = FALSE; - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Save -// -//--------------------------------------------------------------------------- -BOOL DiskTrack::Save(const Filepath& path) -{ - int i; - int j; - int total; - - // Not needed if not initialized - if (!dt.init) { - return TRUE; - } - - // Not needed unless changed - if (!dt.changed) { - return TRUE; - } - - // Need to write - ASSERT(dt.buffer); - ASSERT(dt.changemap); - ASSERT((dt.size >= 8) && (dt.size <= 11)); - ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); - - // Writing in RAW mode is not allowed - ASSERT(!dt.raw); - - // Calculate offset (previous tracks are considered to hold 256 - off_t offset = ((off_t)dt.track << 8); - offset <<= dt.size; - - // Add offset to real image - offset += dt.imgoffset; - - // Calculate length per sector - int length = 1 << dt.size; - - // Open file - Fileio fio; - if (!fio.Open(path, Fileio::ReadWrite)) { - return FALSE; - } - - // Partial write loop - for (i = 0; i < dt.sectors;) { - // If changed - if (dt.changemap[i]) { - // Initialize write size - total = 0; - - // Seek - if (!fio.Seek(offset + ((off_t)i << dt.size))) { - fio.Close(); - return FALSE; - } - - // Consectutive sector length - for (j = i; j < dt.sectors; j++) { - // end when interrupted - if (!dt.changemap[j]) { - break; - } - - // Add one sector - total += length; - } - - // Write - if (!fio.Write(&dt.buffer[i << dt.size], total)) { - fio.Close(); - return FALSE; - } - - // To unmodified sector - i = j; - } else { - // Next Sector - i++; - } - } - - // Close - fio.Close(); - - // Drop the change flag and exit - memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); - dt.changed = FALSE; - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Read Sector -// -//--------------------------------------------------------------------------- -BOOL DiskTrack::Read(BYTE *buf, int sec) const -{ - ASSERT(buf); - ASSERT((sec >= 0) & (sec < 0x100)); - - LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec); - // Error if not initialized - if (!dt.init) { - return FALSE; - } - - // // Error if the number of sectors exceeds the valid number - if (sec >= dt.sectors) { - return FALSE; - } - - // Copy - ASSERT(dt.buffer); - ASSERT((dt.size >= 8) && (dt.size <= 11)); - ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); - memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size); - - // Success - return TRUE; -} - void Disk::TestUnitReady(SASIDEV *controller) { bool status = CheckReady(); @@ -471,49 +155,6 @@ void Disk::Read16(SASIDEV *controller) } } -//--------------------------------------------------------------------------- -// -// Write Sector -// -//--------------------------------------------------------------------------- -BOOL DiskTrack::Write(const BYTE *buf, int sec) -{ - ASSERT(buf); - ASSERT((sec >= 0) & (sec < 0x100)); - ASSERT(!dt.raw); - - // Error if not initialized - if (!dt.init) { - return FALSE; - } - - // // Error if the number of sectors exceeds the valid number - if (sec >= dt.sectors) { - return FALSE; - } - - // Calculate offset and length - int offset = sec << dt.size; - int length = 1 << dt.size; - - // Compare - ASSERT(dt.buffer); - ASSERT((dt.size >= 8) && (dt.size <= 11)); - ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); - if (memcmp(buf, &dt.buffer[offset], length) == 0) { - // 同じものを書き込もうとしているので、正常終了 - return TRUE; - } - - // Copy, change - memcpy(&dt.buffer[offset], buf, length); - dt.changemap[sec] = TRUE; - dt.changed = TRUE; - - // Success - return TRUE; -} - //--------------------------------------------------------------------------- // // WRITE @@ -769,302 +410,6 @@ void Disk::ReadDefectData10(SASIDEV *controller) controller->DataIn(); } -//=========================================================================== -// -// Disk Cache -// -//=========================================================================== - -//--------------------------------------------------------------------------- -// -// Constructor -// -//--------------------------------------------------------------------------- -DiskCache::DiskCache(const Filepath& path, int size, int blocks, off_t imgoff) -{ - ASSERT((size >= 8) && (size <= 11)); - ASSERT(blocks > 0); - ASSERT(imgoff >= 0); - - // Cache work - for (int i = 0; i < CacheMax; i++) { - cache[i].disktrk = NULL; - cache[i].serial = 0; - } - - // Other - serial = 0; - sec_path = path; - sec_size = size; - sec_blocks = blocks; - cd_raw = FALSE; - imgoffset = imgoff; -} - -//--------------------------------------------------------------------------- -// -// Destructor -// -//--------------------------------------------------------------------------- -DiskCache::~DiskCache() -{ - // Clear the track - Clear(); -} - -//--------------------------------------------------------------------------- -// -// RAW Mode Setting -// -//--------------------------------------------------------------------------- -void DiskCache::SetRawMode(BOOL raw) -{ - ASSERT(sec_size == 11); - - // Configuration - cd_raw = raw; -} - -//--------------------------------------------------------------------------- -// -// Save -// -//--------------------------------------------------------------------------- -BOOL DiskCache::Save() -{ - // Save track - for (int i = 0; i < CacheMax; i++) { - // Is it a valid track? - if (cache[i].disktrk) { - // Save - if (!cache[i].disktrk->Save(sec_path)) { - return FALSE; - } - } - } - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Get disk cache information -// -//--------------------------------------------------------------------------- -BOOL DiskCache::GetCache(int index, int& track, DWORD& aserial) const -{ - ASSERT((index >= 0) && (index < CacheMax)); - - // FALSE if unused - if (!cache[index].disktrk) { - return FALSE; - } - - // Set track and serial - track = cache[index].disktrk->GetTrack(); - aserial = cache[index].serial; - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Clear -// -//--------------------------------------------------------------------------- -void DiskCache::Clear() -{ - // Free the cache - for (int i = 0; i < CacheMax; i++) { - if (cache[i].disktrk) { - delete cache[i].disktrk; - cache[i].disktrk = NULL; - } - } -} - -//--------------------------------------------------------------------------- -// -// Sector Read -// -//--------------------------------------------------------------------------- -BOOL DiskCache::Read(BYTE *buf, int block) -{ - ASSERT(sec_size != 0); - - // Update first - Update(); - - // Calculate track (fixed to 256 sectors/track) - int track = block >> 8; - - // Get the track data - DiskTrack *disktrk = Assign(track); - if (!disktrk) { - return FALSE; - } - - // Read the track data to the cache - return disktrk->Read(buf, (BYTE)block); -} - -//--------------------------------------------------------------------------- -// -// Sector write -// -//--------------------------------------------------------------------------- -BOOL DiskCache::Write(const BYTE *buf, int block) -{ - ASSERT(sec_size != 0); - - // Update first - Update(); - - // Calculate track (fixed to 256 sectors/track) - int track = block >> 8; - - // Get that track data - DiskTrack *disktrk = Assign(track); - if (!disktrk) { - return FALSE; - } - - // Write the data to the cache - return disktrk->Write(buf, (BYTE)block); -} - -//--------------------------------------------------------------------------- -// -// Track Assignment -// -//--------------------------------------------------------------------------- -DiskTrack* DiskCache::Assign(int track) -{ - ASSERT(sec_size != 0); - ASSERT(track >= 0); - - // First, check if it is already assigned - for (int i = 0; i < CacheMax; i++) { - if (cache[i].disktrk) { - if (cache[i].disktrk->GetTrack() == track) { - // Track match - cache[i].serial = serial; - return cache[i].disktrk; - } - } - } - - // Next, check for empty - for (int i = 0; i < CacheMax; i++) { - if (!cache[i].disktrk) { - // Try loading - if (Load(i, track)) { - // Success loading - cache[i].serial = serial; - return cache[i].disktrk; - } - - // Load failed - return NULL; - } - } - - // Finally, find the youngest serial number and delete it - - // Set index 0 as candidate c - DWORD s = cache[0].serial; - int c = 0; - - // Compare candidate with serial and update to smaller one - for (int i = 0; i < CacheMax; i++) { - ASSERT(cache[i].disktrk); - - // Compare and update the existing serial - if (cache[i].serial < s) { - s = cache[i].serial; - c = i; - } - } - - // Save this track - if (!cache[c].disktrk->Save(sec_path)) { - return NULL; - } - - // Delete this track - DiskTrack *disktrk = cache[c].disktrk; - cache[c].disktrk = NULL; - - // Load - if (Load(c, track, disktrk)) { - // Successful loading - cache[c].serial = serial; - return cache[c].disktrk; - } - - // Load failed - return NULL; -} - -//--------------------------------------------------------------------------- -// -// Load cache -// -//--------------------------------------------------------------------------- -BOOL DiskCache::Load(int index, int track, DiskTrack *disktrk) -{ - ASSERT((index >= 0) && (index < CacheMax)); - ASSERT(track >= 0); - ASSERT(!cache[index].disktrk); - - // Get the number of sectors on this track - int sectors = sec_blocks - (track << 8); - ASSERT(sectors > 0); - if (sectors > 0x100) { - sectors = 0x100; - } - - // Create a disk track - if (disktrk == NULL) { - disktrk = new DiskTrack(); - } - - // Initialize disk track - disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset); - - // Try loading - if (!disktrk->Load(sec_path)) { - // 失敗 - delete disktrk; - return FALSE; - } - - // Allocation successful, work set - cache[index].disktrk = disktrk; - - return TRUE; -} - -//--------------------------------------------------------------------------- -// -// Update serial number -// -//--------------------------------------------------------------------------- -void DiskCache::Update() -{ - // Update and do nothing except 0 - serial++; - if (serial != 0) { - return; - } - - // Clear serial of all caches (loop in 32bit) - for (int i = 0; i < CacheMax; i++) { - cache[i].serial = 0; - } -} - - //=========================================================================== // // Disk diff --git a/src/raspberrypi/devices/disk_track_cache.cpp b/src/raspberrypi/devices/disk_track_cache.cpp new file mode 100644 index 00000000..c71f5f45 --- /dev/null +++ b/src/raspberrypi/devices/disk_track_cache.cpp @@ -0,0 +1,677 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// Copyright (C) 2010 Y.Sugahara +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Imported NetBSD support and some optimisation patch by Rin Okuyama. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache ] +// +//--------------------------------------------------------------------------- + +#include "os.h" +#include "fileio.h" +#include "disk_track_cache.h" + +//=========================================================================== +// +// Disk Track +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +DiskTrack::DiskTrack() +{ + // Initialization of internal information + dt.track = 0; + dt.size = 0; + dt.sectors = 0; + dt.raw = FALSE; + dt.init = FALSE; + dt.changed = FALSE; + dt.length = 0; + dt.buffer = NULL; + dt.maplen = 0; + dt.changemap = NULL; + dt.imgoffset = 0; +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +DiskTrack::~DiskTrack() +{ + // Release memory, but do not save automatically + if (dt.buffer) { + free(dt.buffer); + dt.buffer = NULL; + } + if (dt.changemap) { + free(dt.changemap); + dt.changemap = NULL; + } +} + +//--------------------------------------------------------------------------- +// +// Initialization +// +//--------------------------------------------------------------------------- +void DiskTrack::Init(int track, int size, int sectors, BOOL raw, off_t imgoff) +{ + ASSERT(track >= 0); + ASSERT((size >= 8) && (size <= 11)); + ASSERT((sectors > 0) && (sectors <= 0x100)); + ASSERT(imgoff >= 0); + + // Set Parameters + dt.track = track; + dt.size = size; + dt.sectors = sectors; + dt.raw = raw; + + // Not initialized (needs to be loaded) + dt.init = FALSE; + + // Not Changed + dt.changed = FALSE; + + // Offset to actual data + dt.imgoffset = imgoff; +} + +//--------------------------------------------------------------------------- +// +// Load +// +//--------------------------------------------------------------------------- +BOOL DiskTrack::Load(const Filepath& path) +{ + Fileio fio; + int i; + + // Not needed if already loaded + if (dt.init) { + ASSERT(dt.buffer); + ASSERT(dt.changemap); + return TRUE; + } + + // Calculate offset (previous tracks are considered to + // hold 256 sectors) + off_t offset = ((off_t)dt.track << 8); + if (dt.raw) { + ASSERT(dt.size == 11); + offset *= 0x930; + offset += 0x10; + } else { + offset <<= dt.size; + } + + // Add offset to real image + offset += dt.imgoffset; + + // Calculate length (data size of this track) + int length = dt.sectors << dt.size; + + // Allocate buffer memory + ASSERT((dt.size >= 8) && (dt.size <= 11)); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + + if (dt.buffer == NULL) { + if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { + LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); + } + dt.length = length; + } + + if (!dt.buffer) { + return FALSE; + } + + // Reallocate if the buffer length is different + if (dt.length != (DWORD)length) { + free(dt.buffer); + if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) { + LOGWARN("%s posix_memalign failed", __PRETTY_FUNCTION__); + } + dt.length = length; + } + + // Reserve change map memory + if (dt.changemap == NULL) { + dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); + dt.maplen = dt.sectors; + } + + if (!dt.changemap) { + return FALSE; + } + + // Reallocate if the buffer length is different + if (dt.maplen != (DWORD)dt.sectors) { + free(dt.changemap); + dt.changemap = (BOOL *)malloc(dt.sectors * sizeof(BOOL)); + dt.maplen = dt.sectors; + } + + // Clear changemap + memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); + + // Read from File + if (!fio.OpenDIO(path, Fileio::ReadOnly)) { + return FALSE; + } + if (dt.raw) { + // Split Reading + for (i = 0; i < dt.sectors; i++) { + // Seek + if (!fio.Seek(offset)) { + fio.Close(); + return FALSE; + } + + // Read + if (!fio.Read(&dt.buffer[i << dt.size], 1 << dt.size)) { + fio.Close(); + return FALSE; + } + + // Next offset + offset += 0x930; + } + } else { + // Continuous reading + if (!fio.Seek(offset)) { + fio.Close(); + return FALSE; + } + if (!fio.Read(dt.buffer, length)) { + fio.Close(); + return FALSE; + } + } + fio.Close(); + + // Set a flag and end normally + dt.init = TRUE; + dt.changed = FALSE; + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Save +// +//--------------------------------------------------------------------------- +BOOL DiskTrack::Save(const Filepath& path) +{ + int i; + int j; + int total; + + // Not needed if not initialized + if (!dt.init) { + return TRUE; + } + + // Not needed unless changed + if (!dt.changed) { + return TRUE; + } + + // Need to write + ASSERT(dt.buffer); + ASSERT(dt.changemap); + ASSERT((dt.size >= 8) && (dt.size <= 11)); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + + // Writing in RAW mode is not allowed + ASSERT(!dt.raw); + + // Calculate offset (previous tracks are considered to hold 256 + off_t offset = ((off_t)dt.track << 8); + offset <<= dt.size; + + // Add offset to real image + offset += dt.imgoffset; + + // Calculate length per sector + int length = 1 << dt.size; + + // Open file + Fileio fio; + if (!fio.Open(path, Fileio::ReadWrite)) { + return FALSE; + } + + // Partial write loop + for (i = 0; i < dt.sectors;) { + // If changed + if (dt.changemap[i]) { + // Initialize write size + total = 0; + + // Seek + if (!fio.Seek(offset + ((off_t)i << dt.size))) { + fio.Close(); + return FALSE; + } + + // Consectutive sector length + for (j = i; j < dt.sectors; j++) { + // end when interrupted + if (!dt.changemap[j]) { + break; + } + + // Add one sector + total += length; + } + + // Write + if (!fio.Write(&dt.buffer[i << dt.size], total)) { + fio.Close(); + return FALSE; + } + + // To unmodified sector + i = j; + } else { + // Next Sector + i++; + } + } + + // Close + fio.Close(); + + // Drop the change flag and exit + memset(dt.changemap, 0x00, dt.sectors * sizeof(BOOL)); + dt.changed = FALSE; + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Read Sector +// +//--------------------------------------------------------------------------- +BOOL DiskTrack::Read(BYTE *buf, int sec) const +{ + ASSERT(buf); + ASSERT((sec >= 0) & (sec < 0x100)); + + LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec); + // Error if not initialized + if (!dt.init) { + return FALSE; + } + + // // Error if the number of sectors exceeds the valid number + if (sec >= dt.sectors) { + return FALSE; + } + + // Copy + ASSERT(dt.buffer); + ASSERT((dt.size >= 8) && (dt.size <= 11)); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + memcpy(buf, &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size); + + // Success + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Write Sector +// +//--------------------------------------------------------------------------- +BOOL DiskTrack::Write(const BYTE *buf, int sec) +{ + ASSERT(buf); + ASSERT((sec >= 0) & (sec < 0x100)); + ASSERT(!dt.raw); + + // Error if not initialized + if (!dt.init) { + return FALSE; + } + + // // Error if the number of sectors exceeds the valid number + if (sec >= dt.sectors) { + return FALSE; + } + + // Calculate offset and length + int offset = sec << dt.size; + int length = 1 << dt.size; + + // Compare + ASSERT(dt.buffer); + ASSERT((dt.size >= 8) && (dt.size <= 11)); + ASSERT((dt.sectors > 0) && (dt.sectors <= 0x100)); + if (memcmp(buf, &dt.buffer[offset], length) == 0) { + // 同じものを書き込もうとしているので、正常終了 + return TRUE; + } + + // Copy, change + memcpy(&dt.buffer[offset], buf, length); + dt.changemap[sec] = TRUE; + dt.changed = TRUE; + + // Success + return TRUE; +} + +//=========================================================================== +// +// Disk Cache +// +//=========================================================================== + +//--------------------------------------------------------------------------- +// +// Constructor +// +//--------------------------------------------------------------------------- +DiskCache::DiskCache(const Filepath& path, int size, int blocks, off_t imgoff) +{ + ASSERT((size >= 8) && (size <= 11)); + ASSERT(blocks > 0); + ASSERT(imgoff >= 0); + + // Cache work + for (int i = 0; i < CacheMax; i++) { + cache[i].disktrk = NULL; + cache[i].serial = 0; + } + + // Other + serial = 0; + sec_path = path; + sec_size = size; + sec_blocks = blocks; + cd_raw = FALSE; + imgoffset = imgoff; +} + +//--------------------------------------------------------------------------- +// +// Destructor +// +//--------------------------------------------------------------------------- +DiskCache::~DiskCache() +{ + // Clear the track + Clear(); +} + +//--------------------------------------------------------------------------- +// +// RAW Mode Setting +// +//--------------------------------------------------------------------------- +void DiskCache::SetRawMode(BOOL raw) +{ + ASSERT(sec_size == 11); + + // Configuration + cd_raw = raw; +} + +//--------------------------------------------------------------------------- +// +// Save +// +//--------------------------------------------------------------------------- +BOOL DiskCache::Save() +{ + // Save track + for (int i = 0; i < CacheMax; i++) { + // Is it a valid track? + if (cache[i].disktrk) { + // Save + if (!cache[i].disktrk->Save(sec_path)) { + return FALSE; + } + } + } + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Get disk cache information +// +//--------------------------------------------------------------------------- +BOOL DiskCache::GetCache(int index, int& track, DWORD& aserial) const +{ + ASSERT((index >= 0) && (index < CacheMax)); + + // FALSE if unused + if (!cache[index].disktrk) { + return FALSE; + } + + // Set track and serial + track = cache[index].disktrk->GetTrack(); + aserial = cache[index].serial; + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Clear +// +//--------------------------------------------------------------------------- +void DiskCache::Clear() +{ + // Free the cache + for (int i = 0; i < CacheMax; i++) { + if (cache[i].disktrk) { + delete cache[i].disktrk; + cache[i].disktrk = NULL; + } + } +} + +//--------------------------------------------------------------------------- +// +// Sector Read +// +//--------------------------------------------------------------------------- +BOOL DiskCache::Read(BYTE *buf, int block) +{ + ASSERT(sec_size != 0); + + // Update first + Update(); + + // Calculate track (fixed to 256 sectors/track) + int track = block >> 8; + + // Get the track data + DiskTrack *disktrk = Assign(track); + if (!disktrk) { + return FALSE; + } + + // Read the track data to the cache + return disktrk->Read(buf, (BYTE)block); +} + +//--------------------------------------------------------------------------- +// +// Sector write +// +//--------------------------------------------------------------------------- +BOOL DiskCache::Write(const BYTE *buf, int block) +{ + ASSERT(sec_size != 0); + + // Update first + Update(); + + // Calculate track (fixed to 256 sectors/track) + int track = block >> 8; + + // Get that track data + DiskTrack *disktrk = Assign(track); + if (!disktrk) { + return FALSE; + } + + // Write the data to the cache + return disktrk->Write(buf, (BYTE)block); +} + +//--------------------------------------------------------------------------- +// +// Track Assignment +// +//--------------------------------------------------------------------------- +DiskTrack* DiskCache::Assign(int track) +{ + ASSERT(sec_size != 0); + ASSERT(track >= 0); + + // First, check if it is already assigned + for (int i = 0; i < CacheMax; i++) { + if (cache[i].disktrk) { + if (cache[i].disktrk->GetTrack() == track) { + // Track match + cache[i].serial = serial; + return cache[i].disktrk; + } + } + } + + // Next, check for empty + for (int i = 0; i < CacheMax; i++) { + if (!cache[i].disktrk) { + // Try loading + if (Load(i, track)) { + // Success loading + cache[i].serial = serial; + return cache[i].disktrk; + } + + // Load failed + return NULL; + } + } + + // Finally, find the youngest serial number and delete it + + // Set index 0 as candidate c + DWORD s = cache[0].serial; + int c = 0; + + // Compare candidate with serial and update to smaller one + for (int i = 0; i < CacheMax; i++) { + ASSERT(cache[i].disktrk); + + // Compare and update the existing serial + if (cache[i].serial < s) { + s = cache[i].serial; + c = i; + } + } + + // Save this track + if (!cache[c].disktrk->Save(sec_path)) { + return NULL; + } + + // Delete this track + DiskTrack *disktrk = cache[c].disktrk; + cache[c].disktrk = NULL; + + // Load + if (Load(c, track, disktrk)) { + // Successful loading + cache[c].serial = serial; + return cache[c].disktrk; + } + + // Load failed + return NULL; +} + +//--------------------------------------------------------------------------- +// +// Load cache +// +//--------------------------------------------------------------------------- +BOOL DiskCache::Load(int index, int track, DiskTrack *disktrk) +{ + ASSERT((index >= 0) && (index < CacheMax)); + ASSERT(track >= 0); + ASSERT(!cache[index].disktrk); + + // Get the number of sectors on this track + int sectors = sec_blocks - (track << 8); + ASSERT(sectors > 0); + if (sectors > 0x100) { + sectors = 0x100; + } + + // Create a disk track + if (disktrk == NULL) { + disktrk = new DiskTrack(); + } + + // Initialize disk track + disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset); + + // Try loading + if (!disktrk->Load(sec_path)) { + // 失敗 + delete disktrk; + return FALSE; + } + + // Allocation successful, work set + cache[index].disktrk = disktrk; + + return TRUE; +} + +//--------------------------------------------------------------------------- +// +// Update serial number +// +//--------------------------------------------------------------------------- +void DiskCache::Update() +{ + // Update and do nothing except 0 + serial++; + if (serial != 0) { + return; + } + + // Clear serial of all caches (loop in 32bit) + for (int i = 0; i < CacheMax; i++) { + cache[i].serial = 0; + } +} + diff --git a/src/raspberrypi/devices/disk_track_cache.h b/src/raspberrypi/devices/disk_track_cache.h new file mode 100644 index 00000000..44e1fb25 --- /dev/null +++ b/src/raspberrypi/devices/disk_track_cache.h @@ -0,0 +1,110 @@ +//--------------------------------------------------------------------------- +// +// X68000 EMULATOR "XM6" +// +// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp) +// Copyright (C) 2014-2020 GIMONS +// +// XM6i +// Copyright (C) 2010-2015 isaki@NetBSD.org +// +// Imported sava's Anex86/T98Next image and MO format support patch. +// Comments translated to english by akuker. +// +// [ DiskTrack and DiskCache] +// +//--------------------------------------------------------------------------- + +#pragma once + +#include "xm6.h" +#include "log.h" +#include "filepath.h" + +class DiskTrack +{ +public: + // Internal data definition + typedef struct { + int track; // Track Number + int size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) + int sectors; // Number of sectors(<0x100) + DWORD length; // Data buffer length + BYTE *buffer; // Data buffer + BOOL init; // Is it initilized? + BOOL changed; // Changed flag + DWORD maplen; // Changed map length + BOOL *changemap; // Changed map + BOOL raw; // RAW mode flag + off_t imgoffset; // Offset to actual data + } disktrk_t; + +public: + // Basic Functions + DiskTrack(); // Constructor + virtual ~DiskTrack(); // Destructor + void Init(int track, int size, int sectors, BOOL raw = FALSE, off_t imgoff = 0);// Initialization + BOOL Load(const Filepath& path); // Load + BOOL Save(const Filepath& path); // Save + + // Read / Write + BOOL Read(BYTE *buf, int sec) const; // Sector Read + BOOL Write(const BYTE *buf, int sec); // Sector Write + + // Other + int GetTrack() const { return dt.track; } // Get track + BOOL IsChanged() const { return dt.changed; } // Changed flag check + +private: + // Internal data + disktrk_t dt; // Internal data +}; + +//=========================================================================== +// +// Disk Cache +// +//=========================================================================== +class DiskCache +{ +public: + // Internal data definition + typedef struct { + DiskTrack *disktrk; // Disk Track + DWORD serial; // Serial + } cache_t; + + // Number of caches + enum { + CacheMax = 16 // Number of tracks to cache + }; + +public: + // Basic Functions + DiskCache(const Filepath& path, int size, int blocks,off_t imgoff = 0);// Constructor + virtual ~DiskCache(); // Destructor + void SetRawMode(BOOL raw); // CD-ROM raw mode setting + + // Access + BOOL Save(); // Save and release all + BOOL Read(BYTE *buf, int block); // Sector Read + BOOL Write(const BYTE *buf, int block); // Sector Write + BOOL GetCache(int index, int& track, DWORD& serial) const; // Get cache information + +private: + // Internal Management + void Clear(); // Clear all tracks + DiskTrack* Assign(int track); // Load track + BOOL Load(int index, int track, DiskTrack *disktrk = NULL); // Load track + void Update(); // Update serial number + + // Internal data + cache_t cache[CacheMax]; // Cache management + DWORD serial; // Last serial number + Filepath sec_path; // Path + int sec_size; // Sector Size (8=256, 9=512, 10=1024, 11=2048, 12=4096) + int sec_blocks; // Blocks per sector + BOOL cd_raw; // CD-ROM RAW mode + off_t imgoffset; // Offset to actual data +}; +