1 /*
2 smc.c - Super Magic Card support for uCON64
3
4 Copyright (c) 2003, 2019 - 2020 dbjh
5
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 #ifdef _MSC_VER
25 #pragma warning(push)
26 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
27 #endif
28 #include <stdlib.h>
29 #ifdef _MSC_VER
30 #pragma warning(pop)
31 #endif
32 #include <string.h>
33 #include "misc/archive.h"
34 #include "misc/file.h"
35 #include "ucon64.h"
36 #include "ucon64_misc.h"
37 #include "backup/ffe.h"
38 #include "backup/smc.h"
39
40
41 #ifdef USE_PARALLEL
42 static st_ucon64_obj_t smc_obj[] =
43 {
44 {UCON64_NES, WF_DEFAULT | WF_STOP | WF_NO_SPLIT},
45 {UCON64_NES, WF_STOP | WF_NO_ROM}
46 };
47 #endif
48
49 const st_getopt2_t smc_usage[] =
50 {
51 {
52 NULL, 0, 0, 0,
53 NULL, "Super Magic Card"/*"1993/1994/1995/19XX Front Far East/FFE http://www.front.com.tw"*/,
54 NULL
55 },
56 #ifdef USE_PARALLEL
57 {
58 "xsmc", 0, 0, UCON64_XSMC, // send only
59 NULL, "send ROM (in FFE format) to Super Magic Card; " OPTION_LONG_S "port" OPTARG_S "PORT",
60 &smc_obj[0]
61 },
62 {
63 "xsmcr", 0, 0, UCON64_XSMCR,
64 NULL, "send/receive RTS data to/from Super Magic Card; " OPTION_LONG_S "port" OPTARG_S "PORT\n"
65 "receives automatically when RTS file does not exist",
66 &smc_obj[1]
67 },
68 #endif
69 {NULL, 0, 0, 0, NULL, NULL, NULL}
70 };
71
72
73 #ifdef USE_PARALLEL
74
75 #define BUFFERSIZE 8192
76
77
78 static unsigned int get_blocks1 (unsigned char *header);
79 static unsigned int get_blocks2 (unsigned char *header);
80 static unsigned int get_blocks3 (unsigned char *header);
81
82
83 unsigned int
get_blocks1(unsigned char * header)84 get_blocks1 (unsigned char *header)
85 {
86 if (header[7] == 0xaa)
87 return header[3];
88 if (header[0] & 0x30)
89 return header[0] & 0x20 ? 32 : 16; // 0x10 => 16; 0x20/0x30 => 32
90 else
91 switch (header[1] >> 5)
92 {
93 case 0:
94 case 4:
95 return 16;
96 case 1:
97 case 2:
98 case 3:
99 return 32;
100 default: // 5/6/7
101 return 4;
102 }
103 }
104
105
106 unsigned int
get_blocks2(unsigned char * header)107 get_blocks2 (unsigned char *header)
108 {
109 if (header[0] & 0x30)
110 return header[0] & 0x10 ? 32 : 16; // 0x10/0x30 => 32; 0x20 => 16
111 else
112 return 0;
113 }
114
115
116 unsigned int
get_blocks3(unsigned char * header)117 get_blocks3 (unsigned char *header)
118 {
119 if (header[7] == 0xaa)
120 return header[4];
121 if (header[0] & 0x30)
122 return 0;
123 else
124 switch (header[1] >> 5)
125 {
126 default: // 0/1/2/3
127 return 0;
128 case 4:
129 case 5:
130 return 4;
131 case 6:
132 return 2;
133 case 7:
134 return 1;
135 }
136 }
137
138
139 int
smc_write_rom(const char * filename,unsigned short parport)140 smc_write_rom (const char *filename, unsigned short parport)
141 {
142 FILE *file;
143 unsigned char *buffer;
144 size_t bytesread, bytessent;
145 unsigned int size, offset, n_blocks1, n_blocks2, n_blocks3, n;
146 time_t starttime;
147
148 ffe_init_io (parport);
149
150 if ((file = fopen (filename, "rb")) == NULL)
151 {
152 fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
153 exit (1);
154 }
155 if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
156 {
157 fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
158 exit (1);
159 }
160
161 ffe_send_command0 (0x4500, 2);
162 ffe_send_command0 (0x42fd, 0x20);
163 ffe_send_command0 (0x43fc, 0);
164
165 fread_checked (buffer, 1, SMC_HEADER_LEN, file);
166
167 n_blocks1 = get_blocks1 (buffer);
168 n_blocks2 = get_blocks2 (buffer);
169 n_blocks3 = get_blocks3 (buffer);
170
171 size = (n_blocks1 + n_blocks2 + n_blocks3) * 8 * 1024 + 8 +
172 (buffer[0] & SMC_TRAINER ? 512 : 0);
173 printf ("Send: %u Bytes (%.4f Mb)\n", size, (float) size / MBIT);
174
175 ffe_send_block (0x5020, buffer, 8); // send "file control block"
176 bytessent = 8;
177
178 if (buffer[1] >> 5 > 4)
179 offset = 12;
180 else
181 offset = 0;
182
183 if (buffer[0] & SMC_TRAINER) // send trainer if present
184 {
185 fread_checked (buffer, 1, 512, file);
186 ffe_send_block (0x600, buffer, 512);
187 bytessent += 512;
188 }
189
190 puts ("Press q to abort\n");
191 starttime = time (NULL);
192
193 for (n = 0; n < n_blocks1; n++)
194 {
195 ffe_send_command0 (0x4507, (unsigned char) (n + offset));
196 if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
197 break;
198 ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
199
200 bytessent += bytesread;
201 ucon64_gauge (starttime, bytessent, size);
202 ffe_checkabort (2);
203 }
204
205 for (n = 0; n < n_blocks2; n++)
206 {
207 ffe_send_command0 (0x4507, (unsigned char) (n + 32));
208 if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
209 break;
210 ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
211
212 bytessent += bytesread;
213 ucon64_gauge (starttime, bytessent, size);
214 ffe_checkabort (2);
215 }
216
217 ffe_send_command0 (0x2001, 0);
218
219 for (n = 0; n < n_blocks3; n++)
220 {
221 if (n == 0)
222 {
223 ffe_send_command0 (0x4500, 0x22);
224 ffe_send_command0 (0x42ff, 0x30);
225 if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
226 break;
227 ffe_send_block (0x6000, buffer, (unsigned short) bytesread);
228 }
229 else
230 {
231 int m;
232
233 ffe_send_command0 (0x4500, 7);
234 for (m = 0; m < 8; m++)
235 ffe_send_command0 ((unsigned short) (0x4510 + m), (unsigned char) (n * 8 + m));
236 if ((bytesread = fread (buffer, 1, BUFFERSIZE, file)) == 0)
237 break;
238 ffe_send_block2 (0, buffer, (unsigned short) bytesread);
239 }
240
241 bytessent += bytesread;
242 ucon64_gauge (starttime, bytessent, size);
243 ffe_checkabort (2);
244 }
245
246 for (n = 0x4504; n < 0x4508; n++)
247 ffe_send_command0 ((unsigned short) n, 0);
248 for (n = 0x4510; n < 0x451c; n++)
249 ffe_send_command0 ((unsigned short) n, 0);
250
251 ffe_send_command (5, 1, 0);
252
253 free (buffer);
254 fclose (file);
255
256 return 0;
257 }
258
259
260 int
smc_read_rts(const char * filename,unsigned short parport)261 smc_read_rts (const char *filename, unsigned short parport)
262 {
263 FILE *file;
264 unsigned char *buffer;
265 unsigned int bytesreceived = 0, size, n;
266 time_t starttime;
267
268 ffe_init_io (parport);
269
270 if ((file = fopen (filename, "wb")) == NULL)
271 {
272 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
273 exit (1);
274 }
275 if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
276 {
277 fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
278 exit (1);
279 }
280
281 size = 0x68 + 4 * 1024 + 5 * 8 * 1024;
282 printf ("Receive: %u Bytes\n", size);
283 memset (buffer, 0, SMC_HEADER_LEN);
284 buffer[8] = 0xaa;
285 buffer[9] = 0xbb;
286 buffer[10] = 1;
287
288 puts ("Press q to abort\n");
289 starttime = time (NULL);
290
291 ffe_send_command (5, 3, 0);
292 ffe_receive_block (0x5840, buffer + 0x100, 0x68);
293 fwrite (buffer, 1, SMC_HEADER_LEN, file);
294 bytesreceived += 0x68;
295
296 ffe_send_command0 (0x4500, 0x32);
297 ffe_send_command0 (0x42ff, 0x30);
298 ffe_receive_block (0x6000, buffer, BUFFERSIZE / 2); // 0x1000
299 fwrite (buffer, 1, BUFFERSIZE / 2, file);
300
301 bytesreceived += BUFFERSIZE / 2;
302 ucon64_gauge (starttime, bytesreceived, size);
303 ffe_checkabort (2);
304
305 for (n = 2; n <= 0x22; n += 0x20)
306 {
307 ffe_send_command0 (0x4500, (unsigned char) n);
308 ffe_receive_block (0x6000, buffer, BUFFERSIZE); // 0x2000
309 fwrite (buffer, 1, BUFFERSIZE, file);
310
311 bytesreceived += BUFFERSIZE;
312 ucon64_gauge (starttime, bytesreceived, size);
313 ffe_checkabort (2);
314 }
315
316 for (n = 1; n <= 3; n++)
317 {
318 ffe_send_command0 (0x43fc, (unsigned char) n);
319 if (n == 1)
320 ffe_send_command0 (0x2001, 0);
321 ffe_receive_block2 (0, buffer, BUFFERSIZE); // 0x2000
322 fwrite (buffer, 1, BUFFERSIZE, file);
323
324 bytesreceived += BUFFERSIZE;
325 ucon64_gauge (starttime, bytesreceived, size);
326 ffe_checkabort (2);
327 }
328
329 ffe_send_command0 (0x43fc, 0);
330 ffe_send_command0 (0x2001, 0x6b);
331
332 free (buffer);
333 fclose (file);
334
335 return 0;
336 }
337
338
339 int
smc_write_rts(const char * filename,unsigned short parport)340 smc_write_rts (const char *filename, unsigned short parport)
341 {
342 FILE *file;
343 unsigned char *buffer;
344 unsigned int bytessent = 0, size, n;
345 time_t starttime;
346
347 ffe_init_io (parport);
348
349 if ((file = fopen (filename, "rb")) == NULL)
350 {
351 fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
352 exit (1);
353 }
354 if ((buffer = (unsigned char *) malloc (BUFFERSIZE)) == NULL)
355 {
356 fprintf (stderr, ucon64_msg[FILE_BUFFER_ERROR], BUFFERSIZE);
357 exit (1);
358 }
359
360 size = 0x68 + 4 * 1024 + 5 * 8 * 1024;
361 printf ("Send: %u Bytes\n", size);
362 fread_checked (buffer, 1, SMC_HEADER_LEN, file);
363
364 puts ("Press q to abort\n");
365 starttime = time (NULL);
366
367 ffe_send_command (5, 3, 0);
368 ffe_send_block (0x5840, buffer + 0x100, 0x68);
369 bytessent += 0x68;
370
371 ffe_send_command0 (0x4500, 0x32);
372 ffe_send_command0 (0x42ff, 0x30);
373 fread_checked (buffer, 1, BUFFERSIZE / 2, file);
374 ffe_send_block (0x6000, buffer, BUFFERSIZE / 2); // 0x1000
375
376 bytessent += BUFFERSIZE / 2;
377 ucon64_gauge (starttime, bytessent, size);
378 ffe_checkabort (2);
379
380 for (n = 2; n <= 0x22; n += 0x20)
381 {
382 ffe_send_command0 (0x4500, (unsigned char) n);
383 fread_checked (buffer, 1, BUFFERSIZE, file);
384 ffe_send_block (0x6000, buffer, BUFFERSIZE); // 0x2000
385
386 bytessent += BUFFERSIZE;
387 ucon64_gauge (starttime, bytessent, size);
388 ffe_checkabort (2);
389 }
390
391 for (n = 1; n <= 3; n++)
392 {
393 ffe_send_command0 (0x43fc, (unsigned char) n);
394 if (n == 1)
395 ffe_send_command0 (0x2001, 0);
396 fread_checked (buffer, 1, BUFFERSIZE, file);
397 ffe_send_block2 (0, buffer, BUFFERSIZE); // 0x2000
398
399 bytessent += BUFFERSIZE;
400 ucon64_gauge (starttime, bytessent, size);
401 ffe_checkabort (2);
402 }
403
404 ffe_send_command0 (0x43fc, 0);
405 ffe_send_command0 (0x2001, 0x6b);
406
407 free (buffer);
408 fclose (file);
409
410 return 0;
411 }
412
413 #endif // USE_PARALLEL
414