Extraced DiskTrack and DiskCache

This commit is contained in:
Uwe Seimet 2021-08-24 14:54:00 +02:00
parent 1887105774
commit 7b97435dc7
3 changed files with 787 additions and 655 deletions

View File

@ -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

View File

@ -0,0 +1,677 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (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;
}
}

View File

@ -0,0 +1,110 @@
//---------------------------------------------------------------------------
//
// X68000 EMULATOR "XM6"
//
// Copyright (C) 2001-2006 (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
};