mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Add a reverse-engineered checksum routine, and some documentation.
This commit is contained in:
@@ -81,6 +81,7 @@ physical disks with these formats and so know they work.
|
|||||||
| [Commodore 64 1541](doc/disk-c64.md) | 🦖 | | and probably the other GCR formats |
|
| [Commodore 64 1541](doc/disk-c64.md) | 🦖 | | and probably the other GCR formats |
|
||||||
| [Brother 120kB](doc/disk-brother.md) | 🦄 | | |
|
| [Brother 120kB](doc/disk-brother.md) | 🦄 | | |
|
||||||
| [Brother 240kB](doc/disk-brother.md) | 🦄 | 🦄 | |
|
| [Brother 240kB](doc/disk-brother.md) | 🦄 | 🦄 | |
|
||||||
|
| [Brother FB-100](doc/disk-fb100.md) | 🦖 | | Tandy Model 100, Husky Hunter, knitting machines |
|
||||||
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦖 | | and probably the 400kB too |
|
| [Macintosh 800kB](doc/disk-macintosh.md) | 🦖 | | and probably the 400kB too |
|
||||||
| [TRS-80](doc/disk-trs80.md) | 🦖 | | a minor variation of the IBM scheme |
|
| [TRS-80](doc/disk-trs80.md) | 🦖 | | a minor variation of the IBM scheme |
|
||||||
{: .datatable }
|
{: .datatable }
|
||||||
@@ -100,6 +101,7 @@ at least, check the CRC so what data's there is probably good.
|
|||||||
| [Victor 9000](doc/disk-victor9k.md) | 🦖 | | 8-inch |
|
| [Victor 9000](doc/disk-victor9k.md) | 🦖 | | 8-inch |
|
||||||
| [Zilog MCZ](doc/disk-zilogmcz.md) | 🦖 | | 8-inch _and_ hard sectors |
|
| [Zilog MCZ](doc/disk-zilogmcz.md) | 🦖 | | 8-inch _and_ hard sectors |
|
||||||
{: .datatable }
|
{: .datatable }
|
||||||
|
|
||||||
### Notes
|
### Notes
|
||||||
|
|
||||||
- IBM PC disks are the lowest-common-denominator standard. A number of other
|
- IBM PC disks are the lowest-common-denominator standard. A number of other
|
||||||
|
|||||||
32
doc/disk-fb100.md
Normal file
32
doc/disk-fb100.md
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
Disk: Brother FB-100
|
||||||
|
====================
|
||||||
|
|
||||||
|
The Brother FB-100 is a serial-attached smart floppy drive used by a several
|
||||||
|
different machines for mass storage, including the Tandy Model 100 and
|
||||||
|
clones, the Husky Hunter 2, and (bizarrely) several knitting machines. It was
|
||||||
|
usually rebadged, sometimes with a cheap paper label stuck over the Brother
|
||||||
|
logo: the most common variant appears to be the Tandy Portable Disk Drive or
|
||||||
|
TPDD:
|
||||||
|
|
||||||
|
<a href="http://www.old-computers.com/museum/computer.asp?c=233&st=1"> <img src="tdpp.jpg" alt="A Tandy Portable Disk Drive"/></a>
|
||||||
|
|
||||||
|
It's a bit of an oddball: the disk encoding is FM with a very custom record
|
||||||
|
scheme: 40-track single-sided 3.5" disks storing 100kB or so each. Each track
|
||||||
|
had only _two_ sectors, each 1280 bytes, but with an additional 17 bytes of
|
||||||
|
ID data used for filesystem management.
|
||||||
|
|
||||||
|
There was also apparently a TPDD-2 which could store twice as much data, but
|
||||||
|
I don't have access to one of those disks.
|
||||||
|
|
||||||
|
Reading discs
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Just do:
|
||||||
|
|
||||||
|
```
|
||||||
|
.obj/fe-readfb100
|
||||||
|
```
|
||||||
|
|
||||||
|
You should end up with an `fb11.img` of the appropriate size. It's a simple
|
||||||
|
array of 80 1297-byte sectors (17 bytes for the ID record plus 1280 bytes for
|
||||||
|
the data).
|
||||||
@@ -30,6 +30,89 @@ static bool search(const RawBits& rawbits, size_t& cursor)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Reverse engineered from a dump of the floppy drive's ROM. I have no idea how
|
||||||
|
* it works.
|
||||||
|
*
|
||||||
|
* LF8BA:
|
||||||
|
* clra
|
||||||
|
* staa X00B0
|
||||||
|
* staa X00B1
|
||||||
|
* ldx #$8000
|
||||||
|
* LF8C2: ldaa $00,x
|
||||||
|
* inx
|
||||||
|
* bsr LF8CF
|
||||||
|
* cpx #$8011
|
||||||
|
* bne LF8C2
|
||||||
|
* ldd X00B0
|
||||||
|
* rts
|
||||||
|
* LF8CF:
|
||||||
|
* eora X00B0
|
||||||
|
* staa X00CF
|
||||||
|
* asla
|
||||||
|
* asla
|
||||||
|
* asla
|
||||||
|
* asla
|
||||||
|
* eora X00CF
|
||||||
|
* staa X00CF
|
||||||
|
* rola
|
||||||
|
* rola
|
||||||
|
* rola
|
||||||
|
* tab
|
||||||
|
* anda #$F8
|
||||||
|
* eora X00B1
|
||||||
|
* staa X00B0
|
||||||
|
* rolb
|
||||||
|
* rolb
|
||||||
|
* andb #$0F
|
||||||
|
* eorb X00B0
|
||||||
|
* stab X00B0
|
||||||
|
* rolb
|
||||||
|
* eorb X00CF
|
||||||
|
* stab X00B1
|
||||||
|
* rts
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void rol(uint8_t& b, bool& c)
|
||||||
|
{
|
||||||
|
bool newc = b & 0x80;
|
||||||
|
b <<= 1;
|
||||||
|
b |= c;
|
||||||
|
c = newc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint16_t checksum(const Bytes& bytes)
|
||||||
|
{
|
||||||
|
uint8_t crclo = 0;
|
||||||
|
uint8_t crchi = 0;
|
||||||
|
for (uint8_t a : bytes)
|
||||||
|
{
|
||||||
|
a ^= crchi;
|
||||||
|
uint8_t t1 = a;
|
||||||
|
a <<= 4;
|
||||||
|
bool c = a & 0x10;
|
||||||
|
a ^= t1;
|
||||||
|
t1 = a;
|
||||||
|
rol(a, c);
|
||||||
|
rol(a, c);
|
||||||
|
rol(a, c);
|
||||||
|
uint8_t b = a;
|
||||||
|
a &= 0xf8;
|
||||||
|
a ^= crclo;
|
||||||
|
crchi = a;
|
||||||
|
rol(b, c);
|
||||||
|
rol(b, c);
|
||||||
|
b &= 0x0f;
|
||||||
|
b ^= crchi;
|
||||||
|
crchi = b;
|
||||||
|
rol(b, c);
|
||||||
|
b ^= t1;
|
||||||
|
crclo = b;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (crchi << 8) | crclo;
|
||||||
|
}
|
||||||
|
|
||||||
void Fb100Decoder::decodeToSectors(const RawBits& rawbits, unsigned,
|
void Fb100Decoder::decodeToSectors(const RawBits& rawbits, unsigned,
|
||||||
RawRecordVector& rawrecords, SectorVector& sectors)
|
RawRecordVector& rawrecords, SectorVector& sectors)
|
||||||
{
|
{
|
||||||
@@ -58,14 +141,19 @@ void Fb100Decoder::decodeToSectors(const RawBits& rawbits, unsigned,
|
|||||||
br.seek(1);
|
br.seek(1);
|
||||||
const Bytes id = br.read(FB100_ID_SIZE);
|
const Bytes id = br.read(FB100_ID_SIZE);
|
||||||
uint16_t wantIdCrc = br.read_be16();
|
uint16_t wantIdCrc = br.read_be16();
|
||||||
|
uint16_t gotIdCrc = checksum(id);
|
||||||
const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
|
const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
|
||||||
uint16_t wantPayloadCrc = br.read_be16();
|
uint16_t wantPayloadCrc = br.read_be16();
|
||||||
|
uint16_t gotPayloadCrc = checksum(payload);
|
||||||
|
|
||||||
|
if (wantIdCrc != gotIdCrc)
|
||||||
|
continue;
|
||||||
|
|
||||||
uint8_t abssector = id[2];
|
uint8_t abssector = id[2];
|
||||||
uint8_t track = abssector >> 1;
|
uint8_t track = abssector >> 1;
|
||||||
uint8_t sectorid = abssector & 1;
|
uint8_t sectorid = abssector & 1;
|
||||||
|
|
||||||
int status = Sector::BAD_CHECKSUM;
|
int status = (wantPayloadCrc == gotPayloadCrc) ? Sector::OK : Sector::BAD_CHECKSUM;
|
||||||
auto sector = std::unique_ptr<Sector>(
|
auto sector = std::unique_ptr<Sector>(
|
||||||
new Sector(status, track, 0, sectorid, payload));
|
new Sector(status, track, 0, sectorid, payload));
|
||||||
sectors.push_back(std::move(sector));
|
sectors.push_back(std::move(sector));
|
||||||
|
|||||||
Reference in New Issue
Block a user