diff --git a/Device/Adaptor.cpp b/Device/Adaptor.cpp index 9ffe284..bbef6ec 100644 --- a/Device/Adaptor.cpp +++ b/Device/Adaptor.cpp @@ -4,6 +4,8 @@ #include #include +#include + using namespace Device; @@ -73,5 +75,392 @@ void DOAdaptor::writeBlock(unsigned block, const void *bp) +#pragma mark - +#pragma mark NibbleAdaptor + + +uint8_t NibbleAdaptor::decode44(uint8_t x, uint8_t y) +{ + return ((x << 1) | 0x01) & y; +} + +std::pair NibbleAdaptor::encode44(uint8_t val) +{ + uint8_t x = (val >> 1) | 0xaa; + uint8_t y = val | 0xaa; + + return std::make_pair(x,y); +} + +uint8_t NibbleAdaptor::encode62(uint8_t val) +{ +#undef __METHOD__ +#define __METHOD__ "NibbleAdaptor::encode62" + + static uint8_t table[64] = { + 0x96, 0x97, 0x9a, 0x9b, 0x9d, 0x9e, 0x9f, 0xa6, + 0xa7, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb2, 0xb3, + + 0xb4, 0xb5, 0xb6, 0xb7, 0xb9, 0xba, 0xbb, 0xbc, + 0xbd, 0xbe, 0xbf, 0xcb, 0xcd, 0xce, 0xcf, 0xd3, + + 0xd6, 0xd7, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, + 0xdf, 0xe5, 0xe6, 0xe7, 0xe9, 0xea, 0xeb, 0xec, + + 0xed, 0xee, 0xef, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, + 0xf7, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff + }; + + if (val > 0x3f) + throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 value."); + + return table[val]; +} + + +uint8_t NibbleAdaptor::decode62(uint8_t val) +{ +#undef __METHOD__ +#define __METHOD__ "decode62" + + // auto-generated via perl. + static uint8_t table[] = { + -1, -1, -1, -1, -1, -1, 0, 1, -1, -1, 2, 3, -1, 4, 5, 6, + -1, -1, -1, -1, -1, -1, 7, 8, -1, -1, -1, 9, 10, 11, 12, 13, + -1, -1, 14, 15, 16, 17, 18, 19, -1, 20, 21, 22, 23, 24, 25, 26, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 27, -1, 28, 29, 30, + -1, -1, -1, 31, -1, -1, 32, 33, -1, 34, 35, 36, 37, 38, 39, 40, + -1, -1, -1, -1, -1, 41, 42, 43, -1, 44, 45, 46, 47, 48, 49, 50, + -1, -1, 51, 52, 53, 54, 55, 56, -1, 57, 58, 59, 60, 61, 62, 63 + }; + + if ((val < 0x90) || (table[val - 0x90] == 0xff)) + throw ProFUSE::Exception(__METHOD__ ": Invalid 6-2 encoding."); + + return table[val - 0x90]; +} + + + +static int FindByte(void *address, uint8_t c, unsigned length, unsigned offset = 0) +{ + + for (unsigned i = offset; i < length; ++i) + { + if ( *((uint8_t *)address) == c) return i; + } + + return -1; +} + +static void LoadBytes(void *src, unsigned length, unsigned offset, void *dest, unsigned count) +{ + // load with wrap-around. + + if (offset + count < length) + { + std::memcpy(dest, (uint8_t *)src + offset, count); + return; + } + + unsigned x = length - offset; + std::memcpy(dest, (uint8_t *)src + offset, x); + + std::memcpy((uint8_t *)dest + x, src, count - x); +} + + + +class CircleBuffer { + +public: + + CircleBuffer(void *address, unsigned length) + { + _address = (uint8_t *)address; + _length = length; + } + + uint8_t operator[](unsigned i) const + { + if (i >= _length) i %= _length; + return _address[i]; + } + + uint8_t& operator[](unsigned i) + { + if (i >= _length) i %= _length; + return _address[i]; + } + +private: + uint8_t *_address; + unsigned _length; + +}; + +/* + * Address Field: + * prologue volume track sector checksum epilogue + * D5 AA 96 XX YY XX YY XX YY XX YY DE AA EB + */ + +/* + * Data Field: + * prologue user data checksum epilogue + * D5 AA AD [6+2 encoded] XX DE AA EB + */ + + +/* + * 0x00 + *------------------------ + * A7 A6 A5 A4 A3 A2 A1 A0 + * B7 B6 B5 B4 B3 B2 B1 B0 + * C7 C6 C5 C4 C3 C2 C1 C0 + * D7 D6 D5 D4 D3 D2 D1 D0 + * E7 E6 E5 E4 E3 E2 E1 E0 + * F7 F6 F5 F4 F3 F2 F1 F0 + * ... + *------------------------ + * 0x100 + * || + * \/ + * 0x00 + * ----------------------- + * 0 0 A7 A6 A5 A4 A3 A2 + * 0 0 B7 B6 B5 B4 B3 B2 + * 0 0 C7 C6 C5 C4 C3 C2 + * 0 0 D7 D6 D5 D4 D3 D2 + * 0 0 E7 E6 E5 E4 E3 E2 + * 0 0 F7 F6 F5 F4 F3 F2 + * ... + * 0x100 (256): + * ----------------------- + * ... + * 0 0 x x x x F0 F1 + * 0 0 x x x x E0 E1 + * 0 0 x x x x D0 D1 + * 0 0 x x x x C0 C1 + * 0 0 x x x x B0 B1 + * 0 0 x x x x A0 A1 + * ----------------------- + * 0x156 (342) + * + * + * + * + * + * + * + */ + + +NibbleAdaptor::NibbleAdaptor(void *address, unsigned length) +{ +#undef __METHOD__ +#define __METHOD__ "NibbleAdaptor::NibbleAdaptor" + + _address = (uint8_t *)address; + _length = length; + + + // build a map of track/sectors. + + unsigned state = 0; + + + _index.resize(35 * 16, -1); + + int offset = 0; + + unsigned track = 0; + unsigned sector = 0; + unsigned volume = 0; + unsigned checksum = 0; + + + CircleBuffer buffer(_address, _length); + for (;;) + { + + offset = FindByte(address, 0xd5, length, offset); + if (offset < 0) break; + + if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0x96) + { + state = 1; + + volume = decode44(buffer[offset + 3], buffer[offset + 4]); + track = decode44(buffer[offset + 5], buffer[offset + 6]); + sector = decode44(buffer[offset + 7], buffer[offset + 8]); + checksum = decode44(buffer[offset + 9], buffer[offset + 10]); + + if (volume ^ track ^ sector ^ checksum) + throw ProFUSE::Exception(__METHOD__ ": Invalid address checksum."); + + if (track > 35 || sector > 16) + throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector."); + + // epilogue is not always de aa eb + continue; + + } + + if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0xad && state == 1) + { + _index[track * 16 + sector] = (offset + 3) % _length; + + state = 0; + continue; + } + + // ???? + + } + + // possible wraparound. + if (state == 1) + { + offset = FindByte(address, 0xd5, length, 0); + + if (offset >= 0) + { + + if (buffer[offset + 1] == 0xaa && buffer[offset + 2] == 0xad) + { + _index[track * 16 + sector] = (offset + 3) % _length; + } + } + } + + + // now check _index for offset = -1, which means the sector/track wasn't found. + + for (std::vector::iterator iter = _index.begin(); iter != _index.end(); ++iter) + { + if (*iter == -1) + throw ProFUSE::Exception(__METHOD__ ": Sector missing."); + } + +} + + + +void NibbleAdaptor::readTrackSector(TrackSector ts, void *bp) +{ +#undef __METHOD__ +#define __METHOD__ "NibbleAdaptor::readTrackSector" + + if (ts.track > 35 || ts.sector > 16) + throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector."); + + + CircleBuffer buffer(_address, _length); + uint8_t bits[86 * 3]; + + uint8_t checksum = 0; + + + unsigned offset = _index[ts.track * 16 + ts.sector]; + + + // first 86 bytes are in the auxbuffer, backwards. + for (unsigned i = 0; i < 86; ++i) + { + uint8_t x = buffer[offset + i]; + x = decode62(x); + + checksum ^= x; + + uint8_t y = checksum; + + for (unsigned j = 0; j < 3; ++i) + { + bits[i + j * 86] = ((y & 0x01) << 1) | ((y & 0x02) >> 1); + y >>= 2; + } + } + + for (unsigned i = 0; i < 256; ++i) + { + uint8_t x = buffer[offset + 86 + i]; + x = decode62(x); + + checksum ^= x; + + uint8_t y = (checksum << 2) | bits[i]; + + + + ((uint8_t *)bp)[i] = y; + } + + if (checksum != buffer[342]) + throw ProFUSE::Exception(__METHOD__ ": Invalid field checksum."); + +} + +void NibbleAdaptor::writeTrackSector(TrackSector ts, const void *bp) +{ +#undef __METHOD__ +#define __METHOD__ "NibbleAdaptor::readTrackSector" + + if (ts.track > 35 || ts.sector > 16) + throw ProFUSE::Exception(__METHOD__ ": Invalid track/sector."); + + uint8_t auxBuffer[86]; + uint8_t checksum = 0; + + // create the aux buffer. + + std::memset(auxBuffer, 0, sizeof(auxBuffer)); + + for (unsigned i = 0, j = 86, shift = 0; i < 256; ++i) + { + uint8_t x = ((const uint8_t *)bp)[i]; + + // grab the bottom 2 bytes and reverse them. + uint8_t y = ((x & 0x01) << 1) | ((x & 0x02) >> 1); + + auxBuffer[--j] |= (y << shift); + + if (j == 0) + { + j = 86; + shift += 2; + } + } + + unsigned offset = _index[ts.track * 16 + ts.sector]; + + CircleBuffer buffer(_address, _length); + // create the checksum while writing to disk.. + + // aux buffer + for (unsigned i = 0; i < 86; ++i) + { + uint8_t x = auxBuffer[i]; + + buffer[offset + i] = encode62(x ^ checksum); + + checksum = x; + } + + for (unsigned i = 0; i < 256; ++i) + { + uint8_t x = ((const uint8_t *)bp)[i]; + x >>= 2; + + buffer[offset + 86 + i] = encode62(x ^ checksum); + + checksum = x; + } + + + + buffer[offset + 342] = checksum; +} + diff --git a/Device/Adaptor.h b/Device/Adaptor.h index 311077f..e76f5d3 100644 --- a/Device/Adaptor.h +++ b/Device/Adaptor.h @@ -1,8 +1,13 @@ #ifndef __DEVICE_ADAPTOR_H__ #define __DEVICE_ADAPTOR_H__ +#include +#include + #include +#include + namespace Device { class Adaptor @@ -38,6 +43,34 @@ namespace Device { // TODO -- nibble adaptor. + + class NibbleAdaptor : public Adaptor + { + public: + + NibbleAdaptor(void *address, unsigned length); + virtual ~NibbleAdaptor(); + + virtual void readBlock(unsigned block, void *bp); + virtual void writeBlock(unsigned block, const void *bp); + + + virtual void readTrackSector(TrackSector ts, void *bp); + virtual void writeTrackSector(TrackSector ts, const void *bp); + + static std::pairencode44(uint8_t); + static uint8_t decode44(uint8_t, uint8_t); + + static uint8_t encode62(uint8_t); + static uint8_t decode62(uint8_t); + + + private: + uint8_t *_address; + unsigned _length; + + std::vector _index; + }; }