Refactor the C64 formats into 35 and 40 track variants. Start work on the C64

filesystem.
This commit is contained in:
David Given
2022-08-30 00:49:24 +02:00
parent 5d6f031973
commit b91edac0ba
12 changed files with 263 additions and 37 deletions

View File

@@ -174,7 +174,7 @@ $(call do-encodedecodetest,atarist820)
$(call do-encodedecodetest,bk800)
$(call do-encodedecodetest,brother120)
$(call do-encodedecodetest,brother240)
$(call do-encodedecodetest,commodore1541,scripts/commodore1541_test.textpb)
$(call do-encodedecodetest,commodore1541t35,scripts/commodore1541_test.textpb)
$(call do-encodedecodetest,commodore1581)
$(call do-encodedecodetest,hp9121)
$(call do-encodedecodetest,ibm1200)

View File

@@ -68,6 +68,7 @@ LIBFLUXENGINE_SRCS = \
lib/vfs/amigaffs.cc \
lib/vfs/applesingle.cc \
lib/vfs/brother120fs.cc \
lib/vfs/cbmfs.cc \
lib/vfs/cpmfs.cc \
lib/vfs/fatfs.cc \
lib/vfs/machfs.cc \

180
lib/vfs/cbmfs.cc Normal file
View File

@@ -0,0 +1,180 @@
#include "lib/globals.h"
#include "lib/vfs/vfs.h"
#include "lib/config.pb.h"
#include <fmt/format.h>
static std::string fromPetscii(const Bytes& bytes)
{
std::stringstream ss;
for (uint8_t b : bytes)
{
if ((b >= 32) && (b <= 126))
ss << (char)tolower(b);
else
ss << fmt::format("%{:2x}", b);
}
return ss.str();
}
static std::string toMode(uint8_t cbm_type)
{
std::stringstream ss;
if (cbm_type & 0x40)
ss << 'L';
if (cbm_type & 0x80)
ss << 'S';
return ss.str();
}
static std::string toFileType(uint8_t cbm_type)
{
switch (cbm_type & 0x0f)
{
case 0: return "del";
case 1: return "seq";
case 2: return "prg";
case 3: return "usr";
case 4: return "rel";
default: return fmt::format("[bad type {:x}]", cbm_type & 0x0f);
}
}
class CbmfsDirent : public Dirent
{
public:
CbmfsDirent(const Bytes& dbuf)
{
ByteReader br(dbuf);
br.skip(2); /* t/s field */
cbm_type = br.read_8();
start_track = br.read_8();
start_sector = br.read_8();
auto filenameBytes = br.read(16).split(0xa0)[0];
filename = fromPetscii(filenameBytes);
side_track = br.read_8();
side_sector = br.read_8();
recordlen = br.read_8();
br.skip(6);
sectors = br.read_le16();
file_type = TYPE_FILE;
length = sectors * 254;
mode = "";
}
public:
unsigned cbm_type;
unsigned start_track;
unsigned start_sector;
unsigned side_track;
unsigned side_sector;
unsigned recordlen;
unsigned sectors;
};
class CbmfsFilesystem : public Filesystem
{
public:
CbmfsFilesystem(
const CbmfsProto& config, std::shared_ptr<SectorInterface> sectors):
Filesystem(sectors),
_config(config)
{
}
FilesystemStatus check()
{
return FS_OK;
}
std::vector<std::unique_ptr<Dirent>> list(const Path& path)
{
if (path.size() != 0)
throw BadPathException();
std::vector<std::unique_ptr<Dirent>> results;
uint8_t t = _config.directory_track();
uint8_t s = 1;
while (t != 0xff)
{
auto b = getSector(t, 0, s);
for (int i = 0; i < 8; i++)
{
auto dbuf = b.slice(i * 32, 32);
if (dbuf[2] == 0)
continue;
results.push_back(std::make_unique<CbmfsDirent>(dbuf));
}
t = b[0] - 1;
s = b[1];
}
return results;
}
std::map<std::string, std::string> getMetadata(const Path& path)
{
if (path.size() != 1)
throw BadPathException();
auto de = findFile(path[0]);
if (!de)
throw FileNotFoundException();
std::map<std::string, std::string> attributes;
attributes["filename"] = de->filename;
attributes["length"] = de->length;
attributes["mode"] = de->mode;
attributes["type"] = "file";
attributes["cbmfs.type"] = toFileType(de->cbm_type);
attributes["cbmfs.start_track"] = fmt::format("{}", de->start_track);
attributes["cbmfs.start_sector"] = fmt::format("{}", de->start_sector);
attributes["cbmfs.side_track"] = fmt::format("{}", de->side_track);
attributes["cbmfs.side_sector"] = fmt::format("{}", de->side_sector);
attributes["cbmfs.recordlen"] = fmt::format("{}", de->recordlen);
attributes["cbmfs.sectors"] = fmt::format("{}", de->sectors);
return attributes;
}
private:
std::unique_ptr<CbmfsDirent> findFile(const std::string& filename)
{
uint8_t t = _config.directory_track();
uint8_t s = 1;
while (t != 0xff)
{
auto b = getSector(t, 0, s);
for (int i = 0; i < 8; i++)
{
auto dbuf = b.slice(i * 32, 32);
if (dbuf[2] == 0)
continue;
auto de = std::make_unique<CbmfsDirent>(dbuf);
if (de->filename == filename)
return de;
}
t = b[0] - 1;
s = b[1];
}
return nullptr;
}
private:
const CbmfsProto& _config;
};
std::unique_ptr<Filesystem> Filesystem::createCbmfsFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> sectors)
{
return std::make_unique<CbmfsFilesystem>(config.cbmfs(), sectors);
}

