1 /*
2 pl.c - Pocket Linker support for uCON64
3
4 Copyright (c) 2004 Walter van Niftrik <w.f.b.w.v.niftrik@stud.tue.nl>
5 Partly based on PokeLink - Copyright (c) Dark Fader / BlackThunder
6 Portions copyright (c) 2004 - 2005, 2015 - 2017, 2020 - 2021 dbjh
7
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 */
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #ifdef _MSC_VER
27 #pragma warning(push)
28 #pragma warning(disable: 4668) // 'symbol' is not defined as a preprocessor macro, replacing with '0' for 'directives'
29 #endif
30 #include <stdlib.h>
31 #ifdef _MSC_VER
32 #pragma warning(pop)
33 #endif
34 #include <string.h>
35 #include "misc/archive.h"
36 #include "ucon64.h"
37 #include "ucon64_misc.h"
38 #include "backup/pl.h"
39
40
41 #ifdef USE_PARALLEL
42 static st_ucon64_obj_t pl_obj[] =
43 {
44 {UCON64_NGP, WF_DEFAULT | WF_STOP | WF_NO_ROM},
45 {UCON64_NGP, WF_STOP | WF_NO_ROM},
46 {UCON64_NGP, WF_SWITCH}
47 };
48 #endif
49
50 const st_getopt2_t pl_usage[] =
51 {
52 {
53 NULL, 0, 0, 0,
54 NULL, "Pocket Linker"/*"19XX Bung Enterprises Ltd"*/,
55 NULL
56 },
57 #ifdef USE_PARALLEL
58 {
59 "xpl", 0, 0, UCON64_XPL,
60 NULL, "send/receive ROM to/from Pocket Linker; " OPTION_LONG_S "port" OPTARG_S "PORT\n"
61 "receives automatically when ROM does not exist",
62 &pl_obj[0]
63 },
64 {
65 "xpli", 0, 0, UCON64_XPLI,
66 NULL, "show information about inserted cartridge; " OPTION_LONG_S "port" OPTARG_S "PORT",
67 &pl_obj[1]
68 },
69 {
70 "xplm", 0, 0, UCON64_XPLM,
71 NULL, "use SPP mode, default is EPP mode",
72 &pl_obj[2]
73 },
74 #endif // USE_PARALLEL
75 {NULL, 0, 0, 0, NULL, NULL, NULL}
76 };
77
78
79 #ifdef USE_PARALLEL
80
81 // flash unlock addresses with chip select
82 #define fx0002aa(A) (((A) & 0x200000) | 0x0002aa)
83 #define fx000555(A) (((A) & 0x200000) | 0x000555)
84 #define fx000aaa(A) (((A) & 0x200000) | 0x000aaa)
85 #define fx002aaa(A) (((A) & 0x200000) | 0x002aaa)
86 #define fx005555(A) (((A) & 0x200000) | 0x005555)
87
88 #define set_data_read outportb (port_a, 0);
89 #define set_data_write outportb (port_a, 1);
90 #define reset_port outportb (port_a, 4);
91
92 #define CMD_READ 0xf0
93 #define CMD_INFO 0x90
94 #define CMD_ERASE 0x80
95
96 #define TYPE_BW 0x00
97 #define TYPE_COLOR 0x01
98 #define TYPE_MULTI 0x02
99
100 static unsigned short port_8, port_9, port_a, port_b, port_c;
101 static int current_ai;
102 static unsigned char ai_value[4];
103
104
105 static void
epp_write_data(unsigned char data)106 epp_write_data (unsigned char data)
107 {
108 outportb (port_c, data);
109 }
110
111
112 static void
spp_write_data(unsigned char data)113 spp_write_data (unsigned char data)
114 {
115 outportb (port_8, data);
116 outportb (port_a, 3);
117 outportb (port_a, 1);
118 }
119
120
121 static void
write_data(unsigned char data)122 write_data (unsigned char data)
123 {
124 ai_value[current_ai] = data;
125 if (ucon64.parport_mode != PPMODE_EPP)
126 spp_write_data (data);
127 else
128 epp_write_data (data);
129 }
130
131
132 static unsigned char
epp_read_data(void)133 epp_read_data (void)
134 {
135 return inportb (port_c);
136 }
137
138
139 static unsigned char
spp_read_data(void)140 spp_read_data (void)
141 {
142 unsigned char byte;
143
144 outportb (port_a, 2);
145 byte = (inportb (port_9) >> 3) & 0x0f;
146 outportb (port_a, 6);
147 byte |= (inportb (port_9) << 1) & 0xf0;
148 outportb (port_a, 0);
149
150 return byte;
151 }
152
153
154 static unsigned char
read_data(void)155 read_data (void)
156 {
157 if (ucon64.parport_mode != PPMODE_EPP)
158 return spp_read_data ();
159 else
160 return epp_read_data ();
161 }
162
163
164 static void
epp_set_ai(unsigned char ai)165 epp_set_ai (unsigned char ai)
166 {
167 current_ai = ai;
168 outportb (port_b, ai);
169 }
170
171
172 static void
spp_set_ai(unsigned char ai)173 spp_set_ai (unsigned char ai)
174 {
175 current_ai = ai;
176 outportb (port_8, ai);
177 outportb (port_a, 9);
178 outportb (port_a, 1);
179 }
180
181
182 static void
set_ai(unsigned char ai)183 set_ai (unsigned char ai)
184 {
185 if (ucon64.parport_mode != PPMODE_EPP)
186 spp_set_ai (ai);
187 else
188 epp_set_ai (ai);
189 }
190
191
192 static void
epp_set_ai_data(unsigned char ai,unsigned char data)193 epp_set_ai_data (unsigned char ai, unsigned char data)
194 {
195 epp_set_ai (ai);
196 epp_write_data (data);
197 }
198
199
200 static void
spp_set_ai_data(unsigned char ai,unsigned char data)201 spp_set_ai_data (unsigned char ai, unsigned char data)
202 {
203 spp_set_ai (ai);
204 spp_write_data (data);
205 }
206
207
208 static void
set_ai_data(unsigned char ai,unsigned char data)209 set_ai_data (unsigned char ai, unsigned char data)
210 {
211 if (ucon64.parport_mode != PPMODE_EPP)
212 spp_set_ai_data (ai, data);
213 else
214 epp_set_ai_data (ai, data);
215 }
216
217
218 static void
init_port(void)219 init_port (void)
220 {
221 parport_reset_timeout (port_8);
222 set_data_write
223 set_ai_data (2, 0);
224 }
225
226
227 static void
end_port(void)228 end_port (void)
229 {
230 set_data_write
231 set_ai_data (2, 0);
232 reset_port
233 }
234
235
236 static int
detect_linker(void)237 detect_linker (void)
238 {
239 init_port ();
240 set_data_write
241 set_ai_data (1, 0x12);
242 set_ai_data (0, 0x34);
243 set_ai (1);
244 set_data_read
245 if (read_data () != 0x12)
246 return 0;
247 set_data_write
248 set_ai (0);
249 set_data_read
250 if (read_data () != 0x34)
251 return 0;
252 end_port ();
253 return 1;
254 }
255
256
257 static void
select_address(unsigned int addr,int inc)258 select_address (unsigned int addr, int inc)
259 {
260 unsigned char data = (((addr >> 14) & 0x3c) | ((addr >> 13) & 0x80) |
261 (inc ? 0x01 : 0x00)); // a[20..16], auto-increment
262
263 if (data != ai_value[2])
264 set_ai_data (2, data);
265 set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
266 set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
267 }
268
269
270 static void
write_address_data(unsigned int addr,unsigned char data)271 write_address_data (unsigned int addr, unsigned char data)
272 {
273 select_address (addr, 0);
274 set_ai_data (3, data);
275 }
276
277
278 static void
send_command(unsigned char cmd)279 send_command (unsigned char cmd)
280 {
281 set_data_write
282 write_address_data (0x5555, 0xaa);
283 write_address_data (0x2aaa, 0x55);
284 write_address_data (0x5555, cmd);
285 }
286
287
288 static void
reset_read(void)289 reset_read (void)
290 {
291 send_command (CMD_READ);
292 }
293
294
295 static unsigned char
read_ai3_data(void)296 read_ai3_data (void)
297 {
298 set_ai (3);
299 set_data_read
300 return read_data ();
301 }
302
303
304 static int
detect_chip(void)305 detect_chip (void)
306 {
307 int ai;
308 unsigned char info[4];
309
310 reset_read ();
311 reset_read ();
312 reset_read ();
313 send_command (CMD_INFO);
314 for (ai = 0; ai < 4; ai++)
315 {
316 set_data_write
317 select_address (ai, 0);
318 info[ai] = read_ai3_data ();
319 }
320 reset_read ();
321 if (((info[0] & 0x90) == 0x90) && (info[2] == 0x01) && (info[3] & 0x80))
322 return 1;
323 else
324 return 0;
325 }
326
327
328 static void
select_chip(unsigned int addr)329 select_chip (unsigned int addr)
330 {
331 set_data_write
332 set_ai_data (2, 2);
333 set_ai_data (3, (unsigned char) ((addr & 0x200000) ? 1 : 2));
334 set_ai_data (2, 0);
335 }
336
337
338 static unsigned int
cart_size(void)339 cart_size (void)
340 {
341 select_chip (0x000000);
342 if (!detect_chip ())
343 return 0; // no cartridge found
344 select_chip (0x200000);
345 if (!detect_chip ())
346 return 0x200000; // 16 megabit
347 return 0x400000; // 32 megabit
348 }
349
350
351 static void
read_blocks(unsigned int addr,unsigned char * buf,int blocks)352 read_blocks (unsigned int addr, unsigned char *buf, int blocks)
353 {
354 int block, i, offset = 0;
355
356 select_chip (addr);
357 for (block = 0; block < blocks; block++)
358 {
359 set_data_write
360 select_address (addr | (block << 8), 1);
361 set_ai (3);
362 set_data_read
363 for (i = 0; i < 0x100; i++)
364 buf[offset++] = read_data ();
365 }
366 }
367
368
369 static int
is_erased(unsigned char * buf,unsigned int len)370 is_erased (unsigned char *buf, unsigned int len)
371 {
372 unsigned int i;
373
374 for (i = 0; i < len; i++)
375 if (buf[i] != 0xff)
376 return 0;
377
378 return 1;
379 }
380
381
382 static int
is_header(unsigned char * buf)383 is_header (unsigned char *buf)
384 {
385 char msg[0x1d];
386
387 #if defined __GNUC__ && __GNUC__ >= 8
388 #pragma GCC diagnostic push
389 #pragma GCC diagnostic ignored "-Wstringop-truncation"
390 #endif
391 strncpy (msg, (char *) buf, 0x1c)[0x1c] = '\0';
392 #if defined __GNUC__ && __GNUC__ >= 8
393 #pragma GCC diagnostic pop
394 #endif
395 if (strstr (msg, "COPYRIGHT") || strstr (msg, "SNK") ||
396 strstr (msg, "LICENSED") || strstr (msg, "CORPORATION"))
397 return 1; // header found
398
399 return 0; // other data found
400 }
401
402
403 static int
same_header(unsigned char * header,unsigned char * buf)404 same_header (unsigned char *header, unsigned char *buf)
405 {
406 return (!memcmp (header, buf, 0x100));
407 }
408
409
410 static unsigned int
game_info(unsigned int cart_size,char name[13],int * type)411 game_info (unsigned int cart_size, char name[13], int *type)
412 {
413 unsigned char header[0x100], buf[0x8000];
414
415 select_chip (0x000000);
416 read_blocks (0x000000, header, 1);
417
418 if (!is_header (header))
419 return 0; // no game found
420
421 if (name)
422 #if defined __GNUC__ && __GNUC__ >= 8
423 #pragma GCC diagnostic push
424 #pragma GCC diagnostic ignored "-Wstringop-truncation"
425 #endif
426 strncpy (name, (char *) (header + 0x24), 12)[12] = '\0';
427 #if defined __GNUC__ && __GNUC__ >= 8
428 #pragma GCC diagnostic pop
429 #endif
430
431 if (type)
432 {
433 if (name && strstr (name, "Multi"))
434 *type = TYPE_MULTI;
435 else if (header[0x23] == 0x10)
436 *type = TYPE_COLOR;
437 else
438 *type = TYPE_BW;
439 }
440
441 read_blocks (0x080000, buf, 128);
442 if ((same_header (buf, header)) || is_erased (buf, 0x8000))
443 return 0x080000; // 4 megabit
444
445 read_blocks (0x100000, buf, 128);
446 if ((same_header (buf, header)) || is_erased (buf, 0x8000))
447 return 0x100000; // 8 megabit
448
449 if (cart_size == 0x400000)
450 {
451 read_blocks (0x200000, buf, 128);
452 if (is_erased (buf, 0x8000))
453 return 0x200000; // 16 megabit
454 return 0x400000; // 32 megabit
455 }
456 return 0x200000; // 16 megabit
457 }
458
459
460 static void
deinit_io(void)461 deinit_io (void)
462 {
463 end_port ();
464 }
465
466
467 static void
init_io(unsigned short port)468 init_io (unsigned short port)
469 {
470 port_8 = port;
471 port_9 = port + 1;
472 port_a = port + 2;
473 port_b = port + 3;
474 port_c = port + 4;
475
476 parport_print_info ();
477
478 if (!detect_linker ())
479 {
480 ucon64.parport_mode = parport_setup (port_8, PPMODE_SPP);
481 if (!detect_linker ())
482 {
483 fputs ("ERROR: Pocket Linker not found or not turned on\n", stderr);
484 deinit_io ();
485 exit (1);
486 }
487 }
488
489 // If we get here, a Pocket Linker was detected
490 if (ucon64.parport_mode == PPMODE_EPP)
491 puts ("Pocket Linker found. EPP found");
492 else
493 puts ("Pocket Linker found. EPP not found or not enabled - SPP used");
494 }
495
496
497 static void
set_address(unsigned int addr,int inc)498 set_address (unsigned int addr, int inc)
499 {
500 set_ai_data (0, (unsigned char) (addr & 0xff)); // a[7..0]
501 set_ai_data (1, (unsigned char) ((addr >> 8) & 0xff)); // a[15..8]
502 set_ai_data (2, 0x02); // latch chip select
503 set_ai_data (3, (unsigned char) ~(1 << (addr >> 21))); // a[23..21]
504 set_ai_data (2, (unsigned char) ((((addr >> 16) & 0x0f) << 2) | // a[20..16], auto-increment
505 (((addr >> 20) & 0x01) << 7) |
506 (inc ? 0x01 : 0x00)));
507 set_ai (3);
508 }
509
510
511 static int
program(unsigned int addr,unsigned char data,int retries)512 program (unsigned int addr, unsigned char data, int retries)
513 {
514 int to = 10000;
515
516 set_data_write
517 set_address (fx005555 (addr), 0); // program byte
518 write_data (0xaa);
519 set_address (fx002aaa (addr), 0);
520 write_data (0x55);
521 set_address (fx005555 (addr), 0);
522 write_data (0xa0);
523 set_address (addr, 0);
524 write_data (data);
525
526 set_data_read
527 while (to--)
528 {
529 unsigned char s = read_data ();
530 if ((s & 128) == 0)
531 return 0; // OK
532 if (s & 32)
533 {
534 s = read_data ();
535 if ((s & 128) == 0)
536 return 0; // OK
537 if (data == read_data ())
538 return 0; // OK
539 }
540 }
541
542 set_data_write
543 set_address (addr, 0);
544 set_data_read
545 if (data == read_data ())
546 return 0; // OK
547 if (retries == 0)
548 return 1; // error
549 return program (addr, data, retries - 1);
550 }
551
552
553 static int
write_block(unsigned int addr,unsigned char * buf)554 write_block (unsigned int addr, unsigned char *buf)
555 {
556 int count;
557
558 select_address (addr, 1);
559 for (count = 0; count < 0x100; count++)
560 {
561 if (buf[count] == 0xff)
562 continue; // nothing to write
563 if (program (addr + count, buf[count], 3))
564 {
565 select_address (addr + count, 0);
566 set_data_read
567 fprintf (stderr, "\nERROR: Programming failed at 0x%06x (w:0x%02x, "
568 "r:0x%02x)\n", addr + count, buf[count], read_data ());
569 return 1;
570 }
571 }
572 return 0;
573 }
574
575
576 #if 0
577 static int
578 wait_erased (void)
579 {
580 int i = 0;
581 unsigned char cur_byte, prev_byte;
582
583 prev_byte = read_ai3_data () & 0x40;
584 while (++i < 0x7ffffff)
585 {
586 cur_byte = read_data () & 0x40;
587 if (cur_byte == prev_byte)
588 return 0; // OK
589 prev_byte = cur_byte;
590 }
591 return 1; // erase error
592 }
593
594
595 static int
596 erase_chip (void)
597 {
598 reset_read ();
599 send_command (CMD_ERASE);
600 write_address_data (0x5555, 0xaa);
601 write_address_data (0x2aaa, 0x55);
602 write_address_data (0x5555, 0x10);
603 return wait_erased ();
604 }
605
606
607 static int
608 erase_cart (unsigned int size)
609 {
610 unsigned int addr;
611 unsigned char buf[0x8000];
612
613 for (addr = 0x000000; addr < size; addr += 0x200000)
614 {
615 select_chip (addr);
616 if (erase_chip ())
617 {
618 fprintf (stderr, "ERROR: Erase chip %d failed\n", addr >> 21);
619 return 1;
620 }
621
622 read_blocks (0x000000, buf, 128);
623 if (!is_erased (buf, 0x8000))
624 {
625 fprintf (stderr, "ERROR: Erase chip %d verify failed\n", addr >> 21);
626 return 1;
627 }
628 }
629 }
630 #endif
631
632
633 static int
erase(void)634 erase (void)
635 {
636 unsigned int addr;
637
638 for (addr = 0; addr < 0x400000; addr += 0x200000)
639 {
640 set_data_write
641 set_address (fx005555 (addr), 0);
642 write_data (0xaa);
643 set_address (fx002aaa (addr), 0);
644 write_data (0x55);
645 set_address (fx005555 (addr), 0);
646 write_data (0x80);
647 set_address (fx005555 (addr), 0);
648 write_data (0xaa);
649 set_address (fx002aaa (addr), 0);
650 write_data (0x55);
651 set_address (fx005555 (addr), 0);
652 write_data (0x10);
653
654 set_data_read
655 while (~read_data () & 0x80) // wait for completion
656 ;
657 }
658 return 0;
659 }
660
661
662 int
pl_read_rom(const char * filename,unsigned short parport)663 pl_read_rom (const char *filename, unsigned short parport)
664 {
665 FILE *file;
666 unsigned int blocksleft, c_size, size, address = 0;
667 unsigned char buffer[0x8000];
668 time_t starttime;
669
670 if ((file = fopen (filename, "wb")) == NULL)
671 {
672 fprintf (stderr, ucon64_msg[OPEN_WRITE_ERROR], filename);
673 exit (1);
674 }
675 init_io (parport);
676
677 c_size = cart_size ();
678
679 if (c_size == 0x00) // Check for cartridge
680 {
681 fputs ("ERROR: No cartridge detected\n", stderr);
682 deinit_io ();
683 exit (1);
684 }
685
686 size = game_info (c_size, NULL, NULL);
687
688 if (size == 0x00)
689 {
690 fputs ("ERROR: No game detected\n", stderr);
691 deinit_io ();
692 exit (1);
693 }
694
695 reset_read ();
696
697 printf ("Receive: %u Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
698
699 blocksleft = size >> 15;
700 starttime = time (NULL);
701
702 while (blocksleft-- > 0)
703 {
704 read_blocks (address, buffer, 128);
705 fwrite (buffer, 1, 0x8000, file);
706 address += 0x8000;
707 ucon64_gauge (starttime, address, size);
708 }
709
710 fclose (file);
711 deinit_io ();
712
713 return 0;
714 }
715
716
717 int
pl_write_rom(const char * filename,unsigned short parport)718 pl_write_rom (const char *filename, unsigned short parport)
719 {
720 FILE *file;
721 unsigned int size, address = 0;
722 size_t bytesread, bytessent = 0;
723 unsigned char buffer[0x100];
724 time_t starttime;
725
726 if ((file = fopen (filename, "rb")) == NULL)
727 {
728 fprintf (stderr, ucon64_msg[OPEN_READ_ERROR], filename);
729 exit (1);
730 }
731 init_io (parport);
732 size = (int) ucon64.fsize;
733
734 erase ();
735 reset_read ();
736
737 printf ("Send: %u Bytes (%.4f Mb)\n\n", size, (float) size / MBIT);
738
739 starttime = time (NULL);
740
741 while ((bytesread = fread (buffer, 1, 0x100, file)) != 0)
742 {
743 if (write_block (address, buffer))
744 break; // write failed
745 bytessent += bytesread;
746 address += 0x100;
747 ucon64_gauge (starttime, bytessent, size);
748 }
749
750 fclose (file);
751 deinit_io ();
752
753 return 0;
754 }
755
756
757 int
pl_info(unsigned short parport)758 pl_info (unsigned short parport)
759 {
760 unsigned int c_size, g_size;
761 int g_type;
762 char g_name[13];
763
764 init_io (parport);
765
766 c_size = cart_size ();
767 if (c_size == 0)
768 {
769 printf ("No cartridge found\n");
770 deinit_io ();
771 return 0;
772 }
773
774 g_size = game_info (c_size, g_name, &g_type);
775
776 if (g_size == 0)
777 printf ("No game found\n");
778 else
779 {
780 printf ("Game name: \"%s\"\n", g_name);
781 printf ("Game type: %s\n", (g_type == TYPE_COLOR) ? "Color" : "B&W");
782 printf ("Game size: %u Bytes (%.4f Mb)\n", g_size, (float) g_size / MBIT);
783 }
784 deinit_io ();
785
786 return 0;
787 }
788
789 #endif // USE_PARALLEL
790