mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Refactor the C64 formats into 35 and 40 track variants. Start work on the C64
filesystem.
This commit is contained in:
2
Makefile
2
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)
|
||||
|
||||
@@ -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
180
lib/vfs/cbmfs.cc
Normal 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);
|
||||
}
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 {}
|
||||
}
|
||||
@@ -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 \
|
||||
|
||||
18
src/formats/commodore1541t35.textpb
Normal file
18
src/formats/commodore1541t35.textpb
Normal 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
|
||||
}
|
||||
|
||||
18
src/formats/commodore1541t40.textpb
Normal file
18
src/formats/commodore1541t40.textpb
Normal 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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user