2023-01-09 02:04:49 +00:00
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// X68000 EMULATOR "XM6"
|
|
|
|
|
//
|
|
|
|
|
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
|
|
|
|
|
// Copyright (C) 2014-2020 GIMONS
|
2023-01-11 03:08:22 +00:00
|
|
|
|
// Copyright (C) 2022-2023 akuker
|
2023-01-09 02:04:49 +00:00
|
|
|
|
//
|
|
|
|
|
// XM6i
|
|
|
|
|
// Copyright (C) 2010-2015 isaki@NetBSD.org
|
|
|
|
|
// Copyright (C) 2010 Y.Sugahara
|
|
|
|
|
//
|
|
|
|
|
// Imported sava's Anex86/T98Next image and MO format support patch.
|
|
|
|
|
// Comments translated to english by akuker.
|
|
|
|
|
//
|
|
|
|
|
// [ DiskTrack and DiskCache ]
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
#include <fstream>
|
|
|
|
|
#include "shared/log.h"
|
2023-01-09 02:04:49 +00:00
|
|
|
|
#include "disk_track_cache.h"
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
using namespace std;
|
|
|
|
|
|
2023-01-09 02:04:49 +00:00
|
|
|
|
//===========================================================================
|
|
|
|
|
//
|
|
|
|
|
// Disk Track
|
|
|
|
|
//
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
|
|
DiskTrack::DiskTrack()
|
|
|
|
|
{
|
|
|
|
|
// Initialization of internal information
|
|
|
|
|
dt.track = 0;
|
|
|
|
|
dt.size = 0;
|
|
|
|
|
dt.sectors = 0;
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.raw = false;
|
|
|
|
|
dt.init = false;
|
|
|
|
|
dt.changed = false;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
dt.length = 0;
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.buffer = nullptr;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
dt.maplen = 0;
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.changemap = nullptr;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
dt.imgoffset = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(track >= 0);
|
|
|
|
|
assert((sectors > 0) && (sectors <= 0x100));
|
|
|
|
|
assert(imgoff >= 0);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Set Parameters
|
|
|
|
|
dt.track = track;
|
|
|
|
|
dt.size = size;
|
|
|
|
|
dt.sectors = sectors;
|
|
|
|
|
dt.raw = raw;
|
|
|
|
|
|
|
|
|
|
// Not initialized (needs to be loaded)
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.init = false;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Not Changed
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.changed = false;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Offset to actual data
|
|
|
|
|
dt.imgoffset = imgoff;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskTrack::Load(const string& path)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
|
|
|
|
// Not needed if already loaded
|
|
|
|
|
if (dt.init) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(dt.buffer);
|
|
|
|
|
assert(dt.changemap);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
|
|
|
|
off_t offset = ((off_t)dt.track << 8);
|
|
|
|
|
if (dt.raw) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(dt.size == 11);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
if (dt.length != (uint32_t)length) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
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) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
dt.maplen = dt.sectors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!dt.changemap) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Reallocate if the buffer length is different
|
2023-01-09 03:39:07 +00:00
|
|
|
|
if (dt.maplen != (uint32_t)dt.sectors) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
free(dt.changemap);
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.changemap = (bool *)malloc(dt.sectors * sizeof(bool));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
dt.maplen = dt.sectors;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Clear changemap
|
2023-01-09 03:39:07 +00:00
|
|
|
|
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Read from File
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fstream fio;
|
|
|
|
|
fio.open(path.c_str(),ios::in);
|
|
|
|
|
if(!fio.is_open()) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if (dt.raw) {
|
|
|
|
|
// Split Reading
|
|
|
|
|
for (int i = 0; i < dt.sectors; i++) {
|
|
|
|
|
// Seek
|
2023-01-09 03:39:07 +00:00
|
|
|
|
if (!fio.seekg(offset)) {
|
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Read
|
2023-01-11 00:21:15 +00:00
|
|
|
|
if (!fio.read((char *)&dt.buffer[i << dt.size], 1 << dt.size)) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Next offset
|
|
|
|
|
offset += 0x930;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Continuous reading
|
2023-01-09 03:39:07 +00:00
|
|
|
|
if (!fio.seekg(offset)) {
|
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
2023-01-11 00:21:15 +00:00
|
|
|
|
if (!fio.read((char*)dt.buffer, length)) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Set a flag and end normally
|
2023-01-09 03:39:07 +00:00
|
|
|
|
dt.init = true;
|
|
|
|
|
dt.changed = false;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskTrack::Save(const string& path)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
|
|
|
|
// Not needed if not initialized
|
|
|
|
|
if (!dt.init) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Not needed unless changed
|
|
|
|
|
if (!dt.changed) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Need to write
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(dt.buffer);
|
|
|
|
|
assert(dt.changemap);
|
|
|
|
|
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Writing in RAW mode is not allowed
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(!dt.raw);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Calculate offset (previous tracks are considered to hold 256 sectors)
|
|
|
|
|
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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fstream fio;
|
|
|
|
|
fio.open(path, ios::in | ios::out);
|
|
|
|
|
if (!fio.is_open()) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Partial write loop
|
|
|
|
|
int total;
|
|
|
|
|
for (int i = 0; i < dt.sectors;) {
|
|
|
|
|
// If changed
|
|
|
|
|
if (dt.changemap[i]) {
|
|
|
|
|
// Initialize write size
|
|
|
|
|
total = 0;
|
|
|
|
|
|
|
|
|
|
// Seek
|
2023-01-09 03:39:07 +00:00
|
|
|
|
if (!fio.seekg(offset + ((off_t)i << dt.size))) {
|
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Consectutive sector length
|
|
|
|
|
int j;
|
|
|
|
|
for (j = i; j < dt.sectors; j++) {
|
|
|
|
|
// end when interrupted
|
|
|
|
|
if (!dt.changemap[j]) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Add one sector
|
|
|
|
|
total += length;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Write
|
2023-01-11 00:21:15 +00:00
|
|
|
|
if (!fio.write((char*)&dt.buffer[i << dt.size], total)) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// To unmodified sector
|
|
|
|
|
i = j;
|
|
|
|
|
} else {
|
|
|
|
|
// Next Sector
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Close
|
2023-01-09 03:39:07 +00:00
|
|
|
|
fio.close();
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Drop the change flag and exit
|
2023-01-09 03:39:07 +00:00
|
|
|
|
memset(dt.changemap, 0x00, dt.sectors * sizeof(bool));
|
|
|
|
|
dt.changed = false;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskTrack::ReadSector(vector<uint8_t>& buf, int sec) const
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert((sec >= 0) & (sec < 0x100));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
2023-01-11 03:08:22 +00:00
|
|
|
|
LOGTRACE("%s reading sector: %d", __PRETTY_FUNCTION__,sec)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
// 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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(dt.buffer);
|
|
|
|
|
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
|
|
|
|
memcpy(buf.data(), &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Success
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskTrack::WriteSector(const vector<uint8_t>& buf, int sec)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert((sec >= 0) & (sec < 0x100));
|
|
|
|
|
assert(!dt.raw);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(dt.buffer);
|
|
|
|
|
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
|
|
|
|
|
if (memcmp(buf.data(), &dt.buffer[offset], length) == 0) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
// Exit normally since it's attempting to write the same thing
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Copy, change
|
2023-01-09 03:39:07 +00:00
|
|
|
|
memcpy(&dt.buffer[offset], buf.data(), length);
|
|
|
|
|
dt.changemap[sec] = true;
|
|
|
|
|
dt.changed = true;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Success
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
//
|
|
|
|
|
// Disk Cache
|
|
|
|
|
//
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
DiskCache::DiskCache(const string& path, int size, uint32_t blocks, off_t imgoff) : DiskImageHandle(path, size, blocks, imgoff)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(blocks > 0);
|
|
|
|
|
assert(imgoff >= 0);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Cache work
|
|
|
|
|
for (int i = 0; i < CacheMax; i++) {
|
|
|
|
|
cache[i].disktrk = NULL;
|
|
|
|
|
cache[i].serial = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DiskCache::~DiskCache()
|
|
|
|
|
{
|
|
|
|
|
// Clear the track
|
|
|
|
|
Clear();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool DiskCache::Save()
|
|
|
|
|
{
|
|
|
|
|
// Save track
|
|
|
|
|
for (int i = 0; i < CacheMax; i++) {
|
|
|
|
|
// Is it a valid track?
|
|
|
|
|
if (cache[i].disktrk) {
|
|
|
|
|
// Save
|
2023-01-11 03:08:22 +00:00
|
|
|
|
if (!cache[i].disktrk->Save(GetPath())) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Get disk cache information
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskCache::GetCache(int index, int& track, uint32_t& aserial) const
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert((index >= 0) && (index < CacheMax));
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// false if unused
|
|
|
|
|
if (!cache[index].disktrk) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Set track and serial
|
|
|
|
|
track = cache[index].disktrk->GetTrack();
|
|
|
|
|
aserial = cache[index].serial;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskCache::ReadSector(vector<uint8_t>& buf, int block)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
|
|
|
|
// Update first
|
|
|
|
|
UpdateSerialNumber();
|
|
|
|
|
|
|
|
|
|
// 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->ReadSector(buf, block & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-09 03:39:07 +00:00
|
|
|
|
bool DiskCache::WriteSector(const vector<uint8_t>& buf, int block)
|
2023-01-09 02:04:49 +00:00
|
|
|
|
{
|
|
|
|
|
// Update first
|
|
|
|
|
UpdateSerialNumber();
|
|
|
|
|
|
|
|
|
|
// 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->WriteSector(buf, block & 0xff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
//
|
|
|
|
|
// Track Assignment
|
|
|
|
|
//
|
|
|
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
DiskTrack* DiskCache::Assign(int track)
|
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(track >= 0);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// 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
|
2023-01-09 03:39:07 +00:00
|
|
|
|
uint32_t s = cache[0].serial;
|
2023-01-09 02:04:49 +00:00
|
|
|
|
int c = 0;
|
|
|
|
|
|
|
|
|
|
// Compare candidate with serial and update to smaller one
|
|
|
|
|
for (int i = 0; i < CacheMax; i++) {
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(cache[i].disktrk);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Compare and update the existing serial
|
|
|
|
|
if (cache[i].serial < s) {
|
|
|
|
|
s = cache[i].serial;
|
|
|
|
|
c = i;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Save this track
|
2023-01-11 03:08:22 +00:00
|
|
|
|
if (!cache[c].disktrk->Save(GetPath())) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Delete this track
|
|
|
|
|
DiskTrack *disktrk = cache[c].disktrk;
|
|
|
|
|
cache[c].disktrk = NULL;
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
{
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert((index >= 0) && (index < CacheMax));
|
|
|
|
|
assert(track >= 0);
|
|
|
|
|
assert(!cache[index].disktrk);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Get the number of sectors on this track
|
2023-01-11 03:08:22 +00:00
|
|
|
|
int sectors = GetBlocksPerSector() - (track << 8);
|
2023-01-09 03:39:07 +00:00
|
|
|
|
assert(sectors > 0);
|
2023-01-09 02:04:49 +00:00
|
|
|
|
if (sectors > 0x100) {
|
|
|
|
|
sectors = 0x100;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create a disk track
|
|
|
|
|
if (disktrk == NULL) {
|
|
|
|
|
disktrk = new DiskTrack();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Initialize disk track
|
2023-01-11 03:08:22 +00:00
|
|
|
|
disktrk->Init(track, GetSectorSize(), GetBlocksPerSector(), GetRawMode(), GetImgOffset());
|
2023-01-09 02:04:49 +00:00
|
|
|
|
|
|
|
|
|
// Try loading
|
2023-01-11 03:08:22 +00:00
|
|
|
|
if (!disktrk->Load(GetPath())) {
|
2023-01-09 02:04:49 +00:00
|
|
|
|
// Failure
|
|
|
|
|
delete disktrk;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Allocation successful, work set
|
|
|
|
|
cache[index].disktrk = disktrk;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DiskCache::UpdateSerialNumber()
|
|
|
|
|
{
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|