RASCSI/cpp/devices/disk_cache.cpp
Uwe Seimet 41bdcd4aed
Issues 1179 and 1182 (#1232)
* Update logging

* Remove duplicate code

* Update unit tests

* Clean up includes

* Merge ProtobufSerializer into protobuf_util namespace

* Precompile regex

* Add const

* Add Split() convenience method, update log level/ID parsing

* Move log.h to legacy folder

* Elimininate gotos

* Fixes for gcc 13

* Update compiler flags

* Update default folder handling

* Use references instead of pointers

* Move code for better encapsulation

* Move code

* Remove unused method argument

* Move device logger

* Remove redundant to_string

* Rename for consistency

* Update handling of protobuf pointers

* Simplify protobuf usage

* Memory handling update

* Add hasher
2023-10-15 08:38:15 +02:00

193 lines
4.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//---------------------------------------------------------------------------
//
// 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.
// Comments translated to english by akuker.
//
//---------------------------------------------------------------------------
#include "disk_track.h"
#include "disk_cache.h"
#include <cstdlib>
#include <cassert>
#include <algorithm>
DiskCache::DiskCache(const string& path, int size, uint32_t blocks, off_t imgoff)
: sec_path(path), sec_size(size), sec_blocks(blocks), imgoffset(imgoff)
{
assert(blocks > 0);
assert(imgoff >= 0);
}
bool DiskCache::Save() const
{
// Save valid tracks
return ranges::none_of(cache.begin(), cache.end(), [this](const cache_t& c)
{ return c.disktrk != nullptr && !c.disktrk->Save(sec_path); });
}
shared_ptr<DiskTrack> DiskCache::GetTrack(uint32_t block)
{
// Update first
UpdateSerialNumber();
// Calculate track (fixed to 256 sectors/track)
int track = block >> 8;
// Get track data
return Assign(track);
}
bool DiskCache::ReadSector(span<uint8_t> buf, uint32_t block)
{
shared_ptr<DiskTrack> disktrk = GetTrack(block);
if (disktrk == nullptr) {
return false;
}
// Read the track data to the cache
return disktrk->ReadSector(buf, block & 0xff);
}
bool DiskCache::WriteSector(span<const uint8_t> buf, uint32_t block)
{
shared_ptr<DiskTrack> disktrk = GetTrack(block);
if (disktrk == nullptr) {
return false;
}
// Write the data to the cache
return disktrk->WriteSector(buf, block & 0xff);
}
//---------------------------------------------------------------------------
//
// Track Assignment
//
//---------------------------------------------------------------------------
shared_ptr<DiskTrack> DiskCache::Assign(int track)
{
assert(sec_size != 0);
assert(track >= 0);
// First, check if it is already assigned
for (cache_t& c : cache) {
if (c.disktrk && c.disktrk->GetTrack() == track) {
// Track match
c.serial = serial;
return c.disktrk;
}
}
// Next, check for empty
for (size_t i = 0; i < cache.size(); i++) {
if (cache[i].disktrk == nullptr) {
// Try loading
if (Load(static_cast<int>(i), track, nullptr)) {
// Success loading
cache[i].serial = serial;
return cache[i].disktrk;
}
// Load failed
return nullptr;
}
}
// Finally, find the youngest serial number and delete it
// Set index 0 as candidate c
uint32_t s = cache[0].serial;
size_t c = 0;
// Compare candidate with serial and update to smaller one
for (size_t i = 0; i < cache.size(); 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 nullptr;
}
// Delete this track
shared_ptr<DiskTrack> disktrk = cache[c].disktrk;
cache[c].disktrk.reset();
if (Load(static_cast<int>(c), track, disktrk)) {
// Successful loading
cache[c].serial = serial;
return cache[c].disktrk;
}
// Load failed
return nullptr;
}
//---------------------------------------------------------------------------
//
// Load cache
//
//---------------------------------------------------------------------------
bool DiskCache::Load(int index, int track, shared_ptr<DiskTrack> disktrk)
{
assert(index >= 0 && index < static_cast<int>(cache.size()));
assert(track >= 0);
assert(cache[index].disktrk == nullptr);
// 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 == nullptr) {
disktrk = make_shared<DiskTrack>();
}
// Initialize disk track
disktrk->Init(track, sec_size, sectors, cd_raw, imgoffset);
// Try loading
if (!disktrk->Load(sec_path)) {
// Failure
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
for (cache_t& c : cache) {
c.serial = 0;
}
}