OXYGENHUB
◆ main openmsx / Contrib / dmk / dsk2dmk.cc
4.5 KiB · C++ · last changed chore(): initial commit 1 month ago source blame history raw
e8555c89 Andy McCall 1
#include "dmk-common.hh"
2
3
#include <array>
4
#include <cassert>
5
#include <cstdint>
6
#include <cstdio>
7
#include <cstdlib>
8
#include <cstring>
9
#include <span>
10
#include <stdexcept>
11
#include <string>
12
#include <sys/stat.h>
13
#include <sys/types.h>
14
#include <vector>
15
16
static constexpr unsigned TRACK_LENGTH = 6250;
17
18
struct DiskInfo
19
{
20
	int gap1;
21
	int gap2;
22
	int gap3;
23
	int gap4a;
24
	int sectorsPerTrack;
25
	int numberCylinders;
26
	int sectorSizeCode;
27
	bool doubleSided;
28
};
29
30
static void fill(uint8_t*& p, int len, uint8_t value)
31
{
32
	memset(p, value, len);
33
	p += len;
34
}
35
36
void convert(const DiskInfo& info, const std::string& input, const std::string& output)
37
{
38
	int numSides = info.doubleSided ? 2 : 1;
39
	int sectorSize = 128 << info.sectorSizeCode;
40
	int totalTracks = numSides * info.numberCylinders;
41
	int totalSectors = totalTracks * info.sectorsPerTrack;
42
	int totalSize = totalSectors * sectorSize;
43
44
	struct stat st;
45
	stat(input.c_str(), &st);
46
	if (st.st_size != totalSize) {
47
		throw std::runtime_error("Wrong input filesize");
48
	}
49
50
	File inf(input, "rb");
51
	File outf(output, "wb");
52
53
	int rawSectorLen =
54
		12 + 10 + info.gap2 + 12 + 4 +
55
		sectorSize + 2 + info.gap3;
56
57
	int gap4b = TRACK_LENGTH - (info.gap4a + 12 + 4 + info.gap1 +
58
		info.sectorsPerTrack * rawSectorLen);
59
	assert(gap4b > 0);
60
	int dmkTrackLen = TRACK_LENGTH + 128;
61
62
	DmkHeader header;
63
	memset(&header, 0, sizeof(header));
64
	header.numTracks = info.numberCylinders;
65
	header.trackLen[0] = dmkTrackLen & 0xff;
66
	header.trackLen[1] = dmkTrackLen >> 8;
67
	header.flags = (info.doubleSided ? (0 << 4) : (1 << 4)) |
68
	               (0 << 6); // double density (MFM)
69
	outf.write(&header, sizeof(header));
70
71
	std::vector<uint8_t*> addrPos(info.sectorsPerTrack);
72
	std::vector<uint8_t*> dataPos(info.sectorsPerTrack);
73
	std::vector<uint8_t> buf(dmkTrackLen); // zero-initialized
74
	uint8_t* ip = buf.data() +   0; // pointer in IDAM table
75
	uint8_t* tp = buf.data() + 128; // pointer in actual track data
76
77
	fill(tp, info.gap4a, 0x4e); // gap4a
78
	fill(tp,         12, 0x00); // sync
79
	fill(tp,          3, 0xc2); // index mark
80
	fill(tp,          1, 0xfc); //
81
	fill(tp, info.gap1,  0x4e); // gap1
82
	for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
83
		fill(tp,         12, 0x00); // sync
84
		fill(tp,          3, 0xa1); // ID addr mark
85
		int pos = tp - buf.data();
86
		assert(pos < 0x4000);
87
		*ip++ = pos & 0xff;
88
		*ip++ = (pos >> 8) | 0x80; // double density (MFM) sector
89
		fill(tp,          1, 0xfe); // ID addr mark (cont)
90
		addrPos[sec] = tp;
91
		fill(tp,          6, 0x00); // C H R N CRC (overwritten later)
92
		fill(tp, info.gap2,  0x4e); // gap2
93
		fill(tp,         12, 0x00); // sync
94
		fill(tp,          3, 0xa1); // data mark
95
		fill(tp,          1, 0xfb); //
96
		dataPos[sec] = tp;
97
		fill(tp, sectorSize, 0x00); // sector data (overwritten later)
98
		fill(tp,          2, 0x00); // CRC (overwritten later)
99
		fill(tp, info.gap3,  0x4e); // gap3
100
	}
101
	fill(tp, gap4b, 0x4e); // gap4b
102
	assert((tp - buf.data()) == dmkTrackLen);
103
104
	for (int cyl = 0; cyl < info.numberCylinders; ++cyl) {
105
		for (int head = 0; head < numSides; ++head) {
106
			for (int sec = 0; sec < info.sectorsPerTrack; ++sec) {
107
				uint8_t* ap = addrPos[sec];
108
				*ap++ = cyl;
109
				*ap++ = head;
110
				*ap++ = sec + 1;
111
				*ap++ = info.sectorSizeCode;
112
113
				uint16_t addrCrc = 0xffff;
114
				assert(ap >= &buf[8]);
115
				const uint8_t* t1 = ap - 8;
116
				for (int i = 0; i < 8; ++i) {
117
					updateCrc(addrCrc, t1[i]);
118
				}
119
				*ap++ = addrCrc >> 8;
120
				*ap++ = addrCrc & 0xff;
121
122
				uint8_t* dp = dataPos[sec];
123
				inf.read(dp, sectorSize);
124
				dp += sectorSize;
125
126
				uint16_t dataCrc = 0xffff;
127
				const uint8_t* t2 = dp - sectorSize - 4;
128
				for (int i = 0; i < sectorSize + 4; ++i) {
129
					updateCrc(dataCrc, t2[i]);
130
				}
131
				*dp++ = dataCrc >> 8;
132
				*dp++ = dataCrc & 0xff;
133
			}
134
			outf.write(buf.data(), dmkTrackLen);
135
		}
136
	}
137
}
138
139
int main(int argc, const char** argv)
140
{
141
	std::span arg(argv, argc);
142
	if (arg.size() != 3) {
143
		printf("dsk2dmk\n"
144
		       "\n"
145
		       "Utility to convert a dsk disk image into a dmk disk\n"
146
		       "image. At the moment this utility is limited to 720kB\n"
147
		       "double sided, double density dsk images.\n"
148
		       "\n"
149
		       "Usage: %s <input.dsk> <output.dmk>\n", arg[0]);
150
		exit(1);
151
	}
152
153
	// TODO add command line options to make these parameters configurable
154
	DiskInfo info;
155
	info.gap1  =  50;
156
	info.gap2  =  22;
157
	info.gap3  =  84;
158
	info.gap4a =  80;
159
	info.sectorsPerTrack = 9;
160
	info.numberCylinders = 80;
161
	info.sectorSizeCode = 2; // 512 = 128 << 2
162
	info.doubleSided = true;
163
164
	try {
165
		convert(info, arg[1], arg[2]);
166
	} catch (std::exception& e) {
167
		fprintf(stderr, "Error: %s\n", e.what());
168
	}
169
}