mirror of
https://github.com/akuker/RASCSI.git
synced 2024-12-02 04:49:24 +00:00
b7cb23e391
* Add statistics and make scsictl accept generic key/value parameters
282 lines
5.7 KiB
C++
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;
|
||
}
|