summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/coco/cococart.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/coco/cococart.cpp')
-rw-r--r--src/devices/bus/coco/cococart.cpp357
1 files changed, 314 insertions, 43 deletions
diff --git a/src/devices/bus/coco/cococart.cpp b/src/devices/bus/coco/cococart.cpp
index 220b0d1cab3..2c385890311 100644
--- a/src/devices/bus/coco/cococart.cpp
+++ b/src/devices/bus/coco/cococart.cpp
@@ -39,24 +39,70 @@
#include "emu.h"
#include "cococart.h"
+#include "formats/rpk.h"
+
+#include "coco_dcmodem.h"
+#include "coco_fdc.h"
+#include "coco_gmc.h"
+#include "coco_ide.h"
+#include "coco_max.h"
+#include "coco_midi.h"
+#include "coco_multi.h"
+#include "coco_orch90.h"
+#include "coco_pak.h"
+#include "coco_psg.h"
+#include "coco_ram.h"
+#include "coco_rs232.h"
+#include "coco_ssc.h"
+#include "coco_stecomp.h"
+#include "coco_sym12.h"
+#include "coco_wpk.h"
+#include "coco_wpk2p.h"
+
+#include "dragon_amtor.h"
+#include "dragon_claw.h"
+#include "dragon_fdc.h"
+#include "dragon_jcbsnd.h"
+#include "dragon_jcbspch.h"
+#include "dragon_msx2.h"
+#include "dragon_serial.h"
+#include "dragon_sprites.h"
/***************************************************************************
PARAMETERS
***************************************************************************/
-#define LOG_LINE 0
+#define LOG_CART (1U << 1) // shows cart line changes
+#define LOG_NMI (1U << 2) // shows switch changes
+#define LOG_HALT (1U << 3) // shows switch changes
+// #define VERBOSE (LOG_CART)
+
+#include "logmacro.h"
+
+#define LOGCART(...) LOGMASKED(LOG_CART, __VA_ARGS__)
+#define LOGNMI(...) LOGMASKED(LOG_NMI, __VA_ARGS__)
+#define LOGHALT(...) LOGMASKED(LOG_HALT, __VA_ARGS__)
/***************************************************************************
CONSTANTS
***************************************************************************/
-enum
+// definitions of RPK PCBs in layout.xml
+static const char *coco_rpk_pcbdefs[] =
{
- TIMER_CART,
- TIMER_NMI,
- TIMER_HALT
+ "standard",
+ "paged16k",
+ nullptr
+};
+
+
+// ...and their mappings to "default card slots"
+static const char *coco_rpk_cardslottypes[] =
+{
+ "pak",
+ "banked_16k"
};
@@ -71,13 +117,15 @@ DEFINE_DEVICE_TYPE(COCOCART_SLOT, cococart_slot_device, "cococart_slot", "CoCo C
// LIVE DEVICE
//**************************************************************************
+ALLOW_SAVE_TYPE(cococart_slot_device::line_value);
+
//-------------------------------------------------
// cococart_slot_device - constructor
//-------------------------------------------------
cococart_slot_device::cococart_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, COCOCART_SLOT, tag, owner, clock),
device_single_card_slot_interface<device_cococart_interface>(mconfig, *this),
- device_image_interface(mconfig, *this),
+ device_cartrom_image_interface(mconfig, *this),
m_cart_callback(*this),
m_nmi_callback(*this),
m_halt_callback(*this), m_cart(nullptr)
@@ -92,11 +140,11 @@ cococart_slot_device::cococart_slot_device(const machine_config &mconfig, const
void cococart_slot_device::device_start()
{
- for(int i=0; i<TIMER_POOL; i++ )
+ for(int i=0; i < TIMER_POOL; i++ )
{
- m_cart_line.timer[i] = timer_alloc(TIMER_CART);
- m_nmi_line.timer[i] = timer_alloc(TIMER_NMI);
- m_halt_line.timer[i] = timer_alloc(TIMER_HALT);
+ m_cart_line.timer[i] = timer_alloc(FUNC(cococart_slot_device::cart_line_timer_tick), this);
+ m_nmi_line.timer[i] = timer_alloc(FUNC(cococart_slot_device::nmi_line_timer_tick), this);
+ m_halt_line.timer[i] = timer_alloc(FUNC(cococart_slot_device::halt_line_timer_tick), this);
}
m_cart_line.timer_index = 0;
@@ -104,7 +152,6 @@ void cococart_slot_device::device_start()
m_cart_line.value = line_value::CLEAR;
m_cart_line.line = 0;
m_cart_line.q_count = 0;
- m_cart_callback.resolve();
m_cart_line.callback = &m_cart_callback;
m_nmi_line.timer_index = 0;
@@ -112,7 +159,6 @@ void cococart_slot_device::device_start()
m_nmi_line.value = line_value::CLEAR;
m_nmi_line.line = 0;
m_nmi_line.q_count = 0;
- m_nmi_callback.resolve();
m_nmi_line.callback = &m_nmi_callback;
m_halt_line.timer_index = 0;
@@ -120,36 +166,62 @@ void cococart_slot_device::device_start()
m_halt_line.value = line_value::CLEAR;
m_halt_line.line = 0;
m_halt_line.q_count = 0;
- m_halt_callback.resolve();
m_halt_line.callback = &m_halt_callback;
m_cart = get_card_device();
+
+ save_item(STRUCT_MEMBER(m_cart_line, timer_index));
+ save_item(STRUCT_MEMBER(m_cart_line, delay));
+ save_item(STRUCT_MEMBER(m_cart_line, value));
+ save_item(STRUCT_MEMBER(m_cart_line, line));
+ save_item(STRUCT_MEMBER(m_cart_line, q_count));
+
+ save_item(STRUCT_MEMBER(m_nmi_line, timer_index));
+ save_item(STRUCT_MEMBER(m_nmi_line, delay));
+ save_item(STRUCT_MEMBER(m_nmi_line, value));
+ save_item(STRUCT_MEMBER(m_nmi_line, line));
+ save_item(STRUCT_MEMBER(m_nmi_line, q_count));
+
+ save_item(STRUCT_MEMBER(m_halt_line, timer_index));
+ save_item(STRUCT_MEMBER(m_halt_line, delay));
+ save_item(STRUCT_MEMBER(m_halt_line, value));
+ save_item(STRUCT_MEMBER(m_halt_line, line));
+ save_item(STRUCT_MEMBER(m_halt_line, q_count));
}
//-------------------------------------------------
-// device_timer - handle timer callbacks
+// cart_line_timer_tick - update the output
+// value for the cart's line to PIA1 CB1
//-------------------------------------------------
-void cococart_slot_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+TIMER_CALLBACK_MEMBER(cococart_slot_device::cart_line_timer_tick)
{
- switch(id)
- {
- case TIMER_CART:
- set_line("CART", m_cart_line, (line_value) param);
- break;
+ set_line(line::CART, m_cart_line, (line_value) param);
+}
- case TIMER_NMI:
- set_line("NMI", m_nmi_line, (line_value) param);
- break;
+//-------------------------------------------------
+// nmi_line_timer_tick - update the output
+// value sent to the CPU's NMI line
+//-------------------------------------------------
- case TIMER_HALT:
- set_line("HALT", m_halt_line, (line_value) param);
- break;
- }
+TIMER_CALLBACK_MEMBER(cococart_slot_device::nmi_line_timer_tick)
+{
+ set_line(line::NMI, m_nmi_line, (line_value) param);
}
+//-------------------------------------------------
+// halt_line_timer_tick - update the output
+// value sent to the CPU's HALT line
+//-------------------------------------------------
+
+TIMER_CALLBACK_MEMBER(cococart_slot_device::halt_line_timer_tick)
+{
+ set_line(line::HALT, m_halt_line, (line_value) param);
+}
+
+
//-------------------------------------------------
// cts_read
@@ -229,14 +301,26 @@ const char *cococart_slot_device::line_value_string(line_value value)
// set_line
//-------------------------------------------------
-void cococart_slot_device::set_line(const char *line_name, coco_cartridge_line &line, cococart_slot_device::line_value value)
+void cococart_slot_device::set_line(line ln, coco_cartridge_line &line, cococart_slot_device::line_value value)
{
if ((line.value != value) || (value == line_value::Q))
{
line.value = value;
- if (LOG_LINE)
- logerror("[%s]: set_line(): %s <= %s\n", machine().describe_context(), line_name, line_value_string(value));
+ switch (ln)
+ {
+ case line::CART:
+ LOGCART( "set_line: CART, value: %s\n", line_value_string(value));
+ break;
+ case line::NMI:
+ LOGNMI( "set_line: NMI, value: %s\n", line_value_string(value));
+ break;
+ case line::HALT:
+ LOGHALT( "set_line: HALT, value: %s\n", line_value_string(value));
+ break;
+ case line::SOUND_ENABLE:
+ break;
+ }
// engage in a bit of gymnastics for this odious 'Q' value
switch(line.value)
@@ -258,9 +342,8 @@ void cococart_slot_device::set_line(const char *line_name, coco_cartridge_line &
break;
}
- /* invoke the callback, if present */
- if (!(*line.callback).isnull())
- (*line.callback)(line.line);
+ /* invoke the callback */
+ (*line.callback)(line.line);
}
}
@@ -427,10 +510,67 @@ void cococart_slot_device::set_cart_base_update(cococart_base_update_delegate up
//-------------------------------------------------
+// read_coco_rpk
+//-------------------------------------------------
+
+static std::error_condition read_coco_rpk(std::unique_ptr<util::random_read> &&stream, rpk_file::ptr &result)
+{
+ // sanity checks
+ static_assert(std::size(coco_rpk_pcbdefs) - 1 == std::size(coco_rpk_cardslottypes));
+
+ // set up the RPK reader
+ rpk_reader reader(coco_rpk_pcbdefs, false);
+
+ // and read the RPK file
+ return reader.read(std::move(stream), result);
+}
+
+
+//-------------------------------------------------
+// read_coco_rpk
+//-------------------------------------------------
+
+static std::error_condition read_coco_rpk(std::unique_ptr<util::random_read> &&stream, u8 *mem, offs_t cart_length, offs_t &actual_length)
+{
+ actual_length = 0;
+
+ // open the RPK
+ rpk_file::ptr file;
+ std::error_condition err = read_coco_rpk(std::move(stream), file);
+ if (err)
+ return err;
+
+ // for now, we are just going to load all sockets into the contiguous block of memory
+ // that cartridges use
+ offs_t pos = 0;
+ for (const rpk_socket &socket : file->sockets())
+ {
+ // only ROM supported for now; if we see anything else it should have been caught in the RPK code
+ assert(socket.type() == rpk_socket::socket_type::ROM);
+
+ // read all bytes
+ std::vector<uint8_t> contents;
+ err = socket.read_file(contents);
+ if (err)
+ return err;
+
+ // copy the bytes
+ offs_t size = (offs_t) std::min(contents.size(), (size_t)cart_length - pos);
+ memcpy(&mem[pos], &contents[0], size);
+ pos += size;
+ }
+
+ // we're done!
+ actual_length = pos;
+ return std::error_condition();
+}
+
+
+//-------------------------------------------------
// call_load
//-------------------------------------------------
-image_init_result cococart_slot_device::call_load()
+std::pair<std::error_condition, std::string> cococart_slot_device::call_load()
{
if (m_cart)
{
@@ -438,14 +578,26 @@ image_init_result cococart_slot_device::call_load()
u8 *base = cart_mem->base();
offs_t read_length, cart_length = cart_mem->bytes();
- if (!loaded_through_softlist())
+ if (loaded_through_softlist())
{
- read_length = fread(base, cart_length);
+ // loaded through softlist
+ read_length = get_software_region_length("rom");
+ memcpy(base, get_software_region("rom"), read_length);
+ }
+ else if (is_filetype("rpk"))
+ {
+ // RPK file
+ util::core_file::ptr proxy;
+ std::error_condition err = util::core_file::open_proxy(image_core_file(), proxy);
+ if (!err)
+ err = read_coco_rpk(std::move(proxy), base, cart_length, read_length);
+ if (err)
+ return std::make_pair(err, std::string());
}
else
{
- read_length = get_software_region_length("rom");
- memcpy(base, get_software_region("rom"), read_length);
+ // conventional ROM image
+ read_length = fread(base, cart_length);
}
while (read_length < cart_length)
@@ -455,7 +607,7 @@ image_init_result cococart_slot_device::call_load()
read_length += len;
}
}
- return image_init_result::PASS;
+ return std::make_pair(std::error_condition(), std::string());
}
@@ -465,9 +617,25 @@ image_init_result cococart_slot_device::call_load()
std::string cococart_slot_device::get_default_card_software(get_default_card_software_hook &hook) const
{
- return software_get_default_slot("pak");
-}
+ // this is the default for anything not in an RPK file
+ int pcb_type = 0;
+ // is this an RPK?
+ if (hook.is_filetype("rpk"))
+ {
+ // RPK file
+ rpk_file::ptr file;
+ util::core_file::ptr proxy;
+ std::error_condition err = util::core_file::open_proxy(*hook.image_file(), proxy);
+ if (!err)
+ err = read_coco_rpk(std::move(proxy), file);
+ if (!err)
+ pcb_type = file->pcb_type();
+ }
+
+ // lookup the default slot
+ return software_get_default_slot(coco_rpk_cardslottypes[pcb_type]);
+}
//**************************************************************************
@@ -484,7 +652,7 @@ template class device_finder<device_cococart_interface, true>;
device_cococart_interface::device_cococart_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "cococart")
- , m_owning_slot(nullptr)
+ , m_owning_slot(dynamic_cast<cococart_slot_device *>(device.owner()))
, m_host(nullptr)
{
}
@@ -505,7 +673,6 @@ device_cococart_interface::~device_cococart_interface()
void device_cococart_interface::interface_config_complete()
{
- m_owning_slot = dynamic_cast<cococart_slot_device *>(device().owner());
m_host = m_owning_slot
? dynamic_cast<device_cococart_host_interface *>(m_owning_slot->owner())
: nullptr;
@@ -649,3 +816,107 @@ void device_cococart_interface::set_line_value(cococart_slot_device::line line,
{
owning_slot().set_line_value(line, value);
}
+
+
+//-------------------------------------------------
+// coco_cart_add_basic_devices
+//-------------------------------------------------
+
+void coco_cart_add_basic_devices(device_slot_interface &device)
+{
+ // basic devices, on both the main slot and the Multi-Pak interface
+ device.option_add_internal("banked_16k", COCO_PAK_BANKED);
+ device.option_add_internal("pak", COCO_PAK);
+ device.option_add("ccpsg", COCO_PSG);
+ device.option_add("dcmodem", COCO_DCMODEM);
+ device.option_add("gmc", COCO_PAK_GMC);
+ device.option_add("ide", COCO_IDE);
+ device.option_add("max", COCO_PAK_MAX);
+ device.option_add("midi", COCO_MIDI);
+ device.option_add("orch90", COCO_ORCH90);
+ device.option_add("ram", COCO_PAK_RAM);
+ device.option_add("rs232", COCO_RS232);
+ device.option_add("ssc", COCO_SSC);
+ device.option_add("ssfm", DRAGON_MSX2);
+ device.option_add("stecomp", COCO_STEREO_COMPOSER);
+ device.option_add("sym12", COCO_SYM12);
+ device.option_add("wpk", COCO_WPK);
+ device.option_add("wpk2", COCO_WPK2);
+ device.option_add("wpkrs", COCO_WPKRS);
+ device.option_add("wpk2p", COCO_WPK2P);
+}
+
+
+//-------------------------------------------------
+// coco_cart_add_fdcs
+//-------------------------------------------------
+
+void coco_cart_add_fdcs(device_slot_interface &device)
+{
+ // FDCs are optional because if they are on a Multi-Pak interface, they must
+ // be on Slot 4
+ device.option_add("cd6809_fdc", CD6809_FDC);
+ device.option_add("cp450_fdc", CP450_FDC);
+ device.option_add("fdc", COCO_FDC);
+ device.option_add("scii", COCO_SCII);
+}
+
+
+//-------------------------------------------------
+// coco_cart_add_multi_pak
+//-------------------------------------------------
+
+void coco_cart_add_multi_pak(device_slot_interface &device)
+{
+ // and the Multi-Pak itself is optional because they cannot be daisy chained
+ device.option_add("multi", COCO_MULTIPAK);
+}
+
+
+//-------------------------------------------------
+// dragon_cart_add_basic_devices
+//-------------------------------------------------
+
+void dragon_cart_add_basic_devices(device_slot_interface &device)
+{
+ device.option_add_internal("amtor", DRAGON_AMTOR);
+ device.option_add("ccpsg", COCO_PSG);
+ device.option_add("claw", DRAGON_CLAW);
+ device.option_add("gmc", COCO_PAK_GMC);
+ device.option_add("jcbsnd", DRAGON_JCBSND);
+ device.option_add("jcbspch", DRAGON_JCBSPCH);
+ device.option_add("max", COCO_PAK_MAX);
+ device.option_add("midi", DRAGON_MIDI);
+ device.option_add("orch90", COCO_ORCH90);
+ device.option_add("pak", COCO_PAK);
+ device.option_add("serial", DRAGON_SERIAL);
+ device.option_add("ram", COCO_PAK_RAM);
+ device.option_add("sprites", DRAGON_SPRITES);
+ device.option_add("ssc", COCO_SSC);
+ device.option_add("ssfm", DRAGON_MSX2);
+ device.option_add("stecomp", COCO_STEREO_COMPOSER);
+ device.option_add("sym12", COCO_SYM12);
+ device.option_add("wpk2p", COCO_WPK2P);
+}
+
+
+//-------------------------------------------------
+// dragon_cart_add_fdcs
+//-------------------------------------------------
+
+void dragon_cart_add_fdcs(device_slot_interface &device)
+{
+ device.option_add("dragon_fdc", DRAGON_FDC);
+ device.option_add("premier_fdc", PREMIER_FDC);
+ device.option_add("sdtandy_fdc", SDTANDY_FDC);
+}
+
+
+//-------------------------------------------------
+// dragon_cart_add_multi_pak
+//-------------------------------------------------
+
+void dragon_cart_add_multi_pak(device_slot_interface &device)
+{
+ device.option_add("multi", DRAGON_MULTIPAK);
+}