diff options
Diffstat (limited to 'src/devices/bus/coco/cococart.cpp')
-rw-r--r-- | src/devices/bus/coco/cococart.cpp | 415 |
1 files changed, 343 insertions, 72 deletions
diff --git a/src/devices/bus/coco/cococart.cpp b/src/devices/bus/coco/cococart.cpp index 990cbde61c4..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, uint32_t clock) : +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_slot_interface(mconfig, *this), - device_image_interface(mconfig, *this), + device_single_card_slot_interface<device_cococart_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,46 +166,72 @@ 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 = dynamic_cast<device_cococart_interface *>(get_card_device()); + 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 //------------------------------------------------- -READ8_MEMBER(cococart_slot_device::cts_read) +u8 cococart_slot_device::cts_read(offs_t offset) { - uint8_t result = 0x00; + u8 result = 0x00; if (m_cart) - result = m_cart->cts_read(space, offset); + result = m_cart->cts_read(offset); return result; } @@ -168,10 +240,10 @@ READ8_MEMBER(cococart_slot_device::cts_read) // cts_write //------------------------------------------------- -WRITE8_MEMBER(cococart_slot_device::cts_write) +void cococart_slot_device::cts_write(offs_t offset, u8 data) { if (m_cart) - m_cart->cts_write(space, offset, data); + m_cart->cts_write(offset, data); } @@ -179,11 +251,11 @@ WRITE8_MEMBER(cococart_slot_device::cts_write) // scs_read //------------------------------------------------- -READ8_MEMBER(cococart_slot_device::scs_read) +u8 cococart_slot_device::scs_read(offs_t offset) { - uint8_t result = 0x00; + u8 result = 0x00; if (m_cart) - result = m_cart->scs_read(space, offset); + result = m_cart->scs_read(offset); return result; } @@ -192,10 +264,10 @@ READ8_MEMBER(cococart_slot_device::scs_read) // scs_write //------------------------------------------------- -WRITE8_MEMBER(cococart_slot_device::scs_write) +void cococart_slot_device::scs_write(offs_t offset, u8 data) { if (m_cart) - m_cart->scs_write(space, offset, data); + m_cart->scs_write(offset, data); } @@ -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); } } @@ -273,8 +356,8 @@ void cococart_slot_device::set_line_timer(coco_cartridge_line &line, cococart_sl { // calculate delay; delay dependant on cycles per second attotime delay = (line.delay != 0) - ? clocks_to_attotime(line.delay) - : attotime::zero; + ? clocks_to_attotime(line.delay) + : attotime::zero; line.timer[line.timer_index]->adjust(delay, (int) value); line.timer_index = (line.timer_index + 1) % TIMER_POOL; @@ -395,7 +478,7 @@ cococart_slot_device::line_value cococart_slot_device::get_line_value(cococart_s // get_cart_base //------------------------------------------------- -uint8_t* cococart_slot_device::get_cart_base() +u8 *cococart_slot_device::get_cart_base() { if (m_cart != nullptr) return m_cart->get_cart_base(); @@ -407,7 +490,7 @@ uint8_t* cococart_slot_device::get_cart_base() // get_cart_size //------------------------------------------------- -uint32_t cococart_slot_device::get_cart_size() +u32 cococart_slot_device::get_cart_size() { if (m_cart != nullptr) return m_cart->get_cart_size(); @@ -427,35 +510,104 @@ 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) { memory_region *cart_mem = m_cart->get_cart_memregion(); - uint8_t *base = cart_mem->base(); + 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) { - offs_t len = std::min(read_length, m_cart->get_cart_size() - read_length); + offs_t len = std::min(read_length, cart_length - read_length); memcpy(base + read_length, base, len); 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]); +} //************************************************************************** @@ -483,8 +651,8 @@ template class device_finder<device_cococart_interface, true>; //------------------------------------------------- device_cococart_interface::device_cococart_interface(const machine_config &mconfig, device_t &device) - : device_slot_card_interface(mconfig, device) - , m_owning_slot(nullptr) + : device_interface(device, "cococart") + , m_owning_slot(dynamic_cast<cococart_slot_device *>(device.owner())) , m_host(nullptr) { } @@ -505,10 +673,9 @@ 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; + ? dynamic_cast<device_cococart_host_interface *>(m_owning_slot->owner()) + : nullptr; } @@ -530,7 +697,7 @@ void device_cococart_interface::interface_pre_start() // on the cartridge slot was asserted ($C000-FFEF) //------------------------------------------------- -READ8_MEMBER(device_cococart_interface::cts_read) +u8 device_cococart_interface::cts_read(offs_t offset) { return 0x00; } @@ -541,7 +708,7 @@ READ8_MEMBER(device_cococart_interface::cts_read) // on the cartridge slot was asserted ($C000-FFEF) //------------------------------------------------- -WRITE8_MEMBER(device_cococart_interface::cts_write) +void device_cococart_interface::cts_write(offs_t offset, u8 data) { } @@ -551,7 +718,7 @@ WRITE8_MEMBER(device_cococart_interface::cts_write) // on the cartridge slot was asserted ($FF40-5F) //------------------------------------------------- -READ8_MEMBER(device_cococart_interface::scs_read) +u8 device_cococart_interface::scs_read(offs_t offset) { return 0x00; } @@ -562,7 +729,7 @@ READ8_MEMBER(device_cococart_interface::scs_read) // on the cartridge slot was asserted ($FF40-5F) //------------------------------------------------- -WRITE8_MEMBER(device_cococart_interface::scs_write) +void device_cococart_interface::scs_write(offs_t offset, u8 data) { } @@ -580,7 +747,7 @@ void device_cococart_interface::set_sound_enable(bool sound_enable) // get_cart_base //------------------------------------------------- -uint8_t* device_cococart_interface::get_cart_base() +u8 *device_cococart_interface::get_cart_base() { return nullptr; } @@ -590,7 +757,7 @@ uint8_t* device_cococart_interface::get_cart_base() // get_cart_size //------------------------------------------------- -uint32_t device_cococart_interface::get_cart_size() +u32 device_cococart_interface::get_cart_size() { return 0x8000; } @@ -626,7 +793,7 @@ void device_cococart_interface::cart_base_changed(void) get_cart_memregion -------------------------------------------------*/ -memory_region* device_cococart_interface::get_cart_memregion() +memory_region *device_cococart_interface::get_cart_memregion() { return 0; } @@ -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); +} |