Files
RASCSI/cpp/devices/scsihd_nec.cpp
T
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

179 lines
4.8 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2001-2006 PI.(ytanaka@ipc-tokai.or.jp)
// Copyright (C) 2014-2020 GIMONS
// Copyright (C) 2021-2023 Uwe Seimet
// Copyright (C) akuker
//
// Licensed under the BSD 3-Clause License.
// See LICENSE file in the project root folder.
//
//---------------------------------------------------------------------------
#include "shared/piscsi_util.h"
#include "shared/piscsi_exceptions.h"
#include "scsi_command_util.h"
#include "scsihd_nec.h"
#include <fstream>
using namespace piscsi_util;
using namespace scsi_command_util;
void SCSIHD_NEC::Open()
{
assert(!IsReady());
off_t size = GetFileSize();
array<char, 512> root_sector;
ifstream in(GetFilename(), ios::binary);
in.read(root_sector.data(), root_sector.size());
if (!in.good() || size < static_cast<off_t>(root_sector.size())) {
throw io_exception("Can't read NEC hard disk file root sector");
}
// Effective size must be a multiple of 512
size = (size / 512) * 512;
// Determine parameters by extension
const auto [image_size, sector_size] = SetParameters(root_sector, static_cast<int>(size));
SetSectorSizeShiftCount(static_cast<uint32_t>(size));
SetBlockCount(image_size >> GetSectorSizeShiftCount());
FinalizeSetup(image_offset);
}
pair<int, int> SCSIHD_NEC::SetParameters(span<const char> data, int size)
{
array<uint8_t, 512> root_sector = {};
memcpy(root_sector.data(), data.data(), root_sector.size());
int image_size;
int sector_size;
// PC-9801-55 NEC compatible?
if (const string ext = GetExtensionLowerCase(GetFilename()); ext == "hdn") {
// Assuming sector size 512, number of sectors 25, number of heads 8 as default settings
image_offset = 0;
image_size = size;
sector_size = 512;
sectors = 25;
heads = 8;
cylinders = size >> 9;
cylinders >>= 3;
cylinders /= 25;
}
// Anex86 HD image?
else if (ext == "hdi") {
image_offset = GetInt32LittleEndian(&root_sector[8]);
image_size = GetInt32LittleEndian(&root_sector[12]);
sector_size = GetInt32LittleEndian(&root_sector[16]);
sectors = GetInt32LittleEndian(&root_sector[20]);
heads = GetInt32LittleEndian(&root_sector[24]);
cylinders = GetInt32LittleEndian(&root_sector[28]);
}
// T98Next HD image?
else if (ext == "nhd") {
if (!memcmp(root_sector.data(), "T98HDDIMAGE.R0\0", 15)) {
image_offset = GetInt32LittleEndian(&root_sector[0x110]);
cylinders = GetInt32LittleEndian(&root_sector[0x114]);
heads = GetInt16LittleEndian(&root_sector[0x118]);
sectors = GetInt16LittleEndian(&root_sector[0x11a]);
sector_size = GetInt16LittleEndian(&root_sector[0x11c]);
image_size = static_cast<int>(static_cast<off_t>(cylinders * heads * sectors * sector_size));
}
else {
throw io_exception("Invalid NEC image file format");
}
}
else {
throw io_exception("Invalid NEC image file extension");
}
if (sector_size == 0) {
throw io_exception("Invalid NEC sector size 0");
}
// Image size consistency check
if (image_offset + image_size > size) {
throw io_exception("NEC image offset/size consistency check failed");
}
if (CalculateShiftCount(sector_size) == 0) {
throw io_exception("Invalid NEC sector size of " + to_string(sector_size) + " byte(s)");
}
return { image_size, sector_size };
}
vector<uint8_t> SCSIHD_NEC::InquiryInternal() const
{
return HandleInquiry(device_type::direct_access, scsi_level::scsi_1_ccs, false);
}
void SCSIHD_NEC::AddFormatPage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<byte> buf(24);
// Page can be saved
buf[0] = (byte)0x80;
// Make the number of bytes in the physical sector appear mutable (although it cannot actually be)
if (changeable) {
SetInt16(buf, 0x0c, -1);
pages[3] = buf;
return;
}
if (IsReady()) {
// Set the number of tracks in one zone (PC-9801-55 seems to see this value)
SetInt16(buf, 0x02, heads);
// Set the number of sectors per track
SetInt16(buf, 0x0a, sectors);
// Set the number of bytes in the physical sector
SetInt16(buf, 0x0c, GetSectorSizeInBytes());
}
// Set removable attributes (remains of the old days)
if (IsRemovable()) {
buf[20] = (byte)0x20;
}
pages[3] = buf;
}
void SCSIHD_NEC::AddDrivePage(map<int, vector<byte>>& pages, bool changeable) const
{
vector<byte> buf(20);
// No changeable area
if (!changeable && IsReady()) {
// Set the number of cylinders
SetInt32(buf, 0x01, cylinders);
// Set the number of heads
buf[0x5] = (byte)heads;
}
pages[4] = buf;
}
int SCSIHD_NEC::GetInt16LittleEndian(const uint8_t *buf)
{
return (static_cast<int>(buf[1]) << 8) | buf[0];
}
int SCSIHD_NEC::GetInt32LittleEndian(const uint8_t *buf)
{
return (static_cast<int>(buf[3]) << 24) | (static_cast<int>(buf[2]) << 16) | (static_cast<int>(buf[1]) << 8) | buf[0];
}