1 /*
2 * NIBTOOL write routines
3 * Copyright 2005-2011 C64 Preservation Project
4 * based on MNIB by Markus Brenner <markus(at)brenner(dot)de>
5 */
6
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <time.h>
11
12 #include "mnibarch.h"
13 #include "gcr.h"
14 #include "nibtools.h"
15
16 void
master_track(CBM_FILE fd,BYTE * track_buffer,BYTE * track_density,int track,size_t tracklen)17 master_track(CBM_FILE fd, BYTE *track_buffer, BYTE *track_density, int track, size_t tracklen)
18 {
19 int i, leader = 0x20;
20 static size_t skewbytes = 0;
21 static BYTE last_density = -1;
22 BYTE rawtrack[NIB_TRACK_LENGTH * 2];
23 BYTE tempfillbyte;
24
25 /* loop last byte of track data for filler */
26 if(fillbyte == 0xfe) /* $fe is special case for loop */
27 tempfillbyte = track_buffer[(track * NIB_TRACK_LENGTH) + tracklen - 1];
28 else
29 tempfillbyte = fillbyte;
30
31 if(verbose>2) printf("(fill:$%.2x)",tempfillbyte);
32
33 if(track_density[track] & BM_NO_SYNC)
34 memset(rawtrack, 0x55, sizeof(rawtrack));
35 else
36 memset(rawtrack, tempfillbyte, sizeof(rawtrack));
37
38 /* apply skew, if specified */
39 if(skew)
40 {
41 skewbytes += skew * (capacity[track_density[track]&3] / 200);
42
43 if(skewbytes > NIB_TRACK_LENGTH)
44 skewbytes = skewbytes - NIB_TRACK_LENGTH;
45
46 if(verbose>1) printf("{skew=%d}", skewbytes);
47 }
48
49 /* check for and correct initial too short sync mark */
50 //if( ((!(track_density[track] & BM_NO_SYNC)) &&
51 // (track_buffer[track * NIB_TRACK_LENGTH] == 0xff) &&
52 // (track_buffer[(track * NIB_TRACK_LENGTH) + 1] != 0xff)) || (presync) )
53 if(presync)
54 {
55 if(verbose>1) printf("{presync}");
56 memset(rawtrack + leader + skewbytes - 2, 0xff, 2);
57 }
58
59 /* merge track data */
60 memcpy(rawtrack + leader + skewbytes, track_buffer + (track * NIB_TRACK_LENGTH), tracklen);
61
62 //printf("[%.2x%.2x%.2x%.2x%.2x] ",
63 // rawtrack[0], rawtrack[1], rawtrack[2], rawtrack[3], rawtrack[4]);
64
65 /* handle short tracks */
66 if(tracklen < capacity[track_density[track]&3])
67 {
68 if(verbose>1) printf("[pad:%d]", capacity[track_density[track]&3] - tracklen);
69 tracklen = capacity[track_density[track]&3];
70 }
71
72 /* "fix" for track 18 mastering */
73 if(track==18*2)
74 memcpy(rawtrack + tracklen - 5, "UJMSU", 5);
75
76 /* replace 0x00 bytes by 0x01, as 0x00 indicates end of track */
77 if(!use_floppycode_srq) // not in srq code
78 replace_bytes(rawtrack, sizeof(rawtrack), 0x00, 0x01);
79
80 /* step to destination track and set density */
81 step_to_halftrack(fd, track);
82 if((track_density[track]&3) != last_density)
83 {
84 set_density(fd, track_density[track]&3);
85 if(verbose>2) printf("[D]");
86 last_density = track_density[track]&3;
87 }
88
89 /* this doesn't work over USB since we aren't in control of timing, I don't think */
90 // try to do track alignment through simple timers
91 if((align_disk) && (auto_capacity_adjust))
92 {
93 /* subtract overhead from one revolution;
94 adjust for motor speed and density; */
95 align_delay = (int) ((175500) + ((300 - motor_speed) * 600));
96 msleep(align_delay);
97 }
98
99 /* burst send track */
100 for (i = 0; i < 3; i ++)
101 {
102 send_mnib_cmd(fd, FL_WRITE, NULL, 0);
103
104 /* IHS will lock forever if IHS is set and it sees no index hole, i.e. side 2 of flippy disk or there is no compatible IHS */
105 /* Arnd has some code to test for it, not implemented yet */
106 burst_write(fd, (unsigned char)((ihs) ? 0x00 : 0x03));
107
108 /* align disk waits until end of sync before writing */
109 burst_write(fd, (unsigned char)((align_disk) ? 0xfb : 0x00));
110
111 if (burst_write_track(fd, rawtrack, (int)(tracklen + leader + skewbytes + 1)))
112 break;
113 else
114 {
115 //putchar('?');
116 printf("(timeout) ");
117 fflush(stdin);
118 burst_read(fd);
119 //msleep(500);
120 //printf("%c ", test_par_port(fd)? '+' : '-');
121 test_par_port(fd);
122 }
123 }
124
125 if(i == 3)
126 {
127 printf("\n\nNo good write of track due to timeouts. Aborting!\n");
128 exit(1);
129 }
130 }
131
132 void
master_disk(CBM_FILE fd,BYTE * track_buffer,BYTE * track_density,size_t * track_length)133 master_disk(CBM_FILE fd, BYTE *track_buffer, BYTE *track_density, size_t *track_length)
134 {
135 int track, verified, retries, added_sync = 0;
136 size_t badgcr, length, verlen, verlen2;
137 BYTE verbuf1[NIB_TRACK_LENGTH], verbuf2[NIB_TRACK_LENGTH], verbuf3[NIB_TRACK_LENGTH], align;
138 size_t gcr_diff;
139 char errorstring[0x1000];
140
141 for (track = start_track; track <= end_track; track += track_inc)
142 {
143 /* double-check our sync-flag assumptions and process track for remaster */
144 track_density[track] =
145 check_sync_flags(track_buffer + (track * NIB_TRACK_LENGTH), track_density[track], track_length[track]);
146
147 /* engineer killer track */
148 if(track_density[track] & BM_FF_TRACK)
149 {
150 kill_track(fd, track);
151 if(verbose) printf("\n%4.1f: KILLED!", (float) track / 2);
152 continue;
153 }
154
155 /* zero out empty tracks entirely */
156 if(!check_formatted(track_buffer + (track * NIB_TRACK_LENGTH), track_length[track]))
157 {
158 zero_track(fd, track);
159 if(verbose) printf("\n%4.1f: UNFORMATTED!", (float) track / 2);
160 continue;
161 }
162
163 /* user display */
164 if(verbose)
165 {
166 printf("\n%4.1f: (", (float)track/2);
167 printf("%d", track_density[track]&3);
168 if ( (track_density[track]&3) != speed_map[track/2]) printf("!");
169 printf(":%d) ", track_length[track]);
170 if (track_density[track] & BM_NO_SYNC) printf("NOSYNC ");
171 if (track_density[track] & BM_FF_TRACK) printf("KILLER ");
172 printf("WRITE ");
173 }
174
175 badgcr = check_bad_gcr(track_buffer + (track * NIB_TRACK_LENGTH), track_length[track]);
176
177 if(increase_sync)
178 {
179 added_sync = lengthen_sync(track_buffer + (track * NIB_TRACK_LENGTH),
180 track_length[track], NIB_TRACK_LENGTH);
181
182 track_length[track] += added_sync;
183 }
184
185 if(increase_sync) { if(verbose) printf("[+sync:%d]", added_sync); }
186 if(badgcr) { if(verbose) printf("[weak:%d]", badgcr); }
187
188 length = compress_halftrack(track, track_buffer + (track * NIB_TRACK_LENGTH),
189 track_density[track], track_length[track]);
190
191 master_track(fd, track_buffer, track_density, track, length);
192
193 if(track_match) // Try to verify our write
194 {
195 verified=retries=0;
196 while(!verified)
197 {
198 // Don't bother to compare unformatted or bad data
199 if (track_length[track] == NIB_TRACK_LENGTH) break;
200
201 memset(verbuf1, 0, NIB_TRACK_LENGTH);
202 if((ihs) && (!(track_density[track] & BM_NO_SYNC)))
203 send_mnib_cmd(fd, FL_READIHS, NULL, 0);
204 else if (Use_SCPlus_IHS) // "-j"
205 send_mnib_cmd(fd, FL_IHS_READ_SCP, NULL, 0);
206 else
207 {
208 if ((track_density[track] & BM_NO_SYNC) || (track_density[track] & BM_FF_TRACK))
209 send_mnib_cmd(fd, FL_READWOSYNC, NULL, 0);
210 else
211 send_mnib_cmd(fd, FL_READNORMAL, NULL, 0);
212 }
213 burst_read(fd);
214 burst_read_track(fd, verbuf1, NIB_TRACK_LENGTH);
215
216 memset(verbuf2, 0, NIB_TRACK_LENGTH);
217 memset(verbuf3, 0, NIB_TRACK_LENGTH);
218 verlen = extract_GCR_track(verbuf2, verbuf1, &align, track/2, track_length[track], track_length[track]);
219 verlen2 = extract_GCR_track(verbuf3, track_buffer+(track * NIB_TRACK_LENGTH), &align, track/2, track_length[track], track_length[track]);
220
221 if(verbose) printf("\n (%d:%d) VERIF", track_density[track]&3, verlen);
222 fprintf(fplog, "\n (%d:%d) VERIF", track_density[track]&3, verlen);
223
224 // Fix bad GCR in tracks for compare
225 badgcr = check_bad_gcr(verbuf2, track_length[track]);
226 if(verbose>1) printf("(badgcr=%.4d:", badgcr);
227 badgcr = check_bad_gcr(verbuf3, track_length[track]);
228 if(verbose>1) printf("%.4d)", badgcr);
229
230 // compare raw gcr data
231 gcr_diff = compare_tracks(verbuf3, verbuf2, verlen, verlen, 1, errorstring);
232 if(verbose) printf(" (diff:%.4d) ", (int)gcr_diff);
233 fprintf(fplog, " (diff:%.4d) ", (int)gcr_diff);
234
235 if(gcr_diff <= (size_t)sector_map[track/2]+10)
236 {
237 printf("OK ");
238 verified=1;
239 }
240 else
241 {
242 retries++;
243 printf("Retry %d ", retries);
244 zero_track(fd, track);
245 master_track(fd, track_buffer, track_density, track, length);
246 }
247 if(((track>70)&&(retries>=3))||(retries>=10))
248 {
249 printf("\n Write verify FAILED - Odd data or bad media! ");
250 verified=1;
251 }
252 }
253 }
254 }
255 }
256
257 void
master_disk_raw(CBM_FILE fd,BYTE * track_buffer,BYTE * track_density,size_t * track_length)258 master_disk_raw(CBM_FILE fd, BYTE *track_buffer, BYTE *track_density, size_t *track_length)
259 {
260 int track, density;
261 BYTE trackbuf[NIB_TRACK_LENGTH];
262 char testfilename[16];
263 FILE *trkin = '\0';
264 size_t length;
265
266 for (track = start_track; track <= end_track; track += track_inc)
267 {
268 printf("\n%4.1f:", (float) track / 2);
269
270 // read in raw track at density (in filename)
271 for (density = 3; density >= 0; density--)
272 {
273 sprintf(testfilename, "raw/tr%.1fd%d", (float) track/2, density);
274
275 if( (trkin = fopen(testfilename, "rb")) )
276 {
277 if(verbose) printf(" [%s] ", testfilename);
278 break;
279 }
280 }
281
282 if (trkin)
283 {
284 /* erase mem and grab data from file */
285 memset(trackbuf, 0x00, sizeof(trackbuf));
286 fseek(trkin, 0, SEEK_END);
287 length = ftell(trkin);
288 rewind(trkin);
289 fread(trackbuf, length, 1, trkin); // @@@SRT: check success
290 fclose(trkin);
291
292 if(length == 0)
293 length = NIB_TRACK_LENGTH;
294
295 /* process track */
296 memcpy(track_buffer + (track * NIB_TRACK_LENGTH), trackbuf, NIB_TRACK_LENGTH);
297 track_density[track] = check_sync_flags(track_buffer + (track * NIB_TRACK_LENGTH), density, length);
298 //length = compress_halftrack(track, track_buffer + (track * NIB_TRACK_LENGTH), track_density[track], length);
299
300 printf(" (%d", track_density[track] & 3);
301 if ( (track_density[track]&3) != speed_map[track/2])
302 printf("!=%d", speed_map[track/2]);
303 if (track_density[track] & BM_NO_SYNC)
304 printf(":NOSYNC");
305 else if (track_density[track] & BM_FF_TRACK)
306 printf(":KILLER");
307 printf(") (%d) ", length);
308
309 /* truncate the end if needed (reduce tail) */
310 if (length > capacity[density & 3])
311 {
312 printf(" (trunc:%d) ", length - capacity[density & 3]);
313 length = capacity[density & 3];
314 }
315 master_track(fd, track_buffer, track_density, track, length);
316 }
317 else
318 printf(" [missing track file - skipped]");
319 }
320 }
321
322 void
unformat_disk(CBM_FILE fd)323 unformat_disk(CBM_FILE fd)
324 {
325 /* this routine writes all 1's and all 0's alternatively to try to both
326 fix old media into working again, and wiping all data
327 */
328 int track, i;
329
330 motor_on(fd);
331 set_density(fd, 2);
332
333 printf("\nUnformatting...\n\n");
334
335 for (track = start_track; track <= end_track; track ++)
336 {
337 for(i=0;i<unformat_passes; i++)
338 {
339 kill_track(fd,track);
340 zero_track(fd, track);
341 }
342 if(verbose) printf("\n%4.1f: UNFORMATTED!", (float) track/2);
343 }
344 }
345
kill_track(CBM_FILE fd,int track)346 void kill_track(CBM_FILE fd, int track)
347 {
348 // step head
349 step_to_halftrack(fd, track);
350
351 // write all $ff bytes
352 send_mnib_cmd(fd, FL_FILLTRACK, NULL, 0);
353 burst_write(fd, 0xff); // 0xff byte is all sync "killer" track
354 burst_read(fd);
355 }
356
357 void
zero_track(CBM_FILE fd,int track)358 zero_track(CBM_FILE fd, int track)
359 {
360 // step head
361 step_to_halftrack(fd, track);
362
363 // write all $0 bytes
364 send_mnib_cmd(fd, FL_FILLTRACK, NULL, 0);
365 burst_write(fd, 0x0); // 0x00 byte is "unformatted"
366 burst_read(fd);
367 }
368
speed_adjust(CBM_FILE fd)369 void speed_adjust(CBM_FILE fd)
370 {
371 int i, cap;
372
373 printf("\nTesting drive motor speed for 100 loops.\n");
374 printf("--------------------------------------------------\n");
375
376 motor_on(fd);
377 step_to_halftrack(fd, start_track);
378 set_bitrate(fd, 2);
379
380 for (i=0; i<100; i++)
381 {
382 cap = track_capacity(fd);
383 printf("Speed = %.2frpm\n", DENSITY2 / cap);
384 }
385
386 }
387
388 /* This routine measures track capacity at all densities */
adjust_target(CBM_FILE fd)389 void adjust_target(CBM_FILE fd)
390 {
391 int i, j;
392 int cap[DENSITY_SAMPLES];
393 int cap_high[4], cap_low[4], cap_margin[4];
394 int run_total;
395 int capacity_margin = 0;
396 BYTE track_dens[4] = { 35*2, 30*2, 24*2, 17*2 };
397
398 printf("\nTesting track capacity at each density\n");
399 printf("--------------------------------------------------\n");
400
401 for (i = 0; i <= 3; i++)
402 {
403 cap_high[i] = 0;
404 cap_low[i] = 0xffff;
405
406 if( (start_track < track_dens[i]) && (end_track > track_dens[i]))
407 step_to_halftrack(fd, track_dens[i]);
408 else
409 step_to_halftrack(fd, start_track);
410
411 set_bitrate(fd, (BYTE)i);
412
413 printf("Density %d: ", i);
414
415 for(j = 0, run_total = 0; j < DENSITY_SAMPLES; j++)
416 {
417 cap[j] = track_capacity(fd);
418 printf("%d ", cap[j]);
419 run_total += cap[j];
420 if(cap[j] > cap_high[i]) cap_high[i] = cap[j];
421 if(cap[j] < cap_low[i]) cap_low[i] = cap[j];
422 }
423 capacity[i] = run_total / DENSITY_SAMPLES ;
424 cap_margin[i] = cap_high[i] - cap_low[i];
425
426 if(cap_margin[i] > capacity_margin)
427 capacity_margin = cap_margin[i];
428
429 switch(i)
430 {
431 case 0:
432 printf("(%.2frpm) margin:%d\n", DENSITY0 / capacity[0], cap_margin[i]);
433 break;
434
435 case 1:
436 printf("(%.2frpm) margin:%d\n", DENSITY1 / capacity[1], cap_margin[i]);
437 break;
438
439 case 2:
440 printf("(%.2frpm) margin:%d\n", DENSITY2 / capacity[2], cap_margin[i]);
441 break;
442
443 case 3:
444 printf("(%.2frpm) margin:%d\n", DENSITY3 / capacity[3], cap_margin[i]);
445 break;
446 }
447
448 capacity[i] -= capacity_margin + extra_capacity_margin;
449 }
450
451 motor_speed = (float)( (DENSITY3 / (capacity[3] + capacity_margin + extra_capacity_margin)) +
452 (DENSITY2 / (capacity[2] + capacity_margin + extra_capacity_margin)) +
453 (DENSITY1 / (capacity[1] + capacity_margin + extra_capacity_margin)) +
454 (DENSITY0 / (capacity[0] + capacity_margin + extra_capacity_margin)) ) / 4;
455
456 printf("--------------------------------------------------\n");
457 printf("Drive motor speed average: %.2f RPM.\n", motor_speed);
458 printf("Track capacity margin: %d\n", capacity_margin + extra_capacity_margin);
459
460 if( (motor_speed > 320) || (motor_speed < 280))
461 {
462 printf("\n\nERROR!\nDrive speed out of range.\nCheck motor, write-protect, or bad media.\n");
463 exit(0);
464 }
465 }
466
467 void
init_aligned_disk(CBM_FILE fd)468 init_aligned_disk(CBM_FILE fd)
469 {
470 int track;
471
472 /* write all 0x55 */
473 printf("\nErasing tracks...\n");
474 for (track = start_track; track <= end_track; track += track_inc)
475 {
476 // step head
477 step_to_halftrack(fd, track);
478
479 // write all $55 bytes
480 send_mnib_cmd(fd, FL_FILLTRACK, NULL, 0);
481 burst_write(fd, 0x55);
482 burst_read(fd);
483 }
484
485 /* drive code version, timers can hang w/o interrupts too long */
486 printf("Sync sweep...\n");
487 send_mnib_cmd(fd, FL_ALIGNDISK, NULL, 0);
488 burst_write(fd, 0);
489 burst_read(fd);
490 printf("Attempted sweep-aligned tracks\n");
491 }
492