mirror of
https://github.com/holub/mame
synced 2025-10-06 09:00:04 +03:00
ti99: Created bus gromport, split monster file gromport
This commit is contained in:
parent
7346e19dfa
commit
347e8a4fb7
@ -2358,6 +2358,7 @@ end
|
|||||||
---------------------------------------------------
|
---------------------------------------------------
|
||||||
--
|
--
|
||||||
--@src/devices/bus/ti99/colorbus/colorbus.h,BUSES["TI99"] = true
|
--@src/devices/bus/ti99/colorbus/colorbus.h,BUSES["TI99"] = true
|
||||||
|
--@src/devices/bus/ti99/gromport/cartridges.h,BUSES["TI99"] = true
|
||||||
--@src/devices/bus/ti99/joyport/joyport.h,BUSES["TI99"] = true
|
--@src/devices/bus/ti99/joyport/joyport.h,BUSES["TI99"] = true
|
||||||
--@src/devices/bus/ti99/peb/peribox.h,BUSES["TI99"] = true
|
--@src/devices/bus/ti99/peb/peribox.h,BUSES["TI99"] = true
|
||||||
--@src/devices/bus/ti99/internal/genboard.h,BUSES["TI99"] = true
|
--@src/devices/bus/ti99/internal/genboard.h,BUSES["TI99"] = true
|
||||||
@ -2375,14 +2376,22 @@ if (BUSES["TI99"]~=null) then
|
|||||||
MAME_DIR .. "src/devices/bus/ti99/internal/evpcconn.h",
|
MAME_DIR .. "src/devices/bus/ti99/internal/evpcconn.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/genboard.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/internal/genboard.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/genboard.h",
|
MAME_DIR .. "src/devices/bus/ti99/internal/genboard.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/gromport.cpp",
|
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/gromport.h",
|
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/ioport.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/internal/ioport.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/internal/ioport.h",
|
MAME_DIR .. "src/devices/bus/ti99/internal/ioport.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.h",
|
MAME_DIR .. "src/devices/bus/ti99/colorbus/busmouse.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/colorbus/colorbus.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/colorbus/colorbus.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/colorbus/colorbus.h",
|
MAME_DIR .. "src/devices/bus/ti99/colorbus/colorbus.h",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/gromport.cpp",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/gromport.h",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/cartridges.cpp",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/cartridges.h",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/gkracker.cpp",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/gkracker.h",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/multiconn.cpp",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/multiconn.h",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/singleconn.cpp",
|
||||||
|
MAME_DIR .. "src/devices/bus/ti99/gromport/singleconn.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/joyport/handset.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/joyport/handset.cpp",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/joyport/handset.h",
|
MAME_DIR .. "src/devices/bus/ti99/joyport/handset.h",
|
||||||
MAME_DIR .. "src/devices/bus/ti99/joyport/joyport.cpp",
|
MAME_DIR .. "src/devices/bus/ti99/joyport/joyport.cpp",
|
||||||
|
File diff suppressed because it is too large
Load Diff
367
src/devices/bus/ti99/gromport/cartridges.h
Normal file
367
src/devices/bus/ti99/gromport/cartridges.h
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/***************************************************************************
|
||||||
|
Cartridge emulations
|
||||||
|
****************************************************************************/
|
||||||
|
#ifndef MAME_BUS_TI99_GROMPORT_CARTRIDGES_H
|
||||||
|
#define MAME_BUS_TI99_GROMPORT_CARTRIDGES_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "emuopts.h"
|
||||||
|
#include "bus/ti99/ti99defs.h"
|
||||||
|
#include "machine/tmc0430.h"
|
||||||
|
#include "softlist_dev.h"
|
||||||
|
#include "gromport.h"
|
||||||
|
#include "unzip.h"
|
||||||
|
#include "xmlfile.h"
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
class ti99_cartridge_pcb;
|
||||||
|
|
||||||
|
enum rpk_open_error
|
||||||
|
{
|
||||||
|
RPK_OK,
|
||||||
|
RPK_NOT_ZIP_FORMAT,
|
||||||
|
RPK_CORRUPT,
|
||||||
|
RPK_OUT_OF_MEMORY,
|
||||||
|
RPK_XML_ERROR,
|
||||||
|
RPK_INVALID_FILE_REF,
|
||||||
|
RPK_ZIP_ERROR,
|
||||||
|
RPK_ZIP_UNSUPPORTED,
|
||||||
|
RPK_MISSING_RAM_LENGTH,
|
||||||
|
RPK_INVALID_RAM_SPEC,
|
||||||
|
RPK_UNKNOWN_RESOURCE_TYPE,
|
||||||
|
RPK_INVALID_RESOURCE_REF,
|
||||||
|
RPK_INVALID_LAYOUT,
|
||||||
|
RPK_MISSING_LAYOUT,
|
||||||
|
RPK_NO_PCB_OR_RESOURCES,
|
||||||
|
RPK_UNKNOWN_PCB_TYPE
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *const error_text[16] =
|
||||||
|
{
|
||||||
|
"No error",
|
||||||
|
"Not a RPK (zip) file",
|
||||||
|
"Module definition corrupt",
|
||||||
|
"Out of memory",
|
||||||
|
"XML format error",
|
||||||
|
"Invalid file reference",
|
||||||
|
"Zip file error",
|
||||||
|
"Unsupported zip version",
|
||||||
|
"Missing RAM length",
|
||||||
|
"Invalid RAM specification",
|
||||||
|
"Unknown resource type",
|
||||||
|
"Invalid resource reference",
|
||||||
|
"layout.xml not valid",
|
||||||
|
"Missing layout",
|
||||||
|
"No pcb or resource found",
|
||||||
|
"Unknown pcb type"
|
||||||
|
};
|
||||||
|
|
||||||
|
class ti99_cartridge_device : public bus8z_device, public device_image_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ti99_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz);
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite);
|
||||||
|
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines);
|
||||||
|
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
||||||
|
|
||||||
|
bool is_available() { return m_pcb != nullptr; }
|
||||||
|
void set_slot(int i);
|
||||||
|
bool is_grom_idle();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void device_start() override { }
|
||||||
|
virtual void device_config_complete() override;
|
||||||
|
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||||
|
virtual const tiny_rom_entry* device_rom_region() const override;
|
||||||
|
|
||||||
|
// Image handling: implementation of methods which are abstract in the parent
|
||||||
|
image_init_result call_load() override;
|
||||||
|
void call_unload() override;
|
||||||
|
virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
|
||||||
|
|
||||||
|
void prepare_cartridge();
|
||||||
|
|
||||||
|
// device_image_interface
|
||||||
|
iodevice_t image_type() const override { return IO_CARTSLOT; }
|
||||||
|
bool is_readable() const override { return true; }
|
||||||
|
bool is_writeable() const override { return false; }
|
||||||
|
bool is_creatable() const override { return false; }
|
||||||
|
bool must_be_loaded() const override { return false; }
|
||||||
|
bool is_reset_on_load() const override { return false; }
|
||||||
|
const char *image_interface() const override { return "ti99_cart"; }
|
||||||
|
const char *file_extensions() const override { return "rpk"; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
/***************** RPK support ********************
|
||||||
|
Actually deprecated, and to be removed as soon as
|
||||||
|
softlists allow for homebrew cartridges
|
||||||
|
***************************************************/
|
||||||
|
|
||||||
|
class rpk_socket;
|
||||||
|
class rpk;
|
||||||
|
|
||||||
|
class rpk_exception
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
rpk_exception(rpk_open_error value): m_err(value), m_detail(nullptr) { }
|
||||||
|
rpk_exception(rpk_open_error value, const char* detail) : m_err(value), m_detail(detail) { }
|
||||||
|
|
||||||
|
const char* to_string()
|
||||||
|
{
|
||||||
|
// FIXME: this leaks memory - in some cases it returns a new buffer, in other cases it returns a pointer to a static string, so the caller can't know whether it needs to be cleaned up
|
||||||
|
if (m_detail==nullptr) return error_text[(int)m_err];
|
||||||
|
std::string errormsg = std::string(error_text[(int)m_err]).append(": ").append(m_detail);
|
||||||
|
return core_strdup(errormsg.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
rpk_open_error m_err;
|
||||||
|
const char* m_detail;
|
||||||
|
};
|
||||||
|
|
||||||
|
class rpk_reader
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
rpk_reader(const pcb_type *types) : m_types(types) { }
|
||||||
|
|
||||||
|
rpk *open(emu_options &options, const char *filename, const char *system_name);
|
||||||
|
|
||||||
|
private:
|
||||||
|
int find_file(util::archive_file &zip, const char *filename, uint32_t crc);
|
||||||
|
std::unique_ptr<rpk_socket> load_rom_resource(util::archive_file &zip, util::xml::data_node const* rom_resource_node, const char* socketname);
|
||||||
|
std::unique_ptr<rpk_socket> load_ram_resource(emu_options &options, util::xml::data_node const* ram_resource_node, const char* socketname, const char* system_name);
|
||||||
|
const pcb_type* m_types;
|
||||||
|
};
|
||||||
|
|
||||||
|
class rpk
|
||||||
|
{
|
||||||
|
friend class rpk_reader;
|
||||||
|
public:
|
||||||
|
rpk(emu_options& options, const char* sysname);
|
||||||
|
~rpk();
|
||||||
|
|
||||||
|
int get_type(void) { return m_type; }
|
||||||
|
uint8_t* get_contents_of_socket(const char *socket_name);
|
||||||
|
int get_resource_length(const char *socket_name);
|
||||||
|
void close();
|
||||||
|
|
||||||
|
private:
|
||||||
|
emu_options& m_options; // need this to find the path to the nvram files
|
||||||
|
int m_type;
|
||||||
|
//const char* m_system_name; // need this to find the path to the nvram files
|
||||||
|
std::unordered_map<std::string,std::unique_ptr<rpk_socket>> m_sockets;
|
||||||
|
|
||||||
|
void add_socket(const char* id, std::unique_ptr<rpk_socket> newsock);
|
||||||
|
};
|
||||||
|
|
||||||
|
class rpk_socket
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
rpk_socket(const char *id, int length, uint8_t *contents);
|
||||||
|
rpk_socket(const char *id, int length, uint8_t *contents, const char *pathname);
|
||||||
|
~rpk_socket() {}
|
||||||
|
|
||||||
|
const char* id() { return m_id; }
|
||||||
|
int get_content_length() { return m_length; }
|
||||||
|
uint8_t* get_contents() { return m_contents; }
|
||||||
|
bool persistent_ram() { return m_pathname != nullptr; }
|
||||||
|
const char* get_pathname() { return m_pathname; }
|
||||||
|
void cleanup() { if (m_contents != nullptr) global_free_array(m_contents); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const char* m_id;
|
||||||
|
uint32_t m_length;
|
||||||
|
uint8_t* m_contents;
|
||||||
|
const char* m_pathname;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool m_readrom;
|
||||||
|
int m_pcbtype;
|
||||||
|
int m_slot;
|
||||||
|
int get_index_from_tagname();
|
||||||
|
|
||||||
|
std::unique_ptr<ti99_cartridge_pcb> m_pcb; // inbound
|
||||||
|
cartridge_connector_device* m_connector; // outbound
|
||||||
|
|
||||||
|
// RPK which is associated to this cartridge
|
||||||
|
// When we close it, the contents are saved to NVRAM if available
|
||||||
|
rpk *m_rpk;
|
||||||
|
};
|
||||||
|
|
||||||
|
/****************************************************************************/
|
||||||
|
|
||||||
|
class ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
friend class ti99_cartridge_device;
|
||||||
|
public:
|
||||||
|
ti99_cartridge_pcb();
|
||||||
|
virtual ~ti99_cartridge_pcb() { }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual DECLARE_READ8Z_MEMBER(readz);
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(write);
|
||||||
|
virtual DECLARE_READ8Z_MEMBER(crureadz);
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(cruwrite);
|
||||||
|
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(set_gromlines);
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
||||||
|
|
||||||
|
DECLARE_READ8Z_MEMBER(gromreadz);
|
||||||
|
DECLARE_WRITE8_MEMBER(gromwrite);
|
||||||
|
inline void set_grom_pointer(int number, device_t *dev);
|
||||||
|
void set_cartridge(ti99_cartridge_device *cart);
|
||||||
|
const char* tag() { return m_tag; }
|
||||||
|
void set_tag(const char* tag) { m_tag = tag; }
|
||||||
|
bool is_grom_idle() { return m_grom_idle; }
|
||||||
|
|
||||||
|
ti99_cartridge_device* m_cart;
|
||||||
|
tmc0430_device* m_grom[5];
|
||||||
|
bool m_grom_idle;
|
||||||
|
int m_grom_size;
|
||||||
|
int m_rom_size;
|
||||||
|
int m_ram_size;
|
||||||
|
|
||||||
|
uint8_t* m_rom_ptr;
|
||||||
|
uint8_t* m_ram_ptr;
|
||||||
|
bool m_romspace_selected;
|
||||||
|
int m_rom_page; // for some cartridge types
|
||||||
|
uint8_t* m_grom_ptr; // for gromemu
|
||||||
|
int m_grom_address; // for gromemu
|
||||||
|
int m_ram_page; // for super
|
||||||
|
const char* m_tag;
|
||||||
|
std::vector<uint8_t> m_nvram; // for MiniMemory
|
||||||
|
std::vector<uint8_t> m_ram; // for MBX
|
||||||
|
};
|
||||||
|
|
||||||
|
/******************** Standard cartridge ******************************/
|
||||||
|
|
||||||
|
class ti99_standard_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********** Paged cartridge (like Extended Basic) ********************/
|
||||||
|
|
||||||
|
class ti99_paged12k_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*********** Paged cartridge (others) ********************/
|
||||||
|
|
||||||
|
class ti99_paged16k_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** Mini Memory ***********************************/
|
||||||
|
|
||||||
|
class ti99_minimem_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************* Super Space II *********************************/
|
||||||
|
|
||||||
|
class ti99_super_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/************************* MBX ***************************************/
|
||||||
|
|
||||||
|
class ti99_mbx_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** Paged 379i ************************************/
|
||||||
|
|
||||||
|
class ti99_paged379i_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
private:
|
||||||
|
int get_paged379i_bank(int rompage);
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** Paged 378 ************************************/
|
||||||
|
|
||||||
|
class ti99_paged378_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** Paged 377 ************************************/
|
||||||
|
|
||||||
|
class ti99_paged377_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** Paged CRU ************************************/
|
||||||
|
|
||||||
|
class ti99_pagedcru_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||||
|
};
|
||||||
|
|
||||||
|
/********************** GROM emulation cartridge ************************************/
|
||||||
|
|
||||||
|
class ti99_gromemu_cartridge : public ti99_cartridge_pcb
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ti99_gromemu_cartridge(): m_waddr_LSB(false), m_grom_selected(false), m_grom_read_mode(false), m_grom_address_mode(false)
|
||||||
|
{ m_grom_address = 0; }
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(gromemureadz);
|
||||||
|
DECLARE_WRITE8_MEMBER(gromemuwrite);
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_waddr_LSB;
|
||||||
|
bool m_grom_selected;
|
||||||
|
bool m_grom_read_mode;
|
||||||
|
bool m_grom_address_mode;
|
||||||
|
};
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
DECLARE_DEVICE_TYPE_NS(TI99_CART, bus::ti99::gromport, ti99_cartridge_device)
|
||||||
|
|
||||||
|
#endif // MAME_BUS_TI99_GROMPORT_CARTRIDGES_H
|
473
src/devices/bus/ti99/gromport/gkracker.cpp
Normal file
473
src/devices/bus/ti99/gromport/gkracker.cpp
Normal file
@ -0,0 +1,473 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/**************************************************************************
|
||||||
|
|
||||||
|
The GRAM Kracker was manufactured by Miller's Graphics and designed to
|
||||||
|
fit into the cartridge slot.
|
||||||
|
|
||||||
|
It offers one own cartridge slot at the top side and a row of switches
|
||||||
|
at its front. It contains buffered SRAM circuits; the base version has
|
||||||
|
56 KiB, and the extended version has 80 KiB.
|
||||||
|
|
||||||
|
The operation of the GRAM Kracker is a bit complex and most likely
|
||||||
|
bound to fail when you have no manual. Accordingly, this emulation is
|
||||||
|
neither simpler nor more difficult to use.
|
||||||
|
|
||||||
|
Concept of operation:
|
||||||
|
|
||||||
|
Loader: The GRAM Kracker contains a small loader utility
|
||||||
|
which allows you to dump cartridges and to load the contents into the
|
||||||
|
SRAM of the GK. This loader utility is active when the switch 5 is put
|
||||||
|
into "Loader on" state. The activated loader hides the TI BASIC
|
||||||
|
interpreter in the console.
|
||||||
|
|
||||||
|
Cartridges: When a cartridge is plugged into the GK the contents may be
|
||||||
|
dumped and saved to disk by the loader. They cannot be directly copied
|
||||||
|
into the GK because the memory locations are hidden by the cartridge.
|
||||||
|
|
||||||
|
Loading the cartridge into the SRAM: With the cartridge unplugged, dumps
|
||||||
|
can be loaded into the SRAM using the loader. This is one major use case
|
||||||
|
of the GK, that is, to load dumps from disk, and in particular modified
|
||||||
|
dumps. (There is no checksum, so contents may be freely changed.)
|
||||||
|
|
||||||
|
Console dump: The GK is also able to dump the console GROMs and also to
|
||||||
|
load them into the SRAM (only in the extended version). Due to a
|
||||||
|
peculiarity of the TI console design it is possible to override the
|
||||||
|
console GROMs with the contents in the cartridge slot.
|
||||||
|
|
||||||
|
A standard procedure for use with the GK:
|
||||||
|
|
||||||
|
Save cartridge:
|
||||||
|
|
||||||
|
- Put switches to [Normal | OpSys | TI BASIC | W/P | Loader On]
|
||||||
|
- Insert a disk image into disk drive 1
|
||||||
|
- Plug in a cartridge
|
||||||
|
- Reset the console (done automatically here)
|
||||||
|
- Visit the option screen, press 1 for GRAM KRACKER
|
||||||
|
- In the GK loader, select 2 for Save Module
|
||||||
|
- Follow the on-screen instructions. Switches are set via the dip switch menu.
|
||||||
|
- Enter a target file name
|
||||||
|
- Saving is complete when the Save operation has been unmarked.
|
||||||
|
|
||||||
|
Load cartridge:
|
||||||
|
|
||||||
|
- Put switches to [Normal | OpSys | TI BASIC | W/P | Loader On]
|
||||||
|
- Insert a disk image into disk drive 1
|
||||||
|
- Make sure no cartridge is plugged in
|
||||||
|
- Press 1 for GRAM KRACKER
|
||||||
|
- Press 3 for Init Module space; follow instructions
|
||||||
|
- Press 1 for Load Module; specify file name on disk
|
||||||
|
- Loading is complete when the Load operation has been unmarked.
|
||||||
|
|
||||||
|
Memory organisation:
|
||||||
|
|
||||||
|
The console has three GROMs with 6 KiB size and occupying 8 KiB of address
|
||||||
|
space each. These are called GROMs 0, 1, and 2. GROM 0 contains the common
|
||||||
|
routines for the computer operation; GROMs 1 and 2 contain TI BASIC.
|
||||||
|
|
||||||
|
Memory locations 6000-7fff are assigned to cartridge ROMs; in some
|
||||||
|
cartridges, a second ROM bank can be used by writing a value to a special
|
||||||
|
ROM access. This way, instead of 8 KiB we often have 16 KiB at these
|
||||||
|
locations.
|
||||||
|
|
||||||
|
Each cartridge can host up to 5 GROMs (called GROM 3, 4, 5, 6, and 7).
|
||||||
|
As in the console, each one occupies 6 KiB in an 8 KiB window.
|
||||||
|
|
||||||
|
The GRAM Kracker offers
|
||||||
|
|
||||||
|
- a loader in an own GROM 1 (which hides the console GROM 1 when active,
|
||||||
|
so we have no BASIC anymore). The contents of the loader must be found
|
||||||
|
by the emulator in a file named ti99_gkracker.zip.
|
||||||
|
|
||||||
|
- a complete set of 8 (simulated) GRAMs with full 8 KiB each (done by a
|
||||||
|
simple addressing circuit); the basic version only offered GRAMs 3-7
|
||||||
|
|
||||||
|
- 16 KiB of RAM memory space for the 6000-7fff area (called "bank 1" and "bank 2")
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- it is mandatory to turn off the loader when loading into GRAM 1, but only
|
||||||
|
after prompted in the on-screen instructions, or the loader will crash
|
||||||
|
- GRAM0 must be properly loaded if switch 2 is set to GRAM0 and the computer is reset
|
||||||
|
- Switch 4 must not be in W/P position (write protect) when loading data
|
||||||
|
into the GK (either other position will do).
|
||||||
|
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
#include "emu.h"
|
||||||
|
#include "gkracker.h"
|
||||||
|
|
||||||
|
DEFINE_DEVICE_TYPE_NS(TI99_GROMPORT_GK, bus::ti99::gromport, ti99_gkracker_device, "ti99_gkracker", "Miller's Graphics GRAM Kracker")
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
GK_OFF = 0,
|
||||||
|
GK_NORMAL = 1,
|
||||||
|
GK_GRAM0 = 0,
|
||||||
|
GK_OPSYS = 1,
|
||||||
|
GK_GRAM12 = 0,
|
||||||
|
GK_TIBASIC = 1,
|
||||||
|
GK_BANK1 = 0,
|
||||||
|
GK_WP = 1,
|
||||||
|
GK_BANK2 = 2,
|
||||||
|
GK_LDON = 0,
|
||||||
|
GK_LDOFF = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
#define GKSWITCH1_TAG "GKSWITCH1"
|
||||||
|
#define GKSWITCH2_TAG "GKSWITCH2"
|
||||||
|
#define GKSWITCH3_TAG "GKSWITCH3"
|
||||||
|
#define GKSWITCH4_TAG "GKSWITCH4"
|
||||||
|
#define GKSWITCH5_TAG "GKSWITCH5"
|
||||||
|
|
||||||
|
#define TRACE_GKRACKER 0
|
||||||
|
#define TRACE_CHANGE 0
|
||||||
|
#define GKRACKER_NVRAM_TAG "gkracker_nvram"
|
||||||
|
#define GKRACKER_ROM_TAG "gkracker_rom"
|
||||||
|
|
||||||
|
ti99_gkracker_device::ti99_gkracker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
|
: cartridge_connector_device(mconfig, TI99_GROMPORT_GK, tag, owner, clock),
|
||||||
|
device_nvram_interface(mconfig, *this),
|
||||||
|
m_romspace_selected(false),
|
||||||
|
m_ram_page(0),
|
||||||
|
m_grom_address(0),
|
||||||
|
m_ram_ptr(nullptr),
|
||||||
|
m_grom_ptr(nullptr),
|
||||||
|
m_waddr_LSB(false),
|
||||||
|
m_cartridge(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_gkracker_device::romgq_line)
|
||||||
|
{
|
||||||
|
m_romspace_selected = (state==ASSERT_LINE);
|
||||||
|
// Propagate to the guest
|
||||||
|
if (m_cartridge != nullptr) m_cartridge->romgq_line(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Combined select lines
|
||||||
|
*/
|
||||||
|
WRITE8_MEMBER(ti99_gkracker_device::set_gromlines)
|
||||||
|
{
|
||||||
|
m_grom_selected = (data != 0);
|
||||||
|
if (m_cartridge != nullptr) m_cartridge->set_gromlines(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_gkracker_device::gclock_in)
|
||||||
|
{
|
||||||
|
if (m_cartridge != nullptr) m_cartridge->gclock_in(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check whether the GROMs are idle.
|
||||||
|
*/
|
||||||
|
bool ti99_gkracker_device::is_grom_idle()
|
||||||
|
{
|
||||||
|
return (m_cartridge != nullptr)? m_cartridge->is_grom_idle() : false;
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(ti99_gkracker_device::readz)
|
||||||
|
{
|
||||||
|
if (m_grom_selected)
|
||||||
|
{
|
||||||
|
// Reads from the GRAM space of the GRAM Kracker.
|
||||||
|
int id = ((m_grom_address & 0xe000)>>13)&0x07;
|
||||||
|
|
||||||
|
// The GK does not have a readable address counter, but the console
|
||||||
|
// GROMs and the GROMs of the guest cartridge will keep our address
|
||||||
|
// counter up to date.
|
||||||
|
if ((offset & 0x0002)==0)
|
||||||
|
{
|
||||||
|
// Reading data
|
||||||
|
if (((id==0) && (m_gk_switch[2]==GK_GRAM0))
|
||||||
|
|| ((id==1) && (m_gk_switch[5]==GK_LDOFF) && (m_gk_switch[3]==GK_GRAM12))
|
||||||
|
|| ((id==2) && (m_gk_switch[3]==GK_GRAM12))
|
||||||
|
|| ((id>=3) && (m_gk_switch[1]==GK_NORMAL)))
|
||||||
|
*value = m_ram_ptr[m_grom_address];
|
||||||
|
|
||||||
|
if ((id==1) && (m_gk_switch[5]==GK_LDON))
|
||||||
|
*value = m_grom_ptr[m_grom_address & 0x1fff];
|
||||||
|
|
||||||
|
// The GK GROM emulation does not wrap at 8K boundaries.
|
||||||
|
m_grom_address = (m_grom_address + 1) & 0xffff;
|
||||||
|
|
||||||
|
// Reset the write address flipflop.
|
||||||
|
m_waddr_LSB = false;
|
||||||
|
if (TRACE_GKRACKER) logerror("GROM read -> %02x\n", *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_romspace_selected)
|
||||||
|
{
|
||||||
|
// Reads from the RAM space of the GRAM Kracker.
|
||||||
|
|
||||||
|
// RAM is stored behind the GRAM area
|
||||||
|
// Note that offset is 0000...1fff
|
||||||
|
// When switch in middle position (WP) do bank select according to page flag
|
||||||
|
if (m_gk_switch[1] == GK_NORMAL)
|
||||||
|
{
|
||||||
|
int base = ((m_gk_switch[4]==GK_BANK1) || ((m_gk_switch[4]==GK_WP) && (m_ram_page==0)))? 0x10000 : 0x12000;
|
||||||
|
*value = m_ram_ptr[offset | base];
|
||||||
|
if (TRACE_GKRACKER) logerror("Read %04x -> %02x\n", offset | 0x6000, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the guest has GROMs or ROMs they will override the GK contents
|
||||||
|
if (m_cartridge != nullptr)
|
||||||
|
{
|
||||||
|
// For debugging
|
||||||
|
uint8_t val1 = *value;
|
||||||
|
|
||||||
|
// Read from the guest cartridge.
|
||||||
|
m_cartridge->readz(space, offset, value, mem_mask);
|
||||||
|
if (TRACE_GKRACKER)
|
||||||
|
if (val1 != *value) logerror("Read (from guest) %04x -> %02x\n", offset, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(ti99_gkracker_device::write)
|
||||||
|
{
|
||||||
|
// write to the guest cartridge if present
|
||||||
|
if (m_cartridge != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge->write(space, offset, data, mem_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_grom_selected)
|
||||||
|
{
|
||||||
|
// Write to the GRAM space of the GRAM Kracker.
|
||||||
|
if ((offset & 0x0002)==0x0002)
|
||||||
|
{
|
||||||
|
// Set address
|
||||||
|
if (m_waddr_LSB == true)
|
||||||
|
{
|
||||||
|
// Accept low address byte (second write)
|
||||||
|
m_grom_address = (m_grom_address & 0xff00) | data;
|
||||||
|
m_waddr_LSB = false;
|
||||||
|
if (TRACE_GKRACKER) logerror("Set GROM address %04x\n", m_grom_address);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Accept high address byte (first write)
|
||||||
|
m_grom_address = (m_grom_address & 0x00ff) | (data << 8);
|
||||||
|
m_waddr_LSB = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Write data byte to GRAM area.
|
||||||
|
if (TRACE_GKRACKER) logerror("GROM write %04x(%04x) <- %02x\n", offset, m_grom_address, data);
|
||||||
|
|
||||||
|
// According to manual:
|
||||||
|
// Writing to GRAM 0: switch 2 set to GRAM 0 + Write protect switch (4) in 1 or 2 position
|
||||||
|
// Writing to GRAM 1: switch 3 set to GRAM 1-2 + Loader off (5); write prot has no effect
|
||||||
|
// Writing to GRAM 2: switch 3 set to GRAM 1-2 (write prot has no effect)
|
||||||
|
// Writing to GRAM 3-7: switch 1 set to GK_NORMAL, no cartridge inserted
|
||||||
|
// GK_NORMAL switch has no effect on GRAM 0-2
|
||||||
|
|
||||||
|
int id = ((m_grom_address & 0xe000)>>13)&0x07;
|
||||||
|
|
||||||
|
if ((id==0 && m_gk_switch[2]==GK_GRAM0 && m_gk_switch[4]!=GK_WP)
|
||||||
|
|| (id==1 && m_gk_switch[3]==GK_GRAM12 && m_gk_switch[5]==GK_LDOFF)
|
||||||
|
|| (id==2 && m_gk_switch[3]==GK_GRAM12)
|
||||||
|
|| (id>=3 && m_gk_switch[1]==GK_NORMAL))
|
||||||
|
m_ram_ptr[m_grom_address] = data;
|
||||||
|
|
||||||
|
// The GK GROM emulation does not wrap at 8K boundaries.
|
||||||
|
m_grom_address = (m_grom_address + 1) & 0xffff;
|
||||||
|
|
||||||
|
// Reset the write address flipflop.
|
||||||
|
m_waddr_LSB = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_romspace_selected)
|
||||||
|
{
|
||||||
|
// Write to the RAM space of the GRAM Kracker
|
||||||
|
if (TRACE_GKRACKER) logerror("Write %04x <- %02x\n", offset | 0x6000, data);
|
||||||
|
|
||||||
|
if (m_gk_switch[1] == GK_NORMAL)
|
||||||
|
{
|
||||||
|
if (m_gk_switch[4]==GK_BANK1) m_ram_ptr[offset | 0x10000] = data;
|
||||||
|
else if (m_gk_switch[4]==GK_BANK2) m_ram_ptr[offset | 0x12000] = data;
|
||||||
|
// Switch in middle position (WP, implies auto-select according to the page flag)
|
||||||
|
// This is handled like in Extended Basic (using addresses)
|
||||||
|
else m_ram_page = (offset >> 1) & 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER( ti99_gkracker_device::crureadz )
|
||||||
|
{
|
||||||
|
if (m_cartridge != nullptr) m_cartridge->crureadz(space, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER( ti99_gkracker_device::cruwrite )
|
||||||
|
{
|
||||||
|
if (m_cartridge != nullptr) m_cartridge->cruwrite(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_CHANGED_MEMBER( ti99_gkracker_device::gk_changed )
|
||||||
|
{
|
||||||
|
if (TRACE_GKRACKER) logerror("Input changed %d - %d\n", (int)((uint64_t)param & 0x07), newval);
|
||||||
|
m_gk_switch[(uint64_t)param & 0x07] = newval;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::insert(int index, ti99_cartridge_device* cart)
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE) logerror("Insert cartridge\n");
|
||||||
|
m_cartridge = cart;
|
||||||
|
// Switch 1 has a third location for resetting. We do the reset by default
|
||||||
|
// here. It can be turned off in the configuration.
|
||||||
|
m_gromport->cartridge_inserted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::remove(int index)
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE) logerror("Remove cartridge\n");
|
||||||
|
m_cartridge = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::gk_install_menu(const char* menutext, int len, int ptr, int next, int start)
|
||||||
|
{
|
||||||
|
const int base = 0x0000;
|
||||||
|
m_ram_ptr[base + ptr] = (uint8_t)((next >> 8) & 0xff);
|
||||||
|
m_ram_ptr[base + ptr+1] = (uint8_t)(next & 0xff);
|
||||||
|
m_ram_ptr[base + ptr+2] = (uint8_t)((start >> 8) & 0xff);
|
||||||
|
m_ram_ptr[base + ptr+3] = (uint8_t)(start & 0xff);
|
||||||
|
|
||||||
|
m_ram_ptr[base + ptr+4] = (uint8_t)(len & 0xff);
|
||||||
|
memcpy(m_ram_ptr + base + ptr+5, menutext, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Define the default for the GRAM Kracker device. The memory is preset with
|
||||||
|
some sample entries which shall indicate that the memory has been tested
|
||||||
|
by the manufacturer.
|
||||||
|
*/
|
||||||
|
void ti99_gkracker_device::nvram_default()
|
||||||
|
{
|
||||||
|
if (TRACE_GKRACKER) logerror("Creating default NVRAM\n");
|
||||||
|
memset(m_ram_ptr, 0, 81920);
|
||||||
|
|
||||||
|
m_ram_ptr[0x6000] = 0xaa;
|
||||||
|
m_ram_ptr[0x6001] = 0x01;
|
||||||
|
m_ram_ptr[0x6002] = 0x01;
|
||||||
|
|
||||||
|
m_ram_ptr[0x6006] = 0x60;
|
||||||
|
m_ram_ptr[0x6007] = 0x20;
|
||||||
|
|
||||||
|
gk_install_menu("GROM 3 OK", 9, 0x60e0, 0, 0x6100);
|
||||||
|
gk_install_menu("GROM 4 OK", 9, 0x60c0, 0x60e0, 0x6100);
|
||||||
|
gk_install_menu("GROM 5 OK", 9, 0x60a0, 0x60c0, 0x6100);
|
||||||
|
gk_install_menu("GROM 6 OK", 9, 0x6080, 0x60a0, 0x6100);
|
||||||
|
gk_install_menu("PROM OK", 9, 0x6060, 0x6080, 0x6100);
|
||||||
|
gk_install_menu("RAMS OK", 9, 0x6040, 0x6060, 0x6100);
|
||||||
|
gk_install_menu("OPTION GRAMS OK", 15, 0x6020, 0x6040, 0x6100);
|
||||||
|
|
||||||
|
m_ram_ptr[0x6100] = 0x0b; // GPL EXIT
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::nvram_read(emu_file &file)
|
||||||
|
{
|
||||||
|
int readsize = file.read(m_ram_ptr, 81920);
|
||||||
|
if (TRACE_GKRACKER) logerror("Reading NVRAM\n");
|
||||||
|
// If we increased the size, fill the remaining parts with 0
|
||||||
|
if (readsize < 81920)
|
||||||
|
{
|
||||||
|
memset(m_ram_ptr + readsize, 0, 81920-readsize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::nvram_write(emu_file &file)
|
||||||
|
{
|
||||||
|
if (TRACE_GKRACKER) logerror("Writing NVRAM\n");
|
||||||
|
file.write(m_ram_ptr, 81920);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::device_start()
|
||||||
|
{
|
||||||
|
m_ram_ptr = memregion(GKRACKER_NVRAM_TAG)->base();
|
||||||
|
m_grom_ptr = memregion(GKRACKER_ROM_TAG)->base();
|
||||||
|
m_cartridge = nullptr;
|
||||||
|
for (int i=1; i < 6; i++) m_gk_switch[i] = 0;
|
||||||
|
save_pointer(NAME(m_gk_switch),6);
|
||||||
|
save_item(NAME(m_romspace_selected));
|
||||||
|
save_item(NAME(m_ram_page));
|
||||||
|
save_item(NAME(m_grom_address));
|
||||||
|
save_item(NAME(m_waddr_LSB));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_gkracker_device::device_reset()
|
||||||
|
{
|
||||||
|
m_gk_switch[1] = ioport(GKSWITCH1_TAG)->read();
|
||||||
|
m_gk_switch[2] = ioport(GKSWITCH2_TAG)->read();
|
||||||
|
m_gk_switch[3] = ioport(GKSWITCH3_TAG)->read();
|
||||||
|
m_gk_switch[4] = ioport(GKSWITCH4_TAG)->read();
|
||||||
|
m_gk_switch[5] = ioport(GKSWITCH5_TAG)->read();
|
||||||
|
m_grom_address = 0; // for the GROM emulation
|
||||||
|
m_ram_page = 0;
|
||||||
|
m_waddr_LSB = false;
|
||||||
|
m_grom_selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( gkracker_slot )
|
||||||
|
MCFG_DEVICE_ADD("cartridge", TI99_CART, 0)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
/*
|
||||||
|
The GRAMKracker ROM
|
||||||
|
*/
|
||||||
|
ROM_START( gkracker_rom )
|
||||||
|
ROM_REGION(0x14000, GKRACKER_NVRAM_TAG, ROMREGION_ERASE00)
|
||||||
|
ROM_REGION(0x2000, GKRACKER_ROM_TAG, 0)
|
||||||
|
ROM_LOAD("gkracker.bin", 0x0000, 0x2000, CRC(86eaaf9f) SHA1(a3bd5257c63e190800921b52dbe3ffa91ad91113))
|
||||||
|
ROM_END
|
||||||
|
|
||||||
|
const tiny_rom_entry *ti99_gkracker_device::device_rom_region() const
|
||||||
|
{
|
||||||
|
return ROM_NAME( gkracker_rom );
|
||||||
|
}
|
||||||
|
|
||||||
|
machine_config_constructor ti99_gkracker_device::device_mconfig_additions() const
|
||||||
|
{
|
||||||
|
return MACHINE_CONFIG_NAME( gkracker_slot );
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_PORTS_START(gkracker)
|
||||||
|
PORT_START( GKSWITCH1_TAG )
|
||||||
|
PORT_DIPNAME( 0x01, 0x01, "GK switch 1" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_gkracker_device, gk_changed, 1)
|
||||||
|
PORT_DIPSETTING( 0x00, "GK Off" )
|
||||||
|
PORT_DIPSETTING( 0x01, DEF_STR( Normal ) )
|
||||||
|
|
||||||
|
PORT_START( GKSWITCH2_TAG )
|
||||||
|
PORT_DIPNAME( 0x01, 0x01, "GK switch 2" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_gkracker_device, gk_changed, 2)
|
||||||
|
PORT_DIPSETTING( 0x00, "GRAM 0" )
|
||||||
|
PORT_DIPSETTING( 0x01, "Op Sys" )
|
||||||
|
|
||||||
|
PORT_START( GKSWITCH3_TAG )
|
||||||
|
PORT_DIPNAME( 0x01, 0x01, "GK switch 3" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_gkracker_device, gk_changed, 3)
|
||||||
|
PORT_DIPSETTING( 0x00, "GRAM 1-2" )
|
||||||
|
PORT_DIPSETTING( 0x01, "TI BASIC" )
|
||||||
|
|
||||||
|
PORT_START( GKSWITCH4_TAG )
|
||||||
|
PORT_DIPNAME( 0x03, 0x01, "GK switch 4" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_gkracker_device, gk_changed, 4)
|
||||||
|
PORT_DIPSETTING( 0x00, "Bank 1" )
|
||||||
|
PORT_DIPSETTING( 0x01, "W/P" )
|
||||||
|
PORT_DIPSETTING( 0x02, "Bank 2" )
|
||||||
|
|
||||||
|
PORT_START( GKSWITCH5_TAG )
|
||||||
|
PORT_DIPNAME( 0x01, 0x00, "GK switch 5" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_gkracker_device, gk_changed, 5)
|
||||||
|
PORT_DIPSETTING( 0x00, "Loader On" )
|
||||||
|
PORT_DIPSETTING( 0x01, "Loader Off" )
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
ioport_constructor ti99_gkracker_device::device_input_ports() const
|
||||||
|
{
|
||||||
|
return INPUT_PORTS_NAME(gkracker);
|
||||||
|
}
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
71
src/devices/bus/ti99/gromport/gkracker.h
Normal file
71
src/devices/bus/ti99/gromport/gkracker.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/****************************************************************************
|
||||||
|
GRAM Kracker.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAME_BUS_TI99_GROMPORT_GKRACKER_H
|
||||||
|
#define MAME_BUS_TI99_GROMPORT_GKRACKER_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "bus/ti99/ti99defs.h"
|
||||||
|
#include "cartridges.h"
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
class ti99_gkracker_device : public cartridge_connector_device, public device_nvram_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ti99_gkracker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
||||||
|
|
||||||
|
void insert(int index, ti99_cartridge_device* cart) override;
|
||||||
|
void remove(int index) override;
|
||||||
|
DECLARE_INPUT_CHANGED_MEMBER( gk_changed );
|
||||||
|
|
||||||
|
// We may have a cartridge plugged into the GK
|
||||||
|
bool is_grom_idle() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
|
||||||
|
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||||
|
virtual const tiny_rom_entry* device_rom_region() const override;
|
||||||
|
virtual ioport_constructor device_input_ports() const override;
|
||||||
|
|
||||||
|
// device_nvram_interface
|
||||||
|
void nvram_default() override;
|
||||||
|
void nvram_read(emu_file &file) override;
|
||||||
|
void nvram_write(emu_file &file) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int m_gk_switch[6]; // Used to cache the switch settings.
|
||||||
|
|
||||||
|
bool m_romspace_selected;
|
||||||
|
int m_ram_page;
|
||||||
|
int m_grom_address;
|
||||||
|
uint8_t* m_ram_ptr;
|
||||||
|
uint8_t* m_grom_ptr;
|
||||||
|
|
||||||
|
bool m_waddr_LSB;
|
||||||
|
|
||||||
|
ti99_cartridge_device *m_cartridge; // guest cartridge
|
||||||
|
|
||||||
|
// Just for proper initialization
|
||||||
|
void gk_install_menu(const char* menutext, int len, int ptr, int next, int start);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_GK, bus::ti99::gromport, ti99_gkracker_device)
|
||||||
|
|
||||||
|
#endif // MAME_BUS_TI99_GROMPORT_GKRACKER_H
|
297
src/devices/bus/ti99/gromport/gromport.cpp
Normal file
297
src/devices/bus/ti99/gromport/gromport.cpp
Normal file
@ -0,0 +1,297 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/***************************************************************************
|
||||||
|
GROM port - the cartridge port of the TI-99/4, TI-99/4A, and
|
||||||
|
TI-99/8 console.
|
||||||
|
|
||||||
|
The name refers to the main intended application scenario, that is,
|
||||||
|
to host cartridges with GROMs. The second, wider port of the console is
|
||||||
|
called I/O port and connects to the Peripheral Expansion System
|
||||||
|
(see peribox.h).
|
||||||
|
|
||||||
|
LEFT
|
||||||
|
|
||||||
|
/RESET 1||2 GND
|
||||||
|
D7 3||4 CRUCLK
|
||||||
|
D6 5||6 CRUIN
|
||||||
|
D5 7||8 A15/CRUOUT
|
||||||
|
D4 9||10 A13
|
||||||
|
D3 11||12 A12
|
||||||
|
D2 13||14 A11
|
||||||
|
D1 15||16 A10
|
||||||
|
D0 17||18 A9
|
||||||
|
+5V 19||20 A8
|
||||||
|
/GS 21||22 A7
|
||||||
|
A14 23||24 A3
|
||||||
|
DBIN 25||26 A6
|
||||||
|
GRMCLK 27||28 A5
|
||||||
|
-5V 29||30 A4
|
||||||
|
READY 31||32 /WE
|
||||||
|
GND 33||34 /ROMG
|
||||||
|
GND 35||36 GND
|
||||||
|
|
||||||
|
RIGHT
|
||||||
|
|
||||||
|
Address bus line ordering, according to TI convention, is A0 (MSB) ... A15 (LSB).
|
||||||
|
A0, A1, and A2 are not delivered to the port but decoded in the console:
|
||||||
|
|
||||||
|
/ROMG is asserted for A0/A1/A2 = 011 (addresses 6000 - 7fff)
|
||||||
|
/GS is asserted for A0...A5 = 100110 (addresses 9800 - 9bff)
|
||||||
|
|
||||||
|
This means that a maximum of 8 KiB of direct memory space can be accessed.
|
||||||
|
The /GS line is used to enable GROM circuits on the board (serial ROMs with
|
||||||
|
own address counter, see tmc0430.h).
|
||||||
|
|
||||||
|
When a cartridge is inserted the /RESET line is pulled to ground, which
|
||||||
|
via a R/C component pulls down the /RESET input of the timer circuit for
|
||||||
|
a short time, which in turn resets the CPU. In order to dump cartridges,
|
||||||
|
a common procedure was to tape the /RESET line of the cartridge. However,
|
||||||
|
inserting a cartridge without resetting often caused so much data bus noise
|
||||||
|
that the console usually locked up.
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
The TI-99/4A computer was strictly designed for cartridge usage. The basic
|
||||||
|
console had only little directly accessible RAM and offered no ways to
|
||||||
|
write machine language programs; cartridges were intended to add various
|
||||||
|
capabilities, or just for running games.
|
||||||
|
|
||||||
|
Beside the seemingly simple handling, Texas Instruments had own intentions
|
||||||
|
behind their cartridge strategy. With only 8 KiB of direct access memory, a
|
||||||
|
major part of the cartridge code had to be stored in GROMs, which had to be
|
||||||
|
licensed from Texas Instruments. Thus they kept firm control over all
|
||||||
|
software development.
|
||||||
|
|
||||||
|
Over the years, and with the increasingly difficult market situations,
|
||||||
|
TI's policies seem to have changed. This may be the reason that the built-in
|
||||||
|
operating system actually allowed for running ROM-only cartridges until TI
|
||||||
|
clipped out this part in the OS, banning cartridges without GROMs. Consoles
|
||||||
|
with this modification were produced in 1983, TI's last year in the home
|
||||||
|
computer business.
|
||||||
|
|
||||||
|
Although only 8 KiB were available for direct addressing, clever techniques
|
||||||
|
were invented by third-party manufacturers. The first extension was utilized
|
||||||
|
by TI themselves in the Extended Basic cartridge which offers two banks
|
||||||
|
of ROM contents. Switching between the banks is achieved by writing a value
|
||||||
|
to the ROM space at 6000 or 6002. Later, cartridges with much more memory
|
||||||
|
space were created, up to the Super Space II cartridge with 128 KiB of
|
||||||
|
buffered SRAM.
|
||||||
|
|
||||||
|
----------------
|
||||||
|
|
||||||
|
From the console case layout the GROM port was intended for a single
|
||||||
|
cartridge only. Although never officially released, the operating system
|
||||||
|
of the TI console supported a multi-cartridge extender with software
|
||||||
|
switching. There were also extenders based on hardware switching (like
|
||||||
|
the Navarone Widget).
|
||||||
|
|
||||||
|
This emulation offers both variants as slot options:
|
||||||
|
|
||||||
|
-gromport single : default single cartridge connector
|
||||||
|
-gromport multi : software-switchable 4-slot cartridge extender
|
||||||
|
-gromport gkracker : GRAM Kracker
|
||||||
|
|
||||||
|
The last option enables another popular device, the GRAM Kracker. This is
|
||||||
|
a device to be plugged into the cartridge slot with five manual switches
|
||||||
|
at the front and an own cartridge slot at its top. It contains buffered
|
||||||
|
SRAM, a built-in ROM, and a GROM simulator which simulates GROM behaviour
|
||||||
|
when accessing the buffered RAM. Its main use is to provide editable
|
||||||
|
storage for the read-only cartridge contents. Cartridges can be plugged
|
||||||
|
into its slot; their contents can be read and written to disk, modified as
|
||||||
|
needed, and loaded into the buffered RAM. Even the console GROMs can be
|
||||||
|
copied into the device; despite running in parallel, the GROM simulator
|
||||||
|
is able to override the console GROMs, thus allowing the user to install
|
||||||
|
a customized OS.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
#include "emu.h"
|
||||||
|
#include "gromport.h"
|
||||||
|
#include "emuopts.h"
|
||||||
|
#include "image.h"
|
||||||
|
#include "softlist.h"
|
||||||
|
|
||||||
|
#include "singleconn.h"
|
||||||
|
#include "multiconn.h"
|
||||||
|
#include "gkracker.h"
|
||||||
|
|
||||||
|
DEFINE_DEVICE_TYPE_NS(TI99_GROMPORT, bus::ti99::gromport, gromport_device, "gromport", "TI-99 Cartridge port")
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
#define TRACE_READ 0
|
||||||
|
#define TRACE_WRITE 0
|
||||||
|
|
||||||
|
gromport_device::gromport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
|
: bus8z_device(mconfig, TI99_GROMPORT, tag, owner, clock),
|
||||||
|
device_slot_interface(mconfig, *this),
|
||||||
|
m_connector(nullptr),
|
||||||
|
m_reset_on_insert(true),
|
||||||
|
m_console_ready(*this),
|
||||||
|
m_console_reset(*this)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Reading via the GROM port. Only 13 address lines are passed through
|
||||||
|
on the TI-99/4A, and 14 lines on the TI-99/8.
|
||||||
|
*/
|
||||||
|
READ8Z_MEMBER(gromport_device::readz)
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
{
|
||||||
|
m_connector->readz(space, offset & m_mask, value);
|
||||||
|
if (TRACE_READ) if (m_romgq) logerror("Read %04x -> %02x\n", offset | 0x6000, *value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Writing via the GROM port. Only 13 address lines are passed through
|
||||||
|
on the TI-99/4A, and 14 lines on the TI-99/8.
|
||||||
|
*/
|
||||||
|
WRITE8_MEMBER(gromport_device::write)
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
{
|
||||||
|
if (TRACE_WRITE) if (m_romgq) logerror("Write %04x <- %02x\n", offset | 0x6000, data);
|
||||||
|
m_connector->write(space, offset & m_mask, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(gromport_device::crureadz)
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
m_connector->crureadz(space, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(gromport_device::cruwrite)
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
m_connector->cruwrite(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(gromport_device::ready_line)
|
||||||
|
{
|
||||||
|
m_console_ready(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Asserted when the console addresses cartridge rom.
|
||||||
|
*/
|
||||||
|
WRITE_LINE_MEMBER(gromport_device::romgq_line)
|
||||||
|
{
|
||||||
|
m_romgq = state;
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
m_connector->romgq_line(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(gromport_device::gclock_in)
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
m_connector->gclock_in(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Combined GROM control lines.
|
||||||
|
*/
|
||||||
|
WRITE8_MEMBER( gromport_device::set_gromlines )
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
m_connector->set_gromlines(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void gromport_device::device_start()
|
||||||
|
{
|
||||||
|
m_console_ready.resolve();
|
||||||
|
m_console_reset.resolve();
|
||||||
|
|
||||||
|
save_item(NAME(m_romgq));
|
||||||
|
}
|
||||||
|
|
||||||
|
void gromport_device::device_reset()
|
||||||
|
{
|
||||||
|
m_reset_on_insert = (ioport("CARTRESET")->read()==0x01);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shall we reset the console when a cartridge has been inserted?
|
||||||
|
This is triggered by the cartridge by pulling down /RESET via a capacitor.
|
||||||
|
Accordingly, when we put a tape over the /RESET contact we can avoid the
|
||||||
|
reset, which is useful when we want to swap the cartridges while a program
|
||||||
|
is runnning.
|
||||||
|
*/
|
||||||
|
void gromport_device::cartridge_inserted()
|
||||||
|
{
|
||||||
|
if (m_reset_on_insert)
|
||||||
|
{
|
||||||
|
m_console_reset(ASSERT_LINE);
|
||||||
|
m_console_reset(CLEAR_LINE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find out whether the GROMs in the cartridge are idle. In that case,
|
||||||
|
cut the clock line.
|
||||||
|
*/
|
||||||
|
bool gromport_device::is_grom_idle()
|
||||||
|
{
|
||||||
|
if (m_connector != nullptr)
|
||||||
|
return m_connector->is_grom_idle();
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gromport_device::device_config_complete()
|
||||||
|
{
|
||||||
|
m_connector = downcast<cartridge_connector_device*>(subdevices().first());
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_PORTS_START(gromport)
|
||||||
|
PORT_START( "CARTRESET" )
|
||||||
|
PORT_CONFNAME( 0x01, 0x01, "RESET on cartridge insert" )
|
||||||
|
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
|
||||||
|
PORT_CONFSETTING( 0x01, DEF_STR( On ) )
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
ioport_constructor gromport_device::device_input_ports() const
|
||||||
|
{
|
||||||
|
return INPUT_PORTS_NAME(gromport);
|
||||||
|
}
|
||||||
|
|
||||||
|
/***************************************************************************
|
||||||
|
Different versions of cartridge connections
|
||||||
|
|
||||||
|
single: the standard console connector, one cartridge
|
||||||
|
multi: a multi-cart expander, up to 4 cartridges with software selection
|
||||||
|
gkracker: GRAMKracker, a device with NVRAM which allows the user to copy
|
||||||
|
the contents of the cartridge plugged into its slot into the NVRAM
|
||||||
|
and to modify it.
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
cartridge_connector_device::cartridge_connector_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||||
|
: bus8z_device(mconfig, type, tag, owner, clock),
|
||||||
|
m_gromport(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER( cartridge_connector_device::ready_line )
|
||||||
|
{
|
||||||
|
m_gromport->ready_line(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
void cartridge_connector_device::device_config_complete()
|
||||||
|
{
|
||||||
|
m_gromport = static_cast<gromport_device*>(owner());
|
||||||
|
}
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
SLOT_INTERFACE_START( gromport4 )
|
||||||
|
SLOT_INTERFACE("single", TI99_GROMPORT_SINGLE)
|
||||||
|
SLOT_INTERFACE("multi", TI99_GROMPORT_MULTI)
|
||||||
|
SLOT_INTERFACE("gkracker", TI99_GROMPORT_GK)
|
||||||
|
SLOT_INTERFACE_END
|
||||||
|
|
||||||
|
SLOT_INTERFACE_START( gromport8 )
|
||||||
|
SLOT_INTERFACE("single", TI99_GROMPORT_SINGLE)
|
||||||
|
SLOT_INTERFACE("multi", TI99_GROMPORT_MULTI)
|
||||||
|
SLOT_INTERFACE_END
|
112
src/devices/bus/ti99/gromport/gromport.h
Normal file
112
src/devices/bus/ti99/gromport/gromport.h
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/***************************************************************************
|
||||||
|
Gromport (Cartridge port) of the TI-99 consoles
|
||||||
|
For details see gromport.cpp
|
||||||
|
|
||||||
|
Michael Zapf
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAME_BUS_TI99_GROMPORT_GROMPORT_H
|
||||||
|
#define MAME_BUS_TI99_GROMPORT_GROMPORT_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bus/ti99/ti99defs.h"
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
struct pcb_type
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
const char* name;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ti99_cartridge_device;
|
||||||
|
class cartridge_connector_device;
|
||||||
|
|
||||||
|
class gromport_device : public bus8z_device, public device_slot_interface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
gromport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz);
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite);
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines); // Combined GROM select lines
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
||||||
|
|
||||||
|
static void set_mask(device_t &device, int mask) { downcast<gromport_device &>(device).m_mask = mask; }
|
||||||
|
|
||||||
|
template <class Object> static devcb_base &static_set_ready_callback(device_t &device, Object &&cb) { return downcast<gromport_device &>(device).m_console_ready.set_callback(std::forward<Object>(cb)); }
|
||||||
|
template <class Object> static devcb_base &static_set_reset_callback(device_t &device, Object &&cb) { return downcast<gromport_device &>(device).m_console_reset.set_callback(std::forward<Object>(cb)); }
|
||||||
|
|
||||||
|
void cartridge_inserted();
|
||||||
|
bool is_grom_idle();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
virtual void device_config_complete() override;
|
||||||
|
virtual ioport_constructor device_input_ports() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
cartridge_connector_device* m_connector;
|
||||||
|
bool m_reset_on_insert;
|
||||||
|
devcb_write_line m_console_ready;
|
||||||
|
devcb_write_line m_console_reset;
|
||||||
|
int m_mask;
|
||||||
|
int m_romgq;
|
||||||
|
};
|
||||||
|
|
||||||
|
class cartridge_connector_device : public bus8z_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual DECLARE_READ8Z_MEMBER(crureadz) = 0;
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(cruwrite) = 0;
|
||||||
|
|
||||||
|
virtual DECLARE_WRITE_LINE_MEMBER(romgq_line) = 0;
|
||||||
|
virtual DECLARE_WRITE8_MEMBER(set_gromlines) = 0;
|
||||||
|
|
||||||
|
virtual DECLARE_WRITE_LINE_MEMBER(gclock_in) = 0;
|
||||||
|
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
||||||
|
|
||||||
|
virtual void insert(int index, bus::ti99::gromport::ti99_cartridge_device* cart) { m_gromport->cartridge_inserted(); }
|
||||||
|
virtual void remove(int index) { }
|
||||||
|
virtual bool is_grom_idle() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
cartridge_connector_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
virtual void device_config_complete() override;
|
||||||
|
|
||||||
|
gromport_device* m_gromport;
|
||||||
|
bool m_grom_selected;
|
||||||
|
};
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
SLOT_INTERFACE_EXTERN(gromport4);
|
||||||
|
SLOT_INTERFACE_EXTERN(gromport8);
|
||||||
|
|
||||||
|
#define MCFG_GROMPORT4_ADD( _tag ) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, TI99_GROMPORT, 0) \
|
||||||
|
bus::ti99::gromport::gromport_device::set_mask(*device, 0x1fff); \
|
||||||
|
MCFG_DEVICE_SLOT_INTERFACE(gromport4, "single", false)
|
||||||
|
|
||||||
|
#define MCFG_GROMPORT8_ADD( _tag ) \
|
||||||
|
MCFG_DEVICE_ADD(_tag, TI99_GROMPORT, 0) \
|
||||||
|
bus::ti99::gromport::gromport_device::set_mask(*device, 0x3fff); \
|
||||||
|
MCFG_DEVICE_SLOT_INTERFACE(gromport8, "single", false)
|
||||||
|
|
||||||
|
#define MCFG_GROMPORT_READY_HANDLER( _ready ) \
|
||||||
|
devcb = &bus::ti99::gromport::gromport_device::static_set_ready_callback( *device, DEVCB_##_ready );
|
||||||
|
|
||||||
|
#define MCFG_GROMPORT_RESET_HANDLER( _reset ) \
|
||||||
|
devcb = &bus::ti99::gromport::gromport_device::static_set_reset_callback( *device, DEVCB_##_reset );
|
||||||
|
|
||||||
|
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT, bus::ti99::gromport, gromport_device)
|
||||||
|
|
||||||
|
#endif // MAME_BUS_TI99_GROMPORT_GROMPORT_H
|
332
src/devices/bus/ti99/gromport/multiconn.cpp
Normal file
332
src/devices/bus/ti99/gromport/multiconn.cpp
Normal file
@ -0,0 +1,332 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/**************************************************************************
|
||||||
|
The multi-cartridge extender
|
||||||
|
|
||||||
|
This is a somewhat mythical device which was never available for the normal
|
||||||
|
customer, but there are reports of the existence of such a device
|
||||||
|
in development labs or demonstrations.
|
||||||
|
|
||||||
|
The interesting thing about this is that the OS of the console
|
||||||
|
fully supports this multi-cartridge extender, providing a selection
|
||||||
|
option on the screen to switch between different plugged-in
|
||||||
|
cartridges.
|
||||||
|
|
||||||
|
The switching is possible by decoding address lines that are reserved
|
||||||
|
for GROM access. GROMs are accessed via four separate addresses
|
||||||
|
9800, 9802, 9C00, 9C02. The addressing scheme looks like this:
|
||||||
|
|
||||||
|
1001 1Wxx xxxx xxM0 W = write(1), read(0), M = address(1), data(0)
|
||||||
|
|
||||||
|
This leaves 8 bits (256 options) which are not decoded inside the
|
||||||
|
console. As the complete address is routed to the port, some circuit
|
||||||
|
just needs to decode the xxx lines and turn on the respective slot.
|
||||||
|
|
||||||
|
One catch must be considered: Some cartridges contain ROMs which are
|
||||||
|
directly accessed and not via ports. This means that the ROMs must
|
||||||
|
be activated according to the slot that is selected.
|
||||||
|
|
||||||
|
Another issue: Each GROM contains an own address counter and an ID.
|
||||||
|
According to the ID the GROM only delivers data if the address counter
|
||||||
|
is within the ID area (0 = 0000-1fff, 1=2000-3fff ... 7=e000-ffff).
|
||||||
|
Thus it is essential that all GROMs stay in sync with their address
|
||||||
|
counters. We have to route all address settings to all slots and their
|
||||||
|
GROMs, even when the slot has not been selected before. The selected
|
||||||
|
just shows its effect when data is read. In this case, only the
|
||||||
|
data from the selected slot will be delivered.
|
||||||
|
|
||||||
|
This may be considered as a design flaw within the complete cartridge system
|
||||||
|
which eventually led to TI not manufacturing that device for the broad
|
||||||
|
market.
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "multiconn.h"
|
||||||
|
|
||||||
|
DEFINE_DEVICE_TYPE_NS(TI99_GROMPORT_MULTI, bus::ti99::gromport, ti99_multi_cart_conn_device, "ti99_mcartconn", "TI-99 Multi-cartridge extender")
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
#define AUTO -1
|
||||||
|
#define TRACE_CHANGE 0
|
||||||
|
|
||||||
|
ti99_multi_cart_conn_device::ti99_multi_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
|
: cartridge_connector_device(mconfig, TI99_GROMPORT_MULTI, tag, owner, clock),
|
||||||
|
m_active_slot(0),
|
||||||
|
m_fixed_slot(0),
|
||||||
|
m_next_free_slot(0)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Activates a slot in the multi-cartridge extender.
|
||||||
|
Setting the slot is done by accessing the GROM ports using a
|
||||||
|
specific address:
|
||||||
|
|
||||||
|
slot 0: 0x9800 (0x9802, 0x9c00, 0x9c02) : cartridge1
|
||||||
|
slot 1: 0x9804 (0x9806, 0x9c04, 0x9c06) : cartridge2
|
||||||
|
...
|
||||||
|
slot 15: 0x983c (0x983e, 0x9c3c, 0x9c3e) : cartridge16
|
||||||
|
|
||||||
|
Scheme:
|
||||||
|
|
||||||
|
1001 1Wxx xxxx xxM0 (M=mode; M=0: data, M=1: address; W=write)
|
||||||
|
|
||||||
|
The following addresses are theoretically available, but the
|
||||||
|
built-in OS does not use them; i.e. cartridges will not be
|
||||||
|
included in the selection list, and their features will not be
|
||||||
|
found by lookup, but they could be accessed directly by user
|
||||||
|
programs.
|
||||||
|
slot 16: 0x9840 (0x9842, 0x9c40, 0x9c42)
|
||||||
|
...
|
||||||
|
slot 255: 0x9bfc (0x9bfe, 0x9ffc, 0x9ffe)
|
||||||
|
|
||||||
|
Setting the GROM base should select one cartridge, but the ROMs in the
|
||||||
|
CPU space must also be switched. As there is no known special mechanism
|
||||||
|
we assume that by switching the GROM base, the ROM is automatically
|
||||||
|
switched.
|
||||||
|
|
||||||
|
Caution: This means that cartridges which do not have at least one
|
||||||
|
GROM cannot be switched with this mechanism.
|
||||||
|
|
||||||
|
We assume that the slot number is already calculated in the caller:
|
||||||
|
slotnumber>=0 && slotnumber<=255
|
||||||
|
|
||||||
|
NOTE: The OS will stop searching when it finds slots 1 and 2 empty.
|
||||||
|
Interestingly, cartridge subroutines are found nevertheless, even when
|
||||||
|
the cartridge is plugged into a higher slot.
|
||||||
|
*/
|
||||||
|
void ti99_multi_cart_conn_device::set_slot(int slotnumber)
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE)
|
||||||
|
if (m_active_slot != slotnumber) logerror("Setting cartslot to %d\n", slotnumber);
|
||||||
|
|
||||||
|
if (m_fixed_slot==AUTO)
|
||||||
|
m_active_slot = slotnumber;
|
||||||
|
else
|
||||||
|
m_active_slot = m_fixed_slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ti99_multi_cart_conn_device::get_active_slot(bool changebase, offs_t offset)
|
||||||
|
{
|
||||||
|
int slot;
|
||||||
|
if (changebase)
|
||||||
|
{
|
||||||
|
// GROM selected?
|
||||||
|
if (m_grom_selected) set_slot((offset>>2) & 0x00ff);
|
||||||
|
}
|
||||||
|
slot = m_active_slot;
|
||||||
|
return slot;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_multi_cart_conn_device::insert(int index, ti99_cartridge_device* cart)
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE) logerror("Insert slot %d\n", index);
|
||||||
|
m_cartridge[index] = cart;
|
||||||
|
m_gromport->cartridge_inserted();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_multi_cart_conn_device::remove(int index)
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE) logerror("Remove slot %d\n", index);
|
||||||
|
m_cartridge[index] = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_multi_cart_conn_device::romgq_line)
|
||||||
|
{
|
||||||
|
m_readrom = state;
|
||||||
|
|
||||||
|
// Propagate to all slots
|
||||||
|
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
||||||
|
{
|
||||||
|
if (m_cartridge[i] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[i]->romgq_line(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Combined select lines
|
||||||
|
*/
|
||||||
|
WRITE8_MEMBER(ti99_multi_cart_conn_device::set_gromlines)
|
||||||
|
{
|
||||||
|
// GROM selected?
|
||||||
|
m_grom_selected = (data != 0);
|
||||||
|
|
||||||
|
// Propagate to all slots
|
||||||
|
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
||||||
|
{
|
||||||
|
if (m_cartridge[i] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[i]->set_gromlines(space, offset, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_multi_cart_conn_device::gclock_in)
|
||||||
|
{
|
||||||
|
// Propagate to all slots
|
||||||
|
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
||||||
|
{
|
||||||
|
if (m_cartridge[i] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[i]->gclock_in(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(ti99_multi_cart_conn_device::readz)
|
||||||
|
{
|
||||||
|
int slot = get_active_slot(true, offset);
|
||||||
|
|
||||||
|
// If we have a GROM access, we need to send the read request to all
|
||||||
|
// attached cartridges so the slot is irrelevant here. Each GROM
|
||||||
|
// contains an internal address counter, and we must make sure they all stay in sync.
|
||||||
|
if (m_grom_selected)
|
||||||
|
{
|
||||||
|
for (int i=0; i < NUMBER_OF_CARTRIDGE_SLOTS; i++)
|
||||||
|
{
|
||||||
|
if (m_cartridge[i] != nullptr)
|
||||||
|
{
|
||||||
|
uint8_t newval = *value;
|
||||||
|
m_cartridge[i]->readz(space, offset, &newval, 0xff);
|
||||||
|
if (i==slot)
|
||||||
|
{
|
||||||
|
*value = newval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[slot]->readz(space, offset, value, 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(ti99_multi_cart_conn_device::write)
|
||||||
|
{
|
||||||
|
// Same issue as above (read)
|
||||||
|
// We don't have GRAM cartridges, anyway, so it's just used for setting the address.
|
||||||
|
if (m_grom_selected)
|
||||||
|
{
|
||||||
|
for (auto & elem : m_cartridge)
|
||||||
|
{
|
||||||
|
if (elem != nullptr)
|
||||||
|
{
|
||||||
|
elem->write(space, offset, data, 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int slot = get_active_slot(true, offset);
|
||||||
|
if (slot < NUMBER_OF_CARTRIDGE_SLOTS && m_cartridge[slot] != nullptr)
|
||||||
|
{
|
||||||
|
// logerror("writing %04x (slot %d) <- %02x\n", offset, slot, data);
|
||||||
|
m_cartridge[slot]->write(space, offset, data, 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(ti99_multi_cart_conn_device::crureadz)
|
||||||
|
{
|
||||||
|
int slot = get_active_slot(false, offset);
|
||||||
|
/* Sanity check. Higher slots are always empty. */
|
||||||
|
if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_cartridge[slot] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[slot]->crureadz(space, offset, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(ti99_multi_cart_conn_device::cruwrite)
|
||||||
|
{
|
||||||
|
int slot = get_active_slot(true, offset);
|
||||||
|
|
||||||
|
/* Sanity check. Higher slots are always empty. */
|
||||||
|
if (slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_cartridge[slot] != nullptr)
|
||||||
|
{
|
||||||
|
m_cartridge[slot]->cruwrite(space, offset, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check whether the GROMs are idle. Just ask the currently
|
||||||
|
active cartridge.
|
||||||
|
*/
|
||||||
|
bool ti99_multi_cart_conn_device::is_grom_idle()
|
||||||
|
{
|
||||||
|
/* Sanity check. Higher slots are always empty. */
|
||||||
|
if (m_active_slot >= NUMBER_OF_CARTRIDGE_SLOTS)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (m_cartridge[m_active_slot] != nullptr)
|
||||||
|
return m_cartridge[m_active_slot]->is_grom_idle();
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_multi_cart_conn_device::device_start()
|
||||||
|
{
|
||||||
|
m_next_free_slot = 0;
|
||||||
|
m_active_slot = 0;
|
||||||
|
for (auto & elem : m_cartridge)
|
||||||
|
{
|
||||||
|
elem = nullptr;
|
||||||
|
}
|
||||||
|
save_item(NAME(m_readrom));
|
||||||
|
save_item(NAME(m_active_slot));
|
||||||
|
save_item(NAME(m_fixed_slot));
|
||||||
|
save_item(NAME(m_next_free_slot));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_multi_cart_conn_device::device_reset(void)
|
||||||
|
{
|
||||||
|
m_active_slot = 0;
|
||||||
|
m_fixed_slot = ioport("CARTSLOT")->read() - 1;
|
||||||
|
m_grom_selected = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( multi_slot )
|
||||||
|
MCFG_DEVICE_ADD("cartridge1", TI99_CART, 0)
|
||||||
|
MCFG_DEVICE_ADD("cartridge2", TI99_CART, 0)
|
||||||
|
MCFG_DEVICE_ADD("cartridge3", TI99_CART, 0)
|
||||||
|
MCFG_DEVICE_ADD("cartridge4", TI99_CART, 0)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
machine_config_constructor ti99_multi_cart_conn_device::device_mconfig_additions() const
|
||||||
|
{
|
||||||
|
return MACHINE_CONFIG_NAME( multi_slot );
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_CHANGED_MEMBER( ti99_multi_cart_conn_device::switch_changed )
|
||||||
|
{
|
||||||
|
if (TRACE_CHANGE) logerror("Slot changed %d - %d\n", (int)((uint64_t)param & 0x07), newval);
|
||||||
|
m_active_slot = m_fixed_slot = newval - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
INPUT_PORTS_START(multi_slot)
|
||||||
|
PORT_START( "CARTSLOT" )
|
||||||
|
PORT_DIPNAME( 0x0f, 0x00, "Multi-cartridge slot" ) PORT_CHANGED_MEMBER(DEVICE_SELF, ti99_multi_cart_conn_device, switch_changed, 0)
|
||||||
|
PORT_DIPSETTING( 0x00, "Auto" )
|
||||||
|
PORT_DIPSETTING( 0x01, "Slot 1" )
|
||||||
|
PORT_DIPSETTING( 0x02, "Slot 2" )
|
||||||
|
PORT_DIPSETTING( 0x03, "Slot 3" )
|
||||||
|
PORT_DIPSETTING( 0x04, "Slot 4" )
|
||||||
|
INPUT_PORTS_END
|
||||||
|
|
||||||
|
ioport_constructor ti99_multi_cart_conn_device::device_input_ports() const
|
||||||
|
{
|
||||||
|
return INPUT_PORTS_NAME(multi_slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
66
src/devices/bus/ti99/gromport/multiconn.h
Normal file
66
src/devices/bus/ti99/gromport/multiconn.h
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/****************************************************************************
|
||||||
|
|
||||||
|
Multi cartridge connector.
|
||||||
|
|
||||||
|
We set the number of slots to 4, although we may have up to 16. From a
|
||||||
|
logical point of view we could have 256, but the operating system only checks
|
||||||
|
the first 16 banks.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAME_BUS_TI99_GROMPORT_MULTICONN_H
|
||||||
|
#define MAME_BUS_TI99_GROMPORT_MULTICONN_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "bus/ti99/ti99defs.h"
|
||||||
|
#include "cartridges.h"
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
class ti99_multi_cart_conn_device : public cartridge_connector_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ti99_multi_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
||||||
|
|
||||||
|
void insert(int index, ti99_cartridge_device* cart) override;
|
||||||
|
void remove(int index) override;
|
||||||
|
DECLARE_INPUT_CHANGED_MEMBER( switch_changed );
|
||||||
|
|
||||||
|
bool is_grom_idle() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static constexpr unsigned NUMBER_OF_CARTRIDGE_SLOTS = 4;
|
||||||
|
|
||||||
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||||
|
virtual ioport_constructor device_input_ports() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_readrom;
|
||||||
|
int m_active_slot;
|
||||||
|
int m_fixed_slot;
|
||||||
|
int m_next_free_slot;
|
||||||
|
ti99_cartridge_device* m_cartridge[NUMBER_OF_CARTRIDGE_SLOTS];
|
||||||
|
|
||||||
|
void set_slot(int slotnumber);
|
||||||
|
int get_active_slot(bool changebase, offs_t offset);
|
||||||
|
};
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_MULTI, bus::ti99::gromport, ti99_multi_cart_conn_device)
|
||||||
|
|
||||||
|
#endif // MAME_BUS_TI99_GROMPORT_MULTICONN_H
|
||||||
|
|
||||||
|
|
||||||
|
|
95
src/devices/bus/ti99/gromport/singleconn.cpp
Normal file
95
src/devices/bus/ti99/gromport/singleconn.cpp
Normal file
@ -0,0 +1,95 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/***************************************************************************
|
||||||
|
|
||||||
|
Single: the standard console connector, one cartridge
|
||||||
|
|
||||||
|
***************************************************************************/
|
||||||
|
|
||||||
|
#include "singleconn.h"
|
||||||
|
|
||||||
|
DEFINE_DEVICE_TYPE_NS(TI99_GROMPORT_SINGLE, bus::ti99::gromport, ti99_single_cart_conn_device, "ti99_scartconn", "TI-99 Standard cartridge connector")
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
ti99_single_cart_conn_device::ti99_single_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||||
|
: cartridge_connector_device(mconfig, TI99_GROMPORT_SINGLE, tag, owner, clock),
|
||||||
|
m_cartridge(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(ti99_single_cart_conn_device::readz)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->readz(space, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(ti99_single_cart_conn_device::write)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->write(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
READ8Z_MEMBER(ti99_single_cart_conn_device::crureadz)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->crureadz(space, offset, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE8_MEMBER(ti99_single_cart_conn_device::cruwrite)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->cruwrite(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_single_cart_conn_device::romgq_line)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->romgq_line(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Combined select lines
|
||||||
|
*/
|
||||||
|
WRITE8_MEMBER(ti99_single_cart_conn_device::set_gromlines)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->set_gromlines(space, offset, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WRITE_LINE_MEMBER(ti99_single_cart_conn_device::gclock_in)
|
||||||
|
{
|
||||||
|
// Pass through
|
||||||
|
m_cartridge->gclock_in(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Check whether the GROMs are idle.
|
||||||
|
*/
|
||||||
|
bool ti99_single_cart_conn_device::is_grom_idle()
|
||||||
|
{
|
||||||
|
return m_cartridge->is_grom_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_single_cart_conn_device::device_start()
|
||||||
|
{
|
||||||
|
m_cartridge = static_cast<ti99_cartridge_device*>(subdevices().first());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ti99_single_cart_conn_device::device_reset()
|
||||||
|
{
|
||||||
|
m_cartridge->set_slot(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static MACHINE_CONFIG_START( single_slot )
|
||||||
|
MCFG_DEVICE_ADD("cartridge", TI99_CART, 0)
|
||||||
|
MACHINE_CONFIG_END
|
||||||
|
|
||||||
|
machine_config_constructor ti99_single_cart_conn_device::device_mconfig_additions() const
|
||||||
|
{
|
||||||
|
return MACHINE_CONFIG_NAME( single_slot );
|
||||||
|
}
|
||||||
|
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
44
src/devices/bus/ti99/gromport/singleconn.h
Normal file
44
src/devices/bus/ti99/gromport/singleconn.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
// license:LGPL-2.1+
|
||||||
|
// copyright-holders:Michael Zapf
|
||||||
|
/****************************************************************************
|
||||||
|
Single cartridge connector.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef MAME_BUS_TI99_GROMPORT_SINGLECONN_H
|
||||||
|
#define MAME_BUS_TI99_GROMPORT_SINGLECONN_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "bus/ti99/ti99defs.h"
|
||||||
|
#include "cartridges.h"
|
||||||
|
|
||||||
|
namespace bus { namespace ti99 { namespace gromport {
|
||||||
|
|
||||||
|
class ti99_single_cart_conn_device : public cartridge_connector_device
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ti99_single_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||||
|
|
||||||
|
DECLARE_READ8Z_MEMBER(readz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(write) override;
|
||||||
|
DECLARE_READ8Z_MEMBER(crureadz) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
||||||
|
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
||||||
|
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
||||||
|
|
||||||
|
bool is_grom_idle() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual void device_start() override;
|
||||||
|
virtual void device_reset() override;
|
||||||
|
virtual machine_config_constructor device_mconfig_additions() const override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ti99_cartridge_device *m_cartridge;
|
||||||
|
};
|
||||||
|
} } } // end namespace bus::ti99::gromport
|
||||||
|
|
||||||
|
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_SINGLE, bus::ti99::gromport, ti99_single_cart_conn_device)
|
||||||
|
|
||||||
|
#endif // MAME_BUS_TI99_GROMPORT_SINGLECONN_H
|
@ -19,7 +19,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "bus/ti99/ti99defs.h"
|
#include "bus/ti99/ti99defs.h"
|
||||||
#include "gromport.h"
|
#include "bus/ti99/gromport/gromport.h"
|
||||||
|
|
||||||
#include "bus/ti99/internal/ioport.h"
|
#include "bus/ti99/internal/ioport.h"
|
||||||
#include "machine/ram.h"
|
#include "machine/ram.h"
|
||||||
@ -442,9 +442,6 @@ public:
|
|||||||
DECLARE_WRITE_LINE_MEMBER( speech_ready );
|
DECLARE_WRITE_LINE_MEMBER( speech_ready );
|
||||||
DECLARE_WRITE_LINE_MEMBER( pbox_ready );
|
DECLARE_WRITE_LINE_MEMBER( pbox_ready );
|
||||||
|
|
||||||
// Emulation
|
|
||||||
// void set_gromport(gromport_device* dev) { m_gromport = dev; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void device_start() override;
|
void device_start() override;
|
||||||
void device_reset() override;
|
void device_reset() override;
|
||||||
@ -509,7 +506,7 @@ private:
|
|||||||
required_device<tms9928a_device> m_video;
|
required_device<tms9928a_device> m_video;
|
||||||
required_device<sn76496_base_device> m_sound;
|
required_device<sn76496_base_device> m_sound;
|
||||||
required_device<cd2501ecd_device> m_speech;
|
required_device<cd2501ecd_device> m_speech;
|
||||||
required_device<bus::ti99::internal::gromport_device> m_gromport;
|
required_device<bus::ti99::gromport::gromport_device> m_gromport;
|
||||||
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
||||||
|
|
||||||
required_device<ram_device> m_sram;
|
required_device<ram_device> m_sram;
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
#include "bus/ti99/ti99defs.h"
|
#include "bus/ti99/ti99defs.h"
|
||||||
#include "machine/tmc0430.h"
|
#include "machine/tmc0430.h"
|
||||||
#include "gromport.h"
|
#include "bus/ti99/gromport/gromport.h"
|
||||||
#include "bus/ti99/internal/ioport.h"
|
#include "bus/ti99/internal/ioport.h"
|
||||||
#include "sound/sn76496.h"
|
#include "sound/sn76496.h"
|
||||||
#include "video/tms9928a.h"
|
#include "video/tms9928a.h"
|
||||||
@ -67,7 +67,7 @@ private:
|
|||||||
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
||||||
|
|
||||||
// Link to the cartridge port (aka GROM port)
|
// Link to the cartridge port (aka GROM port)
|
||||||
required_device<gromport_device> m_gromport;
|
required_device<bus::ti99::gromport::gromport_device> m_gromport;
|
||||||
|
|
||||||
// Memory expansion (internal, 16 bit)
|
// Memory expansion (internal, 16 bit)
|
||||||
required_device<ram_device> m_ram16b;
|
required_device<ram_device> m_ram16b;
|
||||||
|
@ -1,468 +0,0 @@
|
|||||||
// license:LGPL-2.1+
|
|
||||||
// copyright-holders:Michael Zapf
|
|
||||||
/***************************************************************************
|
|
||||||
Gromport (Cartridge port) of the TI-99 consoles
|
|
||||||
For details see gromport.cpp
|
|
||||||
|
|
||||||
Michael Zapf
|
|
||||||
***************************************************************************/
|
|
||||||
|
|
||||||
#ifndef MAME_BUS_TI99_INTERNAL_GROMPORT_H
|
|
||||||
#define MAME_BUS_TI99_INTERNAL_GROMPORT_H
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "bus/ti99/ti99defs.h"
|
|
||||||
#include "machine/tmc0430.h"
|
|
||||||
#include "softlist_dev.h"
|
|
||||||
|
|
||||||
namespace bus { namespace ti99 { namespace internal {
|
|
||||||
|
|
||||||
class cartridge_connector_device;
|
|
||||||
|
|
||||||
class gromport_device : public bus8z_device, public device_slot_interface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
gromport_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz);
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite);
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
|
||||||
|
|
||||||
// Combined GROM select lines
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines);
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
|
||||||
|
|
||||||
static void set_mask(device_t &device, int mask) { downcast<gromport_device &>(device).m_mask = mask; }
|
|
||||||
|
|
||||||
template <class Object> static devcb_base &static_set_ready_callback(device_t &device, Object &&cb) { return downcast<gromport_device &>(device).m_console_ready.set_callback(std::forward<Object>(cb)); }
|
|
||||||
template <class Object> static devcb_base &static_set_reset_callback(device_t &device, Object &&cb) { return downcast<gromport_device &>(device).m_console_reset.set_callback(std::forward<Object>(cb)); }
|
|
||||||
|
|
||||||
void cartridge_inserted();
|
|
||||||
bool is_grom_idle();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void device_start() override;
|
|
||||||
virtual void device_reset() override;
|
|
||||||
virtual void device_config_complete() override;
|
|
||||||
virtual ioport_constructor device_input_ports() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
cartridge_connector_device* m_connector;
|
|
||||||
bool m_reset_on_insert;
|
|
||||||
devcb_write_line m_console_ready;
|
|
||||||
devcb_write_line m_console_reset;
|
|
||||||
int m_mask;
|
|
||||||
int m_romgq;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
class ti99_cartridge_pcb;
|
|
||||||
|
|
||||||
class ti99_cartridge_device : public bus8z_device, public device_image_interface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ti99_cartridge_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz);
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite);
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines);
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
|
||||||
|
|
||||||
bool is_available() { return m_pcb != nullptr; }
|
|
||||||
void set_slot(int i);
|
|
||||||
bool is_grom_idle();
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void device_start() override { }
|
|
||||||
virtual void device_config_complete() override;
|
|
||||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
|
||||||
virtual const tiny_rom_entry* device_rom_region() const override;
|
|
||||||
|
|
||||||
// Image handling: implementation of methods which are abstract in the parent
|
|
||||||
image_init_result call_load() override;
|
|
||||||
void call_unload() override;
|
|
||||||
virtual const software_list_loader &get_software_list_loader() const override { return rom_software_list_loader::instance(); }
|
|
||||||
|
|
||||||
void prepare_cartridge();
|
|
||||||
|
|
||||||
// device_image_interface
|
|
||||||
iodevice_t image_type() const override { return IO_CARTSLOT; }
|
|
||||||
bool is_readable() const override { return true; }
|
|
||||||
bool is_writeable() const override { return false; }
|
|
||||||
bool is_creatable() const override { return false; }
|
|
||||||
bool must_be_loaded() const override { return false; }
|
|
||||||
bool is_reset_on_load() const override { return false; }
|
|
||||||
const char *image_interface() const override { return "ti99_cart"; }
|
|
||||||
const char *file_extensions() const override { return "rpk"; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
class rpk_socket;
|
|
||||||
class rpk_reader;
|
|
||||||
class rpk;
|
|
||||||
|
|
||||||
bool m_readrom;
|
|
||||||
int m_pcbtype;
|
|
||||||
int m_slot;
|
|
||||||
int get_index_from_tagname();
|
|
||||||
|
|
||||||
std::unique_ptr<ti99_cartridge_pcb> m_pcb; // inbound
|
|
||||||
cartridge_connector_device* m_connector; // outbound
|
|
||||||
|
|
||||||
// RPK which is associated to this cartridge
|
|
||||||
// When we close it, the contents are saved to NVRAM if available
|
|
||||||
rpk *m_rpk;
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
class cartridge_connector_device : public bus8z_device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual DECLARE_READ8Z_MEMBER(crureadz) = 0;
|
|
||||||
virtual DECLARE_WRITE8_MEMBER(cruwrite) = 0;
|
|
||||||
|
|
||||||
virtual DECLARE_WRITE_LINE_MEMBER(romgq_line) = 0;
|
|
||||||
virtual DECLARE_WRITE8_MEMBER(set_gromlines) = 0;
|
|
||||||
|
|
||||||
virtual DECLARE_WRITE_LINE_MEMBER(gclock_in) = 0;
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(ready_line);
|
|
||||||
|
|
||||||
virtual void insert(int index, ti99_cartridge_device* cart) { m_gromport->cartridge_inserted(); }
|
|
||||||
virtual void remove(int index) { }
|
|
||||||
virtual bool is_grom_idle() = 0;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
cartridge_connector_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
virtual void device_config_complete() override;
|
|
||||||
|
|
||||||
gromport_device* m_gromport;
|
|
||||||
bool m_grom_selected;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Single cartridge connector.
|
|
||||||
*/
|
|
||||||
class ti99_single_cart_conn_device : public cartridge_connector_device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ti99_single_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
|
||||||
|
|
||||||
bool is_grom_idle() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void device_start() override;
|
|
||||||
virtual void device_reset() override;
|
|
||||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
ti99_cartridge_device *m_cartridge;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
Multi cartridge connector.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* We set the number of slots to 4, although we may have up to 16. From a
|
|
||||||
logical point of view we could have 256, but the operating system only checks
|
|
||||||
the first 16 banks. */
|
|
||||||
|
|
||||||
class ti99_multi_cart_conn_device : public cartridge_connector_device
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ti99_multi_cart_conn_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
|
||||||
|
|
||||||
void insert(int index, ti99_cartridge_device* cart) override;
|
|
||||||
void remove(int index) override;
|
|
||||||
DECLARE_INPUT_CHANGED_MEMBER( switch_changed );
|
|
||||||
|
|
||||||
bool is_grom_idle() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
static constexpr unsigned NUMBER_OF_CARTRIDGE_SLOTS = 4;
|
|
||||||
|
|
||||||
virtual void device_start() override;
|
|
||||||
virtual void device_reset() override;
|
|
||||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
|
||||||
virtual ioport_constructor device_input_ports() const override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_readrom;
|
|
||||||
int m_active_slot;
|
|
||||||
int m_fixed_slot;
|
|
||||||
int m_next_free_slot;
|
|
||||||
ti99_cartridge_device* m_cartridge[NUMBER_OF_CARTRIDGE_SLOTS];
|
|
||||||
|
|
||||||
void set_slot(int slotnumber);
|
|
||||||
int get_active_slot(bool changebase, offs_t offset);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
GRAM Kracker.
|
|
||||||
*/
|
|
||||||
class ti99_gkracker_device : public cartridge_connector_device, public device_nvram_interface
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ti99_gkracker_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
|
||||||
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in) override;
|
|
||||||
|
|
||||||
void insert(int index, ti99_cartridge_device* cart) override;
|
|
||||||
void remove(int index) override;
|
|
||||||
DECLARE_INPUT_CHANGED_MEMBER( gk_changed );
|
|
||||||
|
|
||||||
// We may have a cartridge plugged into the GK
|
|
||||||
bool is_grom_idle() override;
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual void device_start() override;
|
|
||||||
virtual void device_reset() override;
|
|
||||||
|
|
||||||
virtual machine_config_constructor device_mconfig_additions() const override;
|
|
||||||
virtual const tiny_rom_entry* device_rom_region() const override;
|
|
||||||
virtual ioport_constructor device_input_ports() const override;
|
|
||||||
|
|
||||||
// device_nvram_interface
|
|
||||||
void nvram_default() override;
|
|
||||||
void nvram_read(emu_file &file) override;
|
|
||||||
void nvram_write(emu_file &file) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
int m_gk_switch[6]; // Used to cache the switch settings.
|
|
||||||
|
|
||||||
bool m_romspace_selected;
|
|
||||||
int m_ram_page;
|
|
||||||
int m_grom_address;
|
|
||||||
uint8_t* m_ram_ptr;
|
|
||||||
uint8_t* m_grom_ptr;
|
|
||||||
|
|
||||||
bool m_waddr_LSB;
|
|
||||||
|
|
||||||
ti99_cartridge_device *m_cartridge; // guest cartridge
|
|
||||||
|
|
||||||
// Just for proper initialization
|
|
||||||
void gk_install_menu(const char* menutext, int len, int ptr, int next, int start);
|
|
||||||
};
|
|
||||||
|
|
||||||
/****************************************************************************/
|
|
||||||
|
|
||||||
class ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
friend class ti99_cartridge_device;
|
|
||||||
public:
|
|
||||||
ti99_cartridge_pcb();
|
|
||||||
virtual ~ti99_cartridge_pcb() { }
|
|
||||||
|
|
||||||
protected:
|
|
||||||
virtual DECLARE_READ8Z_MEMBER(readz);
|
|
||||||
virtual DECLARE_WRITE8_MEMBER(write);
|
|
||||||
virtual DECLARE_READ8Z_MEMBER(crureadz);
|
|
||||||
virtual DECLARE_WRITE8_MEMBER(cruwrite);
|
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(romgq_line);
|
|
||||||
virtual DECLARE_WRITE8_MEMBER(set_gromlines);
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gclock_in);
|
|
||||||
|
|
||||||
DECLARE_READ8Z_MEMBER(gromreadz);
|
|
||||||
DECLARE_WRITE8_MEMBER(gromwrite);
|
|
||||||
inline void set_grom_pointer(int number, device_t *dev);
|
|
||||||
void set_cartridge(ti99_cartridge_device *cart);
|
|
||||||
const char* tag() { return m_tag; }
|
|
||||||
void set_tag(const char* tag) { m_tag = tag; }
|
|
||||||
bool is_grom_idle() { return m_grom_idle; }
|
|
||||||
|
|
||||||
ti99_cartridge_device* m_cart;
|
|
||||||
tmc0430_device* m_grom[5];
|
|
||||||
bool m_grom_idle;
|
|
||||||
int m_grom_size;
|
|
||||||
int m_rom_size;
|
|
||||||
int m_ram_size;
|
|
||||||
|
|
||||||
uint8_t* m_rom_ptr;
|
|
||||||
uint8_t* m_ram_ptr;
|
|
||||||
bool m_romspace_selected;
|
|
||||||
int m_rom_page; // for some cartridge types
|
|
||||||
uint8_t* m_grom_ptr; // for gromemu
|
|
||||||
int m_grom_address; // for gromemu
|
|
||||||
int m_ram_page; // for super
|
|
||||||
const char* m_tag;
|
|
||||||
std::vector<uint8_t> m_nvram; // for MiniMemory
|
|
||||||
std::vector<uint8_t> m_ram; // for MBX
|
|
||||||
};
|
|
||||||
|
|
||||||
/******************** Standard cartridge ******************************/
|
|
||||||
|
|
||||||
class ti99_standard_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
};
|
|
||||||
|
|
||||||
/*********** Paged cartridge (like Extended Basic) ********************/
|
|
||||||
|
|
||||||
class ti99_paged12k_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*********** Paged cartridge (others) ********************/
|
|
||||||
|
|
||||||
class ti99_paged16k_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** Mini Memory ***********************************/
|
|
||||||
|
|
||||||
class ti99_minimem_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************* Super Space II *********************************/
|
|
||||||
|
|
||||||
class ti99_super_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/************************* MBX ***************************************/
|
|
||||||
|
|
||||||
class ti99_mbx_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** Paged 379i ************************************/
|
|
||||||
|
|
||||||
class ti99_paged379i_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
private:
|
|
||||||
int get_paged379i_bank(int rompage);
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** Paged 378 ************************************/
|
|
||||||
|
|
||||||
class ti99_paged378_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** Paged 377 ************************************/
|
|
||||||
|
|
||||||
class ti99_paged377_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** Paged CRU ************************************/
|
|
||||||
|
|
||||||
class ti99_pagedcru_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(crureadz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(cruwrite) override;
|
|
||||||
};
|
|
||||||
|
|
||||||
/********************** GROM emulation cartridge ************************************/
|
|
||||||
|
|
||||||
class ti99_gromemu_cartridge : public ti99_cartridge_pcb
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
ti99_gromemu_cartridge(): m_waddr_LSB(false), m_grom_selected(false), m_grom_read_mode(false), m_grom_address_mode(false)
|
|
||||||
{ m_grom_address = 0; }
|
|
||||||
DECLARE_READ8Z_MEMBER(readz) override;
|
|
||||||
DECLARE_WRITE8_MEMBER(write) override;
|
|
||||||
DECLARE_READ8Z_MEMBER(gromemureadz);
|
|
||||||
DECLARE_WRITE8_MEMBER(gromemuwrite);
|
|
||||||
DECLARE_WRITE8_MEMBER(set_gromlines) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool m_waddr_LSB;
|
|
||||||
bool m_grom_selected;
|
|
||||||
bool m_grom_read_mode;
|
|
||||||
bool m_grom_address_mode;
|
|
||||||
};
|
|
||||||
|
|
||||||
} } } // end namespace bus::ti99::internal
|
|
||||||
|
|
||||||
SLOT_INTERFACE_EXTERN(gromport4);
|
|
||||||
SLOT_INTERFACE_EXTERN(gromport8);
|
|
||||||
|
|
||||||
#define MCFG_GROMPORT4_ADD( _tag ) \
|
|
||||||
MCFG_DEVICE_ADD(_tag, TI99_GROMPORT, 0) \
|
|
||||||
bus::ti99::internal::gromport_device::set_mask(*device, 0x1fff); \
|
|
||||||
MCFG_DEVICE_SLOT_INTERFACE(gromport4, "single", false)
|
|
||||||
|
|
||||||
#define MCFG_GROMPORT8_ADD( _tag ) \
|
|
||||||
MCFG_DEVICE_ADD(_tag, TI99_GROMPORT, 0) \
|
|
||||||
bus::ti99::internal::gromport_device::set_mask(*device, 0x3fff); \
|
|
||||||
MCFG_DEVICE_SLOT_INTERFACE(gromport8, "single", false)
|
|
||||||
|
|
||||||
#define MCFG_GROMPORT_READY_HANDLER( _ready ) \
|
|
||||||
devcb = &bus::ti99::internal::gromport_device::static_set_ready_callback( *device, DEVCB_##_ready );
|
|
||||||
|
|
||||||
#define MCFG_GROMPORT_RESET_HANDLER( _reset ) \
|
|
||||||
devcb = &bus::ti99::internal::gromport_device::static_set_reset_callback( *device, DEVCB_##_reset );
|
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT, bus::ti99::internal, gromport_device)
|
|
||||||
DECLARE_DEVICE_TYPE_NS(TI99_CART, bus::ti99::internal, ti99_cartridge_device)
|
|
||||||
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_SINGLE, bus::ti99::internal, ti99_single_cart_conn_device)
|
|
||||||
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_MULTI, bus::ti99::internal, ti99_multi_cart_conn_device)
|
|
||||||
DECLARE_DEVICE_TYPE_NS(TI99_GROMPORT_GK, bus::ti99::internal, ti99_gkracker_device)
|
|
||||||
|
|
||||||
#endif // MAME_BUS_TI99_INTERNAL_GROMPORT_H
|
|
@ -48,7 +48,7 @@
|
|||||||
|
|
||||||
#include "bus/ti99/ti99defs.h"
|
#include "bus/ti99/ti99defs.h"
|
||||||
#include "bus/ti99/internal/datamux.h"
|
#include "bus/ti99/internal/datamux.h"
|
||||||
#include "bus/ti99/internal/gromport.h"
|
#include "bus/ti99/gromport/gromport.h"
|
||||||
#include "bus/ti99/internal/evpcconn.h"
|
#include "bus/ti99/internal/evpcconn.h"
|
||||||
|
|
||||||
#include "bus/ti99/joyport/joyport.h"
|
#include "bus/ti99/joyport/joyport.h"
|
||||||
@ -166,7 +166,7 @@ private:
|
|||||||
// Connected devices
|
// Connected devices
|
||||||
required_device<tms9900_device> m_cpu;
|
required_device<tms9900_device> m_cpu;
|
||||||
required_device<tms9901_device> m_tms9901;
|
required_device<tms9901_device> m_tms9901;
|
||||||
required_device<bus::ti99::internal::gromport_device> m_gromport;
|
required_device<bus::ti99::gromport::gromport_device> m_gromport;
|
||||||
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
||||||
required_device<bus::ti99::joyport::joyport_device> m_joyport;
|
required_device<bus::ti99::joyport::joyport_device> m_joyport;
|
||||||
required_device<bus::ti99::internal::datamux_device> m_datamux;
|
required_device<bus::ti99::internal::datamux_device> m_datamux;
|
||||||
|
@ -182,7 +182,7 @@ Known Issues (MZ, 2010-11-07)
|
|||||||
#include "imagedev/cassette.h"
|
#include "imagedev/cassette.h"
|
||||||
|
|
||||||
#include "bus/ti99/internal/998board.h"
|
#include "bus/ti99/internal/998board.h"
|
||||||
#include "bus/ti99/internal/gromport.h"
|
#include "bus/ti99/gromport/gromport.h"
|
||||||
|
|
||||||
#include "bus/ti99/joyport/joyport.h"
|
#include "bus/ti99/joyport/joyport.h"
|
||||||
#include "bus/ti99/internal/ioport.h"
|
#include "bus/ti99/internal/ioport.h"
|
||||||
@ -275,7 +275,7 @@ private:
|
|||||||
// Connected devices
|
// Connected devices
|
||||||
required_device<tms9995_device> m_cpu;
|
required_device<tms9995_device> m_cpu;
|
||||||
required_device<tms9901_device> m_tms9901;
|
required_device<tms9901_device> m_tms9901;
|
||||||
required_device<bus::ti99::internal::gromport_device> m_gromport;
|
required_device<bus::ti99::gromport::gromport_device> m_gromport;
|
||||||
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
||||||
required_device<bus::ti99::internal::mainboard8_device> m_mainboard;
|
required_device<bus::ti99::internal::mainboard8_device> m_mainboard;
|
||||||
required_device<bus::ti99::joyport::joyport_device> m_joyport;
|
required_device<bus::ti99::joyport::joyport_device> m_joyport;
|
||||||
|
Loading…
Reference in New Issue
Block a user