dsk2dmk.cc 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  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. static const unsigned int TRACK_LENGTH = 6250;
  14. struct DiskInfo
  15. {
  16. int gap1;
  17. int gap2;
  18. int gap3;
  19. int gap4a;
  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& input, const string& output)
  75. {
  76. int numSides = info.doubleSided ? 2 : 1;
  77. int sectorSize = 128 << info.sectorSizeCode;
  78. int totalTracks = numSides * info.numberCylinders;
  79. int totalSectors = totalTracks * info.sectorsPerTrack;
  80. int totalSize = totalSectors * sectorSize;
  81. struct stat st;
  82. stat(input.c_str(), &st);
  83. if (st.st_size != totalSize) {
  84. throw runtime_error("Wrong input filesize");
  85. }
  86. File inf(input, "rb");
  87. File outf(output, "wb");
  88. int rawSectorLen =
  89. 12 + 10 + info.gap2 + 12 + 4 +
  90. sectorSize + 2 + info.gap3;
  91. int gap4b = TRACK_LENGTH - (info.gap4a + 12 + 4 + info.gap1 +
  92. info.sectorsPerTrack * rawSectorLen);
  93. assert(gap4b > 0);
  94. int dmkTrackLen = TRACK_LENGTH + 128;
  95. DmkHeader header;
  96. memset(&header, 0, sizeof(header));
  97. header.numTracks = info.numberCylinders;
  98. header.trackLen[0] = dmkTrackLen & 0xff;
  99. header.trackLen[1] = dmkTrackLen >> 8;
  100. header.flags = (info.doubleSided ? (0 << 4) : (1 << 4)) |
  101. (0 << 6); // double density (MFM)
  102. outf.write(&header, sizeof(header));
  103. vector<byte*> addrPos(info.sectorsPerTrack);
  104. vector<byte*> dataPos(info.sectorsPerTrack);
  105. vector<byte> buf(dmkTrackLen); // zero-initialized
  106. byte* ip = &buf[ 0]; // pointer in IDAM table
  107. byte* tp = &buf[128]; // pointer in actual track data
  108. fill(tp, info.gap4a, 0x4e); // gap4a
  109. fill(tp, 12, 0x00); // sync
  110. fill(tp, 3, 0xc2); // index mark
  111. fill(tp, 1, 0xfc); //
  112. fill(tp, info.gap1, 0x4e); // gap1
  113. for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
  114. fill(tp, 12, 0x00); // sync
  115. fill(tp, 3, 0xa1); // ID addr mark
  116. int pos = tp - &buf[0];
  117. assert(pos < 0x4000);
  118. *ip++ = pos & 0xff;
  119. *ip++ = (pos >> 8) | 0x80; // double density (MFM) sector
  120. fill(tp, 1, 0xfe); // ID addr mark (cont)
  121. addrPos[sec] = tp;
  122. fill(tp, 6, 0x00); // C H R N CRC (overwritten later)
  123. fill(tp, info.gap2, 0x4e); // gap2
  124. fill(tp, 12, 0x00); // sync
  125. fill(tp, 3, 0xa1); // data mark
  126. fill(tp, 1, 0xfb); //
  127. dataPos[sec] = tp;
  128. fill(tp, sectorSize, 0x00); // sector data (overwritten later)
  129. fill(tp, 2, 0x00); // CRC (overwritten later)
  130. fill(tp, info.gap3, 0x4e); // gap3
  131. }
  132. fill(tp, gap4b, 0x4e); // gap4b
  133. assert((tp - &buf[0]) == dmkTrackLen);
  134. for (int cyl = 0; cyl < info.numberCylinders; ++cyl) {
  135. for (int head = 0; head < numSides; ++head) {
  136. for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
  137. byte* ap = addrPos[sec];
  138. *ap++ = cyl;
  139. *ap++ = head;
  140. *ap++ = sec + 1;
  141. *ap++ = info.sectorSizeCode;
  142. word addrCrc = 0xffff;
  143. const byte* t1 = ap - 8;
  144. for (int i = 0; i < 8; ++i) {
  145. updateCrc(addrCrc, t1[i]);
  146. }
  147. *ap++ = addrCrc >> 8;
  148. *ap++ = addrCrc & 0xff;
  149. byte* dp = dataPos[sec];
  150. inf.read(dp, sectorSize);
  151. dp += sectorSize;
  152. word dataCrc = 0xffff;
  153. const byte* t2 = dp - sectorSize - 4;
  154. for (int i = 0; i < sectorSize + 4; ++i) {
  155. updateCrc(dataCrc, t2[i]);
  156. }
  157. *dp++ = dataCrc >> 8;
  158. *dp++ = dataCrc & 0xff;
  159. }
  160. outf.write(&buf[0], dmkTrackLen);
  161. }
  162. }
  163. }
  164. int main(int argc, char** argv)
  165. {
  166. if (argc != 3) {
  167. printf("dsk2dmk\n"
  168. "\n"
  169. "Utility to convert a dsk disk image into a dmk disk\n"
  170. "image. At the moment this utility is limited to 720kB\n"
  171. "double sided, double density dsk images.\n"
  172. "\n"
  173. "Usage: %s <input.dsk> <output.dmk>\n", argv[0]);
  174. exit(1);
  175. }
  176. // TODO add command line options to make these parameters configurable
  177. DiskInfo info;
  178. info.gap1 = 50;
  179. info.gap2 = 22;
  180. info.gap3 = 84;
  181. info.gap4a = 80;
  182. info.sectorsPerTrack = 9;
  183. info.numberCylinders = 80;
  184. info.sectorSizeCode = 2; // 512 = 128 << 2
  185. info.doubleSided = true;
  186. try {
  187. convert(info, argv[1], argv[2]);
  188. } catch (std::exception& e) {
  189. fprintf(stderr, "Error: %s\n", e.what());
  190. }
  191. }