Files
RASCSI/cpp/test/scsihd_nec_test.cpp
T
Daniel Markstedt 69535c772b fix NEC image sector size handling
Use the validated image sector size to derive SCSIHD_NEC's sector shift count, instead of the complete image size. This restores correct capacity and MODE SENSE geometry for PC-98 HDN images.
2026-08-30 09:13:03 +02:00

256 lines
6.8 KiB
C++

//---------------------------------------------------------------------------
//
// SCSI Target Emulator PiSCSI
// for Raspberry Pi
//
// Copyright (C) 2022-2023 Uwe Seimet
//
//---------------------------------------------------------------------------
#include "mocks.h"
#include "shared/piscsi_exceptions.h"
#include "devices/scsihd_nec.h"
#include <filesystem>
#include <fstream>
using namespace std;
using namespace filesystem;
void ScsiHdNecTest_SetUpModePages(map<int, vector<byte>>& pages)
{
EXPECT_EQ(5, pages.size()) << "Unexpected number of mode pages";
EXPECT_EQ(12, pages[1].size());
EXPECT_EQ(24, pages[3].size());
EXPECT_EQ(20, pages[4].size());
EXPECT_EQ(12, pages[8].size());
EXPECT_EQ(30, pages[48].size());
}
TEST(ScsiHdNecTest, Inquiry)
{
TestInquiry::Inquiry(SCHD, device_type::direct_access, scsi_level::scsi_1_ccs, "PiSCSI ", 0x1f, false, "file.hdn");
}
TEST(ScsiHdNecTest, SetUpModePages)
{
map<int, vector<byte>> pages;
MockSCSIHD_NEC hd(0);
// Non changeable
hd.SetUpModePages(pages, 0x3f, false);
ScsiHdNecTest_SetUpModePages(pages);
// Changeable
pages.clear();
hd.SetUpModePages(pages, 0x3f, true);
ScsiHdNecTest_SetUpModePages(pages);
}
TEST(ScsiHdNecTest, TestAddErrorPage)
{
map<int, vector<byte>> pages;
MockSCSIHD_NEC hd(0);
hd.SetBlockCount(0x1234);
hd.SetReady(true);
// Non changeable
hd.SetUpModePages(pages, 0x01, false);
EXPECT_EQ(1, pages.size()) << "Unexpected number of mode pages";
const vector<byte>& page_1 = pages[1];
EXPECT_EQ(0x26, to_integer<int>(page_1[2]));
}
TEST(ScsiHdNecTest, TestAddFormatPage)
{
map<int, vector<byte>> pages;
MockSCSIHD_NEC hd(0);
hd.SetBlockCount(0x1234);
hd.SetReady(true);
hd.SetUpModePages(pages, 0x03, false);
EXPECT_EQ(1, pages.size()) << "Unexpected number of mode pages";
vector<byte>& page_3 = pages[3];
EXPECT_EQ(0x80, to_integer<int>(page_3[0]) & 0x80);
EXPECT_EQ(0, to_integer<int>(page_3[20]));
hd.SetRemovable(true);
// Non changeable
hd.SetUpModePages(pages, 0x03, false);
page_3 = pages[3];
EXPECT_EQ(0x20, to_integer<int>(page_3[20]));
pages.clear();
// Changeable
hd.SetUpModePages(pages, 0x03, true);
EXPECT_EQ(0xffff, GetInt16(page_3, 12));
}
TEST(ScsiHdNecTest, TestAddDrivePage)
{
map<int, vector<byte>> pages;
MockSCSIHD_NEC hd(0);
hd.SetBlockCount(0x1234);
hd.SetReady(true);
// Non changeable
hd.SetUpModePages(pages, 0x04, false);
EXPECT_EQ(1, pages.size()) << "Unexpected number of mode pages";
pages.clear();
// Changeable
hd.SetUpModePages(pages, 0x04, true);
EXPECT_EQ(1, pages.size()) << "Unexpected number of mode pages";
}
TEST(ScsiHdNecTest, OpenHdnSetsPc98Geometry)
{
MockSCSIHD_NEC hd(0);
// One PC-9801-55 cylinder: 8 heads, 25 sectors per track, 512 bytes per sector.
path tmp = CreateTempFile(8 * 25 * 512);
const auto hdn = path((string)tmp + ".hdn");
rename(tmp, hdn);
hd.SetFilename(string(hdn));
hd.Open();
EXPECT_EQ(9, hd.GetSectorSizeShiftCount());
EXPECT_EQ(200, hd.GetBlockCount());
map<int, vector<byte>> pages;
hd.SetUpModePages(pages, 0x03, false);
const vector<byte>& format_page = pages[3];
EXPECT_EQ(8, GetInt16(format_page, 2));
EXPECT_EQ(25, GetInt16(format_page, 10));
EXPECT_EQ(512, GetInt16(format_page, 12));
remove(hdn);
}
TEST(ScsiHdNecTest, SetParameters)
{
MockSCSIHD_NEC hd_hdn(0);
MockSCSIHD_NEC hd_hdi(0);
MockSCSIHD_NEC hd_nhd(0);
EXPECT_THROW(hd_hdn.Open(), io_exception) << "Missing filename";
path tmp = CreateTempFile(511);
hd_hdn.SetFilename(string(tmp));
EXPECT_THROW(hd_hdn.Open(), io_exception) << "Root sector file is too small";
remove(tmp);
tmp = CreateTempFile(512);
hd_hdn.SetFilename(string(tmp));
EXPECT_THROW(hd_hdn.Open(), io_exception) << "Invalid file extension";
const auto hdn = path((string)tmp + ".HDN");
rename(tmp, hdn);
hd_hdn.SetFilename(string(hdn));
hd_hdn.Open();
remove(hdn);
tmp = CreateTempFile(512);
const auto hdi = path((string)tmp + ".hdi");
rename(tmp, hdi);
hd_hdi.SetFilename(string(hdi));
EXPECT_THROW(hd_hdi.Open(), io_exception) << "Invalid sector size";
ofstream out;
out.open(hdi);
const array<const char, 4> cylinders1 = { 1, 0, 0, 0 };
out.seekp(28);
out.write(cylinders1.data(), cylinders1.size());
const array<const char, 4> heads1 = { 1, 0, 0, 0 };
out.seekp(24);
out.write(heads1.data(), heads1.size());
const array<const char, 4> sectors1 = { 1, 0, 0, 0 };
out.seekp(20);
out.write(sectors1.data(), sectors1.size());
const array<const char, 4> sector_size1 = { 0, 2, 0, 0 };
out.seekp(16);
out.write(sector_size1.data(), sector_size1.size());
const array<const char, 4> image_size = { 0, 2, 0, 0 };
out.seekp(12);
out.write(image_size.data(), image_size.size());
out.close();
resize_file(hdi, 512);
hd_hdi.Open();
remove(hdi);
tmp = CreateTempFile(512);
const auto nhd = path((string)tmp + ".nhd");
rename(tmp, nhd);
hd_nhd.SetFilename(string(nhd));
EXPECT_THROW(hd_nhd.Open(), io_exception) << "Invalid file format";
out.open(nhd);
out << "T98HDDIMAGE.R0";
out.close();
resize_file(nhd, 512);
EXPECT_THROW(hd_nhd.Open(), io_exception) << "Invalid sector size";
out.open(nhd);
out << "T98HDDIMAGE.R0";
// 512 bytes per sector
array<char, 2> sector_size2 = { 0, 2 };
out.seekp(0x11c);
out.write(sector_size2.data(), sector_size2.size());
out.close();
resize_file(nhd, 512);
EXPECT_THROW(hd_nhd.Open(), io_exception) << "Drive has 0 blocks";
out.open(nhd);
out << "T98HDDIMAGE.R0";
const array<const char, 2> cylinders2 = { 1, 0 };
out.seekp(0x114);
out.write(cylinders2.data(), cylinders2.size());
const array<const char, 2> heads2 = { 1, 0 };
out.seekp(0x118);
out.write(heads2.data(), heads2.size());
const array<const char, 2> sectors2 = { 1, 0 };
out.seekp(0x11a);
out.write(sectors2.data(), sectors2.size());
out.seekp(0x11c);
out.write(sector_size2.data(), sector_size2.size());
const array<const char, 4> image_offset = { 1, 0, 0, 0 };
out.seekp(0x110);
out.write(image_offset.data(), image_offset.size());
out.close();
resize_file(nhd, 512);
EXPECT_THROW(hd_nhd.Open(), io_exception) << "Invalid image offset/size";
out.open(nhd);
out << "T98HDDIMAGE.R0";
out.seekp(0x114);
out.write(cylinders2.data(), cylinders2.size());
out.seekp(0x118);
out.write(heads2.data(), heads2.size());
out.seekp(0x11a);
out.write(sectors2.data(), sectors2.size());
// 1 byte per sector
sector_size2 = { 1, 0 };
out.seekp(0x11c);
out.write(sector_size2.data(), sector_size2.size());
out.close();
resize_file(nhd, 512);
EXPECT_THROW(hd_nhd.Open(), io_exception) << "Invalid NEC disk/sector size";
out.open(nhd);
out << "T98HDDIMAGE.R0";
out.seekp(0x114);
out.write(cylinders2.data(), cylinders2.size());
out.seekp(0x118);
out.write(heads2.data(), heads2.size());
out.seekp(0x11a);
out.write(sectors2.data(), sectors2.size());
sector_size2 = { 0, 2 };
out.seekp(0x11c);
out.write(sector_size2.data(), sector_size2.size());
out.close();
resize_file(nhd, 512);
hd_nhd.Open();
remove(nhd);
}