mirror of
https://github.com/holub/mame
synced 2025-04-22 08:22:15 +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/gromport/cartridges.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/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/genboard.cpp",
|
||||
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.h",
|
||||
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/colorbus.cpp",
|
||||
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.h",
|
||||
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
|
||||
|
||||
#include "bus/ti99/ti99defs.h"
|
||||
#include "gromport.h"
|
||||
#include "bus/ti99/gromport/gromport.h"
|
||||
|
||||
#include "bus/ti99/internal/ioport.h"
|
||||
#include "machine/ram.h"
|
||||
@ -442,9 +442,6 @@ public:
|
||||
DECLARE_WRITE_LINE_MEMBER( speech_ready );
|
||||
DECLARE_WRITE_LINE_MEMBER( pbox_ready );
|
||||
|
||||
// Emulation
|
||||
// void set_gromport(gromport_device* dev) { m_gromport = dev; }
|
||||
|
||||
protected:
|
||||
void device_start() override;
|
||||
void device_reset() override;
|
||||
@ -509,7 +506,7 @@ private:
|
||||
required_device<tms9928a_device> m_video;
|
||||
required_device<sn76496_base_device> m_sound;
|
||||
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<ram_device> m_sram;
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
#include "bus/ti99/ti99defs.h"
|
||||
#include "machine/tmc0430.h"
|
||||
#include "gromport.h"
|
||||
#include "bus/ti99/gromport/gromport.h"
|
||||
#include "bus/ti99/internal/ioport.h"
|
||||
#include "sound/sn76496.h"
|
||||
#include "video/tms9928a.h"
|
||||
@ -67,7 +67,7 @@ private:
|
||||
required_device<bus::ti99::internal::ioport_device> m_ioport;
|
||||
|
||||
// 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)
|
||||
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/internal/datamux.h"
|
||||
#include "bus/ti99/internal/gromport.h"
|
||||
#include "bus/ti99/gromport/gromport.h"
|
||||
#include "bus/ti99/internal/evpcconn.h"
|
||||
|
||||
#include "bus/ti99/joyport/joyport.h"
|
||||
@ -166,7 +166,7 @@ private:
|
||||
// Connected devices
|
||||
required_device<tms9900_device> m_cpu;
|
||||
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::joyport::joyport_device> m_joyport;
|
||||
required_device<bus::ti99::internal::datamux_device> m_datamux;
|
||||
|
@ -182,7 +182,7 @@ Known Issues (MZ, 2010-11-07)
|
||||
#include "imagedev/cassette.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/internal/ioport.h"
|
||||
@ -275,7 +275,7 @@ private:
|
||||
// Connected devices
|
||||
required_device<tms9995_device> m_cpu;
|
||||
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::mainboard8_device> m_mainboard;
|
||||
required_device<bus::ti99::joyport::joyport_device> m_joyport;
|
||||
|
Loading…
Reference in New Issue
Block a user