mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add support for reading ADFS disks --- a slight variation to normal MFM IBM.
Made the IBM reader way more robust in terms of retrying bad reads, as my sample disks were pretty dodgy.
This commit is contained in:
@@ -51,6 +51,8 @@ Currently, not a lot.
|
||||
- IBM MFM 1440kB and 720kB formats, a.k.a. standard PC floppy disks;
|
||||
read only (I haven't got round to writing the write support)
|
||||
|
||||
- [Acorn ADFS disks](doc/acorn-adfs.md): read only (likewise)
|
||||
|
||||
- [Brother 240kB word processor disks](doc/brother.md); read and write
|
||||
|
||||
...aaaand that's it. If you want more, please [get in
|
||||
|
||||
35
doc/acorn-adfs.md
Normal file
35
doc/acorn-adfs.md
Normal file
@@ -0,0 +1,35 @@
|
||||
Acorn ADFS disks
|
||||
================
|
||||
|
||||
Acorn ADFS disks are pretty standard MFM encoded IBM scheme disks, although
|
||||
with different sector sizes and with the 0-based sector identifiers rather
|
||||
than 1-based sector identifiers. There's nothing particularly special here.
|
||||
|
||||
There are various different kinds, which should all work out of the box.
|
||||
Tested ones are:
|
||||
|
||||
- ADFS L: 80 track, 16 sector, 2 sides, 256 bytes per sector == 640kB.
|
||||
- ADFE D/E: 80 track, 5 sector, 2 sides, 1024 bytes per sector == 800kB.
|
||||
|
||||
I expect the others to work, but haven't tried them; [get in
|
||||
touch](https://github.com/davidgiven/fluxengine/issues/new) if you have any
|
||||
news. For ADFS S (single sided 40 track) you'll want `-s :s=0:t=0-79x2`. For
|
||||
ADFS M (single sided 80 track) you'll want `-s :s=0`.
|
||||
|
||||
Be aware that Acorn logical block numbering goes all the way up side 0 and
|
||||
then all the way up side 1. However, FluxEngine uses traditional disk images
|
||||
with alternating sides, with the blocks from track 0 side 0 then track 0 side
|
||||
1 then track 1 side 0 etc. Most Acorn emulators will use both formats, but
|
||||
they might require nudging as the side order can't be reliably autodetected.
|
||||
|
||||
Reading discs
|
||||
-------------
|
||||
|
||||
Just do:
|
||||
|
||||
```
|
||||
.obj/fe-readibm --sector-id-base=0
|
||||
```
|
||||
|
||||
You should end up with an `ibm.img` of the appropriate size for your disk
|
||||
format.
|
||||
@@ -30,6 +30,7 @@ typedef std::vector<std::unique_ptr<Record>> RecordVector;
|
||||
|
||||
extern RecordVector decodeBitsToRecordsMfm(const std::vector<bool>& bitmap);
|
||||
|
||||
extern std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsIbm(const RecordVector& records);
|
||||
extern std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsIbm(
|
||||
const RecordVector& records, int sectorIdBase);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
static_assert(std::is_trivially_copyable<IbmIdam>::value);
|
||||
|
||||
std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsIbm(
|
||||
const RecordVector& records)
|
||||
const RecordVector& records, int sectorIdBase)
|
||||
{
|
||||
bool idamValid = false;
|
||||
IbmIdam idam;
|
||||
@@ -55,8 +55,9 @@ std::vector<std::unique_ptr<Sector>> parseRecordsToSectorsIbm(
|
||||
std::vector<uint8_t> sectordata(size);
|
||||
memcpy(§ordata[0], &data[4], size);
|
||||
|
||||
int sectorNum = idam.sector - sectorIdBase;
|
||||
auto sector = std::unique_ptr<Sector>(
|
||||
new Sector(status, idam.cylinder, idam.side, idam.sector-1, sectordata));
|
||||
new Sector(status, idam.cylinder, idam.side, sectorNum, sectordata));
|
||||
sectors.push_back(std::move(sector));
|
||||
idamValid = false;
|
||||
break;
|
||||
|
||||
@@ -18,6 +18,11 @@ static SettableFlag dumpRecords(
|
||||
{ "--dump-records" },
|
||||
"Dump the parsed records.");
|
||||
|
||||
static IntFlag sectorIdBase(
|
||||
{ "--sector-id-base" },
|
||||
"Sector ID of the first sector.",
|
||||
1);
|
||||
|
||||
int main(int argc, const char* argv[])
|
||||
{
|
||||
setReaderDefaultSource(":t=0-79:s=0-1");
|
||||
@@ -28,6 +33,8 @@ int main(int argc, const char* argv[])
|
||||
for (auto& track : readTracks())
|
||||
{
|
||||
int retries = 5;
|
||||
std::map<int, std::unique_ptr<Sector>> goodSectors;
|
||||
|
||||
retry:
|
||||
std::unique_ptr<Fluxmap> fluxmap = track->read();
|
||||
nanoseconds_t clockPeriod = fluxmap->guessClock();
|
||||
@@ -40,17 +47,24 @@ int main(int argc, const char* argv[])
|
||||
auto records = decodeBitsToRecordsMfm(bitmap);
|
||||
std::cout << records.size() << " records." << std::endl;
|
||||
|
||||
auto sectors = parseRecordsToSectorsIbm(records);
|
||||
auto sectors = parseRecordsToSectorsIbm(records, sectorIdBase);
|
||||
std::cout << " " << sectors.size() << " sectors; ";
|
||||
|
||||
bool hasBadSectors = false;
|
||||
for (auto& sector : sectors)
|
||||
{
|
||||
if (sector->status != Sector::OK)
|
||||
bool sectorPending = goodSectors.find(sector->sector) == goodSectors.end();
|
||||
if (sectorPending)
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " Bad CRC on sector " << sector->sector << "; ";
|
||||
hasBadSectors = true;
|
||||
if (sector->status != Sector::OK)
|
||||
{
|
||||
std::cout << std::endl
|
||||
<< " Bad CRC on sector " << sector->sector << "; ";
|
||||
hasBadSectors = true;
|
||||
}
|
||||
|
||||
if (((sector->status == Sector::OK) || (retries == 0)) && (sector->sector >= 0))
|
||||
goodSectors[sector->sector] = std::move(sector);
|
||||
}
|
||||
}
|
||||
if (hasBadSectors)
|
||||
@@ -67,8 +81,9 @@ int main(int argc, const char* argv[])
|
||||
}
|
||||
|
||||
int size = 0;
|
||||
for (auto& sector : sectors)
|
||||
for (auto& i : goodSectors)
|
||||
{
|
||||
auto& sector = i.second;
|
||||
size += sector->data.size();
|
||||
allSectors[{sector->track, sector->side, sector->sector}] =
|
||||
std::move(sector);
|
||||
|
||||
Reference in New Issue
Block a user