Files
RASCSI/cpp/devices/disk_track.cpp
T
Uwe Seimet b7cb23e391 Add statistics and make scsictl accept generic key/value parameters (#1237/#1238) (#1262)
* Add statistics and make scsictl accept generic key/value parameters
2023-10-30 13:32:45 +01:00

282 lines
5.7 KiB
C++

//---------------------------------------------------------------------------
//
// 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.
// Comments translated to english by akuker.
//
//---------------------------------------------------------------------------
#include "disk_track.h"
#include <spdlog/spdlog.h>
#include <cassert>
#include <cstdlib>
#include <fstream>
DiskTrack::~DiskTrack()
{
// Release memory, but do not save automatically
free(dt.buffer);
}
void DiskTrack::Init(int track, int size, int sectors, bool raw, off_t imgoff)
{
assert(track >= 0);
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;
}
bool DiskTrack::Load(const string& path, uint64_t& cache_miss_read_count)
{
// Not needed if already loaded
if (dt.init) {
assert(dt.buffer);
return true;
}
++cache_miss_read_count;
// 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)
const int length = dt.sectors << dt.size;
// Allocate buffer memory
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
if (dt.buffer == nullptr) {
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
spdlog::warn("posix_memalign failed");
}
dt.length = length;
}
if (dt.buffer == nullptr) {
return false;
}
// Reallocate if the buffer length is different
if (dt.length != static_cast<uint32_t>(length)) {
free(dt.buffer);
if (posix_memalign((void **)&dt.buffer, 512, ((length + 511) / 512) * 512)) {
spdlog::warn("posix_memalign failed");
}
dt.length = length;
}
// Resize and clear changemap
dt.changemap.resize(dt.sectors);
fill(dt.changemap.begin(), dt.changemap.end(), false); //NOSONAR ranges::fill() cannot be applied to vector<bool>
ifstream in(path, ios::binary);
if (in.fail()) {
return false;
}
if (dt.raw) {
// Split Reading
for (int i = 0; i < dt.sectors; i++) {
in.seekg(offset);
if (in.fail()) {
return false;
}
in.read((char *)&dt.buffer[i << dt.size], 1 << dt.size);
if (in.fail()) {
return false;
}
// Next offset
offset += 0x930;
}
} else {
// Continuous reading
in.seekg(offset);
if (in.fail()) {
return false;
}
in.read((char *)dt.buffer, length);
if (in.fail()) {
return false;
}
}
// Set a flag and end normally
dt.init = true;
dt.changed = false;
return true;
}
bool DiskTrack::Save(const string& path, uint64_t& cache_miss_write_count)
{
// Not needed if not initialized
if (!dt.init) {
return true;
}
// Not needed unless changed
if (!dt.changed) {
return true;
}
++cache_miss_write_count;
// Need to write
assert(dt.buffer);
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 sectors)
off_t offset = ((off_t)dt.track << 8);
offset <<= dt.size;
// Add offset to real image
offset += dt.imgoffset;
// Calculate length per sector
const int length = 1 << dt.size;
ofstream out(path, ios::in | ios::out | ios::binary);
if (out.fail()) {
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;
out.seekp(offset + ((off_t)i << dt.size));
if (out.fail()) {
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;
}
out.write((const char *)&dt.buffer[i << dt.size], total);
if (out.fail()) {
return false;
}
// To unmodified sector
i = j;
} else {
// Next Sector
i++;
}
}
// Drop the change flag and exit
fill(dt.changemap.begin(), dt.changemap.end(), false); //NOSONAR ranges::fill() cannot be applied to vector<bool>
dt.changed = false;
return true;
}
bool DiskTrack::ReadSector(span<uint8_t> buf, int sec) const
{
assert(sec >= 0 && sec < 0x100);
// 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.sectors > 0) && (dt.sectors <= 0x100));
memcpy(buf.data(), &dt.buffer[(off_t)sec << dt.size], (off_t)1 << dt.size);
// Success
return true;
}
bool DiskTrack::WriteSector(span<const uint8_t> buf, int sec)
{
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
const int offset = sec << dt.size;
const int length = 1 << dt.size;
// Compare
assert(dt.buffer);
assert((dt.sectors > 0) && (dt.sectors <= 0x100));
if (memcmp(buf.data(), &dt.buffer[offset], length) == 0) {
// Exit normally since it's attempting to write the same thing
return true;
}
// Copy, change
memcpy(&dt.buffer[offset], buf.data(), length);
dt.changemap[sec] = true;
dt.changed = true;
// Success
return true;
}