mirror of
https://github.com/akuker/RASCSI.git
synced 2026-04-21 18:17:07 +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;
|
|
}
|