View File

@@ -38,8 +38,9 @@ Filesystem::Filesystem(std::shared_ptr<SectorInterface> sectors):
{
auto& layout = config.layout();
if (!layout.has_tracks() || !layout.has_sides())
Error() << "FS: filesystem support cannot be used without concrete layout "
"information";
Error()
<< "FS: filesystem support cannot be used without concrete layout "
"information";
unsigned block = 0;
for (const auto& p :
@@ -76,12 +77,15 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystem(
case FilesystemProto::kCpmfs:
return Filesystem::createCpmFsFilesystem(config, image);
case FilesystemProto::kAmigaffs:
case FilesystemProto::kAmigaffs:
return Filesystem::createAmigaFfsFilesystem(config, image);
case FilesystemProto::kMachfs:
case FilesystemProto::kMachfs:
return Filesystem::createMacHfsFilesystem(config, image);
case FilesystemProto::kCbmfs:
return Filesystem::createCbmfsFilesystem(config, image);
default:
Error() << "no filesystem configured";
return std::unique_ptr<Filesystem>();
@@ -90,10 +94,10 @@ std::unique_ptr<Filesystem> Filesystem::createFilesystem(
Bytes Filesystem::getSector(unsigned track, unsigned side, unsigned sector)
{
auto s = _sectors->get(track, side, sector);
if (!s)
throw BadFilesystemException();
return s->data;
auto s = _sectors->get(track, side, sector);
if (!s)
throw BadFilesystemException();
return s->data;
}
Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count)
@@ -106,11 +110,12 @@ Bytes Filesystem::getLogicalSector(uint32_t number, uint32_t count)
for (int i = 0; i < count; i++)
{
auto& it = _locations[number + i];
int track = std::get<0>(it);
int side = std::get<1>(it);
int sector = std::get<2>(it);
auto layoutdata = Layout::getLayoutOfTrack(track, side);
bw += _sectors->get(track, side, sector)->data.slice(0, layoutdata.sector_size());
int track = std::get<0>(it);
int side = std::get<1>(it);
int sector = std::get<2>(it);
auto layoutdata = Layout::getLayoutOfTrack(track, side);
bw += _sectors->get(track, side, sector)
->data.slice(0, layoutdata.sector_size());
}
return data;
}
@@ -124,17 +129,18 @@ void Filesystem::putLogicalSector(uint32_t number, const Bytes& data)
_sectors->put(std::get<0>(i), std::get<1>(i), std::get<2>(i))->data = data;
}
unsigned Filesystem::getOffsetOfSector(unsigned track, unsigned side, unsigned sector)
unsigned Filesystem::getOffsetOfSector(
unsigned track, unsigned side, unsigned sector)
{
location_t key = { track, side, sector };
location_t key = {track, side, sector};
for (int i = 0; i < _locations.size(); i++)
{
if (_locations[i] >= key)
return i;
}
for (int i = 0; i < _locations.size(); i++)
{
if (_locations[i] >= key)
return i;
}
throw BadFilesystemException();
throw BadFilesystemException();
}
unsigned Filesystem::getLogicalSectorCount()

View File

@@ -171,6 +171,8 @@ public:
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createMacHfsFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createCbmfsFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);
static std::unique_ptr<Filesystem> createFilesystem(
const FilesystemProto& config, std::shared_ptr<SectorInterface> image);

