Add a reverse-engineered checksum routine, and some documentation.

This commit is contained in:
David Given
2019-04-12 21:10:15 +02:00
parent 84076674fd
commit 6a215c35ee
3 changed files with 123 additions and 1 deletions

View File

@@ -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 |
| [Brother 120kB](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 |
| [TRS-80](doc/disk-trs80.md) | 🦖 | | a minor variation of the IBM scheme |
{: .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 |
| [Zilog MCZ](doc/disk-zilogmcz.md) | 🦖 | | 8-inch _and_ hard sectors |
{: .datatable }
### Notes
- IBM PC disks are the lowest-common-denominator standard. A number of other

32
doc/disk-fb100.md Normal file
View 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).

View File

@@ -30,6 +30,89 @@ static bool search(const RawBits& rawbits, size_t& cursor)
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,
RawRecordVector& rawrecords, SectorVector& sectors)
{
@@ -58,14 +141,19 @@ void Fb100Decoder::decodeToSectors(const RawBits& rawbits, unsigned,
br.seek(1);
const Bytes id = br.read(FB100_ID_SIZE);
uint16_t wantIdCrc = br.read_be16();
uint16_t gotIdCrc = checksum(id);
const Bytes payload = br.read(FB100_PAYLOAD_SIZE);
uint16_t wantPayloadCrc = br.read_be16();
uint16_t gotPayloadCrc = checksum(payload);
if (wantIdCrc != gotIdCrc)
continue;
uint8_t abssector = id[2];
uint8_t track = 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>(
new Sector(status, track, 0, sectorid, payload));
sectors.push_back(std::move(sector));