ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/writecbm.c
Revision: 1.2
Committed: 2004-01-07T16:53:58Z (20 years, 3 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +14 -43 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     * writecbm.c - Write CBM disk from 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     /* Number of sync GCR bytes */
12     #define SYNC_LENGTH 5
13    
14     /* Number of header gap GCR bytes */
15     #define HEADER_GAP_LENGTH 9
16    
17     /* Number of inter-sector gap GCR bytes */
18     #define GAP_LENGTH 4
19    
20    
21     /* Write byte to Catweasel buffer */
22     #define PUT(x) put_precomp(x)
23    
24     static void put_precomp(unsigned char x)
25     {
26     static int previous = 0, adjust = 0;
27     int newadjust = (previous > 1) - (x > 1);
28    
29     outb(0x80 - clock_table[previous] - adjust - newadjust, c.io_mem);
30     previous = x;
31     adjust = -newadjust;
32     }
33    
34    
35     /*
36     * We take advantage of the fact that all GCR nybbles (5 bits) end in "x1"
37     * or "10", so there is either one or no "0"-bit before the next nybble.
38     * This table stores the sequence of distances between "1"-bits for each
39     * possible 4-bit value. The end marker is -1 if the trailing bit is 1,
40     * and -2 if it is 0. In the latter case, the first distance value for
41     * the next nybble must be incremented by 1.
42     */
43    
44     static const int bin2gcr[16 * 5] = {
45     2, 2, -2, 0, 0, // 01010
46     2, 2, 1, -1, 0, // 01011
47     1, 3, -2, 0, 0, // 10010
48     1, 3, 1, -1, 0, // 10011
49     2, 1, 1, -2, 0, // 01110
50     2, 1, 1, 1, -1, // 01111
51     1, 2, 1, -2, 0, // 10110
52     1, 2, 1, 1, -1, // 10111
53     2, 3, -1, 0, 0, // 01001
54     1, 1, 3, -1, 0, // 11001
55     1, 1, 2, -2, 0, // 11010
56     1, 1, 2, 1, -1, // 11011
57     2, 1, 2, -1, 0, // 01101
58     1, 1, 1, 2, -1, // 11101
59     1, 1, 1, 1, -2, // 11110
60     1, 2, 2, -1, 0 // 10101
61     };
62    
63     /* Encode one nybble */
64     static void encode_nybble(int x, int *trailing_zero)
65     {
66     const int *gcr = bin2gcr + x * 5;
67     int v;
68    
69     do {
70     v = *gcr++;
71     if (v > 0)
72     PUT(v + *trailing_zero);
73     *trailing_zero = (v == -2) ? 1 : 0;
74     } while (v > 0);
75     }
76    
77     /* Encode GCR data from specified buffer */
78     static void encode_gcr(const unsigned char *p, int num)
79     {
80     int trailing_zero = 0;
81    
82     while (num > 0) {
83    
84     // Read byte from buffer
85     unsigned char x = *p++;
86     num--;
87    
88     // Encode upper and lower nybbles
89     encode_nybble(x >> 4, &trailing_zero);
90     encode_nybble(x & 0x0f, &trailing_zero);
91     }
92     }
93    
94    
95     /* Encode sector header */
96     static void encode_header(int track, int sector, unsigned char id1, unsigned char id2)
97     {
98     unsigned char header[8];
99     int i;
100    
101     // Set up header data
102     header[0] = 0x08;
103     header[2] = sector;
104     header[3] = track;
105     header[4] = id2;
106     header[5] = id1;
107     header[6] = 0x0f;
108     header[7] = 0x0f;
109     header[1] = header[2] ^ header[3] ^ header[4] ^ header[5];
110    
111     // Write sync
112     for (i = 0; i < SYNC_LENGTH * 8; i++)
113     PUT(1);
114    
115     // Write header
116     encode_gcr(header, 8);
117    
118     // Write header gap
119     for (i = 0; i < HEADER_GAP_LENGTH * 4; i++)
120     PUT(2);
121     }
122    
123    
124     /* Encode sector data from specified buffer */
125     static void encode_data(int track, const unsigned char *p)
126     {
127     unsigned char tmp[SECTOR_SIZE + 4];
128     int i, sum = 0;
129    
130     // Set up sector data
131     tmp[0] = 0x07;
132     memcpy(tmp + 1, p, SECTOR_SIZE);
133     for (i = 0; i < SECTOR_SIZE; i++)
134     sum ^= p[i];
135     tmp[SECTOR_SIZE + 1] = sum;
136     tmp[SECTOR_SIZE + 2] = 0;
137     tmp[SECTOR_SIZE + 3] = 0;
138    
139     // Write sync
140     for (i = 0; i < SYNC_LENGTH * 8; i++)
141     PUT(1);
142    
143     // Write data
144     encode_gcr(tmp, SECTOR_SIZE + 4);
145    
146     // Write inter-sector gap
147     for (i = 0; i < GAP_LENGTH * 4; i++)
148     PUT(2);
149     }
150    
151    
152     /* Encode sectors from track_buf */
153     static void encode_sectors(int track)
154     {
155     int sector;
156    
157     // Encode each sector
158     for (sector = 0; sector < num_sectors[track]; sector++) {
159     encode_header(track, sector, 0x41, 0x41);
160     encode_data(track, track_buf + SECTOR_SIZE * sector);
161     }
162     }
163    
164    
165     /* Write one track from track_buf, returns 0 on error */
166     static int write_track(int drive, int track)
167     {
168     int i;
169    
170 cebix 1.2 // Seek to track, set speed zone
171     seek_to(drive, track);
172 cebix 1.1
173     // Write empty track
174     inb(c.iobase + 1);
175     for (i = 0; i < bps[std_speed[track]] * 60 / drive_rpm; i++)
176     PUT(2);
177     outb(0xff, c.io_mem);
178     if (!catweasel_write(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
179     fprintf(stderr, "Error writing track %d\n", track);
180     return 0;
181     }
182    
183     // Reset buffer pointer
184     inb(c.iobase + 1);
185    
186     // Encode all sectors
187     encode_sectors(track);
188    
189     // Write to disk (1 revolution + 10%)
190     outb(0xff, c.io_mem);
191     if (!catweasel_write(c.drives + drive, 0, 1, 1100 * 60 / drive_rpm)) {
192     fprintf(stderr, "Error writing track %d\n", track);
193     return 0;
194     }
195    
196     return 1;
197     }
198    
199    
200     int main(int argc, char **argv)
201     {
202 cebix 1.2 int track, ret = 0;
203 cebix 1.1 FILE *f;
204    
205     // Parse arguments
206 cebix 1.2 parse_args(argc, argv);
207 cebix 1.1
208     // Open input file
209 cebix 1.2 f = fopen(file_name, "rb");
210 cebix 1.1 if (f == NULL) {
211 cebix 1.2 fprintf(stderr, "Can't open %s for reading: %s\n", file_name, strerror(errno));
212 cebix 1.1 return 1;
213     }
214    
215     // Obtain access to I/O ports
216 cebix 1.2 ioport_access();
217 cebix 1.1
218     // Init Catweasel
219     catweasel_init_controller(&c);
220    
221     // Start drive
222 cebix 1.2 start_drive(drive_num);
223 cebix 1.1
224     // Disk write protected?
225 cebix 1.2 if (!catweasel_write_protected(c.drives + drive_num)) {
226 cebix 1.1
227     // No, write all tracks
228     for (track = 1; track <= NUM_TRACKS; track++) {
229     printf("Track %d...\n", track);
230     if (fread(track_buf, 256, num_sectors[track], f) != num_sectors[track]) {
231     fprintf(stderr, "Error reading input file\n");
232     break;
233     }
234 cebix 1.2 if (!write_track(drive_num, track))
235 cebix 1.1 break;
236     }
237    
238     } else {
239    
240     fprintf(stderr, "Error: disk write-protected\n");
241     ret = 1;
242     }
243    
244     // Stop drive
245 cebix 1.2 stop_drive(drive_num);
246    
247     // Free Catweasel
248 cebix 1.1 catweasel_free_controller(&c);
249    
250     // Close input file
251     fclose(f);
252    
253     return ret;
254     }