From b91edac0bac9279e6b9061f5123fce415ea21031 Mon Sep 17 00:00:00 2001 From: David Given Date: Tue, 30 Aug 2022 00:49:24 +0200 Subject: [PATCH] Refactor the C64 formats into 35 and 40 track variants. Start work on the C64 filesystem. --- Makefile | 2 +- lib/build.mk | 1 + lib/vfs/cbmfs.cc | 180 ++++++++++++++++++ lib/vfs/vfs.cc | 48 +++-- lib/vfs/vfs.h | 2 + lib/vfs/vfs.proto | 7 + src/fe-getfileinfo.cc | 2 +- src/fe-ls.cc | 2 +- ...odore1541.textpb => _commodore1541.textpb} | 16 +- src/formats/build.mk | 4 +- src/formats/commodore1541t35.textpb | 18 ++ src/formats/commodore1541t40.textpb | 18 ++ 12 files changed, 263 insertions(+), 37 deletions(-) create mode 100644 lib/vfs/cbmfs.cc rename src/formats/{commodore1541.textpb => _commodore1541.textpb} (83%) create mode 100644 src/formats/commodore1541t35.textpb create mode 100644 src/formats/commodore1541t40.textpb diff --git a/Makefile b/Makefile index a88689f2..a9775335 100644 --- a/Makefile +++ b/Makefile @@ -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) diff --git a/lib/build.mk b/lib/build.mk index b0b77944..f7c33303 100644 --- a/lib/build.mk +++ b/lib/build.mk @@ -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 \ diff --git a/lib/vfs/cbmfs.cc b/lib/vfs/cbmfs.cc new file mode 100644 index 00000000..929fbd75 --- /dev/null +++ b/lib/vfs/cbmfs.cc @@ -0,0 +1,180 @@ +#include "lib/globals.h" +#include "lib/vfs/vfs.h" +#include "lib/config.pb.h" +#include + +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 sectors): + Filesystem(sectors), + _config(config) + { + } + + FilesystemStatus check() + { + return FS_OK; + } + + std::vector> list(const Path& path) + { + if (path.size() != 0) + throw BadPathException(); + + std::vector> 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(dbuf)); + } + + t = b[0] - 1; + s = b[1]; + } + + return results; + } + + std::map getMetadata(const Path& path) + { + if (path.size() != 1) + throw BadPathException(); + auto de = findFile(path[0]); + if (!de) + throw FileNotFoundException(); + + std::map 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 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(dbuf); + if (de->filename == filename) + return de; + } + + t = b[0] - 1; + s = b[1]; + } + + return nullptr; + } + +private: + const CbmfsProto& _config; +}; + +std::unique_ptr Filesystem::createCbmfsFilesystem( + const FilesystemProto& config, std::shared_ptr sectors) +{ + return std::make_unique(config.cbmfs(), sectors); +} diff --git a/lib/vfs/vfs.cc b/lib/vfs/vfs.cc index 2cd801ac..34fa7924 100644 --- a/lib/vfs/vfs.cc +++ b/lib/vfs/vfs.cc @@ -38,8 +38,9 @@ Filesystem::Filesystem(std::shared_ptr 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::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(); @@ -90,10 +94,10 @@ std::unique_ptr 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() diff --git a/lib/vfs/vfs.h b/lib/vfs/vfs.h index bcd08ac7..8c31e958 100644 --- a/lib/vfs/vfs.h +++ b/lib/vfs/vfs.h @@ -171,6 +171,8 @@ public: const FilesystemProto& config, std::shared_ptr image); static std::unique_ptr createMacHfsFilesystem( const FilesystemProto& config, std::shared_ptr image); + static std::unique_ptr createCbmfsFilesystem( + const FilesystemProto& config, std::shared_ptr image); static std::unique_ptr createFilesystem( const FilesystemProto& config, std::shared_ptr image); diff --git a/lib/vfs/vfs.proto b/lib/vfs/vfs.proto index b646c66c..48b2b15a 100644 --- a/lib/vfs/vfs.proto +++ b/lib/vfs/vfs.proto @@ -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; } } diff --git a/src/fe-getfileinfo.cc b/src/fe-getfileinfo.cc index 4d3c2bfc..a7d2d088 100644 --- a/src/fe-getfileinfo.cc +++ b/src/fe-getfileinfo.cc @@ -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) { diff --git a/src/fe-ls.cc b/src/fe-ls.cc index 6ce41b45..4986c2eb 100644 --- a/src/fe-ls.cc +++ b/src/fe-ls.cc @@ -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); diff --git a/src/formats/commodore1541.textpb b/src/formats/_commodore1541.textpb similarity index 83% rename from src/formats/commodore1541.textpb rename to src/formats/_commodore1541.textpb index 194f0482..efc2a829 100644 --- a/src/formats/commodore1541.textpb +++ b/src/formats/_commodore1541.textpb @@ -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 {} +} diff --git a/src/formats/build.mk b/src/formats/build.mk index 6f728ec4..92c5b6d7 100644 --- a/src/formats/build.mk +++ b/src/formats/build.mk @@ -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 \ diff --git a/src/formats/commodore1541t35.textpb b/src/formats/commodore1541t35.textpb new file mode 100644 index 00000000..88c9f1fd --- /dev/null +++ b/src/formats/commodore1541t35.textpb @@ -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 +} + diff --git a/src/formats/commodore1541t40.textpb b/src/formats/commodore1541t40.textpb new file mode 100644 index 00000000..86e8073e --- /dev/null +++ b/src/formats/commodore1541t40.textpb @@ -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 +} +