diff --git a/DOC/CREDITS b/DOC/CREDITS index ee9d5fd7..140f13d7 100644 --- a/DOC/CREDITS +++ b/DOC/CREDITS @@ -254,8 +254,11 @@ 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/8M/16M/32M + and Double Ram-Cart 2x128K/256K cartridges support + - SiDiCar 32K cartridge support Chris Lam - RGB values for each Atari colour diff --git a/DOC/NEWS b/DOC/NEWS index 3906fafa..2f442e53 100644 --- a/DOC/NEWS +++ b/DOC/NEWS @@ -21,6 +21,16 @@ Big thanks to all contributors (see git log for each commit author) - 73: Super Cart 256 KB 5200 cartridge (32K banks) - 74: Super Cart 512 KB 5200 cartridge (32K banks) - 75: Atarimax 1 MB Flash cartridge (new) + - 94: Ram-Cart 64 KB cartridge + - 95: Ram-Cart 128 KB cartridge + - 96: Double Ram-Cart 2x128/256 KB cartridge + - 97: Ram-Cart 1 MB cartridge + - 98: Ram-Cart 2 MB cartridge + - 99: Ram-Cart 4 MB cartridge + - 100: Ram-Cart 8 MB cartridge + - 101: Ram-Cart 16 MB cartridge + - 102: Ram-Cart 32 MB cartridge + - 103: SiDiCar 32 KB cartridge See DOC/cart.txt for details. * support for remapping of all function keys (START, SELECT, OPTION etc) diff --git a/DOC/README b/DOC/README index 61df9f23..d759b2ee 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 86 cartridge types, raw and CART format. o Cassette recorder, raw and CAS images. diff --git a/DOC/USAGE b/DOC/USAGE index 57ed72a5..ee0efd6b 100644 --- a/DOC/USAGE +++ b/DOC/USAGE @@ -145,12 +145,12 @@ Command line options -basic Turn on Atari BASIC ROM -cart Insert cartridge (CART or raw format) --cart-type <0..75> Select type of cartridge inserted with -cart. 0 means +-cart-type <0..160> 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..75> Similar to -cart-type. Select type of cartridge inserted +-cart2-type <0..160> 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 b5f3afdd..fe418c20 100644 --- a/DOC/cart.txt +++ b/DOC/cart.txt @@ -125,6 +125,16 @@ Currently supported cartridge types: | 91 | 800/XL/XE | 256 | XE Multicart (256KB) | x | | 92 | 800/XL/XE | 512 | XE Multicart (512KB) | x | | 93 | 800/XL/XE | 1024 | XE Multicart (1024KB) | x | +| 94 | 800/XL/XE | 64 | Ram-Cart 64 KB cartridge | | +| 95 | 800/XL/XE | 128 | Ram-Cart 128 KB cartridge | | +| 96 | 800/XL/XE | 256 | Double Ram-Cart 2x128/256 KB cartridge | | +| 97 | 800/XL/XE | 1M | Ram-Cart 1 MB cartridge | | +| 98 | 800/XL/XE | 2M | Ram-Cart 2 MB cartridge | | +| 99 | 800/XL/XE | 4M | Ram-Cart 4 MB cartridge | | +|100 | 800/XL/XE | 8M | Ram-Cart 8 MB cartridge | | +|101 | 800/XL/XE | 16M | Ram-Cart 16 MB cartridge | | +|102 | 800/XL/XE | 32M | Ram-Cart 32 MB cartridge | | +|103 | 800/XL/XE | 32 | SiDiCar 32 KB cartridge | | |160 | 800/XL/XE | 64 |JRC64 cartridge (interleaved) | x | +----+-----------+------+-----------------------------------------------+---+ @@ -851,6 +861,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. @@ -1345,6 +1356,406 @@ Reference: http://www.retrobits.net/atari/osshack.shtml Reference: https://blog.idorobots.org/entries/atari-xe-multicart.html + +---------------------------------------------------------------------------+ + | Type 94: 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#64%20KB + + +---------------------------------------------------------------------------+ + | Type 95: Ram-Cart 128 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's identical to cartridge type 94 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#128%20KB + + +---------------------------------------------------------------------------+ + | Type 96: Double Ram-Cart 2x128/256 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company. + It's similar to cartridge type 95 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 94 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#2x128%20KB%20/%20256%20KB + + +---------------------------------------------------------------------------+ + | Type 97: Ram-Cart 1 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by Unerring Masters company then refectored + and republished in new form by GALTRON company. + It's similar to cartridge type 95 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#1%20MB + + +---------------------------------------------------------------------------+ + | Type 98: Ram-Cart 2 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by GALTRON company. + It's identical to cartridge type 97. + + 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#2%20MB + + +---------------------------------------------------------------------------+ + | Type 99: Ram-Cart 4 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by GALTRON company. + It's identical to cartridge type 97. + + 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#4%20MB + + +---------------------------------------------------------------------------+ + | Type 100: Ram-Cart 8 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by GALTRON company. + It's identical to cartridge type 97 but extended with additional control register. + + There are no switches beside R/W and RESET on the top of case, so bank is selected + only by software. + + Control register CARTCTL ($D500) 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 - bank select bit 3 + 3 - bank select bit 0 + 4 - bank select bit 1 + 5 - bank select bit 2 + 6 - bank select bit 4 + 7 - bank select bit 5 + + Additional register MODSEL ($D501) is using to select 1MB memory module. + Bits meaning: + + 0 - module select bit 0 + 1 - module select bit 1 + 2 - module select bit 2 + 3 - not connected + 4 - not connected + 5 - not connected + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %02107625 43xxxxxx xxxxxxxx + ::::::: :::::::: :::::::: + ::::::: ::++++++-++++++++-- address bus A0..A13 + :::++++-++----------------- CARCTL register bits + +++------------------------ MODSEL register bits + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#8%2C%2016%20i%2032%20MB + + +---------------------------------------------------------------------------+ + | Type 101: Ram-Cart 16 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by GALTRON company. + It's identical to cartridge type 97 but extended with additional control register. + + There are no switches beside R/W and RESET on the top of case, so bank is selected + only by software. + + Control register CARTCTL ($D500) 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 - bank select bit 3 + 3 - bank select bit 0 + 4 - bank select bit 1 + 5 - bank select bit 2 + 6 - bank select bit 4 + 7 - bank select bit 5 + + Additional register MODSEL ($D501) is using to select 1MB memory module. + Bits meaning: + + 0 - module select bit 0 + 1 - module select bit 1 + 2 - module select bit 2 + 3 - module select bit 3 + 4 - not connected + 5 - not connected + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %32107625 43xxxxxx xxxxxxxx + ::::::: :::::::: :::::::: + :::::::: ::++++++-++++++++-- address bus A0..A13 + ::::++++-++----------------- CARCTL register bits + ++++------------------------ MODSEL register bits + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#8%2C%2016%20i%2032%20MB + + +---------------------------------------------------------------------------+ + | Type 102: Ram-Cart 32 MB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge released by GALTRON company. + It's identical to cartridge type 97 but extended with additional control register. + + There are no switches beside R/W and RESET on the top of case, so bank is selected + only by software. + + Control register CARTCTL ($D500) 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 - bank select bit 3 + 3 - bank select bit 0 + 4 - bank select bit 1 + 5 - bank select bit 2 + 6 - bank select bit 4 + 7 - bank select bit 5 + + Additional register MODSEL ($D501) is using to select 1MB memory module. + Bits meaning: + + 0 - module select bit 0 + 1 - module select bit 1 + 2 - module select bit 2 + 3 - module select bit 3 + 4 - module select bit 4 + 5 - not connected + 6 - not connected + 7 - not connected + + Cartridge memory address bits mapping: + + %00000004 32107625 43xxxxxx xxxxxxxx + : :::::::: :::::::: :::::::: + : :::::::: ::++++++-++++++++-- address bus A0..A13 + : ::::++++-++----------------- CARCTL register bits + +-++++------------------------ MODSEL register bits + + Reference: + http://atariki.krap.pl/index.php/Ram-Cart#8%2C%2016%20i%2032%20MB + + +---------------------------------------------------------------------------+ + | Type 103: SiDiCar 32 KB cartridge | + +---------------------------------------------------------------------------+ + + A bank switched cartridge described by "Tajemnice Atari" magazine closely + related to polish software publisher L.K.Avalon. + It uses CMOS static RAM 62256 chip with battery power supplied and small logic + providing control register to select memory bank and making its visibility + in Atari memory area. + + RAM is divided into four 8K banks visible in $8000..$9FFF area. + Write only control register CARSET is located in $D5FF, however it's available + on whole $D5 page because only /CCTL line is used to build simplified decoder. + + Control register bits meaning: + + 0 - bank select + 1 - bank select + 2 - not connected + 3 - not connected + 4 - $8000..$9FFF window enable: 0-disabled, 1-enabled + 5 - not connected + 6 - not connected + 7 - write to control register 0-enabled, 1-disabled + + Cartridge memory address bits mapping: + + %010xxxxx xxxxxxxx + ::::::: :::::::: + ::+++++-++++++++-- address bus A0..A12 + ++---------------- control register bits + + Control register contains $00 on power-on. + + Reference: + http://atariki.krap.pl/index.php/SiDiCar + +---------------------------------------------------------------------------+ | Type 160: JRC64 cartridge (interleaved) | +---------------------------------------------------------------------------+ diff --git a/src/atari800.man b/src/atari800.man index fa66f3ef..db62d3e6 100644 --- a/src/atari800.man +++ b/src/atari800.man @@ -269,7 +269,7 @@ Turn on Atari BASIC ROM .BI \-cart\ filename Insert cartridge (CART or raw format) .TP -.BR "\-cart\-type 0" .. 75 +.BR "\-cart\-type 0 .. 160" Select type of the cartridge inserted with the \fB\-cart\fR option. When inserting a raw ROM image its type cannot be detected automaticcaly, and must be provided with this option. @@ -503,6 +503,42 @@ Super Cart 512 KB 5200 cartridge (32K banks) .TP .B 75 Atarimax 1 MB Flash cartridge (new) +.TP +.B 76-93 +Reserved +.TP +.B 94 +Ram-Cart 64 KB cartridge +.TP +.B 95 +Ram-Cart 128 KB cartridge +.TP +.B 96 +Double Ram-Cart 2x128/256 KB cartridge +.TP +.B 97 +Ram-Cart 1 MB cartridge +.TP +.B 98 +Ram-Cart 2 MB cartridge +.TP +.B 99 +Ram-Cart 4 MB cartridge +.TP +.B 100 +Ram-Cart 8 MB cartridge +.TP +.B 101 +Ram-Cart 16 MB cartridge +.TP +.B 102 +Ram-Cart 32 MB cartridge +.TP +.B 103 +SiDiCar 32 KB cartridge +.TP +.B 104-160 +Reserved .PD .PP If this option is not given, the user will be asked to choose the cartridge @@ -514,7 +550,7 @@ Insert piggyback cartridge (CART or raw format). This works only if the first cartridge is a pass-through (currently only SpartaDOS X 64KB and 128KB types). .TP -.BR "\-cart2\-type 0" .. 75 +.BR "\-cart2\-type 0 .. 160" Select type of the cartridge inserted with the \fB-cart2\fR option. When inserting a raw ROM image its type cannot be detected automatically, and must be provided with this option. diff --git a/src/cartridge.c b/src/cartridge.c index e8c75966..48ee9c36 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-2023 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. @@ -78,14 +78,40 @@ 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; + case CARTRIDGE_RAMCART_1M: + state ^= (cart_state & 0x4000) >> 12; /* exchange 128k modules */ + /*case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_32M:*/ + } + return ((state & 0x0038) << 11) | ((state & 0x0004) << 15) | ((state & 0x0fc0) << 12) | ((state & 0x40000) << 6); +} + +static ULONG Calculate_SiDiCar_Address(int cart_type, int cart_state) +{ + return (cart_state & 0x0003) << 11; +} + /* 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) @@ -97,9 +123,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); } } @@ -107,7 +133,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); @@ -124,9 +150,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); } } @@ -140,7 +166,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); } } @@ -155,13 +181,13 @@ 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); } } static void set_bank_5200_SUPER(void) { - MEMORY_CopyROM(0x4000, 0xbfff, active_cart->image + active_cart->state * 0x8000); + MEMORY_CopyFromCart(0x4000, 0xbfff, active_cart->image + active_cart->state * 0x8000); } static void set_bank_SDX_128(void) @@ -170,7 +196,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); } } @@ -180,14 +206,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); } } @@ -202,15 +228,73 @@ 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); + } +} + +/* SiDiCar */ +static void set_bank_SIDICAR(int mask, int old_state) +{ + ULONG offset; + + if (old_state & 0x10) { + offset = Calculate_SiDiCar_Address(active_cart->type, old_state & mask); + MEMORY_CopyToCart(0x8000, 0x9fff, active_cart->image + offset); } + + if (active_cart->state & 0x10) { + offset = Calculate_SiDiCar_Address(active_cart->type, active_cart->state & mask); + MEMORY_Cart809fEnable(); + MEMORY_SetRAM(0x8000, 0x9fff); + MEMORY_CopyFromCart(0x8000, 0x9fff, active_cart->image + offset); + } + else + MEMORY_Cart809fDisable(); } + /* 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) { @@ -327,6 +411,36 @@ static void SwitchBank(int old_state) case CARTRIDGE_THECART_64M: set_bank_A0BF(0x4000, 0x1fff); break; + case CARTRIDGE_RAMCART_64: + set_bank_RAMCART(0x00018, old_state); + break; + case CARTRIDGE_RAMCART_128: + set_bank_RAMCART(0x00038, old_state); + break; + case CARTRIDGE_DOUBLE_RAMCART_256: + set_bank_RAMCART(0x0603c, old_state); + break; + case CARTRIDGE_RAMCART_1M: + set_bank_RAMCART(0x000fc, old_state); + break; + case CARTRIDGE_RAMCART_2M: + set_bank_RAMCART(0x001fc, old_state); + break; + case CARTRIDGE_RAMCART_4M: + set_bank_RAMCART(0x003fc, old_state); + break; + case CARTRIDGE_RAMCART_8M: + set_bank_RAMCART(0x007fc, old_state); + break; + case CARTRIDGE_RAMCART_16M: + set_bank_RAMCART(0x00ffc, old_state); + break; + case CARTRIDGE_RAMCART_32M: + set_bank_RAMCART(0x40ffc, old_state); + break; + case CARTRIDGE_SIDICAR_32: + set_bank_SIDICAR(0x03, old_state); + break; } #if DEBUG if (old_state != active_cart->state) @@ -334,6 +448,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). */ @@ -359,18 +479,18 @@ static void MapActiveCart(void) #endif break; 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); @@ -382,17 +502,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 */ @@ -400,49 +520,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: @@ -450,7 +570,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: @@ -482,7 +602,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: @@ -490,43 +610,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); @@ -542,10 +662,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(); @@ -559,11 +679,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(); @@ -581,7 +701,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: @@ -597,13 +717,23 @@ 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: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_32M: + case CARTRIDGE_SIDICAR_32: 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(); @@ -894,6 +1024,27 @@ static UBYTE GetByte(CARTRIDGE_image_t *cart, UWORD addr, int no_side_effects) return (~cart->state & 0x4000) >> 14; } break; + case CARTRIDGE_RAMCART_32M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_8M: + if (addr == 0xd501) + return ((cart->state & 0x0f00) >> 8) | ((cart->state & 0x40000) >> 14); + else + case CARTRIDGE_RAMCART_4M: + case CARTRIDGE_RAMCART_2M: + if (addr == 0xd500) + return cart->state; + break; + case CARTRIDGE_RAMCART_1M: + if ((!(cart->state & 0x10000) || (addr == 0xd500)) && (cart->state & 0x20000)) + return cart->state; + break; + case CARTRIDGE_DOUBLE_RAMCART_256: + if (cart->state & 0x20000) + return cart->state | 0x00c0; + /*case CARTRIDGE_RAMCART_128: + case CARTRIDGE_RAMCART_64: + return cart->state | 0x00e0;*/ } return 0xff; } @@ -988,6 +1139,55 @@ 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 & 0x7f000) | (byte & 0x1f); + break; + case CARTRIDGE_RAMCART_128: + if (!(old_state & 0x0004)) /* lock bit not set */ + new_state = (old_state & 0x7f000) | (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 & 0x7f000) | (byte & 0x3f); + break; + case CARTRIDGE_RAMCART_1M: + if (!(cart->state & 0x10000) || (addr == 0xd500)) { + if (old_state & 0x8000) /* modified version (jumpers ABC installed) */ + new_state = (old_state & 0x7ff00) | byte; + else /* stock version */ + new_state = (old_state & 0x7ffc4) | (byte & 0x3b); + } + break; + case CARTRIDGE_RAMCART_2M: + case CARTRIDGE_RAMCART_4M: + if (addr == 0xd500) { + if (old_state & 0x8000) /* modified version (jumpers ABC installed) */ + new_state = (old_state & 0x7ff00) | byte; + else /* stock version */ + new_state = (old_state & 0x7ffc4) | (byte & 0x3b); + } + break; + case CARTRIDGE_RAMCART_8M: + if (addr == 0xd501) + new_state = (old_state & 0x3f0ff) | ((byte & 0x07) << 8); + else + case CARTRIDGE_RAMCART_16M: + if (addr == 0xd501) + new_state = (old_state & 0x3f0ff) | ((byte & 0x0f) << 8); + else + case CARTRIDGE_RAMCART_32M: + if (addr == 0xd501) + new_state = (old_state & 0x3f0ff) | ((byte & 0x0f) << 8) | ((byte & 0x10) << 14); + else if (addr == 0xd500) + new_state = (old_state & 0x7ff00) | byte; + break; + case CARTRIDGE_SIDICAR_32: + /* Although the $D5FF location is proposed by the author for the CARSET control register, + a simplified decoder built based on the use of the /CCTL signal is used. */ + if (/*(addr == 0xd5ff) &&*/ !(byte & 0x80)) + new_state = byte & 0x13; + break; default: /* Check types switchable by access to page D5. */ if (!access_D5(cart, addr, &new_state)) @@ -1069,7 +1269,7 @@ static void access_BountyBob1(UWORD addr) addr -= 0xf6; new_state = (active_cart->state & 0x0c) | addr; if (new_state != active_cart->state) { - MEMORY_CopyROM(base_addr, base_addr + 0x0fff, + MEMORY_CopyFromCart(base_addr, base_addr + 0x0fff, active_cart->image + addr * 0x1000); active_cart->state = new_state; } @@ -1086,7 +1286,7 @@ static void access_BountyBob2(UWORD addr) addr -= 0xf6; new_state = (active_cart->state & 0x03) | (addr << 2); if (new_state != active_cart->state) { - MEMORY_CopyROM(base_addr, base_addr + 0x0fff, + MEMORY_CopyFromCart(base_addr, base_addr + 0x0fff, active_cart->image + 0x4000 + addr * 0x1000); active_cart->state = new_state; } @@ -1329,9 +1529,69 @@ 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: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_32M: + case CARTRIDGE_SIDICAR_32: + CARTRIDGE_WriteImage(cart->filename, cart->type, cart->image, cart->size << 10, cart->raw, -1); + } + free(cart->image); cart->image = NULL; } @@ -1375,21 +1635,7 @@ void CARTRIDGE_ColdStart(void) { MapActiveCart(); } -/* Loads a cartridge from FILENAME. Copies FILENAME to CART->FILENAME. - If loading failed, sets CART->TYPE to CARTRIDGE_NONE and returns one of: - * CARTRIDGE_CANT_OPEN if there was an error when opening file, - * CARTRIDGE_BAD_FORMAT if the file is not a proper cartridge image. - - If loading succeeded, allocates a buffer with cartridge image data and puts - it in CART->IMAGE. Then sets CART->TYPE if possible, and returns one of: - * 0 if cartridge type was recognized; CART->TYPE is then set correctly; - * CARTRIDGE_BAD_CHECKSUM if cartridge is a CART file but with invalid - checksum; CART->TYPE is then set correctly; - * a positive integer: size in KB if cartridge type was not guessed; - CART->TYPE is then set to CARTRIDGE_UNKNOWN. The caller is expected to - select a cartridge type according to the returned size, and call either - CARTRIDGE_SetType() or CARTRIDGE_SetTypeAutoReboot(). */ -static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) +int CARTRIDGE_ReadImage(const char *filename, CARTRIDGE_image_t *cart) { FILE *fp; int len; @@ -1409,12 +1655,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 */ @@ -1432,16 +1684,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') && @@ -1455,11 +1710,16 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) int checksum; int result; len = CARTRIDGES[type].kb << 10; + cart->raw = FALSE; cart->size = CARTRIDGES[type].kb; /* 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) | @@ -1468,7 +1728,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; } } @@ -1476,6 +1736,29 @@ static int InsertCartridge(const char *filename, CARTRIDGE_image_t *cart) return CARTRIDGE_BAD_FORMAT; } +/* Loads a cartridge from FILENAME. Copies FILENAME to CART->FILENAME. + If loading failed, sets CART->TYPE to CARTRIDGE_NONE and returns one of: + * CARTRIDGE_CANT_OPEN if there was an error when opening file, + * CARTRIDGE_BAD_FORMAT if the file is not a proper cartridge image. + + If loading succeeded, allocates a buffer with cartridge image data and puts + it in CART->IMAGE. Then sets CART->TYPE if possible, and returns one of: + * 0 if cartridge type was recognized; CART->TYPE is then set correctly; + * CARTRIDGE_BAD_CHECKSUM if cartridge is a CART file but with invalid + checksum; CART->TYPE is then set correctly; + * a positive integer: size in KB if cartridge type was not guessed; + CART->TYPE is then set to CARTRIDGE_UNKNOWN. The caller is expected to + select a cartridge type according to the returned size, and call either + CARTRIDGE_SetType() or CARTRIDGE_SetTypeAutoReboot(). */ +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 */ @@ -1683,7 +1966,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) { @@ -1698,6 +1981,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; @@ -1732,9 +2019,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 @@ -1757,6 +2048,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) { @@ -1764,6 +2056,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); } } @@ -1772,3 +2065,4 @@ void CARTRIDGE_StateSave(void) /* vim:ts=4:sw=4: */ + diff --git a/src/cartridge.h b/src/cartridge.h index bab9cf2a..4209b2a5 100644 --- a/src/cartridge.h +++ b/src/cartridge.h @@ -10,12 +10,48 @@ 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 + * 8: bank select in 8/16/32M + * 9: 2/4 switch state in 4M + * 9: bank select in 8/16/32M + * 10: bank select in 8/16/32M + * 11: bank select in 16/32M + * 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 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 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) + * 18: bank select in 32M + */ 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; @@ -29,6 +65,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 cartridge from FILENAME. Copies FILENAME to CARTRIDGE_main.filename. @@ -95,4 +132,8 @@ void CARTRIDGE_BountyBob2PutByte(UWORD addr, UBYTE value); /* addr must be $bfxx in 5200 mode only. */ void CARTRIDGE_5200SuperCartPutByte(UWORD addr, UBYTE value); +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/cartridge_info.c b/src/cartridge_info.c index c5803048..cb4ba875 100644 --- a/src/cartridge_info.c +++ b/src/cartridge_info.c @@ -26,7 +26,7 @@ #include "cartridge.h" cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { - { "NONE", 0 }, + { "NONE", 0 }, /* 0 */ { "Standard 8 KB cartridge", 8 }, { "Standard 16 KB cartridge", 16 }, { "OSS two chip 16 KB cartridge (034M)", 16 }, @@ -36,7 +36,7 @@ cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { { "Bounty Bob 40 KB 5200 cartridge", 40 }, { "64 KB Williams cartridge", 64 }, { "Express 64 KB cartridge", 64 }, - { "Diamond 64 KB cartridge", 64 }, + { "Diamond 64 KB cartridge", 64 }, /* 10 */ { "SpartaDOS X 64 KB cartridge", 64 }, { "XEGS 32 KB cartridge", 32 }, { "XEGS 64 KB cartridge (banks 0-7)", 64 }, @@ -46,7 +46,7 @@ cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { { "Decoded Atrax 128 KB cartridge", 128 }, { "Bounty Bob 40 KB cartridge", 40 }, { "Standard 8 KB 5200 cartridge", 8 }, - { "Standard 4 KB 5200 cartridge", 4 }, + { "Standard 4 KB 5200 cartridge", 4 }, /* 20 */ { "Right slot 8 KB cartridge", 8 }, { "32 KB Williams cartridge", 32 }, { "XEGS 256 KB cartridge", 256 }, @@ -56,17 +56,17 @@ cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { { "MegaCart 32 KB cartridge", 32 }, { "MegaCart 64 KB cartridge", 64 }, { "MegaCart 128 KB cartridge", 128 }, - { "MegaCart 256 KB cartridge", 256 }, + { "MegaCart 256 KB cartridge", 256 }, /* 30 */ { "MegaCart 512 KB cartridge", 512 }, { "MegaCart 1 MB cartridge", 1024 }, { "Switchable XEGS 32 KB cartridge", 32 }, - { "Switchable XEGS 64 KB cartridge", 64 }, + { "Switchable XEGS 64 KB cartridge", 64 }, { "Switchable XEGS 128 KB cartridge", 128 }, { "Switchable XEGS 256 KB cartridge", 256 }, { "Switchable XEGS 512 KB cartridge", 512 }, { "Switchable XEGS 1 MB cartridge", 1024 }, { "Phoenix 8 KB cartridge", 8 }, - { "Blizzard 16 KB cartridge", 16 }, + { "Blizzard 16 KB cartridge", 16 }, /* 40 */ { "Atarimax 128 KB Flash cartridge", 128 }, { "Atarimax 1 MB Flash cartridge (old)", 1024 }, { "SpartaDOS X 128 KB cartridge", 128 }, @@ -76,17 +76,17 @@ cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { { "AST 32 KB cartridge", 32 }, { "Atrax SDX 64 KB cartridge", 64 }, { "Atrax SDX 128 KB cartridge", 128 }, - { "Turbosoft 64 KB cartridge", 64 }, + { "Turbosoft 64 KB cartridge", 64 }, /* 50 */ { "Turbosoft 128 KB cartridge", 128 }, { "Ultracart 32 KB cartridge", 32 }, - { "Low bank 8 KB cartridge", 8 }, + { "Low bank 8 KB cartridge", 8 }, { "SIC! 128 KB cartridge", 128 }, { "SIC! 256 KB cartridge", 256 }, { "SIC! 512 KB cartridge", 512 }, - { "Standard 2 KB cartridge", 2 }, + { "Standard 2 KB cartridge", 2 }, { "Standard 4 KB cartridge", 4 }, { "Right slot 4 KB cartridge", 4 }, - { "Blizzard 32 KB cartridge", 32 }, + { "Blizzard 32 KB cartridge", 32 }, /* 60 */ { "MegaMax 2 MB cartridge", 2048 }, { "The!Cart 128 MB cartridge", 128*1024 }, { "Flash MegaCart 4 MB cartridge", 4*1024 }, @@ -96,12 +96,101 @@ cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT] = { { "XEGS 64 KB cartridge (banks 8-15)", 64 }, { "Atrax 128 KB cartridge", 128 }, { "aDawliah 32 KB cartridge", 32 }, - { "aDawliah 64 KB cartridge", 64 }, + { "aDawliah 64 KB cartridge", 64 }, /* 70 */ { "Super Cart 64 KB 5200 cartridge", 64 }, { "Super Cart 128 KB 5200 cartridge", 128 }, { "Super Cart 256 KB 5200 cartridge", 256 }, { "Super Cart 512 KB 5200 cartridge", 512 }, - { "Atarimax 1 MB Flash cartridge (new)", 1024 } + { "Atarimax 1 MB Flash cartridge (new)", 1024 }, + + { "16 KB Williams cartridge", 16 }, + { "MIO diagnostics 8KB cartridge", 8 }, + { "Telelink II cartridge", 8 }, + { "Pronto cartridge", 16 }, + { "JRC64 cartridge (linear)", 64 }, /* 80 */ + { "MDDOS cartridge", 64 }, + { "COS32 cartridge", 32 }, + { "SIC+ 1024 KB cartridge", 1024 }, + { "Corina 1M + 8K EEPROM cartridge", 1024 }, + { "Corina 512K + 512K SRAM + 8K EEPROM cartridge", 512 }, + { "XE Multicart (8KB) cartridge", 8 }, + { "XE Multicart (16KB) cartridge", 16 }, + { "XE Multicart (32KB) cartridge", 32 }, + { "XE Multicart (64KB) cartridge", 64 }, + { "XE Multicart (128KB) cartridge", 128 }, /* 90 */ + { "XE Multicart (256KB) cartridge", 256 }, + { "XE Multicart (512KB) cartridge", 512 }, + { "XE Multicart (1024KB) cartridge", 1024 }, + + { "Ram-Cart 64 KB cartridge", 64 }, + { "Ram-Cart 128 KB cartridge", 128 }, + { "Double Ram-Cart 256 KB cartridge", 256 }, + { "Ram-Cart 1 MB cartridge", 1*1024 }, + { "Ram-Cart 2 MB cartridge", 2*1024 }, + { "Ram-Cart 4 MB cartridge", 4*1024 }, + { "Ram-Cart 8 MB cartridge", 8*1024 }, /* 100 */ + { "Ram-Cart 16 MB cartridge", 16*1024 }, + { "Ram-Cart 32 MB cartridge", 32*1024 }, + { "SiDiCar 32 KB cartridge", 32 }, + + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, /* 110 */ + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, /* 120 */ + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, /* 130 */ + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, /* 140 */ + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, /* 150 */ + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + { "", 0 }, + + { "JRC64 cartridge (interleaved)", 64 } /* 160 */ }; int CARTRIDGE_Checksum(const UBYTE *image, int nbytes) diff --git a/src/cartridge_info.h b/src/cartridge_info.h index cdff8bcb..1e1814b8 100644 --- a/src/cartridge_info.h +++ b/src/cartridge_info.h @@ -116,7 +116,39 @@ enum { CARTRIDGE_5200_SUPER_256 = 73, CARTRIDGE_5200_SUPER_512 = 74, CARTRIDGE_ATMAX_NEW_1024 = 75, - CARTRIDGE_TYPE_COUNT = 76 + + CARTRIDGE_WILL_16 = 76, + CARTRIDGE_MIO_DIAG_8 = 77, + CARTRIDGE_TELELINK2 = 78, + CARTRIDGE_PRONTO = 79, + CARTRIDGE_JRC64_LIN = 80, + CARTRIDGE_MDDOS = 81, + CARTRIDGE_COS32 = 82, + CARTRIDGE_SICPLUS_1024 = 83, + CARTRIDGE_CORINA_1024_8 = 84, + CARTRIDGE_CORINA_512_512_8 = 85, + CARTRIDGE_XEMULTI_8 = 86, + CARTRIDGE_XEMULTI_16 = 87, + CARTRIDGE_XEMULTI_32 = 88, + CARTRIDGE_XEMULTI_64 = 89, + CARTRIDGE_XEMULTI_128 = 90, + CARTRIDGE_XEMULTI_256 = 91, + CARTRIDGE_XEMULTI_512 = 92, + CARTRIDGE_XEMULTI_1024 = 93, + + CARTRIDGE_RAMCART_64 = 94, + CARTRIDGE_RAMCART_128 = 95, + CARTRIDGE_DOUBLE_RAMCART_256 = 96, + CARTRIDGE_RAMCART_1M = 97, + CARTRIDGE_RAMCART_2M = 98, + CARTRIDGE_RAMCART_4M = 99, + CARTRIDGE_RAMCART_8M = 100, + CARTRIDGE_RAMCART_16M = 101, + CARTRIDGE_RAMCART_32M = 102, + CARTRIDGE_SIDICAR_32 = 103, + + CARTRIDGE_JRC64_INT = 160, + CARTRIDGE_TYPE_COUNT = 161 }; extern cart_t const CARTRIDGES[CARTRIDGE_TYPE_COUNT]; diff --git a/src/memory.h b/src/memory.h index 75181210..4519ac6b 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 29d29da5..d84e1202 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" @@ -1261,7 +1262,7 @@ static void monitor_breakpoints(void) printf("X%s%02X", op, MONITOR_breakpoint_table[i].value); break; case MONITOR_BREAKPOINT_Y >> 3: - printf("A%s%02X", op, MONITOR_breakpoint_table[i].value); + printf("Y%s%02X", op, MONITOR_breakpoint_table[i].value); break; case MONITOR_BREAKPOINT_S >> 3: printf("S%s%02X", op, MONITOR_breakpoint_table[i].value); @@ -2630,6 +2631,160 @@ 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 cartridge\n", desc); + printf("Type: %03i (%s)\n", cart->type, CARTRIDGES[cart->type].description); + 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 & 0x0004) ? "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 & 0x0004) ? "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; + case CARTRIDGE_RAMCART_8M: + 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( "Bank: $%02X 1M Module: $%02X\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x0004) << 1) | ((cart->state & 0x00c0) >> 2), + ((cart->state & 0x0700) >> 8) ); + break; + case CARTRIDGE_RAMCART_16M: + 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( "Bank: $%02X 1M Module: $%02X\n", + ((cart->state & 0x0038) >> 3) | ((cart->state & 0x0004) << 1) | ((cart->state & 0x00c0) >> 2), + ((cart->state & 0x0f00) >> 8) ); + break; + case CARTRIDGE_RAMCART_32M: + 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( "Bank: $%02X 1M Module: $%02X\n", + ((cart->state & 0x00038) >> 3) | ((cart->state & 0x00004) << 1) | ((cart->state & 0x000c0) >> 2), + ((cart->state & 0x00f00) >> 8) | ((cart->state & 0x40000) >> 14) ); + break; + case CARTRIDGE_SIDICAR_32: + printf("Memory: $8000-$9FFF: %s\n", (cart->state & 0x10) ? "On" : "Off"); + printf("Bank: $%02X\n", (cart->state & 0x03)); + 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,8 +3028,9 @@ 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" - "READ filename startaddr nbytes - Read file into memory\n"); + "CART - Show cartridge information\n"); printf( + "READ filename startaddr nbytes - Read file into memory\n" "WRITE [XEX] startaddr endaddr [runaddr] [file]\n" " - Write memory block to a file (memdump.dat).\n" " With XEX, writes an Atari executable with\n" @@ -3677,6 +3833,8 @@ int MONITOR_Run(void) else if (strcmp(t, "HARDWARE") == 0) monitor_set_hardware(); #endif /* PAGED_ATTRIB */ + else if (strcmp(t, "CART") == 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 a9caca76..b05116e9 100644 --- a/src/ui.c +++ b/src/ui.c @@ -1016,13 +1016,11 @@ int UI_SelectCartType(int k) UI_driver->fInit(); - for (cart_entry = 1; cart_entry < CARTRIDGE_TYPE_COUNT; - cart_entry++) { + for (cart_entry = 1; cart_entry < CARTRIDGE_TYPE_COUNT; cart_entry++) { if (CARTRIDGES[cart_entry].kb == k) { menu_array[menu_entry].flags = UI_ITEM_ACTION; menu_array[menu_entry].retval = cart_entry; - menu_array[menu_entry].item = - CARTRIDGES[cart_entry].description; + menu_array[menu_entry].item = CARTRIDGES[cart_entry].description; menu_entry++; } } @@ -1033,8 +1031,38 @@ int UI_SelectCartType(int k) /* Terminate menu_array, but do it by hand */ menu_array[menu_entry].flags = UI_ITEM_END; - option = UI_driver->fSelect("Select Cartridge Type", 0, option, - menu_array, NULL); + option = UI_driver->fSelect("Select Cartridge Type", 0, option, menu_array, NULL); + if (option > 0) + return option; + + return CARTRIDGE_NONE; +} + +int UI_SelectCartTypeBetween(int *types) +{ + UI_tMenuItem menu_array[CARTRIDGE_TYPE_COUNT] = { 0 }; + int cart_entry; + int menu_entry = 0; + int option = 0; + + UI_driver->fInit(); + + for (cart_entry = 1; cart_entry < CARTRIDGE_TYPE_COUNT; cart_entry++) { + if (cart_entry == types[menu_entry]) { + menu_array[menu_entry].flags = UI_ITEM_ACTION; + menu_array[menu_entry].retval = cart_entry; + menu_array[menu_entry].item = CARTRIDGES[cart_entry].description; + menu_entry++; + } + } + + if (menu_entry == 0) + return CARTRIDGE_NONE; + + /* Terminate menu_array, but do it by hand */ + menu_array[menu_entry].flags = UI_ITEM_END; + + option = UI_driver->fSelect("Select Cartridge Type", 0, option, menu_array, NULL); if (option > 0) return option; @@ -1048,19 +1076,43 @@ 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_ACTION(13, "Ram-Cart address decoder:"), + 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 }; - - 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_RAMCART_8M, + CARTRIDGE_RAMCART_16M, + CARTRIDGE_RAMCART_32M, + CARTRIDGE_SIDICAR_32, + + CARTRIDGE_NONE /* obligatory */ + }; + int option = 2; int seltype; + CARTRIDGE_image_t *ramcart; + int old_state; for (;;) { static char cart_filename[FILENAME_MAX]; @@ -1084,132 +1136,210 @@ 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) { + 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: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_32M: + 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: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_32M: + 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 = + menu_array[13].flags = + menu_array[14].flags = + menu_array[15].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[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) { + 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: + if (ramcart->type == CARTRIDGE_RAMCART_1M) { + 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"; + + 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_32M: + case CARTRIDGE_RAMCART_16M: + case CARTRIDGE_RAMCART_8M: + case CARTRIDGE_RAMCART_128: + case CARTRIDGE_RAMCART_64: + SetItemChecked(menu_array, 4, ramcart->state & 0x1000); /* R/W */ + } + menu_array[15].flags = UI_ITEM_ACTION; } - SetItemChecked(menu_array, 4, CARTRIDGE_autoreboot); + SetItemChecked(menu_array, 16, 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); @@ -1235,11 +1365,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); @@ -1262,9 +1392,77 @@ static void CartManagement(void) break; } break; - case 4: + case 4: /* Ram-Cart R/W */ + ramcart->state ^= 0x1000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 5: /* Ram-Cart P1 (2x128/256K) */ + ramcart->state ^= 0x2000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 6: /* Ram-Cart P2 (Exchange 128K modules) */ + ramcart->state ^= 0x4000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 7: /* Ram-Cart jumpers ABC installation flag */ + ramcart->state ^= 0x8000; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 8: /* Ram-Cart A */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0004; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 9: /* Ram-Cart B */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0040; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 10: /* Ram-Cart C */ + if (!(ramcart->state & 0x8000)) { + ramcart->state ^= 0x0080; + CARTRIDGE_UpdateState(ramcart, old_state); + } + break; + case 11: /* Ram-Cart 1/2M or D */ + ramcart->state ^= 0x0100; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 12: /* Ram-Cart 2/4M */ + ramcart->state ^= 0x0200; + CARTRIDGE_UpdateState(ramcart, old_state); + break; + case 13: /* Ram-Cart address decoder */ + if (ramcart->type == CARTRIDGE_RAMCART_1M) + ramcart->state ^= 0x10000; + break; + 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 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) { + if ( CARTRIDGE_WriteImage( + cart_filename, + cart_type, NULL, CARTRIDGES[cart_type].kb << 10, FALSE, 0x00 ) ) + CantSave(cart_filename); + else + Created(cart_filename); + } + } + break; default: return; } @@ -4134,7 +4332,7 @@ static void AboutEmulator(void) Atari800_TITLE "\0" "Copyright (c) 1995-1998 David Firth\0" "and\0" - "(c)1998-2015 Atari800 Development Team\0" + "(c)1998-2023 Atari800 Development Team\0" "See CREDITS file for details.\0" "http://atari800.atari.org/\0" "\0" diff --git a/src/ui.h b/src/ui.h index 05c7c07b..71bfee91 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);