From 185f5f14e0375c80e7fcef83e7f0f245ffa41b19 Mon Sep 17 00:00:00 2001 From: Jerzy Kut Date: Tue, 14 Apr 2020 23:36:02 +0200 Subject: [PATCH 1/3] Support for all known Ram-Cart cartridges: 64K, 128K, 1M, 2M, 4M and Double Ram-Cart 2x128K/256K. --- DOC/CREDITS | 3 +- DOC/NEWS | 8 + DOC/README | 2 +- DOC/USAGE | 4 +- DOC/cart.txt | 232 +++++++++++++++++++++++ src/cartridge.c | 430 +++++++++++++++++++++++++++++++++++------- src/cartridge.h | 54 +++++- src/memory.h | 3 +- src/monitor.c | 127 +++++++++++++ src/ui.c | 486 ++++++++++++++++++++++++++++++++---------------- src/ui.h | 1 + 11 files changed, 1109 insertions(+), 241 deletions(-) diff --git a/DOC/CREDITS b/DOC/CREDITS index c64f123..69bf410 100644 --- a/DOC/CREDITS +++ b/DOC/CREDITS @@ -254,8 +254,9 @@ Jindrich Kubec - hours of testing on real Atari800XL - research on real cartridges -Jerzy Kut +Jerzy Kut - MapRAM memory expansion for the XL/XE + - Ram-Cart 64K/128K/1M/2M/4M and Double Ram-Cart 2x128K/256K cartridges support Chris Lam - RGB values for each Atari colour diff --git a/DOC/NEWS b/DOC/NEWS index e9c2e38..8eb19b8 100644 --- a/DOC/NEWS +++ b/DOC/NEWS @@ -1,3 +1,11 @@ +Version 4.2.1 +========================== + + New Features: + ------------- + * Ram-Cart cartridges support (types 71-76) + + Version 4.2.0 (2019/12/28) - released at SILK ========================== diff --git a/DOC/README b/DOC/README index bea69bb..a07ed8a 100644 --- a/DOC/README +++ b/DOC/README @@ -110,7 +110,7 @@ o ATR, XFD, DCM, ATR.GZ, XFD.GZ and .PRO disk images. o Direct loading of Atari executable files and Atari BASIC programs. -o 59 cartridge types, raw and CART format. +o 76 cartridge types, raw and CART format. o Cassette recorder, raw and CAS images. diff --git a/DOC/USAGE b/DOC/USAGE index e19f85a..95f034f 100644 --- a/DOC/USAGE +++ b/DOC/USAGE @@ -143,12 +143,12 @@ Command line options -basic Turn on Atari BASIC ROM -cart Insert cartridge (CART or raw format) --cart-type <0..70> Select type of cartridge inserted with -cart. 0 means +-cart-type <0..76> Select type of cartridge inserted with -cart. 0 means no cartridge, and other values indicate a specific cartridge type as in cart.txt. -cart2 Insert second cartridge (CART or raw format) Only if first cartridge is SpartaDOS X (64 or 128) --cart2-type <0..70> Similar to -cart-type. Select type of cartridge inserted +-cart2-type <0..76> Similar to -cart-type. Select type of cartridge inserted with -cart2. -cart-autoreboot Automatically reboot after cartridge inserting/removing (doesn't affect the piggyback cartridge) diff --git a/DOC/cart.txt b/DOC/cart.txt index efd5f1e..26e5368 100644 --- a/DOC/cart.txt +++ b/DOC/cart.txt @@ -102,6 +102,12 @@ Currently supported cartridge types: | 68 | 800/XL/XE | 128 | Atrax 128 KB cartridge | | | 69 | 800/XL/XE | 32 | aDawliah 32 KB cartridge | | | 70 | 800/XL/XE | 64 | aDawliah 64 KB cartridge | | +| 71 | 800/XL/XE | 64 | Ram-Cart 64 KB cartridge | | +| 72 | 800/XL/XE | 128 | Ram-Cart 128 KB cartridge | | +| 73 | 800/XL/XE | 256 | Double Ram-Cart 2x128/256 KB cartridge | | +| 74 | 800/XL/XE | 1M | Ram-Cart 1 MB cartridge | | +| 75 | 800/XL/XE | 2M | Ram-Cart 2 MB cartridge | | +| 76 | 800/XL/XE | 4M | Ram-Cart 4 MB cartridge | | +----+-----------+------+-----------------------------------------------+---+ Id is the cartridge type code stored in the CART file. @@ -824,6 +830,7 @@ Reference: http://www.retrobits.net/atari/osshack.shtml Bits 2..0 - 16KB bank number (0..7) Default value = 0 which means 0 bank upper subbank in address $A000-$BFFF To switch cart off - poke $40 info $D500-$D51F + The cartridge also supports programming of the Flash ROM - this feature is currently not emulated. @@ -1088,3 +1095,228 @@ Reference: http://www.retrobits.net/atari/osshack.shtml Reference: http://atarionline.pl/forum/comments.php?DiscussionID=4260&page=1#Item_13 + + +---------------------------------------------------------------------------+ + | Type 71: Ram-Cart 64 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It uses SRAM with 3V battery power supplied and operates in two different modes + ("Read Only" and "Read/Write") turned by the user using switch on top of the case. + Two static RAM 32Kx8 chips (D43257GU) and small logic providing control register + to select memory bank and making it's visibility in Atari memory area is inside. + + RAM is divided into four 16K banks with their's lower half visible in $8000..$9FFF + and upper half in $A000..$BFFF areas. + Read/Write control register is located in $D500, but is available on the whole + $D5 page for the sake of simplified address decoder is used. + + Control register bits meaning: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - control register lock: 0-unlocked, 1-locked until power off + 3 - bank select + 4 - bank select + 5 - not connected + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %00000000 43xxxxxx xxxxxxxx + :::::::: :::::::: + ::++++++-++++++++-- address bus A0..A13 + ++----------------- control register bits + + Control register contains $00 on power-on. + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#64KB + + +---------------------------------------------------------------------------+ + | Type 72: Ram-Cart 128 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's identical to cartridge type 71 but uses four 32Kx8 RAM chips. + + Location of control register and it's bits meaning is the same, but additional + bit 5 is used to select bank as well as bits 3 and 4. + + Control register bits meaning: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - control register lock: 0-unlocked, 1-locked until power off + 3 - bank select + 4 - bank select + 5 - bank select + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %00000005 43xxxxxx xxxxxxxx + : :::::::: :::::::: + : ::++++++-++++++++-- address bus A0..A13 + +-++----------------- control register bits + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#128KB + + +---------------------------------------------------------------------------+ + | Type 73: Double Ram-Cart 2x128/256 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's similar to cartridge type 72 but uses two 128Kx8 RAM chips (CXK581000P). + + Location of control register and it's bits meaning is almost the same, + but bit 2 has different meaning depending on state of P1 and P2 switches. + + Additional P1 button on the top of case is used to choose mode of operation: + * 2x128K - selected when P1 is in state 0 + * 256K - selected when P1 is in state 1 + + Bit 2 of control register has the same meaning as in 72 cartridge type + once 2x128K mode is chosen. Button P2 is used to choose active 128K module. + + If 256K mode is chosen then bit 2 is used to select 128K module and address + full 256K memory area. P2 swaps 128K areas once it's 1 - if it's 0 then 128K + modules are addressed in normal order. + + Control register bits meaning in this mode: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - select 128K module: + * 0=$0xxxx-$1xxxx, 1=$2xxxx-$3xxxx if P2=0 + * 0-$2xxxx-$3xxxx, 1=$0xxxx-$1xxxx if P2=1 + 3 - bank select + 4 - bank select + 5 - bank select + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %00000025 43xxxxxx xxxxxxxx + :: :::::::: :::::::: + :: ::++++++-++++++++-- address bus A0..A13 + ++-++----------------- control register bits + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#2x128KB%20/%20256KB + + +---------------------------------------------------------------------------+ + | Type 74: Ram-Cart 1 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's similar to cartridge type 72 but bits 2, 6 and 7 have changed function. + + Three switches A, B and C on the top of case are used to select one of eight + 128K modules. They state can be read by control register. + + Control register bits meaning: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - state of A switch + 3 - bank select + 4 - bank select + 5 - bank select + 6 - state of B switch + 7 - state of C switch + + Cartridge memory address bits mapping: + + %0000CBA5 43xxxxxx xxxxxxxx + :::: :::::::: :::::::: + :::: ::++++++-++++++++-- address bus A0..A13 + :::+-++----------------- control register bits + +++--------------------- switches + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#1MB + + +---------------------------------------------------------------------------+ + | Type 75: Ram-Cart 2 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's identical to cartridge type 74. + + Three switches A, B and C on the top of case are used to select one of eight + 128K modules. They state can be read by control register. + Additional switch 1/2M is used to choose one of two 1MB module. + + Control register bits meaning: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - state of A switch + 3 - bank select + 4 - bank select + 5 - bank select + 6 - state of B switch + 7 - state of C switch + + Cartridge memory address bits mapping: + + %0001CBA5 43xxxxxx xxxxxxxx + ::::: :::::::: :::::::: + ::::: ::++++++-++++++++-- address bus A0..A13 + ::::+-++----------------- control register bits + ++++--------------------- switches + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#2MB + + +---------------------------------------------------------------------------+ + | Type 76: Ram-Cart 4 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's identical to cartridge type 75. + + Three switches A, B and C on the top of case are used to select one of eight + 128K modules. They state can be read by control register. + Additional switch 1/2M is used to choose one of two 1MB module. + Additional switch 2/4M is used to choose one of two 2MB module. + + Control register bits meaning: + + 0 - $A000..$BFFF window enable: + * "Read Only" mode: 0-enabled, 1-disabled + * "Read/Write" mode: 0-disabled, 1-enabled + 1 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 2 - state of A switch + 3 - bank select + 4 - bank select + 5 - bank select + 6 - state of B switch + 7 - state of C switch + + Cartridge memory address bits mapping: + + %0021CBA5 43xxxxxx xxxxxxxx + :::::: :::::::: :::::::: + :::::: ::++++++-++++++++-- address bus A0..A13 + :::::+-++----------------- control register bits + +++++--------------------- switches + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#4MB + diff --git a/src/cartridge.c b/src/cartridge.c index 85e5897..fb5f229 100644 --- a/src/cartridge.c +++ b/src/cartridge.c @@ -2,7 +2,7 @@ * cartridge.c - cartridge emulation * * Copyright (C) 2001-2010 Piotr Fusik - * Copyright (C) 2001-2010 Atari800 development team (see DOC/CREDITS) + * Copyright (C) 2001-2020 Atari800 development team (see DOC/CREDITS) * * This file is part of the Atari800 emulator project which emulates * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers. @@ -50,7 +50,8 @@ /* #define DEBUG 1 */ -int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1] = { + +const int CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1] = { 0, 8, /* CARTRIDGE_STD_8 */ 16, /* CARTRIDGE_STD_16 */ @@ -121,7 +122,93 @@ int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1] = { 64, /* CARTRIDGE_XEGS_64_8F */ 128, /* CARTRIDGE_ATRAX_128 */ 32, /* CARTRIDGE_ADAWLIAH_32 */ - 64 /* CARTRIDGE_ADAWLIAH_64 */ + 64, /* CARTRIDGE_ADAWLIAH_64 */ + 64, /* CARTRIDGE_RAMCART_64 */ + 128, /* CARTRIDGE_RAMCART_128 */ + 256, /* CARTRIDGE_DOUBLE_RAMCART_256 */ + 1024, /* CARTRIDGE_RAMCART_1M */ + 2048, /* CARTRIDGE_RAMCART_2M */ + 4096 /* CARTRIDGE_RAMCART_4M */ +}; + +const char *CARTRIDGE_desc[CARTRIDGE_LAST_SUPPORTED + 1] = { + "", + CARTRIDGE_STD_8_DESC, + CARTRIDGE_STD_16_DESC, + CARTRIDGE_OSS_034M_16_DESC, + CARTRIDGE_5200_32_DESC, + CARTRIDGE_DB_32_DESC, + CARTRIDGE_5200_EE_16_DESC, + CARTRIDGE_5200_40_DESC, + CARTRIDGE_WILL_64_DESC, + CARTRIDGE_EXP_64_DESC, + CARTRIDGE_DIAMOND_64_DESC, + CARTRIDGE_SDX_64_DESC, + CARTRIDGE_XEGS_32_DESC, + CARTRIDGE_XEGS_07_64_DESC, + CARTRIDGE_XEGS_128_DESC, + CARTRIDGE_OSS_M091_16_DESC, + CARTRIDGE_5200_NS_16_DESC, + CARTRIDGE_ATRAX_DEC_128_DESC, + CARTRIDGE_BBSB_40_DESC, + CARTRIDGE_5200_8_DESC, + CARTRIDGE_5200_4_DESC, + CARTRIDGE_RIGHT_8_DESC, + CARTRIDGE_WILL_32_DESC, + CARTRIDGE_XEGS_256_DESC, + CARTRIDGE_XEGS_512_DESC, + CARTRIDGE_XEGS_1024_DESC, + CARTRIDGE_MEGA_16_DESC, + CARTRIDGE_MEGA_32_DESC, + CARTRIDGE_MEGA_64_DESC, + CARTRIDGE_MEGA_128_DESC, + CARTRIDGE_MEGA_256_DESC, + CARTRIDGE_MEGA_512_DESC, + CARTRIDGE_MEGA_1024_DESC, + CARTRIDGE_SWXEGS_32_DESC, + CARTRIDGE_SWXEGS_64_DESC, + CARTRIDGE_SWXEGS_128_DESC, + CARTRIDGE_SWXEGS_256_DESC, + CARTRIDGE_SWXEGS_512_DESC, + CARTRIDGE_SWXEGS_1024_DESC, + CARTRIDGE_PHOENIX_8_DESC, + CARTRIDGE_BLIZZARD_16_DESC, + CARTRIDGE_ATMAX_128_DESC, + CARTRIDGE_ATMAX_1024_DESC, + CARTRIDGE_SDX_128_DESC, + CARTRIDGE_OSS_8_DESC, + CARTRIDGE_OSS_043M_16_DESC, + CARTRIDGE_BLIZZARD_4_DESC, + CARTRIDGE_AST_32_DESC, + CARTRIDGE_ATRAX_SDX_64_DESC, + CARTRIDGE_ATRAX_SDX_128_DESC, + CARTRIDGE_TURBOSOFT_64_DESC, + CARTRIDGE_TURBOSOFT_128_DESC, + CARTRIDGE_ULTRACART_32_DESC, + CARTRIDGE_LOW_BANK_8_DESC, + CARTRIDGE_SIC_128_DESC, + CARTRIDGE_SIC_256_DESC, + CARTRIDGE_SIC_512_DESC, + CARTRIDGE_STD_2_DESC, + CARTRIDGE_STD_4_DESC, + CARTRIDGE_RIGHT_4_DESC, + CARTRIDGE_BLIZZARD_32_DESC, + CARTRIDGE_MEGAMAX_2048_DESC, + CARTRIDGE_THECART_128M_DESC, + CARTRIDGE_MEGA_4096_DESC, + CARTRIDGE_MEGA_2048_DESC, + CARTRIDGE_THECART_32M_DESC, + CARTRIDGE_THECART_64M_DESC, + CARTRIDGE_XEGS_8F_64_DESC, + CARTRIDGE_ATRAX_128_DESC, + CARTRIDGE_ADAWLIAH_32_DESC, + CARTRIDGE_ADAWLIAH_64_DESC, + CARTRIDGE_RAMCART_64_DESC, + CARTRIDGE_RAMCART_128_DESC, + CARTRIDGE_DOUBLE_RAMCART_256_DESC, + CARTRIDGE_RAMCART_1M_DESC, + CARTRIDGE_RAMCART_2M_DESC, + CARTRIDGE_RAMCART_4M_DESC }; int CARTRIDGE_autoreboot = TRUE; @@ -148,14 +235,32 @@ static int CartIsPassthrough(int type) type == CARTRIDGE_ATRAX_SDX_64 || type == CARTRIDGE_ATRAX_SDX_128; } -CARTRIDGE_image_t CARTRIDGE_main = { CARTRIDGE_NONE, 0, 0, NULL, "" }; /* Left/Right cartridge */ -CARTRIDGE_image_t CARTRIDGE_piggyback = { CARTRIDGE_NONE, 0, 0, NULL, "" }; /* Pass through cartridge for SpartaDOSX */ +CARTRIDGE_image_t CARTRIDGE_main = { CARTRIDGE_NONE, 0, 0, NULL, "", TRUE }; /* Left/Right cartridge */ +CARTRIDGE_image_t CARTRIDGE_piggyback = { CARTRIDGE_NONE, 0, 0, NULL, "", TRUE }; /* Pass through cartridge for SpartaDOSX */ /* The currently active cartridge in the left slot - normally points to CARTRIDGE_main but can be switched to CARTRIDGE_piggyback if the main cartridge is a SpartaDOS X. */ static CARTRIDGE_image_t *active_cart = &CARTRIDGE_main; +static ULONG Calculate_RamCart_Address(int cart_type, int cart_state) +{ + int state = cart_state; + switch (cart_type) + { + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + if (!(cart_state & 0x2000)) /* 2x128K */ + state &= 0xfffb; + state ^= (cart_state & 0x4000) >> 12; /* exchange 128k modules */ + /*case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M:*/ + } + return ((state & 0x0038) << 11) | ((state & 0x0004) << 15) | ((state & 0x03c0) << 12); +} + /* DB_32, XEGS_32, XEGS_07_64, XEGS_128, XEGS_256, XEGS_512, XEGS_1024, SWXEGS_32, SWXEGS_64, SWXEGS_128, SWXEGS_256, SWXEGS_512, SWXEGS_1024 */ static void set_bank_809F(int main, int old_state) @@ -167,9 +272,9 @@ static void set_bank_809F(int main, int old_state) else { MEMORY_Cart809fEnable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image + active_cart->state * 0x2000); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + active_cart->state * 0x2000); if (old_state & 0x80) - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + main); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + main); } } @@ -177,7 +282,7 @@ static void set_bank_809F(int main, int old_state) static void set_bank_XEGS_8F_64(void) { if (active_cart->state & 0x08) - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image + (active_cart->state & ~0x08) * 0x2000); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + (active_cart->state & ~0x08) * 0x2000); else /* $8000-$9FFF is left unconnected. */ MEMORY_dFillMem(0x8000, 0xff, 0x2000); @@ -194,9 +299,9 @@ static void set_bank_A0AF(int main, int old_state) /* Fill cart area with 0xFF. */ MEMORY_dFillMem(0xa000, 0xff, 0x1000); else - MEMORY_CopyROM(0xa000, 0xafff, active_cart->image + active_cart->state * 0x1000); + MEMORY_CopyFromCart(0xa000, 0xafff, active_cart->image + active_cart->state * 0x1000); if (old_state < 0) - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image + main); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image + main); } } @@ -210,7 +315,7 @@ static void set_bank_A0BF(int disable_mask, int bank_mask) MEMORY_CartA0bfDisable(); else { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + (active_cart->state & bank_mask) * 0x2000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + (active_cart->state & bank_mask) * 0x2000); } } @@ -225,7 +330,7 @@ static void set_bank_80BF(void) else { MEMORY_Cart809fEnable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0x8000, 0xbfff, active_cart->image + (active_cart->state & 0x7f) * 0x4000); + MEMORY_CopyFromCart(0x8000, 0xbfff, active_cart->image + (active_cart->state & 0x7f) * 0x4000); } } @@ -235,7 +340,7 @@ static void set_bank_SDX_128(void) MEMORY_CartA0bfDisable(); else { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + ((active_cart->state & 7) + ((active_cart->state & 0x10) >> 1)) * 0x2000); } } @@ -245,14 +350,14 @@ static void set_bank_SIC(int n) MEMORY_Cart809fDisable(); else { MEMORY_Cart809fEnable(); - MEMORY_CopyROM(0x8000, 0x9fff, + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + (active_cart->state & n) * 0x4000); } if (active_cart->state & 0x40) MEMORY_CartA0bfDisable(); else { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + (active_cart->state & n) * 0x4000 + 0x2000); } } @@ -267,15 +372,53 @@ static void set_bank_MEGA_4096(void) else { MEMORY_Cart809fEnable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0x8000, 0xbfff, active_cart->image + active_cart->state * 0x4000); + MEMORY_CopyFromCart(0x8000, 0xbfff, active_cart->image + active_cart->state * 0x4000); + } +} + +/* Ram-Cart */ +static void set_bank_RAMCART(int mask, int old_state) +{ + ULONG offset; + + if (old_state & 0x1000) { + if (old_state & 0x0002) { + offset = Calculate_RamCart_Address(active_cart->type, old_state & mask); + MEMORY_CopyToCart(0x8000, 0x9fff, active_cart->image + offset); + } + if (old_state & 0x0001) { + offset = Calculate_RamCart_Address(active_cart->type, old_state & mask); + MEMORY_CopyToCart(0xa000, 0xbfff, active_cart->image + offset + 0x2000); + } + } + + if (active_cart->state & 0x0002) { + offset = Calculate_RamCart_Address(active_cart->type, active_cart->state & mask); + MEMORY_Cart809fEnable(); + if (active_cart->state & 0x1000) + MEMORY_SetRAM(0x8000, 0x9fff); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + offset); + } + else + MEMORY_Cart809fDisable(); + + if ((active_cart->state & 0x0001) ^ ((active_cart->state & 0x1000) >> 12)) + MEMORY_CartA0bfDisable(); + else { + offset = Calculate_RamCart_Address(active_cart->type, active_cart->state & mask); + MEMORY_CartA0bfEnable(); + if (active_cart->state & 0x1000) + MEMORY_SetRAM(0xa000, 0xbfff); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + offset + 0x2000); } } + /* Called on a read or write operation to page $D5. Switches banks or enables/disables the cartridge pointed to by *active_cart. */ static void SwitchBank(int old_state) { /* All bank-switched cartridges besides two BBSB's are included in - this swithch. The BBSB cartridges are not bank-switched by + this switch. The BBSB cartridges are not bank-switched by access to page $D5, but in CARTRIDGE_BountyBob1() and CARTRIDGE_BountyBob2(), so they need not be processed here. */ switch (active_cart->type) { @@ -391,6 +534,24 @@ static void SwitchBank(int old_state) case CARTRIDGE_THECART_64M: set_bank_A0BF(0x4000, 0x1fff); break; + case CARTRIDGE_RAMCART_64: + set_bank_RAMCART(0x0018, old_state); + break; + case CARTRIDGE_RAMCART_128: + set_bank_RAMCART(0x0038, old_state); + break; + case CARTRIDGE_DOUBLE_RAMCART_256: + set_bank_RAMCART(0x603c, old_state); + break; + case CARTRIDGE_RAMCART_1M: + set_bank_RAMCART(0x00fc, old_state); + break; + case CARTRIDGE_RAMCART_2M: + set_bank_RAMCART(0x01fc, old_state); + break; + case CARTRIDGE_RAMCART_4M: + set_bank_RAMCART(0x03fc, old_state); + break; } #if DEBUG if (old_state != active_cart->state) @@ -398,6 +559,12 @@ static void SwitchBank(int old_state) #endif } +void CARTRIDGE_UpdateState(CARTRIDGE_image_t *cart, int old_state) +{ + if (cart == active_cart) + SwitchBank(old_state); +} + /* Maps *active_cart to memory. If the cartridge is bankswitched, the mapping is performed according to its current state (ie. it doesn't reset to bank 0 or whatever). */ @@ -410,18 +577,18 @@ static void MapActiveCart(void) MEMORY_SetROM(0x5ff6, 0x5ff9); switch (active_cart->type) { case CARTRIDGE_5200_32: - MEMORY_CopyROM(0x4000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0x4000, 0xbfff, active_cart->image); break; case CARTRIDGE_5200_EE_16: - MEMORY_CopyROM(0x4000, 0x5fff, active_cart->image); - MEMORY_CopyROM(0x6000, 0x9fff, active_cart->image); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x2000); + MEMORY_CopyFromCart(0x4000, 0x5fff, active_cart->image); + MEMORY_CopyFromCart(0x6000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x2000); break; case CARTRIDGE_5200_40: - MEMORY_CopyROM(0x4000, 0x4fff, active_cart->image + (active_cart->state & 0x03) * 0x1000); - MEMORY_CopyROM(0x5000, 0x5fff, active_cart->image + 0x4000 + ((active_cart->state & 0x0c) >> 2) * 0x1000); - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image + 0x8000); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x8000); + MEMORY_CopyFromCart(0x4000, 0x4fff, active_cart->image + (active_cart->state & 0x03) * 0x1000); + MEMORY_CopyFromCart(0x5000, 0x5fff, active_cart->image + 0x4000 + ((active_cart->state & 0x0c) >> 2) * 0x1000); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + 0x8000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x8000); #ifndef PAGED_ATTRIB MEMORY_SetHARDWARE(0x4ff6, 0x4ff9); MEMORY_SetHARDWARE(0x5ff6, 0x5ff9); @@ -433,17 +600,17 @@ static void MapActiveCart(void) #endif break; case CARTRIDGE_5200_NS_16: - MEMORY_CopyROM(0x8000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0xbfff, active_cart->image); break; case CARTRIDGE_5200_8: - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image); break; case CARTRIDGE_5200_4: - MEMORY_CopyROM(0x8000, 0x8fff, active_cart->image); - MEMORY_CopyROM(0x9000, 0x9fff, active_cart->image); - MEMORY_CopyROM(0xa000, 0xafff, active_cart->image); - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0x8fff, active_cart->image); + MEMORY_CopyFromCart(0x9000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0xa000, 0xafff, active_cart->image); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image); break; default: /* clear cartridge area so the 5200 will crash */ @@ -451,49 +618,49 @@ static void MapActiveCart(void) break; } } - else { + else { /* Atari800_machine_type != Atari800_MACHINE_5200 */ switch (active_cart->type) { case CARTRIDGE_STD_2: MEMORY_Cart809fDisable(); MEMORY_CartA0bfEnable(); MEMORY_dFillMem(0xa000, 0xff, 0x1800); - MEMORY_CopyROM(0xb800, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0xb800, 0xbfff, active_cart->image); break; case CARTRIDGE_STD_4: MEMORY_Cart809fDisable(); MEMORY_CartA0bfEnable(); MEMORY_dFillMem(0xa000, 0xff, 0x1000); - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image); break; case CARTRIDGE_BLIZZARD_4: MEMORY_Cart809fDisable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xafff, active_cart->image); - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0xa000, 0xafff, active_cart->image); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image); break; case CARTRIDGE_STD_8: case CARTRIDGE_PHOENIX_8: MEMORY_Cart809fDisable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image); break; case CARTRIDGE_LOW_BANK_8: MEMORY_Cart809fEnable(); MEMORY_CartA0bfDisable(); - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image); break; case CARTRIDGE_STD_16: case CARTRIDGE_BLIZZARD_16: MEMORY_Cart809fEnable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0x8000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0xbfff, active_cart->image); break; case CARTRIDGE_OSS_034M_16: case CARTRIDGE_OSS_043M_16: MEMORY_Cart809fDisable(); if (active_cart->state >= 0) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image + 0x3000); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image + 0x3000); } break; case CARTRIDGE_OSS_M091_16: @@ -501,7 +668,7 @@ static void MapActiveCart(void) MEMORY_Cart809fDisable(); if (active_cart->state >= 0) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xb000, 0xbfff, active_cart->image); + MEMORY_CopyFromCart(0xb000, 0xbfff, active_cart->image); } break; case CARTRIDGE_WILL_64: @@ -532,7 +699,7 @@ static void MapActiveCart(void) case CARTRIDGE_SWXEGS_32: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x6000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x6000); } break; case CARTRIDGE_XEGS_07_64: @@ -540,43 +707,43 @@ static void MapActiveCart(void) case CARTRIDGE_XEGS_8F_64: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0xe000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0xe000); } break; case CARTRIDGE_XEGS_128: case CARTRIDGE_SWXEGS_128: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x1e000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x1e000); } break; case CARTRIDGE_XEGS_256: case CARTRIDGE_SWXEGS_256: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x3e000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x3e000); } break; case CARTRIDGE_XEGS_512: case CARTRIDGE_SWXEGS_512: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x7e000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x7e000); } break; case CARTRIDGE_XEGS_1024: case CARTRIDGE_SWXEGS_1024: if (!(active_cart->state & 0x80)) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0xfe000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0xfe000); } break; case CARTRIDGE_BBSB_40: MEMORY_Cart809fEnable(); MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0x8000, 0x8fff, active_cart->image + (active_cart->state & 0x03) * 0x1000); - MEMORY_CopyROM(0x9000, 0x9fff, active_cart->image + 0x4000 + ((active_cart->state & 0x0c) >> 2) * 0x1000); - MEMORY_CopyROM(0xa000, 0xbfff, active_cart->image + 0x8000); + MEMORY_CopyFromCart(0x8000, 0x8fff, active_cart->image + (active_cart->state & 0x03) * 0x1000); + MEMORY_CopyFromCart(0x9000, 0x9fff, active_cart->image + 0x4000 + ((active_cart->state & 0x0c) >> 2) * 0x1000); + MEMORY_CopyFromCart(0xa000, 0xbfff, active_cart->image + 0x8000); #ifndef PAGED_ATTRIB MEMORY_SetHARDWARE(0x8ff6, 0x8ff9); MEMORY_SetHARDWARE(0x9ff6, 0x9ff9); @@ -592,10 +759,10 @@ static void MapActiveCart(void) if (Atari800_machine_type == Atari800_MACHINE_800) { MEMORY_Cart809fEnable(); MEMORY_dFillMem(0x8000, 0xff, 0x1000); - MEMORY_CopyROM(0x9000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0x9000, 0x9fff, active_cart->image); if ((!Atari800_disable_basic || BINLOAD_loading_basic) && MEMORY_have_basic) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, MEMORY_basic); + MEMORY_CopyFromCart(0xa000, 0xbfff, MEMORY_basic); } else MEMORY_CartA0bfDisable(); @@ -609,11 +776,11 @@ static void MapActiveCart(void) case CARTRIDGE_RIGHT_8: if (Atari800_machine_type == Atari800_MACHINE_800) { MEMORY_Cart809fEnable(); - MEMORY_CopyROM(0x8000, 0x9fff, active_cart->image); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image); if (!Atari800_builtin_basic && (!Atari800_disable_basic || BINLOAD_loading_basic) && MEMORY_have_basic) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, MEMORY_basic); + MEMORY_CopyFromCart(0xa000, 0xbfff, MEMORY_basic); } else MEMORY_CartA0bfDisable(); @@ -631,7 +798,7 @@ static void MapActiveCart(void) MEMORY_CartA0bfEnable(); /* Copy the chosen bank 32 times over 0xa000-0xbfff. */ for (i = 0xa000; i < 0xc000; i += 0x100) - MEMORY_CopyROM(i, i + 0xff, active_cart->image + (active_cart->state & 0xffff)); + MEMORY_CopyFromCart(i, i + 0xff, active_cart->image + (active_cart->state & 0xffff)); } break; case CARTRIDGE_MEGA_16: @@ -647,13 +814,19 @@ static void MapActiveCart(void) case CARTRIDGE_SIC_256: case CARTRIDGE_SIC_512: case CARTRIDGE_MEGAMAX_2048: + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: break; default: MEMORY_Cart809fDisable(); if (!Atari800_builtin_basic && (!Atari800_disable_basic || BINLOAD_loading_basic) && MEMORY_have_basic) { MEMORY_CartA0bfEnable(); - MEMORY_CopyROM(0xa000, 0xbfff, MEMORY_basic); + MEMORY_CopyFromCart(0xa000, 0xbfff, MEMORY_basic); } else MEMORY_CartA0bfDisable(); @@ -943,6 +1116,15 @@ static UBYTE GetByte(CARTRIDGE_image_t *cart, UWORD addr, int no_side_effects) return (~cart->state & 0x4000) >> 14; } break; + case CARTRIDGE_RAMCART_64: + return cart->state | 0x00e0; + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + return cart->state | 0x00c0; + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + return cart->state; } return 0xff; } @@ -1037,6 +1219,26 @@ static void PutByte(CARTRIDGE_image_t *cart, UWORD addr, UBYTE byte) break; } break; + case CARTRIDGE_RAMCART_64: + if (!(old_state & 0x0004)) /* lock bit not set */ + new_state = (old_state & 0xf000) | (byte & 0x1f); + break; + case CARTRIDGE_RAMCART_128: + if (!(old_state & 0x0004)) /* lock bit not set */ + new_state = (old_state & 0xf000) | (byte & 0x3f); + break; + case CARTRIDGE_DOUBLE_RAMCART_256: + if ((old_state & 0x2000) || !(old_state & 0x0004)) /* 256K mode or lock bit not set */ + new_state = (old_state & 0xf000) | (byte & 0x3f); + break; + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + if (old_state & 0x8000) /* modified version (jumpers ABC installed) */ + new_state = (old_state & 0xff00) | byte; + else /* stock version */ + new_state = (old_state & 0xffc4) | (byte & 0x3b); + break; default: /* Check types switchable by access to page D5. */ if (!access_D5(cart, addr, &new_state)) @@ -1112,13 +1314,13 @@ void CARTRIDGE_BountyBob1(UWORD addr) if (Atari800_machine_type == Atari800_MACHINE_5200) { if (addr >= 0x4ff6 && addr <= 0x4ff9) { addr -= 0x4ff6; - MEMORY_CopyROM(0x4000, 0x4fff, active_cart->image + addr * 0x1000); + MEMORY_CopyFromCart(0x4000, 0x4fff, active_cart->image + addr * 0x1000); active_cart->state = (active_cart->state & 0x0c) | addr; } } else { if (addr >= 0x8ff6 && addr <= 0x8ff9) { addr -= 0x8ff6; - MEMORY_CopyROM(0x8000, 0x8fff, active_cart->image + addr * 0x1000); + MEMORY_CopyFromCart(0x8000, 0x8fff, active_cart->image + addr * 0x1000); active_cart->state = (active_cart->state & 0x0c) | addr; } } @@ -1129,14 +1331,14 @@ void CARTRIDGE_BountyBob2(UWORD addr) if (Atari800_machine_type == Atari800_MACHINE_5200) { if (addr >= 0x5ff6 && addr <= 0x5ff9) { addr -= 0x5ff6; - MEMORY_CopyROM(0x5000, 0x5fff, active_cart->image + 0x4000 + addr * 0x1000); + MEMORY_CopyFromCart(0x5000, 0x5fff, active_cart->image + 0x4000 + addr * 0x1000); active_cart->state = (active_cart->state & 0x03) | (addr << 2); } } else { if (addr >= 0x9ff6 && addr <= 0x9ff9) { addr -= 0x9ff6; - MEMORY_CopyROM(0x9000, 0x9fff, active_cart->image + 0x4000 + addr * 0x1000); + MEMORY_CopyFromCart(0x9000, 0x9fff, active_cart->image + 0x4000 + addr * 0x1000); active_cart->state = (active_cart->state & 0x03) | (addr << 2); } } @@ -1389,9 +1591,65 @@ static void InitCartridge(CARTRIDGE_image_t *cart) MapActiveCart(); } +int CARTRIDGE_WriteImage(char *filename, int type, UBYTE *image, int size, int raw, UBYTE value) { + FILE *fp = fopen(filename, "wb"); + if (fp != NULL) { + if (!raw) { + UBYTE header[0x10]; + int checksum = 0; + if (image != NULL) + checksum = CARTRIDGE_Checksum(image, size); + + header[0x0] = 'C'; + header[0x1] = 'A'; + header[0x2] = 'R'; + header[0x3] = 'T'; + + header[0x4] = 0; + header[0x5] = 0; + header[0x6] = 0; + header[0x7] = type; + + header[0x8] = checksum >> 24; + header[0x9] = checksum >> 16; + header[0xa] = checksum >> 8; + header[0xb] = checksum; + + header[0xc] = 0; + header[0xd] = 0; + header[0xe] = 0; + header[0xf] = 0; + + fwrite(&header, 1, sizeof(header), fp); + } + if (image != NULL) + fwrite(image, 1, size, fp); + else + while (size-- > 0) + fwrite(&value, 1, 1, fp); + + fclose(fp); + return 0; + } + else { + Log_print("Error writing cartridge \"%s\".\n", filename); + return -1; + } +} + static void RemoveCart(CARTRIDGE_image_t *cart) { if (cart->image != NULL) { + switch (cart->type) { + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + CARTRIDGE_WriteImage(cart->filename, cart->type, cart->image, cart->size << 10, cart->raw, -1); + } + free(cart->image); cart->image = NULL; } @@ -1435,10 +1693,7 @@ void CARTRIDGE_ColdStart(void) { MapActiveCart(); } -/* Loads a cartridge from FILENAME. Copies FILENAME to CART_FILENAME. - Allocates a buffer with cartridge image data and puts it in *CART_IMAGE. - Sets *CART_TYPE to the cartridge type. */ -static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) +int CARTRIDGE_ReadImage(const char *filename, CARTRIDGE_image_t *cart) { FILE *fp; int len; @@ -1458,12 +1713,18 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) /* Save Filename for state save */ strcpy(cart->filename, filename); + cart->raw = TRUE; + /* if full kilobytes, assume it is raw image */ if ((len & 0x3ff) == 0) { /* alloc memory and read data */ cart->image = (UBYTE *) Util_malloc(len); if (fread(cart->image, 1, len, fp) < len) { Log_print("Error reading cartridge.\n"); + fclose(fp); + free(cart->image); + cart->image = NULL; + return CARTRIDGE_TOO_FEW_DATA; } fclose(fp); /* find cart type */ @@ -1481,16 +1742,19 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) } } if (cart->type != CARTRIDGE_NONE) { - InitCartridge(cart); + /*InitCartridge(cart);*/ return 0; /* ok */ } free(cart->image); cart->image = NULL; return CARTRIDGE_BAD_FORMAT; } + /* if not full kilobytes, assume it is CART file */ if (fread(header, 1, 16, fp) < 16) { Log_print("Error reading cartridge.\n"); + fclose(fp); + return CARTRIDGE_BAD_FORMAT; } if ((header[0] == 'C') && (header[1] == 'A') && @@ -1504,11 +1768,16 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) int checksum; int result; len = CARTRIDGE_kb[type] << 10; + cart->raw = FALSE; cart->size = CARTRIDGE_kb[type]; /* alloc memory and read data */ cart->image = (UBYTE *) Util_malloc(len); if (fread(cart->image, 1, len, fp) < len) { Log_print("Error reading cartridge.\n"); + fclose(fp); + free(cart->image); + cart->image = NULL; + return CARTRIDGE_TOO_FEW_DATA; } fclose(fp); checksum = (header[8] << 24) | @@ -1517,7 +1786,7 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) header[11]; cart->type = type; result = checksum == CARTRIDGE_Checksum(cart->image, len) ? 0 : CARTRIDGE_BAD_CHECKSUM; - InitCartridge(cart); + /*InitCartridge(cart);*/ return result; } } @@ -1525,6 +1794,18 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) return CARTRIDGE_BAD_FORMAT; } +/* Loads a cartridge from FILENAME. Copies FILENAME to CART_FILENAME. + Allocates a buffer with cartridge image data and puts it in *CART_IMAGE. + Sets *CART_TYPE to the cartridge type. */ +static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) +{ + int kb = CARTRIDGE_ReadImage(filename, cart); + if ((kb == CARTRIDGE_BAD_CHECKSUM) || (kb == 0)) { + InitCartridge(cart); + } + return kb; +} + int CARTRIDGE_Insert(const char *filename) { /* remove currently inserted cart */ @@ -1732,7 +2013,7 @@ void CARTRIDGE_StateRead(UBYTE version) int saved_type = CARTRIDGE_NONE; char filename[FILENAME_MAX]; - /* Read the cart type from the file. If there is no cart type, becaused we have + /* Read the cart type from the file. If there is no cart type, because we have reached the end of the file, this will just default to CART_NONE */ StateSav_ReadINT(&saved_type, 1); if (saved_type != CARTRIDGE_NONE) { @@ -1747,6 +2028,10 @@ void CARTRIDGE_StateRead(UBYTE version) if (version >= 7) /* Read the cartridge's state (current bank etc.). */ StateSav_ReadINT(&CARTRIDGE_main.state, 1); + if (version >= 8) { + /* Read the cartridge's image type (raw, cart - for RAM carts updating on remove). */ + StateSav_ReadINT(&CARTRIDGE_main.raw, 1); + } } else CARTRIDGE_main.type = saved_type; @@ -1781,9 +2066,13 @@ void CARTRIDGE_StateRead(UBYTE version) did not store the cartridge state. */ return; } + if (version >= 8) { + /* Read the cartridge's image type (raw, cart - for RAM carts updating on remove). */ + StateSav_ReadINT(&CARTRIDGE_piggyback.raw, 1); + } } - /* Determine active cartridge (main or piggyback. */ + /* Determine active cartridge (main or piggyback). */ if (CartIsPassthrough(CARTRIDGE_main.type) && (CARTRIDGE_main.state & 0x0c) == 0x08) active_cart = &CARTRIDGE_piggyback; else @@ -1806,6 +2095,7 @@ void CARTRIDGE_StateSave(void) if (CARTRIDGE_main.type != CARTRIDGE_NONE) { StateSav_SaveFNAME(CARTRIDGE_main.filename); StateSav_SaveINT(&CARTRIDGE_main.state, 1); + StateSav_SaveINT(&CARTRIDGE_main.raw, 1); } if (CARTRIDGE_piggyback.type != CARTRIDGE_NONE) { @@ -1813,6 +2103,7 @@ void CARTRIDGE_StateSave(void) StateSav_SaveINT(&CARTRIDGE_piggyback.type, 1); StateSav_SaveFNAME(CARTRIDGE_piggyback.filename); StateSav_SaveINT(&CARTRIDGE_piggyback.state, 1); + StateSav_SaveINT(&CARTRIDGE_piggyback.raw, 1); } } @@ -1821,3 +2112,4 @@ void CARTRIDGE_StateSave(void) /* vim:ts=4:sw=4: */ + diff --git a/src/cartridge.h b/src/cartridge.h index 4f30d85..e720b6d 100644 --- a/src/cartridge.h +++ b/src/cartridge.h @@ -77,11 +77,18 @@ enum { CARTRIDGE_ATRAX_128 = 68, CARTRIDGE_ADAWLIAH_32 = 69, CARTRIDGE_ADAWLIAH_64 = 70, - CARTRIDGE_LAST_SUPPORTED = 70 + CARTRIDGE_RAMCART_64 = 71, + CARTRIDGE_RAMCART_128 = 72, + CARTRIDGE_DOUBLE_RAMCART_256 = 73, + CARTRIDGE_RAMCART_1M = 74, + CARTRIDGE_RAMCART_2M = 75, + CARTRIDGE_RAMCART_4M = 76, + CARTRIDGE_LAST_SUPPORTED = 76 }; #define CARTRIDGE_MAX_SIZE (128 * 1024 * 1024) -extern int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1]; +extern const int CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1]; +extern const char *CARTRIDGE_desc[CARTRIDGE_LAST_SUPPORTED + 1]; #define CARTRIDGE_STD_8_DESC "Standard 8 KB cartridge" #define CARTRIDGE_STD_16_DESC "Standard 16 KB cartridge" @@ -153,18 +160,54 @@ extern int const CARTRIDGE_kb[CARTRIDGE_LAST_SUPPORTED + 1]; #define CARTRIDGE_ATRAX_128_DESC "Atrax 128 KB cartridge" #define CARTRIDGE_ADAWLIAH_32_DESC "aDawliah 32 KB cartridge" #define CARTRIDGE_ADAWLIAH_64_DESC "aDawliah 64 KB cartridge" +#define CARTRIDGE_RAMCART_64_DESC "Ram-Cart 64 KB cartridge" +#define CARTRIDGE_RAMCART_128_DESC "Ram-Cart 128 KB cartridge" +#define CARTRIDGE_DOUBLE_RAMCART_256_DESC "Double Ram-Cart 256 KB cartridge" +#define CARTRIDGE_RAMCART_1M_DESC "Ram-Cart 1 MB cartridge" +#define CARTRIDGE_RAMCART_2M_DESC "Ram-Cart 2 MB cartridge" +#define CARTRIDGE_RAMCART_4M_DESC "Ram-Cart 4 MB cartridge" /* Indicates whether the emulator should automatically reboot (coldstart) after inserting/removing a cartridge. (Doesn't affect the piggyback cartridge - in this case system will never autoreboot.) */ extern int CARTRIDGE_autoreboot; +/* + * Ram-Cart state flag bits meaning: + * --------------------------------- + * Lower byte contains value of control register at $D500 + * 0: $A000-$BFFF enable (0-on in ReadOnly mode and off in Read/Write mode, 1-off in RO and on in R/W mode) + * 1: $8000-$9FFF enable (0-off, 1-on) + * 2: lock in 64K/128K/2x128K (0-off, 1-on) + * 2: bank select in 256K and modified 1M/2M/4M (when ABC jumpers are installed) + * 2: read A switch in stock 1M/2M/4M (not affected by write) + * 3: bank select in 64K + * 4: bank select in 64K + * 5: bank select in 128K + * 6: bank select in modified 1M/2M/4M + * 6: read B switch in stock 1M/2M/4M (not affected by write) + * 7: bank select in modified 1M/2M/4M + * 7: read C switch in stock 1M/2M/4M (not affected by write) + * Upper byte contains state of switches on the top of case + * 8: 1/2M switch state in 2M + * 8: D switch state in 4M + * 9: 2/4 switch state in 4M + * 10: not used + * 11: not used + * 12: R/W switch state (0-ReadOnly, 1-Read/Write mode) + * 13: P1 switch state for Double Ram-Cart 2x128K/256K (0-2x128K, 1-256K mode) + * 14: P2 switch state for Double Ram-Cart 2x128K/256K + * (0-first module, 1-second module when cart is in 2x128K mode; + * 0-normal module order, 1-swapped module order when cart is in 256K mode) + * 15: jumpers ABC installed flag (0-stock mode, 1-jumpers installed) + */ typedef struct CARTRIDGE_image_t { int type; int state; /* Cartridge's state, such as selected bank or switch on/off. */ - int size; /* Size of the image, in kilobytes */ + int size; /* Size of the image, in kilobytes. */ UBYTE *image; char filename[FILENAME_MAX]; + int raw; /* File contains RAW data (important for writeable cartridges). */ } CARTRIDGE_image_t; extern CARTRIDGE_image_t CARTRIDGE_main; @@ -180,6 +223,7 @@ void CARTRIDGE_Exit(void); #define CARTRIDGE_CANT_OPEN -1 /* Can't open cartridge image file */ #define CARTRIDGE_BAD_FORMAT -2 /* Unknown cartridge format */ #define CARTRIDGE_BAD_CHECKSUM -3 /* Warning: bad CART checksum */ +#define CARTRIDGE_TOO_FEW_DATA -4 /* Too few data in file */ /* Inserts the left cartrifge. */ int CARTRIDGE_Insert(const char *filename); /* Inserts the left cartridge and reboots the system if needed. */ @@ -216,4 +260,8 @@ void CARTRIDGE_BountyBob1PutByte(UWORD addr, UBYTE value); void CARTRIDGE_BountyBob2PutByte(UWORD addr, UBYTE value); #endif +int CARTRIDGE_ReadImage(const char *filename, CARTRIDGE_image_t *cart); +int CARTRIDGE_WriteImage(char *filename, int type, UBYTE *image, int size, int raw, UBYTE value); + +void CARTRIDGE_UpdateState(CARTRIDGE_image_t *cart, int old_state); #endif /* CARTRIDGE_H_ */ diff --git a/src/memory.h b/src/memory.h index 7518121..4519ac6 100644 --- a/src/memory.h +++ b/src/memory.h @@ -116,7 +116,8 @@ void MEMORY_Cart809fDisable(void); void MEMORY_Cart809fEnable(void); void MEMORY_CartA0bfDisable(void); void MEMORY_CartA0bfEnable(void); -#define MEMORY_CopyROM(addr1, addr2, src) memcpy(MEMORY_mem + (addr1), src, (addr2) - (addr1) + 1) +#define MEMORY_CopyFromCart(addr1, addr2, src) memcpy(MEMORY_mem + (addr1), src, (addr2) - (addr1) + 1) +#define MEMORY_CopyToCart(addr1, addr2, dst) memcpy(dst, MEMORY_mem + (addr1), (addr2) - (addr1) + 1) void MEMORY_GetCharset(UBYTE *cs); /* Mosaic and Axlon 400/800 RAM extensions */ diff --git a/src/monitor.c b/src/monitor.c index 29d29da..ed194aa 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -44,6 +44,7 @@ #include "cpu.h" #include "gtia.h" #include "memory.h" +#include "cartridge.h" #include "monitor.h" #include "pia.h" #include "pokey.h" @@ -2630,6 +2631,129 @@ static void configure_labels(UWORD *addr) } #endif /* MONITOR_HINTS */ +static void print_flags(char *buf, char* flags, UWORD value) +{ + int i; + int l = strlen(flags); + for (i = 0; i < l; i++) + buf[i] = (value & (1 << (l-1-i))) + ? flags[i] + : '_'; +} + +static void show_cartridge_info(CARTRIDGE_image_t *cart, char *desc) +{ + if (cart->type != CARTRIDGE_NONE) { + printf("%s\n", desc); + printf("Type: %03i (%s)\n", cart->type, CARTRIDGE_desc[cart->type]); + printf("Image: %s (%s)\n", cart->filename, cart->raw ? "RAW" : "CART"); + + switch (cart->type) { + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + printf("Memory: $8000-$9FFF: %s $A000-$BFFF: %s\n", + (cart->state & 0x0002) ? "On " : "Off", + ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); + printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); + printf("Register: %s\n", (cart->state & 0x0002) ? "Locked" : "Enabled"); + printf("Bank: $%02X\n", (cart->state & 0x0038) >> 3); + break; + case CARTRIDGE_DOUBLE_RAMCART_256: + printf("Memory: $8000-$9FFF: %s $A000-$BFFF: %s\n", + (cart->state & 0x0002) ? "On " : "Off", + ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); + printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); + if (cart->state & 0x2000) { + printf( "Bank: $%02X 128K Module Order: %s 256K mode\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x004) << 1), + (cart->state & 0x4000) ? "Swapped" : "Normal " ); + } + else { + printf("Register: %s\n", (cart->state & 0x0002) ? "Locked" : "Enabled"); + printf( "Bank: $%02X 128K Module: %i 2x128K mode\n", + (cart->state & 0x0038) >> 3, + (cart->state & 0x4000) >> 14 ); + } + break; + case CARTRIDGE_RAMCART_1M: { + char switches[] = "---"; + printf("Memory: $8000-$9FFF: %s $A000-$BFFF: %s\n", + (cart->state & 0x0002) ? "On " : "Off", + ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); + printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); + if (cart->state & 0x8000) { + print_flags(switches, "---", (cart->state | 0x00ff) >> 5); + printf( "Bank: $%02X 1M Module: $%02X (%s) ABC jumpers installed\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x0004) << 1) | ((cart->state & 0x00c0) >> 2), + ((cart->state & 0x0300) >> 8), + switches ); + } + else { + print_flags(switches, "CBA", ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5) ); + printf( "Bank: $%02X 128K Module: $%02X (%s)\n", + ((cart->state & 0x0038) >> 3), + ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5), + switches ); + } + } + break; + case CARTRIDGE_RAMCART_2M: { + char switches[] = "----"; + printf("Memory: $8000-$9FFF: %s $A000-$BFFF: %s\n", + (cart->state & 0x0002) ? "On " : "Off", + ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); + printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); + if (cart->state & 0x8000) { + print_flags(switches, "1---", (cart->state | 0x00ff) >> 5); + printf( "Bank: $%02X 1M Module: $%02X (%s) ABC jumpers installed\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x0004) << 1) | ((cart->state & 0x00c0) >> 2), + ((cart->state & 0x0300) >> 8), + switches ); + } + else { + print_flags(switches, "1CBA", ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5) ); + printf( "Bank: $%02X 128K Module: $%02X (%s)\n", + ((cart->state & 0x0038) >> 3), + ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5), + switches ); + } + } + break; + case CARTRIDGE_RAMCART_4M: { + char switches[] = "-----"; + printf("Memory: $8000-$9FFF: %s $A000-$BFFF: %s\n", + (cart->state & 0x0002) ? "On " : "Off", + ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); + printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); + if (cart->state & 0x8000) { + print_flags(switches, "2D---", (cart->state | 0x00ff) >> 5); + printf( "Bank: $%02X 1M Module: $%02X (%s) ABC jumpers installed\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x0004) << 1) | ((cart->state & 0x00c0) >> 2), + ((cart->state & 0x0300) >> 8), + switches ); + } + else { + print_flags(switches, "2DCBA", ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5) ); + printf( "Bank: $%02X 128K Module: $%02X (%s)\n", + ((cart->state & 0x0038) >> 3), + ((cart->state & 0x0004) >> 2) | ((cart->state & 0x03c0) >> 5), + switches ); + } + } + break; + default: + printf("State: $%08X\n", cart->state); + } + } +} + +/* Displays cartridge info. */ +static void show_CARTRIDGE(void) +{ + show_cartridge_info(&CARTRIDGE_main, "Main"); + show_cartridge_info(&CARTRIDGE_piggyback, "Piggyback"); +} + /* Displays current ANTIC state. */ static void show_ANTIC(void) { @@ -2873,6 +2997,7 @@ static void show_help(void) "RAM startaddr endaddr - Convert memory block into RAM\n" "ROM startaddr endaddr - Convert memory block into ROM\n" "HARDWARE startaddr endaddr - Convert memory block into HARDWARE\n" + "CARTRIDGE - Show cartridge information\n" "READ filename startaddr nbytes - Read file into memory\n"); printf( "WRITE [XEX] startaddr endaddr [runaddr] [file]\n" @@ -3677,6 +3802,8 @@ int MONITOR_Run(void) else if (strcmp(t, "HARDWARE") == 0) monitor_set_hardware(); #endif /* PAGED_ATTRIB */ + else if (strcmp(t, "CARTRIDGE") == 0) + show_CARTRIDGE(); else if (strcmp(t, "COLDSTART") == 0) { Atari800_Coldstart(); PLUS_EXIT_MONITOR; diff --git a/src/ui.c b/src/ui.c index 8808790..9d6e099 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1005,82 +1005,88 @@ static void DiskManagement(void) } } +static UI_tMenuItem menu_array[] = { + UI_MENU_ACTION(CARTRIDGE_STD_8, CARTRIDGE_STD_8_DESC), + UI_MENU_ACTION(CARTRIDGE_STD_16, CARTRIDGE_STD_16_DESC), + UI_MENU_ACTION(CARTRIDGE_OSS_034M_16, CARTRIDGE_OSS_034M_16_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_32, CARTRIDGE_5200_32_DESC), + UI_MENU_ACTION(CARTRIDGE_DB_32, CARTRIDGE_DB_32_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_EE_16, CARTRIDGE_5200_EE_16_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_40, CARTRIDGE_5200_40_DESC), + UI_MENU_ACTION(CARTRIDGE_WILL_64, CARTRIDGE_WILL_64_DESC), + UI_MENU_ACTION(CARTRIDGE_EXP_64, CARTRIDGE_EXP_64_DESC), + UI_MENU_ACTION(CARTRIDGE_DIAMOND_64, CARTRIDGE_DIAMOND_64_DESC), + UI_MENU_ACTION(CARTRIDGE_SDX_64, CARTRIDGE_SDX_64_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_32, CARTRIDGE_XEGS_32_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_07_64, CARTRIDGE_XEGS_07_64_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_128, CARTRIDGE_XEGS_128_DESC), + UI_MENU_ACTION(CARTRIDGE_OSS_M091_16, CARTRIDGE_OSS_M091_16_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_NS_16, CARTRIDGE_5200_NS_16_DESC), + UI_MENU_ACTION(CARTRIDGE_ATRAX_DEC_128, CARTRIDGE_ATRAX_DEC_128_DESC), + UI_MENU_ACTION(CARTRIDGE_BBSB_40, CARTRIDGE_BBSB_40_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_8, CARTRIDGE_5200_8_DESC), + UI_MENU_ACTION(CARTRIDGE_5200_4, CARTRIDGE_5200_4_DESC), + UI_MENU_ACTION(CARTRIDGE_RIGHT_8, CARTRIDGE_RIGHT_8_DESC), + UI_MENU_ACTION(CARTRIDGE_WILL_32, CARTRIDGE_WILL_32_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_256, CARTRIDGE_XEGS_256_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_512, CARTRIDGE_XEGS_512_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_1024, CARTRIDGE_XEGS_1024_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_16, CARTRIDGE_MEGA_16_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_32, CARTRIDGE_MEGA_32_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_64, CARTRIDGE_MEGA_64_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_128, CARTRIDGE_MEGA_128_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_256, CARTRIDGE_MEGA_256_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_512, CARTRIDGE_MEGA_512_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_1024, CARTRIDGE_MEGA_1024_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_32, CARTRIDGE_SWXEGS_32_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_64, CARTRIDGE_SWXEGS_64_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_128, CARTRIDGE_SWXEGS_128_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_256, CARTRIDGE_SWXEGS_256_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_512, CARTRIDGE_SWXEGS_512_DESC), + UI_MENU_ACTION(CARTRIDGE_SWXEGS_1024, CARTRIDGE_SWXEGS_1024_DESC), + UI_MENU_ACTION(CARTRIDGE_PHOENIX_8, CARTRIDGE_PHOENIX_8_DESC), + UI_MENU_ACTION(CARTRIDGE_BLIZZARD_16, CARTRIDGE_BLIZZARD_16_DESC), + UI_MENU_ACTION(CARTRIDGE_ATMAX_128, CARTRIDGE_ATMAX_128_DESC), + UI_MENU_ACTION(CARTRIDGE_ATMAX_1024, CARTRIDGE_ATMAX_1024_DESC), + UI_MENU_ACTION(CARTRIDGE_SDX_128, CARTRIDGE_SDX_128_DESC), + UI_MENU_ACTION(CARTRIDGE_OSS_8, CARTRIDGE_OSS_8_DESC), + UI_MENU_ACTION(CARTRIDGE_OSS_043M_16, CARTRIDGE_OSS_043M_16_DESC), + UI_MENU_ACTION(CARTRIDGE_BLIZZARD_4, CARTRIDGE_BLIZZARD_4_DESC), + UI_MENU_ACTION(CARTRIDGE_AST_32, CARTRIDGE_AST_32_DESC), + UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_64, CARTRIDGE_ATRAX_SDX_64_DESC), + UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_128, CARTRIDGE_ATRAX_SDX_128_DESC), + UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_64, CARTRIDGE_TURBOSOFT_64_DESC), + UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_128, CARTRIDGE_TURBOSOFT_128_DESC), + UI_MENU_ACTION(CARTRIDGE_ULTRACART_32, CARTRIDGE_ULTRACART_32_DESC), + UI_MENU_ACTION(CARTRIDGE_LOW_BANK_8, CARTRIDGE_LOW_BANK_8_DESC), + UI_MENU_ACTION(CARTRIDGE_SIC_128, CARTRIDGE_SIC_128_DESC), + UI_MENU_ACTION(CARTRIDGE_SIC_256, CARTRIDGE_SIC_256_DESC), + UI_MENU_ACTION(CARTRIDGE_SIC_512, CARTRIDGE_SIC_512_DESC), + UI_MENU_ACTION(CARTRIDGE_STD_2, CARTRIDGE_STD_2_DESC), + UI_MENU_ACTION(CARTRIDGE_STD_4, CARTRIDGE_STD_4_DESC), + UI_MENU_ACTION(CARTRIDGE_RIGHT_4, CARTRIDGE_RIGHT_4_DESC), + UI_MENU_ACTION(CARTRIDGE_BLIZZARD_32, CARTRIDGE_BLIZZARD_32_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGAMAX_2048, CARTRIDGE_MEGAMAX_2048_DESC), + UI_MENU_ACTION(CARTRIDGE_THECART_128M, CARTRIDGE_THECART_128M_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_4096, CARTRIDGE_MEGA_4096_DESC), + UI_MENU_ACTION(CARTRIDGE_MEGA_2048, CARTRIDGE_MEGA_2048_DESC), + UI_MENU_ACTION(CARTRIDGE_THECART_32M, CARTRIDGE_THECART_32M_DESC), + UI_MENU_ACTION(CARTRIDGE_THECART_64M, CARTRIDGE_THECART_64M_DESC), + UI_MENU_ACTION(CARTRIDGE_XEGS_8F_64, CARTRIDGE_XEGS_8F_64_DESC), + UI_MENU_ACTION(CARTRIDGE_ATRAX_128, CARTRIDGE_ATRAX_128_DESC), + UI_MENU_ACTION(CARTRIDGE_ADAWLIAH_32, CARTRIDGE_ADAWLIAH_32_DESC), + UI_MENU_ACTION(CARTRIDGE_ADAWLIAH_64, CARTRIDGE_ADAWLIAH_64_DESC), + UI_MENU_ACTION(CARTRIDGE_RAMCART_64,CARTRIDGE_RAMCART_64_DESC), + UI_MENU_ACTION(CARTRIDGE_RAMCART_128,CARTRIDGE_RAMCART_128_DESC), + UI_MENU_ACTION(CARTRIDGE_DOUBLE_RAMCART_256,CARTRIDGE_DOUBLE_RAMCART_256_DESC), + UI_MENU_ACTION(CARTRIDGE_RAMCART_1M,CARTRIDGE_RAMCART_1M_DESC), + UI_MENU_ACTION(CARTRIDGE_RAMCART_2M,CARTRIDGE_RAMCART_2M_DESC), + UI_MENU_ACTION(CARTRIDGE_RAMCART_4M,CARTRIDGE_RAMCART_4M_DESC), + UI_MENU_END +}; + int UI_SelectCartType(int k) { - static UI_tMenuItem menu_array[] = { - UI_MENU_ACTION(CARTRIDGE_STD_8, CARTRIDGE_STD_8_DESC), - UI_MENU_ACTION(CARTRIDGE_STD_16, CARTRIDGE_STD_16_DESC), - UI_MENU_ACTION(CARTRIDGE_OSS_034M_16, CARTRIDGE_OSS_034M_16_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_32, CARTRIDGE_5200_32_DESC), - UI_MENU_ACTION(CARTRIDGE_DB_32, CARTRIDGE_DB_32_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_EE_16, CARTRIDGE_5200_EE_16_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_40, CARTRIDGE_5200_40_DESC), - UI_MENU_ACTION(CARTRIDGE_WILL_64, CARTRIDGE_WILL_64_DESC), - UI_MENU_ACTION(CARTRIDGE_EXP_64, CARTRIDGE_EXP_64_DESC), - UI_MENU_ACTION(CARTRIDGE_DIAMOND_64, CARTRIDGE_DIAMOND_64_DESC), - UI_MENU_ACTION(CARTRIDGE_SDX_64, CARTRIDGE_SDX_64_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_32, CARTRIDGE_XEGS_32_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_07_64, CARTRIDGE_XEGS_07_64_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_128, CARTRIDGE_XEGS_128_DESC), - UI_MENU_ACTION(CARTRIDGE_OSS_M091_16, CARTRIDGE_OSS_M091_16_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_NS_16, CARTRIDGE_5200_NS_16_DESC), - UI_MENU_ACTION(CARTRIDGE_ATRAX_DEC_128, CARTRIDGE_ATRAX_DEC_128_DESC), - UI_MENU_ACTION(CARTRIDGE_BBSB_40, CARTRIDGE_BBSB_40_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_8, CARTRIDGE_5200_8_DESC), - UI_MENU_ACTION(CARTRIDGE_5200_4, CARTRIDGE_5200_4_DESC), - UI_MENU_ACTION(CARTRIDGE_RIGHT_8, CARTRIDGE_RIGHT_8_DESC), - UI_MENU_ACTION(CARTRIDGE_WILL_32, CARTRIDGE_WILL_32_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_256, CARTRIDGE_XEGS_256_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_512, CARTRIDGE_XEGS_512_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_1024, CARTRIDGE_XEGS_1024_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_16, CARTRIDGE_MEGA_16_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_32, CARTRIDGE_MEGA_32_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_64, CARTRIDGE_MEGA_64_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_128, CARTRIDGE_MEGA_128_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_256, CARTRIDGE_MEGA_256_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_512, CARTRIDGE_MEGA_512_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_1024, CARTRIDGE_MEGA_1024_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_32, CARTRIDGE_SWXEGS_32_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_64, CARTRIDGE_SWXEGS_64_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_128, CARTRIDGE_SWXEGS_128_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_256, CARTRIDGE_SWXEGS_256_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_512, CARTRIDGE_SWXEGS_512_DESC), - UI_MENU_ACTION(CARTRIDGE_SWXEGS_1024, CARTRIDGE_SWXEGS_1024_DESC), - UI_MENU_ACTION(CARTRIDGE_PHOENIX_8, CARTRIDGE_PHOENIX_8_DESC), - UI_MENU_ACTION(CARTRIDGE_BLIZZARD_16, CARTRIDGE_BLIZZARD_16_DESC), - UI_MENU_ACTION(CARTRIDGE_ATMAX_128, CARTRIDGE_ATMAX_128_DESC), - UI_MENU_ACTION(CARTRIDGE_ATMAX_1024, CARTRIDGE_ATMAX_1024_DESC), - UI_MENU_ACTION(CARTRIDGE_SDX_128, CARTRIDGE_SDX_128_DESC), - UI_MENU_ACTION(CARTRIDGE_OSS_8, CARTRIDGE_OSS_8_DESC), - UI_MENU_ACTION(CARTRIDGE_OSS_043M_16, CARTRIDGE_OSS_043M_16_DESC), - UI_MENU_ACTION(CARTRIDGE_BLIZZARD_4, CARTRIDGE_BLIZZARD_4_DESC), - UI_MENU_ACTION(CARTRIDGE_AST_32, CARTRIDGE_AST_32_DESC), - UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_64, CARTRIDGE_ATRAX_SDX_64_DESC), - UI_MENU_ACTION(CARTRIDGE_ATRAX_SDX_128, CARTRIDGE_ATRAX_SDX_128_DESC), - UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_64, CARTRIDGE_TURBOSOFT_64_DESC), - UI_MENU_ACTION(CARTRIDGE_TURBOSOFT_128, CARTRIDGE_TURBOSOFT_128_DESC), - UI_MENU_ACTION(CARTRIDGE_ULTRACART_32, CARTRIDGE_ULTRACART_32_DESC), - UI_MENU_ACTION(CARTRIDGE_LOW_BANK_8, CARTRIDGE_LOW_BANK_8_DESC), - UI_MENU_ACTION(CARTRIDGE_SIC_128, CARTRIDGE_SIC_128_DESC), - UI_MENU_ACTION(CARTRIDGE_SIC_256, CARTRIDGE_SIC_256_DESC), - UI_MENU_ACTION(CARTRIDGE_SIC_512, CARTRIDGE_SIC_512_DESC), - UI_MENU_ACTION(CARTRIDGE_STD_2, CARTRIDGE_STD_2_DESC), - UI_MENU_ACTION(CARTRIDGE_STD_4, CARTRIDGE_STD_4_DESC), - UI_MENU_ACTION(CARTRIDGE_RIGHT_4, CARTRIDGE_RIGHT_4_DESC), - UI_MENU_ACTION(CARTRIDGE_BLIZZARD_32, CARTRIDGE_BLIZZARD_32_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGAMAX_2048, CARTRIDGE_MEGAMAX_2048_DESC), - UI_MENU_ACTION(CARTRIDGE_THECART_128M, CARTRIDGE_THECART_128M_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_4096, CARTRIDGE_MEGA_4096_DESC), - UI_MENU_ACTION(CARTRIDGE_MEGA_2048, CARTRIDGE_MEGA_2048_DESC), - UI_MENU_ACTION(CARTRIDGE_THECART_32M, CARTRIDGE_THECART_32M_DESC), - UI_MENU_ACTION(CARTRIDGE_THECART_64M, CARTRIDGE_THECART_64M_DESC), - UI_MENU_ACTION(CARTRIDGE_XEGS_8F_64, CARTRIDGE_XEGS_8F_64_DESC), - UI_MENU_ACTION(CARTRIDGE_ATRAX_128, CARTRIDGE_ATRAX_128_DESC), - UI_MENU_ACTION(CARTRIDGE_ADAWLIAH_32, CARTRIDGE_ADAWLIAH_32_DESC), - UI_MENU_ACTION(CARTRIDGE_ADAWLIAH_64, CARTRIDGE_ADAWLIAH_64_DESC), - UI_MENU_END - }; - int i; int option = 0; @@ -1105,6 +1111,34 @@ int UI_SelectCartType(int k) return CARTRIDGE_NONE; } +int UI_SelectCartTypeBetween(int *types) +{ + int i; + int j = 0; + int option = 0; + + UI_driver->fInit(); + + for (i = 1; i <= CARTRIDGE_LAST_SUPPORTED; i++) + if (i == types[j]) { + j++; + if (option == 0) + option = i; + menu_array[i - 1].flags = UI_ITEM_ACTION; + } + else + menu_array[i - 1].flags = UI_ITEM_HIDDEN; + + if (option == 0) + return CARTRIDGE_NONE; + + option = UI_driver->fSelect("Select Cartridge Type", 0, option, menu_array, NULL); + if (option > 0) + return option; + + return CARTRIDGE_NONE; +} + static void CartManagement(void) { static UI_tMenuItem menu_array[] = { @@ -1112,19 +1146,36 @@ static void CartManagement(void) UI_MENU_FILESEL(1, "Extract ROM image from Cartridge"), UI_MENU_FILESEL_PREFIX_TIP(2, "Cartridge:", NULL, NULL), UI_MENU_FILESEL_PREFIX_TIP(3, "Piggyback:", NULL, NULL), - UI_MENU_CHECK(4, "Reboot after cartridge change:"), + UI_MENU_CHECK(4, "Ram-Cart R/W switch:"), + UI_MENU_ACTION(5, "Ram-Cart P1 switch:"), + UI_MENU_ACTION(6, "Ram-Cart P2 switch:"), + UI_MENU_ACTION(7, "Ram-Cart ABC jumpers:"), + UI_MENU_CHECK(8, "Ram-Cart A switch:"), + UI_MENU_CHECK(9, "Ram-Cart B switch:"), + UI_MENU_CHECK(10, "Ram-Cart C switch:"), + UI_MENU_CHECK(11, "Ram-Cart 1/2M switch:"), /* or "Ram-Cart D switch" */ + UI_MENU_CHECK(12, "Ram-Cart 2/4M switch:"), + UI_MENU_CHECK(13, "Reboot after cartridge change:"), + UI_MENU_FILESEL(14, "Make blank Cartridge"), UI_MENU_END }; - - typedef struct { - UBYTE id[4]; - UBYTE type[4]; - UBYTE checksum[4]; - UBYTE gash[4]; - } Header; - + + /* Cartridge types should be placed here in ascending order and ended by CARTRIDGE_NONE */ + static int writable_carts_array[] = { + CARTRIDGE_RAMCART_64, + CARTRIDGE_RAMCART_128, + CARTRIDGE_DOUBLE_RAMCART_256, + CARTRIDGE_RAMCART_1M, + CARTRIDGE_RAMCART_2M, + CARTRIDGE_RAMCART_4M, + + CARTRIDGE_NONE /* obligatory */ + }; + int option = 2; int seltype; + CARTRIDGE_image_t *ramcart; + int old_state; for (;;) { static char cart_filename[FILENAME_MAX]; @@ -1152,128 +1203,180 @@ static void CartManagement(void) menu_array[3].flags = UI_ITEM_HIDDEN; } - SetItemChecked(menu_array, 4, CARTRIDGE_autoreboot); + ramcart = NULL; + switch (CARTRIDGE_main.type) { + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + ramcart = &CARTRIDGE_main; + break; + } + switch (CARTRIDGE_piggyback.type) { + case CARTRIDGE_RAMCART_64: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_DOUBLE_RAMCART_256: + case CARTRIDGE_RAMCART_1M: + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + ramcart = &CARTRIDGE_piggyback; + } + menu_array[4].flags = + menu_array[5].flags = + menu_array[6].flags = + menu_array[7].flags = + menu_array[8].flags = + menu_array[9].flags = + menu_array[10].flags = + menu_array[11].flags = + menu_array[12].flags = UI_ITEM_HIDDEN; + old_state = -1; + if (ramcart != NULL) { + old_state = ramcart->state; + + if (ramcart->type == CARTRIDGE_RAMCART_2M) + menu_array[11].item = "Ram-Cart 1/2M switch"; + else if (ramcart->type == CARTRIDGE_RAMCART_4M) + menu_array[11].item = "Ram-Cart D switch"; + + switch (ramcart->type) { + case CARTRIDGE_DOUBLE_RAMCART_256: + menu_array[5].flags = + menu_array[6].flags = UI_ITEM_ACTION; + if (ramcart->state & 0x2000) { + menu_array[5].suffix = "256K"; + menu_array[6].suffix = ramcart->state & 0x4000 ? "Swapped Order" : "Normal Order"; + } + else { + menu_array[5].suffix = "2x128K"; + menu_array[6].suffix = ramcart->state & 0x4000 ? "Second Module" : "First Module"; + } + SetItemChecked(menu_array, 4, ramcart->state & 0x1000); /* R/W */ + break; + case CARTRIDGE_RAMCART_4M: + SetItemChecked(menu_array, 12, ramcart->state & 0x0200); /* 2/4M */ + case CARTRIDGE_RAMCART_2M: + SetItemChecked(menu_array, 11, ramcart->state & 0x0100); /* 1/2M or D */ + case CARTRIDGE_RAMCART_1M: + menu_array[7].flags = UI_ITEM_ACTION; + if (ramcart->state & 0x8000) { + menu_array[10].flags = + menu_array[9].flags = + menu_array[8].flags = UI_ITEM_ACTION; + menu_array[10].suffix = + menu_array[9].suffix = + menu_array[8].suffix = "N/A"; + menu_array[7].suffix = "Installed"; + } + else { + SetItemChecked(menu_array, 10, ramcart->state & 0x0080); /* C */ + SetItemChecked(menu_array, 9, ramcart->state & 0x0040); /* B */ + SetItemChecked(menu_array, 8, ramcart->state & 0x0004); /* A */ + menu_array[7].suffix = "None"; + } + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_RAMCART_64: + SetItemChecked(menu_array, 4, ramcart->state & 0x1000); /* R/W */ + } + } + + SetItemChecked(menu_array, 13, CARTRIDGE_autoreboot); option = UI_driver->fSelect("Cartridge Management", 0, option, menu_array, &seltype); switch (option) { case 0: if (UI_driver->fGetLoadFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { - FILE *f; - int nbytes; - int type; - UBYTE *image; - int checksum; - Header header; - - f = fopen(cart_filename, "rb"); - if (f == NULL) { + int error; + CARTRIDGE_image_t cart; + + int kb = CARTRIDGE_ReadImage(cart_filename, &cart); + if (kb == CARTRIDGE_CANT_OPEN) { CantLoad(cart_filename); break; } - nbytes = Util_flen(f); - if ((nbytes & 0x3ff) != 0) { - fclose(f); - UI_driver->fMessage("ROM image must be full kilobytes long", 1); + else if (kb == CARTRIDGE_TOO_FEW_DATA) { + UI_driver->fMessage("Error reading CART file", 1); break; } - type = UI_SelectCartType(nbytes >> 10); - if (type == CARTRIDGE_NONE) { - fclose(f); + else if (kb == CARTRIDGE_BAD_FORMAT) { + UI_driver->fMessage("ROM image must be full kilobytes long", 1); break; } - image = (UBYTE *) Util_malloc(nbytes); - Util_rewind(f); - if ((int) fread(image, 1, nbytes, f) != nbytes) { - fclose(f); - CantLoad(cart_filename); + if (!cart.raw) { + free(cart.image); + UI_driver->fMessage("Not an image file", 1); break; } - fclose(f); - if (!UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) + cart.type = UI_SelectCartType(kb); + if (cart.type == CARTRIDGE_NONE) { + free(cart.image); break; + } - checksum = CARTRIDGE_Checksum(image, nbytes); - header.id[0] = 'C'; - header.id[1] = 'A'; - header.id[2] = 'R'; - header.id[3] = 'T'; - header.type[0] = '\0'; - header.type[1] = '\0'; - header.type[2] = '\0'; - header.type[3] = (UBYTE) type; - header.checksum[0] = (UBYTE) (checksum >> 24); - header.checksum[1] = (UBYTE) (checksum >> 16); - header.checksum[2] = (UBYTE) (checksum >> 8); - header.checksum[3] = (UBYTE) checksum; - header.gash[0] = '\0'; - header.gash[1] = '\0'; - header.gash[2] = '\0'; - header.gash[3] = '\0'; - - f = fopen(cart_filename, "wb"); - if (f == NULL) { - CantSave(cart_filename); + if (!UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { + free(cart.image); break; } - fwrite(&header, 1, sizeof(header), f); - fwrite(image, 1, nbytes, f); - fclose(f); - free(image); - Created(cart_filename); + + error = CARTRIDGE_WriteImage(cart_filename, cart.type, cart.image, kb << 10, FALSE, -1); + free(cart.image); + if (error) + CantSave(cart_filename); + else + Created(cart_filename); } break; case 1: if (UI_driver->fGetLoadFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { - FILE *f; - int nbytes; - Header header; - UBYTE *image; + int error; + CARTRIDGE_image_t cart; - f = fopen(cart_filename, "rb"); - if (f == NULL) { + int kb = CARTRIDGE_ReadImage(cart_filename, &cart); + if (kb == CARTRIDGE_CANT_OPEN) { CantLoad(cart_filename); break; } - nbytes = Util_flen(f) - sizeof(header); - Util_rewind(f); - if (nbytes <= 0 || fread(&header, 1, sizeof(header), f) != sizeof(header) - || header.id[0] != 'C' || header.id[1] != 'A' || header.id[2] != 'R' || header.id[3] != 'T') { - fclose(f); - UI_driver->fMessage("Not a CART file", 1); + else if (kb == CARTRIDGE_TOO_FEW_DATA) { + UI_driver->fMessage("Error reading CART file", 1); break; } - image = (UBYTE *) Util_malloc(nbytes); - if (fread(image, 1, nbytes, f) < nbytes) { - UI_driver->fMessage("Error reading CART file", 1); + else if (kb == CARTRIDGE_BAD_FORMAT) { + UI_driver->fMessage("Not a CART file", 1); break; } - fclose(f); - if (!UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) + if (cart.raw) { + free(cart.image); + UI_driver->fMessage("Not a CART file", 1); break; + } - f = fopen(cart_filename, "wb"); - if (f == NULL) { - CantSave(cart_filename); + if (!UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { + free(cart.image); break; } - fwrite(image, 1, nbytes, f); - fclose(f); - free(image); - Created(cart_filename); + + error = CARTRIDGE_WriteImage(cart_filename, CARTRIDGE_UNKNOWN, cart.image, cart.size << 10, TRUE, -1); + free(cart.image); + if (error) + CantSave(cart_filename); + else + Created(cart_filename); } break; case 2: switch (seltype) { case UI_USER_SELECT: /* Enter */ - if (UI_driver->fGetLoadFilename(CARTRIDGE_main.filename, UI_atari_files_dir, UI_n_atari_files_dir)) { - int r = CARTRIDGE_InsertAutoReboot(CARTRIDGE_main.filename); + if (UI_driver->fGetLoadFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { + int r = CARTRIDGE_InsertAutoReboot(cart_filename); switch (r) { case CARTRIDGE_CANT_OPEN: - CantLoad(CARTRIDGE_main.filename); + CantLoad(cart_filename); break; case CARTRIDGE_BAD_FORMAT: UI_driver->fMessage("Unknown cartridge format", 1); @@ -1299,11 +1402,11 @@ static void CartManagement(void) case 3: switch (seltype) { case UI_USER_SELECT: /* Enter */ - if (UI_driver->fGetLoadFilename(CARTRIDGE_piggyback.filename, UI_atari_files_dir, UI_n_atari_files_dir)) { - int r = CARTRIDGE_Insert_Second(CARTRIDGE_piggyback.filename); + if (UI_driver->fGetLoadFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { + int r = CARTRIDGE_Insert_Second(cart_filename); switch (r) { case CARTRIDGE_CANT_OPEN: - CantLoad(CARTRIDGE_piggyback.filename); + CantLoad(cart_filename); break; case CARTRIDGE_BAD_FORMAT: UI_driver->fMessage("Unknown cartridge format", 1); @@ -1326,9 +1429,64 @@ static void CartManagement(void) break; } break; - case 4: + case 4: /* R/W */ + ramcart->state ^= 0x1000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 5: /* P1 (2x128/256K) */ + ramcart->state ^= 0x2000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 6: /* P2 (Exchange 128K modules) */ + ramcart->state ^= 0x4000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 7: + ramcart->state ^= 0x8000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 8: /* A */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0004; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 9: /* B */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0040; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 10: /* C */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0080; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 11: /* 1/2M or D */ + ramcart->state ^= 0x0100; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 12: /* 2/4M */ + ramcart->state ^= 0x0200; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 13: CARTRIDGE_autoreboot = !CARTRIDGE_autoreboot; break; + case 14: + if (UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { + int cart_type = UI_SelectCartTypeBetween(writable_carts_array); + if (cart_type != CARTRIDGE_NONE) { + if ( CARTRIDGE_WriteImage( + cart_filename, + cart_type, NULL, CARTRIDGE_kb[cart_type] << 10, FALSE, 0x00 ) ) + CantSave(cart_filename); + else + Created(cart_filename); + } + } + break; default: return; } diff --git a/src/ui.h b/src/ui.h index bc01473..70c4fce 100644 --- a/src/ui.h +++ b/src/ui.h @@ -30,6 +30,7 @@ /* Three legitimate entries to UI module. */ int UI_SelectCartType(int k); +int UI_SelectCartTypeBetween(int *types); int UI_Initialise(int *argc, char *argv[]); void UI_Run(void); -- 2.17.1 From 31fcd4e61453fdbc3229505203c5995b5db1edb3 Mon Sep 17 00:00:00 2001 From: Jerzy Kut Date: Thu, 16 Apr 2020 00:17:40 +0200 Subject: [PATCH 2/3] Full address decoder option for 1M Zenon/Dial card. --- src/cartridge.c | 15 +++++++++------ src/cartridge.h | 6 ++++-- src/ui.c | 28 ++++++++++++++++++++-------- 3 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/cartridge.c b/src/cartridge.c index fb5f229..18a526b 100644 --- a/src/cartridge.c +++ b/src/cartridge.c @@ -1122,9 +1122,10 @@ static UBYTE GetByte(CARTRIDGE_image_t *cart, UWORD addr, int no_side_effects) case CARTRIDGE_DOUBLE_RAMCART_256: return cart->state | 0x00c0; case CARTRIDGE_RAMCART_1M: + if (!(cart->state & 0x10000) || (addr == 0xd500)) case CARTRIDGE_RAMCART_2M: case CARTRIDGE_RAMCART_4M: - return cart->state; + return cart->state; } return 0xff; } @@ -1232,12 +1233,14 @@ static void PutByte(CARTRIDGE_image_t *cart, UWORD addr, UBYTE byte) new_state = (old_state & 0xf000) | (byte & 0x3f); break; case CARTRIDGE_RAMCART_1M: + if (!(cart->state & 0x10000) || (addr == 0xd500)) case CARTRIDGE_RAMCART_2M: - case CARTRIDGE_RAMCART_4M: - if (old_state & 0x8000) /* modified version (jumpers ABC installed) */ - new_state = (old_state & 0xff00) | byte; - else /* stock version */ - new_state = (old_state & 0xffc4) | (byte & 0x3b); + case CARTRIDGE_RAMCART_4M: { + if (old_state & 0x8000) /* modified version (jumpers ABC installed) */ + new_state = (old_state & 0xff00) | byte; + else /* stock version */ + new_state = (old_state & 0xffc4) | (byte & 0x3b); + } break; default: /* Check types switchable by access to page D5. */ diff --git a/src/cartridge.h b/src/cartridge.h index e720b6d..60fbbb4 100644 --- a/src/cartridge.h +++ b/src/cartridge.h @@ -192,14 +192,16 @@ extern int CARTRIDGE_autoreboot; * 8: 1/2M switch state in 2M * 8: D switch state in 4M * 9: 2/4 switch state in 4M - * 10: not used - * 11: not used + * 10: reserved + * 11: reserved * 12: R/W switch state (0-ReadOnly, 1-Read/Write mode) * 13: P1 switch state for Double Ram-Cart 2x128K/256K (0-2x128K, 1-256K mode) * 14: P2 switch state for Double Ram-Cart 2x128K/256K * (0-first module, 1-second module when cart is in 2x128K mode; * 0-normal module order, 1-swapped module order when cart is in 256K mode) * 15: jumpers ABC installed flag (0-stock mode, 1-jumpers installed) + * Next byte contains additional flags for many variants of Zenon/Dial carts + * 16: full address decoder for 1M (0-not installed, 1-installed) */ typedef struct CARTRIDGE_image_t { int type; diff --git a/src/ui.c b/src/ui.c index 9d6e099..e2c619e 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1155,8 +1155,9 @@ static void CartManagement(void) UI_MENU_CHECK(10, "Ram-Cart C switch:"), UI_MENU_CHECK(11, "Ram-Cart 1/2M switch:"), /* or "Ram-Cart D switch" */ UI_MENU_CHECK(12, "Ram-Cart 2/4M switch:"), - UI_MENU_CHECK(13, "Reboot after cartridge change:"), - UI_MENU_FILESEL(14, "Make blank Cartridge"), + UI_MENU_ACTION(13, "Ram-Cart address decoder:"), + UI_MENU_CHECK(14, "Reboot after cartridge change:"), + UI_MENU_FILESEL(15, "Make blank Cartridge"), UI_MENU_END }; @@ -1199,9 +1200,8 @@ static void CartManagement(void) menu_array[3].item = CARTRIDGE_piggyback.filename; menu_array[3].suffix = "Return:insert Backspace:remove"; } - } else { + } else menu_array[3].flags = UI_ITEM_HIDDEN; - } ramcart = NULL; switch (CARTRIDGE_main.type) { @@ -1231,7 +1231,8 @@ static void CartManagement(void) menu_array[9].flags = menu_array[10].flags = menu_array[11].flags = - menu_array[12].flags = UI_ITEM_HIDDEN; + menu_array[12].flags = + menu_array[13].flags = UI_ITEM_HIDDEN; old_state = -1; if (ramcart != NULL) { old_state = ramcart->state; @@ -1260,6 +1261,13 @@ static void CartManagement(void) case CARTRIDGE_RAMCART_2M: SetItemChecked(menu_array, 11, ramcart->state & 0x0100); /* 1/2M or D */ case CARTRIDGE_RAMCART_1M: + if (ramcart->type == CARTRIDGE_RAMCART_1M) { + menu_array[13].flags = UI_ITEM_ACTION; + menu_array[13].suffix = ramcart->state & 0x10000 ? "Full" : "Simple"; + } + else + menu_array[13].suffix = "N/A"; + menu_array[7].flags = UI_ITEM_ACTION; if (ramcart->state & 0x8000) { menu_array[10].flags = @@ -1282,7 +1290,7 @@ static void CartManagement(void) } } - SetItemChecked(menu_array, 13, CARTRIDGE_autoreboot); + SetItemChecked(menu_array, 14, CARTRIDGE_autoreboot); option = UI_driver->fSelect("Cartridge Management", 0, option, menu_array, &seltype); @@ -1471,10 +1479,14 @@ static void CartManagement(void) ramcart->state ^= 0x0200; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 13: - CARTRIDGE_autoreboot = !CARTRIDGE_autoreboot; + case 13: /* address decoder */ + if (ramcart->type == CARTRIDGE_RAMCART_1M) + ramcart->state ^= 0x10000; break; case 14: + CARTRIDGE_autoreboot = !CARTRIDGE_autoreboot; + break; + case 15: if (UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { int cart_type = UI_SelectCartTypeBetween(writable_carts_array); if (cart_type != CARTRIDGE_NONE) { -- 2.17.1 From a8e6dfe82e080543202753ff6ee1b37854d7324f Mon Sep 17 00:00:00 2001 From: Jerzy Kut Date: Thu, 16 Apr 2020 23:38:36 +0200 Subject: [PATCH 3/3] Write Only/Read Write Control register option for Double Ram-Cart and Ram-Cart 1M. Reset button. Locked bit status fixed in monitor CARTRIDGE command. --- src/cartridge.c | 13 ++++++------ src/cartridge.h | 5 +++-- src/monitor.c | 4 ++-- src/ui.c | 55 +++++++++++++++++++++++++++++++++---------------- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/src/cartridge.c b/src/cartridge.c index 18a526b..263625f 100644 --- a/src/cartridge.c +++ b/src/cartridge.c @@ -253,9 +253,9 @@ static ULONG Calculate_RamCart_Address(int cart_type, int cart_state) case CARTRIDGE_DOUBLE_RAMCART_256: if (!(cart_state & 0x2000)) /* 2x128K */ state &= 0xfffb; + case CARTRIDGE_RAMCART_1M: state ^= (cart_state & 0x4000) >> 12; /* exchange 128k modules */ - /*case CARTRIDGE_RAMCART_1M: - case CARTRIDGE_RAMCART_2M: + /*case CARTRIDGE_RAMCART_2M: case CARTRIDGE_RAMCART_4M:*/ } return ((state & 0x0038) << 11) | ((state & 0x0004) << 15) | ((state & 0x03c0) << 12); @@ -1116,13 +1116,14 @@ static UBYTE GetByte(CARTRIDGE_image_t *cart, UWORD addr, int no_side_effects) return (~cart->state & 0x4000) >> 14; } break; - case CARTRIDGE_RAMCART_64: + /*case CARTRIDGE_RAMCART_64: return cart->state | 0x00e0; - case CARTRIDGE_RAMCART_128: + case CARTRIDGE_RAMCART_128:*/ case CARTRIDGE_DOUBLE_RAMCART_256: - return cart->state | 0x00c0; + if (cart->state & 0x20000) + return cart->state | 0x00c0; case CARTRIDGE_RAMCART_1M: - if (!(cart->state & 0x10000) || (addr == 0xd500)) + if ((!(cart->state & 0x10000) || (addr == 0xd500)) && (cart->state & 0x20000)) case CARTRIDGE_RAMCART_2M: case CARTRIDGE_RAMCART_4M: return cart->state; diff --git a/src/cartridge.h b/src/cartridge.h index 60fbbb4..c75112c 100644 --- a/src/cartridge.h +++ b/src/cartridge.h @@ -196,12 +196,13 @@ extern int CARTRIDGE_autoreboot; * 11: reserved * 12: R/W switch state (0-ReadOnly, 1-Read/Write mode) * 13: P1 switch state for Double Ram-Cart 2x128K/256K (0-2x128K, 1-256K mode) - * 14: P2 switch state for Double Ram-Cart 2x128K/256K + * 14: P2 switch state for Double Ram-Cart 2x128K/256K and 1M from Zenon/Dial * (0-first module, 1-second module when cart is in 2x128K mode; * 0-normal module order, 1-swapped module order when cart is in 256K mode) * 15: jumpers ABC installed flag (0-stock mode, 1-jumpers installed) * Next byte contains additional flags for many variants of Zenon/Dial carts - * 16: full address decoder for 1M (0-not installed, 1-installed) + * 16: full address decoder for 1M from Zenon/Dial (0-not installed, 1-installed) + * 17: control register type for 2x128K/256K and 1M from Zenon/Dial (0-write only, 1-read/write) */ typedef struct CARTRIDGE_image_t { int type; diff --git a/src/monitor.c b/src/monitor.c index ed194aa..397d876 100644 --- a/src/monitor.c +++ b/src/monitor.c @@ -2655,7 +2655,7 @@ static void show_cartridge_info(CARTRIDGE_image_t *cart, char *desc) (cart->state & 0x0002) ? "On " : "Off", ((cart->state & 0x0001) ^ ((cart->state & 0x1000) >> 12)) ? "Off" : "On " ); printf("Access: %s\n", (cart->state & 0x1000) ? "Read/Write" : "Read Only"); - printf("Register: %s\n", (cart->state & 0x0002) ? "Locked" : "Enabled"); + printf("Register: %s\n", (cart->state & 0x0004) ? "Locked" : "Enabled"); printf("Bank: $%02X\n", (cart->state & 0x0038) >> 3); break; case CARTRIDGE_DOUBLE_RAMCART_256: @@ -2669,7 +2669,7 @@ static void show_cartridge_info(CARTRIDGE_image_t *cart, char *desc) (cart->state & 0x4000) ? "Swapped" : "Normal " ); } else { - printf("Register: %s\n", (cart->state & 0x0002) ? "Locked" : "Enabled"); + printf("Register: %s\n", (cart->state & 0x0004) ? "Locked" : "Enabled"); printf( "Bank: $%02X 128K Module: %i 2x128K mode\n", (cart->state & 0x0038) >> 3, (cart->state & 0x4000) >> 14 ); diff --git a/src/ui.c b/src/ui.c index e2c619e..a6ffd5b 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1156,8 +1156,10 @@ static void CartManagement(void) UI_MENU_CHECK(11, "Ram-Cart 1/2M switch:"), /* or "Ram-Cart D switch" */ UI_MENU_CHECK(12, "Ram-Cart 2/4M switch:"), UI_MENU_ACTION(13, "Ram-Cart address decoder:"), - UI_MENU_CHECK(14, "Reboot after cartridge change:"), - UI_MENU_FILESEL(15, "Make blank Cartridge"), + UI_MENU_ACTION(14, "Ram-Cart control register:"), + UI_MENU_ACTION(15, "Ram-Cart Reset"), + UI_MENU_CHECK(16, "Reboot after cartridge change:"), + UI_MENU_FILESEL(17, "Make blank Cartridge"), UI_MENU_END }; @@ -1232,7 +1234,8 @@ static void CartManagement(void) menu_array[10].flags = menu_array[11].flags = menu_array[12].flags = - menu_array[13].flags = UI_ITEM_HIDDEN; + menu_array[13].flags = + menu_array[14].flags = UI_ITEM_HIDDEN; old_state = -1; if (ramcart != NULL) { old_state = ramcart->state; @@ -1244,6 +1247,9 @@ static void CartManagement(void) switch (ramcart->type) { case CARTRIDGE_DOUBLE_RAMCART_256: + menu_array[14].flags = UI_ITEM_ACTION; + menu_array[14].suffix = ramcart->state & 0x20000 ? "Read/Write" : "Write Only"; + menu_array[5].flags = menu_array[6].flags = UI_ITEM_ACTION; if (ramcart->state & 0x2000) { @@ -1262,8 +1268,12 @@ static void CartManagement(void) SetItemChecked(menu_array, 11, ramcart->state & 0x0100); /* 1/2M or D */ case CARTRIDGE_RAMCART_1M: if (ramcart->type == CARTRIDGE_RAMCART_1M) { - menu_array[13].flags = UI_ITEM_ACTION; - menu_array[13].suffix = ramcart->state & 0x10000 ? "Full" : "Simple"; + menu_array[6].flags = + menu_array[13].flags = + menu_array[14].flags = UI_ITEM_ACTION; + menu_array[6].suffix = ramcart->state & 0x4000 ? "Swapped Order" : "Normal Order"; + menu_array[13].suffix = ramcart->state & 0x10000 ? "Full" : "Simplified"; + menu_array[14].suffix = ramcart->state & 0x20000 ? "Read/Write" : "Write Only"; } else menu_array[13].suffix = "N/A"; @@ -1290,7 +1300,7 @@ static void CartManagement(void) } } - SetItemChecked(menu_array, 14, CARTRIDGE_autoreboot); + SetItemChecked(menu_array, 16, CARTRIDGE_autoreboot); option = UI_driver->fSelect("Cartridge Management", 0, option, menu_array, &seltype); @@ -1437,56 +1447,65 @@ static void CartManagement(void) break; } break; - case 4: /* R/W */ + case 4: /* Ram-Cart R/W */ ramcart->state ^= 0x1000; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 5: /* P1 (2x128/256K) */ + case 5: /* Ram-Cart P1 (2x128/256K) */ ramcart->state ^= 0x2000; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 6: /* P2 (Exchange 128K modules) */ + case 6: /* Ram-Cart P2 (Exchange 128K modules) */ ramcart->state ^= 0x4000; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 7: + case 7: /* Ram-Cart jumpers ABC installation flag */ ramcart->state ^= 0x8000; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 8: /* A */ + case 8: /* Ram-Cart A */ if (!(ramcart->state & 0x8000)) { ramcart->state ^= 0x0004; CARTRIDGE_UpdateState(ramcart, old_state); } break; - case 9: /* B */ + case 9: /* Ram-Cart B */ if (!(ramcart->state & 0x8000)) { ramcart->state ^= 0x0040; CARTRIDGE_UpdateState(ramcart, old_state); } break; - case 10: /* C */ + case 10: /* Ram-Cart C */ if (!(ramcart->state & 0x8000)) { ramcart->state ^= 0x0080; CARTRIDGE_UpdateState(ramcart, old_state); } break; - case 11: /* 1/2M or D */ + case 11: /* Ram-Cart 1/2M or D */ ramcart->state ^= 0x0100; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 12: /* 2/4M */ + case 12: /* Ram-Cart 2/4M */ ramcart->state ^= 0x0200; CARTRIDGE_UpdateState(ramcart, old_state); break; - case 13: /* address decoder */ + case 13: /* Ram-Cart address decoder */ if (ramcart->type == CARTRIDGE_RAMCART_1M) ramcart->state ^= 0x10000; break; - case 14: + case 14: /* Ram-Cart control register */ + if (ramcart->type == CARTRIDGE_DOUBLE_RAMCART_256 || ramcart->type == CARTRIDGE_RAMCART_1M) + ramcart->state ^= 0x20000; + break; + case 15: /* Ram-Cart Reset */ + ramcart->state &= 0xfff00; + CARTRIDGE_UpdateState(ramcart, old_state); + UI_driver->fMessage("Ram-Cart reinitialized", 1); + break; + case 16: CARTRIDGE_autoreboot = !CARTRIDGE_autoreboot; break; - case 15: + case 17: if (UI_driver->fGetSaveFilename(cart_filename, UI_atari_files_dir, UI_n_atari_files_dir)) { int cart_type = UI_SelectCartTypeBetween(writable_carts_array); if (cart_type != CARTRIDGE_NONE) { -- 2.17.1