Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
716 | lvd | 1 | #include "std.h" |
2 | |||
3 | #include "emul.h" |
||
4 | #include "vars.h" |
||
5 | |||
6 | #include "util.h" |
||
7 | #include "wd93crc.h " |
||
8 | |||
9 | #pragma pack(push, 1) |
||
10 | struct TFdiSecHdr |
||
11 | { |
||
12 | enum |
||
13 | { |
||
14 | FL_DELETED_DATA = 0x80, |
||
15 | FL_NO_DATA = 0x40, |
||
16 | FL_GOOD_CRC_4096 = 0x20, |
||
17 | FL_GOOD_CRC_2048 = 0x10, |
||
18 | FL_GOOD_CRC_1024 = 0x8, |
||
19 | FL_GOOD_CRC_512 = 0x4, |
||
20 | FL_GOOD_CRC_256 = 0x2, |
||
21 | FL_GOOD_CRC_128 = 0x1 |
||
22 | }; |
||
23 | |||
24 | u8 c; |
||
25 | u8 h; |
||
26 | u8 r; |
||
27 | u8 n; |
||
28 | // flags: |
||
29 | // bit 7 - 1 = deleted data (F8) / 0 = normal data (FB) |
||
30 | // bit 6 - 1 - sector with no data |
||
31 | // bits 0..5 - 1 = good crc for sector size (128, 256, 512, 1024, 2048, 4096) |
||
32 | u8 fl; |
||
33 | u16 DataOffset; |
||
34 | }; |
||
35 | |||
36 | struct TFdiTrkHdr |
||
37 | { |
||
38 | u32 TrkOffset; |
||
39 | u16 Res1; |
||
40 | u8 Spt; |
||
41 | TFdiSecHdr Sec[]; |
||
42 | }; |
||
43 | |||
44 | struct TFdiHdr |
||
45 | { |
||
46 | char Sig[3]; |
||
47 | u8 Rw; |
||
48 | u16 c; |
||
49 | u16 h; |
||
50 | u16 TextOffset; |
||
51 | u16 DataOffset; |
||
52 | u16 AddLen; |
||
53 | u8 AddData[]; // AddLen -> TFdiAddInfo |
||
54 | // TFdiTrkHdr Trk[c*h]; |
||
55 | }; |
||
56 | |||
57 | struct TFdiAddInfo |
||
58 | { |
||
59 | enum { BAD_BYTES = 1 }; |
||
60 | enum { FDI_2 = 2 }; |
||
61 | u16 Ver; // 2 - FDI 2 |
||
62 | u16 AddInfoType; // 1 - bad bytes info |
||
63 | u32 TrkAddInfoOffset; // -> TFdiTrkAddInfo |
||
64 | u32 DataOffset; |
||
65 | }; |
||
66 | |||
67 | struct TFdiSecAddInfo |
||
68 | { |
||
69 | u8 Flags; // 1 - Массив сбойных байтов присутствует |
||
70 | // Смещение битового массива сбойных байтов внутри трэка |
||
71 | // Число битов определяется размером сектора |
||
72 | // Один бит соответствует одному сбойному байту |
||
73 | u16 DataOffset; |
||
74 | }; |
||
75 | |||
76 | struct TFdiTrkAddInfo |
||
77 | { |
||
78 | u32 TrkOffset; // Смещение массива сбойных байтов для трэка относительно TFdiAddInfo->DataOffset, |
||
79 | // 0xFFFFFFFF - Массив описателей параметров секторов отсутствует |
||
80 | TFdiSecAddInfo Sec[]; // Spt |
||
81 | }; |
||
82 | #pragma pack(pop) |
||
83 | |||
84 | |||
85 | int FDD::read_fdi() |
||
86 | { |
||
87 | const TFdiHdr *FdiHdr = (const TFdiHdr *)snbuf; |
||
88 | unsigned cyls = FdiHdr->c; |
||
89 | unsigned sides = FdiHdr->h; |
||
90 | unsigned AddLen = FdiHdr->AddLen; |
||
91 | |||
92 | if(cyls > MAX_CYLS) |
||
93 | { |
||
94 | err_printf("cylinders (%u) > MAX_CYLS(%d)", cyls, MAX_CYLS); |
||
95 | return 0; |
||
96 | } |
||
97 | |||
98 | if(sides > 2) |
||
99 | { |
||
100 | err_printf("sides (%u) > 2", sides); |
||
101 | return 0; |
||
102 | } |
||
103 | |||
104 | newdisk(cyls, sides); |
||
105 | |||
106 | const TFdiAddInfo *FdiAddInfo = 0; |
||
107 | const TFdiTrkAddInfo *FdiTrkAddInfo = 0; |
||
108 | if(AddLen >= sizeof(TFdiAddInfo)) |
||
109 | { |
||
110 | // Проверить параметры FdiAddInfo (версию, тип и т.д.) |
||
111 | FdiAddInfo = (const TFdiAddInfo *)FdiHdr->AddData; |
||
112 | if(FdiAddInfo->Ver >= TFdiAddInfo::FDI_2 && FdiAddInfo->AddInfoType == TFdiAddInfo::BAD_BYTES) |
||
113 | { |
||
114 | FdiTrkAddInfo = (const TFdiTrkAddInfo *)(snbuf + FdiAddInfo->TrkAddInfoOffset); |
||
115 | } |
||
116 | } |
||
117 | |||
118 | strncpy(dsc, (const char *)&snbuf[FdiHdr->TextOffset], sizeof(dsc)); |
||
119 | dsc[sizeof(dsc) - 1] = 0; |
||
120 | |||
121 | int res = 1; |
||
122 | const TFdiTrkHdr *FdiTrkHdr = (const TFdiTrkHdr *)&snbuf[sizeof(TFdiHdr) + FdiHdr->AddLen]; |
||
123 | u8 *dat = snbuf + FdiHdr->DataOffset; |
||
124 | |||
125 | for (unsigned c = 0; c < cyls; c++) |
||
126 | { |
||
127 | for (unsigned s = 0; s < sides; s++) |
||
128 | { |
||
129 | t.seek(this, c,s, JUST_SEEK); |
||
130 | |||
131 | u8 *t0 = dat + FdiTrkHdr->TrkOffset; |
||
132 | unsigned ns = FdiTrkHdr->Spt; |
||
133 | u8 *wp0 = 0; |
||
134 | if(FdiTrkAddInfo && FdiTrkAddInfo->TrkOffset != UINT_MAX) |
||
135 | { |
||
136 | wp0 = snbuf + FdiAddInfo->DataOffset + FdiTrkAddInfo->TrkOffset; |
||
137 | if(wp0 > snbuf + snapsize) |
||
138 | { |
||
139 | err_printf("bad bytes data is beyond disk image end"); |
||
140 | return 0; |
||
141 | } |
||
142 | } |
||
143 | |||
144 | for (unsigned sec = 0; sec < ns; sec++) |
||
145 | { |
||
146 | t.hdr[sec].c = FdiTrkHdr->Sec[sec].c; |
||
147 | t.hdr[sec].s = FdiTrkHdr->Sec[sec].h; |
||
148 | t.hdr[sec].n = FdiTrkHdr->Sec[sec].r; |
||
149 | t.hdr[sec].l = FdiTrkHdr->Sec[sec].n; |
||
150 | t.hdr[sec].c1 = 0; |
||
151 | t.hdr[sec].wp = 0; |
||
152 | |||
153 | if (FdiTrkHdr->Sec[sec].fl & TFdiSecHdr::FL_NO_DATA) |
||
154 | t.hdr[sec].data = 0; |
||
155 | else |
||
156 | { |
||
157 | if (t0 + FdiTrkHdr->Sec[sec].DataOffset > snbuf + snapsize) |
||
158 | { |
||
159 | err_printf("sector data is beyond disk image end"); |
||
160 | return 0; |
||
161 | } |
||
162 | t.hdr[sec].data = t0 + FdiTrkHdr->Sec[sec].DataOffset; |
||
163 | |||
164 | if(FdiTrkAddInfo && FdiTrkAddInfo->TrkOffset != UINT_MAX) |
||
165 | { |
||
166 | t.hdr[sec].wp = ((FdiTrkAddInfo->Sec[sec].Flags & 1) ? (wp0 + FdiTrkAddInfo->Sec[sec].DataOffset) : 0); |
||
167 | } |
||
168 | #if 0 |
||
169 | if(FdiTrkHdr->Sec[sec].n > 3) |
||
170 | { |
||
171 | u8 buf[1+1024]; |
||
172 | buf[0] = (FdiTrkHdr->Sec[sec].fl & TFdiSecHdr::FL_DELETED_DATA) ? 0xF8 : 0xFB; |
||
173 | memcpy(buf+1, t.hdr[sec].data, 128U << (FdiTrkHdr->Sec[sec].n & 3)); |
||
174 | |||
175 | u16 crc_calc = wd93_crc(buf, (128U << (FdiTrkHdr->Sec[sec].n & 3)) + 1); |
||
176 | u16 crc_from_hdr = *(u16*)(t.hdr[sec].data+(128U << (FdiTrkHdr->Sec[sec].n & 3))); |
||
177 | printf("phys: c=%-2u, h=%u, s=%u | hdr: c=0x%02X, h=0x%02X, r=0x%02X, n=%02X(%u) | crc1=0x%04X, crc2=0x%04X\n", |
||
178 | c, s, sec, |
||
179 | FdiTrkHdr->Sec[sec].c, FdiTrkHdr->Sec[sec].h, FdiTrkHdr->Sec[sec].r, FdiTrkHdr->Sec[sec].n, (FdiTrkHdr->Sec[sec].n & 3), |
||
180 | crc_calc, crc_from_hdr); |
||
181 | |||
182 | if(crc_calc == crc_from_hdr) |
||
183 | { |
||
184 | TFdiTrkHdr *FdiTrkHdrRW = const_cast<TFdiTrkHdr *>(FdiTrkHdr); |
||
185 | FdiTrkHdrRW->Sec[sec].fl |= (1<<(FdiTrkHdr->Sec[sec].n & 3)); |
||
186 | |||
187 | } |
||
188 | } |
||
189 | #endif |
||
190 | t.hdr[sec].c2 = (FdiTrkHdr->Sec[sec].fl & (1<<(FdiTrkHdr->Sec[sec].n & 3))) ? 0:2; // [vv] |
||
191 | } |
||
192 | /* [vv] |
||
193 | if (t.hdr[sec].l>5) |
||
194 | { |
||
195 | t.hdr[sec].data = 0; |
||
196 | if (!(trk[4] & 0x40)) |
||
197 | res = 0; |
||
198 | } |
||
199 | */ |
||
200 | } // sec |
||
201 | t.s = ns; |
||
202 | t.format(); |
||
203 | |||
204 | if(FdiTrkAddInfo) |
||
205 | { |
||
206 | FdiTrkAddInfo = (const TFdiTrkAddInfo *)(((const u8 *)FdiTrkAddInfo) + sizeof(TFdiTrkAddInfo) + |
||
207 | ((FdiTrkAddInfo->TrkOffset != UINT_MAX) ? FdiTrkHdr->Spt * sizeof(TFdiSecAddInfo) : 0)); |
||
208 | } |
||
209 | |||
210 | FdiTrkHdr = (const TFdiTrkHdr *)(((const u8 *)FdiTrkHdr) + sizeof(TFdiTrkHdr) + FdiTrkHdr->Spt * sizeof(TFdiSecHdr)); |
||
211 | } // s |
||
212 | } |
||
213 | return res; |
||
214 | } |
||
215 | |||
216 | int FDD::write_fdi(FILE *ff) |
||
217 | { |
||
218 | unsigned b, c, s, se, total_s = 0; |
||
219 | unsigned sectors_wp = 0; // Общее число секторов для которых пишутся заголовки с дополнительной информацией |
||
220 | unsigned total_size = 0; // Общий размер данных занимаемый секторами |
||
221 | |||
222 | // Подсчет общего числа секторов на диске |
||
223 | for (c = 0; c < cyls; c++) |
||
224 | { |
||
225 | for (s = 0; s < sides; s++) |
||
226 | { |
||
227 | t.seek(this, c, s, LOAD_SECTORS); |
||
228 | for(se = 0; se < t.s; se++) |
||
229 | { |
||
230 | total_size += (t.hdr[se].data ? t.hdr[se].datlen : 0); |
||
231 | } |
||
232 | for(se = 0; se < t.s; se++) |
||
233 | { |
||
234 | if(t.hdr[se].wp_start) |
||
235 | { |
||
236 | sectors_wp += t.s; |
||
237 | break; |
||
238 | } |
||
239 | } |
||
240 | total_s += t.s; |
||
241 | } |
||
242 | } |
||
243 | |||
244 | unsigned AddLen = sectors_wp ? sizeof(TFdiAddInfo) : 0; |
||
245 | unsigned tlen = strlen(dsc)+1; |
||
246 | unsigned hsize = sizeof(TFdiHdr) + AddLen + cyls * sides * sizeof(TFdiTrkHdr) + total_s * sizeof(TFdiSecHdr); |
||
247 | unsigned AddHdrsSize = cyls * sides * sizeof(TFdiTrkAddInfo) + sectors_wp * sizeof(TFdiSecAddInfo); |
||
248 | |||
249 | // Формирование FDI заголовка |
||
250 | TFdiHdr *FdiHdr = (TFdiHdr *)snbuf; |
||
251 | memcpy(FdiHdr->Sig, "FDI", 3); |
||
252 | FdiHdr->Rw = 0; |
||
253 | FdiHdr->c = cyls; |
||
254 | FdiHdr->h = sides; |
||
255 | FdiHdr->TextOffset = hsize; |
||
256 | FdiHdr->DataOffset = FdiHdr->TextOffset + tlen; |
||
257 | FdiHdr->AddLen = AddLen; |
||
258 | |||
259 | TFdiAddInfo *FdiAddInfo = (TFdiAddInfo *)FdiHdr->AddData; |
||
260 | if(AddLen) |
||
261 | { |
||
262 | FdiAddInfo->Ver = TFdiAddInfo::FDI_2; // FDI ver 2 |
||
263 | FdiAddInfo->AddInfoType = TFdiAddInfo::BAD_BYTES; // Информация о сбойных байтах |
||
264 | FdiAddInfo->TrkAddInfoOffset = FdiHdr->DataOffset + total_size; |
||
265 | FdiAddInfo->DataOffset = FdiAddInfo->TrkAddInfoOffset + AddHdrsSize; |
||
266 | } |
||
267 | |||
268 | // Запись FDI заголовка с дополнительными данными |
||
269 | if(fwrite(FdiHdr, sizeof(TFdiHdr) + AddLen, 1, ff) != 1) |
||
270 | return 0; |
||
271 | |||
272 | unsigned trkoffs = 0; |
||
273 | for (c = 0; c < cyls; c++) |
||
274 | { |
||
275 | for (s = 0; s < sides; s++) |
||
276 | { |
||
277 | t.seek(this, c, s, LOAD_SECTORS); |
||
278 | |||
279 | // Формирование заголовка трэка |
||
280 | TFdiTrkHdr FdiTrkHdr; |
||
281 | FdiTrkHdr.TrkOffset = trkoffs; |
||
282 | FdiTrkHdr.Res1 = 0; |
||
283 | FdiTrkHdr.Spt = t.s; |
||
284 | |||
285 | // Запись заголовка трэка |
||
286 | if(fwrite(&FdiTrkHdr, sizeof(FdiTrkHdr), 1, ff) != 1) |
||
287 | return 0; |
||
288 | |||
289 | unsigned secoffs = 0; |
||
290 | for (se = 0; se < t.s; se++) |
||
291 | { |
||
292 | // Формирование заголовка сектора |
||
293 | TFdiSecHdr FdiSecHdr; |
||
294 | FdiSecHdr.c = t.hdr[se].c; |
||
295 | FdiSecHdr.h = t.hdr[se].s; |
||
296 | FdiSecHdr.r = t.hdr[se].n; |
||
297 | FdiSecHdr.n = t.hdr[se].l; |
||
298 | FdiSecHdr.fl = 0; |
||
299 | |||
300 | if(t.hdr[se].data) |
||
301 | { |
||
302 | if(t.hdr[se].data[-1] == 0xF8) |
||
303 | FdiSecHdr.fl |= TFdiSecHdr::FL_DELETED_DATA; |
||
304 | else |
||
305 | FdiSecHdr.fl |= (t.hdr[se].c2 ? (1<<(t.hdr[se].l & 3)) : 0); // [vv] |
||
306 | } |
||
307 | else |
||
308 | { |
||
309 | FdiSecHdr.fl |= TFdiSecHdr::FL_NO_DATA; |
||
310 | } |
||
311 | |||
312 | FdiSecHdr.DataOffset = secoffs; |
||
313 | |||
314 | |||
315 | // Запись заголовка сектора |
||
316 | if(fwrite(&FdiSecHdr, sizeof(FdiSecHdr), 1, ff) != 1) |
||
317 | return 0; |
||
318 | secoffs += t.hdr[se].datlen; |
||
319 | } |
||
320 | trkoffs += secoffs; |
||
321 | } |
||
322 | } |
||
323 | |||
324 | // Запись комментария |
||
325 | fseek(ff, FdiHdr->TextOffset, SEEK_SET); |
||
326 | if(fwrite(dsc, tlen, 1, ff) != 1) |
||
327 | return 0; |
||
328 | |||
329 | // Запись зон данных трэков |
||
330 | for (c = 0; c < cyls; c++) |
||
331 | { |
||
332 | for (s = 0; s < sides; s++) |
||
333 | { |
||
334 | t.seek(this, c, s, LOAD_SECTORS); |
||
335 | for (unsigned se = 0; se < t.s; se++) |
||
336 | { |
||
337 | if (t.hdr[se].data) |
||
338 | { |
||
339 | if (fwrite(t.hdr[se].data, t.hdr[se].datlen, 1, ff) != 1) |
||
340 | return 0; |
||
341 | } |
||
342 | } |
||
343 | } |
||
344 | } |
||
345 | |||
346 | // Запись дополниетльной информации (информации о сбойных байтах) |
||
347 | if(AddLen) |
||
348 | { |
||
349 | trkoffs = 0; |
||
350 | for (c = 0; c < cyls; c++) |
||
351 | { |
||
352 | for (s = 0; s < sides; s++) |
||
353 | { |
||
354 | t.seek(this, c, s, LOAD_SECTORS); |
||
355 | |||
356 | // Формирование заголовка трэка |
||
357 | TFdiTrkAddInfo FdiTrkAddInfo; |
||
358 | FdiTrkAddInfo.TrkOffset = UINT_MAX; |
||
359 | for(b = 0; b < t.trklen; b++) |
||
360 | { |
||
361 | if(t.test_wp(b)) |
||
362 | { |
||
363 | FdiTrkAddInfo.TrkOffset = trkoffs; |
||
364 | break; |
||
365 | } |
||
366 | } |
||
367 | |||
368 | // Запись заголовка трэка |
||
369 | if(fwrite(&FdiTrkAddInfo, sizeof(FdiTrkAddInfo), 1, ff) != 1) |
||
370 | return 0; |
||
371 | |||
372 | unsigned secoffs = 0; |
||
373 | if(FdiTrkAddInfo.TrkOffset != UINT_MAX) |
||
374 | { |
||
375 | for (se = 0; se < t.s; se++) |
||
376 | { |
||
377 | // Формирование заголовка сектора |
||
378 | TFdiSecAddInfo FdiSecAddInfo; |
||
379 | FdiSecAddInfo.Flags = 0; |
||
380 | FdiSecAddInfo.DataOffset = 0; |
||
381 | |||
382 | if(t.hdr[se].wp_start) |
||
383 | { |
||
384 | FdiSecAddInfo.Flags |= 1; |
||
385 | FdiSecAddInfo.DataOffset = secoffs; |
||
386 | } |
||
387 | |||
388 | // Запись заголовка сектора |
||
389 | if(fwrite(&FdiSecAddInfo, sizeof(FdiSecAddInfo), 1, ff) != 1) |
||
390 | return 0; |
||
391 | secoffs += (t.hdr[se].wp_start ? ((t.hdr[se].datlen + 7) >> 3) : 0); |
||
392 | } |
||
393 | } |
||
394 | trkoffs += secoffs; |
||
395 | } |
||
396 | } |
||
397 | |||
398 | // Запись зон сбойных байтов |
||
399 | for (c = 0; c < cyls; c++) |
||
400 | { |
||
401 | for (s = 0; s < sides; s++) |
||
402 | { |
||
403 | t.seek(this, c, s, LOAD_SECTORS); |
||
404 | for (unsigned se = 0; se < t.s; se++) |
||
405 | { |
||
406 | if (t.hdr[se].wp_start) |
||
407 | { |
||
408 | unsigned nbits = t.hdr[se].datlen; |
||
409 | |||
410 | u8 wp_bits[1024U >> 3U] = { 0 }; |
||
411 | for(b = 0; b < nbits; b++) |
||
412 | { |
||
413 | if(t.test_wp(t.hdr[se].wp_start + b)) |
||
414 | { |
||
415 | set_bit(wp_bits, b); |
||
416 | } |
||
417 | } |
||
418 | if (fwrite(wp_bits, (nbits + 7) >> 3, 1, ff) != 1) |
||
419 | return 0; |
||
420 | } |
||
421 | } |
||
422 | } |
||
423 | } |
||
424 | } |
||
425 | |||
426 | return 1; |
||
427 | } |