123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216 |
- #include <string>
- #include <stdexcept>
- #include <cassert>
- #include <cstdint>
- #include <cstdio>
- #include <cstring>
- #include <cstdlib>
- #include <sys/stat.h>
- #include <sys/types.h>
- using namespace std;
- static const int TRACK_LENGTH = 6250;
- static const int DMK_TRACK_LEN = TRACK_LENGTH + 128;
- static const int NUM_CYLINDERS = 40;
- static const int GAP1 = 50;
- static const int GAP2 = 22;
- static const int GAP3 = 34;
- static const int GAP4a = 80;
- struct DmkHeader
- {
- uint8_t writeProtected;
- uint8_t numTracks;
- uint8_t trackLen[2];
- uint8_t flags;
- uint8_t reserved[7];
- uint8_t format[4];
- };
- class File
- {
- public:
- File(const char* filename, const char* mode)
- : f(fopen(filename, mode))
- {
- if (!f) {
- throw runtime_error(string("Couldn't open: ") + filename);
- }
- }
- ~File()
- {
- fclose(f);
- }
- void read(void* data, int size)
- {
- if (fread(data, size, 1, f) != 1) {
- throw runtime_error("Couldn't read file");
- }
- }
- void write(const void* data, int size)
- {
- if (fwrite(data, size, 1, f) != 1) {
- throw runtime_error("Couldn't write file");
- }
- }
- private:
- FILE* f;
- };
- static uint16_t calculateCrc(const uint8_t* p, int n)
- {
- uint16_t crc = 0xffff;
- for (int i = 0; i < n; ++i) {
- for (int j = 8; j < 16; ++j) {
- crc = (crc << 1) ^ ((((crc ^ (p[i] << j)) & 0x8000) ? 0x1021 : 0));
- }
- }
- return crc;
- }
- static void fill(uint8_t*& p, int len, uint8_t value)
- {
- memset(p, value, len);
- p += len;
- }
- static void convertTrack(int cyl, int head,
- int sectorsPerTrack, int sectorSizeCode, int gap3,
- File& inf, File& outf)
- {
- int sectorSize = 128 << sectorSizeCode;
- int rawSectorLen = 12 + 10 + GAP2 + 12 + 4 + sectorSize + 2 + gap3;
- int gap4b = TRACK_LENGTH - (GAP4a + 12 + 4 + GAP1 + sectorsPerTrack * rawSectorLen);
- assert(gap4b > 0);
- uint8_t buf[DMK_TRACK_LEN];
- memset(buf, 0, sizeof(buf));
- uint8_t* ip = &buf[ 0]; // pointer in IDAM table
- uint8_t* tp = &buf[128]; // pointer in actual track data
- fill(tp, GAP4a, 0x4e); // gap4a
- fill(tp, 12, 0x00); // sync
- fill(tp, 3, 0xc2); // index mark
- fill(tp, 1, 0xfc); //
- fill(tp, GAP1, 0x4e); // gap1
- for (int sec = 0; sec < sectorsPerTrack; ++sec) {
- fill(tp, 12, 0x00); // sync
- fill(tp, 3, 0xa1); // ID addr mark
- int pos = tp - &buf[0];
- assert(pos < 0x4000);
- *ip++ = pos & 0xff;
- *ip++ = (pos >> 8) | 0x80; // double density (MFM) sector
- fill(tp, 1, 0xfe); // ID addr mark (cont)
- *tp++ = cyl; // C
- *tp++ = head; // H
- *tp++ = sec + 1; // R
- *tp++ = sectorSizeCode; // N
- auto addrCrc = calculateCrc(tp - 8, 8);
- *tp++ = addrCrc >> 8; // CRC-1
- *tp++ = addrCrc & 0xff; // CRC-2
- fill(tp, GAP2, 0x4e); // gap2
- fill(tp, 12, 0x00); // sync
- fill(tp, 3, 0xa1); // data mark
- fill(tp, 1, 0xfb); //
- inf.read(tp, sectorSize);
- auto dataCrc = calculateCrc(tp - 4, sectorSize + 4);
- tp += sectorSize;
- *tp++ = dataCrc >> 8;
- *tp++ = dataCrc & 0xff;
- fill(tp, gap3, 0x4e); // gap3
- }
- fill(tp, gap4b, 0x4e); // gap4b
- assert((tp - &buf[0]) == DMK_TRACK_LEN);
- outf.write(&buf[0], DMK_TRACK_LEN);
- }
- static void convert(const char* input, const char* output)
- {
- // Single or double sided input image?
- struct stat st;
- stat(input, &st);
- bool doubleSided;
- switch (st.st_size) {
- case 172032:
- doubleSided = false;
- break;
- case 346112:
- doubleSided = true;
- break;
- default:
- throw runtime_error(
- "input filesize should be exactly 172032 or 346112 bytes.\n");
- }
- // Write DMK header
- DmkHeader header;
- memset(&header, 0, sizeof(header));
- header.numTracks = NUM_CYLINDERS;
- header.trackLen[0] = DMK_TRACK_LEN & 0xff;
- header.trackLen[1] = DMK_TRACK_LEN >> 8;
- header.flags = (doubleSided ? (0 << 4) : (1 << 4)) |
- (0 << 6); // double density (MFM)
- File outf(output, "wb");
- outf.write(&header, sizeof(header));
- // Read input image and convert to DMK, track per track
- File inf(input, "rb");
- int numSides = doubleSided ? 2 : 1;
- for (int cyl = 0; cyl < NUM_CYLINDERS; ++cyl) {
- for (int head = 0; head < numSides; ++head) {
- // first track has different layout
- int sectorsPerTrack;
- int sectorSizeCode;
- int gap3;
- if ((head == 0) && (cyl == 0)) {
- sectorsPerTrack = 18;
- sectorSizeCode = 0; // 128 bytes
- gap3 = 84;
- } else {
- sectorsPerTrack = 17;
- sectorSizeCode = 1; // 256 bytes
- gap3 = 34;
- }
- convertTrack(cyl, head,
- sectorsPerTrack, sectorSizeCode, gap3,
- inf, outf);
- }
- }
- }
- int main(int argc, char** argv)
- {
- if (argc != 3) {
- printf("svi2dmk\n"
- "-------\n"
- "\n"
- "Utility to convert a SVI disk image into a DMK disk image.\n"
- "\n"
- "The SVI image is expected to have to following format:\n"
- " - 1st track (track 0, side 0) contains 18 sectors of 128 bytes.\n"
- " - All other tracks contain 17 sectors of 256 bytes.\n"
- " - There are 40 tracks on the disk.\n"
- " - The disk can be either single or double sided.\n"
- "This means that the size of the input image should be exactly\n"
- "172032 bytes for single sided disks or 346112 bytes for double\n"
- "sided disks.\n"
- "\n"
- "Usage: %s <input.dsk> <output.dmk>\n", argv[0]);
- exit(1);
- }
- try {
- convert(argv[1], argv[2]);
- } catch (std::exception& e) {
- fprintf(stderr, "Error: %s\n", e.what());
- exit(2);
- }
- }
|