Rev 885 | Details | Compare with Previous | 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" |
||
885 | lvd | 7 | #include "wd93crc.h" |
716 | lvd | 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 | |||
784 | DimkaM | 106 | const TFdiAddInfo *FdiAddInfo = nullptr; |
107 | const TFdiTrkAddInfo *FdiTrkAddInfo = nullptr; |
||
716 | lvd | 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; |
||
784 | DimkaM | 133 | u8 *wp0 = nullptr; |
716 | lvd | 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; |
||
784 | DimkaM | 151 | t.hdr[sec].wp = nullptr; |
800 | DimkaM | 152 | t.hdr[sec].datlen = 0; |
716 | lvd | 153 | |
154 | if (FdiTrkHdr->Sec[sec].fl & TFdiSecHdr::FL_NO_DATA) |
||
800 | DimkaM | 155 | { |
784 | DimkaM | 156 | t.hdr[sec].data = nullptr; |
800 | DimkaM | 157 | } |
716 | lvd | 158 | else |
159 | { |
||
160 | if (t0 + FdiTrkHdr->Sec[sec].DataOffset > snbuf + snapsize) |
||
161 | { |
||
162 | err_printf("sector data is beyond disk image end"); |
||
163 | return 0; |
||
164 | } |
||
165 | t.hdr[sec].data = t0 + FdiTrkHdr->Sec[sec].DataOffset; |
||
166 | |||
167 | if(FdiTrkAddInfo && FdiTrkAddInfo->TrkOffset != UINT_MAX) |
||
168 | { |
||
784 | DimkaM | 169 | t.hdr[sec].wp = ((FdiTrkAddInfo->Sec[sec].Flags & 1) ? (wp0 + FdiTrkAddInfo->Sec[sec].DataOffset) : nullptr); |
716 | lvd | 170 | } |
171 | #if 0 |
||
172 | if(FdiTrkHdr->Sec[sec].n > 3) |
||
173 | { |
||
174 | u8 buf[1+1024]; |
||
175 | buf[0] = (FdiTrkHdr->Sec[sec].fl & TFdiSecHdr::FL_DELETED_DATA) ? 0xF8 : 0xFB; |
||
176 | memcpy(buf+1, t.hdr[sec].data, 128U << (FdiTrkHdr->Sec[sec].n & 3)); |
||
177 | |||
178 | u16 crc_calc = wd93_crc(buf, (128U << (FdiTrkHdr->Sec[sec].n & 3)) + 1); |
||
179 | u16 crc_from_hdr = *(u16*)(t.hdr[sec].data+(128U << (FdiTrkHdr->Sec[sec].n & 3))); |
||
180 | 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", |
||
181 | c, s, sec, |
||
182 | FdiTrkHdr->Sec[sec].c, FdiTrkHdr->Sec[sec].h, FdiTrkHdr->Sec[sec].r, FdiTrkHdr->Sec[sec].n, (FdiTrkHdr->Sec[sec].n & 3), |
||
183 | crc_calc, crc_from_hdr); |
||
184 | |||
185 | if(crc_calc == crc_from_hdr) |
||
186 | { |
||
187 | TFdiTrkHdr *FdiTrkHdrRW = const_cast<TFdiTrkHdr *>(FdiTrkHdr); |
||
188 | FdiTrkHdrRW->Sec[sec].fl |= (1<<(FdiTrkHdr->Sec[sec].n & 3)); |
||
189 | |||
190 | } |
||
191 | } |
||
192 | #endif |
||
193 | t.hdr[sec].c2 = (FdiTrkHdr->Sec[sec].fl & (1<<(FdiTrkHdr->Sec[sec].n & 3))) ? 0:2; // [vv] |
||
194 | } |
||
195 | /* [vv] |
||
196 | if (t.hdr[sec].l>5) |
||
197 | { |
||
198 | t.hdr[sec].data = 0; |
||
199 | if (!(trk[4] & 0x40)) |
||
200 | res = 0; |
||
201 | } |
||
202 | */ |
||
203 | } // sec |
||
204 | t.s = ns; |
||
205 | t.format(); |
||
206 | |||
207 | if(FdiTrkAddInfo) |
||
208 | { |
||
209 | FdiTrkAddInfo = (const TFdiTrkAddInfo *)(((const u8 *)FdiTrkAddInfo) + sizeof(TFdiTrkAddInfo) + |
||
210 | ((FdiTrkAddInfo->TrkOffset != UINT_MAX) ? FdiTrkHdr->Spt * sizeof(TFdiSecAddInfo) : 0)); |
||
211 | } |
||
212 | |||
213 | FdiTrkHdr = (const TFdiTrkHdr *)(((const u8 *)FdiTrkHdr) + sizeof(TFdiTrkHdr) + FdiTrkHdr->Spt * sizeof(TFdiSecHdr)); |
||
214 | } // s |
||
215 | } |
||
216 | return res; |
||
217 | } |
||
218 | |||
219 | int FDD::write_fdi(FILE *ff) |
||
220 | { |
||
221 | unsigned b, c, s, se, total_s = 0; |
||
222 | unsigned sectors_wp = 0; // Общее число секторов для которых пишутся заголовки с дополнительной информацией |
||
223 | unsigned total_size = 0; // Общий размер данных занимаемый секторами |
||
224 | |||
225 | // Подсчет общего числа секторов на диске |
||
226 | for (c = 0; c < cyls; c++) |
||
227 | { |
||
228 | for (s = 0; s < sides; s++) |
||
229 | { |
||
230 | t.seek(this, c, s, LOAD_SECTORS); |
||
231 | for(se = 0; se < t.s; se++) |
||
232 | { |
||
233 | total_size += (t.hdr[se].data ? t.hdr[se].datlen : 0); |
||
234 | } |
||
235 | for(se = 0; se < t.s; se++) |
||
236 | { |
||
237 | if(t.hdr[se].wp_start) |
||
238 | { |
||
239 | sectors_wp += t.s; |
||
240 | break; |
||
241 | } |
||
242 | } |
||
243 | total_s += t.s; |
||
244 | } |
||
245 | } |
||
246 | |||
247 | unsigned AddLen = sectors_wp ? sizeof(TFdiAddInfo) : 0; |
||
784 | DimkaM | 248 | unsigned tlen = unsigned(strlen(dsc)+1); |
716 | lvd | 249 | unsigned hsize = sizeof(TFdiHdr) + AddLen + cyls * sides * sizeof(TFdiTrkHdr) + total_s * sizeof(TFdiSecHdr); |
250 | unsigned AddHdrsSize = cyls * sides * sizeof(TFdiTrkAddInfo) + sectors_wp * sizeof(TFdiSecAddInfo); |
||
251 | |||
252 | // Формирование FDI заголовка |
||
253 | TFdiHdr *FdiHdr = (TFdiHdr *)snbuf; |
||
254 | memcpy(FdiHdr->Sig, "FDI", 3); |
||
255 | FdiHdr->Rw = 0; |
||
784 | DimkaM | 256 | FdiHdr->c = u16(cyls); |
257 | FdiHdr->h = u16(sides); |
||
258 | FdiHdr->TextOffset = u16(hsize); |
||
259 | FdiHdr->DataOffset = u16(FdiHdr->TextOffset + tlen); |
||
260 | FdiHdr->AddLen = u16(AddLen); |
||
716 | lvd | 261 | |
262 | TFdiAddInfo *FdiAddInfo = (TFdiAddInfo *)FdiHdr->AddData; |
||
263 | if(AddLen) |
||
264 | { |
||
265 | FdiAddInfo->Ver = TFdiAddInfo::FDI_2; // FDI ver 2 |
||
266 | FdiAddInfo->AddInfoType = TFdiAddInfo::BAD_BYTES; // Информация о сбойных байтах |
||
267 | FdiAddInfo->TrkAddInfoOffset = FdiHdr->DataOffset + total_size; |
||
268 | FdiAddInfo->DataOffset = FdiAddInfo->TrkAddInfoOffset + AddHdrsSize; |
||
269 | } |
||
270 | |||
271 | // Запись FDI заголовка с дополнительными данными |
||
272 | if(fwrite(FdiHdr, sizeof(TFdiHdr) + AddLen, 1, ff) != 1) |
||
273 | return 0; |
||
274 | |||
275 | unsigned trkoffs = 0; |
||
276 | for (c = 0; c < cyls; c++) |
||
277 | { |
||
278 | for (s = 0; s < sides; s++) |
||
279 | { |
||
280 | t.seek(this, c, s, LOAD_SECTORS); |
||
281 | |||
282 | // Формирование заголовка трэка |
||
283 | TFdiTrkHdr FdiTrkHdr; |
||
284 | FdiTrkHdr.TrkOffset = trkoffs; |
||
285 | FdiTrkHdr.Res1 = 0; |
||
784 | DimkaM | 286 | FdiTrkHdr.Spt = u8(t.s); |
716 | lvd | 287 | |
288 | // Запись заголовка трэка |
||
289 | if(fwrite(&FdiTrkHdr, sizeof(FdiTrkHdr), 1, ff) != 1) |
||
290 | return 0; |
||
291 | |||
292 | unsigned secoffs = 0; |
||
293 | for (se = 0; se < t.s; se++) |
||
294 | { |
||
295 | // Формирование заголовка сектора |
||
296 | TFdiSecHdr FdiSecHdr; |
||
297 | FdiSecHdr.c = t.hdr[se].c; |
||
298 | FdiSecHdr.h = t.hdr[se].s; |
||
299 | FdiSecHdr.r = t.hdr[se].n; |
||
300 | FdiSecHdr.n = t.hdr[se].l; |
||
301 | FdiSecHdr.fl = 0; |
||
302 | |||
303 | if(t.hdr[se].data) |
||
304 | { |
||
305 | if(t.hdr[se].data[-1] == 0xF8) |
||
306 | FdiSecHdr.fl |= TFdiSecHdr::FL_DELETED_DATA; |
||
307 | else |
||
308 | FdiSecHdr.fl |= (t.hdr[se].c2 ? (1<<(t.hdr[se].l & 3)) : 0); // [vv] |
||
309 | } |
||
310 | else |
||
311 | { |
||
312 | FdiSecHdr.fl |= TFdiSecHdr::FL_NO_DATA; |
||
313 | } |
||
314 | |||
784 | DimkaM | 315 | FdiSecHdr.DataOffset = u16(secoffs); |
716 | lvd | 316 | |
317 | |||
318 | // Запись заголовка сектора |
||
319 | if(fwrite(&FdiSecHdr, sizeof(FdiSecHdr), 1, ff) != 1) |
||
320 | return 0; |
||
321 | secoffs += t.hdr[se].datlen; |
||
322 | } |
||
323 | trkoffs += secoffs; |
||
324 | } |
||
325 | } |
||
326 | |||
327 | // Запись комментария |
||
328 | fseek(ff, FdiHdr->TextOffset, SEEK_SET); |
||
329 | if(fwrite(dsc, tlen, 1, ff) != 1) |
||
330 | return 0; |
||
331 | |||
332 | // Запись зон данных трэков |
||
333 | for (c = 0; c < cyls; c++) |
||
334 | { |
||
335 | for (s = 0; s < sides; s++) |
||
336 | { |
||
337 | t.seek(this, c, s, LOAD_SECTORS); |
||
338 | for (unsigned se = 0; se < t.s; se++) |
||
339 | { |
||
340 | if (t.hdr[se].data) |
||
341 | { |
||
342 | if (fwrite(t.hdr[se].data, t.hdr[se].datlen, 1, ff) != 1) |
||
343 | return 0; |
||
344 | } |
||
345 | } |
||
346 | } |
||
347 | } |
||
348 | |||
349 | // Запись дополниетльной информации (информации о сбойных байтах) |
||
350 | if(AddLen) |
||
351 | { |
||
352 | trkoffs = 0; |
||
353 | for (c = 0; c < cyls; c++) |
||
354 | { |
||
355 | for (s = 0; s < sides; s++) |
||
356 | { |
||
357 | t.seek(this, c, s, LOAD_SECTORS); |
||
358 | |||
359 | // Формирование заголовка трэка |
||
360 | TFdiTrkAddInfo FdiTrkAddInfo; |
||
361 | FdiTrkAddInfo.TrkOffset = UINT_MAX; |
||
362 | for(b = 0; b < t.trklen; b++) |
||
363 | { |
||
364 | if(t.test_wp(b)) |
||
365 | { |
||
366 | FdiTrkAddInfo.TrkOffset = trkoffs; |
||
367 | break; |
||
368 | } |
||
369 | } |
||
370 | |||
371 | // Запись заголовка трэка |
||
372 | if(fwrite(&FdiTrkAddInfo, sizeof(FdiTrkAddInfo), 1, ff) != 1) |
||
373 | return 0; |
||
374 | |||
375 | unsigned secoffs = 0; |
||
376 | if(FdiTrkAddInfo.TrkOffset != UINT_MAX) |
||
377 | { |
||
378 | for (se = 0; se < t.s; se++) |
||
379 | { |
||
380 | // Формирование заголовка сектора |
||
381 | TFdiSecAddInfo FdiSecAddInfo; |
||
382 | FdiSecAddInfo.Flags = 0; |
||
383 | FdiSecAddInfo.DataOffset = 0; |
||
384 | |||
385 | if(t.hdr[se].wp_start) |
||
386 | { |
||
387 | FdiSecAddInfo.Flags |= 1; |
||
784 | DimkaM | 388 | FdiSecAddInfo.DataOffset = u16(secoffs); |
716 | lvd | 389 | } |
390 | |||
391 | // Запись заголовка сектора |
||
392 | if(fwrite(&FdiSecAddInfo, sizeof(FdiSecAddInfo), 1, ff) != 1) |
||
393 | return 0; |
||
394 | secoffs += (t.hdr[se].wp_start ? ((t.hdr[se].datlen + 7) >> 3) : 0); |
||
395 | } |
||
396 | } |
||
397 | trkoffs += secoffs; |
||
398 | } |
||
399 | } |
||
400 | |||
401 | // Запись зон сбойных байтов |
||
402 | for (c = 0; c < cyls; c++) |
||
403 | { |
||
404 | for (s = 0; s < sides; s++) |
||
405 | { |
||
406 | t.seek(this, c, s, LOAD_SECTORS); |
||
407 | for (unsigned se = 0; se < t.s; se++) |
||
408 | { |
||
409 | if (t.hdr[se].wp_start) |
||
410 | { |
||
411 | unsigned nbits = t.hdr[se].datlen; |
||
412 | |||
413 | u8 wp_bits[1024U >> 3U] = { 0 }; |
||
414 | for(b = 0; b < nbits; b++) |
||
415 | { |
||
416 | if(t.test_wp(t.hdr[se].wp_start + b)) |
||
417 | { |
||
418 | set_bit(wp_bits, b); |
||
419 | } |
||
420 | } |
||
421 | if (fwrite(wp_bits, (nbits + 7) >> 3, 1, ff) != 1) |
||
422 | return 0; |
||
423 | } |
||
424 | } |
||
425 | } |
||
426 | } |
||
427 | } |
||
428 | |||
429 | return 1; |
||
430 | } |