View File

@@ -41,6 +41,12 @@ message AmigaFfsProto {
message MacHfsProto {
}
message CbmfsProto {
optional uint32 directory_track = 1
[default = 17,
(help) = "which track the directory is on (zero-based numbering)"];
}
message FilesystemProto {
oneof filesystem {
AcornDfsProto acorndfs = 1;
@@ -49,6 +55,7 @@ message FilesystemProto {
CpmFsProto cpmfs = 4;
AmigaFfsProto amigaffs = 5;
MacHfsProto machfs = 6;
CbmfsProto cbmfs = 7;
}
}

View File

@@ -32,7 +32,7 @@ int mainGetFileInfo(int argc, const char* argv[])
auto attributes = filesystem->getMetadata(Path(directory));
for (const auto& e : attributes)
fmt::print("{} = {}\n", e.first, e.second);
fmt::print("{}={}\n", e.first, e.second);
}
catch (const FilesystemException& e)
{

View File

@@ -54,7 +54,7 @@ int mainLs(int argc, const char* argv[])
{
fmt::print("{} {:{}} {:6} {}\n",
fileTypeChar(dirent->file_type),
dirent->filename,
"'" + dirent->filename + "'",
maxlen,
dirent->length,
dirent->mode);

View File

@@ -1,4 +1,4 @@
comment: 'Commodore 1541 170kB 5.25" SS GCR'
comment: 'Commodore 1541 common settings'
image_reader {
filename: "commodore1541.d64"
@@ -11,7 +11,6 @@ image_writer {
}
layout {
tracks: 40
sides: 1
layoutdata {
sector_size: 256
@@ -57,15 +56,8 @@ decoder {
c64 {}
}
tracks {
start: 0
end: 39
}
heads {
start: 0
end: 0
}
tpi: 48
filesystem {
cbmfs {}
}

View File

@@ -2,6 +2,7 @@ FORMATS = \
_micropolis \
_northstar \
_mx \
_commodore1541 \
40track_drive \
acornadfs \
acorndfs \
@@ -24,7 +25,8 @@ FORMATS = \
bk800 \
brother120 \
brother240 \
commodore1541 \
commodore1541t35 \
commodore1541t40 \
commodore1581 \
eco1 \
epsonpf10 \

View File

@@ -0,0 +1,18 @@
comment: 'Commodore 1541 171kB 5.25" 35-track SS GCR'
include: '_commodore1541'
layout {
tracks: 35
}
tracks {
start: 0
end: 34
}
heads {
start: 0
end: 0
}

View File

@@ -0,0 +1,18 @@
comment: 'Commodore 1541 170kB 5.25" 35-track SS GCR'
include: '_commodore1541'
layout {
tracks: 40
}
tracks {
start: 0
end: 39
}
heads {
start: 0
end: 0
}