svi2dmk.cc 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. #include <string>
  2. #include <stdexcept>
  3. #include <cassert>
  4. #include <cstdint>
  5. #include <cstdio>
  6. #include <cstring>
  7. #include <cstdlib>
  8. #include <sys/stat.h>
  9. #include <sys/types.h>
  10. using namespace std;
  11. static const int TRACK_LENGTH = 6250;
  12. static const int DMK_TRACK_LEN = TRACK_LENGTH + 128;
  13. static const int NUM_CYLINDERS = 40;
  14. static const int GAP1 = 50;
  15. static const int GAP2 = 22;
  16. static const int GAP3 = 34;
  17. static const int GAP4a = 80;
  18. struct DmkHeader
  19. {
  20. uint8_t writeProtected;
  21. uint8_t numTracks;
  22. uint8_t trackLen[2];
  23. uint8_t flags;
  24. uint8_t reserved[7];
  25. uint8_t format[4];
  26. };
  27. class File
  28. {
  29. public:
  30. File(const char* filename, const char* mode)
  31. : f(fopen(filename, mode))
  32. {
  33. if (!f) {
  34. throw runtime_error(string("Couldn't open: ") + filename);
  35. }
  36. }
  37. ~File()
  38. {
  39. fclose(f);
  40. }
  41. void read(void* data, int size)
  42. {
  43. if (fread(data, size, 1, f) != 1) {
  44. throw runtime_error("Couldn't read file");
  45. }
  46. }
  47. void write(const void* data, int size)
  48. {
  49. if (fwrite(data, size, 1, f) != 1) {
  50. throw runtime_error("Couldn't write file");
  51. }
  52. }
  53. private:
  54. FILE* f;
  55. };
  56. static uint16_t calculateCrc(const uint8_t* p, int n)
  57. {
  58. uint16_t crc = 0xffff;
  59. for (int i = 0; i < n; ++i) {
  60. for (int j = 8; j < 16; ++j) {
  61. crc = (crc << 1) ^ ((((crc ^ (p[i] << j)) & 0x8000) ? 0x1021 : 0));
  62. }
  63. }
  64. return crc;
  65. }
  66. static void fill(uint8_t*& p, int len, uint8_t value)
  67. {
  68. memset(p, value, len);
  69. p += len;
  70. }
  71. static void convertTrack(int cyl, int head,
  72. int sectorsPerTrack, int sectorSizeCode, int gap3,
  73. File& inf, File& outf)
  74. {
  75. int sectorSize = 128 << sectorSizeCode;
  76. int rawSectorLen = 12 + 10 + GAP2 + 12 + 4 + sectorSize + 2 + gap3;
  77. int gap4b = TRACK_LENGTH - (GAP4a + 12 + 4 + GAP1 + sectorsPerTrack * rawSectorLen);
  78. assert(gap4b > 0);
  79. uint8_t buf[DMK_TRACK_LEN];
  80. memset(buf, 0, sizeof(buf));
  81. uint8_t* ip = &buf[ 0]; // pointer in IDAM table
  82. uint8_t* tp = &buf[128]; // pointer in actual track data
  83. fill(tp, GAP4a, 0x4e); // gap4a
  84. fill(tp, 12, 0x00); // sync
  85. fill(tp, 3, 0xc2); // index mark
  86. fill(tp, 1, 0xfc); //
  87. fill(tp, GAP1, 0x4e); // gap1
  88. for (int sec = 0; sec < sectorsPerTrack; ++sec) {
  89. fill(tp, 12, 0x00); // sync
  90. fill(tp, 3, 0xa1); // ID addr mark
  91. int pos = tp - &buf[0];
  92. assert(pos < 0x4000);
  93. *ip++ = pos & 0xff;
  94. *ip++ = (pos >> 8) | 0x80; // double density (MFM) sector
  95. fill(tp, 1, 0xfe); // ID addr mark (cont)
  96. *tp++ = cyl; // C
  97. *tp++ = head; // H
  98. *tp++ = sec + 1; // R
  99. *tp++ = sectorSizeCode; // N
  100. auto addrCrc = calculateCrc(tp - 8, 8);
  101. *tp++ = addrCrc >> 8; // CRC-1
  102. *tp++ = addrCrc & 0xff; // CRC-2
  103. fill(tp, GAP2, 0x4e); // gap2
  104. fill(tp, 12, 0x00); // sync
  105. fill(tp, 3, 0xa1); // data mark
  106. fill(tp, 1, 0xfb); //
  107. inf.read(tp, sectorSize);
  108. auto dataCrc = calculateCrc(tp - 4, sectorSize + 4);
  109. tp += sectorSize;
  110. *tp++ = dataCrc >> 8;
  111. *tp++ = dataCrc & 0xff;
  112. fill(tp, gap3, 0x4e); // gap3
  113. }
  114. fill(tp, gap4b, 0x4e); // gap4b
  115. assert((tp - &buf[0]) == DMK_TRACK_LEN);
  116. outf.write(&buf[0], DMK_TRACK_LEN);
  117. }
  118. static void convert(const char* input, const char* output)
  119. {
  120. // Single or double sided input image?
  121. struct stat st;
  122. stat(input, &st);
  123. bool doubleSided;
  124. switch (st.st_size) {
  125. case 172032:
  126. doubleSided = false;
  127. break;
  128. case 346112:
  129. doubleSided = true;
  130. break;
  131. default:
  132. throw runtime_error(
  133. "input filesize should be exactly 172032 or 346112 bytes.\n");
  134. }
  135. // Write DMK header
  136. DmkHeader header;
  137. memset(&header, 0, sizeof(header));
  138. header.numTracks = NUM_CYLINDERS;
  139. header.trackLen[0] = DMK_TRACK_LEN & 0xff;
  140. header.trackLen[1] = DMK_TRACK_LEN >> 8;
  141. header.flags = (doubleSided ? (0 << 4) : (1 << 4)) |
  142. (0 << 6); // double density (MFM)
  143. File outf(output, "wb");
  144. outf.write(&header, sizeof(header));
  145. // Read input image and convert to DMK, track per track
  146. File inf(input, "rb");
  147. int numSides = doubleSided ? 2 : 1;
  148. for (int cyl = 0; cyl < NUM_CYLINDERS; ++cyl) {
  149. for (int head = 0; head < numSides; ++head) {
  150. // first track has different layout
  151. int sectorsPerTrack;
  152. int sectorSizeCode;
  153. int gap3;
  154. if ((head == 0) && (cyl == 0)) {
  155. sectorsPerTrack = 18;
  156. sectorSizeCode = 0; // 128 bytes
  157. gap3 = 84;
  158. } else {
  159. sectorsPerTrack = 17;
  160. sectorSizeCode = 1; // 256 bytes
  161. gap3 = 34;
  162. }
  163. convertTrack(cyl, head,
  164. sectorsPerTrack, sectorSizeCode, gap3,
  165. inf, outf);
  166. }
  167. }
  168. }
  169. int main(int argc, char** argv)
  170. {
  171. if (argc != 3) {
  172. printf("svi2dmk\n"
  173. "-------\n"
  174. "\n"
  175. "Utility to convert a SVI disk image into a DMK disk image.\n"
  176. "\n"
  177. "The SVI image is expected to have to following format:\n"
  178. " - 1st track (track 0, side 0) contains 18 sectors of 128 bytes.\n"
  179. " - All other tracks contain 17 sectors of 256 bytes.\n"
  180. " - There are 40 tracks on the disk.\n"
  181. " - The disk can be either single or double sided.\n"
  182. "This means that the size of the input image should be exactly\n"
  183. "172032 bytes for single sided disks or 346112 bytes for double\n"
  184. "sided disks.\n"
  185. "\n"
  186. "Usage: %s <input.dsk> <output.dmk>\n", argv[0]);
  187. exit(1);
  188. }
  189. try {
  190. convert(argv[1], argv[2]);
  191. } catch (std::exception& e) {
  192. fprintf(stderr, "Error: %s\n", e.what());
  193. exit(2);
  194. }
  195. }