1 /*
2 * c64tpi.c - IEEE488 interface for the C64.
3 *
4 * Written by
5 * Andre Fachat <a.fachat@physik.tu-chemnitz.de>
6 * Andreas Boose <viceteam@t-online.de>
7 *
8 * This file is part of VICE, the Versatile Commodore Emulator.
9 * See README for copyright notice.
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
24 * 02111-1307 USA.
25 *
26 */
27
28 #include "vice.h"
29
30 #include <stdio.h>
31 #include <string.h>
32
33 #include "archdep.h"
34 #include "c64.h"
35 #include "c64cart.h" /* for export_t */
36 #define CARTRIDGE_INCLUDE_SLOT0_API
37 #include "c64cartsystem.h"
38 #undef CARTRIDGE_INCLUDE_SLOT0_API
39 #include "c64mem.h"
40 #include "cartio.h"
41 #include "cartridge.h"
42 #include "cmdline.h"
43 #include "drive.h"
44 #include "export.h"
45 #include "lib.h"
46 #include "log.h"
47 #include "parallel.h"
48 #include "maincpu.h"
49 #include "monitor.h"
50 #include "resources.h"
51 #include "tpi.h"
52 #include "types.h"
53 #include "util.h"
54 #include "crt.h"
55
56 #define CARTRIDGE_INCLUDE_PRIVATE_API
57 #include "c64tpi.h"
58 #undef CARTRIDGE_INCLUDE_PRIVATE_API
59
60 /*
61 IEEE488 interface for c64 and c128
62
63 - 4kb ROM, mapped to $8000 in 8k game config
64
65 - the hardware uses a TPI at $DF00-$DF07 (mirrored through $DF08-$DFFF)
66
67 TODO: register description
68 */
69
70 /* #define DEBUGTPI */
71
72 #ifdef DEBUGTPI
73 #define DBG(x) printf x
74 #else
75 #define DBG(x)
76 #endif
77
78 #define mytpi_init tpi_init
79 #define mytpi_set_int tpi_set_int
80
81 /* 4 KB ROM */
82 #define TPI_ROM_SIZE 0x1000
83 static uint8_t *tpi_rom = NULL;
84
85 static tpi_context_t *tpi_context;
86
87 /* ---------------------------------------------------------------------*/
88 static void tpi_io2_store(uint16_t addr, uint8_t data);
89 static uint8_t tpi_io2_read(uint16_t addr);
90 static uint8_t tpi_io2_peek(uint16_t addr);
91 static int tpi_io2_dump(void);
92
93 static io_source_t tpi_io2_device = {
94 CARTRIDGE_NAME_IEEE488,
95 IO_DETACH_CART,
96 NULL,
97 0xdf00, 0xdfff, 0x07,
98 1, /* read is always valid */
99 tpi_io2_store,
100 tpi_io2_read,
101 tpi_io2_peek,
102 tpi_io2_dump,
103 CARTRIDGE_IEEE488,
104 0,
105 0
106 };
107
108 static io_source_list_t *tpi_list_item = NULL;
109
110 static const export_resource_t export_res = {
111 CARTRIDGE_NAME_IEEE488, 0, 1, NULL, &tpi_io2_device, CARTRIDGE_IEEE488
112 };
113
114 /* ---------------------------------------------------------------------*/
115
116 static int ieee488_enabled = 0;
117
118 static int tpi_extexrom = 0;
119 static int tpi_extgame = 0;
120
121 static int rom_enabled = 1;
122
tpi_cart_enabled(void)123 int tpi_cart_enabled(void)
124 {
125 return ieee488_enabled;
126 }
127
128 /* ---------------------------------------------------------------------*/
129
tpi_io2_store(uint16_t addr,uint8_t data)130 static void tpi_io2_store(uint16_t addr, uint8_t data)
131 {
132 DBG(("TPI io2 w %02x (%02x)\n", addr, data));
133 tpicore_store(tpi_context, addr, data);
134 }
135
tpi_io2_read(uint16_t addr)136 static uint8_t tpi_io2_read(uint16_t addr)
137 {
138 DBG(("TPI io2 r %02x\n", addr));
139 return tpicore_read(tpi_context, addr);
140 }
141
tpi_io2_peek(uint16_t addr)142 static uint8_t tpi_io2_peek(uint16_t addr)
143 {
144 return tpicore_peek(tpi_context, addr);
145 }
146
tpi_io2_dump(void)147 static int tpi_io2_dump(void)
148 {
149 mon_out("TPI\n");
150 tpicore_dump(tpi_context);
151 return 0;
152 }
153 /* ---------------------------------------------------------------------*/
154
tpi_roml_read(uint16_t addr,uint8_t * value)155 int tpi_roml_read(uint16_t addr, uint8_t *value)
156 {
157 if (rom_enabled) {
158 *value = tpi_rom[addr & 0xfff];
159 return CART_READ_VALID;
160 }
161 return CART_READ_THROUGH;
162 }
163
tpi_peek_mem(uint16_t addr,uint8_t * value)164 int tpi_peek_mem(uint16_t addr, uint8_t *value)
165 {
166 if ((addr >= 0x8000) && (addr <= 0x9fff)) {
167 if (rom_enabled) {
168 *value = tpi_rom[addr & 0xfff];
169 return CART_READ_VALID;
170 }
171 }
172 return CART_READ_THROUGH;
173 }
174
175 /* ---------------------------------------------------------------------*/
176
177 /*
178 Port A (ieee control)
179
180 Port B (ieee data)
181
182 Port C
183
184 bit 7 in passthrough port exrom line
185 bit 6 out (unused ?)
186 bit 5 out (unused ?)
187 bit 4 out ROML enable
188 bit 3 out expansionport exrom line
189 bit 2 out (unused ?)
190 bit 1 out IEEE (U4, Pin 12)
191 bit 0 out IEEE (U4, Pin 18)
192 */
193
set_int(unsigned int int_num,int value)194 static void set_int(unsigned int int_num, int value)
195 {
196 }
197
restore_int(unsigned int int_num,int value)198 static void restore_int(unsigned int int_num, int value)
199 {
200 }
201
set_ca(tpi_context_t * tpi_ctx,int a)202 static void set_ca(tpi_context_t *tpi_ctx, int a)
203 {
204 }
205
set_cb(tpi_context_t * tpi_ctx,int a)206 static void set_cb(tpi_context_t *tpi_ctx, int a)
207 {
208 }
209
210 static int ieee_is_dev = 1;
211 static uint8_t ieee_is_out = 1;
212
reset(tpi_context_t * tpi_ctx)213 static void reset(tpi_context_t *tpi_ctx)
214 {
215 /* assuming input after reset */
216 parallel_cpu_set_atn(0);
217 parallel_cpu_set_ndac(0);
218 parallel_cpu_set_nrfd(0);
219 parallel_cpu_set_dav(0);
220 parallel_cpu_set_eoi(0);
221 parallel_cpu_set_bus(0xff);
222
223 ieee_is_dev = 1;
224 ieee_is_out = 1;
225 }
226
store_pa(tpi_context_t * tpi_ctx,uint8_t byte)227 static void store_pa(tpi_context_t *tpi_ctx, uint8_t byte)
228 {
229 if (byte != tpi_ctx->oldpa) {
230 uint8_t tmp = ~byte;
231
232 ieee_is_dev = byte & 0x01;
233 ieee_is_out = byte & 0x02;
234
235 parallel_cpu_set_bus((uint8_t)(ieee_is_out ? tpi_ctx->oldpb : 0xff));
236
237 if (ieee_is_out) {
238 parallel_cpu_set_ndac(0);
239 parallel_cpu_set_nrfd(0);
240 parallel_cpu_set_dav((uint8_t)(tmp & 0x10));
241 parallel_cpu_set_eoi((uint8_t)(tmp & 0x20));
242 } else {
243 parallel_cpu_set_nrfd((uint8_t)(tmp & 0x80));
244 parallel_cpu_set_ndac((uint8_t)(tmp & 0x40));
245 parallel_cpu_set_dav(0);
246 parallel_cpu_set_eoi(0);
247 }
248 if (ieee_is_dev) {
249 parallel_cpu_set_atn(0);
250 } else {
251 parallel_cpu_set_atn((uint8_t)(tmp & 0x08));
252 }
253 }
254 }
255
store_pb(tpi_context_t * tpi_ctx,uint8_t byte)256 static void store_pb(tpi_context_t *tpi_ctx, uint8_t byte)
257 {
258 parallel_cpu_set_bus((uint8_t)(ieee_is_out ? byte : 0xff));
259 }
260
undump_pa(tpi_context_t * tpi_ctx,uint8_t byte)261 static void undump_pa(tpi_context_t *tpi_ctx, uint8_t byte)
262 {
263 uint8_t tmp = ~byte;
264 ieee_is_dev = byte & 0x01;
265 ieee_is_out = byte & 0x02;
266
267 parallel_cpu_set_bus((uint8_t)(ieee_is_out ? tpi_ctx->oldpb : 0xff));
268
269 if (ieee_is_out) {
270 parallel_cpu_set_ndac(0);
271 parallel_cpu_set_nrfd(0);
272 parallel_cpu_set_dav((uint8_t)(tmp & 0x10));
273 parallel_cpu_set_eoi((uint8_t)(tmp & 0x20));
274 } else {
275 parallel_cpu_set_nrfd((uint8_t)(tmp & 0x80));
276 parallel_cpu_set_ndac((uint8_t)(tmp & 0x40));
277 parallel_cpu_set_dav(0);
278 parallel_cpu_set_eoi(0);
279 }
280 if (ieee_is_dev) {
281 parallel_cpu_restore_atn(0);
282 } else {
283 parallel_cpu_restore_atn((uint8_t)(tmp & 0x08));
284 }
285 }
286
undump_pb(tpi_context_t * tpi_ctx,uint8_t byte)287 static void undump_pb(tpi_context_t *tpi_ctx, uint8_t byte)
288 {
289 parallel_cpu_set_bus((uint8_t)(ieee_is_out ? byte : 0xff));
290 }
291
store_pc(tpi_context_t * tpi_ctx,uint8_t byte)292 static void store_pc(tpi_context_t *tpi_ctx, uint8_t byte)
293 {
294 int exrom = ((byte & 0x08) ? 0 : 1); /* bit 3, 1 = active */
295 rom_enabled = ((byte & 0x10) ? 1 : 0); /* bit 4, 1 = active */
296 /* passthrough support */
297 DBG(("TPI store_pc %02x (rom enabled: %d exrom: %d game: %d)\n",
298 byte, rom_enabled, exrom ^ 1, tpi_extgame));
299 cart_config_changed_slot0((uint8_t)((exrom << 1) | tpi_extgame),
300 (uint8_t)((exrom << 1) | tpi_extgame), CMODE_READ);
301 }
302
undump_pc(tpi_context_t * tpi_ctx,uint8_t byte)303 static void undump_pc(tpi_context_t *tpi_ctx, uint8_t byte)
304 {
305 }
306
read_pa(tpi_context_t * tpi_ctx)307 static uint8_t read_pa(tpi_context_t *tpi_ctx)
308 {
309 uint8_t byte;
310
311 drive_cpu_execute_all(maincpu_clk);
312
313 byte = 0xff;
314 if (ieee_is_out) {
315 if (parallel_nrfd) {
316 byte &= 0x7f;
317 }
318 if (parallel_ndac) {
319 byte &= 0xbf;
320 }
321 } else {
322 if (parallel_dav) {
323 byte &= 0xef;
324 }
325 if (parallel_eoi) {
326 byte &= 0xdf;
327 }
328 }
329 if (ieee_is_dev) {
330 if (parallel_atn) {
331 byte &= 0xf7;
332 }
333 }
334
335 byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPA])
336 | (tpi_ctx->c_tpi[TPI_PA] & tpi_ctx->c_tpi[TPI_DDPA]);
337
338 return byte;
339 }
340
read_pb(tpi_context_t * tpi_ctx)341 static uint8_t read_pb(tpi_context_t *tpi_ctx)
342 {
343 uint8_t byte;
344
345 drive_cpu_execute_all(maincpu_clk);
346
347 byte = ieee_is_out ? 0xff : parallel_bus;
348 byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPB])
349 | (tpi_ctx->c_tpi[TPI_PB] & tpi_ctx->c_tpi[TPI_DDPB]);
350
351 return byte;
352 }
353
read_pc(tpi_context_t * tpi_ctx)354 static uint8_t read_pc(tpi_context_t *tpi_ctx)
355 {
356 uint8_t byte = 0xff;
357
358 if (tpi_extexrom) {
359 byte &= ~(1 << 7);
360 }
361 byte = (byte & ~(tpi_ctx->c_tpi)[TPI_DDPC])
362 | (tpi_ctx->c_tpi[TPI_PC] & tpi_ctx->c_tpi[TPI_DDPC]);
363 return byte;
364 }
365
366 /* ---------------------------------------------------------------------*/
367
tpi_reset(void)368 void tpi_reset(void)
369 {
370 DBG(("TPI: tpi_reset\n"));
371 tpicore_reset(tpi_context);
372 cart_config_changed_slot0(CMODE_8KGAME, CMODE_8KGAME, CMODE_READ);
373 rom_enabled = 1;
374 }
375
tpi_init(void)376 void tpi_init(void)
377 {
378 tpi_context->log = log_open(tpi_context->myname);
379 }
380
tpi_shutdown(void)381 void tpi_shutdown(void)
382 {
383 tpicore_shutdown(tpi_context);
384 }
385
tpi_setup_context(machine_context_t * machine_ctx)386 void tpi_setup_context(machine_context_t *machine_ctx)
387 {
388 tpi_context = lib_malloc(sizeof(tpi_context_t));
389
390 tpi_context->prv = NULL;
391
392 tpi_context->context = (void *)machine_ctx;
393
394 tpi_context->rmw_flag = &maincpu_rmw_flag;
395 tpi_context->clk_ptr = &maincpu_clk;
396
397 tpi_context->myname = lib_msprintf("TPI");
398
399 tpicore_setup_context(tpi_context);
400
401 tpi_context->store_pa = store_pa;
402 tpi_context->store_pb = store_pb;
403 tpi_context->store_pc = store_pc;
404 tpi_context->read_pa = read_pa;
405 tpi_context->read_pb = read_pb;
406 tpi_context->read_pc = read_pc;
407 tpi_context->undump_pa = undump_pa;
408 tpi_context->undump_pb = undump_pb;
409 tpi_context->undump_pc = undump_pc;
410 tpi_context->reset = reset;
411 tpi_context->set_ca = set_ca;
412 tpi_context->set_cb = set_cb;
413 tpi_context->set_int = set_int;
414 tpi_context->restore_int = restore_int;
415 }
416
tpi_passthrough_changed(export_t * ex)417 void tpi_passthrough_changed(export_t *ex)
418 {
419 tpi_extexrom = ex->exrom;
420 tpi_extgame = ex->game;
421 DBG(("IEEE488 passthrough changed exrom: %d game: %d\n", tpi_extexrom, tpi_extgame));
422
423 cart_set_port_game_slot0(tpi_extgame);
424 cart_port_config_changed_slot0();
425 }
426
427 /* ---------------------------------------------------------------------*/
428
429 static char *ieee488_filename = NULL;
430
set_ieee488_enabled(int value,void * param)431 static int set_ieee488_enabled(int value, void *param)
432 {
433 int val = value ? 1 : 0;
434
435 DBG(("IEEE: set_enabled: (%p) '%s' %d to %d\n", param, ieee488_filename, ieee488_enabled, val));
436 if (ieee488_enabled && !val) {
437 cart_power_off();
438 #ifdef DEBUGTPI
439 if (tpi_list_item == NULL) {
440 DBG(("IEEE: BUG: ieee488_enabled == 1 and tpi_list_item == NULL ?!\n"));
441 }
442 #endif
443 lib_free(tpi_rom);
444 tpi_rom = NULL;
445 export_remove(&export_res);
446 io_source_unregister(tpi_list_item);
447 tpi_list_item = NULL;
448 ieee488_enabled = 0;
449 DBG(("IEEE: set_enabled unregistered\n"));
450 } else if (!ieee488_enabled && val) {
451 if (tpi_rom == NULL) {
452 tpi_rom = lib_malloc(TPI_ROM_SIZE);
453 }
454 if (param) {
455 /* if the param is != NULL, then we should load the default image file */
456 if (ieee488_filename) {
457 if (*ieee488_filename) {
458 DBG(("IEEE: attach default image\n"));
459 if (cartridge_attach_image(CARTRIDGE_IEEE488, ieee488_filename) < 0) {
460 DBG(("IEEE: set_enabled did not register\n"));
461 lib_free(tpi_rom);
462 tpi_rom = NULL;
463 return -1;
464 }
465 /* ieee488_enabled = 1; */ /* cartridge_attach_image will end up calling set_ieee488_enabled again */
466 return 0;
467 }
468 }
469 } else {
470 cart_power_off();
471 /* if the param is == NULL, then we should actually set the resource */
472 if (export_add(&export_res) < 0) {
473 DBG(("IEEE: set_enabled did not register\n"));
474 lib_free(tpi_rom);
475 tpi_rom = NULL;
476 return -1;
477 } else {
478 DBG(("IEEE: set_enabled registered\n"));
479 tpi_list_item = io_source_register(&tpi_io2_device);
480 ieee488_enabled = 1;
481 }
482 }
483 }
484
485 DBG(("IEEE: set_enabled done: '%s' %d : %d\n", ieee488_filename, val, ieee488_enabled));
486 return 0;
487 }
488
set_ieee488_filename(const char * name,void * param)489 static int set_ieee488_filename(const char *name, void *param)
490 {
491 int enabled;
492
493 if (name != NULL && *name != '\0') {
494 if (util_check_filename_access(name) < 0) {
495 return -1;
496 }
497 }
498 DBG(("IEEE: set_name: %d '%s'\n", ieee488_enabled, ieee488_filename));
499
500 util_string_set(&ieee488_filename, name);
501 resources_get_int("IEEE488", &enabled);
502
503 if (set_ieee488_enabled(enabled, (void*)1) < 0) {
504 lib_free(ieee488_filename);
505 ieee488_filename = NULL;
506 DBG(("IEEE: set_name done: %d '%s'\n", ieee488_enabled, ieee488_filename));
507 return -1;
508 }
509
510 DBG(("IEEE: set_name done: %d '%s'\n", ieee488_enabled, ieee488_filename));
511 return 0;
512 }
513
514 static const resource_string_t resources_string[] = {
515 { "IEEE488Image", "", RES_EVENT_NO, NULL,
516 &ieee488_filename, set_ieee488_filename, NULL },
517 RESOURCE_STRING_LIST_END
518 };
519
520 static const resource_int_t resources_int[] = {
521 { "IEEE488", 0, RES_EVENT_SAME, NULL,
522 &ieee488_enabled, set_ieee488_enabled, (void *)1 },
523 RESOURCE_INT_LIST_END
524 };
525
tpi_resources_init(void)526 int tpi_resources_init(void)
527 {
528 if (resources_register_string(resources_string) < 0) {
529 return -1;
530 }
531 return resources_register_int(resources_int);
532 }
533
tpi_resources_shutdown(void)534 void tpi_resources_shutdown(void)
535 {
536 lib_free(ieee488_filename);
537 ieee488_filename = NULL;
538 }
539
540 /* ------------------------------------------------------------------------- */
541
542 static const cmdline_option_t cmdline_options[] =
543 {
544 { "-ieee488", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
545 NULL, NULL, "IEEE488", (resource_value_t)1,
546 NULL, "Enable the IEEE488 interface emulation" },
547 { "+ieee488", SET_RESOURCE, CMDLINE_ATTRIB_NONE,
548 NULL, NULL, "IEEE488", (resource_value_t)0,
549 NULL, "Disable the IEEE488 interface emulation" },
550 { "-ieee488image", SET_RESOURCE, CMDLINE_ATTRIB_NEED_ARGS,
551 NULL, NULL, "IEEE488Image", NULL,
552 "<Name>", "specify IEEE488 interface image name" },
553 CMDLINE_LIST_END
554 };
555
tpi_cmdline_options_init(void)556 int tpi_cmdline_options_init(void)
557 {
558 return cmdline_register_options(cmdline_options);
559 }
560
561 /* ---------------------------------------------------------------------*/
562
tpi_get_file_name(void)563 const char *tpi_get_file_name(void)
564 {
565 return ieee488_filename;
566 }
567
tpi_config_setup(uint8_t * rawcart)568 void tpi_config_setup(uint8_t *rawcart)
569 {
570 DBG(("TPI: config_setup\n"));
571 memcpy(tpi_rom, rawcart, TPI_ROM_SIZE);
572 }
573
tpi_mmu_translate(unsigned int addr,uint8_t ** base,int * start,int * limit)574 int tpi_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit)
575 {
576 if (rom_enabled) {
577 switch (addr & 0xf000) {
578 case 0x9000:
579 *base = tpi_rom - 0x9000;
580 *start = 0x9000;
581 *limit = 0x9ffd;
582 return CART_READ_VALID;
583 case 0x8000:
584 *base = tpi_rom - 0x8000;
585 *start = 0x8000;
586 *limit = 0x8ffd;
587 return CART_READ_VALID;
588 default:
589 break;
590 }
591 }
592 return CART_READ_THROUGH;
593 }
594
tpi_config_init(export_t * ex)595 void tpi_config_init(export_t *ex)
596 {
597 DBG(("TPI: tpi_config_init\n"));
598
599 tpi_extexrom = ex->exrom;
600 tpi_extgame = ex->game;
601
602 cart_set_port_exrom_slot0(1);
603 cart_set_port_game_slot0(tpi_extgame);
604 cart_port_config_changed_slot0();
605 rom_enabled = 1;
606 }
607
tpi_common_attach(void)608 static int tpi_common_attach(void)
609 {
610 DBG(("TPI: tpi_common_attach\n"));
611 return set_ieee488_enabled(1, NULL);
612 }
613
tpi_bin_attach(const char * filename,uint8_t * rawcart)614 int tpi_bin_attach(const char *filename, uint8_t *rawcart)
615 {
616 DBG(("TPI: tpi_bin_attach\n"));
617
618 if (util_file_load(filename, rawcart, TPI_ROM_SIZE, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) {
619 return -1;
620 }
621 return tpi_common_attach();
622 }
623
tpi_crt_attach(FILE * fd,uint8_t * rawcart)624 int tpi_crt_attach(FILE *fd, uint8_t *rawcart)
625 {
626 crt_chip_header_t chip;
627
628 if (crt_read_chip_header(&chip, fd)) {
629 return -1;
630 }
631
632 if (chip.size != TPI_ROM_SIZE) {
633 return -1;
634 }
635
636 if (crt_read_chip(rawcart, 0, &chip, fd)) {
637 return -1;
638 }
639
640 return tpi_common_attach();
641 }
642
tpi_detach(void)643 void tpi_detach(void)
644 {
645 set_ieee488_enabled(0, NULL);
646 }
647
tpi_enable(void)648 int tpi_enable(void)
649 {
650 return set_ieee488_enabled(1, (void*)1);
651 }
652
tpi_disable(void)653 int tpi_disable(void)
654 {
655 return set_ieee488_enabled(0, (void*)1);
656 }
657
658
659 /* ---------------------------------------------------------------------*/
660
tpi_snapshot_read_module(struct snapshot_s * s)661 int tpi_snapshot_read_module(struct snapshot_s *s)
662 {
663 if (tpicore_snapshot_read_module(tpi_context, s) < 0) {
664 ieee488_enabled = 0;
665 return -1;
666 } else {
667 ieee488_enabled = 1;
668 }
669 return 0;
670 }
671
tpi_snapshot_write_module(struct snapshot_s * s)672 int tpi_snapshot_write_module(struct snapshot_s *s)
673 {
674 if (tpicore_snapshot_write_module(tpi_context, s) < 0) {
675 return -1;
676 }
677 return 0;
678 }
679