diff --git a/vice/doc/vice.texi b/vice/doc/vice.texi index 914f46d1fd..a0dcf2a490 100644 --- a/vice/doc/vice.texi +++ b/vice/doc/vice.texi @@ -9767,6 +9767,8 @@ Super Snapshot V5 @item Turtle Graphics II @item +Universal Cartridge +@item Warp Speed @item Westermann Learning @@ -10140,6 +10142,12 @@ The following cartridge types are valid: 78: Partner 64 @item 79: Hyper-BASIC +@item +80: Universal Cartridge 1 +@item +81: Universal Cartridge 1.5 +@item +82: Universal Cartridge 2 @end itemize @vindex CartridgeFile @@ -11481,6 +11489,18 @@ Attach raw 16KiB Stardos cartridge image. @item -cartturtle Attach raw 16KiB Turtle Graphics II cartridge image. +@findex -cartuc1 +@item -cartuc1 +Attach raw 128KiB Universal Cartridge 1 image. + +@findex -cartuc15 +@item -cartuc15 +Attach raw 512KiB Universal Cartridge 1.5 image. + +@findex -cartuc2 +@item -cartuc2 +Attach raw 512KiB Universal Cartridge 2 image. + @findex -cartwl @item -cartwl Attach raw 16KiB Westermann Learning cartridge image. @@ -23038,6 +23058,12 @@ Super Snapshot V5 .crt file Stardos .crt file @item turtle Turtle Graphics II .crt file +@item uc1 +Universal Cartridge 1 .crt file +@item uc15 +Universal Cartridge 1.5 .crt file +@item uc2 +Universal Cartridge 2 .crt file @item wl Westermann Learning .crt file @item ws @@ -29723,6 +29749,12 @@ $0010- xxxx - ROM data @tab Partner 64 @item 79 @tab Hyper-BASIC +@item 80 +@tab Universal Cartridge 1 +@item 81 +@tab Universal Cartridge 1.5 +@item 82 +@tab Universal Cartridge 2 @end multitable (*Note: Ocean type 1 includes Navy Seals, Robocop 2 & 3, Shadow of the Beast, @@ -32676,7 +32708,7 @@ rom bank 0x00 - 0x03 (0x04) 8192* 4 32KiB mapped to e000 MC6821 registers mapped to io2 at dfc0..dfc4 - press reset and hold delete to get the main menu -- press reset and hold control to skip cbm80 check +- press reset and hold control to skip cbm80 check (dont start additional cartridge) - press RESTORE, then... @@ -33248,7 +33280,7 @@ and runs the original sd2iec firmware. @example 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- -0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE +0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 46 01 00 00 00 00 00 00 00 ...@@...F........ 0020: 4d 55 4c 54 49 4d 41 58 00 00 00 00 00 00 00 00 MULTIMAX........ 0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ @@ -33612,7 +33644,7 @@ the IO lines all the time. @end example This cartridge type was found in an argentinian H.E.R.O. clone cartridge, - ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. + ROM memory is organized in 8KiB ($2000) banks located at $8000-$9FFF. There appears to be one register mirrored over IO2 (the software uses $DFFF). Banks are selected by writing to the lower 2 bits of the register, bit 5 disables the cartridge. @@ -33664,7 +33696,7 @@ the IO lines all the time. @example 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII ----------------------------------------------- ---------------- -0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE +0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE 0010: 00 00 00 40 01 00 00 4c 00 01 00 00 00 00 00 00 ...@...L........ 0020: 48 45 53 20 54 75 72 74 6c 65 20 47 72 61 70 68 HES Turtle Graph 0030: 69 63 73 20 49 49 00 00 00 00 00 00 00 00 00 00 ics II.......... @@ -33716,7 +33748,7 @@ incorrect, any further information and/or corrections are appreciated. When the cart starts, the first half of the active ROM is banked to ROML ($8000-$9fff). When reading from the I/O-2 range the second half of the active ROM bank is enabled in RMH ($A000-$BFFF). When reading from the I/O-1 range the cart is -disabled. +disabled. When a freeze happens the first half of the ROM is mapped to ROML ($8000-$9FFF) and the second half to ROMH ($E000-$FFFF). @@ -33819,6 +33851,191 @@ E0C0: 2C CA 91 AD 0A 03 AE 0B 03 8D B8 02 8E B9 02 A9 ,............... bit 6 and/or 7 - _EXROM, 0 = make cart visible @end example +@c @node FIXME +@subsubsection 80 - Universal Cartridge 1 + +@multitable @columnfractions .3 .7 +@item Size +@tab 32KiB, 64KiB or 128KiB sizes (2 to 8 banks of 16KiB each) +@item EXROM +@tab active (lo) (0) +@item GAME +@tab inactive (lo) (0) +@item Startup mode +@tab 16KiB Game +@item Load address +@tab (banks 00-07) - $8000-BFFF +@end multitable + +@example + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII + ----------------------------------------------- ---------------- +0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE +0010: 00 00 00 40 01 00 00 50 00 00 01 00 00 00 00 00 ...@@........... +0020: 75 63 2d 6c 4f 41 44 45 52 00 00 00 00 00 00 00 uc-lOADER....... +0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . +0050: 19 80 9e 82 c3 c2 cd 38 30 4c 55 84 4c 64 84 4c .......80... .. +.. +2050: 43 48 49 50 00 00 20 10 00 02 00 00 a0 00 20 00 CHIP.. ....... . +2060: 00 3F 0A 01 00 86 4E 24 28 31 30 29 3A 4A 4F 59 .?....N$(10):JOY +.. +4060: 43 48 49 50 00 00 20 10 00 02 00 01 80 00 20 00 CHIP.. ....... . +4070: 00 8B C9 28 4E 24 2C 31 29 B3 B1 22 FF 22 A7 32 ...(N$,1)..".".2 +.. +6070: 43 48 49 50 00 00 20 10 00 02 00 01 a0 00 20 00 CHIP.. ....... . +6080: AE 01 83 33 2C 37 2C 22 32 29 20 44 45 4C 20 4B ...3,7,"2) DEL K +@end example + + This cartridge type has up to 128K ROM memory and 32K SRAM memory. Each + Bank is organized in 16KiB ($4000), banks are located at $8000-$BFFF. + Bank switching is done by writing the bank number to $DE00 (Bit 0 to 2). + +@example + Register at IO1 ($DE00): + Bit 0-2 bank number + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - ROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) + + UC1 Documentation: + https://oe7twj.at/index.php?title=Universal_Cartridge_1 +@end example + + In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to + 0 to indicate the RESET/power-up configuration of 16 KiB ROM. + + There is a Windows Tool which can create RAW Image file and UC1 CRT file. + The content of the image file is configurable using a CSV file. + + Since UC1 cartridge can set /EXROM and /GAME signal, all known C64 basic + configurations for cartridges (Off, 8K, 16K, UltiMax) are configurable. + + Cartridge memory can be either ROM or SRAM. + SRAM can be protected, so it appears as ROM memory. + IO Register can be disabled, so configuration cannot be overwritten. + Basic CRT files (8K, 16K, UltiMax) can be loaded into UC1 SRAM from + ROM or Disk and ececuted by a Reset. + + +@c @node FIXME +@subsubsection 81 - Universal Cartridge 1.5 + +@multitable @columnfractions .3 .7 +@item Size +@tab 128KiB, 256KiB or 512KiB sizes (8 to 32 banks of 16KiB each) +@item EXROM +@tab active (lo) (0) +@item GAME +@tab inactive (lo) (0) +@item Startup mode +@tab 16KiB Game +@item Load address +@tab (banks 00-07) - $8000-BFFF +@end multitable + +@example + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII + ----------------------------------------------- ---------------- +0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE +0010: 00 00 00 40 01 00 00 51 00 00 01 00 00 00 00 00 ...@@........... +0020: 75 63 2d 6c 4f 41 44 45 52 00 00 00 00 00 00 00 uc-lOADER....... +0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . +0050: 19 80 9e 82 c3 c2 cd 38 30 4c 55 84 4c 64 84 4c .......80... .. +.. +2050: 43 48 49 50 00 00 20 10 00 02 00 00 a0 00 20 00 CHIP.. ....... . +2060: 00 3F 0A 01 00 86 4E 24 28 31 30 29 3A 4A 4F 59 .?....N$(10):JOY +.. +4060: 43 48 49 50 00 00 20 10 00 02 00 01 80 00 20 00 CHIP.. ....... . +4070: 00 8B C9 28 4E 24 2C 31 29 B3 B1 22 FF 22 A7 32 ...(N$,1)..".".2 +.. +6070: 43 48 49 50 00 00 20 10 00 02 00 01 a0 00 20 00 CHIP.. ....... . +6080: AE 01 83 33 2C 37 2C 22 32 29 20 44 45 4C 20 4B ...3,7,"2) DEL K +@end example + + This cartridge has nearly the same hardware spec as an UC2 cartridge. + The difference is in the hardware components. + UC2 is controlled by an CPLD and UC15 uses GAL and TTL. + + From the software side the difference is: + UC2 can read back the register values. + UC15 cannot readback cause register are simple TTL FF. + + +@c @node FIXME +@subsubsection 82 - Universal Cartridge 2 + +@multitable @columnfractions .3 .7 +@item Size +@tab 128KiB, 256KiB or 512KiB sizes (8 to 32 banks of 16KiB each) +@item EXROM +@tab active (lo) (0) +@item GAME +@tab inactive (lo) (0) +@item Startup mode +@tab 16KiB Game +@item Load address +@tab (banks 00-07) - $8000-BFFF +@end multitable + +@example + 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F ASCII + ----------------------------------------------- ---------------- +0000: 43 36 34 20 43 41 52 54 52 49 44 47 45 20 20 20 C64 CARTRIDGE +0010: 00 00 00 40 01 00 00 52 00 00 01 00 00 00 00 00 ...@@........... +0020: 75 63 2d 6c 4f 41 44 45 52 00 00 00 00 00 00 00 uc-lOADER....... +0030: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................ +0040: 43 48 49 50 00 00 20 10 00 02 00 00 80 00 20 00 CHIP.. ....... . +0050: 19 80 9e 82 c3 c2 cd 38 30 4c 55 84 4c 64 84 4c .......80... .. +.. +2050: 43 48 49 50 00 00 20 10 00 02 00 00 a0 00 20 00 CHIP.. ....... . +2060: 00 3F 0A 01 00 86 4E 24 28 31 30 29 3A 4A 4F 59 .?....N$(10):JOY +.. +4060: 43 48 49 50 00 00 20 10 00 02 00 01 80 00 20 00 CHIP.. ....... . +4070: 00 8B C9 28 4E 24 2C 31 29 B3 B1 22 FF 22 A7 32 ...(N$,1)..".".2 +.. +6070: 43 48 49 50 00 00 20 10 00 02 00 01 a0 00 20 00 CHIP.. ....... . +6080: AE 01 83 33 2C 37 2C 22 32 29 20 44 45 4C 20 4B ...3,7,"2) DEL K +@end example + + This cartridge type has up to 512K ROM memory and 512K SRAM memory. Each + Bank is organized in 16KiB ($4000), banks are located at $8000-$BFFF. + Bank switching is done by writing the bank number to $DE02 (Bit 0 to 4). + +@example + Register A at IO1 ($DE02): + Bit 0-4 bank number + + Register B at IO1 ($DE03): + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - ROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) + + UC2 Documentation: + https://oe7twj.at/index.php?title=Universal_Cartridge_2 +@end example + + In the cartridge header, EXROM ($18) is set to 0, GAME ($19) is set to + 0 to indicate the RESET/power-up configuration of 16 KiB ROM. + + There is a Windows Tool which can create RAW Image file and UC2 CRT file. + The content of the image file is configurable using a CSV file. + + Since UC2 cartridge can set /EXROM and /GAME signal, all known C64 basic + configurations for cartridges (Off, 8K, 16K, UltiMax) are configurable. + + Cartridge memory can be either ROM or SRAM. + SRAM can be protected, so it appears as ROM memory. + IO Register can be disabled, so configuration cannot be overwritten. + Basic CRT files (8K, 16K, UltiMax) can be loaded into UC2 SRAM from + ROM or Disk and ececuted by a Reset. + + @c @node FIXME @subsection C128 Cartridge Specifics diff --git a/vice/src/c64/cart/Makefile.am b/vice/src/c64/cart/Makefile.am index 250651075f..47275038c3 100644 --- a/vice/src/c64/cart/Makefile.am +++ b/vice/src/c64/cart/Makefile.am @@ -210,6 +210,10 @@ libc64cart_a_SOURCES = \ supersnapshot4.h \ turtlegraphics.c \ turtlegraphics.h \ + uc1.c \ + uc1.h \ + uc2.c \ + uc2.h \ warpspeed.c \ warpspeed.h \ westermann.c \ diff --git a/vice/src/c64/cart/c64cart.c b/vice/src/c64/cart/c64cart.c index 76cf8c7188..5a1501db21 100644 --- a/vice/src/c64/cart/c64cart.c +++ b/vice/src/c64/cart/c64cart.c @@ -133,6 +133,8 @@ #include "supersnapshot.h" #include "superexplode5.h" #include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" #include "warpspeed.h" #include "westermann.h" #include "zaxxon.h" @@ -302,6 +304,9 @@ static cartridge_info_t cartlist[] = { { CARTRIDGE_NAME_REX_EP256, CARTRIDGE_REX_EP256, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_REX_RAMFLOPPY, CARTRIDGE_REX_RAMFLOPPY, CARTRIDGE_GROUP_UTIL }, { CARTRIDGE_NAME_RGCD, CARTRIDGE_RGCD, CARTRIDGE_GROUP_GAME }, + { CARTRIDGE_NAME_UC1, CARTRIDGE_UC1, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_UC15, CARTRIDGE_UC15, CARTRIDGE_GROUP_UTIL }, + { CARTRIDGE_NAME_UC2, CARTRIDGE_UC2, CARTRIDGE_GROUP_UTIL }, #ifdef HAVE_RAWNET { CARTRIDGE_NAME_RRNETMK3, CARTRIDGE_RRNETMK3, CARTRIDGE_GROUP_UTIL }, #endif @@ -491,6 +496,9 @@ static int set_cartridge_type(int val, void *param) case CARTRIDGE_SUPER_SNAPSHOT: case CARTRIDGE_SUPER_SNAPSHOT_V5: case CARTRIDGE_TURTLE_GRAPHICS_II: + case CARTRIDGE_UC1: + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: case CARTRIDGE_WARPSPEED: case CARTRIDGE_WESTERMANN: case CARTRIDGE_ZAXXON: @@ -923,6 +931,15 @@ static int crt_attach(const char *filename, uint8_t *rawcart) case CARTRIDGE_PARTNER64: rc = partner64_crt_attach(fd, rawcart); break; + case CARTRIDGE_UC1: + rc = uc1_crt_attach(fd, rawcart); + break; + case CARTRIDGE_UC15: + rc = uc15_crt_attach(fd, rawcart); + break; + case CARTRIDGE_UC2: + rc = uc2_crt_attach(fd, rawcart); + break; #if 0 case CARTRIDGE_RAMCART: /* slot 1 */ rc = ramcart_crt_attach(fd, rawcart, filename); diff --git a/vice/src/c64/cart/c64carthooks.c b/vice/src/c64/cart/c64carthooks.c index 7f6d3d4b2c..7300bb3046 100644 --- a/vice/src/c64/cart/c64carthooks.c +++ b/vice/src/c64/cart/c64carthooks.c @@ -147,6 +147,9 @@ #include "supersnapshot.h" #include "supersnapshot4.h" #include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" + #ifdef HAVE_RAWNET #include "ethernetcart.h" #endif @@ -412,6 +415,15 @@ static const cmdline_option_t cmdline_options[] = { "-cartrgcd", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RGCD, NULL, NULL, "", "Attach raw 64KiB RGCD cartridge image" }, + { "-cartuc1", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC1, NULL, NULL, + "", "Attach raw UC-1 cartridge image" }, + { "-cartuc15", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC15, NULL, NULL, + "", "Attach raw UC-1.5 cartridge image" }, + { "-cartuc2", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, + cart_attach_cmdline, (void *)CARTRIDGE_UC2, NULL, NULL, + "", "Attach raw UC-2 cartridge image" }, #ifdef HAVE_RAWNET { "-cartrrnet", CALL_FUNCTION, CMDLINE_ATTRIB_NEED_ARGS, cart_attach_cmdline, (void *)CARTRIDGE_RRNETMK3, NULL, NULL, @@ -1017,6 +1029,12 @@ int cart_bin_attach(int type, const char *filename, uint8_t *rawcart) return rexramfloppy_bin_attach(filename, rawcart); case CARTRIDGE_RGCD: return rgcd_bin_attach(filename, rawcart); + case CARTRIDGE_UC1: + return uc1_bin_attach(filename, rawcart); + case CARTRIDGE_UC15: + return uc15_bin_attach(filename, rawcart); + case CARTRIDGE_UC2: + return uc2_bin_attach(filename, rawcart); #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: return rrnetmk3_bin_attach(filename, rawcart); @@ -1288,6 +1306,13 @@ void cart_attach(int type, uint8_t *rawcart) case CARTRIDGE_ROSS: ross_config_setup(rawcart); break; + case CARTRIDGE_UC1: + uc1_config_setup(rawcart); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_config_setup(rawcart); + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_config_setup(rawcart); @@ -1884,6 +1909,13 @@ void cart_detach(int type) case CARTRIDGE_RGCD: rgcd_detach(); break; + case CARTRIDGE_UC1: + uc1_detach(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_detach(); + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_detach(); @@ -2179,6 +2211,13 @@ void cartridge_init_config(void) case CARTRIDGE_RGCD: rgcd_config_init(); break; + case CARTRIDGE_UC1: + uc1_config_init(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_config_init(); + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_config_init(); @@ -2378,6 +2417,13 @@ void cartridge_reset(void) case CARTRIDGE_REX_RAMFLOPPY: rexramfloppy_reset(); break; + case CARTRIDGE_UC1: + uc1_reset(); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_reset(); + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_reset(); @@ -2506,6 +2552,13 @@ void cartridge_powerup(void) case CARTRIDGE_SUPER_SNAPSHOT_V5: supersnapshot_v5_powerup(); break; + case CARTRIDGE_UC1: + uc1_powerup(); + break; + case CARTRIDGE_UC2: + case CARTRIDGE_UC15: + uc2_powerup(); + break; } /* "Slot 1" */ @@ -3117,6 +3170,13 @@ void cartridge_mmu_translate(unsigned int addr, uint8_t **base, int *start, int case CARTRIDGE_RETRO_REPLAY: retroreplay_mmu_translate(addr, base, start, limit); return; + case CARTRIDGE_UC1: + uc1_mmu_translate(addr, base, start, limit); + return; + case CARTRIDGE_UC2: + case CARTRIDGE_UC15: + uc2_mmu_translate(addr, base, start, limit); + return; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_mmu_translate(addr, base, start, limit); @@ -3581,6 +3641,17 @@ int cartridge_snapshot_write_modules(struct snapshot_s *s) return -1; } break; + case CARTRIDGE_UC1: + if (uc1_snapshot_write_module(s) < 0) { + return -1; + } + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + if (uc2_snapshot_write_module(s) < 0) { + return -1; + } + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: if (rrnetmk3_snapshot_write_module(s) < 0) { @@ -4175,6 +4246,17 @@ int cartridge_snapshot_read_modules(struct snapshot_s *s) goto fail2; } break; + case CARTRIDGE_UC1: + if (uc1_snapshot_read_module(s) < 0) { + goto fail2; + } + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + if (uc2_snapshot_read_module(s) < 0) { + goto fail2; + } + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: if (rrnetmk3_snapshot_read_module(s) < 0) { diff --git a/vice/src/c64/cart/c64cartmem.c b/vice/src/c64/cart/c64cartmem.c index 7170a9bdc9..29bcfde9f8 100644 --- a/vice/src/c64/cart/c64cartmem.c +++ b/vice/src/c64/cart/c64cartmem.c @@ -125,6 +125,8 @@ #include "supersnapshot.h" #include "supersnapshot4.h" #include "turtlegraphics.h" +#include "uc1.h" +#include "uc2.h" #include "warpspeed.h" #include "westermann.h" #include "zaxxon.h" @@ -663,6 +665,11 @@ static uint8_t roml_read_slotmain(uint16_t addr) return partner64_roml_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_roml_read(addr); + case CARTRIDGE_UC1: + return uc1_roml_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_roml_read(addr); case CARTRIDGE_REX_RAMFLOPPY: return rexramfloppy_roml_read(addr); #ifdef HAVE_RAWNET @@ -833,6 +840,13 @@ void roml_store(uint16_t addr, uint8_t value) case CARTRIDGE_RETRO_REPLAY: retroreplay_roml_store(addr, value); return; + case CARTRIDGE_UC1: + uc1_roml_store(addr, value); + return; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_store(addr, value); + return; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: rrnetmk3_roml_store(addr, value); @@ -921,6 +935,11 @@ static uint8_t romh_read_slotmain(uint16_t addr) return partner64_romh_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_romh_read(addr); + case CARTRIDGE_UC1: + return uc1_romh_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_romh_read(addr); case CARTRIDGE_SNAPSHOT64: return snapshot64_romh_read(addr); case CARTRIDGE_EXOS: @@ -1055,6 +1074,11 @@ static uint8_t ultimax_romh_read_hirom_slotmain(uint16_t addr) return partner64_romh_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_romh_read(addr); + case CARTRIDGE_UC1: + return uc1_romh_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_romh_read(addr); case CARTRIDGE_SNAPSHOT64: return snapshot64_romh_read(addr); case CARTRIDGE_STARDOS: @@ -1236,6 +1260,13 @@ void romh_no_ultimax_store(uint16_t addr, uint8_t value) retroreplay_romh_store(addr, value); return; /* writes to cartridge RAM should not fall through to C64 RAM in mode 0x22 */ break; + case CARTRIDGE_UC1: + uc1_romh_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_romh_store(addr, value); + break; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; @@ -1289,6 +1320,13 @@ void roml_no_ultimax_store(uint16_t addr, uint8_t value) return; /* FIXME: this is weird */ } break; + case CARTRIDGE_UC1: + uc1_roml_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_store(addr, value); + break; case CARTRIDGE_REX_RAMFLOPPY: rexramfloppy_roml_store(addr, value); return; /* writes to cartridge RAM should not fall through to C64 RAM */ @@ -1350,6 +1388,13 @@ void raml_no_ultimax_store(uint16_t addr, uint8_t value) return; /* FIXME: this is weird */ } break; + case CARTRIDGE_UC1: + uc1_roml_no_ultimax_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_roml_no_ultimax_store(addr, value); + break; case CARTRIDGE_CRT: /* invalid */ DBG(("CARTMEM: BUG! invalid type %d for main cart (addr %04x)\n", mem_cartridge_type, addr)); break; @@ -1446,6 +1491,11 @@ static uint8_t ultimax_1000_7fff_read_slot1(uint16_t addr) return ide64_ram_read(addr); case CARTRIDGE_MMC_REPLAY: return mmcreplay_1000_7fff_read(addr); + case CARTRIDGE_UC1: + return uc1_1000_7fff_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_1000_7fff_read(addr); case CARTRIDGE_PARTNER64: case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: @@ -1507,6 +1557,8 @@ uint8_t ultimax_1000_7fff_read(uint16_t addr) /* ultimax store - 1000 to 7fff */ void ultimax_1000_7fff_store(uint16_t addr, uint8_t value) { + DBG(("ultimax_1000_7fff_store()\n")); + /* "Slot 0" */ if (magicvoice_cart_enabled() || ieeeflash64_cart_enabled()) { @@ -1532,6 +1584,13 @@ void ultimax_1000_7fff_store(uint16_t addr, uint8_t value) case CARTRIDGE_CAPTURE: capture_1000_7fff_store(addr, value); break; + case CARTRIDGE_UC1: + uc1_1000_7fff_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + uc2_1000_7fff_store(addr, value); + break; case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: case CARTRIDGE_FORMEL64: @@ -1584,6 +1643,11 @@ static uint8_t ultimax_a000_bfff_read_slot1(uint16_t addr) return partner64_a000_bfff_read(addr); case CARTRIDGE_RETRO_REPLAY: return retroreplay_a000_bfff_read(addr); + case CARTRIDGE_UC1: + return uc1_a000_bfff_read(addr); + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + return uc2_a000_bfff_read(addr); case CARTRIDGE_CAPTURE: case CARTRIDGE_EXOS: case CARTRIDGE_FORMEL64: @@ -1681,6 +1745,15 @@ void ultimax_a000_bfff_store(uint16_t addr, uint8_t value) case CARTRIDGE_RETRO_REPLAY: retroreplay_a000_bfff_store(addr, value); break; + case CARTRIDGE_UC1: + /* fake ultimax hack, c64 ram */ + uc1_a000_bfff_store(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + /* fake ultimax hack, c64 ram */ + uc2_a000_bfff_store(addr, value); + break; case CARTRIDGE_CAPTURE: case CARTRIDGE_EXOS: case CARTRIDGE_FINAL_PLUS: @@ -1988,6 +2061,13 @@ static int ultimax_romh_phi1_read_slotmain(uint16_t addr, uint8_t *value) break; case CARTRIDGE_NONE: break; + case CARTRIDGE_UC1: + res = uc1_romh_phi1_read(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_romh_phi1_read(addr, value); + break; default: /* generic fallback */ *value = ultimax_romh_read_hirom(addr); @@ -2104,6 +2184,13 @@ static int ultimax_romh_phi2_read_slotmain(uint16_t addr, uint8_t *value) break; case CARTRIDGE_NONE: break; + case CARTRIDGE_UC1: + res = uc1_romh_phi2_read(addr, value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_romh_phi2_read(addr, value); + break; default: /* generic fallback */ *value = ultimax_romh_read_hirom(addr); @@ -2327,6 +2414,13 @@ static uint8_t cartridge_peek_mem_slotmain(uint16_t addr) case CARTRIDGE_RETRO_REPLAY: res = retroreplay_peek_mem(&export_slotmain, addr, &value); break; + case CARTRIDGE_UC1: + res = uc1_peek_mem(&export_slotmain, addr, &value); + break; + case CARTRIDGE_UC15: + case CARTRIDGE_UC2: + res = uc2_peek_mem(&export_slotmain, addr, &value); + break; #ifdef HAVE_RAWNET case CARTRIDGE_RRNETMK3: res = rrnetmk3_peek_mem(&export_slotmain, addr, &value); diff --git a/vice/src/c64/cart/uc1.c b/vice/src/c64/cart/uc1.c new file mode 100644 index 0000000000..9f52b1d9c8 --- /dev/null +++ b/vice/src/c64/cart/uc1.c @@ -0,0 +1,800 @@ +/* + * uc1.c - Cartridge handling, Universal Cartridge 1. + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + +/* +#define UC1_DEBUG +*/ + + + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "c64cart.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64pla.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "export.h" +#include "lib.h" +#include "maincpu.h" +#include "monitor.h" +#include "resources.h" +#include "ram.h" +#include "snapshot.h" +#include "types.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" +#include "uc1.h" + + + +#ifdef UC1_DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + + + + +#define MAXBANKS 8 /* ROM banks (16K each) */ +#define CART_RAM_SIZE (32 * 1024) /* RAM size */ + + + +#define EXROM(regv) ((regv & 0x80) ? 1:0) +#define GAME(regv) ((regv & 0x40) ? 1:0) +#define RAMSEL(regv) ((regv & 0x20) ? 1:0) +#define RAMWRE(regv) ((regv & 0x10) ? 1:0) +#define IOENA(regv) ((regv & 0x08) ? 0:1) + + + + +/* + "UC-1" Cartridge + + - this cart comes in 3 ROM sizes, 32Kb (2 banks), 64Kb (4 banks) and 128Kb (8 banks).. + - this cart comes with 32K SRAM + + - ROM is after reset mapped in at $8000-$BFFF (16k game). + + - 1 register at io1 / de00: + + Bit 0-2 bank number + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - EPROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) +*/ + + +#define CRT_OFF 0xC0 +#define CRT_8K 0x40 +#define CRT_16K 0x00 +#define CRT_ULTI 0x80 + + +/*-- UC register and bank mask -----*/ +static uint8_t regval = 0; +static uint8_t bankmask = 0x07; +static uint8_t cmode = 0; + +/*-- for performace reason pre calculated flags -----*/ +static int write_ram = 0; /* from $4000 to $7FFF and $8000 to $BFFF */ +static int read_ram = 0; + +/*-- FAKE ULTIMAX (only while mode write RAM) -----*/ +static int fakeUlti = 0; +static int read_l = 0; +static int read_h = 0; + + +/* 32 KB RAM */ +static uint8_t *cart_ram = NULL; + + + +/* + *-- Set UC register at IO1 ----- + */ +static void uc1_io1_storeReg(uint8_t value) +{ + unsigned int wflag = 0; + uint8_t mode = 0; + uint8_t mode_phi1 = 0; + uint8_t mode_phi2 = 0; + + regval = value; + cmode = value & 0xC0; + + if(cmode == CRT_8K) { + /*-- 8K selected -----*/ + mode = CMODE_8KGAME; + read_l = 1; + read_h = 0; + } else if(cmode == CRT_16K) { + /*-- 16K selected -----*/ + mode = CMODE_16KGAME; + read_l = 1; + read_h = 1; + } else if(cmode == CRT_ULTI) { + /*-- UltiMax selected -----*/ + mode = CMODE_ULTIMAX; + read_l = 1; + read_h = 1; + } else { + /*-- CRT_OFF -----*/ + mode = CMODE_RAM; + read_l = 0; + read_h = 0; + } + mode_phi1 = mode; /* VIC */ + mode_phi2 = mode; /* CPU */ + + if(RAMWRE(regval) && cmode != CRT_OFF && cart_ram != NULL) { + /*-- RAM writable -----*/ + mode_phi2 = CMODE_ULTIMAX; /* FAKE UltiMax */ + wflag |= CMODE_WRITE; + wflag |= CMODE_EXPORT_RAM; + write_ram = 1; + } else { + /*-- RAM readonly -----*/ + wflag |= CMODE_READ; + write_ram = 0; + } + + if(RAMSEL(regval) && cart_ram != NULL) { + /*-- RAM selected -----*/ + wflag |= CMODE_EXPORT_RAM; + read_ram = 1; + } else { + /*-- ROM selected -----*/ + read_ram = 0; + } + + cart_config_changed_slotmain(mode_phi1, mode_phi2, wflag); + cart_romlbank_set_slotmain(value & bankmask); + cart_romhbank_set_slotmain(value & bankmask); + + if(cmode == CRT_OFF) { + cart_set_port_game_slotmain(0); + cart_set_port_exrom_slotmain(0); + cart_port_config_changed_slotmain(); + write_ram = 0; + fakeUlti = 0; + } else if(write_ram == 0) { + /*-- normal mode -----*/ + write_ram = 0; + fakeUlti = 0; + } else { + /*-- SRAM write - fake UltiMax -----*/ + DBG(("-FAKE UTLIMAX-")); + fakeUlti = 1; + write_ram = 1; + } + export_ram = write_ram | read_ram; + + DBG(("UC1 reg: %02x bank: %d (%d banks), %s, %s, %s, %s, %s, %s", + regval, (regval & bankmask), bankmask + 1, + EXROM(regval) ? "EXROM" : "/EXROM", + GAME(regval) ? "GAME" : "/GAME", + ( EXROM(regval) && GAME(regval)) ? "DISABLED" : + (!EXROM(regval) && GAME(regval)) ? "8KB" : + (!EXROM(regval) && !GAME(regval)) ? "16KB" : "Ultimax", + RAMSEL(regval) ? "RAM" : "ROM", + RAMWRE(regval) ? "write enabled" : "write disabled", + IOENA(regval) ? "IO enabled" : "IO disabled") + ); +} + +static void resetRegister(void) +{ + uc1_io1_storeReg(0); +} + +/* + *-- Set UC register at IO1 ----- + */ +static void uc1_io1_store(uint16_t addr, uint8_t value) +{ + if(IOENA(regval)) { + uc1_io1_storeReg(value); + } +} + +static uint8_t uc1_io1_peek(uint16_t addr) +{ + return regval; +} + +static uint8_t uc1_io1_read(uint16_t addr) +{ + return 0; +} + +static int uc1_dump(void) +{ + mon_out("UC1 reg: %02x (bank: %d (%d banks), %s, %s, %s, %s, %s, %s)\n", + regval, (regval & bankmask), bankmask + 1, + EXROM(regval) ? "EXROM" : "/EXROM", + GAME(regval) ? "GAME" : "/GAME", + ( EXROM(regval) && GAME(regval)) ? "DISABLED" : + (!EXROM(regval) && GAME(regval)) ? "8KB" : + (!EXROM(regval) && !GAME(regval)) ? "16KB" : "Ultimax", + RAMSEL(regval) ? "RAM" : "ROM", + RAMWRE(regval) ? "write enabled" : "write disabled", + IOENA(regval) ? "IO enabled" : "IO disabled" + ); + return 0; +} + +/* ---------------------------------------------------------------------*/ + + +/* + *-- get cart pointer l ----- + */ +static inline uint8_t *get_mem_l(uint16_t addr, bool ram) +{ + if (ram) { + return cart_ram + (addr & 0x1fff) + ((roml_bank & 1) << 14); + } + return roml_banks + ((addr & 0x1fff) + (roml_bank << 13)); +} + +/* + *-- get cart pointer h ----- + */ +static inline uint8_t *get_mem_h(uint16_t addr, bool ram) +{ + if (ram) { + return cart_ram + (addr & 0x1fff) + 0x2000 + ((roml_bank & 1) << 14); + } + return romh_banks + ((addr & 0x1fff) + (roml_bank << 13)); +} + +/* + *-- read ROM-L or RAM-L ----- + */ +static inline uint8_t read_cart_l(uint16_t addr) +{ + return *(get_mem_l(addr, read_ram)); +} + +/* + *-- read ROM-H or RAM-H ----- + */ +static inline uint8_t read_cart_h(uint16_t addr) +{ + return *(get_mem_h(addr, read_ram)); +} + +/* + *-- write ROM-L or RAM-L ----- + */ +static inline void write_cart_l(uint16_t addr, uint8_t value) +{ + if (write_ram) { + *(get_mem_l(addr, 1)) = value; + } +} + +/* + *-- write ROM-H or RAM-H ----- + */ +static inline void write_cart_h(uint16_t addr, uint8_t value) +{ + if (write_ram) { + *(get_mem_h(addr, 1)) = value; + } +} + + + +/* + *-- read ROM-L or RAM-L if active ----- + */ +uint8_t uc1_roml_read(uint16_t addr) +{ + return read_cart_l(addr); +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +void uc1_roml_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + } +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +int uc1_roml_no_ultimax_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + return 1; + } + return 0; +} + + +/* + *-- read ROM-H or RAM-H if active ----- + */ +uint8_t uc1_romh_read(uint16_t addr) +{ + if(read_h) { + return read_cart_h(addr); + } + return mem_read_without_ultimax(addr); +} + +/* + *-- write RAM-H if active ----- + */ +void uc1_romh_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + + + +void uc1_poke(uint16_t addr, uint8_t value) +{ + DBG(("poke: $%04X, %02X", addr, value)); +} + +uint8_t uc1_peek(uint16_t addr) +{ + DBG(("peek: $%04X", addr)); + return 0; +} + + +/* VIC reads */ +int uc1_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + +/* CPU reads */ +int uc1_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + + +/* + read from cart memory for monitor (without side effects) + + the majority of carts can use the generic fallback, custom functions + must be provided by those carts where either: + - the cart is not in "Main Slot" + - "fake ultimax" mapping is used + - memory can not be read without side effects +*/ +int uc1_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if(addr >= 0xE000) { + if(cmode == CRT_ULTI && read_h) { + *value = uc1_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0xA000 && addr < 0xC000) { + if(cmode == CRT_16K && read_h) { + *value = uc1_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0x8000) { + if(read_l) { + *value = uc1_roml_read(addr); + return CART_READ_VALID; + } + } + + DBG(("uc1_peek_mem(read_through): $%04X", addr)); + return CART_READ_THROUGH; +} + +/* + *-- FAKE ULTIMAX for write into 16K range: $4,$5,$6,$7 ----- + */ +void uc1_1000_7fff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + if (addr >= 0x6000) { + write_cart_h(addr, value); + } else if (addr >= 0x4000) { + write_cart_l(addr, value); + } + if (addr >= 0x8000) { + DBG(("uc1_1000_7fff_store(): $%04X (%02X)", addr, value)); + } + mem_store_without_ultimax(addr, value); + } +} + +/* + $1000-$7fff in ultimax mode - this is always regular ram +*/ +uint8_t uc1_1000_7fff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* + $a000 in ultimax mode +*/ +uint8_t uc1_a000_bfff_read(uint16_t addr) +{ + if (cmode == CRT_16K) { + return read_cart_h(addr); + } + if (cmode == CRT_8K) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +void uc1_a000_bfff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + +/* + $c000 in ultimax mode - this is always regular ram +*/ +uint8_t uc1_c000_cfff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + + + +void uc1_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ +/* FIXME: this is broken, code-in-ram execution from AR "acid test" fails */ +#if 0 + switch (addr & 0xe000) { + case 0x4000: + if (write_ram) { + DBG(("translate $4xxx")); + *base = cart_ram; + *start = 0x4000; + *limit = 0x5ffd; + return; + } + break; + case 0x6000: + if (write_ram) { + DBG(("translate $6xxx")); + *base = cart_ram + 0x2000; + *start = 0x4000; + *limit = 0x5ffd; + return; + } + break; + case 0x8000: + if (export_ram) { + DBG(("translate $8xxx")); + *base = cart_ram; + } else { + *base = roml_banks + (roml_bank << 13) - 0x8000; + } + *start = 0x8000; + *limit = 0x9ffd; + return; + case 0xa000: + if (export_ram) { + DBG(("translate $Axxx")); + *base = cart_ram + 0x2000; + } else { + *base = romh_banks + (romh_bank << 13) - 0xa000; + } + *start = 0xa000; + *limit = 0xbffd; + return; + case 0xe000: + if (export_ram) { + DBG(("translate $Exxx")); + *base = cart_ram + 0x2000; + } else { + *base = romh_banks + (romh_bank << 13) - 0xe000; + } + *start = 0xe000; + *limit = 0xfffd; + return; + default: + break; + } +#endif + *base = NULL; + *start = 0; + *limit = 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t uc1_device = { + CARTRIDGE_NAME_UC1, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc1_io1_store, /* store function */ + NULL, /* NO poke function */ + uc1_io1_read, /* read function */ + uc1_io1_peek, /* peek function */ + uc1_dump, /* device state information dump function */ + CARTRIDGE_UC1, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; + + +static io_source_list_t *uc1_list_item = NULL; + +static const export_resource_t export_res = { + CARTRIDGE_NAME_UC1, 0, 1, &uc1_device, NULL, CARTRIDGE_UC1 +}; + + + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + + +/* ---------------------------------------------------------------------*/ + +void uc1_powerup(void) +{ + resetRegister(); +} + +void uc1_config_init(void) +{ +/* + wflag: + bit 4 0x10 - trigger nmi after config changed + bit 3 0x08 - export ram enabled + bit 2 0x04 - vic phi2 mode (always sees ram if set) + bit 1 0x02 - release freeze (stop asserting NMI) + bit 0 0x01 - r/w flag +*/ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + + resetRegister(); +} + +void uc1_reset(void) +{ + resetRegister(); +} + +void uc1_config_setup(uint8_t *rawcart) +{ + int i; + + for (i = 0; i < MAXBANKS; i++) { /* split interleaved low and high banks */ + memcpy(roml_banks + i * 0x2000, rawcart + i * 0x4000, 0x2000); + memcpy(romh_banks + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000); + } + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int uc1_common_attach(void) +{ + uc1_io1_storeReg(regval); + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (export_add(&export_res) < 0) { + return -1; + } + uc1_list_item = io_source_register(&uc1_device); + return 0; +} + +int uc1_bin_attach(const char *filename, uint8_t *rawcart) +{ + regval = 0; + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x03; + if (util_file_load(filename, rawcart, 0x10000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x01; + if (util_file_load(filename, rawcart, 0x8000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + return uc1_common_attach(); +} + +int uc1_crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + regval = 0; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if (chip.size == 0x2000) { + if (chip.bank >= MAXBANKS || !(chip.start == 0x8000 || chip.start == 0xa000 || chip.start == 0xe000)) { + return -1; + } + if (crt_read_chip(rawcart, (chip.bank << 14) | (chip.start & 0x2000), &chip, fd)) { + return -1; + } + } else if (chip.size == 0x4000) { + if (chip.bank >= MAXBANKS || chip.start != 0x8000) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + } else { + return -1; + } + } + return uc1_common_attach(); +} + +void uc1_detach(void) +{ + export_remove(&export_res); + io_source_unregister(uc1_list_item); + uc1_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 2 +#define SNAP_MODULE_NAME "CARTUC1" + +int uc1_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regval) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int uc1_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + if (cart_ram == NULL) { + return -1; + } + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (0 + || (SMR_B(m, ®val) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (uc1_common_attach() == -1) { + return -1; + } + uc1_io1_store(0xde00, regval); + return 0; +} diff --git a/vice/src/c64/cart/uc1.h b/vice/src/c64/cart/uc1.h new file mode 100644 index 0000000000..696427dc2e --- /dev/null +++ b/vice/src/c64/cart/uc1.h @@ -0,0 +1,72 @@ +/* + * uc1.h - Cartridge handling, Universal Cartridge 1 + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_UC1_H +#define VICE_UC1_H + +#include + +#include "types.h" + +void uc1_config_init(void); +void uc1_config_setup(uint8_t *rawcart); +int uc1_bin_attach(const char *filename, uint8_t *rawcart); +int uc1_crt_attach(FILE *fd, uint8_t *rawcart); +void uc1_detach(void); + +void uc1_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +uint8_t uc1_roml_read(uint16_t addr); +void uc1_roml_store(uint16_t addr, uint8_t value); +int uc1_roml_no_ultimax_store(uint16_t addr, uint8_t value); +uint8_t uc1_romh_read(uint16_t addr); +int uc1_romh_phi1_read(uint16_t addr, uint8_t *value); +int uc1_romh_phi2_read(uint16_t addr, uint8_t *value); + +void uc1_romh_store(uint16_t addr, uint8_t value); + +void uc1_poke(uint16_t addr, uint8_t value); +uint8_t uc1_peek(uint16_t addr); + +int uc1_peek_mem(export_t *ex, uint16_t addr, uint8_t *value); + + +uint8_t uc1_1000_7fff_read(uint16_t addr); +void uc1_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t uc1_a000_bfff_read(uint16_t addr); +void uc1_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t uc1_c000_cfff_read(uint16_t addr); +void uc1_c000_cfff_store(uint16_t addr, uint8_t value); + +void uc1_reset(void); +void uc1_powerup(void); + +struct snapshot_s; + +int uc1_snapshot_write_module(struct snapshot_s *s); +int uc1_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/vice/src/c64/cart/uc2.c b/vice/src/c64/cart/uc2.c new file mode 100644 index 0000000000..93a5b11185 --- /dev/null +++ b/vice/src/c64/cart/uc2.c @@ -0,0 +1,929 @@ +/* + * uc2.c - Cartridge handling, Universal Cartridge 2 + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + + + + +/* #define UC2_DEBUG */ + + + + +#include "vice.h" + +#include +#include + +#include "archdep.h" +#include "c64cart.h" +#define CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64cartsystem.h" +#undef CARTRIDGE_INCLUDE_SLOTMAIN_API +#include "c64mem.h" +#include "c64pla.h" +#include "cartio.h" +#include "cartridge.h" +#include "cmdline.h" +#include "crt.h" +#include "export.h" +#include "lib.h" +#include "maincpu.h" +#include "monitor.h" +#include "resources.h" +#include "ram.h" +#include "snapshot.h" +#include "types.h" +#include "util.h" +#include "crt.h" +#include "vicii-phi1.h" +#include "uc2.h" + + + +#ifdef UC2_DEBUG +#define DBG(x) log_printf x +#else +#define DBG(x) +#endif + + + + +#define MAXBANKS 32 /* ROM banks (16K each, 512K) */ +#define CART_RAM_SIZE (512 * 1024) /* RAM size 512K */ + + + +#define EXROM(regv) ((regv & 0x80) ? 1:0) +#define GAME(regv) ((regv & 0x40) ? 1:0) +#define RAMSEL(regv) ((regv & 0x20) ? 1:0) +#define RAMWRE(regv) ((regv & 0x10) ? 1:0) +#define IOENA(regv) ((regv & 0x08) ? 0:1) +#define MAXM(regv) ((regv & 0x04) ? 1:0) + + + + +/* + "UC-2" Cartridge + + this cart comes in 3 ROM sizes, 128Kb (8 banks), 256Kb (16 banks) and 512Kb (32 banks).. + - this cart comes with 512K SRAM + + - ROM is after reset mapped in at $8000-$BFFF (16k game cart). + + - 2 register at io1 / De02,DE03. + (register are write and readable) + + Register A (IO1:$DE02): + Bit 0-4 bank number + + Register B (IO1:$DE03): + Bit 2 MAX machine flag + Bit 3 --- IO Register disable (1 - Register is invisible) + Bit 4 --- SRAM write enable (1 - SRAM is writable) + Bit 5 --- SRAM select (1 - RAM, 0 - EPROM) + Bit 6 --- Signal /GAME (C64 Cartridge Mode) + Bit 7 --- Signal /EXROM (C64 Cartridge Mode) +*/ + + +#define CRT_OFF 0xC0 +#define CRT_8K 0x40 +#define CRT_16K 0x00 +#define CRT_ULTI 0x80 + + +/*-- UC register and bank mask ----- */ +static uint8_t regA = 0; +static uint8_t regB = 0; +static uint8_t bankmask = 0x1F; +static uint8_t cmode = 0; +static uint8_t ucmode = 2; + +/*-- for performace reason pre calculated flags ----- */ +static int write_ram = 0; /* from $4000 to $7FFF and $8000 to $BFFF */ +static int read_ram = 0; + +/*-- FAKE ULTIMAX (only while mode write RAM) ----- */ +static int fakeUlti = 0; +static int read_l = 0; +static int read_h = 0; + + +/* 512 KB RAM */ +static uint8_t *cart_ram = NULL; + + + +/* + *-- Set UC register A ----- + */ +static inline void uc2_io1_storeA(uint8_t value) +{ + regA = value & 0x1F; + cart_romlbank_set_slotmain(regA & bankmask); + cart_romhbank_set_slotmain(regA & bankmask); + + DBG(("UC2 reg-A: %02x (bank: %d (%d banks))", + regA, (regA & bankmask), bankmask + 1) + ); +} + +/* + *-- Set UC register B ----- + */ +static inline void uc2_io1_storeB(uint8_t value) +{ + unsigned int wflag = 0; + uint8_t mode = 0; + uint8_t mode_phi1 = 0; + uint8_t mode_phi2 = 0; + + regB = value; + cmode = value & 0xC0; + + if(cmode == CRT_8K) { + /*-- 8K selected ----- */ + mode = CMODE_8KGAME; + read_l = 1; + read_h = 0; + } else if(cmode == CRT_16K) { + /*-- 16K selected ----- */ + mode = CMODE_16KGAME; + read_l = 1; + read_h = 1; + } else if(cmode == CRT_ULTI) { + /*-- UltiMax selected ----- */ + mode = CMODE_ULTIMAX; + read_l = 1; + read_h = 1; + } else { + /*-- CRT_OFF ----- */ + mode = CMODE_RAM; + read_l = 0; + read_h = 0; + } + mode_phi1 = mode; /* VIC */ + mode_phi2 = mode; /* CPU */ + + if(RAMWRE(regB) && cmode != CRT_OFF && cart_ram != NULL) { + /*-- RAM writable -----*/ + mode_phi2 = CMODE_ULTIMAX; /* FAKE UltiMax */ + wflag |= CMODE_WRITE; + wflag |= CMODE_EXPORT_RAM; + write_ram = 1; + } else { + /*-- RAM readonly -----*/ + wflag |= CMODE_READ; + write_ram = 0; + } + if(RAMSEL(regB) && cart_ram != NULL) { + /*-- RAM selected -----*/ + wflag |= CMODE_EXPORT_RAM; + read_ram = 1; + } else { + /*-- ROM selected -----*/ + read_ram = 0; + } + + cart_config_changed_slotmain(mode_phi1, mode_phi2, wflag); + cart_romlbank_set_slotmain(regA & bankmask); + cart_romhbank_set_slotmain(regA & bankmask); + + if(cmode == CRT_OFF) { + cart_set_port_game_slotmain(0); + cart_set_port_exrom_slotmain(0); + cart_port_config_changed_slotmain(); + write_ram = 0; + fakeUlti = 0; + } else if(write_ram == 0) { + /*-- normal mode -----*/ + write_ram = 0; + fakeUlti = 0; + } else { + /*-- SRAM write - fake UltiMax -----*/ + DBG(("-FAKE UTLIMAX-")); + fakeUlti = 1; + write_ram = 1; + } + export_ram = write_ram | read_ram; + + DBG(("UC2 reg-B: %02x %s, %s, %s, %s, %s, %s", regB, + EXROM(regB) ? "EXROM" : "/EXROM", + GAME(regB) ? "GAME" : "/GAME", + ( EXROM(regB) && GAME(regB)) ? "DISABLED" : + (!EXROM(regB) && GAME(regB)) ? "8KB" : + (!EXROM(regB) && !GAME(regB)) ? "16KB" : "Ultimax", + RAMSEL(regB) ? "RAM" : "ROM", + RAMWRE(regB) ? "write enabled" : "write disabled", + IOENA(regB) ? "IO enabled" : "IO disabled") + ); +} +static void resetRegister(void) +{ + uc2_io1_storeA(0); + uc2_io1_storeB(0); +} + +/* + *-- Set UC register at IO1 ----- + */ +static void uc2_io1_store(uint16_t addr, uint8_t value) +{ + if(IOENA(regB)) { + switch(addr & 0x3) { + case 2: /* register A */ + uc2_io1_storeA(value); + break; + case 3: /* register B */ + uc2_io1_storeB(value); + break; + } + } +} + + + +static uint8_t uc2_io1_peek(uint16_t addr) +{ + if(IOENA(regB)) { + switch(addr & 0x3) { + case 2: /* register A */ + return(regA); + case 3: /* register B */ + return(regB); + } + } + return 0; +} + +static uint8_t uc2_io1_read(uint16_t addr) +{ + return uc2_io1_peek(addr); +} + +static int uc2_dump(void) +{ + mon_out("UC2 reg: %02x (bank: %d (%d banks), %s, %s, %s, %s, %s, %s)\n", + regA, (regA & bankmask), bankmask + 1, + EXROM(regB) ? "EXROM" : "/EXROM", + GAME(regB) ? "GAME" : "/GAME", + ( EXROM(regB) && GAME(regB)) ? "DISABLED" : + (!EXROM(regB) && GAME(regB)) ? "8KB" : + (!EXROM(regB) && !GAME(regB)) ? "16KB" : "Ultimax", + RAMSEL(regB) ? "RAM" : "ROM", + RAMWRE(regB) ? "write enabled" : "write disabled", + IOENA(regB) ? "IO enabled" : "IO disabled" + ); + return 0; +} + +/* ---------------------------------------------------------------------*/ + + +/* + *-- get cart pointer l ----- + */ +static inline uint8_t *get_mem_l(uint16_t addr, bool ram) +{ + if (ram && cart_ram != NULL) { + return cart_ram + (addr & 0x1fff) + (regA << 14); + } + return roml_banks + ((addr & 0x1fff) + (regA << 13)); +} + +/* + *-- get cart pointer h ----- + */ +static inline uint8_t *get_mem_h(uint16_t addr, bool ram) +{ + if (ram && cart_ram != NULL) { + return cart_ram + (addr & 0x1fff) + 0x2000 + (regA << 14); + } + return romh_banks + ((addr & 0x1fff) + (regA << 13)); +} + +/* + *-- read ROM-L or RAM-L ----- + */ +static inline uint8_t read_cart_l(uint16_t addr) +{ +#ifdef UC2_DEBUG2 + if (read_ram) { + if((addr & 0xFFF) == 0) { + DBG(("read RAM-L: $%04X (%02X)", addr, *(get_mem_l(addr, read_ram)))); + } + } +#endif + return *(get_mem_l(addr, read_ram)); +} + +/* + *-- read ROM-H or RAM-H ----- + */ +static inline uint8_t read_cart_h(uint16_t addr) +{ +#ifdef UC2_DEBUG2 + if (read_ram) { + if((addr & 0xFFF) == 0) { + DBG(("read RAM-H: $%04X (%02X)", addr, *(get_mem_h(addr, read_ram)))); + } + } +#endif + return *(get_mem_h(addr, read_ram)); +} + +/* + *-- write ROM-L or RAM-L ----- + */ +static inline void write_cart_l(uint16_t addr, uint8_t value) +{ + if (write_ram) { +#ifdef UC2_DEBUG + if((addr & 0xFFF) == 0) { + DBG(("write RAM-L: $%04X, %02X", addr, value)); + } +#endif + *(get_mem_l(addr, 1)) = value; + } +} + +/* + *-- write ROM-H or RAM-H ----- + */ +static inline void write_cart_h(uint16_t addr, uint8_t value) +{ + if (write_ram) { +#ifdef UC2_DEBUG + if((addr & 0xFFF) == 0) { + DBG(("write RAM-H: $%04X, %02X", addr, value)); + } +#endif + *(get_mem_h(addr, 1)) = value; + } +} + + + +/* + *-- read ROM-L or RAM-L if active ----- + */ +uint8_t uc2_roml_read(uint16_t addr) +{ + return read_cart_l(addr); +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +void uc2_roml_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + } +} + +/* + *-- write ROM-L or RAM-L if active ----- +*/ +int uc2_roml_no_ultimax_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_l(addr, value); + return 1; + } + return 0; +} + + +/* + *-- read ROM-H or RAM-H if active ----- + */ +uint8_t uc2_romh_read(uint16_t addr) +{ + if(read_h) { + return read_cart_h(addr); + } + return mem_read_without_ultimax(addr); +} + +/* + *-- write RAM-H if active ----- + */ +void uc2_romh_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + + + +void uc2_poke(uint16_t addr, uint8_t value) +{ + DBG(("poke: $%04X, %02X", addr, value)); +} + +uint8_t uc2_peek(uint16_t addr) +{ + DBG(("peek: $%04X", addr)); + return 0; +} + + +/* VIC reads */ +int uc2_romh_phi1_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + /*-- ROM-H: 2000-3FFF,6000-7FFF,A000-BFFF,E000-FFFF -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} +/* CPU reads */ +int uc2_romh_phi2_read(uint16_t addr, uint8_t *value) +{ + if(read_h) { + /*-- UltiMax -----*/ + /*-- ROM-H: 2000-3FFF,6000-7FFF,A000-BFFF,E000-FFFF -----*/ + *value = read_cart_h(addr); + return CART_READ_VALID; + } + return CART_READ_THROUGH_NO_ULTIMAX; +} + + +/* + read from cart memory for monitor (without side effects) + + the majority of carts can use the generic fallback, custom functions + must be provided by those carts where either: + - the cart is not in "Main Slot" + - "fake ultimax" mapping is used + - memory can not be read without side effects +*/ +int uc2_peek_mem(export_t *ex, uint16_t addr, uint8_t *value) +{ + if(addr >= 0xE000) { + /*-- Kernal: E000-FFFF -----*/ + if(cmode == CRT_ULTI && read_h) { + *value = uc2_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0xA000 && addr < 0xC000) { + /*-- ROM-H: A000-BFFF -----*/ + if(cmode == CRT_16K && read_h) { + *value = uc2_romh_read(addr); + return CART_READ_VALID; + } + } else if(addr >= 0x8000) { + /*-- ROM-L: 8000-9FFF -----*/ + if(read_l) { + *value = uc2_roml_read(addr); + return CART_READ_VALID; + } + } + + DBG(("uc2_peek_mem(read_through): $%04X ", addr)); + return CART_READ_THROUGH; +} + +/* + *-- FAKE ULTIMAX for write into 16K range: $4,$5,$6,$7 ----- + */ +void uc2_1000_7fff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + if (addr >= 0x6000) { + write_cart_h(addr, value); + } else if (addr >= 0x4000) { + write_cart_l(addr, value); + } + if (addr >= 0x8000) { + DBG(("uc2_1000_7fff_store(): $%04X (%02X)", addr, value)); + } + mem_store_without_ultimax(addr, value); + } +} + +/* + $1000-$7fff in ultimax mode - this is always regular ram +*/ +uint8_t uc2_1000_7fff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +/* + $a000 in ultimax mode +*/ +uint8_t uc2_a000_bfff_read(uint16_t addr) +{ + if (cmode == CRT_16K) { + return read_cart_h(addr); + } + if (cmode == CRT_8K) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + +void uc2_a000_bfff_store(uint16_t addr, uint8_t value) +{ + if (write_ram) { + write_cart_h(addr, value); + } +} + +/* + $c000 in ultimax mode - this is always regular ram +*/ +uint8_t uc2_c000_cfff_read(uint16_t addr) +{ + if (fakeUlti) { + return mem_read_without_ultimax(addr); + } + return vicii_read_phi1(); +} + + + +void uc2_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit) +{ +/* FIXME: this is broken, code-in-ram execution from AR "acid test" fails */ +#if 0 + switch (addr & 0xe000) { + case 0x4000: + if (write_ram) { + DBG(("translate $4xxx")); + *base = cart_ram; + *start = 0x4000; + *limit = 0x5ffd; + return; + } + break; + case 0x6000: + if (write_ram) { + DBG(("translate $6xxx")); + *base = cart_ram + 0x2000; + *start = 0x4000; + *limit = 0x5ffd; + return; + } + break; + case 0x8000: + if (export_ram) { + DBG(("translate $8xxx")); + *base = cart_ram; + } else { + *base = regAs + (regA << 13) - 0x8000; + } + *start = 0x8000; + *limit = 0x9ffd; + return; + case 0xa000: + if (export_ram) { + DBG(("translate $Axxx")); + *base = cart_ram + 0x2000; + } else { + *base = romh_banks + (regA << 13) - 0xa000; + } + *start = 0xa000; + *limit = 0xbffd; + return; + case 0xe000: + if (export_ram) { + DBG(("translate $Exxx")); + *base = cart_ram + 0x2000; + } else { + *base = romh_banks + (regA << 13) - 0xe000; + } + *start = 0xe000; + *limit = 0xfffd; + return; + default: + break; + } +#endif + *base = NULL; + *start = 0; + *limit = 0; +} + +/* ---------------------------------------------------------------------*/ + +static io_source_t uc2_device = { + CARTRIDGE_NAME_UC2, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc2_io1_store, /* store function */ + NULL, /* NO poke function */ + uc2_io1_read, /* read function */ + uc2_io1_peek, /* peek function */ + uc2_dump, /* device state information dump function */ + CARTRIDGE_UC2, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; +static const export_resource_t export_res_uc2 = { + CARTRIDGE_NAME_UC2, 0, 1, &uc2_device, NULL, CARTRIDGE_UC2 +}; + +static io_source_t uc15_device = { + CARTRIDGE_NAME_UC15, /* name of the device */ + IO_DETACH_CART, /* use cartridge ID to detach the device when involved in a read-collision */ + IO_DETACH_NO_RESOURCE, /* does not use a resource for detach */ + 0xde00, 0xdeff, 0xff, /* range for the device, address is ignored, reg:$de00, mirrors:$de01-$deff */ + 0, /* read is never valid, reg is write only */ + uc2_io1_store, /* store function */ + NULL, /* NO poke function */ + uc2_io1_read, /* read function */ + uc2_io1_peek, /* peek function */ + uc2_dump, /* device state information dump function */ + CARTRIDGE_UC15, /* cartridge ID */ + IO_PRIO_NORMAL, /* normal priority, device read needs to be checked for collisions */ + 0, /* insertion order, gets filled in by the registration function */ + IO_MIRROR_NONE /* NO mirroring */ +}; +static const export_resource_t export_res_uc15 = { + CARTRIDGE_NAME_UC15, 0, 1, &uc15_device, NULL, CARTRIDGE_UC15 +}; + + +static io_source_list_t *uc_list_item = NULL; + + +/* ---------------------------------------------------------------------*/ + +/* FIXME: this still needs to be tweaked to match the hardware */ +static RAMINITPARAM ramparam = { + .start_value = 255, + .value_invert = 2, + .value_offset = 1, + + .pattern_invert = 0x100, + .pattern_invert_value = 255, + + .random_start = 0, + .random_repeat = 0, + .random_chance = 0, +}; + + +/* ---------------------------------------------------------------------*/ + +void uc2_powerup(void) +{ + resetRegister(); +} + +void uc2_config_init(void) +{ +/* + wflag: + bit 4 0x10 - trigger nmi after config changed + bit 3 0x08 - export ram enabled + bit 2 0x04 - vic phi2 mode (always sees ram if set) + bit 1 0x02 - release freeze (stop asserting NMI) + bit 0 0x01 - r/w flag +*/ + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); + + resetRegister(); +} + +void uc2_reset(void) +{ + resetRegister(); +} + +void uc2_config_setup(uint8_t *rawcart) +{ + int i; + + for (i = 0; i < MAXBANKS; i++) { /* split interleaved low and high banks */ + memcpy(roml_banks + i * 0x2000, rawcart + i * 0x4000, 0x2000); + memcpy(romh_banks + i * 0x2000, rawcart + i * 0x4000 + 0x2000, 0x2000); + } + cart_config_changed_slotmain(CMODE_16KGAME, CMODE_16KGAME, CMODE_READ); +} + +/* ---------------------------------------------------------------------*/ + +static int uc2_common_attach(void) +{ + uc2_io1_storeA(regA); + uc2_io1_storeB(regB); + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if(ucmode == 2) { + if (export_add(&export_res_uc2) < 0) { + return -1; + } + uc_list_item = io_source_register(&uc2_device); + } else { + if (export_add(&export_res_uc15) < 0) { + return -1; + } + uc_list_item = io_source_register(&uc15_device); + } + return 0; +} + +static int bin_attach(const char *filename, uint8_t *rawcart) +{ + bankmask = 0x1f; + if (util_file_load(filename, rawcart, 0x80000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x0f; + if (util_file_load(filename, rawcart, 0x40000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + bankmask = 0x07; + if (util_file_load(filename, rawcart, 0x20000, UTIL_FILE_LOAD_SKIP_ADDRESS) < 0) { + return -1; + } + } + } + return uc2_common_attach(); +} + +static int crt_attach(FILE *fd, uint8_t *rawcart) +{ + crt_chip_header_t chip; + + while (1) { + if (crt_read_chip_header(&chip, fd)) { + break; + } + if (chip.size == 0x2000) { + if (chip.bank >= MAXBANKS || !(chip.start == 0x8000 || chip.start == 0xa000 || chip.start == 0xe000)) { + return -1; + } + if (crt_read_chip(rawcart, (chip.bank << 14) | (chip.start & 0x2000), &chip, fd)) { + return -1; + } + } else if (chip.size == 0x4000) { + if (chip.bank >= MAXBANKS || chip.start != 0x8000) { + return -1; + } + if (crt_read_chip(rawcart, chip.bank << 14, &chip, fd)) { + return -1; + } + } else { + return -1; + } + } + return uc2_common_attach(); +} + + +int uc2_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("UC2 attach BIN file")); + ucmode = 2; + return bin_attach(filename, rawcart); +} + +int uc15_bin_attach(const char *filename, uint8_t *rawcart) +{ + DBG(("UC15 attach BIN file")); + ucmode = 1; + return bin_attach(filename, rawcart); +} + +int uc2_crt_attach(FILE *fd, uint8_t *rawcart) +{ + DBG(("UC2 attach CRT file")); + ucmode = 2; + return crt_attach(fd, rawcart); +} + +int uc15_crt_attach(FILE *fd, uint8_t *rawcart) +{ + DBG(("UC15 attach CRT file")); + ucmode = 1; + return crt_attach(fd, rawcart); +} + +void uc2_detach(void) +{ + lib_free(cart_ram); + cart_ram = NULL; + + + if(ucmode == 2) { + export_remove(&export_res_uc2); + } + else { + export_remove(&export_res_uc15); + } + io_source_unregister(uc_list_item); + uc_list_item = NULL; +} + +/* ---------------------------------------------------------------------*/ + +#define CART_DUMP_VER_MAJOR 0 +#define CART_DUMP_VER_MINOR 2 +#define SNAP_MODULE_NAME "CARTUC2" + +int uc2_snapshot_write_module(snapshot_t *s) +{ + snapshot_module_t *m; + + m = snapshot_module_create(s, SNAP_MODULE_NAME, + CART_DUMP_VER_MAJOR, CART_DUMP_VER_MINOR); + if (m == NULL) { + return -1; + } + + if (0 + || (SMW_B(m, (uint8_t)regA) < 0) + || (SMW_B(m, (uint8_t)regB) < 0) + || (SMW_B(m, (uint8_t)bankmask) < 0) + || (SMW_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMW_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + return 0; +} + +int uc2_snapshot_read_module(snapshot_t *s) +{ + uint8_t vmajor, vminor; + snapshot_module_t *m; + + m = snapshot_module_open(s, SNAP_MODULE_NAME, &vmajor, &vminor); + if (m == NULL) { + return -1; + } + + if ((vmajor != CART_DUMP_VER_MAJOR) || (vminor != CART_DUMP_VER_MINOR)) { + snapshot_module_close(m); + return -1; + } + + if (cart_ram == NULL) { + cart_ram = lib_malloc(CART_RAM_SIZE); + if (cart_ram == NULL) { + return -1; + } + ram_init_with_pattern(cart_ram, CART_RAM_SIZE, &ramparam); + } + + if (0 + || (SMR_B(m, ®A) < 0) + || (SMR_B(m, ®B) < 0) + || (SMR_B(m, &bankmask) < 0) + || (SMR_BA(m, roml_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, romh_banks, 0x2000 * MAXBANKS) < 0) + || (SMR_BA(m, cart_ram, CART_RAM_SIZE) < 0)) { + snapshot_module_close(m); + return -1; + } + + snapshot_module_close(m); + + if (uc2_common_attach() == -1) { + return -1; + } + return 0; +} diff --git a/vice/src/c64/cart/uc2.h b/vice/src/c64/cart/uc2.h new file mode 100644 index 0000000000..afb26d63af --- /dev/null +++ b/vice/src/c64/cart/uc2.h @@ -0,0 +1,75 @@ +/* + * uc2.h - Cartridge handling, Universal Cartridge 2. + * + * Written by + * Thomas Winkler + * + * This file is part of VICE, the Versatile Commodore Emulator. + * See README for copyright notice. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + * 02111-1307 USA. + * + */ + +#ifndef VICE_UC2_H +#define VICE_UC2_H + +#include + +#include "types.h" + +void uc2_config_init(void); +void uc2_config_setup(uint8_t *rawcart); +int uc2_bin_attach(const char *filename, uint8_t *rawcart); +int uc2_crt_attach(FILE *fd, uint8_t *rawcart); +void uc2_detach(void); + +int uc15_bin_attach(const char *filename, uint8_t *rawcart); +int uc15_crt_attach(FILE *fd, uint8_t *rawcart); + +void uc2_mmu_translate(unsigned int addr, uint8_t **base, int *start, int *limit); + +uint8_t uc2_roml_read(uint16_t addr); +void uc2_roml_store(uint16_t addr, uint8_t value); +int uc2_roml_no_ultimax_store(uint16_t addr, uint8_t value); +uint8_t uc2_romh_read(uint16_t addr); +int uc2_romh_phi1_read(uint16_t addr, uint8_t *value); +int uc2_romh_phi2_read(uint16_t addr, uint8_t *value); + +void uc2_romh_store(uint16_t addr, uint8_t value); + +void uc2_poke(uint16_t addr, uint8_t value); +uint8_t uc2_peek(uint16_t addr); + +int uc2_peek_mem(export_t *ex, uint16_t addr, uint8_t *value); + + +uint8_t uc2_1000_7fff_read(uint16_t addr); +void uc2_1000_7fff_store(uint16_t addr, uint8_t value); +uint8_t uc2_a000_bfff_read(uint16_t addr); +void uc2_a000_bfff_store(uint16_t addr, uint8_t value); +uint8_t uc2_c000_cfff_read(uint16_t addr); +void uc2_c000_cfff_store(uint16_t addr, uint8_t value); + +void uc2_reset(void); +void uc2_powerup(void); + +struct snapshot_s; + +int uc2_snapshot_write_module(struct snapshot_s *s); +int uc2_snapshot_read_module(struct snapshot_s *s); + +#endif diff --git a/vice/src/cartridge.h b/vice/src/cartridge.h index a55ee4f506..aba4fd1083 100644 --- a/vice/src/cartridge.h +++ b/vice/src/cartridge.h @@ -262,7 +262,10 @@ void cartridge_sound_chip_init(void); #define CARTRIDGE_FREEZE_FRAME_MK2 77 /* freezeframe2.c */ #define CARTRIDGE_PARTNER64 78 /* partner64.c */ #define CARTRIDGE_HYPERBASIC 79 /* hyperbasic.c */ -#define CARTRIDGE_LAST 79 /* cartconv: last cartridge in list */ +#define CARTRIDGE_UC1 80 /* uc1.c */ +#define CARTRIDGE_UC15 81 /* uc2.c */ +#define CARTRIDGE_UC2 82 /* uc2.c */ +#define CARTRIDGE_LAST 82 /* cartconv: last cartridge in list */ /* list of canonical names for the c64 cartridges: note: often it is hard to determine "the" official name, let alone the way it @@ -380,6 +383,9 @@ void cartridge_sound_chip_init(void); #define CARTRIDGE_NAME_WESTERMANN "Westermann Learning" #define CARTRIDGE_NAME_ZAXXON "Zaxxon" #define CARTRIDGE_NAME_ZIPPCODE48 "ZIPP-CODE 48" +#define CARTRIDGE_NAME_UC1 "Universal Cartridge 1" /* uc1.c :: universal cartridge 1 */ +#define CARTRIDGE_NAME_UC15 "Universal Cartridge 1.5" /* uc2.c :: universal cartridge 1.5 */ +#define CARTRIDGE_NAME_UC2 "Universal Cartridge 2" /* uc2.c :: universal cartridge 2 */ #define CARTRIDGE_NAME_GENERIC_8KB "generic 8KiB game" #define CARTRIDGE_NAME_GENERIC_16KB "generic 16KiB game" diff --git a/vice/src/tools/cartconv/c64-cartridges.c b/vice/src/tools/cartconv/c64-cartridges.c index 64fc65aa60..99027d212a 100644 --- a/vice/src/tools/cartconv/c64-cartridges.c +++ b/vice/src/tools/cartconv/c64-cartridges.c @@ -141,6 +141,16 @@ const cart_t cart_info[] = { {0, 1, CARTRIDGE_SIZE_16KB, 0x4000, 0x8000, 1, 0, CARTRIDGE_NAME_FREEZE_FRAME_MK2, "ff2", save_regular_crt}, {1, 0, CARTRIDGE_SIZE_16KB, 0x2000, 0x8000, 2, 0, CARTRIDGE_NAME_PARTNER64, "partner64", save_stardos_crt}, {0, 1, CARTRIDGE_SIZE_64KB, 0x2000, 0x8000, 8, 0, CARTRIDGE_NAME_HYPERBASIC, "hyper", save_regular_crt}, + {0, 0, CARTRIDGE_SIZE_32KB | + CARTRIDGE_SIZE_64KB | + CARTRIDGE_SIZE_128KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_UC1, "uc1", save_regular_crt}, + {0, 0, CARTRIDGE_SIZE_128KB | + CARTRIDGE_SIZE_256KB | + CARTRIDGE_SIZE_512KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_UC15, "uc15", save_regular_crt}, + {0, 0, CARTRIDGE_SIZE_128KB | + CARTRIDGE_SIZE_256KB | + CARTRIDGE_SIZE_512KB, 0x4000, 0x8000, 0, 0, CARTRIDGE_NAME_UC2, "uc2", save_regular_crt}, {0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL} }; +/* exrom, game, sizes, bank size, load addr, num banks, data type, name, option, saver */