ViewVC Help
View File | Revision Log | Show Annotations | Revision Graph | Root Listing
root/cebix/cwcbm/common.c
Revision: 1.2
Committed: 2004-01-10T14:05:59Z (20 years, 2 months ago) by cebix
Content type: text/plain
Branch: MAIN
Changes since 1.1: +163 -45 lines
Log Message:
added support for 8050 and 8250 formats

File Contents

# Content
1 /*
2 * common.c - Common parts of readcbm and writecbm
3 *
4 * Written in 2003-2004 by Christian Bauer <Christian.Bauer@uni-mainz.de>
5 */
6
7 #include "catweasel.h"
8 #include "common.h"
9
10
11 /* Effective crystal frequencies */
12 #define CRYSTAL_FREQ_1541 4000000 // 4 MHz
13 #define CRYSTAL_FREQ_8050 6000000 // 6 MHz
14
15 /* CBM drive RPM */
16 #define NOMINAL_RPM 300
17
18 /* Catweasel frequency (7 MHz) */
19 #define CW_FREQ 7080500.0
20
21
22 /* 1541 disk format */
23 static const int bps_1541[4] = {
24 CRYSTAL_FREQ_1541 / 16, CRYSTAL_FREQ_1541 / 15,
25 CRYSTAL_FREQ_1541 / 14, CRYSTAL_FREQ_1541 / 13
26 };
27
28 static const int std_speed_1541[36] = {
29 0,
30 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
31 2, 2, 2, 2, 2, 2, 2,
32 1, 1, 1, 1, 1, 1,
33 0, 0, 0, 0, 0
34 };
35
36 static const int num_sectors_1541[36] = {
37 0,
38 21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,
39 19,19,19,19,19,19,19,
40 18,18,18,18,18,18,
41 17,17,17,17,17
42 };
43
44 static const struct format_t format_1541 = {
45 1, // sides
46 35, // tracks_per_side
47 bps_1541, // bps
48 std_speed_1541, // std_speed
49 num_sectors_1541 // num_sectors
50 };
51
52 /* 8050 disk format */
53 static const int bps_8050[4] = {
54 CRYSTAL_FREQ_8050 / 16, CRYSTAL_FREQ_8050 / 15,
55 CRYSTAL_FREQ_8050 / 14, CRYSTAL_FREQ_8050 / 13
56 };
57
58 static const int std_speed_8050[78] = {
59 0,
60 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
61 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
62 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
64 };
65
66 static const int num_sectors_8050[78] = {
67 0,
68 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
69 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
70 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
71 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23
72 };
73
74 static const struct format_t format_8050 = {
75 1, // sides
76 77, // tracks_per_side
77 bps_8050, // bps
78 std_speed_8050, // std_speed
79 num_sectors_8050 // num_sectors
80 };
81
82 /* 8250 disk format */
83 static const int std_speed_8250[155] = {
84 0,
85 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
86 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
87 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
88 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
90 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
91 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
92 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
93 };
94
95 static const int num_sectors_8250[155] = {
96 0,
97 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
98 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
99 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
100 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
101 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29,
102 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
103 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
104 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23
105 };
106
107 static const struct format_t format_8250 = {
108 2, // sides
109 77, // tracks_per_side
110 bps_8050, // bps
111 std_speed_8250, // std_speed
112 num_sectors_8250 // num_sectors
113 };
114
115 /* Selected format */
116 const struct format_t *format = NULL;
117
118
119 /* Command line arguments */
120 int drive_num = 0;
121 int drive_rpm = 360;
122 int drive_40tracks = 0;
123 int steps_per_track = 1;
124 const char *file_name;
125
126
127 /* Catweasel controller struct */
128 catweasel_contr c;
129
130
131 /* Clock table (nominal number of Catweasel clocks per inter-flux-change gap) */
132 int clock_table[4] = {0, 0, 0, 0};
133
134 /* Threshold table */
135 int thresh_table[3] = {0, 0, 0};
136
137
138 /* Track buffer */
139 unsigned char track_buf[MAX_SECTORS * SECTOR_SIZE];
140
141
142 /* Print usage information */
143 static void usage(const char *prgname)
144 {
145 fprintf(stderr,
146 "Reads/writes CBM formatted disks with the Catweasel controller\n\n"
147 "Usage: %s <options> <file>\n\n"
148 "Options:\n"
149 " -h | --help this text\n"
150 " -p | --port n Catweasel I/O port address (hex, required)\n"
151 " -d | --drive n drive number (0 or 1)\n"
152 " -f | --format n disk format type (1541, 8050, or 8250)\n"
153 " -4 | --40tracks assume 300RPM 40-track drive\n",
154 prgname
155 );
156 exit(1);
157 }
158
159
160 /* Parse command line arguments */
161 void parse_args(int argc, char **argv)
162 {
163 static struct option long_opts[] = {
164 {"help", 0, 0, 'h'},
165 {"port", 1, 0, 'p'},
166 {"drive", 1, 0, 'd'},
167 {"format", 1, 0, 'f'},
168 {"40tracks", 0, 0, '4'},
169 {NULL, 0, 0, 0}
170 };
171
172 int format_type = 0;
173
174 // Init Catweasel struct
175 memset(&c, 0, sizeof(c));
176 c.msdelay = msdelay;
177
178 // Parse arguments
179 for (;;) {
180 int ch;
181 if ((ch = getopt_long(argc, argv, "hp:d:f:4", long_opts, NULL)) == -1)
182 break;
183
184 switch (ch) {
185 case 0: /* Long option */
186 break;
187 case 'p':
188 c.iobase = strtol(optarg, NULL, 16);
189 break;
190 case 'd':
191 drive_num = atoi(optarg);
192 if (drive_num < 0 || drive_num > 1)
193 usage(argv[0]);
194 break;
195 case 'f':
196 format_type = atoi(optarg);
197 if (format_type == 1541 || format_type == 8050 || format_type == 8250)
198 select_format(format_type);
199 else
200 usage(argv[0]);
201 break;
202 case '4':
203 drive_rpm = 300;
204 drive_40tracks = 1;
205 break;
206 case 'h':
207 default:
208 usage(argv[0]);
209 break;
210 }
211 }
212
213 if (optind >= argc)
214 usage(argv[0]);
215 else
216 file_name = argv[optind];
217
218 // Check for consistency
219 if (c.iobase == 0)
220 usage(argv[0]);
221 if (format_type == 0)
222 select_format(1541);
223 if (format->tracks_per_side >= 40 && drive_40tracks) {
224 fprintf(stderr, "Can't use 80 track disk format on 40 track drive\n");
225 exit(1);
226 }
227 if (format->tracks_per_side < 40 && !drive_40tracks)
228 steps_per_track = 2; // double step
229
230 // Set Catweasel type
231 if (c.iobase < 0x1000)
232 c.type = CATWEASEL_TYPE_MK1;
233 else
234 c.type = CATWEASEL_TYPE_MK3;
235 }
236
237
238 /* Obtain access to I/O ports */
239 void ioport_access(void)
240 {
241 if ((c.type == CATWEASEL_TYPE_MK1 && ioperm(c.iobase, 8, 1) == -1)
242 || (c.type == CATWEASEL_TYPE_MK3 && iopl(3) == -1)) {
243 fprintf(stderr, "No access to I/O ports\n");
244 exit(1);
245 }
246 setuid(getuid());
247 }
248
249
250 /* Delay specified number of milliseconds */
251 void msdelay(int ms)
252 {
253 usleep(ms * 1000);
254 }
255
256
257 /* Select disk format */
258 void select_format(int type)
259 {
260 switch (type) {
261 case 1541:
262 format = &format_1541;
263 break;
264 case 8050:
265 format = &format_8050;
266 break;
267 case 8250:
268 format = &format_8250;
269 break;
270 default:
271 fprintf(stderr, "Invalid disk format type\n");
272 exit(1);
273 }
274 }
275
276
277 /* Set speed zone and tables */
278 static void set_zone(int track)
279 {
280 int zone = format->std_speed[track];
281 int bps = format->bps[zone];
282 clock_table[0] = 0;
283 clock_table[1] = CW_FREQ * NOMINAL_RPM * 1 / (bps * drive_rpm);
284 clock_table[2] = CW_FREQ * NOMINAL_RPM * 2 / (bps * drive_rpm);
285 clock_table[3] = CW_FREQ * NOMINAL_RPM * 3 / (bps * drive_rpm);
286 thresh_table[0] = (clock_table[0] + clock_table[1]) / 2;
287 thresh_table[1] = (clock_table[1] + clock_table[2]) / 2;
288 thresh_table[2] = (clock_table[2] + clock_table[3]) / 2;
289 }
290
291
292 /* Seek to given CBM track (1..35) and select correct side and speed zone */
293 void seek_to(int drive, int track)
294 {
295 // Set speed zone and tables
296 set_zone(track);
297
298 // Seek to track
299 int cw_track = ((track - 1) % format->tracks_per_side) * steps_per_track;
300 //cw_track -= 3;
301 //if (cw_track < 0) cw_track = 0;
302 catweasel_seek(c.drives + drive, cw_track);
303 msdelay(20);
304 }
305
306
307 /* Start drive */
308 void start_drive(int drive)
309 {
310 catweasel_select(&c, drive == 0, drive == 1);
311 catweasel_set_motor(c.drives + drive, 1);
312 msdelay(500);
313 catweasel_seek(c.drives + drive, 0);
314 msdelay(20);
315 }
316
317
318 /* Stop drive */
319 void stop_drive(int drive)
320 {
321 catweasel_set_motor(c.drives + drive, 0);
322 catweasel_select(&c, 0, 0);
323 }