der2dmk.cc 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. #include <string>
  2. #include <stdexcept>
  3. #include <vector>
  4. #include <cassert>
  5. #include <cstdio>
  6. #include <cstring>
  7. #include <cstdlib>
  8. #include <sys/stat.h>
  9. #include <sys/types.h>
  10. using namespace std;
  11. typedef unsigned char byte; // 8 bit
  12. typedef unsigned short word; // 16 bit
  13. struct DiskInfo
  14. {
  15. int gap1;
  16. int gap2;
  17. int gap3;
  18. int gap4a;
  19. int gap4b;
  20. int sectorsPerTrack;
  21. int numberCylinders;
  22. int sectorSizeCode;
  23. bool doubleSided;
  24. };
  25. struct DmkHeader
  26. {
  27. byte writeProtected;
  28. byte numTracks;
  29. byte trackLen[2];
  30. byte flags;
  31. byte reserved[7];
  32. byte format[4];
  33. };
  34. class File
  35. {
  36. public:
  37. File(const string& filename, const char* mode)
  38. : f(fopen(filename.c_str(), mode))
  39. {
  40. if (!f) {
  41. throw runtime_error("Couldn't open: " + filename);
  42. }
  43. }
  44. ~File()
  45. {
  46. fclose(f);
  47. }
  48. void read(void* data, int size)
  49. {
  50. if (fread(data, size, 1, f) != 1) {
  51. throw runtime_error("Couldn't read file");
  52. }
  53. }
  54. void write(const void* data, int size)
  55. {
  56. if (fwrite(data, size, 1, f) != 1) {
  57. throw runtime_error("Couldn't write file");
  58. }
  59. }
  60. private:
  61. FILE* f;
  62. };
  63. static void updateCrc(word& crc, byte val)
  64. {
  65. for (int i = 8; i < 16; ++i) {
  66. crc = (crc << 1) ^ ((((crc ^ (val << i)) & 0x8000) ? 0x1021 : 0));
  67. }
  68. }
  69. static void fill(byte*& p, int len, byte value)
  70. {
  71. memset(p, value, len);
  72. p += len;
  73. }
  74. void convert(const DiskInfo& info, const string& dsk,
  75. const string& der, const string& dmk)
  76. {
  77. int numSides = info.doubleSided ? 2 : 1;
  78. int sectorSize = 128 << info.sectorSizeCode;
  79. int totalTracks = numSides * info.numberCylinders;
  80. int totalSectors = totalTracks * info.sectorsPerTrack;
  81. int totalSize = totalSectors * sectorSize;
  82. struct stat st;
  83. stat(dsk.c_str(), &st);
  84. if (st.st_size != totalSize) {
  85. throw runtime_error("Wrong input filesize");
  86. }
  87. File inf (dsk, "rb");
  88. File derf(der, "rb");
  89. File outf(dmk, "wb");
  90. static const char* const DER_HEADER = "DiskImage errors\r\n\032";
  91. char derHeader[20];
  92. derf.read(derHeader, 20);
  93. if (memcmp(derHeader, DER_HEADER, 20) != 0) {
  94. throw runtime_error("Invalid .der file.");
  95. }
  96. int derSize = (totalSectors + 7) / 8;
  97. vector<byte> derBuf(derSize);
  98. derf.read(derBuf.data(), derSize);
  99. int rawSectorLen =
  100. 12 + 10 + info.gap2 + 12 + 4 +
  101. sectorSize + 2 + info.gap3;
  102. int rawTrackLen =
  103. info.gap4a + 12 + 4 + info.gap1 +
  104. info.sectorsPerTrack * rawSectorLen + info.gap4b;
  105. assert(rawTrackLen == 6250);
  106. int dmkTrackLen = rawTrackLen + 128;
  107. DmkHeader header;
  108. memset(&header, 0, sizeof(header));
  109. header.numTracks = info.numberCylinders;
  110. header.trackLen[0] = dmkTrackLen & 0xff;
  111. header.trackLen[1] = dmkTrackLen >> 8;
  112. header.flags = (info.doubleSided ? (0 << 4) : (1 << 4)) |
  113. (0 << 6); // double density (MFM)
  114. outf.write(&header, sizeof(header));
  115. vector<byte*> addrPos(info.sectorsPerTrack);
  116. vector<byte*> dataPos(info.sectorsPerTrack);
  117. vector<byte> buf(dmkTrackLen); // zero-initialized
  118. byte* ip = &buf[ 0]; // pointer in IDAM table
  119. byte* tp = &buf[128]; // pointer in actual track data
  120. fill(tp, info.gap4a, 0x4e); // gap4a
  121. fill(tp, 12, 0x00); // sync
  122. fill(tp, 3, 0xc2); // index mark
  123. fill(tp, 1, 0xfc); //
  124. fill(tp, info.gap1, 0x4e); // gap1
  125. for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
  126. fill(tp, 12, 0x00); // sync
  127. fill(tp, 3, 0xa1); // ID addr mark
  128. int pos = tp - &buf[0];
  129. assert(pos < 0x4000);
  130. *ip++ = pos & 0xff;
  131. *ip++ = (pos >> 8) | 0x80; // double density (MFM) sector
  132. fill(tp, 1, 0xfe); // ID addr mark (cont)
  133. addrPos[sec] = tp;
  134. fill(tp, 6, 0x00); // C H R N CRC (overwritten later)
  135. fill(tp, info.gap2, 0x4e); // gap2
  136. fill(tp, 12, 0x00); // sync
  137. fill(tp, 3, 0xa1); // data mark
  138. fill(tp, 1, 0xfb); //
  139. dataPos[sec] = tp;
  140. fill(tp, sectorSize, 0x00); // sector data (overwritten later)
  141. fill(tp, 2, 0x00); // CRC (overwritten later)
  142. fill(tp, info.gap3, 0x4e); // gap3
  143. }
  144. fill(tp, info.gap4b, 0x4e); // gap4b
  145. assert((tp - &buf[0]) == dmkTrackLen);
  146. int derCount = 0;
  147. for (int cyl = 0; cyl < info.numberCylinders; ++cyl) {
  148. for (int head = 0; head < numSides; ++head) {
  149. for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
  150. byte* ap = addrPos[sec];
  151. *ap++ = cyl;
  152. *ap++ = head;
  153. *ap++ = sec + 1;
  154. *ap++ = info.sectorSizeCode;
  155. word addrCrc = 0xffff;
  156. const byte* t1 = ap - 8;
  157. for (int i = 0; i < 8; ++i) {
  158. updateCrc(addrCrc, t1[i]);
  159. }
  160. *ap++ = addrCrc >> 8;
  161. *ap++ = addrCrc & 0xff;
  162. byte* dp = dataPos[sec];
  163. inf.read(dp, sectorSize);
  164. dp += sectorSize;
  165. word dataCrc = 0xffff;
  166. const byte* t2 = dp - sectorSize - 4;
  167. for (int i = 0; i < sectorSize + 4; ++i) {
  168. updateCrc(dataCrc, t2[i]);
  169. }
  170. if (derBuf[derCount / 8] & (0x80 >> (derCount % 8))) {
  171. // create CRC error for this sector
  172. dataCrc ^= 0xffff;
  173. }
  174. ++derCount;
  175. *dp++ = dataCrc >> 8;
  176. *dp++ = dataCrc & 0xff;
  177. }
  178. outf.write(&buf[0], dmkTrackLen);
  179. }
  180. }
  181. }
  182. int main(int argc, char** argv)
  183. {
  184. if (argc != 4) {
  185. printf("der2dmk\n"
  186. "\n"
  187. "Utility to convert a dsk disk image with associated disk\n"
  188. "error file into a dmk disk image. At the moment this utility\n"
  189. "is limited to 720kB double sided, double density dsk images.\n"
  190. "\n"
  191. "Usage: %s <input.dsk> <input.der> <output.dmk>\n", argv[0]);
  192. exit(1);
  193. }
  194. // TODO add command line options to make these parameters configurable
  195. DiskInfo info;
  196. info.gap1 = 50;
  197. info.gap2 = 22;
  198. info.gap3 = 84;
  199. info.gap4a = 80;
  200. info.gap4b = 182; // TODO calculate from other values
  201. info.sectorsPerTrack = 9;
  202. info.numberCylinders = 80;
  203. info.sectorSizeCode = 2; // 512 = 128 << 2
  204. info.doubleSided = true;
  205. try {
  206. convert(info, argv[1], argv[2], argv[3]);
  207. } catch (std::exception& e) {
  208. fprintf(stderr, "Error: %s\n", e.what());
  209. }
  210. }