ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/readcbm.c
Revision: 1.2
Committed: 2004-01-07T16:53:58Z (20 years, 2 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +13 -42 lines
Log Message:
- better argument parsing
- drive type (40/80 tracks) selectable with command line option
- works with Catweasel PCI MK3

File Contents

# User Rev Content
1 cebix 1.1 /*
2     * readcbm.c - Read CBM disk to image file with the Catweasel controller
3     *
4 cebix 1.2 * Written in 2003-2004 by Christian Bauer <Christian.Bauer@uni-mainz.de>
5 cebix 1.1 */
6    
7     #include "catweasel.h"
8     #include "common.h"
9    
10    
11     /* Raw track buffer and buffer pointer */
12     #define RAW_SIZE (128*1024)
13     static unsigned char raw_buf[RAW_SIZE];
14     static int buf_ptr = 0;
15    
16    
17     /* Search for next header sync, returns 0 if not found */
18     static int search_header_sync(void)
19     {
20     while (1) {
21    
22     // End of buffer reached? Then bail out
23     if (raw_buf[buf_ptr] & 0x80)
24     return 0;
25     if (buf_ptr > RAW_SIZE - 13)
26     return 0;
27    
28     // Header sync: 10 "1"-bits followed by GCR-encoded 0x08 (= 1111111112233)
29     if (raw_buf[buf_ptr + 0] == 1 && raw_buf[buf_ptr + 1] == 1
30     && raw_buf[buf_ptr + 2] == 1 && raw_buf[buf_ptr + 3] == 1
31     && raw_buf[buf_ptr + 4] == 1 && raw_buf[buf_ptr + 5] == 1
32     && raw_buf[buf_ptr + 6] == 1 && raw_buf[buf_ptr + 7] == 1
33     && raw_buf[buf_ptr + 8] == 1 && raw_buf[buf_ptr + 9] == 2
34     && raw_buf[buf_ptr + 10] == 2 && raw_buf[buf_ptr + 11] == 3
35     && raw_buf[buf_ptr + 12] == 3) {
36    
37     // Found, advance buffer pointer to header mark
38     buf_ptr += 9;
39     // fprintf(stderr, "Header found at %d\n", buf_ptr);
40     return 1;
41     }
42    
43     // Advance buffer pointer
44     buf_ptr++;
45     }
46     }
47    
48    
49     /* Search for next data sync, returns 0 if not found */
50     static int search_data_sync(void)
51     {
52     while (1) {
53    
54     // End of buffer reached? Then bail out
55     if (raw_buf[buf_ptr] & 0x80)
56     return 0;
57     if (buf_ptr > RAW_SIZE - 15)
58     return 0;
59    
60     // Data sync: 10 "1"-bits followed by GCR-encoded 0x07 (= 111111111222211)
61     if (raw_buf[buf_ptr + 0] == 1 && raw_buf[buf_ptr + 1] == 1
62     && raw_buf[buf_ptr + 2] == 1 && raw_buf[buf_ptr + 3] == 1
63     && raw_buf[buf_ptr + 4] == 1 && raw_buf[buf_ptr + 5] == 1
64     && raw_buf[buf_ptr + 6] == 1 && raw_buf[buf_ptr + 7] == 1
65     && raw_buf[buf_ptr + 8] == 1 && raw_buf[buf_ptr + 9] == 2
66     && raw_buf[buf_ptr + 10] == 2 && raw_buf[buf_ptr + 11] == 2
67     && raw_buf[buf_ptr + 12] == 2 && raw_buf[buf_ptr + 13] == 1
68     && raw_buf[buf_ptr + 14] == 1) {
69    
70     // Found, advance buffer pointer to data mark
71     buf_ptr += 9;
72     // fprintf(stderr, "Data found at %d\n", buf_ptr);
73     return 1;
74     }
75    
76     // Advance buffer pointer
77     buf_ptr++;
78     }
79     }
80    
81    
82     static const unsigned int gcr2bin_table_hi[32] = {
83     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
84     0xff, 0x80, 0x00, 0x10, 0xff, 0xc0, 0x40, 0x50,
85     0xff, 0xff, 0x20, 0x30, 0xff, 0xf0, 0x60, 0x70,
86     0xff, 0x90, 0xa0, 0xb0, 0xff, 0xd0, 0xe0, 0xff
87     };
88    
89     static const unsigned int gcr2bin_table_lo[32] = {
90     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
91     0xff, 0x08, 0x00, 0x01, 0xff, 0x0c, 0x04, 0x05,
92     0xff, 0xff, 0x02, 0x03, 0xff, 0x0f, 0x06, 0x07,
93     0xff, 0x09, 0x0a, 0x0b, 0xff, 0x0d, 0x0e, 0xff
94     };
95    
96     /* Decode GCR data to specified buffer */
97     static int decode_gcr(unsigned char *p, int num)
98     {
99     unsigned int r = 0;
100     int bit_count = 0;
101    
102     while (num > 0) {
103    
104     // Read clock value
105     unsigned char x = raw_buf[buf_ptr];
106    
107     // End of buffer reached? Then bail out
108     if (x & 0x80)
109     return 0;
110    
111     // Advance buffer pointer
112     buf_ptr++;
113    
114     // Assemble bits
115     r = (r << x) | 1;
116     bit_count += x;
117    
118     // 10 bits (= one GCR-encoded byte) assembled?
119     if (bit_count >= 10) {
120    
121     // Yes, write decoded byte to buffer
122     unsigned int gcr = (r >> (bit_count - 10)) & 0x3ff;
123     unsigned char bin_hi = gcr2bin_table_hi[gcr >> 5],
124     bin_lo = gcr2bin_table_lo[gcr & 0x1f];
125     *p++ = bin_hi | bin_lo;
126     num--;
127     bit_count -= 10;
128     }
129     }
130    
131     return 1;
132     }
133    
134    
135     /* Decode header and check for validity, returns 0 on error */
136     static int decode_header(int track, int *sector)
137     {
138     unsigned char header[6];
139     *sector = 0;
140    
141     // Decode header bytes
142     if (!decode_gcr(header, 6)) {
143     fprintf(stderr, "Track %d: buffer underrun reading header\n", track);
144     return 0;
145     }
146     // printf("hdr: %02x %02x %02x %02x %02x %02x\n", header[0], header[1], header[2], header[3], header[4], header[5]);
147    
148     // Check for validity
149     if (header[0] != 0x08) {
150     fprintf(stderr, "Track %d: invalid header mark (shouldn't happen)\n", track);
151     return 0;
152     }
153     if (header[1] ^ header[2] ^ header[3] ^ header[4] ^ header[5]) {
154     fprintf(stderr, "Track %d: header checksum incorrect\n", track);
155     // we'll try to continue anyways
156     }
157     if (header[2] >= num_sectors[track]) {
158     fprintf(stderr, "Track %d: invalid sector number in header\n", track);
159     return 0;
160     }
161     if (header[3] != track) {
162     fprintf(stderr, "Track %d: invalid track number in header (seek error?)\n", track);
163     return 0;
164     }
165    
166     // Everything seems OK, return sector number
167     *sector = header[2];
168     return 1;
169     }
170    
171    
172     /* Decode sector data to buffer, returns 0 on error */
173     static int decode_data(int track, int sector, unsigned char *p)
174     {
175     unsigned char tmp[SECTOR_SIZE + 2];
176     unsigned char sum = 0;
177     int i;
178    
179     // Decode data bytes
180     if (!decode_gcr(tmp, SECTOR_SIZE + 2)) {
181     fprintf(stderr, "Track %d sector %d: buffer underrun reading data\n", track, sector);
182     return 0;
183     }
184    
185     // Check for validity
186     if (tmp[0] != 0x07) {
187     fprintf(stderr, "Track %d sector %d: invalid data mark (shouldn't happen)\n", track, sector);
188     return 0;
189     }
190     for (i = 1; i < SECTOR_SIZE+2; i++)
191     sum ^= tmp[i];
192     if (sum) {
193     fprintf(stderr, "Track %d sector %d: data checksum incorrect\n", track, sector);
194     // we'll try to continue anyways
195     }
196    
197     // Copy data
198     memcpy(p, tmp + 1, SECTOR_SIZE);
199     return 1;
200     }
201    
202    
203     /* Decode sectors from raw_buf to track_buf */
204     static void decode_sectors(int track)
205     {
206     int sector;
207    
208     // No sector read yet
209     unsigned long sector_found = 0;
210     unsigned long all_sectors = (1 << num_sectors[track]) - 1;
211    
212     // Reset buffer pointer
213     buf_ptr = 0;
214    
215     // Process entire buffer
216     while (1) {
217    
218     // Search for next header sync
219     if (!search_header_sync())
220     break;
221    
222     // Decode sector header
223     if (decode_header(track, &sector)) {
224    
225     // Sector already read? Then don't do it again
226     if (sector_found & (1 << sector))
227     continue;
228    
229     // Search for next data sync
230     if (!search_data_sync())
231     break;
232    
233     // Decode sector data
234     if (decode_data(track, sector, track_buf + sector * SECTOR_SIZE)) {
235     sector_found |= 1 << sector;
236    
237     // All sectors read? Then we are done
238     if (sector_found == all_sectors)
239     break;
240     }
241     }
242     }
243    
244     // Check if all sectors of the track were found
245     if (sector_found != all_sectors) {
246     for (sector = 0; sector < num_sectors[track]; sector++)
247     if (!(sector_found & (1 << sector)))
248     fprintf(stderr, "Track %d: sector %d not found\n", track, sector);
249     }
250     }
251    
252    
253     /* Read one track into track_buf, returns 0 on error */
254     static int read_track(int drive, int track)
255     {
256     int i;
257    
258 cebix 1.2 // Seek to track, set speed zone
259     seek_to(drive, track);
260 cebix 1.1
261     // Clear buffer
262     memset(track_buf, 0, num_sectors[track] * SECTOR_SIZE);
263    
264     // Read track (1 revolution + 10%)
265     if (!catweasel_read(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
266     fprintf(stderr, "Error reading track %d\n", track);
267     return 0;
268     }
269    
270     // Copy track data to buffer, apply thresholds
271     for (i = 0; i < RAW_SIZE; i++) {
272     unsigned char x = inb(c.io_mem), y;
273     if (x & 0x80) {
274     memset(raw_buf + i, 0x80, RAW_SIZE - i);
275     break;
276     }
277     if (x < thresh_table[0])
278     y = 0;
279     else if (x < thresh_table[1])
280     y = 1;
281     else if (x < thresh_table[2])
282     y = 2;
283     else
284     y = 3;
285     raw_buf[i] = y;
286     }
287     raw_buf[RAW_SIZE - 1] = 0x80;
288    
289     // Decode all sectors
290     decode_sectors(track);
291    
292     return 1;
293     }
294    
295    
296     int main(int argc, char **argv)
297     {
298 cebix 1.2 int track;
299 cebix 1.1 FILE *f;
300    
301     // Parse arguments
302 cebix 1.2 parse_args(argc, argv);
303 cebix 1.1
304     // Open output file
305 cebix 1.2 f = fopen(file_name, "wb");
306 cebix 1.1 if (f == NULL) {
307 cebix 1.2 fprintf(stderr, "Can't open %s for writing: %s\n", file_name, strerror(errno));
308 cebix 1.1 return 1;
309     }
310    
311     // Obtain access to I/O ports
312 cebix 1.2 ioport_access();
313 cebix 1.1
314     // Init Catweasel
315     catweasel_init_controller(&c);
316    
317     // Start drive
318 cebix 1.2 start_drive(drive_num);
319 cebix 1.1
320     // Read all tracks
321     for (track = 1; track <= NUM_TRACKS; track++) {
322     printf("Track %d...\n", track);
323 cebix 1.2 if (!read_track(drive_num, track))
324 cebix 1.1 break;
325     fwrite(track_buf, 256, num_sectors[track], f);
326     }
327    
328     // Stop drive
329 cebix 1.2 stop_drive(drive_num);
330    
331     // Free Catweasel
332 cebix 1.1 catweasel_free_controller(&c);
333    
334     // Close output file
335     fclose(f);
336    
337     return 0;
338     }